From 7bde76ca2c649213546f412c28b7b05260338ad4 Mon Sep 17 00:00:00 2001 From: Reese Gallagher Date: Sat, 24 Aug 2024 12:42:38 -0400 Subject: [PATCH 001/115] [rmodels] More performant point cloud rendering with `DrawModelPoints()` (#4203) * Added the ability to draw a model as a point cloud * Added example to demonstrate drawing a model as a point cloud * polished the demo a bit * picture for example * adhere to conventions for example * update png to match aspect ratio * minor changes * address code convention comments * added point rendering to makefiles * added point rendering to readme and renumbered examples * comment formatting --------- Co-authored-by: Reese Gallagher Co-authored-by: Ray --- examples/Makefile | 1 + examples/Makefile.Web | 1 + examples/README.md | 50 +++--- examples/models/models_point_rendering.c | 171 +++++++++++++++++++++ examples/models/models_point_rendering.png | Bin 0 -> 130183 bytes src/raylib.h | 2 + src/rmodels.c | 24 +++ 7 files changed, 224 insertions(+), 25 deletions(-) create mode 100644 examples/models/models_point_rendering.c create mode 100644 examples/models/models_point_rendering.png diff --git a/examples/Makefile b/examples/Makefile index 93b05a0c7..904917f7c 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -582,6 +582,7 @@ MODELS = \ models/models_mesh_generation \ models/models_mesh_picking \ models/models_orthographic_projection \ + models/models_point_rendering \ models/models_rlgl_solar_system \ models/models_skybox \ models/models_waving_cubes \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 46a8a98ea..7057da1c0 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -447,6 +447,7 @@ MODELS = \ models/models_mesh_generation \ models/models_mesh_picking \ models/models_orthographic_projection \ + models/models_point_rendering \ models/models_rlgl_solar_system \ models/models_skybox \ models/models_waving_cubes \ diff --git a/examples/README.md b/examples/README.md index 317f43c89..d573ff23e 100644 --- a/examples/README.md +++ b/examples/README.md @@ -147,11 +147,12 @@ Examples using raylib models functionality, including models loading/generation | 91 | [models_loading_vox](models/models_loading_vox.c) | models_loading_vox | ⭐️☆☆☆ | **4.0** | **4.0** | [Johann Nadalutti](https://github.com/procfxgen) | | 92 | [models_loading_m3d](models/models_loading_m3d.c) | models_loading_m3d | ⭐️☆☆☆ | **4.2** | **4.2** | [bzt](https://bztsrc.gitlab.io/model3d) | | 93 | [models_orthographic_projection](models/models_orthographic_projection.c) | models_orthographic_projection | ⭐️☆☆☆ | 2.0 | 3.7 | [Max Danielsson](https://github.com/autious) | -| 94 | [models_rlgl_solar_system](models/models_rlgl_solar_system.c) | models_rlgl_solar_system | ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) | -| 95 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) | models_yaw_pitch_roll | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Berni](https://github.com/Berni8k) | -| 96 | [models_waving_cubes](models/models_waving_cubes.c) | models_waving_cubes | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [codecat](https://github.com/codecat) | -| 97 | [models_heightmap](models/models_heightmap.c) | models_heightmap | ⭐️☆☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) | -| 98 | [models_skybox](models/models_skybox.c) | models_skybox | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) | +| 94 | [models_point_rendering](models/models_point_rendering.c) | models_point_rendering | ⭐️⭐️☆☆ | 5.0 | 5.0 | [Reese Gallagher](https://github.com/satchelfrost) | +| 95 | [models_rlgl_solar_system](models/models_rlgl_solar_system.c) | models_rlgl_solar_system | ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) | +| 96 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) | models_yaw_pitch_roll | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Berni](https://github.com/Berni8k) | +| 97 | [models_waving_cubes](models/models_waving_cubes.c) | models_waving_cubes | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [codecat](https://github.com/codecat) | +| 98 | [models_heightmap](models/models_heightmap.c) | models_heightmap | ⭐️☆☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) | +| 99 | [models_skybox](models/models_skybox.c) | models_skybox | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) | ### category: shaders @@ -159,26 +160,25 @@ Examples using raylib shaders functionality, including shaders loading, paramete | ## | example | image | difficulty
level | version
created | last version
updated | original
developer | |----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------| -| 99 | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) | shaders_basic_lighting | ⭐️⭐️⭐️⭐️ | 3.0 | **4.2** | [Chris Camacho](https://github.com/codifies) | -| 100 | [shaders_model_shader](shaders/shaders_model_shader.c) | shaders_model_shader | ⭐️⭐️☆☆ | 1.3 | 3.7 | [Ray](https://github.com/raysan5) | -| 101 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) | shaders_shapes_textures | ⭐️⭐️☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) | -| 102 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) | shaders_custom_uniform | ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | -| 103 | [shaders_postprocessing](shaders/shaders_postprocessing.c) | shaders_postprocessing | ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | -| 104 | [shaders_palette_switch](shaders/shaders_palette_switch.c) | shaders_palette_switch | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Marco Lizza](https://github.com/MarcoLizza) | -| 105 | [shaders_raymarching](shaders/shaders_raymarching.c) | shaders_raymarching | ⭐️⭐️⭐️⭐️ | 2.0 | **4.2** | [Ray](https://github.com/raysan5) | -| 106 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) | shaders_texture_drawing | ⭐️⭐️☆☆ | 2.0 | 3.7 | [Michał Ciesielski](https://github.com/) | -| 107 | [shaders_texture_outline](shaders/shaders_texture_outline.c) | shaders_texture_outline | ⭐️⭐️⭐️☆ | **4.0** | **4.0** | [Samuel Skiff](https://github.com/GoldenThumbs) | -| 108 | [shaders_texture_waves](shaders/shaders_texture_waves.c) | shaders_texture_waves | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) | -| 109 | [shaders_julia_set](shaders/shaders_julia_set.c) | shaders_julia_set | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [eggmund](https://github.com/eggmund) | -| 110 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) | shaders_eratosthenes | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [ProfJski](https://github.com/ProfJski) | -| 111 | [shaders_fog](shaders/shaders_fog.c) | shaders_fog | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | -| 112 | [shaders_simple_mask](shaders/shaders_simple_mask.c) | shaders_simple_mask | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | -| 113 | [shaders_hot_reloading](shaders/shaders_hot_reloading.c) | shaders_hot_reloading | ⭐️⭐️⭐️☆ | 3.0 | 3.5 | [Ray](https://github.com/raysan5) | -| 114 | [shaders_mesh_instancing](shaders/shaders_mesh_instancing.c) | shaders_mesh_instancing | ⭐️⭐️⭐️⭐️ | 3.7 | **4.2** | [seanpringle](https://github.com/seanpringle) | -| 115 | [shaders_multi_sample2d](shaders/shaders_multi_sample2d.c) | shaders_multi_sample2d | ⭐️⭐️☆☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) | -| 116 | [shaders_spotlight](shaders/shaders_spotlight.c) | shaders_spotlight | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | -| 117 | [shaders_deferred_render](shaders/shaders_deferred_render.c) | shaders_deferred_render | ⭐️⭐️⭐️⭐️ | 4.5 | 4.5 | [Justin Andreas Lacoste](https://github.com/27justin) | -| 118 | [shaders_vertex_displacement](shaders/shaders_vertex_displacement.c) | shaders_deferred_render | ⭐️☆☆☆ | 1.5 | 1.5 | [Alex ZH](https://github.com/ZzzhHe) | +| 100 | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) | shaders_basic_lighting | ⭐️⭐️⭐️⭐️ | 3.0 | **4.2** | [Chris Camacho](https://github.com/codifies) | +| 101 | [shaders_model_shader](shaders/shaders_model_shader.c) | shaders_model_shader | ⭐️⭐️☆☆ | 1.3 | 3.7 | [Ray](https://github.com/raysan5) | +| 102 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) | shaders_shapes_textures | ⭐️⭐️☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) | +| 103 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) | shaders_custom_uniform | ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | +| 104 | [shaders_postprocessing](shaders/shaders_postprocessing.c) | shaders_postprocessing | ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | +| 105 | [shaders_palette_switch](shaders/shaders_palette_switch.c) | shaders_palette_switch | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Marco Lizza](https://github.com/MarcoLizza) | +| 106 | [shaders_raymarching](shaders/shaders_raymarching.c) | shaders_raymarching | ⭐️⭐️⭐️⭐️ | 2.0 | **4.2** | [Ray](https://github.com/raysan5) | +| 107 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) | shaders_texture_drawing | ⭐️⭐️☆☆ | 2.0 | 3.7 | [Michał Ciesielski](https://github.com/) | +| 108 | [shaders_texture_outline](shaders/shaders_texture_outline.c) | shaders_texture_outline | ⭐️⭐️⭐️☆ | **4.0** | **4.0** | [Samuel Skiff](https://github.com/GoldenThumbs) | +| 109 | [shaders_texture_waves](shaders/shaders_texture_waves.c) | shaders_texture_waves | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) | +| 110 | [shaders_julia_set](shaders/shaders_julia_set.c) | shaders_julia_set | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [eggmund](https://github.com/eggmund) | +| 111 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) | shaders_eratosthenes | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [ProfJski](https://github.com/ProfJski) | +| 112 | [shaders_fog](shaders/shaders_fog.c) | shaders_fog | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | +| 113 | [shaders_simple_mask](shaders/shaders_simple_mask.c) | shaders_simple_mask | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | +| 114 | [shaders_hot_reloading](shaders/shaders_hot_reloading.c) | shaders_hot_reloading | ⭐️⭐️⭐️☆ | 3.0 | 3.5 | [Ray](https://github.com/raysan5) | +| 115 | [shaders_mesh_instancing](shaders/shaders_mesh_instancing.c) | shaders_mesh_instancing | ⭐️⭐️⭐️⭐️ | 3.7 | **4.2** | [seanpringle](https://github.com/seanpringle) | +| 116 | [shaders_multi_sample2d](shaders/shaders_multi_sample2d.c) | shaders_multi_sample2d | ⭐️⭐️☆☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) | +| 117 | [shaders_spotlight](shaders/shaders_spotlight.c) | shaders_spotlight | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | +| 118 | [shaders_deferred_render](shaders/shaders_deferred_render.c) | shaders_deferred_render | ⭐️⭐️⭐️⭐️ | 4.5 | 4.5 | [Justin Andreas Lacoste](https://github.com/27justin) | ### category: audio diff --git a/examples/models/models_point_rendering.c b/examples/models/models_point_rendering.c new file mode 100644 index 000000000..128a70f57 --- /dev/null +++ b/examples/models/models_point_rendering.c @@ -0,0 +1,171 @@ +/******************************************************************************************* +* +* raylib example - point rendering +* +* Example originally created with raylib 5.0, last time updated with raylib 5.0 +* +* Example contributed by Reese Gallagher (@satchelfrost) and reviewed by Ramon Santamaria (@raysan5) +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2024 Reese Gallagher (@satchelfrost) +* +********************************************************************************************/ + +#include "raylib.h" +#include // Required for: rand() +#include // Required for: cos(), sin() + +#define MAX_POINTS 10000000 // 10 million +#define MIN_POINTS 1000 // 1 thousand + +static float RandFloat(); + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + InitWindow(screenWidth, screenHeight, "raylib [models] example - point rendering"); + SetTargetFPS(60); + + Camera camera = { + .position = {3.0f, 3.0f, 3.0f}, + .target = {0.0f, 0.0f, 0.0f}, + .up = {0.0f, 1.0f, 0.0f}, + .fovy = 45.0f, + .projection = CAMERA_PERSPECTIVE, + }; + + Vector3 position = {0.0f, 0.0f, 0.0f}; + bool useDrawModelPoints = true; + bool numPointsChanged = false; + int numPoints = 1000; + Mesh mesh = GenPoints(numPoints); + Model model = LoadModelFromMesh(mesh); + //-------------------------------------------------------------------------------------- + + // Main game loop + while(!WindowShouldClose()) + { + // Update + //---------------------------------------------------------------------------------- + UpdateCamera(&camera, CAMERA_ORBITAL); + + if (IsKeyPressed(KEY_SPACE)) useDrawModelPoints = !useDrawModelPoints; + if (IsKeyPressed(KEY_UP)) + { + numPoints = (numPoints * 10 > MAX_POINTS) ? MAX_POINTS : numPoints * 10; + numPointsChanged = true; + TraceLog(LOG_INFO, "num points %d", numPoints); + } + if (IsKeyPressed(KEY_DOWN)) + { + numPoints = (numPoints / 10 < MIN_POINTS) ? MIN_POINTS : numPoints / 10; + numPointsChanged = true; + TraceLog(LOG_INFO, "num points %d", numPoints); + } + + // upload a different point cloud size + if (numPointsChanged) + { + UnloadModel(model); + mesh = GenPoints(numPoints); + model = LoadModelFromMesh(mesh); + numPointsChanged = false; + } + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + ClearBackground(BLACK); + BeginMode3D(camera); + + // The new method only uploads the points once to the GPU + if (useDrawModelPoints) + { + DrawModelPoints(model, position, 1.0f, WHITE); + } + // The old method must continually draw the "points" (lines) + else + { + for (int i = 0; i < numPoints; i++) + { + Vector3 pos = { + .x = mesh.vertices[i * 3 + 0], + .y = mesh.vertices[i * 3 + 1], + .z = mesh.vertices[i * 3 + 2], + }; + Color color = { + .r = mesh.colors[i * 4 + 0], + .g = mesh.colors[i * 4 + 1], + .b = mesh.colors[i * 4 + 2], + .a = mesh.colors[i * 4 + 3], + }; + DrawPoint3D(pos, color); + } + } + + // Draw a unit sphere for reference + DrawSphereWires(position, 1.0f, 10, 10, YELLOW); + EndMode3D(); + + // Text formatting + Color color = WHITE; + int fps = GetFPS(); + if ((fps < 30) && (fps >= 15)) color = ORANGE; + else if (fps < 15) color = RED; + DrawText(TextFormat("%2i FPS", fps), 20, 20, 40, color); + DrawText(TextFormat("Point Count: %d", numPoints), 20, screenHeight - 50, 40, WHITE); + DrawText("Up - increase points", 20, 70, 20, WHITE); + DrawText("Down - decrease points", 20, 100, 20, WHITE); + DrawText("Space - drawing function", 20, 130, 20, WHITE); + if (useDrawModelPoints) DrawText("DrawModelPoints()", 20, 160, 20, GREEN); + else DrawText("DrawPoint3D()", 20, 160, 20, RED); + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadModel(model); + CloseWindow(); + //-------------------------------------------------------------------------------------- + return 0; +} + +// Generate a spherical point cloud +Mesh GenPoints(int numPoints) +{ + Mesh mesh = { + .triangleCount = 1, + .vertexCount = numPoints, + .vertices = (float *)MemAlloc(numPoints * 3 * sizeof(float)), + .colors = (unsigned char*)MemAlloc(numPoints * 4 * sizeof(unsigned char)), + }; + + // https://en.wikipedia.org/wiki/Spherical_coordinate_system + for (int i = 0; i < numPoints; i++) + { + float theta = PI * rand() / RAND_MAX; + float phi = 2.0f * PI * rand() / RAND_MAX; + float r = 10.0f * rand() / RAND_MAX; + mesh.vertices[i * 3 + 0] = r * sin(theta) * cos(phi); + mesh.vertices[i * 3 + 1] = r * sin(theta) * sin(phi); + mesh.vertices[i * 3 + 2] = r * cos(theta); + Color color = ColorFromHSV(r * 360.0f, 1.0f, 1.0f); + mesh.colors[i * 4 + 0] = color.r; + mesh.colors[i * 4 + 1] = color.g; + mesh.colors[i * 4 + 2] = color.b; + mesh.colors[i * 4 + 3] = color.a; + } + + // Upload mesh data from CPU (RAM) to GPU (VRAM) memory + UploadMesh(&mesh, false); + return mesh; +} diff --git a/examples/models/models_point_rendering.png b/examples/models/models_point_rendering.png new file mode 100644 index 0000000000000000000000000000000000000000..a1fc718e4dd508ba6768abb6f7a0c02a1fabaf9f GIT binary patch literal 130183 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%0D_wHBg^j<|d*2-RL2s(cI%66v7 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 literal 0 HcmV?d00001 diff --git a/src/raylib.h b/src/raylib.h index 0759c259f..f51a444e1 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1545,6 +1545,8 @@ RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); 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 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 DrawModelPoints(Model model, Vector3 position, float scale, Color tint); // Draw a model as points +RLAPI void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model as points with extended parameters RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, 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 diff --git a/src/rmodels.c b/src/rmodels.c index 8afa3df57..966a8665c 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -3631,6 +3631,30 @@ void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rlDisableWireMode(); } +// Draw a model points +void DrawModelPoints(Model model, Vector3 position, float scale, Color tint) +{ + rlEnablePointMode(); + rlDisableBackfaceCulling(); + + DrawModel(model, position, scale, tint); + + rlEnableBackfaceCulling(); + rlDisableWireMode(); +} + +// Draw a model points +void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint) +{ + rlEnablePointMode(); + rlDisableBackfaceCulling(); + + DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint); + + rlEnableBackfaceCulling(); + rlDisableWireMode(); +} + // Draw a billboard void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint) { From dfd8055270691429076283f407d4176929f56e80 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 24 Aug 2024 16:42:52 +0000 Subject: [PATCH 002/115] Update raylib_api.* by CI --- parser/output/raylib_api.json | 54 ++++++++ parser/output/raylib_api.lua | 24 ++++ parser/output/raylib_api.txt | 238 ++++++++++++++++++---------------- parser/output/raylib_api.xml | 16 ++- 4 files changed, 221 insertions(+), 111 deletions(-) diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json index c4ce91e87..dfe37e2fe 100644 --- a/parser/output/raylib_api.json +++ b/parser/output/raylib_api.json @@ -10366,6 +10366,60 @@ } ] }, + { + "name": "DrawModelPoints", + "description": "Draw a model as points", + "returnType": "void", + "params": [ + { + "type": "Model", + "name": "model" + }, + { + "type": "Vector3", + "name": "position" + }, + { + "type": "float", + "name": "scale" + }, + { + "type": "Color", + "name": "tint" + } + ] + }, + { + "name": "DrawModelPointsEx", + "description": "Draw a model as points with extended parameters", + "returnType": "void", + "params": [ + { + "type": "Model", + "name": "model" + }, + { + "type": "Vector3", + "name": "position" + }, + { + "type": "Vector3", + "name": "rotationAxis" + }, + { + "type": "float", + "name": "rotationAngle" + }, + { + "type": "Vector3", + "name": "scale" + }, + { + "type": "Color", + "name": "tint" + } + ] + }, { "name": "DrawBoundingBox", "description": "Draw bounding box (wires)", diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua index 3a9e2f04f..933b2c704 100644 --- a/parser/output/raylib_api.lua +++ b/parser/output/raylib_api.lua @@ -7213,6 +7213,30 @@ return { {type = "Color", name = "tint"} } }, + { + name = "DrawModelPoints", + description = "Draw a model as points", + returnType = "void", + params = { + {type = "Model", name = "model"}, + {type = "Vector3", name = "position"}, + {type = "float", name = "scale"}, + {type = "Color", name = "tint"} + } + }, + { + name = "DrawModelPointsEx", + description = "Draw a model as points with extended parameters", + returnType = "void", + params = { + {type = "Model", name = "model"}, + {type = "Vector3", name = "position"}, + {type = "Vector3", name = "rotationAxis"}, + {type = "float", name = "rotationAngle"}, + {type = "Vector3", name = "scale"}, + {type = "Color", name = "tint"} + } + }, { name = "DrawBoundingBox", description = "Draw bounding box (wires)", diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt index afa9b525d..94562d66a 100644 --- a/parser/output/raylib_api.txt +++ b/parser/output/raylib_api.txt @@ -984,7 +984,7 @@ Callback 006: AudioCallback() (2 input parameters) Param[1]: bufferData (type: void *) Param[2]: frames (type: unsigned int) -Functions found: 573 +Functions found: 575 Function 001: InitWindow() (3 input parameters) Name: InitWindow @@ -3955,13 +3955,31 @@ Function 464: DrawModelWiresEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 465: DrawBoundingBox() (2 input parameters) +Function 465: DrawModelPoints() (4 input parameters) + Name: DrawModelPoints + Return type: void + Description: Draw a model as points + Param[1]: model (type: Model) + Param[2]: position (type: Vector3) + Param[3]: scale (type: float) + Param[4]: tint (type: Color) +Function 466: DrawModelPointsEx() (6 input parameters) + Name: DrawModelPointsEx + Return type: void + Description: Draw a model as points with extended parameters + Param[1]: model (type: Model) + Param[2]: position (type: Vector3) + Param[3]: rotationAxis (type: Vector3) + Param[4]: rotationAngle (type: float) + Param[5]: scale (type: Vector3) + Param[6]: tint (type: Color) +Function 467: 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 466: DrawBillboard() (5 input parameters) +Function 468: DrawBillboard() (5 input parameters) Name: DrawBillboard Return type: void Description: Draw a billboard texture @@ -3970,7 +3988,7 @@ Function 466: DrawBillboard() (5 input parameters) Param[3]: position (type: Vector3) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 467: DrawBillboardRec() (6 input parameters) +Function 469: DrawBillboardRec() (6 input parameters) Name: DrawBillboardRec Return type: void Description: Draw a billboard texture defined by source @@ -3980,7 +3998,7 @@ Function 467: DrawBillboardRec() (6 input parameters) Param[4]: position (type: Vector3) Param[5]: size (type: Vector2) Param[6]: tint (type: Color) -Function 468: DrawBillboardPro() (9 input parameters) +Function 470: DrawBillboardPro() (9 input parameters) Name: DrawBillboardPro Return type: void Description: Draw a billboard texture defined by source and rotation @@ -3993,13 +4011,13 @@ Function 468: DrawBillboardPro() (9 input parameters) Param[7]: origin (type: Vector2) Param[8]: rotation (type: float) Param[9]: tint (type: Color) -Function 469: UploadMesh() (2 input parameters) +Function 471: 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 470: UpdateMeshBuffer() (5 input parameters) +Function 472: UpdateMeshBuffer() (5 input parameters) Name: UpdateMeshBuffer Return type: void Description: Update mesh vertex data in GPU for a specific buffer index @@ -4008,19 +4026,19 @@ Function 470: UpdateMeshBuffer() (5 input parameters) Param[3]: data (type: const void *) Param[4]: dataSize (type: int) Param[5]: offset (type: int) -Function 471: UnloadMesh() (1 input parameters) +Function 473: UnloadMesh() (1 input parameters) Name: UnloadMesh Return type: void Description: Unload mesh data from CPU and GPU Param[1]: mesh (type: Mesh) -Function 472: DrawMesh() (3 input parameters) +Function 474: 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 473: DrawMeshInstanced() (4 input parameters) +Function 475: DrawMeshInstanced() (4 input parameters) Name: DrawMeshInstanced Return type: void Description: Draw multiple mesh instances with material and different transforms @@ -4028,35 +4046,35 @@ Function 473: DrawMeshInstanced() (4 input parameters) Param[2]: material (type: Material) Param[3]: transforms (type: const Matrix *) Param[4]: instances (type: int) -Function 474: GetMeshBoundingBox() (1 input parameters) +Function 476: GetMeshBoundingBox() (1 input parameters) Name: GetMeshBoundingBox Return type: BoundingBox Description: Compute mesh bounding box limits Param[1]: mesh (type: Mesh) -Function 475: GenMeshTangents() (1 input parameters) +Function 477: GenMeshTangents() (1 input parameters) Name: GenMeshTangents Return type: void Description: Compute mesh tangents Param[1]: mesh (type: Mesh *) -Function 476: ExportMesh() (2 input parameters) +Function 478: 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 477: ExportMeshAsCode() (2 input parameters) +Function 479: ExportMeshAsCode() (2 input parameters) Name: ExportMeshAsCode Return type: bool Description: Export mesh as code file (.h) defining multiple arrays of vertex attributes Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 478: GenMeshPoly() (2 input parameters) +Function 480: GenMeshPoly() (2 input parameters) Name: GenMeshPoly Return type: Mesh Description: Generate polygonal mesh Param[1]: sides (type: int) Param[2]: radius (type: float) -Function 479: GenMeshPlane() (4 input parameters) +Function 481: GenMeshPlane() (4 input parameters) Name: GenMeshPlane Return type: Mesh Description: Generate plane mesh (with subdivisions) @@ -4064,42 +4082,42 @@ Function 479: GenMeshPlane() (4 input parameters) Param[2]: length (type: float) Param[3]: resX (type: int) Param[4]: resZ (type: int) -Function 480: GenMeshCube() (3 input parameters) +Function 482: 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 481: GenMeshSphere() (3 input parameters) +Function 483: 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 482: GenMeshHemiSphere() (3 input parameters) +Function 484: 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 483: GenMeshCylinder() (3 input parameters) +Function 485: 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 484: GenMeshCone() (3 input parameters) +Function 486: 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 485: GenMeshTorus() (4 input parameters) +Function 487: GenMeshTorus() (4 input parameters) Name: GenMeshTorus Return type: Mesh Description: Generate torus mesh @@ -4107,7 +4125,7 @@ Function 485: GenMeshTorus() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 486: GenMeshKnot() (4 input parameters) +Function 488: GenMeshKnot() (4 input parameters) Name: GenMeshKnot Return type: Mesh Description: Generate trefoil knot mesh @@ -4115,84 +4133,84 @@ Function 486: GenMeshKnot() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 487: GenMeshHeightmap() (2 input parameters) +Function 489: 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 488: GenMeshCubicmap() (2 input parameters) +Function 490: 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 489: LoadMaterials() (2 input parameters) +Function 491: 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 490: LoadMaterialDefault() (0 input parameters) +Function 492: LoadMaterialDefault() (0 input parameters) Name: LoadMaterialDefault Return type: Material Description: Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) No input parameters -Function 491: IsMaterialReady() (1 input parameters) +Function 493: IsMaterialReady() (1 input parameters) Name: IsMaterialReady Return type: bool Description: Check if a material is ready Param[1]: material (type: Material) -Function 492: UnloadMaterial() (1 input parameters) +Function 494: UnloadMaterial() (1 input parameters) Name: UnloadMaterial Return type: void Description: Unload material from GPU memory (VRAM) Param[1]: material (type: Material) -Function 493: SetMaterialTexture() (3 input parameters) +Function 495: 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 494: SetModelMeshMaterial() (3 input parameters) +Function 496: 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 495: LoadModelAnimations() (2 input parameters) +Function 497: LoadModelAnimations() (2 input parameters) Name: LoadModelAnimations Return type: ModelAnimation * Description: Load model animations from file Param[1]: fileName (type: const char *) Param[2]: animCount (type: int *) -Function 496: UpdateModelAnimation() (3 input parameters) +Function 498: 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 497: UnloadModelAnimation() (1 input parameters) +Function 499: UnloadModelAnimation() (1 input parameters) Name: UnloadModelAnimation Return type: void Description: Unload animation data Param[1]: anim (type: ModelAnimation) -Function 498: UnloadModelAnimations() (2 input parameters) +Function 500: UnloadModelAnimations() (2 input parameters) Name: UnloadModelAnimations Return type: void Description: Unload animation array data Param[1]: animations (type: ModelAnimation *) Param[2]: animCount (type: int) -Function 499: IsModelAnimationValid() (2 input parameters) +Function 501: 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 500: CheckCollisionSpheres() (4 input parameters) +Function 502: CheckCollisionSpheres() (4 input parameters) Name: CheckCollisionSpheres Return type: bool Description: Check collision between two spheres @@ -4200,40 +4218,40 @@ Function 500: CheckCollisionSpheres() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector3) Param[4]: radius2 (type: float) -Function 501: CheckCollisionBoxes() (2 input parameters) +Function 503: 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 502: CheckCollisionBoxSphere() (3 input parameters) +Function 504: 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 503: GetRayCollisionSphere() (3 input parameters) +Function 505: 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 504: GetRayCollisionBox() (2 input parameters) +Function 506: 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 505: GetRayCollisionMesh() (3 input parameters) +Function 507: 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 506: GetRayCollisionTriangle() (4 input parameters) +Function 508: GetRayCollisionTriangle() (4 input parameters) Name: GetRayCollisionTriangle Return type: RayCollision Description: Get collision info between ray and triangle @@ -4241,7 +4259,7 @@ Function 506: GetRayCollisionTriangle() (4 input parameters) Param[2]: p1 (type: Vector3) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) -Function 507: GetRayCollisionQuad() (5 input parameters) +Function 509: GetRayCollisionQuad() (5 input parameters) Name: GetRayCollisionQuad Return type: RayCollision Description: Get collision info between ray and quad @@ -4250,158 +4268,158 @@ Function 507: GetRayCollisionQuad() (5 input parameters) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) Param[5]: p4 (type: Vector3) -Function 508: InitAudioDevice() (0 input parameters) +Function 510: InitAudioDevice() (0 input parameters) Name: InitAudioDevice Return type: void Description: Initialize audio device and context No input parameters -Function 509: CloseAudioDevice() (0 input parameters) +Function 511: CloseAudioDevice() (0 input parameters) Name: CloseAudioDevice Return type: void Description: Close the audio device and context No input parameters -Function 510: IsAudioDeviceReady() (0 input parameters) +Function 512: IsAudioDeviceReady() (0 input parameters) Name: IsAudioDeviceReady Return type: bool Description: Check if audio device has been initialized successfully No input parameters -Function 511: SetMasterVolume() (1 input parameters) +Function 513: SetMasterVolume() (1 input parameters) Name: SetMasterVolume Return type: void Description: Set master volume (listener) Param[1]: volume (type: float) -Function 512: GetMasterVolume() (0 input parameters) +Function 514: GetMasterVolume() (0 input parameters) Name: GetMasterVolume Return type: float Description: Get master volume (listener) No input parameters -Function 513: LoadWave() (1 input parameters) +Function 515: LoadWave() (1 input parameters) Name: LoadWave Return type: Wave Description: Load wave data from file Param[1]: fileName (type: const char *) -Function 514: LoadWaveFromMemory() (3 input parameters) +Function 516: 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 515: IsWaveReady() (1 input parameters) +Function 517: IsWaveReady() (1 input parameters) Name: IsWaveReady Return type: bool Description: Checks if wave data is ready Param[1]: wave (type: Wave) -Function 516: LoadSound() (1 input parameters) +Function 518: LoadSound() (1 input parameters) Name: LoadSound Return type: Sound Description: Load sound from file Param[1]: fileName (type: const char *) -Function 517: LoadSoundFromWave() (1 input parameters) +Function 519: LoadSoundFromWave() (1 input parameters) Name: LoadSoundFromWave Return type: Sound Description: Load sound from wave data Param[1]: wave (type: Wave) -Function 518: LoadSoundAlias() (1 input parameters) +Function 520: LoadSoundAlias() (1 input parameters) Name: LoadSoundAlias Return type: Sound Description: Create a new sound that shares the same sample data as the source sound, does not own the sound data Param[1]: source (type: Sound) -Function 519: IsSoundReady() (1 input parameters) +Function 521: IsSoundReady() (1 input parameters) Name: IsSoundReady Return type: bool Description: Checks if a sound is ready Param[1]: sound (type: Sound) -Function 520: UpdateSound() (3 input parameters) +Function 522: 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 521: UnloadWave() (1 input parameters) +Function 523: UnloadWave() (1 input parameters) Name: UnloadWave Return type: void Description: Unload wave data Param[1]: wave (type: Wave) -Function 522: UnloadSound() (1 input parameters) +Function 524: UnloadSound() (1 input parameters) Name: UnloadSound Return type: void Description: Unload sound Param[1]: sound (type: Sound) -Function 523: UnloadSoundAlias() (1 input parameters) +Function 525: UnloadSoundAlias() (1 input parameters) Name: UnloadSoundAlias Return type: void Description: Unload a sound alias (does not deallocate sample data) Param[1]: alias (type: Sound) -Function 524: ExportWave() (2 input parameters) +Function 526: 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 525: ExportWaveAsCode() (2 input parameters) +Function 527: 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 526: PlaySound() (1 input parameters) +Function 528: PlaySound() (1 input parameters) Name: PlaySound Return type: void Description: Play a sound Param[1]: sound (type: Sound) -Function 527: StopSound() (1 input parameters) +Function 529: StopSound() (1 input parameters) Name: StopSound Return type: void Description: Stop playing a sound Param[1]: sound (type: Sound) -Function 528: PauseSound() (1 input parameters) +Function 530: PauseSound() (1 input parameters) Name: PauseSound Return type: void Description: Pause a sound Param[1]: sound (type: Sound) -Function 529: ResumeSound() (1 input parameters) +Function 531: ResumeSound() (1 input parameters) Name: ResumeSound Return type: void Description: Resume a paused sound Param[1]: sound (type: Sound) -Function 530: IsSoundPlaying() (1 input parameters) +Function 532: IsSoundPlaying() (1 input parameters) Name: IsSoundPlaying Return type: bool Description: Check if a sound is currently playing Param[1]: sound (type: Sound) -Function 531: SetSoundVolume() (2 input parameters) +Function 533: 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 532: SetSoundPitch() (2 input parameters) +Function 534: 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 533: SetSoundPan() (2 input parameters) +Function 535: 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 534: WaveCopy() (1 input parameters) +Function 536: WaveCopy() (1 input parameters) Name: WaveCopy Return type: Wave Description: Copy a wave to a new wave Param[1]: wave (type: Wave) -Function 535: WaveCrop() (3 input parameters) +Function 537: WaveCrop() (3 input parameters) Name: WaveCrop Return type: void Description: Crop a wave to defined frames range Param[1]: wave (type: Wave *) Param[2]: initFrame (type: int) Param[3]: finalFrame (type: int) -Function 536: WaveFormat() (4 input parameters) +Function 538: WaveFormat() (4 input parameters) Name: WaveFormat Return type: void Description: Convert wave data to desired format @@ -4409,203 +4427,203 @@ Function 536: WaveFormat() (4 input parameters) Param[2]: sampleRate (type: int) Param[3]: sampleSize (type: int) Param[4]: channels (type: int) -Function 537: LoadWaveSamples() (1 input parameters) +Function 539: 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 538: UnloadWaveSamples() (1 input parameters) +Function 540: UnloadWaveSamples() (1 input parameters) Name: UnloadWaveSamples Return type: void Description: Unload samples data loaded with LoadWaveSamples() Param[1]: samples (type: float *) -Function 539: LoadMusicStream() (1 input parameters) +Function 541: LoadMusicStream() (1 input parameters) Name: LoadMusicStream Return type: Music Description: Load music stream from file Param[1]: fileName (type: const char *) -Function 540: LoadMusicStreamFromMemory() (3 input parameters) +Function 542: 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 541: IsMusicReady() (1 input parameters) +Function 543: IsMusicReady() (1 input parameters) Name: IsMusicReady Return type: bool Description: Checks if a music stream is ready Param[1]: music (type: Music) -Function 542: UnloadMusicStream() (1 input parameters) +Function 544: UnloadMusicStream() (1 input parameters) Name: UnloadMusicStream Return type: void Description: Unload music stream Param[1]: music (type: Music) -Function 543: PlayMusicStream() (1 input parameters) +Function 545: PlayMusicStream() (1 input parameters) Name: PlayMusicStream Return type: void Description: Start music playing Param[1]: music (type: Music) -Function 544: IsMusicStreamPlaying() (1 input parameters) +Function 546: IsMusicStreamPlaying() (1 input parameters) Name: IsMusicStreamPlaying Return type: bool Description: Check if music is playing Param[1]: music (type: Music) -Function 545: UpdateMusicStream() (1 input parameters) +Function 547: UpdateMusicStream() (1 input parameters) Name: UpdateMusicStream Return type: void Description: Updates buffers for music streaming Param[1]: music (type: Music) -Function 546: StopMusicStream() (1 input parameters) +Function 548: StopMusicStream() (1 input parameters) Name: StopMusicStream Return type: void Description: Stop music playing Param[1]: music (type: Music) -Function 547: PauseMusicStream() (1 input parameters) +Function 549: PauseMusicStream() (1 input parameters) Name: PauseMusicStream Return type: void Description: Pause music playing Param[1]: music (type: Music) -Function 548: ResumeMusicStream() (1 input parameters) +Function 550: ResumeMusicStream() (1 input parameters) Name: ResumeMusicStream Return type: void Description: Resume playing paused music Param[1]: music (type: Music) -Function 549: SeekMusicStream() (2 input parameters) +Function 551: 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 550: SetMusicVolume() (2 input parameters) +Function 552: 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 551: SetMusicPitch() (2 input parameters) +Function 553: 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 552: SetMusicPan() (2 input parameters) +Function 554: 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 553: GetMusicTimeLength() (1 input parameters) +Function 555: GetMusicTimeLength() (1 input parameters) Name: GetMusicTimeLength Return type: float Description: Get music time length (in seconds) Param[1]: music (type: Music) -Function 554: GetMusicTimePlayed() (1 input parameters) +Function 556: GetMusicTimePlayed() (1 input parameters) Name: GetMusicTimePlayed Return type: float Description: Get current music time played (in seconds) Param[1]: music (type: Music) -Function 555: LoadAudioStream() (3 input parameters) +Function 557: 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 556: IsAudioStreamReady() (1 input parameters) +Function 558: IsAudioStreamReady() (1 input parameters) Name: IsAudioStreamReady Return type: bool Description: Checks if an audio stream is ready Param[1]: stream (type: AudioStream) -Function 557: UnloadAudioStream() (1 input parameters) +Function 559: UnloadAudioStream() (1 input parameters) Name: UnloadAudioStream Return type: void Description: Unload audio stream and free memory Param[1]: stream (type: AudioStream) -Function 558: UpdateAudioStream() (3 input parameters) +Function 560: 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 559: IsAudioStreamProcessed() (1 input parameters) +Function 561: IsAudioStreamProcessed() (1 input parameters) Name: IsAudioStreamProcessed Return type: bool Description: Check if any audio stream buffers requires refill Param[1]: stream (type: AudioStream) -Function 560: PlayAudioStream() (1 input parameters) +Function 562: PlayAudioStream() (1 input parameters) Name: PlayAudioStream Return type: void Description: Play audio stream Param[1]: stream (type: AudioStream) -Function 561: PauseAudioStream() (1 input parameters) +Function 563: PauseAudioStream() (1 input parameters) Name: PauseAudioStream Return type: void Description: Pause audio stream Param[1]: stream (type: AudioStream) -Function 562: ResumeAudioStream() (1 input parameters) +Function 564: ResumeAudioStream() (1 input parameters) Name: ResumeAudioStream Return type: void Description: Resume audio stream Param[1]: stream (type: AudioStream) -Function 563: IsAudioStreamPlaying() (1 input parameters) +Function 565: IsAudioStreamPlaying() (1 input parameters) Name: IsAudioStreamPlaying Return type: bool Description: Check if audio stream is playing Param[1]: stream (type: AudioStream) -Function 564: StopAudioStream() (1 input parameters) +Function 566: StopAudioStream() (1 input parameters) Name: StopAudioStream Return type: void Description: Stop audio stream Param[1]: stream (type: AudioStream) -Function 565: SetAudioStreamVolume() (2 input parameters) +Function 567: 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 566: SetAudioStreamPitch() (2 input parameters) +Function 568: 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 567: SetAudioStreamPan() (2 input parameters) +Function 569: 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 568: SetAudioStreamBufferSizeDefault() (1 input parameters) +Function 570: SetAudioStreamBufferSizeDefault() (1 input parameters) Name: SetAudioStreamBufferSizeDefault Return type: void Description: Default size for new audio streams Param[1]: size (type: int) -Function 569: SetAudioStreamCallback() (2 input parameters) +Function 571: 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 570: AttachAudioStreamProcessor() (2 input parameters) +Function 572: AttachAudioStreamProcessor() (2 input parameters) Name: AttachAudioStreamProcessor Return type: void Description: Attach audio stream processor to stream, receives the samples as 'float' Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 571: DetachAudioStreamProcessor() (2 input parameters) +Function 573: 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 572: AttachAudioMixedProcessor() (1 input parameters) +Function 574: AttachAudioMixedProcessor() (1 input parameters) Name: AttachAudioMixedProcessor Return type: void Description: Attach audio stream processor to the entire audio pipeline, receives the samples as 'float' Param[1]: processor (type: AudioCallback) -Function 573: DetachAudioMixedProcessor() (1 input parameters) +Function 575: DetachAudioMixedProcessor() (1 input parameters) Name: DetachAudioMixedProcessor Return type: void Description: Detach audio stream processor from the entire audio pipeline diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index 8a6560f48..02cfd02d0 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -670,7 +670,7 @@ - + @@ -2637,6 +2637,20 @@ + + + + + + + + + + + + + + From bc0bd98763bba496836c5cfc1418949256bc6f4d Mon Sep 17 00:00:00 2001 From: Colleague Riley Date: Sat, 24 Aug 2024 12:43:46 -0400 Subject: [PATCH 003/115] (rcore_desktop_rgfw.c) fix errors when compiling with mingw (#4282) * (rcore_desktop_rgfw.c) fix errors when compiling with mingw * define WideCharToMultiByte --- src/external/RGFW.h | 4 +++- src/platforms/rcore_desktop_rgfw.c | 6 +----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/external/RGFW.h b/src/external/RGFW.h index 367a46fa6..35e782d4a 100644 --- a/src/external/RGFW.h +++ b/src/external/RGFW.h @@ -4999,7 +4999,9 @@ static const struct wl_callback_listener wl_surface_frame_listener = { #define WIN32_LEAN_AND_MEAN #define OEMRESOURCE #include - + + __declspec(dllimport) int __stdcall WideCharToMultiByte( UINT CodePage, DWORD dwFlags, const WCHAR* lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar); + #include #include #include diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index afea0c2e6..64ab432e6 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -76,9 +76,7 @@ void CloseWindow(void); #define Size NSSIZE #endif -#if defined(_MSC_VER) __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar); -#endif #include "../external/RGFW.h" @@ -538,10 +536,8 @@ void *GetWindowHandle(void) { #ifdef RGFW_WEBASM return (void*)platform.window->src.ctx; -#elif !defined(RGFW_WINDOWS) - return (void *)platform.window->src.window; #else - return platform.window->src.hwnd; + return (void*)platform.window->src.window; #endif } From 414133dbe7b063566a338d9c4ef1c9eb0651dec4 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 24 Aug 2024 18:56:06 +0200 Subject: [PATCH 004/115] Update models_point_rendering.c --- examples/models/models_point_rendering.c | 107 +++++++++++++---------- 1 file changed, 59 insertions(+), 48 deletions(-) diff --git a/examples/models/models_point_rendering.c b/examples/models/models_point_rendering.c index 128a70f57..68d498453 100644 --- a/examples/models/models_point_rendering.c +++ b/examples/models/models_point_rendering.c @@ -14,13 +14,15 @@ ********************************************************************************************/ #include "raylib.h" -#include // Required for: rand() -#include // Required for: cos(), sin() -#define MAX_POINTS 10000000 // 10 million -#define MIN_POINTS 1000 // 1 thousand +#include // Required for: rand() +#include // Required for: cos(), sin() -static float RandFloat(); +#define MAX_POINTS 10000000 // 10 million +#define MIN_POINTS 1000 // 1 thousand + +// Generate mesh using points +Mesh GenMeshPoints(int numPoints); //------------------------------------------------------------------------------------ // Program main entry point @@ -31,23 +33,26 @@ int main() //-------------------------------------------------------------------------------------- const int screenWidth = 800; const int screenHeight = 450; + InitWindow(screenWidth, screenHeight, "raylib [models] example - point rendering"); - SetTargetFPS(60); Camera camera = { - .position = {3.0f, 3.0f, 3.0f}, - .target = {0.0f, 0.0f, 0.0f}, - .up = {0.0f, 1.0f, 0.0f}, + .position = { 3.0f, 3.0f, 3.0f }, + .target = { 0.0f, 0.0f, 0.0f }, + .up = { 0.0f, 1.0f, 0.0f }, .fovy = 45.0f, - .projection = CAMERA_PERSPECTIVE, + .projection = CAMERA_PERSPECTIVE }; - Vector3 position = {0.0f, 0.0f, 0.0f}; + Vector3 position = { 0.0f, 0.0f, 0.0f }; bool useDrawModelPoints = true; bool numPointsChanged = false; int numPoints = 1000; - Mesh mesh = GenPoints(numPoints); + + Mesh mesh = GenMeshPoints(numPoints); Model model = LoadModelFromMesh(mesh); + + //SetTargetFPS(60); //-------------------------------------------------------------------------------------- // Main game loop @@ -60,30 +65,30 @@ int main() if (IsKeyPressed(KEY_SPACE)) useDrawModelPoints = !useDrawModelPoints; if (IsKeyPressed(KEY_UP)) { - numPoints = (numPoints * 10 > MAX_POINTS) ? MAX_POINTS : numPoints * 10; + numPoints = (numPoints*10 > MAX_POINTS)? MAX_POINTS : numPoints*10; numPointsChanged = true; - TraceLog(LOG_INFO, "num points %d", numPoints); } if (IsKeyPressed(KEY_DOWN)) { - numPoints = (numPoints / 10 < MIN_POINTS) ? MIN_POINTS : numPoints / 10; + numPoints = (numPoints/10 < MIN_POINTS)? MIN_POINTS : numPoints/10; numPointsChanged = true; - TraceLog(LOG_INFO, "num points %d", numPoints); } - // upload a different point cloud size + // Upload a different point cloud size if (numPointsChanged) { UnloadModel(model); - mesh = GenPoints(numPoints); + mesh = GenMeshPoints(numPoints); model = LoadModelFromMesh(mesh); numPointsChanged = false; } + //---------------------------------------------------------------------------------- // Draw //---------------------------------------------------------------------------------- BeginDrawing(); ClearBackground(BLACK); + BeginMode3D(camera); // The new method only uploads the points once to the GPU @@ -91,42 +96,43 @@ int main() { DrawModelPoints(model, position, 1.0f, WHITE); } - // The old method must continually draw the "points" (lines) else { + // The old method must continually draw the "points" (lines) for (int i = 0; i < numPoints; i++) { Vector3 pos = { - .x = mesh.vertices[i * 3 + 0], - .y = mesh.vertices[i * 3 + 1], - .z = mesh.vertices[i * 3 + 2], + .x = mesh.vertices[i*3 + 0], + .y = mesh.vertices[i*3 + 1], + .z = mesh.vertices[i*3 + 2], }; Color color = { - .r = mesh.colors[i * 4 + 0], - .g = mesh.colors[i * 4 + 1], - .b = mesh.colors[i * 4 + 2], - .a = mesh.colors[i * 4 + 3], + .r = mesh.colors[i*4 + 0], + .g = mesh.colors[i*4 + 1], + .b = mesh.colors[i*4 + 2], + .a = mesh.colors[i*4 + 3], }; + DrawPoint3D(pos, color); } } // Draw a unit sphere for reference DrawSphereWires(position, 1.0f, 10, 10, YELLOW); + EndMode3D(); - // Text formatting - Color color = WHITE; - int fps = GetFPS(); - if ((fps < 30) && (fps >= 15)) color = ORANGE; - else if (fps < 15) color = RED; - DrawText(TextFormat("%2i FPS", fps), 20, 20, 40, color); + // Draw UI text DrawText(TextFormat("Point Count: %d", numPoints), 20, screenHeight - 50, 40, WHITE); DrawText("Up - increase points", 20, 70, 20, WHITE); DrawText("Down - decrease points", 20, 100, 20, WHITE); DrawText("Space - drawing function", 20, 130, 20, WHITE); - if (useDrawModelPoints) DrawText("DrawModelPoints()", 20, 160, 20, GREEN); - else DrawText("DrawPoint3D()", 20, 160, 20, RED); + + if (useDrawModelPoints) DrawText("Using: DrawModelPoints()", 20, 160, 20, GREEN); + else DrawText("Using: DrawPoint3D()", 20, 160, 20, RED); + + DrawFPS(10, 10); + EndDrawing(); //---------------------------------------------------------------------------------- } @@ -134,38 +140,43 @@ int main() // De-Initialization //-------------------------------------------------------------------------------------- UnloadModel(model); + CloseWindow(); //-------------------------------------------------------------------------------------- return 0; } // Generate a spherical point cloud -Mesh GenPoints(int numPoints) +Mesh GenMeshPoints(int numPoints) { Mesh mesh = { .triangleCount = 1, .vertexCount = numPoints, - .vertices = (float *)MemAlloc(numPoints * 3 * sizeof(float)), - .colors = (unsigned char*)MemAlloc(numPoints * 4 * sizeof(unsigned char)), + .vertices = (float *)MemAlloc(numPoints*3*sizeof(float)), + .colors = (unsigned char*)MemAlloc(numPoints*4*sizeof(unsigned char)), }; // https://en.wikipedia.org/wiki/Spherical_coordinate_system for (int i = 0; i < numPoints; i++) { - float theta = PI * rand() / RAND_MAX; - float phi = 2.0f * PI * rand() / RAND_MAX; - float r = 10.0f * rand() / RAND_MAX; - mesh.vertices[i * 3 + 0] = r * sin(theta) * cos(phi); - mesh.vertices[i * 3 + 1] = r * sin(theta) * sin(phi); - mesh.vertices[i * 3 + 2] = r * cos(theta); - Color color = ColorFromHSV(r * 360.0f, 1.0f, 1.0f); - mesh.colors[i * 4 + 0] = color.r; - mesh.colors[i * 4 + 1] = color.g; - mesh.colors[i * 4 + 2] = color.b; - mesh.colors[i * 4 + 3] = color.a; + float theta = PI*rand()/RAND_MAX; + float phi = 2.0f*PI*rand()/RAND_MAX; + float r = 10.0f*rand()/RAND_MAX; + + mesh.vertices[i*3 + 0] = r*sin(theta)*cos(phi); + mesh.vertices[i*3 + 1] = r*sin(theta)*sin(phi); + mesh.vertices[i*3 + 2] = r*cos(theta); + + Color color = ColorFromHSV(r*360.0f, 1.0f, 1.0f); + + mesh.colors[i*4 + 0] = color.r; + mesh.colors[i*4 + 1] = color.g; + mesh.colors[i*4 + 2] = color.b; + mesh.colors[i*4 + 3] = color.a; } // Upload mesh data from CPU (RAM) to GPU (VRAM) memory UploadMesh(&mesh, false); + return mesh; } From 78e86b6ea5824699f9fdaf708f532e5215ea9e7f Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 24 Aug 2024 18:58:43 +0200 Subject: [PATCH 005/115] Update rlgl.h --- src/rlgl.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/rlgl.h b/src/rlgl.h index 5fb9497cd..2f8515ee2 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -665,7 +665,7 @@ RLAPI void rlDisableScissorTest(void); // Disable scissor test RLAPI void rlScissor(int x, int y, int width, int height); // Scissor test RLAPI void rlEnableWireMode(void); // Enable wire mode RLAPI void rlEnablePointMode(void); // Enable point mode -RLAPI void rlDisableWireMode(void); // Disable wire mode ( and point ) maybe rename +RLAPI void rlDisableWireMode(void); // Disable wire (and point) mode RLAPI void rlSetLineWidth(float width); // Set the line drawing width RLAPI float rlGetLineWidth(void); // Get the line drawing width RLAPI void rlEnableSmoothLines(void); // Enable line aliasing @@ -1948,6 +1948,7 @@ void rlEnableWireMode(void) #endif } +// Enable point mode void rlEnablePointMode(void) { #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) @@ -1956,6 +1957,7 @@ void rlEnablePointMode(void) glEnable(GL_PROGRAM_POINT_SIZE); #endif } + // Disable wire mode void rlDisableWireMode(void) { @@ -4236,6 +4238,8 @@ void rlSetUniform(int locIndex, const void *value, int uniformType, int count) case RL_SHADER_UNIFORM_IVEC4: glUniform4iv(locIndex, count, (int *)value); break; case RL_SHADER_UNIFORM_SAMPLER2D: glUniform1iv(locIndex, count, (int *)value); break; default: TRACELOG(RL_LOG_WARNING, "SHADER: Failed to set uniform value, data type not recognized"); + + // TODO: Support glUniform1uiv(), glUniform2uiv(), glUniform3uiv(), glUniform4uiv() } #endif } From 4c9282b09025677a90e5e54ffe142824560163b6 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 24 Aug 2024 18:59:24 +0200 Subject: [PATCH 006/115] ADDED: `isGpuReady` flag, allow font loading with no GPU acceleration --- src/rcore.c | 48 ++++++++++++++++++++++++++++-------------------- src/rtext.c | 32 ++++++++++++++++++-------------- 2 files changed, 46 insertions(+), 34 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index e8041ea41..972d58600 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -360,10 +360,15 @@ typedef struct CoreData { //---------------------------------------------------------------------------------- RLAPI const char *raylib_version = RAYLIB_VERSION; // raylib version exported symbol, required for some bindings -CoreData CORE = { 0 }; // Global CORE state context +CoreData CORE = { 0 }; // Global CORE state context + +// Flag to note GPU acceleration is available, +// referenced from other modules to support GPU data loading +// NOTE: Useful to allow Texture, RenderTexture, Font.texture, Mesh.vaoId/vboId, Shader loading +bool isGpuReady = false; #if defined(SUPPORT_SCREEN_CAPTURE) -static int screenshotCounter = 0; // Screenshots counter +static int screenshotCounter = 0; // Screenshots counter #endif #if defined(SUPPORT_GIF_RECORDING) @@ -637,28 +642,31 @@ void InitWindow(int width, int height, const char *title) // Initialize rlgl default data (buffers and shaders) // NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height); + isGpuReady = true; // Flag to note GPU has been initialized successfully // Setup default viewport SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height); -#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT) - // Load default font - // WARNING: External function: Module required: rtext - LoadFontDefault(); - #if defined(SUPPORT_MODULE_RSHAPES) - // Set font white rectangle for shapes drawing, so shapes and text can be batched together - // WARNING: rshapes module is required, if not available, default internal white rectangle is used - Rectangle rec = GetFontDefault().recs[95]; - if (CORE.Window.flags & FLAG_MSAA_4X_HINT) - { - // NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering - SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 }); - } - else - { - // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding - SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 }); - } +#if defined(SUPPORT_MODULE_RTEXT) + #if defined(SUPPORT_DEFAULT_FONT) + // Load default font + // WARNING: External function: Module required: rtext + LoadFontDefault(); + #if defined(SUPPORT_MODULE_RSHAPES) + // Set font white rectangle for shapes drawing, so shapes and text can be batched together + // WARNING: rshapes module is required, if not available, default internal white rectangle is used + Rectangle rec = GetFontDefault().recs[95]; + if (CORE.Window.flags & FLAG_MSAA_4X_HINT) + { + // NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering + SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 }); + } + else + { + // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding + SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 }); + } + #endif #endif #else #if defined(SUPPORT_MODULE_RSHAPES) diff --git a/src/rtext.c b/src/rtext.c index 8c1dc3c5e..4f1be2cd7 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -124,6 +124,7 @@ //---------------------------------------------------------------------------------- // Global variables //---------------------------------------------------------------------------------- +extern bool isGpuReady; #if defined(SUPPORT_DEFAULT_FONT) // Default font provided by raylib // NOTE: Default font is loaded on InitWindow() and disposed on CloseWindow() [module: core] @@ -252,7 +253,7 @@ extern void LoadFontDefault(void) counter++; } - defaultFont.texture = LoadTextureFromImage(imFont); + if (isGpuReady) defaultFont.texture = LoadTextureFromImage(imFont); // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, glyphCount //------------------------------------------------------------------------------ @@ -308,7 +309,7 @@ extern void LoadFontDefault(void) extern void UnloadFontDefault(void) { for (int i = 0; i < defaultFont.glyphCount; i++) UnloadImage(defaultFont.glyphs[i].image); - UnloadTexture(defaultFont.texture); + if (isGpuReady) UnloadTexture(defaultFont.texture); RL_FREE(defaultFont.glyphs); RL_FREE(defaultFont.recs); } @@ -362,11 +363,14 @@ Font LoadFont(const char *fileName) UnloadImage(image); } - if (font.texture.id == 0) TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName); - else + if (isGpuReady) { - 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); + if (font.texture.id == 0) TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName); + else + { + 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); + } } return font; @@ -487,7 +491,7 @@ Font LoadFontFromImage(Image image, Color key, int firstChar) }; // Set font with all data parsed from image - font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture + if (isGpuReady) font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture font.glyphCount = index; font.glyphPadding = 0; @@ -556,7 +560,7 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int font.glyphPadding = FONT_TTF_DEFAULT_CHARS_PADDING; Image atlas = GenImageFontAtlas(font.glyphs, &font.recs, font.glyphCount, font.baseSize, font.glyphPadding, 0); - font.texture = LoadTextureFromImage(atlas); + if (isGpuReady) font.texture = LoadTextureFromImage(atlas); // Update glyphs[i].image to use alpha, required to be used on ImageDrawText() for (int i = 0; i < font.glyphCount; i++) @@ -580,7 +584,7 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int // Check if a font is ready bool IsFontReady(Font font) { - return ((font.texture.id > 0) && // Validate OpenGL id fot font texture atlas + return ((font.texture.id > 0) && // Validate OpenGL id for 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 @@ -946,7 +950,7 @@ void UnloadFont(Font font) if (font.texture.id != GetFontDefault().texture.id) { UnloadFontData(font.glyphs, font.glyphCount); - UnloadTexture(font.texture); + if (isGpuReady) UnloadTexture(font.texture); RL_FREE(font.recs); TRACELOGD("FONT: Unloaded font data from RAM and VRAM"); @@ -1066,7 +1070,7 @@ bool ExportFontAsCode(Font font, const char *fileName) byteCount += sprintf(txtData + byteCount, " Image imFont = { fontImageData_%s, %i, %i, 1, %i };\n\n", styleName, image.width, image.height, image.format); #endif byteCount += sprintf(txtData + byteCount, " // Load texture from image\n"); - byteCount += sprintf(txtData + byteCount, " font.texture = LoadTextureFromImage(imFont);\n"); + byteCount += sprintf(txtData + byteCount, " if (isGpuReady) font.texture = LoadTextureFromImage(imFont);\n"); #if defined(SUPPORT_COMPRESSED_FONT_ATLAS) byteCount += sprintf(txtData + byteCount, " UnloadImage(imFont); // Uncompressed data can be unloaded from memory\n\n"); #endif @@ -1277,7 +1281,7 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing { Vector2 textSize = { 0 }; - if ((font.texture.id == 0) || (text == NULL)) return textSize; // Security check + if ((isGpuReady && (font.texture.id == 0)) || (text == NULL)) return textSize; // Security check int size = TextLength(text); // Get size in bytes of text int tempByteCounter = 0; // Used to count longer text line num chars @@ -2257,7 +2261,7 @@ static Font LoadBMFont(const char *fileName) RL_FREE(imFonts); - font.texture = LoadTextureFromImage(fullFont); + if (isGpuReady) font.texture = LoadTextureFromImage(fullFont); // Fill font characters info data font.baseSize = fontSize; @@ -2299,7 +2303,7 @@ static Font LoadBMFont(const char *fileName) UnloadImage(fullFont); UnloadFileText(fileText); - if (font.texture.id == 0) + if (isGpuReady && (font.texture.id == 0)) { UnloadFont(font); font = GetFontDefault(); From 0aba21f71c30f3375fa898f8c733089528617639 Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Sat, 24 Aug 2024 11:31:28 -0700 Subject: [PATCH 007/115] [RCORE] Update comments on fullscreen and boderless window to describe what they do (#4280) * Update raylib_api.* by CI * update fullscreen and borderless comments to better describe what they do. * Update raylib_api.* by CI --------- Co-authored-by: github-actions[bot] --- parser/output/raylib_api.json | 4 ++-- parser/output/raylib_api.lua | 4 ++-- parser/output/raylib_api.txt | 4 ++-- parser/output/raylib_api.xml | 4 ++-- src/raylib.h | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json index dfe37e2fe..03b19325a 100644 --- a/parser/output/raylib_api.json +++ b/parser/output/raylib_api.json @@ -3215,12 +3215,12 @@ }, { "name": "ToggleFullscreen", - "description": "Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP)", + "description": "Toggle window state: fullscreen/windowed [resizes monitor to match window resolution] (only PLATFORM_DESKTOP)", "returnType": "void" }, { "name": "ToggleBorderlessWindowed", - "description": "Toggle window state: borderless windowed (only PLATFORM_DESKTOP)", + "description": "Toggle window state: borderless windowed [resizes window to match monitor resolution] (only PLATFORM_DESKTOP)", "returnType": "void" }, { diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua index 933b2c704..7d74c9a41 100644 --- a/parser/output/raylib_api.lua +++ b/parser/output/raylib_api.lua @@ -3158,12 +3158,12 @@ return { }, { name = "ToggleFullscreen", - description = "Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP)", + description = "Toggle window state: fullscreen/windowed [resizes monitor to match window resolution] (only PLATFORM_DESKTOP)", returnType = "void" }, { name = "ToggleBorderlessWindowed", - description = "Toggle window state: borderless windowed (only PLATFORM_DESKTOP)", + description = "Toggle window state: borderless windowed [resizes window to match monitor resolution] (only PLATFORM_DESKTOP)", returnType = "void" }, { diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt index 94562d66a..fb30ebe5f 100644 --- a/parser/output/raylib_api.txt +++ b/parser/output/raylib_api.txt @@ -1056,12 +1056,12 @@ Function 013: ClearWindowState() (1 input parameters) Function 014: ToggleFullscreen() (0 input parameters) Name: ToggleFullscreen Return type: void - Description: Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP) + Description: Toggle window state: fullscreen/windowed [resizes monitor to match window resolution] (only PLATFORM_DESKTOP) No input parameters Function 015: ToggleBorderlessWindowed() (0 input parameters) Name: ToggleBorderlessWindowed Return type: void - Description: Toggle window state: borderless windowed (only PLATFORM_DESKTOP) + Description: Toggle window state: borderless windowed [resizes window to match monitor resolution] (only PLATFORM_DESKTOP) No input parameters Function 016: MaximizeWindow() (0 input parameters) Name: MaximizeWindow diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index 02cfd02d0..532b9e3b9 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -703,9 +703,9 @@ - + - + diff --git a/src/raylib.h b/src/raylib.h index f51a444e1..7e9af7ada 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -968,8 +968,8 @@ RLAPI bool IsWindowResized(void); // Check if wi RLAPI bool IsWindowState(unsigned int flag); // Check if one specific window flag is enabled RLAPI void SetWindowState(unsigned int flags); // Set window configuration state using flags (only PLATFORM_DESKTOP) RLAPI void ClearWindowState(unsigned int flags); // Clear window configuration state flags -RLAPI void ToggleFullscreen(void); // Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP) -RLAPI void ToggleBorderlessWindowed(void); // Toggle window state: borderless windowed (only PLATFORM_DESKTOP) +RLAPI void ToggleFullscreen(void); // Toggle window state: fullscreen/windowed [resizes monitor to match window resolution] (only PLATFORM_DESKTOP) +RLAPI void ToggleBorderlessWindowed(void); // Toggle window state: borderless windowed [resizes window to match monitor resolution] (only PLATFORM_DESKTOP) 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) From 0c06a08e0738a5777d150b7b4562cd8595680271 Mon Sep 17 00:00:00 2001 From: Dave Green <34277803+SoloByte@users.noreply.github.com> Date: Sat, 24 Aug 2024 20:33:21 +0200 Subject: [PATCH 008/115] [rcore][desktop_glfw] Keeping CORE.Window.position properly in sync with glfw window position (#4190) * WindowPosCallback added. CORE.Window.position is now properly kept in sync with the glfw window position. * Update rcore_desktop_glfw.c Comments updated. * Setting CORE.Window.position correctly in InitPlatform() as well. This also fixes not centering the window correctly when the high dpi flag was enabled. * Fixes centering the window in the SetWindowMonitor() function. Here the render size has to be used again in case the high dpi flag is enabled. * Update Window Position Update Window Position right away in ToggleFullscreen() & ToggleBorderlessWindowed() functions --- src/platforms/rcore_desktop_glfw.c | 47 ++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index d64bf60db..c6685846c 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -109,6 +109,7 @@ static void ErrorCallback(int error, const char *description); // Window callbacks events static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized +static void WindowPosCallback(GLFWwindow* window, int x, int y); // GLFW3 WindowPos Callback, runs when window is moved static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored static void WindowMaximizeCallback(GLFWwindow* window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus @@ -147,8 +148,8 @@ void ToggleFullscreen(void) if (!CORE.Window.fullscreen) { // Store previous window position (in case we exit fullscreen) - glfwGetWindowPos(platform.handle, &CORE.Window.position.x, &CORE.Window.position.y); - + CORE.Window.previousPosition = CORE.Window.position; + int monitorCount = 0; int monitorIndex = GetCurrentMonitor(); GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); @@ -179,7 +180,11 @@ void ToggleFullscreen(void) CORE.Window.fullscreen = false; CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE; - glfwSetWindowMonitor(platform.handle, NULL, CORE.Window.position.x, CORE.Window.position.y, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); + glfwSetWindowMonitor(platform.handle, NULL, CORE.Window.previousPosition.x, CORE.Window.previousPosition.y, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); + + // we update the window position right away + CORE.Window.position.x = CORE.Window.previousPosition.x; + CORE.Window.position.y = CORE.Window.previousPosition.y; } // Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS) @@ -190,11 +195,11 @@ void ToggleFullscreen(void) // Toggle borderless windowed mode void ToggleBorderlessWindowed(void) { - // Leave fullscreen before attempting to set borderless windowed mode and get screen position from it + // Leave fullscreen before attempting to set borderless windowed mode bool wasOnFullscreen = false; if (CORE.Window.fullscreen) { - CORE.Window.previousPosition = CORE.Window.position; + // fullscreen already saves the previous position so it does not need to be set here again ToggleFullscreen(); wasOnFullscreen = true; } @@ -213,7 +218,7 @@ void ToggleBorderlessWindowed(void) { // Store screen position and size // NOTE: If it was on fullscreen, screen position was already stored, so skip setting it here - if (!wasOnFullscreen) glfwGetWindowPos(platform.handle, &CORE.Window.previousPosition.x, &CORE.Window.previousPosition.y); + if (!wasOnFullscreen) CORE.Window.previousPosition = CORE.Window.position; CORE.Window.previousScreen = CORE.Window.screen; // Set undecorated and topmost modes and flags @@ -255,6 +260,9 @@ void ToggleBorderlessWindowed(void) glfwFocusWindow(platform.handle); CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE; + + CORE.Window.position.x = CORE.Window.previousPosition.x; + CORE.Window.position.y = CORE.Window.previousPosition.y; } } else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor"); @@ -592,6 +600,9 @@ void SetWindowTitle(const char *title) // Set window position on screen (windowed mode) void SetWindowPosition(int x, int y) { + // Update CORE.Window.position as well + CORE.Window.position.x = x; + CORE.Window.position.y = y; glfwSetWindowPos(platform.handle, x, y); } @@ -614,8 +625,9 @@ void SetWindowMonitor(int monitor) { TRACELOG(LOG_INFO, "GLFW: Selected monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor])); - const int screenWidth = CORE.Window.screen.width; - const int screenHeight = CORE.Window.screen.height; + // Here the render width has to be used again in case high dpi flag is enabled + const int screenWidth = CORE.Window.render.width; + const int screenHeight = CORE.Window.render.height; int monitorWorkareaX = 0; int monitorWorkareaY = 0; int monitorWorkareaWidth = 0; @@ -1568,12 +1580,17 @@ int InitPlatform(void) int monitorWidth = 0; int monitorHeight = 0; glfwGetMonitorWorkarea(monitor, &monitorX, &monitorY, &monitorWidth, &monitorHeight); - - int posX = monitorX + (monitorWidth - (int)CORE.Window.screen.width)/2; - int posY = monitorY + (monitorHeight - (int)CORE.Window.screen.height)/2; + + // Here CORE.Window.render.width/height should be used instead of CORE.Window.screen.width/height to center the window correctly when the high dpi flag is enabled. + int posX = monitorX + (monitorWidth - (int)CORE.Window.render.width)/2; + int posY = monitorY + (monitorHeight - (int)CORE.Window.render.height)/2; if (posX < monitorX) posX = monitorX; if (posY < monitorY) posY = monitorY; SetWindowPosition(posX, posY); + + // Update CORE.Window.position here so it is correct from the start + CORE.Window.position.x = posX; + CORE.Window.position.y = posY; } // Load OpenGL extensions @@ -1585,6 +1602,7 @@ int InitPlatform(void) //---------------------------------------------------------------------------- // Set window callback events glfwSetWindowSizeCallback(platform.handle, WindowSizeCallback); // NOTE: Resizing not allowed by default! + glfwSetWindowPosCallback(platform.handle, WindowPosCallback); glfwSetWindowMaximizeCallback(platform.handle, WindowMaximizeCallback); glfwSetWindowIconifyCallback(platform.handle, WindowIconifyCallback); glfwSetWindowFocusCallback(platform.handle, WindowFocusCallback); @@ -1681,7 +1699,12 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height) // NOTE: Postprocessing texture is not scaled to new size } - +static void WindowPosCallback(GLFWwindow* window, int x, int y) +{ + // Set current window position + CORE.Window.position.x = x; + CORE.Window.position.y = y; +} static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley) { CORE.Window.screenScale = MatrixScale(scalex, scaley, 1.0f); From d314afc451e4b0ed6fe69249dffccb65bd1e0582 Mon Sep 17 00:00:00 2001 From: Tchan0 <61758157+Tchan0@users.noreply.github.com> Date: Sat, 24 Aug 2024 20:35:49 +0200 Subject: [PATCH 009/115] rlgl.h: glint64 did not exist before OpenGL 3.2 (#4284) Compilation breaks on rlgl.h for early OpenGL versions. Glint64 did not exist on those versions (< OpenGL 3.2) --- src/rlgl.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 2f8515ee2..3efed736a 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -4414,14 +4414,14 @@ void rlUpdateShaderBuffer(unsigned int id, const void *data, unsigned int dataSi // Get SSBO buffer size unsigned int rlGetShaderBufferSize(unsigned int id) { - GLint64 size = 0; - #if defined(GRAPHICS_API_OPENGL_43) + GLint64 size = 0; glBindBuffer(GL_SHADER_STORAGE_BUFFER, id); glGetBufferParameteri64v(GL_SHADER_STORAGE_BUFFER, GL_BUFFER_SIZE, &size); -#endif - return (size > 0)? (unsigned int)size : 0; +#else + return 0; +#endif } // Read SSBO buffer data (GPU->CPU) From 8dbf3712445c27e86bebf1b82e1de04cf1099a91 Mon Sep 17 00:00:00 2001 From: Tchan0 <61758157+Tchan0@users.noreply.github.com> Date: Sun, 25 Aug 2024 11:23:08 +0200 Subject: [PATCH 010/115] Examples makefiles: align /usr/local with /src Makefile (#4286) * align /usr/local with src Makefile Align /usr/local with the /src Makefile, where it can be overriden. * /usr/local: allow override align /usr/local with the /src Makefile, where it can be overriden --- examples/Makefile | 5 +++-- examples/Makefile.Web | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index 904917f7c..bdbb6e351 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -70,8 +70,9 @@ RAYLIB_SRC_PATH ?= ../src # Locations of raylib.h and libraylib.a/libraylib.so # NOTE: Those variables are only used for PLATFORM_OS: LINUX, BSD -RAYLIB_INCLUDE_PATH ?= /usr/local/include -RAYLIB_LIB_PATH ?= /usr/local/lib +DESTDIR ?= /usr/local +RAYLIB_INCLUDE_PATH ?= $(DESTDIR)/include +RAYLIB_LIB_PATH ?= $(DESTDIR)/lib # Library type compilation: STATIC (.a) or SHARED (.so/.dll) RAYLIB_LIBTYPE ?= STATIC diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 7057da1c0..bd48c2a4a 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -35,8 +35,9 @@ RAYLIB_PATH ?= .. # Locations of raylib.h and libraylib.a/libraylib.so # NOTE: Those variables are only used for PLATFORM_OS: LINUX, BSD -RAYLIB_INCLUDE_PATH ?= /usr/local/include -RAYLIB_LIB_PATH ?= /usr/local/lib +DESTDIR ?= /usr/local +RAYLIB_INCLUDE_PATH ?= $(DESTDIR)/include +RAYLIB_LIB_PATH ?= $(DESTDIR)/lib # Library type compilation: STATIC (.a) or SHARED (.so/.dll) RAYLIB_LIBTYPE ?= STATIC From dec7f12b148ea4383c166d42812e19e0c793bdb0 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 25 Aug 2024 12:51:55 +0200 Subject: [PATCH 011/115] Update raylib.h --- src/raylib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raylib.h b/src/raylib.h index 7e9af7ada..30ba8bd2a 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1443,7 +1443,7 @@ RLAPI int GetPixelDataSize(int width, int height, int format); // G // Font loading/unloading functions RLAPI Font GetFontDefault(void); // Get the default Font RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM) -RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set +RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height 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 *codepoints, int codepointCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf' RLAPI bool IsFontReady(Font font); // Check if a font is ready From 157c7c21d451e022f8227ee5b756a99689a1d3a3 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 25 Aug 2024 12:52:27 +0200 Subject: [PATCH 012/115] ADDED: more uniform data type options #4137 --- src/rlgl.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/rlgl.h b/src/rlgl.h index 3efed736a..34fabe45e 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -527,6 +527,10 @@ typedef enum { RL_SHADER_UNIFORM_IVEC2, // Shader uniform type: ivec2 (2 int) RL_SHADER_UNIFORM_IVEC3, // Shader uniform type: ivec3 (3 int) RL_SHADER_UNIFORM_IVEC4, // Shader uniform type: ivec4 (4 int) + RL_SHADER_UNIFORM_UINT, // Shader uniform type: unsigned int + RL_SHADER_UNIFORM_UIVEC2, // Shader uniform type: uivec2 (2 unsigned int) + RL_SHADER_UNIFORM_UIVEC3, // Shader uniform type: uivec3 (3 unsigned int) + RL_SHADER_UNIFORM_UIVEC4, // Shader uniform type: uivec4 (4 unsigned int) RL_SHADER_UNIFORM_SAMPLER2D // Shader uniform type: sampler2d } rlShaderUniformDataType; @@ -4236,6 +4240,10 @@ void rlSetUniform(int locIndex, const void *value, int uniformType, int count) case RL_SHADER_UNIFORM_IVEC2: glUniform2iv(locIndex, count, (int *)value); break; case RL_SHADER_UNIFORM_IVEC3: glUniform3iv(locIndex, count, (int *)value); break; case RL_SHADER_UNIFORM_IVEC4: glUniform4iv(locIndex, count, (int *)value); break; + case RL_SHADER_UNIFORM_UINT: glUniform1uiv(locIndex, count, (unsigned int *)value); break; + case RL_SHADER_UNIFORM_UIVEC2: glUniform2uiv(locIndex, count, (unsigned int *)value); break; + case RL_SHADER_UNIFORM_UIVEC3: glUniform3uiv(locIndex, count, (unsigned int *)value); break; + case RL_SHADER_UNIFORM_UIVEC4: glUniform4uiv(locIndex, count, (unsigned int *)value); break; case RL_SHADER_UNIFORM_SAMPLER2D: glUniform1iv(locIndex, count, (int *)value); break; default: TRACELOG(RL_LOG_WARNING, "SHADER: Failed to set uniform value, data type not recognized"); From 5604f6d8a34b94118a9f24e433eb06e771d8378c Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 25 Aug 2024 12:57:05 +0200 Subject: [PATCH 013/115] Update rlgl.h --- src/rlgl.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rlgl.h b/src/rlgl.h index 34fabe45e..9b94d402c 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -4240,10 +4240,12 @@ void rlSetUniform(int locIndex, const void *value, int uniformType, int count) case RL_SHADER_UNIFORM_IVEC2: glUniform2iv(locIndex, count, (int *)value); break; case RL_SHADER_UNIFORM_IVEC3: glUniform3iv(locIndex, count, (int *)value); break; case RL_SHADER_UNIFORM_IVEC4: glUniform4iv(locIndex, count, (int *)value); break; + #if !defined(GRAPHICS_API_OPENGL_ES2) case RL_SHADER_UNIFORM_UINT: glUniform1uiv(locIndex, count, (unsigned int *)value); break; case RL_SHADER_UNIFORM_UIVEC2: glUniform2uiv(locIndex, count, (unsigned int *)value); break; case RL_SHADER_UNIFORM_UIVEC3: glUniform3uiv(locIndex, count, (unsigned int *)value); break; case RL_SHADER_UNIFORM_UIVEC4: glUniform4uiv(locIndex, count, (unsigned int *)value); break; + #endif case RL_SHADER_UNIFORM_SAMPLER2D: glUniform1iv(locIndex, count, (int *)value); break; default: TRACELOG(RL_LOG_WARNING, "SHADER: Failed to set uniform value, data type not recognized"); From f5ef3578100ff06dc1ad3752076e5771de4717f9 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 25 Aug 2024 13:55:53 +0200 Subject: [PATCH 014/115] Update rtext.c --- src/rtext.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rtext.c b/src/rtext.c index 4f1be2cd7..34b6fcedb 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -677,6 +677,8 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz { stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL); chars[i].advanceX = (int)((float)chars[i].advanceX*scaleFactor); + + if (chh > fontSize) TRACELOG(LOG_WARNING, "FONT: Character [0x%08x] size is bigger than expected font size", ch); // Load characters images chars[i].image.width = chw; From 91a9888baa61e221cb6e68a5fd8fc005fffcbca8 Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Sun, 25 Aug 2024 09:49:52 -0700 Subject: [PATCH 015/115] [rModels] Correctly split obj meshes by material (#4285) * Correctly split meshes from tinyobj by material so they can be represented by raylib correctly * PR Feedback --- src/rmodels.c | 304 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 206 insertions(+), 98 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index 966a8665c..5fb512403 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -2016,6 +2016,8 @@ static void ProcessMaterialsOBJ(Material *materials, tinyobj_material_t *mats, i // NOTE: Uses default shader, which only supports MATERIAL_MAP_DIFFUSE materials[m] = LoadMaterialDefault(); + if (mats == NULL) continue; + // Get default texture, in case no texture is defined // NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8 materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; @@ -4073,130 +4075,236 @@ static void BuildPoseFromParentJoints(BoneInfo *bones, int boneCount, Transform // - the mesh is automatically triangulated by tinyobj static Model LoadOBJ(const char *fileName) { + tinyobj_attrib_t objAttributes = { 0 }; + tinyobj_shape_t* objShapes = NULL; + unsigned int objShapeCount = 0; + + tinyobj_material_t* objMaterials = NULL; + unsigned int objMaterialCount = 0; + Model model = { 0 }; + model.transform = MatrixIdentity(); - tinyobj_attrib_t attrib = { 0 }; - tinyobj_shape_t *meshes = NULL; - unsigned int meshCount = 0; + char* fileText = LoadFileText(fileName); - tinyobj_material_t *materials = NULL; - unsigned int materialCount = 0; - - char *fileText = LoadFileText(fileName); - - if (fileText != NULL) + if (fileText == NULL) { - unsigned int dataSize = (unsigned int)strlen(fileText); + TRACELOG(LOG_ERROR, "MODEL Unable to read obj file %s", fileName); + return model; + } - char currentDir[1024] = { 0 }; - strcpy(currentDir, GetWorkingDirectory()); // Save current working directory - const char *workingDir = GetDirectoryPath(fileName); // Switch to OBJ directory for material path correctness - if (CHDIR(workingDir) != 0) + char currentDir[1024] = { 0 }; + strcpy(currentDir, GetWorkingDirectory()); // Save current working directory + const char* workingDir = GetDirectoryPath(fileName); // Switch to OBJ directory for material path correctness + if (CHDIR(workingDir) != 0) + { + TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", workingDir); + } + + unsigned int dataSize = (unsigned int)strlen(fileText); + + unsigned int flags = TINYOBJ_FLAG_TRIANGULATE; + int ret = tinyobj_parse_obj(&objAttributes, &objShapes, &objShapeCount, &objMaterials, &objMaterialCount, fileText, dataSize, flags); + + if (ret != TINYOBJ_SUCCESS) + { + TRACELOG(LOG_ERROR, "MODEL Unable to read obj data %s", fileName); + return model; + } + + UnloadFileText(fileText); + + unsigned int faceVertIndex = 0; + unsigned int nextShape = 1; + int lastMaterial = -1; + unsigned int meshIndex = 0; + + // count meshes + unsigned int nextShapeEnd = objAttributes.num_face_num_verts; + + // see how many verts till the next shape + + if (objShapeCount > 1) nextShapeEnd = objShapes[nextShape].face_offset; + + // walk all the faces + for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++) + { + if (faceVertIndex >= nextShapeEnd) { - TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", workingDir); + // try to find the last vert in the next shape + nextShape++; + if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset; + else nextShapeEnd = objAttributes.num_face_num_verts; // this is actually the total number of face verts in the file, not faces + meshIndex++; + } + else if (lastMaterial != -1 && objAttributes.material_ids[faceId] != lastMaterial) + { + meshIndex++;// if this is a new material, we need to allocate a new mesh } - unsigned int flags = TINYOBJ_FLAG_TRIANGULATE; - int ret = tinyobj_parse_obj(&attrib, &meshes, &meshCount, &materials, &materialCount, fileText, dataSize, flags); + lastMaterial = objAttributes.material_ids[faceId]; + faceVertIndex += objAttributes.face_num_verts[faceId]; + } - if (ret != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load OBJ data", fileName); - else TRACELOG(LOG_INFO, "MODEL: [%s] OBJ data loaded successfully: %i meshes/%i materials", fileName, meshCount, materialCount); + // allocate the base meshes and materials + model.meshCount = meshIndex + 1; + model.meshes = (Mesh*)MemAlloc(sizeof(Mesh) * model.meshCount); - // WARNING: We are not splitting meshes by materials (previous implementation) - // Depending on the provided OBJ that was not the best option and it just crashed - // so, implementation was simplified to prioritize parsed meshes - model.meshCount = meshCount; + if (objMaterialCount > 0) + { + model.materialCount = objMaterialCount; + model.materials = (Material*)MemAlloc(sizeof(Material) * objMaterialCount); + } + else // we must allocate at least one material + { + model.materialCount = 1; + model.materials = (Material*)MemAlloc(sizeof(Material) * 1); + } - // Set number of materials available - // NOTE: There could be more materials available than meshes but it will be resolved at - // model.meshMaterial, just assigning the right material to corresponding mesh - model.materialCount = materialCount; - if (model.materialCount == 0) + model.meshMaterial = (int*)MemAlloc(sizeof(int) * model.meshCount); + + // see how many verts are in each mesh + unsigned int* localMeshVertexCounts = (unsigned int*)MemAlloc(sizeof(unsigned int) * model.meshCount); + + faceVertIndex = 0; + nextShapeEnd = objAttributes.num_face_num_verts; + lastMaterial = -1; + meshIndex = 0; + unsigned int localMeshVertexCount = 0; + + nextShape = 1; + if (objShapeCount > 1) + nextShapeEnd = objShapes[nextShape].face_offset; + + // walk all the faces + for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++) + { + bool newMesh = false; // do we need a new mesh? + if (faceVertIndex >= nextShapeEnd) { - model.materialCount = 1; - TRACELOG(LOG_INFO, "MODEL: No materials provided, setting one default material for all meshes"); + // try to find the last vert in the next shape + nextShape++; + if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset; + else nextShapeEnd = objAttributes.num_face_num_verts; // this is actually the total number of face verts in the file, not faces + + newMesh = true; } - else if (model.materialCount > 1 && model.meshCount > 1) + else if (lastMaterial != -1 && objAttributes.material_ids[faceId] != lastMaterial) { - // TEMP warning about multiple materials, to be removed when proper splitting code is implemented - // any obj with multiple materials will need to have it's materials assigned by the user in code to work at this time - TRACELOG(LOG_INFO, "MODEL: OBJ has multiple materials, manual material assignment will be required."); + newMesh = true; } - // Init model meshes and materials - model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh)); - model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); // Material index assigned to each mesh - model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material)); + lastMaterial = objAttributes.material_ids[faceId]; - // Process each provided mesh - for (int i = 0; i < model.meshCount; i++) + if (newMesh) { - // WARNING: We need to calculate the mesh triangles manually using meshes[i].face_offset - // because in case of triangulated quads, meshes[i].length actually report quads, - // despite the triangulation that is efectively considered on attrib.num_faces - unsigned int tris = 0; - if (i == model.meshCount - 1) tris = attrib.num_faces - meshes[i].face_offset; - else tris = meshes[i + 1].face_offset; + localMeshVertexCounts[meshIndex] = localMeshVertexCount; - model.meshes[i].vertexCount = tris*3; - model.meshes[i].triangleCount = tris; // Face count (triangulated) - model.meshes[i].vertices = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); - model.meshes[i].texcoords = (float *)RL_CALLOC(model.meshes[i].vertexCount*2, sizeof(float)); - model.meshes[i].normals = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); - model.meshMaterial[i] = 0; // By default, assign material 0 to each mesh - - // Process all mesh faces - for (unsigned int face = 0, f = meshes[i].face_offset, v = 0, vt = 0, vn = 0; face < tris; face++, f++, v += 3, vt += 3, vn += 3) - { - // Get indices for the face - tinyobj_vertex_index_t idx0 = attrib.faces[f*3 + 0]; - tinyobj_vertex_index_t idx1 = attrib.faces[f*3 + 1]; - tinyobj_vertex_index_t idx2 = attrib.faces[f*3 + 2]; - - // Fill vertices buffer (float) using vertex index of the face - for (int n = 0; n < 3; n++) { model.meshes[i].vertices[v*3 + n] = attrib.vertices[idx0.v_idx*3 + n]; } - for (int n = 0; n < 3; n++) { model.meshes[i].vertices[(v + 1)*3 + n] = attrib.vertices[idx1.v_idx*3 + n]; } - for (int n = 0; n < 3; n++) { model.meshes[i].vertices[(v + 2)*3 + n] = attrib.vertices[idx2.v_idx*3 + n]; } - - if (attrib.num_texcoords > 0) - { - // Fill texcoords buffer (float) using vertex index of the face - // NOTE: Y-coordinate must be flipped upside-down - model.meshes[i].texcoords[vt*2 + 0] = attrib.texcoords[idx0.vt_idx*2 + 0]; - model.meshes[i].texcoords[vt*2 + 1] = 1.0f - attrib.texcoords[idx0.vt_idx*2 + 1]; - - model.meshes[i].texcoords[(vt + 1)*2 + 0] = attrib.texcoords[idx1.vt_idx*2 + 0]; - model.meshes[i].texcoords[(vt + 1)*2 + 1] = 1.0f - attrib.texcoords[idx1.vt_idx*2 + 1]; - - model.meshes[i].texcoords[(vt + 2)*2 + 0] = attrib.texcoords[idx2.vt_idx*2 + 0]; - model.meshes[i].texcoords[(vt + 2)*2 + 1] = 1.0f - attrib.texcoords[idx2.vt_idx*2 + 1]; - } - - if (attrib.num_normals > 0) - { - // Fill normals buffer (float) using vertex index of the face - for (int n = 0; n < 3; n++) { model.meshes[i].normals[vn*3 + n] = attrib.normals[idx0.vn_idx*3 + n]; } - for (int n = 0; n < 3; n++) { model.meshes[i].normals[(vn + 1)*3 + n] = attrib.normals[idx1.vn_idx*3 + n]; } - for (int n = 0; n < 3; n++) { model.meshes[i].normals[(vn + 2)*3 + n] = attrib.normals[idx2.vn_idx*3 + n]; } - } - } + localMeshVertexCount = 0; + meshIndex++; } - // Init model materials - if (materialCount > 0) ProcessMaterialsOBJ(model.materials, materials, materialCount); - else model.materials[0] = LoadMaterialDefault(); // Set default material for the mesh + faceVertIndex += objAttributes.face_num_verts[faceId]; + localMeshVertexCount += objAttributes.face_num_verts[faceId]; + } + localMeshVertexCounts[meshIndex] = localMeshVertexCount; - tinyobj_attrib_free(&attrib); - tinyobj_shapes_free(meshes, model.meshCount); - tinyobj_materials_free(materials, materialCount); + for (int i = 0; i < model.meshCount; i++) + { + // allocate the buffers for each mesh + unsigned int vertexCount = localMeshVertexCounts[i]; - UnloadFileText(fileText); + model.meshes[i].vertexCount = vertexCount; + model.meshes[i].triangleCount = vertexCount / 3; - // Restore current working directory - if (CHDIR(currentDir) != 0) + model.meshes[i].vertices = (float*)MemAlloc(sizeof(float) * vertexCount * 3); + model.meshes[i].normals = (float*)MemAlloc(sizeof(float) * vertexCount * 3); + model.meshes[i].texcoords = (float*)MemAlloc(sizeof(float) * vertexCount * 2); + model.meshes[i].colors = (unsigned char*)MemAlloc(sizeof(unsigned char) * vertexCount * 4); + } + + MemFree(localMeshVertexCounts); + localMeshVertexCounts = NULL; + + // fill meshes + faceVertIndex = 0; + + nextShapeEnd = objAttributes.num_face_num_verts; + + // see how many verts till the next shape + nextShape = 1; + if (objShapeCount > 1) nextShapeEnd = objShapes[nextShape].face_offset; + lastMaterial = -1; + meshIndex = 0; + localMeshVertexCount = 0; + + // walk all the faces + for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++) + { + bool newMesh = false; // do we need a new mesh? + if (faceVertIndex >= nextShapeEnd) { - TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", currentDir); + // try to find the last vert in the next shape + nextShape++; + if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset; + else nextShapeEnd = objAttributes.num_face_num_verts; // this is actually the total number of face verts in the file, not faces + newMesh = true; } + // if this is a new material, we need to allocate a new mesh + if (lastMaterial != -1 && objAttributes.material_ids[faceId] != lastMaterial) newMesh = true; + lastMaterial = objAttributes.material_ids[faceId];; + + if (newMesh) + { + localMeshVertexCount = 0; + meshIndex++; + } + + int matId = 0; + if (lastMaterial >= 0 && lastMaterial < (int)objMaterialCount) + matId = lastMaterial; + + model.meshMaterial[meshIndex] = matId; + + for (int f = 0; f < objAttributes.face_num_verts[faceId]; f++) + { + int vertIndex = objAttributes.faces[faceVertIndex].v_idx; + int normalIndex = objAttributes.faces[faceVertIndex].vn_idx; + int texcordIndex = objAttributes.faces[faceVertIndex].vt_idx; + + for (int i = 0; i < 3; i++) + model.meshes[meshIndex].vertices[localMeshVertexCount * 3 + i] = objAttributes.vertices[vertIndex * 3 + i]; + + for (int i = 0; i < 3; i++) + model.meshes[meshIndex].normals[localMeshVertexCount * 3 + i] = objAttributes.normals[normalIndex * 3 + i]; + + for (int i = 0; i < 2; i++) + model.meshes[meshIndex].texcoords[localMeshVertexCount * 2 + i] = objAttributes.texcoords[texcordIndex * 2 + i]; + + model.meshes[meshIndex].texcoords[localMeshVertexCount * 2 + 1] = 1.0f - model.meshes[meshIndex].texcoords[localMeshVertexCount * 2 + 1]; + + for (int i = 0; i < 4; i++) + model.meshes[meshIndex].colors[localMeshVertexCount * 4 + i] = 255; + + faceVertIndex++; + localMeshVertexCount++; + } + } + + if (objMaterialCount > 0) ProcessMaterialsOBJ(model.materials, objMaterials, objMaterialCount); + else model.materials[0] = LoadMaterialDefault(); // Set default material for the mesh + + tinyobj_attrib_free(&objAttributes); + tinyobj_shapes_free(objShapes, objShapeCount); + tinyobj_materials_free(objMaterials, objMaterialCount); + + for (int i = 0; i < model.meshCount; i++) + UploadMesh(model.meshes + i, true); + + // Restore current working directory + if (CHDIR(currentDir) != 0) + { + TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", currentDir); } return model; From 8ea5db3ec43d1fa702b29df9066307d0d337b229 Mon Sep 17 00:00:00 2001 From: Hesham Abourgheba Date: Sun, 25 Aug 2024 19:51:08 +0300 Subject: [PATCH 016/115] fix(rcore/android): Allow main() to return it its caller on configuration changes. (#4288) --- src/platforms/rcore_android.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c index 7a2162025..55706c591 100644 --- a/src/platforms/rcore_android.c +++ b/src/platforms/rcore_android.c @@ -694,11 +694,12 @@ void PollInputEvents(void) // Process this event if (platform.source != NULL) platform.source->process(platform.app, platform.source); - // NOTE: Never close window, native activity is controlled by the system! + // NOTE: Allow closing the window in case a configuration change happened. + // The android_main function should be allowed to return to its caller in order for the + // Android OS to relaunch the activity. if (platform.app->destroyRequested != 0) { - //CORE.Window.shouldClose = true; - //ANativeActivity_finish(platform.app->activity); + CORE.Window.shouldClose = true; } } } @@ -781,7 +782,7 @@ int InitPlatform(void) // Process this event if (platform.source != NULL) platform.source->process(platform.app, platform.source); - // NOTE: Never close window, native activity is controlled by the system! + // NOTE: It's highly likely destroyRequested will never be non-zero at the start of the activity lifecycle. //if (platform.app->destroyRequested != 0) CORE.Window.shouldClose = true; } } @@ -812,6 +813,12 @@ void ClosePlatform(void) eglTerminate(platform.device); platform.device = EGL_NO_DISPLAY; } + + // NOTE: Reset global state in case the activity is being relaunched. + if (platform.app->destroyRequested != 0) { + CORE = (CoreData){0}; + platform = (PlatformData){0}; + } } // Initialize display device and framebuffer From 5f49ec3d6448502d798d4d404e08e354ec48012a Mon Sep 17 00:00:00 2001 From: hanaxars <156359933+hanaxars@users.noreply.github.com> Date: Wed, 28 Aug 2024 19:35:35 +0300 Subject: [PATCH 017/115] Fix missing equal sign (#4294) I just noticed there is a missing equal sign. This PR fixes this. --- src/platforms/rcore_drm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c index 291fd93c7..43dc19c71 100644 --- a/src/platforms/rcore_drm.c +++ b/src/platforms/rcore_drm.c @@ -206,7 +206,7 @@ static const short linuxToRaylibMap[KEYMAP_SIZE] = { [BTN_TL] = GAMEPAD_BUTTON_LEFT_TRIGGER_1, [BTN_TL2] = GAMEPAD_BUTTON_LEFT_TRIGGER_2, [BTN_TR] = GAMEPAD_BUTTON_RIGHT_TRIGGER_1, - [BTN_TR2] GAMEPAD_BUTTON_RIGHT_TRIGGER_2, + [BTN_TR2] = GAMEPAD_BUTTON_RIGHT_TRIGGER_2, [BTN_SELECT] = GAMEPAD_BUTTON_MIDDLE_LEFT, [BTN_MODE] = GAMEPAD_BUTTON_MIDDLE, [BTN_START] = GAMEPAD_BUTTON_MIDDLE_RIGHT, From 59b44a4908e830bca755af3d83d25a64f6d54bd2 Mon Sep 17 00:00:00 2001 From: carverdamien Date: Mon, 2 Sep 2024 10:01:30 +0200 Subject: [PATCH 018/115] Add uConsole mapping (#4297) --- src/external/glfw/src/mappings.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/external/glfw/src/mappings.h b/src/external/glfw/src/mappings.h index 270fa4cd8..7b0f35a26 100644 --- a/src/external/glfw/src/mappings.h +++ b/src/external/glfw/src/mappings.h @@ -996,6 +996,7 @@ const char* _glfwDefaultMappings[] = "03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,", "03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", "03000000120c0000101e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"03000000af1e00002400000010010000,Clockwork Pi DevTerm,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b9,x:b3,y:b0,platform:Linux,", #endif // GLFW_BUILD_LINUX_JOYSTICK }; From 42022c3531e4ca6739fd0ecc760c882eabf4493a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Jask=C3=B3lski?= Date: Tue, 3 Sep 2024 14:38:12 +0200 Subject: [PATCH 019/115] fix: In certain cases the connector status is reported UNKNOWN, should be conisdered as CONNECTED (#4305) Co-authored-by: Michal Jaskolski --- src/platforms/rcore_drm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c index 43dc19c71..ee2875838 100644 --- a/src/platforms/rcore_drm.c +++ b/src/platforms/rcore_drm.c @@ -763,8 +763,10 @@ int InitPlatform(void) drmModeConnector *con = drmModeGetConnector(platform.fd, res->connectors[i]); TRACELOG(LOG_TRACE, "DISPLAY: Connector modes detected: %i", con->count_modes); - - if ((con->connection == DRM_MODE_CONNECTED) && (con->encoder_id)) + + // In certain cases the status of the conneciton is reported as UKNOWN, but it is still connected. + // This might be a hardware or software limitation like on Raspberry Pi Zero with composite output. + if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) && (con->encoder_id)) { TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected"); platform.connector = con; From ed61bdb568046e80e6fd30485375433c4231fd46 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Wed, 4 Sep 2024 20:37:00 +0930 Subject: [PATCH 020/115] Fix seg fault with long comment lines (#4306) #4304 --- 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 cfb0133c3..83991c003 100644 --- a/parser/raylib_parser.c +++ b/parser/raylib_parser.c @@ -139,7 +139,7 @@ typedef struct EnumInfo { // Function info data typedef struct FunctionInfo { char name[64]; // Function name - char desc[128]; // Function description (comment at the end) + char desc[256]; // Function description (comment at the end) char retType[32]; // Return value type int paramCount; // Number of function parameters char paramType[MAX_FUNCTION_PARAMETERS][32]; // Parameters type From 10b01ba7c2139b9203045bb56aa8403ca810cc6b Mon Sep 17 00:00:00 2001 From: masnm <49545838+masnm@users.noreply.github.com> Date: Sat, 7 Sep 2024 03:16:17 +0600 Subject: [PATCH 021/115] Change implicit conversion to explicit conversion to remove warning (#4308) --- src/external/par_shapes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/external/par_shapes.h b/src/external/par_shapes.h index 994a605a9..d5309137b 100644 --- a/src/external/par_shapes.h +++ b/src/external/par_shapes.h @@ -1130,7 +1130,7 @@ static par_shapes__rule* par_shapes__pick_rule(const char* name, total += rule->weight; } } - float r = (float) rand() / RAND_MAX; + float r = (float) rand() / (float) RAND_MAX; float t = 0; for (int i = 0; i < nrules; i++) { rule = rules + i; From 0656440e38208e4d57201706520eb0571fb13bd9 Mon Sep 17 00:00:00 2001 From: masnm <49545838+masnm@users.noreply.github.com> Date: Mon, 9 Sep 2024 00:24:53 +0600 Subject: [PATCH 022/115] fix vld1q_f16 undeclared in arm on stb_image_resize2.h v2.10 (#4309) --- src/external/stb_image_resize2.h | 1655 +++++++++++++++++------------- 1 file changed, 962 insertions(+), 693 deletions(-) diff --git a/src/external/stb_image_resize2.h b/src/external/stb_image_resize2.h index e0c428246..ae8d730bf 100644 --- a/src/external/stb_image_resize2.h +++ b/src/external/stb_image_resize2.h @@ -1,9 +1,9 @@ -/* stb_image_resize2 - v2.01 - public domain image resizing - - by Jeff Roberts (v2) and Jorge L Rodriguez +/* stb_image_resize2 - v2.10 - public domain image resizing + + by Jeff Roberts (v2) and Jorge L Rodriguez http://github.com/nothings/stb - Can be threaded with the extended API. SSE2, AVX, Neon and WASM SIMD support. Only + Can be threaded with the extended API. SSE2, AVX, Neon and WASM SIMD support. Only scaling and translation is supported, no rotations or shears. COMPILING & LINKING @@ -67,60 +67,60 @@ ADDITIONAL DOCUMENTATION MEMORY ALLOCATION - By default, we use malloc and free for memory allocation. To override the + By default, we use malloc and free for memory allocation. To override the memory allocation, before the implementation #include, add a: #define STBIR_MALLOC(size,user_data) ... #define STBIR_FREE(ptr,user_data) ... - Each resize makes exactly one call to malloc/free (unless you use the + Each resize makes exactly one call to malloc/free (unless you use the extended API where you can do one allocation for many resizes). Under address sanitizer, we do separate allocations to find overread/writes. PERFORMANCE This library was written with an emphasis on performance. When testing - stb_image_resize with RGBA, the fastest mode is STBIR_4CHANNEL with + stb_image_resize with RGBA, the fastest mode is STBIR_4CHANNEL with STBIR_TYPE_UINT8 pixels and CLAMPed edges (which is what many other resize - libs do by default). Also, make sure SIMD is turned on of course (default + libs do by default). Also, make sure SIMD is turned on of course (default for 64-bit targets). Avoid WRAP edge mode if you want the fastest speed. This library also comes with profiling built-in. If you define STBIR_PROFILE, - you can use the advanced API and get low-level profiling information by + you can use the advanced API and get low-level profiling information by calling stbir_resize_extended_profile_info() or stbir_resize_split_profile_info() after a resize. SIMD - Most of the routines have optimized SSE2, AVX, NEON and WASM versions. + Most of the routines have optimized SSE2, AVX, NEON and WASM versions. - On Microsoft compilers, we automatically turn on SIMD for 64-bit x64 and - ARM; for 32-bit x86 and ARM, you select SIMD mode by defining STBIR_SSE2 or + On Microsoft compilers, we automatically turn on SIMD for 64-bit x64 and + ARM; for 32-bit x86 and ARM, you select SIMD mode by defining STBIR_SSE2 or STBIR_NEON. For AVX and AVX2, we auto-select it by detecting the /arch:AVX - or /arch:AVX2 switches. You can also always manually turn SSE2, AVX or AVX2 + or /arch:AVX2 switches. You can also always manually turn SSE2, AVX or AVX2 support on by defining STBIR_SSE2, STBIR_AVX or STBIR_AVX2. On Linux, SSE2 and Neon is on by default for 64-bit x64 or ARM64. For 32-bit, we select x86 SIMD mode by whether you have -msse2, -mavx or -mavx2 enabled on the command line. For 32-bit ARM, you must pass -mfpu=neon-vfpv4 for both - clang and GCC, but GCC also requires an additional -mfp16-format=ieee to + clang and GCC, but GCC also requires an additional -mfp16-format=ieee to automatically enable NEON. On x86 platforms, you can also define STBIR_FP16C to turn on FP16C instructions for converting back and forth to half-floats. This is autoselected when we - are using AVX2. Clang and GCC also require the -mf16c switch. ARM always uses - the built-in half float hardware NEON instructions. + are using AVX2. Clang and GCC also require the -mf16c switch. ARM always uses + the built-in half float hardware NEON instructions. - You can also tell us to use multiply-add instructions with STBIR_USE_FMA. + You can also tell us to use multiply-add instructions with STBIR_USE_FMA. Because x86 doesn't always have fma, we turn it off by default to maintain determinism across all platforms. If you don't care about non-FMA determinism - and are willing to restrict yourself to more recent x86 CPUs (around the AVX + and are willing to restrict yourself to more recent x86 CPUs (around the AVX timeframe), then fma will give you around a 15% speedup. You can force off SIMD in all cases by defining STBIR_NO_SIMD. You can turn off AVX or AVX2 specifically with STBIR_NO_AVX or STBIR_NO_AVX2. AVX is 10% to 40% faster, and AVX2 is generally another 12%. - + ALPHA CHANNEL - Most of the resizing functions provide the ability to control how the alpha + Most of the resizing functions provide the ability to control how the alpha channel of an image is processed. When alpha represents transparency, it is important that when combining @@ -167,33 +167,33 @@ stb_image_resize expects case #1 by default, applying alpha weighting to images, expecting the input images to be unpremultiplied. This is what the - COLOR+ALPHA buffer types tell the resizer to do. + COLOR+ALPHA buffer types tell the resizer to do. - When you use the pixel layouts STBIR_RGBA, STBIR_BGRA, STBIR_ARGB, - STBIR_ABGR, STBIR_RX, or STBIR_XR you are telling us that the pixels are - non-premultiplied. In these cases, the resizer will alpha weight the colors - (effectively creating the premultiplied image), do the filtering, and then + When you use the pixel layouts STBIR_RGBA, STBIR_BGRA, STBIR_ARGB, + STBIR_ABGR, STBIR_RX, or STBIR_XR you are telling us that the pixels are + non-premultiplied. In these cases, the resizer will alpha weight the colors + (effectively creating the premultiplied image), do the filtering, and then convert back to non-premult on exit. When you use the pixel layouts STBIR_RGBA_PM, STBIR_RGBA_PM, STBIR_RGBA_PM, - STBIR_RGBA_PM, STBIR_RX_PM or STBIR_XR_PM, you are telling that the pixels - ARE premultiplied. In this case, the resizer doesn't have to do the - premultipling - it can filter directly on the input. This about twice as - fast as the non-premultiplied case, so it's the right option if your data is + STBIR_RGBA_PM, STBIR_RX_PM or STBIR_XR_PM, you are telling that the pixels + ARE premultiplied. In this case, the resizer doesn't have to do the + premultipling - it can filter directly on the input. This about twice as + fast as the non-premultiplied case, so it's the right option if your data is already setup correctly. - When you use the pixel layout STBIR_4CHANNEL or STBIR_2CHANNEL, you are - telling us that there is no channel that represents transparency; it may be - RGB and some unrelated fourth channel that has been stored in the alpha - channel, but it is actually not alpha. No special processing will be - performed. + When you use the pixel layout STBIR_4CHANNEL or STBIR_2CHANNEL, you are + telling us that there is no channel that represents transparency; it may be + RGB and some unrelated fourth channel that has been stored in the alpha + channel, but it is actually not alpha. No special processing will be + performed. - The difference between the generic 4 or 2 channel layouts, and the + The difference between the generic 4 or 2 channel layouts, and the specialized _PM versions is with the _PM versions you are telling us that the data *is* alpha, just don't premultiply it. That's important when using SRGB pixel formats, we need to know where the alpha is, because it is converted linearly (rather than with the SRGB converters). - + Because alpha weighting produces the same effect as premultiplying, you even have the option with non-premultiplied inputs to let the resizer produce a premultiplied output. Because the intially computed alpha-weighted @@ -201,10 +201,10 @@ than the normal path which un-premultiplies the output image as a final step. Finally, when converting both in and out of non-premulitplied space (for - example, when using STBIR_RGBA), we go to somewhat heroic measures to - ensure that areas with zero alpha value pixels get something reasonable - in the RGB values. If you don't care about the RGB values of zero alpha - pixels, you can call the stbir_set_non_pm_alpha_speed_over_quality() + example, when using STBIR_RGBA), we go to somewhat heroic measures to + ensure that areas with zero alpha value pixels get something reasonable + in the RGB values. If you don't care about the RGB values of zero alpha + pixels, you can call the stbir_set_non_pm_alpha_speed_over_quality() function - this runs a premultiplied resize about 25% faster. That said, when you really care about speed, using premultiplied pixels for both in and out (STBIR_RGBA_PM, etc) much faster than both of these premultiplied @@ -218,38 +218,38 @@ layouts with the same number of channels. DETERMINISM - We commit to being deterministic (from x64 to ARM to scalar to SIMD, etc). - This requires compiling with fast-math off (using at least /fp:precise). + We commit to being deterministic (from x64 to ARM to scalar to SIMD, etc). + This requires compiling with fast-math off (using at least /fp:precise). Also, you must turn off fp-contracting (which turns mult+adds into fmas)! - We attempt to do this with pragmas, but with Clang, you usually want to add + We attempt to do this with pragmas, but with Clang, you usually want to add -ffp-contract=off to the command line as well. - For 32-bit x86, you must use SSE and SSE2 codegen for determinism. That is, - if the scalar x87 unit gets used at all, we immediately lose determinism. + For 32-bit x86, you must use SSE and SSE2 codegen for determinism. That is, + if the scalar x87 unit gets used at all, we immediately lose determinism. On Microsoft Visual Studio 2008 and earlier, from what we can tell there is - no way to be deterministic in 32-bit x86 (some x87 always leaks in, even - with fp:strict). On 32-bit x86 GCC, determinism requires both -msse2 and + no way to be deterministic in 32-bit x86 (some x87 always leaks in, even + with fp:strict). On 32-bit x86 GCC, determinism requires both -msse2 and -fpmath=sse. Note that we will not be deterministic with float data containing NaNs - - the NaNs will propagate differently on different SIMD and platforms. + the NaNs will propagate differently on different SIMD and platforms. - If you turn on STBIR_USE_FMA, then we will be deterministic with other - fma targets, but we will differ from non-fma targets (this is unavoidable, - because a fma isn't simply an add with a mult - it also introduces a - rounding difference compared to non-fma instruction sequences. + If you turn on STBIR_USE_FMA, then we will be deterministic with other + fma targets, but we will differ from non-fma targets (this is unavoidable, + because a fma isn't simply an add with a mult - it also introduces a + rounding difference compared to non-fma instruction sequences. FLOAT PIXEL FORMAT RANGE - Any range of values can be used for the non-alpha float data that you pass - in (0 to 1, -1 to 1, whatever). However, if you are inputting float values - but *outputting* bytes or shorts, you must use a range of 0 to 1 so that we - scale back properly. The alpha channel must also be 0 to 1 for any format - that does premultiplication prior to resizing. + Any range of values can be used for the non-alpha float data that you pass + in (0 to 1, -1 to 1, whatever). However, if you are inputting float values + but *outputting* bytes or shorts, you must use a range of 0 to 1 so that we + scale back properly. The alpha channel must also be 0 to 1 for any format + that does premultiplication prior to resizing. - Note also that with float output, using filters with negative lobes, the - output filtered values might go slightly out of range. You can define - STBIR_FLOAT_LOW_CLAMP and/or STBIR_FLOAT_HIGH_CLAMP to specify the range - to clamp to on output, if that's important. + Note also that with float output, using filters with negative lobes, the + output filtered values might go slightly out of range. You can define + STBIR_FLOAT_LOW_CLAMP and/or STBIR_FLOAT_HIGH_CLAMP to specify the range + to clamp to on output, if that's important. MAX/MIN SCALE FACTORS The input pixel resolutions are in integers, and we do the internal pointer @@ -263,13 +263,13 @@ buffers). FLIPPED IMAGES - Stride is just the delta from one scanline to the next. This means you can - use a negative stride to handle inverted images (point to the final + Stride is just the delta from one scanline to the next. This means you can + use a negative stride to handle inverted images (point to the final scanline and use a negative stride). You can invert the input or output, using negative strides. DEFAULT FILTERS - For functions which don't provide explicit control over what filters to + For functions which don't provide explicit control over what filters to use, you can change the compile-time defaults with: #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something @@ -278,18 +278,18 @@ See stbir_filter in the header-file section for the list of filters. NEW FILTERS - A number of 1D filter kernels are supplied. For a list of supported - filters, see the stbir_filter enum. You can install your own filters by + A number of 1D filter kernels are supplied. For a list of supported + filters, see the stbir_filter enum. You can install your own filters by using the stbir_set_filter_callbacks function. PROGRESS - For interactive use with slow resize operations, you can use the the - scanline callbacks in the extended API. It would have to be a *very* large + For interactive use with slow resize operations, you can use the the + scanline callbacks in the extended API. It would have to be a *very* large image resample to need progress though - we're very fast. CEIL and FLOOR - In scalar mode, the only functions we use from math.h are ceilf and floorf, - but if you have your own versions, you can define the STBIR_CEILF(v) and + In scalar mode, the only functions we use from math.h are ceilf and floorf, + but if you have your own versions, you can define the STBIR_CEILF(v) and STBIR_FLOORF(v) macros and we'll use them instead. In SIMD, we just use our own versions. @@ -304,7 +304,7 @@ * For SIMD encode and decode scanline routines, do any pre-aligning for bad input/output buffer alignments and pitch? * For very wide scanlines, we should we do vertical strips to stay within - L2 cache. Maybe do chunks of 1K pixels at a time. There would be + L2 cache. Maybe do chunks of 1K pixels at a time. There would be some pixel reconversion, but probably dwarfed by things falling out of cache. Probably also something possible with alternating between scattering and gathering at high resize scales? @@ -316,21 +316,38 @@ the pivot cost and the extra memory touches). Need to buffer the whole image so have to balance memory use. * Most of our code is internally function pointers, should we compile - all the SIMD stuff always and dynamically dispatch? + all the SIMD stuff always and dynamically dispatch? CONTRIBUTORS Jeff Roberts: 2.0 implementation, optimizations, SIMD - Martins Mozeiko: NEON simd, WASM simd, clang and GCC whisperer. + Martins Mozeiko: NEON simd, WASM simd, clang and GCC whisperer Fabian Giesen: half float and srgb converters Sean Barrett: API design, optimizations Jorge L Rodriguez: Original 1.0 implementation - Aras Pranckevicius: bugfixes for 1.0 + Aras Pranckevicius: bugfixes Nathan Reed: warning fixes for 1.0 REVISIONS - 2.00 (2022-02-20) mostly new source: new api, optimizations, simd, vertical-first, etc - (2x-5x faster without simd, 4x-12x faster with simd) - (in some cases, 20x to 40x faster - resizing to very small for example) + 2.10 (2024-07-27) fix the defines GCC and mingw for loop unroll control, + fix MSVC 32-bit arm half float routines. + 2.09 (2024-06-19) fix the defines for 32-bit ARM GCC builds (was selecting + hardware half floats). + 2.08 (2024-06-10) fix for RGB->BGR three channel flips and add SIMD (thanks + to Ryan Salsbury), fix for sub-rect resizes, use the + pragmas to control unrolling when they are available. + 2.07 (2024-05-24) fix for slow final split during threaded conversions of very + wide scanlines when downsampling (caused by extra input + converting), fix for wide scanline resamples with many + splits (int overflow), fix GCC warning. + 2.06 (2024-02-10) fix for identical width/height 3x or more down-scaling + undersampling a single row on rare resize ratios (about 1%). + 2.05 (2024-02-07) fix for 2 pixel to 1 pixel resizes with wrap (thanks Aras), + fix for output callback (thanks Julien Koenen). + 2.04 (2023-11-17) fix for rare AVX bug, shadowed symbol (thanks Nikola Smiljanic). + 2.03 (2023-11-01) ASAN and TSAN warnings fixed, minor tweaks. + 2.00 (2023-10-10) mostly new source: new api, optimizations, simd, vertical-first, etc + 2x-5x faster without simd, 4x-12x faster with simd, + in some cases, 20x to 40x faster esp resizing large to very small. 0.96 (2019-03-04) fixed warnings 0.95 (2017-07-23) fixed warnings 0.94 (2017-03-18) fixed warnings @@ -368,7 +385,7 @@ typedef uint64_t stbir_uint64; #define STBIR_SSE #endif #endif -#endif +#endif #if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(_M_AMD64) || defined(__SSE2__) || defined(STBIR_SSE) || defined(STBIR_SSE2) #ifndef STBIR_SSE2 @@ -383,7 +400,7 @@ typedef uint64_t stbir_uint64; #endif #if defined(__AVX2__) || defined(STBIR_AVX2) #ifndef STBIR_NO_AVX2 - #ifndef STBIR_AVX2 + #ifndef STBIR_AVX2 #define STBIR_AVX2 #endif #if defined( _MSC_VER ) && !defined(__clang__) @@ -400,15 +417,15 @@ typedef uint64_t stbir_uint64; #endif #endif -#if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(_M_ARM) || (__ARM_NEON_FP & 4) != 0 && __ARM_FP16_FORMAT_IEEE != 0 +#if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || ((__ARM_NEON_FP & 4) != 0) || defined(__ARM_NEON__) #ifndef STBIR_NEON #define STBIR_NEON #endif #endif -#if defined(_M_ARM) +#if defined(_M_ARM) || defined(__arm__) #ifdef STBIR_USE_FMA -#undef STBIR_USE_FMA // no FMA for 32-bit arm on MSVC +#undef STBIR_USE_FMA // no FMA for 32-bit arm on MSVC #endif #endif @@ -435,7 +452,7 @@ typedef uint64_t stbir_uint64; // // Easy-to-use API: // -// * stride is the offset between successive rows of image data +// * stride is the offset between successive rows of image data // in memory, in bytes. specify 0 for packed continuously in memory // * colorspace is linear or sRGB as specified by function name // * Uses the default filters @@ -448,27 +465,35 @@ typedef uint64_t stbir_uint64; // order of channels // whether color is premultiplied by alpha // for back compatibility, you can cast the old channel count to an stbir_pixel_layout -typedef enum +typedef enum { - STBIR_BGR = 0, // 3-chan, with order specified (for channel flipping) - STBIR_1CHANNEL = 1, + STBIR_1CHANNEL = 1, STBIR_2CHANNEL = 2, - STBIR_RGB = 3, // 3-chan, with order specified (for channel flipping) - STBIR_RGBA = 4, // alpha formats, alpha is NOT premultiplied into color channels - + STBIR_RGB = 3, // 3-chan, with order specified (for channel flipping) + STBIR_BGR = 0, // 3-chan, with order specified (for channel flipping) STBIR_4CHANNEL = 5, + + STBIR_RGBA = 4, // alpha formats, where alpha is NOT premultiplied into color channels STBIR_BGRA = 6, STBIR_ARGB = 7, STBIR_ABGR = 8, STBIR_RA = 9, STBIR_AR = 10, - STBIR_RGBA_PM = 11, // alpha formats, alpha is premultiplied into color channels + STBIR_RGBA_PM = 11, // alpha formats, where alpha is premultiplied into color channels STBIR_BGRA_PM = 12, STBIR_ARGB_PM = 13, STBIR_ABGR_PM = 14, STBIR_RA_PM = 15, STBIR_AR_PM = 16, + + STBIR_RGBA_NO_AW = 11, // alpha formats, where NO alpha weighting is applied at all! + STBIR_BGRA_NO_AW = 12, // these are just synonyms for the _PM flags (which also do + STBIR_ARGB_NO_AW = 13, // no alpha weighting). These names just make it more clear + STBIR_ABGR_NO_AW = 14, // for some folks). + STBIR_RA_NO_AW = 15, + STBIR_AR_NO_AW = 16, + } stbir_pixel_layout; //=============================================================== @@ -549,8 +574,8 @@ STBIRDEF void * stbir_resize( const void *input_pixels , int input_w , int inpu // * Separate input and output data types // * Can specify regions with subpixel correctness // * Can specify alpha flags -// * Can specify a memory callback -// * Can specify a callback data type for pixel input and output +// * Can specify a memory callback +// * Can specify a callback data type for pixel input and output // * Can be threaded for a single resize // * Can be used to resize many frames without recalculating the sampler info // @@ -577,7 +602,7 @@ typedef float stbir__kernel_callback( float x, float scale, void * user_data ); typedef float stbir__support_callback( float scale, void * user_data ); // internal structure with precomputed scaling -typedef struct stbir__info stbir__info; +typedef struct stbir__info stbir__info; typedef struct STBIR_RESIZE // use the stbir_resize_init and stbir_override functions to set these values for future compatibility { @@ -604,7 +629,7 @@ typedef struct STBIR_RESIZE // use the stbir_resize_init and stbir_override fun stbir_edge horizontal_edge, vertical_edge; stbir__kernel_callback * horizontal_filter_kernel; stbir__support_callback * horizontal_filter_support; stbir__kernel_callback * vertical_filter_kernel; stbir__support_callback * vertical_filter_support; - stbir__info * samplers; + stbir__info * samplers; } STBIR_RESIZE; // extended complexity api @@ -620,7 +645,7 @@ STBIRDEF void stbir_resize_init( STBIR_RESIZE * resize, // You can update these parameters any time after resize_init and there is no cost //-------------------------------- -STBIRDEF void stbir_set_datatypes( STBIR_RESIZE * resize, stbir_datatype input_type, stbir_datatype output_type ); +STBIRDEF void stbir_set_datatypes( STBIR_RESIZE * resize, stbir_datatype input_type, stbir_datatype output_type ); STBIRDEF void stbir_set_pixel_callbacks( STBIR_RESIZE * resize, stbir_input_callback * input_cb, stbir_output_callback * output_cb ); // no callbacks by default STBIRDEF void stbir_set_user_data( STBIR_RESIZE * resize, void * user_data ); // pass back STBIR_RESIZE* by default STBIRDEF void stbir_set_buffer_ptrs( STBIR_RESIZE * resize, const void * input_pixels, int input_stride_in_bytes, void * output_pixels, int output_stride_in_bytes ); @@ -636,7 +661,7 @@ STBIRDEF int stbir_set_pixel_layouts( STBIR_RESIZE * resize, stbir_pixel_layout STBIRDEF int stbir_set_edgemodes( STBIR_RESIZE * resize, stbir_edge horizontal_edge, stbir_edge vertical_edge ); // CLAMP by default STBIRDEF int stbir_set_filters( STBIR_RESIZE * resize, stbir_filter horizontal_filter, stbir_filter vertical_filter ); // STBIR_DEFAULT_FILTER_UPSAMPLE/DOWNSAMPLE by default -STBIRDEF int stbir_set_filter_callbacks( STBIR_RESIZE * resize, stbir__kernel_callback * horizontal_filter, stbir__support_callback * horizontal_support, stbir__kernel_callback * vertical_filter, stbir__support_callback * vertical_support ); +STBIRDEF int stbir_set_filter_callbacks( STBIR_RESIZE * resize, stbir__kernel_callback * horizontal_filter, stbir__support_callback * horizontal_support, stbir__kernel_callback * vertical_filter, stbir__support_callback * vertical_support ); STBIRDEF int stbir_set_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby, int subw, int subh ); // sets both sub-regions (full regions by default) STBIRDEF int stbir_set_input_subrect( STBIR_RESIZE * resize, double s0, double t0, double s1, double t1 ); // sets input sub-region (full region by default) @@ -658,7 +683,7 @@ STBIRDEF int stbir_set_non_pm_alpha_speed_over_quality( STBIR_RESIZE * resize, i //-------------------------------- // This builds the samplers and does one allocation -STBIRDEF int stbir_build_samplers( STBIR_RESIZE * resize ); +STBIRDEF int stbir_build_samplers( STBIR_RESIZE * resize ); // You MUST call this, if you call stbir_build_samplers or stbir_build_samplers_with_splits STBIRDEF void stbir_free_samplers( STBIR_RESIZE * resize ); @@ -681,7 +706,7 @@ STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize ); // It returns the number of splits (threads) that you can call it with. /// It might be less if the image resize can't be split up that many ways. -STBIRDEF int stbir_build_samplers_with_splits( STBIR_RESIZE * resize, int try_splits ); +STBIRDEF int stbir_build_samplers_with_splits( STBIR_RESIZE * resize, int try_splits ); // This function does a split of the resizing (you call this fuction for each // split, on multiple threads). A split is a piece of the output resize pixel space. @@ -691,10 +716,10 @@ STBIRDEF int stbir_build_samplers_with_splits( STBIR_RESIZE * resize, int try_sp // Usually, you will always call stbir_resize_split with split_start as the thread_index // and "1" for the split_count. // But, if you have a weird situation where you MIGHT want 8 threads, but sometimes -// only 4 threads, you can use 0,2,4,6 for the split_start's and use "2" for the +// only 4 threads, you can use 0,2,4,6 for the split_start's and use "2" for the // split_count each time to turn in into a 4 thread resize. (This is unusual). -STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start, int split_count ); +STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start, int split_count ); //=============================================================== @@ -705,10 +730,10 @@ STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start // The input callback is super flexible - it calls you with the input address // (based on the stride and base pointer), it gives you an optional_output // pointer that you can fill, or you can just return your own pointer into -// your own data. +// your own data. // -// You can also do conversion from non-supported data types if necessary - in -// this case, you ignore the input_ptr and just use the x and y parameters to +// You can also do conversion from non-supported data types if necessary - in +// this case, you ignore the input_ptr and just use the x and y parameters to // calculate your own input_ptr based on the size of each non-supported pixel. // (Something like the third example below.) // @@ -722,14 +747,14 @@ STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start // return input_ptr; // use buffer from call // } // -// Next example, copying: (copy from some other buffer or stream): +// Next example, copying: (copy from some other buffer or stream): // void const * my_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context ) // { // CopyOrStreamData( optional_output, other_data_src, num_pixels * pixel_width_in_bytes ); // return optional_output; // return the optional buffer that we filled // } // -// Third example, input another buffer without copying: (zero-copy from other buffer): +// Third example, input another buffer without copying: (zero-copy from other buffer): // void const * my_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context ) // { // void * pixels = ( (char*) other_image_base ) + ( y * other_image_stride ) + ( x * other_pixel_width_in_bytes ); @@ -758,7 +783,7 @@ STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start #ifdef STBIR_PROFILE -typedef struct STBIR_PROFILE_INFO +typedef struct STBIR_PROFILE_INFO { stbir_uint64 total_clocks; @@ -766,7 +791,7 @@ typedef struct STBIR_PROFILE_INFO // there are "resize_count" number of zones stbir_uint64 clocks[ 8 ]; char const ** descriptions; - + // count of clocks and descriptions stbir_uint32 count; } STBIR_PROFILE_INFO; @@ -865,15 +890,15 @@ STBIRDEF void stbir_resize_split_profile_info( STBIR_PROFILE_INFO * out_info, ST #endif // the internal pixel layout enums are in a different order, so we can easily do range comparisons of types -// the public pixel layout is ordered in a way that if you cast num_channels (1-4) to the enum, you get something sensible -typedef enum +// the public pixel layout is ordered in a way that if you cast num_channels (1-4) to the enum, you get something sensible +typedef enum { STBIRI_1CHANNEL = 0, STBIRI_2CHANNEL = 1, STBIRI_RGB = 2, STBIRI_BGR = 3, STBIRI_4CHANNEL = 4, - + STBIRI_RGBA = 5, STBIRI_BGRA = 6, STBIRI_ARGB = 7, @@ -979,7 +1004,7 @@ typedef struct stbir__span spans[2]; // can be two spans, if doing input subrect with clamp mode WRAP } stbir__extents; -typedef struct +typedef struct { #ifdef STBIR_PROFILE union @@ -1010,7 +1035,7 @@ typedef struct typedef void stbir__decode_pixels_func( float * decode, int width_times_channels, void const * input ); typedef void stbir__alpha_weight_func( float * decode_buffer, int width_times_channels ); -typedef void stbir__horizontal_gather_channels_func( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, +typedef void stbir__horizontal_gather_channels_func( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer, stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width ); typedef void stbir__alpha_unweight_func(float * encode_buffer, int width_times_channels ); typedef void stbir__encode_pixels_func( void * output, int width_times_channels, float const * encode ); @@ -1053,10 +1078,10 @@ struct stbir__info stbir__horizontal_gather_channels_func * horizontal_gather_channels; stbir__alpha_unweight_func * alpha_unweight; stbir__encode_pixels_func * encode_pixels; - - int alloced_total; + + int alloc_ring_buffer_num_entries; // Number of entries in the ring buffer that will be allocated int splits; // count of splits - + stbir_internal_pixel_layout input_pixel_layout_internal; stbir_internal_pixel_layout output_pixel_layout_internal; @@ -1065,7 +1090,7 @@ struct stbir__info int vertical_first; int channels; int effective_channels; // same as channels, except on RGBA/ARGB (7), or XA/AX (3) - int alloc_ring_buffer_num_entries; // Number of entries in the ring buffer that will be allocated + size_t alloced_total; }; @@ -1076,10 +1101,11 @@ struct stbir__info #define stbir__small_float ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20)) // min/max friendly -#define STBIR_CLAMP(x, xmin, xmax) do { \ +#define STBIR_CLAMP(x, xmin, xmax) for(;;) { \ if ( (x) < (xmin) ) (x) = (xmin); \ if ( (x) > (xmax) ) (x) = (xmax); \ -} while (0) + break; \ +} static stbir__inline int stbir__min(int a, int b) { @@ -1141,7 +1167,7 @@ static const stbir_uint32 fp32_to_srgb8_tab4[104] = { 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559, 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723, }; - + static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) { static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps @@ -1172,19 +1198,44 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #define STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT 32 // when downsampling and <= 32 scanlines of buffering, use gather. gather used down to 1/8th scaling for 25% win. #endif -// restrict pointers for the output pointers +#ifndef STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS +#define STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS 4 // when threading, what is the minimum number of scanlines for a split? +#endif + +// restrict pointers for the output pointers, other loop and unroll control #if defined( _MSC_VER ) && !defined(__clang__) #define STBIR_STREAMOUT_PTR( star ) star __restrict #define STBIR_NO_UNROLL( ptr ) __assume(ptr) // this oddly keeps msvc from unrolling a loop -#elif defined( __clang__ ) + #if _MSC_VER >= 1900 + #define STBIR_NO_UNROLL_LOOP_START __pragma(loop( no_vector )) + #else + #define STBIR_NO_UNROLL_LOOP_START + #endif +#elif defined( __clang__ ) #define STBIR_STREAMOUT_PTR( star ) star __restrict__ - #define STBIR_NO_UNROLL( ptr ) __asm__ (""::"r"(ptr)) -#elif defined( __GNUC__ ) + #define STBIR_NO_UNROLL( ptr ) __asm__ (""::"r"(ptr)) + #if ( __clang_major__ >= 4 ) || ( ( __clang_major__ >= 3 ) && ( __clang_minor__ >= 5 ) ) + #define STBIR_NO_UNROLL_LOOP_START _Pragma("clang loop unroll(disable)") _Pragma("clang loop vectorize(disable)") + #else + #define STBIR_NO_UNROLL_LOOP_START + #endif +#elif defined( __GNUC__ ) #define STBIR_STREAMOUT_PTR( star ) star __restrict__ #define STBIR_NO_UNROLL( ptr ) __asm__ (""::"r"(ptr)) + #if __GNUC__ >= 14 + #define STBIR_NO_UNROLL_LOOP_START _Pragma("GCC unroll 0") _Pragma("GCC novector") + #else + #define STBIR_NO_UNROLL_LOOP_START + #endif + #define STBIR_NO_UNROLL_LOOP_START_INF_FOR #else #define STBIR_STREAMOUT_PTR( star ) star #define STBIR_NO_UNROLL( ptr ) + #define STBIR_NO_UNROLL_LOOP_START +#endif + +#ifndef STBIR_NO_UNROLL_LOOP_START_INF_FOR +#define STBIR_NO_UNROLL_LOOP_START_INF_FOR STBIR_NO_UNROLL_LOOP_START #endif #ifdef STBIR_NO_SIMD // force simd off for whatever reason @@ -1223,7 +1274,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #ifdef STBIR_SSE2 #include - + #define stbir__simdf __m128 #define stbir__simdi __m128i @@ -1254,7 +1305,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #define stbir__simdi_store2( ptr, reg ) _mm_storel_epi64( (__m128i*)(ptr), (reg) ) #define stbir__prefetch( ptr ) _mm_prefetch((char*)(ptr), _MM_HINT_T0 ) - + #define stbir__simdi_expand_u8_to_u32(out0,out1,out2,out3,ireg) \ { \ stbir__simdi zero = _mm_setzero_si128(); \ @@ -1285,7 +1336,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #define stbir__simdf_convert_float_to_uint8( f ) ((unsigned char)_mm_cvtsi128_si32(_mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(f,STBIR__CONSTF(STBIR_max_uint8_as_float)),_mm_setzero_ps())))) #define stbir__simdf_convert_float_to_short( f ) ((unsigned short)_mm_cvtsi128_si32(_mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(f,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps())))) - #define stbir__simdi_to_int( i ) _mm_cvtsi128_si32(i) + #define stbir__simdi_to_int( i ) _mm_cvtsi128_si32(i) #define stbir__simdi_convert_i32_to_float(out, ireg) (out) = _mm_cvtepi32_ps( ireg ) #define stbir__simdf_add( out, reg0, reg1 ) (out) = _mm_add_ps( reg0, reg1 ) #define stbir__simdf_mult( out, reg0, reg1 ) (out) = _mm_mul_ps( reg0, reg1 ) @@ -1440,10 +1491,10 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #define stbir__simdi8_convert_i32_to_float(out, ireg) (out) = _mm256_cvtepi32_ps( ireg ) #define stbir__simdf8_convert_float_to_i32( i, f ) (i) = _mm256_cvttps_epi32(f) - + #define stbir__simdf8_bot4s( out, a, b ) (out) = _mm256_permute2f128_ps(a,b, (0<<0)+(2<<4) ) #define stbir__simdf8_top4s( out, a, b ) (out) = _mm256_permute2f128_ps(a,b, (1<<0)+(3<<4) ) - + #define stbir__simdf8_gettop4( reg ) _mm256_extractf128_ps(reg,1) #ifdef STBIR_AVX2 @@ -1471,8 +1522,8 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) out = _mm256_castsi256_si128( _mm256_permute4x64_epi64( _mm256_packus_epi16( t, t ), (0<<0)+(2<<2)+(1<<4)+(3<<6) ) ); \ } - #define stbir__simdi8_expand_u16_to_u32(out,ireg) out = _mm256_unpacklo_epi16( _mm256_permute4x64_epi64(_mm256_castsi128_si256(ireg),(0<<0)+(2<<2)+(1<<4)+(3<<6)), _mm256_setzero_si256() ); - + #define stbir__simdi8_expand_u16_to_u32(out,ireg) out = _mm256_unpacklo_epi16( _mm256_permute4x64_epi64(_mm256_castsi128_si256(ireg),(0<<0)+(2<<2)+(1<<4)+(3<<6)), _mm256_setzero_si256() ); + #define stbir__simdf8_pack_to_16words(out,aa,bb) \ { \ stbir__simdf8 af,bf; \ @@ -1496,7 +1547,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) a = _mm_unpackhi_epi8( ireg, zero ); \ out1 = _mm256_setr_m128i( _mm_unpacklo_epi16( a, zero ), _mm_unpackhi_epi16( a, zero ) ); \ } - + #define stbir__simdf8_pack_to_16bytes(out,aa,bb) \ { \ stbir__simdi t; \ @@ -1514,7 +1565,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) t = _mm_packus_epi16( t, t ); \ out = _mm_castps_si128( _mm_shuffle_ps( _mm_castsi128_ps(out), _mm_castsi128_ps(t), (0<<0)+(1<<2)+(0<<4)+(1<<6) ) ); \ } - + #define stbir__simdi8_expand_u16_to_u32(out,ireg) \ { \ stbir__simdi a,b,zero = _mm_setzero_si128(); \ @@ -1549,7 +1600,6 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #define stbir__simdf8_0123to2222( out, in ) (out) = stbir__simdf_swiz(_mm256_castps256_ps128(in), 2,2,2,2 ) - #define stbir__simdf8_load2( out, ptr ) (out) = _mm256_castsi256_ps(_mm256_castsi128_si256( _mm_loadl_epi64( (__m128i*)(ptr)) )) // top values can be random (not denormal or nan for perf) #define stbir__simdf8_load4b( out, ptr ) (out) = _mm256_broadcast_ps( (__m128 const *)(ptr) ) static __m256i stbir_00112233 = { STBIR__CONST_4d_32i( 0, 0, 1, 1 ), STBIR__CONST_4d_32i( 2, 2, 3, 3 ) }; @@ -1582,11 +1632,11 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #ifdef STBIR_USE_FMA // not on by default to maintain bit identical simd to non-simd #define stbir__simdf8_madd( out, add, mul1, mul2 ) (out) = _mm256_fmadd_ps( mul1, mul2, add ) #define stbir__simdf8_madd_mem( out, add, mul, ptr ) (out) = _mm256_fmadd_ps( mul, _mm256_loadu_ps( (float const*)(ptr) ), add ) - #define stbir__simdf8_madd_mem4( out, add, mul, ptr ) (out) = _mm256_fmadd_ps( _mm256_castps128_ps256( mul ), _mm256_castps128_ps256( _mm_loadu_ps( (float const*)(ptr) ) ), add ) + #define stbir__simdf8_madd_mem4( out, add, mul, ptr )(out) = _mm256_fmadd_ps( _mm256_setr_m128( mul, _mm_setzero_ps() ), _mm256_setr_m128( _mm_loadu_ps( (float const*)(ptr) ), _mm_setzero_ps() ), add ) #else #define stbir__simdf8_madd( out, add, mul1, mul2 ) (out) = _mm256_add_ps( add, _mm256_mul_ps( mul1, mul2 ) ) #define stbir__simdf8_madd_mem( out, add, mul, ptr ) (out) = _mm256_add_ps( add, _mm256_mul_ps( mul, _mm256_loadu_ps( (float const*)(ptr) ) ) ) - #define stbir__simdf8_madd_mem4( out, add, mul, ptr ) (out) = _mm256_add_ps( add, _mm256_castps128_ps256( _mm_mul_ps( mul, _mm_loadu_ps( (float const*)(ptr) ) ) ) ) + #define stbir__simdf8_madd_mem4( out, add, mul, ptr ) (out) = _mm256_add_ps( add, _mm256_setr_m128( _mm_mul_ps( mul, _mm_loadu_ps( (float const*)(ptr) ) ), _mm_setzero_ps() ) ) #endif #define stbir__if_simdf8_cast_to_simdf4( val ) _mm256_castps256_ps128( val ) @@ -1627,7 +1677,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) } #elif defined(STBIR_NEON) - + #include #define stbir__simdf float32x4_t @@ -1686,7 +1736,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #define stbir__simdf_convert_float_to_i32( i, f ) (i) = vreinterpretq_u32_s32( vcvtq_s32_f32(f) ) #define stbir__simdf_convert_float_to_int( f ) vgetq_lane_s32(vcvtq_s32_f32(f), 0) - #define stbir__simdi_to_int( i ) (int)vgetq_lane_u32(i, 0) + #define stbir__simdi_to_int( i ) (int)vgetq_lane_u32(i, 0) #define stbir__simdf_convert_float_to_uint8( f ) ((unsigned char)vgetq_lane_s32(vcvtq_s32_f32(vmaxq_f32(vminq_f32(f,STBIR__CONSTF(STBIR_max_uint8_as_float)),vdupq_n_f32(0))), 0)) #define stbir__simdf_convert_float_to_short( f ) ((unsigned short)vgetq_lane_s32(vcvtq_s32_f32(vmaxq_f32(vminq_f32(f,STBIR__CONSTF(STBIR_max_uint16_as_float)),vdupq_n_f32(0))), 0)) #define stbir__simdi_convert_i32_to_float(out, ireg) (out) = vcvtq_f32_s32( vreinterpretq_s32_u32(ireg) ) @@ -1737,12 +1787,20 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) ((stbir_uint64)(4*b+0)<<32) | ((stbir_uint64)(4*b+1)<<40) | ((stbir_uint64)(4*b+2)<<48) | ((stbir_uint64)(4*b+3)<<56)), \ vcreate_u8( (4*c+0) | ((4*c+1)<<8) | ((4*c+2)<<16) | ((4*c+3)<<24) | \ ((stbir_uint64)(4*d+0)<<32) | ((stbir_uint64)(4*d+1)<<40) | ((stbir_uint64)(4*d+2)<<48) | ((stbir_uint64)(4*d+3)<<56) ) ) + + static stbir__inline uint8x16x2_t stbir_make16x2(float32x4_t rega,float32x4_t regb) + { + uint8x16x2_t r = { vreinterpretq_u8_f32(rega), vreinterpretq_u8_f32(regb) }; + return r; + } #else #define stbir_make16(a,b,c,d) (uint8x16_t){4*a+0,4*a+1,4*a+2,4*a+3,4*b+0,4*b+1,4*b+2,4*b+3,4*c+0,4*c+1,4*c+2,4*c+3,4*d+0,4*d+1,4*d+2,4*d+3} + #define stbir_make16x2(a,b) (uint8x16x2_t){{vreinterpretq_u8_f32(a),vreinterpretq_u8_f32(b)}} #endif #define stbir__simdf_swiz( reg, one, two, three, four ) vreinterpretq_f32_u8( vqtbl1q_u8( vreinterpretq_u8_f32(reg), stbir_make16(one, two, three, four) ) ) - + #define stbir__simdf_swiz2( rega, regb, one, two, three, four ) vreinterpretq_f32_u8( vqtbl2q_u8( stbir_make16x2(rega,regb), stbir_make16(one, two, three, four) ) ) + #define stbir__simdi_16madd( out, reg0, reg1 ) \ { \ int16x8_t r0 = vreinterpretq_s16_u32(reg0); \ @@ -1942,7 +2000,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #define stbir__simdf_convert_float_to_i32( i, f ) (i) = wasm_i32x4_trunc_sat_f32x4(f) #define stbir__simdf_convert_float_to_int( f ) wasm_i32x4_extract_lane(wasm_i32x4_trunc_sat_f32x4(f), 0) - #define stbir__simdi_to_int( i ) wasm_i32x4_extract_lane(i, 0) + #define stbir__simdi_to_int( i ) wasm_i32x4_extract_lane(i, 0) #define stbir__simdf_convert_float_to_uint8( f ) ((unsigned char)wasm_i32x4_extract_lane(wasm_i32x4_trunc_sat_f32x4(wasm_f32x4_max(wasm_f32x4_min(f,STBIR_max_uint8_as_float),wasm_f32x4_const_splat(0))), 0)) #define stbir__simdf_convert_float_to_short( f ) ((unsigned short)wasm_i32x4_extract_lane(wasm_i32x4_trunc_sat_f32x4(wasm_f32x4_max(wasm_f32x4_min(f,STBIR_max_uint16_as_float),wasm_f32x4_const_splat(0))), 0)) #define stbir__simdi_convert_i32_to_float(out, ireg) (out) = wasm_f32x4_convert_i32x4(ireg) @@ -2125,7 +2183,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #endif -#if defined(STBIR_NEON) && !defined(_M_ARM) +#if defined(STBIR_NEON) && !defined(_M_ARM) && !defined(__arm__) #if defined( _MSC_VER ) && !defined(__clang__) typedef __int16 stbir__FP16; @@ -2142,7 +2200,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #endif -#if !defined(STBIR_NEON) && !defined(STBIR_FP16C) || defined(STBIR_NEON) && defined(_M_ARM) +#if (!defined(STBIR_NEON) && !defined(STBIR_FP16C)) || (defined(STBIR_NEON) && defined(_M_ARM)) || (defined(STBIR_NEON) && defined(__arm__)) // Fabian's half float routines, see: https://gist.github.com/rygorous/2156668 @@ -2168,7 +2226,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) unsigned int sign_mask = 0x80000000u; stbir__FP16 o = { 0 }; stbir__FP32 f; - unsigned int sign; + unsigned int sign; f.f = val; sign = f.u & sign_mask; @@ -2369,24 +2427,6 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) stbir__simdi_store( output,final ); } -#elif defined(STBIR_WASM) || (defined(STBIR_NEON) && defined(_MSC_VER) && defined(_M_ARM)) // WASM or 32-bit ARM on MSVC/clang - - static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input) - { - for (int i=0; i<8; i++) - { - output[i] = stbir__half_to_float(input[i]); - } - } - - static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input) - { - for (int i=0; i<8; i++) - { - output[i] = stbir__float_to_half(input[i]); - } - } - #elif defined(STBIR_NEON) && defined(_MSC_VER) && defined(_M_ARM64) && !defined(__clang__) // 64-bit ARM on MSVC (not clang) static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input) @@ -2415,7 +2455,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) return vget_lane_f16(vcvt_f16_f32(vdupq_n_f32(f)), 0).n16_u16[0]; } -#elif defined(STBIR_NEON) // 64-bit ARM +#elif defined(STBIR_NEON) && ( defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) ) // 64-bit ARM static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input) { @@ -2441,6 +2481,23 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) return vget_lane_f16(vcvt_f16_f32(vdupq_n_f32(f)), 0); } +#elif defined(STBIR_WASM) || (defined(STBIR_NEON) && (defined(_MSC_VER) || defined(_M_ARM) || defined(__arm__))) // WASM or 32-bit ARM on MSVC/clang + + static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input) + { + for (int i=0; i<8; i++) + { + output[i] = stbir__half_to_float(input[i]); + } + } + static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input) + { + for (int i=0; i<8; i++) + { + output[i] = stbir__float_to_half(input[i]); + } + } + #endif @@ -2462,10 +2519,10 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in) #define stbir__simdf_0123to3012( out, reg ) (out) = stbir__simdf_swiz( reg, 3,0,1,2 ) #define stbir__simdf_0123to0011( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,1,1 ) #define stbir__simdf_0123to1100( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,0,0 ) -#define stbir__simdf_0123to2233( out, reg ) (out) = stbir__simdf_swiz( reg, 2,2,3,3 ) -#define stbir__simdf_0123to1133( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,3,3 ) -#define stbir__simdf_0123to0022( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,2,2 ) -#define stbir__simdf_0123to1032( out, reg ) (out) = stbir__simdf_swiz( reg, 1,0,3,2 ) +#define stbir__simdf_0123to2233( out, reg ) (out) = stbir__simdf_swiz( reg, 2,2,3,3 ) +#define stbir__simdf_0123to1133( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,3,3 ) +#define stbir__simdf_0123to0022( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,2,2 ) +#define stbir__simdf_0123to1032( out, reg ) (out) = stbir__simdf_swiz( reg, 1,0,3,2 ) typedef union stbir__simdi_u32 { @@ -2493,14 +2550,16 @@ static const STBIR__SIMDI_CONST(STBIR_topscale, 0x02000000); // Adding this switch saves about 5K on clang which is Captain Unroll the 3rd. #define STBIR_SIMD_STREAMOUT_PTR( star ) STBIR_STREAMOUT_PTR( star ) #define STBIR_SIMD_NO_UNROLL(ptr) STBIR_NO_UNROLL(ptr) +#define STBIR_SIMD_NO_UNROLL_LOOP_START STBIR_NO_UNROLL_LOOP_START +#define STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR STBIR_NO_UNROLL_LOOP_START_INF_FOR #ifdef STBIR_MEMCPY #undef STBIR_MEMCPY -#define STBIR_MEMCPY stbir_simd_memcpy #endif +#define STBIR_MEMCPY stbir_simd_memcpy // override normal use of memcpy with much simpler copy (faster and smaller with our sized copies) -static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes ) +static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes ) { char STBIR_SIMD_STREAMOUT_PTR (*) d = (char*) dest; char STBIR_SIMD_STREAMOUT_PTR( * ) d_end = ((char*) dest) + bytes; @@ -2513,8 +2572,9 @@ static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes ) { if ( bytes < 16 ) { - if ( bytes ) + if ( bytes ) { + STBIR_SIMD_NO_UNROLL_LOOP_START do { STBIR_SIMD_NO_UNROLL(d); @@ -2529,8 +2589,9 @@ static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes ) // do one unaligned to get us aligned for the stream out below stbir__simdf_load( x, ( d + ofs_to_src ) ); stbir__simdf_store( d, x ); - d = (char*)( ( ( (ptrdiff_t)d ) + 16 ) & ~15 ); + d = (char*)( ( ( (size_t)d ) + 16 ) & ~15 ); + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { STBIR_SIMD_NO_UNROLL(d); @@ -2561,12 +2622,13 @@ static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes ) stbir__simdfX_store( d + 4*stbir__simdfX_float_count, x1 ); stbir__simdfX_store( d + 8*stbir__simdfX_float_count, x2 ); stbir__simdfX_store( d + 12*stbir__simdfX_float_count, x3 ); - d = (char*)( ( ( (ptrdiff_t)d ) + (16*stbir__simdfX_float_count) ) & ~((16*stbir__simdfX_float_count)-1) ); + d = (char*)( ( ( (size_t)d ) + (16*stbir__simdfX_float_count) ) & ~((16*stbir__simdfX_float_count)-1) ); + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { STBIR_SIMD_NO_UNROLL(d); - + if ( d > ( d_end - (16*stbir__simdfX_float_count) ) ) { if ( d == d_end ) @@ -2590,7 +2652,7 @@ static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes ) // memcpy that is specically intentionally overlapping (src is smaller then dest, so can be // a normal forward copy, bytes is divisible by 4 and bytes is greater than or equal to // the diff between dest and src) -static void stbir_overlapping_memcpy( void * dest, void const * src, size_t bytes ) +static void stbir_overlapping_memcpy( void * dest, void const * src, size_t bytes ) { char STBIR_SIMD_STREAMOUT_PTR (*) sd = (char*) src; char STBIR_SIMD_STREAMOUT_PTR( * ) s_end = ((char*) src) + bytes; @@ -2599,6 +2661,7 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte if ( ofs_to_dest >= 16 ) // is the overlap more than 16 away? { char STBIR_SIMD_STREAMOUT_PTR( * ) s_end16 = ((char*) src) + (bytes&~15); + STBIR_SIMD_NO_UNROLL_LOOP_START do { stbir__simdf x; @@ -2615,7 +2678,7 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte do { STBIR_SIMD_NO_UNROLL(sd); - *(int*)( sd + ofs_to_dest ) = *(int*) sd; + *(int*)( sd + ofs_to_dest ) = *(int*) sd; sd += 4; } while ( sd < s_end ); } @@ -2624,13 +2687,17 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte // when in scalar mode, we let unrolling happen, so this macro just does the __restrict #define STBIR_SIMD_STREAMOUT_PTR( star ) STBIR_STREAMOUT_PTR( star ) -#define STBIR_SIMD_NO_UNROLL(ptr) +#define STBIR_SIMD_NO_UNROLL(ptr) +#define STBIR_SIMD_NO_UNROLL_LOOP_START +#define STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR #endif // SSE2 #ifdef STBIR_PROFILE +#ifndef STBIR_PROFILE_FUNC + #if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(__SSE2__) || defined(STBIR_SSE) || defined( _M_IX86_FP ) || defined(__i386) || defined( __i386__ ) || defined( _M_IX86 ) || defined( _X86_ ) #ifdef _MSC_VER @@ -2640,7 +2707,7 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte #else // non msvc - static stbir__inline stbir_uint64 STBIR_PROFILE_FUNC() + static stbir__inline stbir_uint64 STBIR_PROFILE_FUNC() { stbir_uint32 lo, hi; asm volatile ("rdtsc" : "=a" (lo), "=d" (hi) ); @@ -2649,7 +2716,7 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte #endif // msvc -#elif defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(__ARM_NEON__) +#elif defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(__ARM_NEON__) #if defined( _MSC_VER ) && !defined(__clang__) @@ -2670,8 +2737,9 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte #error Unknown platform for profiling. -#endif //x64 and +#endif // x64, arm +#endif // STBIR_PROFILE_FUNC #define STBIR_ONLY_PROFILE_GET_SPLIT_INFO ,stbir__per_split_info * split_info #define STBIR_ONLY_PROFILE_SET_SPLIT_INFO ,split_info @@ -2680,7 +2748,7 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte #define STBIR_ONLY_PROFILE_BUILD_SET_INFO ,profile_info // super light-weight micro profiler -#define STBIR_PROFILE_START_ll( info, wh ) { stbir_uint64 wh##thiszonetime = STBIR_PROFILE_FUNC(); stbir_uint64 * wh##save_parent_excluded_ptr = info->current_zone_excluded_ptr; stbir_uint64 wh##current_zone_excluded = 0; info->current_zone_excluded_ptr = &wh##current_zone_excluded; +#define STBIR_PROFILE_START_ll( info, wh ) { stbir_uint64 wh##thiszonetime = STBIR_PROFILE_FUNC(); stbir_uint64 * wh##save_parent_excluded_ptr = info->current_zone_excluded_ptr; stbir_uint64 wh##current_zone_excluded = 0; info->current_zone_excluded_ptr = &wh##current_zone_excluded; #define STBIR_PROFILE_END_ll( info, wh ) wh##thiszonetime = STBIR_PROFILE_FUNC() - wh##thiszonetime; info->profile.named.wh += wh##thiszonetime - wh##current_zone_excluded; *wh##save_parent_excluded_ptr += wh##thiszonetime; info->current_zone_excluded_ptr = wh##save_parent_excluded_ptr; } #define STBIR_PROFILE_FIRST_START_ll( info, wh ) { int i; info->current_zone_excluded_ptr = &info->profile.named.total; for(i=0;iprofile.array);i++) info->profile.array[i]=0; } STBIR_PROFILE_START_ll( info, wh ); #define STBIR_PROFILE_CLEAR_EXTRAS_ll( info, num ) { int extra; for(extra=1;extra<(num);extra++) { int i; for(i=0;iprofile.array);i++) (info)[extra].profile.array[i]=0; } } @@ -2710,8 +2778,8 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte #define STBIR_PROFILE_FIRST_START( wh ) #define STBIR_PROFILE_CLEAR_EXTRAS( ) -#define STBIR_PROFILE_BUILD_START( wh ) -#define STBIR_PROFILE_BUILD_END( wh ) +#define STBIR_PROFILE_BUILD_START( wh ) +#define STBIR_PROFILE_BUILD_END( wh ) #define STBIR_PROFILE_BUILD_FIRST_START( wh ) #define STBIR_PROFILE_BUILD_CLEAR( info ) @@ -2736,10 +2804,10 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte #ifndef STBIR_SIMD -// memcpy that is specically intentionally overlapping (src is smaller then dest, so can be +// memcpy that is specifically intentionally overlapping (src is smaller then dest, so can be // a normal forward copy, bytes is divisible by 4 and bytes is greater than or equal to // the diff between dest and src) -static void stbir_overlapping_memcpy( void * dest, void const * src, size_t bytes ) +static void stbir_overlapping_memcpy( void * dest, void const * src, size_t bytes ) { char STBIR_SIMD_STREAMOUT_PTR (*) sd = (char*) src; char STBIR_SIMD_STREAMOUT_PTR( * ) s_end = ((char*) src) + bytes; @@ -2748,10 +2816,11 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte if ( ofs_to_dest >= 8 ) // is the overlap more than 8 away? { char STBIR_SIMD_STREAMOUT_PTR( * ) s_end8 = ((char*) src) + (bytes&~7); + STBIR_NO_UNROLL_LOOP_START do { STBIR_NO_UNROLL(sd); - *(stbir_uint64*)( sd + ofs_to_dest ) = *(stbir_uint64*) sd; + *(stbir_uint64*)( sd + ofs_to_dest ) = *(stbir_uint64*) sd; sd += 8; } while ( sd < s_end8 ); @@ -2759,10 +2828,11 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte return; } + STBIR_NO_UNROLL_LOOP_START do { STBIR_NO_UNROLL(sd); - *(int*)( sd + ofs_to_dest ) = *(int*) sd; + *(int*)( sd + ofs_to_dest ) = *(int*) sd; sd += 4; } while ( sd < s_end ); } @@ -2863,13 +2933,6 @@ static float stbir__filter_mitchell(float x, float s, void * user_data) return (0.0f); } -static float stbir__support_zero(float s, void * user_data) -{ - STBIR__UNUSED(s); - STBIR__UNUSED(user_data); - return 0; -} - static float stbir__support_zeropoint5(float s, void * user_data) { STBIR__UNUSED(s); @@ -2884,7 +2947,7 @@ static float stbir__support_one(float s, void * user_data) return 1; } -static float stbir__support_two(float s, void * user_data) +static float stbir__support_two(float s, void * user_data) { STBIR__UNUSED(s); STBIR__UNUSED(user_data); @@ -2903,7 +2966,7 @@ static int stbir__get_filter_pixel_width(stbir__support_callback * support, floa return (int)STBIR_CEILF(support(scale,user_data) * 2.0f / scale); } -// this is how many coefficents per run of the filter (which is different +// this is how many coefficents per run of the filter (which is different // from the filter_pixel_width depending on if we are scattering or gathering) static int stbir__get_coefficient_width(stbir__sampler * samp, int is_gather, void * user_data) { @@ -2924,7 +2987,7 @@ static int stbir__get_coefficient_width(stbir__sampler * samp, int is_gather, vo } } -static int stbir__get_contributors(stbir__sampler * samp, int is_gather) +static int stbir__get_contributors(stbir__sampler * samp, int is_gather) { if (is_gather) return samp->scale_info.output_sub_size; @@ -2954,7 +3017,7 @@ static int stbir__edge_reflect_full( int n, int max ) { if (n < 0) { - if (n > -max) + if (n > -max) return -n; else return max - 1; @@ -3056,7 +3119,7 @@ static void stbir__get_extents( stbir__sampler * samp, stbir__extents * scanline left_margin = -min_n; min_n = 0; } - + right_margin = 0; if ( max_n >= input_full_size ) { @@ -3081,7 +3144,7 @@ static void stbir__get_extents( stbir__sampler * samp, stbir__extents * scanline // don't have to do edge calc for zero clamp if ( edge == STBIR_EDGE_ZERO ) return; - + // convert margin pixels to the pixels within the input (min and max) for( j = -left_margin ; j < 0 ; j++ ) { @@ -3179,20 +3242,20 @@ static void stbir__calculate_in_pixel_range( int * first_pixel, int * last_pixel float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius; float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius; - float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) * inv_scale; - float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) * inv_scale; + float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) * inv_scale; + float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) * inv_scale; first = (int)(STBIR_FLOORF(in_pixel_influence_lowerbound + 0.5f)); last = (int)(STBIR_FLOORF(in_pixel_influence_upperbound - 0.5f)); if ( edge == STBIR_EDGE_WRAP ) { - if ( first <= -input_size ) - first = -(input_size-1); + if ( first < -input_size ) + first = -input_size; if ( last >= (input_size*2)) last = (input_size*2) - 1; } - + *first_pixel = first; *last_pixel = last; } @@ -3213,10 +3276,10 @@ static void stbir__calculate_coefficients_for_gather_upsample( float out_filter_ int i; int last_non_zero; float out_pixel_center = (float)n + 0.5f; - float in_center_of_out = (out_pixel_center + out_shift) * inv_scale; + float in_center_of_out = (out_pixel_center + out_shift) * inv_scale; int in_first_pixel, in_last_pixel; - + stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, out_pixel_center, out_filter_radius, inv_scale, out_shift, input_size, edge ); last_non_zero = -1; @@ -3229,7 +3292,7 @@ static void stbir__calculate_coefficients_for_gather_upsample( float out_filter_ if ( ( ( coeff < stbir__small_float ) && ( coeff > -stbir__small_float ) ) ) { if ( i == 0 ) // if we're at the front, just eat zero contributors - { + { STBIR_ASSERT ( ( in_last_pixel - in_first_pixel ) != 0 ); // there should be at least one contrib ++in_first_pixel; i--; @@ -3239,10 +3302,10 @@ static void stbir__calculate_coefficients_for_gather_upsample( float out_filter_ } else last_non_zero = i; - + coefficient_group[i] = coeff; } - + in_last_pixel = last_non_zero+in_first_pixel; // kills trailing zeros contributors->n0 = in_first_pixel; contributors->n1 = in_last_pixel; @@ -3354,7 +3417,7 @@ static void stbir__calculate_coefficients_for_gather_downsample( int start, int stbir__contributors * contribs = contributors + out; // is this the first time this output pixel has been seen? Init it. - if ( out > first_out_inited ) + if ( out > first_out_inited ) { STBIR_ASSERT( out == ( first_out_inited + 1 ) ); // ensure we have only advanced one at time first_out_inited = out; @@ -3362,7 +3425,7 @@ static void stbir__calculate_coefficients_for_gather_downsample( int start, int contribs->n1 = in_pixel; coeffs[0] = coeff; } - else + else { // insert on end (always in order) if ( coeffs[0] == 0.0f ) // if the first coefficent is zero, then zap it for this coeffs @@ -3379,10 +3442,16 @@ static void stbir__calculate_coefficients_for_gather_downsample( int start, int } } +#ifdef STBIR_RENORMALIZE_IN_FLOAT +#define STBIR_RENORM_TYPE float +#else +#define STBIR_RENORM_TYPE double +#endif + static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter_extent_info* filter_info, stbir__scale_info * scale_info, int num_contributors, stbir__contributors* contributors, float * coefficient_group, int coefficient_width ) { int input_size = scale_info->input_full_size; - int input_last_n1 = input_size - 1; + int input_last_n1 = input_size - 1; int n, end; int lowest = 0x7fffffff; int highest = -0x7fffffff; @@ -3400,14 +3469,14 @@ static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter for (n = 0; n < end; n++) { int i; - float filter_scale, total_filter = 0; + STBIR_RENORM_TYPE filter_scale, total_filter = 0; int e; // add all contribs e = contribs->n1 - contribs->n0; for( i = 0 ; i <= e ; i++ ) { - total_filter += coeffs[i]; + total_filter += (STBIR_RENORM_TYPE) coeffs[i]; STBIR_ASSERT( ( coeffs[i] >= -2.0f ) && ( coeffs[i] <= 2.0f ) ); // check for wonky weights } @@ -3423,10 +3492,11 @@ static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter // if the total isn't 1.0, rescale everything if ( ( total_filter < (1.0f-stbir__small_float) ) || ( total_filter > (1.0f+stbir__small_float) ) ) { - filter_scale = 1.0f / total_filter; + filter_scale = ((STBIR_RENORM_TYPE)1.0) / total_filter; + // scale them all for (i = 0; i <= e; i++) - coeffs[i] *= filter_scale; + coeffs[i] = (float) ( coeffs[i] * filter_scale ); } } ++contribs; @@ -3483,13 +3553,13 @@ static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter else if ( ( edge == STBIR_EDGE_CLAMP ) || ( edge == STBIR_EDGE_REFLECT ) ) { // for clamp and reflect, calculate the true inbounds position (based on edge type) and just add that to the existing weight - + // right hand side first if ( contribs->n1 > input_last_n1 ) { int start = contribs->n0; int endi = contribs->n1; - contribs->n1 = input_last_n1; + contribs->n1 = input_last_n1; for( i = input_size; i <= endi; i++ ) stbir__insert_coeff( contribs, coeffs, stbir__edge_wrap_slow[edge]( i, input_size ), coeffs[i-start] ); } @@ -3500,18 +3570,18 @@ static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter int save_n0; float save_n0_coeff; float * c = coeffs - ( contribs->n0 + 1 ); - + // reinsert the coeffs with it reflected or clamped (insert accumulates, if the coeffs exist) - for( i = -1 ; i > contribs->n0 ; i-- ) + for( i = -1 ; i > contribs->n0 ; i-- ) stbir__insert_coeff( contribs, coeffs, stbir__edge_wrap_slow[edge]( i, input_size ), *c-- ); save_n0 = contribs->n0; save_n0_coeff = c[0]; // save it, since we didn't do the final one (i==n0), because there might be too many coeffs to hold (before we resize)! // now slide all the coeffs down (since we have accumulated them in the positive contribs) and reset the first contrib - contribs->n0 = 0; + contribs->n0 = 0; for(i = 0 ; i <= contribs->n1 ; i++ ) coeffs[i] = coeffs[i-save_n0]; - + // now that we have shrunk down the contribs, we insert the first one safely stbir__insert_coeff( contribs, coeffs, stbir__edge_wrap_slow[edge]( save_n0, input_size ), save_n0_coeff ); } @@ -3547,7 +3617,9 @@ static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter filter_info->widest = widest; } -static int stbir__pack_coefficients( int num_contributors, stbir__contributors* contributors, float * coefficents, int coefficient_width, int widest, int row_width ) +#undef STBIR_RENORM_TYPE + +static int stbir__pack_coefficients( int num_contributors, stbir__contributors* contributors, float * coefficents, int coefficient_width, int widest, int row0, int row1 ) { #define STBIR_MOVE_1( dest, src ) { STBIR_NO_UNROLL(dest); ((stbir_uint32*)(dest))[0] = ((stbir_uint32*)(src))[0]; } #define STBIR_MOVE_2( dest, src ) { STBIR_NO_UNROLL(dest); ((stbir_uint64*)(dest))[0] = ((stbir_uint64*)(src))[0]; } @@ -3556,6 +3628,10 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* #else #define STBIR_MOVE_4( dest, src ) { STBIR_NO_UNROLL(dest); ((stbir_uint64*)(dest))[0] = ((stbir_uint64*)(src))[0]; ((stbir_uint64*)(dest))[1] = ((stbir_uint64*)(src))[1]; } #endif + + int row_end = row1 + 1; + STBIR__UNUSED( row0 ); // only used in an assert + if ( coefficient_width != widest ) { float * pc = coefficents; @@ -3564,6 +3640,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* switch( widest ) { case 1: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_1( pc, coeffs ); ++pc; @@ -3571,6 +3648,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 2: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_2( pc, coeffs ); pc += 2; @@ -3578,6 +3656,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 3: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_2( pc, coeffs ); STBIR_MOVE_1( pc+2, coeffs+2 ); @@ -3586,6 +3665,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 4: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_4( pc, coeffs ); pc += 4; @@ -3593,6 +3673,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 5: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_4( pc, coeffs ); STBIR_MOVE_1( pc+4, coeffs+4 ); @@ -3601,6 +3682,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 6: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_4( pc, coeffs ); STBIR_MOVE_2( pc+4, coeffs+4 ); @@ -3609,6 +3691,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 7: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_4( pc, coeffs ); STBIR_MOVE_2( pc+4, coeffs+4 ); @@ -3618,6 +3701,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 8: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_4( pc, coeffs ); STBIR_MOVE_4( pc+4, coeffs+4 ); @@ -3626,6 +3710,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 9: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_4( pc, coeffs ); STBIR_MOVE_4( pc+4, coeffs+4 ); @@ -3635,6 +3720,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 10: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_4( pc, coeffs ); STBIR_MOVE_4( pc+4, coeffs+4 ); @@ -3644,6 +3730,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 11: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_4( pc, coeffs ); STBIR_MOVE_4( pc+4, coeffs+4 ); @@ -3654,6 +3741,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; case 12: + STBIR_NO_UNROLL_LOOP_START do { STBIR_MOVE_4( pc, coeffs ); STBIR_MOVE_4( pc+4, coeffs+4 ); @@ -3663,6 +3751,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* } while ( pc < pc_end ); break; default: + STBIR_NO_UNROLL_LOOP_START do { float * copy_end = pc + widest - 4; float * c = coeffs; @@ -3673,6 +3762,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* c += 4; } while ( pc <= copy_end ); copy_end += 4; + STBIR_NO_UNROLL_LOOP_START while ( pc < copy_end ) { STBIR_MOVE_1( pc, c ); @@ -3688,7 +3778,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* coefficents[ widest * num_contributors ] = 8888.0f; // the minimum we might read for unrolled filters widths is 12. So, we need to - // make sure we never read outside the decode buffer, by possibly moving + // make sure we never read outside the decode buffer, by possibly moving // the sample area back into the scanline, and putting zeros weights first. // we start on the right edge and check until we're well past the possible // clip area (2*widest). @@ -3697,13 +3787,13 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* float * coeffs = coefficents + widest * ( num_contributors - 1 ); // go until no chance of clipping (this is usually less than 8 lops) - while ( ( ( contribs->n0 + widest*2 ) >= row_width ) && ( contribs >= contributors ) ) + while ( ( contribs >= contributors ) && ( ( contribs->n0 + widest*2 ) >= row_end ) ) { // might we clip?? - if ( ( contribs->n0 + widest ) > row_width ) + if ( ( contribs->n0 + widest ) > row_end ) { int stop_range = widest; - + // if range is larger than 12, it will be handled by generic loops that can terminate on the exact length // of this contrib n1, instead of a fixed widest amount - so calculate this if ( widest > 12 ) @@ -3712,22 +3802,22 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* // how far will be read in the n_coeff loop (which depends on the widest count mod4); mod = widest & 3; - stop_range = ( ( ( contribs->n1 - contribs->n0 + 1 ) - mod + 3 ) & ~3 ) + mod; + stop_range = ( ( ( contribs->n1 - contribs->n0 + 1 ) - mod + 3 ) & ~3 ) + mod; // the n_coeff loops do a minimum amount of coeffs, so factor that in! if ( stop_range < ( 8 + mod ) ) stop_range = 8 + mod; } // now see if we still clip with the refined range - if ( ( contribs->n0 + stop_range ) > row_width ) + if ( ( contribs->n0 + stop_range ) > row_end ) { - int new_n0 = row_width - stop_range; + int new_n0 = row_end - stop_range; int num = contribs->n1 - contribs->n0 + 1; int backup = contribs->n0 - new_n0; float * from_co = coeffs + num - 1; float * to_co = from_co + backup; - STBIR_ASSERT( ( new_n0 >= 0 ) && ( new_n0 < contribs->n0 ) ); + STBIR_ASSERT( ( new_n0 >= row0 ) && ( new_n0 < contribs->n0 ) ); // move the coeffs over while( num ) @@ -3746,7 +3836,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors* // how far will be read in the n_coeff loop (which depends on the widest count mod4); mod = widest & 3; - stop_range = ( ( ( contribs->n1 - contribs->n0 + 1 ) - mod + 3 ) & ~3 ) + mod; + stop_range = ( ( ( contribs->n1 - contribs->n0 + 1 ) - mod + 3 ) & ~3 ) + mod; // the n_coeff loops do a minimum amount of coeffs, so factor that in! if ( stop_range < ( 8 + mod ) ) stop_range = 8 + mod; @@ -3774,7 +3864,7 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot int input_full_size = samp->scale_info.input_full_size; int gather_num_contributors = samp->num_contributors; stbir__contributors* gather_contributors = samp->contributors; - float * gather_coeffs = samp->coefficients; + float * gather_coeffs = samp->coefficients; int gather_coefficient_width = samp->coefficient_width; switch ( samp->is_gather ) @@ -3792,16 +3882,16 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot break; case 0: // scatter downsample (only on vertical) - case 2: // gather downsample + case 2: // gather downsample { float in_pixels_radius = support(scale,user_data) * inv_scale; int filter_pixel_margin = samp->filter_pixel_margin; int input_end = input_full_size + filter_pixel_margin; - + // if this is a scatter, we do a downsample gather to get the coeffs, and then pivot after if ( !samp->is_gather ) { - // check if we are using the same gather downsample on the horizontal as this vertical, + // check if we are using the same gather downsample on the horizontal as this vertical, // if so, then we don't have to generate them, we can just pivot from the horizontal. if ( other_axis_for_pivot ) { @@ -3846,30 +3936,37 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot float * scatter_coeffs = samp->coefficients + ( gn0 + filter_pixel_margin ) * scatter_coefficient_width; float * g_coeffs = gather_coeffs; scatter_contributors = samp->contributors + ( gn0 + filter_pixel_margin ); - + for (k = gn0 ; k <= gn1 ; k++ ) { float gc = *g_coeffs++; - if ( ( k > highest_set ) || ( scatter_contributors->n0 > scatter_contributors->n1 ) ) + + // skip zero and denormals - must skip zeros to avoid adding coeffs beyond scatter_coefficient_width + // (which happens when pivoting from horizontal, which might have dummy zeros) + if ( ( ( gc >= stbir__small_float ) || ( gc <= -stbir__small_float ) ) ) { + if ( ( k > highest_set ) || ( scatter_contributors->n0 > scatter_contributors->n1 ) ) { - // if we are skipping over several contributors, we need to clear the skipped ones - stbir__contributors * clear_contributors = samp->contributors + ( highest_set + filter_pixel_margin + 1); - while ( clear_contributors < scatter_contributors ) { - clear_contributors->n0 = 0; - clear_contributors->n1 = -1; - ++clear_contributors; + // if we are skipping over several contributors, we need to clear the skipped ones + stbir__contributors * clear_contributors = samp->contributors + ( highest_set + filter_pixel_margin + 1); + while ( clear_contributors < scatter_contributors ) + { + clear_contributors->n0 = 0; + clear_contributors->n1 = -1; + ++clear_contributors; + } } + scatter_contributors->n0 = n; + scatter_contributors->n1 = n; + scatter_coeffs[0] = gc; + highest_set = k; } - scatter_contributors->n0 = n; - scatter_contributors->n1 = n; - scatter_coeffs[0] = gc; - highest_set = k; - } - else - { - stbir__insert_coeff( scatter_contributors, scatter_coeffs, n, gc ); + else + { + stbir__insert_coeff( scatter_contributors, scatter_coeffs, n, gc ); + } + STBIR_ASSERT( ( scatter_contributors->n1 - scatter_contributors->n0 + 1 ) <= scatter_coefficient_width ); } ++scatter_contributors; scatter_coeffs += scatter_coefficient_width; @@ -3908,11 +4005,11 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot #define stbir__decode_suffix BGRA #define stbir__decode_swizzle -#define stbir__decode_order0 2 +#define stbir__decode_order0 2 #define stbir__decode_order1 1 #define stbir__decode_order2 0 #define stbir__decode_order3 3 -#define stbir__encode_order0 2 +#define stbir__encode_order0 2 #define stbir__encode_order1 1 #define stbir__encode_order2 0 #define stbir__encode_order3 3 @@ -3922,11 +4019,11 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot #define stbir__decode_suffix ARGB #define stbir__decode_swizzle -#define stbir__decode_order0 1 +#define stbir__decode_order0 1 #define stbir__decode_order1 2 #define stbir__decode_order2 3 #define stbir__decode_order3 0 -#define stbir__encode_order0 3 +#define stbir__encode_order0 3 #define stbir__encode_order1 0 #define stbir__encode_order2 1 #define stbir__encode_order3 2 @@ -3936,11 +4033,11 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot #define stbir__decode_suffix ABGR #define stbir__decode_swizzle -#define stbir__decode_order0 3 +#define stbir__decode_order0 3 #define stbir__decode_order1 2 #define stbir__decode_order2 1 #define stbir__decode_order3 0 -#define stbir__encode_order0 3 +#define stbir__encode_order0 3 #define stbir__encode_order1 2 #define stbir__encode_order2 1 #define stbir__encode_order3 0 @@ -3950,12 +4047,12 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot #define stbir__decode_suffix AR #define stbir__decode_swizzle -#define stbir__decode_order0 1 -#define stbir__decode_order1 0 +#define stbir__decode_order0 1 +#define stbir__decode_order1 0 #define stbir__decode_order2 3 #define stbir__decode_order3 2 -#define stbir__encode_order0 1 -#define stbir__encode_order1 0 +#define stbir__encode_order0 1 +#define stbir__encode_order1 0 #define stbir__encode_order2 3 #define stbir__encode_order3 2 #define stbir__coder_min_num 2 @@ -3973,9 +4070,10 @@ static void stbir__fancy_alpha_weight_4ch( float * out_buffer, int width_times_c // fancy alpha is stored internally as R G B A Rpm Gpm Bpm #ifdef STBIR_SIMD - + #ifdef STBIR_SIMD8 decode += 16; + STBIR_NO_UNROLL_LOOP_START while ( decode <= end_decode ) { stbir__simdf8 d0,d1,a0,a1,p0,p1; @@ -3998,8 +4096,9 @@ static void stbir__fancy_alpha_weight_4ch( float * out_buffer, int width_times_c out += 28; } decode -= 16; - #else + #else decode += 8; + STBIR_NO_UNROLL_LOOP_START while ( decode <= end_decode ) { stbir__simdf d0,a0,d1,a1,p0,p1; @@ -4022,12 +4121,14 @@ static void stbir__fancy_alpha_weight_4ch( float * out_buffer, int width_times_c // might be one last odd pixel #ifdef STBIR_SIMD8 + STBIR_NO_UNROLL_LOOP_START while ( decode < end_decode ) #else if ( decode < end_decode ) #endif { stbir__simdf d,a,p; + STBIR_NO_UNROLL(decode); stbir__simdf_load( d, decode ); stbir__simdf_0123to3333( a, d ); stbir__simdf_mult( p, a, d ); @@ -4069,6 +4170,7 @@ static void stbir__fancy_alpha_weight_2ch( float * out_buffer, int width_times_c decode += 8; if ( decode <= end_decode ) { + STBIR_NO_UNROLL_LOOP_START do { #ifdef STBIR_SIMD8 stbir__simdf8 d0,a0,p0; @@ -4077,11 +4179,11 @@ static void stbir__fancy_alpha_weight_2ch( float * out_buffer, int width_times_c stbir__simdf8_0123to11331133( p0, d0 ); stbir__simdf8_0123to00220022( a0, d0 ); stbir__simdf8_mult( p0, p0, a0 ); - + stbir__simdf_store2( out, stbir__if_simdf8_cast_to_simdf4( d0 ) ); stbir__simdf_store( out+2, stbir__if_simdf8_cast_to_simdf4( p0 ) ); stbir__simdf_store2h( out+3, stbir__if_simdf8_cast_to_simdf4( d0 ) ); - + stbir__simdf_store2( out+6, stbir__simdf8_gettop4( d0 ) ); stbir__simdf_store( out+8, stbir__simdf8_gettop4( p0 ) ); stbir__simdf_store2h( out+9, stbir__simdf8_gettop4( d0 ) ); @@ -4112,6 +4214,7 @@ static void stbir__fancy_alpha_weight_2ch( float * out_buffer, int width_times_c decode -= 8; #endif + STBIR_SIMD_NO_UNROLL_LOOP_START while( decode < end_decode ) { float x = decode[0], y = decode[1]; @@ -4132,6 +4235,7 @@ static void stbir__fancy_alpha_unweight_4ch( float * encode_buffer, int width_ti // fancy RGBA is stored internally as R G B A Rpm Gpm Bpm + STBIR_SIMD_NO_UNROLL_LOOP_START do { float alpha = input[3]; #ifdef STBIR_SIMD @@ -4199,6 +4303,7 @@ static void stbir__simple_alpha_weight_4ch( float * decode_buffer, int width_tim #ifdef STBIR_SIMD { decode += 2 * stbir__simdfX_float_count; + STBIR_NO_UNROLL_LOOP_START while ( decode <= end_decode ) { stbir__simdfX d0,a0,d1,a1; @@ -4217,6 +4322,7 @@ static void stbir__simple_alpha_weight_4ch( float * decode_buffer, int width_tim // few last pixels remnants #ifdef STBIR_SIMD8 + STBIR_NO_UNROLL_LOOP_START while ( decode < end_decode ) #else if ( decode < end_decode ) @@ -4252,6 +4358,7 @@ static void stbir__simple_alpha_weight_2ch( float * decode_buffer, int width_tim #ifdef STBIR_SIMD decode += 2 * stbir__simdfX_float_count; + STBIR_NO_UNROLL_LOOP_START while ( decode <= end_decode ) { stbir__simdfX d0,a0,d1,a1; @@ -4269,6 +4376,7 @@ static void stbir__simple_alpha_weight_2ch( float * decode_buffer, int width_tim decode -= 2 * stbir__simdfX_float_count; #endif + STBIR_SIMD_NO_UNROLL_LOOP_START while( decode < end_decode ) { float alpha = decode[1]; @@ -4283,6 +4391,7 @@ static void stbir__simple_alpha_unweight_4ch( float * encode_buffer, int width_t float STBIR_SIMD_STREAMOUT_PTR(*) encode = encode_buffer; float const * end_output = encode_buffer + width_times_channels; + STBIR_SIMD_NO_UNROLL_LOOP_START do { float alpha = encode[3]; @@ -4330,9 +4439,77 @@ static void stbir__simple_flip_3ch( float * decode_buffer, int width_times_chann float STBIR_STREAMOUT_PTR(*) decode = decode_buffer; float const * end_decode = decode_buffer + width_times_channels; - decode += 12; +#ifdef STBIR_SIMD + #ifdef stbir__simdf_swiz2 // do we have two argument swizzles? + end_decode -= 12; + STBIR_NO_UNROLL_LOOP_START + while( decode <= end_decode ) + { + // on arm64 8 instructions, no overlapping stores + stbir__simdf a,b,c,na,nb; + STBIR_SIMD_NO_UNROLL(decode); + stbir__simdf_load( a, decode ); + stbir__simdf_load( b, decode+4 ); + stbir__simdf_load( c, decode+8 ); + + na = stbir__simdf_swiz2( a, b, 2, 1, 0, 5 ); + b = stbir__simdf_swiz2( a, b, 4, 3, 6, 7 ); + nb = stbir__simdf_swiz2( b, c, 0, 1, 4, 3 ); + c = stbir__simdf_swiz2( b, c, 2, 7, 6, 5 ); + + stbir__simdf_store( decode, na ); + stbir__simdf_store( decode+4, nb ); + stbir__simdf_store( decode+8, c ); + decode += 12; + } + end_decode += 12; + #else + end_decode -= 24; + STBIR_NO_UNROLL_LOOP_START + while( decode <= end_decode ) + { + // 26 instructions on x64 + stbir__simdf a,b,c,d,e,f,g; + float i21, i23; + STBIR_SIMD_NO_UNROLL(decode); + stbir__simdf_load( a, decode ); + stbir__simdf_load( b, decode+3 ); + stbir__simdf_load( c, decode+6 ); + stbir__simdf_load( d, decode+9 ); + stbir__simdf_load( e, decode+12 ); + stbir__simdf_load( f, decode+15 ); + stbir__simdf_load( g, decode+18 ); + + a = stbir__simdf_swiz( a, 2, 1, 0, 3 ); + b = stbir__simdf_swiz( b, 2, 1, 0, 3 ); + c = stbir__simdf_swiz( c, 2, 1, 0, 3 ); + d = stbir__simdf_swiz( d, 2, 1, 0, 3 ); + e = stbir__simdf_swiz( e, 2, 1, 0, 3 ); + f = stbir__simdf_swiz( f, 2, 1, 0, 3 ); + g = stbir__simdf_swiz( g, 2, 1, 0, 3 ); + + // stores overlap, need to be in order, + stbir__simdf_store( decode, a ); + i21 = decode[21]; + stbir__simdf_store( decode+3, b ); + i23 = decode[23]; + stbir__simdf_store( decode+6, c ); + stbir__simdf_store( decode+9, d ); + stbir__simdf_store( decode+12, e ); + stbir__simdf_store( decode+15, f ); + stbir__simdf_store( decode+18, g ); + decode[21] = i23; + decode[23] = i21; + decode += 24; + } + end_decode += 24; + #endif +#else + end_decode -= 12; + STBIR_NO_UNROLL_LOOP_START while( decode <= end_decode ) { + // 16 instructions float t0,t1,t2,t3; STBIR_NO_UNROLL(decode); t0 = decode[0]; t1 = decode[3]; t2 = decode[6]; t3 = decode[9]; @@ -4340,8 +4517,10 @@ static void stbir__simple_flip_3ch( float * decode_buffer, int width_times_chann decode[2] = t0; decode[5] = t1; decode[8] = t2; decode[11] = t3; decode += 12; } - decode -= 12; + end_decode += 12; +#endif + STBIR_NO_UNROLL_LOOP_START while( decode < end_decode ) { float t = decode[0]; @@ -4362,14 +4541,14 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir_edge edge_horizontal = stbir_info->horizontal.edge; stbir_edge edge_vertical = stbir_info->vertical.edge; int row = stbir__edge_wrap(edge_vertical, n, stbir_info->vertical.scale_info.input_full_size); - const void* input_plane_data = ( (char *) stbir_info->input_data ) + (ptrdiff_t)row * (ptrdiff_t) stbir_info->input_stride_bytes; + const void* input_plane_data = ( (char *) stbir_info->input_data ) + (size_t)row * (size_t) stbir_info->input_stride_bytes; stbir__span const * spans = stbir_info->scanline_extents.spans; float* full_decode_buffer = output_buffer - stbir_info->scanline_extents.conservative.n0 * effective_channels; // if we are on edge_zero, and we get in here with an out of bounds n, then the calculate filters has failed STBIR_ASSERT( !(edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->vertical.scale_info.input_full_size)) ); - do + do { float * decode_buffer; void const * input_data; @@ -4377,7 +4556,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float int width_times_channels; int width; - if ( spans->n1 < spans->n0 ) + if ( spans->n1 < spans->n0 ) break; width = spans->n1 + 1 - spans->n0; @@ -4394,7 +4573,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float // call the callback with a temp buffer (that they can choose to use or not). the temp is just right aligned memory in the decode_buffer itself input_data = stbir_info->in_pixels_cb( ( (char*) end_decode ) - ( width * input_sample_in_bytes ), input_plane_data, width, spans->pixel_offset_for_input, row, stbir_info->user_data ); } - + STBIR_PROFILE_START( decode ); // convert the pixels info the float decode_buffer, (we index from end_decode, so that when channelsdecode_pixels( (float*)end_decode - width_times_channels, width_times_channels, input_data ); @@ -4418,7 +4597,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float // this code only runs if we're in edge_wrap, and we're doing the entire scanline int e, start_x[2]; int input_full_size = stbir_info->horizontal.scale_info.input_full_size; - + start_x[0] = -stbir_info->scanline_extents.edge_sizes[0]; // left edge start x start_x[1] = input_full_size; // right edge @@ -4447,7 +4626,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf tot,c; \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load1( c, hc ); \ - stbir__simdf_mult1_mem( tot, c, decode ); + stbir__simdf_mult1_mem( tot, c, decode ); #define stbir__2_coeff_only() \ stbir__simdf tot,c,d; \ @@ -4456,7 +4635,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_load2( d, decode ); \ stbir__simdf_mult( tot, c, d ); \ stbir__simdf_0123to1230( c, tot ); \ - stbir__simdf_add1( tot, tot, c ); + stbir__simdf_add1( tot, tot, c ); #define stbir__3_coeff_only() \ stbir__simdf tot,c,t; \ @@ -4466,7 +4645,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to1230( c, tot ); \ stbir__simdf_0123to2301( t, tot ); \ stbir__simdf_add1( tot, tot, c ); \ - stbir__simdf_add1( tot, tot, t ); + stbir__simdf_add1( tot, tot, t ); #define stbir__store_output_tiny() \ stbir__simdf_store1( output, tot ); \ @@ -4483,7 +4662,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float #define stbir__4_coeff_continue_from_4( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load( c, hc + (ofs) ); \ - stbir__simdf_madd_mem( tot, tot, c, decode+(ofs) ); + stbir__simdf_madd_mem( tot, tot, c, decode+(ofs) ); #define stbir__1_coeff_remnant( ofs ) \ { stbir__simdf d; \ @@ -4495,7 +4674,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float { stbir__simdf d; \ stbir__simdf_load2z( c, hc+(ofs) ); \ stbir__simdf_load2( d, decode+(ofs) ); \ - stbir__simdf_madd( tot, tot, d, c ); } + stbir__simdf_madd( tot, tot, d, c ); } #define stbir__3_coeff_setup() \ stbir__simdf mask; \ @@ -4520,18 +4699,18 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float #define stbir__1_coeff_only() \ float tot; \ - tot = decode[0]*hc[0]; + tot = decode[0]*hc[0]; #define stbir__2_coeff_only() \ float tot; \ tot = decode[0] * hc[0]; \ - tot += decode[1] * hc[1]; + tot += decode[1] * hc[1]; #define stbir__3_coeff_only() \ float tot; \ tot = decode[0] * hc[0]; \ tot += decode[1] * hc[1]; \ - tot += decode[2] * hc[2]; + tot += decode[2] * hc[2]; #define stbir__store_output_tiny() \ output[0] = tot; \ @@ -4544,16 +4723,16 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float tot0 = decode[0] * hc[0]; \ tot1 = decode[1] * hc[1]; \ tot2 = decode[2] * hc[2]; \ - tot3 = decode[3] * hc[3]; + tot3 = decode[3] * hc[3]; #define stbir__4_coeff_continue_from_4( ofs ) \ tot0 += decode[0+(ofs)] * hc[0+(ofs)]; \ tot1 += decode[1+(ofs)] * hc[1+(ofs)]; \ tot2 += decode[2+(ofs)] * hc[2+(ofs)]; \ - tot3 += decode[3+(ofs)] * hc[3+(ofs)]; + tot3 += decode[3+(ofs)] * hc[3+(ofs)]; #define stbir__1_coeff_remnant( ofs ) \ - tot0 += decode[0+(ofs)] * hc[0+(ofs)]; + tot0 += decode[0+(ofs)] * hc[0+(ofs)]; #define stbir__2_coeff_remnant( ofs ) \ tot0 += decode[0+(ofs)] * hc[0+(ofs)]; \ @@ -4562,7 +4741,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float #define stbir__3_coeff_remnant( ofs ) \ tot0 += decode[0+(ofs)] * hc[0+(ofs)]; \ tot1 += decode[1+(ofs)] * hc[1+(ofs)]; \ - tot2 += decode[2+(ofs)] * hc[2+(ofs)]; + tot2 += decode[2+(ofs)] * hc[2+(ofs)]; #define stbir__store_output() \ output[0] = (tot0+tot2)+(tot1+tot3); \ @@ -4570,7 +4749,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float ++horizontal_contributors; \ output += 1; -#endif +#endif #define STBIR__horizontal_channels 1 #define STB_IMAGE_RESIZE_DO_HORIZONTALS @@ -4588,14 +4767,14 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_load1z( c, hc ); \ stbir__simdf_0123to0011( c, c ); \ stbir__simdf_load2( d, decode ); \ - stbir__simdf_mult( tot, d, c ); + stbir__simdf_mult( tot, d, c ); #define stbir__2_coeff_only() \ stbir__simdf tot,c; \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load2( c, hc ); \ stbir__simdf_0123to0011( c, c ); \ - stbir__simdf_mult_mem( tot, c, decode ); + stbir__simdf_mult_mem( tot, c, decode ); #define stbir__3_coeff_only() \ stbir__simdf tot,c,cs,d; \ @@ -4605,7 +4784,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_mult_mem( tot, c, decode ); \ stbir__simdf_0123to2222( c, cs ); \ stbir__simdf_load2z( d, decode+4 ); \ - stbir__simdf_madd( tot, tot, d, c ); + stbir__simdf_madd( tot, tot, d, c ); #define stbir__store_output_tiny() \ stbir__simdf_0123to2301( c, tot ); \ @@ -4628,7 +4807,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf8_load4b( cs, hc + (ofs) ); \ stbir__simdf8_0123to00112233( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*2 ); + stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*2 ); #define stbir__1_coeff_remnant( ofs ) \ { stbir__simdf t; \ @@ -4649,13 +4828,13 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf8_load4b( cs, hc + (ofs) ); \ stbir__simdf8_0123to00112233( c, cs ); \ stbir__simdf8_load6z( d, decode+(ofs)*2 ); \ - stbir__simdf8_madd( tot0, tot0, c, d ); } + stbir__simdf8_madd( tot0, tot0, c, d ); } #define stbir__store_output() \ - { stbir__simdf t,c; \ + { stbir__simdf t,d; \ stbir__simdf8_add4halves( t, stbir__if_simdf8_cast_to_simdf4(tot0), tot0 ); \ - stbir__simdf_0123to2301( c, t ); \ - stbir__simdf_add( t, t, c ); \ + stbir__simdf_0123to2301( d, t ); \ + stbir__simdf_add( t, t, d ); \ stbir__simdf_store2( output, t ); \ horizontal_coefficients += coefficient_width; \ ++horizontal_contributors; \ @@ -4670,7 +4849,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to0011( c, cs ); \ stbir__simdf_mult_mem( tot0, c, decode ); \ stbir__simdf_0123to2233( c, cs ); \ - stbir__simdf_mult_mem( tot1, c, decode+4 ); + stbir__simdf_mult_mem( tot1, c, decode+4 ); #define stbir__4_coeff_continue_from_4( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -4678,7 +4857,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to0011( c, cs ); \ stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*2 ); \ stbir__simdf_0123to2233( c, cs ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*2+4 ); + stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*2+4 ); #define stbir__1_coeff_remnant( ofs ) \ { stbir__simdf d; \ @@ -4690,7 +4869,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float #define stbir__2_coeff_remnant( ofs ) \ stbir__simdf_load2( cs, hc + (ofs) ); \ stbir__simdf_0123to0011( c, cs ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*2 ); + stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*2 ); #define stbir__3_coeff_remnant( ofs ) \ { stbir__simdf d; \ @@ -4699,7 +4878,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*2 ); \ stbir__simdf_0123to2222( c, cs ); \ stbir__simdf_load2z( d, decode + (ofs) * 2 + 4 ); \ - stbir__simdf_madd( tot1, tot1, d, c ); } + stbir__simdf_madd( tot1, tot1, d, c ); } #define stbir__store_output() \ stbir__simdf_add( tot0, tot0, tot1 ); \ @@ -4718,7 +4897,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float float tota,totb,c; \ c = hc[0]; \ tota = decode[0]*c; \ - totb = decode[1]*c; + totb = decode[1]*c; #define stbir__2_coeff_only() \ float tota,totb,c; \ @@ -4727,7 +4906,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float totb = decode[1]*c; \ c = hc[1]; \ tota += decode[2]*c; \ - totb += decode[3]*c; + totb += decode[3]*c; // this weird order of add matches the simd #define stbir__3_coeff_only() \ @@ -4740,7 +4919,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float totb += decode[5]*c; \ c = hc[1]; \ tota += decode[2]*c; \ - totb += decode[3]*c; + totb += decode[3]*c; #define stbir__store_output_tiny() \ output[0] = tota; \ @@ -4762,7 +4941,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float totb2 = decode[5]*c; \ c = hc[3]; \ tota3 = decode[6]*c; \ - totb3 = decode[7]*c; + totb3 = decode[7]*c; #define stbir__4_coeff_continue_from_4( ofs ) \ c = hc[0+(ofs)]; \ @@ -4776,12 +4955,12 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float totb2 += decode[5+(ofs)*2]*c; \ c = hc[3+(ofs)]; \ tota3 += decode[6+(ofs)*2]*c; \ - totb3 += decode[7+(ofs)*2]*c; + totb3 += decode[7+(ofs)*2]*c; #define stbir__1_coeff_remnant( ofs ) \ c = hc[0+(ofs)]; \ tota0 += decode[0+(ofs)*2] * c; \ - totb0 += decode[1+(ofs)*2] * c; + totb0 += decode[1+(ofs)*2] * c; #define stbir__2_coeff_remnant( ofs ) \ c = hc[0+(ofs)]; \ @@ -4789,7 +4968,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float totb0 += decode[1+(ofs)*2] * c; \ c = hc[1+(ofs)]; \ tota1 += decode[2+(ofs)*2] * c; \ - totb1 += decode[3+(ofs)*2] * c; + totb1 += decode[3+(ofs)*2] * c; #define stbir__3_coeff_remnant( ofs ) \ c = hc[0+(ofs)]; \ @@ -4800,7 +4979,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float totb1 += decode[3+(ofs)*2] * c; \ c = hc[2+(ofs)]; \ tota2 += decode[4+(ofs)*2] * c; \ - totb2 += decode[5+(ofs)*2] * c; + totb2 += decode[5+(ofs)*2] * c; #define stbir__store_output() \ output[0] = (tota0+tota2)+(tota1+tota3); \ @@ -4809,7 +4988,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float ++horizontal_contributors; \ output += 2; -#endif +#endif #define STBIR__horizontal_channels 2 #define STB_IMAGE_RESIZE_DO_HORIZONTALS @@ -4827,7 +5006,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_load1z( c, hc ); \ stbir__simdf_0123to0001( c, c ); \ stbir__simdf_load( d, decode ); \ - stbir__simdf_mult( tot, d, c ); + stbir__simdf_mult( tot, d, c ); #define stbir__2_coeff_only() \ stbir__simdf tot,c,cs,d; \ @@ -4838,7 +5017,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_mult( tot, d, c ); \ stbir__simdf_0123to1111( c, cs ); \ stbir__simdf_load( d, decode+3 ); \ - stbir__simdf_madd( tot, tot, d, c ); + stbir__simdf_madd( tot, tot, d, c ); #define stbir__3_coeff_only() \ stbir__simdf tot,c,d,cs; \ @@ -4852,7 +5031,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_madd( tot, tot, d, c ); \ stbir__simdf_0123to2222( c, cs ); \ stbir__simdf_load( d, decode+6 ); \ - stbir__simdf_madd( tot, tot, d, c ); + stbir__simdf_madd( tot, tot, d, c ); #define stbir__store_output_tiny() \ stbir__simdf_store2( output, tot ); \ @@ -4872,7 +5051,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf8_0123to00001111( c, cs ); \ stbir__simdf8_mult_mem( tot0, c, decode - 1 ); \ stbir__simdf8_0123to22223333( c, cs ); \ - stbir__simdf8_mult_mem( tot1, c, decode+6 - 1 ); + stbir__simdf8_mult_mem( tot1, c, decode+6 - 1 ); #define stbir__4_coeff_continue_from_4( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -4880,26 +5059,26 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf8_0123to00001111( c, cs ); \ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*3 - 1 ); \ stbir__simdf8_0123to22223333( c, cs ); \ - stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*3 + 6 - 1 ); + stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*3 + 6 - 1 ); #define stbir__1_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load1rep4( t, hc + (ofs) ); \ - stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*3 - 1 ); + stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*3 - 1 ); #define stbir__2_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf8_load4b( cs, hc + (ofs) - 2 ); \ stbir__simdf8_0123to22223333( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*3 - 1 ); - + stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*3 - 1 ); + #define stbir__3_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf8_load4b( cs, hc + (ofs) ); \ stbir__simdf8_0123to00001111( c, cs ); \ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*3 - 1 ); \ stbir__simdf8_0123to2222( t, cs ); \ - stbir__simdf8_madd_mem4( tot1, tot1, t, decode+(ofs)*3 + 6 - 1 ); + stbir__simdf8_madd_mem4( tot1, tot1, t, decode+(ofs)*3 + 6 - 1 ); #define stbir__store_output() \ stbir__simdf8_add( tot0, tot0, tot1 ); \ @@ -4930,7 +5109,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to1122( c, cs ); \ stbir__simdf_mult_mem( tot1, c, decode+4 ); \ stbir__simdf_0123to2333( c, cs ); \ - stbir__simdf_mult_mem( tot2, c, decode+8 ); + stbir__simdf_mult_mem( tot2, c, decode+8 ); #define stbir__4_coeff_continue_from_4( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -4940,13 +5119,13 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to1122( c, cs ); \ stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*3+4 ); \ stbir__simdf_0123to2333( c, cs ); \ - stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*3+8 ); + stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*3+8 ); #define stbir__1_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load1z( c, hc + (ofs) ); \ stbir__simdf_0123to0001( c, c ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 ); + stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 ); #define stbir__2_coeff_remnant( ofs ) \ { stbir__simdf d; \ @@ -4956,7 +5135,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 ); \ stbir__simdf_0123to1122( c, cs ); \ stbir__simdf_load2z( d, decode+(ofs)*3+4 ); \ - stbir__simdf_madd( tot1, tot1, c, d ); } + stbir__simdf_madd( tot1, tot1, c, d ); } #define stbir__3_coeff_remnant( ofs ) \ { stbir__simdf d; \ @@ -4968,7 +5147,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*3+4 ); \ stbir__simdf_0123to2222( c, cs ); \ stbir__simdf_load1z( d, decode+(ofs)*3+8 ); \ - stbir__simdf_madd( tot2, tot2, c, d ); } + stbir__simdf_madd( tot2, tot2, c, d ); } #define stbir__store_output() \ stbir__simdf_0123ABCDto3ABx( c, tot0, tot1 ); \ @@ -4999,7 +5178,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float c = hc[0]; \ tot0 = decode[0]*c; \ tot1 = decode[1]*c; \ - tot2 = decode[2]*c; + tot2 = decode[2]*c; #define stbir__2_coeff_only() \ float tot0, tot1, tot2, c; \ @@ -5010,7 +5189,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float c = hc[1]; \ tot0 += decode[3]*c; \ tot1 += decode[4]*c; \ - tot2 += decode[5]*c; + tot2 += decode[5]*c; #define stbir__3_coeff_only() \ float tot0, tot1, tot2, c; \ @@ -5025,7 +5204,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float c = hc[2]; \ tot0 += decode[6]*c; \ tot1 += decode[7]*c; \ - tot2 += decode[8]*c; + tot2 += decode[8]*c; #define stbir__store_output_tiny() \ output[0] = tot0; \ @@ -5052,7 +5231,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float c = hc[3]; \ totd0 = decode[9]*c; \ totd1 = decode[10]*c; \ - totd2 = decode[11]*c; + totd2 = decode[11]*c; #define stbir__4_coeff_continue_from_4( ofs ) \ c = hc[0+(ofs)]; \ @@ -5070,7 +5249,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float c = hc[3+(ofs)]; \ totd0 += decode[9+(ofs)*3]*c; \ totd1 += decode[10+(ofs)*3]*c; \ - totd2 += decode[11+(ofs)*3]*c; + totd2 += decode[11+(ofs)*3]*c; #define stbir__1_coeff_remnant( ofs ) \ c = hc[0+(ofs)]; \ @@ -5100,7 +5279,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float c = hc[2+(ofs)]; \ totc0 += decode[6+(ofs)*3]*c; \ totc1 += decode[7+(ofs)*3]*c; \ - totc2 += decode[8+(ofs)*3]*c; + totc2 += decode[8+(ofs)*3]*c; #define stbir__store_output() \ output[0] = (tota0+totc0)+(totb0+totd0); \ @@ -5110,7 +5289,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float ++horizontal_contributors; \ output += 3; -#endif +#endif #define STBIR__horizontal_channels 3 #define STB_IMAGE_RESIZE_DO_HORIZONTALS @@ -5126,7 +5305,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load1( c, hc ); \ stbir__simdf_0123to0000( c, c ); \ - stbir__simdf_mult_mem( tot, c, decode ); + stbir__simdf_mult_mem( tot, c, decode ); #define stbir__2_coeff_only() \ stbir__simdf tot,c,cs; \ @@ -5135,7 +5314,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to0000( c, cs ); \ stbir__simdf_mult_mem( tot, c, decode ); \ stbir__simdf_0123to1111( c, cs ); \ - stbir__simdf_madd_mem( tot, tot, c, decode+4 ); + stbir__simdf_madd_mem( tot, tot, c, decode+4 ); #define stbir__3_coeff_only() \ stbir__simdf tot,c,cs; \ @@ -5146,7 +5325,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to1111( c, cs ); \ stbir__simdf_madd_mem( tot, tot, c, decode+4 ); \ stbir__simdf_0123to2222( c, cs ); \ - stbir__simdf_madd_mem( tot, tot, c, decode+8 ); + stbir__simdf_madd_mem( tot, tot, c, decode+8 ); #define stbir__store_output_tiny() \ stbir__simdf_store( output, tot ); \ @@ -5163,7 +5342,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf8_0123to00001111( c, cs ); \ stbir__simdf8_mult_mem( tot0, c, decode ); \ stbir__simdf8_0123to22223333( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+8 ); + stbir__simdf8_madd_mem( tot0, tot0, c, decode+8 ); #define stbir__4_coeff_continue_from_4( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5171,26 +5350,26 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf8_0123to00001111( c, cs ); \ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); \ stbir__simdf8_0123to22223333( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4+8 ); + stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4+8 ); #define stbir__1_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load1rep4( t, hc + (ofs) ); \ - stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*4 ); + stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*4 ); #define stbir__2_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf8_load4b( cs, hc + (ofs) - 2 ); \ stbir__simdf8_0123to22223333( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); - + stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); + #define stbir__3_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf8_load4b( cs, hc + (ofs) ); \ stbir__simdf8_0123to00001111( c, cs ); \ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); \ stbir__simdf8_0123to2222( t, cs ); \ - stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*4+8 ); + stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*4+8 ); #define stbir__store_output() \ stbir__simdf8_add4halves( t, stbir__if_simdf8_cast_to_simdf4(tot0), tot0 ); \ @@ -5199,7 +5378,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float ++horizontal_contributors; \ output += 4; -#else +#else #define stbir__4_coeff_start() \ stbir__simdf tot0,tot1,c,cs; \ @@ -5212,7 +5391,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to2222( c, cs ); \ stbir__simdf_madd_mem( tot0, tot0, c, decode+8 ); \ stbir__simdf_0123to3333( c, cs ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+12 ); + stbir__simdf_madd_mem( tot1, tot1, c, decode+12 ); #define stbir__4_coeff_continue_from_4( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5224,13 +5403,13 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to2222( c, cs ); \ stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4+8 ); \ stbir__simdf_0123to3333( c, cs ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+12 ); + stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+12 ); #define stbir__1_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load1( c, hc + (ofs) ); \ stbir__simdf_0123to0000( c, c ); \ - stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); + stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); #define stbir__2_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5238,8 +5417,8 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_0123to0000( c, cs ); \ stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); \ stbir__simdf_0123to1111( c, cs ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+4 ); - + stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+4 ); + #define stbir__3_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load( cs, hc + (ofs) ); \ @@ -5365,7 +5544,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float x0 += decode[0+(ofs)*4] * c; \ x1 += decode[1+(ofs)*4] * c; \ x2 += decode[2+(ofs)*4] * c; \ - x3 += decode[3+(ofs)*4] * c; + x3 += decode[3+(ofs)*4] * c; #define stbir__2_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5378,8 +5557,8 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float y0 += decode[4+(ofs)*4] * c; \ y1 += decode[5+(ofs)*4] * c; \ y2 += decode[6+(ofs)*4] * c; \ - y3 += decode[7+(ofs)*4] * c; - + y3 += decode[7+(ofs)*4] * c; + #define stbir__3_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ c = hc[0+(ofs)]; \ @@ -5396,7 +5575,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float x0 += decode[8+(ofs)*4] * c; \ x1 += decode[9+(ofs)*4] * c; \ x2 += decode[10+(ofs)*4] * c; \ - x3 += decode[11+(ofs)*4] * c; + x3 += decode[11+(ofs)*4] * c; #define stbir__store_output() \ output[0] = x0 + y0; \ @@ -5407,7 +5586,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float ++horizontal_contributors; \ output += 4; -#endif +#endif #define STBIR__horizontal_channels 4 #define STB_IMAGE_RESIZE_DO_HORIZONTALS @@ -5426,7 +5605,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_load1( c, hc ); \ stbir__simdf_0123to0000( c, c ); \ stbir__simdf_mult_mem( tot0, c, decode ); \ - stbir__simdf_mult_mem( tot1, c, decode+3 ); + stbir__simdf_mult_mem( tot1, c, decode+3 ); #define stbir__2_coeff_only() \ stbir__simdf tot0,tot1,c,cs; \ @@ -5437,7 +5616,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_mult_mem( tot1, c, decode+3 ); \ stbir__simdf_0123to1111( c, cs ); \ stbir__simdf_madd_mem( tot0, tot0, c, decode+7 ); \ - stbir__simdf_madd_mem( tot1, tot1, c,decode+10 ); + stbir__simdf_madd_mem( tot1, tot1, c,decode+10 ); #define stbir__3_coeff_only() \ stbir__simdf tot0,tot1,c,cs; \ @@ -5451,7 +5630,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_madd_mem( tot1, tot1, c, decode+10 ); \ stbir__simdf_0123to2222( c, cs ); \ stbir__simdf_madd_mem( tot0, tot0, c, decode+14 ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+17 ); + stbir__simdf_madd_mem( tot1, tot1, c, decode+17 ); #define stbir__store_output_tiny() \ stbir__simdf_store( output+3, tot1 ); \ @@ -5473,7 +5652,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf8_0123to22222222( c, cs ); \ stbir__simdf8_madd_mem( tot0, tot0, c, decode+14 ); \ stbir__simdf8_0123to33333333( c, cs ); \ - stbir__simdf8_madd_mem( tot1, tot1, c, decode+21 ); + stbir__simdf8_madd_mem( tot1, tot1, c, decode+21 ); #define stbir__4_coeff_continue_from_4( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5485,19 +5664,19 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf8_0123to22222222( c, cs ); \ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 ); \ stbir__simdf8_0123to33333333( c, cs ); \ - stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+21 ); + stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+21 ); #define stbir__1_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf8_load1b( c, hc + (ofs) ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); + stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); #define stbir__2_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf8_load1b( c, hc + (ofs) ); \ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \ stbir__simdf8_load1b( c, hc + (ofs)+1 ); \ - stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+7 ); + stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+7 ); #define stbir__3_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5507,7 +5686,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf8_0123to11111111( c, cs ); \ stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+7 ); \ stbir__simdf8_0123to22222222( c, cs ); \ - stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 ); + stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 ); #define stbir__store_output() \ stbir__simdf8_add( tot0, tot0, tot1 ); \ @@ -5540,7 +5719,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_madd_mem( tot1, tot1, c, decode+17 ); \ stbir__simdf_0123to3333( c, cs ); \ stbir__simdf_madd_mem( tot2, tot2, c, decode+21 ); \ - stbir__simdf_madd_mem( tot3, tot3, c, decode+24 ); + stbir__simdf_madd_mem( tot3, tot3, c, decode+24 ); #define stbir__4_coeff_continue_from_4( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5556,7 +5735,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+17 ); \ stbir__simdf_0123to3333( c, cs ); \ stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*7+21 ); \ - stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+24 ); + stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+24 ); #define stbir__1_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5573,8 +5752,8 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+3 ); \ stbir__simdf_0123to1111( c, cs ); \ stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*7+7 ); \ - stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+10 ); - + stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+10 ); + #define stbir__3_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ stbir__simdf_load( cs, hc + (ofs) ); \ @@ -5586,7 +5765,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+10 ); \ stbir__simdf_0123to2222( c, cs ); \ stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 ); \ - stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+17 ); + stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+17 ); #define stbir__store_output() \ stbir__simdf_add( tot0, tot0, tot2 ); \ @@ -5610,7 +5789,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float tot3 = decode[3]*c; \ tot4 = decode[4]*c; \ tot5 = decode[5]*c; \ - tot6 = decode[6]*c; + tot6 = decode[6]*c; #define stbir__2_coeff_only() \ float tot0, tot1, tot2, tot3, tot4, tot5, tot6, c; \ @@ -5704,7 +5883,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float y3 += decode[24] * c; \ y4 += decode[25] * c; \ y5 += decode[26] * c; \ - y6 += decode[27] * c; + y6 += decode[27] * c; #define stbir__4_coeff_continue_from_4( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5739,7 +5918,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float y3 += decode[24+(ofs)*7] * c; \ y4 += decode[25+(ofs)*7] * c; \ y5 += decode[26+(ofs)*7] * c; \ - y6 += decode[27+(ofs)*7] * c; + y6 += decode[27+(ofs)*7] * c; #define stbir__1_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ @@ -5770,7 +5949,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float y4 += decode[11+(ofs)*7] * c; \ y5 += decode[12+(ofs)*7] * c; \ y6 += decode[13+(ofs)*7] * c; \ - + #define stbir__3_coeff_remnant( ofs ) \ STBIR_SIMD_NO_UNROLL(decode); \ c = hc[0+(ofs)]; \ @@ -5810,7 +5989,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float ++horizontal_contributors; \ output += 7; -#endif +#endif #define STBIR__horizontal_channels 7 #define STB_IMAGE_RESIZE_DO_HORIZONTALS @@ -5937,7 +6116,7 @@ static void stbir__encode_scanline( stbir__info const * stbir_info, void *output // if we have an output callback, we first convert the decode buffer in place (and then hand that to the callback) if ( stbir_info->out_pixels_cb ) output_buffer = encode_buffer; - + STBIR_PROFILE_START( encode ); // convert into the output buffer stbir_info->encode_pixels( output_buffer, width_times_channels, encode_buffer ); @@ -5945,7 +6124,7 @@ static void stbir__encode_scanline( stbir__info const * stbir_info, void *output // if we have an output callback, call it to send the data if ( stbir_info->out_pixels_cb ) - stbir_info->out_pixels_cb( output_buffer_data, num_pixels, row, stbir_info->user_data ); + stbir_info->out_pixels_cb( output_buffer, num_pixels, row, stbir_info->user_data ); } @@ -6015,7 +6194,7 @@ static void stbir__resample_vertical_gather(stbir__info const * stbir_info, stbi stbir__resample_horizontal_gather(stbir_info, encode_buffer, decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); } - stbir__encode_scanline( stbir_info, ( (char *) stbir_info->output_data ) + ((ptrdiff_t)n * (ptrdiff_t)stbir_info->output_stride_bytes), + stbir__encode_scanline( stbir_info, ( (char *) stbir_info->output_data ) + ((size_t)n * (size_t)stbir_info->output_stride_bytes), encode_buffer, n STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); } @@ -6030,7 +6209,7 @@ static void stbir__decode_and_resample_for_vertical_gather_loop(stbir__info cons // update new end scanline split_info->ring_buffer_last_scanline = n; - // get ring buffer + // get ring buffer ring_buffer_index = (split_info->ring_buffer_begin_index + (split_info->ring_buffer_last_scanline - split_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries; ring_buffer = stbir__get_ring_buffer_entry(stbir_info, split_info, ring_buffer_index); @@ -6056,7 +6235,7 @@ static void stbir__vertical_gather_loop( stbir__info const * stbir_info, stbir__ // initialize the ring buffer for gathering split_info->ring_buffer_begin_index = 0; - split_info->ring_buffer_first_scanline = stbir_info->vertical.extent_info.lowest; + split_info->ring_buffer_first_scanline = vertical_contributors->n0; split_info->ring_buffer_last_scanline = split_info->ring_buffer_first_scanline - 1; // means "empty" for (y = start_output_y; y < end_output_y; y++) @@ -6080,12 +6259,12 @@ static void stbir__vertical_gather_loop( stbir__info const * stbir_info, stbir__ split_info->ring_buffer_first_scanline++; split_info->ring_buffer_begin_index++; } - + if ( stbir_info->vertical_first ) { float * ring_buffer = stbir__get_ring_buffer_scanline( stbir_info, split_info, ++split_info->ring_buffer_last_scanline ); // Decode the nth scanline from the source image into the decode buffer. - stbir__decode_scanline( stbir_info, split_info->ring_buffer_last_scanline, ring_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); + stbir__decode_scanline( stbir_info, split_info->ring_buffer_last_scanline, ring_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); } else { @@ -6108,10 +6287,10 @@ static void stbir__encode_first_scanline_from_scatter(stbir__info const * stbir_ { // evict a scanline out into the output buffer float* ring_buffer_entry = stbir__get_ring_buffer_entry(stbir_info, split_info, split_info->ring_buffer_begin_index ); - + // dump the scanline out - stbir__encode_scanline( stbir_info, ( (char *)stbir_info->output_data ) + ( (ptrdiff_t)split_info->ring_buffer_first_scanline * (ptrdiff_t)stbir_info->output_stride_bytes ), ring_buffer_entry, split_info->ring_buffer_first_scanline STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); - + stbir__encode_scanline( stbir_info, ( (char *)stbir_info->output_data ) + ( (size_t)split_info->ring_buffer_first_scanline * (size_t)stbir_info->output_stride_bytes ), ring_buffer_entry, split_info->ring_buffer_first_scanline STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); + // mark it as empty ring_buffer_entry[ 0 ] = STBIR__FLOAT_EMPTY_MARKER; @@ -6129,10 +6308,10 @@ static void stbir__horizontal_resample_and_encode_first_scanline_from_scatter(st // Now resample it into the buffer. stbir__resample_horizontal_gather( stbir_info, split_info->vertical_buffer, ring_buffer_entry STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); - + // dump the scanline out - stbir__encode_scanline( stbir_info, ( (char *)stbir_info->output_data ) + ( (ptrdiff_t)split_info->ring_buffer_first_scanline * (ptrdiff_t)stbir_info->output_stride_bytes ), split_info->vertical_buffer, split_info->ring_buffer_first_scanline STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); - + stbir__encode_scanline( stbir_info, ( (char *)stbir_info->output_data ) + ( (size_t)split_info->ring_buffer_first_scanline * (size_t)stbir_info->output_stride_bytes ), split_info->vertical_buffer, split_info->ring_buffer_first_scanline STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); + // mark it as empty ring_buffer_entry[ 0 ] = STBIR__FLOAT_EMPTY_MARKER; @@ -6172,7 +6351,7 @@ static void stbir__resample_vertical_scatter(stbir__info const * stbir_info, stb STBIR_PROFILE_END( vertical ); } -typedef void stbir__handle_scanline_for_scatter_func(stbir__info const * stbir_info, stbir__per_split_info* split_info); +typedef void stbir__handle_scanline_for_scatter_func(stbir__info const * stbir_info, stbir__per_split_info* split_info); static void stbir__vertical_scatter_loop( stbir__info const * stbir_info, stbir__per_split_info* split_info, int split_count ) { @@ -6193,7 +6372,7 @@ static void stbir__vertical_scatter_loop( stbir__info const * stbir_info, stbir_ end_input_y = split_info[split_count-1].end_input_y; // adjust for starting offset start_input_y - y = start_input_y + stbir_info->vertical.filter_pixel_margin; + y = start_input_y + stbir_info->vertical.filter_pixel_margin; vertical_contributors += y ; vertical_coefficients += stbir_info->vertical.coefficient_width * y; @@ -6240,7 +6419,7 @@ static void stbir__vertical_scatter_loop( stbir__info const * stbir_info, stbir_ split_info->start_input_y = y; on_first_input_y = 0; - // clip the region + // clip the region if ( out_first_scanline < start_output_y ) { vc += start_output_y - out_first_scanline; @@ -6253,11 +6432,11 @@ static void stbir__vertical_scatter_loop( stbir__info const * stbir_info, stbir_ // if very first scanline, init the index if (split_info->ring_buffer_begin_index < 0) split_info->ring_buffer_begin_index = out_first_scanline - start_output_y; - + STBIR_ASSERT( split_info->ring_buffer_begin_index <= out_first_scanline ); // Decode the nth scanline from the source image into the decode buffer. - stbir__decode_scanline( stbir_info, y, split_info->decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); + stbir__decode_scanline( stbir_info, y, split_info->decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO ); // When horizontal first, we resample horizontally into the vertical buffer before we scatter it out if ( !stbir_info->vertical_first ) @@ -6269,7 +6448,7 @@ static void stbir__vertical_scatter_loop( stbir__info const * stbir_info, stbir_ if ( ( ( split_info->ring_buffer_last_scanline - split_info->ring_buffer_first_scanline + 1 ) == stbir_info->ring_buffer_num_entries ) && ( out_last_scanline > split_info->ring_buffer_last_scanline ) ) handle_scanline_for_scatter( stbir_info, split_info ); - + // Now the horizontal buffer is ready to write to all ring buffer rows, so do it. stbir__resample_vertical_scatter(stbir_info, split_info, out_first_scanline, out_last_scanline, vc, (float*)scanline_scatter_buffer, (float*)scanline_scatter_buffer_end ); @@ -6305,7 +6484,7 @@ static void stbir__set_sampler(stbir__sampler * samp, stbir_filter filter, stbir if (scale_info->scale >= ( 1.0f - stbir__small_float ) ) { if ( (scale_info->scale <= ( 1.0f + stbir__small_float ) ) && ( STBIR_CEILF(scale_info->pixel_shift) == scale_info->pixel_shift ) ) - filter = STBIR_FILTER_POINT_SAMPLE; + filter = STBIR_FILTER_POINT_SAMPLE; else filter = STBIR_DEFAULT_FILTER_UPSAMPLE; } @@ -6313,7 +6492,7 @@ static void stbir__set_sampler(stbir__sampler * samp, stbir_filter filter, stbir samp->filter_enum = filter; STBIR_ASSERT(samp->filter_enum != 0); - STBIR_ASSERT((unsigned)samp->filter_enum < STBIR_FILTER_OTHER); + STBIR_ASSERT((unsigned)samp->filter_enum < STBIR_FILTER_OTHER); samp->filter_kernel = stbir__builtin_kernels[ filter ]; samp->filter_support = stbir__builtin_supports[ filter ]; @@ -6339,15 +6518,31 @@ static void stbir__set_sampler(stbir__sampler * samp, stbir_filter filter, stbir // pre calculate stuff based on the above samp->coefficient_width = stbir__get_coefficient_width(samp, samp->is_gather, user_data); + // filter_pixel_width is the conservative size in pixels of input that affect an output pixel. + // In rare cases (only with 2 pix to 1 pix with the default filters), it's possible that the + // filter will extend before or after the scanline beyond just one extra entire copy of the + // scanline (we would hit the edge twice). We don't let you do that, so we clamp the total + // width to 3x the total of input pixel (once for the scanline, once for the left side + // overhang, and once for the right side). We only do this for edge mode, since the other + // modes can just re-edge clamp back in again. if ( edge == STBIR_EDGE_WRAP ) - if ( samp->filter_pixel_width > ( scale_info->input_full_size * 2 ) ) // this can only happen when shrinking to a single pixel - samp->filter_pixel_width = scale_info->input_full_size * 2; + if ( samp->filter_pixel_width > ( scale_info->input_full_size * 3 ) ) + samp->filter_pixel_width = scale_info->input_full_size * 3; // This is how much to expand buffers to account for filters seeking outside // the image boundaries. samp->filter_pixel_margin = samp->filter_pixel_width / 2; + + // filter_pixel_margin is the amount that this filter can overhang on just one side of either + // end of the scanline (left or the right). Since we only allow you to overhang 1 scanline's + // worth of pixels, we clamp this one side of overhang to the input scanline size. Again, + // this clamping only happens in rare cases with the default filters (2 pix to 1 pix). + if ( edge == STBIR_EDGE_WRAP ) + if ( samp->filter_pixel_margin > scale_info->input_full_size ) + samp->filter_pixel_margin = scale_info->input_full_size; samp->num_contributors = stbir__get_contributors(samp, samp->is_gather); + samp->contributors_size = samp->num_contributors * sizeof(stbir__contributors); samp->coefficients_size = samp->num_contributors * samp->coefficient_width * sizeof(float) + sizeof(float); // extra sizeof(float) is padding @@ -6397,8 +6592,8 @@ static void stbir__get_conservative_extents( stbir__sampler * samp, stbir__contr range->n0 = in_first_pixel; stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, (float)output_sub_size, 0, inv_scale, out_shift, input_full_size, edge ); range->n1 = in_last_pixel; - - // now go through the margin to the start of area to find bottom + + // now go through the margin to the start of area to find bottom n = range->n0 + 1; input_end = -filter_pixel_margin; while( n >= input_end ) @@ -6413,7 +6608,7 @@ static void stbir__get_conservative_extents( stbir__sampler * samp, stbir__contr --n; } - // now go through the end of the area through the margin to find top + // now go through the end of the area through the margin to find top n = range->n1 - 1; input_end = n + 1 + filter_pixel_margin; while( n <= input_end ) @@ -6462,7 +6657,7 @@ static void stbir__get_split_info( stbir__per_split_info* split_info, int splits cur = 0; for( i = 0 ; i < splits ; i++ ) { - int each; + int each; split_info[i].start_output_y = cur; each = left / ( splits - i ); split_info[i].end_output_y = cur + each; @@ -6478,7 +6673,7 @@ static void stbir__get_split_info( stbir__per_split_info* split_info, int splits static void stbir__free_internal_mem( stbir__info *info ) { #define STBIR__FREE_AND_CLEAR( ptr ) { if ( ptr ) { void * p = (ptr); (ptr) = 0; STBIR_FREE( p, info->user_data); } } - + if ( info ) { #ifndef STBIR__SEPARATE_ALLOCATIONS @@ -6496,16 +6691,16 @@ static void stbir__free_internal_mem( stbir__info *info ) for( j = 0 ; j < info->alloc_ring_buffer_num_entries ; j++ ) { #ifdef STBIR_SIMD8 - if ( info->effective_channels == 3 ) + if ( info->effective_channels == 3 ) --info->split_info[i].ring_buffers[j]; // avx in 3 channel mode needs one float at the start of the buffer - #endif + #endif STBIR__FREE_AND_CLEAR( info->split_info[i].ring_buffers[j] ); } #ifdef STBIR_SIMD8 - if ( info->effective_channels == 3 ) + if ( info->effective_channels == 3 ) --info->split_info[i].decode_buffer; // avx in 3 channel mode needs one float at the start of the buffer - #endif + #endif STBIR__FREE_AND_CLEAR( info->split_info[i].decode_buffer ); STBIR__FREE_AND_CLEAR( info->split_info[i].ring_buffers ); STBIR__FREE_AND_CLEAR( info->split_info[i].vertical_buffer ); @@ -6522,7 +6717,7 @@ static void stbir__free_internal_mem( stbir__info *info ) STBIR__FREE_AND_CLEAR( info ); #endif } - + #undef STBIR__FREE_AND_CLEAR } @@ -6534,20 +6729,20 @@ static int stbir__get_max_split( int splits, int height ) for( i = 0 ; i < splits ; i++ ) { int each = height / ( splits - i ); - if ( each > max ) + if ( each > max ) max = each; height -= each; } return max; } -static stbir__horizontal_gather_channels_func ** stbir__horizontal_gather_n_coeffs_funcs[8] = -{ +static stbir__horizontal_gather_channels_func ** stbir__horizontal_gather_n_coeffs_funcs[8] = +{ 0, stbir__horizontal_gather_1_channels_with_n_coeffs_funcs, stbir__horizontal_gather_2_channels_with_n_coeffs_funcs, stbir__horizontal_gather_3_channels_with_n_coeffs_funcs, stbir__horizontal_gather_4_channels_with_n_coeffs_funcs, 0,0, stbir__horizontal_gather_7_channels_with_n_coeffs_funcs }; -static stbir__horizontal_gather_channels_func ** stbir__horizontal_gather_channels_funcs[8] = -{ +static stbir__horizontal_gather_channels_func ** stbir__horizontal_gather_channels_funcs[8] = +{ 0, stbir__horizontal_gather_1_channels_funcs, stbir__horizontal_gather_2_channels_funcs, stbir__horizontal_gather_3_channels_funcs, stbir__horizontal_gather_4_channels_funcs, 0,0, stbir__horizontal_gather_7_channels_funcs }; @@ -6622,28 +6817,28 @@ static STBIR__V_FIRST_INFO STBIR__V_FIRST_INFO_BUFFER = {0}; #endif // Figure out whether to scale along the horizontal or vertical first. -// This only *super* important when you are scaling by a massively -// different amount in the vertical vs the horizontal (for example, if -// you are scaling by 2x in the width, and 0.5x in the height, then you -// want to do the vertical scale first, because it's around 3x faster +// This only *super* important when you are scaling by a massively +// different amount in the vertical vs the horizontal (for example, if +// you are scaling by 2x in the width, and 0.5x in the height, then you +// want to do the vertical scale first, because it's around 3x faster // in that order. // -// In more normal circumstances, this makes a 20-40% differences, so +// In more normal circumstances, this makes a 20-40% differences, so // it's good to get right, but not critical. The normal way that you -// decide which direction goes first is just figuring out which -// direction does more multiplies. But with modern CPUs with their +// decide which direction goes first is just figuring out which +// direction does more multiplies. But with modern CPUs with their // fancy caches and SIMD and high IPC abilities, so there's just a lot -// more that goes into it. +// more that goes into it. // -// My handwavy sort of solution is to have an app that does a whole +// My handwavy sort of solution is to have an app that does a whole // bunch of timing for both vertical and horizontal first modes, // and then another app that can read lots of these timing files // and try to search for the best weights to use. Dotimings.c // is the app that does a bunch of timings, and vf_train.c is the -// app that solves for the best weights (and shows how well it +// app that solves for the best weights (and shows how well it // does currently). -static int stbir__should_do_vertical_first( float weights_table[STBIR_RESIZE_CLASSIFICATIONS][4], int horizontal_filter_pixel_width, float horizontal_scale, int horizontal_output_size, int vertical_filter_pixel_width, float vertical_scale, int vertical_output_size, int is_gather, STBIR__V_FIRST_INFO * info ) +static int stbir__should_do_vertical_first( float weights_table[STBIR_RESIZE_CLASSIFICATIONS][4], int horizontal_filter_pixel_width, float horizontal_scale, int horizontal_output_size, int vertical_filter_pixel_width, float vertical_scale, int vertical_output_size, int is_gather, STBIR__V_FIRST_INFO * info ) { double v_cost, h_cost; float * weights; @@ -6655,15 +6850,15 @@ static int stbir__should_do_vertical_first( float weights_table[STBIR_RESIZE_CLA v_classification = ( vertical_output_size < horizontal_output_size ) ? 6 : 7; else if ( vertical_scale <= 1.0f ) v_classification = ( is_gather ) ? 1 : 0; - else if ( vertical_scale <= 2.0f) + else if ( vertical_scale <= 2.0f) v_classification = 2; - else if ( vertical_scale <= 3.0f) + else if ( vertical_scale <= 3.0f) v_classification = 3; - else if ( vertical_scale <= 4.0f) + else if ( vertical_scale <= 4.0f) v_classification = 5; - else + else v_classification = 6; - + // use the right weights weights = weights_table[ v_classification ]; @@ -6684,10 +6879,10 @@ static int stbir__should_do_vertical_first( float weights_table[STBIR_RESIZE_CLA info->is_gather = is_gather; } - // and this allows us to override everything for testing (see dotiming.c) - if ( ( info ) && ( info->control_v_first ) ) + // and this allows us to override everything for testing (see dotiming.c) + if ( ( info ) && ( info->control_v_first ) ) vertical_first = ( info->control_v_first == 2 ) ? 1 : 0; - + return vertical_first; } @@ -6699,9 +6894,9 @@ static unsigned char stbir__pixel_channels[] = { }; // the internal pixel layout enums are in a different order, so we can easily do range comparisons of types -// the public pixel layout is ordered in a way that if you cast num_channels (1-4) to the enum, you get something sensible +// the public pixel layout is ordered in a way that if you cast num_channels (1-4) to the enum, you get something sensible static stbir_internal_pixel_layout stbir__pixel_layout_convert_public_to_internal[] = { - STBIRI_BGR, STBIRI_1CHANNEL, STBIRI_2CHANNEL, STBIRI_RGB, STBIRI_RGBA, + STBIRI_BGR, STBIRI_1CHANNEL, STBIRI_2CHANNEL, STBIRI_RGB, STBIRI_RGBA, STBIRI_4CHANNEL, STBIRI_BGRA, STBIRI_ARGB, STBIRI_ABGR, STBIRI_RA, STBIRI_AR, STBIRI_RGBA_PM, STBIRI_BGRA_PM, STBIRI_ARGB_PM, STBIRI_ABGR_PM, STBIRI_RA_PM, STBIRI_AR_PM, }; @@ -6712,17 +6907,17 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample stbir__info * info = 0; void * alloced = 0; - int alloced_total = 0; + size_t alloced_total = 0; int vertical_first; int decode_buffer_size, ring_buffer_length_bytes, ring_buffer_size, vertical_buffer_size, alloc_ring_buffer_num_entries; int alpha_weighting_type = 0; // 0=none, 1=simple, 2=fancy - int conservative_split_output_size = stbir__get_max_split( splits, vertical->scale_info.output_sub_size ); - stbir_internal_pixel_layout input_pixel_layout = stbir__pixel_layout_convert_public_to_internal[ input_pixel_layout_public ]; + int conservative_split_output_size = stbir__get_max_split( splits, vertical->scale_info.output_sub_size ); + stbir_internal_pixel_layout input_pixel_layout = stbir__pixel_layout_convert_public_to_internal[ input_pixel_layout_public ]; stbir_internal_pixel_layout output_pixel_layout = stbir__pixel_layout_convert_public_to_internal[ output_pixel_layout_public ]; - int channels = stbir__pixel_channels[ input_pixel_layout ]; + int channels = stbir__pixel_channels[ input_pixel_layout ]; int effective_channels = channels; - + // first figure out what type of alpha weighting to use (if any) if ( ( horizontal->filter_enum != STBIR_FILTER_POINT_SAMPLE ) || ( vertical->filter_enum != STBIR_FILTER_POINT_SAMPLE ) ) // no alpha weighting on point sampling { @@ -6760,11 +6955,11 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample // sometimes read one float off in some of the unrolled loops (with a weight of zero coeff, so it doesn't have an effect) decode_buffer_size = ( conservative->n1 - conservative->n0 + 1 ) * effective_channels * sizeof(float) + sizeof(float); // extra float for padding - + #if defined( STBIR__SEPARATE_ALLOCATIONS ) && defined(STBIR_SIMD8) if ( effective_channels == 3 ) decode_buffer_size += sizeof(float); // avx in 3 channel mode needs one float at the start of the buffer (only with separate allocations) -#endif +#endif ring_buffer_length_bytes = horizontal->scale_info.output_sub_size * effective_channels * sizeof(float) + sizeof(float); // extra float for padding @@ -6803,9 +6998,9 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample #define STBIR__NEXT_PTR( ptr, size, ntype ) advance_mem = (void*) ( ( ((size_t)advance_mem) + 15 ) & ~15 ); if ( alloced ) ptr = (ntype*)advance_mem; advance_mem = ((char*)advance_mem) + (size); #endif - STBIR__NEXT_PTR( info, sizeof( stbir__info ), stbir__info ); + STBIR__NEXT_PTR( info, sizeof( stbir__info ), stbir__info ); - STBIR__NEXT_PTR( info->split_info, sizeof( stbir__per_split_info ) * splits, stbir__per_split_info ); + STBIR__NEXT_PTR( info->split_info, sizeof( stbir__per_split_info ) * splits, stbir__per_split_info ); if ( info ) { @@ -6820,39 +7015,39 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample info->channels = channels; info->effective_channels = effective_channels; - + info->offset_x = new_x; info->offset_y = new_y; info->alloc_ring_buffer_num_entries = alloc_ring_buffer_num_entries; - info->ring_buffer_num_entries = 0; + info->ring_buffer_num_entries = 0; info->ring_buffer_length_bytes = ring_buffer_length_bytes; info->splits = splits; info->vertical_first = vertical_first; - info->input_pixel_layout_internal = input_pixel_layout; + info->input_pixel_layout_internal = input_pixel_layout; info->output_pixel_layout_internal = output_pixel_layout; // setup alpha weight functions info->alpha_weight = 0; info->alpha_unweight = 0; - + // handle alpha weighting functions and overrides if ( alpha_weighting_type == 2 ) { // high quality alpha multiplying on the way in, dividing on the way out - info->alpha_weight = fancy_alpha_weights[ input_pixel_layout - STBIRI_RGBA ]; + info->alpha_weight = fancy_alpha_weights[ input_pixel_layout - STBIRI_RGBA ]; info->alpha_unweight = fancy_alpha_unweights[ output_pixel_layout - STBIRI_RGBA ]; } else if ( alpha_weighting_type == 4 ) { // fast alpha multiplying on the way in, dividing on the way out - info->alpha_weight = simple_alpha_weights[ input_pixel_layout - STBIRI_RGBA ]; + info->alpha_weight = simple_alpha_weights[ input_pixel_layout - STBIRI_RGBA ]; info->alpha_unweight = simple_alpha_unweights[ output_pixel_layout - STBIRI_RGBA ]; } else if ( alpha_weighting_type == 1 ) { // fast alpha on the way in, leave in premultiplied form on way out - info->alpha_weight = simple_alpha_weights[ input_pixel_layout - STBIRI_RGBA ]; + info->alpha_weight = simple_alpha_weights[ input_pixel_layout - STBIRI_RGBA ]; } else if ( alpha_weighting_type == 3 ) { @@ -6871,7 +7066,7 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample info->alpha_weight = stbir__simple_flip_3ch; } - } + } // get all the per-split buffers for( i = 0 ; i < splits ; i++ ) @@ -6883,7 +7078,7 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample #ifdef STBIR_SIMD8 if ( ( info ) && ( effective_channels == 3 ) ) ++info->split_info[i].decode_buffer; // avx in 3 channel mode needs one float at the start of the buffer - #endif + #endif STBIR__NEXT_PTR( info->split_info[i].ring_buffers, alloc_ring_buffer_num_entries * sizeof(float*), float* ); { @@ -6894,7 +7089,7 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample #ifdef STBIR_SIMD8 if ( ( info ) && ( effective_channels == 3 ) ) ++info->split_info[i].ring_buffers[j]; // avx in 3 channel mode needs one float at the start of the buffer - #endif + #endif } } #else @@ -6922,10 +7117,10 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample #endif if ( temp_mem_amt >= both ) { - if ( info ) - { - vertical->gather_prescatter_contributors = (stbir__contributors*)info->split_info[0].decode_buffer; - vertical->gather_prescatter_coefficients = (float*) ( ( (char*)info->split_info[0].decode_buffer ) + vertical->gather_prescatter_contributors_size ); + if ( info ) + { + vertical->gather_prescatter_contributors = (stbir__contributors*)info->split_info[0].decode_buffer; + vertical->gather_prescatter_coefficients = (float*) ( ( (char*)info->split_info[0].decode_buffer ) + vertical->gather_prescatter_contributors_size ); } } else @@ -6948,7 +7143,7 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample if ( diff_shift < 0.0f ) diff_shift = -diff_shift; if ( ( diff_scale <= stbir__small_float ) && ( diff_shift <= stbir__small_float ) ) { - if ( horizontal->is_gather == vertical->is_gather ) + if ( horizontal->is_gather == vertical->is_gather ) { copy_horizontal = 1; goto no_vert_alloc; @@ -6975,16 +7170,16 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample // but if the number of coeffs <= 12, use another set of special cases. <=12 coeffs is any enlarging resize, or shrinking resize down to about 1/3 size if ( horizontal->extent_info.widest <= 12 ) info->horizontal_gather_channels = stbir__horizontal_gather_channels_funcs[ effective_channels ][ horizontal->extent_info.widest - 1 ]; - + info->scanline_extents.conservative.n0 = conservative->n0; info->scanline_extents.conservative.n1 = conservative->n1; - + // get exact extents stbir__get_extents( horizontal, &info->scanline_extents ); // pack the horizontal coeffs - horizontal->coefficient_width = stbir__pack_coefficients(horizontal->num_contributors, horizontal->contributors, horizontal->coefficients, horizontal->coefficient_width, horizontal->extent_info.widest, info->scanline_extents.conservative.n1 + 1 ); - + horizontal->coefficient_width = stbir__pack_coefficients(horizontal->num_contributors, horizontal->contributors, horizontal->coefficients, horizontal->coefficient_width, horizontal->extent_info.widest, info->scanline_extents.conservative.n0, info->scanline_extents.conservative.n1 ); + STBIR_MEMCPY( &info->horizontal, horizontal, sizeof( stbir__sampler ) ); STBIR_PROFILE_BUILD_END( horizontal ); @@ -7014,36 +7209,27 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample info->ring_buffer_num_entries = conservative_split_output_size; STBIR_ASSERT( info->ring_buffer_num_entries <= info->alloc_ring_buffer_num_entries ); - // a few of the horizontal gather functions read one dword past the end (but mask it out), so put in a normal value so no snans or denormals accidentally sneak in + // a few of the horizontal gather functions read past the end of the decode (but mask it out), + // so put in normal values so no snans or denormals accidentally sneak in (also, in the ring + // buffer for vertical first) for( i = 0 ; i < splits ; i++ ) { - int width, ofs; - - // find the right most span - if ( info->scanline_extents.spans[0].n1 > info->scanline_extents.spans[1].n1 ) - width = info->scanline_extents.spans[0].n1 - info->scanline_extents.spans[0].n0; - else - width = info->scanline_extents.spans[1].n1 - info->scanline_extents.spans[1].n0; - - // this calc finds the exact end of the decoded scanline for all filter modes. - // usually this is just the width * effective channels. But we have to account - // for the area to the left of the scanline for wrap filtering and alignment, this - // is stored as a negative value in info->scanline_extents.conservative.n0. Next, - // we need to skip the exact size of the right hand size filter area (again for - // wrap mode), this is in info->scanline_extents.edge_sizes[1]). - ofs = ( width + 1 - info->scanline_extents.conservative.n0 + info->scanline_extents.edge_sizes[1] ) * effective_channels; - - // place a known, but numerically valid value in the decode buffer - info->split_info[i].decode_buffer[ ofs ] = 9999.0f; + int t, ofs, start; + + ofs = decode_buffer_size / 4; + start = ofs - 4; + if ( start < 0 ) start = 0; + + for( t = start ; t < ofs; t++ ) + info->split_info[i].decode_buffer[ t ] = 9999.0f; - // if vertical filtering first, place a known, but numerically valid value in the all - // of the ring buffer accumulators if ( vertical_first ) { - int j; + int j; for( j = 0; j < info->ring_buffer_num_entries ; j++ ) { - stbir__get_ring_buffer_entry( info, info->split_info + i, j )[ ofs ] = 9999.0f; + for( t = start ; t < ofs; t++ ) + stbir__get_ring_buffer_entry( info, info->split_info + i, j )[ t ] = 9999.0f; } } } @@ -7055,7 +7241,7 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample // is this the first time through loop? if ( info == 0 ) { - alloced_total = (int) ( 15 + (size_t)advance_mem ); + alloced_total = ( 15 + (size_t)advance_mem ); alloced = STBIR_MALLOC( alloced_total, user_data ); if ( alloced == 0 ) return 0; @@ -7065,7 +7251,7 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample } } -static int stbir__perform_resize( stbir__info const * info, int split_start, int split_count ) +static int stbir__perform_resize( stbir__info const * info, int split_start, int split_count ) { stbir__per_split_info * split_info = info->split_info + split_start; @@ -7085,7 +7271,7 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r { static stbir__decode_pixels_func * decode_simple[STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]= { - /* 1ch-4ch */ stbir__decode_uint8_srgb, stbir__decode_uint8_srgb, 0, stbir__decode_float_linear, stbir__decode_half_float_linear, + /* 1ch-4ch */ stbir__decode_uint8_srgb, stbir__decode_uint8_srgb, 0, stbir__decode_float_linear, stbir__decode_half_float_linear, }; static stbir__decode_pixels_func * decode_alphas[STBIRI_AR-STBIRI_RGBA+1][STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]= @@ -7148,7 +7334,7 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r stbir_datatype input_type, output_type; input_type = resize->input_data_type; - output_type = resize->output_data_type; + output_type = resize->output_data_type; info->input_data = resize->input_pixels; info->input_stride_bytes = resize->input_stride_in_bytes; info->output_stride_bytes = resize->output_stride_in_bytes; @@ -7156,7 +7342,7 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r // if we're completely point sampling, then we can turn off SRGB if ( ( info->horizontal.filter_enum == STBIR_FILTER_POINT_SAMPLE ) && ( info->vertical.filter_enum == STBIR_FILTER_POINT_SAMPLE ) ) { - if ( ( ( input_type == STBIR_TYPE_UINT8_SRGB ) || ( input_type == STBIR_TYPE_UINT8_SRGB_ALPHA ) ) && + if ( ( ( input_type == STBIR_TYPE_UINT8_SRGB ) || ( input_type == STBIR_TYPE_UINT8_SRGB_ALPHA ) ) && ( ( output_type == STBIR_TYPE_UINT8_SRGB ) || ( output_type == STBIR_TYPE_UINT8_SRGB_ALPHA ) ) ) { input_type = STBIR_TYPE_UINT8; @@ -7164,7 +7350,7 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r } } - // recalc the output and input strides + // recalc the output and input strides if ( info->input_stride_bytes == 0 ) info->input_stride_bytes = info->channels * info->horizontal.scale_info.input_full_size * stbir__type_size[input_type]; @@ -7172,7 +7358,7 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r info->output_stride_bytes = info->channels * info->horizontal.scale_info.output_sub_size * stbir__type_size[output_type]; // calc offset - info->output_data = ( (char*) resize->output_pixels ) + ( (ptrdiff_t) info->offset_y * (ptrdiff_t) resize->output_stride_in_bytes ) + ( info->offset_x * info->channels * stbir__type_size[output_type] ); + info->output_data = ( (char*) resize->output_pixels ) + ( (size_t) info->offset_y * (size_t) resize->output_stride_in_bytes ) + ( info->offset_x * info->channels * stbir__type_size[output_type] ); info->in_pixels_cb = resize->input_cb; info->user_data = resize->user_data; @@ -7205,7 +7391,7 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r if ( ( output_type == STBIR_TYPE_UINT8 ) || ( output_type == STBIR_TYPE_UINT16 ) ) { int non_scaled = 0; - + // check if we can run unscaled - 0-255.0/0-65535.0 instead of 0-1.0 (which is a tiny bit faster when doing linear 8->8 or 16->16) if ( ( !info->alpha_weight ) && ( !info->alpha_unweight ) ) // don't short circuit when alpha weighting (get everything to 0-1.0 as usual) if ( ( ( input_type == STBIR_TYPE_UINT8 ) && ( output_type == STBIR_TYPE_UINT8 ) ) || ( ( input_type == STBIR_TYPE_UINT16 ) && ( output_type == STBIR_TYPE_UINT16 ) ) ) @@ -7225,16 +7411,16 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r } info->input_type = input_type; - info->output_type = output_type; + info->output_type = output_type; info->decode_pixels = decode_pixels; - info->encode_pixels = encode_pixels; + info->encode_pixels = encode_pixels; } static void stbir__clip( int * outx, int * outsubw, int outw, double * u0, double * u1 ) { double per, adj; int over; - + // do left/top edge if ( *outx < 0 ) { @@ -7253,7 +7439,7 @@ static void stbir__clip( int * outx, int * outsubw, int outw, double * u0, doubl *u1 += adj; // decrease u1 *outsubw = outw - *outx; } -} +} // converts a double to a rational that has less than one float bit of error (returns 0 if unable to do so) static int stbir__double_to_rational(double f, stbir_uint32 limit, stbir_uint32 *numer, stbir_uint32 *denom, int limit_denom ) // limit_denom (1) or limit numer (0) @@ -7270,7 +7456,7 @@ static int stbir__double_to_rational(double f, stbir_uint32 limit, stbir_uint32 bot = 1 << 25; // keep refining, but usually stops in a few loops - usually 5 for bad cases - for(;;) + for(;;) { stbir_uint64 est, temp; @@ -7303,13 +7489,13 @@ static int stbir__double_to_rational(double f, stbir_uint32 limit, stbir_uint32 bot = temp; // move remainders - temp = est * denom_estimate + denom_last; - denom_last = denom_estimate; + temp = est * denom_estimate + denom_last; + denom_last = denom_estimate; denom_estimate = temp; // move remainders - temp = est * numer_estimate + numer_last; - numer_last = numer_estimate; + temp = est * numer_estimate + numer_last; + numer_last = numer_estimate; numer_estimate = temp; } @@ -7353,11 +7539,11 @@ static int stbir__calculate_region_transform( stbir__scale_info * scale_info, in output_s = ( (double)output_sub_range) / output_range; - // figure out the scaling to use - ratio = output_s / input_s; + // figure out the scaling to use + ratio = output_s / input_s; // save scale before clipping - scale = ( output_range / input_range ) * ratio; + scale = ( output_range / input_range ) * ratio; scale_info->scale = (float)scale; scale_info->inv_scale = (float)( 1.0 / scale ); @@ -7368,11 +7554,11 @@ static int stbir__calculate_region_transform( stbir__scale_info * scale_info, in input_s = input_s1 - input_s0; // after clipping do we have zero input area? - if ( input_s <= stbir__small_float ) + if ( input_s <= stbir__small_float ) return 0; - // calculate and store the starting source offsets in output pixel space - scale_info->pixel_shift = (float) ( input_s0 * ratio * output_range ); + // calculate and store the starting source offsets in output pixel space + scale_info->pixel_shift = (float) ( input_s0 * ratio * output_range ); scale_info->scale_is_rational = stbir__double_to_rational( scale, ( scale <= 1.0 ) ? output_full_range : input_full_range, &scale_info->scale_numerator, &scale_info->scale_denominator, ( scale >= 1.0 ) ); @@ -7389,7 +7575,6 @@ static void stbir__init_and_set_layout( STBIR_RESIZE * resize, stbir_pixel_layou resize->output_cb = 0; resize->user_data = resize; resize->samplers = 0; - resize->needs_rebuild = 1; resize->called_alloc = 0; resize->horizontal_filter = STBIR_FILTER_DEFAULT; resize->horizontal_filter_kernel = 0; resize->horizontal_filter_support = 0; @@ -7403,9 +7588,10 @@ static void stbir__init_and_set_layout( STBIR_RESIZE * resize, stbir_pixel_layou resize->output_data_type = data_type; resize->input_pixel_layout_public = pixel_layout; resize->output_pixel_layout_public = pixel_layout; + resize->needs_rebuild = 1; } -STBIRDEF void stbir_resize_init( STBIR_RESIZE * resize, +STBIRDEF void stbir_resize_init( STBIR_RESIZE * resize, const void *input_pixels, int input_w, int input_h, int input_stride_in_bytes, // stride can be zero void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, // stride can be zero stbir_pixel_layout pixel_layout, stbir_datatype data_type ) @@ -7428,17 +7614,27 @@ STBIRDEF void stbir_set_datatypes( STBIR_RESIZE * resize, stbir_datatype input_t { resize->input_data_type = input_type; resize->output_data_type = output_type; + if ( ( resize->samplers ) && ( !resize->needs_rebuild ) ) + stbir__update_info_from_resize( resize->samplers, resize ); } STBIRDEF void stbir_set_pixel_callbacks( STBIR_RESIZE * resize, stbir_input_callback * input_cb, stbir_output_callback * output_cb ) // no callbacks by default { resize->input_cb = input_cb; resize->output_cb = output_cb; + + if ( ( resize->samplers ) && ( !resize->needs_rebuild ) ) + { + resize->samplers->in_pixels_cb = input_cb; + resize->samplers->out_pixels_cb = output_cb; + } } STBIRDEF void stbir_set_user_data( STBIR_RESIZE * resize, void * user_data ) // pass back STBIR_RESIZE* by default { resize->user_data = user_data; + if ( ( resize->samplers ) && ( !resize->needs_rebuild ) ) + resize->samplers->user_data = user_data; } STBIRDEF void stbir_set_buffer_ptrs( STBIR_RESIZE * resize, const void * input_pixels, int input_stride_in_bytes, void * output_pixels, int output_stride_in_bytes ) @@ -7447,6 +7643,8 @@ STBIRDEF void stbir_set_buffer_ptrs( STBIR_RESIZE * resize, const void * input_p resize->input_stride_in_bytes = input_stride_in_bytes; resize->output_pixels = output_pixels; resize->output_stride_in_bytes = output_stride_in_bytes; + if ( ( resize->samplers ) && ( !resize->needs_rebuild ) ) + stbir__update_info_from_resize( resize->samplers, resize ); } @@ -7549,7 +7747,7 @@ STBIRDEF int stbir_set_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby, return 1; } -static int stbir__perform_build( STBIR_RESIZE * resize, int splits ) +static int stbir__perform_build( STBIR_RESIZE * resize, int splits ) { stbir__contributors conservative = { 0, 0 }; stbir__sampler horizontal, vertical; @@ -7563,13 +7761,13 @@ static int stbir__perform_build( STBIR_RESIZE * resize, int splits ) // have we already built the samplers? if ( resize->samplers ) return 0; - + #define STBIR_RETURN_ERROR_AND_ASSERT( exp ) STBIR_ASSERT( !(exp) ); if (exp) return 0; STBIR_RETURN_ERROR_AND_ASSERT( (unsigned)resize->horizontal_filter >= STBIR_FILTER_OTHER) STBIR_RETURN_ERROR_AND_ASSERT( (unsigned)resize->vertical_filter >= STBIR_FILTER_OTHER) #undef STBIR_RETURN_ERROR_AND_ASSERT - if ( splits <= 0 ) + if ( splits <= 0 ) return 0; STBIR_PROFILE_BUILD_FIRST_START( build ); @@ -7593,9 +7791,9 @@ static int stbir__perform_build( STBIR_RESIZE * resize, int splits ) stbir__get_conservative_extents( &horizontal, &conservative, resize->user_data ); stbir__set_sampler(&vertical, resize->vertical_filter, resize->horizontal_filter_kernel, resize->vertical_filter_support, resize->vertical_edge, &vertical.scale_info, 0, resize->user_data ); - if ( ( vertical.scale_info.output_sub_size / splits ) < 4 ) // each split should be a minimum of 4 scanlines (handwavey choice) + if ( ( vertical.scale_info.output_sub_size / splits ) < STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS ) // each split should be a minimum of 4 scanlines (handwavey choice) { - splits = vertical.scale_info.output_sub_size / 4; + splits = vertical.scale_info.output_sub_size / STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS; if ( splits == 0 ) splits = 1; } @@ -7603,7 +7801,7 @@ static int stbir__perform_build( STBIR_RESIZE * resize, int splits ) out_info = stbir__alloc_internal_mem_and_build_samplers( &horizontal, &vertical, &conservative, resize->input_pixel_layout_public, resize->output_pixel_layout_public, splits, new_output_subx, new_output_suby, resize->fast_alpha, resize->user_data STBIR_ONLY_PROFILE_BUILD_SET_INFO ); STBIR_PROFILE_BUILD_END( alloc ); STBIR_PROFILE_BUILD_END( build ); - + if ( out_info ) { resize->splits = splits; @@ -7612,6 +7810,10 @@ static int stbir__perform_build( STBIR_RESIZE * resize, int splits ) #ifdef STBIR_PROFILE STBIR_MEMCPY( &out_info->profile, &profile_infod.profile, sizeof( out_info->profile ) ); #endif + + // update anything that can be changed without recalcing samplers + stbir__update_info_from_resize( out_info, resize ); + return splits; } @@ -7640,7 +7842,7 @@ STBIRDEF int stbir_build_samplers_with_splits( STBIR_RESIZE * resize, int splits } STBIR_PROFILE_BUILD_CLEAR( resize->samplers ); - + return 1; } @@ -7652,7 +7854,7 @@ STBIRDEF int stbir_build_samplers( STBIR_RESIZE * resize ) STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize ) { int result; - + if ( ( resize->samplers == 0 ) || ( resize->needs_rebuild ) ) { int alloc_state = resize->called_alloc; // remember allocated state @@ -7665,10 +7867,10 @@ STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize ) if ( !stbir_build_samplers( resize ) ) return 0; - + resize->called_alloc = alloc_state; - // if build_samplers succeeded (above), but there are no samplers set, then + // if build_samplers succeeded (above), but there are no samplers set, then // the area to stretch into was zero pixels, so don't do anything and return // success if ( resize->samplers == 0 ) @@ -7680,10 +7882,6 @@ STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize ) STBIR_PROFILE_BUILD_CLEAR( resize->samplers ); } - - // update anything that can be changed without recalcing samplers - stbir__update_info_from_resize( resize->samplers, resize ); - // do resize result = stbir__perform_resize( resize->samplers, 0, resize->splits ); @@ -7692,7 +7890,7 @@ STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize ) { stbir_free_samplers( resize ); resize->samplers = 0; - } + } return result; } @@ -7707,14 +7905,11 @@ STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start // you **must** build samplers first when using split resize if ( ( resize->samplers == 0 ) || ( resize->needs_rebuild ) ) - return 0; - + return 0; + if ( ( split_start >= resize->splits ) || ( split_start < 0 ) || ( ( split_start + split_count ) > resize->splits ) || ( split_count <= 0 ) ) return 0; - - // update anything that can be changed without recalcing samplers - stbir__update_info_from_resize( resize->samplers, resize ); - + // do resize return stbir__perform_resize( resize->samplers, split_start, split_count ); } @@ -7735,7 +7930,7 @@ static int stbir__check_output_stuff( void ** ret_ptr, int * ret_pitch, void * o if ( output_stride_in_bytes < pitch ) return 0; - size = output_stride_in_bytes * output_h; + size = (size_t)output_stride_in_bytes * (size_t)output_h; if ( size == 0 ) return 0; @@ -7752,7 +7947,7 @@ static int stbir__check_output_stuff( void ** ret_ptr, int * ret_pitch, void * o *ret_pitch = pitch; } - return 1; + return 1; } @@ -7767,9 +7962,9 @@ STBIRDEF unsigned char * stbir_resize_uint8_linear( const unsigned char *input_p if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, sizeof( unsigned char ), output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) ) return 0; - stbir_resize_init( &resize, - input_pixels, input_w, input_h, input_stride_in_bytes, - (optr) ? optr : output_pixels, output_w, output_h, opitch, + stbir_resize_init( &resize, + input_pixels, input_w, input_h, input_stride_in_bytes, + (optr) ? optr : output_pixels, output_w, output_h, opitch, pixel_layout, STBIR_TYPE_UINT8 ); if ( !stbir_resize_extended( &resize ) ) @@ -7793,9 +7988,9 @@ STBIRDEF unsigned char * stbir_resize_uint8_srgb( const unsigned char *input_pix if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, sizeof( unsigned char ), output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) ) return 0; - stbir_resize_init( &resize, - input_pixels, input_w, input_h, input_stride_in_bytes, - (optr) ? optr : output_pixels, output_w, output_h, opitch, + stbir_resize_init( &resize, + input_pixels, input_w, input_h, input_stride_in_bytes, + (optr) ? optr : output_pixels, output_w, output_h, opitch, pixel_layout, STBIR_TYPE_UINT8_SRGB ); if ( !stbir_resize_extended( &resize ) ) @@ -7820,9 +8015,9 @@ STBIRDEF float * stbir_resize_float_linear( const float *input_pixels , int inpu if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, sizeof( float ), output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) ) return 0; - stbir_resize_init( &resize, - input_pixels, input_w, input_h, input_stride_in_bytes, - (optr) ? optr : output_pixels, output_w, output_h, opitch, + stbir_resize_init( &resize, + input_pixels, input_w, input_h, input_stride_in_bytes, + (optr) ? optr : output_pixels, output_w, output_h, opitch, pixel_layout, STBIR_TYPE_FLOAT ); if ( !stbir_resize_extended( &resize ) ) @@ -7838,7 +8033,7 @@ STBIRDEF float * stbir_resize_float_linear( const float *input_pixels , int inpu STBIRDEF void * stbir_resize( const void *input_pixels , int input_w , int input_h, int input_stride_in_bytes, void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, - stbir_pixel_layout pixel_layout, stbir_datatype data_type, + stbir_pixel_layout pixel_layout, stbir_datatype data_type, stbir_edge edge, stbir_filter filter ) { STBIR_RESIZE resize; @@ -7848,9 +8043,9 @@ STBIRDEF void * stbir_resize( const void *input_pixels , int input_w , int input if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, stbir__type_size[data_type], output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) ) return 0; - stbir_resize_init( &resize, - input_pixels, input_w, input_h, input_stride_in_bytes, - (optr) ? optr : output_pixels, output_w, output_h, output_stride_in_bytes, + stbir_resize_init( &resize, + input_pixels, input_w, input_h, input_stride_in_bytes, + (optr) ? optr : output_pixels, output_w, output_h, output_stride_in_bytes, pixel_layout, data_type ); resize.horizontal_edge = edge; @@ -7958,7 +8153,7 @@ STBIRDEF void stbir_resize_extended_profile_info( STBIR_PROFILE_INFO * info, STB #else // STB_IMAGE_RESIZE_HORIZONTALS&STB_IMAGE_RESIZE_DO_VERTICALS // we reinclude the header file to define all the horizontal functions -// specializing each function for the number of coeffs is 20-40% faster *OVERALL* +// specializing each function for the number of coeffs is 20-40% faster *OVERALL* // by including the header file again this way, we can still debug the functions @@ -7991,16 +8186,16 @@ STBIRDEF void stbir_resize_extended_profile_info( STBIR_PROFILE_INFO * info, STB #define stbir__encode_order2 2 #define stbir__encode_order3 3 #define stbir__decode_simdf8_flip(reg) -#define stbir__decode_simdf4_flip(reg) +#define stbir__decode_simdf4_flip(reg) #define stbir__encode_simdf8_unflip(reg) -#define stbir__encode_simdf4_unflip(reg) +#define stbir__encode_simdf4_unflip(reg) #endif #ifdef STBIR_SIMD8 #define stbir__encode_simdfX_unflip stbir__encode_simdf8_unflip #else #define stbir__encode_simdfX_unflip stbir__encode_simdf4_unflip -#endif +#endif static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * decodep, int width_times_channels, void const * inputp ) { @@ -8013,6 +8208,7 @@ static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * deco if ( width_times_channels >= 16 ) { decode_end -= 16; + STBIR_NO_UNROLL_LOOP_START_INF_FOR for(;;) { #ifdef STBIR_SIMD8 @@ -8054,7 +8250,7 @@ static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * deco #endif decode += 16; input += 16; - if ( decode <= decode_end ) + if ( decode <= decode_end ) continue; if ( decode == ( decode_end + 16 ) ) break; @@ -8068,6 +8264,7 @@ static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * deco // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four decode += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( decode <= decode_end ) { STBIR_SIMD_NO_UNROLL(decode); @@ -8083,6 +8280,7 @@ static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * deco // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( decode < decode_end ) { STBIR_NO_UNROLL(decode); @@ -8109,6 +8307,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outpu { float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2; end_output -= stbir__simdfX_float_count*2; + STBIR_NO_UNROLL_LOOP_START_INF_FOR for(;;) { stbir__simdfX e0, e1; @@ -8119,15 +8318,15 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outpu stbir__encode_simdfX_unflip( e0 ); stbir__encode_simdfX_unflip( e1 ); #ifdef STBIR_SIMD8 - stbir__simdf8_pack_to_16bytes( i, e0, e1 ); + stbir__simdf8_pack_to_16bytes( i, e0, e1 ); stbir__simdi_store( output, i ); #else - stbir__simdf_pack_to_8bytes( i, e0, e1 ); + stbir__simdf_pack_to_8bytes( i, e0, e1 ); stbir__simdi_store2( output, i ); #endif encode += stbir__simdfX_float_count*2; output += stbir__simdfX_float_count*2; - if ( output <= end_output ) + if ( output <= end_output ) continue; if ( output == ( end_output + stbir__simdfX_float_count*2 ) ) break; @@ -8140,6 +8339,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outpu // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_NO_UNROLL_LOOP_START while( output <= end_output ) { stbir__simdf e0; @@ -8158,9 +8358,10 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outpu // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( output < end_output ) { - stbir__simdf e0; + stbir__simdf e0; STBIR_NO_UNROLL(encode); stbir__simdf_madd1_mem( e0, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint8_as_float), encode+stbir__encode_order0 ); output[0] = stbir__simdf_convert_float_to_uint8( e0 ); #if stbir__coder_min_num >= 2 @@ -8173,7 +8374,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outpu encode += stbir__coder_min_num; } #endif - + #else // try to do blocks of 4 when you can @@ -8194,6 +8395,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outpu // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( output < end_output ) { float f; @@ -8223,6 +8425,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_linear)( float * decodep, int if ( width_times_channels >= 16 ) { decode_end -= 16; + STBIR_NO_UNROLL_LOOP_START_INF_FOR for(;;) { #ifdef STBIR_SIMD8 @@ -8258,7 +8461,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_linear)( float * decodep, int #endif decode += 16; input += 16; - if ( decode <= decode_end ) + if ( decode <= decode_end ) continue; if ( decode == ( decode_end + 16 ) ) break; @@ -8272,6 +8475,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_linear)( float * decodep, int // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four decode += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( decode <= decode_end ) { STBIR_SIMD_NO_UNROLL(decode); @@ -8287,6 +8491,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_linear)( float * decodep, int // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( decode < decode_end ) { STBIR_NO_UNROLL(decode); @@ -8313,6 +8518,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear )( void * outputp, int { float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2; end_output -= stbir__simdfX_float_count*2; + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { stbir__simdfX e0, e1; @@ -8323,15 +8529,15 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear )( void * outputp, int stbir__encode_simdfX_unflip( e0 ); stbir__encode_simdfX_unflip( e1 ); #ifdef STBIR_SIMD8 - stbir__simdf8_pack_to_16bytes( i, e0, e1 ); + stbir__simdf8_pack_to_16bytes( i, e0, e1 ); stbir__simdi_store( output, i ); #else - stbir__simdf_pack_to_8bytes( i, e0, e1 ); + stbir__simdf_pack_to_8bytes( i, e0, e1 ); stbir__simdi_store2( output, i ); #endif encode += stbir__simdfX_float_count*2; output += stbir__simdfX_float_count*2; - if ( output <= end_output ) + if ( output <= end_output ) continue; if ( output == ( end_output + stbir__simdfX_float_count*2 ) ) break; @@ -8344,6 +8550,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear )( void * outputp, int // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_NO_UNROLL_LOOP_START while( output <= end_output ) { stbir__simdf e0; @@ -8382,6 +8589,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear )( void * outputp, int // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( output < end_output ) { float f; @@ -8422,6 +8630,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_srgb)( float * decodep, int wi // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( decode < decode_end ) { STBIR_NO_UNROLL(decode); @@ -8441,7 +8650,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_srgb)( float * decodep, int wi #define stbir__min_max_shift20( i, f ) \ stbir__simdf_max( f, f, stbir_simdf_casti(STBIR__CONSTI( STBIR_almost_zero )) ); \ stbir__simdf_min( f, f, stbir_simdf_casti(STBIR__CONSTI( STBIR_almost_one )) ); \ - stbir__simdi_32shr( i, stbir_simdi_castf( f ), 20 ); + stbir__simdi_32shr( i, stbir_simdi_castf( f ), 20 ); #define stbir__scale_and_convert( i, f ) \ stbir__simdf_madd( f, STBIR__CONSTF( STBIR_simd_point5 ), STBIR__CONSTF( STBIR_max_uint8_as_float ), f ); \ @@ -8468,7 +8677,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_srgb)( float * decodep, int wi temp1.m128i_u32[0] = table[temp1.m128i_i32[0]]; temp1.m128i_u32[1] = table[temp1.m128i_i32[1]]; temp1.m128i_u32[2] = table[temp1.m128i_i32[2]]; temp1.m128i_u32[3] = table[temp1.m128i_i32[3]]; \ v0 = temp0.m128i_i128; \ v1 = temp1.m128i_i128; \ -} +} #define stbir__simdi_table_lookup3( v0,v1,v2, table ) \ { \ @@ -8499,7 +8708,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_srgb)( float * decodep, int wi v1 = temp1.m128i_i128; \ v2 = temp2.m128i_i128; \ v3 = temp3.m128i_i128; \ -} +} static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int width_times_channels, float const * encode ) { @@ -8507,16 +8716,16 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int w unsigned char * end_output = ( (unsigned char*) output ) + width_times_channels; #ifdef STBIR_SIMD - stbir_uint32 const * to_srgb = fp32_to_srgb8_tab4 - (127-13)*8; if ( width_times_channels >= 16 ) { float const * end_encode_m16 = encode + width_times_channels - 16; end_output -= 16; + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { stbir__simdf f0, f1, f2, f3; - stbir__simdi i0, i1, i2, i3; + stbir__simdi i0, i1, i2, i3; STBIR_SIMD_NO_UNROLL(encode); stbir__simdf_load4_transposed( f0, f1, f2, f3, encode ); @@ -8525,9 +8734,9 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int w stbir__min_max_shift20( i1, f1 ); stbir__min_max_shift20( i2, f2 ); stbir__min_max_shift20( i3, f3 ); - - stbir__simdi_table_lookup4( i0, i1, i2, i3, to_srgb ); - + + stbir__simdi_table_lookup4( i0, i1, i2, i3, ( fp32_to_srgb8_tab4 - (127-13)*8 ) ); + stbir__linear_to_srgb_finish( i0, f0 ); stbir__linear_to_srgb_finish( i1, f1 ); stbir__linear_to_srgb_finish( i2, f2 ); @@ -8537,7 +8746,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int w encode += 16; output += 16; - if ( output <= end_output ) + if ( output <= end_output ) continue; if ( output == ( end_output + 16 ) ) break; @@ -8551,6 +8760,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int w // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while ( output <= end_output ) { STBIR_SIMD_NO_UNROLL(encode); @@ -8568,7 +8778,8 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int w // do the remnants #if stbir__coder_min_num < 4 - while( output < end_output ) + STBIR_NO_UNROLL_LOOP_START + while( output < end_output ) { STBIR_NO_UNROLL(encode); output[0] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order0] ); @@ -8608,12 +8819,12 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb4_linearalpha )( void * o unsigned char * end_output = ( (unsigned char*) output ) + width_times_channels; #ifdef STBIR_SIMD - stbir_uint32 const * to_srgb = fp32_to_srgb8_tab4 - (127-13)*8; if ( width_times_channels >= 16 ) { float const * end_encode_m16 = encode + width_times_channels - 16; end_output -= 16; + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { stbir__simdf f0, f1, f2, f3; @@ -8625,10 +8836,10 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb4_linearalpha )( void * o stbir__min_max_shift20( i0, f0 ); stbir__min_max_shift20( i1, f1 ); stbir__min_max_shift20( i2, f2 ); - stbir__scale_and_convert( i3, f3 ); - - stbir__simdi_table_lookup3( i0, i1, i2, to_srgb ); - + stbir__scale_and_convert( i3, f3 ); + + stbir__simdi_table_lookup3( i0, i1, i2, ( fp32_to_srgb8_tab4 - (127-13)*8 ) ); + stbir__linear_to_srgb_finish( i0, f0 ); stbir__linear_to_srgb_finish( i1, f1 ); stbir__linear_to_srgb_finish( i2, f2 ); @@ -8638,7 +8849,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb4_linearalpha )( void * o output += 16; encode += 16; - if ( output <= end_output ) + if ( output <= end_output ) continue; if ( output == ( end_output + 16 ) ) break; @@ -8649,9 +8860,10 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb4_linearalpha )( void * o } #endif + STBIR_SIMD_NO_UNROLL_LOOP_START do { float f; - STBIR_SIMD_NO_UNROLL(encode); + STBIR_SIMD_NO_UNROLL(encode); output[stbir__decode_order0] = stbir__linear_to_srgb_uchar( encode[0] ); output[stbir__decode_order1] = stbir__linear_to_srgb_uchar( encode[1] ); @@ -8686,7 +8898,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_srgb2_linearalpha)( float * de decode += 4; } decode -= 4; - if( decode < decode_end ) + if( decode < decode_end ) { decode[0] = stbir__srgb_uchar_to_linear_float[ stbir__decode_order0 ]; decode[1] = ( (float) input[stbir__decode_order1] ) * stbir__max_uint8_as_float_inverted; @@ -8699,16 +8911,16 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb2_linearalpha )( void * o unsigned char * end_output = ( (unsigned char*) output ) + width_times_channels; #ifdef STBIR_SIMD - stbir_uint32 const * to_srgb = fp32_to_srgb8_tab4 - (127-13)*8; if ( width_times_channels >= 16 ) { float const * end_encode_m16 = encode + width_times_channels - 16; end_output -= 16; + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { stbir__simdf f0, f1, f2, f3; - stbir__simdi i0, i1, i2, i3; + stbir__simdi i0, i1, i2, i3; STBIR_SIMD_NO_UNROLL(encode); stbir__simdf_load4_transposed( f0, f1, f2, f3, encode ); @@ -8717,9 +8929,9 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb2_linearalpha )( void * o stbir__scale_and_convert( i1, f1 ); stbir__min_max_shift20( i2, f2 ); stbir__scale_and_convert( i3, f3 ); - - stbir__simdi_table_lookup2( i0, i2, to_srgb ); - + + stbir__simdi_table_lookup2( i0, i2, ( fp32_to_srgb8_tab4 - (127-13)*8 ) ); + stbir__linear_to_srgb_finish( i0, f0 ); stbir__linear_to_srgb_finish( i2, f2 ); @@ -8727,7 +8939,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb2_linearalpha )( void * o output += 16; encode += 16; - if ( output <= end_output ) + if ( output <= end_output ) continue; if ( output == ( end_output + 16 ) ) break; @@ -8738,6 +8950,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb2_linearalpha )( void * o } #endif + STBIR_SIMD_NO_UNROLL_LOOP_START do { float f; STBIR_SIMD_NO_UNROLL(encode); @@ -8766,6 +8979,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear_scaled)( float * decod if ( width_times_channels >= 8 ) { decode_end -= 8; + STBIR_NO_UNROLL_LOOP_START_INF_FOR for(;;) { #ifdef STBIR_SIMD8 @@ -8793,9 +9007,9 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear_scaled)( float * decod stbir__simdf_store( decode + 0, of0 ); stbir__simdf_store( decode + 4, of1 ); #endif - decode += 8; + decode += 8; input += 8; - if ( decode <= decode_end ) + if ( decode <= decode_end ) continue; if ( decode == ( decode_end + 8 ) ) break; @@ -8809,6 +9023,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear_scaled)( float * decod // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four decode += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( decode <= decode_end ) { STBIR_SIMD_NO_UNROLL(decode); @@ -8824,6 +9039,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear_scaled)( float * decod // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( decode < decode_end ) { STBIR_NO_UNROLL(decode); @@ -8852,6 +9068,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * output { float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2; end_output -= stbir__simdfX_float_count*2; + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { stbir__simdfX e0, e1; @@ -8865,7 +9082,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * output stbir__simdiX_store( output, i ); encode += stbir__simdfX_float_count*2; output += stbir__simdfX_float_count*2; - if ( output <= end_output ) + if ( output <= end_output ) continue; if ( output == ( end_output + stbir__simdfX_float_count*2 ) ) break; @@ -8879,6 +9096,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * output // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_NO_UNROLL_LOOP_START while( output <= end_output ) { stbir__simdf e; @@ -8897,6 +9115,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * output // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( output < end_output ) { stbir__simdf e; @@ -8912,12 +9131,13 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * output encode += stbir__coder_min_num; } #endif - + #else // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( output <= end_output ) { float f; @@ -8934,6 +9154,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * output // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( output < end_output ) { float f; @@ -8963,6 +9184,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear)( float * decodep, int if ( width_times_channels >= 8 ) { decode_end -= 8; + STBIR_NO_UNROLL_LOOP_START_INF_FOR for(;;) { #ifdef STBIR_SIMD8 @@ -8989,7 +9211,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear)( float * decodep, int #endif decode += 8; input += 8; - if ( decode <= decode_end ) + if ( decode <= decode_end ) continue; if ( decode == ( decode_end + 8 ) ) break; @@ -9003,6 +9225,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear)( float * decodep, int // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four decode += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( decode <= decode_end ) { STBIR_SIMD_NO_UNROLL(decode); @@ -9018,6 +9241,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear)( float * decodep, int // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( decode < decode_end ) { STBIR_NO_UNROLL(decode); @@ -9045,6 +9269,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int { float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2; end_output -= stbir__simdfX_float_count*2; + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { stbir__simdfX e0, e1; @@ -9058,7 +9283,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int stbir__simdiX_store( output, i ); encode += stbir__simdfX_float_count*2; output += stbir__simdfX_float_count*2; - if ( output <= end_output ) + if ( output <= end_output ) continue; if ( output == ( end_output + stbir__simdfX_float_count*2 ) ) break; @@ -9072,6 +9297,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_NO_UNROLL_LOOP_START while( output <= end_output ) { stbir__simdf e; @@ -9093,6 +9319,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( output <= end_output ) { float f; @@ -9111,6 +9338,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( output < end_output ) { float f; @@ -9139,6 +9367,7 @@ static void STBIR__CODER_NAME(stbir__decode_half_float_linear)( float * decodep, { stbir__FP16 const * end_input_m8 = input + width_times_channels - 8; decode_end -= 8; + STBIR_NO_UNROLL_LOOP_START_INF_FOR for(;;) { STBIR_NO_UNROLL(decode); @@ -9166,7 +9395,7 @@ static void STBIR__CODER_NAME(stbir__decode_half_float_linear)( float * decodep, #endif decode += 8; input += 8; - if ( decode <= decode_end ) + if ( decode <= decode_end ) continue; if ( decode == ( decode_end + 8 ) ) break; @@ -9180,6 +9409,7 @@ static void STBIR__CODER_NAME(stbir__decode_half_float_linear)( float * decodep, // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four decode += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( decode <= decode_end ) { STBIR_SIMD_NO_UNROLL(decode); @@ -9195,6 +9425,7 @@ static void STBIR__CODER_NAME(stbir__decode_half_float_linear)( float * decodep, // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( decode < decode_end ) { STBIR_NO_UNROLL(decode); @@ -9221,6 +9452,7 @@ static void STBIR__CODER_NAME( stbir__encode_half_float_linear )( void * outputp { float const * end_encode_m8 = encode + width_times_channels - 8; end_output -= 8; + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { STBIR_SIMD_NO_UNROLL(encode); @@ -9247,7 +9479,7 @@ static void STBIR__CODER_NAME( stbir__encode_half_float_linear )( void * outputp #endif encode += 8; output += 8; - if ( output <= end_output ) + if ( output <= end_output ) continue; if ( output == ( end_output + 8 ) ) break; @@ -9261,6 +9493,7 @@ static void STBIR__CODER_NAME( stbir__encode_half_float_linear )( void * outputp // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( output <= end_output ) { STBIR_SIMD_NO_UNROLL(output); @@ -9276,6 +9509,7 @@ static void STBIR__CODER_NAME( stbir__encode_half_float_linear )( void * outputp // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( output < end_output ) { STBIR_NO_UNROLL(output); @@ -9304,6 +9538,7 @@ static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int { float const * end_input_m16 = input + width_times_channels - 16; decode_end -= 16; + STBIR_NO_UNROLL_LOOP_START_INF_FOR for(;;) { STBIR_NO_UNROLL(decode); @@ -9338,7 +9573,7 @@ static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int #endif decode += 16; input += 16; - if ( decode <= decode_end ) + if ( decode <= decode_end ) continue; if ( decode == ( decode_end + 16 ) ) break; @@ -9352,6 +9587,7 @@ static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four decode += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( decode <= decode_end ) { STBIR_SIMD_NO_UNROLL(decode); @@ -9367,6 +9603,7 @@ static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( decode < decode_end ) { STBIR_NO_UNROLL(decode); @@ -9383,10 +9620,10 @@ static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int #endif #else - + if ( (void*)decodep != inputp ) STBIR_MEMCPY( decodep, inputp, width_times_channels * sizeof( float ) ); - + #endif } @@ -9426,6 +9663,7 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int { float const * end_encode_m8 = encode + width_times_channels - ( stbir__simdfX_float_count * 2 ); end_output -= ( stbir__simdfX_float_count * 2 ); + STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR for(;;) { stbir__simdfX e0, e1; @@ -9435,18 +9673,18 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int #ifdef STBIR_FLOAT_HIGH_CLAMP stbir__simdfX_min( e0, e0, high_clamp ); stbir__simdfX_min( e1, e1, high_clamp ); -#endif +#endif #ifdef STBIR_FLOAT_LOW_CLAMP stbir__simdfX_max( e0, e0, low_clamp ); stbir__simdfX_max( e1, e1, low_clamp ); -#endif +#endif stbir__encode_simdfX_unflip( e0 ); stbir__encode_simdfX_unflip( e1 ); stbir__simdfX_store( output, e0 ); stbir__simdfX_store( output+stbir__simdfX_float_count, e1 ); encode += stbir__simdfX_float_count * 2; output += stbir__simdfX_float_count * 2; - if ( output < end_output ) + if ( output < end_output ) continue; if ( output == ( end_output + ( stbir__simdfX_float_count * 2 ) ) ) break; @@ -9459,6 +9697,7 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_NO_UNROLL_LOOP_START while( output <= end_output ) { stbir__simdf e0; @@ -9466,10 +9705,10 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int stbir__simdf_load( e0, encode ); #ifdef STBIR_FLOAT_HIGH_CLAMP stbir__simdf_min( e0, e0, high_clamp ); -#endif +#endif #ifdef STBIR_FLOAT_LOW_CLAMP stbir__simdf_max( e0, e0, low_clamp ); -#endif +#endif stbir__encode_simdf4_unflip( e0 ); stbir__simdf_store( output-4, e0 ); output += 4; @@ -9483,6 +9722,7 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int // try to do blocks of 4 when you can #if stbir__coder_min_num != 3 // doesn't divide cleanly by four output += 4; + STBIR_SIMD_NO_UNROLL_LOOP_START while( output <= end_output ) { float e; @@ -9502,6 +9742,7 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int // do the remnants #if stbir__coder_min_num < 4 + STBIR_NO_UNROLL_LOOP_START while( output < end_output ) { float e; @@ -9517,18 +9758,18 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int encode += stbir__coder_min_num; } #endif - + #endif } -#undef stbir__decode_suffix +#undef stbir__decode_suffix #undef stbir__decode_simdf8_flip #undef stbir__decode_simdf4_flip -#undef stbir__decode_order0 +#undef stbir__decode_order0 #undef stbir__decode_order1 #undef stbir__decode_order2 #undef stbir__decode_order3 -#undef stbir__encode_order0 +#undef stbir__encode_order0 #undef stbir__encode_order1 #undef stbir__encode_order2 #undef stbir__encode_order3 @@ -9612,7 +9853,8 @@ static void STBIR_chans( stbir__vertical_scatter_with_,_coeffs)( float ** output stbIF5(stbir__simdfX c5 = stbir__simdf_frepX( c5s ); ) stbIF6(stbir__simdfX c6 = stbir__simdf_frepX( c6s ); ) stbIF7(stbir__simdfX c7 = stbir__simdf_frepX( c7s ); ) - while ( ( (char*)input_end - (char*) input ) >= (16*stbir__simdfX_float_count) ) + STBIR_SIMD_NO_UNROLL_LOOP_START + while ( ( (char*)input_end - (char*) input ) >= (16*stbir__simdfX_float_count) ) { stbir__simdfX o0, o1, o2, o3, r0, r1, r2, r3; STBIR_SIMD_NO_UNROLL(output0); @@ -9621,52 +9863,53 @@ static void STBIR_chans( stbir__vertical_scatter_with_,_coeffs)( float ** output #ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE stbIF0( stbir__simdfX_load( o0, output0 ); stbir__simdfX_load( o1, output0+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output0+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output0+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c0 ); stbir__simdfX_madd( o1, o1, r1, c0 ); stbir__simdfX_madd( o2, o2, r2, c0 ); stbir__simdfX_madd( o3, o3, r3, c0 ); + stbir__simdfX_madd( o0, o0, r0, c0 ); stbir__simdfX_madd( o1, o1, r1, c0 ); stbir__simdfX_madd( o2, o2, r2, c0 ); stbir__simdfX_madd( o3, o3, r3, c0 ); stbir__simdfX_store( output0, o0 ); stbir__simdfX_store( output0+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output0+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output0+(3*stbir__simdfX_float_count), o3 ); ) stbIF1( stbir__simdfX_load( o0, output1 ); stbir__simdfX_load( o1, output1+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output1+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output1+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c1 ); stbir__simdfX_madd( o1, o1, r1, c1 ); stbir__simdfX_madd( o2, o2, r2, c1 ); stbir__simdfX_madd( o3, o3, r3, c1 ); + stbir__simdfX_madd( o0, o0, r0, c1 ); stbir__simdfX_madd( o1, o1, r1, c1 ); stbir__simdfX_madd( o2, o2, r2, c1 ); stbir__simdfX_madd( o3, o3, r3, c1 ); stbir__simdfX_store( output1, o0 ); stbir__simdfX_store( output1+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output1+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output1+(3*stbir__simdfX_float_count), o3 ); ) stbIF2( stbir__simdfX_load( o0, output2 ); stbir__simdfX_load( o1, output2+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output2+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output2+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c2 ); stbir__simdfX_madd( o1, o1, r1, c2 ); stbir__simdfX_madd( o2, o2, r2, c2 ); stbir__simdfX_madd( o3, o3, r3, c2 ); + stbir__simdfX_madd( o0, o0, r0, c2 ); stbir__simdfX_madd( o1, o1, r1, c2 ); stbir__simdfX_madd( o2, o2, r2, c2 ); stbir__simdfX_madd( o3, o3, r3, c2 ); stbir__simdfX_store( output2, o0 ); stbir__simdfX_store( output2+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output2+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output2+(3*stbir__simdfX_float_count), o3 ); ) stbIF3( stbir__simdfX_load( o0, output3 ); stbir__simdfX_load( o1, output3+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output3+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output3+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c3 ); stbir__simdfX_madd( o1, o1, r1, c3 ); stbir__simdfX_madd( o2, o2, r2, c3 ); stbir__simdfX_madd( o3, o3, r3, c3 ); + stbir__simdfX_madd( o0, o0, r0, c3 ); stbir__simdfX_madd( o1, o1, r1, c3 ); stbir__simdfX_madd( o2, o2, r2, c3 ); stbir__simdfX_madd( o3, o3, r3, c3 ); stbir__simdfX_store( output3, o0 ); stbir__simdfX_store( output3+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output3+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output3+(3*stbir__simdfX_float_count), o3 ); ) stbIF4( stbir__simdfX_load( o0, output4 ); stbir__simdfX_load( o1, output4+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output4+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output4+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c4 ); stbir__simdfX_madd( o1, o1, r1, c4 ); stbir__simdfX_madd( o2, o2, r2, c4 ); stbir__simdfX_madd( o3, o3, r3, c4 ); + stbir__simdfX_madd( o0, o0, r0, c4 ); stbir__simdfX_madd( o1, o1, r1, c4 ); stbir__simdfX_madd( o2, o2, r2, c4 ); stbir__simdfX_madd( o3, o3, r3, c4 ); stbir__simdfX_store( output4, o0 ); stbir__simdfX_store( output4+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output4+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output4+(3*stbir__simdfX_float_count), o3 ); ) stbIF5( stbir__simdfX_load( o0, output5 ); stbir__simdfX_load( o1, output5+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output5+(2*stbir__simdfX_float_count)); stbir__simdfX_load( o3, output5+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c5 ); stbir__simdfX_madd( o1, o1, r1, c5 ); stbir__simdfX_madd( o2, o2, r2, c5 ); stbir__simdfX_madd( o3, o3, r3, c5 ); + stbir__simdfX_madd( o0, o0, r0, c5 ); stbir__simdfX_madd( o1, o1, r1, c5 ); stbir__simdfX_madd( o2, o2, r2, c5 ); stbir__simdfX_madd( o3, o3, r3, c5 ); stbir__simdfX_store( output5, o0 ); stbir__simdfX_store( output5+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output5+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output5+(3*stbir__simdfX_float_count), o3 ); ) stbIF6( stbir__simdfX_load( o0, output6 ); stbir__simdfX_load( o1, output6+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output6+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output6+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c6 ); stbir__simdfX_madd( o1, o1, r1, c6 ); stbir__simdfX_madd( o2, o2, r2, c6 ); stbir__simdfX_madd( o3, o3, r3, c6 ); + stbir__simdfX_madd( o0, o0, r0, c6 ); stbir__simdfX_madd( o1, o1, r1, c6 ); stbir__simdfX_madd( o2, o2, r2, c6 ); stbir__simdfX_madd( o3, o3, r3, c6 ); stbir__simdfX_store( output6, o0 ); stbir__simdfX_store( output6+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output6+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output6+(3*stbir__simdfX_float_count), o3 ); ) stbIF7( stbir__simdfX_load( o0, output7 ); stbir__simdfX_load( o1, output7+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output7+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output7+(3*stbir__simdfX_float_count) ); - stbir__simdfX_madd( o0, o0, r0, c7 ); stbir__simdfX_madd( o1, o1, r1, c7 ); stbir__simdfX_madd( o2, o2, r2, c7 ); stbir__simdfX_madd( o3, o3, r3, c7 ); + stbir__simdfX_madd( o0, o0, r0, c7 ); stbir__simdfX_madd( o1, o1, r1, c7 ); stbir__simdfX_madd( o2, o2, r2, c7 ); stbir__simdfX_madd( o3, o3, r3, c7 ); stbir__simdfX_store( output7, o0 ); stbir__simdfX_store( output7+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output7+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output7+(3*stbir__simdfX_float_count), o3 ); ) #else - stbIF0( stbir__simdfX_mult( o0, r0, c0 ); stbir__simdfX_mult( o1, r1, c0 ); stbir__simdfX_mult( o2, r2, c0 ); stbir__simdfX_mult( o3, r3, c0 ); + stbIF0( stbir__simdfX_mult( o0, r0, c0 ); stbir__simdfX_mult( o1, r1, c0 ); stbir__simdfX_mult( o2, r2, c0 ); stbir__simdfX_mult( o3, r3, c0 ); stbir__simdfX_store( output0, o0 ); stbir__simdfX_store( output0+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output0+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output0+(3*stbir__simdfX_float_count), o3 ); ) - stbIF1( stbir__simdfX_mult( o0, r0, c1 ); stbir__simdfX_mult( o1, r1, c1 ); stbir__simdfX_mult( o2, r2, c1 ); stbir__simdfX_mult( o3, r3, c1 ); + stbIF1( stbir__simdfX_mult( o0, r0, c1 ); stbir__simdfX_mult( o1, r1, c1 ); stbir__simdfX_mult( o2, r2, c1 ); stbir__simdfX_mult( o3, r3, c1 ); stbir__simdfX_store( output1, o0 ); stbir__simdfX_store( output1+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output1+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output1+(3*stbir__simdfX_float_count), o3 ); ) - stbIF2( stbir__simdfX_mult( o0, r0, c2 ); stbir__simdfX_mult( o1, r1, c2 ); stbir__simdfX_mult( o2, r2, c2 ); stbir__simdfX_mult( o3, r3, c2 ); + stbIF2( stbir__simdfX_mult( o0, r0, c2 ); stbir__simdfX_mult( o1, r1, c2 ); stbir__simdfX_mult( o2, r2, c2 ); stbir__simdfX_mult( o3, r3, c2 ); stbir__simdfX_store( output2, o0 ); stbir__simdfX_store( output2+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output2+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output2+(3*stbir__simdfX_float_count), o3 ); ) - stbIF3( stbir__simdfX_mult( o0, r0, c3 ); stbir__simdfX_mult( o1, r1, c3 ); stbir__simdfX_mult( o2, r2, c3 ); stbir__simdfX_mult( o3, r3, c3 ); + stbIF3( stbir__simdfX_mult( o0, r0, c3 ); stbir__simdfX_mult( o1, r1, c3 ); stbir__simdfX_mult( o2, r2, c3 ); stbir__simdfX_mult( o3, r3, c3 ); stbir__simdfX_store( output3, o0 ); stbir__simdfX_store( output3+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output3+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output3+(3*stbir__simdfX_float_count), o3 ); ) - stbIF4( stbir__simdfX_mult( o0, r0, c4 ); stbir__simdfX_mult( o1, r1, c4 ); stbir__simdfX_mult( o2, r2, c4 ); stbir__simdfX_mult( o3, r3, c4 ); + stbIF4( stbir__simdfX_mult( o0, r0, c4 ); stbir__simdfX_mult( o1, r1, c4 ); stbir__simdfX_mult( o2, r2, c4 ); stbir__simdfX_mult( o3, r3, c4 ); stbir__simdfX_store( output4, o0 ); stbir__simdfX_store( output4+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output4+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output4+(3*stbir__simdfX_float_count), o3 ); ) - stbIF5( stbir__simdfX_mult( o0, r0, c5 ); stbir__simdfX_mult( o1, r1, c5 ); stbir__simdfX_mult( o2, r2, c5 ); stbir__simdfX_mult( o3, r3, c5 ); + stbIF5( stbir__simdfX_mult( o0, r0, c5 ); stbir__simdfX_mult( o1, r1, c5 ); stbir__simdfX_mult( o2, r2, c5 ); stbir__simdfX_mult( o3, r3, c5 ); stbir__simdfX_store( output5, o0 ); stbir__simdfX_store( output5+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output5+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output5+(3*stbir__simdfX_float_count), o3 ); ) - stbIF6( stbir__simdfX_mult( o0, r0, c6 ); stbir__simdfX_mult( o1, r1, c6 ); stbir__simdfX_mult( o2, r2, c6 ); stbir__simdfX_mult( o3, r3, c6 ); + stbIF6( stbir__simdfX_mult( o0, r0, c6 ); stbir__simdfX_mult( o1, r1, c6 ); stbir__simdfX_mult( o2, r2, c6 ); stbir__simdfX_mult( o3, r3, c6 ); stbir__simdfX_store( output6, o0 ); stbir__simdfX_store( output6+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output6+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output6+(3*stbir__simdfX_float_count), o3 ); ) - stbIF7( stbir__simdfX_mult( o0, r0, c7 ); stbir__simdfX_mult( o1, r1, c7 ); stbir__simdfX_mult( o2, r2, c7 ); stbir__simdfX_mult( o3, r3, c7 ); + stbIF7( stbir__simdfX_mult( o0, r0, c7 ); stbir__simdfX_mult( o1, r1, c7 ); stbir__simdfX_mult( o2, r2, c7 ); stbir__simdfX_mult( o3, r3, c7 ); stbir__simdfX_store( output7, o0 ); stbir__simdfX_store( output7+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output7+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output7+(3*stbir__simdfX_float_count), o3 ); ) #endif input += (4*stbir__simdfX_float_count); stbIF0( output0 += (4*stbir__simdfX_float_count); ) stbIF1( output1 += (4*stbir__simdfX_float_count); ) stbIF2( output2 += (4*stbir__simdfX_float_count); ) stbIF3( output3 += (4*stbir__simdfX_float_count); ) stbIF4( output4 += (4*stbir__simdfX_float_count); ) stbIF5( output5 += (4*stbir__simdfX_float_count); ) stbIF6( output6 += (4*stbir__simdfX_float_count); ) stbIF7( output7 += (4*stbir__simdfX_float_count); ) } - while ( ( (char*)input_end - (char*) input ) >= 16 ) + STBIR_SIMD_NO_UNROLL_LOOP_START + while ( ( (char*)input_end - (char*) input ) >= 16 ) { stbir__simdf o0, r0; STBIR_SIMD_NO_UNROLL(output0); @@ -9692,13 +9935,14 @@ static void STBIR_chans( stbir__vertical_scatter_with_,_coeffs)( float ** output stbIF6( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c6 ) ); stbir__simdf_store( output6, o0 ); ) stbIF7( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c7 ) ); stbir__simdf_store( output7, o0 ); ) #endif - + input += 4; stbIF0( output0 += 4; ) stbIF1( output1 += 4; ) stbIF2( output2 += 4; ) stbIF3( output3 += 4; ) stbIF4( output4 += 4; ) stbIF5( output5 += 4; ) stbIF6( output6 += 4; ) stbIF7( output7 += 4; ) } } #else - while ( ( (char*)input_end - (char*) input ) >= 16 ) + STBIR_NO_UNROLL_LOOP_START + while ( ( (char*)input_end - (char*) input ) >= 16 ) { float r0, r1, r2, r3; STBIR_NO_UNROLL(input); @@ -9729,7 +9973,8 @@ static void STBIR_chans( stbir__vertical_scatter_with_,_coeffs)( float ** output stbIF0( output0 += 4; ) stbIF1( output1 += 4; ) stbIF2( output2 += 4; ) stbIF3( output3 += 4; ) stbIF4( output4 += 4; ) stbIF5( output5 += 4; ) stbIF6( output6 += 4; ) stbIF7( output7 += 4; ) } #endif - while ( input < input_end ) + STBIR_NO_UNROLL_LOOP_START + while ( input < input_end ) { float r = input[0]; STBIR_NO_UNROLL(output0); @@ -9779,7 +10024,7 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, STBIR_MEMCPY( output, input0, (char*)input0_end - (char*)input0 ); return; } -#endif +#endif #ifdef STBIR_SIMD { @@ -9791,14 +10036,15 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, stbIF5(stbir__simdfX c5 = stbir__simdf_frepX( c5s ); ) stbIF6(stbir__simdfX c6 = stbir__simdf_frepX( c6s ); ) stbIF7(stbir__simdfX c7 = stbir__simdf_frepX( c7s ); ) - - while ( ( (char*)input0_end - (char*) input0 ) >= (16*stbir__simdfX_float_count) ) + + STBIR_SIMD_NO_UNROLL_LOOP_START + while ( ( (char*)input0_end - (char*) input0 ) >= (16*stbir__simdfX_float_count) ) { stbir__simdfX o0, o1, o2, o3, r0, r1, r2, r3; STBIR_SIMD_NO_UNROLL(output); // prefetch four loop iterations ahead (doesn't affect much for small resizes, but helps with big ones) - stbIF0( stbir__prefetch( input0 + (16*stbir__simdfX_float_count) ); ) + stbIF0( stbir__prefetch( input0 + (16*stbir__simdfX_float_count) ); ) stbIF1( stbir__prefetch( input1 + (16*stbir__simdfX_float_count) ); ) stbIF2( stbir__prefetch( input2 + (16*stbir__simdfX_float_count) ); ) stbIF3( stbir__prefetch( input3 + (16*stbir__simdfX_float_count) ); ) @@ -9836,7 +10082,8 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, stbIF0( input0 += (4*stbir__simdfX_float_count); ) stbIF1( input1 += (4*stbir__simdfX_float_count); ) stbIF2( input2 += (4*stbir__simdfX_float_count); ) stbIF3( input3 += (4*stbir__simdfX_float_count); ) stbIF4( input4 += (4*stbir__simdfX_float_count); ) stbIF5( input5 += (4*stbir__simdfX_float_count); ) stbIF6( input6 += (4*stbir__simdfX_float_count); ) stbIF7( input7 += (4*stbir__simdfX_float_count); ) } - while ( ( (char*)input0_end - (char*) input0 ) >= 16 ) + STBIR_SIMD_NO_UNROLL_LOOP_START + while ( ( (char*)input0_end - (char*) input0 ) >= 16 ) { stbir__simdf o0, r0; STBIR_SIMD_NO_UNROLL(output); @@ -9860,7 +10107,8 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, } } #else - while ( ( (char*)input0_end - (char*) input0 ) >= 16 ) + STBIR_NO_UNROLL_LOOP_START + while ( ( (char*)input0_end - (char*) input0 ) >= 16 ) { float o0, o1, o2, o3; STBIR_NO_UNROLL(output); @@ -9881,7 +10129,8 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, stbIF0( input0 += 4; ) stbIF1( input1 += 4; ) stbIF2( input2 += 4; ) stbIF3( input3 += 4; ) stbIF4( input4 += 4; ) stbIF5( input5 += 4; ) stbIF6( input6 += 4; ) stbIF7( input7 += 4; ) } #endif - while ( input0 < input0_end ) + STBIR_NO_UNROLL_LOOP_START + while ( input0 < input0_end ) { float o0; STBIR_NO_UNROLL(output); @@ -9897,7 +10146,7 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, stbIF5( o0 += input5[0] * c5s; ) stbIF6( o0 += input6[0] * c6s; ) stbIF7( o0 += input7[0] * c7s; ) - output[0] = o0; + output[0] = o0; ++output; stbIF0( ++input0; ) stbIF1( ++input1; ) stbIF2( ++input2; ) stbIF3( ++input3; ) stbIF4( ++input4; ) stbIF5( ++input5; ) stbIF6( ++input6; ) stbIF7( ++input7; ) } @@ -9928,25 +10177,25 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, #ifndef stbir__2_coeff_only #define stbir__2_coeff_only() \ stbir__1_coeff_only(); \ - stbir__1_coeff_remnant(1); + stbir__1_coeff_remnant(1); #endif #ifndef stbir__2_coeff_remnant #define stbir__2_coeff_remnant( ofs ) \ stbir__1_coeff_remnant(ofs); \ - stbir__1_coeff_remnant((ofs)+1); + stbir__1_coeff_remnant((ofs)+1); #endif - + #ifndef stbir__3_coeff_only #define stbir__3_coeff_only() \ stbir__2_coeff_only(); \ - stbir__1_coeff_remnant(2); + stbir__1_coeff_remnant(2); #endif - + #ifndef stbir__3_coeff_remnant #define stbir__3_coeff_remnant( ofs ) \ stbir__2_coeff_remnant(ofs); \ - stbir__1_coeff_remnant((ofs)+2); + stbir__1_coeff_remnant((ofs)+2); #endif #ifndef stbir__3_coeff_setup @@ -9956,13 +10205,13 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp, #ifndef stbir__4_coeff_start #define stbir__4_coeff_start() \ stbir__2_coeff_only(); \ - stbir__2_coeff_remnant(2); + stbir__2_coeff_remnant(2); #endif - + #ifndef stbir__4_coeff_continue_from_4 #define stbir__4_coeff_continue_from_4( ofs ) \ stbir__2_coeff_remnant(ofs); \ - stbir__2_coeff_remnant((ofs)+2); + stbir__2_coeff_remnant((ofs)+2); #endif #ifndef stbir__store_output_tiny @@ -9973,8 +10222,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_1_coeff)( floa { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__1_coeff_only(); stbir__store_output_tiny(); @@ -9985,8 +10235,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_2_coeffs)( flo { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__2_coeff_only(); stbir__store_output_tiny(); @@ -9997,8 +10248,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_3_coeffs)( flo { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__3_coeff_only(); stbir__store_output_tiny(); @@ -10009,8 +10261,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_4_coeffs)( flo { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); stbir__store_output(); @@ -10021,8 +10274,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_5_coeffs)( flo { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); stbir__1_coeff_remnant(4); @@ -10034,8 +10288,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_6_coeffs)( flo { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); stbir__2_coeff_remnant(4); @@ -10048,10 +10303,11 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_7_coeffs)( flo float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; stbir__3_coeff_setup(); + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; - + stbir__4_coeff_start(); stbir__3_coeff_remnant(4); stbir__store_output(); @@ -10062,8 +10318,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_8_coeffs)( flo { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); stbir__4_coeff_continue_from_4(4); @@ -10075,8 +10332,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_9_coeffs)( flo { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); stbir__4_coeff_continue_from_4(4); @@ -10089,8 +10347,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_10_coeffs)( fl { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); stbir__4_coeff_continue_from_4(4); @@ -10104,8 +10363,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_11_coeffs)( fl float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; stbir__3_coeff_setup(); + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); stbir__4_coeff_continue_from_4(4); @@ -10118,8 +10378,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_12_coeffs)( fl { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); stbir__4_coeff_continue_from_4(4); @@ -10132,12 +10393,14 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod0 { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 4 + 3 ) >> 2; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 4 + 3 ) >> 2; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); + STBIR_SIMD_NO_UNROLL_LOOP_START do { hc += 4; decode += STBIR__horizontal_channels * 4; @@ -10152,19 +10415,21 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod1 { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 5 + 3 ) >> 2; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 5 + 3 ) >> 2; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); + STBIR_SIMD_NO_UNROLL_LOOP_START do { hc += 4; decode += STBIR__horizontal_channels * 4; stbir__4_coeff_continue_from_4( 0 ); --n; } while ( n > 0 ); - stbir__1_coeff_remnant( 4 ); + stbir__1_coeff_remnant( 4 ); stbir__store_output(); } while ( output < output_end ); } @@ -10173,19 +10438,21 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod2 { float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 6 + 3 ) >> 2; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 6 + 3 ) >> 2; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); + STBIR_SIMD_NO_UNROLL_LOOP_START do { hc += 4; decode += STBIR__horizontal_channels * 4; stbir__4_coeff_continue_from_4( 0 ); --n; } while ( n > 0 ); - stbir__2_coeff_remnant( 4 ); + stbir__2_coeff_remnant( 4 ); stbir__store_output(); } while ( output < output_end ); @@ -10196,19 +10463,21 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod3 float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels; float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer; stbir__3_coeff_setup(); + STBIR_SIMD_NO_UNROLL_LOOP_START do { - float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; - int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 7 + 3 ) >> 2; + float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels; + int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 7 + 3 ) >> 2; float const * hc = horizontal_coefficients; stbir__4_coeff_start(); + STBIR_SIMD_NO_UNROLL_LOOP_START do { hc += 4; decode += STBIR__horizontal_channels * 4; stbir__4_coeff_continue_from_4( 0 ); --n; } while ( n > 0 ); - stbir__3_coeff_remnant( 4 ); + stbir__3_coeff_remnant( 4 ); stbir__store_output(); } while ( output < output_end ); @@ -10216,26 +10485,26 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod3 static stbir__horizontal_gather_channels_func * STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_funcs)[4]= { - STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod0), - STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod1), - STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod2), - STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod3), + STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod0), + STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod1), + STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod2), + STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod3), }; static stbir__horizontal_gather_channels_func * STBIR_chans(stbir__horizontal_gather_,_channels_funcs)[12]= { - STBIR_chans(stbir__horizontal_gather_,_channels_with_1_coeff), - STBIR_chans(stbir__horizontal_gather_,_channels_with_2_coeffs), + STBIR_chans(stbir__horizontal_gather_,_channels_with_1_coeff), + STBIR_chans(stbir__horizontal_gather_,_channels_with_2_coeffs), STBIR_chans(stbir__horizontal_gather_,_channels_with_3_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_4_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_5_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_6_coeffs), + STBIR_chans(stbir__horizontal_gather_,_channels_with_4_coeffs), + STBIR_chans(stbir__horizontal_gather_,_channels_with_5_coeffs), + STBIR_chans(stbir__horizontal_gather_,_channels_with_6_coeffs), STBIR_chans(stbir__horizontal_gather_,_channels_with_7_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_8_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_9_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_10_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_11_coeffs), - STBIR_chans(stbir__horizontal_gather_,_channels_with_12_coeffs), + STBIR_chans(stbir__horizontal_gather_,_channels_with_8_coeffs), + STBIR_chans(stbir__horizontal_gather_,_channels_with_9_coeffs), + STBIR_chans(stbir__horizontal_gather_,_channels_with_10_coeffs), + STBIR_chans(stbir__horizontal_gather_,_channels_with_11_coeffs), + STBIR_chans(stbir__horizontal_gather_,_channels_with_12_coeffs), }; #undef STBIR__horizontal_channels @@ -10266,38 +10535,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. ------------------------------------------------------------------------------ */ From fd961deba76c7c4939440fa6e6574eb86e68c5fb Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 10 Sep 2024 00:44:25 -0500 Subject: [PATCH 023/115] Update BINDINGS.md (#4311) I've updated the bindings --- BINDINGS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BINDINGS.md b/BINDINGS.md index 7fd0dfd93..2c986f236 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -9,7 +9,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers | [raylib](https://github.com/raysan5/raylib) | **5.0** | [C/C++](https://en.wikipedia.org/wiki/C_(programming_language)) | Zlib | | [raylib-beef](https://github.com/Starpelly/raylib-beef) | **5.0** | [Beef](https://www.beeflang.org) | MIT | | [raylib-boo](https://github.com/Rabios/raylib-boo) | 3.7 | [Boo](http://boo-language.github.io) | MIT | -| [raybit](https://github.com/Alex-Velez/raybit) | 3.7 | [Brainfuck](https://en.wikipedia.org/wiki/Brainfuck) | MIT | +| [raybit](https://github.com/Alex-Velez/raybit) | **5.0** | [Brainfuck](https://en.wikipedia.org/wiki/Brainfuck) | MIT | | [Raylib-cs](https://github.com/ChrisDill/Raylib-cs) | **5.0** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | Zlib | | [Raylib-CsLo](https://github.com/NotNotTech/Raylib-CsLo) | 4.2 | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | MPL-2.0 | | [Raylib-CSharp-Vinculum](https://github.com/ZeroElectric/Raylib-CSharp-Vinculum) | **5.0** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | MPL-2.0 | From ed702673ea0ff49da2ca494686814376ad040941 Mon Sep 17 00:00:00 2001 From: Jett <30197659+JettMonstersGoBoom@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:57:19 -0400 Subject: [PATCH 024/115] fix for hardcoded index values in vboID array (#4312) changing any of the #defines in CONFIG.H would cause issues when rendering. --- src/config.h | 1 + src/rmodels.c | 60 +++++++++++++++++++++++++-------------------------- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/config.h b/src/config.h index c54583e74..9cbe90e35 100644 --- a/src/config.h +++ b/src/config.h @@ -119,6 +119,7 @@ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3 #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4 #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6 // 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 diff --git a/src/rmodels.c b/src/rmodels.c index 5fb512403..9994ddb76 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1246,13 +1246,13 @@ void UploadMesh(Mesh *mesh, bool dynamic) mesh->vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VERTEX_BUFFERS, sizeof(unsigned int)); mesh->vaoId = 0; // Vertex Array Object - mesh->vboId[0] = 0; // Vertex buffer: positions - mesh->vboId[1] = 0; // Vertex buffer: texcoords - mesh->vboId[2] = 0; // Vertex buffer: normals - mesh->vboId[3] = 0; // Vertex buffer: colors - mesh->vboId[4] = 0; // Vertex buffer: tangents - mesh->vboId[5] = 0; // Vertex buffer: texcoords2 - mesh->vboId[6] = 0; // Vertex buffer: indices + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION] = 0; // Vertex buffer: positions + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = 0; // Vertex buffer: texcoords + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = 0; // Vertex buffer: normals + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] = 0; // Vertex buffer: colors + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = 0; // Vertex buffer: tangents + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = 0; // Vertex buffer: texcoords2 + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = 0; // Vertex buffer: indices #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) mesh->vaoId = rlLoadVertexArray(); @@ -1262,12 +1262,12 @@ void UploadMesh(Mesh *mesh, bool dynamic) // Enable vertex attributes: position (shader-location = 0) void *vertices = (mesh->animVertices != NULL)? mesh->animVertices : mesh->vertices; - mesh->vboId[0] = rlLoadVertexBuffer(vertices, mesh->vertexCount*3*sizeof(float), dynamic); + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION] = rlLoadVertexBuffer(vertices, mesh->vertexCount*3*sizeof(float), dynamic); rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, 3, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION); // Enable vertex attributes: texcoords (shader-location = 1) - mesh->vboId[1] = rlLoadVertexBuffer(mesh->texcoords, mesh->vertexCount*2*sizeof(float), dynamic); + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = rlLoadVertexBuffer(mesh->texcoords, mesh->vertexCount*2*sizeof(float), dynamic); rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, 2, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD); @@ -1278,7 +1278,7 @@ void UploadMesh(Mesh *mesh, bool dynamic) { // Enable vertex attributes: normals (shader-location = 2) void *normals = (mesh->animNormals != NULL)? mesh->animNormals : mesh->normals; - mesh->vboId[2] = rlLoadVertexBuffer(normals, mesh->vertexCount*3*sizeof(float), dynamic); + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = rlLoadVertexBuffer(normals, mesh->vertexCount*3*sizeof(float), dynamic); rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, 3, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL); } @@ -1294,7 +1294,7 @@ void UploadMesh(Mesh *mesh, bool dynamic) if (mesh->colors != NULL) { // Enable vertex attribute: color (shader-location = 3) - mesh->vboId[3] = rlLoadVertexBuffer(mesh->colors, mesh->vertexCount*4*sizeof(unsigned char), dynamic); + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] = rlLoadVertexBuffer(mesh->colors, mesh->vertexCount*4*sizeof(unsigned char), dynamic); rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, 4, RL_UNSIGNED_BYTE, 1, 0, 0); rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR); } @@ -1310,7 +1310,7 @@ void UploadMesh(Mesh *mesh, bool dynamic) if (mesh->tangents != NULL) { // Enable vertex attribute: tangent (shader-location = 4) - mesh->vboId[4] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), dynamic); + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), dynamic); rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, 4, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT); } @@ -1326,7 +1326,7 @@ void UploadMesh(Mesh *mesh, bool dynamic) if (mesh->texcoords2 != NULL) { // Enable vertex attribute: texcoord2 (shader-location = 5) - mesh->vboId[5] = rlLoadVertexBuffer(mesh->texcoords2, mesh->vertexCount*2*sizeof(float), dynamic); + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = rlLoadVertexBuffer(mesh->texcoords2, mesh->vertexCount*2*sizeof(float), dynamic); rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, 2, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2); } @@ -1341,7 +1341,7 @@ void UploadMesh(Mesh *mesh, bool dynamic) if (mesh->indices != NULL) { - mesh->vboId[6] = rlLoadVertexBufferElement(mesh->indices, mesh->triangleCount*3*sizeof(unsigned short), dynamic); + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = rlLoadVertexBufferElement(mesh->indices, mesh->triangleCount*3*sizeof(unsigned short), dynamic); } if (mesh->vaoId > 0) TRACELOG(LOG_INFO, "VAO: [ID %i] Mesh uploaded successfully to VRAM (GPU)", mesh->vaoId); @@ -1478,19 +1478,19 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) if (!rlEnableVertexArray(mesh.vaoId)) { // Bind mesh VBO data: vertex position (shader-location = 0) - rlEnableVertexBuffer(mesh.vboId[0]); + rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]); // Bind mesh VBO data: vertex texcoords (shader-location = 1) - rlEnableVertexBuffer(mesh.vboId[1]); + rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]); if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1) { // Bind mesh VBO data: vertex normals (shader-location = 2) - rlEnableVertexBuffer(mesh.vboId[2]); + rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL], 3, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL]); } @@ -1498,9 +1498,9 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) // Bind mesh VBO data: vertex colors (shader-location = 3, if available) if (material.shader.locs[SHADER_LOC_VERTEX_COLOR] != -1) { - if (mesh.vboId[3] != 0) + if (mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] != 0) { - rlEnableVertexBuffer(mesh.vboId[3]); + rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR], 4, RL_UNSIGNED_BYTE, 1, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]); } @@ -1517,7 +1517,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) // Bind mesh VBO data: vertex tangents (shader-location = 4, if available) if (material.shader.locs[SHADER_LOC_VERTEX_TANGENT] != -1) { - rlEnableVertexBuffer(mesh.vboId[4]); + rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT], 4, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT]); } @@ -1525,12 +1525,12 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available) if (material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] != -1) { - rlEnableVertexBuffer(mesh.vboId[5]); + rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]); } - if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]); + if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]); } int eyeCount = 1; @@ -1696,19 +1696,19 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i if (!rlEnableVertexArray(mesh.vaoId)) { // Bind mesh VBO data: vertex position (shader-location = 0) - rlEnableVertexBuffer(mesh.vboId[0]); + rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]); // Bind mesh VBO data: vertex texcoords (shader-location = 1) - rlEnableVertexBuffer(mesh.vboId[1]); + rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]); if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1) { // Bind mesh VBO data: vertex normals (shader-location = 2) - rlEnableVertexBuffer(mesh.vboId[2]); + rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL], 3, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL]); } @@ -1716,9 +1716,9 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i // Bind mesh VBO data: vertex colors (shader-location = 3, if available) if (material.shader.locs[SHADER_LOC_VERTEX_COLOR] != -1) { - if (mesh.vboId[3] != 0) + if (mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] != 0) { - rlEnableVertexBuffer(mesh.vboId[3]); + rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR], 4, RL_UNSIGNED_BYTE, 1, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]); } @@ -1735,7 +1735,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i // Bind mesh VBO data: vertex tangents (shader-location = 4, if available) if (material.shader.locs[SHADER_LOC_VERTEX_TANGENT] != -1) { - rlEnableVertexBuffer(mesh.vboId[4]); + rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT], 4, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT]); } @@ -1743,12 +1743,12 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available) if (material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] != -1) { - rlEnableVertexBuffer(mesh.vboId[5]); + rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2]); rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]); } - if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]); + if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]); } int eyeCount = 1; From d02fcc5262f5b359b3645614a90d1e613f7e7f53 Mon Sep 17 00:00:00 2001 From: base Date: Sun, 15 Sep 2024 07:51:20 -0300 Subject: [PATCH 025/115] chore: GetApplicationDirectory definition for FreeBSD (#4318) --- src/rcore.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/rcore.c b/src/rcore.c index 972d58600..44dfd746f 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -165,6 +165,10 @@ unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod); unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); #elif defined(__linux__) #include +#elif defined(__FreeBSD__) + #include + #include + #include #elif defined(__APPLE__) #include #include @@ -2161,6 +2165,28 @@ const char *GetApplicationDirectory(void) appDir[0] = '.'; appDir[1] = '/'; } +#elif defined(__FreeBSD__) + size_t size = sizeof(appDir); + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; + + if (sysctl(mib, 4, appDir, &size, NULL, 0) == 0) + { + int len = strlen(appDir); + for (int i = len; i >= 0; --i) + { + if (appDir[i] == '/') + { + appDir[i + 1] = '\0'; + break; + } + } + } + else + { + appDir[0] = '.'; + appDir[1] = '/'; + } + #endif return appDir; From ddc523ffbe8a0af2e4783d947cdff6c9c53f7048 Mon Sep 17 00:00:00 2001 From: SusgUY446 <129160115+SusgUY446@users.noreply.github.com> Date: Sun, 15 Sep 2024 12:55:45 +0200 Subject: [PATCH 026/115] [rtextures] add MixColors. a function to mix 2 colors together (#4310) * added MixColors function to mix 2 colors together (Line 1428 raylib.h and Line 4995 in rtextures.c) * renamed MixColors to ColorLerp (https://github.com/raysan5/raylib/pull/4310#issuecomment-2340121038) * changed ColorLerp to be more like other functions --------- Co-authored-by: CI <-ci@not-real.com> --- src/raylib.h | 1 + src/rtextures.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/raylib.h b/src/raylib.h index 30ba8bd2a..a9cdbe94b 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1435,6 +1435,7 @@ RLAPI Color GetColor(unsigned int hexValue); // G RLAPI Color GetPixelColor(void *srcPtr, int format); // Get Color from a source pixel pointer of certain format RLAPI void SetPixelColor(void *dstPtr, Color color, int format); // Set color formatted into destination pixel pointer RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes for certain format +RLAPI Color ColorLerp(Color color1, Color color2, float d); // Mix 2 Colors Together //------------------------------------------------------------------------------------ // Font Loading and Text Drawing Functions (Module: text) diff --git a/src/rtextures.c b/src/rtextures.c index 867add38e..f391b0d91 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -4985,6 +4985,8 @@ Vector3 ColorToHSV(Color color) return hsv; } + + // Get a Color from HSV values // Implementation reference: https://en.wikipedia.org/wiki/HSL_and_HSV#Alternative_HSV_conversion // NOTE: Color->HSV->Color conversion will not yield exactly the same color due to rounding errors @@ -5422,6 +5424,24 @@ int GetPixelDataSize(int width, int height, int format) return dataSize; } + +// Mix 2 Colors togehter. +// d = dominance. 0.5 for equal +Color ColorLerp(Color color1, Color color2, float d) +{ + Color newColor = { 0, 0, 0, 0 }; + if (d < 0) {d=0.0f;} + else if(d>1) {d=1.0f;} + + newColor.r = (unsigned char)((1.0f-d) * color1.r + d * color2.r); + newColor.g = (unsigned char)((1.0f-d) * color1.g + d * color2.g); + newColor.b = (unsigned char)((1.0f-d) * color1.b + d * color2.b); + newColor.a = (unsigned char)((1.0f-d) * color1.a + d * color2.a); + + return newColor; +} + + //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- From 68e7cadabcc4966c38251f59cb1bddb66f72bbeb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 15 Sep 2024 10:56:01 +0000 Subject: [PATCH 027/115] Update raylib_api.* by CI --- parser/output/raylib_api.json | 21 +- parser/output/raylib_api.lua | 12 +- parser/output/raylib_api.txt | 393 +++++++++++++++++----------------- parser/output/raylib_api.xml | 9 +- 4 files changed, 238 insertions(+), 197 deletions(-) diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json index 03b19325a..48096a951 100644 --- a/parser/output/raylib_api.json +++ b/parser/output/raylib_api.json @@ -8844,6 +8844,25 @@ } ] }, + { + "name": "ColorLerp", + "description": "Mix 2 Colors Together", + "returnType": "Color", + "params": [ + { + "type": "Color", + "name": "color1" + }, + { + "type": "Color", + "name": "color2" + }, + { + "type": "float", + "name": "d" + } + ] + }, { "name": "GetFontDefault", "description": "Get the default Font", @@ -8862,7 +8881,7 @@ }, { "name": "LoadFontEx", - "description": "Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character setFont", + "description": "Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height", "returnType": "Font", "params": [ { diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua index 7d74c9a41..66095be61 100644 --- a/parser/output/raylib_api.lua +++ b/parser/output/raylib_api.lua @@ -6414,6 +6414,16 @@ return { {type = "int", name = "format"} } }, + { + name = "ColorLerp", + description = "Mix 2 Colors Together", + returnType = "Color", + params = { + {type = "Color", name = "color1"}, + {type = "Color", name = "color2"}, + {type = "float", name = "d"} + } + }, { name = "GetFontDefault", description = "Get the default Font", @@ -6429,7 +6439,7 @@ return { }, { name = "LoadFontEx", - description = "Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character setFont", + description = "Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height", returnType = "Font", params = { {type = "const char *", name = "fileName"}, diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt index fb30ebe5f..6c489498b 100644 --- a/parser/output/raylib_api.txt +++ b/parser/output/raylib_api.txt @@ -984,7 +984,7 @@ Callback 006: AudioCallback() (2 input parameters) Param[1]: bufferData (type: void *) Param[2]: frames (type: unsigned int) -Functions found: 575 +Functions found: 576 Function 001: InitWindow() (3 input parameters) Name: InitWindow @@ -3393,32 +3393,39 @@ Function 384: GetPixelDataSize() (3 input parameters) Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: format (type: int) -Function 385: GetFontDefault() (0 input parameters) +Function 385: ColorLerp() (3 input parameters) + Name: ColorLerp + Return type: Color + Description: Mix 2 Colors Together + Param[1]: color1 (type: Color) + Param[2]: color2 (type: Color) + Param[3]: d (type: float) +Function 386: GetFontDefault() (0 input parameters) Name: GetFontDefault Return type: Font Description: Get the default Font No input parameters -Function 386: LoadFont() (1 input parameters) +Function 387: 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 387: LoadFontEx() (4 input parameters) +Function 388: LoadFontEx() (4 input parameters) Name: LoadFontEx Return type: Font - Description: Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character setFont + Description: Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height Param[1]: fileName (type: const char *) Param[2]: fontSize (type: int) Param[3]: codepoints (type: int *) Param[4]: codepointCount (type: int) -Function 388: LoadFontFromImage() (3 input parameters) +Function 389: 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 389: LoadFontFromMemory() (6 input parameters) +Function 390: LoadFontFromMemory() (6 input parameters) Name: LoadFontFromMemory Return type: Font Description: Load font from memory buffer, fileType refers to extension: i.e. '.ttf' @@ -3428,12 +3435,12 @@ Function 389: LoadFontFromMemory() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: codepoints (type: int *) Param[6]: codepointCount (type: int) -Function 390: IsFontReady() (1 input parameters) +Function 391: IsFontReady() (1 input parameters) Name: IsFontReady Return type: bool Description: Check if a font is ready Param[1]: font (type: Font) -Function 391: LoadFontData() (6 input parameters) +Function 392: LoadFontData() (6 input parameters) Name: LoadFontData Return type: GlyphInfo * Description: Load font data for further use @@ -3443,7 +3450,7 @@ Function 391: LoadFontData() (6 input parameters) Param[4]: codepoints (type: int *) Param[5]: codepointCount (type: int) Param[6]: type (type: int) -Function 392: GenImageFontAtlas() (6 input parameters) +Function 393: GenImageFontAtlas() (6 input parameters) Name: GenImageFontAtlas Return type: Image Description: Generate image font atlas using chars info @@ -3453,30 +3460,30 @@ Function 392: GenImageFontAtlas() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: padding (type: int) Param[6]: packMethod (type: int) -Function 393: UnloadFontData() (2 input parameters) +Function 394: UnloadFontData() (2 input parameters) Name: UnloadFontData Return type: void Description: Unload font chars info data (RAM) Param[1]: glyphs (type: GlyphInfo *) Param[2]: glyphCount (type: int) -Function 394: UnloadFont() (1 input parameters) +Function 395: UnloadFont() (1 input parameters) Name: UnloadFont Return type: void Description: Unload font from GPU memory (VRAM) Param[1]: font (type: Font) -Function 395: ExportFontAsCode() (2 input parameters) +Function 396: 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 396: DrawFPS() (2 input parameters) +Function 397: DrawFPS() (2 input parameters) Name: DrawFPS Return type: void Description: Draw current FPS Param[1]: posX (type: int) Param[2]: posY (type: int) -Function 397: DrawText() (5 input parameters) +Function 398: DrawText() (5 input parameters) Name: DrawText Return type: void Description: Draw text (using default font) @@ -3485,7 +3492,7 @@ Function 397: DrawText() (5 input parameters) Param[3]: posY (type: int) Param[4]: fontSize (type: int) Param[5]: color (type: Color) -Function 398: DrawTextEx() (6 input parameters) +Function 399: DrawTextEx() (6 input parameters) Name: DrawTextEx Return type: void Description: Draw text using font and additional parameters @@ -3495,7 +3502,7 @@ Function 398: DrawTextEx() (6 input parameters) Param[4]: fontSize (type: float) Param[5]: spacing (type: float) Param[6]: tint (type: Color) -Function 399: DrawTextPro() (8 input parameters) +Function 400: DrawTextPro() (8 input parameters) Name: DrawTextPro Return type: void Description: Draw text using Font and pro parameters (rotation) @@ -3507,7 +3514,7 @@ Function 399: DrawTextPro() (8 input parameters) Param[6]: fontSize (type: float) Param[7]: spacing (type: float) Param[8]: tint (type: Color) -Function 400: DrawTextCodepoint() (5 input parameters) +Function 401: DrawTextCodepoint() (5 input parameters) Name: DrawTextCodepoint Return type: void Description: Draw one character (codepoint) @@ -3516,7 +3523,7 @@ Function 400: DrawTextCodepoint() (5 input parameters) Param[3]: position (type: Vector2) Param[4]: fontSize (type: float) Param[5]: tint (type: Color) -Function 401: DrawTextCodepoints() (7 input parameters) +Function 402: DrawTextCodepoints() (7 input parameters) Name: DrawTextCodepoints Return type: void Description: Draw multiple character (codepoint) @@ -3527,18 +3534,18 @@ Function 401: DrawTextCodepoints() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 402: SetTextLineSpacing() (1 input parameters) +Function 403: SetTextLineSpacing() (1 input parameters) Name: SetTextLineSpacing Return type: void Description: Set vertical line spacing when drawing with line-breaks Param[1]: spacing (type: int) -Function 403: MeasureText() (2 input parameters) +Function 404: 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 404: MeasureTextEx() (4 input parameters) +Function 405: MeasureTextEx() (4 input parameters) Name: MeasureTextEx Return type: Vector2 Description: Measure string size for Font @@ -3546,195 +3553,195 @@ Function 404: MeasureTextEx() (4 input parameters) Param[2]: text (type: const char *) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) -Function 405: GetGlyphIndex() (2 input parameters) +Function 406: 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 406: GetGlyphInfo() (2 input parameters) +Function 407: 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 407: GetGlyphAtlasRec() (2 input parameters) +Function 408: 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 408: LoadUTF8() (2 input parameters) +Function 409: 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 409: UnloadUTF8() (1 input parameters) +Function 410: UnloadUTF8() (1 input parameters) Name: UnloadUTF8 Return type: void Description: Unload UTF-8 text encoded from codepoints array Param[1]: text (type: char *) -Function 410: LoadCodepoints() (2 input parameters) +Function 411: 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 411: UnloadCodepoints() (1 input parameters) +Function 412: UnloadCodepoints() (1 input parameters) Name: UnloadCodepoints Return type: void Description: Unload codepoints data from memory Param[1]: codepoints (type: int *) -Function 412: GetCodepointCount() (1 input parameters) +Function 413: 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 413: GetCodepoint() (2 input parameters) +Function 414: 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 414: GetCodepointNext() (2 input parameters) +Function 415: 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 415: GetCodepointPrevious() (2 input parameters) +Function 416: 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 416: CodepointToUTF8() (2 input parameters) +Function 417: 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 417: TextCopy() (2 input parameters) +Function 418: 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 418: TextIsEqual() (2 input parameters) +Function 419: 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 419: TextLength() (1 input parameters) +Function 420: 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 420: TextFormat() (2 input parameters) +Function 421: 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 421: TextSubtext() (3 input parameters) +Function 422: 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 422: TextReplace() (3 input parameters) +Function 423: TextReplace() (3 input parameters) Name: TextReplace Return type: char * Description: Replace text string (WARNING: memory must be freed!) Param[1]: text (type: const char *) Param[2]: replace (type: const char *) Param[3]: by (type: const char *) -Function 423: TextInsert() (3 input parameters) +Function 424: 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 424: TextJoin() (3 input parameters) +Function 425: 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 425: TextSplit() (3 input parameters) +Function 426: 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 426: TextAppend() (3 input parameters) +Function 427: 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 427: TextFindIndex() (2 input parameters) +Function 428: 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 428: TextToUpper() (1 input parameters) +Function 429: 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 429: TextToLower() (1 input parameters) +Function 430: 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 430: TextToPascal() (1 input parameters) +Function 431: 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 431: TextToSnake() (1 input parameters) +Function 432: TextToSnake() (1 input parameters) Name: TextToSnake Return type: const char * Description: Get Snake case notation version of provided string Param[1]: text (type: const char *) -Function 432: TextToCamel() (1 input parameters) +Function 433: TextToCamel() (1 input parameters) Name: TextToCamel Return type: const char * Description: Get Camel case notation version of provided string Param[1]: text (type: const char *) -Function 433: TextToInteger() (1 input parameters) +Function 434: 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 434: TextToFloat() (1 input parameters) +Function 435: TextToFloat() (1 input parameters) Name: TextToFloat Return type: float Description: Get float value from text (negative values not supported) Param[1]: text (type: const char *) -Function 435: DrawLine3D() (3 input parameters) +Function 436: 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 436: DrawPoint3D() (2 input parameters) +Function 437: 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 437: DrawCircle3D() (5 input parameters) +Function 438: DrawCircle3D() (5 input parameters) Name: DrawCircle3D Return type: void Description: Draw a circle in 3D world space @@ -3743,7 +3750,7 @@ Function 437: DrawCircle3D() (5 input parameters) Param[3]: rotationAxis (type: Vector3) Param[4]: rotationAngle (type: float) Param[5]: color (type: Color) -Function 438: DrawTriangle3D() (4 input parameters) +Function 439: DrawTriangle3D() (4 input parameters) Name: DrawTriangle3D Return type: void Description: Draw a color-filled triangle (vertex in counter-clockwise order!) @@ -3751,14 +3758,14 @@ Function 438: DrawTriangle3D() (4 input parameters) Param[2]: v2 (type: Vector3) Param[3]: v3 (type: Vector3) Param[4]: color (type: Color) -Function 439: DrawTriangleStrip3D() (3 input parameters) +Function 440: DrawTriangleStrip3D() (3 input parameters) Name: DrawTriangleStrip3D Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector3 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 440: DrawCube() (5 input parameters) +Function 441: DrawCube() (5 input parameters) Name: DrawCube Return type: void Description: Draw cube @@ -3767,14 +3774,14 @@ Function 440: DrawCube() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 441: DrawCubeV() (3 input parameters) +Function 442: 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 442: DrawCubeWires() (5 input parameters) +Function 443: DrawCubeWires() (5 input parameters) Name: DrawCubeWires Return type: void Description: Draw cube wires @@ -3783,21 +3790,21 @@ Function 442: DrawCubeWires() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 443: DrawCubeWiresV() (3 input parameters) +Function 444: 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 444: DrawSphere() (3 input parameters) +Function 445: 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 445: DrawSphereEx() (5 input parameters) +Function 446: DrawSphereEx() (5 input parameters) Name: DrawSphereEx Return type: void Description: Draw sphere with extended parameters @@ -3806,7 +3813,7 @@ Function 445: DrawSphereEx() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 446: DrawSphereWires() (5 input parameters) +Function 447: DrawSphereWires() (5 input parameters) Name: DrawSphereWires Return type: void Description: Draw sphere wires @@ -3815,7 +3822,7 @@ Function 446: DrawSphereWires() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 447: DrawCylinder() (6 input parameters) +Function 448: DrawCylinder() (6 input parameters) Name: DrawCylinder Return type: void Description: Draw a cylinder/cone @@ -3825,7 +3832,7 @@ Function 447: DrawCylinder() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 448: DrawCylinderEx() (6 input parameters) +Function 449: DrawCylinderEx() (6 input parameters) Name: DrawCylinderEx Return type: void Description: Draw a cylinder with base at startPos and top at endPos @@ -3835,7 +3842,7 @@ Function 448: DrawCylinderEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 449: DrawCylinderWires() (6 input parameters) +Function 450: DrawCylinderWires() (6 input parameters) Name: DrawCylinderWires Return type: void Description: Draw a cylinder/cone wires @@ -3845,7 +3852,7 @@ Function 449: DrawCylinderWires() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 450: DrawCylinderWiresEx() (6 input parameters) +Function 451: DrawCylinderWiresEx() (6 input parameters) Name: DrawCylinderWiresEx Return type: void Description: Draw a cylinder wires with base at startPos and top at endPos @@ -3855,7 +3862,7 @@ Function 450: DrawCylinderWiresEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 451: DrawCapsule() (6 input parameters) +Function 452: DrawCapsule() (6 input parameters) Name: DrawCapsule Return type: void Description: Draw a capsule with the center of its sphere caps at startPos and endPos @@ -3865,7 +3872,7 @@ Function 451: DrawCapsule() (6 input parameters) Param[4]: slices (type: int) Param[5]: rings (type: int) Param[6]: color (type: Color) -Function 452: DrawCapsuleWires() (6 input parameters) +Function 453: DrawCapsuleWires() (6 input parameters) Name: DrawCapsuleWires Return type: void Description: Draw capsule wireframe with the center of its sphere caps at startPos and endPos @@ -3875,51 +3882,51 @@ Function 452: DrawCapsuleWires() (6 input parameters) Param[4]: slices (type: int) Param[5]: rings (type: int) Param[6]: color (type: Color) -Function 453: DrawPlane() (3 input parameters) +Function 454: 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 454: DrawRay() (2 input parameters) +Function 455: 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 455: DrawGrid() (2 input parameters) +Function 456: 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 456: LoadModel() (1 input parameters) +Function 457: LoadModel() (1 input parameters) Name: LoadModel Return type: Model Description: Load model from files (meshes and materials) Param[1]: fileName (type: const char *) -Function 457: LoadModelFromMesh() (1 input parameters) +Function 458: LoadModelFromMesh() (1 input parameters) Name: LoadModelFromMesh Return type: Model Description: Load model from generated mesh (default material) Param[1]: mesh (type: Mesh) -Function 458: IsModelReady() (1 input parameters) +Function 459: IsModelReady() (1 input parameters) Name: IsModelReady Return type: bool Description: Check if a model is ready Param[1]: model (type: Model) -Function 459: UnloadModel() (1 input parameters) +Function 460: 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 460: GetModelBoundingBox() (1 input parameters) +Function 461: GetModelBoundingBox() (1 input parameters) Name: GetModelBoundingBox Return type: BoundingBox Description: Compute model bounding box limits (considers all meshes) Param[1]: model (type: Model) -Function 461: DrawModel() (4 input parameters) +Function 462: DrawModel() (4 input parameters) Name: DrawModel Return type: void Description: Draw a model (with texture if set) @@ -3927,7 +3934,7 @@ Function 461: DrawModel() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 462: DrawModelEx() (6 input parameters) +Function 463: DrawModelEx() (6 input parameters) Name: DrawModelEx Return type: void Description: Draw a model with extended parameters @@ -3937,7 +3944,7 @@ Function 462: DrawModelEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 463: DrawModelWires() (4 input parameters) +Function 464: DrawModelWires() (4 input parameters) Name: DrawModelWires Return type: void Description: Draw a model wires (with texture if set) @@ -3945,7 +3952,7 @@ Function 463: DrawModelWires() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 464: DrawModelWiresEx() (6 input parameters) +Function 465: DrawModelWiresEx() (6 input parameters) Name: DrawModelWiresEx Return type: void Description: Draw a model wires (with texture if set) with extended parameters @@ -3955,7 +3962,7 @@ Function 464: DrawModelWiresEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 465: DrawModelPoints() (4 input parameters) +Function 466: DrawModelPoints() (4 input parameters) Name: DrawModelPoints Return type: void Description: Draw a model as points @@ -3963,7 +3970,7 @@ Function 465: DrawModelPoints() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 466: DrawModelPointsEx() (6 input parameters) +Function 467: DrawModelPointsEx() (6 input parameters) Name: DrawModelPointsEx Return type: void Description: Draw a model as points with extended parameters @@ -3973,13 +3980,13 @@ Function 466: DrawModelPointsEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 467: DrawBoundingBox() (2 input parameters) +Function 468: 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 468: DrawBillboard() (5 input parameters) +Function 469: DrawBillboard() (5 input parameters) Name: DrawBillboard Return type: void Description: Draw a billboard texture @@ -3988,7 +3995,7 @@ Function 468: DrawBillboard() (5 input parameters) Param[3]: position (type: Vector3) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 469: DrawBillboardRec() (6 input parameters) +Function 470: DrawBillboardRec() (6 input parameters) Name: DrawBillboardRec Return type: void Description: Draw a billboard texture defined by source @@ -3998,7 +4005,7 @@ Function 469: DrawBillboardRec() (6 input parameters) Param[4]: position (type: Vector3) Param[5]: size (type: Vector2) Param[6]: tint (type: Color) -Function 470: DrawBillboardPro() (9 input parameters) +Function 471: DrawBillboardPro() (9 input parameters) Name: DrawBillboardPro Return type: void Description: Draw a billboard texture defined by source and rotation @@ -4011,13 +4018,13 @@ Function 470: DrawBillboardPro() (9 input parameters) Param[7]: origin (type: Vector2) Param[8]: rotation (type: float) Param[9]: tint (type: Color) -Function 471: UploadMesh() (2 input parameters) +Function 472: 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 472: UpdateMeshBuffer() (5 input parameters) +Function 473: UpdateMeshBuffer() (5 input parameters) Name: UpdateMeshBuffer Return type: void Description: Update mesh vertex data in GPU for a specific buffer index @@ -4026,19 +4033,19 @@ Function 472: UpdateMeshBuffer() (5 input parameters) Param[3]: data (type: const void *) Param[4]: dataSize (type: int) Param[5]: offset (type: int) -Function 473: UnloadMesh() (1 input parameters) +Function 474: UnloadMesh() (1 input parameters) Name: UnloadMesh Return type: void Description: Unload mesh data from CPU and GPU Param[1]: mesh (type: Mesh) -Function 474: DrawMesh() (3 input parameters) +Function 475: 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 475: DrawMeshInstanced() (4 input parameters) +Function 476: DrawMeshInstanced() (4 input parameters) Name: DrawMeshInstanced Return type: void Description: Draw multiple mesh instances with material and different transforms @@ -4046,35 +4053,35 @@ Function 475: DrawMeshInstanced() (4 input parameters) Param[2]: material (type: Material) Param[3]: transforms (type: const Matrix *) Param[4]: instances (type: int) -Function 476: GetMeshBoundingBox() (1 input parameters) +Function 477: GetMeshBoundingBox() (1 input parameters) Name: GetMeshBoundingBox Return type: BoundingBox Description: Compute mesh bounding box limits Param[1]: mesh (type: Mesh) -Function 477: GenMeshTangents() (1 input parameters) +Function 478: GenMeshTangents() (1 input parameters) Name: GenMeshTangents Return type: void Description: Compute mesh tangents Param[1]: mesh (type: Mesh *) -Function 478: ExportMesh() (2 input parameters) +Function 479: 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 479: ExportMeshAsCode() (2 input parameters) +Function 480: ExportMeshAsCode() (2 input parameters) Name: ExportMeshAsCode Return type: bool Description: Export mesh as code file (.h) defining multiple arrays of vertex attributes Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 480: GenMeshPoly() (2 input parameters) +Function 481: GenMeshPoly() (2 input parameters) Name: GenMeshPoly Return type: Mesh Description: Generate polygonal mesh Param[1]: sides (type: int) Param[2]: radius (type: float) -Function 481: GenMeshPlane() (4 input parameters) +Function 482: GenMeshPlane() (4 input parameters) Name: GenMeshPlane Return type: Mesh Description: Generate plane mesh (with subdivisions) @@ -4082,42 +4089,42 @@ Function 481: GenMeshPlane() (4 input parameters) Param[2]: length (type: float) Param[3]: resX (type: int) Param[4]: resZ (type: int) -Function 482: GenMeshCube() (3 input parameters) +Function 483: 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 483: GenMeshSphere() (3 input parameters) +Function 484: 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 484: GenMeshHemiSphere() (3 input parameters) +Function 485: 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 485: GenMeshCylinder() (3 input parameters) +Function 486: 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 486: GenMeshCone() (3 input parameters) +Function 487: 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 487: GenMeshTorus() (4 input parameters) +Function 488: GenMeshTorus() (4 input parameters) Name: GenMeshTorus Return type: Mesh Description: Generate torus mesh @@ -4125,7 +4132,7 @@ Function 487: GenMeshTorus() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 488: GenMeshKnot() (4 input parameters) +Function 489: GenMeshKnot() (4 input parameters) Name: GenMeshKnot Return type: Mesh Description: Generate trefoil knot mesh @@ -4133,84 +4140,84 @@ Function 488: GenMeshKnot() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 489: GenMeshHeightmap() (2 input parameters) +Function 490: 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 490: GenMeshCubicmap() (2 input parameters) +Function 491: 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 491: LoadMaterials() (2 input parameters) +Function 492: 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 492: LoadMaterialDefault() (0 input parameters) +Function 493: LoadMaterialDefault() (0 input parameters) Name: LoadMaterialDefault Return type: Material Description: Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) No input parameters -Function 493: IsMaterialReady() (1 input parameters) +Function 494: IsMaterialReady() (1 input parameters) Name: IsMaterialReady Return type: bool Description: Check if a material is ready Param[1]: material (type: Material) -Function 494: UnloadMaterial() (1 input parameters) +Function 495: UnloadMaterial() (1 input parameters) Name: UnloadMaterial Return type: void Description: Unload material from GPU memory (VRAM) Param[1]: material (type: Material) -Function 495: SetMaterialTexture() (3 input parameters) +Function 496: 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 496: SetModelMeshMaterial() (3 input parameters) +Function 497: 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 497: LoadModelAnimations() (2 input parameters) +Function 498: LoadModelAnimations() (2 input parameters) Name: LoadModelAnimations Return type: ModelAnimation * Description: Load model animations from file Param[1]: fileName (type: const char *) Param[2]: animCount (type: int *) -Function 498: UpdateModelAnimation() (3 input parameters) +Function 499: 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 499: UnloadModelAnimation() (1 input parameters) +Function 500: UnloadModelAnimation() (1 input parameters) Name: UnloadModelAnimation Return type: void Description: Unload animation data Param[1]: anim (type: ModelAnimation) -Function 500: UnloadModelAnimations() (2 input parameters) +Function 501: UnloadModelAnimations() (2 input parameters) Name: UnloadModelAnimations Return type: void Description: Unload animation array data Param[1]: animations (type: ModelAnimation *) Param[2]: animCount (type: int) -Function 501: IsModelAnimationValid() (2 input parameters) +Function 502: 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 502: CheckCollisionSpheres() (4 input parameters) +Function 503: CheckCollisionSpheres() (4 input parameters) Name: CheckCollisionSpheres Return type: bool Description: Check collision between two spheres @@ -4218,40 +4225,40 @@ Function 502: CheckCollisionSpheres() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector3) Param[4]: radius2 (type: float) -Function 503: CheckCollisionBoxes() (2 input parameters) +Function 504: 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 504: CheckCollisionBoxSphere() (3 input parameters) +Function 505: 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 505: GetRayCollisionSphere() (3 input parameters) +Function 506: 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 506: GetRayCollisionBox() (2 input parameters) +Function 507: 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 507: GetRayCollisionMesh() (3 input parameters) +Function 508: 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 508: GetRayCollisionTriangle() (4 input parameters) +Function 509: GetRayCollisionTriangle() (4 input parameters) Name: GetRayCollisionTriangle Return type: RayCollision Description: Get collision info between ray and triangle @@ -4259,7 +4266,7 @@ Function 508: GetRayCollisionTriangle() (4 input parameters) Param[2]: p1 (type: Vector3) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) -Function 509: GetRayCollisionQuad() (5 input parameters) +Function 510: GetRayCollisionQuad() (5 input parameters) Name: GetRayCollisionQuad Return type: RayCollision Description: Get collision info between ray and quad @@ -4268,158 +4275,158 @@ Function 509: GetRayCollisionQuad() (5 input parameters) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) Param[5]: p4 (type: Vector3) -Function 510: InitAudioDevice() (0 input parameters) +Function 511: InitAudioDevice() (0 input parameters) Name: InitAudioDevice Return type: void Description: Initialize audio device and context No input parameters -Function 511: CloseAudioDevice() (0 input parameters) +Function 512: CloseAudioDevice() (0 input parameters) Name: CloseAudioDevice Return type: void Description: Close the audio device and context No input parameters -Function 512: IsAudioDeviceReady() (0 input parameters) +Function 513: IsAudioDeviceReady() (0 input parameters) Name: IsAudioDeviceReady Return type: bool Description: Check if audio device has been initialized successfully No input parameters -Function 513: SetMasterVolume() (1 input parameters) +Function 514: SetMasterVolume() (1 input parameters) Name: SetMasterVolume Return type: void Description: Set master volume (listener) Param[1]: volume (type: float) -Function 514: GetMasterVolume() (0 input parameters) +Function 515: GetMasterVolume() (0 input parameters) Name: GetMasterVolume Return type: float Description: Get master volume (listener) No input parameters -Function 515: LoadWave() (1 input parameters) +Function 516: LoadWave() (1 input parameters) Name: LoadWave Return type: Wave Description: Load wave data from file Param[1]: fileName (type: const char *) -Function 516: LoadWaveFromMemory() (3 input parameters) +Function 517: 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 517: IsWaveReady() (1 input parameters) +Function 518: IsWaveReady() (1 input parameters) Name: IsWaveReady Return type: bool Description: Checks if wave data is ready Param[1]: wave (type: Wave) -Function 518: LoadSound() (1 input parameters) +Function 519: LoadSound() (1 input parameters) Name: LoadSound Return type: Sound Description: Load sound from file Param[1]: fileName (type: const char *) -Function 519: LoadSoundFromWave() (1 input parameters) +Function 520: LoadSoundFromWave() (1 input parameters) Name: LoadSoundFromWave Return type: Sound Description: Load sound from wave data Param[1]: wave (type: Wave) -Function 520: LoadSoundAlias() (1 input parameters) +Function 521: LoadSoundAlias() (1 input parameters) Name: LoadSoundAlias Return type: Sound Description: Create a new sound that shares the same sample data as the source sound, does not own the sound data Param[1]: source (type: Sound) -Function 521: IsSoundReady() (1 input parameters) +Function 522: IsSoundReady() (1 input parameters) Name: IsSoundReady Return type: bool Description: Checks if a sound is ready Param[1]: sound (type: Sound) -Function 522: UpdateSound() (3 input parameters) +Function 523: 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 523: UnloadWave() (1 input parameters) +Function 524: UnloadWave() (1 input parameters) Name: UnloadWave Return type: void Description: Unload wave data Param[1]: wave (type: Wave) -Function 524: UnloadSound() (1 input parameters) +Function 525: UnloadSound() (1 input parameters) Name: UnloadSound Return type: void Description: Unload sound Param[1]: sound (type: Sound) -Function 525: UnloadSoundAlias() (1 input parameters) +Function 526: UnloadSoundAlias() (1 input parameters) Name: UnloadSoundAlias Return type: void Description: Unload a sound alias (does not deallocate sample data) Param[1]: alias (type: Sound) -Function 526: ExportWave() (2 input parameters) +Function 527: 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 527: ExportWaveAsCode() (2 input parameters) +Function 528: 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 528: PlaySound() (1 input parameters) +Function 529: PlaySound() (1 input parameters) Name: PlaySound Return type: void Description: Play a sound Param[1]: sound (type: Sound) -Function 529: StopSound() (1 input parameters) +Function 530: StopSound() (1 input parameters) Name: StopSound Return type: void Description: Stop playing a sound Param[1]: sound (type: Sound) -Function 530: PauseSound() (1 input parameters) +Function 531: PauseSound() (1 input parameters) Name: PauseSound Return type: void Description: Pause a sound Param[1]: sound (type: Sound) -Function 531: ResumeSound() (1 input parameters) +Function 532: ResumeSound() (1 input parameters) Name: ResumeSound Return type: void Description: Resume a paused sound Param[1]: sound (type: Sound) -Function 532: IsSoundPlaying() (1 input parameters) +Function 533: IsSoundPlaying() (1 input parameters) Name: IsSoundPlaying Return type: bool Description: Check if a sound is currently playing Param[1]: sound (type: Sound) -Function 533: SetSoundVolume() (2 input parameters) +Function 534: 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 534: SetSoundPitch() (2 input parameters) +Function 535: 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 535: SetSoundPan() (2 input parameters) +Function 536: 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 536: WaveCopy() (1 input parameters) +Function 537: WaveCopy() (1 input parameters) Name: WaveCopy Return type: Wave Description: Copy a wave to a new wave Param[1]: wave (type: Wave) -Function 537: WaveCrop() (3 input parameters) +Function 538: WaveCrop() (3 input parameters) Name: WaveCrop Return type: void Description: Crop a wave to defined frames range Param[1]: wave (type: Wave *) Param[2]: initFrame (type: int) Param[3]: finalFrame (type: int) -Function 538: WaveFormat() (4 input parameters) +Function 539: WaveFormat() (4 input parameters) Name: WaveFormat Return type: void Description: Convert wave data to desired format @@ -4427,203 +4434,203 @@ Function 538: WaveFormat() (4 input parameters) Param[2]: sampleRate (type: int) Param[3]: sampleSize (type: int) Param[4]: channels (type: int) -Function 539: LoadWaveSamples() (1 input parameters) +Function 540: 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 540: UnloadWaveSamples() (1 input parameters) +Function 541: UnloadWaveSamples() (1 input parameters) Name: UnloadWaveSamples Return type: void Description: Unload samples data loaded with LoadWaveSamples() Param[1]: samples (type: float *) -Function 541: LoadMusicStream() (1 input parameters) +Function 542: LoadMusicStream() (1 input parameters) Name: LoadMusicStream Return type: Music Description: Load music stream from file Param[1]: fileName (type: const char *) -Function 542: LoadMusicStreamFromMemory() (3 input parameters) +Function 543: 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 543: IsMusicReady() (1 input parameters) +Function 544: IsMusicReady() (1 input parameters) Name: IsMusicReady Return type: bool Description: Checks if a music stream is ready Param[1]: music (type: Music) -Function 544: UnloadMusicStream() (1 input parameters) +Function 545: UnloadMusicStream() (1 input parameters) Name: UnloadMusicStream Return type: void Description: Unload music stream Param[1]: music (type: Music) -Function 545: PlayMusicStream() (1 input parameters) +Function 546: PlayMusicStream() (1 input parameters) Name: PlayMusicStream Return type: void Description: Start music playing Param[1]: music (type: Music) -Function 546: IsMusicStreamPlaying() (1 input parameters) +Function 547: IsMusicStreamPlaying() (1 input parameters) Name: IsMusicStreamPlaying Return type: bool Description: Check if music is playing Param[1]: music (type: Music) -Function 547: UpdateMusicStream() (1 input parameters) +Function 548: UpdateMusicStream() (1 input parameters) Name: UpdateMusicStream Return type: void Description: Updates buffers for music streaming Param[1]: music (type: Music) -Function 548: StopMusicStream() (1 input parameters) +Function 549: StopMusicStream() (1 input parameters) Name: StopMusicStream Return type: void Description: Stop music playing Param[1]: music (type: Music) -Function 549: PauseMusicStream() (1 input parameters) +Function 550: PauseMusicStream() (1 input parameters) Name: PauseMusicStream Return type: void Description: Pause music playing Param[1]: music (type: Music) -Function 550: ResumeMusicStream() (1 input parameters) +Function 551: ResumeMusicStream() (1 input parameters) Name: ResumeMusicStream Return type: void Description: Resume playing paused music Param[1]: music (type: Music) -Function 551: SeekMusicStream() (2 input parameters) +Function 552: 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 552: SetMusicVolume() (2 input parameters) +Function 553: 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 553: SetMusicPitch() (2 input parameters) +Function 554: 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 554: SetMusicPan() (2 input parameters) +Function 555: 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 555: GetMusicTimeLength() (1 input parameters) +Function 556: GetMusicTimeLength() (1 input parameters) Name: GetMusicTimeLength Return type: float Description: Get music time length (in seconds) Param[1]: music (type: Music) -Function 556: GetMusicTimePlayed() (1 input parameters) +Function 557: GetMusicTimePlayed() (1 input parameters) Name: GetMusicTimePlayed Return type: float Description: Get current music time played (in seconds) Param[1]: music (type: Music) -Function 557: LoadAudioStream() (3 input parameters) +Function 558: 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 558: IsAudioStreamReady() (1 input parameters) +Function 559: IsAudioStreamReady() (1 input parameters) Name: IsAudioStreamReady Return type: bool Description: Checks if an audio stream is ready Param[1]: stream (type: AudioStream) -Function 559: UnloadAudioStream() (1 input parameters) +Function 560: UnloadAudioStream() (1 input parameters) Name: UnloadAudioStream Return type: void Description: Unload audio stream and free memory Param[1]: stream (type: AudioStream) -Function 560: UpdateAudioStream() (3 input parameters) +Function 561: 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 561: IsAudioStreamProcessed() (1 input parameters) +Function 562: IsAudioStreamProcessed() (1 input parameters) Name: IsAudioStreamProcessed Return type: bool Description: Check if any audio stream buffers requires refill Param[1]: stream (type: AudioStream) -Function 562: PlayAudioStream() (1 input parameters) +Function 563: PlayAudioStream() (1 input parameters) Name: PlayAudioStream Return type: void Description: Play audio stream Param[1]: stream (type: AudioStream) -Function 563: PauseAudioStream() (1 input parameters) +Function 564: PauseAudioStream() (1 input parameters) Name: PauseAudioStream Return type: void Description: Pause audio stream Param[1]: stream (type: AudioStream) -Function 564: ResumeAudioStream() (1 input parameters) +Function 565: ResumeAudioStream() (1 input parameters) Name: ResumeAudioStream Return type: void Description: Resume audio stream Param[1]: stream (type: AudioStream) -Function 565: IsAudioStreamPlaying() (1 input parameters) +Function 566: IsAudioStreamPlaying() (1 input parameters) Name: IsAudioStreamPlaying Return type: bool Description: Check if audio stream is playing Param[1]: stream (type: AudioStream) -Function 566: StopAudioStream() (1 input parameters) +Function 567: StopAudioStream() (1 input parameters) Name: StopAudioStream Return type: void Description: Stop audio stream Param[1]: stream (type: AudioStream) -Function 567: SetAudioStreamVolume() (2 input parameters) +Function 568: 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 568: SetAudioStreamPitch() (2 input parameters) +Function 569: 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 569: SetAudioStreamPan() (2 input parameters) +Function 570: 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 570: SetAudioStreamBufferSizeDefault() (1 input parameters) +Function 571: SetAudioStreamBufferSizeDefault() (1 input parameters) Name: SetAudioStreamBufferSizeDefault Return type: void Description: Default size for new audio streams Param[1]: size (type: int) -Function 571: SetAudioStreamCallback() (2 input parameters) +Function 572: 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 572: AttachAudioStreamProcessor() (2 input parameters) +Function 573: AttachAudioStreamProcessor() (2 input parameters) Name: AttachAudioStreamProcessor Return type: void Description: Attach audio stream processor to stream, receives the samples as 'float' Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 573: DetachAudioStreamProcessor() (2 input parameters) +Function 574: 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 574: AttachAudioMixedProcessor() (1 input parameters) +Function 575: AttachAudioMixedProcessor() (1 input parameters) Name: AttachAudioMixedProcessor Return type: void Description: Attach audio stream processor to the entire audio pipeline, receives the samples as 'float' Param[1]: processor (type: AudioCallback) -Function 575: DetachAudioMixedProcessor() (1 input parameters) +Function 576: DetachAudioMixedProcessor() (1 input parameters) Name: DetachAudioMixedProcessor Return type: void Description: Detach audio stream processor from the entire audio pipeline diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index 532b9e3b9..1cd645651 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -670,7 +670,7 @@ - + @@ -2236,12 +2236,17 @@ + + + + + - + From b807f633d95d8aa762565362b9df1034287fd1b1 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 15 Sep 2024 13:01:59 +0200 Subject: [PATCH 028/115] REVIEWED: `ColorLerp()` formatting #4310 --- src/raylib.h | 2 +- src/rtextures.c | 34 ++++++++++++++++------------------ 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index a9cdbe94b..84f136355 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1431,11 +1431,11 @@ RLAPI Color ColorBrightness(Color color, float factor); // G 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 ColorLerp(Color color1, Color color2, float factor); // Get color lerp interpolation between two colors, factor [0.0f..1.0f] RLAPI Color GetColor(unsigned int hexValue); // Get Color structure from hexadecimal value RLAPI Color GetPixelColor(void *srcPtr, int format); // Get Color from a source pixel pointer of certain format RLAPI void SetPixelColor(void *dstPtr, Color color, int format); // Set color formatted into destination pixel pointer RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes for certain format -RLAPI Color ColorLerp(Color color1, Color color2, float d); // Mix 2 Colors Together //------------------------------------------------------------------------------------ // Font Loading and Text Drawing Functions (Module: text) diff --git a/src/rtextures.c b/src/rtextures.c index f391b0d91..0a5ab793e 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -5185,6 +5185,22 @@ Color ColorAlphaBlend(Color dst, Color src, Color tint) return out; } +// Get color lerp interpolation between two colors, factor [0.0f..1.0f] +Color ColorLerp(Color color1, Color color2, float factor) +{ + Color color = { 0 }; + + if (d < 0) d = 0.0f; + else if (d > 1) d = 1.0f; + + color.r = (unsigned char)((1.0f - factor)*color1.r + factor*color2.r); + color.g = (unsigned char)((1.0f - factor)*color1.g + factor*color2.g); + color.b = (unsigned char)((1.0f - factor)*color1.b + factor*color2.b); + color.a = (unsigned char)((1.0f - factor)*color1.a + factor*color2.a); + + return color; +} + // Get a Color struct from hexadecimal value Color GetColor(unsigned int hexValue) { @@ -5424,24 +5440,6 @@ int GetPixelDataSize(int width, int height, int format) return dataSize; } - -// Mix 2 Colors togehter. -// d = dominance. 0.5 for equal -Color ColorLerp(Color color1, Color color2, float d) -{ - Color newColor = { 0, 0, 0, 0 }; - if (d < 0) {d=0.0f;} - else if(d>1) {d=1.0f;} - - newColor.r = (unsigned char)((1.0f-d) * color1.r + d * color2.r); - newColor.g = (unsigned char)((1.0f-d) * color1.g + d * color2.g); - newColor.b = (unsigned char)((1.0f-d) * color1.b + d * color2.b); - newColor.a = (unsigned char)((1.0f-d) * color1.a + d * color2.a); - - return newColor; -} - - //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- From 8d92e65773019fa48fe1fe56cf3a247e4e11ac14 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 15 Sep 2024 11:02:18 +0000 Subject: [PATCH 029/115] Update raylib_api.* by CI --- parser/output/raylib_api.json | 38 +++++++++++++++++------------------ parser/output/raylib_api.lua | 20 +++++++++--------- parser/output/raylib_api.txt | 22 ++++++++++---------- parser/output/raylib_api.xml | 10 ++++----- 4 files changed, 45 insertions(+), 45 deletions(-) diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json index 48096a951..423b55282 100644 --- a/parser/output/raylib_api.json +++ b/parser/output/raylib_api.json @@ -8780,6 +8780,25 @@ } ] }, + { + "name": "ColorLerp", + "description": "Get color lerp interpolation between two colors, factor [0.0f..1.0f]", + "returnType": "Color", + "params": [ + { + "type": "Color", + "name": "color1" + }, + { + "type": "Color", + "name": "color2" + }, + { + "type": "float", + "name": "factor" + } + ] + }, { "name": "GetColor", "description": "Get Color structure from hexadecimal value", @@ -8844,25 +8863,6 @@ } ] }, - { - "name": "ColorLerp", - "description": "Mix 2 Colors Together", - "returnType": "Color", - "params": [ - { - "type": "Color", - "name": "color1" - }, - { - "type": "Color", - "name": "color2" - }, - { - "type": "float", - "name": "d" - } - ] - }, { "name": "GetFontDefault", "description": "Get the default Font", diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua index 66095be61..0aad16644 100644 --- a/parser/output/raylib_api.lua +++ b/parser/output/raylib_api.lua @@ -6377,6 +6377,16 @@ return { {type = "Color", name = "tint"} } }, + { + name = "ColorLerp", + description = "Get color lerp interpolation between two colors, factor [0.0f..1.0f]", + returnType = "Color", + params = { + {type = "Color", name = "color1"}, + {type = "Color", name = "color2"}, + {type = "float", name = "factor"} + } + }, { name = "GetColor", description = "Get Color structure from hexadecimal value", @@ -6414,16 +6424,6 @@ return { {type = "int", name = "format"} } }, - { - name = "ColorLerp", - description = "Mix 2 Colors Together", - returnType = "Color", - params = { - {type = "Color", name = "color1"}, - {type = "Color", name = "color2"}, - {type = "float", name = "d"} - } - }, { name = "GetFontDefault", description = "Get the default Font", diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt index 6c489498b..55420d158 100644 --- a/parser/output/raylib_api.txt +++ b/parser/output/raylib_api.txt @@ -3368,38 +3368,38 @@ Function 380: ColorAlphaBlend() (3 input parameters) Param[1]: dst (type: Color) Param[2]: src (type: Color) Param[3]: tint (type: Color) -Function 381: GetColor() (1 input parameters) +Function 381: ColorLerp() (3 input parameters) + Name: ColorLerp + Return type: Color + Description: Get color lerp interpolation between two colors, factor [0.0f..1.0f] + Param[1]: color1 (type: Color) + Param[2]: color2 (type: Color) + Param[3]: factor (type: float) +Function 382: GetColor() (1 input parameters) Name: GetColor Return type: Color Description: Get Color structure from hexadecimal value Param[1]: hexValue (type: unsigned int) -Function 382: GetPixelColor() (2 input parameters) +Function 383: 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 383: SetPixelColor() (3 input parameters) +Function 384: 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 384: GetPixelDataSize() (3 input parameters) +Function 385: 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 385: ColorLerp() (3 input parameters) - Name: ColorLerp - Return type: Color - Description: Mix 2 Colors Together - Param[1]: color1 (type: Color) - Param[2]: color2 (type: Color) - Param[3]: d (type: float) Function 386: GetFontDefault() (0 input parameters) Name: GetFontDefault Return type: Font diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index 1cd645651..3f8f65b13 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -2219,6 +2219,11 @@ + + + + + @@ -2236,11 +2241,6 @@ - - - - - From e9bbf02b2b450269c08ba348d352159f4658024b Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 15 Sep 2024 13:03:12 +0200 Subject: [PATCH 030/115] Update rtextures.c --- src/rtextures.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rtextures.c b/src/rtextures.c index 0a5ab793e..8bda75ad8 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -5190,8 +5190,8 @@ Color ColorLerp(Color color1, Color color2, float factor) { Color color = { 0 }; - if (d < 0) d = 0.0f; - else if (d > 1) d = 1.0f; + if (factor < 0.0f) factor = 0.0f; + else if (factor > 1.0f) factor = 1.0f; color.r = (unsigned char)((1.0f - factor)*color1.r + factor*color2.r); color.g = (unsigned char)((1.0f - factor)*color1.g + factor*color2.g); From 16e9317220bcede380873d2000c1ccd5062e3f07 Mon Sep 17 00:00:00 2001 From: foxblock Date: Sun, 15 Sep 2024 13:05:01 +0200 Subject: [PATCH 031/115] [rcore] Add filtering folders to `LoadDirectoryFilesEx()`/`ScanDirectoryFiles()` (#4302) * Add filtering folders in ScanDirectoryFiles and ScanDirectoryFilesRecursively Add define FILTER_FOLDER for that purpose Fix folder names matching filter being added to result * Move FILTER_FOLDER define to internals of rcore and document option in comment --- src/raylib.h | 2 +- src/rcore.c | 38 ++++++++++++++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index 84f136355..a1514e32c 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1126,7 +1126,7 @@ RLAPI bool ChangeDirectory(const char *dir); // Change work RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths -RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and recursive directory scan +RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and recursive directory scan. Use "/DIR" in the filter string to include directories in the result RLAPI void UnloadDirectoryFiles(FilePathList files); // Unload filepaths RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window RLAPI FilePathList LoadDroppedFiles(void); // Load dropped filepaths diff --git a/src/rcore.c b/src/rcore.c index 44dfd746f..50e26423b 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -251,6 +251,10 @@ unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); #define MAX_AUTOMATION_EVENTS 16384 // Maximum number of automation events to record #endif +#ifndef FILTER_FOLDER + #define FILTER_FOLDER "/DIR" // Filter string used in ScanDirectoryFiles, ScanDirectoryFilesRecursively and LoadDirectoryFilesEx to include directories in the result array +#endif + // Flags operation macros #define FLAG_SET(n, f) ((n) |= (f)) #define FLAG_CLEAR(n, f) ((n) &= ~(f)) @@ -3339,10 +3343,21 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const if (filter != NULL) { - if (IsFileExtension(path, filter)) + if (IsPathFile(path)) { - strcpy(files->paths[files->count], path); - files->count++; + if (IsFileExtension(path, filter)) + { + strcpy(files->paths[files->count], path); + files->count++; + } + } + else + { + if (TextFindIndex(filter, FILTER_FOLDER) >= 0) + { + strcpy(files->paths[files->count], path); + files->count++; + } } } else @@ -3402,7 +3417,22 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi break; } } - else ScanDirectoryFilesRecursively(path, files, filter); + else + { + if (filter != NULL && TextFindIndex(filter, FILTER_FOLDER) >= 0) + { + strcpy(files->paths[files->count], path); + files->count++; + } + + if (files->count >= files->capacity) + { + TRACELOG(LOG_WARNING, "FILEIO: Maximum filepath scan capacity reached (%i files)", files->capacity); + break; + } + + ScanDirectoryFilesRecursively(path, files, filter); + } } } From 7ec1c288beb633a1e3fade91b0c7e348a2c24431 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 15 Sep 2024 11:05:15 +0000 Subject: [PATCH 032/115] Update raylib_api.* by CI --- parser/output/raylib_api.json | 2 +- parser/output/raylib_api.lua | 2 +- parser/output/raylib_api.txt | 2 +- parser/output/raylib_api.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json index 423b55282..7e9ad9c12 100644 --- a/parser/output/raylib_api.json +++ b/parser/output/raylib_api.json @@ -4523,7 +4523,7 @@ }, { "name": "LoadDirectoryFilesEx", - "description": "Load directory filepaths with extension filtering and recursive directory scan", + "description": "Load directory filepaths with extension filtering and recursive directory scan. Use "/DIR" in the filter string to include directories in the result", "returnType": "FilePathList", "params": [ { diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua index 0aad16644..5a644a3ad 100644 --- a/parser/output/raylib_api.lua +++ b/parser/output/raylib_api.lua @@ -4076,7 +4076,7 @@ return { }, { name = "LoadDirectoryFilesEx", - description = "Load directory filepaths with extension filtering and recursive directory scan", + description = "Load directory filepaths with extension filtering and recursive directory scan. Use "/DIR" in the filter string to include directories in the result", returnType = "FilePathList", params = { {type = "const char *", name = "basePath"}, diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt index 55420d158..19181328f 100644 --- a/parser/output/raylib_api.txt +++ b/parser/output/raylib_api.txt @@ -1722,7 +1722,7 @@ Function 137: LoadDirectoryFiles() (1 input parameters) Function 138: LoadDirectoryFilesEx() (3 input parameters) Name: LoadDirectoryFilesEx Return type: FilePathList - Description: Load directory filepaths with extension filtering and recursive directory scan + Description: Load directory filepaths with extension filtering and recursive directory scan. Use "/DIR" in the filter string to include directories in the result Param[1]: basePath (type: const char *) Param[2]: filter (type: const char *) Param[3]: scanSubdirs (type: bool) diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index 3f8f65b13..f73e9241b 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -1081,7 +1081,7 @@ - + From 0e4ebaf89df19a3cbf3fb8c9215e94dfb1344d9b Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 15 Sep 2024 13:20:43 +0200 Subject: [PATCH 033/115] REVIEWED: `DrawTexturePro()` to avoid negative dest rec #4316 --- src/rtextures.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/rtextures.c b/src/rtextures.c index 8bda75ad8..6d3c21cf4 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -4565,6 +4565,9 @@ void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 if (source.width < 0) { flipX = true; source.width *= -1; } if (source.height < 0) source.y -= source.height; + + if (dest.width < 0) dest.width *= -1; + if (dest.height < 0) dest.height *= -1; Vector2 topLeft = { 0 }; Vector2 topRight = { 0 }; From 627e76cf7b82786d7e8a69b5bb1d5e7d023e7976 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 17 Sep 2024 10:26:32 +0200 Subject: [PATCH 034/115] REVIEWED: Directory filter tag #4323 --- src/rcore.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 50e26423b..5de1fc721 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -251,9 +251,9 @@ unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); #define MAX_AUTOMATION_EVENTS 16384 // Maximum number of automation events to record #endif -#ifndef FILTER_FOLDER - #define FILTER_FOLDER "/DIR" // Filter string used in ScanDirectoryFiles, ScanDirectoryFilesRecursively and LoadDirectoryFilesEx to include directories in the result array -#endif +#ifndef DIRECTORY_FILTER_TAG + #define DIRECTORY_FILTER_TAG "DIR" // Name tag used to request directory inclusion on directory scan +#endif // NOTE: Used in ScanDirectoryFiles(), ScanDirectoryFilesRecursively() and LoadDirectoryFilesEx() // Flags operation macros #define FLAG_SET(n, f) ((n) |= (f)) @@ -3353,7 +3353,7 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const } else { - if (TextFindIndex(filter, FILTER_FOLDER) >= 0) + if (TextFindIndex(filter, DIRECTORY_FILTER_TAG) >= 0) { strcpy(files->paths[files->count], path); files->count++; @@ -3419,7 +3419,7 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi } else { - if (filter != NULL && TextFindIndex(filter, FILTER_FOLDER) >= 0) + if ((filter != NULL) && (TextFindIndex(filter, DIRECTORY_FILTER_TAG) >= 0)) { strcpy(files->paths[files->count], path); files->count++; From c2bd1845eb65dedcce4dff519b2c2dc20336a3cf Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 17 Sep 2024 10:30:26 +0200 Subject: [PATCH 035/115] Reviewed #4323 --- parser/raylib_parser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parser/raylib_parser.c b/parser/raylib_parser.c index 83991c003..94a715562 100644 --- a/parser/raylib_parser.c +++ b/parser/raylib_parser.c @@ -72,7 +72,7 @@ #define MAX_CALLBACKS_TO_PARSE 64 // Maximum number of callbacks 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) +#define MAX_LINE_LENGTH 1024 // Maximum length of one line (including comments) #define MAX_STRUCT_FIELDS 64 // Maximum number of struct fields #define MAX_ENUM_VALUES 512 // Maximum number of enum values @@ -139,7 +139,7 @@ typedef struct EnumInfo { // Function info data typedef struct FunctionInfo { char name[64]; // Function name - char desc[256]; // Function description (comment at the end) + char desc[512]; // Function description (comment at the end) char retType[32]; // Return value type int paramCount; // Number of function parameters char paramType[MAX_FUNCTION_PARAMETERS][32]; // Parameters type From 0a03ed913beb8a3d7555c5e9b804a0a327fceb9c Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 17 Sep 2024 17:30:40 +0200 Subject: [PATCH 036/115] Update raylib.h --- src/raylib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raylib.h b/src/raylib.h index a1514e32c..08474b5e5 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1126,7 +1126,7 @@ RLAPI bool ChangeDirectory(const char *dir); // Change work RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths -RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and recursive directory scan. Use "/DIR" in the filter string to include directories in the result +RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result RLAPI void UnloadDirectoryFiles(FilePathList files); // Unload filepaths RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window RLAPI FilePathList LoadDroppedFiles(void); // Load dropped filepaths From c762a99bd57c4e19551967451b42b195ac71b4bb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 17 Sep 2024 15:30:59 +0000 Subject: [PATCH 037/115] Update raylib_api.* by CI --- parser/output/raylib_api.json | 2 +- parser/output/raylib_api.lua | 2 +- parser/output/raylib_api.txt | 2 +- parser/output/raylib_api.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json index 7e9ad9c12..781454dc2 100644 --- a/parser/output/raylib_api.json +++ b/parser/output/raylib_api.json @@ -4523,7 +4523,7 @@ }, { "name": "LoadDirectoryFilesEx", - "description": "Load directory filepaths with extension filtering and recursive directory scan. Use "/DIR" in the filter string to include directories in the result", + "description": "Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result", "returnType": "FilePathList", "params": [ { diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua index 5a644a3ad..9cf39855e 100644 --- a/parser/output/raylib_api.lua +++ b/parser/output/raylib_api.lua @@ -4076,7 +4076,7 @@ return { }, { name = "LoadDirectoryFilesEx", - description = "Load directory filepaths with extension filtering and recursive directory scan. Use "/DIR" in the filter string to include directories in the result", + description = "Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result", returnType = "FilePathList", params = { {type = "const char *", name = "basePath"}, diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt index 19181328f..07b34c0ce 100644 --- a/parser/output/raylib_api.txt +++ b/parser/output/raylib_api.txt @@ -1722,7 +1722,7 @@ Function 137: LoadDirectoryFiles() (1 input parameters) Function 138: LoadDirectoryFilesEx() (3 input parameters) Name: LoadDirectoryFilesEx Return type: FilePathList - Description: Load directory filepaths with extension filtering and recursive directory scan. Use "/DIR" in the filter string to include directories in the result + Description: Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result Param[1]: basePath (type: const char *) Param[2]: filter (type: const char *) Param[3]: scanSubdirs (type: bool) diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index f73e9241b..6bd5a4581 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -1081,7 +1081,7 @@ - + From 2f0cf8fbe1c389e99c1cc97bb163cbc8f92b9327 Mon Sep 17 00:00:00 2001 From: Brian E <72316548+Brian-ED@users.noreply.github.com> Date: Fri, 20 Sep 2024 09:01:15 +0200 Subject: [PATCH 038/115] [BINDINGS.md] Added raylib-bqn, moved rayed-bqn (#4331) * [BINDINGS.md] Added raylib-bqn, moved rayed-bqn rayed-bqn has had a lot of progress and I've realized it has diverged too much from raylib, and so I made raylib-bqn to be a simple binding, while rayed-bqn will be a utility wrapper. * removed accidental newline --- BINDINGS.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BINDINGS.md b/BINDINGS.md index 2c986f236..6ac54498e 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -78,7 +78,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers | [raylib-zig-bindings](https://github.com/L-Briand/raylib-zig-bindings) | **5.0** | [Zig](https://ziglang.org) | Zlib | | [hare-raylib](https://git.sr.ht/~evantj/hare-raylib) | **auto** | [Hare](https://harelang.org) | Zlib | | [raylib-sunder](https://github.com/ashn-dot-dev/raylib-sunder) | **auto** | [Sunder](https://github.com/ashn-dot-dev/sunder) | 0BSD | -| [rayed-bqn](https://github.com/Brian-ED/rayed-bqn) | **auto** | [BQN](https://mlochbaum.github.io/BQN) | MIT | +| [raylib-bqn](https://github.com/Brian-ED/raylib-bqn) | **5.0** | [BQN](https://mlochbaum.github.io/BQN) | MIT | | [rayjs](https://github.com/mode777/rayjs) | 4.6-dev | [QuickJS](https://bellard.org/quickjs) | MIT | | [raylib-raku](https://github.com/vushu/raylib-raku) | **auto** | [Raku](https://www.raku.org) | Artistic License 2.0 | | [Raylib.lean](https://github.com/KislyjKisel/Raylib.lean) | 4.5 | [Lean4](https://lean-lang.org) | BSD-3-Clause | @@ -92,6 +92,7 @@ These are utility wrappers for specific languages, they are not required to use | ---------------------------------------------------- | :------------: | :------------------------------------------: | :-----: | | [raylib-cpp](https://github.com/robloach/raylib-cpp) | **5.0** | [C++](https://en.wikipedia.org/wiki/C%2B%2B) | Zlib | | [claylib](https://github.com/defun-games/claylib) | 4.5 | [Common Lisp](https://common-lisp.net) | Zlib | +| [rayed-bqn](https://github.com/Brian-ED/rayed-bqn) | **5.0** | [BQN](https://mlochbaum.github.io/BQN) | MIT | ### Older or Unmaintained Language Bindings From 86ead962633f5ee819829550dc8acdd9cd07f667 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Fri, 20 Sep 2024 11:30:37 -0400 Subject: [PATCH 039/115] [rmodels] Optional GPU skinning (#4321) * Added optional GPU skinning * Added skinned bone matrices support for different file formats. * Moved new shader locations to end of enum to avoid breaking existing examples. Added gpu skinning on drawing of instanced meshes. * Added GPU skinning example. * Removed variable declaration to avoid shadowing warning. --- examples/Makefile | 3 +- examples/models/models_gpu_skinning.c | 117 +++++++++++++ .../resources/shaders/glsl100/skinning.fs | 17 ++ .../resources/shaders/glsl100/skinning.vs | 34 ++++ .../resources/shaders/glsl330/skinning.fs | 17 ++ .../resources/shaders/glsl330/skinning.vs | 34 ++++ src/config.h | 16 +- src/raylib.h | 12 +- src/rcore.c | 5 + src/rlgl.h | 41 ++++- src/rmodels.c | 164 +++++++++++++++++- 11 files changed, 437 insertions(+), 23 deletions(-) create mode 100644 examples/models/models_gpu_skinning.c create mode 100644 examples/models/resources/shaders/glsl100/skinning.fs create mode 100644 examples/models/resources/shaders/glsl100/skinning.vs create mode 100644 examples/models/resources/shaders/glsl330/skinning.fs create mode 100644 examples/models/resources/shaders/glsl330/skinning.vs diff --git a/examples/Makefile b/examples/Makefile index bdbb6e351..c17258427 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -587,7 +587,8 @@ MODELS = \ models/models_rlgl_solar_system \ models/models_skybox \ models/models_waving_cubes \ - models/models_yaw_pitch_roll + models/models_yaw_pitch_roll \ + models/models_gpu_skinning SHADERS = \ shaders/shaders_basic_lighting \ diff --git a/examples/models/models_gpu_skinning.c b/examples/models/models_gpu_skinning.c new file mode 100644 index 000000000..e9cd73f4b --- /dev/null +++ b/examples/models/models_gpu_skinning.c @@ -0,0 +1,117 @@ +/******************************************************************************************* +* +* raylib [core] example - Doing skinning on the gpu using a vertex shader +* +* Example originally created with raylib 4.5, last time updated with raylib 4.5 +* +* Example contributed by Daniel Holden (@orangeduck) and reviewed by Ramon Santamaria (@raysan5) +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2024 Daniel Holden (@orangeduck) +* +********************************************************************************************/ + +#include "raylib.h" + +#include "raymath.h" + +#if defined(PLATFORM_DESKTOP) + #define GLSL_VERSION 330 +#else // PLATFORM_ANDROID, PLATFORM_WEB + #define GLSL_VERSION 100 +#endif + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [models] example - GPU skinning"); + + // Define the camera to look into our 3d world + Camera camera = { 0 }; + camera.position = (Vector3){ 5.0f, 5.0f, 5.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 2.0f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type + + // Load gltf model + Model characterModel = LoadModel("resources/models/gltf/greenman.glb"); // Load character model + + // Load skinning shader + Shader skinningShader = LoadShader(TextFormat("resources/shaders/glsl%i/skinning.vs", GLSL_VERSION), + TextFormat("resources/shaders/glsl%i/skinning.fs", GLSL_VERSION)); + + characterModel.materials[1].shader = skinningShader; + + // Load gltf model animations + int animsCount = 0; + unsigned int animIndex = 0; + unsigned int animCurrentFrame = 0; + ModelAnimation *modelAnimations = LoadModelAnimations("resources/models/gltf/greenman.glb", &animsCount); + + Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position + + DisableCursor(); // Limit cursor to relative movement inside the window + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateCamera(&camera, CAMERA_THIRD_PERSON); + + // Select current animation + if (IsKeyPressed(KEY_T)) animIndex = (animIndex + 1)%animsCount; + else if (IsKeyPressed(KEY_G)) animIndex = (animIndex + animsCount - 1)%animsCount; + + // Update model animation + ModelAnimation anim = modelAnimations[animIndex]; + animCurrentFrame = (animCurrentFrame + 1)%anim.frameCount; + UpdateModelAnimationBoneMatrices(characterModel, anim, animCurrentFrame); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode3D(camera); + + // Draw character + characterModel.transform = MatrixTranslate(position.x, position.y, position.z); + UpdateModelAnimationBoneMatrices(characterModel, anim, animCurrentFrame); + DrawMesh(characterModel.meshes[0], characterModel.materials[1], characterModel.transform); + + DrawGrid(10, 1.0f); + EndMode3D(); + + DrawText("Use the T/G to switch animation", 10, 10, 20, GRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadModelAnimations(modelAnimations, animsCount); + UnloadModel(characterModel); // Unload character model and meshes/material + UnloadShader(skinningShader); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/models/resources/shaders/glsl100/skinning.fs b/examples/models/resources/shaders/glsl100/skinning.fs new file mode 100644 index 000000000..ef6568036 --- /dev/null +++ b/examples/models/resources/shaders/glsl100/skinning.fs @@ -0,0 +1,17 @@ +#version 100 + +// Input vertex attributes (from vertex shader) +in vec2 fragTexCoord; +in vec4 fragColor; + +// Output fragment color +out vec4 finalColor; + +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +void main() +{ + vec4 texelColor = texture(texture0, fragTexCoord); + finalColor = texelColor*colDiffuse*fragColor; +} diff --git a/examples/models/resources/shaders/glsl100/skinning.vs b/examples/models/resources/shaders/glsl100/skinning.vs new file mode 100644 index 000000000..9c92e2a8c --- /dev/null +++ b/examples/models/resources/shaders/glsl100/skinning.vs @@ -0,0 +1,34 @@ +#version 100 + +in vec3 vertexPosition; +in vec2 vertexTexCoord; +in vec4 vertexColor; +in vec4 vertexBoneIds; +in vec4 vertexBoneWeights; + +#define MAX_BONE_NUM 128 +uniform mat4 boneMatrices[MAX_BONE_NUM]; + +uniform mat4 mvp; + +out vec2 fragTexCoord; +out vec4 fragColor; + +void main() +{ + int boneIndex0 = int(vertexBoneIds.x); + int boneIndex1 = int(vertexBoneIds.y); + int boneIndex2 = int(vertexBoneIds.z); + int boneIndex3 = int(vertexBoneIds.w); + + vec4 skinnedPosition = + vertexBoneWeights.x * (boneMatrices[boneIndex0] * vec4(vertexPosition, 1.0f)) + + vertexBoneWeights.y * (boneMatrices[boneIndex1] * vec4(vertexPosition, 1.0f)) + + vertexBoneWeights.z * (boneMatrices[boneIndex2] * vec4(vertexPosition, 1.0f)) + + vertexBoneWeights.w * (boneMatrices[boneIndex3] * vec4(vertexPosition, 1.0f)); + + fragTexCoord = vertexTexCoord; + fragColor = vertexColor; + + gl_Position = mvp * skinnedPosition; +} \ No newline at end of file diff --git a/examples/models/resources/shaders/glsl330/skinning.fs b/examples/models/resources/shaders/glsl330/skinning.fs new file mode 100644 index 000000000..d4311ffcc --- /dev/null +++ b/examples/models/resources/shaders/glsl330/skinning.fs @@ -0,0 +1,17 @@ +#version 330 + +// Input vertex attributes (from vertex shader) +in vec2 fragTexCoord; +in vec4 fragColor; + +// Output fragment color +out vec4 finalColor; + +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +void main() +{ + vec4 texelColor = texture(texture0, fragTexCoord); + finalColor = texelColor*colDiffuse*fragColor; +} diff --git a/examples/models/resources/shaders/glsl330/skinning.vs b/examples/models/resources/shaders/glsl330/skinning.vs new file mode 100644 index 000000000..2dc976c48 --- /dev/null +++ b/examples/models/resources/shaders/glsl330/skinning.vs @@ -0,0 +1,34 @@ +#version 330 + +in vec3 vertexPosition; +in vec2 vertexTexCoord; +in vec4 vertexColor; +in vec4 vertexBoneIds; +in vec4 vertexBoneWeights; + +#define MAX_BONE_NUM 128 +uniform mat4 boneMatrices[MAX_BONE_NUM]; + +uniform mat4 mvp; + +out vec2 fragTexCoord; +out vec4 fragColor; + +void main() +{ + int boneIndex0 = int(vertexBoneIds.x); + int boneIndex1 = int(vertexBoneIds.y); + int boneIndex2 = int(vertexBoneIds.z); + int boneIndex3 = int(vertexBoneIds.w); + + vec4 skinnedPosition = + vertexBoneWeights.x * (boneMatrices[boneIndex0] * vec4(vertexPosition, 1.0f)) + + vertexBoneWeights.y * (boneMatrices[boneIndex1] * vec4(vertexPosition, 1.0f)) + + vertexBoneWeights.z * (boneMatrices[boneIndex2] * vec4(vertexPosition, 1.0f)) + + vertexBoneWeights.w * (boneMatrices[boneIndex3] * vec4(vertexPosition, 1.0f)); + + fragTexCoord = vertexTexCoord; + fragColor = vertexColor; + + gl_Position = mvp * skinnedPosition; +} \ No newline at end of file diff --git a/src/config.h b/src/config.h index 9cbe90e35..f6e3fe304 100644 --- a/src/config.h +++ b/src/config.h @@ -113,13 +113,15 @@ #define RL_CULL_DISTANCE_FAR 1000.0 // Default projection matrix far cull distance // Default shader vertex attribute locations -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 6 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 7 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 8 // 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 diff --git a/src/raylib.h b/src/raylib.h index 08474b5e5..ee34b6441 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -352,8 +352,10 @@ typedef struct Mesh { // Animation vertex data float *animVertices; // Animated vertex positions (after bones transformations) float *animNormals; // Animated normals (after bones transformations) - unsigned char *boneIds; // Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) - float *boneWeights; // Vertex bone weight, up to 4 bones influence by vertex (skinning) + unsigned char *boneIds; // Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) (shader-location = 6) + float *boneWeights; // Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7) + Matrix *boneMatrices; // Bones animated transformation matrices + int boneCount; // Number of bones // OpenGL identifiers unsigned int vaoId; // OpenGL Vertex Array Object id @@ -790,7 +792,10 @@ typedef enum { SHADER_LOC_MAP_CUBEMAP, // Shader location: samplerCube texture: cubemap SHADER_LOC_MAP_IRRADIANCE, // Shader location: samplerCube texture: irradiance SHADER_LOC_MAP_PREFILTER, // Shader location: samplerCube texture: prefilter - SHADER_LOC_MAP_BRDF // Shader location: sampler2d texture: brdf + SHADER_LOC_MAP_BRDF, // Shader location: sampler2d texture: brdf + SHADER_LOC_VERTEX_BONEIDS, // Shader location: vertex attribute: boneIds + SHADER_LOC_VERTEX_BONEWEIGHTS, // Shader location: vertex attribute: boneWeights + SHADER_LOC_BONE_MATRICES // Shader location: array of matrices uniform: boneMatrices } ShaderLocationIndex; #define SHADER_LOC_MAP_DIFFUSE SHADER_LOC_MAP_ALBEDO @@ -1591,6 +1596,7 @@ RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame); RLAPI void UnloadModelAnimation(ModelAnimation anim); // Unload animation data RLAPI void UnloadModelAnimations(ModelAnimation *animations, int animCount); // Unload animation array data RLAPI bool IsModelAnimationValid(Model model, ModelAnimation anim); // Check model animation skeleton match +RLAPI void UpdateModelAnimationBoneMatrices(Model model, ModelAnimation anim, int frame); // Update model animation mesh bone matrices // Collision detection functions RLAPI bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2); // Check collision between two spheres diff --git a/src/rcore.c b/src/rcore.c index 5de1fc721..2fd79f5c9 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1303,6 +1303,8 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode) // vertex color location = 3 // vertex tangent location = 4 // vertex texcoord2 location = 5 + // vertex boneIds location = 6 + // vertex boneWeights location = 7 // NOTE: If any location is not found, loc point becomes -1 @@ -1318,6 +1320,8 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode) shader.locs[SHADER_LOC_VERTEX_NORMAL] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL); shader.locs[SHADER_LOC_VERTEX_TANGENT] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT); shader.locs[SHADER_LOC_VERTEX_COLOR] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR); + shader.locs[SHADER_LOC_VERTEX_BONEIDS] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS); + shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS); // Get handles to GLSL uniform locations (vertex shader) shader.locs[SHADER_LOC_MATRIX_MVP] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_MVP); @@ -1325,6 +1329,7 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode) shader.locs[SHADER_LOC_MATRIX_PROJECTION] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION); shader.locs[SHADER_LOC_MATRIX_MODEL] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL); shader.locs[SHADER_LOC_MATRIX_NORMAL] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL); + shader.locs[SHADER_LOC_BONE_MATRICES] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_BONE_MATRICES); // Get handles to GLSL uniform locations (fragment shader) shader.locs[SHADER_LOC_COLOR_DIFFUSE] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR); diff --git a/src/rlgl.h b/src/rlgl.h index 9b94d402c..b98934a11 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -68,12 +68,15 @@ * #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR * #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT * #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 +* #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS "vertexBoneIds" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS +* #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS * #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 * #define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL "matModel" // model matrix * #define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView))) * #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color) +* #define RL_DEFAULT_SHADER_UNIFORM_NAME_BONE_MATRICES "boneMatrices" // bone matrices * #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0) * #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1) * #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2) @@ -324,22 +327,28 @@ // Default shader vertex attribute locations #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0 + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1 + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2 + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3 + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5 + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5 +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 6 +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 7 #endif //---------------------------------------------------------------------------------- @@ -759,6 +768,7 @@ RLAPI int rlGetLocationUniform(unsigned int shaderId, const char *uniformName); RLAPI int rlGetLocationAttrib(unsigned int shaderId, const char *attribName); // Get shader location attribute RLAPI void rlSetUniform(int locIndex, const void *value, int uniformType, int count); // Set shader value uniform RLAPI void rlSetUniformMatrix(int locIndex, Matrix mat); // Set shader value matrix +RLAPI void rlSetUniformMatrices(int locIndex, const Matrix *mat, int count); // Set shader value matrices RLAPI void rlSetUniformSampler(int locIndex, unsigned int textureId); // Set shader value sampler RLAPI void rlSetShader(unsigned int id, int *locs); // Set shader currently active (id and locations) @@ -977,6 +987,12 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 #endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS + #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS "vertexBoneIds" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS + #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS +#endif #ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_MVP #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix @@ -996,6 +1012,9 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color) #endif +#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_BONE_MATRICES + #define RL_DEFAULT_SHADER_UNIFORM_NAME_BONE_MATRICES "boneMatrices" // bone matrices +#endif #ifndef RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0) #endif @@ -4148,6 +4167,8 @@ unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR); glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT); glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2); + glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS); + glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS); // NOTE: If some attrib name is no found on the shader, it locations becomes -1 @@ -4283,6 +4304,14 @@ void rlSetUniformMatrix(int locIndex, Matrix mat) #endif } +// Set shader value uniform matrix +void rlSetUniformMatrices(int locIndex, const Matrix *matrices, int count) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glUniformMatrix4fv(locIndex, count, true, (const float*)matrices); +#endif +} + // Set shader value uniform sampler void rlSetUniformSampler(int locIndex, unsigned int textureId) { diff --git a/src/rmodels.c b/src/rmodels.c index 9994ddb76..055fb1b1c 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -130,7 +130,7 @@ #define MAX_MATERIAL_MAPS 12 // Maximum number of maps supported #endif #ifndef MAX_MESH_VERTEX_BUFFERS - #define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh + #define MAX_MESH_VERTEX_BUFFERS 9 // Maximum vertex buffers (VBO) per mesh #endif //---------------------------------------------------------------------------------- @@ -1248,11 +1248,13 @@ void UploadMesh(Mesh *mesh, bool dynamic) mesh->vaoId = 0; // Vertex Array Object mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION] = 0; // Vertex buffer: positions mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = 0; // Vertex buffer: texcoords - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = 0; // Vertex buffer: normals - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] = 0; // Vertex buffer: colors - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = 0; // Vertex buffer: tangents - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = 0; // Vertex buffer: texcoords2 - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = 0; // Vertex buffer: indices + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = 0; // Vertex buffer: normals + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] = 0; // Vertex buffer: colors + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = 0; // Vertex buffer: tangents + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = 0; // Vertex buffer: texcoords2 + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS] = 0; // Vertex buffer: boneIds + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = 0; // Vertex buffer: boneWeights + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = 0; // Vertex buffer: indices #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) mesh->vaoId = rlLoadVertexArray(); @@ -1338,6 +1340,38 @@ void UploadMesh(Mesh *mesh, bool dynamic) rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, value, SHADER_ATTRIB_VEC2, 2); rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2); } + + if (mesh->boneIds != NULL) + { + // Enable vertex attribute: boneIds (shader-location = 6) + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS] = rlLoadVertexBuffer(mesh->boneIds, mesh->vertexCount*4*sizeof(unsigned char), dynamic); + rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, 4, RL_UNSIGNED_BYTE, 0, 0, 0); + rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS); + } + else + { + // Default vertex attribute: boneIds + // WARNING: Default value provided to shader if location available + float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, value, SHADER_ATTRIB_VEC4, 4); + rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS); + } + + if (mesh->boneWeights != NULL) + { + // Enable vertex attribute: boneWeights (shader-location = 7) + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = rlLoadVertexBuffer(mesh->boneWeights, mesh->vertexCount*4*sizeof(float), dynamic); + rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, 4, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS); + } + else + { + // Default vertex attribute: boneWeights + // WARNING: Default value provided to shader if location available + float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, value, SHADER_ATTRIB_VEC4, 2); + rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS); + } if (mesh->indices != NULL) { @@ -1451,6 +1485,13 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) // Upload model normal matrix (if locations available) if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel))); + + // Upload Bone Transforms + if (material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1 && mesh.boneMatrices) + { + rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount); + } + //----------------------------------------------------- // Bind active texture maps (if available) @@ -1529,6 +1570,22 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]); } + + // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available) + if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1) + { + rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS]); + rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS], 4, RL_UNSIGNED_BYTE, 0, 0, 0); + rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS]); + } + + // Bind mesh VBO data: vertex bone weights (shader-location = 7, if available) + if (material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] != -1) + { + rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS]); + rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS], 4, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS]); + } if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]); } @@ -1671,6 +1728,13 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i // Upload model normal matrix (if locations available) if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel))); + + // Upload Bone Transforms + if (material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1 && mesh.boneMatrices) + { + rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount); + } + //----------------------------------------------------- // Bind active texture maps (if available) @@ -1747,6 +1811,22 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]); } + + // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available) + if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1) + { + rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS]); + rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS], 4, RL_UNSIGNED_BYTE, 0, 0, 0); + rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS]); + } + + // Bind mesh VBO data: vertex bone weights (shader-location = 7, if available) + if (material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] != -1) + { + rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS]); + rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS], 4, RL_FLOAT, 0, 0, 0); + rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS]); + } if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]); } @@ -1825,6 +1905,7 @@ void UnloadMesh(Mesh mesh) RL_FREE(mesh.animNormals); RL_FREE(mesh.boneWeights); RL_FREE(mesh.boneIds); + RL_FREE(mesh.boneMatrices); } // Export mesh data to file @@ -2255,6 +2336,50 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame) } } +void UpdateModelAnimationBoneMatrices(Model model, ModelAnimation anim, int frame) +{ + if ((anim.frameCount > 0) && (anim.bones != NULL) && (anim.framePoses != NULL)) + { + if (frame >= anim.frameCount) frame = frame%anim.frameCount; + + for (int i = 0; i < model.meshCount; i++) + { + if (model.meshes[i].boneMatrices) + { + assert(model.meshes[i].boneCount == anim.boneCount); + + for (int boneId = 0; boneId < model.meshes[i].boneCount; boneId++) + { + Vector3 inTranslation = model.bindPose[boneId].translation; + Quaternion inRotation = model.bindPose[boneId].rotation; + Vector3 inScale = model.bindPose[boneId].scale; + + Vector3 outTranslation = anim.framePoses[frame][boneId].translation; + Quaternion outRotation = anim.framePoses[frame][boneId].rotation; + Vector3 outScale = anim.framePoses[frame][boneId].scale; + + Vector3 invTranslation = Vector3RotateByQuaternion(Vector3Negate(inTranslation), QuaternionInvert(inRotation)); + Quaternion invRotation = QuaternionInvert(inRotation); + Vector3 invScale = Vector3Divide((Vector3){ 1.0f, 1.0f, 1.0f }, inScale); + + Vector3 boneTranslation = Vector3Add( + Vector3RotateByQuaternion(Vector3Multiply(outScale, invTranslation), + outRotation), outTranslation); + Quaternion boneRotation = QuaternionMultiply(outRotation, invRotation); + Vector3 boneScale = Vector3Multiply(outScale, invScale); + + Matrix boneMatrix = MatrixMultiply(MatrixMultiply( + QuaternionToMatrix(boneRotation), + MatrixTranslate(boneTranslation.x, boneTranslation.y, boneTranslation.z)), + MatrixScale(boneScale.x, boneScale.y, boneScale.z)); + + model.meshes[i].boneMatrices[boneId] = boneMatrix; + } + } + } + } +} + // Unload animation array data void UnloadModelAnimations(ModelAnimation *animations, int animCount) { @@ -4671,6 +4796,17 @@ static Model LoadIQM(const char *fileName) } BuildPoseFromParentJoints(model.bones, model.boneCount, model.bindPose); + + for (int i = 0; i < model.meshCount; i++) + { + model.meshes[i].boneCount = model.boneCount; + model.meshes[i].boneMatrices = RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix)); + + for (int j = 0; j < model.meshes[i].boneCount; j++) + { + model.meshes[i].boneMatrices[j] = MatrixIdentity(); + } + } UnloadFileData(fileData); @@ -5754,6 +5890,15 @@ static Model LoadGLTF(const char *fileName) { memcpy(model.meshes[meshIndex].animNormals, model.meshes[meshIndex].normals, model.meshes[meshIndex].vertexCount*3*sizeof(float)); } + + // Bone Transform Matrices + model.meshes[meshIndex].boneCount = model.boneCount; + model.meshes[meshIndex].boneMatrices = RL_CALLOC(model.meshes[meshIndex].boneCount, sizeof(Matrix)); + + for (int j = 0; j < model.meshes[meshIndex].boneCount; j++) + { + model.meshes[meshIndex].boneMatrices[j] = MatrixIdentity(); + } meshIndex++; // Move to next mesh } @@ -6522,6 +6667,13 @@ static Model LoadM3D(const char *fileName) { memcpy(model.meshes[i].animVertices, model.meshes[i].vertices, model.meshes[i].vertexCount*3*sizeof(float)); memcpy(model.meshes[i].animNormals, model.meshes[i].normals, model.meshes[i].vertexCount*3*sizeof(float)); + + model.meshes[i].boneCount = model.boneCount; + model.meshes[i].boneMatrices = RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix)); + for (j = 0; j < model.meshes[i].boneCount; j++) + { + model.meshes[i].boneMatrices[j] = MatrixIdentity(); + } } } From c09dadd9b5e347d6b6393a7274fef6db553dbd25 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 20 Sep 2024 15:30:53 +0000 Subject: [PATCH 040/115] Update raylib_api.* by CI --- parser/output/raylib_api.json | 48 +++++++++- parser/output/raylib_api.lua | 39 +++++++- parser/output/raylib_api.txt | 174 ++++++++++++++++++---------------- parser/output/raylib_api.xml | 20 +++- 4 files changed, 191 insertions(+), 90 deletions(-) diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json index 781454dc2..d1c58757b 100644 --- a/parser/output/raylib_api.json +++ b/parser/output/raylib_api.json @@ -850,12 +850,22 @@ { "type": "unsigned char *", "name": "boneIds", - "description": "Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning)" + "description": "Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) (shader-location = 6)" }, { "type": "float *", "name": "boneWeights", - "description": "Vertex bone weight, up to 4 bones influence by vertex (skinning)" + "description": "Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7)" + }, + { + "type": "Matrix *", + "name": "boneMatrices", + "description": "Bones animated transformation matrices" + }, + { + "type": "int", + "name": "boneCount", + "description": "Number of bones" }, { "type": "unsigned int", @@ -2518,6 +2528,21 @@ "name": "SHADER_LOC_MAP_BRDF", "value": 25, "description": "Shader location: sampler2d texture: brdf" + }, + { + "name": "SHADER_LOC_VERTEX_BONEIDS", + "value": 26, + "description": "Shader location: vertex attribute: boneIds" + }, + { + "name": "SHADER_LOC_VERTEX_BONEWEIGHTS", + "value": 27, + "description": "Shader location: vertex attribute: boneWeights" + }, + { + "name": "SHADER_LOC_BONE_MATRICES", + "value": 28, + "description": "Shader location: array of matrices uniform: boneMatrices" } ] }, @@ -11066,6 +11091,25 @@ } ] }, + { + "name": "UpdateModelAnimationBoneMatrices", + "description": "Update model animation mesh bone matrices", + "returnType": "void", + "params": [ + { + "type": "Model", + "name": "model" + }, + { + "type": "ModelAnimation", + "name": "anim" + }, + { + "type": "int", + "name": "frame" + } + ] + }, { "name": "CheckCollisionSpheres", "description": "Check collision between two spheres", diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua index 9cf39855e..0d99407b7 100644 --- a/parser/output/raylib_api.lua +++ b/parser/output/raylib_api.lua @@ -850,12 +850,22 @@ return { { type = "unsigned char *", name = "boneIds", - description = "Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning)" + description = "Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) (shader-location = 6)" }, { type = "float *", name = "boneWeights", - description = "Vertex bone weight, up to 4 bones influence by vertex (skinning)" + description = "Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7)" + }, + { + type = "Matrix *", + name = "boneMatrices", + description = "Bones animated transformation matrices" + }, + { + type = "int", + name = "boneCount", + description = "Number of bones" }, { type = "unsigned int", @@ -2518,6 +2528,21 @@ return { name = "SHADER_LOC_MAP_BRDF", value = 25, description = "Shader location: sampler2d texture: brdf" + }, + { + name = "SHADER_LOC_VERTEX_BONEIDS", + value = 26, + description = "Shader location: vertex attribute: boneIds" + }, + { + name = "SHADER_LOC_VERTEX_BONEWEIGHTS", + value = 27, + description = "Shader location: vertex attribute: boneWeights" + }, + { + name = "SHADER_LOC_BONE_MATRICES", + value = 28, + description = "Shader location: array of matrices uniform: boneMatrices" } } }, @@ -7586,6 +7611,16 @@ return { {type = "ModelAnimation", name = "anim"} } }, + { + name = "UpdateModelAnimationBoneMatrices", + description = "Update model animation mesh bone matrices", + returnType = "void", + params = { + {type = "Model", name = "model"}, + {type = "ModelAnimation", name = "anim"}, + {type = "int", name = "frame"} + } + }, { name = "CheckCollisionSpheres", description = "Check collision between two spheres", diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt index 07b34c0ce..9c92906e0 100644 --- a/parser/output/raylib_api.txt +++ b/parser/output/raylib_api.txt @@ -403,7 +403,7 @@ Struct 14: Camera2D (4 fields) Field[2]: Vector2 target // Camera target (rotation and zoom origin) Field[3]: float rotation // Camera rotation in degrees Field[4]: float zoom // Camera zoom (scaling), should be 1.0f by default -Struct 15: Mesh (15 fields) +Struct 15: Mesh (17 fields) Name: Mesh Description: Mesh, vertex data and vao/vbo Field[1]: int vertexCount // Number of vertices stored in arrays @@ -417,10 +417,12 @@ Struct 15: Mesh (15 fields) Field[9]: unsigned short * indices // Vertex indices (in case vertex data comes indexed) Field[10]: float * animVertices // Animated vertex positions (after bones transformations) Field[11]: float * animNormals // Animated normals (after bones transformations) - Field[12]: unsigned char * boneIds // Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) - Field[13]: float * boneWeights // Vertex bone weight, up to 4 bones influence by vertex (skinning) - Field[14]: unsigned int vaoId // OpenGL Vertex Array Object id - Field[15]: unsigned int * vboId // OpenGL Vertex Buffer Objects id (default vertex data) + Field[12]: unsigned char * boneIds // Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) (shader-location = 6) + Field[13]: float * boneWeights // Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7) + Field[14]: Matrix * boneMatrices // Bones animated transformation matrices + Field[15]: int boneCount // Number of bones + Field[16]: unsigned int vaoId // OpenGL Vertex Array Object id + Field[17]: unsigned int * vboId // OpenGL Vertex Buffer Objects id (default vertex data) Struct 16: Shader (2 fields) Name: Shader Description: Shader @@ -793,7 +795,7 @@ Enum 08: MaterialMapIndex (11 values) Value[MATERIAL_MAP_IRRADIANCE]: 8 Value[MATERIAL_MAP_PREFILTER]: 9 Value[MATERIAL_MAP_BRDF]: 10 -Enum 09: ShaderLocationIndex (26 values) +Enum 09: ShaderLocationIndex (29 values) Name: ShaderLocationIndex Description: Shader location index Value[SHADER_LOC_VERTEX_POSITION]: 0 @@ -822,6 +824,9 @@ Enum 09: ShaderLocationIndex (26 values) Value[SHADER_LOC_MAP_IRRADIANCE]: 23 Value[SHADER_LOC_MAP_PREFILTER]: 24 Value[SHADER_LOC_MAP_BRDF]: 25 + Value[SHADER_LOC_VERTEX_BONEIDS]: 26 + Value[SHADER_LOC_VERTEX_BONEWEIGHTS]: 27 + Value[SHADER_LOC_BONE_MATRICES]: 28 Enum 10: ShaderUniformDataType (9 values) Name: ShaderUniformDataType Description: Shader uniform data type @@ -984,7 +989,7 @@ Callback 006: AudioCallback() (2 input parameters) Param[1]: bufferData (type: void *) Param[2]: frames (type: unsigned int) -Functions found: 576 +Functions found: 577 Function 001: InitWindow() (3 input parameters) Name: InitWindow @@ -4217,7 +4222,14 @@ Function 502: IsModelAnimationValid() (2 input parameters) Description: Check model animation skeleton match Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) -Function 503: CheckCollisionSpheres() (4 input parameters) +Function 503: UpdateModelAnimationBoneMatrices() (3 input parameters) + Name: UpdateModelAnimationBoneMatrices + Return type: void + Description: Update model animation mesh bone matrices + Param[1]: model (type: Model) + Param[2]: anim (type: ModelAnimation) + Param[3]: frame (type: int) +Function 504: CheckCollisionSpheres() (4 input parameters) Name: CheckCollisionSpheres Return type: bool Description: Check collision between two spheres @@ -4225,40 +4237,40 @@ Function 503: CheckCollisionSpheres() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector3) Param[4]: radius2 (type: float) -Function 504: CheckCollisionBoxes() (2 input parameters) +Function 505: 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 505: CheckCollisionBoxSphere() (3 input parameters) +Function 506: 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 506: GetRayCollisionSphere() (3 input parameters) +Function 507: 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 507: GetRayCollisionBox() (2 input parameters) +Function 508: 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 508: GetRayCollisionMesh() (3 input parameters) +Function 509: 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 509: GetRayCollisionTriangle() (4 input parameters) +Function 510: GetRayCollisionTriangle() (4 input parameters) Name: GetRayCollisionTriangle Return type: RayCollision Description: Get collision info between ray and triangle @@ -4266,7 +4278,7 @@ Function 509: GetRayCollisionTriangle() (4 input parameters) Param[2]: p1 (type: Vector3) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) -Function 510: GetRayCollisionQuad() (5 input parameters) +Function 511: GetRayCollisionQuad() (5 input parameters) Name: GetRayCollisionQuad Return type: RayCollision Description: Get collision info between ray and quad @@ -4275,158 +4287,158 @@ Function 510: GetRayCollisionQuad() (5 input parameters) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) Param[5]: p4 (type: Vector3) -Function 511: InitAudioDevice() (0 input parameters) +Function 512: InitAudioDevice() (0 input parameters) Name: InitAudioDevice Return type: void Description: Initialize audio device and context No input parameters -Function 512: CloseAudioDevice() (0 input parameters) +Function 513: CloseAudioDevice() (0 input parameters) Name: CloseAudioDevice Return type: void Description: Close the audio device and context No input parameters -Function 513: IsAudioDeviceReady() (0 input parameters) +Function 514: IsAudioDeviceReady() (0 input parameters) Name: IsAudioDeviceReady Return type: bool Description: Check if audio device has been initialized successfully No input parameters -Function 514: SetMasterVolume() (1 input parameters) +Function 515: SetMasterVolume() (1 input parameters) Name: SetMasterVolume Return type: void Description: Set master volume (listener) Param[1]: volume (type: float) -Function 515: GetMasterVolume() (0 input parameters) +Function 516: GetMasterVolume() (0 input parameters) Name: GetMasterVolume Return type: float Description: Get master volume (listener) No input parameters -Function 516: LoadWave() (1 input parameters) +Function 517: LoadWave() (1 input parameters) Name: LoadWave Return type: Wave Description: Load wave data from file Param[1]: fileName (type: const char *) -Function 517: LoadWaveFromMemory() (3 input parameters) +Function 518: 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 518: IsWaveReady() (1 input parameters) +Function 519: IsWaveReady() (1 input parameters) Name: IsWaveReady Return type: bool Description: Checks if wave data is ready Param[1]: wave (type: Wave) -Function 519: LoadSound() (1 input parameters) +Function 520: LoadSound() (1 input parameters) Name: LoadSound Return type: Sound Description: Load sound from file Param[1]: fileName (type: const char *) -Function 520: LoadSoundFromWave() (1 input parameters) +Function 521: LoadSoundFromWave() (1 input parameters) Name: LoadSoundFromWave Return type: Sound Description: Load sound from wave data Param[1]: wave (type: Wave) -Function 521: LoadSoundAlias() (1 input parameters) +Function 522: LoadSoundAlias() (1 input parameters) Name: LoadSoundAlias Return type: Sound Description: Create a new sound that shares the same sample data as the source sound, does not own the sound data Param[1]: source (type: Sound) -Function 522: IsSoundReady() (1 input parameters) +Function 523: IsSoundReady() (1 input parameters) Name: IsSoundReady Return type: bool Description: Checks if a sound is ready Param[1]: sound (type: Sound) -Function 523: UpdateSound() (3 input parameters) +Function 524: 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 524: UnloadWave() (1 input parameters) +Function 525: UnloadWave() (1 input parameters) Name: UnloadWave Return type: void Description: Unload wave data Param[1]: wave (type: Wave) -Function 525: UnloadSound() (1 input parameters) +Function 526: UnloadSound() (1 input parameters) Name: UnloadSound Return type: void Description: Unload sound Param[1]: sound (type: Sound) -Function 526: UnloadSoundAlias() (1 input parameters) +Function 527: UnloadSoundAlias() (1 input parameters) Name: UnloadSoundAlias Return type: void Description: Unload a sound alias (does not deallocate sample data) Param[1]: alias (type: Sound) -Function 527: ExportWave() (2 input parameters) +Function 528: 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 528: ExportWaveAsCode() (2 input parameters) +Function 529: 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 529: PlaySound() (1 input parameters) +Function 530: PlaySound() (1 input parameters) Name: PlaySound Return type: void Description: Play a sound Param[1]: sound (type: Sound) -Function 530: StopSound() (1 input parameters) +Function 531: StopSound() (1 input parameters) Name: StopSound Return type: void Description: Stop playing a sound Param[1]: sound (type: Sound) -Function 531: PauseSound() (1 input parameters) +Function 532: PauseSound() (1 input parameters) Name: PauseSound Return type: void Description: Pause a sound Param[1]: sound (type: Sound) -Function 532: ResumeSound() (1 input parameters) +Function 533: ResumeSound() (1 input parameters) Name: ResumeSound Return type: void Description: Resume a paused sound Param[1]: sound (type: Sound) -Function 533: IsSoundPlaying() (1 input parameters) +Function 534: IsSoundPlaying() (1 input parameters) Name: IsSoundPlaying Return type: bool Description: Check if a sound is currently playing Param[1]: sound (type: Sound) -Function 534: SetSoundVolume() (2 input parameters) +Function 535: 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 535: SetSoundPitch() (2 input parameters) +Function 536: 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 536: SetSoundPan() (2 input parameters) +Function 537: 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 537: WaveCopy() (1 input parameters) +Function 538: WaveCopy() (1 input parameters) Name: WaveCopy Return type: Wave Description: Copy a wave to a new wave Param[1]: wave (type: Wave) -Function 538: WaveCrop() (3 input parameters) +Function 539: WaveCrop() (3 input parameters) Name: WaveCrop Return type: void Description: Crop a wave to defined frames range Param[1]: wave (type: Wave *) Param[2]: initFrame (type: int) Param[3]: finalFrame (type: int) -Function 539: WaveFormat() (4 input parameters) +Function 540: WaveFormat() (4 input parameters) Name: WaveFormat Return type: void Description: Convert wave data to desired format @@ -4434,203 +4446,203 @@ Function 539: WaveFormat() (4 input parameters) Param[2]: sampleRate (type: int) Param[3]: sampleSize (type: int) Param[4]: channels (type: int) -Function 540: LoadWaveSamples() (1 input parameters) +Function 541: 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 541: UnloadWaveSamples() (1 input parameters) +Function 542: UnloadWaveSamples() (1 input parameters) Name: UnloadWaveSamples Return type: void Description: Unload samples data loaded with LoadWaveSamples() Param[1]: samples (type: float *) -Function 542: LoadMusicStream() (1 input parameters) +Function 543: LoadMusicStream() (1 input parameters) Name: LoadMusicStream Return type: Music Description: Load music stream from file Param[1]: fileName (type: const char *) -Function 543: LoadMusicStreamFromMemory() (3 input parameters) +Function 544: 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 544: IsMusicReady() (1 input parameters) +Function 545: IsMusicReady() (1 input parameters) Name: IsMusicReady Return type: bool Description: Checks if a music stream is ready Param[1]: music (type: Music) -Function 545: UnloadMusicStream() (1 input parameters) +Function 546: UnloadMusicStream() (1 input parameters) Name: UnloadMusicStream Return type: void Description: Unload music stream Param[1]: music (type: Music) -Function 546: PlayMusicStream() (1 input parameters) +Function 547: PlayMusicStream() (1 input parameters) Name: PlayMusicStream Return type: void Description: Start music playing Param[1]: music (type: Music) -Function 547: IsMusicStreamPlaying() (1 input parameters) +Function 548: IsMusicStreamPlaying() (1 input parameters) Name: IsMusicStreamPlaying Return type: bool Description: Check if music is playing Param[1]: music (type: Music) -Function 548: UpdateMusicStream() (1 input parameters) +Function 549: UpdateMusicStream() (1 input parameters) Name: UpdateMusicStream Return type: void Description: Updates buffers for music streaming Param[1]: music (type: Music) -Function 549: StopMusicStream() (1 input parameters) +Function 550: StopMusicStream() (1 input parameters) Name: StopMusicStream Return type: void Description: Stop music playing Param[1]: music (type: Music) -Function 550: PauseMusicStream() (1 input parameters) +Function 551: PauseMusicStream() (1 input parameters) Name: PauseMusicStream Return type: void Description: Pause music playing Param[1]: music (type: Music) -Function 551: ResumeMusicStream() (1 input parameters) +Function 552: ResumeMusicStream() (1 input parameters) Name: ResumeMusicStream Return type: void Description: Resume playing paused music Param[1]: music (type: Music) -Function 552: SeekMusicStream() (2 input parameters) +Function 553: 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 553: SetMusicVolume() (2 input parameters) +Function 554: 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 554: SetMusicPitch() (2 input parameters) +Function 555: 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 555: SetMusicPan() (2 input parameters) +Function 556: 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 556: GetMusicTimeLength() (1 input parameters) +Function 557: GetMusicTimeLength() (1 input parameters) Name: GetMusicTimeLength Return type: float Description: Get music time length (in seconds) Param[1]: music (type: Music) -Function 557: GetMusicTimePlayed() (1 input parameters) +Function 558: GetMusicTimePlayed() (1 input parameters) Name: GetMusicTimePlayed Return type: float Description: Get current music time played (in seconds) Param[1]: music (type: Music) -Function 558: LoadAudioStream() (3 input parameters) +Function 559: 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 559: IsAudioStreamReady() (1 input parameters) +Function 560: IsAudioStreamReady() (1 input parameters) Name: IsAudioStreamReady Return type: bool Description: Checks if an audio stream is ready Param[1]: stream (type: AudioStream) -Function 560: UnloadAudioStream() (1 input parameters) +Function 561: UnloadAudioStream() (1 input parameters) Name: UnloadAudioStream Return type: void Description: Unload audio stream and free memory Param[1]: stream (type: AudioStream) -Function 561: UpdateAudioStream() (3 input parameters) +Function 562: 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 562: IsAudioStreamProcessed() (1 input parameters) +Function 563: IsAudioStreamProcessed() (1 input parameters) Name: IsAudioStreamProcessed Return type: bool Description: Check if any audio stream buffers requires refill Param[1]: stream (type: AudioStream) -Function 563: PlayAudioStream() (1 input parameters) +Function 564: PlayAudioStream() (1 input parameters) Name: PlayAudioStream Return type: void Description: Play audio stream Param[1]: stream (type: AudioStream) -Function 564: PauseAudioStream() (1 input parameters) +Function 565: PauseAudioStream() (1 input parameters) Name: PauseAudioStream Return type: void Description: Pause audio stream Param[1]: stream (type: AudioStream) -Function 565: ResumeAudioStream() (1 input parameters) +Function 566: ResumeAudioStream() (1 input parameters) Name: ResumeAudioStream Return type: void Description: Resume audio stream Param[1]: stream (type: AudioStream) -Function 566: IsAudioStreamPlaying() (1 input parameters) +Function 567: IsAudioStreamPlaying() (1 input parameters) Name: IsAudioStreamPlaying Return type: bool Description: Check if audio stream is playing Param[1]: stream (type: AudioStream) -Function 567: StopAudioStream() (1 input parameters) +Function 568: StopAudioStream() (1 input parameters) Name: StopAudioStream Return type: void Description: Stop audio stream Param[1]: stream (type: AudioStream) -Function 568: SetAudioStreamVolume() (2 input parameters) +Function 569: 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 569: SetAudioStreamPitch() (2 input parameters) +Function 570: 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 570: SetAudioStreamPan() (2 input parameters) +Function 571: 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 571: SetAudioStreamBufferSizeDefault() (1 input parameters) +Function 572: SetAudioStreamBufferSizeDefault() (1 input parameters) Name: SetAudioStreamBufferSizeDefault Return type: void Description: Default size for new audio streams Param[1]: size (type: int) -Function 572: SetAudioStreamCallback() (2 input parameters) +Function 573: 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 573: AttachAudioStreamProcessor() (2 input parameters) +Function 574: AttachAudioStreamProcessor() (2 input parameters) Name: AttachAudioStreamProcessor Return type: void Description: Attach audio stream processor to stream, receives the samples as 'float' Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 574: DetachAudioStreamProcessor() (2 input parameters) +Function 575: 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 575: AttachAudioMixedProcessor() (1 input parameters) +Function 576: AttachAudioMixedProcessor() (1 input parameters) Name: AttachAudioMixedProcessor Return type: void Description: Attach audio stream processor to the entire audio pipeline, receives the samples as 'float' Param[1]: processor (type: AudioCallback) -Function 576: DetachAudioMixedProcessor() (1 input parameters) +Function 577: DetachAudioMixedProcessor() (1 input parameters) Name: DetachAudioMixedProcessor Return type: void Description: Detach audio stream processor from the entire audio pipeline diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index 6bd5a4581..13ea5b7ab 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -160,7 +160,7 @@ - + @@ -172,8 +172,10 @@ - - + + + + @@ -505,7 +507,7 @@ - + @@ -532,6 +534,9 @@ + + + @@ -670,7 +675,7 @@ - + @@ -2822,6 +2827,11 @@ + + + + + From e5d0cc978ae933ccccd41758d50d1cd57e3474d1 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 20 Sep 2024 17:32:01 +0200 Subject: [PATCH 041/115] Some minor tweaks --- src/platforms/rcore_desktop_rgfw.c | 2 +- src/rlgl.h | 3 +++ src/rmodels.c | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index 64ab432e6..ef01820cb 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -940,7 +940,7 @@ void PollInputEvents(void) SetupViewport(platform.window->r.w, platform.window->r.h); CORE.Window.screen.width = platform.window->r.w; CORE.Window.screen.height = platform.window->r.h; - CORE.Window.currentFbo.width = platform.window->r.w;; + CORE.Window.currentFbo.width = platform.window->r.w; CORE.Window.currentFbo.height = platform.window->r.h; CORE.Window.resizedLastFrame = true; } break; diff --git a/src/rlgl.h b/src/rlgl.h index b98934a11..83ef966ce 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -350,6 +350,9 @@ #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 7 #endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6 +#endif //---------------------------------------------------------------------------------- // Types and Structures Definition diff --git a/src/rmodels.c b/src/rmodels.c index 055fb1b1c..ebdd178fd 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -4377,7 +4377,7 @@ static Model LoadOBJ(const char *fileName) } // if this is a new material, we need to allocate a new mesh if (lastMaterial != -1 && objAttributes.material_ids[faceId] != lastMaterial) newMesh = true; - lastMaterial = objAttributes.material_ids[faceId];; + lastMaterial = objAttributes.material_ids[faceId]; if (newMesh) { From 212b1e5fe7a898729a5b24d6f4c1720c508cb0be Mon Sep 17 00:00:00 2001 From: Asdqwe Date: Sat, 21 Sep 2024 18:11:40 -0300 Subject: [PATCH 042/115] Fix rlgl standalone defaults (#4334) --- src/rlgl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 83ef966ce..875b568f5 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -351,7 +351,7 @@ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 7 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6 + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 8 #endif //---------------------------------------------------------------------------------- @@ -4272,7 +4272,7 @@ void rlSetUniform(int locIndex, const void *value, int uniformType, int count) #endif case RL_SHADER_UNIFORM_SAMPLER2D: glUniform1iv(locIndex, count, (int *)value); break; default: TRACELOG(RL_LOG_WARNING, "SHADER: Failed to set uniform value, data type not recognized"); - + // TODO: Support glUniform1uiv(), glUniform2uiv(), glUniform3uiv(), glUniform4uiv() } #endif From 93379137664b33f7245cccf9542e0a4a0b9e30a8 Mon Sep 17 00:00:00 2001 From: Ridge3Dproductions <78836162+Ridge3Dproductions@users.noreply.github.com> Date: Sat, 21 Sep 2024 17:12:48 -0400 Subject: [PATCH 043/115] Projects: Fix CMake example project (#4332) * Update CMakeLists.txt Add missing link flags * Update README.md Remove unneeded flag because this flag is defined in the updated CMakeList file * Update CMakeLists.txt --- projects/CMake/CMakeLists.txt | 4 ++-- projects/CMake/README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/projects/CMake/CMakeLists.txt b/projects/CMake/CMakeLists.txt index a95d68a4f..96e33f344 100644 --- a/projects/CMake/CMakeLists.txt +++ b/projects/CMake/CMakeLists.txt @@ -30,8 +30,8 @@ target_link_libraries(${PROJECT_NAME} raylib) # Web Configurations if (${PLATFORM} STREQUAL "Web") - # Tell Emscripten to build an example.html file. - set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".html") + set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".html") # Tell Emscripten to build an example.html file. + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY -s GL_ENABLE_GET_PROC_ADDRESS=1") endif() # Checks if OSX and links appropriate frameworks (Only required on MacOS) diff --git a/projects/CMake/README.md b/projects/CMake/README.md index f7873c30f..fc4fe5542 100644 --- a/projects/CMake/README.md +++ b/projects/CMake/README.md @@ -22,6 +22,6 @@ Compiling for the web requires the [Emscripten SDK](https://emscripten.org/docs/ ``` bash mkdir build cd build -emcmake cmake .. -DPLATFORM=Web -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXE_LINKER_FLAGS="-s USE_GLFW=3" -DCMAKE_EXECUTABLE_SUFFIX=".html" +emcmake cmake .. -DPLATFORM=Web -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXECUTABLE_SUFFIX=".html" emmake make -``` \ No newline at end of file +``` From daaca40416f4d1006382ecd51457df89ace0e21d Mon Sep 17 00:00:00 2001 From: Daniil Kisel <56605335+KislyjKisel@users.noreply.github.com> Date: Sun, 22 Sep 2024 14:45:10 +0300 Subject: [PATCH 044/115] Update parser's readme to mirror fixed help text (#4336) --- parser/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parser/README.md b/parser/README.md index 45a2689a0..6616cdc51 100644 --- a/parser/README.md +++ b/parser/README.md @@ -41,7 +41,7 @@ OPTIONS: -f, --format : Define output format for parser data. Supported types: DEFAULT, JSON, XML, LUA - -d, --define : Define functions specifiers (i.e. RLAPI for raylib.h, RMDEF for raymath.h, etc.) + -d, --define : Define functions specifiers (i.e. RLAPI for raylib.h, RMAPI for raymath.h, etc.) NOTE: If no specifier defined, defaults to: RLAPI -t, --truncate : Define string to truncate input after (i.e. "RLGL IMPLEMENTATION" for rlgl.h) @@ -56,7 +56,7 @@ EXAMPLES: > raylib_parser --output raylib_data.info --format XML Process to generate as XML text data - > raylib_parser --input raymath.h --output raymath_data.info --format XML + > raylib_parser --input raymath.h --output raymath_data.info --format XML --define RMAPI Process to generate as XML text data ``` From 7d3f04ca356c9a088e0901c7a179955683e66207 Mon Sep 17 00:00:00 2001 From: Daniil Kisel <56605335+KislyjKisel@users.noreply.github.com> Date: Sun, 22 Sep 2024 15:36:06 +0300 Subject: [PATCH 045/115] Update BINDINGS.md (#4337) Updated Lean4 bindings --- BINDINGS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BINDINGS.md b/BINDINGS.md index 6ac54498e..e79d39c36 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -81,7 +81,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers | [raylib-bqn](https://github.com/Brian-ED/raylib-bqn) | **5.0** | [BQN](https://mlochbaum.github.io/BQN) | MIT | | [rayjs](https://github.com/mode777/rayjs) | 4.6-dev | [QuickJS](https://bellard.org/quickjs) | MIT | | [raylib-raku](https://github.com/vushu/raylib-raku) | **auto** | [Raku](https://www.raku.org) | Artistic License 2.0 | -| [Raylib.lean](https://github.com/KislyjKisel/Raylib.lean) | 4.5 | [Lean4](https://lean-lang.org) | BSD-3-Clause | +| [Raylib.lean](https://github.com/KislyjKisel/Raylib.lean) | **5.5-dev** | [Lean4](https://lean-lang.org) | BSD-3-Clause | | [raylib-cobol](https://codeberg.org/glowiak/raylib-cobol) | **auto** | [COBOL](https://gnucobol.sourceforge.io) | Public domain | | [raylib-apl](https://github.com/Brian-ED/raylib-apl) | **5.0** | [Dyalog APL](https://www.dyalog.com/) | MIT | From 1eb8ff5e54d73365997fec442103e686aaed1d90 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 22 Sep 2024 18:05:58 +0200 Subject: [PATCH 046/115] `LoadFontDefault()`: Initialize glyphs and recs to zero #4319 --- src/rtext.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rtext.c b/src/rtext.c index 34b6fcedb..e4c89d5f1 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -260,8 +260,8 @@ extern void LoadFontDefault(void) // Allocate space for our characters info data // NOTE: This memory must be freed at end! --> Done by CloseWindow() - defaultFont.glyphs = (GlyphInfo *)RL_MALLOC(defaultFont.glyphCount*sizeof(GlyphInfo)); - defaultFont.recs = (Rectangle *)RL_MALLOC(defaultFont.glyphCount*sizeof(Rectangle)); + defaultFont.glyphs = (GlyphInfo *)RL_CALLOC(defaultFont.glyphCount, sizeof(GlyphInfo)); + defaultFont.recs = (Rectangle *)RL_CALLOC(defaultFont.glyphCount, sizeof(Rectangle)); int currentLine = 0; int currentPosX = charsDivisor; From 55a25ac04bb448fcc17e9347314b56d5b6881ae0 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 22 Sep 2024 22:11:08 +0200 Subject: [PATCH 047/115] ADDED: `MakeDirectory()` --- src/raylib.h | 1 + src/rcore.c | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index ee34b6441..f298fd731 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1127,6 +1127,7 @@ RLAPI const char *GetDirectoryPath(const char *filePath); // Get full pa RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a given path (uses static string) RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string) RLAPI const char *GetApplicationDirectory(void); // Get the directory of the running application (uses static string) +RLAPI int MakeDirectory(const char *dirPath); // Create directories (including full path requested), returns 0 on success RLAPI bool ChangeDirectory(const char *dir); // Change working directory, return true on success RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS diff --git a/src/rcore.c b/src/rcore.c index 2fd79f5c9..1501aced1 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -191,16 +191,25 @@ unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); #endif #if defined(_WIN32) - #include // Required for: _getch(), _chdir() + #include // Required for: _access() [Used in FileExists()] + #include // Required for: _getch(), _chdir(), _mkdir() #define GETCWD _getcwd // NOTE: MSDN recommends not to use getcwd(), chdir() #define CHDIR _chdir - #include // Required for: _access() [Used in FileExists()] #else #include // Required for: getch(), chdir() (POSIX), access() #define GETCWD getcwd #define CHDIR chdir #endif +#if defined(_MSC_VER) && ((defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__)) + #include // Required for: _mkdir() + #define MKDIR(dir) _mkdir(dir) +#elif defined __GNUC__ + #include + #include // Required for: mkdir() + #define MKDIR(dir) mkdir(dir) // OLD: mkdir(dir, 0777) -> w64devkit complaints! +#endif + //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -2267,6 +2276,40 @@ void UnloadDirectoryFiles(FilePathList files) RL_FREE(files.paths); } +// Create directories (including full path requested), returns 0 on success +int MakeDirectory(const char *dirPath) +{ + if ((dirPath == NULL) || (dirPath[0] == '\0')) return 1; // Path is not valid + if (DirectoryExists(dirPath)) return 0; // Path already exists (is valid) + + // Copy path string to avoid modifying original + int len = (int)strlen(dirPath) + 1; + char *pathcpy = (char *)RL_CALLOC(len, 1); + memcpy(pathcpy, dirPath, len); + + // Iterate over pathcpy, create each subdirectory as needed + for (int i = 0; (i < len) && (pathcpy[i] != '\0'); i++) + { + if (pathcpy[i] == ':') i++; + else + { + if ((pathcpy[i] == '\\') || (pathcpy[i] == '/')) + { + pathcpy[i] = '\0'; + if (!DirectoryExists(pathcpy)) MKDIR(pathcpy); + pathcpy[i] = '/'; + } + } + } + + // Create final directory + if (!DirectoryExists(pathcpy)) MKDIR(pathcpy); + + RL_FREE(pathcpy); + + return 0; +} + // Change working directory, returns true on success bool ChangeDirectory(const char *dir) { From 1c7b18923ca05e67309f9d8732fcca9a0b1de8df Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 22 Sep 2024 20:11:24 +0000 Subject: [PATCH 048/115] Update raylib_api.* by CI --- parser/output/raylib_api.json | 11 + parser/output/raylib_api.lua | 8 + parser/output/raylib_api.txt | 895 +++++++++++++++++----------------- parser/output/raylib_api.xml | 5 +- 4 files changed, 473 insertions(+), 446 deletions(-) diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json index d1c58757b..2e599496d 100644 --- a/parser/output/raylib_api.json +++ b/parser/output/raylib_api.json @@ -4502,6 +4502,17 @@ "description": "Get the directory of the running application (uses static string)", "returnType": "const char *" }, + { + "name": "MakeDirectory", + "description": "Create directories (including full path requested), returns 0 on success", + "returnType": "int", + "params": [ + { + "type": "const char *", + "name": "dirPath" + } + ] + }, { "name": "ChangeDirectory", "description": "Change working directory, return true on success", diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua index 0d99407b7..69ae07eda 100644 --- a/parser/output/raylib_api.lua +++ b/parser/output/raylib_api.lua @@ -4067,6 +4067,14 @@ return { description = "Get the directory of the running application (uses static string)", returnType = "const char *" }, + { + name = "MakeDirectory", + description = "Create directories (including full path requested), returns 0 on success", + returnType = "int", + params = { + {type = "const char *", name = "dirPath"} + } + }, { name = "ChangeDirectory", description = "Change working directory, return true on success", diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt index 9c92906e0..458d12da0 100644 --- a/parser/output/raylib_api.txt +++ b/parser/output/raylib_api.txt @@ -989,7 +989,7 @@ Callback 006: AudioCallback() (2 input parameters) Param[1]: bufferData (type: void *) Param[2]: frames (type: unsigned int) -Functions found: 577 +Functions found: 578 Function 001: InitWindow() (3 input parameters) Name: InitWindow @@ -1704,373 +1704,378 @@ Function 133: GetApplicationDirectory() (0 input parameters) Return type: const char * Description: Get the directory of the running application (uses static string) No input parameters -Function 134: ChangeDirectory() (1 input parameters) +Function 134: MakeDirectory() (1 input parameters) + Name: MakeDirectory + Return type: int + Description: Create directories (including full path requested), returns 0 on success + Param[1]: dirPath (type: const char *) +Function 135: ChangeDirectory() (1 input parameters) Name: ChangeDirectory Return type: bool Description: Change working directory, return true on success Param[1]: dir (type: const char *) -Function 135: IsPathFile() (1 input parameters) +Function 136: 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 136: IsFileNameValid() (1 input parameters) +Function 137: IsFileNameValid() (1 input parameters) Name: IsFileNameValid Return type: bool Description: Check if fileName is valid for the platform/OS Param[1]: fileName (type: const char *) -Function 137: LoadDirectoryFiles() (1 input parameters) +Function 138: LoadDirectoryFiles() (1 input parameters) Name: LoadDirectoryFiles Return type: FilePathList Description: Load directory filepaths Param[1]: dirPath (type: const char *) -Function 138: LoadDirectoryFilesEx() (3 input parameters) +Function 139: LoadDirectoryFilesEx() (3 input parameters) Name: LoadDirectoryFilesEx Return type: FilePathList Description: Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result Param[1]: basePath (type: const char *) Param[2]: filter (type: const char *) Param[3]: scanSubdirs (type: bool) -Function 139: UnloadDirectoryFiles() (1 input parameters) +Function 140: UnloadDirectoryFiles() (1 input parameters) Name: UnloadDirectoryFiles Return type: void Description: Unload filepaths Param[1]: files (type: FilePathList) -Function 140: IsFileDropped() (0 input parameters) +Function 141: IsFileDropped() (0 input parameters) Name: IsFileDropped Return type: bool Description: Check if a file has been dropped into window No input parameters -Function 141: LoadDroppedFiles() (0 input parameters) +Function 142: LoadDroppedFiles() (0 input parameters) Name: LoadDroppedFiles Return type: FilePathList Description: Load dropped filepaths No input parameters -Function 142: UnloadDroppedFiles() (1 input parameters) +Function 143: UnloadDroppedFiles() (1 input parameters) Name: UnloadDroppedFiles Return type: void Description: Unload dropped filepaths Param[1]: files (type: FilePathList) -Function 143: GetFileModTime() (1 input parameters) +Function 144: GetFileModTime() (1 input parameters) Name: GetFileModTime Return type: long Description: Get file modification time (last write time) Param[1]: fileName (type: const char *) -Function 144: CompressData() (3 input parameters) +Function 145: 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 145: DecompressData() (3 input parameters) +Function 146: 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 146: EncodeDataBase64() (3 input parameters) +Function 147: 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 147: DecodeDataBase64() (2 input parameters) +Function 148: 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 148: LoadAutomationEventList() (1 input parameters) +Function 149: LoadAutomationEventList() (1 input parameters) Name: LoadAutomationEventList Return type: AutomationEventList Description: Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS Param[1]: fileName (type: const char *) -Function 149: UnloadAutomationEventList() (1 input parameters) +Function 150: UnloadAutomationEventList() (1 input parameters) Name: UnloadAutomationEventList Return type: void Description: Unload automation events list from file Param[1]: list (type: AutomationEventList) -Function 150: ExportAutomationEventList() (2 input parameters) +Function 151: ExportAutomationEventList() (2 input parameters) Name: ExportAutomationEventList Return type: bool Description: Export automation events list as text file Param[1]: list (type: AutomationEventList) Param[2]: fileName (type: const char *) -Function 151: SetAutomationEventList() (1 input parameters) +Function 152: SetAutomationEventList() (1 input parameters) Name: SetAutomationEventList Return type: void Description: Set automation event list to record to Param[1]: list (type: AutomationEventList *) -Function 152: SetAutomationEventBaseFrame() (1 input parameters) +Function 153: SetAutomationEventBaseFrame() (1 input parameters) Name: SetAutomationEventBaseFrame Return type: void Description: Set automation event internal base frame to start recording Param[1]: frame (type: int) -Function 153: StartAutomationEventRecording() (0 input parameters) +Function 154: StartAutomationEventRecording() (0 input parameters) Name: StartAutomationEventRecording Return type: void Description: Start recording automation events (AutomationEventList must be set) No input parameters -Function 154: StopAutomationEventRecording() (0 input parameters) +Function 155: StopAutomationEventRecording() (0 input parameters) Name: StopAutomationEventRecording Return type: void Description: Stop recording automation events No input parameters -Function 155: PlayAutomationEvent() (1 input parameters) +Function 156: PlayAutomationEvent() (1 input parameters) Name: PlayAutomationEvent Return type: void Description: Play a recorded automation event Param[1]: event (type: AutomationEvent) -Function 156: IsKeyPressed() (1 input parameters) +Function 157: IsKeyPressed() (1 input parameters) Name: IsKeyPressed Return type: bool Description: Check if a key has been pressed once Param[1]: key (type: int) -Function 157: IsKeyPressedRepeat() (1 input parameters) +Function 158: IsKeyPressedRepeat() (1 input parameters) Name: IsKeyPressedRepeat Return type: bool Description: Check if a key has been pressed again (Only PLATFORM_DESKTOP) Param[1]: key (type: int) -Function 158: IsKeyDown() (1 input parameters) +Function 159: IsKeyDown() (1 input parameters) Name: IsKeyDown Return type: bool Description: Check if a key is being pressed Param[1]: key (type: int) -Function 159: IsKeyReleased() (1 input parameters) +Function 160: IsKeyReleased() (1 input parameters) Name: IsKeyReleased Return type: bool Description: Check if a key has been released once Param[1]: key (type: int) -Function 160: IsKeyUp() (1 input parameters) +Function 161: IsKeyUp() (1 input parameters) Name: IsKeyUp Return type: bool Description: Check if a key is NOT being pressed Param[1]: key (type: int) -Function 161: GetKeyPressed() (0 input parameters) +Function 162: 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 162: GetCharPressed() (0 input parameters) +Function 163: 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 163: SetExitKey() (1 input parameters) +Function 164: 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 164: IsGamepadAvailable() (1 input parameters) +Function 165: IsGamepadAvailable() (1 input parameters) Name: IsGamepadAvailable Return type: bool Description: Check if a gamepad is available Param[1]: gamepad (type: int) -Function 165: GetGamepadName() (1 input parameters) +Function 166: GetGamepadName() (1 input parameters) Name: GetGamepadName Return type: const char * Description: Get gamepad internal name id Param[1]: gamepad (type: int) -Function 166: IsGamepadButtonPressed() (2 input parameters) +Function 167: 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 167: IsGamepadButtonDown() (2 input parameters) +Function 168: 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 168: IsGamepadButtonReleased() (2 input parameters) +Function 169: 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 169: IsGamepadButtonUp() (2 input parameters) +Function 170: 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 170: GetGamepadButtonPressed() (0 input parameters) +Function 171: GetGamepadButtonPressed() (0 input parameters) Name: GetGamepadButtonPressed Return type: int Description: Get the last gamepad button pressed No input parameters -Function 171: GetGamepadAxisCount() (1 input parameters) +Function 172: GetGamepadAxisCount() (1 input parameters) Name: GetGamepadAxisCount Return type: int Description: Get gamepad axis count for a gamepad Param[1]: gamepad (type: int) -Function 172: GetGamepadAxisMovement() (2 input parameters) +Function 173: 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 173: SetGamepadMappings() (1 input parameters) +Function 174: SetGamepadMappings() (1 input parameters) Name: SetGamepadMappings Return type: int Description: Set internal gamepad mappings (SDL_GameControllerDB) Param[1]: mappings (type: const char *) -Function 174: SetGamepadVibration() (3 input parameters) +Function 175: SetGamepadVibration() (3 input parameters) Name: SetGamepadVibration Return type: void Description: Set gamepad vibration for both motors Param[1]: gamepad (type: int) Param[2]: leftMotor (type: float) Param[3]: rightMotor (type: float) -Function 175: IsMouseButtonPressed() (1 input parameters) +Function 176: 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 176: IsMouseButtonDown() (1 input parameters) +Function 177: IsMouseButtonDown() (1 input parameters) Name: IsMouseButtonDown Return type: bool Description: Check if a mouse button is being pressed Param[1]: button (type: int) -Function 177: IsMouseButtonReleased() (1 input parameters) +Function 178: 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 178: IsMouseButtonUp() (1 input parameters) +Function 179: 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 179: GetMouseX() (0 input parameters) +Function 180: GetMouseX() (0 input parameters) Name: GetMouseX Return type: int Description: Get mouse position X No input parameters -Function 180: GetMouseY() (0 input parameters) +Function 181: GetMouseY() (0 input parameters) Name: GetMouseY Return type: int Description: Get mouse position Y No input parameters -Function 181: GetMousePosition() (0 input parameters) +Function 182: GetMousePosition() (0 input parameters) Name: GetMousePosition Return type: Vector2 Description: Get mouse position XY No input parameters -Function 182: GetMouseDelta() (0 input parameters) +Function 183: GetMouseDelta() (0 input parameters) Name: GetMouseDelta Return type: Vector2 Description: Get mouse delta between frames No input parameters -Function 183: SetMousePosition() (2 input parameters) +Function 184: 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 184: SetMouseOffset() (2 input parameters) +Function 185: SetMouseOffset() (2 input parameters) Name: SetMouseOffset Return type: void Description: Set mouse offset Param[1]: offsetX (type: int) Param[2]: offsetY (type: int) -Function 185: SetMouseScale() (2 input parameters) +Function 186: SetMouseScale() (2 input parameters) Name: SetMouseScale Return type: void Description: Set mouse scaling Param[1]: scaleX (type: float) Param[2]: scaleY (type: float) -Function 186: GetMouseWheelMove() (0 input parameters) +Function 187: 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 187: GetMouseWheelMoveV() (0 input parameters) +Function 188: GetMouseWheelMoveV() (0 input parameters) Name: GetMouseWheelMoveV Return type: Vector2 Description: Get mouse wheel movement for both X and Y No input parameters -Function 188: SetMouseCursor() (1 input parameters) +Function 189: SetMouseCursor() (1 input parameters) Name: SetMouseCursor Return type: void Description: Set mouse cursor Param[1]: cursor (type: int) -Function 189: GetTouchX() (0 input parameters) +Function 190: 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 190: GetTouchY() (0 input parameters) +Function 191: 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 191: GetTouchPosition() (1 input parameters) +Function 192: 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 192: GetTouchPointId() (1 input parameters) +Function 193: GetTouchPointId() (1 input parameters) Name: GetTouchPointId Return type: int Description: Get touch point identifier for given index Param[1]: index (type: int) -Function 193: GetTouchPointCount() (0 input parameters) +Function 194: GetTouchPointCount() (0 input parameters) Name: GetTouchPointCount Return type: int Description: Get number of touch points No input parameters -Function 194: SetGesturesEnabled() (1 input parameters) +Function 195: SetGesturesEnabled() (1 input parameters) Name: SetGesturesEnabled Return type: void Description: Enable a set of gestures using flags Param[1]: flags (type: unsigned int) -Function 195: IsGestureDetected() (1 input parameters) +Function 196: IsGestureDetected() (1 input parameters) Name: IsGestureDetected Return type: bool Description: Check if a gesture have been detected Param[1]: gesture (type: unsigned int) -Function 196: GetGestureDetected() (0 input parameters) +Function 197: GetGestureDetected() (0 input parameters) Name: GetGestureDetected Return type: int Description: Get latest detected gesture No input parameters -Function 197: GetGestureHoldDuration() (0 input parameters) +Function 198: GetGestureHoldDuration() (0 input parameters) Name: GetGestureHoldDuration Return type: float Description: Get gesture hold time in milliseconds No input parameters -Function 198: GetGestureDragVector() (0 input parameters) +Function 199: GetGestureDragVector() (0 input parameters) Name: GetGestureDragVector Return type: Vector2 Description: Get gesture drag vector No input parameters -Function 199: GetGestureDragAngle() (0 input parameters) +Function 200: GetGestureDragAngle() (0 input parameters) Name: GetGestureDragAngle Return type: float Description: Get gesture drag angle No input parameters -Function 200: GetGesturePinchVector() (0 input parameters) +Function 201: GetGesturePinchVector() (0 input parameters) Name: GetGesturePinchVector Return type: Vector2 Description: Get gesture pinch delta No input parameters -Function 201: GetGesturePinchAngle() (0 input parameters) +Function 202: GetGesturePinchAngle() (0 input parameters) Name: GetGesturePinchAngle Return type: float Description: Get gesture pinch angle No input parameters -Function 202: UpdateCamera() (2 input parameters) +Function 203: UpdateCamera() (2 input parameters) Name: UpdateCamera Return type: void Description: Update camera position for selected mode Param[1]: camera (type: Camera *) Param[2]: mode (type: int) -Function 203: UpdateCameraPro() (4 input parameters) +Function 204: UpdateCameraPro() (4 input parameters) Name: UpdateCameraPro Return type: void Description: Update camera movement/rotation @@ -2078,36 +2083,36 @@ Function 203: UpdateCameraPro() (4 input parameters) Param[2]: movement (type: Vector3) Param[3]: rotation (type: Vector3) Param[4]: zoom (type: float) -Function 204: SetShapesTexture() (2 input parameters) +Function 205: 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 205: GetShapesTexture() (0 input parameters) +Function 206: GetShapesTexture() (0 input parameters) Name: GetShapesTexture Return type: Texture2D Description: Get texture that is used for shapes drawing No input parameters -Function 206: GetShapesTextureRectangle() (0 input parameters) +Function 207: GetShapesTextureRectangle() (0 input parameters) Name: GetShapesTextureRectangle Return type: Rectangle Description: Get texture source rectangle that is used for shapes drawing No input parameters -Function 207: DrawPixel() (3 input parameters) +Function 208: 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 208: DrawPixelV() (2 input parameters) +Function 209: 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 209: DrawLine() (5 input parameters) +Function 210: DrawLine() (5 input parameters) Name: DrawLine Return type: void Description: Draw a line @@ -2116,14 +2121,14 @@ Function 209: DrawLine() (5 input parameters) Param[3]: endPosX (type: int) Param[4]: endPosY (type: int) Param[5]: color (type: Color) -Function 210: DrawLineV() (3 input parameters) +Function 211: DrawLineV() (3 input parameters) Name: DrawLineV Return type: void Description: Draw a line (using gl lines) Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: color (type: Color) -Function 211: DrawLineEx() (4 input parameters) +Function 212: DrawLineEx() (4 input parameters) Name: DrawLineEx Return type: void Description: Draw a line (using triangles/quads) @@ -2131,14 +2136,14 @@ Function 211: DrawLineEx() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 212: DrawLineStrip() (3 input parameters) +Function 213: DrawLineStrip() (3 input parameters) Name: DrawLineStrip Return type: void Description: Draw lines sequence (using gl lines) Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 213: DrawLineBezier() (4 input parameters) +Function 214: DrawLineBezier() (4 input parameters) Name: DrawLineBezier Return type: void Description: Draw line segment cubic-bezier in-out interpolation @@ -2146,7 +2151,7 @@ Function 213: DrawLineBezier() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 214: DrawCircle() (4 input parameters) +Function 215: DrawCircle() (4 input parameters) Name: DrawCircle Return type: void Description: Draw a color-filled circle @@ -2154,7 +2159,7 @@ Function 214: DrawCircle() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 215: DrawCircleSector() (6 input parameters) +Function 216: DrawCircleSector() (6 input parameters) Name: DrawCircleSector Return type: void Description: Draw a piece of a circle @@ -2164,7 +2169,7 @@ Function 215: DrawCircleSector() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 216: DrawCircleSectorLines() (6 input parameters) +Function 217: DrawCircleSectorLines() (6 input parameters) Name: DrawCircleSectorLines Return type: void Description: Draw circle sector outline @@ -2174,7 +2179,7 @@ Function 216: DrawCircleSectorLines() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 217: DrawCircleGradient() (5 input parameters) +Function 218: DrawCircleGradient() (5 input parameters) Name: DrawCircleGradient Return type: void Description: Draw a gradient-filled circle @@ -2183,14 +2188,14 @@ Function 217: DrawCircleGradient() (5 input parameters) Param[3]: radius (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 218: DrawCircleV() (3 input parameters) +Function 219: 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 219: DrawCircleLines() (4 input parameters) +Function 220: DrawCircleLines() (4 input parameters) Name: DrawCircleLines Return type: void Description: Draw circle outline @@ -2198,14 +2203,14 @@ Function 219: DrawCircleLines() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 220: DrawCircleLinesV() (3 input parameters) +Function 221: DrawCircleLinesV() (3 input parameters) Name: DrawCircleLinesV Return type: void Description: Draw circle outline (Vector version) Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 221: DrawEllipse() (5 input parameters) +Function 222: DrawEllipse() (5 input parameters) Name: DrawEllipse Return type: void Description: Draw ellipse @@ -2214,7 +2219,7 @@ Function 221: DrawEllipse() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 222: DrawEllipseLines() (5 input parameters) +Function 223: DrawEllipseLines() (5 input parameters) Name: DrawEllipseLines Return type: void Description: Draw ellipse outline @@ -2223,7 +2228,7 @@ Function 222: DrawEllipseLines() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 223: DrawRing() (7 input parameters) +Function 224: DrawRing() (7 input parameters) Name: DrawRing Return type: void Description: Draw ring @@ -2234,7 +2239,7 @@ Function 223: DrawRing() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 224: DrawRingLines() (7 input parameters) +Function 225: DrawRingLines() (7 input parameters) Name: DrawRingLines Return type: void Description: Draw ring outline @@ -2245,7 +2250,7 @@ Function 224: DrawRingLines() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 225: DrawRectangle() (5 input parameters) +Function 226: DrawRectangle() (5 input parameters) Name: DrawRectangle Return type: void Description: Draw a color-filled rectangle @@ -2254,20 +2259,20 @@ Function 225: DrawRectangle() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 226: DrawRectangleV() (3 input parameters) +Function 227: 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 227: DrawRectangleRec() (2 input parameters) +Function 228: 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 228: DrawRectanglePro() (4 input parameters) +Function 229: DrawRectanglePro() (4 input parameters) Name: DrawRectanglePro Return type: void Description: Draw a color-filled rectangle with pro parameters @@ -2275,7 +2280,7 @@ Function 228: DrawRectanglePro() (4 input parameters) Param[2]: origin (type: Vector2) Param[3]: rotation (type: float) Param[4]: color (type: Color) -Function 229: DrawRectangleGradientV() (6 input parameters) +Function 230: DrawRectangleGradientV() (6 input parameters) Name: DrawRectangleGradientV Return type: void Description: Draw a vertical-gradient-filled rectangle @@ -2285,7 +2290,7 @@ Function 229: DrawRectangleGradientV() (6 input parameters) Param[4]: height (type: int) Param[5]: top (type: Color) Param[6]: bottom (type: Color) -Function 230: DrawRectangleGradientH() (6 input parameters) +Function 231: DrawRectangleGradientH() (6 input parameters) Name: DrawRectangleGradientH Return type: void Description: Draw a horizontal-gradient-filled rectangle @@ -2295,7 +2300,7 @@ Function 230: DrawRectangleGradientH() (6 input parameters) Param[4]: height (type: int) Param[5]: left (type: Color) Param[6]: right (type: Color) -Function 231: DrawRectangleGradientEx() (5 input parameters) +Function 232: DrawRectangleGradientEx() (5 input parameters) Name: DrawRectangleGradientEx Return type: void Description: Draw a gradient-filled rectangle with custom vertex colors @@ -2304,7 +2309,7 @@ Function 231: DrawRectangleGradientEx() (5 input parameters) Param[3]: bottomLeft (type: Color) Param[4]: topRight (type: Color) Param[5]: bottomRight (type: Color) -Function 232: DrawRectangleLines() (5 input parameters) +Function 233: DrawRectangleLines() (5 input parameters) Name: DrawRectangleLines Return type: void Description: Draw rectangle outline @@ -2313,14 +2318,14 @@ Function 232: DrawRectangleLines() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 233: DrawRectangleLinesEx() (3 input parameters) +Function 234: 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 234: DrawRectangleRounded() (4 input parameters) +Function 235: DrawRectangleRounded() (4 input parameters) Name: DrawRectangleRounded Return type: void Description: Draw rectangle with rounded edges @@ -2328,7 +2333,7 @@ Function 234: DrawRectangleRounded() (4 input parameters) Param[2]: roundness (type: float) Param[3]: segments (type: int) Param[4]: color (type: Color) -Function 235: DrawRectangleRoundedLines() (4 input parameters) +Function 236: DrawRectangleRoundedLines() (4 input parameters) Name: DrawRectangleRoundedLines Return type: void Description: Draw rectangle lines with rounded edges @@ -2336,7 +2341,7 @@ Function 235: DrawRectangleRoundedLines() (4 input parameters) Param[2]: roundness (type: float) Param[3]: segments (type: int) Param[4]: color (type: Color) -Function 236: DrawRectangleRoundedLinesEx() (5 input parameters) +Function 237: DrawRectangleRoundedLinesEx() (5 input parameters) Name: DrawRectangleRoundedLinesEx Return type: void Description: Draw rectangle with rounded edges outline @@ -2345,7 +2350,7 @@ Function 236: DrawRectangleRoundedLinesEx() (5 input parameters) Param[3]: segments (type: int) Param[4]: lineThick (type: float) Param[5]: color (type: Color) -Function 237: DrawTriangle() (4 input parameters) +Function 238: DrawTriangle() (4 input parameters) Name: DrawTriangle Return type: void Description: Draw a color-filled triangle (vertex in counter-clockwise order!) @@ -2353,7 +2358,7 @@ Function 237: DrawTriangle() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 238: DrawTriangleLines() (4 input parameters) +Function 239: DrawTriangleLines() (4 input parameters) Name: DrawTriangleLines Return type: void Description: Draw triangle outline (vertex in counter-clockwise order!) @@ -2361,21 +2366,21 @@ Function 238: DrawTriangleLines() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 239: DrawTriangleFan() (3 input parameters) +Function 240: DrawTriangleFan() (3 input parameters) Name: DrawTriangleFan Return type: void Description: Draw a triangle fan defined by points (first vertex is the center) Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 240: DrawTriangleStrip() (3 input parameters) +Function 241: DrawTriangleStrip() (3 input parameters) Name: DrawTriangleStrip Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 241: DrawPoly() (5 input parameters) +Function 242: DrawPoly() (5 input parameters) Name: DrawPoly Return type: void Description: Draw a regular polygon (Vector version) @@ -2384,7 +2389,7 @@ Function 241: DrawPoly() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 242: DrawPolyLines() (5 input parameters) +Function 243: DrawPolyLines() (5 input parameters) Name: DrawPolyLines Return type: void Description: Draw a polygon outline of n sides @@ -2393,7 +2398,7 @@ Function 242: DrawPolyLines() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 243: DrawPolyLinesEx() (6 input parameters) +Function 244: DrawPolyLinesEx() (6 input parameters) Name: DrawPolyLinesEx Return type: void Description: Draw a polygon outline of n sides with extended parameters @@ -2403,7 +2408,7 @@ Function 243: DrawPolyLinesEx() (6 input parameters) Param[4]: rotation (type: float) Param[5]: lineThick (type: float) Param[6]: color (type: Color) -Function 244: DrawSplineLinear() (4 input parameters) +Function 245: DrawSplineLinear() (4 input parameters) Name: DrawSplineLinear Return type: void Description: Draw spline: Linear, minimum 2 points @@ -2411,7 +2416,7 @@ Function 244: DrawSplineLinear() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 245: DrawSplineBasis() (4 input parameters) +Function 246: DrawSplineBasis() (4 input parameters) Name: DrawSplineBasis Return type: void Description: Draw spline: B-Spline, minimum 4 points @@ -2419,7 +2424,7 @@ Function 245: DrawSplineBasis() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 246: DrawSplineCatmullRom() (4 input parameters) +Function 247: DrawSplineCatmullRom() (4 input parameters) Name: DrawSplineCatmullRom Return type: void Description: Draw spline: Catmull-Rom, minimum 4 points @@ -2427,7 +2432,7 @@ Function 246: DrawSplineCatmullRom() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 247: DrawSplineBezierQuadratic() (4 input parameters) +Function 248: DrawSplineBezierQuadratic() (4 input parameters) Name: DrawSplineBezierQuadratic Return type: void Description: Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...] @@ -2435,7 +2440,7 @@ Function 247: DrawSplineBezierQuadratic() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 248: DrawSplineBezierCubic() (4 input parameters) +Function 249: DrawSplineBezierCubic() (4 input parameters) Name: DrawSplineBezierCubic Return type: void Description: Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...] @@ -2443,7 +2448,7 @@ Function 248: DrawSplineBezierCubic() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 249: DrawSplineSegmentLinear() (4 input parameters) +Function 250: DrawSplineSegmentLinear() (4 input parameters) Name: DrawSplineSegmentLinear Return type: void Description: Draw spline segment: Linear, 2 points @@ -2451,7 +2456,7 @@ Function 249: DrawSplineSegmentLinear() (4 input parameters) Param[2]: p2 (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 250: DrawSplineSegmentBasis() (6 input parameters) +Function 251: DrawSplineSegmentBasis() (6 input parameters) Name: DrawSplineSegmentBasis Return type: void Description: Draw spline segment: B-Spline, 4 points @@ -2461,7 +2466,7 @@ Function 250: DrawSplineSegmentBasis() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 251: DrawSplineSegmentCatmullRom() (6 input parameters) +Function 252: DrawSplineSegmentCatmullRom() (6 input parameters) Name: DrawSplineSegmentCatmullRom Return type: void Description: Draw spline segment: Catmull-Rom, 4 points @@ -2471,7 +2476,7 @@ Function 251: DrawSplineSegmentCatmullRom() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 252: DrawSplineSegmentBezierQuadratic() (5 input parameters) +Function 253: DrawSplineSegmentBezierQuadratic() (5 input parameters) Name: DrawSplineSegmentBezierQuadratic Return type: void Description: Draw spline segment: Quadratic Bezier, 2 points, 1 control point @@ -2480,7 +2485,7 @@ Function 252: DrawSplineSegmentBezierQuadratic() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: thick (type: float) Param[5]: color (type: Color) -Function 253: DrawSplineSegmentBezierCubic() (6 input parameters) +Function 254: DrawSplineSegmentBezierCubic() (6 input parameters) Name: DrawSplineSegmentBezierCubic Return type: void Description: Draw spline segment: Cubic Bezier, 2 points, 2 control points @@ -2490,14 +2495,14 @@ Function 253: DrawSplineSegmentBezierCubic() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 254: GetSplinePointLinear() (3 input parameters) +Function 255: GetSplinePointLinear() (3 input parameters) Name: GetSplinePointLinear Return type: Vector2 Description: Get (evaluate) spline point: Linear Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: t (type: float) -Function 255: GetSplinePointBasis() (5 input parameters) +Function 256: GetSplinePointBasis() (5 input parameters) Name: GetSplinePointBasis Return type: Vector2 Description: Get (evaluate) spline point: B-Spline @@ -2506,7 +2511,7 @@ Function 255: GetSplinePointBasis() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 256: GetSplinePointCatmullRom() (5 input parameters) +Function 257: GetSplinePointCatmullRom() (5 input parameters) Name: GetSplinePointCatmullRom Return type: Vector2 Description: Get (evaluate) spline point: Catmull-Rom @@ -2515,7 +2520,7 @@ Function 256: GetSplinePointCatmullRom() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 257: GetSplinePointBezierQuad() (4 input parameters) +Function 258: GetSplinePointBezierQuad() (4 input parameters) Name: GetSplinePointBezierQuad Return type: Vector2 Description: Get (evaluate) spline point: Quadratic Bezier @@ -2523,7 +2528,7 @@ Function 257: GetSplinePointBezierQuad() (4 input parameters) Param[2]: c2 (type: Vector2) Param[3]: p3 (type: Vector2) Param[4]: t (type: float) -Function 258: GetSplinePointBezierCubic() (5 input parameters) +Function 259: GetSplinePointBezierCubic() (5 input parameters) Name: GetSplinePointBezierCubic Return type: Vector2 Description: Get (evaluate) spline point: Cubic Bezier @@ -2532,13 +2537,13 @@ Function 258: GetSplinePointBezierCubic() (5 input parameters) Param[3]: c3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 259: CheckCollisionRecs() (2 input parameters) +Function 260: 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 260: CheckCollisionCircles() (4 input parameters) +Function 261: CheckCollisionCircles() (4 input parameters) Name: CheckCollisionCircles Return type: bool Description: Check collision between two circles @@ -2546,27 +2551,27 @@ Function 260: CheckCollisionCircles() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector2) Param[4]: radius2 (type: float) -Function 261: CheckCollisionCircleRec() (3 input parameters) +Function 262: 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 262: CheckCollisionPointRec() (2 input parameters) +Function 263: 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 263: CheckCollisionPointCircle() (3 input parameters) +Function 264: 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 264: CheckCollisionPointTriangle() (4 input parameters) +Function 265: CheckCollisionPointTriangle() (4 input parameters) Name: CheckCollisionPointTriangle Return type: bool Description: Check if point is inside a triangle @@ -2574,14 +2579,14 @@ Function 264: CheckCollisionPointTriangle() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: p3 (type: Vector2) -Function 265: CheckCollisionPointPoly() (3 input parameters) +Function 266: CheckCollisionPointPoly() (3 input parameters) Name: CheckCollisionPointPoly Return type: bool Description: Check if point is within a polygon described by array of vertices Param[1]: point (type: Vector2) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) -Function 266: CheckCollisionLines() (5 input parameters) +Function 267: 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 @@ -2590,7 +2595,7 @@ Function 266: CheckCollisionLines() (5 input parameters) Param[3]: startPos2 (type: Vector2) Param[4]: endPos2 (type: Vector2) Param[5]: collisionPoint (type: Vector2 *) -Function 267: CheckCollisionPointLine() (4 input parameters) +Function 268: 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] @@ -2598,7 +2603,7 @@ Function 267: CheckCollisionPointLine() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: threshold (type: int) -Function 268: CheckCollisionCircleLine() (4 input parameters) +Function 269: CheckCollisionCircleLine() (4 input parameters) Name: CheckCollisionCircleLine Return type: bool Description: Check if circle collides with a line created betweeen two points [p1] and [p2] @@ -2606,18 +2611,18 @@ Function 268: CheckCollisionCircleLine() (4 input parameters) Param[2]: radius (type: float) Param[3]: p1 (type: Vector2) Param[4]: p2 (type: Vector2) -Function 269: GetCollisionRec() (2 input parameters) +Function 270: 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 270: LoadImage() (1 input parameters) +Function 271: 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 271: LoadImageRaw() (5 input parameters) +Function 272: LoadImageRaw() (5 input parameters) Name: LoadImageRaw Return type: Image Description: Load image from RAW file data @@ -2626,20 +2631,20 @@ Function 271: LoadImageRaw() (5 input parameters) Param[3]: height (type: int) Param[4]: format (type: int) Param[5]: headerSize (type: int) -Function 272: LoadImageSvg() (3 input parameters) +Function 273: LoadImageSvg() (3 input parameters) Name: LoadImageSvg Return type: Image Description: Load image from SVG file data or string with specified size Param[1]: fileNameOrString (type: const char *) Param[2]: width (type: int) Param[3]: height (type: int) -Function 273: LoadImageAnim() (2 input parameters) +Function 274: 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 274: LoadImageAnimFromMemory() (4 input parameters) +Function 275: LoadImageAnimFromMemory() (4 input parameters) Name: LoadImageAnimFromMemory Return type: Image Description: Load image sequence from memory buffer @@ -2647,60 +2652,60 @@ Function 274: LoadImageAnimFromMemory() (4 input parameters) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) Param[4]: frames (type: int *) -Function 275: LoadImageFromMemory() (3 input parameters) +Function 276: 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 276: LoadImageFromTexture() (1 input parameters) +Function 277: LoadImageFromTexture() (1 input parameters) Name: LoadImageFromTexture Return type: Image Description: Load image from GPU texture data Param[1]: texture (type: Texture2D) -Function 277: LoadImageFromScreen() (0 input parameters) +Function 278: LoadImageFromScreen() (0 input parameters) Name: LoadImageFromScreen Return type: Image Description: Load image from screen buffer and (screenshot) No input parameters -Function 278: IsImageReady() (1 input parameters) +Function 279: IsImageReady() (1 input parameters) Name: IsImageReady Return type: bool Description: Check if an image is ready Param[1]: image (type: Image) -Function 279: UnloadImage() (1 input parameters) +Function 280: UnloadImage() (1 input parameters) Name: UnloadImage Return type: void Description: Unload image from CPU memory (RAM) Param[1]: image (type: Image) -Function 280: ExportImage() (2 input parameters) +Function 281: 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 281: ExportImageToMemory() (3 input parameters) +Function 282: ExportImageToMemory() (3 input parameters) Name: ExportImageToMemory Return type: unsigned char * Description: Export image to memory buffer Param[1]: image (type: Image) Param[2]: fileType (type: const char *) Param[3]: fileSize (type: int *) -Function 282: ExportImageAsCode() (2 input parameters) +Function 283: 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 283: GenImageColor() (3 input parameters) +Function 284: 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 284: GenImageGradientLinear() (5 input parameters) +Function 285: GenImageGradientLinear() (5 input parameters) Name: GenImageGradientLinear Return type: Image Description: Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient @@ -2709,7 +2714,7 @@ Function 284: GenImageGradientLinear() (5 input parameters) Param[3]: direction (type: int) Param[4]: start (type: Color) Param[5]: end (type: Color) -Function 285: GenImageGradientRadial() (5 input parameters) +Function 286: GenImageGradientRadial() (5 input parameters) Name: GenImageGradientRadial Return type: Image Description: Generate image: radial gradient @@ -2718,7 +2723,7 @@ Function 285: GenImageGradientRadial() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 286: GenImageGradientSquare() (5 input parameters) +Function 287: GenImageGradientSquare() (5 input parameters) Name: GenImageGradientSquare Return type: Image Description: Generate image: square gradient @@ -2727,7 +2732,7 @@ Function 286: GenImageGradientSquare() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 287: GenImageChecked() (6 input parameters) +Function 288: GenImageChecked() (6 input parameters) Name: GenImageChecked Return type: Image Description: Generate image: checked @@ -2737,14 +2742,14 @@ Function 287: GenImageChecked() (6 input parameters) Param[4]: checksY (type: int) Param[5]: col1 (type: Color) Param[6]: col2 (type: Color) -Function 288: GenImageWhiteNoise() (3 input parameters) +Function 289: 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 289: GenImagePerlinNoise() (5 input parameters) +Function 290: GenImagePerlinNoise() (5 input parameters) Name: GenImagePerlinNoise Return type: Image Description: Generate image: perlin noise @@ -2753,45 +2758,45 @@ Function 289: GenImagePerlinNoise() (5 input parameters) Param[3]: offsetX (type: int) Param[4]: offsetY (type: int) Param[5]: scale (type: float) -Function 290: GenImageCellular() (3 input parameters) +Function 291: 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 291: GenImageText() (3 input parameters) +Function 292: 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 292: ImageCopy() (1 input parameters) +Function 293: ImageCopy() (1 input parameters) Name: ImageCopy Return type: Image Description: Create an image duplicate (useful for transformations) Param[1]: image (type: Image) -Function 293: ImageFromImage() (2 input parameters) +Function 294: ImageFromImage() (2 input parameters) Name: ImageFromImage Return type: Image Description: Create an image from another image piece Param[1]: image (type: Image) Param[2]: rec (type: Rectangle) -Function 294: ImageFromChannel() (2 input parameters) +Function 295: ImageFromChannel() (2 input parameters) Name: ImageFromChannel Return type: Image Description: Create an image from a selected channel of another image (GRAYSCALE) Param[1]: image (type: Image) Param[2]: selectedChannel (type: int) -Function 295: ImageText() (3 input parameters) +Function 296: ImageText() (3 input parameters) Name: ImageText Return type: Image Description: Create an image from text (default font) Param[1]: text (type: const char *) Param[2]: fontSize (type: int) Param[3]: color (type: Color) -Function 296: ImageTextEx() (5 input parameters) +Function 297: ImageTextEx() (5 input parameters) Name: ImageTextEx Return type: Image Description: Create an image from text (custom sprite font) @@ -2800,76 +2805,76 @@ Function 296: ImageTextEx() (5 input parameters) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) Param[5]: tint (type: Color) -Function 297: ImageFormat() (2 input parameters) +Function 298: ImageFormat() (2 input parameters) Name: ImageFormat Return type: void Description: Convert image data to desired format Param[1]: image (type: Image *) Param[2]: newFormat (type: int) -Function 298: ImageToPOT() (2 input parameters) +Function 299: ImageToPOT() (2 input parameters) Name: ImageToPOT Return type: void Description: Convert image to POT (power-of-two) Param[1]: image (type: Image *) Param[2]: fill (type: Color) -Function 299: ImageCrop() (2 input parameters) +Function 300: ImageCrop() (2 input parameters) Name: ImageCrop Return type: void Description: Crop an image to a defined rectangle Param[1]: image (type: Image *) Param[2]: crop (type: Rectangle) -Function 300: ImageAlphaCrop() (2 input parameters) +Function 301: ImageAlphaCrop() (2 input parameters) Name: ImageAlphaCrop Return type: void Description: Crop image depending on alpha value Param[1]: image (type: Image *) Param[2]: threshold (type: float) -Function 301: ImageAlphaClear() (3 input parameters) +Function 302: ImageAlphaClear() (3 input parameters) Name: ImageAlphaClear Return type: void Description: Clear alpha channel to desired color Param[1]: image (type: Image *) Param[2]: color (type: Color) Param[3]: threshold (type: float) -Function 302: ImageAlphaMask() (2 input parameters) +Function 303: ImageAlphaMask() (2 input parameters) Name: ImageAlphaMask Return type: void Description: Apply alpha mask to image Param[1]: image (type: Image *) Param[2]: alphaMask (type: Image) -Function 303: ImageAlphaPremultiply() (1 input parameters) +Function 304: ImageAlphaPremultiply() (1 input parameters) Name: ImageAlphaPremultiply Return type: void Description: Premultiply alpha channel Param[1]: image (type: Image *) -Function 304: ImageBlurGaussian() (2 input parameters) +Function 305: 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 305: ImageKernelConvolution() (3 input parameters) +Function 306: ImageKernelConvolution() (3 input parameters) Name: ImageKernelConvolution Return type: void Description: Apply custom square convolution kernel to image Param[1]: image (type: Image *) Param[2]: kernel (type: const float *) Param[3]: kernelSize (type: int) -Function 306: ImageResize() (3 input parameters) +Function 307: 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 307: ImageResizeNN() (3 input parameters) +Function 308: 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 308: ImageResizeCanvas() (6 input parameters) +Function 309: ImageResizeCanvas() (6 input parameters) Name: ImageResizeCanvas Return type: void Description: Resize canvas and fill with color @@ -2879,12 +2884,12 @@ Function 308: ImageResizeCanvas() (6 input parameters) Param[4]: offsetX (type: int) Param[5]: offsetY (type: int) Param[6]: fill (type: Color) -Function 309: ImageMipmaps() (1 input parameters) +Function 310: ImageMipmaps() (1 input parameters) Name: ImageMipmaps Return type: void Description: Compute all mipmap levels for a provided image Param[1]: image (type: Image *) -Function 310: ImageDither() (5 input parameters) +Function 311: ImageDither() (5 input parameters) Name: ImageDither Return type: void Description: Dither image data to 16bpp or lower (Floyd-Steinberg dithering) @@ -2893,109 +2898,109 @@ Function 310: ImageDither() (5 input parameters) Param[3]: gBpp (type: int) Param[4]: bBpp (type: int) Param[5]: aBpp (type: int) -Function 311: ImageFlipVertical() (1 input parameters) +Function 312: ImageFlipVertical() (1 input parameters) Name: ImageFlipVertical Return type: void Description: Flip image vertically Param[1]: image (type: Image *) -Function 312: ImageFlipHorizontal() (1 input parameters) +Function 313: ImageFlipHorizontal() (1 input parameters) Name: ImageFlipHorizontal Return type: void Description: Flip image horizontally Param[1]: image (type: Image *) -Function 313: ImageRotate() (2 input parameters) +Function 314: ImageRotate() (2 input parameters) Name: ImageRotate Return type: void Description: Rotate image by input angle in degrees (-359 to 359) Param[1]: image (type: Image *) Param[2]: degrees (type: int) -Function 314: ImageRotateCW() (1 input parameters) +Function 315: ImageRotateCW() (1 input parameters) Name: ImageRotateCW Return type: void Description: Rotate image clockwise 90deg Param[1]: image (type: Image *) -Function 315: ImageRotateCCW() (1 input parameters) +Function 316: ImageRotateCCW() (1 input parameters) Name: ImageRotateCCW Return type: void Description: Rotate image counter-clockwise 90deg Param[1]: image (type: Image *) -Function 316: ImageColorTint() (2 input parameters) +Function 317: 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 317: ImageColorInvert() (1 input parameters) +Function 318: ImageColorInvert() (1 input parameters) Name: ImageColorInvert Return type: void Description: Modify image color: invert Param[1]: image (type: Image *) -Function 318: ImageColorGrayscale() (1 input parameters) +Function 319: ImageColorGrayscale() (1 input parameters) Name: ImageColorGrayscale Return type: void Description: Modify image color: grayscale Param[1]: image (type: Image *) -Function 319: ImageColorContrast() (2 input parameters) +Function 320: 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 320: ImageColorBrightness() (2 input parameters) +Function 321: 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 321: ImageColorReplace() (3 input parameters) +Function 322: 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 322: LoadImageColors() (1 input parameters) +Function 323: 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 323: LoadImagePalette() (3 input parameters) +Function 324: 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 324: UnloadImageColors() (1 input parameters) +Function 325: UnloadImageColors() (1 input parameters) Name: UnloadImageColors Return type: void Description: Unload color data loaded with LoadImageColors() Param[1]: colors (type: Color *) -Function 325: UnloadImagePalette() (1 input parameters) +Function 326: UnloadImagePalette() (1 input parameters) Name: UnloadImagePalette Return type: void Description: Unload colors palette loaded with LoadImagePalette() Param[1]: colors (type: Color *) -Function 326: GetImageAlphaBorder() (2 input parameters) +Function 327: 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 327: GetImageColor() (3 input parameters) +Function 328: 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 328: ImageClearBackground() (2 input parameters) +Function 329: 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 329: ImageDrawPixel() (4 input parameters) +Function 330: ImageDrawPixel() (4 input parameters) Name: ImageDrawPixel Return type: void Description: Draw pixel within an image @@ -3003,14 +3008,14 @@ Function 329: ImageDrawPixel() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: color (type: Color) -Function 330: ImageDrawPixelV() (3 input parameters) +Function 331: 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 331: ImageDrawLine() (6 input parameters) +Function 332: ImageDrawLine() (6 input parameters) Name: ImageDrawLine Return type: void Description: Draw line within an image @@ -3020,7 +3025,7 @@ Function 331: ImageDrawLine() (6 input parameters) Param[4]: endPosX (type: int) Param[5]: endPosY (type: int) Param[6]: color (type: Color) -Function 332: ImageDrawLineV() (4 input parameters) +Function 333: ImageDrawLineV() (4 input parameters) Name: ImageDrawLineV Return type: void Description: Draw line within an image (Vector version) @@ -3028,7 +3033,7 @@ Function 332: ImageDrawLineV() (4 input parameters) Param[2]: start (type: Vector2) Param[3]: end (type: Vector2) Param[4]: color (type: Color) -Function 333: ImageDrawLineEx() (5 input parameters) +Function 334: ImageDrawLineEx() (5 input parameters) Name: ImageDrawLineEx Return type: void Description: Draw a line defining thickness within an image @@ -3037,7 +3042,7 @@ Function 333: ImageDrawLineEx() (5 input parameters) Param[3]: end (type: Vector2) Param[4]: thick (type: int) Param[5]: color (type: Color) -Function 334: ImageDrawCircle() (5 input parameters) +Function 335: ImageDrawCircle() (5 input parameters) Name: ImageDrawCircle Return type: void Description: Draw a filled circle within an image @@ -3046,7 +3051,7 @@ Function 334: ImageDrawCircle() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 335: ImageDrawCircleV() (4 input parameters) +Function 336: ImageDrawCircleV() (4 input parameters) Name: ImageDrawCircleV Return type: void Description: Draw a filled circle within an image (Vector version) @@ -3054,7 +3059,7 @@ Function 335: ImageDrawCircleV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 336: ImageDrawCircleLines() (5 input parameters) +Function 337: ImageDrawCircleLines() (5 input parameters) Name: ImageDrawCircleLines Return type: void Description: Draw circle outline within an image @@ -3063,7 +3068,7 @@ Function 336: ImageDrawCircleLines() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 337: ImageDrawCircleLinesV() (4 input parameters) +Function 338: ImageDrawCircleLinesV() (4 input parameters) Name: ImageDrawCircleLinesV Return type: void Description: Draw circle outline within an image (Vector version) @@ -3071,7 +3076,7 @@ Function 337: ImageDrawCircleLinesV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 338: ImageDrawRectangle() (6 input parameters) +Function 339: ImageDrawRectangle() (6 input parameters) Name: ImageDrawRectangle Return type: void Description: Draw rectangle within an image @@ -3081,7 +3086,7 @@ Function 338: ImageDrawRectangle() (6 input parameters) Param[4]: width (type: int) Param[5]: height (type: int) Param[6]: color (type: Color) -Function 339: ImageDrawRectangleV() (4 input parameters) +Function 340: ImageDrawRectangleV() (4 input parameters) Name: ImageDrawRectangleV Return type: void Description: Draw rectangle within an image (Vector version) @@ -3089,14 +3094,14 @@ Function 339: ImageDrawRectangleV() (4 input parameters) Param[2]: position (type: Vector2) Param[3]: size (type: Vector2) Param[4]: color (type: Color) -Function 340: ImageDrawRectangleRec() (3 input parameters) +Function 341: 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 341: ImageDrawRectangleLines() (4 input parameters) +Function 342: ImageDrawRectangleLines() (4 input parameters) Name: ImageDrawRectangleLines Return type: void Description: Draw rectangle lines within an image @@ -3104,7 +3109,7 @@ Function 341: ImageDrawRectangleLines() (4 input parameters) Param[2]: rec (type: Rectangle) Param[3]: thick (type: int) Param[4]: color (type: Color) -Function 342: ImageDrawTriangle() (5 input parameters) +Function 343: ImageDrawTriangle() (5 input parameters) Name: ImageDrawTriangle Return type: void Description: Draw triangle within an image @@ -3113,7 +3118,7 @@ Function 342: ImageDrawTriangle() (5 input parameters) Param[3]: v2 (type: Vector2) Param[4]: v3 (type: Vector2) Param[5]: color (type: Color) -Function 343: ImageDrawTriangleEx() (7 input parameters) +Function 344: ImageDrawTriangleEx() (7 input parameters) Name: ImageDrawTriangleEx Return type: void Description: Draw triangle with interpolated colors within an image @@ -3124,7 +3129,7 @@ Function 343: ImageDrawTriangleEx() (7 input parameters) Param[5]: c1 (type: Color) Param[6]: c2 (type: Color) Param[7]: c3 (type: Color) -Function 344: ImageDrawTriangleLines() (5 input parameters) +Function 345: ImageDrawTriangleLines() (5 input parameters) Name: ImageDrawTriangleLines Return type: void Description: Draw triangle outline within an image @@ -3133,7 +3138,7 @@ Function 344: ImageDrawTriangleLines() (5 input parameters) Param[3]: v2 (type: Vector2) Param[4]: v3 (type: Vector2) Param[5]: color (type: Color) -Function 345: ImageDrawTriangleFan() (4 input parameters) +Function 346: ImageDrawTriangleFan() (4 input parameters) Name: ImageDrawTriangleFan Return type: void Description: Draw a triangle fan defined by points within an image (first vertex is the center) @@ -3141,7 +3146,7 @@ Function 345: ImageDrawTriangleFan() (4 input parameters) Param[2]: points (type: Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 346: ImageDrawTriangleStrip() (4 input parameters) +Function 347: ImageDrawTriangleStrip() (4 input parameters) Name: ImageDrawTriangleStrip Return type: void Description: Draw a triangle strip defined by points within an image @@ -3149,7 +3154,7 @@ Function 346: ImageDrawTriangleStrip() (4 input parameters) Param[2]: points (type: Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 347: ImageDraw() (5 input parameters) +Function 348: ImageDraw() (5 input parameters) Name: ImageDraw Return type: void Description: Draw a source image within a destination image (tint applied to source) @@ -3158,7 +3163,7 @@ Function 347: ImageDraw() (5 input parameters) Param[3]: srcRec (type: Rectangle) Param[4]: dstRec (type: Rectangle) Param[5]: tint (type: Color) -Function 348: ImageDrawText() (6 input parameters) +Function 349: ImageDrawText() (6 input parameters) Name: ImageDrawText Return type: void Description: Draw text (using default font) within an image (destination) @@ -3168,7 +3173,7 @@ Function 348: ImageDrawText() (6 input parameters) Param[4]: posY (type: int) Param[5]: fontSize (type: int) Param[6]: color (type: Color) -Function 349: ImageDrawTextEx() (7 input parameters) +Function 350: ImageDrawTextEx() (7 input parameters) Name: ImageDrawTextEx Return type: void Description: Draw text (custom sprite font) within an image (destination) @@ -3179,79 +3184,79 @@ Function 349: ImageDrawTextEx() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 350: LoadTexture() (1 input parameters) +Function 351: 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 351: LoadTextureFromImage() (1 input parameters) +Function 352: LoadTextureFromImage() (1 input parameters) Name: LoadTextureFromImage Return type: Texture2D Description: Load texture from image data Param[1]: image (type: Image) -Function 352: LoadTextureCubemap() (2 input parameters) +Function 353: 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 353: LoadRenderTexture() (2 input parameters) +Function 354: 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 354: IsTextureReady() (1 input parameters) +Function 355: IsTextureReady() (1 input parameters) Name: IsTextureReady Return type: bool Description: Check if a texture is ready Param[1]: texture (type: Texture2D) -Function 355: UnloadTexture() (1 input parameters) +Function 356: UnloadTexture() (1 input parameters) Name: UnloadTexture Return type: void Description: Unload texture from GPU memory (VRAM) Param[1]: texture (type: Texture2D) -Function 356: IsRenderTextureReady() (1 input parameters) +Function 357: IsRenderTextureReady() (1 input parameters) Name: IsRenderTextureReady Return type: bool Description: Check if a render texture is ready Param[1]: target (type: RenderTexture2D) -Function 357: UnloadRenderTexture() (1 input parameters) +Function 358: UnloadRenderTexture() (1 input parameters) Name: UnloadRenderTexture Return type: void Description: Unload render texture from GPU memory (VRAM) Param[1]: target (type: RenderTexture2D) -Function 358: UpdateTexture() (2 input parameters) +Function 359: 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 359: UpdateTextureRec() (3 input parameters) +Function 360: 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 360: GenTextureMipmaps() (1 input parameters) +Function 361: GenTextureMipmaps() (1 input parameters) Name: GenTextureMipmaps Return type: void Description: Generate GPU mipmaps for a texture Param[1]: texture (type: Texture2D *) -Function 361: SetTextureFilter() (2 input parameters) +Function 362: 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 362: SetTextureWrap() (2 input parameters) +Function 363: 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 363: DrawTexture() (4 input parameters) +Function 364: DrawTexture() (4 input parameters) Name: DrawTexture Return type: void Description: Draw a Texture2D @@ -3259,14 +3264,14 @@ Function 363: DrawTexture() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: tint (type: Color) -Function 364: DrawTextureV() (3 input parameters) +Function 365: 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 365: DrawTextureEx() (5 input parameters) +Function 366: DrawTextureEx() (5 input parameters) Name: DrawTextureEx Return type: void Description: Draw a Texture2D with extended parameters @@ -3275,7 +3280,7 @@ Function 365: DrawTextureEx() (5 input parameters) Param[3]: rotation (type: float) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 366: DrawTextureRec() (4 input parameters) +Function 367: DrawTextureRec() (4 input parameters) Name: DrawTextureRec Return type: void Description: Draw a part of a texture defined by a rectangle @@ -3283,7 +3288,7 @@ Function 366: DrawTextureRec() (4 input parameters) Param[2]: source (type: Rectangle) Param[3]: position (type: Vector2) Param[4]: tint (type: Color) -Function 367: DrawTexturePro() (6 input parameters) +Function 368: DrawTexturePro() (6 input parameters) Name: DrawTexturePro Return type: void Description: Draw a part of a texture defined by a rectangle with 'pro' parameters @@ -3293,7 +3298,7 @@ Function 367: DrawTexturePro() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 368: DrawTextureNPatch() (6 input parameters) +Function 369: DrawTextureNPatch() (6 input parameters) Name: DrawTextureNPatch Return type: void Description: Draws a texture (or part of it) that stretches or shrinks nicely @@ -3303,119 +3308,119 @@ Function 368: DrawTextureNPatch() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 369: ColorIsEqual() (2 input parameters) +Function 370: ColorIsEqual() (2 input parameters) Name: ColorIsEqual Return type: bool Description: Check if two colors are equal Param[1]: col1 (type: Color) Param[2]: col2 (type: Color) -Function 370: Fade() (2 input parameters) +Function 371: Fade() (2 input parameters) Name: Fade Return type: Color Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f Param[1]: color (type: Color) Param[2]: alpha (type: float) -Function 371: ColorToInt() (1 input parameters) +Function 372: ColorToInt() (1 input parameters) Name: ColorToInt Return type: int Description: Get hexadecimal value for a Color (0xRRGGBBAA) Param[1]: color (type: Color) -Function 372: ColorNormalize() (1 input parameters) +Function 373: ColorNormalize() (1 input parameters) Name: ColorNormalize Return type: Vector4 Description: Get Color normalized as float [0..1] Param[1]: color (type: Color) -Function 373: ColorFromNormalized() (1 input parameters) +Function 374: ColorFromNormalized() (1 input parameters) Name: ColorFromNormalized Return type: Color Description: Get Color from normalized values [0..1] Param[1]: normalized (type: Vector4) -Function 374: ColorToHSV() (1 input parameters) +Function 375: ColorToHSV() (1 input parameters) Name: ColorToHSV Return type: Vector3 Description: Get HSV values for a Color, hue [0..360], saturation/value [0..1] Param[1]: color (type: Color) -Function 375: ColorFromHSV() (3 input parameters) +Function 376: ColorFromHSV() (3 input parameters) Name: ColorFromHSV Return type: Color Description: Get a Color from HSV values, hue [0..360], saturation/value [0..1] Param[1]: hue (type: float) Param[2]: saturation (type: float) Param[3]: value (type: float) -Function 376: ColorTint() (2 input parameters) +Function 377: 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 377: ColorBrightness() (2 input parameters) +Function 378: 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 378: ColorContrast() (2 input parameters) +Function 379: 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 379: ColorAlpha() (2 input parameters) +Function 380: 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 380: ColorAlphaBlend() (3 input parameters) +Function 381: 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 381: ColorLerp() (3 input parameters) +Function 382: ColorLerp() (3 input parameters) Name: ColorLerp Return type: Color Description: Get color lerp interpolation between two colors, factor [0.0f..1.0f] Param[1]: color1 (type: Color) Param[2]: color2 (type: Color) Param[3]: factor (type: float) -Function 382: GetColor() (1 input parameters) +Function 383: GetColor() (1 input parameters) Name: GetColor Return type: Color Description: Get Color structure from hexadecimal value Param[1]: hexValue (type: unsigned int) -Function 383: GetPixelColor() (2 input parameters) +Function 384: 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 384: SetPixelColor() (3 input parameters) +Function 385: 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 385: GetPixelDataSize() (3 input parameters) +Function 386: 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 386: GetFontDefault() (0 input parameters) +Function 387: GetFontDefault() (0 input parameters) Name: GetFontDefault Return type: Font Description: Get the default Font No input parameters -Function 387: LoadFont() (1 input parameters) +Function 388: 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 388: LoadFontEx() (4 input parameters) +Function 389: LoadFontEx() (4 input parameters) Name: LoadFontEx Return type: Font Description: Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height @@ -3423,14 +3428,14 @@ Function 388: LoadFontEx() (4 input parameters) Param[2]: fontSize (type: int) Param[3]: codepoints (type: int *) Param[4]: codepointCount (type: int) -Function 389: LoadFontFromImage() (3 input parameters) +Function 390: 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 390: LoadFontFromMemory() (6 input parameters) +Function 391: LoadFontFromMemory() (6 input parameters) Name: LoadFontFromMemory Return type: Font Description: Load font from memory buffer, fileType refers to extension: i.e. '.ttf' @@ -3440,12 +3445,12 @@ Function 390: LoadFontFromMemory() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: codepoints (type: int *) Param[6]: codepointCount (type: int) -Function 391: IsFontReady() (1 input parameters) +Function 392: IsFontReady() (1 input parameters) Name: IsFontReady Return type: bool Description: Check if a font is ready Param[1]: font (type: Font) -Function 392: LoadFontData() (6 input parameters) +Function 393: LoadFontData() (6 input parameters) Name: LoadFontData Return type: GlyphInfo * Description: Load font data for further use @@ -3455,7 +3460,7 @@ Function 392: LoadFontData() (6 input parameters) Param[4]: codepoints (type: int *) Param[5]: codepointCount (type: int) Param[6]: type (type: int) -Function 393: GenImageFontAtlas() (6 input parameters) +Function 394: GenImageFontAtlas() (6 input parameters) Name: GenImageFontAtlas Return type: Image Description: Generate image font atlas using chars info @@ -3465,30 +3470,30 @@ Function 393: GenImageFontAtlas() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: padding (type: int) Param[6]: packMethod (type: int) -Function 394: UnloadFontData() (2 input parameters) +Function 395: UnloadFontData() (2 input parameters) Name: UnloadFontData Return type: void Description: Unload font chars info data (RAM) Param[1]: glyphs (type: GlyphInfo *) Param[2]: glyphCount (type: int) -Function 395: UnloadFont() (1 input parameters) +Function 396: UnloadFont() (1 input parameters) Name: UnloadFont Return type: void Description: Unload font from GPU memory (VRAM) Param[1]: font (type: Font) -Function 396: ExportFontAsCode() (2 input parameters) +Function 397: 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 397: DrawFPS() (2 input parameters) +Function 398: DrawFPS() (2 input parameters) Name: DrawFPS Return type: void Description: Draw current FPS Param[1]: posX (type: int) Param[2]: posY (type: int) -Function 398: DrawText() (5 input parameters) +Function 399: DrawText() (5 input parameters) Name: DrawText Return type: void Description: Draw text (using default font) @@ -3497,7 +3502,7 @@ Function 398: DrawText() (5 input parameters) Param[3]: posY (type: int) Param[4]: fontSize (type: int) Param[5]: color (type: Color) -Function 399: DrawTextEx() (6 input parameters) +Function 400: DrawTextEx() (6 input parameters) Name: DrawTextEx Return type: void Description: Draw text using font and additional parameters @@ -3507,7 +3512,7 @@ Function 399: DrawTextEx() (6 input parameters) Param[4]: fontSize (type: float) Param[5]: spacing (type: float) Param[6]: tint (type: Color) -Function 400: DrawTextPro() (8 input parameters) +Function 401: DrawTextPro() (8 input parameters) Name: DrawTextPro Return type: void Description: Draw text using Font and pro parameters (rotation) @@ -3519,7 +3524,7 @@ Function 400: DrawTextPro() (8 input parameters) Param[6]: fontSize (type: float) Param[7]: spacing (type: float) Param[8]: tint (type: Color) -Function 401: DrawTextCodepoint() (5 input parameters) +Function 402: DrawTextCodepoint() (5 input parameters) Name: DrawTextCodepoint Return type: void Description: Draw one character (codepoint) @@ -3528,7 +3533,7 @@ Function 401: DrawTextCodepoint() (5 input parameters) Param[3]: position (type: Vector2) Param[4]: fontSize (type: float) Param[5]: tint (type: Color) -Function 402: DrawTextCodepoints() (7 input parameters) +Function 403: DrawTextCodepoints() (7 input parameters) Name: DrawTextCodepoints Return type: void Description: Draw multiple character (codepoint) @@ -3539,18 +3544,18 @@ Function 402: DrawTextCodepoints() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 403: SetTextLineSpacing() (1 input parameters) +Function 404: SetTextLineSpacing() (1 input parameters) Name: SetTextLineSpacing Return type: void Description: Set vertical line spacing when drawing with line-breaks Param[1]: spacing (type: int) -Function 404: MeasureText() (2 input parameters) +Function 405: 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 405: MeasureTextEx() (4 input parameters) +Function 406: MeasureTextEx() (4 input parameters) Name: MeasureTextEx Return type: Vector2 Description: Measure string size for Font @@ -3558,195 +3563,195 @@ Function 405: MeasureTextEx() (4 input parameters) Param[2]: text (type: const char *) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) -Function 406: GetGlyphIndex() (2 input parameters) +Function 407: 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 407: GetGlyphInfo() (2 input parameters) +Function 408: 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 408: GetGlyphAtlasRec() (2 input parameters) +Function 409: 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 409: LoadUTF8() (2 input parameters) +Function 410: 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 410: UnloadUTF8() (1 input parameters) +Function 411: UnloadUTF8() (1 input parameters) Name: UnloadUTF8 Return type: void Description: Unload UTF-8 text encoded from codepoints array Param[1]: text (type: char *) -Function 411: LoadCodepoints() (2 input parameters) +Function 412: 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 412: UnloadCodepoints() (1 input parameters) +Function 413: UnloadCodepoints() (1 input parameters) Name: UnloadCodepoints Return type: void Description: Unload codepoints data from memory Param[1]: codepoints (type: int *) -Function 413: GetCodepointCount() (1 input parameters) +Function 414: 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 414: GetCodepoint() (2 input parameters) +Function 415: 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 415: GetCodepointNext() (2 input parameters) +Function 416: 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 416: GetCodepointPrevious() (2 input parameters) +Function 417: 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 417: CodepointToUTF8() (2 input parameters) +Function 418: 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 418: TextCopy() (2 input parameters) +Function 419: 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 419: TextIsEqual() (2 input parameters) +Function 420: 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 420: TextLength() (1 input parameters) +Function 421: 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 421: TextFormat() (2 input parameters) +Function 422: 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 422: TextSubtext() (3 input parameters) +Function 423: 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 423: TextReplace() (3 input parameters) +Function 424: TextReplace() (3 input parameters) Name: TextReplace Return type: char * Description: Replace text string (WARNING: memory must be freed!) Param[1]: text (type: const char *) Param[2]: replace (type: const char *) Param[3]: by (type: const char *) -Function 424: TextInsert() (3 input parameters) +Function 425: 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 425: TextJoin() (3 input parameters) +Function 426: 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 426: TextSplit() (3 input parameters) +Function 427: 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 427: TextAppend() (3 input parameters) +Function 428: 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 428: TextFindIndex() (2 input parameters) +Function 429: 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 429: TextToUpper() (1 input parameters) +Function 430: 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 430: TextToLower() (1 input parameters) +Function 431: 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 431: TextToPascal() (1 input parameters) +Function 432: 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 432: TextToSnake() (1 input parameters) +Function 433: TextToSnake() (1 input parameters) Name: TextToSnake Return type: const char * Description: Get Snake case notation version of provided string Param[1]: text (type: const char *) -Function 433: TextToCamel() (1 input parameters) +Function 434: TextToCamel() (1 input parameters) Name: TextToCamel Return type: const char * Description: Get Camel case notation version of provided string Param[1]: text (type: const char *) -Function 434: TextToInteger() (1 input parameters) +Function 435: 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 435: TextToFloat() (1 input parameters) +Function 436: TextToFloat() (1 input parameters) Name: TextToFloat Return type: float Description: Get float value from text (negative values not supported) Param[1]: text (type: const char *) -Function 436: DrawLine3D() (3 input parameters) +Function 437: 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 437: DrawPoint3D() (2 input parameters) +Function 438: 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 438: DrawCircle3D() (5 input parameters) +Function 439: DrawCircle3D() (5 input parameters) Name: DrawCircle3D Return type: void Description: Draw a circle in 3D world space @@ -3755,7 +3760,7 @@ Function 438: DrawCircle3D() (5 input parameters) Param[3]: rotationAxis (type: Vector3) Param[4]: rotationAngle (type: float) Param[5]: color (type: Color) -Function 439: DrawTriangle3D() (4 input parameters) +Function 440: DrawTriangle3D() (4 input parameters) Name: DrawTriangle3D Return type: void Description: Draw a color-filled triangle (vertex in counter-clockwise order!) @@ -3763,14 +3768,14 @@ Function 439: DrawTriangle3D() (4 input parameters) Param[2]: v2 (type: Vector3) Param[3]: v3 (type: Vector3) Param[4]: color (type: Color) -Function 440: DrawTriangleStrip3D() (3 input parameters) +Function 441: DrawTriangleStrip3D() (3 input parameters) Name: DrawTriangleStrip3D Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector3 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 441: DrawCube() (5 input parameters) +Function 442: DrawCube() (5 input parameters) Name: DrawCube Return type: void Description: Draw cube @@ -3779,14 +3784,14 @@ Function 441: DrawCube() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 442: DrawCubeV() (3 input parameters) +Function 443: 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 443: DrawCubeWires() (5 input parameters) +Function 444: DrawCubeWires() (5 input parameters) Name: DrawCubeWires Return type: void Description: Draw cube wires @@ -3795,21 +3800,21 @@ Function 443: DrawCubeWires() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 444: DrawCubeWiresV() (3 input parameters) +Function 445: 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 445: DrawSphere() (3 input parameters) +Function 446: 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 446: DrawSphereEx() (5 input parameters) +Function 447: DrawSphereEx() (5 input parameters) Name: DrawSphereEx Return type: void Description: Draw sphere with extended parameters @@ -3818,7 +3823,7 @@ Function 446: DrawSphereEx() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 447: DrawSphereWires() (5 input parameters) +Function 448: DrawSphereWires() (5 input parameters) Name: DrawSphereWires Return type: void Description: Draw sphere wires @@ -3827,7 +3832,7 @@ Function 447: DrawSphereWires() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 448: DrawCylinder() (6 input parameters) +Function 449: DrawCylinder() (6 input parameters) Name: DrawCylinder Return type: void Description: Draw a cylinder/cone @@ -3837,7 +3842,7 @@ Function 448: DrawCylinder() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 449: DrawCylinderEx() (6 input parameters) +Function 450: DrawCylinderEx() (6 input parameters) Name: DrawCylinderEx Return type: void Description: Draw a cylinder with base at startPos and top at endPos @@ -3847,7 +3852,7 @@ Function 449: DrawCylinderEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 450: DrawCylinderWires() (6 input parameters) +Function 451: DrawCylinderWires() (6 input parameters) Name: DrawCylinderWires Return type: void Description: Draw a cylinder/cone wires @@ -3857,7 +3862,7 @@ Function 450: DrawCylinderWires() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 451: DrawCylinderWiresEx() (6 input parameters) +Function 452: DrawCylinderWiresEx() (6 input parameters) Name: DrawCylinderWiresEx Return type: void Description: Draw a cylinder wires with base at startPos and top at endPos @@ -3867,7 +3872,7 @@ Function 451: DrawCylinderWiresEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 452: DrawCapsule() (6 input parameters) +Function 453: DrawCapsule() (6 input parameters) Name: DrawCapsule Return type: void Description: Draw a capsule with the center of its sphere caps at startPos and endPos @@ -3877,7 +3882,7 @@ Function 452: DrawCapsule() (6 input parameters) Param[4]: slices (type: int) Param[5]: rings (type: int) Param[6]: color (type: Color) -Function 453: DrawCapsuleWires() (6 input parameters) +Function 454: DrawCapsuleWires() (6 input parameters) Name: DrawCapsuleWires Return type: void Description: Draw capsule wireframe with the center of its sphere caps at startPos and endPos @@ -3887,51 +3892,51 @@ Function 453: DrawCapsuleWires() (6 input parameters) Param[4]: slices (type: int) Param[5]: rings (type: int) Param[6]: color (type: Color) -Function 454: DrawPlane() (3 input parameters) +Function 455: 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 455: DrawRay() (2 input parameters) +Function 456: 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 456: DrawGrid() (2 input parameters) +Function 457: 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 457: LoadModel() (1 input parameters) +Function 458: LoadModel() (1 input parameters) Name: LoadModel Return type: Model Description: Load model from files (meshes and materials) Param[1]: fileName (type: const char *) -Function 458: LoadModelFromMesh() (1 input parameters) +Function 459: LoadModelFromMesh() (1 input parameters) Name: LoadModelFromMesh Return type: Model Description: Load model from generated mesh (default material) Param[1]: mesh (type: Mesh) -Function 459: IsModelReady() (1 input parameters) +Function 460: IsModelReady() (1 input parameters) Name: IsModelReady Return type: bool Description: Check if a model is ready Param[1]: model (type: Model) -Function 460: UnloadModel() (1 input parameters) +Function 461: 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 461: GetModelBoundingBox() (1 input parameters) +Function 462: GetModelBoundingBox() (1 input parameters) Name: GetModelBoundingBox Return type: BoundingBox Description: Compute model bounding box limits (considers all meshes) Param[1]: model (type: Model) -Function 462: DrawModel() (4 input parameters) +Function 463: DrawModel() (4 input parameters) Name: DrawModel Return type: void Description: Draw a model (with texture if set) @@ -3939,7 +3944,7 @@ Function 462: DrawModel() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 463: DrawModelEx() (6 input parameters) +Function 464: DrawModelEx() (6 input parameters) Name: DrawModelEx Return type: void Description: Draw a model with extended parameters @@ -3949,7 +3954,7 @@ Function 463: DrawModelEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 464: DrawModelWires() (4 input parameters) +Function 465: DrawModelWires() (4 input parameters) Name: DrawModelWires Return type: void Description: Draw a model wires (with texture if set) @@ -3957,7 +3962,7 @@ Function 464: DrawModelWires() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 465: DrawModelWiresEx() (6 input parameters) +Function 466: DrawModelWiresEx() (6 input parameters) Name: DrawModelWiresEx Return type: void Description: Draw a model wires (with texture if set) with extended parameters @@ -3967,7 +3972,7 @@ Function 465: DrawModelWiresEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 466: DrawModelPoints() (4 input parameters) +Function 467: DrawModelPoints() (4 input parameters) Name: DrawModelPoints Return type: void Description: Draw a model as points @@ -3975,7 +3980,7 @@ Function 466: DrawModelPoints() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 467: DrawModelPointsEx() (6 input parameters) +Function 468: DrawModelPointsEx() (6 input parameters) Name: DrawModelPointsEx Return type: void Description: Draw a model as points with extended parameters @@ -3985,13 +3990,13 @@ Function 467: DrawModelPointsEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 468: DrawBoundingBox() (2 input parameters) +Function 469: 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 469: DrawBillboard() (5 input parameters) +Function 470: DrawBillboard() (5 input parameters) Name: DrawBillboard Return type: void Description: Draw a billboard texture @@ -4000,7 +4005,7 @@ Function 469: DrawBillboard() (5 input parameters) Param[3]: position (type: Vector3) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 470: DrawBillboardRec() (6 input parameters) +Function 471: DrawBillboardRec() (6 input parameters) Name: DrawBillboardRec Return type: void Description: Draw a billboard texture defined by source @@ -4010,7 +4015,7 @@ Function 470: DrawBillboardRec() (6 input parameters) Param[4]: position (type: Vector3) Param[5]: size (type: Vector2) Param[6]: tint (type: Color) -Function 471: DrawBillboardPro() (9 input parameters) +Function 472: DrawBillboardPro() (9 input parameters) Name: DrawBillboardPro Return type: void Description: Draw a billboard texture defined by source and rotation @@ -4023,13 +4028,13 @@ Function 471: DrawBillboardPro() (9 input parameters) Param[7]: origin (type: Vector2) Param[8]: rotation (type: float) Param[9]: tint (type: Color) -Function 472: UploadMesh() (2 input parameters) +Function 473: 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 473: UpdateMeshBuffer() (5 input parameters) +Function 474: UpdateMeshBuffer() (5 input parameters) Name: UpdateMeshBuffer Return type: void Description: Update mesh vertex data in GPU for a specific buffer index @@ -4038,19 +4043,19 @@ Function 473: UpdateMeshBuffer() (5 input parameters) Param[3]: data (type: const void *) Param[4]: dataSize (type: int) Param[5]: offset (type: int) -Function 474: UnloadMesh() (1 input parameters) +Function 475: UnloadMesh() (1 input parameters) Name: UnloadMesh Return type: void Description: Unload mesh data from CPU and GPU Param[1]: mesh (type: Mesh) -Function 475: DrawMesh() (3 input parameters) +Function 476: 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 476: DrawMeshInstanced() (4 input parameters) +Function 477: DrawMeshInstanced() (4 input parameters) Name: DrawMeshInstanced Return type: void Description: Draw multiple mesh instances with material and different transforms @@ -4058,35 +4063,35 @@ Function 476: DrawMeshInstanced() (4 input parameters) Param[2]: material (type: Material) Param[3]: transforms (type: const Matrix *) Param[4]: instances (type: int) -Function 477: GetMeshBoundingBox() (1 input parameters) +Function 478: GetMeshBoundingBox() (1 input parameters) Name: GetMeshBoundingBox Return type: BoundingBox Description: Compute mesh bounding box limits Param[1]: mesh (type: Mesh) -Function 478: GenMeshTangents() (1 input parameters) +Function 479: GenMeshTangents() (1 input parameters) Name: GenMeshTangents Return type: void Description: Compute mesh tangents Param[1]: mesh (type: Mesh *) -Function 479: ExportMesh() (2 input parameters) +Function 480: 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 480: ExportMeshAsCode() (2 input parameters) +Function 481: ExportMeshAsCode() (2 input parameters) Name: ExportMeshAsCode Return type: bool Description: Export mesh as code file (.h) defining multiple arrays of vertex attributes Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 481: GenMeshPoly() (2 input parameters) +Function 482: GenMeshPoly() (2 input parameters) Name: GenMeshPoly Return type: Mesh Description: Generate polygonal mesh Param[1]: sides (type: int) Param[2]: radius (type: float) -Function 482: GenMeshPlane() (4 input parameters) +Function 483: GenMeshPlane() (4 input parameters) Name: GenMeshPlane Return type: Mesh Description: Generate plane mesh (with subdivisions) @@ -4094,42 +4099,42 @@ Function 482: GenMeshPlane() (4 input parameters) Param[2]: length (type: float) Param[3]: resX (type: int) Param[4]: resZ (type: int) -Function 483: GenMeshCube() (3 input parameters) +Function 484: 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 484: GenMeshSphere() (3 input parameters) +Function 485: 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 485: GenMeshHemiSphere() (3 input parameters) +Function 486: 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 486: GenMeshCylinder() (3 input parameters) +Function 487: 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 487: GenMeshCone() (3 input parameters) +Function 488: 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 488: GenMeshTorus() (4 input parameters) +Function 489: GenMeshTorus() (4 input parameters) Name: GenMeshTorus Return type: Mesh Description: Generate torus mesh @@ -4137,7 +4142,7 @@ Function 488: GenMeshTorus() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 489: GenMeshKnot() (4 input parameters) +Function 490: GenMeshKnot() (4 input parameters) Name: GenMeshKnot Return type: Mesh Description: Generate trefoil knot mesh @@ -4145,91 +4150,91 @@ Function 489: GenMeshKnot() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 490: GenMeshHeightmap() (2 input parameters) +Function 491: 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 491: GenMeshCubicmap() (2 input parameters) +Function 492: 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 492: LoadMaterials() (2 input parameters) +Function 493: 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 493: LoadMaterialDefault() (0 input parameters) +Function 494: LoadMaterialDefault() (0 input parameters) Name: LoadMaterialDefault Return type: Material Description: Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) No input parameters -Function 494: IsMaterialReady() (1 input parameters) +Function 495: IsMaterialReady() (1 input parameters) Name: IsMaterialReady Return type: bool Description: Check if a material is ready Param[1]: material (type: Material) -Function 495: UnloadMaterial() (1 input parameters) +Function 496: UnloadMaterial() (1 input parameters) Name: UnloadMaterial Return type: void Description: Unload material from GPU memory (VRAM) Param[1]: material (type: Material) -Function 496: SetMaterialTexture() (3 input parameters) +Function 497: 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 497: SetModelMeshMaterial() (3 input parameters) +Function 498: 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 498: LoadModelAnimations() (2 input parameters) +Function 499: LoadModelAnimations() (2 input parameters) Name: LoadModelAnimations Return type: ModelAnimation * Description: Load model animations from file Param[1]: fileName (type: const char *) Param[2]: animCount (type: int *) -Function 499: UpdateModelAnimation() (3 input parameters) +Function 500: 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 500: UnloadModelAnimation() (1 input parameters) +Function 501: UnloadModelAnimation() (1 input parameters) Name: UnloadModelAnimation Return type: void Description: Unload animation data Param[1]: anim (type: ModelAnimation) -Function 501: UnloadModelAnimations() (2 input parameters) +Function 502: UnloadModelAnimations() (2 input parameters) Name: UnloadModelAnimations Return type: void Description: Unload animation array data Param[1]: animations (type: ModelAnimation *) Param[2]: animCount (type: int) -Function 502: IsModelAnimationValid() (2 input parameters) +Function 503: 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 503: UpdateModelAnimationBoneMatrices() (3 input parameters) +Function 504: UpdateModelAnimationBoneMatrices() (3 input parameters) Name: UpdateModelAnimationBoneMatrices Return type: void Description: Update model animation mesh bone matrices Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) Param[3]: frame (type: int) -Function 504: CheckCollisionSpheres() (4 input parameters) +Function 505: CheckCollisionSpheres() (4 input parameters) Name: CheckCollisionSpheres Return type: bool Description: Check collision between two spheres @@ -4237,40 +4242,40 @@ Function 504: CheckCollisionSpheres() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector3) Param[4]: radius2 (type: float) -Function 505: CheckCollisionBoxes() (2 input parameters) +Function 506: 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 506: CheckCollisionBoxSphere() (3 input parameters) +Function 507: 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 507: GetRayCollisionSphere() (3 input parameters) +Function 508: 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 508: GetRayCollisionBox() (2 input parameters) +Function 509: 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 509: GetRayCollisionMesh() (3 input parameters) +Function 510: 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 510: GetRayCollisionTriangle() (4 input parameters) +Function 511: GetRayCollisionTriangle() (4 input parameters) Name: GetRayCollisionTriangle Return type: RayCollision Description: Get collision info between ray and triangle @@ -4278,7 +4283,7 @@ Function 510: GetRayCollisionTriangle() (4 input parameters) Param[2]: p1 (type: Vector3) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) -Function 511: GetRayCollisionQuad() (5 input parameters) +Function 512: GetRayCollisionQuad() (5 input parameters) Name: GetRayCollisionQuad Return type: RayCollision Description: Get collision info between ray and quad @@ -4287,158 +4292,158 @@ Function 511: GetRayCollisionQuad() (5 input parameters) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) Param[5]: p4 (type: Vector3) -Function 512: InitAudioDevice() (0 input parameters) +Function 513: InitAudioDevice() (0 input parameters) Name: InitAudioDevice Return type: void Description: Initialize audio device and context No input parameters -Function 513: CloseAudioDevice() (0 input parameters) +Function 514: CloseAudioDevice() (0 input parameters) Name: CloseAudioDevice Return type: void Description: Close the audio device and context No input parameters -Function 514: IsAudioDeviceReady() (0 input parameters) +Function 515: IsAudioDeviceReady() (0 input parameters) Name: IsAudioDeviceReady Return type: bool Description: Check if audio device has been initialized successfully No input parameters -Function 515: SetMasterVolume() (1 input parameters) +Function 516: SetMasterVolume() (1 input parameters) Name: SetMasterVolume Return type: void Description: Set master volume (listener) Param[1]: volume (type: float) -Function 516: GetMasterVolume() (0 input parameters) +Function 517: GetMasterVolume() (0 input parameters) Name: GetMasterVolume Return type: float Description: Get master volume (listener) No input parameters -Function 517: LoadWave() (1 input parameters) +Function 518: LoadWave() (1 input parameters) Name: LoadWave Return type: Wave Description: Load wave data from file Param[1]: fileName (type: const char *) -Function 518: LoadWaveFromMemory() (3 input parameters) +Function 519: 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 519: IsWaveReady() (1 input parameters) +Function 520: IsWaveReady() (1 input parameters) Name: IsWaveReady Return type: bool Description: Checks if wave data is ready Param[1]: wave (type: Wave) -Function 520: LoadSound() (1 input parameters) +Function 521: LoadSound() (1 input parameters) Name: LoadSound Return type: Sound Description: Load sound from file Param[1]: fileName (type: const char *) -Function 521: LoadSoundFromWave() (1 input parameters) +Function 522: LoadSoundFromWave() (1 input parameters) Name: LoadSoundFromWave Return type: Sound Description: Load sound from wave data Param[1]: wave (type: Wave) -Function 522: LoadSoundAlias() (1 input parameters) +Function 523: LoadSoundAlias() (1 input parameters) Name: LoadSoundAlias Return type: Sound Description: Create a new sound that shares the same sample data as the source sound, does not own the sound data Param[1]: source (type: Sound) -Function 523: IsSoundReady() (1 input parameters) +Function 524: IsSoundReady() (1 input parameters) Name: IsSoundReady Return type: bool Description: Checks if a sound is ready Param[1]: sound (type: Sound) -Function 524: UpdateSound() (3 input parameters) +Function 525: 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 525: UnloadWave() (1 input parameters) +Function 526: UnloadWave() (1 input parameters) Name: UnloadWave Return type: void Description: Unload wave data Param[1]: wave (type: Wave) -Function 526: UnloadSound() (1 input parameters) +Function 527: UnloadSound() (1 input parameters) Name: UnloadSound Return type: void Description: Unload sound Param[1]: sound (type: Sound) -Function 527: UnloadSoundAlias() (1 input parameters) +Function 528: UnloadSoundAlias() (1 input parameters) Name: UnloadSoundAlias Return type: void Description: Unload a sound alias (does not deallocate sample data) Param[1]: alias (type: Sound) -Function 528: ExportWave() (2 input parameters) +Function 529: 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 529: ExportWaveAsCode() (2 input parameters) +Function 530: 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 530: PlaySound() (1 input parameters) +Function 531: PlaySound() (1 input parameters) Name: PlaySound Return type: void Description: Play a sound Param[1]: sound (type: Sound) -Function 531: StopSound() (1 input parameters) +Function 532: StopSound() (1 input parameters) Name: StopSound Return type: void Description: Stop playing a sound Param[1]: sound (type: Sound) -Function 532: PauseSound() (1 input parameters) +Function 533: PauseSound() (1 input parameters) Name: PauseSound Return type: void Description: Pause a sound Param[1]: sound (type: Sound) -Function 533: ResumeSound() (1 input parameters) +Function 534: ResumeSound() (1 input parameters) Name: ResumeSound Return type: void Description: Resume a paused sound Param[1]: sound (type: Sound) -Function 534: IsSoundPlaying() (1 input parameters) +Function 535: IsSoundPlaying() (1 input parameters) Name: IsSoundPlaying Return type: bool Description: Check if a sound is currently playing Param[1]: sound (type: Sound) -Function 535: SetSoundVolume() (2 input parameters) +Function 536: 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 536: SetSoundPitch() (2 input parameters) +Function 537: 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 537: SetSoundPan() (2 input parameters) +Function 538: 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 538: WaveCopy() (1 input parameters) +Function 539: WaveCopy() (1 input parameters) Name: WaveCopy Return type: Wave Description: Copy a wave to a new wave Param[1]: wave (type: Wave) -Function 539: WaveCrop() (3 input parameters) +Function 540: WaveCrop() (3 input parameters) Name: WaveCrop Return type: void Description: Crop a wave to defined frames range Param[1]: wave (type: Wave *) Param[2]: initFrame (type: int) Param[3]: finalFrame (type: int) -Function 540: WaveFormat() (4 input parameters) +Function 541: WaveFormat() (4 input parameters) Name: WaveFormat Return type: void Description: Convert wave data to desired format @@ -4446,203 +4451,203 @@ Function 540: WaveFormat() (4 input parameters) Param[2]: sampleRate (type: int) Param[3]: sampleSize (type: int) Param[4]: channels (type: int) -Function 541: LoadWaveSamples() (1 input parameters) +Function 542: 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 542: UnloadWaveSamples() (1 input parameters) +Function 543: UnloadWaveSamples() (1 input parameters) Name: UnloadWaveSamples Return type: void Description: Unload samples data loaded with LoadWaveSamples() Param[1]: samples (type: float *) -Function 543: LoadMusicStream() (1 input parameters) +Function 544: LoadMusicStream() (1 input parameters) Name: LoadMusicStream Return type: Music Description: Load music stream from file Param[1]: fileName (type: const char *) -Function 544: LoadMusicStreamFromMemory() (3 input parameters) +Function 545: 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 545: IsMusicReady() (1 input parameters) +Function 546: IsMusicReady() (1 input parameters) Name: IsMusicReady Return type: bool Description: Checks if a music stream is ready Param[1]: music (type: Music) -Function 546: UnloadMusicStream() (1 input parameters) +Function 547: UnloadMusicStream() (1 input parameters) Name: UnloadMusicStream Return type: void Description: Unload music stream Param[1]: music (type: Music) -Function 547: PlayMusicStream() (1 input parameters) +Function 548: PlayMusicStream() (1 input parameters) Name: PlayMusicStream Return type: void Description: Start music playing Param[1]: music (type: Music) -Function 548: IsMusicStreamPlaying() (1 input parameters) +Function 549: IsMusicStreamPlaying() (1 input parameters) Name: IsMusicStreamPlaying Return type: bool Description: Check if music is playing Param[1]: music (type: Music) -Function 549: UpdateMusicStream() (1 input parameters) +Function 550: UpdateMusicStream() (1 input parameters) Name: UpdateMusicStream Return type: void Description: Updates buffers for music streaming Param[1]: music (type: Music) -Function 550: StopMusicStream() (1 input parameters) +Function 551: StopMusicStream() (1 input parameters) Name: StopMusicStream Return type: void Description: Stop music playing Param[1]: music (type: Music) -Function 551: PauseMusicStream() (1 input parameters) +Function 552: PauseMusicStream() (1 input parameters) Name: PauseMusicStream Return type: void Description: Pause music playing Param[1]: music (type: Music) -Function 552: ResumeMusicStream() (1 input parameters) +Function 553: ResumeMusicStream() (1 input parameters) Name: ResumeMusicStream Return type: void Description: Resume playing paused music Param[1]: music (type: Music) -Function 553: SeekMusicStream() (2 input parameters) +Function 554: 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 554: SetMusicVolume() (2 input parameters) +Function 555: 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 555: SetMusicPitch() (2 input parameters) +Function 556: 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 556: SetMusicPan() (2 input parameters) +Function 557: 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 557: GetMusicTimeLength() (1 input parameters) +Function 558: GetMusicTimeLength() (1 input parameters) Name: GetMusicTimeLength Return type: float Description: Get music time length (in seconds) Param[1]: music (type: Music) -Function 558: GetMusicTimePlayed() (1 input parameters) +Function 559: GetMusicTimePlayed() (1 input parameters) Name: GetMusicTimePlayed Return type: float Description: Get current music time played (in seconds) Param[1]: music (type: Music) -Function 559: LoadAudioStream() (3 input parameters) +Function 560: 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 560: IsAudioStreamReady() (1 input parameters) +Function 561: IsAudioStreamReady() (1 input parameters) Name: IsAudioStreamReady Return type: bool Description: Checks if an audio stream is ready Param[1]: stream (type: AudioStream) -Function 561: UnloadAudioStream() (1 input parameters) +Function 562: UnloadAudioStream() (1 input parameters) Name: UnloadAudioStream Return type: void Description: Unload audio stream and free memory Param[1]: stream (type: AudioStream) -Function 562: UpdateAudioStream() (3 input parameters) +Function 563: 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 563: IsAudioStreamProcessed() (1 input parameters) +Function 564: IsAudioStreamProcessed() (1 input parameters) Name: IsAudioStreamProcessed Return type: bool Description: Check if any audio stream buffers requires refill Param[1]: stream (type: AudioStream) -Function 564: PlayAudioStream() (1 input parameters) +Function 565: PlayAudioStream() (1 input parameters) Name: PlayAudioStream Return type: void Description: Play audio stream Param[1]: stream (type: AudioStream) -Function 565: PauseAudioStream() (1 input parameters) +Function 566: PauseAudioStream() (1 input parameters) Name: PauseAudioStream Return type: void Description: Pause audio stream Param[1]: stream (type: AudioStream) -Function 566: ResumeAudioStream() (1 input parameters) +Function 567: ResumeAudioStream() (1 input parameters) Name: ResumeAudioStream Return type: void Description: Resume audio stream Param[1]: stream (type: AudioStream) -Function 567: IsAudioStreamPlaying() (1 input parameters) +Function 568: IsAudioStreamPlaying() (1 input parameters) Name: IsAudioStreamPlaying Return type: bool Description: Check if audio stream is playing Param[1]: stream (type: AudioStream) -Function 568: StopAudioStream() (1 input parameters) +Function 569: StopAudioStream() (1 input parameters) Name: StopAudioStream Return type: void Description: Stop audio stream Param[1]: stream (type: AudioStream) -Function 569: SetAudioStreamVolume() (2 input parameters) +Function 570: 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 570: SetAudioStreamPitch() (2 input parameters) +Function 571: 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 571: SetAudioStreamPan() (2 input parameters) +Function 572: 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 572: SetAudioStreamBufferSizeDefault() (1 input parameters) +Function 573: SetAudioStreamBufferSizeDefault() (1 input parameters) Name: SetAudioStreamBufferSizeDefault Return type: void Description: Default size for new audio streams Param[1]: size (type: int) -Function 573: SetAudioStreamCallback() (2 input parameters) +Function 574: 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 574: AttachAudioStreamProcessor() (2 input parameters) +Function 575: AttachAudioStreamProcessor() (2 input parameters) Name: AttachAudioStreamProcessor Return type: void Description: Attach audio stream processor to stream, receives the samples as 'float' Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 575: DetachAudioStreamProcessor() (2 input parameters) +Function 576: 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 576: AttachAudioMixedProcessor() (1 input parameters) +Function 577: AttachAudioMixedProcessor() (1 input parameters) Name: AttachAudioMixedProcessor Return type: void Description: Attach audio stream processor to the entire audio pipeline, receives the samples as 'float' Param[1]: processor (type: AudioCallback) -Function 577: DetachAudioMixedProcessor() (1 input parameters) +Function 578: DetachAudioMixedProcessor() (1 input parameters) Name: DetachAudioMixedProcessor Return type: void Description: Detach audio stream processor from the entire audio pipeline diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index 13ea5b7ab..140f4910d 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -675,7 +675,7 @@ - + @@ -1074,6 +1074,9 @@ + + + From 100f6624d62d29638fc7174f41a6cba1548fb3e2 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 22 Sep 2024 22:36:17 +0200 Subject: [PATCH 049/115] Update rcore.c --- src/rcore.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 1501aced1..50814443c 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -205,9 +205,13 @@ unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); #include // Required for: _mkdir() #define MKDIR(dir) _mkdir(dir) #elif defined __GNUC__ - #include - #include // Required for: mkdir() - #define MKDIR(dir) mkdir(dir) // OLD: mkdir(dir, 0777) -> w64devkit complaints! + #if defined(__linux__) + #define MKDIR(dir) mkdir(dir, 0777); + #else + #include + #include // Required for: mkdir() + #define MKDIR(dir) _mkdir(dir) // OLD: mkdir(dir, 0777) -> w64devkit complaints! + #endif #endif //---------------------------------------------------------------------------------- From 352c450ad02b9920110bbaa57171f3a184dc4a22 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 22 Sep 2024 22:43:35 +0200 Subject: [PATCH 050/115] 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 50814443c..03d3d1fb4 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -210,7 +210,7 @@ unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); #else #include #include // Required for: mkdir() - #define MKDIR(dir) _mkdir(dir) // OLD: mkdir(dir, 0777) -> w64devkit complaints! + #define MKDIR(dir) mkdir(dir) // OLD: mkdir(dir, 0777) -> w64devkit complaints! #endif #endif From 24a1cd8c5b95116c207d8f9189fc6eba245ac40c Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 22 Sep 2024 22:50:47 +0200 Subject: [PATCH 051/115] Update rcore.c --- src/rcore.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 03d3d1fb4..74659b6fd 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -205,12 +205,14 @@ unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); #include // Required for: _mkdir() #define MKDIR(dir) _mkdir(dir) #elif defined __GNUC__ - #if defined(__linux__) + #if defined(EMSCRIPTEN) + #define MKDIR(dir) mkdir(dir) + #elif defined(__linux__) #define MKDIR(dir) mkdir(dir, 0777); #else #include #include // Required for: mkdir() - #define MKDIR(dir) mkdir(dir) // OLD: mkdir(dir, 0777) -> w64devkit complaints! + #define MKDIR(dir) _mkdir(dir) // OLD: mkdir(dir, 0777) -> w64devkit complaints! #endif #endif From 291063c98fd9ebcff1e852f0eaeab1deb6e8f028 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 22 Sep 2024 22:56:21 +0200 Subject: [PATCH 052/115] Update rcore.c --- src/rcore.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 74659b6fd..ccd58bdb2 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -195,26 +195,30 @@ unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); #include // Required for: _getch(), _chdir(), _mkdir() #define GETCWD _getcwd // NOTE: MSDN recommends not to use getcwd(), chdir() #define CHDIR _chdir + #define MKDIR(dir) _mkdir(dir) #else #include // Required for: getch(), chdir() (POSIX), access() #define GETCWD getcwd #define CHDIR chdir + #define MKDIR(dir) mkdir(dir, 0777) #endif +/* #if defined(_MSC_VER) && ((defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__)) - #include // Required for: _mkdir() - #define MKDIR(dir) _mkdir(dir) + //#include // Required for: _mkdir() + //#define MKDIR(dir) _mkdir(dir) #elif defined __GNUC__ #if defined(EMSCRIPTEN) - #define MKDIR(dir) mkdir(dir) + #define MKDIR(dir) mkdir(dir, 0777) #elif defined(__linux__) - #define MKDIR(dir) mkdir(dir, 0777); + #define MKDIR(dir) mkdir(dir, 0777) #else #include #include // Required for: mkdir() #define MKDIR(dir) _mkdir(dir) // OLD: mkdir(dir, 0777) -> w64devkit complaints! #endif #endif +*/ //---------------------------------------------------------------------------------- // Defines and Macros From 13178b9373cebffb97a4ff66b734bacbb9d8758d Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 22 Sep 2024 23:01:22 +0200 Subject: [PATCH 053/115] Update rcore.c --- src/rcore.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index ccd58bdb2..3cdacbd96 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -197,29 +197,12 @@ unsigned int __stdcall timeEndPeriod(unsigned int uPeriod); #define CHDIR _chdir #define MKDIR(dir) _mkdir(dir) #else - #include // Required for: getch(), chdir() (POSIX), access() + #include // Required for: getch(), chdir(), mkdir(), access() #define GETCWD getcwd #define CHDIR chdir #define MKDIR(dir) mkdir(dir, 0777) #endif -/* -#if defined(_MSC_VER) && ((defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__)) - //#include // Required for: _mkdir() - //#define MKDIR(dir) _mkdir(dir) -#elif defined __GNUC__ - #if defined(EMSCRIPTEN) - #define MKDIR(dir) mkdir(dir, 0777) - #elif defined(__linux__) - #define MKDIR(dir) mkdir(dir, 0777) - #else - #include - #include // Required for: mkdir() - #define MKDIR(dir) _mkdir(dir) // OLD: mkdir(dir, 0777) -> w64devkit complaints! - #endif -#endif -*/ - //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- From 55e83468c9bb515a5f2725751e5f187a7b9b5afd Mon Sep 17 00:00:00 2001 From: Menno van der Graaf Date: Tue, 24 Sep 2024 20:02:54 +0200 Subject: [PATCH 054/115] Fix isGpuReady flag on android (#4340) --- src/platforms/rcore_android.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c index 55706c591..6318931cc 100644 --- a/src/platforms/rcore_android.c +++ b/src/platforms/rcore_android.c @@ -74,7 +74,7 @@ typedef struct { // Global Variables Definition //---------------------------------------------------------------------------------- extern CoreData CORE; // Global CORE state context - +extern bool isGpuReady; // Flag to note GPU has been initialized successfully static PlatformData platform = { 0 }; // Platform specific data //---------------------------------------------------------------------------------- @@ -989,6 +989,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) // Initialize OpenGL context (states and resources) // NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height); + isGpuReady = true; // Setup default viewport // NOTE: It updated CORE.Window.render.width and CORE.Window.render.height From 0573ef03820f0948b38d52236d15c2f18c871cc7 Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Fri, 27 Sep 2024 14:06:54 -0700 Subject: [PATCH 055/115] [SHAPES] Add more detail to comment for DrawPixel (#4344) * Update raylib_api.* by CI * Add comment that draw pixel uses geometry and may be slow * Update raylib_api.* by CI --------- Co-authored-by: github-actions[bot] --- parser/output/raylib_api.json | 4 ++-- parser/output/raylib_api.lua | 4 ++-- parser/output/raylib_api.txt | 4 ++-- parser/output/raylib_api.xml | 4 ++-- src/raylib.h | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json index 2e599496d..ca3b276cf 100644 --- a/parser/output/raylib_api.json +++ b/parser/output/raylib_api.json @@ -5274,7 +5274,7 @@ }, { "name": "DrawPixel", - "description": "Draw a pixel", + "description": "Draw a pixel using geometry [Can be slow, use with care]", "returnType": "void", "params": [ { @@ -5293,7 +5293,7 @@ }, { "name": "DrawPixelV", - "description": "Draw a pixel (Vector version)", + "description": "Draw a pixel using geometry (Vector version) [Can be slow, use with care]", "returnType": "void", "params": [ { diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua index 69ae07eda..b010e19cf 100644 --- a/parser/output/raylib_api.lua +++ b/parser/output/raylib_api.lua @@ -4614,7 +4614,7 @@ return { }, { name = "DrawPixel", - description = "Draw a pixel", + description = "Draw a pixel using geometry [Can be slow, use with care]", returnType = "void", params = { {type = "int", name = "posX"}, @@ -4624,7 +4624,7 @@ return { }, { name = "DrawPixelV", - description = "Draw a pixel (Vector version)", + description = "Draw a pixel using geometry (Vector version) [Can be slow, use with care]", returnType = "void", params = { {type = "Vector2", name = "position"}, diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt index 458d12da0..19abf2d00 100644 --- a/parser/output/raylib_api.txt +++ b/parser/output/raylib_api.txt @@ -2102,14 +2102,14 @@ Function 207: GetShapesTextureRectangle() (0 input parameters) Function 208: DrawPixel() (3 input parameters) Name: DrawPixel Return type: void - Description: Draw a pixel + Description: Draw a pixel using geometry [Can be slow, use with care] Param[1]: posX (type: int) Param[2]: posY (type: int) Param[3]: color (type: Color) Function 209: DrawPixelV() (2 input parameters) Name: DrawPixelV Return type: void - Description: Draw a pixel (Vector version) + Description: Draw a pixel using geometry (Vector version) [Can be slow, use with care] Param[1]: position (type: Vector2) Param[2]: color (type: Color) Function 210: DrawLine() (5 input parameters) diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index 140f4910d..13afbcb64 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -1297,12 +1297,12 @@ - + - + diff --git a/src/raylib.h b/src/raylib.h index f298fd731..106a96ae5 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1234,8 +1234,8 @@ RLAPI Texture2D GetShapesTexture(void); // Get t RLAPI Rectangle GetShapesTextureRectangle(void); // Get texture source rectangle that is used for shapes drawing // Basic shapes drawing functions -RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel -RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel (Vector version) +RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel using geometry [Can be slow, use with care] +RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel using geometry (Vector version) [Can be slow, use with care] RLAPI void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw a line RLAPI void DrawLineV(Vector2 startPos, Vector2 endPos, Color color); // Draw a line (using gl lines) RLAPI void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line (using triangles/quads) From 84a4d93bc4e421e2fc654b0e4d7c513ac17990e0 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 30 Sep 2024 12:06:53 +0200 Subject: [PATCH 056/115] Fix #4349 --- src/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.h b/src/config.h index f6e3fe304..ca9489822 100644 --- a/src/config.h +++ b/src/config.h @@ -228,7 +228,7 @@ // 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_MESH_VERTEX_BUFFERS 9 // Maximum vertex buffers (VBO) per mesh //------------------------------------------------------------------------------------ // Module: raudio - Configuration Flags From 0e7bcd5639729fac1df19ed2d0622ff3daab59e3 Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Mon, 30 Sep 2024 03:10:02 -0700 Subject: [PATCH 057/115] [MODELS] Disable GPU skinning for MacOS platform (#4348) * Update raylib_api.* by CI * Disable GPU skinning on MacOS Add GPU skinning example to MSVC Projects. * Update raylib_api.* by CI --------- Co-authored-by: github-actions[bot] --- examples/models/models_gpu_skinning.c | 2 + parser/output/raylib_api.json | 2 +- parser/output/raylib_api.lua | 2 +- parser/output/raylib_api.txt | 2 +- parser/output/raylib_api.xml | 2 +- .../examples/models_gpu_skinning.vcxproj | 387 ++++++++++++++++++ projects/VS2022/raylib.sln | 19 + src/config.h | 15 +- src/raylib.h | 2 +- src/rlgl.h | 14 +- src/rmodels.c | 18 +- 11 files changed, 447 insertions(+), 18 deletions(-) create mode 100644 projects/VS2022/examples/models_gpu_skinning.vcxproj diff --git a/examples/models/models_gpu_skinning.c b/examples/models/models_gpu_skinning.c index e9cd73f4b..846f0a890 100644 --- a/examples/models/models_gpu_skinning.c +++ b/examples/models/models_gpu_skinning.c @@ -10,6 +10,8 @@ * BSD-like license that allows static linking with closed source software * * Copyright (c) 2024 Daniel Holden (@orangeduck) +* +* Note: Due to limitations in the Apple OpenGL driver, this feature does not work on MacOS * ********************************************************************************************/ diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json index ca3b276cf..58fb9d6a8 100644 --- a/parser/output/raylib_api.json +++ b/parser/output/raylib_api.json @@ -11104,7 +11104,7 @@ }, { "name": "UpdateModelAnimationBoneMatrices", - "description": "Update model animation mesh bone matrices", + "description": "Update model animation mesh bone matrices (Note GPU skinning does not work on Mac)", "returnType": "void", "params": [ { diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua index b010e19cf..bea3813cf 100644 --- a/parser/output/raylib_api.lua +++ b/parser/output/raylib_api.lua @@ -7621,7 +7621,7 @@ return { }, { name = "UpdateModelAnimationBoneMatrices", - description = "Update model animation mesh bone matrices", + description = "Update model animation mesh bone matrices (Note GPU skinning does not work on Mac)", returnType = "void", params = { {type = "Model", name = "model"}, diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt index 19abf2d00..9a953b768 100644 --- a/parser/output/raylib_api.txt +++ b/parser/output/raylib_api.txt @@ -4230,7 +4230,7 @@ Function 503: IsModelAnimationValid() (2 input parameters) Function 504: UpdateModelAnimationBoneMatrices() (3 input parameters) Name: UpdateModelAnimationBoneMatrices Return type: void - Description: Update model animation mesh bone matrices + Description: Update model animation mesh bone matrices (Note GPU skinning does not work on Mac) Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) Param[3]: frame (type: int) diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index 13afbcb64..895680f2c 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -2830,7 +2830,7 @@ - + diff --git a/projects/VS2022/examples/models_gpu_skinning.vcxproj b/projects/VS2022/examples/models_gpu_skinning.vcxproj new file mode 100644 index 000000000..bd596bed6 --- /dev/null +++ b/projects/VS2022/examples/models_gpu_skinning.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 + + + + {8245DAD9-D402-4D5C-8F45-32229CD3B263} + Win32Proj + models_loading + 10.0 + models_gpu_skinning + + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + 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 diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index 294d0e84d..2b262bcfe 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -299,6 +299,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_splines_drawing", "e EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_top_down_lights", "examples\shapes_top_down_lights.vcxproj", "{703BE7BA-5B99-4F70-806D-3A259F6A991E}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_gpu_skinning", "examples\models_gpu_skinning.vcxproj", "{8245DAD9-D402-4D5C-8F45-32229CD3B263}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug.DLL|x64 = Debug.DLL|x64 @@ -2531,6 +2533,22 @@ Global {703BE7BA-5B99-4F70-806D-3A259F6A991E}.Release|x64.Build.0 = Release|x64 {703BE7BA-5B99-4F70-806D-3A259F6A991E}.Release|x86.ActiveCfg = Release|Win32 {703BE7BA-5B99-4F70-806D-3A259F6A991E}.Release|x86.Build.0 = Release|Win32 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug|x64.ActiveCfg = Debug|x64 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug|x64.Build.0 = Debug|x64 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug|x86.ActiveCfg = Debug|Win32 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug|x86.Build.0 = Debug|Win32 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release|x64.ActiveCfg = Release|x64 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release|x64.Build.0 = Release|x64 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release|x86.ActiveCfg = Release|Win32 + {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2682,6 +2700,7 @@ Global {D8026C60-CCBC-45DF-9085-BF21569EB414} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE} {DF25E545-00FF-4E64-844C-7DF98991F901} = {278D8859-20B1-428F-8448-064F46E1F021} {703BE7BA-5B99-4F70-806D-3A259F6A991E} = {278D8859-20B1-428F-8448-064F46E1F021} + {8245DAD9-D402-4D5C-8F45-32229CD3B263} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} diff --git a/src/config.h b/src/config.h index ca9489822..8bba37606 100644 --- a/src/config.h +++ b/src/config.h @@ -119,9 +119,18 @@ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3 #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4 #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 6 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 7 -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 8 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6 + +// The mac OpenGL drivers do not support more than 8 VBOs, so we can't support GPU animations +#ifndef __APPLE__ +#define RL_SUPPORT_MESH_ANIMATION_VBO +#endif + +#ifdef RL_SUPPORT_MESH_ANIMATION_VBO +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 7 +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8 +#endif + // 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 diff --git a/src/raylib.h b/src/raylib.h index 106a96ae5..08121c50c 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1597,7 +1597,7 @@ RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame); RLAPI void UnloadModelAnimation(ModelAnimation anim); // Unload animation data RLAPI void UnloadModelAnimations(ModelAnimation *animations, int animCount); // Unload animation array data RLAPI bool IsModelAnimationValid(Model model, ModelAnimation anim); // Check model animation skeleton match -RLAPI void UpdateModelAnimationBoneMatrices(Model model, ModelAnimation anim, int frame); // Update model animation mesh bone matrices +RLAPI void UpdateModelAnimationBoneMatrices(Model model, ModelAnimation anim, int frame); // Update model animation mesh bone matrices (Note GPU skinning does not work on Mac) // Collision detection functions RLAPI bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2); // Check collision between two spheres diff --git a/src/rlgl.h b/src/rlgl.h index 875b568f5..843c46a2a 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -344,16 +344,17 @@ #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5 #endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6 +#endif #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 6 + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 7 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 7 -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 8 + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8 #endif + //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- @@ -4170,8 +4171,11 @@ unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR); glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT); glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2); + +#ifdef RL_SUPPORT_MESH_ANIMATION_VBO glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS); glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS); +#endif // NOTE: If some attrib name is no found on the shader, it locations becomes -1 diff --git a/src/rmodels.c b/src/rmodels.c index ebdd178fd..d5c2f9954 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1252,9 +1252,10 @@ void UploadMesh(Mesh *mesh, bool dynamic) mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] = 0; // Vertex buffer: colors mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = 0; // Vertex buffer: tangents mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = 0; // Vertex buffer: texcoords2 + mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = 0; // Vertex buffer: indices mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS] = 0; // Vertex buffer: boneIds mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = 0; // Vertex buffer: boneWeights - mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = 0; // Vertex buffer: indices + #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) mesh->vaoId = rlLoadVertexArray(); @@ -1340,7 +1341,8 @@ void UploadMesh(Mesh *mesh, bool dynamic) rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, value, SHADER_ATTRIB_VEC2, 2); rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2); } - + +#ifdef RL_SUPPORT_MESH_ANIMATION_VBO if (mesh->boneIds != NULL) { // Enable vertex attribute: boneIds (shader-location = 6) @@ -1372,6 +1374,7 @@ void UploadMesh(Mesh *mesh, bool dynamic) rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, value, SHADER_ATTRIB_VEC4, 2); rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS); } +#endif if (mesh->indices != NULL) { @@ -1485,13 +1488,14 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) // Upload model normal matrix (if locations available) if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel))); - + +#ifdef RL_SUPPORT_MESH_ANIMATION_VBO // Upload Bone Transforms if (material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1 && mesh.boneMatrices) { rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount); } - +#endif //----------------------------------------------------- // Bind active texture maps (if available) @@ -1570,7 +1574,8 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]); } - + +#ifdef RL_SUPPORT_MESH_ANIMATION_VBO // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available) if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1) { @@ -1586,6 +1591,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS], 4, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS]); } +#endif if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]); } @@ -1729,11 +1735,13 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i // Upload model normal matrix (if locations available) if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel))); +#ifdef RL_SUPPORT_MESH_ANIMATION_VBO // Upload Bone Transforms if (material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1 && mesh.boneMatrices) { rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount); } +#endif //----------------------------------------------------- From 282d6478baa51a509bf0a4b1d761a0bd7fd8bbf7 Mon Sep 17 00:00:00 2001 From: Asdqwe Date: Tue, 1 Oct 2024 07:09:06 -0300 Subject: [PATCH 058/115] Complements the #4348 GPU skinning fix (#4352) --- src/rlgl.h | 5 ++++- src/rmodels.c | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 843c46a2a..98310c101 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -345,14 +345,17 @@ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES -#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6 + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6 #endif + +#ifdef RL_SUPPORT_MESH_ANIMATION_VBO #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 7 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8 #endif +#endif //---------------------------------------------------------------------------------- diff --git a/src/rmodels.c b/src/rmodels.c index d5c2f9954..b7f18f307 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1253,8 +1253,11 @@ void UploadMesh(Mesh *mesh, bool dynamic) mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = 0; // Vertex buffer: tangents mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = 0; // Vertex buffer: texcoords2 mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = 0; // Vertex buffer: indices + +#ifdef RL_SUPPORT_MESH_ANIMATION_VBO mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS] = 0; // Vertex buffer: boneIds mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = 0; // Vertex buffer: boneWeights +#endif #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) @@ -1819,7 +1822,8 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]); } - + +#ifdef RL_SUPPORT_MESH_ANIMATION_VBO // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available) if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1) { @@ -1835,6 +1839,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS], 4, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS]); } +#endif if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]); } From d9c10ed2646eea784ba71ae24ef53f67a497fc08 Mon Sep 17 00:00:00 2001 From: Asdqwe Date: Wed, 2 Oct 2024 05:49:06 -0300 Subject: [PATCH 059/115] Fixes GetClipboardText() memory leak for PLATFORM_DESKTOP_SDL (#4354) --- src/platforms/rcore_desktop_sdl.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 794f9e6a0..90372c2f6 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -57,6 +57,13 @@ #include "SDL_opengl.h" // SDL OpenGL functionality (if required, instead of internal renderer) #endif +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#ifndef MAX_CLIPBOARD_BUFFER_LENGTH + #define MAX_CLIPBOARD_BUFFER_LENGTH 1024 // Size of the clipboard buffer used on GetClipboardText() +#endif + //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- @@ -852,10 +859,22 @@ void SetClipboardText(const char *text) } // Get clipboard text content -// NOTE: returned string must be freed with SDL_free() const char *GetClipboardText(void) { - return SDL_GetClipboardText(); + static char buffer[MAX_CLIPBOARD_BUFFER_LENGTH] = { 0 }; + + char *clipboard = SDL_GetClipboardText(); + + int clipboardSize = snprintf(buffer, sizeof(buffer), "%s", clipboard); + if (clipboardSize >= MAX_CLIPBOARD_BUFFER_LENGTH) + { + char *truncate = buffer + MAX_CLIPBOARD_BUFFER_LENGTH - 4; + sprintf(truncate, "..."); + } + + SDL_free(clipboard); + + return buffer; } // Show mouse cursor @@ -1589,8 +1608,8 @@ int InitPlatform(void) // Initialize storage system //---------------------------------------------------------------------------- // Define base path for storage - CORE.Storage.basePath = SDL_GetBasePath(); // Alternative: GetWorkingDirectory(); - CHDIR(CORE.Storage.basePath); + CORE.Storage.basePath = SDL_GetBasePath(); // Alternative: GetWorkingDirectory(); + CHDIR(CORE.Storage.basePath); //---------------------------------------------------------------------------- TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL): Initialized successfully"); From 09987b01cc2c1f4e49d3a2bb11cf235a5a529435 Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Wed, 2 Oct 2024 01:49:56 -0700 Subject: [PATCH 060/115] [MODELS] Better fix for GPU skinning issues (#4353) * Make the max VBO match the animation flag. * re-enable GPU skinning for mac, and fix the max buffer to be correct based on the GPU skinning support flag. --- src/config.h | 13 ++++++++----- src/rlgl.h | 2 +- src/rmodels.c | 8 ++++---- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/config.h b/src/config.h index 8bba37606..5504a1823 100644 --- a/src/config.h +++ b/src/config.h @@ -121,12 +121,10 @@ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5 #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6 -// The mac OpenGL drivers do not support more than 8 VBOs, so we can't support GPU animations -#ifndef __APPLE__ -#define RL_SUPPORT_MESH_ANIMATION_VBO -#endif -#ifdef RL_SUPPORT_MESH_ANIMATION_VBO +#define RL_SUPPORT_MESH_GPU_SKINNING // Remove this if your GPU does not support more than 8 VBOs + +#ifdef RL_SUPPORT_MESH_GPU_SKINNING #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 7 #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8 #endif @@ -237,7 +235,12 @@ // rmodels: Configuration values //------------------------------------------------------------------------------------ #define MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported + +#ifdef RL_SUPPORT_MESH_GPU_SKINNING #define MAX_MESH_VERTEX_BUFFERS 9 // Maximum vertex buffers (VBO) per mesh +#else +#define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh +#endif //------------------------------------------------------------------------------------ // Module: raudio - Configuration Flags diff --git a/src/rlgl.h b/src/rlgl.h index 98310c101..95af8e0e7 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -4175,7 +4175,7 @@ unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT); glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2); -#ifdef RL_SUPPORT_MESH_ANIMATION_VBO +#ifdef RL_SUPPORT_MESH_GPU_SKINNING glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS); glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS); #endif diff --git a/src/rmodels.c b/src/rmodels.c index b7f18f307..7e17386e1 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1345,7 +1345,7 @@ void UploadMesh(Mesh *mesh, bool dynamic) rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2); } -#ifdef RL_SUPPORT_MESH_ANIMATION_VBO +#ifdef RL_SUPPORT_MESH_GPU_SKINNING if (mesh->boneIds != NULL) { // Enable vertex attribute: boneIds (shader-location = 6) @@ -1492,7 +1492,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) // Upload model normal matrix (if locations available) if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel))); -#ifdef RL_SUPPORT_MESH_ANIMATION_VBO +#ifdef RL_SUPPORT_MESH_GPU_SKINNING // Upload Bone Transforms if (material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1 && mesh.boneMatrices) { @@ -1578,7 +1578,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]); } -#ifdef RL_SUPPORT_MESH_ANIMATION_VBO +#ifdef RL_SUPPORT_MESH_GPU_SKINNING // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available) if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1) { @@ -1738,7 +1738,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i // Upload model normal matrix (if locations available) if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel))); -#ifdef RL_SUPPORT_MESH_ANIMATION_VBO +#ifdef RL_SUPPORT_MESH_GPU_SKINNING // Upload Bone Transforms if (material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1 && mesh.boneMatrices) { From 96d91a38923094951e481d9fbc26291026e48fea Mon Sep 17 00:00:00 2001 From: Asdqwe Date: Wed, 2 Oct 2024 06:41:21 -0300 Subject: [PATCH 061/115] [rlgl] Fix rlgl standalone defaults (#4357) * Fix rlgl standalone defaults * Fix rmodels --- src/rlgl.h | 2 +- src/rmodels.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 95af8e0e7..43698f63a 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -348,7 +348,7 @@ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6 #endif -#ifdef RL_SUPPORT_MESH_ANIMATION_VBO +#ifdef RL_SUPPORT_MESH_GPU_SKINNING #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 7 #endif diff --git a/src/rmodels.c b/src/rmodels.c index 7e17386e1..d2bf528ff 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1254,7 +1254,7 @@ void UploadMesh(Mesh *mesh, bool dynamic) mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = 0; // Vertex buffer: texcoords2 mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = 0; // Vertex buffer: indices -#ifdef RL_SUPPORT_MESH_ANIMATION_VBO +#ifdef RL_SUPPORT_MESH_GPU_SKINNING mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS] = 0; // Vertex buffer: boneIds mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = 0; // Vertex buffer: boneWeights #endif @@ -1823,7 +1823,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]); } -#ifdef RL_SUPPORT_MESH_ANIMATION_VBO +#ifdef RL_SUPPORT_MESH_GPU_SKINNING // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available) if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1) { From 20ce8ba04651502203151f94e4736484fb390b45 Mon Sep 17 00:00:00 2001 From: Ashley Chekhov <70078024+FluxFlu@users.noreply.github.com> Date: Fri, 4 Oct 2024 09:04:26 +0000 Subject: [PATCH 062/115] Typo fix (#4356) Seemed to be a typo. Hope this helps. --- examples/textures/textures_image_drawing.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/textures/textures_image_drawing.c b/examples/textures/textures_image_drawing.c index f49bc9e77..d0eee999d 100644 --- a/examples/textures/textures_image_drawing.c +++ b/examples/textures/textures_image_drawing.c @@ -47,7 +47,7 @@ int main(void) UnloadImage(cat); // Unload image from RAM - // Load custom font for frawing on image + // Load custom font for drawing on image Font font = LoadFont("resources/custom_jupiter_crash.png"); // Draw over image using custom font @@ -93,4 +93,4 @@ int main(void) //-------------------------------------------------------------------------------------- return 0; -} \ No newline at end of file +} From 0ef07918542b17956c63aa5a037a64b6c60bcd46 Mon Sep 17 00:00:00 2001 From: Nikolas Date: Fri, 4 Oct 2024 11:05:19 +0200 Subject: [PATCH 063/115] Allow Zig build script to change desktop backend (#4358) --- src/build.zig | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/build.zig b/src/build.zig index 4e112d78f..b08b909de 100644 --- a/src/build.zig +++ b/src/build.zig @@ -40,6 +40,17 @@ pub fn addRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. return raylib; } +fn setDesktopPlatform(raylib: *std.Build.Step.Compile, platform: PlatformBackend) void { + raylib.defineCMacro("PLATFORM_DESKTOP", null); + + switch (platform) { + .glfw => raylib.defineCMacro("PLATFORM_DESKTOP_GLFW", null), + .rgfw => raylib.defineCMacro("PLATFORM_DESKTOP_RGFW", null), + .sdl => raylib.defineCMacro("PLATFORM_DESKTOP_SDL", null), + else => {} + } +} + fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile { raylib_flags_arr.clearRetainingCapacity(); @@ -102,7 +113,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. raylib.linkLibC(); // No GLFW required on PLATFORM_DRM - if (!options.platform_drm) { + if (options.platform != .drm) { raylib.addIncludePath(b.path("src/external/glfw/include")); } @@ -136,10 +147,10 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. raylib.linkSystemLibrary("gdi32"); raylib.linkSystemLibrary("opengl32"); - raylib.defineCMacro("PLATFORM_DESKTOP", null); + setDesktopPlatform(raylib, options.platform); }, .linux => { - if (!options.platform_drm) { + if (options.platform != .drm) { try c_source_files.append("rglfw.c"); raylib.linkSystemLibrary("GL"); raylib.linkSystemLibrary("rt"); @@ -177,7 +188,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. waylandGenerate(b, raylib, "xdg-activation-v1.xml", "xdg-activation-v1-client-protocol"); waylandGenerate(b, raylib, "idle-inhibit-unstable-v1.xml", "idle-inhibit-unstable-v1-client-protocol"); } - raylib.defineCMacro("PLATFORM_DESKTOP", null); + setDesktopPlatform(raylib, options.platform); } else { if (options.opengl_version == .auto) { raylib.linkSystemLibrary("GLESv2"); @@ -211,7 +222,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. raylib.linkSystemLibrary("Xxf86vm"); raylib.linkSystemLibrary("Xcursor"); - raylib.defineCMacro("PLATFORM_DESKTOP", null); + setDesktopPlatform(raylib, options.platform); }, .macos => { // On macos rglfw.c include Objective-C files. @@ -227,7 +238,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. raylib.linkFramework("AppKit"); raylib.linkFramework("IOKit"); - raylib.defineCMacro("PLATFORM_DESKTOP", null); + setDesktopPlatform(raylib, options.platform); }, .emscripten => { raylib.defineCMacro("PLATFORM_WEB", null); @@ -286,7 +297,7 @@ pub const Options = struct { rtext: bool = true, rtextures: bool = true, raygui: bool = false, - platform_drm: bool = false, + platform: PlatformBackend = .glfw, shared: bool = false, linux_display_backend: LinuxDisplayBackend = .Both, opengl_version: OpenglVersion = .auto, @@ -323,6 +334,13 @@ pub const LinuxDisplayBackend = enum { Both, }; +pub const PlatformBackend = enum { + glfw, + rgfw, + sdl, + drm +}; + 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 @@ -336,7 +354,7 @@ pub fn build(b: *std.Build) !void { const defaults = Options{}; const options = Options{ - .platform_drm = b.option(bool, "platform_drm", "Compile raylib in native mode (no X11)") orelse defaults.platform_drm, + .platform = b.option(PlatformBackend, "platform", "Choose the platform backedn for desktop target") orelse defaults.platform, .raudio = b.option(bool, "raudio", "Compile with audio support") orelse defaults.raudio, .rmodels = b.option(bool, "rmodels", "Compile with models support") orelse defaults.rmodels, .rtext = b.option(bool, "rtext", "Compile with text support") orelse defaults.rtext, From cded3782056ab1cb8b83e6fe346be1ea4f9e1aae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Zyba=C5=82a?= Date: Fri, 4 Oct 2024 11:08:12 +0200 Subject: [PATCH 064/115] [build] CMake: Fix GRAPHICS check (#4359) --- cmake/LibraryConfigurations.cmake | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cmake/LibraryConfigurations.cmake b/cmake/LibraryConfigurations.cmake index 6d2250c71..fb7898306 100644 --- a/cmake/LibraryConfigurations.cmake +++ b/cmake/LibraryConfigurations.cmake @@ -100,9 +100,10 @@ elseif ("${PLATFORM}" MATCHES "SDL") endif () if (NOT ${OPENGL_VERSION} MATCHES "OFF") - set(${SUGGESTED_GRAPHICS} "${GRAPHICS}") + set(SUGGESTED_GRAPHICS "${GRAPHICS}") + if (${OPENGL_VERSION} MATCHES "4.3") - set(GRAPHICS "GRAPHICS_API_OPENGL_43") + set(GRAPHICS "GRAPHICS_API_OPENGL_43") elseif (${OPENGL_VERSION} MATCHES "3.3") set(GRAPHICS "GRAPHICS_API_OPENGL_33") elseif (${OPENGL_VERSION} MATCHES "2.1") @@ -114,8 +115,8 @@ if (NOT ${OPENGL_VERSION} MATCHES "OFF") elseif (${OPENGL_VERSION} MATCHES "ES 3.0") set(GRAPHICS "GRAPHICS_API_OPENGL_ES3") endif () - if ("${SUGGESTED_GRAPHICS}" AND NOT "${SUGGESTED_GRAPHICS}" STREQUAL "${GRAPHICS}") - message(WARNING "You are overriding the suggested GRAPHICS=${SUGGESTED_GRAPHICS} with ${GRAPHICS}! This may fail") + if (NOT "${SUGGESTED_GRAPHICS}" STREQUAL "" AND NOT "${SUGGESTED_GRAPHICS}" STREQUAL "${GRAPHICS}") + message(WARNING "You are overriding the suggested GRAPHICS=${SUGGESTED_GRAPHICS} with ${GRAPHICS}! This may fail.") endif () endif () From da95f88c3641f8f27c5d531154fdd92c5232acc6 Mon Sep 17 00:00:00 2001 From: Anthony Carbajal <5776225+CrackedPixel@users.noreply.github.com> Date: Fri, 4 Oct 2024 04:15:43 -0500 Subject: [PATCH 065/115] updated camera speeds with GetFrameTime (#4362) --- src/rcamera.h | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/rcamera.h b/src/rcamera.h index c7f6fed3a..ccab549c1 100644 --- a/src/rcamera.h +++ b/src/rcamera.h @@ -444,11 +444,17 @@ void UpdateCamera(Camera *camera, int mode) bool lockView = ((mode == CAMERA_FREE) || (mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL)); bool rotateUp = false; + // Camera speeds based on frame time + float cameraMoveSpeed = CAMERA_MOVE_SPEED*GetFrameTime(); + float cameraRotationSpeed = CAMERA_ROTATION_SPEED*GetFrameTime(); + float cameraPanSpeed = CAMERA_PAN_SPEED*GetFrameTime(); + float cameraOrbitalSpeed = CAMERA_ORBITAL_SPEED*GetFrameTime(); + if (mode == CAMERA_CUSTOM) {} else if (mode == CAMERA_ORBITAL) { // Orbital can just orbit - Matrix rotation = MatrixRotate(GetCameraUp(camera), CAMERA_ORBITAL_SPEED*GetFrameTime()); + Matrix rotation = MatrixRotate(GetCameraUp(camera), cameraOrbitalSpeed); Vector3 view = Vector3Subtract(camera->position, camera->target); view = Vector3Transform(view, rotation); camera->position = Vector3Add(camera->target, view); @@ -456,22 +462,22 @@ void UpdateCamera(Camera *camera, int mode) 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); + if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -cameraRotationSpeed, lockView, rotateAroundTarget, rotateUp); + if (IsKeyDown(KEY_UP)) CameraPitch(camera, cameraRotationSpeed, lockView, rotateAroundTarget, rotateUp); + if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -cameraRotationSpeed, rotateAroundTarget); + if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, cameraRotationSpeed, rotateAroundTarget); + if (IsKeyDown(KEY_Q)) CameraRoll(camera, -cameraRotationSpeed); + if (IsKeyDown(KEY_E)) CameraRoll(camera, cameraRotationSpeed); // Camera movement // Camera pan (for CAMERA_FREE) if ((mode == CAMERA_FREE) && (IsMouseButtonDown(MOUSE_BUTTON_MIDDLE))) { const Vector2 mouseDelta = GetMouseDelta(); - if (mouseDelta.x > 0.0f) CameraMoveRight(camera, CAMERA_PAN_SPEED, moveInWorldPlane); - if (mouseDelta.x < 0.0f) CameraMoveRight(camera, -CAMERA_PAN_SPEED, moveInWorldPlane); - if (mouseDelta.y > 0.0f) CameraMoveUp(camera, -CAMERA_PAN_SPEED); - if (mouseDelta.y < 0.0f) CameraMoveUp(camera, CAMERA_PAN_SPEED); + if (mouseDelta.x > 0.0f) CameraMoveRight(camera, cameraPanSpeed, moveInWorldPlane); + if (mouseDelta.x < 0.0f) CameraMoveRight(camera, -cameraPanSpeed, moveInWorldPlane); + if (mouseDelta.y > 0.0f) CameraMoveUp(camera, -cameraPanSpeed); + if (mouseDelta.y < 0.0f) CameraMoveUp(camera, cameraPanSpeed); } else { @@ -481,7 +487,6 @@ void UpdateCamera(Camera *camera, int mode) } // Keyboard support - float cameraMoveSpeed = CAMERA_MOVE_SPEED*GetFrameTime(); if (IsKeyDown(KEY_W)) CameraMoveForward(camera, cameraMoveSpeed, moveInWorldPlane); if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -cameraMoveSpeed, moveInWorldPlane); if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -cameraMoveSpeed, moveInWorldPlane); From d06287d5624005a4edfe6ea7adbce0b8ce11dc8f Mon Sep 17 00:00:00 2001 From: Anthony Carbajal <5776225+CrackedPixel@users.noreply.github.com> Date: Fri, 4 Oct 2024 04:16:03 -0500 Subject: [PATCH 066/115] taken from FluxFlus PR (#4363) From f9e709915a2c3e9f75d0ad3bb3f55dcfe0fdbe23 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 4 Oct 2024 11:24:02 +0200 Subject: [PATCH 067/115] Fix #4355 --- src/platforms/rcore_desktop_glfw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index c6685846c..f7b94178c 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -1447,7 +1447,7 @@ int InitPlatform(void) } } - TRACELOG(LOG_WARNING, "SYSTEM: Closest fullscreen videomode: %i x %i", CORE.Window.display.width, CORE.Window.display.height); + TRACELOG(LOG_INFO, "SYSTEM: Closest fullscreen videomode: %i x %i", CORE.Window.display.width, CORE.Window.display.height); // NOTE: ISSUE: Closest videomode could not match monitor aspect-ratio, for example, // for a desired screen size of 800x450 (16:9), closest supported videomode is 800x600 (4:3), From 74ce90ce671fbcd0d31e26d7b13d142b8425de60 Mon Sep 17 00:00:00 2001 From: Magnus Oblerion <82583559+oblerion@users.noreply.github.com> Date: Sun, 6 Oct 2024 15:47:47 +0200 Subject: [PATCH 068/115] [example] Input virtual controls example (#4342) * Add files via upload * Update core_input_gamepad_virtual.c * Add files via upload * Update and rename core_input_gamepad_virtual.c to core_virtual_Dpad.c * Update and rename core_virtual_Dpad.c to core_input_virtual_controls.c * Delete examples/core/core_input_gamepad_virtual.png * Add files via upload * Update Makefile * Update Makefile.Web * Update README.md * Update README.md * Create core_input_virtual_controls.vcxproj * Delete projects/VS2022/examples/core_input_virtual_controls.vcxproj --- examples/Makefile | 1 + examples/Makefile.Web | 1 + examples/README.md | 245 +++++++++--------- examples/core/core_input_virtual_controls.c | 123 +++++++++ examples/core/core_input_virtual_controls.png | Bin 0 -> 9604 bytes 5 files changed, 248 insertions(+), 122 deletions(-) create mode 100644 examples/core/core_input_virtual_controls.c create mode 100644 examples/core/core_input_virtual_controls.png diff --git a/examples/Makefile b/examples/Makefile index c17258427..01c8e45d7 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -492,6 +492,7 @@ CORE = \ core/core_input_mouse \ core/core_input_mouse_wheel \ core/core_input_multitouch \ + core/core_input_virtual_controls \ core/core_loading_thread \ core/core_random_sequence \ core/core_random_values \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index bd48c2a4a..b176217ae 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -359,6 +359,7 @@ CORE = \ core/core_input_mouse \ core/core_input_mouse_wheel \ core/core_input_multitouch \ + core/core_input_virtual_controls \ core/core_loading_thread \ core/core_random_sequence \ core/core_random_values \ diff --git a/examples/README.md b/examples/README.md index d573ff23e..ee528d049 100644 --- a/examples/README.md +++ b/examples/README.md @@ -31,31 +31,32 @@ Examples using raylib core platform functionality like window creation, inputs, | 05 | [core_input_gamepad](core/core_input_gamepad.c) | core_input_gamepad | ⭐️☆☆☆ | 1.1 | **4.2** | [Ray](https://github.com/raysan5) | | 06 | [core_input_multitouch](core/core_input_multitouch.c) | core_input_multitouch | ⭐️☆☆☆ | 2.1 | 2.5 | [Berni](https://github.com/Berni8k) | | 07 | [core_input_gestures](core/core_input_gestures.c) | core_input_gestures | ⭐️⭐️☆☆ | 1.4 | **4.2** | [Ray](https://github.com/raysan5) | -| 08 | [core_2d_camera](core/core_2d_camera.c) | core_2d_camera | ⭐️⭐️☆☆ | 1.5 | 3.0 | [Ray](https://github.com/raysan5) | -| 09 | [core_2d_camera_mouse_zoom](core/core_2d_camera_mouse_zoom.c) | core_2d_camera_mouse_zoom | ⭐️⭐️☆☆ | **4.2** | **4.2** | [Jeffery Myers](https://github.com/JeffM2501) | -| 10 | [core_2d_camera_platformer](core/core_2d_camera_platformer.c) | core_2d_camera_platformer | ⭐️⭐️⭐️☆ | 2.5 | 3.0 | [avyy](https://github.com/avyy) | -| 11 | [core_2d_camera_split_screen](core/core_2d_camera_split_screen.c) | core_2d_camera_split_screen | ⭐️⭐️⭐️⭐️ | **4.5** | **4.5** | [Gabriel dos Santos Sanches](https://github.com/gabrielssanches) | -| 12 | [core_3d_camera_mode](core/core_3d_camera_mode.c) | core_3d_camera_mode | ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) | -| 13 | [core_3d_camera_free](core/core_3d_camera_free.c) | core_3d_camera_free | ⭐️☆☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) | -| 14 | [core_3d_camera_first_person](core/core_3d_camera_first_person.c) | core_3d_camera_first_person | ⭐️⭐️☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) | -| 15 | [core_3d_camera:split_screen](core/core_3d_camera_split_screen.c) | core_3d_camera_split_screen | ⭐️⭐️⭐️⭐️ | 3.7 | **4.0** | [Jeffery Myers](https://github.com/JeffM2501) | -| 16 | [core_3d_picking](core/core_3d_picking.c) | core_3d_picking | ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | -| 17 | [core_world_screen](core/core_world_screen.c) | core_world_screen | ⭐️⭐️☆☆ | 1.3 | 1.4 | [Ray](https://github.com/raysan5) | -| 18 | [core_custom_logging](core/core_custom_logging.c) | core_custom_logging | ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Pablo Marcos Oltra](https://github.com/pamarcos) | -| 19 | [core_window_flags](core/core_window_flags.c) | core_window_flags | ⭐️⭐️⭐️☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) | -| 20 | [core_window_letterbox](core/core_window_letterbox.c) | core_window_letterbox | ⭐️⭐️☆☆ | 2.5 | **4.0** | [Anata](https://github.com/anatagawa) | -| 21 | [core_window_should_close](core/core_window_should_close.c) | core_window_should_close | ⭐️☆☆☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) | -| 22 | [core_drop_files](core/core_drop_files.c) | core_drop_files | ⭐️⭐️☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) | -| 23 | [core_random_values](core/core_random_values.c) | core_random_values | ⭐️☆☆☆ | 1.1 | 1.1 | [Ray](https://github.com/raysan5) | -| 24 | [core_storage_values](core/core_storage_values.c) | core_storage_values | ⭐️⭐️☆☆ | 1.4 | **4.2** | [Ray](https://github.com/raysan5) | -| 25 | [core_vr_simulator](core/core_vr_simulator.c) | core_vr_simulator | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) | -| 26 | [core_loading_thread](core/core_loading_thread.c) | core_loading_thread | ⭐️⭐️⭐️☆ | 2.5 | 3.0 | [Ray](https://github.com/raysan5) | -| 27 | [core_scissor_test](core/core_scissor_test.c) | core_scissor_test | ⭐️☆☆☆ | 2.5 | 3.0 | [Chris Dill](https://github.com/MysteriousSpace) | -| 28 | [core_basic_screen_manager](core/core_basic_screen_manager.c) | core_basic_screen_manager | ⭐️☆☆☆ | **4.0** | **4.0** | [Ray](https://github.com/raysan5) | -| 29 | [core_custom_frame_control](core/core_custom_frame_control.c) | core_custom_frame_control | ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Ray](https://github.com/raysan5) | -| 30 | [core_smooth_pixelperfect](core/core_smooth_pixelperfect.c) | core_smooth_pixelperfect | ⭐️⭐️⭐️☆ | 3.7 | **4.0** | [Giancamillo Alessandroni](https://github.com/NotManyIdeasDev) | -| 31 | [core_window_should_close](core/core_window_should_close.c) | core_window_should_close | ⭐️⭐️☆☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) | -| 32 | [core_random_sequence](core/core_random_sequence.c) | core_random_sequence | ⭐️☆☆☆ | **5.0** | **5.0** | [REDl3east](https://github.com/REDl3east) | +| 08 | [core_input_virtual_controls](core/core_input_virtual_controls.c) | core_input_virtual_controls | ⭐️⭐️☆☆ | **5.0** | **5.0** | [oblerion](https://github.com/oblerion) | +| 09 | [core_2d_camera](core/core_2d_camera.c) | core_2d_camera | ⭐️⭐️☆☆ | 1.5 | 3.0 | [Ray](https://github.com/raysan5) | +| 10 | [core_2d_camera_mouse_zoom](core/core_2d_camera_mouse_zoom.c) | core_2d_camera_mouse_zoom | ⭐️⭐️☆☆ | **4.2** | **4.2** | [Jeffery Myers](https://github.com/JeffM2501) | +| 11 | [core_2d_camera_platformer](core/core_2d_camera_platformer.c) | core_2d_camera_platformer | ⭐️⭐️⭐️☆ | 2.5 | 3.0 | [avyy](https://github.com/avyy) | +| 12 | [core_2d_camera_split_screen](core/core_2d_camera_split_screen.c) | core_2d_camera_split_screen | ⭐️⭐️⭐️⭐️ | **4.5** | **4.5** | [Gabriel dos Santos Sanches](https://github.com/gabrielssanches) | +| 13 | [core_3d_camera_mode](core/core_3d_camera_mode.c) | core_3d_camera_mode | ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) | +| 14 | [core_3d_camera_free](core/core_3d_camera_free.c) | core_3d_camera_free | ⭐️☆☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) | +| 15 | [core_3d_camera_first_person](core/core_3d_camera_first_person.c) | core_3d_camera_first_person | ⭐️⭐️☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) | +| 16 | [core_3d_camera:split_screen](core/core_3d_camera_split_screen.c) | core_3d_camera_split_screen | ⭐️⭐️⭐️⭐️ | 3.7 | **4.0** | [Jeffery Myers](https://github.com/JeffM2501) | +| 17 | [core_3d_picking](core/core_3d_picking.c) | core_3d_picking | ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | +| 18 | [core_world_screen](core/core_world_screen.c) | core_world_screen | ⭐️⭐️☆☆ | 1.3 | 1.4 | [Ray](https://github.com/raysan5) | +| 19 | [core_custom_logging](core/core_custom_logging.c) | core_custom_logging | ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Pablo Marcos Oltra](https://github.com/pamarcos) | +| 20 | [core_window_flags](core/core_window_flags.c) | core_window_flags | ⭐️⭐️⭐️☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) | +| 21 | [core_window_letterbox](core/core_window_letterbox.c) | core_window_letterbox | ⭐️⭐️☆☆ | 2.5 | **4.0** | [Anata](https://github.com/anatagawa) | +| 22 | [core_window_should_close](core/core_window_should_close.c) | core_window_should_close | ⭐️☆☆☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) | +| 23 | [core_drop_files](core/core_drop_files.c) | core_drop_files | ⭐️⭐️☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) | +| 24 | [core_random_values](core/core_random_values.c) | core_random_values | ⭐️☆☆☆ | 1.1 | 1.1 | [Ray](https://github.com/raysan5) | +| 25 | [core_storage_values](core/core_storage_values.c) | core_storage_values | ⭐️⭐️☆☆ | 1.4 | **4.2** | [Ray](https://github.com/raysan5) | +| 26 | [core_vr_simulator](core/core_vr_simulator.c) | core_vr_simulator | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) | +| 27 | [core_loading_thread](core/core_loading_thread.c) | core_loading_thread | ⭐️⭐️⭐️☆ | 2.5 | 3.0 | [Ray](https://github.com/raysan5) | +| 28 | [core_scissor_test](core/core_scissor_test.c) | core_scissor_test | ⭐️☆☆☆ | 2.5 | 3.0 | [Chris Dill](https://github.com/MysteriousSpace) | +| 29 | [core_basic_screen_manager](core/core_basic_screen_manager.c) | core_basic_screen_manager | ⭐️☆☆☆ | **4.0** | **4.0** | [Ray](https://github.com/raysan5) | +| 30 | [core_custom_frame_control](core/core_custom_frame_control.c) | core_custom_frame_control | ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Ray](https://github.com/raysan5) | +| 31 | [core_smooth_pixelperfect](core/core_smooth_pixelperfect.c) | core_smooth_pixelperfect | ⭐️⭐️⭐️☆ | 3.7 | **4.0** | [Giancamillo Alessandroni](https://github.com/NotManyIdeasDev) | +| 32 | [core_window_should_close](core/core_window_should_close.c) | core_window_should_close | ⭐️⭐️☆☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) | +| 33 | [core_random_sequence](core/core_random_sequence.c) | core_random_sequence | ⭐️☆☆☆ | **5.0** | **5.0** | [REDl3east](https://github.com/REDl3east) | ### category: shapes @@ -63,22 +64,22 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes]( | ## | example | image | difficulty
level | version
created | last version
updated | original
developer | |----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------| -| 31 | [shapes_basic_shapes](shapes/shapes_basic_shapes.c) | shapes_basic_shapes | ⭐️☆☆☆ | 1.0 | **4.0** | [Ray](https://github.com/raysan5) | -| 32 | [shapes_bouncing_ball](shapes/shapes_bouncing_ball.c) | shapes_bouncing_ball | ⭐️☆☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) | -| 33 | [shapes_colors_palette](shapes/shapes_colors_palette.c) | shapes_colors_palette | ⭐️⭐️☆☆ | 1.0 | 2.5 | [Ray](https://github.com/raysan5) | -| 34 | [shapes_logo_raylib](shapes/shapes_logo_raylib.c) | shapes_logo_raylib | ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) | -| 35 | [shapes_logo_raylib_anim](shapes/shapes_logo_raylib_anim.c) | shapes_logo_raylib_anim | ⭐️⭐️☆☆ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) | -| 36 | [shapes_rectangle_scaling](shapes/shapes_rectangle_scaling.c) | shapes_rectangle_scaling | ⭐️⭐️☆☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) | -| 37 | [shapes_lines_bezier](shapes/shapes_lines_bezier.c) | shapes_lines_bezier | ⭐️☆☆☆ | 1.7 | 1.7 | [Ray](https://github.com/raysan5) | -| 38 | [shapes_collision_area](shapes/shapes_collision_area.c) | shapes_collision_area | ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) | -| 39 | [shapes_following_eyes](shapes/shapes_following_eyes.c) | shapes_following_eyes | ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) | -| 40 | [shapes_easings_ball_anim](shapes/shapes_easings_ball_anim.c) | shapes_easings_ball_anim | ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) | -| 41 | [shapes_easings_box_anim](shapes/shapes_easings_box_anim.c) | shapes_easings_box_anim | ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) | -| 42 | [shapes_easings_rectangle_array](shapes/shapes_easings_rectangle_array.c) | shapes_easings_rectangle_array | ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) | -| 43 | [shapes_draw_ring](shapes/shapes_draw_ring.c) | shapes_draw_ring | ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) | -| 44 | [shapes_draw_circle_sector](shapes/shapes_draw_circle_sector.c) | shapes_draw_circle_sector | ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) | -| 45 | [shapes_draw_rectangle_rounded](shapes/shapes_draw_rectangle_rounded.c) | shapes_draw_rectangle_rounded | ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) | -| 46 | [shapes_top_down_lights](shapes/shapes_top_down_lights.c) | shapes_top_down_lights | ⭐️⭐️⭐️⭐️ | **4.2** | **4.2** | [Jeffery Myers](https://github.com/JeffM2501) | +| 34 | [shapes_basic_shapes](shapes/shapes_basic_shapes.c) | shapes_basic_shapes | ⭐️☆☆☆ | 1.0 | **4.0** | [Ray](https://github.com/raysan5) | +| 35 | [shapes_bouncing_ball](shapes/shapes_bouncing_ball.c) | shapes_bouncing_ball | ⭐️☆☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) | +| 36 | [shapes_colors_palette](shapes/shapes_colors_palette.c) | shapes_colors_palette | ⭐️⭐️☆☆ | 1.0 | 2.5 | [Ray](https://github.com/raysan5) | +| 37 | [shapes_logo_raylib](shapes/shapes_logo_raylib.c) | shapes_logo_raylib | ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) | +| 38 | [shapes_logo_raylib_anim](shapes/shapes_logo_raylib_anim.c) | shapes_logo_raylib_anim | ⭐️⭐️☆☆ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) | +| 39 | [shapes_rectangle_scaling](shapes/shapes_rectangle_scaling.c) | shapes_rectangle_scaling | ⭐️⭐️☆☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) | +| 40 | [shapes_lines_bezier](shapes/shapes_lines_bezier.c) | shapes_lines_bezier | ⭐️☆☆☆ | 1.7 | 1.7 | [Ray](https://github.com/raysan5) | +| 41 | [shapes_collision_area](shapes/shapes_collision_area.c) | shapes_collision_area | ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) | +| 42 | [shapes_following_eyes](shapes/shapes_following_eyes.c) | shapes_following_eyes | ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) | +| 43 | [shapes_easings_ball_anim](shapes/shapes_easings_ball_anim.c) | shapes_easings_ball_anim | ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) | +| 44 | [shapes_easings_box_anim](shapes/shapes_easings_box_anim.c) | shapes_easings_box_anim | ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) | +| 45 | [shapes_easings_rectangle_array](shapes/shapes_easings_rectangle_array.c) | shapes_easings_rectangle_array | ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) | +| 46 | [shapes_draw_ring](shapes/shapes_draw_ring.c) | shapes_draw_ring | ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) | +| 47 | [shapes_draw_circle_sector](shapes/shapes_draw_circle_sector.c) | shapes_draw_circle_sector | ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) | +| 48 | [shapes_draw_rectangle_rounded](shapes/shapes_draw_rectangle_rounded.c) | shapes_draw_rectangle_rounded | ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) | +| 49 | [shapes_top_down_lights](shapes/shapes_top_down_lights.c) | shapes_top_down_lights | ⭐️⭐️⭐️⭐️ | **4.2** | **4.2** | [Jeffery Myers](https://github.com/JeffM2501) | ### category: textures @@ -86,28 +87,28 @@ Examples using raylib textures functionality, including image/textures loading/g | ## | example | image | difficulty
level | version
created | last version
updated | original
developer | |----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------| -| 47 | [textures_logo_raylib](textures/textures_logo_raylib.c) | textures_logo_raylib | ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) | -| 48 | [textures_srcrec_dstrec](textures/textures_srcrec_dstrec.c) | textures_srcrec_dstrec | ⭐️⭐️⭐️☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) | -| 49 | [textures_image_drawing](textures/textures_image_drawing.c) | textures_image_drawing | ⭐️⭐️☆☆ | 1.4 | 1.4 | [Ray](https://github.com/raysan5) | -| 50 | [textures_image_generation](textures/textures_image_generation.c) | textures_image_generation | ⭐️⭐️☆☆ | 1.8 | 1.8 | [Ray](https://github.com/raysan5) | -| 51 | [textures_image_loading](textures/textures_image_loading.c) | textures_image_loading | ⭐️☆☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) | -| 52 | [textures_image_processing](textures/textures_image_processing.c) | textures_image_processing | ⭐️⭐️⭐️☆ | 1.4 | 3.5 | [Ray](https://github.com/raysan5) | -| 53 | [textures_image_text](textures/textures_image_text.c) | textures_image_text | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) | -| 54 | [textures_to_image](textures/textures_to_image.c) | textures_to_image | ⭐️☆☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | -| 55 | [textures_raw_data](textures/textures_raw_data.c) | textures_raw_data | ⭐️⭐️⭐️☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) | -| 56 | [textures_particles_blending](textures/textures_particles_blending.c) | textures_particles_blending | ⭐️☆☆☆ | 1.7 | 3.5 | [Ray](https://github.com/raysan5) | -| 57 | [textures_npatch_drawing](textures/textures_npatch_drawing.c) | textures_npatch_drawing | ⭐️⭐️⭐️☆ | 2.0 | 2.5 | [Jorge A. Gomes](https://github.com/overdev) | -| 58 | [textures_background_scrolling](textures/textures_background_scrolling.c) | textures_background_scrolling | ⭐️☆☆☆ | 2.0 | 2.5 | [Ray](https://github.com/raysan5) | -| 59 | [textures_sprite_anim](textures/textures_sprite_anim.c) | textures_sprite_anim | ⭐️⭐️☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) | -| 60 | [textures_sprite_button](textures/textures_sprite_button.c) | textures_sprite_button | ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) | -| 61 | [textures_sprite_explosion](textures/textures_sprite_explosion.c) | textures_sprite_explosion | ⭐️⭐️☆☆ | 2.5 | 3.5 | [Ray](https://github.com/raysan5) | -| 62 | [textures_bunnymark](textures/textures_bunnymark.c) | textures_bunnymark | ⭐️⭐️⭐️☆ | 1.6 | 2.5 | [Ray](https://github.com/raysan5) | -| 63 | [textures_mouse_painting](textures/textures_mouse_painting.c) | textures_mouse_painting | ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Chris Dill](https://github.com/MysteriousSpace) | -| 64 | [textures_blend_modes](textures/textures_blend_modes.c) | textures_blend_modes | ⭐️☆☆☆ | 3.5 | 3.5 | [Karlo Licudine](https://github.com/accidentalrebel) | -| 65 | [textures_draw_tiled](textures/textures_draw_tiled.c) | textures_draw_tiled | ⭐️⭐️⭐️☆ | 3.0 | **4.2** | [Vlad Adrian](https://github.com/demizdor) | -| 66 | [textures_polygon](textures/textures_polygon.c) | textures_polygon | ⭐️☆☆☆ | 3.7 | 3.7 | [Chris Camacho](https://github.com/codifies) | -| 67 | [textures_fog_of_war](textures/textures_fog_of_war.c) | textures_fog_of_war | ⭐️⭐️⭐️☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) | -| 68 | [textures_gif_player](textures/textures_gif_player.c) | textures_gif_player | ⭐️⭐️⭐️☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) | +| 50 | [textures_logo_raylib](textures/textures_logo_raylib.c) | textures_logo_raylib | ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) | +| 51 | [textures_srcrec_dstrec](textures/textures_srcrec_dstrec.c) | textures_srcrec_dstrec | ⭐️⭐️⭐️☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) | +| 52 | [textures_image_drawing](textures/textures_image_drawing.c) | textures_image_drawing | ⭐️⭐️☆☆ | 1.4 | 1.4 | [Ray](https://github.com/raysan5) | +| 53 | [textures_image_generation](textures/textures_image_generation.c) | textures_image_generation | ⭐️⭐️☆☆ | 1.8 | 1.8 | [Ray](https://github.com/raysan5) | +| 54 | [textures_image_loading](textures/textures_image_loading.c) | textures_image_loading | ⭐️☆☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) | +| 55 | [textures_image_processing](textures/textures_image_processing.c) | textures_image_processing | ⭐️⭐️⭐️☆ | 1.4 | 3.5 | [Ray](https://github.com/raysan5) | +| 56 | [textures_image_text](textures/textures_image_text.c) | textures_image_text | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) | +| 57 | [textures_to_image](textures/textures_to_image.c) | textures_to_image | ⭐️☆☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | +| 58 | [textures_raw_data](textures/textures_raw_data.c) | textures_raw_data | ⭐️⭐️⭐️☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) | +| 59 | [textures_particles_blending](textures/textures_particles_blending.c) | textures_particles_blending | ⭐️☆☆☆ | 1.7 | 3.5 | [Ray](https://github.com/raysan5) | +| 60 | [textures_npatch_drawing](textures/textures_npatch_drawing.c) | textures_npatch_drawing | ⭐️⭐️⭐️☆ | 2.0 | 2.5 | [Jorge A. Gomes](https://github.com/overdev) | +| 61 | [textures_background_scrolling](textures/textures_background_scrolling.c) | textures_background_scrolling | ⭐️☆☆☆ | 2.0 | 2.5 | [Ray](https://github.com/raysan5) | +| 62 | [textures_sprite_anim](textures/textures_sprite_anim.c) | textures_sprite_anim | ⭐️⭐️☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) | +| 63 | [textures_sprite_button](textures/textures_sprite_button.c) | textures_sprite_button | ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) | +| 64 | [textures_sprite_explosion](textures/textures_sprite_explosion.c) | textures_sprite_explosion | ⭐️⭐️☆☆ | 2.5 | 3.5 | [Ray](https://github.com/raysan5) | +| 65 | [textures_bunnymark](textures/textures_bunnymark.c) | textures_bunnymark | ⭐️⭐️⭐️☆ | 1.6 | 2.5 | [Ray](https://github.com/raysan5) | +| 66 | [textures_mouse_painting](textures/textures_mouse_painting.c) | textures_mouse_painting | ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Chris Dill](https://github.com/MysteriousSpace) | +| 67 | [textures_blend_modes](textures/textures_blend_modes.c) | textures_blend_modes | ⭐️☆☆☆ | 3.5 | 3.5 | [Karlo Licudine](https://github.com/accidentalrebel) | +| 68 | [textures_draw_tiled](textures/textures_draw_tiled.c) | textures_draw_tiled | ⭐️⭐️⭐️☆ | 3.0 | **4.2** | [Vlad Adrian](https://github.com/demizdor) | +| 69 | [textures_polygon](textures/textures_polygon.c) | textures_polygon | ⭐️☆☆☆ | 3.7 | 3.7 | [Chris Camacho](https://github.com/codifies) | +| 70 | [textures_fog_of_war](textures/textures_fog_of_war.c) | textures_fog_of_war | ⭐️⭐️⭐️☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) | +| 71 | [textures_gif_player](textures/textures_gif_player.c) | textures_gif_player | ⭐️⭐️⭐️☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) | ### category: text @@ -115,18 +116,18 @@ Examples using raylib text functionality, including sprite fonts loading/generat | ## | example | image | difficulty
level | version
created | last version
updated | original
developer | |----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------| -| 69 | [text_raylib_fonts](text/text_raylib_fonts.c) | text_raylib_fonts | ⭐️☆☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) | -| 70 | [text_font_spritefont](text/text_font_spritefont.c) | text_font_spritefont | ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) | -| 71 | [text_font_filters](text/text_font_filters.c) | text_font_filters | ⭐️⭐️☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) | -| 72 | [text_font_loading](text/text_font_loading.c) | text_font_loading | ⭐️☆☆☆ | 1.4 | 3.0 | [Ray](https://github.com/raysan5) | -| 73 | [text_font_sdf](text/text_font_sdf.c) | text_font_sdf | ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | -| 74 | [text_format_text](text/text_format_text.c) | text_format_text | ⭐️☆☆☆ | 1.1 | 3.0 | [Ray](https://github.com/raysan5) | -| 75 | [text_input_box](text/text_input_box.c) | text_input_box | ⭐️⭐️☆☆ | 1.7 | 3.5 | [Ray](https://github.com/raysan5) | -| 76 | [text_writing_anim](text/text_writing_anim.c) | text_writing_anim | ⭐️⭐️☆☆ | 1.4 | 1.4 | [Ray](https://github.com/raysan5) | -| 77 | [text_rectangle_bounds](text/text_rectangle_bounds.c) | text_rectangle_bounds | ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Vlad Adrian](https://github.com/demizdor) | -| 78 | [text_unicode](text/text_unicode.c) | text_unicode | ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Vlad Adrian](https://github.com/demizdor) | -| 79 | [text_draw_3d](text/text_draw_3d.c) | text_draw_3d | ⭐️⭐️⭐️⭐️ | 3.5 | **4.0** | [Vlad Adrian](https://github.com/demizdor) | -| 80 | [text_codepoints_loading](text/text_codepoints_loading.c) | text_codepoints_loading | ⭐️⭐️⭐️☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) | +| 72 | [text_raylib_fonts](text/text_raylib_fonts.c) | text_raylib_fonts | ⭐️☆☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) | +| 73 | [text_font_spritefont](text/text_font_spritefont.c) | text_font_spritefont | ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) | +| 74 | [text_font_filters](text/text_font_filters.c) | text_font_filters | ⭐️⭐️☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) | +| 75 | [text_font_loading](text/text_font_loading.c) | text_font_loading | ⭐️☆☆☆ | 1.4 | 3.0 | [Ray](https://github.com/raysan5) | +| 76 | [text_font_sdf](text/text_font_sdf.c) | text_font_sdf | ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | +| 77 | [text_format_text](text/text_format_text.c) | text_format_text | ⭐️☆☆☆ | 1.1 | 3.0 | [Ray](https://github.com/raysan5) | +| 78 | [text_input_box](text/text_input_box.c) | text_input_box | ⭐️⭐️☆☆ | 1.7 | 3.5 | [Ray](https://github.com/raysan5) | +| 79 | [text_writing_anim](text/text_writing_anim.c) | text_writing_anim | ⭐️⭐️☆☆ | 1.4 | 1.4 | [Ray](https://github.com/raysan5) | +| 80 | [text_rectangle_bounds](text/text_rectangle_bounds.c) | text_rectangle_bounds | ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Vlad Adrian](https://github.com/demizdor) | +| 81 | [text_unicode](text/text_unicode.c) | text_unicode | ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Vlad Adrian](https://github.com/demizdor) | +| 82 | [text_draw_3d](text/text_draw_3d.c) | text_draw_3d | ⭐️⭐️⭐️⭐️ | 3.5 | **4.0** | [Vlad Adrian](https://github.com/demizdor) | +| 83 | [text_codepoints_loading](text/text_codepoints_loading.c) | text_codepoints_loading | ⭐️⭐️⭐️☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) | ### category: models @@ -134,25 +135,25 @@ Examples using raylib models functionality, including models loading/generation | ## | example | image | difficulty
level | version
created | last version
updated | original
developer | |----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------| -| 81 | [models_animation](models/models_animation.c) | models_animation | ⭐️⭐️☆☆ | 2.5 | 3.5 | [culacant](https://github.com/culacant) | -| 82 | [models_billboard](models/models_billboard.c) | models_billboard | ⭐️⭐️⭐️☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) | -| 83 | [models_box_collisions](models/models_box_collisions.c) | models_box_collisions | ⭐️☆☆☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) | -| 84 | [models_cubicmap](models/models_cubicmap.c) | models_cubicmap | ⭐️⭐️☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) | -| 85 | [models_first_person_maze](models/models_first_person_maze.c) | models_first_person_maze | ⭐️⭐️☆☆ | 2.5 | 3.5 | [Ray](https://github.com/raysan5) | -| 86 | [models_geometric_shapes](models/models_geometric_shapes.c) | models_geometric_shapes | ⭐️☆☆☆ | 1.0 | 3.5 | [Ray](https://github.com/raysan5) | -| 87 | [models_mesh_generation](models/models_mesh_generation.c) | models_mesh_generation | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) | -| 88 | [models_mesh_picking](models/models_mesh_picking.c) | models_mesh_picking | ⭐️⭐️⭐️☆ | 1.7 | **4.0** | [Joel Davis](https://github.com/joeld42) | -| 89 | [models_loading](models/models_loading.c) | models_loading | ⭐️☆☆☆ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) | -| 90 | [models_loading_gltf](models/models_loading_gltf.c) | models_loading_gltf | ⭐️☆☆☆ | 3.7 | **4.2** | [Ray](https://github.com/raysan5) | -| 91 | [models_loading_vox](models/models_loading_vox.c) | models_loading_vox | ⭐️☆☆☆ | **4.0** | **4.0** | [Johann Nadalutti](https://github.com/procfxgen) | -| 92 | [models_loading_m3d](models/models_loading_m3d.c) | models_loading_m3d | ⭐️☆☆☆ | **4.2** | **4.2** | [bzt](https://bztsrc.gitlab.io/model3d) | -| 93 | [models_orthographic_projection](models/models_orthographic_projection.c) | models_orthographic_projection | ⭐️☆☆☆ | 2.0 | 3.7 | [Max Danielsson](https://github.com/autious) | -| 94 | [models_point_rendering](models/models_point_rendering.c) | models_point_rendering | ⭐️⭐️☆☆ | 5.0 | 5.0 | [Reese Gallagher](https://github.com/satchelfrost) | -| 95 | [models_rlgl_solar_system](models/models_rlgl_solar_system.c) | models_rlgl_solar_system | ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) | -| 96 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) | models_yaw_pitch_roll | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Berni](https://github.com/Berni8k) | -| 97 | [models_waving_cubes](models/models_waving_cubes.c) | models_waving_cubes | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [codecat](https://github.com/codecat) | -| 98 | [models_heightmap](models/models_heightmap.c) | models_heightmap | ⭐️☆☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) | -| 99 | [models_skybox](models/models_skybox.c) | models_skybox | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) | +| 84 | [models_animation](models/models_animation.c) | models_animation | ⭐️⭐️☆☆ | 2.5 | 3.5 | [culacant](https://github.com/culacant) | +| 85 | [models_billboard](models/models_billboard.c) | models_billboard | ⭐️⭐️⭐️☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) | +| 86 | [models_box_collisions](models/models_box_collisions.c) | models_box_collisions | ⭐️☆☆☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) | +| 87 | [models_cubicmap](models/models_cubicmap.c) | models_cubicmap | ⭐️⭐️☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) | +| 88 | [models_first_person_maze](models/models_first_person_maze.c) | models_first_person_maze | ⭐️⭐️☆☆ | 2.5 | 3.5 | [Ray](https://github.com/raysan5) | +| 89 | [models_geometric_shapes](models/models_geometric_shapes.c) | models_geometric_shapes | ⭐️☆☆☆ | 1.0 | 3.5 | [Ray](https://github.com/raysan5) | +| 90 | [models_mesh_generation](models/models_mesh_generation.c) | models_mesh_generation | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) | +| 91 | [models_mesh_picking](models/models_mesh_picking.c) | models_mesh_picking | ⭐️⭐️⭐️☆ | 1.7 | **4.0** | [Joel Davis](https://github.com/joeld42) | +| 92 | [models_loading](models/models_loading.c) | models_loading | ⭐️☆☆☆ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) | +| 93 | [models_loading_gltf](models/models_loading_gltf.c) | models_loading_gltf | ⭐️☆☆☆ | 3.7 | **4.2** | [Ray](https://github.com/raysan5) | +| 94 | [models_loading_vox](models/models_loading_vox.c) | models_loading_vox | ⭐️☆☆☆ | **4.0** | **4.0** | [Johann Nadalutti](https://github.com/procfxgen) | +| 95 | [models_loading_m3d](models/models_loading_m3d.c) | models_loading_m3d | ⭐️☆☆☆ | **4.2** | **4.2** | [bzt](https://bztsrc.gitlab.io/model3d) | +| 96 | [models_orthographic_projection](models/models_orthographic_projection.c) | models_orthographic_projection | ⭐️☆☆☆ | 2.0 | 3.7 | [Max Danielsson](https://github.com/autious) | +| 97 | [models_point_rendering](models/models_point_rendering.c) | models_point_rendering | ⭐️⭐️☆☆ | 5.0 | 5.0 | [Reese Gallagher](https://github.com/satchelfrost) | +| 98 | [models_rlgl_solar_system](models/models_rlgl_solar_system.c) | models_rlgl_solar_system | ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) | +| 99 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) | models_yaw_pitch_roll | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Berni](https://github.com/Berni8k) | +| 100 | [models_waving_cubes](models/models_waving_cubes.c) | models_waving_cubes | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [codecat](https://github.com/codecat) | +| 101 | [models_heightmap](models/models_heightmap.c) | models_heightmap | ⭐️☆☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) | +| 102 | [models_skybox](models/models_skybox.c) | models_skybox | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) | ### category: shaders @@ -160,25 +161,25 @@ Examples using raylib shaders functionality, including shaders loading, paramete | ## | example | image | difficulty
level | version
created | last version
updated | original
developer | |----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------| -| 100 | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) | shaders_basic_lighting | ⭐️⭐️⭐️⭐️ | 3.0 | **4.2** | [Chris Camacho](https://github.com/codifies) | -| 101 | [shaders_model_shader](shaders/shaders_model_shader.c) | shaders_model_shader | ⭐️⭐️☆☆ | 1.3 | 3.7 | [Ray](https://github.com/raysan5) | -| 102 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) | shaders_shapes_textures | ⭐️⭐️☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) | -| 103 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) | shaders_custom_uniform | ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | -| 104 | [shaders_postprocessing](shaders/shaders_postprocessing.c) | shaders_postprocessing | ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | -| 105 | [shaders_palette_switch](shaders/shaders_palette_switch.c) | shaders_palette_switch | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Marco Lizza](https://github.com/MarcoLizza) | -| 106 | [shaders_raymarching](shaders/shaders_raymarching.c) | shaders_raymarching | ⭐️⭐️⭐️⭐️ | 2.0 | **4.2** | [Ray](https://github.com/raysan5) | -| 107 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) | shaders_texture_drawing | ⭐️⭐️☆☆ | 2.0 | 3.7 | [Michał Ciesielski](https://github.com/) | -| 108 | [shaders_texture_outline](shaders/shaders_texture_outline.c) | shaders_texture_outline | ⭐️⭐️⭐️☆ | **4.0** | **4.0** | [Samuel Skiff](https://github.com/GoldenThumbs) | -| 109 | [shaders_texture_waves](shaders/shaders_texture_waves.c) | shaders_texture_waves | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) | -| 110 | [shaders_julia_set](shaders/shaders_julia_set.c) | shaders_julia_set | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [eggmund](https://github.com/eggmund) | -| 111 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) | shaders_eratosthenes | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [ProfJski](https://github.com/ProfJski) | -| 112 | [shaders_fog](shaders/shaders_fog.c) | shaders_fog | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | -| 113 | [shaders_simple_mask](shaders/shaders_simple_mask.c) | shaders_simple_mask | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | -| 114 | [shaders_hot_reloading](shaders/shaders_hot_reloading.c) | shaders_hot_reloading | ⭐️⭐️⭐️☆ | 3.0 | 3.5 | [Ray](https://github.com/raysan5) | -| 115 | [shaders_mesh_instancing](shaders/shaders_mesh_instancing.c) | shaders_mesh_instancing | ⭐️⭐️⭐️⭐️ | 3.7 | **4.2** | [seanpringle](https://github.com/seanpringle) | -| 116 | [shaders_multi_sample2d](shaders/shaders_multi_sample2d.c) | shaders_multi_sample2d | ⭐️⭐️☆☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) | -| 117 | [shaders_spotlight](shaders/shaders_spotlight.c) | shaders_spotlight | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | -| 118 | [shaders_deferred_render](shaders/shaders_deferred_render.c) | shaders_deferred_render | ⭐️⭐️⭐️⭐️ | 4.5 | 4.5 | [Justin Andreas Lacoste](https://github.com/27justin) | +| 103 | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) | shaders_basic_lighting | ⭐️⭐️⭐️⭐️ | 3.0 | **4.2** | [Chris Camacho](https://github.com/codifies) | +| 104 | [shaders_model_shader](shaders/shaders_model_shader.c) | shaders_model_shader | ⭐️⭐️☆☆ | 1.3 | 3.7 | [Ray](https://github.com/raysan5) | +| 105 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) | shaders_shapes_textures | ⭐️⭐️☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) | +| 106 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) | shaders_custom_uniform | ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | +| 107 | [shaders_postprocessing](shaders/shaders_postprocessing.c) | shaders_postprocessing | ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | +| 108 | [shaders_palette_switch](shaders/shaders_palette_switch.c) | shaders_palette_switch | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Marco Lizza](https://github.com/MarcoLizza) | +| 109 | [shaders_raymarching](shaders/shaders_raymarching.c) | shaders_raymarching | ⭐️⭐️⭐️⭐️ | 2.0 | **4.2** | [Ray](https://github.com/raysan5) | +| 110 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) | shaders_texture_drawing | ⭐️⭐️☆☆ | 2.0 | 3.7 | [Michał Ciesielski](https://github.com/) | +| 111 | [shaders_texture_outline](shaders/shaders_texture_outline.c) | shaders_texture_outline | ⭐️⭐️⭐️☆ | **4.0** | **4.0** | [Samuel Skiff](https://github.com/GoldenThumbs) | +| 112 | [shaders_texture_waves](shaders/shaders_texture_waves.c) | shaders_texture_waves | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) | +| 113 | [shaders_julia_set](shaders/shaders_julia_set.c) | shaders_julia_set | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [eggmund](https://github.com/eggmund) | +| 114 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) | shaders_eratosthenes | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [ProfJski](https://github.com/ProfJski) | +| 115 | [shaders_fog](shaders/shaders_fog.c) | shaders_fog | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | +| 116 | [shaders_simple_mask](shaders/shaders_simple_mask.c) | shaders_simple_mask | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | +| 117 | [shaders_hot_reloading](shaders/shaders_hot_reloading.c) | shaders_hot_reloading | ⭐️⭐️⭐️☆ | 3.0 | 3.5 | [Ray](https://github.com/raysan5) | +| 118 | [shaders_mesh_instancing](shaders/shaders_mesh_instancing.c) | shaders_mesh_instancing | ⭐️⭐️⭐️⭐️ | 3.7 | **4.2** | [seanpringle](https://github.com/seanpringle) | +| 119 | [shaders_multi_sample2d](shaders/shaders_multi_sample2d.c) | shaders_multi_sample2d | ⭐️⭐️☆☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) | +| 120 | [shaders_spotlight](shaders/shaders_spotlight.c) | shaders_spotlight | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | +| 121 | [shaders_deferred_render](shaders/shaders_deferred_render.c) | shaders_deferred_render | ⭐️⭐️⭐️⭐️ | 4.5 | 4.5 | [Justin Andreas Lacoste](https://github.com/27justin) | ### category: audio @@ -186,10 +187,10 @@ Examples using raylib audio functionality, including sound/music loading and pla | ## | example | image | difficulty
level | version
created | last version
updated | original
developer | |----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------| -| 119 | [audio_module_playing](audio/audio_module_playing.c) | audio_module_playing | ⭐️☆☆☆ | 1.5 | 3.5 | [Ray](https://github.com/raysan5) | -| 120 | [audio_music_stream](audio/audio_music_stream.c) | audio_music_stream | ⭐️☆☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) | -| 121 | [audio_raw_stream](audio/audio_raw_stream.c) | audio_raw_stream | ⭐️⭐️⭐️☆ | 1.6 | **4.2** | [Ray](https://github.com/raysan5) | -| 122 | [audio_sound_loading](audio/audio_sound_loading.c) | audio_sound_loading | ⭐️☆☆☆ | 1.1 | 3.5 | [Ray](https://github.com/raysan5) | +| 122 | [audio_module_playing](audio/audio_module_playing.c) | audio_module_playing | ⭐️☆☆☆ | 1.5 | 3.5 | [Ray](https://github.com/raysan5) | +| 123 | [audio_music_stream](audio/audio_music_stream.c) | audio_music_stream | ⭐️☆☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) | +| 124 | [audio_raw_stream](audio/audio_raw_stream.c) | audio_raw_stream | ⭐️⭐️⭐️☆ | 1.6 | **4.2** | [Ray](https://github.com/raysan5) | +| 125 | [audio_sound_loading](audio/audio_sound_loading.c) | audio_sound_loading | ⭐️☆☆☆ | 1.1 | 3.5 | [Ray](https://github.com/raysan5) | ### category: others @@ -197,11 +198,11 @@ Examples showing raylib misc functionality that does not fit in other categories | ## | example | image | difficulty
level | version
created | last version
updated | original
developer | |----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------| -| 123 | [rlgl_standalone](others/rlgl_standalone.c) | rlgl_standalone | ⭐️⭐️⭐️⭐️ | 1.6 | **4.0** | [Ray](https://github.com/raysan5) | -| 124 | [rlgl_compute_shader](others/rlgl_compute_shader.c) | rlgl_compute_shader | ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Teddy Astie](https://github.com/tsnake41) | -| 125 | [easings_testbed](others/easings_testbed.c) | easings_testbed | ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Juan Miguel López](https://github.com/flashback-fx) | -| 126 | [raylib_opengl_interop](others/raylib_opengl_interop.c) | raylib_opengl_interop | ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Stephan Soller](https://github.com/arkanis) | -| 127 | [embedded_files_loading](others/embedded_files_loading.c) | embedded_files_loading | ⭐️⭐️☆☆ | 3.5 | 3.5 | [Kristian Holmgren](https://github.com/defutura) | +| 126 | [rlgl_standalone](others/rlgl_standalone.c) | rlgl_standalone | ⭐️⭐️⭐️⭐️ | 1.6 | **4.0** | [Ray](https://github.com/raysan5) | +| 127 | [rlgl_compute_shader](others/rlgl_compute_shader.c) | rlgl_compute_shader | ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Teddy Astie](https://github.com/tsnake41) | +| 128 | [easings_testbed](others/easings_testbed.c) | easings_testbed | ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Juan Miguel López](https://github.com/flashback-fx) | +| 129 | [raylib_opengl_interop](others/raylib_opengl_interop.c) | raylib_opengl_interop | ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Stephan Soller](https://github.com/arkanis) | +| 130 | [embedded_files_loading](others/embedded_files_loading.c) | embedded_files_loading | ⭐️⭐️☆☆ | 3.5 | 3.5 | [Kristian Holmgren](https://github.com/defutura) | As always contributions are welcome, feel free to send new examples! Here is an [examples template](examples_template.c) to start with! diff --git a/examples/core/core_input_virtual_controls.c b/examples/core/core_input_virtual_controls.c new file mode 100644 index 000000000..ae7f770aa --- /dev/null +++ b/examples/core/core_input_virtual_controls.c @@ -0,0 +1,123 @@ +/******************************************************************************************* +* +* raylib [core] example - input virtual controls +* +* Example originally created with raylib 5.0, last time updated with raylib 5.0 +* +* Example create by GreenSnakeLinux (@GreenSnakeLinux), +* lighter by oblerion (@oblerion) and +* reviewed by Ramon Santamaria (@raysan5) +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2024 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" +#include +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - input virtual controls"); + + const int dpadX = 90; + const int dpadY = 300; + const int dpadRad = 25;//radius of each pad + Color dpadColor = BLUE; + int dpadKeydown = -1;//-1 if not down, else 0,1,2,3 + + + const float dpadCollider[4][2]= // collider array with x,y position + { + {dpadX,dpadY-dpadRad*1.5},//up + {dpadX-dpadRad*1.5,dpadY},//left + {dpadX+dpadRad*1.5,dpadY},//right + {dpadX,dpadY+dpadRad*1.5}//down + }; + const char dpadLabel[4]="XYBA";//label of Dpad + + float playerX=100; + float playerY=100; + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //-------------------------------------------------------------------------- + dpadKeydown = -1; //reset + float inputX=0; + float inputY=0; + if(GetTouchPointCount()>0) + {//use touch pos + inputX = GetTouchX(); + inputY = GetTouchY(); + } + else + {//use mouse pos + inputX = GetMouseX(); + inputY = GetMouseY(); + } + for(int i=0;i<4;i++) + { + //test distance each collider and input < radius + if( fabsf(dpadCollider[i][1]-inputY) + fabsf(dpadCollider[i][0]-inputX) < dpadRad) + { + dpadKeydown = i; + break; + } + } + // move player + switch(dpadKeydown){ + case 0: playerY -= 50*GetFrameTime(); + break; + case 1: playerX -= 50*GetFrameTime(); + break; + case 2: playerX += 50*GetFrameTime(); + break; + case 3: playerY += 50*GetFrameTime(); + default:; + }; + //-------------------------------------------------------------------------- + + // Draw + //-------------------------------------------------------------------------- + BeginDrawing(); + ClearBackground(RAYWHITE); + for(int i=0;i<4;i++) + { + //draw all pad + DrawCircle(dpadCollider[i][0],dpadCollider[i][1],dpadRad,dpadColor); + if(i!=dpadKeydown) + { + //draw label + DrawText(TextSubtext(dpadLabel,i,1), + dpadCollider[i][0]-5, + dpadCollider[i][1]-5,16,BLACK); + } + + } + DrawText("Player",playerX,playerY,16,BLACK); + EndDrawing(); + //-------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + diff --git a/examples/core/core_input_virtual_controls.png b/examples/core/core_input_virtual_controls.png new file mode 100644 index 0000000000000000000000000000000000000000..a9776e68a3dfdd01f5b8afc51859ace27a150622 GIT binary patch literal 9604 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 NdAj Date: Sun, 6 Oct 2024 08:52:01 -0500 Subject: [PATCH 069/115] [zig] Fix build.zig bug (#4366) * fixed zig config.h bug * zig fmt --- src/build.zig | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/build.zig b/src/build.zig index b08b909de..71729e4d2 100644 --- a/src/build.zig +++ b/src/build.zig @@ -47,7 +47,7 @@ fn setDesktopPlatform(raylib: *std.Build.Step.Compile, platform: PlatformBackend .glfw => raylib.defineCMacro("PLATFORM_DESKTOP_GLFW", null), .rgfw => raylib.defineCMacro("PLATFORM_DESKTOP_RGFW", null), .sdl => raylib.defineCMacro("PLATFORM_DESKTOP_SDL", null), - else => {} + else => {}, } } @@ -74,11 +74,12 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. while (lines.next()) |line| { if (!std.mem.containsAtLeast(u8, line, 1, "SUPPORT")) continue; if (std.mem.startsWith(u8, line, "//")) continue; + if (std.mem.startsWith(u8, line, "#if")) continue; var flag = std.mem.trimLeft(u8, line, " \t"); // Trim whitespace flag = flag["#define ".len - 1 ..]; // Remove #define flag = std.mem.trimLeft(u8, flag, " \t"); // Trim whitespace - flag = flag[0..std.mem.indexOf(u8, flag, " ").?]; // Flag is only one word, so capture till space + flag = flag[0 .. std.mem.indexOf(u8, flag, " ") orelse continue]; // Flag is only one word, so capture till space flag = try std.fmt.allocPrint(b.allocator, "-D{s}", .{flag}); // Prepend with -D // If user specifies the flag skip it @@ -301,6 +302,7 @@ pub const Options = struct { shared: bool = false, linux_display_backend: LinuxDisplayBackend = .Both, opengl_version: OpenglVersion = .auto, + /// config should be a list of cflags, eg, "-DSUPPORT_CUSTOM_FRAME_CONTROL" config: ?[]const u8 = null, raygui_dependency_name: []const u8 = "raygui", @@ -338,7 +340,7 @@ pub const PlatformBackend = enum { glfw, rgfw, sdl, - drm + drm, }; pub fn build(b: *std.Build) !void { From 43b109a4e3fa40c03bdf0ea3a45c908c10a2774f Mon Sep 17 00:00:00 2001 From: Anthony Carbajal <5776225+CrackedPixel@users.noreply.github.com> Date: Mon, 7 Oct 2024 02:32:04 -0500 Subject: [PATCH 070/115] removed old comment (#4370) --- src/rcore.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/rcore.c b/src/rcore.c index 3cdacbd96..e154d6173 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -578,7 +578,6 @@ const char *TextFormat(const char *text, ...); // Formatting of tex //void DisableCursor(void) // Initialize window and OpenGL context -// NOTE: data parameter could be used to pass any kind of required data to the initialization void InitWindow(int width, int height, const char *title) { TRACELOG(LOG_INFO, "Initializing raylib %s", RAYLIB_VERSION); From 89a37cd3151ef2a91643d797941711889bddf0fb Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 7 Oct 2024 21:03:55 +0200 Subject: [PATCH 071/115] Update CHANGELOG --- CHANGELOG | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 2141926ce..b5b50e4d7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,17 @@ changelog Current Release: raylib 5.0 (18 November 2023) +------------------------------------------------------------------------- +Release: raylib 5.5 - 11th Anniversary Edition? (18 November 2024?) +------------------------------------------------------------------------- +KEY CHANGES: + - + - + - + +Detailed changes: +... + ------------------------------------------------------------------------- Release: raylib 5.0 - 10th Anniversary Edition (18 November 2023) ------------------------------------------------------------------------- From 712ab798d1fbf66310240b1e66f0ad6f5a673a4c Mon Sep 17 00:00:00 2001 From: Anthony Carbajal <5776225+CrackedPixel@users.noreply.github.com> Date: Tue, 8 Oct 2024 11:33:33 -0500 Subject: [PATCH 072/115] updated makefile to disable wayland by default (#4369) --- src/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Makefile b/src/Makefile index 4740f1f01..137c28b53 100644 --- a/src/Makefile +++ b/src/Makefile @@ -109,8 +109,9 @@ RAYLIB_MODULE_RAYGUI_PATH ?= $(RAYLIB_SRC_PATH)/../../raygui/src # Use external GLFW library instead of rglfw module USE_EXTERNAL_GLFW ?= FALSE -# Enable support for both Wayland and X11 by default on Linux when using GLFW -GLFW_LINUX_ENABLE_WAYLAND ?= TRUE +# Enable support for X11 by default on Linux when using GLFW +# NOTE: Wayland is disabled by default, only enable if you are sure +GLFW_LINUX_ENABLE_WAYLAND ?= FALSE GLFW_LINUX_ENABLE_X11 ?= TRUE # PLATFORM_DESKTOP_SDL: It requires SDL library to be provided externally From 44e37c5f975b024cfea04ec35a1f843315fee7f4 Mon Sep 17 00:00:00 2001 From: Colleague Riley Date: Tue, 8 Oct 2024 12:39:15 -0400 Subject: [PATCH 073/115] Update RGFW (#4372) * (rcore_desktop_rgfw.c) fix errors when compiling with mingw * define WideCharToMultiByte * update RGFW * move stdcall def to windows only * fix raw cursor input --- src/external/RGFW.h | 271 +++++++++++++++++------------ src/platforms/rcore_desktop_rgfw.c | 25 +-- 2 files changed, 165 insertions(+), 131 deletions(-) diff --git a/src/external/RGFW.h b/src/external/RGFW.h index 35e782d4a..fb389d5b4 100644 --- a/src/external/RGFW.h +++ b/src/external/RGFW.h @@ -192,7 +192,7 @@ typedef u32 b32; #endif -#define RGFW_TRUE 1 +#define RGFW_TRUE (!(0)) #define RGFW_FALSE 0 /* thse OS macros looks better & are standardized */ @@ -276,11 +276,6 @@ #endif #ifdef RGFW_EGL - #if defined(__APPLE__) - #warning EGL is not supported for Cocoa, switching back to the native opengl api - #undef RGFW_EGL - #endif - #include #elif defined(RGFW_OSMESA) #ifndef __APPLE__ @@ -611,10 +606,17 @@ typedef struct RGFW_window { /** * @defgroup Window_management * @{ */ + +/*! + * the class name for X11 and WinAPI. apps with the same class will be grouped by the WM + * by default the class name will == the root window's name +*/ +RGFWDEF void RGFW_setClassName(char* name); + /*! this has to be set before createWindow is called, else the fulscreen size is used */ RGFWDEF void RGFW_setBufferSize(RGFW_area size); /*!< the buffer cannot be resized (by RGFW) */ -RGFW_window* RGFW_createWindow( +RGFWDEF RGFW_window* RGFW_createWindow( const char* name, /* name of the window */ RGFW_rect rect, /* rect of window */ u16 args /* extra arguments (NULL / (u16)0 means no args used)*/ @@ -635,7 +637,7 @@ RGFWDEF RGFW_area RGFW_getScreenSize(void); although you still need some way to tell RGFW to process events eg. `RGFW_window_checkEvents` */ -RGFW_Event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current event (returns a pointer to win->event or NULL if there is no event)*/ +RGFWDEF RGFW_Event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current event (returns a pointer to win->event or NULL if there is no event)*/ /*! for RGFW_window_eventWait and RGFW_window_checkEvents @@ -706,7 +708,7 @@ RGFWDEF void RGFW_window_setName(RGFW_window* win, char* name ); -void RGFW_window_setIcon(RGFW_window* win, /*!< source window */ +RGFWDEF void RGFW_window_setIcon(RGFW_window* win, /*!< source window */ u8* icon /*!< icon bitmap */, RGFW_area a /*!< width and height of the bitmap*/, i32 channels /*!< how many channels the bitmap has (rgb : 3, rgba : 4) */ @@ -1609,9 +1611,6 @@ RGFW_window* RGFW_window_basic_init(RGFW_rect rect, u16 args) { if (args & RGFW_FULLSCREEN) rect = RGFW_RECT(0, 0, screenR.w, screenR.h); - if (args & RGFW_CENTER) - rect = RGFW_RECT((screenR.w - rect.w) / 2, (screenR.h - rect.h) / 2, rect.w, rect.h); - /* set and init the new window's data */ win->r = rect; win->event.inFocus = 1; @@ -1627,7 +1626,7 @@ RGFW_window* RGFW_window_basic_init(RGFW_rect rect, u16 args) { void RGFW_window_scaleToMonitor(RGFW_window* win) { RGFW_monitor monitor = RGFW_window_getMonitor(win); - RGFW_window_resize(win, RGFW_AREA(((u32) monitor.scaleX) * win->r.w, ((u32) monitor.scaleX) * win->r.h)); + RGFW_window_resize(win, RGFW_AREA((u32)(monitor.scaleX * (float)win->r.w), (u32)(monitor.scaleX * (float)win->r.h))); } #endif @@ -1637,6 +1636,16 @@ RGFW_window* RGFW_root = NULL; #define RGFW_HOLD_MOUSE (1L<<2) /*!< hold the moues still */ #define RGFW_MOUSE_LEFT (1L<<3) /* if mouse left the window */ +#ifdef RGFW_MACOS +RGFWDEF void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer); +RGFWDEF void* RGFW_cocoaGetLayer(void); +#endif + +char* RGFW_className = NULL; +void RGFW_setClassName(char* name) { + RGFW_className = name; +} + void RGFW_clipboardFree(char* str) { RGFW_FREE(str); } RGFW_keyState RGFW_mouseButtons[5] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} }; @@ -2073,6 +2082,8 @@ void RGFW_updateLockState(RGFW_window* win, b8 capital, b8 numlock) { #ifdef RGFW_WINDOWS win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.hdc); + #elif defined(RGFW_MACOS) + win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType)0); #else win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display); #endif @@ -2104,8 +2115,15 @@ void RGFW_updateLockState(RGFW_window* win, b8 capital, b8 numlock) { EGLint numConfigs; eglChooseConfig(win->src.EGL_display, egl_config, &config, 1, &numConfigs); - - win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL); + #if defined(RGFW_MACOS) + void* layer = RGFW_cocoaGetLayer(); + + RGFW_window_cocoaSetLayer(win, layer); + + win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) layer, NULL); + #else + win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL); + #endif EGLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, @@ -2322,7 +2340,7 @@ Start of Linux / Unix defines u8 RGFW_mouseIconSrc[] = { XC_arrow, XC_left_ptr, XC_xterm, XC_crosshair, XC_hand2, XC_sb_h_double_arrow, XC_sb_v_double_arrow, XC_bottom_left_corner, XC_bottom_right_corner, XC_fleur, XC_X_cursor}; /*atoms needed for drag and drop*/ - Atom XdndAware, XdndTypeList, XdndSelection, XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop, XdndFinished, XdndActionCopy, XdndActionMove, XdndActionLink, XdndActionAsk, XdndActionPrivate; + Atom XdndAware, XdndTypeList, XdndSelection, XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop, XdndFinished, XdndActionCopy, XtextPlain, XtextUriList; Atom wm_delete_window = 0; @@ -2563,9 +2581,13 @@ Start of Linux / Unix defines // In your .desktop app, if you set the property // StartupWMClass=RGFW that will assoicate the launcher icon // with your application - robrohan + + if (RGFW_className == NULL) + RGFW_className = (char*)name; + XClassHint *hint = XAllocClassHint(); assert(hint != NULL); - hint->res_class = (char*)"RGFW"; + hint->res_class = (char*)RGFW_className; hint->res_name = (char*)name; // just use the window name as the app name XSetClassHint((Display*) win->src.display, win->src.window, hint); XFree(hint); @@ -2609,6 +2631,11 @@ Start of Linux / Unix defines RGFW_window_scaleToMonitor(win); #endif + if (args & RGFW_CENTER) { + RGFW_area screenR = RGFW_getScreenSize(); + RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2)); + } + if (args & RGFW_NO_RESIZE) { /* make it so the user can't resize the window*/ XSizeHints* sh = XAllocSizeHints(); sh->flags = (1L << 4) | (1L << 5); @@ -2646,7 +2673,6 @@ Start of Linux / Unix defines if (args & RGFW_ALLOW_DND) { /* init drag and drop atoms and turn on drag and drop for this window */ win->_winArgs |= RGFW_ALLOW_DND; - XdndAware = XInternAtom((Display*) win->src.display, "XdndAware", False); XdndTypeList = XInternAtom((Display*) win->src.display, "XdndTypeList", False); XdndSelection = XInternAtom((Display*) win->src.display, "XdndSelection", False); @@ -2660,15 +2686,16 @@ Start of Linux / Unix defines /* actions */ XdndActionCopy = XInternAtom((Display*) win->src.display, "XdndActionCopy", False); - XdndActionMove = XInternAtom((Display*) win->src.display, "XdndActionMove", False); - XdndActionLink = XInternAtom((Display*) win->src.display, "XdndActionLink", False); - XdndActionAsk = XInternAtom((Display*) win->src.display, "XdndActionAsk", False); - XdndActionPrivate = XInternAtom((Display*) win->src.display, "XdndActionPrivate", False); - const Atom version = 5; + + XtextUriList = XInternAtom((Display*) win->src.display, "text/uri-list", False); + XtextPlain = XInternAtom((Display*) win->src.display, "text/plain", False); + + XdndAware = XInternAtom((Display*) win->src.display, "XdndAware", False); + const u8 version = 5; XChangeProperty((Display*) win->src.display, (Window) win->src.window, XdndAware, 4, 32, - PropModeReplace, (u8*) &version, 1); /*!< turns on drag and drop */ + PropModeReplace, &version, 1); /*!< turns on drag and drop */ } #ifdef RGFW_EGL @@ -2716,17 +2743,16 @@ Start of Linux / Unix defines return RGFWMouse; } - typedef struct XDND { - long source, version; - i32 format; - } XDND; /*!< data structure for xdnd events */ - XDND xdnd; - int xAxis = 0, yAxis = 0; RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) { assert(win != NULL); + static struct { + long source, version; + i32 format; + } xdnd; + if (win->event.type == 0) RGFW_resetKey(); @@ -2893,13 +2919,16 @@ Start of Linux / Unix defines win->event.droppedFilesCount = 0; - /* - much of this event (drag and drop code) is source from glfw - */ - if ((win->_winArgs & RGFW_ALLOW_DND) == 0) break; + XEvent reply = { ClientMessage }; + reply.xclient.window = xdnd.source; + reply.xclient.format = 32; + reply.xclient.data.l[0] = (long) win->src.window; + reply.xclient.data.l[1] = 0; + reply.xclient.data.l[2] = None; + if (E.xclient.message_type == XdndEnter) { unsigned long count; Atom* formats; @@ -2944,28 +2973,11 @@ Start of Linux / Unix defines formats = real_formats; } - u32 i; - for (i = 0; i < (u32)count; i++) { - char* name = XGetAtomName((Display*) win->src.display, formats[i]); - - char* links[2] = { (char*) (const char*) "text/uri-list", (char*) (const char*) "text/plain" }; - for (; 1; name++) { - u32 j; - for (j = 0; j < 2; j++) { - if (*links[j] != *name) { - links[j] = (char*) (const char*) "\1"; - continue; - } - - if (*links[j] == '\0' && *name == '\0') - xdnd.format = formats[i]; - - if (*links[j] != '\0' && *links[j] != '\1') - links[j]++; - } - - if (*name == '\0') - break; + unsigned long i; + for (i = 0; i < count; i++) { + if (formats[i] == XtextUriList || formats[i] == XtextPlain) { + xdnd.format = formats[i]; + break; } } @@ -2994,13 +3006,8 @@ Start of Linux / Unix defines win->event.point.x = xpos; win->event.point.y = ypos; - XEvent reply = { ClientMessage }; reply.xclient.window = xdnd.source; reply.xclient.message_type = XdndStatus; - reply.xclient.format = 32; - reply.xclient.data.l[0] = (long) win->src.window; - reply.xclient.data.l[2] = 0; - reply.xclient.data.l[3] = 0; if (xdnd.format) { reply.xclient.data.l[1] = 1; @@ -3035,12 +3042,6 @@ Start of Linux / Unix defines time); } else if (xdnd.version >= 2) { XEvent reply = { ClientMessage }; - reply.xclient.window = xdnd.source; - reply.xclient.message_type = XdndFinished; - reply.xclient.format = 32; - reply.xclient.data.l[0] = (long) win->src.window; - reply.xclient.data.l[1] = 0; - reply.xclient.data.l[2] = None; XSendEvent((Display*) win->src.display, xdnd.source, False, NoEventMask, &reply); @@ -3125,11 +3126,7 @@ Start of Linux / Unix defines XFree(data); if (xdnd.version >= 2) { - XEvent reply = { ClientMessage }; - reply.xclient.window = xdnd.source; reply.xclient.message_type = XdndFinished; - reply.xclient.format = 32; - reply.xclient.data.l[0] = (long) win->src.window; reply.xclient.data.l[1] = result; reply.xclient.data.l[2] = XdndActionCopy; @@ -3480,7 +3477,7 @@ Start of Linux / Unix defines *size = sizeN; return s; - } + } /* almost all of this function is sourced from GLFW @@ -3520,9 +3517,6 @@ Start of Linux / Unix defines XEvent reply = { SelectionNotify }; reply.xselection.property = 0; - const Atom formats[] = { UTF8_STRING, XA_STRING }; - const i32 formatCount = sizeof(formats) / sizeof(formats[0]); - if (request->target == TARGETS) { const Atom targets[] = { TARGETS, MULTIPLE, @@ -3552,15 +3546,7 @@ Start of Linux / Unix defines unsigned long i; for (i = 0; i < (u32)count; i += 2) { - i32 j; - - for (j = 0; j < formatCount; j++) { - if (targets[i] == formats[j]) - break; - } - - if (j < formatCount) - { + if (targets[i] == UTF8_STRING || targets[i] == XA_STRING) { XChangeProperty((Display*) RGFW_root->src.display, request->requestor, targets[i + 1], @@ -3727,32 +3713,54 @@ Start of Linux / Unix defines RGFW_monitor monitor; Display* display = XOpenDisplay(NULL); + + RGFW_area size = RGFW_getScreenSize(); - monitor.rect = RGFW_RECT(0, 0, DisplayWidth(display, screen), DisplayHeight(display, screen)); - monitor.physW = (monitor.rect.w * 25.4f / 96.f); - monitor.physH = (monitor.rect.h * 25.4f / 96.f); - - strncpy(monitor.name, DisplayString(display), 128); - + monitor.rect = RGFW_RECT(0, 0, size.w, size.h); + monitor.physW = DisplayWidthMM(display, screen); + monitor.physH = DisplayHeightMM(display, screen); + XGetSystemContentScale(display, &monitor.scaleX, &monitor.scaleY); - XRRScreenResources* sr = XRRGetScreenResourcesCurrent(display, RootWindow(display, screen)); XRRCrtcInfo* ci = NULL; - int crtc = 0; + int crtc = screen; if (sr->ncrtc > crtc) { ci = XRRGetCrtcInfo(display, sr, sr->crtcs[crtc]); } - + if (ci == NULL) { + float dpi_width = round((double)monitor.rect.w/(((double)monitor.physW)/25.4)); + float dpi_height = round((double)monitor.rect.h/(((double)monitor.physH)/25.4)); + + monitor.scaleX = (float) (dpi_width) / (float) 96; + monitor.scaleY = (float) (dpi_height) / (float) 96; XRRFreeScreenResources(sr); XCloseDisplay(display); return monitor; } + + XRROutputInfo* info = XRRGetOutputInfo (display, sr, sr->outputs[screen]); + monitor.physW = info->mm_width; + monitor.physH = info->mm_height; monitor.rect.x = ci->x; monitor.rect.y = ci->y; + monitor.rect.w = ci->width; + monitor.rect.h = ci->height; + + float dpi_width = round((double)monitor.rect.w/(((double)monitor.physW)/25.4)); + float dpi_height = round((double)monitor.rect.h/(((double)monitor.physH)/25.4)); + + monitor.scaleX = (float) (dpi_width) / (float) 96; + monitor.scaleY = (float) (dpi_height) / (float) 96; + + if (monitor.scaleX > 1 && monitor.scaleX < 1.1) + monitor.scaleX = 1; + + if (monitor.scaleY > 1 && monitor.scaleY < 1.1) + monitor.scaleY = 1; XRRFreeCrtcInfo(ci); XRRFreeScreenResources(sr); @@ -4150,9 +4158,6 @@ RGFW_Event RGFW_eventPipe_pop(RGFW_window* win) { if (win->src.eventLen >= 0) ev = win->src.events[win->src.eventLen]; - else { - printf("H2\n"); - } return ev; } @@ -4675,6 +4680,10 @@ static const struct wl_callback_listener wl_surface_frame_listener = { decoration_manager, win->src.xdg_toplevel); } + if (args & RGFW_CENTER) { + RGFW_area screenR = RGFW_getScreenSize(); + RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2)); + } if (args & RGFW_OPENGL_SOFTWARE) setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1); @@ -4999,9 +5008,7 @@ static const struct wl_callback_listener wl_surface_frame_listener = { #define WIN32_LEAN_AND_MEAN #define OEMRESOURCE #include - - __declspec(dllimport) int __stdcall WideCharToMultiByte( UINT CodePage, DWORD dwFlags, const WCHAR* lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar); - + #include #include #include @@ -5009,6 +5016,10 @@ static const struct wl_callback_listener wl_surface_frame_listener = { #include #include + #include + + __declspec(dllimport) int __stdcall WideCharToMultiByte( UINT CodePage, DWORD dwFlags, const WCHAR* lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar); + #ifndef RGFW_NO_XINPUT typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*); PFN_XInputGetState XInputGetStateSRC = NULL; @@ -5226,14 +5237,15 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ } void RGFW_releaseCursor(RGFW_window* win) { + RGFW_UNUSED(win); ClipCursor(NULL); const RAWINPUTDEVICE id = { 0x01, 0x02, RIDEV_REMOVE, NULL }; RegisterRawInputDevices(&id, 1, sizeof(id)); } void RGFW_captureCursor(RGFW_window* win, RGFW_rect rect) { - RGFW_UNUSED(win) - + RGFW_UNUSED(win); RGFW_UNUSED(rect); + RECT clipRect; GetClientRect(win->src.window, &clipRect); ClientToScreen(win->src.window, (POINT*) &clipRect.left); @@ -5254,6 +5266,7 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ if (RGFW_Shcore_dll == NULL) { RGFW_Shcore_dll = LoadLibraryA("shcore.dll"); GetDpiForMonitorSRC = (PFN_GetDpiForMonitor)(void*)GetProcAddress(RGFW_Shcore_dll, "GetDpiForMonitor"); + SetProcessDPIAware(); } #endif @@ -5288,7 +5301,10 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ WNDCLASSA Class = { }; #endif - Class.lpszClassName = name; + if (RGFW_className == NULL) + RGFW_className = (char*)name; + + Class.lpszClassName = RGFW_className; Class.hInstance = inh; Class.hCursor = LoadCursor(NULL, IDC_ARROW); Class.lpfnWndProc = WndProc; @@ -5501,6 +5517,11 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ if (args & RGFW_SCALE_TO_MONITOR) RGFW_window_scaleToMonitor(win); #endif + + if (args & RGFW_CENTER) { + RGFW_area screenR = RGFW_getScreenSize(); + RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2)); + } #ifdef RGFW_EGL if ((args & RGFW_NO_INIT_API) == 0) @@ -6102,7 +6123,8 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ if (GetDpiForMonitor != NULL) { u32 x, y; - GetDpiForMonitor(src, MDT_ANGULAR_DPI, &x, &y); + GetDpiForMonitor(src, MDT_EFFECTIVE_DPI, &x, &y); + monitor.scaleX = (float) (x) / (float) USER_DEFAULT_SCREEN_DPI; monitor.scaleY = (float) (y) / (float) USER_DEFAULT_SCREEN_DPI; } @@ -6117,7 +6139,7 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ /* Calculate physical height in inches */ monitor.physW = GetSystemMetrics(SM_CYSCREEN) / (float) ppiX; monitor.physH = GetSystemMetrics(SM_CXSCREEN) / (float) ppiY; - + return monitor; } #endif /* RGFW_NO_MONITOR */ @@ -6152,7 +6174,7 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ RGFW_mInfo info; info.iIndex = 0; while (EnumDisplayMonitors(NULL, NULL, GetMonitorHandle, (LPARAM) &info)); - + return RGFW_monitors; } @@ -7104,7 +7126,6 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ for (int i = 0; i < count; i++) { id fileURL = objc_msgSend_arr(fileURLs, sel_registerName("objectAtIndex:"), i); const char *filePath = ((const char* (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("UTF8String")); - // printf("File: %s\n", filePath); strncpy(win->event.droppedFiles[i], filePath, RGFW_MAX_PATH); win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0'; } @@ -7208,6 +7229,16 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ #endif } + + void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer) { + objc_msgSend_void_id(win->src.view, sel_registerName("setLayer"), layer); + } + + void* RGFW_cocoaGetLayer(void) { + return objc_msgSend_class(objc_getClass("CAMetalLayer"), sel_registerName("layer")); + } + + NSPasteboardType const NSPasteboardTypeURL = "public.url"; NSPasteboardType const NSPasteboardTypeFileURL = "public.file-url"; @@ -7263,6 +7294,11 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ NSString* str = NSString_stringWithUTF8String(name); objc_msgSend_void_id(win->src.window, sel_registerName("setTitle:"), str); +#ifdef RGFW_EGL + if ((args & RGFW_NO_INIT_API) == 0) + RGFW_createOpenGLContext(win); +#endif + #ifdef RGFW_OPENGL if ((args & RGFW_NO_INIT_API) == 0) { void* attrs = RGFW_initFormatAttribs(args & RGFW_OPENGL_SOFTWARE); @@ -7329,6 +7365,11 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ RGFW_window_scaleToMonitor(win); #endif + if (args & RGFW_CENTER) { + RGFW_area screenR = RGFW_getScreenSize(); + RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2)); + } + if (args & RGFW_HIDE_MOUSE) RGFW_window_showMouse(win, 0); @@ -7935,6 +7976,7 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ } void RGFW_releaseCursor(RGFW_window* win) { + RGFW_UNUSED(win); CGAssociateMouseAndMouseCursorPosition(1); } @@ -7994,13 +8036,11 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ monitor.rect = RGFW_RECT((int) bounds.origin.x, (int) bounds.origin.y, (int) bounds.size.width, (int) bounds.size.height); CGSize screenSizeMM = CGDisplayScreenSize(display); - monitor.physW = screenSizeMM.width / 25.4; - monitor.physH = screenSizeMM.height / 25.4; + monitor.physW = screenSizeMM.width; + monitor.physH = screenSizeMM.height; - monitor.scaleX = (monitor.rect.w / (screenSizeMM.width)) / 2.6; - monitor.scaleY = (monitor.rect.h / (screenSizeMM.height)) / 2.6; - - snprintf(monitor.name, 128, "%i %i %i", CGDisplayModelNumber(display), CGDisplayVendorNumber(display), CGDisplaySerialNumber(display)); + monitor.scaleX = ((monitor.rect.w / (screenSizeMM.width / 25.4)) / 96) + 0.25; + monitor.scaleY = ((monitor.rect.h / (screenSizeMM.height / 25.4)) / 96) + 0.25; return monitor; } @@ -8090,6 +8130,8 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ #if defined(RGFW_OPENGL) NSOpenGLContext_setValues(win->src.ctx, &swapInterval, 222); + #else + RGFW_UNUSED(swapInterval); #endif } #endif @@ -8532,7 +8574,7 @@ RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) { emscripten_webgl_make_context_current(win->src.ctx); #ifdef LEGACY_GL_EMULATION - EM_ASM("Module.useWebGL = true; GLImmediate.init();"); + EM_ASM("Module.useWebGL = true; GLImmediate.init();"); #endif emscripten_set_canvas_element_size("#canvas", rect.w, rect.h); @@ -8875,11 +8917,12 @@ u64 RGFW_getTime(void) { } void RGFW_releaseCursor(RGFW_window* win) { + RGFW_UNUSED(win); emscripten_exit_pointerlock(); } void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { - RGFW_UNUSED(win) + RGFW_UNUSED(win); RGFW_UNUSED(r); emscripten_request_pointerlock("#canvas", 1); } diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index ef01820cb..76f4cdd0a 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -1,6 +1,6 @@ /********************************************************************************************** * -* rcore_desktop_rgfw template - Functions to manage window, graphics device and inputs +* rcore_desktop_rgfw - Functions to manage window, graphics device and inputs * * PLATFORM: RGFW * - Windows (Win32, Win64) @@ -69,6 +69,7 @@ void CloseWindow(void); #define CloseWindow CloseWindow_win32 #define ShowCursor __imp_ShowCursor #define _APISETSTRING_ + __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar); #endif #if defined(__APPLE__) @@ -76,8 +77,6 @@ void CloseWindow(void); #define Size NSSIZE #endif -__declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar); - #include "../external/RGFW.h" #if defined(__WIN32) || defined(__WIN64) @@ -289,7 +288,6 @@ void SetWindowState(unsigned int flags) } if (flags & FLAG_WINDOW_RESIZABLE) { - printf("%i %i\n", platform.window->r.w, platform.window->r.h); RGFW_window_setMaxSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h)); RGFW_window_setMinSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h)); } @@ -688,7 +686,7 @@ void DisableCursor(void) { RGFW_disableCursor = true; - RGFW_window_mouseHold(platform.window, RGFW_AREA(CORE.Window.screen.width / 2, CORE.Window.screen.height / 2)); + RGFW_window_mouseHold(platform.window, RGFW_AREA(0, 0)); HideCursor(); } @@ -873,8 +871,8 @@ void PollInputEvents(void) CORE.Window.resizedLastFrame = false; + CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; #define RGFW_HOLD_MOUSE (1L<<2) - #if defined(RGFW_X11) //|| defined(RGFW_MACOS) if (platform.window->_winArgs & RGFW_HOLD_MOUSE) { CORE.Input.Mouse.previousPosition = (Vector2){ 0.0f, 0.0f }; @@ -884,9 +882,9 @@ void PollInputEvents(void) { CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; } -#endif - while (RGFW_window_checkEvent(platform.window)) + + while (RGFW_window_checkEvent(platform.window)) { if ((platform.window->event.type >= RGFW_jsButtonPressed) && (platform.window->event.type <= RGFW_jsAxisMove)) @@ -1030,15 +1028,8 @@ void PollInputEvents(void) { if (platform.window->_winArgs & RGFW_HOLD_MOUSE) { - CORE.Input.Mouse.previousPosition = (Vector2){ 0.0f, 0.0f }; - - if (event->point.x) - CORE.Input.Mouse.previousPosition.x = CORE.Input.Mouse.currentPosition.x; - if (event->point.y) - CORE.Input.Mouse.previousPosition.y = CORE.Input.Mouse.currentPosition.y; - - CORE.Input.Mouse.currentPosition.x = (float)event->point.x; - CORE.Input.Mouse.currentPosition.y = (float)event->point.y; + CORE.Input.Mouse.currentPosition.x += (float)event->point.x; + CORE.Input.Mouse.currentPosition.y += (float)event->point.y; } else { From 3fb1ba25aca0a6b023ca254a0910df36b0744e64 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 8 Oct 2024 18:45:52 +0200 Subject: [PATCH 074/115] Removed tabs and triple line-breaks --- src/platforms/rcore_android.c | 1 - src/platforms/rcore_desktop_glfw.c | 1 - src/platforms/rcore_desktop_rgfw.c | 11 +++-------- src/platforms/rcore_drm.c | 1 - src/platforms/rcore_template.c | 1 - src/platforms/rcore_web.c | 1 - src/rcamera.h | 1 - src/rlgl.h | 1 - src/rmodels.c | 5 ----- src/rtextures.c | 2 -- src/utils.c | 1 - 11 files changed, 3 insertions(+), 23 deletions(-) diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c index 6318931cc..88438c9b0 100644 --- a/src/platforms/rcore_android.c +++ b/src/platforms/rcore_android.c @@ -704,7 +704,6 @@ void PollInputEvents(void) } } - //---------------------------------------------------------------------------------- // Module Internal Functions Definition //---------------------------------------------------------------------------------- diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index f7b94178c..d42274d14 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -1234,7 +1234,6 @@ void PollInputEvents(void) glfwSetWindowShouldClose(platform.handle, GLFW_FALSE); } - //---------------------------------------------------------------------------------- // Module Internal Functions Definition //---------------------------------------------------------------------------------- diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index 76f4cdd0a..20bff2128 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -69,7 +69,7 @@ void CloseWindow(void); #define CloseWindow CloseWindow_win32 #define ShowCursor __imp_ShowCursor #define _APISETSTRING_ - __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar); + __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar); #endif #if defined(__APPLE__) @@ -870,9 +870,8 @@ void PollInputEvents(void) //----------------------------------------------------------------------------- CORE.Window.resizedLastFrame = false; - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; - #define RGFW_HOLD_MOUSE (1L<<2) + #define RGFW_HOLD_MOUSE (1L<<2) if (platform.window->_winArgs & RGFW_HOLD_MOUSE) { CORE.Input.Mouse.previousPosition = (Vector2){ 0.0f, 0.0f }; @@ -883,10 +882,8 @@ void PollInputEvents(void) CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; } - - while (RGFW_window_checkEvent(platform.window)) + while (RGFW_window_checkEvent(platform.window)) { - if ((platform.window->event.type >= RGFW_jsButtonPressed) && (platform.window->event.type <= RGFW_jsAxisMove)) { if (!CORE.Input.Gamepad.ready[platform.window->event.joystick]) @@ -1196,7 +1193,6 @@ void PollInputEvents(void) //----------------------------------------------------------------------------- } - //---------------------------------------------------------------------------------- // Module Internal Functions Definition //---------------------------------------------------------------------------------- @@ -1253,7 +1249,6 @@ int InitPlatform(void) */ SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); - if (CORE.Window.flags & FLAG_VSYNC_HINT) RGFW_window_swapInterval(platform.window, 1); RGFW_window_makeCurrent(platform.window); diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c index ee2875838..e77457b1b 100644 --- a/src/platforms/rcore_drm.c +++ b/src/platforms/rcore_drm.c @@ -1480,7 +1480,6 @@ static void ConfigureEvdevDevice(char *device) TEST_BIT(keyBits, BTN_MOUSE)) isMouse = true; } - if (TEST_BIT(evBits, EV_KEY)) { // The first 32 keys as defined in input-event-codes.h are pretty much diff --git a/src/platforms/rcore_template.c b/src/platforms/rcore_template.c index 938f4ed7d..6bc3432eb 100644 --- a/src/platforms/rcore_template.c +++ b/src/platforms/rcore_template.c @@ -430,7 +430,6 @@ void PollInputEvents(void) // TODO: Poll input events for current platform } - //---------------------------------------------------------------------------------- // Module Internal Functions Definition //---------------------------------------------------------------------------------- diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c index ff7a92dbc..35c15a6b6 100644 --- a/src/platforms/rcore_web.c +++ b/src/platforms/rcore_web.c @@ -935,7 +935,6 @@ void PollInputEvents(void) // so, if mouse is not moved it returns a (0, 0) position... this behaviour should be reviewed! //for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ 0, 0 }; - // Gamepad support using emscripten API // NOTE: GLFW3 joystick functionality not available in web diff --git a/src/rcamera.h b/src/rcamera.h index ccab549c1..bd2b36e03 100644 --- a/src/rcamera.h +++ b/src/rcamera.h @@ -162,7 +162,6 @@ RLAPI Matrix GetCameraProjectionMatrix(Camera* camera, float aspect); #endif // RCAMERA_H - /*********************************************************************************** * * CAMERA IMPLEMENTATION diff --git a/src/rlgl.h b/src/rlgl.h index 43698f63a..1695c2f56 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -357,7 +357,6 @@ #endif #endif - //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- diff --git a/src/rmodels.c b/src/rmodels.c index d2bf528ff..c9fa222eb 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -702,7 +702,6 @@ void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, fl rlPopMatrix(); } - // Draw a wired cylinder with base at startPos and top at endPos // NOTE: It could be also used for pyramid and cone void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color) @@ -1259,7 +1258,6 @@ void UploadMesh(Mesh *mesh, bool dynamic) mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = 0; // Vertex buffer: boneWeights #endif - #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) mesh->vaoId = rlLoadVertexArray(); rlEnableVertexArray(mesh->vaoId); @@ -2098,7 +2096,6 @@ bool ExportMeshAsCode(Mesh mesh, const char *fileName) return success; } - #if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL) // Process obj materials static void ProcessMaterialsOBJ(Material *materials, tinyobj_material_t *mats, int materialCount) @@ -5680,8 +5677,6 @@ static Model LoadGLTF(const char *fileName) else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName); } else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName); - - } // NOTE: Attributes related to animations are processed separately diff --git a/src/rtextures.c b/src/rtextures.c index 6d3c21cf4..e81f05fe8 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -4988,8 +4988,6 @@ Vector3 ColorToHSV(Color color) return hsv; } - - // Get a Color from HSV values // Implementation reference: https://en.wikipedia.org/wiki/HSL_and_HSV#Alternative_HSV_conversion // NOTE: Color->HSV->Color conversion will not yield exactly the same color due to rounding errors diff --git a/src/utils.c b/src/utils.c index fcbdba005..c5d9748d4 100644 --- a/src/utils.c +++ b/src/utils.c @@ -76,7 +76,6 @@ void SetSaveFileDataCallback(SaveFileDataCallback callback) { saveFileData = cal void SetLoadFileTextCallback(LoadFileTextCallback callback) { loadFileText = callback; } // Set custom file text loader void SetSaveFileTextCallback(SaveFileTextCallback callback) { saveFileText = callback; } // Set custom file text saver - #if defined(PLATFORM_ANDROID) static AAssetManager *assetManager = NULL; // Android assets manager pointer static const char *internalDataPath = NULL; // Android internal data path From 454acca84be6fbdb8dd57ba848c80ba5f1981b73 Mon Sep 17 00:00:00 2001 From: Harald Scheirich Date: Thu, 10 Oct 2024 12:53:02 -0400 Subject: [PATCH 075/115] Some update to gltf loading (#4373) Only warns when there are more animations than currently implemented Allows mesh indices to be unsigned char --- src/rmodels.c | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index c9fa222eb..92be04fca 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -5226,17 +5226,19 @@ static Model LoadGLTF(const char *fileName) ***********************************************************************************************/ // Macro to simplify attributes loading code - #define LOAD_ATTRIBUTE(accesor, numComp, dataType, dstPtr) \ + #define LOAD_ATTRIBUTE(accesor, numComp, srcType, dstPtr) LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, srcType) + + #define LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, dstType) \ { \ int n = 0; \ - dataType *buffer = (dataType *)accesor->buffer_view->buffer->data + accesor->buffer_view->offset/sizeof(dataType) + accesor->offset/sizeof(dataType); \ + srcType *buffer = (srcType *)accesor->buffer_view->buffer->data + accesor->buffer_view->offset/sizeof(srcType) + accesor->offset/sizeof(srcType); \ for (unsigned int k = 0; k < accesor->count; k++) \ {\ for (int l = 0; l < numComp; l++) \ {\ - dstPtr[numComp*k + l] = buffer[n + l];\ + dstPtr[numComp*k + l] = (dstType)buffer[n + l];\ }\ - n += (int)(accesor->stride/sizeof(dataType));\ + n += (int)(accesor->stride/sizeof(srcType));\ }\ } @@ -5697,23 +5699,25 @@ static Model LoadGLTF(const char *fileName) // Load unsigned short data type into mesh.indices LOAD_ATTRIBUTE(attribute, 1, unsigned short, model.meshes[meshIndex].indices) } + else if (attribute->component_type == cgltf_component_type_r_8u) + { + // Init raylib mesh indices to copy glTF attribute data + model.meshes[meshIndex].indices = RL_MALLOC(attribute->count * sizeof(unsigned short)); + LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned char, model.meshes[meshIndex].indices, unsigned short) + + } else if (attribute->component_type == cgltf_component_type_r_32u) { // Init raylib mesh indices to copy glTF attribute data model.meshes[meshIndex].indices = RL_MALLOC(attribute->count*sizeof(unsigned short)); - - // Load data into a temp buffer to be converted to raylib data type - unsigned int *temp = RL_MALLOC(attribute->count*sizeof(unsigned int)); - LOAD_ATTRIBUTE(attribute, 1, unsigned int, temp); - - // Convert data to raylib indices data type (unsigned short) - for (unsigned int d = 0; d < attribute->count; d++) model.meshes[meshIndex].indices[d] = (unsigned short)temp[d]; + LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned int, model.meshes[meshIndex].indices, unsigned short); TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data converted from u32 to u16, possible loss of data", fileName); - - RL_FREE(temp); } - else TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data format not supported, use u16", fileName); + else + { + TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data format not supported, use u16", fileName); + } } else model.meshes[meshIndex].triangleCount = model.meshes[meshIndex].vertexCount/3; // Unindexed mesh @@ -5745,7 +5749,7 @@ static Model LoadGLTF(const char *fileName) // - 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) + if (data->skins_count > 0) { cgltf_skin skin = data->skins[0]; model.bones = LoadBoneInfoGLTF(skin, &model.boneCount); @@ -5765,9 +5769,9 @@ static Model LoadGLTF(const char *fileName) MatrixDecompose(worldMatrix, &(model.bindPose[i].translation), &(model.bindPose[i].rotation), &(model.bindPose[i].scale)); } } - else if (data->skins_count > 1) + 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); + TRACELOG(LOG_WARNING, "MODEL: [%s] can only load one skin (armature) per model, but gltf skins_count == %i", fileName, data->skins_count); } meshIndex = 0; @@ -6088,7 +6092,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo if (result == cgltf_result_success) { - if (data->skins_count == 1) + if (data->skins_count > 0) { cgltf_skin skin = data->skins[0]; *animCount = (int)data->animations_count; @@ -6223,7 +6227,11 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo 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); + + if (data->skins_count > 1) + { + TRACELOG(LOG_WARNING, "MODEL: [%s] expected exactly one skin to load animation data from, but found %i", fileName, data->skins_count); + } cgltf_free(data); } From c4be01329493d0e772a04de08639b4da32905d2a Mon Sep 17 00:00:00 2001 From: William Culver <39485061+cedeon@users.noreply.github.com> Date: Thu, 10 Oct 2024 17:56:29 +0100 Subject: [PATCH 076/115] Fix build.zig (#4374) --- src/build.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/build.zig b/src/build.zig index 71729e4d2..895896269 100644 --- a/src/build.zig +++ b/src/build.zig @@ -24,7 +24,7 @@ pub fn addRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. .rshapes = options.rshapes, .rtext = options.rtext, .rtextures = options.rtextures, - .platform_drm = options.platform_drm, + .platform = options.platform, .shared = options.shared, .linux_display_backend = options.linux_display_backend, .opengl_version = options.opengl_version, From d3f86eb9573320f87b64882c8b9a33585d3133a7 Mon Sep 17 00:00:00 2001 From: Sage Hane Date: Thu, 10 Oct 2024 16:56:43 +0000 Subject: [PATCH 077/115] build.zig: Improve logic (#4375) * build.zig: Fix `@src` logic * build.zig: Clarify build error * build.zig: Add option for enabling `raygui` * build.zig: Expose `Options` type --- build.zig | 3 +++ src/build.zig | 41 +++++++++++++++++++++++------------------ 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/build.zig b/build.zig index 01e7b49fb..029482608 100644 --- a/build.zig +++ b/build.zig @@ -9,3 +9,6 @@ pub fn build(b: *std.Build) !void { // expose helper functions to user's build.zig pub const addRaylib = raylib.addRaylib; pub const addRaygui = raylib.addRaygui; + +// expose options for compiling +pub const RaylibOptions = raylib.Options; diff --git a/src/build.zig b/src/build.zig index 895896269..8944c7087 100644 --- a/src/build.zig +++ b/src/build.zig @@ -51,6 +51,10 @@ fn setDesktopPlatform(raylib: *std.Build.Step.Compile, platform: PlatformBackend } } +fn srcDir() []const u8 { + return std.fs.path.dirname(@src().file) orelse "."; +} + fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile { raylib_flags_arr.clearRetainingCapacity(); @@ -65,8 +69,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. "-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/3674 }); if (options.config) |config| { - const file = try std.fs.path.join(b.allocator, &.{ std.fs.path.dirname(@src().file) orelse ".", "config.h" }); - defer b.allocator.free(file); + const file = b.pathJoin(&.{ srcDir(), "config.h" }); const content = try std.fs.cwd().readFileAlloc(b.allocator, file, std.math.maxInt(usize)); defer b.allocator.free(content); @@ -115,7 +118,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. // No GLFW required on PLATFORM_DRM if (options.platform != .drm) { - raylib.addIncludePath(b.path("src/external/glfw/include")); + raylib.addIncludePath(b.path(b.pathJoin(&.{ srcDir(), "external/glfw/include" }))); } var c_source_files = try std.ArrayList([]const u8).initCapacity(b.allocator, 2); @@ -168,17 +171,16 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. if (options.linux_display_backend == .Wayland or options.linux_display_backend == .Both) { _ = b.findProgram(&.{"wayland-scanner"}, &.{}) catch { std.log.err( - \\ Wayland may not be installed on the system. + \\ `wayland-scanner` may not be installed on the system. \\ You can switch to X11 in your `build.zig` by changing `Options.linux_display_backend` , .{}); - @panic("No Wayland"); + @panic("`wayland-scanner` not found"); }; raylib.defineCMacro("_GLFW_WAYLAND", null); raylib.linkSystemLibrary("wayland-client"); raylib.linkSystemLibrary("wayland-cursor"); raylib.linkSystemLibrary("wayland-egl"); raylib.linkSystemLibrary("xkbcommon"); - raylib.addIncludePath(b.path("src")); waylandGenerate(b, raylib, "wayland.xml", "wayland-client-protocol"); waylandGenerate(b, raylib, "xdg-shell.xml", "xdg-shell-client-protocol"); waylandGenerate(b, raylib, "xdg-decoration-unstable-v1.xml", "xdg-decoration-unstable-v1-client-protocol"); @@ -229,7 +231,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. // On macos rglfw.c include Objective-C files. try raylib_flags_arr.append(b.allocator, "-ObjC"); raylib.root_module.addCSourceFile(.{ - .file = b.path("src/rglfw.c"), + .file = b.path(b.pathJoin(&.{ srcDir(), "rglfw.c" })), .flags = raylib_flags_arr.items, }); _ = raylib_flags_arr.pop(); @@ -251,8 +253,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. @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); + const cache_include = b.pathJoin(&.{ b.sysroot.?, "cache", "sysroot", "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(); @@ -263,9 +264,8 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. }, } - raylib.addIncludePath(b.path("src")); raylib.root_module.addCSourceFiles(.{ - .root = b.path("src"), + .root = b.path(srcDir()), .files = c_source_files.items, .flags = raylib_flags_arr.items, }); @@ -358,6 +358,7 @@ pub fn build(b: *std.Build) !void { const options = Options{ .platform = b.option(PlatformBackend, "platform", "Choose the platform backedn for desktop target") orelse defaults.platform, .raudio = b.option(bool, "raudio", "Compile with audio support") orelse defaults.raudio, + .raygui = b.option(bool, "raygui", "Compile with raygui support") orelse defaults.raygui, .rmodels = b.option(bool, "rmodels", "Compile with models support") orelse defaults.rmodels, .rtext = b.option(bool, "rtext", "Compile with text support") orelse defaults.rtext, .rtextures = b.option(bool, "rtextures", "Compile with textures support") orelse defaults.rtextures, @@ -370,17 +371,21 @@ pub fn build(b: *std.Build) !void { const lib = try compileRaylib(b, target, optimize, options); - lib.installHeader(b.path("src/raylib.h"), "raylib.h"); - lib.installHeader(b.path("src/raymath.h"), "raymath.h"); - lib.installHeader(b.path("src/rlgl.h"), "rlgl.h"); + lib.installHeader(b.path(b.pathJoin(&.{ srcDir(), "raylib.h" })), "raylib.h"); + lib.installHeader(b.path(b.pathJoin(&.{ srcDir(), "raymath.h" })), "raymath.h"); + lib.installHeader(b.path(b.pathJoin(&.{ srcDir(), "rlgl.h" })), "rlgl.h"); b.installArtifact(lib); } -const waylandDir = "src/external/glfw/deps/wayland"; - -fn waylandGenerate(b: *std.Build, raylib: *std.Build.Step.Compile, comptime protocol: []const u8, comptime basename: []const u8) void { - const protocolDir = waylandDir ++ "/" ++ protocol; +fn waylandGenerate( + b: *std.Build, + raylib: *std.Build.Step.Compile, + comptime protocol: []const u8, + comptime basename: []const u8, +) void { + const waylandDir = b.pathJoin(&.{ srcDir(), "external/glfw/deps/wayland" }); + const protocolDir = b.pathJoin(&.{ waylandDir, protocol }); const clientHeader = basename ++ ".h"; const privateCode = basename ++ "-code.h"; From 1effe921291f5a260ef6e2841f0ed19ccb0c3e7c Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 10 Oct 2024 20:37:46 +0200 Subject: [PATCH 078/115] `WARNING`: REMOVED: SVG files loading and drawing, moving it to raylib-extras --- examples/Makefile | 1 - examples/Makefile.Web | 5 - examples/textures/resources/test.svg | 1 - examples/textures/textures_svg_loading.c | 72 - examples/textures/textures_svg_loading.png | Bin 13850 -> 0 bytes projects/VS2022/raylib.sln | 2 - src/config.h | 1 - src/external/nanosvg.h | 3053 -------------------- src/external/nanosvgrast.h | 1458 ---------- src/rtextures.c | 116 - 10 files changed, 4709 deletions(-) delete mode 100644 examples/textures/resources/test.svg delete mode 100644 examples/textures/textures_svg_loading.c delete mode 100644 examples/textures/textures_svg_loading.png delete mode 100644 src/external/nanosvg.h delete mode 100644 src/external/nanosvgrast.h diff --git a/examples/Makefile b/examples/Makefile index 01c8e45d7..65ee4fb80 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -549,7 +549,6 @@ TEXTURES = \ textures/textures_sprite_button \ textures/textures_sprite_explosion \ textures/textures_srcrec_dstrec \ - textures/textures_svg_loading \ textures/textures_textured_curve \ textures/textures_to_image diff --git a/examples/Makefile.Web b/examples/Makefile.Web index b176217ae..f6c8b785a 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -415,7 +415,6 @@ TEXTURES = \ textures/textures_sprite_button \ textures/textures_sprite_explosion \ textures/textures_srcrec_dstrec \ - textures/textures_svg_loading \ textures/textures_textured_curve \ textures/textures_to_image @@ -776,10 +775,6 @@ textures/textures_srcrec_dstrec: textures/textures_srcrec_dstrec.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file textures/resources/scarfy.png@resources/scarfy.png -textures/textures_svg_loading: textures/textures_svg_loading.c - $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ - --preload-file textures/resources/test.svg - 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 diff --git a/examples/textures/resources/test.svg b/examples/textures/resources/test.svg deleted file mode 100644 index 3d9bbb113..000000000 --- a/examples/textures/resources/test.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/textures/textures_svg_loading.c b/examples/textures/textures_svg_loading.c deleted file mode 100644 index 434ec7602..000000000 --- a/examples/textures/textures_svg_loading.c +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************************* -* -* raylib [textures] example - SVG loading and texture creation -* -* NOTE: Images are loaded in CPU memory (RAM); textures are loaded in GPU memory (VRAM) -* -* Example originally created with raylib 4.2, last time updated with raylib 4.2 -* -* 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 Dennis Meinen (@bixxy#4258 on Discord) -* -********************************************************************************************/ - -#include "raylib.h" - -//------------------------------------------------------------------------------------ -// Program main entry point -//------------------------------------------------------------------------------------ -int main(void) -{ - // Initialization - //-------------------------------------------------------------------------------------- - const int screenWidth = 800; - const int screenHeight = 450; - - InitWindow(screenWidth, screenHeight, "raylib [textures] example - svg loading"); - - // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required) - - Image image = LoadImageSvg("resources/test.svg", 400, 350); // Loaded in CPU memory (RAM) - Texture2D texture = LoadTextureFromImage(image); // Image converted to texture, GPU memory (VRAM) - UnloadImage(image); // Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM - - 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 - //---------------------------------------------------------------------------------- - // TODO: Update your variables here - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(RAYWHITE); - - DrawTexture(texture, screenWidth/2 - texture.width/2, screenHeight/2 - texture.height/2, WHITE); - - //Red border to illustrate how the SVG is centered within the specified dimensions - DrawRectangleLines((screenWidth / 2 - texture.width / 2) - 1, (screenHeight / 2 - texture.height / 2) - 1, texture.width + 2, texture.height + 2, RED); - - DrawText("this IS a texture loaded from an SVG file!", 300, 410, 10, GRAY); - - EndDrawing(); - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - UnloadTexture(texture); // Texture unloading - - CloseWindow(); // Close window and OpenGL context - //-------------------------------------------------------------------------------------- - - return 0; -} \ No newline at end of file diff --git a/examples/textures/textures_svg_loading.png b/examples/textures/textures_svg_loading.png deleted file mode 100644 index fa98605fa8508a068537defae8a8fc960a6a6c08..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13850 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, image->height); - // Use... - for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) { - for (NSVGpath *path = shape->paths; path != NULL; path = path->next) { - for (int i = 0; i < path->npts-1; i += 3) { - float* p = &path->pts[i*2]; - drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]); - } - } - } - // Delete - nsvgDelete(image); -*/ - -enum NSVGpaintType { - NSVG_PAINT_NONE = 0, - NSVG_PAINT_COLOR = 1, - NSVG_PAINT_LINEAR_GRADIENT = 2, - NSVG_PAINT_RADIAL_GRADIENT = 3 -}; - -enum NSVGspreadType { - NSVG_SPREAD_PAD = 0, - NSVG_SPREAD_REFLECT = 1, - NSVG_SPREAD_REPEAT = 2 -}; - -enum NSVGlineJoin { - NSVG_JOIN_MITER = 0, - NSVG_JOIN_ROUND = 1, - NSVG_JOIN_BEVEL = 2 -}; - -enum NSVGlineCap { - NSVG_CAP_BUTT = 0, - NSVG_CAP_ROUND = 1, - NSVG_CAP_SQUARE = 2 -}; - -enum NSVGfillRule { - NSVG_FILLRULE_NONZERO = 0, - NSVG_FILLRULE_EVENODD = 1 -}; - -enum NSVGflags { - NSVG_FLAGS_VISIBLE = 0x01 -}; - -typedef struct NSVGgradientStop { - unsigned int color; - float offset; -} NSVGgradientStop; - -typedef struct NSVGgradient { - float xform[6]; - char spread; - float fx, fy; - int nstops; - NSVGgradientStop stops[1]; -} NSVGgradient; - -typedef struct NSVGpaint { - char type; - union { - unsigned int color; - NSVGgradient* gradient; - }; -} NSVGpaint; - -typedef struct NSVGpath -{ - float* pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ... - int npts; // Total number of bezier points. - char closed; // Flag indicating if shapes should be treated as closed. - float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. - struct NSVGpath* next; // Pointer to next path, or NULL if last element. -} NSVGpath; - -typedef struct NSVGshape -{ - char id[64]; // Optional 'id' attr of the shape or its group - NSVGpaint fill; // Fill paint - NSVGpaint stroke; // Stroke paint - float opacity; // Opacity of the shape. - float strokeWidth; // Stroke width (scaled). - float strokeDashOffset; // Stroke dash offset (scaled). - float strokeDashArray[8]; // Stroke dash array (scaled). - char strokeDashCount; // Number of dash values in dash array. - char strokeLineJoin; // Stroke join type. - char strokeLineCap; // Stroke cap type. - float miterLimit; // Miter limit - char fillRule; // Fill rule, see NSVGfillRule. - unsigned char flags; // Logical or of NSVG_FLAGS_* flags - float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. - NSVGpath* paths; // Linked list of paths in the image. - struct NSVGshape* next; // Pointer to next shape, or NULL if last element. -} NSVGshape; - -typedef struct NSVGimage -{ - float width; // Width of the image. - float height; // Height of the image. - NSVGshape* shapes; // Linked list of shapes in the image. -} NSVGimage; - -// Parses SVG file from a file, returns SVG image as paths. -NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi); - -// Parses SVG file from a null terminated string, returns SVG image as paths. -// Important note: changes the string. -NSVGimage* nsvgParse(char* input, const char* units, float dpi); - -// Duplicates a path. -NSVGpath* nsvgDuplicatePath(NSVGpath* p); - -// Deletes an image. -void nsvgDelete(NSVGimage* image); - -#ifndef NANOSVG_CPLUSPLUS -#ifdef __cplusplus -} -#endif -#endif - -#ifdef NANOSVG_IMPLEMENTATION - -#include -#include -#include -#include - -#define NSVG_PI (3.14159265358979323846264338327f) -#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs. - -#define NSVG_ALIGN_MIN 0 -#define NSVG_ALIGN_MID 1 -#define NSVG_ALIGN_MAX 2 -#define NSVG_ALIGN_NONE 0 -#define NSVG_ALIGN_MEET 1 -#define NSVG_ALIGN_SLICE 2 - -#define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0) -#define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16)) - -#ifdef _MSC_VER - #pragma warning (disable: 4996) // Switch off security warnings - #pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings - #ifdef __cplusplus - #define NSVG_INLINE inline - #else - #define NSVG_INLINE - #endif -#else - #define NSVG_INLINE inline -#endif - - -static int nsvg__isspace(char c) -{ - return strchr(" \t\n\v\f\r", c) != 0; -} - -static int nsvg__isdigit(char c) -{ - return c >= '0' && c <= '9'; -} - -static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; } -static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; } - - -// Simple XML parser - -#define NSVG_XML_TAG 1 -#define NSVG_XML_CONTENT 2 -#define NSVG_XML_MAX_ATTRIBS 256 - -static void nsvg__parseContent(char* s, - void (*contentCb)(void* ud, const char* s), - void* ud) -{ - // Trim start white spaces - while (*s && nsvg__isspace(*s)) s++; - if (!*s) return; - - if (contentCb) - (*contentCb)(ud, s); -} - -static void nsvg__parseElement(char* s, - void (*startelCb)(void* ud, const char* el, const char** attr), - void (*endelCb)(void* ud, const char* el), - void* ud) -{ - const char* attr[NSVG_XML_MAX_ATTRIBS]; - int nattr = 0; - char* name; - int start = 0; - int end = 0; - char quote; - - // Skip white space after the '<' - while (*s && nsvg__isspace(*s)) s++; - - // Check if the tag is end tag - if (*s == '/') { - s++; - end = 1; - } else { - start = 1; - } - - // Skip comments, data and preprocessor stuff. - if (!*s || *s == '?' || *s == '!') - return; - - // Get tag name - name = s; - while (*s && !nsvg__isspace(*s)) s++; - if (*s) { *s++ = '\0'; } - - // Get attribs - while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) { - char* name = NULL; - char* value = NULL; - - // Skip white space before the attrib name - while (*s && nsvg__isspace(*s)) s++; - if (!*s) break; - if (*s == '/') { - end = 1; - break; - } - name = s; - // Find end of the attrib name. - while (*s && !nsvg__isspace(*s) && *s != '=') s++; - if (*s) { *s++ = '\0'; } - // Skip until the beginning of the value. - while (*s && *s != '\"' && *s != '\'') s++; - if (!*s) break; - quote = *s; - s++; - // Store value and find the end of it. - value = s; - while (*s && *s != quote) s++; - if (*s) { *s++ = '\0'; } - - // Store only well formed attributes - if (name && value) { - attr[nattr++] = name; - attr[nattr++] = value; - } - } - - // List terminator - attr[nattr++] = 0; - attr[nattr++] = 0; - - // Call callbacks. - if (start && startelCb) - (*startelCb)(ud, name, attr); - if (end && endelCb) - (*endelCb)(ud, name); -} - -int nsvg__parseXML(char* input, - void (*startelCb)(void* ud, const char* el, const char** attr), - void (*endelCb)(void* ud, const char* el), - void (*contentCb)(void* ud, const char* s), - void* ud) -{ - char* s = input; - char* mark = s; - int state = NSVG_XML_CONTENT; - while (*s) { - if (*s == '<' && state == NSVG_XML_CONTENT) { - // Start of a tag - *s++ = '\0'; - nsvg__parseContent(mark, contentCb, ud); - mark = s; - state = NSVG_XML_TAG; - } else if (*s == '>' && state == NSVG_XML_TAG) { - // Start of a content or new tag. - *s++ = '\0'; - nsvg__parseElement(mark, startelCb, endelCb, ud); - mark = s; - state = NSVG_XML_CONTENT; - } else { - s++; - } - } - - return 1; -} - - -/* Simple SVG parser. */ - -#define NSVG_MAX_ATTR 128 - -enum NSVGgradientUnits { - NSVG_USER_SPACE = 0, - NSVG_OBJECT_SPACE = 1 -}; - -#define NSVG_MAX_DASHES 8 - -enum NSVGunits { - NSVG_UNITS_USER, - NSVG_UNITS_PX, - NSVG_UNITS_PT, - NSVG_UNITS_PC, - NSVG_UNITS_MM, - NSVG_UNITS_CM, - NSVG_UNITS_IN, - NSVG_UNITS_PERCENT, - NSVG_UNITS_EM, - NSVG_UNITS_EX -}; - -typedef struct NSVGcoordinate { - float value; - int units; -} NSVGcoordinate; - -typedef struct NSVGlinearData { - NSVGcoordinate x1, y1, x2, y2; -} NSVGlinearData; - -typedef struct NSVGradialData { - NSVGcoordinate cx, cy, r, fx, fy; -} NSVGradialData; - -typedef struct NSVGgradientData -{ - char id[64]; - char ref[64]; - char type; - union { - NSVGlinearData linear; - NSVGradialData radial; - }; - char spread; - char units; - float xform[6]; - int nstops; - NSVGgradientStop* stops; - struct NSVGgradientData* next; -} NSVGgradientData; - -typedef struct NSVGattrib -{ - char id[64]; - float xform[6]; - unsigned int fillColor; - unsigned int strokeColor; - float opacity; - float fillOpacity; - float strokeOpacity; - char fillGradient[64]; - char strokeGradient[64]; - float strokeWidth; - float strokeDashOffset; - float strokeDashArray[NSVG_MAX_DASHES]; - int strokeDashCount; - char strokeLineJoin; - char strokeLineCap; - float miterLimit; - char fillRule; - float fontSize; - unsigned int stopColor; - float stopOpacity; - float stopOffset; - char hasFill; - char hasStroke; - char visible; -} NSVGattrib; - -typedef struct NSVGparser -{ - NSVGattrib attr[NSVG_MAX_ATTR]; - int attrHead; - float* pts; - int npts; - int cpts; - NSVGpath* plist; - NSVGimage* image; - NSVGgradientData* gradients; - NSVGshape* shapesTail; - float viewMinx, viewMiny, viewWidth, viewHeight; - int alignX, alignY, alignType; - float dpi; - char pathFlag; - char defsFlag; -} NSVGparser; - -static void nsvg__xformIdentity(float* t) -{ - t[0] = 1.0f; t[1] = 0.0f; - t[2] = 0.0f; t[3] = 1.0f; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformSetTranslation(float* t, float tx, float ty) -{ - t[0] = 1.0f; t[1] = 0.0f; - t[2] = 0.0f; t[3] = 1.0f; - t[4] = tx; t[5] = ty; -} - -static void nsvg__xformSetScale(float* t, float sx, float sy) -{ - t[0] = sx; t[1] = 0.0f; - t[2] = 0.0f; t[3] = sy; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformSetSkewX(float* t, float a) -{ - t[0] = 1.0f; t[1] = 0.0f; - t[2] = tanf(a); t[3] = 1.0f; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformSetSkewY(float* t, float a) -{ - t[0] = 1.0f; t[1] = tanf(a); - t[2] = 0.0f; t[3] = 1.0f; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformSetRotation(float* t, float a) -{ - float cs = cosf(a), sn = sinf(a); - t[0] = cs; t[1] = sn; - t[2] = -sn; t[3] = cs; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformMultiply(float* t, float* s) -{ - float t0 = t[0] * s[0] + t[1] * s[2]; - float t2 = t[2] * s[0] + t[3] * s[2]; - float t4 = t[4] * s[0] + t[5] * s[2] + s[4]; - t[1] = t[0] * s[1] + t[1] * s[3]; - t[3] = t[2] * s[1] + t[3] * s[3]; - t[5] = t[4] * s[1] + t[5] * s[3] + s[5]; - t[0] = t0; - t[2] = t2; - t[4] = t4; -} - -static void nsvg__xformInverse(float* inv, float* t) -{ - double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1]; - if (det > -1e-6 && det < 1e-6) { - nsvg__xformIdentity(t); - return; - } - invdet = 1.0 / det; - inv[0] = (float)(t[3] * invdet); - inv[2] = (float)(-t[2] * invdet); - inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet); - inv[1] = (float)(-t[1] * invdet); - inv[3] = (float)(t[0] * invdet); - inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet); -} - -static void nsvg__xformPremultiply(float* t, float* s) -{ - float s2[6]; - memcpy(s2, s, sizeof(float)*6); - nsvg__xformMultiply(s2, t); - memcpy(t, s2, sizeof(float)*6); -} - -static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t) -{ - *dx = x*t[0] + y*t[2] + t[4]; - *dy = x*t[1] + y*t[3] + t[5]; -} - -static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t) -{ - *dx = x*t[0] + y*t[2]; - *dy = x*t[1] + y*t[3]; -} - -#define NSVG_EPSILON (1e-12) - -static int nsvg__ptInBounds(float* pt, float* bounds) -{ - return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3]; -} - - -static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3) -{ - double it = 1.0-t; - return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3; -} - -static void nsvg__curveBounds(float* bounds, float* curve) -{ - int i, j, count; - double roots[2], a, b, c, b2ac, t, v; - float* v0 = &curve[0]; - float* v1 = &curve[2]; - float* v2 = &curve[4]; - float* v3 = &curve[6]; - - // Start the bounding box by end points - bounds[0] = nsvg__minf(v0[0], v3[0]); - bounds[1] = nsvg__minf(v0[1], v3[1]); - bounds[2] = nsvg__maxf(v0[0], v3[0]); - bounds[3] = nsvg__maxf(v0[1], v3[1]); - - // Bezier curve fits inside the convex hull of it's control points. - // If control points are inside the bounds, we're done. - if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds)) - return; - - // Add bezier curve inflection points in X and Y. - for (i = 0; i < 2; i++) { - a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i]; - b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i]; - c = 3.0 * v1[i] - 3.0 * v0[i]; - count = 0; - if (fabs(a) < NSVG_EPSILON) { - if (fabs(b) > NSVG_EPSILON) { - t = -c / b; - if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) - roots[count++] = t; - } - } else { - b2ac = b*b - 4.0*c*a; - if (b2ac > NSVG_EPSILON) { - t = (-b + sqrt(b2ac)) / (2.0 * a); - if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) - roots[count++] = t; - t = (-b - sqrt(b2ac)) / (2.0 * a); - if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) - roots[count++] = t; - } - } - for (j = 0; j < count; j++) { - v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]); - bounds[0+i] = nsvg__minf(bounds[0+i], (float)v); - bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v); - } - } -} - -static NSVGparser* nsvg__createParser(void) -{ - NSVGparser* p; - p = (NSVGparser*)malloc(sizeof(NSVGparser)); - if (p == NULL) goto error; - memset(p, 0, sizeof(NSVGparser)); - - p->image = (NSVGimage*)malloc(sizeof(NSVGimage)); - if (p->image == NULL) goto error; - memset(p->image, 0, sizeof(NSVGimage)); - - // Init style - nsvg__xformIdentity(p->attr[0].xform); - memset(p->attr[0].id, 0, sizeof p->attr[0].id); - p->attr[0].fillColor = NSVG_RGB(0,0,0); - p->attr[0].strokeColor = NSVG_RGB(0,0,0); - p->attr[0].opacity = 1; - p->attr[0].fillOpacity = 1; - p->attr[0].strokeOpacity = 1; - p->attr[0].stopOpacity = 1; - p->attr[0].strokeWidth = 1; - p->attr[0].strokeLineJoin = NSVG_JOIN_MITER; - p->attr[0].strokeLineCap = NSVG_CAP_BUTT; - p->attr[0].miterLimit = 4; - p->attr[0].fillRule = NSVG_FILLRULE_NONZERO; - p->attr[0].hasFill = 1; - p->attr[0].visible = 1; - - return p; - -error: - if (p) { - if (p->image) free(p->image); - free(p); - } - return NULL; -} - -static void nsvg__deletePaths(NSVGpath* path) -{ - while (path) { - NSVGpath *next = path->next; - if (path->pts != NULL) - free(path->pts); - free(path); - path = next; - } -} - -static void nsvg__deletePaint(NSVGpaint* paint) -{ - if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT) - free(paint->gradient); -} - -static void nsvg__deleteGradientData(NSVGgradientData* grad) -{ - NSVGgradientData* next; - while (grad != NULL) { - next = grad->next; - free(grad->stops); - free(grad); - grad = next; - } -} - -static void nsvg__deleteParser(NSVGparser* p) -{ - if (p != NULL) { - nsvg__deletePaths(p->plist); - nsvg__deleteGradientData(p->gradients); - nsvgDelete(p->image); - free(p->pts); - free(p); - } -} - -static void nsvg__resetPath(NSVGparser* p) -{ - p->npts = 0; -} - -static void nsvg__addPoint(NSVGparser* p, float x, float y) -{ - if (p->npts+1 > p->cpts) { - p->cpts = p->cpts ? p->cpts*2 : 8; - p->pts = (float*)realloc(p->pts, p->cpts*2*sizeof(float)); - if (!p->pts) return; - } - p->pts[p->npts*2+0] = x; - p->pts[p->npts*2+1] = y; - p->npts++; -} - -static void nsvg__moveTo(NSVGparser* p, float x, float y) -{ - if (p->npts > 0) { - p->pts[(p->npts-1)*2+0] = x; - p->pts[(p->npts-1)*2+1] = y; - } else { - nsvg__addPoint(p, x, y); - } -} - -static void nsvg__lineTo(NSVGparser* p, float x, float y) -{ - float px,py, dx,dy; - if (p->npts > 0) { - px = p->pts[(p->npts-1)*2+0]; - py = p->pts[(p->npts-1)*2+1]; - dx = x - px; - dy = y - py; - nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f); - nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f); - nsvg__addPoint(p, x, y); - } -} - -static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y) -{ - if (p->npts > 0) { - nsvg__addPoint(p, cpx1, cpy1); - nsvg__addPoint(p, cpx2, cpy2); - nsvg__addPoint(p, x, y); - } -} - -static NSVGattrib* nsvg__getAttr(NSVGparser* p) -{ - return &p->attr[p->attrHead]; -} - -static void nsvg__pushAttr(NSVGparser* p) -{ - if (p->attrHead < NSVG_MAX_ATTR-1) { - p->attrHead++; - memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(NSVGattrib)); - } -} - -static void nsvg__popAttr(NSVGparser* p) -{ - if (p->attrHead > 0) - p->attrHead--; -} - -static float nsvg__actualOrigX(NSVGparser* p) -{ - return p->viewMinx; -} - -static float nsvg__actualOrigY(NSVGparser* p) -{ - return p->viewMiny; -} - -static float nsvg__actualWidth(NSVGparser* p) -{ - return p->viewWidth; -} - -static float nsvg__actualHeight(NSVGparser* p) -{ - return p->viewHeight; -} - -static float nsvg__actualLength(NSVGparser* p) -{ - float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p); - return sqrtf(w*w + h*h) / sqrtf(2.0f); -} - -static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length) -{ - NSVGattrib* attr = nsvg__getAttr(p); - switch (c.units) { - case NSVG_UNITS_USER: return c.value; - case NSVG_UNITS_PX: return c.value; - case NSVG_UNITS_PT: return c.value / 72.0f * p->dpi; - case NSVG_UNITS_PC: return c.value / 6.0f * p->dpi; - case NSVG_UNITS_MM: return c.value / 25.4f * p->dpi; - case NSVG_UNITS_CM: return c.value / 2.54f * p->dpi; - case NSVG_UNITS_IN: return c.value * p->dpi; - case NSVG_UNITS_EM: return c.value * attr->fontSize; - case NSVG_UNITS_EX: return c.value * attr->fontSize * 0.52f; // x-height of Helvetica. - case NSVG_UNITS_PERCENT: return orig + c.value / 100.0f * length; - default: return c.value; - } - return c.value; -} - -static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id) -{ - NSVGgradientData* grad = p->gradients; - if (id == NULL || *id == '\0') - return NULL; - while (grad != NULL) { - if (strcmp(grad->id, id) == 0) - return grad; - grad = grad->next; - } - return NULL; -} - -static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, char* paintType) -{ - NSVGattrib* attr = nsvg__getAttr(p); - NSVGgradientData* data = NULL; - NSVGgradientData* ref = NULL; - NSVGgradientStop* stops = NULL; - NSVGgradient* grad; - float ox, oy, sw, sh, sl; - int nstops = 0; - int refIter; - - data = nsvg__findGradientData(p, id); - if (data == NULL) return NULL; - - // TODO: use ref to fill in all unset values too. - ref = data; - refIter = 0; - while (ref != NULL) { - NSVGgradientData* nextRef = NULL; - if (stops == NULL && ref->stops != NULL) { - stops = ref->stops; - nstops = ref->nstops; - break; - } - nextRef = nsvg__findGradientData(p, ref->ref); - if (nextRef == ref) break; // prevent infite loops on malformed data - ref = nextRef; - refIter++; - if (refIter > 32) break; // prevent infite loops on malformed data - } - if (stops == NULL) return NULL; - - grad = (NSVGgradient*)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(nstops-1)); - if (grad == NULL) return NULL; - - // The shape width and height. - if (data->units == NSVG_OBJECT_SPACE) { - ox = localBounds[0]; - oy = localBounds[1]; - sw = localBounds[2] - localBounds[0]; - sh = localBounds[3] - localBounds[1]; - } else { - ox = nsvg__actualOrigX(p); - oy = nsvg__actualOrigY(p); - sw = nsvg__actualWidth(p); - sh = nsvg__actualHeight(p); - } - sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f); - - if (data->type == NSVG_PAINT_LINEAR_GRADIENT) { - float x1, y1, x2, y2, dx, dy; - x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw); - y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh); - x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw); - y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh); - // Calculate transform aligned to the line - dx = x2 - x1; - dy = y2 - y1; - grad->xform[0] = dy; grad->xform[1] = -dx; - grad->xform[2] = dx; grad->xform[3] = dy; - grad->xform[4] = x1; grad->xform[5] = y1; - } else { - float cx, cy, fx, fy, r; - cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw); - cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh); - fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw); - fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh); - r = nsvg__convertToPixels(p, data->radial.r, 0, sl); - // Calculate transform aligned to the circle - grad->xform[0] = r; grad->xform[1] = 0; - grad->xform[2] = 0; grad->xform[3] = r; - grad->xform[4] = cx; grad->xform[5] = cy; - grad->fx = fx / r; - grad->fy = fy / r; - } - - nsvg__xformMultiply(grad->xform, data->xform); - nsvg__xformMultiply(grad->xform, attr->xform); - - grad->spread = data->spread; - memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop)); - grad->nstops = nstops; - - *paintType = data->type; - - return grad; -} - -static float nsvg__getAverageScale(float* t) -{ - float sx = sqrtf(t[0]*t[0] + t[2]*t[2]); - float sy = sqrtf(t[1]*t[1] + t[3]*t[3]); - return (sx + sy) * 0.5f; -} - -static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform) -{ - NSVGpath* path; - float curve[4*2], curveBounds[4]; - int i, first = 1; - for (path = shape->paths; path != NULL; path = path->next) { - nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform); - for (i = 0; i < path->npts-1; i += 3) { - nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform); - nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform); - nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform); - nsvg__curveBounds(curveBounds, curve); - if (first) { - bounds[0] = curveBounds[0]; - bounds[1] = curveBounds[1]; - bounds[2] = curveBounds[2]; - bounds[3] = curveBounds[3]; - first = 0; - } else { - bounds[0] = nsvg__minf(bounds[0], curveBounds[0]); - bounds[1] = nsvg__minf(bounds[1], curveBounds[1]); - bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]); - bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]); - } - curve[0] = curve[6]; - curve[1] = curve[7]; - } - } -} - -static void nsvg__addShape(NSVGparser* p) -{ - NSVGattrib* attr = nsvg__getAttr(p); - float scale = 1.0f; - NSVGshape* shape; - NSVGpath* path; - int i; - - if (p->plist == NULL) - return; - - shape = (NSVGshape*)malloc(sizeof(NSVGshape)); - if (shape == NULL) goto error; - memset(shape, 0, sizeof(NSVGshape)); - - memcpy(shape->id, attr->id, sizeof shape->id); - scale = nsvg__getAverageScale(attr->xform); - shape->strokeWidth = attr->strokeWidth * scale; - shape->strokeDashOffset = attr->strokeDashOffset * scale; - shape->strokeDashCount = (char)attr->strokeDashCount; - for (i = 0; i < attr->strokeDashCount; i++) - shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale; - shape->strokeLineJoin = attr->strokeLineJoin; - shape->strokeLineCap = attr->strokeLineCap; - shape->miterLimit = attr->miterLimit; - shape->fillRule = attr->fillRule; - shape->opacity = attr->opacity; - - shape->paths = p->plist; - p->plist = NULL; - - // Calculate shape bounds - shape->bounds[0] = shape->paths->bounds[0]; - shape->bounds[1] = shape->paths->bounds[1]; - shape->bounds[2] = shape->paths->bounds[2]; - shape->bounds[3] = shape->paths->bounds[3]; - for (path = shape->paths->next; path != NULL; path = path->next) { - shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]); - shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]); - shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]); - shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]); - } - - // Set fill - if (attr->hasFill == 0) { - shape->fill.type = NSVG_PAINT_NONE; - } else if (attr->hasFill == 1) { - shape->fill.type = NSVG_PAINT_COLOR; - shape->fill.color = attr->fillColor; - shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24; - } else if (attr->hasFill == 2) { - float inv[6], localBounds[4]; - nsvg__xformInverse(inv, attr->xform); - nsvg__getLocalBounds(localBounds, shape, inv); - shape->fill.gradient = nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type); - if (shape->fill.gradient == NULL) { - shape->fill.type = NSVG_PAINT_NONE; - } - } - - // Set stroke - if (attr->hasStroke == 0) { - shape->stroke.type = NSVG_PAINT_NONE; - } else if (attr->hasStroke == 1) { - shape->stroke.type = NSVG_PAINT_COLOR; - shape->stroke.color = attr->strokeColor; - shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24; - } else if (attr->hasStroke == 2) { - float inv[6], localBounds[4]; - nsvg__xformInverse(inv, attr->xform); - nsvg__getLocalBounds(localBounds, shape, inv); - shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, &shape->stroke.type); - if (shape->stroke.gradient == NULL) - shape->stroke.type = NSVG_PAINT_NONE; - } - - // Set flags - shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00); - - // Add to tail - if (p->image->shapes == NULL) - p->image->shapes = shape; - else - p->shapesTail->next = shape; - p->shapesTail = shape; - - return; - -error: - if (shape) free(shape); -} - -static void nsvg__addPath(NSVGparser* p, char closed) -{ - NSVGattrib* attr = nsvg__getAttr(p); - NSVGpath* path = NULL; - float bounds[4]; - float* curve; - int i; - - if (p->npts < 4) - return; - - if (closed) - nsvg__lineTo(p, p->pts[0], p->pts[1]); - - // Expect 1 + N*3 points (N = number of cubic bezier segments). - if ((p->npts % 3) != 1) - return; - - path = (NSVGpath*)malloc(sizeof(NSVGpath)); - if (path == NULL) goto error; - memset(path, 0, sizeof(NSVGpath)); - - path->pts = (float*)malloc(p->npts*2*sizeof(float)); - if (path->pts == NULL) goto error; - path->closed = closed; - path->npts = p->npts; - - // Transform path. - for (i = 0; i < p->npts; ++i) - nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], attr->xform); - - // Find bounds - for (i = 0; i < path->npts-1; i += 3) { - curve = &path->pts[i*2]; - nsvg__curveBounds(bounds, curve); - if (i == 0) { - path->bounds[0] = bounds[0]; - path->bounds[1] = bounds[1]; - path->bounds[2] = bounds[2]; - path->bounds[3] = bounds[3]; - } else { - path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]); - path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]); - path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]); - path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]); - } - } - - path->next = p->plist; - p->plist = path; - - return; - -error: - if (path != NULL) { - if (path->pts != NULL) free(path->pts); - free(path); - } -} - -// We roll our own string to float because the std library one uses locale and messes things up. -static double nsvg__atof(const char* s) -{ - char* cur = (char*)s; - char* end = NULL; - double res = 0.0, sign = 1.0; - long long intPart = 0, fracPart = 0; - char hasIntPart = 0, hasFracPart = 0; - - // Parse optional sign - if (*cur == '+') { - cur++; - } else if (*cur == '-') { - sign = -1; - cur++; - } - - // Parse integer part - if (nsvg__isdigit(*cur)) { - // Parse digit sequence - intPart = strtoll(cur, &end, 10); - if (cur != end) { - res = (double)intPart; - hasIntPart = 1; - cur = end; - } - } - - // Parse fractional part. - if (*cur == '.') { - cur++; // Skip '.' - if (nsvg__isdigit(*cur)) { - // Parse digit sequence - fracPart = strtoll(cur, &end, 10); - if (cur != end) { - res += (double)fracPart / pow(10.0, (double)(end - cur)); - hasFracPart = 1; - cur = end; - } - } - } - - // A valid number should have integer or fractional part. - if (!hasIntPart && !hasFracPart) - return 0.0; - - // Parse optional exponent - if (*cur == 'e' || *cur == 'E') { - long expPart = 0; - cur++; // skip 'E' - expPart = strtol(cur, &end, 10); // Parse digit sequence with sign - if (cur != end) { - res *= pow(10.0, (double)expPart); - } - } - - return res * sign; -} - - -static const char* nsvg__parseNumber(const char* s, char* it, const int size) -{ - const int last = size-1; - int i = 0; - - // sign - if (*s == '-' || *s == '+') { - if (i < last) it[i++] = *s; - s++; - } - // integer part - while (*s && nsvg__isdigit(*s)) { - if (i < last) it[i++] = *s; - s++; - } - if (*s == '.') { - // decimal point - if (i < last) it[i++] = *s; - s++; - // fraction part - while (*s && nsvg__isdigit(*s)) { - if (i < last) it[i++] = *s; - s++; - } - } - // exponent - if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) { - if (i < last) it[i++] = *s; - s++; - if (*s == '-' || *s == '+') { - if (i < last) it[i++] = *s; - s++; - } - while (*s && nsvg__isdigit(*s)) { - if (i < last) it[i++] = *s; - s++; - } - } - it[i] = '\0'; - - return s; -} - -static const char* nsvg__getNextPathItem(const char* s, char* it) -{ - it[0] = '\0'; - // Skip white spaces and commas - while (*s && (nsvg__isspace(*s) || *s == ',')) s++; - if (!*s) return s; - if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) { - s = nsvg__parseNumber(s, it, 64); - } else { - // Parse command - it[0] = *s++; - it[1] = '\0'; - return s; - } - - return s; -} - -static unsigned int nsvg__parseColorHex(const char* str) -{ - unsigned int r=0, g=0, b=0; - if (sscanf(str, "#%2x%2x%2x", &r, &g, &b) == 3 ) // 2 digit hex - return NSVG_RGB(r, g, b); - if (sscanf(str, "#%1x%1x%1x", &r, &g, &b) == 3 ) // 1 digit hex, e.g. #abc -> 0xccbbaa - return NSVG_RGB(r*17, g*17, b*17); // same effect as (r<<4|r), (g<<4|g), .. - return NSVG_RGB(128, 128, 128); -} - -// Parse rgb color. The pointer 'str' must point at "rgb(" (4+ characters). -// This function returns gray (rgb(128, 128, 128) == '#808080') on parse errors -// for backwards compatibility. Note: other image viewers return black instead. - -static unsigned int nsvg__parseColorRGB(const char* str) -{ - int i; - unsigned int rgbi[3]; - float rgbf[3]; - // try decimal integers first - if (sscanf(str, "rgb(%u, %u, %u)", &rgbi[0], &rgbi[1], &rgbi[2]) != 3) { - // integers failed, try percent values (float, locale independent) - const char delimiter[3] = {',', ',', ')'}; - str += 4; // skip "rgb(" - for (i = 0; i < 3; i++) { - while (*str && (nsvg__isspace(*str))) str++; // skip leading spaces - if (*str == '+') str++; // skip '+' (don't allow '-') - if (!*str) break; - rgbf[i] = nsvg__atof(str); - - // Note 1: it would be great if nsvg__atof() returned how many - // bytes it consumed but it doesn't. We need to skip the number, - // the '%' character, spaces, and the delimiter ',' or ')'. - - // Note 2: The following code does not allow values like "33.%", - // i.e. a decimal point w/o fractional part, but this is consistent - // with other image viewers, e.g. firefox, chrome, eog, gimp. - - while (*str && nsvg__isdigit(*str)) str++; // skip integer part - if (*str == '.') { - str++; - if (!nsvg__isdigit(*str)) break; // error: no digit after '.' - while (*str && nsvg__isdigit(*str)) str++; // skip fractional part - } - if (*str == '%') str++; else break; - while (nsvg__isspace(*str)) str++; - if (*str == delimiter[i]) str++; - else break; - } - if (i == 3) { - rgbi[0] = roundf(rgbf[0] * 2.55f); - rgbi[1] = roundf(rgbf[1] * 2.55f); - rgbi[2] = roundf(rgbf[2] * 2.55f); - } else { - rgbi[0] = rgbi[1] = rgbi[2] = 128; - } - } - // clip values as the CSS spec requires - for (i = 0; i < 3; i++) { - if (rgbi[i] > 255) rgbi[i] = 255; - } - return NSVG_RGB(rgbi[0], rgbi[1], rgbi[2]); -} - -typedef struct NSVGNamedColor { - const char* name; - unsigned int color; -} NSVGNamedColor; - -NSVGNamedColor nsvg__colors[] = { - - { "red", NSVG_RGB(255, 0, 0) }, - { "green", NSVG_RGB( 0, 128, 0) }, - { "blue", NSVG_RGB( 0, 0, 255) }, - { "yellow", NSVG_RGB(255, 255, 0) }, - { "cyan", NSVG_RGB( 0, 255, 255) }, - { "magenta", NSVG_RGB(255, 0, 255) }, - { "black", NSVG_RGB( 0, 0, 0) }, - { "grey", NSVG_RGB(128, 128, 128) }, - { "gray", NSVG_RGB(128, 128, 128) }, - { "white", NSVG_RGB(255, 255, 255) }, - -#ifdef NANOSVG_ALL_COLOR_KEYWORDS - { "aliceblue", NSVG_RGB(240, 248, 255) }, - { "antiquewhite", NSVG_RGB(250, 235, 215) }, - { "aqua", NSVG_RGB( 0, 255, 255) }, - { "aquamarine", NSVG_RGB(127, 255, 212) }, - { "azure", NSVG_RGB(240, 255, 255) }, - { "beige", NSVG_RGB(245, 245, 220) }, - { "bisque", NSVG_RGB(255, 228, 196) }, - { "blanchedalmond", NSVG_RGB(255, 235, 205) }, - { "blueviolet", NSVG_RGB(138, 43, 226) }, - { "brown", NSVG_RGB(165, 42, 42) }, - { "burlywood", NSVG_RGB(222, 184, 135) }, - { "cadetblue", NSVG_RGB( 95, 158, 160) }, - { "chartreuse", NSVG_RGB(127, 255, 0) }, - { "chocolate", NSVG_RGB(210, 105, 30) }, - { "coral", NSVG_RGB(255, 127, 80) }, - { "cornflowerblue", NSVG_RGB(100, 149, 237) }, - { "cornsilk", NSVG_RGB(255, 248, 220) }, - { "crimson", NSVG_RGB(220, 20, 60) }, - { "darkblue", NSVG_RGB( 0, 0, 139) }, - { "darkcyan", NSVG_RGB( 0, 139, 139) }, - { "darkgoldenrod", NSVG_RGB(184, 134, 11) }, - { "darkgray", NSVG_RGB(169, 169, 169) }, - { "darkgreen", NSVG_RGB( 0, 100, 0) }, - { "darkgrey", NSVG_RGB(169, 169, 169) }, - { "darkkhaki", NSVG_RGB(189, 183, 107) }, - { "darkmagenta", NSVG_RGB(139, 0, 139) }, - { "darkolivegreen", NSVG_RGB( 85, 107, 47) }, - { "darkorange", NSVG_RGB(255, 140, 0) }, - { "darkorchid", NSVG_RGB(153, 50, 204) }, - { "darkred", NSVG_RGB(139, 0, 0) }, - { "darksalmon", NSVG_RGB(233, 150, 122) }, - { "darkseagreen", NSVG_RGB(143, 188, 143) }, - { "darkslateblue", NSVG_RGB( 72, 61, 139) }, - { "darkslategray", NSVG_RGB( 47, 79, 79) }, - { "darkslategrey", NSVG_RGB( 47, 79, 79) }, - { "darkturquoise", NSVG_RGB( 0, 206, 209) }, - { "darkviolet", NSVG_RGB(148, 0, 211) }, - { "deeppink", NSVG_RGB(255, 20, 147) }, - { "deepskyblue", NSVG_RGB( 0, 191, 255) }, - { "dimgray", NSVG_RGB(105, 105, 105) }, - { "dimgrey", NSVG_RGB(105, 105, 105) }, - { "dodgerblue", NSVG_RGB( 30, 144, 255) }, - { "firebrick", NSVG_RGB(178, 34, 34) }, - { "floralwhite", NSVG_RGB(255, 250, 240) }, - { "forestgreen", NSVG_RGB( 34, 139, 34) }, - { "fuchsia", NSVG_RGB(255, 0, 255) }, - { "gainsboro", NSVG_RGB(220, 220, 220) }, - { "ghostwhite", NSVG_RGB(248, 248, 255) }, - { "gold", NSVG_RGB(255, 215, 0) }, - { "goldenrod", NSVG_RGB(218, 165, 32) }, - { "greenyellow", NSVG_RGB(173, 255, 47) }, - { "honeydew", NSVG_RGB(240, 255, 240) }, - { "hotpink", NSVG_RGB(255, 105, 180) }, - { "indianred", NSVG_RGB(205, 92, 92) }, - { "indigo", NSVG_RGB( 75, 0, 130) }, - { "ivory", NSVG_RGB(255, 255, 240) }, - { "khaki", NSVG_RGB(240, 230, 140) }, - { "lavender", NSVG_RGB(230, 230, 250) }, - { "lavenderblush", NSVG_RGB(255, 240, 245) }, - { "lawngreen", NSVG_RGB(124, 252, 0) }, - { "lemonchiffon", NSVG_RGB(255, 250, 205) }, - { "lightblue", NSVG_RGB(173, 216, 230) }, - { "lightcoral", NSVG_RGB(240, 128, 128) }, - { "lightcyan", NSVG_RGB(224, 255, 255) }, - { "lightgoldenrodyellow", NSVG_RGB(250, 250, 210) }, - { "lightgray", NSVG_RGB(211, 211, 211) }, - { "lightgreen", NSVG_RGB(144, 238, 144) }, - { "lightgrey", NSVG_RGB(211, 211, 211) }, - { "lightpink", NSVG_RGB(255, 182, 193) }, - { "lightsalmon", NSVG_RGB(255, 160, 122) }, - { "lightseagreen", NSVG_RGB( 32, 178, 170) }, - { "lightskyblue", NSVG_RGB(135, 206, 250) }, - { "lightslategray", NSVG_RGB(119, 136, 153) }, - { "lightslategrey", NSVG_RGB(119, 136, 153) }, - { "lightsteelblue", NSVG_RGB(176, 196, 222) }, - { "lightyellow", NSVG_RGB(255, 255, 224) }, - { "lime", NSVG_RGB( 0, 255, 0) }, - { "limegreen", NSVG_RGB( 50, 205, 50) }, - { "linen", NSVG_RGB(250, 240, 230) }, - { "maroon", NSVG_RGB(128, 0, 0) }, - { "mediumaquamarine", NSVG_RGB(102, 205, 170) }, - { "mediumblue", NSVG_RGB( 0, 0, 205) }, - { "mediumorchid", NSVG_RGB(186, 85, 211) }, - { "mediumpurple", NSVG_RGB(147, 112, 219) }, - { "mediumseagreen", NSVG_RGB( 60, 179, 113) }, - { "mediumslateblue", NSVG_RGB(123, 104, 238) }, - { "mediumspringgreen", NSVG_RGB( 0, 250, 154) }, - { "mediumturquoise", NSVG_RGB( 72, 209, 204) }, - { "mediumvioletred", NSVG_RGB(199, 21, 133) }, - { "midnightblue", NSVG_RGB( 25, 25, 112) }, - { "mintcream", NSVG_RGB(245, 255, 250) }, - { "mistyrose", NSVG_RGB(255, 228, 225) }, - { "moccasin", NSVG_RGB(255, 228, 181) }, - { "navajowhite", NSVG_RGB(255, 222, 173) }, - { "navy", NSVG_RGB( 0, 0, 128) }, - { "oldlace", NSVG_RGB(253, 245, 230) }, - { "olive", NSVG_RGB(128, 128, 0) }, - { "olivedrab", NSVG_RGB(107, 142, 35) }, - { "orange", NSVG_RGB(255, 165, 0) }, - { "orangered", NSVG_RGB(255, 69, 0) }, - { "orchid", NSVG_RGB(218, 112, 214) }, - { "palegoldenrod", NSVG_RGB(238, 232, 170) }, - { "palegreen", NSVG_RGB(152, 251, 152) }, - { "paleturquoise", NSVG_RGB(175, 238, 238) }, - { "palevioletred", NSVG_RGB(219, 112, 147) }, - { "papayawhip", NSVG_RGB(255, 239, 213) }, - { "peachpuff", NSVG_RGB(255, 218, 185) }, - { "peru", NSVG_RGB(205, 133, 63) }, - { "pink", NSVG_RGB(255, 192, 203) }, - { "plum", NSVG_RGB(221, 160, 221) }, - { "powderblue", NSVG_RGB(176, 224, 230) }, - { "purple", NSVG_RGB(128, 0, 128) }, - { "rosybrown", NSVG_RGB(188, 143, 143) }, - { "royalblue", NSVG_RGB( 65, 105, 225) }, - { "saddlebrown", NSVG_RGB(139, 69, 19) }, - { "salmon", NSVG_RGB(250, 128, 114) }, - { "sandybrown", NSVG_RGB(244, 164, 96) }, - { "seagreen", NSVG_RGB( 46, 139, 87) }, - { "seashell", NSVG_RGB(255, 245, 238) }, - { "sienna", NSVG_RGB(160, 82, 45) }, - { "silver", NSVG_RGB(192, 192, 192) }, - { "skyblue", NSVG_RGB(135, 206, 235) }, - { "slateblue", NSVG_RGB(106, 90, 205) }, - { "slategray", NSVG_RGB(112, 128, 144) }, - { "slategrey", NSVG_RGB(112, 128, 144) }, - { "snow", NSVG_RGB(255, 250, 250) }, - { "springgreen", NSVG_RGB( 0, 255, 127) }, - { "steelblue", NSVG_RGB( 70, 130, 180) }, - { "tan", NSVG_RGB(210, 180, 140) }, - { "teal", NSVG_RGB( 0, 128, 128) }, - { "thistle", NSVG_RGB(216, 191, 216) }, - { "tomato", NSVG_RGB(255, 99, 71) }, - { "turquoise", NSVG_RGB( 64, 224, 208) }, - { "violet", NSVG_RGB(238, 130, 238) }, - { "wheat", NSVG_RGB(245, 222, 179) }, - { "whitesmoke", NSVG_RGB(245, 245, 245) }, - { "yellowgreen", NSVG_RGB(154, 205, 50) }, -#endif -}; - -static unsigned int nsvg__parseColorName(const char* str) -{ - int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor); - - for (i = 0; i < ncolors; i++) { - if (strcmp(nsvg__colors[i].name, str) == 0) { - return nsvg__colors[i].color; - } - } - - return NSVG_RGB(128, 128, 128); -} - -static unsigned int nsvg__parseColor(const char* str) -{ - size_t len = 0; - while(*str == ' ') ++str; - len = strlen(str); - if (len >= 1 && *str == '#') - return nsvg__parseColorHex(str); - else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(') - return nsvg__parseColorRGB(str); - return nsvg__parseColorName(str); -} - -static float nsvg__parseOpacity(const char* str) -{ - float val = nsvg__atof(str); - if (val < 0.0f) val = 0.0f; - if (val > 1.0f) val = 1.0f; - return val; -} - -static float nsvg__parseMiterLimit(const char* str) -{ - float val = nsvg__atof(str); - if (val < 0.0f) val = 0.0f; - return val; -} - -static int nsvg__parseUnits(const char* units) -{ - if (units[0] == 'p' && units[1] == 'x') - return NSVG_UNITS_PX; - else if (units[0] == 'p' && units[1] == 't') - return NSVG_UNITS_PT; - else if (units[0] == 'p' && units[1] == 'c') - return NSVG_UNITS_PC; - else if (units[0] == 'm' && units[1] == 'm') - return NSVG_UNITS_MM; - else if (units[0] == 'c' && units[1] == 'm') - return NSVG_UNITS_CM; - else if (units[0] == 'i' && units[1] == 'n') - return NSVG_UNITS_IN; - else if (units[0] == '%') - return NSVG_UNITS_PERCENT; - else if (units[0] == 'e' && units[1] == 'm') - return NSVG_UNITS_EM; - else if (units[0] == 'e' && units[1] == 'x') - return NSVG_UNITS_EX; - return NSVG_UNITS_USER; -} - -static int nsvg__isCoordinate(const char* s) -{ - // optional sign - if (*s == '-' || *s == '+') - s++; - // must have at least one digit, or start by a dot - return (nsvg__isdigit(*s) || *s == '.'); -} - -static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str) -{ - NSVGcoordinate coord = {0, NSVG_UNITS_USER}; - char buf[64]; - coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64)); - coord.value = nsvg__atof(buf); - return coord; -} - -static NSVGcoordinate nsvg__coord(float v, int units) -{ - NSVGcoordinate coord = {v, units}; - return coord; -} - -static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, float length) -{ - NSVGcoordinate coord = nsvg__parseCoordinateRaw(str); - return nsvg__convertToPixels(p, coord, orig, length); -} - -static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int* na) -{ - const char* end; - const char* ptr; - char it[64]; - - *na = 0; - ptr = str; - while (*ptr && *ptr != '(') ++ptr; - if (*ptr == 0) - return 1; - end = ptr; - while (*end && *end != ')') ++end; - if (*end == 0) - return 1; - - while (ptr < end) { - if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) { - if (*na >= maxNa) return 0; - ptr = nsvg__parseNumber(ptr, it, 64); - args[(*na)++] = (float)nsvg__atof(it); - } else { - ++ptr; - } - } - return (int)(end - str); -} - - -static int nsvg__parseMatrix(float* xform, const char* str) -{ - float t[6]; - int na = 0; - int len = nsvg__parseTransformArgs(str, t, 6, &na); - if (na != 6) return len; - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseTranslate(float* xform, const char* str) -{ - float args[2]; - float t[6]; - int na = 0; - int len = nsvg__parseTransformArgs(str, args, 2, &na); - if (na == 1) args[1] = 0.0; - - nsvg__xformSetTranslation(t, args[0], args[1]); - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseScale(float* xform, const char* str) -{ - float args[2]; - int na = 0; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 2, &na); - if (na == 1) args[1] = args[0]; - nsvg__xformSetScale(t, args[0], args[1]); - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseSkewX(float* xform, const char* str) -{ - float args[1]; - int na = 0; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 1, &na); - nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI); - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseSkewY(float* xform, const char* str) -{ - float args[1]; - int na = 0; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 1, &na); - nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI); - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseRotate(float* xform, const char* str) -{ - float args[3]; - int na = 0; - float m[6]; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 3, &na); - if (na == 1) - args[1] = args[2] = 0.0f; - nsvg__xformIdentity(m); - - if (na > 1) { - nsvg__xformSetTranslation(t, -args[1], -args[2]); - nsvg__xformMultiply(m, t); - } - - nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI); - nsvg__xformMultiply(m, t); - - if (na > 1) { - nsvg__xformSetTranslation(t, args[1], args[2]); - nsvg__xformMultiply(m, t); - } - - memcpy(xform, m, sizeof(float)*6); - - return len; -} - -static void nsvg__parseTransform(float* xform, const char* str) -{ - float t[6]; - int len; - nsvg__xformIdentity(xform); - while (*str) - { - if (strncmp(str, "matrix", 6) == 0) - len = nsvg__parseMatrix(t, str); - else if (strncmp(str, "translate", 9) == 0) - len = nsvg__parseTranslate(t, str); - else if (strncmp(str, "scale", 5) == 0) - len = nsvg__parseScale(t, str); - else if (strncmp(str, "rotate", 6) == 0) - len = nsvg__parseRotate(t, str); - else if (strncmp(str, "skewX", 5) == 0) - len = nsvg__parseSkewX(t, str); - else if (strncmp(str, "skewY", 5) == 0) - len = nsvg__parseSkewY(t, str); - else{ - ++str; - continue; - } - if (len != 0) { - str += len; - } else { - ++str; - continue; - } - - nsvg__xformPremultiply(xform, t); - } -} - -static void nsvg__parseUrl(char* id, const char* str) -{ - int i = 0; - str += 4; // "url("; - if (*str && *str == '#') - str++; - while (i < 63 && *str && *str != ')') { - id[i] = *str++; - i++; - } - id[i] = '\0'; -} - -static char nsvg__parseLineCap(const char* str) -{ - if (strcmp(str, "butt") == 0) - return NSVG_CAP_BUTT; - else if (strcmp(str, "round") == 0) - return NSVG_CAP_ROUND; - else if (strcmp(str, "square") == 0) - return NSVG_CAP_SQUARE; - // TODO: handle inherit. - return NSVG_CAP_BUTT; -} - -static char nsvg__parseLineJoin(const char* str) -{ - if (strcmp(str, "miter") == 0) - return NSVG_JOIN_MITER; - else if (strcmp(str, "round") == 0) - return NSVG_JOIN_ROUND; - else if (strcmp(str, "bevel") == 0) - return NSVG_JOIN_BEVEL; - // TODO: handle inherit. - return NSVG_JOIN_MITER; -} - -static char nsvg__parseFillRule(const char* str) -{ - if (strcmp(str, "nonzero") == 0) - return NSVG_FILLRULE_NONZERO; - else if (strcmp(str, "evenodd") == 0) - return NSVG_FILLRULE_EVENODD; - // TODO: handle inherit. - return NSVG_FILLRULE_NONZERO; -} - -static const char* nsvg__getNextDashItem(const char* s, char* it) -{ - int n = 0; - it[0] = '\0'; - // Skip white spaces and commas - while (*s && (nsvg__isspace(*s) || *s == ',')) s++; - // Advance until whitespace, comma or end. - while (*s && (!nsvg__isspace(*s) && *s != ',')) { - if (n < 63) - it[n++] = *s; - s++; - } - it[n++] = '\0'; - return s; -} - -static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* strokeDashArray) -{ - char item[64]; - int count = 0, i; - float sum = 0.0f; - - // Handle "none" - if (str[0] == 'n') - return 0; - - // Parse dashes - while (*str) { - str = nsvg__getNextDashItem(str, item); - if (!*item) break; - if (count < NSVG_MAX_DASHES) - strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p))); - } - - for (i = 0; i < count; i++) - sum += strokeDashArray[i]; - if (sum <= 1e-6f) - count = 0; - - return count; -} - -static void nsvg__parseStyle(NSVGparser* p, const char* str); - -static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value) -{ - float xform[6]; - NSVGattrib* attr = nsvg__getAttr(p); - if (!attr) return 0; - - if (strcmp(name, "style") == 0) { - nsvg__parseStyle(p, value); - } else if (strcmp(name, "display") == 0) { - if (strcmp(value, "none") == 0) - attr->visible = 0; - // Don't reset ->visible on display:inline, one display:none hides the whole subtree - - } else if (strcmp(name, "fill") == 0) { - if (strcmp(value, "none") == 0) { - attr->hasFill = 0; - } else if (strncmp(value, "url(", 4) == 0) { - attr->hasFill = 2; - nsvg__parseUrl(attr->fillGradient, value); - } else { - attr->hasFill = 1; - attr->fillColor = nsvg__parseColor(value); - } - } else if (strcmp(name, "opacity") == 0) { - attr->opacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "fill-opacity") == 0) { - attr->fillOpacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "stroke") == 0) { - if (strcmp(value, "none") == 0) { - attr->hasStroke = 0; - } else if (strncmp(value, "url(", 4) == 0) { - attr->hasStroke = 2; - nsvg__parseUrl(attr->strokeGradient, value); - } else { - attr->hasStroke = 1; - attr->strokeColor = nsvg__parseColor(value); - } - } else if (strcmp(name, "stroke-width") == 0) { - attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); - } else if (strcmp(name, "stroke-dasharray") == 0) { - attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray); - } else if (strcmp(name, "stroke-dashoffset") == 0) { - attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); - } else if (strcmp(name, "stroke-opacity") == 0) { - attr->strokeOpacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "stroke-linecap") == 0) { - attr->strokeLineCap = nsvg__parseLineCap(value); - } else if (strcmp(name, "stroke-linejoin") == 0) { - attr->strokeLineJoin = nsvg__parseLineJoin(value); - } else if (strcmp(name, "stroke-miterlimit") == 0) { - attr->miterLimit = nsvg__parseMiterLimit(value); - } else if (strcmp(name, "fill-rule") == 0) { - attr->fillRule = nsvg__parseFillRule(value); - } else if (strcmp(name, "font-size") == 0) { - attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); - } else if (strcmp(name, "transform") == 0) { - nsvg__parseTransform(xform, value); - nsvg__xformPremultiply(attr->xform, xform); - } else if (strcmp(name, "stop-color") == 0) { - attr->stopColor = nsvg__parseColor(value); - } else if (strcmp(name, "stop-opacity") == 0) { - attr->stopOpacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "offset") == 0) { - attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f); - } else if (strcmp(name, "id") == 0) { - strncpy(attr->id, value, 63); - attr->id[63] = '\0'; - } else { - return 0; - } - return 1; -} - -static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* end) -{ - const char* str; - const char* val; - char name[512]; - char value[512]; - int n; - - str = start; - while (str < end && *str != ':') ++str; - - val = str; - - // Right Trim - while (str > start && (*str == ':' || nsvg__isspace(*str))) --str; - ++str; - - n = (int)(str - start); - if (n > 511) n = 511; - if (n) memcpy(name, start, n); - name[n] = 0; - - while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val; - - n = (int)(end - val); - if (n > 511) n = 511; - if (n) memcpy(value, val, n); - value[n] = 0; - - return nsvg__parseAttr(p, name, value); -} - -static void nsvg__parseStyle(NSVGparser* p, const char* str) -{ - const char* start; - const char* end; - - while (*str) { - // Left Trim - while(*str && nsvg__isspace(*str)) ++str; - start = str; - while(*str && *str != ';') ++str; - end = str; - - // Right Trim - while (end > start && (*end == ';' || nsvg__isspace(*end))) --end; - ++end; - - nsvg__parseNameValue(p, start, end); - if (*str) ++str; - } -} - -static void nsvg__parseAttribs(NSVGparser* p, const char** attr) -{ - int i; - for (i = 0; attr[i]; i += 2) - { - if (strcmp(attr[i], "style") == 0) - nsvg__parseStyle(p, attr[i + 1]); - else - nsvg__parseAttr(p, attr[i], attr[i + 1]); - } -} - -static int nsvg__getArgsPerElement(char cmd) -{ - switch (cmd) { - case 'v': - case 'V': - case 'h': - case 'H': - return 1; - case 'm': - case 'M': - case 'l': - case 'L': - case 't': - case 'T': - return 2; - case 'q': - case 'Q': - case 's': - case 'S': - return 4; - case 'c': - case 'C': - return 6; - case 'a': - case 'A': - return 7; - case 'z': - case 'Z': - return 0; - } - return -1; -} - -static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) { - *cpx += args[0]; - *cpy += args[1]; - } else { - *cpx = args[0]; - *cpy = args[1]; - } - nsvg__moveTo(p, *cpx, *cpy); -} - -static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) { - *cpx += args[0]; - *cpy += args[1]; - } else { - *cpx = args[0]; - *cpy = args[1]; - } - nsvg__lineTo(p, *cpx, *cpy); -} - -static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) - *cpx += args[0]; - else - *cpx = args[0]; - nsvg__lineTo(p, *cpx, *cpy); -} - -static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) - *cpy += args[0]; - else - *cpy = args[0]; - nsvg__lineTo(p, *cpx, *cpy); -} - -static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x2, y2, cx1, cy1, cx2, cy2; - - if (rel) { - cx1 = *cpx + args[0]; - cy1 = *cpy + args[1]; - cx2 = *cpx + args[2]; - cy2 = *cpy + args[3]; - x2 = *cpx + args[4]; - y2 = *cpy + args[5]; - } else { - cx1 = args[0]; - cy1 = args[1]; - cx2 = args[2]; - cy2 = args[3]; - x2 = args[4]; - y2 = args[5]; - } - - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); - - *cpx2 = cx2; - *cpy2 = cy2; - *cpx = x2; - *cpy = y2; -} - -static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x1, y1, x2, y2, cx1, cy1, cx2, cy2; - - x1 = *cpx; - y1 = *cpy; - if (rel) { - cx2 = *cpx + args[0]; - cy2 = *cpy + args[1]; - x2 = *cpx + args[2]; - y2 = *cpy + args[3]; - } else { - cx2 = args[0]; - cy2 = args[1]; - x2 = args[2]; - y2 = args[3]; - } - - cx1 = 2*x1 - *cpx2; - cy1 = 2*y1 - *cpy2; - - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); - - *cpx2 = cx2; - *cpy2 = cy2; - *cpx = x2; - *cpy = y2; -} - -static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x1, y1, x2, y2, cx, cy; - float cx1, cy1, cx2, cy2; - - x1 = *cpx; - y1 = *cpy; - if (rel) { - cx = *cpx + args[0]; - cy = *cpy + args[1]; - x2 = *cpx + args[2]; - y2 = *cpy + args[3]; - } else { - cx = args[0]; - cy = args[1]; - x2 = args[2]; - y2 = args[3]; - } - - // Convert to cubic bezier - cx1 = x1 + 2.0f/3.0f*(cx - x1); - cy1 = y1 + 2.0f/3.0f*(cy - y1); - cx2 = x2 + 2.0f/3.0f*(cx - x2); - cy2 = y2 + 2.0f/3.0f*(cy - y2); - - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); - - *cpx2 = cx; - *cpy2 = cy; - *cpx = x2; - *cpy = y2; -} - -static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x1, y1, x2, y2, cx, cy; - float cx1, cy1, cx2, cy2; - - x1 = *cpx; - y1 = *cpy; - if (rel) { - x2 = *cpx + args[0]; - y2 = *cpy + args[1]; - } else { - x2 = args[0]; - y2 = args[1]; - } - - cx = 2*x1 - *cpx2; - cy = 2*y1 - *cpy2; - - // Convert to cubix bezier - cx1 = x1 + 2.0f/3.0f*(cx - x1); - cy1 = y1 + 2.0f/3.0f*(cy - y1); - cx2 = x2 + 2.0f/3.0f*(cx - x2); - cy2 = y2 + 2.0f/3.0f*(cy - y2); - - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); - - *cpx2 = cx; - *cpy2 = cy; - *cpx = x2; - *cpy = y2; -} - -static float nsvg__sqr(float x) { return x*x; } -static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); } - -static float nsvg__vecrat(float ux, float uy, float vx, float vy) -{ - return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy)); -} - -static float nsvg__vecang(float ux, float uy, float vx, float vy) -{ - float r = nsvg__vecrat(ux,uy, vx,vy); - if (r < -1.0f) r = -1.0f; - if (r > 1.0f) r = 1.0f; - return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r); -} - -static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - // Ported from canvg (https://code.google.com/p/canvg/) - float rx, ry, rotx; - float x1, y1, x2, y2, cx, cy, dx, dy, d; - float x1p, y1p, cxp, cyp, s, sa, sb; - float ux, uy, vx, vy, a1, da; - float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6]; - float sinrx, cosrx; - int fa, fs; - int i, ndivs; - float hda, kappa; - - rx = fabsf(args[0]); // y radius - ry = fabsf(args[1]); // x radius - rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle - fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc - fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction - x1 = *cpx; // start point - y1 = *cpy; - if (rel) { // end point - x2 = *cpx + args[5]; - y2 = *cpy + args[6]; - } else { - x2 = args[5]; - y2 = args[6]; - } - - dx = x1 - x2; - dy = y1 - y2; - d = sqrtf(dx*dx + dy*dy); - if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) { - // The arc degenerates to a line - nsvg__lineTo(p, x2, y2); - *cpx = x2; - *cpy = y2; - return; - } - - sinrx = sinf(rotx); - cosrx = cosf(rotx); - - // Convert to center point parameterization. - // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes - // 1) Compute x1', y1' - x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f; - y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f; - d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry); - if (d > 1) { - d = sqrtf(d); - rx *= d; - ry *= d; - } - // 2) Compute cx', cy' - s = 0.0f; - sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p); - sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p); - if (sa < 0.0f) sa = 0.0f; - if (sb > 0.0f) - s = sqrtf(sa / sb); - if (fa == fs) - s = -s; - cxp = s * rx * y1p / ry; - cyp = s * -ry * x1p / rx; - - // 3) Compute cx,cy from cx',cy' - cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp; - cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp; - - // 4) Calculate theta1, and delta theta. - ux = (x1p - cxp) / rx; - uy = (y1p - cyp) / ry; - vx = (-x1p - cxp) / rx; - vy = (-y1p - cyp) / ry; - a1 = nsvg__vecang(1.0f,0.0f, ux,uy); // Initial angle - da = nsvg__vecang(ux,uy, vx,vy); // Delta angle - -// if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI; -// if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0; - - if (fs == 0 && da > 0) - da -= 2 * NSVG_PI; - else if (fs == 1 && da < 0) - da += 2 * NSVG_PI; - - // Approximate the arc using cubic spline segments. - t[0] = cosrx; t[1] = sinrx; - t[2] = -sinrx; t[3] = cosrx; - t[4] = cx; t[5] = cy; - - // Split arc into max 90 degree segments. - // The loop assumes an iteration per end point (including start and end), this +1. - ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f); - hda = (da / (float)ndivs) / 2.0f; - // Fix for ticket #179: division by 0: avoid cotangens around 0 (infinite) - if ((hda < 1e-3f) && (hda > -1e-3f)) - hda *= 0.5f; - else - hda = (1.0f - cosf(hda)) / sinf(hda); - kappa = fabsf(4.0f / 3.0f * hda); - if (da < 0.0f) - kappa = -kappa; - - for (i = 0; i <= ndivs; i++) { - a = a1 + da * ((float)i/(float)ndivs); - dx = cosf(a); - dy = sinf(a); - nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position - nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); // tangent - if (i > 0) - nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, x, y); - px = x; - py = y; - ptanx = tanx; - ptany = tany; - } - - *cpx = x2; - *cpy = y2; -} - -static void nsvg__parsePath(NSVGparser* p, const char** attr) -{ - const char* s = NULL; - char cmd = '\0'; - float args[10]; - int nargs; - int rargs = 0; - char initPoint; - float cpx, cpy, cpx2, cpy2; - const char* tmp[4]; - char closedFlag; - int i; - char item[64]; - - for (i = 0; attr[i]; i += 2) { - if (strcmp(attr[i], "d") == 0) { - s = attr[i + 1]; - } else { - tmp[0] = attr[i]; - tmp[1] = attr[i + 1]; - tmp[2] = 0; - tmp[3] = 0; - nsvg__parseAttribs(p, tmp); - } - } - - if (s) { - nsvg__resetPath(p); - cpx = 0; cpy = 0; - cpx2 = 0; cpy2 = 0; - initPoint = 0; - closedFlag = 0; - nargs = 0; - - while (*s) { - s = nsvg__getNextPathItem(s, item); - if (!*item) break; - if (cmd != '\0' && nsvg__isCoordinate(item)) { - if (nargs < 10) - args[nargs++] = (float)nsvg__atof(item); - if (nargs >= rargs) { - switch (cmd) { - case 'm': - case 'M': - nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0); - // Moveto can be followed by multiple coordinate pairs, - // which should be treated as linetos. - cmd = (cmd == 'm') ? 'l' : 'L'; - rargs = nsvg__getArgsPerElement(cmd); - cpx2 = cpx; cpy2 = cpy; - initPoint = 1; - break; - case 'l': - case 'L': - nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - case 'H': - case 'h': - nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - case 'V': - case 'v': - nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - case 'C': - case 'c': - nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0); - break; - case 'S': - case 's': - nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0); - break; - case 'Q': - case 'q': - nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0); - break; - case 'T': - case 't': - nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0); - break; - case 'A': - case 'a': - nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - default: - if (nargs >= 2) { - cpx = args[nargs-2]; - cpy = args[nargs-1]; - cpx2 = cpx; cpy2 = cpy; - } - break; - } - nargs = 0; - } - } else { - cmd = item[0]; - if (cmd == 'M' || cmd == 'm') { - // Commit path. - if (p->npts > 0) - nsvg__addPath(p, closedFlag); - // Start new subpath. - nsvg__resetPath(p); - closedFlag = 0; - nargs = 0; - } else if (initPoint == 0) { - // Do not allow other commands until initial point has been set (moveTo called once). - cmd = '\0'; - } - if (cmd == 'Z' || cmd == 'z') { - closedFlag = 1; - // Commit path. - if (p->npts > 0) { - // Move current point to first point - cpx = p->pts[0]; - cpy = p->pts[1]; - cpx2 = cpx; cpy2 = cpy; - nsvg__addPath(p, closedFlag); - } - // Start new subpath. - nsvg__resetPath(p); - nsvg__moveTo(p, cpx, cpy); - closedFlag = 0; - nargs = 0; - } - rargs = nsvg__getArgsPerElement(cmd); - if (rargs == -1) { - // Command not recognized - cmd = '\0'; - rargs = 0; - } - } - } - // Commit path. - if (p->npts) - nsvg__addPath(p, closedFlag); - } - - nsvg__addShape(p); -} - -static void nsvg__parseRect(NSVGparser* p, const char** attr) -{ - float x = 0.0f; - float y = 0.0f; - float w = 0.0f; - float h = 0.0f; - float rx = -1.0f; // marks not set - float ry = -1.0f; - int i; - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "width") == 0) w = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)); - if (strcmp(attr[i], "height") == 0) h = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)); - if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); - if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); - } - } - - if (rx < 0.0f && ry > 0.0f) rx = ry; - if (ry < 0.0f && rx > 0.0f) ry = rx; - if (rx < 0.0f) rx = 0.0f; - if (ry < 0.0f) ry = 0.0f; - if (rx > w/2.0f) rx = w/2.0f; - if (ry > h/2.0f) ry = h/2.0f; - - if (w != 0.0f && h != 0.0f) { - nsvg__resetPath(p); - - if (rx < 0.00001f || ry < 0.0001f) { - nsvg__moveTo(p, x, y); - nsvg__lineTo(p, x+w, y); - nsvg__lineTo(p, x+w, y+h); - nsvg__lineTo(p, x, y+h); - } else { - // Rounded rectangle - nsvg__moveTo(p, x+rx, y); - nsvg__lineTo(p, x+w-rx, y); - nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, y+ry*(1-NSVG_KAPPA90), x+w, y+ry); - nsvg__lineTo(p, x+w, y+h-ry); - nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h); - nsvg__lineTo(p, x+rx, y+h); - nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry); - nsvg__lineTo(p, x, y+ry); - nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y); - } - - nsvg__addPath(p, 1); - - nsvg__addShape(p); - } -} - -static void nsvg__parseCircle(NSVGparser* p, const char** attr) -{ - float cx = 0.0f; - float cy = 0.0f; - float r = 0.0f; - int i; - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "r") == 0) r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p))); - } - } - - if (r > 0.0f) { - nsvg__resetPath(p); - - nsvg__moveTo(p, cx+r, cy); - nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r); - nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy); - nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r); - nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy); - - nsvg__addPath(p, 1); - - nsvg__addShape(p); - } -} - -static void nsvg__parseEllipse(NSVGparser* p, const char** attr) -{ - float cx = 0.0f; - float cy = 0.0f; - float rx = 0.0f; - float ry = 0.0f; - int i; - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); - if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); - } - } - - if (rx > 0.0f && ry > 0.0f) { - - nsvg__resetPath(p); - - nsvg__moveTo(p, cx+rx, cy); - nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry); - nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy); - nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry); - nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy); - - nsvg__addPath(p, 1); - - nsvg__addShape(p); - } -} - -static void nsvg__parseLine(NSVGparser* p, const char** attr) -{ - float x1 = 0.0; - float y1 = 0.0; - float x2 = 0.0; - float y2 = 0.0; - int i; - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - } - } - - nsvg__resetPath(p); - - nsvg__moveTo(p, x1, y1); - nsvg__lineTo(p, x2, y2); - - nsvg__addPath(p, 0); - - nsvg__addShape(p); -} - -static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag) -{ - int i; - const char* s; - float args[2]; - int nargs, npts = 0; - char item[64]; - - nsvg__resetPath(p); - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "points") == 0) { - s = attr[i + 1]; - nargs = 0; - while (*s) { - s = nsvg__getNextPathItem(s, item); - args[nargs++] = (float)nsvg__atof(item); - if (nargs >= 2) { - if (npts == 0) - nsvg__moveTo(p, args[0], args[1]); - else - nsvg__lineTo(p, args[0], args[1]); - nargs = 0; - npts++; - } - } - } - } - } - - nsvg__addPath(p, (char)closeFlag); - - nsvg__addShape(p); -} - -static void nsvg__parseSVG(NSVGparser* p, const char** attr) -{ - int i; - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "width") == 0) { - p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); - } else if (strcmp(attr[i], "height") == 0) { - p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); - } else if (strcmp(attr[i], "viewBox") == 0) { - const char *s = attr[i + 1]; - char buf[64]; - s = nsvg__parseNumber(s, buf, 64); - p->viewMinx = nsvg__atof(buf); - while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++; - if (!*s) return; - s = nsvg__parseNumber(s, buf, 64); - p->viewMiny = nsvg__atof(buf); - while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++; - if (!*s) return; - s = nsvg__parseNumber(s, buf, 64); - p->viewWidth = nsvg__atof(buf); - while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++; - if (!*s) return; - s = nsvg__parseNumber(s, buf, 64); - p->viewHeight = nsvg__atof(buf); - } else if (strcmp(attr[i], "preserveAspectRatio") == 0) { - if (strstr(attr[i + 1], "none") != 0) { - // No uniform scaling - p->alignType = NSVG_ALIGN_NONE; - } else { - // Parse X align - if (strstr(attr[i + 1], "xMin") != 0) - p->alignX = NSVG_ALIGN_MIN; - else if (strstr(attr[i + 1], "xMid") != 0) - p->alignX = NSVG_ALIGN_MID; - else if (strstr(attr[i + 1], "xMax") != 0) - p->alignX = NSVG_ALIGN_MAX; - // Parse X align - if (strstr(attr[i + 1], "yMin") != 0) - p->alignY = NSVG_ALIGN_MIN; - else if (strstr(attr[i + 1], "yMid") != 0) - p->alignY = NSVG_ALIGN_MID; - else if (strstr(attr[i + 1], "yMax") != 0) - p->alignY = NSVG_ALIGN_MAX; - // Parse meet/slice - p->alignType = NSVG_ALIGN_MEET; - if (strstr(attr[i + 1], "slice") != 0) - p->alignType = NSVG_ALIGN_SLICE; - } - } - } - } -} - -static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type) -{ - int i; - NSVGgradientData* grad = (NSVGgradientData*)malloc(sizeof(NSVGgradientData)); - if (grad == NULL) return; - memset(grad, 0, sizeof(NSVGgradientData)); - grad->units = NSVG_OBJECT_SPACE; - grad->type = type; - if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) { - grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); - grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); - grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT); - grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); - } else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) { - grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); - grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); - grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); - } - - nsvg__xformIdentity(grad->xform); - - for (i = 0; attr[i]; i += 2) { - if (strcmp(attr[i], "id") == 0) { - strncpy(grad->id, attr[i+1], 63); - grad->id[63] = '\0'; - } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "gradientUnits") == 0) { - if (strcmp(attr[i+1], "objectBoundingBox") == 0) - grad->units = NSVG_OBJECT_SPACE; - else - grad->units = NSVG_USER_SPACE; - } else if (strcmp(attr[i], "gradientTransform") == 0) { - nsvg__parseTransform(grad->xform, attr[i + 1]); - } else if (strcmp(attr[i], "cx") == 0) { - grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "cy") == 0) { - grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "r") == 0) { - grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "fx") == 0) { - grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "fy") == 0) { - grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "x1") == 0) { - grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "y1") == 0) { - grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "x2") == 0) { - grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "y2") == 0) { - grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "spreadMethod") == 0) { - if (strcmp(attr[i+1], "pad") == 0) - grad->spread = NSVG_SPREAD_PAD; - else if (strcmp(attr[i+1], "reflect") == 0) - grad->spread = NSVG_SPREAD_REFLECT; - else if (strcmp(attr[i+1], "repeat") == 0) - grad->spread = NSVG_SPREAD_REPEAT; - } else if (strcmp(attr[i], "xlink:href") == 0) { - const char *href = attr[i+1]; - strncpy(grad->ref, href+1, 62); - grad->ref[62] = '\0'; - } - } - } - - grad->next = p->gradients; - p->gradients = grad; -} - -static void nsvg__parseGradientStop(NSVGparser* p, const char** attr) -{ - NSVGattrib* curAttr = nsvg__getAttr(p); - NSVGgradientData* grad; - NSVGgradientStop* stop; - int i, idx; - - curAttr->stopOffset = 0; - curAttr->stopColor = 0; - curAttr->stopOpacity = 1.0f; - - for (i = 0; attr[i]; i += 2) { - nsvg__parseAttr(p, attr[i], attr[i + 1]); - } - - // Add stop to the last gradient. - grad = p->gradients; - if (grad == NULL) return; - - grad->nstops++; - grad->stops = (NSVGgradientStop*)realloc(grad->stops, sizeof(NSVGgradientStop)*grad->nstops); - if (grad->stops == NULL) return; - - // Insert - idx = grad->nstops-1; - for (i = 0; i < grad->nstops-1; i++) { - if (curAttr->stopOffset < grad->stops[i].offset) { - idx = i; - break; - } - } - if (idx != grad->nstops-1) { - for (i = grad->nstops-1; i > idx; i--) - grad->stops[i] = grad->stops[i-1]; - } - - stop = &grad->stops[idx]; - stop->color = curAttr->stopColor; - stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24; - stop->offset = curAttr->stopOffset; -} - -static void nsvg__startElement(void* ud, const char* el, const char** attr) -{ - NSVGparser* p = (NSVGparser*)ud; - - if (p->defsFlag) { - // Skip everything but gradients in defs - if (strcmp(el, "linearGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); - } else if (strcmp(el, "radialGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); - } else if (strcmp(el, "stop") == 0) { - nsvg__parseGradientStop(p, attr); - } - return; - } - - if (strcmp(el, "g") == 0) { - nsvg__pushAttr(p); - nsvg__parseAttribs(p, attr); - } else if (strcmp(el, "path") == 0) { - if (p->pathFlag) // Do not allow nested paths. - return; - nsvg__pushAttr(p); - nsvg__parsePath(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "rect") == 0) { - nsvg__pushAttr(p); - nsvg__parseRect(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "circle") == 0) { - nsvg__pushAttr(p); - nsvg__parseCircle(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "ellipse") == 0) { - nsvg__pushAttr(p); - nsvg__parseEllipse(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "line") == 0) { - nsvg__pushAttr(p); - nsvg__parseLine(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "polyline") == 0) { - nsvg__pushAttr(p); - nsvg__parsePoly(p, attr, 0); - nsvg__popAttr(p); - } else if (strcmp(el, "polygon") == 0) { - nsvg__pushAttr(p); - nsvg__parsePoly(p, attr, 1); - nsvg__popAttr(p); - } else if (strcmp(el, "linearGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); - } else if (strcmp(el, "radialGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); - } else if (strcmp(el, "stop") == 0) { - nsvg__parseGradientStop(p, attr); - } else if (strcmp(el, "defs") == 0) { - p->defsFlag = 1; - } else if (strcmp(el, "svg") == 0) { - nsvg__parseSVG(p, attr); - } -} - -static void nsvg__endElement(void* ud, const char* el) -{ - NSVGparser* p = (NSVGparser*)ud; - - if (strcmp(el, "g") == 0) { - nsvg__popAttr(p); - } else if (strcmp(el, "path") == 0) { - p->pathFlag = 0; - } else if (strcmp(el, "defs") == 0) { - p->defsFlag = 0; - } -} - -static void nsvg__content(void* ud, const char* s) -{ - NSVG_NOTUSED(ud); - NSVG_NOTUSED(s); - // empty -} - -static void nsvg__imageBounds(NSVGparser* p, float* bounds) -{ - NSVGshape* shape; - shape = p->image->shapes; - if (shape == NULL) { - bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0; - return; - } - bounds[0] = shape->bounds[0]; - bounds[1] = shape->bounds[1]; - bounds[2] = shape->bounds[2]; - bounds[3] = shape->bounds[3]; - for (shape = shape->next; shape != NULL; shape = shape->next) { - bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]); - bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]); - bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]); - bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]); - } -} - -static float nsvg__viewAlign(float content, float container, int type) -{ - if (type == NSVG_ALIGN_MIN) - return 0; - else if (type == NSVG_ALIGN_MAX) - return container - content; - // mid - return (container - content) * 0.5f; -} - -static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy) -{ - float t[6]; - nsvg__xformSetTranslation(t, tx, ty); - nsvg__xformMultiply (grad->xform, t); - - nsvg__xformSetScale(t, sx, sy); - nsvg__xformMultiply (grad->xform, t); -} - -static void nsvg__scaleToViewbox(NSVGparser* p, const char* units) -{ - NSVGshape* shape; - NSVGpath* path; - float tx, ty, sx, sy, us, bounds[4], t[6], avgs; - int i; - float* pt; - - // Guess image size if not set completely. - nsvg__imageBounds(p, bounds); - - if (p->viewWidth == 0) { - if (p->image->width > 0) { - p->viewWidth = p->image->width; - } else { - p->viewMinx = bounds[0]; - p->viewWidth = bounds[2] - bounds[0]; - } - } - if (p->viewHeight == 0) { - if (p->image->height > 0) { - p->viewHeight = p->image->height; - } else { - p->viewMiny = bounds[1]; - p->viewHeight = bounds[3] - bounds[1]; - } - } - if (p->image->width == 0) - p->image->width = p->viewWidth; - if (p->image->height == 0) - p->image->height = p->viewHeight; - - tx = -p->viewMinx; - ty = -p->viewMiny; - sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0; - sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0; - // Unit scaling - us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f); - - // Fix aspect ratio - if (p->alignType == NSVG_ALIGN_MEET) { - // fit whole image into viewbox - sx = sy = nsvg__minf(sx, sy); - tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; - ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; - } else if (p->alignType == NSVG_ALIGN_SLICE) { - // fill whole viewbox with image - sx = sy = nsvg__maxf(sx, sy); - tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; - ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; - } - - // Transform - sx *= us; - sy *= us; - avgs = (sx+sy) / 2.0f; - for (shape = p->image->shapes; shape != NULL; shape = shape->next) { - shape->bounds[0] = (shape->bounds[0] + tx) * sx; - shape->bounds[1] = (shape->bounds[1] + ty) * sy; - shape->bounds[2] = (shape->bounds[2] + tx) * sx; - shape->bounds[3] = (shape->bounds[3] + ty) * sy; - for (path = shape->paths; path != NULL; path = path->next) { - path->bounds[0] = (path->bounds[0] + tx) * sx; - path->bounds[1] = (path->bounds[1] + ty) * sy; - path->bounds[2] = (path->bounds[2] + tx) * sx; - path->bounds[3] = (path->bounds[3] + ty) * sy; - for (i =0; i < path->npts; i++) { - pt = &path->pts[i*2]; - pt[0] = (pt[0] + tx) * sx; - pt[1] = (pt[1] + ty) * sy; - } - } - - if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) { - nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy); - memcpy(t, shape->fill.gradient->xform, sizeof(float)*6); - nsvg__xformInverse(shape->fill.gradient->xform, t); - } - if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) { - nsvg__scaleGradient(shape->stroke.gradient, tx,ty, sx,sy); - memcpy(t, shape->stroke.gradient->xform, sizeof(float)*6); - nsvg__xformInverse(shape->stroke.gradient->xform, t); - } - - shape->strokeWidth *= avgs; - shape->strokeDashOffset *= avgs; - for (i = 0; i < shape->strokeDashCount; i++) - shape->strokeDashArray[i] *= avgs; - } -} - -NSVGimage* nsvgParse(char* input, const char* units, float dpi) -{ - NSVGparser* p; - NSVGimage* ret = 0; - - p = nsvg__createParser(); - if (p == NULL) { - return NULL; - } - p->dpi = dpi; - - nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p); - - // Scale to viewBox - nsvg__scaleToViewbox(p, units); - - ret = p->image; - p->image = NULL; - - nsvg__deleteParser(p); - - return ret; -} - -NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi) -{ - FILE* fp = NULL; - size_t size; - char* data = NULL; - NSVGimage* image = NULL; - - fp = fopen(filename, "rb"); - if (!fp) goto error; - fseek(fp, 0, SEEK_END); - size = ftell(fp); - fseek(fp, 0, SEEK_SET); - data = (char*)malloc(size+1); - if (data == NULL) goto error; - if (fread(data, 1, size, fp) != size) goto error; - data[size] = '\0'; // Must be null terminated. - fclose(fp); - image = nsvgParse(data, units, dpi); - free(data); - - return image; - -error: - if (fp) fclose(fp); - if (data) free(data); - if (image) nsvgDelete(image); - return NULL; -} - -NSVGpath* nsvgDuplicatePath(NSVGpath* p) -{ - NSVGpath* res = NULL; - - if (p == NULL) - return NULL; - - res = (NSVGpath*)malloc(sizeof(NSVGpath)); - if (res == NULL) goto error; - memset(res, 0, sizeof(NSVGpath)); - - res->pts = (float*)malloc(p->npts*2*sizeof(float)); - if (res->pts == NULL) goto error; - memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2); - res->npts = p->npts; - - memcpy(res->bounds, p->bounds, sizeof(p->bounds)); - - res->closed = p->closed; - - return res; - -error: - if (res != NULL) { - free(res->pts); - free(res); - } - return NULL; -} - -void nsvgDelete(NSVGimage* image) -{ - NSVGshape *snext, *shape; - if (image == NULL) return; - shape = image->shapes; - while (shape != NULL) { - snext = shape->next; - nsvg__deletePaths(shape->paths); - nsvg__deletePaint(&shape->fill); - nsvg__deletePaint(&shape->stroke); - free(shape); - shape = snext; - } - free(image); -} - -#endif // NANOSVG_IMPLEMENTATION - -#endif // NANOSVG_H diff --git a/src/external/nanosvgrast.h b/src/external/nanosvgrast.h deleted file mode 100644 index 6e23acb7b..000000000 --- a/src/external/nanosvgrast.h +++ /dev/null @@ -1,1458 +0,0 @@ -/* - * Copyright (c) 2013-14 Mikko Mononen memon@inside.org - * - * 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. - * - * The polygon rasterization is heavily based on stb_truetype rasterizer - * by Sean Barrett - http://nothings.org/ - * - */ - -#ifndef NANOSVGRAST_H -#define NANOSVGRAST_H - -#include "nanosvg.h" - -#ifndef NANOSVGRAST_CPLUSPLUS -#ifdef __cplusplus -extern "C" { -#endif -#endif - -typedef struct NSVGrasterizer NSVGrasterizer; - -/* Example Usage: - // Load SVG - NSVGimage* image; - image = nsvgParseFromFile("test.svg", "px", 96); - - // Create rasterizer (can be used to render multiple images). - struct NSVGrasterizer* rast = nsvgCreateRasterizer(); - // Allocate memory for image - unsigned char* img = malloc(w*h*4); - // Rasterize - nsvgRasterize(rast, image, 0,0,1, img, w, h, w*4); -*/ - -// Allocated rasterizer context. -NSVGrasterizer* nsvgCreateRasterizer(void); - -// Rasterizes SVG image, returns RGBA image (non-premultiplied alpha) -// r - pointer to rasterizer context -// image - pointer to image to rasterize -// tx,ty - image offset (applied after scaling) -// scale - image scale -// dst - pointer to destination image data, 4 bytes per pixel (RGBA) -// w - width of the image to render -// h - height of the image to render -// stride - number of bytes per scaleline in the destination buffer -void nsvgRasterize(NSVGrasterizer* r, - NSVGimage* image, float tx, float ty, float scale, - unsigned char* dst, int w, int h, int stride); - -// Deletes rasterizer context. -void nsvgDeleteRasterizer(NSVGrasterizer*); - - -#ifndef NANOSVGRAST_CPLUSPLUS -#ifdef __cplusplus -} -#endif -#endif - -#ifdef NANOSVGRAST_IMPLEMENTATION - -#include -#include -#include - -#define NSVG__SUBSAMPLES 5 -#define NSVG__FIXSHIFT 10 -#define NSVG__FIX (1 << NSVG__FIXSHIFT) -#define NSVG__FIXMASK (NSVG__FIX-1) -#define NSVG__MEMPAGE_SIZE 1024 - -typedef struct NSVGedge { - float x0,y0, x1,y1; - int dir; - struct NSVGedge* next; -} NSVGedge; - -typedef struct NSVGpoint { - float x, y; - float dx, dy; - float len; - float dmx, dmy; - unsigned char flags; -} NSVGpoint; - -typedef struct NSVGactiveEdge { - int x,dx; - float ey; - int dir; - struct NSVGactiveEdge *next; -} NSVGactiveEdge; - -typedef struct NSVGmemPage { - unsigned char mem[NSVG__MEMPAGE_SIZE]; - int size; - struct NSVGmemPage* next; -} NSVGmemPage; - -typedef struct NSVGcachedPaint { - char type; - char spread; - float xform[6]; - unsigned int colors[256]; -} NSVGcachedPaint; - -struct NSVGrasterizer -{ - float px, py; - - float tessTol; - float distTol; - - NSVGedge* edges; - int nedges; - int cedges; - - NSVGpoint* points; - int npoints; - int cpoints; - - NSVGpoint* points2; - int npoints2; - int cpoints2; - - NSVGactiveEdge* freelist; - NSVGmemPage* pages; - NSVGmemPage* curpage; - - unsigned char* scanline; - int cscanline; - - unsigned char* bitmap; - int width, height, stride; -}; - -NSVGrasterizer* nsvgCreateRasterizer(void) -{ - NSVGrasterizer* r = (NSVGrasterizer*)malloc(sizeof(NSVGrasterizer)); - if (r == NULL) goto error; - memset(r, 0, sizeof(NSVGrasterizer)); - - r->tessTol = 0.25f; - r->distTol = 0.01f; - - return r; - -error: - nsvgDeleteRasterizer(r); - return NULL; -} - -void nsvgDeleteRasterizer(NSVGrasterizer* r) -{ - NSVGmemPage* p; - - if (r == NULL) return; - - p = r->pages; - while (p != NULL) { - NSVGmemPage* next = p->next; - free(p); - p = next; - } - - if (r->edges) free(r->edges); - if (r->points) free(r->points); - if (r->points2) free(r->points2); - if (r->scanline) free(r->scanline); - - free(r); -} - -static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur) -{ - NSVGmemPage *newp; - - // If using existing chain, return the next page in chain - if (cur != NULL && cur->next != NULL) { - return cur->next; - } - - // Alloc new page - newp = (NSVGmemPage*)malloc(sizeof(NSVGmemPage)); - if (newp == NULL) return NULL; - memset(newp, 0, sizeof(NSVGmemPage)); - - // Add to linked list - if (cur != NULL) - cur->next = newp; - else - r->pages = newp; - - return newp; -} - -static void nsvg__resetPool(NSVGrasterizer* r) -{ - NSVGmemPage* p = r->pages; - while (p != NULL) { - p->size = 0; - p = p->next; - } - r->curpage = r->pages; -} - -static unsigned char* nsvg__alloc(NSVGrasterizer* r, int size) -{ - unsigned char* buf; - if (size > NSVG__MEMPAGE_SIZE) return NULL; - if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) { - r->curpage = nsvg__nextPage(r, r->curpage); - } - buf = &r->curpage->mem[r->curpage->size]; - r->curpage->size += size; - return buf; -} - -static int nsvg__ptEquals(float x1, float y1, float x2, float y2, float tol) -{ - float dx = x2 - x1; - float dy = y2 - y1; - return dx*dx + dy*dy < tol*tol; -} - -static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags) -{ - NSVGpoint* pt; - - if (r->npoints > 0) { - pt = &r->points[r->npoints-1]; - if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) { - pt->flags = (unsigned char)(pt->flags | flags); - return; - } - } - - if (r->npoints+1 > r->cpoints) { - r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64; - r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints); - if (r->points == NULL) return; - } - - pt = &r->points[r->npoints]; - pt->x = x; - pt->y = y; - pt->flags = (unsigned char)flags; - r->npoints++; -} - -static void nsvg__appendPathPoint(NSVGrasterizer* r, NSVGpoint pt) -{ - if (r->npoints+1 > r->cpoints) { - r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64; - r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints); - if (r->points == NULL) return; - } - r->points[r->npoints] = pt; - r->npoints++; -} - -static void nsvg__duplicatePoints(NSVGrasterizer* r) -{ - if (r->npoints > r->cpoints2) { - r->cpoints2 = r->npoints; - r->points2 = (NSVGpoint*)realloc(r->points2, sizeof(NSVGpoint) * r->cpoints2); - if (r->points2 == NULL) return; - } - - memcpy(r->points2, r->points, sizeof(NSVGpoint) * r->npoints); - r->npoints2 = r->npoints; -} - -static void nsvg__addEdge(NSVGrasterizer* r, float x0, float y0, float x1, float y1) -{ - NSVGedge* e; - - // Skip horizontal edges - if (y0 == y1) - return; - - if (r->nedges+1 > r->cedges) { - r->cedges = r->cedges > 0 ? r->cedges * 2 : 64; - r->edges = (NSVGedge*)realloc(r->edges, sizeof(NSVGedge) * r->cedges); - if (r->edges == NULL) return; - } - - e = &r->edges[r->nedges]; - r->nedges++; - - if (y0 < y1) { - e->x0 = x0; - e->y0 = y0; - e->x1 = x1; - e->y1 = y1; - e->dir = 1; - } else { - e->x0 = x1; - e->y0 = y1; - e->x1 = x0; - e->y1 = y0; - e->dir = -1; - } -} - -static float nsvg__normalize(float *x, float* y) -{ - float d = sqrtf((*x)*(*x) + (*y)*(*y)); - if (d > 1e-6f) { - float id = 1.0f / d; - *x *= id; - *y *= id; - } - return d; -} - -static float nsvg__absf(float x) { return x < 0 ? -x : x; } - -static void nsvg__flattenCubicBez(NSVGrasterizer* r, - float x1, float y1, float x2, float y2, - float x3, float y3, float x4, float y4, - int level, int type) -{ - float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234; - float dx,dy,d2,d3; - - if (level > 10) return; - - x12 = (x1+x2)*0.5f; - y12 = (y1+y2)*0.5f; - x23 = (x2+x3)*0.5f; - y23 = (y2+y3)*0.5f; - x34 = (x3+x4)*0.5f; - y34 = (y3+y4)*0.5f; - x123 = (x12+x23)*0.5f; - y123 = (y12+y23)*0.5f; - - dx = x4 - x1; - dy = y4 - y1; - d2 = nsvg__absf(((x2 - x4) * dy - (y2 - y4) * dx)); - d3 = nsvg__absf(((x3 - x4) * dy - (y3 - y4) * dx)); - - if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) { - nsvg__addPathPoint(r, x4, y4, type); - return; - } - - x234 = (x23+x34)*0.5f; - y234 = (y23+y34)*0.5f; - x1234 = (x123+x234)*0.5f; - y1234 = (y123+y234)*0.5f; - - nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0); - nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type); -} - -static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float scale) -{ - int i, j; - NSVGpath* path; - - for (path = shape->paths; path != NULL; path = path->next) { - r->npoints = 0; - // Flatten path - nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0); - for (i = 0; i < path->npts-1; i += 3) { - float* p = &path->pts[i*2]; - nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, 0); - } - // Close path - nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0); - // Build edges - for (i = 0, j = r->npoints-1; i < r->npoints; j = i++) - nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y); - } -} - -enum NSVGpointFlags -{ - NSVG_PT_CORNER = 0x01, - NSVG_PT_BEVEL = 0x02, - NSVG_PT_LEFT = 0x04 -}; - -static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) -{ - float w = lineWidth * 0.5f; - float dx = p1->x - p0->x; - float dy = p1->y - p0->y; - float len = nsvg__normalize(&dx, &dy); - float px = p0->x + dx*len*0.5f, py = p0->y + dy*len*0.5f; - float dlx = dy, dly = -dx; - float lx = px - dlx*w, ly = py - dly*w; - float rx = px + dlx*w, ry = py + dly*w; - left->x = lx; left->y = ly; - right->x = rx; right->y = ry; -} - -static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect) -{ - float w = lineWidth * 0.5f; - float px = p->x, py = p->y; - float dlx = dy, dly = -dx; - float lx = px - dlx*w, ly = py - dly*w; - float rx = px + dlx*w, ry = py + dly*w; - - nsvg__addEdge(r, lx, ly, rx, ry); - - if (connect) { - nsvg__addEdge(r, left->x, left->y, lx, ly); - nsvg__addEdge(r, rx, ry, right->x, right->y); - } - left->x = lx; left->y = ly; - right->x = rx; right->y = ry; -} - -static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect) -{ - float w = lineWidth * 0.5f; - float px = p->x - dx*w, py = p->y - dy*w; - float dlx = dy, dly = -dx; - float lx = px - dlx*w, ly = py - dly*w; - float rx = px + dlx*w, ry = py + dly*w; - - nsvg__addEdge(r, lx, ly, rx, ry); - - if (connect) { - nsvg__addEdge(r, left->x, left->y, lx, ly); - nsvg__addEdge(r, rx, ry, right->x, right->y); - } - left->x = lx; left->y = ly; - right->x = rx; right->y = ry; -} - -#ifndef NSVG_PI -#define NSVG_PI (3.14159265358979323846264338327f) -#endif - -static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int ncap, int connect) -{ - int i; - float w = lineWidth * 0.5f; - float px = p->x, py = p->y; - float dlx = dy, dly = -dx; - float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0; - - for (i = 0; i < ncap; i++) { - float a = (float)i/(float)(ncap-1)*NSVG_PI; - float ax = cosf(a) * w, ay = sinf(a) * w; - float x = px - dlx*ax - dx*ay; - float y = py - dly*ax - dy*ay; - - if (i > 0) - nsvg__addEdge(r, prevx, prevy, x, y); - - prevx = x; - prevy = y; - - if (i == 0) { - lx = x; ly = y; - } else if (i == ncap-1) { - rx = x; ry = y; - } - } - - if (connect) { - nsvg__addEdge(r, left->x, left->y, lx, ly); - nsvg__addEdge(r, rx, ry, right->x, right->y); - } - - left->x = lx; left->y = ly; - right->x = rx; right->y = ry; -} - -static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) -{ - float w = lineWidth * 0.5f; - float dlx0 = p0->dy, dly0 = -p0->dx; - float dlx1 = p1->dy, dly1 = -p1->dx; - float lx0 = p1->x - (dlx0 * w), ly0 = p1->y - (dly0 * w); - float rx0 = p1->x + (dlx0 * w), ry0 = p1->y + (dly0 * w); - float lx1 = p1->x - (dlx1 * w), ly1 = p1->y - (dly1 * w); - float rx1 = p1->x + (dlx1 * w), ry1 = p1->y + (dly1 * w); - - nsvg__addEdge(r, lx0, ly0, left->x, left->y); - nsvg__addEdge(r, lx1, ly1, lx0, ly0); - - nsvg__addEdge(r, right->x, right->y, rx0, ry0); - nsvg__addEdge(r, rx0, ry0, rx1, ry1); - - left->x = lx1; left->y = ly1; - right->x = rx1; right->y = ry1; -} - -static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) -{ - float w = lineWidth * 0.5f; - float dlx0 = p0->dy, dly0 = -p0->dx; - float dlx1 = p1->dy, dly1 = -p1->dx; - float lx0, rx0, lx1, rx1; - float ly0, ry0, ly1, ry1; - - if (p1->flags & NSVG_PT_LEFT) { - lx0 = lx1 = p1->x - p1->dmx * w; - ly0 = ly1 = p1->y - p1->dmy * w; - nsvg__addEdge(r, lx1, ly1, left->x, left->y); - - rx0 = p1->x + (dlx0 * w); - ry0 = p1->y + (dly0 * w); - rx1 = p1->x + (dlx1 * w); - ry1 = p1->y + (dly1 * w); - nsvg__addEdge(r, right->x, right->y, rx0, ry0); - nsvg__addEdge(r, rx0, ry0, rx1, ry1); - } else { - lx0 = p1->x - (dlx0 * w); - ly0 = p1->y - (dly0 * w); - lx1 = p1->x - (dlx1 * w); - ly1 = p1->y - (dly1 * w); - nsvg__addEdge(r, lx0, ly0, left->x, left->y); - nsvg__addEdge(r, lx1, ly1, lx0, ly0); - - rx0 = rx1 = p1->x + p1->dmx * w; - ry0 = ry1 = p1->y + p1->dmy * w; - nsvg__addEdge(r, right->x, right->y, rx1, ry1); - } - - left->x = lx1; left->y = ly1; - right->x = rx1; right->y = ry1; -} - -static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth, int ncap) -{ - int i, n; - float w = lineWidth * 0.5f; - float dlx0 = p0->dy, dly0 = -p0->dx; - float dlx1 = p1->dy, dly1 = -p1->dx; - float a0 = atan2f(dly0, dlx0); - float a1 = atan2f(dly1, dlx1); - float da = a1 - a0; - float lx, ly, rx, ry; - - if (da < NSVG_PI) da += NSVG_PI*2; - if (da > NSVG_PI) da -= NSVG_PI*2; - - n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * (float)ncap); - if (n < 2) n = 2; - if (n > ncap) n = ncap; - - lx = left->x; - ly = left->y; - rx = right->x; - ry = right->y; - - for (i = 0; i < n; i++) { - float u = (float)i/(float)(n-1); - float a = a0 + u*da; - float ax = cosf(a) * w, ay = sinf(a) * w; - float lx1 = p1->x - ax, ly1 = p1->y - ay; - float rx1 = p1->x + ax, ry1 = p1->y + ay; - - nsvg__addEdge(r, lx1, ly1, lx, ly); - nsvg__addEdge(r, rx, ry, rx1, ry1); - - lx = lx1; ly = ly1; - rx = rx1; ry = ry1; - } - - left->x = lx; left->y = ly; - right->x = rx; right->y = ry; -} - -static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1, float lineWidth) -{ - float w = lineWidth * 0.5f; - float lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w); - float rx = p1->x + (p1->dmx * w), ry = p1->y + (p1->dmy * w); - - nsvg__addEdge(r, lx, ly, left->x, left->y); - nsvg__addEdge(r, right->x, right->y, rx, ry); - - left->x = lx; left->y = ly; - right->x = rx; right->y = ry; -} - -static int nsvg__curveDivs(float r, float arc, float tol) -{ - float da = acosf(r / (r + tol)) * 2.0f; - int divs = (int)ceilf(arc / da); - if (divs < 2) divs = 2; - return divs; -} - -static void nsvg__expandStroke(NSVGrasterizer* r, NSVGpoint* points, int npoints, int closed, int lineJoin, int lineCap, float lineWidth) -{ - int ncap = nsvg__curveDivs(lineWidth*0.5f, NSVG_PI, r->tessTol); // Calculate divisions per half circle. - NSVGpoint left = {0,0,0,0,0,0,0,0}, right = {0,0,0,0,0,0,0,0}, firstLeft = {0,0,0,0,0,0,0,0}, firstRight = {0,0,0,0,0,0,0,0}; - NSVGpoint* p0, *p1; - int j, s, e; - - // Build stroke edges - if (closed) { - // Looping - p0 = &points[npoints-1]; - p1 = &points[0]; - s = 0; - e = npoints; - } else { - // Add cap - p0 = &points[0]; - p1 = &points[1]; - s = 1; - e = npoints-1; - } - - if (closed) { - nsvg__initClosed(&left, &right, p0, p1, lineWidth); - firstLeft = left; - firstRight = right; - } else { - // Add cap - float dx = p1->x - p0->x; - float dy = p1->y - p0->y; - nsvg__normalize(&dx, &dy); - if (lineCap == NSVG_CAP_BUTT) - nsvg__buttCap(r, &left, &right, p0, dx, dy, lineWidth, 0); - else if (lineCap == NSVG_CAP_SQUARE) - nsvg__squareCap(r, &left, &right, p0, dx, dy, lineWidth, 0); - else if (lineCap == NSVG_CAP_ROUND) - nsvg__roundCap(r, &left, &right, p0, dx, dy, lineWidth, ncap, 0); - } - - for (j = s; j < e; ++j) { - if (p1->flags & NSVG_PT_CORNER) { - if (lineJoin == NSVG_JOIN_ROUND) - nsvg__roundJoin(r, &left, &right, p0, p1, lineWidth, ncap); - else if (lineJoin == NSVG_JOIN_BEVEL || (p1->flags & NSVG_PT_BEVEL)) - nsvg__bevelJoin(r, &left, &right, p0, p1, lineWidth); - else - nsvg__miterJoin(r, &left, &right, p0, p1, lineWidth); - } else { - nsvg__straightJoin(r, &left, &right, p1, lineWidth); - } - p0 = p1++; - } - - if (closed) { - // Loop it - nsvg__addEdge(r, firstLeft.x, firstLeft.y, left.x, left.y); - nsvg__addEdge(r, right.x, right.y, firstRight.x, firstRight.y); - } else { - // Add cap - float dx = p1->x - p0->x; - float dy = p1->y - p0->y; - nsvg__normalize(&dx, &dy); - if (lineCap == NSVG_CAP_BUTT) - nsvg__buttCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1); - else if (lineCap == NSVG_CAP_SQUARE) - nsvg__squareCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1); - else if (lineCap == NSVG_CAP_ROUND) - nsvg__roundCap(r, &right, &left, p1, -dx, -dy, lineWidth, ncap, 1); - } -} - -static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoin) -{ - int i, j; - NSVGpoint* p0, *p1; - - p0 = &r->points[r->npoints-1]; - p1 = &r->points[0]; - for (i = 0; i < r->npoints; i++) { - // Calculate segment direction and length - p0->dx = p1->x - p0->x; - p0->dy = p1->y - p0->y; - p0->len = nsvg__normalize(&p0->dx, &p0->dy); - // Advance - p0 = p1++; - } - - // calculate joins - p0 = &r->points[r->npoints-1]; - p1 = &r->points[0]; - for (j = 0; j < r->npoints; j++) { - float dlx0, dly0, dlx1, dly1, dmr2, cross; - dlx0 = p0->dy; - dly0 = -p0->dx; - dlx1 = p1->dy; - dly1 = -p1->dx; - // Calculate extrusions - p1->dmx = (dlx0 + dlx1) * 0.5f; - p1->dmy = (dly0 + dly1) * 0.5f; - dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy; - if (dmr2 > 0.000001f) { - float s2 = 1.0f / dmr2; - if (s2 > 600.0f) { - s2 = 600.0f; - } - p1->dmx *= s2; - p1->dmy *= s2; - } - - // Clear flags, but keep the corner. - p1->flags = (p1->flags & NSVG_PT_CORNER) ? NSVG_PT_CORNER : 0; - - // Keep track of left turns. - cross = p1->dx * p0->dy - p0->dx * p1->dy; - if (cross > 0.0f) - p1->flags |= NSVG_PT_LEFT; - - // Check to see if the corner needs to be beveled. - if (p1->flags & NSVG_PT_CORNER) { - if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NSVG_JOIN_BEVEL || lineJoin == NSVG_JOIN_ROUND) { - p1->flags |= NSVG_PT_BEVEL; - } - } - - p0 = p1++; - } -} - -static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float scale) -{ - int i, j, closed; - NSVGpath* path; - NSVGpoint* p0, *p1; - float miterLimit = shape->miterLimit; - int lineJoin = shape->strokeLineJoin; - int lineCap = shape->strokeLineCap; - float lineWidth = shape->strokeWidth * scale; - - for (path = shape->paths; path != NULL; path = path->next) { - // Flatten path - r->npoints = 0; - nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, NSVG_PT_CORNER); - for (i = 0; i < path->npts-1; i += 3) { - float* p = &path->pts[i*2]; - nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, NSVG_PT_CORNER); - } - if (r->npoints < 2) - continue; - - closed = path->closed; - - // If the first and last points are the same, remove the last, mark as closed path. - p0 = &r->points[r->npoints-1]; - p1 = &r->points[0]; - if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) { - r->npoints--; - p0 = &r->points[r->npoints-1]; - closed = 1; - } - - if (shape->strokeDashCount > 0) { - int idash = 0, dashState = 1; - float totalDist = 0, dashLen, allDashLen, dashOffset; - NSVGpoint cur; - - if (closed) - nsvg__appendPathPoint(r, r->points[0]); - - // Duplicate points -> points2. - nsvg__duplicatePoints(r); - - r->npoints = 0; - cur = r->points2[0]; - nsvg__appendPathPoint(r, cur); - - // Figure out dash offset. - allDashLen = 0; - for (j = 0; j < shape->strokeDashCount; j++) - allDashLen += shape->strokeDashArray[j]; - if (shape->strokeDashCount & 1) - allDashLen *= 2.0f; - // Find location inside pattern - dashOffset = fmodf(shape->strokeDashOffset, allDashLen); - if (dashOffset < 0.0f) - dashOffset += allDashLen; - - while (dashOffset > shape->strokeDashArray[idash]) { - dashOffset -= shape->strokeDashArray[idash]; - idash = (idash + 1) % shape->strokeDashCount; - } - dashLen = (shape->strokeDashArray[idash] - dashOffset) * scale; - - for (j = 1; j < r->npoints2; ) { - float dx = r->points2[j].x - cur.x; - float dy = r->points2[j].y - cur.y; - float dist = sqrtf(dx*dx + dy*dy); - - if ((totalDist + dist) > dashLen) { - // Calculate intermediate point - float d = (dashLen - totalDist) / dist; - float x = cur.x + dx * d; - float y = cur.y + dy * d; - nsvg__addPathPoint(r, x, y, NSVG_PT_CORNER); - - // Stroke - if (r->npoints > 1 && dashState) { - nsvg__prepareStroke(r, miterLimit, lineJoin); - nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth); - } - // Advance dash pattern - dashState = !dashState; - idash = (idash+1) % shape->strokeDashCount; - dashLen = shape->strokeDashArray[idash] * scale; - // Restart - cur.x = x; - cur.y = y; - cur.flags = NSVG_PT_CORNER; - totalDist = 0.0f; - r->npoints = 0; - nsvg__appendPathPoint(r, cur); - } else { - totalDist += dist; - cur = r->points2[j]; - nsvg__appendPathPoint(r, cur); - j++; - } - } - // Stroke any leftover path - if (r->npoints > 1 && dashState) - nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth); - } else { - nsvg__prepareStroke(r, miterLimit, lineJoin); - nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin, lineCap, lineWidth); - } - } -} - -static int nsvg__cmpEdge(const void *p, const void *q) -{ - const NSVGedge* a = (const NSVGedge*)p; - const NSVGedge* b = (const NSVGedge*)q; - - if (a->y0 < b->y0) return -1; - if (a->y0 > b->y0) return 1; - return 0; -} - - -static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float startPoint) -{ - NSVGactiveEdge* z; - - if (r->freelist != NULL) { - // Restore from freelist. - z = r->freelist; - r->freelist = z->next; - } else { - // Alloc new edge. - z = (NSVGactiveEdge*)nsvg__alloc(r, sizeof(NSVGactiveEdge)); - if (z == NULL) return NULL; - } - - float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); -// STBTT_assert(e->y0 <= start_point); - // round dx down to avoid going too far - if (dxdy < 0) - z->dx = (int)(-floorf(NSVG__FIX * -dxdy)); - else - z->dx = (int)floorf(NSVG__FIX * dxdy); - z->x = (int)floorf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0))); -// z->x -= off_x * FIX; - z->ey = e->y1; - z->next = 0; - z->dir = e->dir; - - return z; -} - -static void nsvg__freeActive(NSVGrasterizer* r, NSVGactiveEdge* z) -{ - z->next = r->freelist; - r->freelist = z; -} - -static void nsvg__fillScanline(unsigned char* scanline, int len, int x0, int x1, int maxWeight, int* xmin, int* xmax) -{ - int i = x0 >> NSVG__FIXSHIFT; - int j = x1 >> NSVG__FIXSHIFT; - if (i < *xmin) *xmin = i; - if (j > *xmax) *xmax = j; - if (i < len && j >= 0) { - if (i == j) { - // x0,x1 are the same pixel, so compute combined coverage - scanline[i] = (unsigned char)(scanline[i] + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT)); - } else { - if (i >= 0) // add antialiasing for x0 - scanline[i] = (unsigned char)(scanline[i] + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT)); - else - i = -1; // clip - - if (j < len) // add antialiasing for x1 - scanline[j] = (unsigned char)(scanline[j] + (((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT)); - else - j = len; // clip - - for (++i; i < j; ++i) // fill pixels between x0 and x1 - scanline[i] = (unsigned char)(scanline[i] + maxWeight); - } - } -} - -// note: this routine clips fills that extend off the edges... ideally this -// wouldn't happen, but it could happen if the truetype glyph bounding boxes -// are wrong, or if the user supplies a too-small bitmap -static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEdge* e, int maxWeight, int* xmin, int* xmax, char fillRule) -{ - // non-zero winding fill - int x0 = 0, w = 0; - - if (fillRule == NSVG_FILLRULE_NONZERO) { - // Non-zero - while (e != NULL) { - if (w == 0) { - // if we're currently at zero, we need to record the edge start point - x0 = e->x; w += e->dir; - } else { - int x1 = e->x; w += e->dir; - // if we went to zero, we need to draw - if (w == 0) - nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax); - } - e = e->next; - } - } else if (fillRule == NSVG_FILLRULE_EVENODD) { - // Even-odd - while (e != NULL) { - if (w == 0) { - // if we're currently at zero, we need to record the edge start point - x0 = e->x; w = 1; - } else { - int x1 = e->x; w = 0; - nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax); - } - e = e->next; - } - } -} - -static float nsvg__clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); } - -static unsigned int nsvg__RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a) -{ - return ((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16) | ((unsigned int)a << 24); -} - -static unsigned int nsvg__lerpRGBA(unsigned int c0, unsigned int c1, float u) -{ - int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f); - int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8; - int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8; - int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8; - int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8; - return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a); -} - -static unsigned int nsvg__applyOpacity(unsigned int c, float u) -{ - int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f); - int r = (c) & 0xff; - int g = (c>>8) & 0xff; - int b = (c>>16) & 0xff; - int a = (((c>>24) & 0xff)*iu) >> 8; - return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a); -} - -static inline int nsvg__div255(int x) -{ - return ((x+1) * 257) >> 16; -} - -static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* cover, int x, int y, - float tx, float ty, float scale, NSVGcachedPaint* cache) -{ - - if (cache->type == NSVG_PAINT_COLOR) { - int i, cr, cg, cb, ca; - cr = cache->colors[0] & 0xff; - cg = (cache->colors[0] >> 8) & 0xff; - cb = (cache->colors[0] >> 16) & 0xff; - ca = (cache->colors[0] >> 24) & 0xff; - - for (i = 0; i < count; i++) { - int r,g,b; - int a = nsvg__div255((int)cover[0] * ca); - int ia = 255 - a; - // Premultiply - r = nsvg__div255(cr * a); - g = nsvg__div255(cg * a); - b = nsvg__div255(cb * a); - - // Blend over - r += nsvg__div255(ia * (int)dst[0]); - g += nsvg__div255(ia * (int)dst[1]); - b += nsvg__div255(ia * (int)dst[2]); - a += nsvg__div255(ia * (int)dst[3]); - - dst[0] = (unsigned char)r; - dst[1] = (unsigned char)g; - dst[2] = (unsigned char)b; - dst[3] = (unsigned char)a; - - cover++; - dst += 4; - } - } else if (cache->type == NSVG_PAINT_LINEAR_GRADIENT) { - // TODO: spread modes. - // TODO: plenty of opportunities to optimize. - float fx, fy, dx, gy; - float* t = cache->xform; - int i, cr, cg, cb, ca; - unsigned int c; - - fx = ((float)x - tx) / scale; - fy = ((float)y - ty) / scale; - dx = 1.0f / scale; - - for (i = 0; i < count; i++) { - int r,g,b,a,ia; - gy = fx*t[1] + fy*t[3] + t[5]; - c = cache->colors[(int)nsvg__clampf(gy*255.0f, 0, 255.0f)]; - cr = (c) & 0xff; - cg = (c >> 8) & 0xff; - cb = (c >> 16) & 0xff; - ca = (c >> 24) & 0xff; - - a = nsvg__div255((int)cover[0] * ca); - ia = 255 - a; - - // Premultiply - r = nsvg__div255(cr * a); - g = nsvg__div255(cg * a); - b = nsvg__div255(cb * a); - - // Blend over - r += nsvg__div255(ia * (int)dst[0]); - g += nsvg__div255(ia * (int)dst[1]); - b += nsvg__div255(ia * (int)dst[2]); - a += nsvg__div255(ia * (int)dst[3]); - - dst[0] = (unsigned char)r; - dst[1] = (unsigned char)g; - dst[2] = (unsigned char)b; - dst[3] = (unsigned char)a; - - cover++; - dst += 4; - fx += dx; - } - } else if (cache->type == NSVG_PAINT_RADIAL_GRADIENT) { - // TODO: spread modes. - // TODO: plenty of opportunities to optimize. - // TODO: focus (fx,fy) - float fx, fy, dx, gx, gy, gd; - float* t = cache->xform; - int i, cr, cg, cb, ca; - unsigned int c; - - fx = ((float)x - tx) / scale; - fy = ((float)y - ty) / scale; - dx = 1.0f / scale; - - for (i = 0; i < count; i++) { - int r,g,b,a,ia; - gx = fx*t[0] + fy*t[2] + t[4]; - gy = fx*t[1] + fy*t[3] + t[5]; - gd = sqrtf(gx*gx + gy*gy); - c = cache->colors[(int)nsvg__clampf(gd*255.0f, 0, 255.0f)]; - cr = (c) & 0xff; - cg = (c >> 8) & 0xff; - cb = (c >> 16) & 0xff; - ca = (c >> 24) & 0xff; - - a = nsvg__div255((int)cover[0] * ca); - ia = 255 - a; - - // Premultiply - r = nsvg__div255(cr * a); - g = nsvg__div255(cg * a); - b = nsvg__div255(cb * a); - - // Blend over - r += nsvg__div255(ia * (int)dst[0]); - g += nsvg__div255(ia * (int)dst[1]); - b += nsvg__div255(ia * (int)dst[2]); - a += nsvg__div255(ia * (int)dst[3]); - - dst[0] = (unsigned char)r; - dst[1] = (unsigned char)g; - dst[2] = (unsigned char)b; - dst[3] = (unsigned char)a; - - cover++; - dst += 4; - fx += dx; - } - } -} - -static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, float scale, NSVGcachedPaint* cache, char fillRule) -{ - NSVGactiveEdge *active = NULL; - int y, s; - int e = 0; - int maxWeight = (255 / NSVG__SUBSAMPLES); // weight per vertical scanline - int xmin, xmax; - - for (y = 0; y < r->height; y++) { - memset(r->scanline, 0, r->width); - xmin = r->width; - xmax = 0; - for (s = 0; s < NSVG__SUBSAMPLES; ++s) { - // find center of pixel for this scanline - float scany = (float)(y*NSVG__SUBSAMPLES + s) + 0.5f; - NSVGactiveEdge **step = &active; - - // update all active edges; - // remove all active edges that terminate before the center of this scanline - while (*step) { - NSVGactiveEdge *z = *step; - if (z->ey <= scany) { - *step = z->next; // delete from list -// NSVG__assert(z->valid); - nsvg__freeActive(r, z); - } else { - z->x += z->dx; // advance to position for current scanline - step = &((*step)->next); // advance through list - } - } - - // resort the list if needed - for (;;) { - int changed = 0; - step = &active; - while (*step && (*step)->next) { - if ((*step)->x > (*step)->next->x) { - NSVGactiveEdge* t = *step; - NSVGactiveEdge* q = t->next; - t->next = q->next; - q->next = t; - *step = q; - changed = 1; - } - step = &(*step)->next; - } - if (!changed) break; - } - - // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline - while (e < r->nedges && r->edges[e].y0 <= scany) { - if (r->edges[e].y1 > scany) { - NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany); - if (z == NULL) break; - // find insertion point - if (active == NULL) { - active = z; - } else if (z->x < active->x) { - // insert at front - z->next = active; - active = z; - } else { - // find thing to insert AFTER - NSVGactiveEdge* p = active; - while (p->next && p->next->x < z->x) - p = p->next; - // at this point, p->next->x is NOT < z->x - z->next = p->next; - p->next = z; - } - } - e++; - } - - // now process all active edges in non-zero fashion - if (active != NULL) - nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax, fillRule); - } - // Blit - if (xmin < 0) xmin = 0; - if (xmax > r->width-1) xmax = r->width-1; - if (xmin <= xmax) { - nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty, scale, cache); - } - } - -} - -static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int stride) -{ - int x,y; - - // Unpremultiply - for (y = 0; y < h; y++) { - unsigned char *row = &image[y*stride]; - for (x = 0; x < w; x++) { - int r = row[0], g = row[1], b = row[2], a = row[3]; - if (a != 0) { - row[0] = (unsigned char)(r*255/a); - row[1] = (unsigned char)(g*255/a); - row[2] = (unsigned char)(b*255/a); - } - row += 4; - } - } - - // Defringe - for (y = 0; y < h; y++) { - unsigned char *row = &image[y*stride]; - for (x = 0; x < w; x++) { - int r = 0, g = 0, b = 0, a = row[3], n = 0; - if (a == 0) { - if (x-1 > 0 && row[-1] != 0) { - r += row[-4]; - g += row[-3]; - b += row[-2]; - n++; - } - if (x+1 < w && row[7] != 0) { - r += row[4]; - g += row[5]; - b += row[6]; - n++; - } - if (y-1 > 0 && row[-stride+3] != 0) { - r += row[-stride]; - g += row[-stride+1]; - b += row[-stride+2]; - n++; - } - if (y+1 < h && row[stride+3] != 0) { - r += row[stride]; - g += row[stride+1]; - b += row[stride+2]; - n++; - } - if (n > 0) { - row[0] = (unsigned char)(r/n); - row[1] = (unsigned char)(g/n); - row[2] = (unsigned char)(b/n); - } - } - row += 4; - } - } -} - - -static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opacity) -{ - int i, j; - NSVGgradient* grad; - - cache->type = paint->type; - - if (paint->type == NSVG_PAINT_COLOR) { - cache->colors[0] = nsvg__applyOpacity(paint->color, opacity); - return; - } - - grad = paint->gradient; - - cache->spread = grad->spread; - memcpy(cache->xform, grad->xform, sizeof(float)*6); - - if (grad->nstops == 0) { - for (i = 0; i < 256; i++) - cache->colors[i] = 0; - } if (grad->nstops == 1) { - for (i = 0; i < 256; i++) - cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity); - } else { - unsigned int ca, cb = 0; - float ua, ub, du, u; - int ia, ib, count; - - ca = nsvg__applyOpacity(grad->stops[0].color, opacity); - ua = nsvg__clampf(grad->stops[0].offset, 0, 1); - ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1); - ia = (int)(ua * 255.0f); - ib = (int)(ub * 255.0f); - for (i = 0; i < ia; i++) { - cache->colors[i] = ca; - } - - for (i = 0; i < grad->nstops-1; i++) { - ca = nsvg__applyOpacity(grad->stops[i].color, opacity); - cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity); - ua = nsvg__clampf(grad->stops[i].offset, 0, 1); - ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1); - ia = (int)(ua * 255.0f); - ib = (int)(ub * 255.0f); - count = ib - ia; - if (count <= 0) continue; - u = 0; - du = 1.0f / (float)count; - for (j = 0; j < count; j++) { - cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u); - u += du; - } - } - - for (i = ib; i < 256; i++) - cache->colors[i] = cb; - } - -} - -/* -static void dumpEdges(NSVGrasterizer* r, const char* name) -{ - float xmin = 0, xmax = 0, ymin = 0, ymax = 0; - NSVGedge *e = NULL; - int i; - if (r->nedges == 0) return; - FILE* fp = fopen(name, "w"); - if (fp == NULL) return; - - xmin = xmax = r->edges[0].x0; - ymin = ymax = r->edges[0].y0; - for (i = 0; i < r->nedges; i++) { - e = &r->edges[i]; - xmin = nsvg__minf(xmin, e->x0); - xmin = nsvg__minf(xmin, e->x1); - xmax = nsvg__maxf(xmax, e->x0); - xmax = nsvg__maxf(xmax, e->x1); - ymin = nsvg__minf(ymin, e->y0); - ymin = nsvg__minf(ymin, e->y1); - ymax = nsvg__maxf(ymax, e->y0); - ymax = nsvg__maxf(ymax, e->y1); - } - - fprintf(fp, "", xmin, ymin, (xmax - xmin), (ymax - ymin)); - - for (i = 0; i < r->nedges; i++) { - e = &r->edges[i]; - fprintf(fp ,"", e->x0,e->y0, e->x1,e->y1); - } - - for (i = 0; i < r->npoints; i++) { - if (i+1 < r->npoints) - fprintf(fp ,"", r->points[i].x, r->points[i].y, r->points[i+1].x, r->points[i+1].y); - fprintf(fp ,"", r->points[i].x, r->points[i].y, r->points[i].flags == 0 ? "#f00" : "#0f0"); - } - - fprintf(fp, ""); - fclose(fp); -} -*/ - -void nsvgRasterize(NSVGrasterizer* r, - NSVGimage* image, float tx, float ty, float scale, - unsigned char* dst, int w, int h, int stride) -{ - NSVGshape *shape = NULL; - NSVGedge *e = NULL; - NSVGcachedPaint cache; - int i; - - r->bitmap = dst; - r->width = w; - r->height = h; - r->stride = stride; - - if (w > r->cscanline) { - r->cscanline = w; - r->scanline = (unsigned char*)realloc(r->scanline, w); - if (r->scanline == NULL) return; - } - - for (i = 0; i < h; i++) - memset(&dst[i*stride], 0, w*4); - - for (shape = image->shapes; shape != NULL; shape = shape->next) { - if (!(shape->flags & NSVG_FLAGS_VISIBLE)) - continue; - - if (shape->fill.type != NSVG_PAINT_NONE) { - nsvg__resetPool(r); - r->freelist = NULL; - r->nedges = 0; - - nsvg__flattenShape(r, shape, scale); - - // Scale and translate edges - for (i = 0; i < r->nedges; i++) { - e = &r->edges[i]; - e->x0 = tx + e->x0; - e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES; - e->x1 = tx + e->x1; - e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES; - } - - // Rasterize edges - if (r->nedges != 0) - qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge); - - // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule - nsvg__initPaint(&cache, &shape->fill, shape->opacity); - - nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, shape->fillRule); - } - if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) { - nsvg__resetPool(r); - r->freelist = NULL; - r->nedges = 0; - - nsvg__flattenShapeStroke(r, shape, scale); - -// dumpEdges(r, "edge.svg"); - - // Scale and translate edges - for (i = 0; i < r->nedges; i++) { - e = &r->edges[i]; - e->x0 = tx + e->x0; - e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES; - e->x1 = tx + e->x1; - e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES; - } - - // Rasterize edges - if (r->nedges != 0) - qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge); - - // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule - nsvg__initPaint(&cache, &shape->stroke, shape->opacity); - - nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO); - } - } - - nsvg__unpremultiplyAlpha(dst, w, h, stride); - - r->bitmap = NULL; - r->width = 0; - r->height = 0; - r->stride = 0; -} - -#endif // NANOSVGRAST_IMPLEMENTATION - -#endif // NANOSVGRAST_H diff --git a/src/rtextures.c b/src/rtextures.c index e81f05fe8..43d16dc7b 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -225,14 +225,6 @@ #pragma GCC diagnostic pop #endif -#if defined(SUPPORT_FILEFORMAT_SVG) - #define NANOSVG_IMPLEMENTATION // Expands implementation - #include "external/nanosvg.h" - - #define NANOSVGRAST_IMPLEMENTATION - #include "external/nanosvgrast.h" -#endif - //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -335,84 +327,6 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int return image; } -// Load an image from a SVG file or string with custom size -Image LoadImageSvg(const char *fileNameOrString, int width, int height) -{ - Image image = { 0 }; - -#if defined(SUPPORT_FILEFORMAT_SVG) - bool isSvgStringValid = false; - - // Validate fileName or string - if (fileNameOrString != NULL) - { - int dataSize = 0; - unsigned char *fileData = NULL; - - if (FileExists(fileNameOrString)) - { - fileData = LoadFileData(fileNameOrString, &dataSize); - isSvgStringValid = true; - } - else - { - // Validate fileData as valid SVG string data - // - if ((fileNameOrString != NULL) && - (fileNameOrString[0] == '<') && - (fileNameOrString[1] == 's') && - (fileNameOrString[2] == 'v') && - (fileNameOrString[3] == 'g')) - { - fileData = (unsigned char *)fileNameOrString; - isSvgStringValid = true; - } - } - - if (isSvgStringValid) - { - struct NSVGimage *svgImage = nsvgParse((char *)fileData, "px", 96.0f); - - unsigned char *img = RL_MALLOC(width*height*4); - - // Calculate scales for both the width and the height - const float scaleWidth = width/svgImage->width; - const float scaleHeight = height/svgImage->height; - - // Set the largest of the 2 scales to be the scale to use - const float scale = (scaleHeight > scaleWidth)? scaleWidth : scaleHeight; - - int offsetX = 0; - int offsetY = 0; - - if (scaleHeight > scaleWidth) offsetY = (height - svgImage->height*scale)/2; - else offsetX = (width - svgImage->width*scale)/2; - - // Rasterize - struct NSVGrasterizer *rast = nsvgCreateRasterizer(); - nsvgRasterize(rast, svgImage, (int)offsetX, (int)offsetY, scale, img, width, height, width*4); - - // Populate image struct with all data - image.data = img; - image.width = width; - image.height = height; - image.mipmaps = 1; - image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; - - // Free used memory - nsvgDelete(svgImage); - nsvgDeleteRasterizer(rast); - } - - if (isSvgStringValid && (fileData != (unsigned char *)fileNameOrString)) UnloadFileData(fileData); - } -#else - TRACELOG(LOG_WARNING, "SVG image support not enabled, image can not be loaded"); -#endif - - return image; -} - // Load animated image data // - Image.data buffer includes all frames: [image#0][image#1][image#2][...] // - Number of frames is returned through 'frames' parameter @@ -600,36 +514,6 @@ Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, i } } #endif -#if defined(SUPPORT_FILEFORMAT_SVG) - else if ((strcmp(fileType, ".svg") == 0) || (strcmp(fileType, ".SVG") == 0)) - { - // Validate fileData as valid SVG string data - // - if ((fileData != NULL) && - (fileData[0] == '<') && - (fileData[1] == 's') && - (fileData[2] == 'v') && - (fileData[3] == 'g')) - { - struct NSVGimage *svgImage = nsvgParse((char *)fileData, "px", 96.0f); - unsigned char *img = RL_MALLOC(svgImage->width*svgImage->height*4); - - // Rasterize - struct NSVGrasterizer *rast = nsvgCreateRasterizer(); - nsvgRasterize(rast, svgImage, 0, 0, 1.0f, img, svgImage->width, svgImage->height, svgImage->width*4); - - // Populate image struct with all data - image.data = img; - image.width = svgImage->width; - image.height = svgImage->height; - image.mipmaps = 1; - image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; - - nsvgDelete(svgImage); - nsvgDeleteRasterizer(rast); - } - } -#endif #if defined(SUPPORT_FILEFORMAT_DDS) else if ((strcmp(fileType, ".dds") == 0) || (strcmp(fileType, ".DDS") == 0)) { From d29eb34cfb2688ca11d1a84883c849fa0500881d Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 10 Oct 2024 21:17:31 +0200 Subject: [PATCH 079/115] REMOVED: `LoadImageSvg()` --- src/raylib.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/raylib.h b/src/raylib.h index 08121c50c..e0c74af30 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1312,7 +1312,6 @@ RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2); // 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 LoadImageSvg(const char *fileNameOrString, int width, int height); // Load image from SVG file data or string with specified size RLAPI Image LoadImageAnim(const char *fileName, int *frames); // Load image sequence from file (frames appended to image.data) RLAPI Image LoadImageAnimFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int *frames); // Load image sequence from memory buffer RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load image from memory buffer, fileType refers to extension: i.e. '.png' From f5328a9bb63a0e0eca7dead15cfa01a3ec1417c2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 10 Oct 2024 19:17:48 +0000 Subject: [PATCH 080/115] Update raylib_api.* by CI --- parser/output/raylib_api.json | 19 -- parser/output/raylib_api.lua | 10 - parser/output/raylib_api.txt | 619 +++++++++++++++++----------------- parser/output/raylib_api.xml | 7 +- 4 files changed, 307 insertions(+), 348 deletions(-) diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json index 58fb9d6a8..2c8fe31e9 100644 --- a/parser/output/raylib_api.json +++ b/parser/output/raylib_api.json @@ -6815,25 +6815,6 @@ } ] }, - { - "name": "LoadImageSvg", - "description": "Load image from SVG file data or string with specified size", - "returnType": "Image", - "params": [ - { - "type": "const char *", - "name": "fileNameOrString" - }, - { - "type": "int", - "name": "width" - }, - { - "type": "int", - "name": "height" - } - ] - }, { "name": "LoadImageAnim", "description": "Load image sequence from file (frames appended to image.data)", diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua index bea3813cf..6c287b7a4 100644 --- a/parser/output/raylib_api.lua +++ b/parser/output/raylib_api.lua @@ -5339,16 +5339,6 @@ return { {type = "int", name = "headerSize"} } }, - { - name = "LoadImageSvg", - description = "Load image from SVG file data or string with specified size", - returnType = "Image", - params = { - {type = "const char *", name = "fileNameOrString"}, - {type = "int", name = "width"}, - {type = "int", name = "height"} - } - }, { name = "LoadImageAnim", description = "Load image sequence from file (frames appended to image.data)", diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt index 9a953b768..9764769a7 100644 --- a/parser/output/raylib_api.txt +++ b/parser/output/raylib_api.txt @@ -989,7 +989,7 @@ Callback 006: AudioCallback() (2 input parameters) Param[1]: bufferData (type: void *) Param[2]: frames (type: unsigned int) -Functions found: 578 +Functions found: 577 Function 001: InitWindow() (3 input parameters) Name: InitWindow @@ -2631,20 +2631,13 @@ Function 272: LoadImageRaw() (5 input parameters) Param[3]: height (type: int) Param[4]: format (type: int) Param[5]: headerSize (type: int) -Function 273: LoadImageSvg() (3 input parameters) - Name: LoadImageSvg - Return type: Image - Description: Load image from SVG file data or string with specified size - Param[1]: fileNameOrString (type: const char *) - Param[2]: width (type: int) - Param[3]: height (type: int) -Function 274: LoadImageAnim() (2 input parameters) +Function 273: 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 275: LoadImageAnimFromMemory() (4 input parameters) +Function 274: LoadImageAnimFromMemory() (4 input parameters) Name: LoadImageAnimFromMemory Return type: Image Description: Load image sequence from memory buffer @@ -2652,60 +2645,60 @@ Function 275: LoadImageAnimFromMemory() (4 input parameters) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) Param[4]: frames (type: int *) -Function 276: LoadImageFromMemory() (3 input parameters) +Function 275: 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 277: LoadImageFromTexture() (1 input parameters) +Function 276: LoadImageFromTexture() (1 input parameters) Name: LoadImageFromTexture Return type: Image Description: Load image from GPU texture data Param[1]: texture (type: Texture2D) -Function 278: LoadImageFromScreen() (0 input parameters) +Function 277: LoadImageFromScreen() (0 input parameters) Name: LoadImageFromScreen Return type: Image Description: Load image from screen buffer and (screenshot) No input parameters -Function 279: IsImageReady() (1 input parameters) +Function 278: IsImageReady() (1 input parameters) Name: IsImageReady Return type: bool Description: Check if an image is ready Param[1]: image (type: Image) -Function 280: UnloadImage() (1 input parameters) +Function 279: UnloadImage() (1 input parameters) Name: UnloadImage Return type: void Description: Unload image from CPU memory (RAM) Param[1]: image (type: Image) -Function 281: ExportImage() (2 input parameters) +Function 280: 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 282: ExportImageToMemory() (3 input parameters) +Function 281: ExportImageToMemory() (3 input parameters) Name: ExportImageToMemory Return type: unsigned char * Description: Export image to memory buffer Param[1]: image (type: Image) Param[2]: fileType (type: const char *) Param[3]: fileSize (type: int *) -Function 283: ExportImageAsCode() (2 input parameters) +Function 282: 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 284: GenImageColor() (3 input parameters) +Function 283: 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 285: GenImageGradientLinear() (5 input parameters) +Function 284: GenImageGradientLinear() (5 input parameters) Name: GenImageGradientLinear Return type: Image Description: Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient @@ -2714,7 +2707,7 @@ Function 285: GenImageGradientLinear() (5 input parameters) Param[3]: direction (type: int) Param[4]: start (type: Color) Param[5]: end (type: Color) -Function 286: GenImageGradientRadial() (5 input parameters) +Function 285: GenImageGradientRadial() (5 input parameters) Name: GenImageGradientRadial Return type: Image Description: Generate image: radial gradient @@ -2723,7 +2716,7 @@ Function 286: GenImageGradientRadial() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 287: GenImageGradientSquare() (5 input parameters) +Function 286: GenImageGradientSquare() (5 input parameters) Name: GenImageGradientSquare Return type: Image Description: Generate image: square gradient @@ -2732,7 +2725,7 @@ Function 287: GenImageGradientSquare() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 288: GenImageChecked() (6 input parameters) +Function 287: GenImageChecked() (6 input parameters) Name: GenImageChecked Return type: Image Description: Generate image: checked @@ -2742,14 +2735,14 @@ Function 288: GenImageChecked() (6 input parameters) Param[4]: checksY (type: int) Param[5]: col1 (type: Color) Param[6]: col2 (type: Color) -Function 289: GenImageWhiteNoise() (3 input parameters) +Function 288: 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 290: GenImagePerlinNoise() (5 input parameters) +Function 289: GenImagePerlinNoise() (5 input parameters) Name: GenImagePerlinNoise Return type: Image Description: Generate image: perlin noise @@ -2758,45 +2751,45 @@ Function 290: GenImagePerlinNoise() (5 input parameters) Param[3]: offsetX (type: int) Param[4]: offsetY (type: int) Param[5]: scale (type: float) -Function 291: GenImageCellular() (3 input parameters) +Function 290: 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 292: GenImageText() (3 input parameters) +Function 291: 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 293: ImageCopy() (1 input parameters) +Function 292: ImageCopy() (1 input parameters) Name: ImageCopy Return type: Image Description: Create an image duplicate (useful for transformations) Param[1]: image (type: Image) -Function 294: ImageFromImage() (2 input parameters) +Function 293: ImageFromImage() (2 input parameters) Name: ImageFromImage Return type: Image Description: Create an image from another image piece Param[1]: image (type: Image) Param[2]: rec (type: Rectangle) -Function 295: ImageFromChannel() (2 input parameters) +Function 294: ImageFromChannel() (2 input parameters) Name: ImageFromChannel Return type: Image Description: Create an image from a selected channel of another image (GRAYSCALE) Param[1]: image (type: Image) Param[2]: selectedChannel (type: int) -Function 296: ImageText() (3 input parameters) +Function 295: ImageText() (3 input parameters) Name: ImageText Return type: Image Description: Create an image from text (default font) Param[1]: text (type: const char *) Param[2]: fontSize (type: int) Param[3]: color (type: Color) -Function 297: ImageTextEx() (5 input parameters) +Function 296: ImageTextEx() (5 input parameters) Name: ImageTextEx Return type: Image Description: Create an image from text (custom sprite font) @@ -2805,76 +2798,76 @@ Function 297: ImageTextEx() (5 input parameters) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) Param[5]: tint (type: Color) -Function 298: ImageFormat() (2 input parameters) +Function 297: ImageFormat() (2 input parameters) Name: ImageFormat Return type: void Description: Convert image data to desired format Param[1]: image (type: Image *) Param[2]: newFormat (type: int) -Function 299: ImageToPOT() (2 input parameters) +Function 298: ImageToPOT() (2 input parameters) Name: ImageToPOT Return type: void Description: Convert image to POT (power-of-two) Param[1]: image (type: Image *) Param[2]: fill (type: Color) -Function 300: ImageCrop() (2 input parameters) +Function 299: ImageCrop() (2 input parameters) Name: ImageCrop Return type: void Description: Crop an image to a defined rectangle Param[1]: image (type: Image *) Param[2]: crop (type: Rectangle) -Function 301: ImageAlphaCrop() (2 input parameters) +Function 300: ImageAlphaCrop() (2 input parameters) Name: ImageAlphaCrop Return type: void Description: Crop image depending on alpha value Param[1]: image (type: Image *) Param[2]: threshold (type: float) -Function 302: ImageAlphaClear() (3 input parameters) +Function 301: ImageAlphaClear() (3 input parameters) Name: ImageAlphaClear Return type: void Description: Clear alpha channel to desired color Param[1]: image (type: Image *) Param[2]: color (type: Color) Param[3]: threshold (type: float) -Function 303: ImageAlphaMask() (2 input parameters) +Function 302: ImageAlphaMask() (2 input parameters) Name: ImageAlphaMask Return type: void Description: Apply alpha mask to image Param[1]: image (type: Image *) Param[2]: alphaMask (type: Image) -Function 304: ImageAlphaPremultiply() (1 input parameters) +Function 303: ImageAlphaPremultiply() (1 input parameters) Name: ImageAlphaPremultiply Return type: void Description: Premultiply alpha channel Param[1]: image (type: Image *) -Function 305: ImageBlurGaussian() (2 input parameters) +Function 304: 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 306: ImageKernelConvolution() (3 input parameters) +Function 305: ImageKernelConvolution() (3 input parameters) Name: ImageKernelConvolution Return type: void Description: Apply custom square convolution kernel to image Param[1]: image (type: Image *) Param[2]: kernel (type: const float *) Param[3]: kernelSize (type: int) -Function 307: ImageResize() (3 input parameters) +Function 306: 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 308: ImageResizeNN() (3 input parameters) +Function 307: 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 309: ImageResizeCanvas() (6 input parameters) +Function 308: ImageResizeCanvas() (6 input parameters) Name: ImageResizeCanvas Return type: void Description: Resize canvas and fill with color @@ -2884,12 +2877,12 @@ Function 309: ImageResizeCanvas() (6 input parameters) Param[4]: offsetX (type: int) Param[5]: offsetY (type: int) Param[6]: fill (type: Color) -Function 310: ImageMipmaps() (1 input parameters) +Function 309: ImageMipmaps() (1 input parameters) Name: ImageMipmaps Return type: void Description: Compute all mipmap levels for a provided image Param[1]: image (type: Image *) -Function 311: ImageDither() (5 input parameters) +Function 310: ImageDither() (5 input parameters) Name: ImageDither Return type: void Description: Dither image data to 16bpp or lower (Floyd-Steinberg dithering) @@ -2898,109 +2891,109 @@ Function 311: ImageDither() (5 input parameters) Param[3]: gBpp (type: int) Param[4]: bBpp (type: int) Param[5]: aBpp (type: int) -Function 312: ImageFlipVertical() (1 input parameters) +Function 311: ImageFlipVertical() (1 input parameters) Name: ImageFlipVertical Return type: void Description: Flip image vertically Param[1]: image (type: Image *) -Function 313: ImageFlipHorizontal() (1 input parameters) +Function 312: ImageFlipHorizontal() (1 input parameters) Name: ImageFlipHorizontal Return type: void Description: Flip image horizontally Param[1]: image (type: Image *) -Function 314: ImageRotate() (2 input parameters) +Function 313: ImageRotate() (2 input parameters) Name: ImageRotate Return type: void Description: Rotate image by input angle in degrees (-359 to 359) Param[1]: image (type: Image *) Param[2]: degrees (type: int) -Function 315: ImageRotateCW() (1 input parameters) +Function 314: ImageRotateCW() (1 input parameters) Name: ImageRotateCW Return type: void Description: Rotate image clockwise 90deg Param[1]: image (type: Image *) -Function 316: ImageRotateCCW() (1 input parameters) +Function 315: ImageRotateCCW() (1 input parameters) Name: ImageRotateCCW Return type: void Description: Rotate image counter-clockwise 90deg Param[1]: image (type: Image *) -Function 317: ImageColorTint() (2 input parameters) +Function 316: 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 318: ImageColorInvert() (1 input parameters) +Function 317: ImageColorInvert() (1 input parameters) Name: ImageColorInvert Return type: void Description: Modify image color: invert Param[1]: image (type: Image *) -Function 319: ImageColorGrayscale() (1 input parameters) +Function 318: ImageColorGrayscale() (1 input parameters) Name: ImageColorGrayscale Return type: void Description: Modify image color: grayscale Param[1]: image (type: Image *) -Function 320: ImageColorContrast() (2 input parameters) +Function 319: 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 321: ImageColorBrightness() (2 input parameters) +Function 320: 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 322: ImageColorReplace() (3 input parameters) +Function 321: 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 323: LoadImageColors() (1 input parameters) +Function 322: 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 324: LoadImagePalette() (3 input parameters) +Function 323: 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 325: UnloadImageColors() (1 input parameters) +Function 324: UnloadImageColors() (1 input parameters) Name: UnloadImageColors Return type: void Description: Unload color data loaded with LoadImageColors() Param[1]: colors (type: Color *) -Function 326: UnloadImagePalette() (1 input parameters) +Function 325: UnloadImagePalette() (1 input parameters) Name: UnloadImagePalette Return type: void Description: Unload colors palette loaded with LoadImagePalette() Param[1]: colors (type: Color *) -Function 327: GetImageAlphaBorder() (2 input parameters) +Function 326: 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 328: GetImageColor() (3 input parameters) +Function 327: 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 329: ImageClearBackground() (2 input parameters) +Function 328: 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 330: ImageDrawPixel() (4 input parameters) +Function 329: ImageDrawPixel() (4 input parameters) Name: ImageDrawPixel Return type: void Description: Draw pixel within an image @@ -3008,14 +3001,14 @@ Function 330: ImageDrawPixel() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: color (type: Color) -Function 331: ImageDrawPixelV() (3 input parameters) +Function 330: 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 332: ImageDrawLine() (6 input parameters) +Function 331: ImageDrawLine() (6 input parameters) Name: ImageDrawLine Return type: void Description: Draw line within an image @@ -3025,7 +3018,7 @@ Function 332: ImageDrawLine() (6 input parameters) Param[4]: endPosX (type: int) Param[5]: endPosY (type: int) Param[6]: color (type: Color) -Function 333: ImageDrawLineV() (4 input parameters) +Function 332: ImageDrawLineV() (4 input parameters) Name: ImageDrawLineV Return type: void Description: Draw line within an image (Vector version) @@ -3033,7 +3026,7 @@ Function 333: ImageDrawLineV() (4 input parameters) Param[2]: start (type: Vector2) Param[3]: end (type: Vector2) Param[4]: color (type: Color) -Function 334: ImageDrawLineEx() (5 input parameters) +Function 333: ImageDrawLineEx() (5 input parameters) Name: ImageDrawLineEx Return type: void Description: Draw a line defining thickness within an image @@ -3042,7 +3035,7 @@ Function 334: ImageDrawLineEx() (5 input parameters) Param[3]: end (type: Vector2) Param[4]: thick (type: int) Param[5]: color (type: Color) -Function 335: ImageDrawCircle() (5 input parameters) +Function 334: ImageDrawCircle() (5 input parameters) Name: ImageDrawCircle Return type: void Description: Draw a filled circle within an image @@ -3051,7 +3044,7 @@ Function 335: ImageDrawCircle() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 336: ImageDrawCircleV() (4 input parameters) +Function 335: ImageDrawCircleV() (4 input parameters) Name: ImageDrawCircleV Return type: void Description: Draw a filled circle within an image (Vector version) @@ -3059,7 +3052,7 @@ Function 336: ImageDrawCircleV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 337: ImageDrawCircleLines() (5 input parameters) +Function 336: ImageDrawCircleLines() (5 input parameters) Name: ImageDrawCircleLines Return type: void Description: Draw circle outline within an image @@ -3068,7 +3061,7 @@ Function 337: ImageDrawCircleLines() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 338: ImageDrawCircleLinesV() (4 input parameters) +Function 337: ImageDrawCircleLinesV() (4 input parameters) Name: ImageDrawCircleLinesV Return type: void Description: Draw circle outline within an image (Vector version) @@ -3076,7 +3069,7 @@ Function 338: ImageDrawCircleLinesV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 339: ImageDrawRectangle() (6 input parameters) +Function 338: ImageDrawRectangle() (6 input parameters) Name: ImageDrawRectangle Return type: void Description: Draw rectangle within an image @@ -3086,7 +3079,7 @@ Function 339: ImageDrawRectangle() (6 input parameters) Param[4]: width (type: int) Param[5]: height (type: int) Param[6]: color (type: Color) -Function 340: ImageDrawRectangleV() (4 input parameters) +Function 339: ImageDrawRectangleV() (4 input parameters) Name: ImageDrawRectangleV Return type: void Description: Draw rectangle within an image (Vector version) @@ -3094,14 +3087,14 @@ Function 340: ImageDrawRectangleV() (4 input parameters) Param[2]: position (type: Vector2) Param[3]: size (type: Vector2) Param[4]: color (type: Color) -Function 341: ImageDrawRectangleRec() (3 input parameters) +Function 340: 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 342: ImageDrawRectangleLines() (4 input parameters) +Function 341: ImageDrawRectangleLines() (4 input parameters) Name: ImageDrawRectangleLines Return type: void Description: Draw rectangle lines within an image @@ -3109,7 +3102,7 @@ Function 342: ImageDrawRectangleLines() (4 input parameters) Param[2]: rec (type: Rectangle) Param[3]: thick (type: int) Param[4]: color (type: Color) -Function 343: ImageDrawTriangle() (5 input parameters) +Function 342: ImageDrawTriangle() (5 input parameters) Name: ImageDrawTriangle Return type: void Description: Draw triangle within an image @@ -3118,7 +3111,7 @@ Function 343: ImageDrawTriangle() (5 input parameters) Param[3]: v2 (type: Vector2) Param[4]: v3 (type: Vector2) Param[5]: color (type: Color) -Function 344: ImageDrawTriangleEx() (7 input parameters) +Function 343: ImageDrawTriangleEx() (7 input parameters) Name: ImageDrawTriangleEx Return type: void Description: Draw triangle with interpolated colors within an image @@ -3129,7 +3122,7 @@ Function 344: ImageDrawTriangleEx() (7 input parameters) Param[5]: c1 (type: Color) Param[6]: c2 (type: Color) Param[7]: c3 (type: Color) -Function 345: ImageDrawTriangleLines() (5 input parameters) +Function 344: ImageDrawTriangleLines() (5 input parameters) Name: ImageDrawTriangleLines Return type: void Description: Draw triangle outline within an image @@ -3138,7 +3131,7 @@ Function 345: ImageDrawTriangleLines() (5 input parameters) Param[3]: v2 (type: Vector2) Param[4]: v3 (type: Vector2) Param[5]: color (type: Color) -Function 346: ImageDrawTriangleFan() (4 input parameters) +Function 345: ImageDrawTriangleFan() (4 input parameters) Name: ImageDrawTriangleFan Return type: void Description: Draw a triangle fan defined by points within an image (first vertex is the center) @@ -3146,7 +3139,7 @@ Function 346: ImageDrawTriangleFan() (4 input parameters) Param[2]: points (type: Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 347: ImageDrawTriangleStrip() (4 input parameters) +Function 346: ImageDrawTriangleStrip() (4 input parameters) Name: ImageDrawTriangleStrip Return type: void Description: Draw a triangle strip defined by points within an image @@ -3154,7 +3147,7 @@ Function 347: ImageDrawTriangleStrip() (4 input parameters) Param[2]: points (type: Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 348: ImageDraw() (5 input parameters) +Function 347: ImageDraw() (5 input parameters) Name: ImageDraw Return type: void Description: Draw a source image within a destination image (tint applied to source) @@ -3163,7 +3156,7 @@ Function 348: ImageDraw() (5 input parameters) Param[3]: srcRec (type: Rectangle) Param[4]: dstRec (type: Rectangle) Param[5]: tint (type: Color) -Function 349: ImageDrawText() (6 input parameters) +Function 348: ImageDrawText() (6 input parameters) Name: ImageDrawText Return type: void Description: Draw text (using default font) within an image (destination) @@ -3173,7 +3166,7 @@ Function 349: ImageDrawText() (6 input parameters) Param[4]: posY (type: int) Param[5]: fontSize (type: int) Param[6]: color (type: Color) -Function 350: ImageDrawTextEx() (7 input parameters) +Function 349: ImageDrawTextEx() (7 input parameters) Name: ImageDrawTextEx Return type: void Description: Draw text (custom sprite font) within an image (destination) @@ -3184,79 +3177,79 @@ Function 350: ImageDrawTextEx() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 351: LoadTexture() (1 input parameters) +Function 350: 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 352: LoadTextureFromImage() (1 input parameters) +Function 351: LoadTextureFromImage() (1 input parameters) Name: LoadTextureFromImage Return type: Texture2D Description: Load texture from image data Param[1]: image (type: Image) -Function 353: LoadTextureCubemap() (2 input parameters) +Function 352: 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 354: LoadRenderTexture() (2 input parameters) +Function 353: 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 355: IsTextureReady() (1 input parameters) +Function 354: IsTextureReady() (1 input parameters) Name: IsTextureReady Return type: bool Description: Check if a texture is ready Param[1]: texture (type: Texture2D) -Function 356: UnloadTexture() (1 input parameters) +Function 355: UnloadTexture() (1 input parameters) Name: UnloadTexture Return type: void Description: Unload texture from GPU memory (VRAM) Param[1]: texture (type: Texture2D) -Function 357: IsRenderTextureReady() (1 input parameters) +Function 356: IsRenderTextureReady() (1 input parameters) Name: IsRenderTextureReady Return type: bool Description: Check if a render texture is ready Param[1]: target (type: RenderTexture2D) -Function 358: UnloadRenderTexture() (1 input parameters) +Function 357: UnloadRenderTexture() (1 input parameters) Name: UnloadRenderTexture Return type: void Description: Unload render texture from GPU memory (VRAM) Param[1]: target (type: RenderTexture2D) -Function 359: UpdateTexture() (2 input parameters) +Function 358: 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 360: UpdateTextureRec() (3 input parameters) +Function 359: 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 361: GenTextureMipmaps() (1 input parameters) +Function 360: GenTextureMipmaps() (1 input parameters) Name: GenTextureMipmaps Return type: void Description: Generate GPU mipmaps for a texture Param[1]: texture (type: Texture2D *) -Function 362: SetTextureFilter() (2 input parameters) +Function 361: 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 363: SetTextureWrap() (2 input parameters) +Function 362: 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 364: DrawTexture() (4 input parameters) +Function 363: DrawTexture() (4 input parameters) Name: DrawTexture Return type: void Description: Draw a Texture2D @@ -3264,14 +3257,14 @@ Function 364: DrawTexture() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: tint (type: Color) -Function 365: DrawTextureV() (3 input parameters) +Function 364: 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 366: DrawTextureEx() (5 input parameters) +Function 365: DrawTextureEx() (5 input parameters) Name: DrawTextureEx Return type: void Description: Draw a Texture2D with extended parameters @@ -3280,7 +3273,7 @@ Function 366: DrawTextureEx() (5 input parameters) Param[3]: rotation (type: float) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 367: DrawTextureRec() (4 input parameters) +Function 366: DrawTextureRec() (4 input parameters) Name: DrawTextureRec Return type: void Description: Draw a part of a texture defined by a rectangle @@ -3288,7 +3281,7 @@ Function 367: DrawTextureRec() (4 input parameters) Param[2]: source (type: Rectangle) Param[3]: position (type: Vector2) Param[4]: tint (type: Color) -Function 368: DrawTexturePro() (6 input parameters) +Function 367: DrawTexturePro() (6 input parameters) Name: DrawTexturePro Return type: void Description: Draw a part of a texture defined by a rectangle with 'pro' parameters @@ -3298,7 +3291,7 @@ Function 368: DrawTexturePro() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 369: DrawTextureNPatch() (6 input parameters) +Function 368: DrawTextureNPatch() (6 input parameters) Name: DrawTextureNPatch Return type: void Description: Draws a texture (or part of it) that stretches or shrinks nicely @@ -3308,119 +3301,119 @@ Function 369: DrawTextureNPatch() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 370: ColorIsEqual() (2 input parameters) +Function 369: ColorIsEqual() (2 input parameters) Name: ColorIsEqual Return type: bool Description: Check if two colors are equal Param[1]: col1 (type: Color) Param[2]: col2 (type: Color) -Function 371: Fade() (2 input parameters) +Function 370: Fade() (2 input parameters) Name: Fade Return type: Color Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f Param[1]: color (type: Color) Param[2]: alpha (type: float) -Function 372: ColorToInt() (1 input parameters) +Function 371: ColorToInt() (1 input parameters) Name: ColorToInt Return type: int Description: Get hexadecimal value for a Color (0xRRGGBBAA) Param[1]: color (type: Color) -Function 373: ColorNormalize() (1 input parameters) +Function 372: ColorNormalize() (1 input parameters) Name: ColorNormalize Return type: Vector4 Description: Get Color normalized as float [0..1] Param[1]: color (type: Color) -Function 374: ColorFromNormalized() (1 input parameters) +Function 373: ColorFromNormalized() (1 input parameters) Name: ColorFromNormalized Return type: Color Description: Get Color from normalized values [0..1] Param[1]: normalized (type: Vector4) -Function 375: ColorToHSV() (1 input parameters) +Function 374: ColorToHSV() (1 input parameters) Name: ColorToHSV Return type: Vector3 Description: Get HSV values for a Color, hue [0..360], saturation/value [0..1] Param[1]: color (type: Color) -Function 376: ColorFromHSV() (3 input parameters) +Function 375: ColorFromHSV() (3 input parameters) Name: ColorFromHSV Return type: Color Description: Get a Color from HSV values, hue [0..360], saturation/value [0..1] Param[1]: hue (type: float) Param[2]: saturation (type: float) Param[3]: value (type: float) -Function 377: ColorTint() (2 input parameters) +Function 376: 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 378: ColorBrightness() (2 input parameters) +Function 377: 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 379: ColorContrast() (2 input parameters) +Function 378: 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 380: ColorAlpha() (2 input parameters) +Function 379: 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 381: ColorAlphaBlend() (3 input parameters) +Function 380: 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 382: ColorLerp() (3 input parameters) +Function 381: ColorLerp() (3 input parameters) Name: ColorLerp Return type: Color Description: Get color lerp interpolation between two colors, factor [0.0f..1.0f] Param[1]: color1 (type: Color) Param[2]: color2 (type: Color) Param[3]: factor (type: float) -Function 383: GetColor() (1 input parameters) +Function 382: GetColor() (1 input parameters) Name: GetColor Return type: Color Description: Get Color structure from hexadecimal value Param[1]: hexValue (type: unsigned int) -Function 384: GetPixelColor() (2 input parameters) +Function 383: 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 385: SetPixelColor() (3 input parameters) +Function 384: 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 386: GetPixelDataSize() (3 input parameters) +Function 385: 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 387: GetFontDefault() (0 input parameters) +Function 386: GetFontDefault() (0 input parameters) Name: GetFontDefault Return type: Font Description: Get the default Font No input parameters -Function 388: LoadFont() (1 input parameters) +Function 387: 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 389: LoadFontEx() (4 input parameters) +Function 388: LoadFontEx() (4 input parameters) Name: LoadFontEx Return type: Font Description: Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height @@ -3428,14 +3421,14 @@ Function 389: LoadFontEx() (4 input parameters) Param[2]: fontSize (type: int) Param[3]: codepoints (type: int *) Param[4]: codepointCount (type: int) -Function 390: LoadFontFromImage() (3 input parameters) +Function 389: 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 391: LoadFontFromMemory() (6 input parameters) +Function 390: LoadFontFromMemory() (6 input parameters) Name: LoadFontFromMemory Return type: Font Description: Load font from memory buffer, fileType refers to extension: i.e. '.ttf' @@ -3445,12 +3438,12 @@ Function 391: LoadFontFromMemory() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: codepoints (type: int *) Param[6]: codepointCount (type: int) -Function 392: IsFontReady() (1 input parameters) +Function 391: IsFontReady() (1 input parameters) Name: IsFontReady Return type: bool Description: Check if a font is ready Param[1]: font (type: Font) -Function 393: LoadFontData() (6 input parameters) +Function 392: LoadFontData() (6 input parameters) Name: LoadFontData Return type: GlyphInfo * Description: Load font data for further use @@ -3460,7 +3453,7 @@ Function 393: LoadFontData() (6 input parameters) Param[4]: codepoints (type: int *) Param[5]: codepointCount (type: int) Param[6]: type (type: int) -Function 394: GenImageFontAtlas() (6 input parameters) +Function 393: GenImageFontAtlas() (6 input parameters) Name: GenImageFontAtlas Return type: Image Description: Generate image font atlas using chars info @@ -3470,30 +3463,30 @@ Function 394: GenImageFontAtlas() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: padding (type: int) Param[6]: packMethod (type: int) -Function 395: UnloadFontData() (2 input parameters) +Function 394: UnloadFontData() (2 input parameters) Name: UnloadFontData Return type: void Description: Unload font chars info data (RAM) Param[1]: glyphs (type: GlyphInfo *) Param[2]: glyphCount (type: int) -Function 396: UnloadFont() (1 input parameters) +Function 395: UnloadFont() (1 input parameters) Name: UnloadFont Return type: void Description: Unload font from GPU memory (VRAM) Param[1]: font (type: Font) -Function 397: ExportFontAsCode() (2 input parameters) +Function 396: 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 398: DrawFPS() (2 input parameters) +Function 397: DrawFPS() (2 input parameters) Name: DrawFPS Return type: void Description: Draw current FPS Param[1]: posX (type: int) Param[2]: posY (type: int) -Function 399: DrawText() (5 input parameters) +Function 398: DrawText() (5 input parameters) Name: DrawText Return type: void Description: Draw text (using default font) @@ -3502,7 +3495,7 @@ Function 399: DrawText() (5 input parameters) Param[3]: posY (type: int) Param[4]: fontSize (type: int) Param[5]: color (type: Color) -Function 400: DrawTextEx() (6 input parameters) +Function 399: DrawTextEx() (6 input parameters) Name: DrawTextEx Return type: void Description: Draw text using font and additional parameters @@ -3512,7 +3505,7 @@ Function 400: DrawTextEx() (6 input parameters) Param[4]: fontSize (type: float) Param[5]: spacing (type: float) Param[6]: tint (type: Color) -Function 401: DrawTextPro() (8 input parameters) +Function 400: DrawTextPro() (8 input parameters) Name: DrawTextPro Return type: void Description: Draw text using Font and pro parameters (rotation) @@ -3524,7 +3517,7 @@ Function 401: DrawTextPro() (8 input parameters) Param[6]: fontSize (type: float) Param[7]: spacing (type: float) Param[8]: tint (type: Color) -Function 402: DrawTextCodepoint() (5 input parameters) +Function 401: DrawTextCodepoint() (5 input parameters) Name: DrawTextCodepoint Return type: void Description: Draw one character (codepoint) @@ -3533,7 +3526,7 @@ Function 402: DrawTextCodepoint() (5 input parameters) Param[3]: position (type: Vector2) Param[4]: fontSize (type: float) Param[5]: tint (type: Color) -Function 403: DrawTextCodepoints() (7 input parameters) +Function 402: DrawTextCodepoints() (7 input parameters) Name: DrawTextCodepoints Return type: void Description: Draw multiple character (codepoint) @@ -3544,18 +3537,18 @@ Function 403: DrawTextCodepoints() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 404: SetTextLineSpacing() (1 input parameters) +Function 403: SetTextLineSpacing() (1 input parameters) Name: SetTextLineSpacing Return type: void Description: Set vertical line spacing when drawing with line-breaks Param[1]: spacing (type: int) -Function 405: MeasureText() (2 input parameters) +Function 404: 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 406: MeasureTextEx() (4 input parameters) +Function 405: MeasureTextEx() (4 input parameters) Name: MeasureTextEx Return type: Vector2 Description: Measure string size for Font @@ -3563,195 +3556,195 @@ Function 406: MeasureTextEx() (4 input parameters) Param[2]: text (type: const char *) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) -Function 407: GetGlyphIndex() (2 input parameters) +Function 406: 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 408: GetGlyphInfo() (2 input parameters) +Function 407: 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 409: GetGlyphAtlasRec() (2 input parameters) +Function 408: 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 410: LoadUTF8() (2 input parameters) +Function 409: 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 411: UnloadUTF8() (1 input parameters) +Function 410: UnloadUTF8() (1 input parameters) Name: UnloadUTF8 Return type: void Description: Unload UTF-8 text encoded from codepoints array Param[1]: text (type: char *) -Function 412: LoadCodepoints() (2 input parameters) +Function 411: 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 413: UnloadCodepoints() (1 input parameters) +Function 412: UnloadCodepoints() (1 input parameters) Name: UnloadCodepoints Return type: void Description: Unload codepoints data from memory Param[1]: codepoints (type: int *) -Function 414: GetCodepointCount() (1 input parameters) +Function 413: 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 415: GetCodepoint() (2 input parameters) +Function 414: 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 416: GetCodepointNext() (2 input parameters) +Function 415: 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 417: GetCodepointPrevious() (2 input parameters) +Function 416: 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 418: CodepointToUTF8() (2 input parameters) +Function 417: 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 419: TextCopy() (2 input parameters) +Function 418: 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 420: TextIsEqual() (2 input parameters) +Function 419: 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 421: TextLength() (1 input parameters) +Function 420: 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 422: TextFormat() (2 input parameters) +Function 421: 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 423: TextSubtext() (3 input parameters) +Function 422: 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 424: TextReplace() (3 input parameters) +Function 423: TextReplace() (3 input parameters) Name: TextReplace Return type: char * Description: Replace text string (WARNING: memory must be freed!) Param[1]: text (type: const char *) Param[2]: replace (type: const char *) Param[3]: by (type: const char *) -Function 425: TextInsert() (3 input parameters) +Function 424: 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 426: TextJoin() (3 input parameters) +Function 425: 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 427: TextSplit() (3 input parameters) +Function 426: 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 428: TextAppend() (3 input parameters) +Function 427: 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 429: TextFindIndex() (2 input parameters) +Function 428: 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 430: TextToUpper() (1 input parameters) +Function 429: 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 431: TextToLower() (1 input parameters) +Function 430: 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 432: TextToPascal() (1 input parameters) +Function 431: 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 433: TextToSnake() (1 input parameters) +Function 432: TextToSnake() (1 input parameters) Name: TextToSnake Return type: const char * Description: Get Snake case notation version of provided string Param[1]: text (type: const char *) -Function 434: TextToCamel() (1 input parameters) +Function 433: TextToCamel() (1 input parameters) Name: TextToCamel Return type: const char * Description: Get Camel case notation version of provided string Param[1]: text (type: const char *) -Function 435: TextToInteger() (1 input parameters) +Function 434: 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 436: TextToFloat() (1 input parameters) +Function 435: TextToFloat() (1 input parameters) Name: TextToFloat Return type: float Description: Get float value from text (negative values not supported) Param[1]: text (type: const char *) -Function 437: DrawLine3D() (3 input parameters) +Function 436: 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 438: DrawPoint3D() (2 input parameters) +Function 437: 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 439: DrawCircle3D() (5 input parameters) +Function 438: DrawCircle3D() (5 input parameters) Name: DrawCircle3D Return type: void Description: Draw a circle in 3D world space @@ -3760,7 +3753,7 @@ Function 439: DrawCircle3D() (5 input parameters) Param[3]: rotationAxis (type: Vector3) Param[4]: rotationAngle (type: float) Param[5]: color (type: Color) -Function 440: DrawTriangle3D() (4 input parameters) +Function 439: DrawTriangle3D() (4 input parameters) Name: DrawTriangle3D Return type: void Description: Draw a color-filled triangle (vertex in counter-clockwise order!) @@ -3768,14 +3761,14 @@ Function 440: DrawTriangle3D() (4 input parameters) Param[2]: v2 (type: Vector3) Param[3]: v3 (type: Vector3) Param[4]: color (type: Color) -Function 441: DrawTriangleStrip3D() (3 input parameters) +Function 440: DrawTriangleStrip3D() (3 input parameters) Name: DrawTriangleStrip3D Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector3 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 442: DrawCube() (5 input parameters) +Function 441: DrawCube() (5 input parameters) Name: DrawCube Return type: void Description: Draw cube @@ -3784,14 +3777,14 @@ Function 442: DrawCube() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 443: DrawCubeV() (3 input parameters) +Function 442: 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 444: DrawCubeWires() (5 input parameters) +Function 443: DrawCubeWires() (5 input parameters) Name: DrawCubeWires Return type: void Description: Draw cube wires @@ -3800,21 +3793,21 @@ Function 444: DrawCubeWires() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 445: DrawCubeWiresV() (3 input parameters) +Function 444: 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 446: DrawSphere() (3 input parameters) +Function 445: 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 447: DrawSphereEx() (5 input parameters) +Function 446: DrawSphereEx() (5 input parameters) Name: DrawSphereEx Return type: void Description: Draw sphere with extended parameters @@ -3823,7 +3816,7 @@ Function 447: DrawSphereEx() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 448: DrawSphereWires() (5 input parameters) +Function 447: DrawSphereWires() (5 input parameters) Name: DrawSphereWires Return type: void Description: Draw sphere wires @@ -3832,7 +3825,7 @@ Function 448: DrawSphereWires() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 449: DrawCylinder() (6 input parameters) +Function 448: DrawCylinder() (6 input parameters) Name: DrawCylinder Return type: void Description: Draw a cylinder/cone @@ -3842,7 +3835,7 @@ Function 449: DrawCylinder() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 450: DrawCylinderEx() (6 input parameters) +Function 449: DrawCylinderEx() (6 input parameters) Name: DrawCylinderEx Return type: void Description: Draw a cylinder with base at startPos and top at endPos @@ -3852,7 +3845,7 @@ Function 450: DrawCylinderEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 451: DrawCylinderWires() (6 input parameters) +Function 450: DrawCylinderWires() (6 input parameters) Name: DrawCylinderWires Return type: void Description: Draw a cylinder/cone wires @@ -3862,7 +3855,7 @@ Function 451: DrawCylinderWires() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 452: DrawCylinderWiresEx() (6 input parameters) +Function 451: DrawCylinderWiresEx() (6 input parameters) Name: DrawCylinderWiresEx Return type: void Description: Draw a cylinder wires with base at startPos and top at endPos @@ -3872,7 +3865,7 @@ Function 452: DrawCylinderWiresEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 453: DrawCapsule() (6 input parameters) +Function 452: DrawCapsule() (6 input parameters) Name: DrawCapsule Return type: void Description: Draw a capsule with the center of its sphere caps at startPos and endPos @@ -3882,7 +3875,7 @@ Function 453: DrawCapsule() (6 input parameters) Param[4]: slices (type: int) Param[5]: rings (type: int) Param[6]: color (type: Color) -Function 454: DrawCapsuleWires() (6 input parameters) +Function 453: DrawCapsuleWires() (6 input parameters) Name: DrawCapsuleWires Return type: void Description: Draw capsule wireframe with the center of its sphere caps at startPos and endPos @@ -3892,51 +3885,51 @@ Function 454: DrawCapsuleWires() (6 input parameters) Param[4]: slices (type: int) Param[5]: rings (type: int) Param[6]: color (type: Color) -Function 455: DrawPlane() (3 input parameters) +Function 454: 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 456: DrawRay() (2 input parameters) +Function 455: 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 457: DrawGrid() (2 input parameters) +Function 456: 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 458: LoadModel() (1 input parameters) +Function 457: LoadModel() (1 input parameters) Name: LoadModel Return type: Model Description: Load model from files (meshes and materials) Param[1]: fileName (type: const char *) -Function 459: LoadModelFromMesh() (1 input parameters) +Function 458: LoadModelFromMesh() (1 input parameters) Name: LoadModelFromMesh Return type: Model Description: Load model from generated mesh (default material) Param[1]: mesh (type: Mesh) -Function 460: IsModelReady() (1 input parameters) +Function 459: IsModelReady() (1 input parameters) Name: IsModelReady Return type: bool Description: Check if a model is ready Param[1]: model (type: Model) -Function 461: UnloadModel() (1 input parameters) +Function 460: 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 462: GetModelBoundingBox() (1 input parameters) +Function 461: GetModelBoundingBox() (1 input parameters) Name: GetModelBoundingBox Return type: BoundingBox Description: Compute model bounding box limits (considers all meshes) Param[1]: model (type: Model) -Function 463: DrawModel() (4 input parameters) +Function 462: DrawModel() (4 input parameters) Name: DrawModel Return type: void Description: Draw a model (with texture if set) @@ -3944,7 +3937,7 @@ Function 463: DrawModel() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 464: DrawModelEx() (6 input parameters) +Function 463: DrawModelEx() (6 input parameters) Name: DrawModelEx Return type: void Description: Draw a model with extended parameters @@ -3954,7 +3947,7 @@ Function 464: DrawModelEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 465: DrawModelWires() (4 input parameters) +Function 464: DrawModelWires() (4 input parameters) Name: DrawModelWires Return type: void Description: Draw a model wires (with texture if set) @@ -3962,7 +3955,7 @@ Function 465: DrawModelWires() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 466: DrawModelWiresEx() (6 input parameters) +Function 465: DrawModelWiresEx() (6 input parameters) Name: DrawModelWiresEx Return type: void Description: Draw a model wires (with texture if set) with extended parameters @@ -3972,7 +3965,7 @@ Function 466: DrawModelWiresEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 467: DrawModelPoints() (4 input parameters) +Function 466: DrawModelPoints() (4 input parameters) Name: DrawModelPoints Return type: void Description: Draw a model as points @@ -3980,7 +3973,7 @@ Function 467: DrawModelPoints() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 468: DrawModelPointsEx() (6 input parameters) +Function 467: DrawModelPointsEx() (6 input parameters) Name: DrawModelPointsEx Return type: void Description: Draw a model as points with extended parameters @@ -3990,13 +3983,13 @@ Function 468: DrawModelPointsEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 469: DrawBoundingBox() (2 input parameters) +Function 468: 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 470: DrawBillboard() (5 input parameters) +Function 469: DrawBillboard() (5 input parameters) Name: DrawBillboard Return type: void Description: Draw a billboard texture @@ -4005,7 +3998,7 @@ Function 470: DrawBillboard() (5 input parameters) Param[3]: position (type: Vector3) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 471: DrawBillboardRec() (6 input parameters) +Function 470: DrawBillboardRec() (6 input parameters) Name: DrawBillboardRec Return type: void Description: Draw a billboard texture defined by source @@ -4015,7 +4008,7 @@ Function 471: DrawBillboardRec() (6 input parameters) Param[4]: position (type: Vector3) Param[5]: size (type: Vector2) Param[6]: tint (type: Color) -Function 472: DrawBillboardPro() (9 input parameters) +Function 471: DrawBillboardPro() (9 input parameters) Name: DrawBillboardPro Return type: void Description: Draw a billboard texture defined by source and rotation @@ -4028,13 +4021,13 @@ Function 472: DrawBillboardPro() (9 input parameters) Param[7]: origin (type: Vector2) Param[8]: rotation (type: float) Param[9]: tint (type: Color) -Function 473: UploadMesh() (2 input parameters) +Function 472: 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 474: UpdateMeshBuffer() (5 input parameters) +Function 473: UpdateMeshBuffer() (5 input parameters) Name: UpdateMeshBuffer Return type: void Description: Update mesh vertex data in GPU for a specific buffer index @@ -4043,19 +4036,19 @@ Function 474: UpdateMeshBuffer() (5 input parameters) Param[3]: data (type: const void *) Param[4]: dataSize (type: int) Param[5]: offset (type: int) -Function 475: UnloadMesh() (1 input parameters) +Function 474: UnloadMesh() (1 input parameters) Name: UnloadMesh Return type: void Description: Unload mesh data from CPU and GPU Param[1]: mesh (type: Mesh) -Function 476: DrawMesh() (3 input parameters) +Function 475: 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 477: DrawMeshInstanced() (4 input parameters) +Function 476: DrawMeshInstanced() (4 input parameters) Name: DrawMeshInstanced Return type: void Description: Draw multiple mesh instances with material and different transforms @@ -4063,35 +4056,35 @@ Function 477: DrawMeshInstanced() (4 input parameters) Param[2]: material (type: Material) Param[3]: transforms (type: const Matrix *) Param[4]: instances (type: int) -Function 478: GetMeshBoundingBox() (1 input parameters) +Function 477: GetMeshBoundingBox() (1 input parameters) Name: GetMeshBoundingBox Return type: BoundingBox Description: Compute mesh bounding box limits Param[1]: mesh (type: Mesh) -Function 479: GenMeshTangents() (1 input parameters) +Function 478: GenMeshTangents() (1 input parameters) Name: GenMeshTangents Return type: void Description: Compute mesh tangents Param[1]: mesh (type: Mesh *) -Function 480: ExportMesh() (2 input parameters) +Function 479: 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 481: ExportMeshAsCode() (2 input parameters) +Function 480: ExportMeshAsCode() (2 input parameters) Name: ExportMeshAsCode Return type: bool Description: Export mesh as code file (.h) defining multiple arrays of vertex attributes Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 482: GenMeshPoly() (2 input parameters) +Function 481: GenMeshPoly() (2 input parameters) Name: GenMeshPoly Return type: Mesh Description: Generate polygonal mesh Param[1]: sides (type: int) Param[2]: radius (type: float) -Function 483: GenMeshPlane() (4 input parameters) +Function 482: GenMeshPlane() (4 input parameters) Name: GenMeshPlane Return type: Mesh Description: Generate plane mesh (with subdivisions) @@ -4099,42 +4092,42 @@ Function 483: GenMeshPlane() (4 input parameters) Param[2]: length (type: float) Param[3]: resX (type: int) Param[4]: resZ (type: int) -Function 484: GenMeshCube() (3 input parameters) +Function 483: 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 485: GenMeshSphere() (3 input parameters) +Function 484: 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 486: GenMeshHemiSphere() (3 input parameters) +Function 485: 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 487: GenMeshCylinder() (3 input parameters) +Function 486: 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 488: GenMeshCone() (3 input parameters) +Function 487: 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 489: GenMeshTorus() (4 input parameters) +Function 488: GenMeshTorus() (4 input parameters) Name: GenMeshTorus Return type: Mesh Description: Generate torus mesh @@ -4142,7 +4135,7 @@ Function 489: GenMeshTorus() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 490: GenMeshKnot() (4 input parameters) +Function 489: GenMeshKnot() (4 input parameters) Name: GenMeshKnot Return type: Mesh Description: Generate trefoil knot mesh @@ -4150,91 +4143,91 @@ Function 490: GenMeshKnot() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 491: GenMeshHeightmap() (2 input parameters) +Function 490: 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 492: GenMeshCubicmap() (2 input parameters) +Function 491: 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 493: LoadMaterials() (2 input parameters) +Function 492: 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 494: LoadMaterialDefault() (0 input parameters) +Function 493: LoadMaterialDefault() (0 input parameters) Name: LoadMaterialDefault Return type: Material Description: Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) No input parameters -Function 495: IsMaterialReady() (1 input parameters) +Function 494: IsMaterialReady() (1 input parameters) Name: IsMaterialReady Return type: bool Description: Check if a material is ready Param[1]: material (type: Material) -Function 496: UnloadMaterial() (1 input parameters) +Function 495: UnloadMaterial() (1 input parameters) Name: UnloadMaterial Return type: void Description: Unload material from GPU memory (VRAM) Param[1]: material (type: Material) -Function 497: SetMaterialTexture() (3 input parameters) +Function 496: 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 498: SetModelMeshMaterial() (3 input parameters) +Function 497: 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 499: LoadModelAnimations() (2 input parameters) +Function 498: LoadModelAnimations() (2 input parameters) Name: LoadModelAnimations Return type: ModelAnimation * Description: Load model animations from file Param[1]: fileName (type: const char *) Param[2]: animCount (type: int *) -Function 500: UpdateModelAnimation() (3 input parameters) +Function 499: 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 501: UnloadModelAnimation() (1 input parameters) +Function 500: UnloadModelAnimation() (1 input parameters) Name: UnloadModelAnimation Return type: void Description: Unload animation data Param[1]: anim (type: ModelAnimation) -Function 502: UnloadModelAnimations() (2 input parameters) +Function 501: UnloadModelAnimations() (2 input parameters) Name: UnloadModelAnimations Return type: void Description: Unload animation array data Param[1]: animations (type: ModelAnimation *) Param[2]: animCount (type: int) -Function 503: IsModelAnimationValid() (2 input parameters) +Function 502: 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 504: UpdateModelAnimationBoneMatrices() (3 input parameters) +Function 503: UpdateModelAnimationBoneMatrices() (3 input parameters) Name: UpdateModelAnimationBoneMatrices Return type: void Description: Update model animation mesh bone matrices (Note GPU skinning does not work on Mac) Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) Param[3]: frame (type: int) -Function 505: CheckCollisionSpheres() (4 input parameters) +Function 504: CheckCollisionSpheres() (4 input parameters) Name: CheckCollisionSpheres Return type: bool Description: Check collision between two spheres @@ -4242,40 +4235,40 @@ Function 505: CheckCollisionSpheres() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector3) Param[4]: radius2 (type: float) -Function 506: CheckCollisionBoxes() (2 input parameters) +Function 505: 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 507: CheckCollisionBoxSphere() (3 input parameters) +Function 506: 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 508: GetRayCollisionSphere() (3 input parameters) +Function 507: 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 509: GetRayCollisionBox() (2 input parameters) +Function 508: 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 510: GetRayCollisionMesh() (3 input parameters) +Function 509: 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 511: GetRayCollisionTriangle() (4 input parameters) +Function 510: GetRayCollisionTriangle() (4 input parameters) Name: GetRayCollisionTriangle Return type: RayCollision Description: Get collision info between ray and triangle @@ -4283,7 +4276,7 @@ Function 511: GetRayCollisionTriangle() (4 input parameters) Param[2]: p1 (type: Vector3) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) -Function 512: GetRayCollisionQuad() (5 input parameters) +Function 511: GetRayCollisionQuad() (5 input parameters) Name: GetRayCollisionQuad Return type: RayCollision Description: Get collision info between ray and quad @@ -4292,158 +4285,158 @@ Function 512: GetRayCollisionQuad() (5 input parameters) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) Param[5]: p4 (type: Vector3) -Function 513: InitAudioDevice() (0 input parameters) +Function 512: InitAudioDevice() (0 input parameters) Name: InitAudioDevice Return type: void Description: Initialize audio device and context No input parameters -Function 514: CloseAudioDevice() (0 input parameters) +Function 513: CloseAudioDevice() (0 input parameters) Name: CloseAudioDevice Return type: void Description: Close the audio device and context No input parameters -Function 515: IsAudioDeviceReady() (0 input parameters) +Function 514: IsAudioDeviceReady() (0 input parameters) Name: IsAudioDeviceReady Return type: bool Description: Check if audio device has been initialized successfully No input parameters -Function 516: SetMasterVolume() (1 input parameters) +Function 515: SetMasterVolume() (1 input parameters) Name: SetMasterVolume Return type: void Description: Set master volume (listener) Param[1]: volume (type: float) -Function 517: GetMasterVolume() (0 input parameters) +Function 516: GetMasterVolume() (0 input parameters) Name: GetMasterVolume Return type: float Description: Get master volume (listener) No input parameters -Function 518: LoadWave() (1 input parameters) +Function 517: LoadWave() (1 input parameters) Name: LoadWave Return type: Wave Description: Load wave data from file Param[1]: fileName (type: const char *) -Function 519: LoadWaveFromMemory() (3 input parameters) +Function 518: 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 520: IsWaveReady() (1 input parameters) +Function 519: IsWaveReady() (1 input parameters) Name: IsWaveReady Return type: bool Description: Checks if wave data is ready Param[1]: wave (type: Wave) -Function 521: LoadSound() (1 input parameters) +Function 520: LoadSound() (1 input parameters) Name: LoadSound Return type: Sound Description: Load sound from file Param[1]: fileName (type: const char *) -Function 522: LoadSoundFromWave() (1 input parameters) +Function 521: LoadSoundFromWave() (1 input parameters) Name: LoadSoundFromWave Return type: Sound Description: Load sound from wave data Param[1]: wave (type: Wave) -Function 523: LoadSoundAlias() (1 input parameters) +Function 522: LoadSoundAlias() (1 input parameters) Name: LoadSoundAlias Return type: Sound Description: Create a new sound that shares the same sample data as the source sound, does not own the sound data Param[1]: source (type: Sound) -Function 524: IsSoundReady() (1 input parameters) +Function 523: IsSoundReady() (1 input parameters) Name: IsSoundReady Return type: bool Description: Checks if a sound is ready Param[1]: sound (type: Sound) -Function 525: UpdateSound() (3 input parameters) +Function 524: 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 526: UnloadWave() (1 input parameters) +Function 525: UnloadWave() (1 input parameters) Name: UnloadWave Return type: void Description: Unload wave data Param[1]: wave (type: Wave) -Function 527: UnloadSound() (1 input parameters) +Function 526: UnloadSound() (1 input parameters) Name: UnloadSound Return type: void Description: Unload sound Param[1]: sound (type: Sound) -Function 528: UnloadSoundAlias() (1 input parameters) +Function 527: UnloadSoundAlias() (1 input parameters) Name: UnloadSoundAlias Return type: void Description: Unload a sound alias (does not deallocate sample data) Param[1]: alias (type: Sound) -Function 529: ExportWave() (2 input parameters) +Function 528: 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 530: ExportWaveAsCode() (2 input parameters) +Function 529: 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 531: PlaySound() (1 input parameters) +Function 530: PlaySound() (1 input parameters) Name: PlaySound Return type: void Description: Play a sound Param[1]: sound (type: Sound) -Function 532: StopSound() (1 input parameters) +Function 531: StopSound() (1 input parameters) Name: StopSound Return type: void Description: Stop playing a sound Param[1]: sound (type: Sound) -Function 533: PauseSound() (1 input parameters) +Function 532: PauseSound() (1 input parameters) Name: PauseSound Return type: void Description: Pause a sound Param[1]: sound (type: Sound) -Function 534: ResumeSound() (1 input parameters) +Function 533: ResumeSound() (1 input parameters) Name: ResumeSound Return type: void Description: Resume a paused sound Param[1]: sound (type: Sound) -Function 535: IsSoundPlaying() (1 input parameters) +Function 534: IsSoundPlaying() (1 input parameters) Name: IsSoundPlaying Return type: bool Description: Check if a sound is currently playing Param[1]: sound (type: Sound) -Function 536: SetSoundVolume() (2 input parameters) +Function 535: 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 537: SetSoundPitch() (2 input parameters) +Function 536: 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 538: SetSoundPan() (2 input parameters) +Function 537: 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 539: WaveCopy() (1 input parameters) +Function 538: WaveCopy() (1 input parameters) Name: WaveCopy Return type: Wave Description: Copy a wave to a new wave Param[1]: wave (type: Wave) -Function 540: WaveCrop() (3 input parameters) +Function 539: WaveCrop() (3 input parameters) Name: WaveCrop Return type: void Description: Crop a wave to defined frames range Param[1]: wave (type: Wave *) Param[2]: initFrame (type: int) Param[3]: finalFrame (type: int) -Function 541: WaveFormat() (4 input parameters) +Function 540: WaveFormat() (4 input parameters) Name: WaveFormat Return type: void Description: Convert wave data to desired format @@ -4451,203 +4444,203 @@ Function 541: WaveFormat() (4 input parameters) Param[2]: sampleRate (type: int) Param[3]: sampleSize (type: int) Param[4]: channels (type: int) -Function 542: LoadWaveSamples() (1 input parameters) +Function 541: 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 543: UnloadWaveSamples() (1 input parameters) +Function 542: UnloadWaveSamples() (1 input parameters) Name: UnloadWaveSamples Return type: void Description: Unload samples data loaded with LoadWaveSamples() Param[1]: samples (type: float *) -Function 544: LoadMusicStream() (1 input parameters) +Function 543: LoadMusicStream() (1 input parameters) Name: LoadMusicStream Return type: Music Description: Load music stream from file Param[1]: fileName (type: const char *) -Function 545: LoadMusicStreamFromMemory() (3 input parameters) +Function 544: 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 546: IsMusicReady() (1 input parameters) +Function 545: IsMusicReady() (1 input parameters) Name: IsMusicReady Return type: bool Description: Checks if a music stream is ready Param[1]: music (type: Music) -Function 547: UnloadMusicStream() (1 input parameters) +Function 546: UnloadMusicStream() (1 input parameters) Name: UnloadMusicStream Return type: void Description: Unload music stream Param[1]: music (type: Music) -Function 548: PlayMusicStream() (1 input parameters) +Function 547: PlayMusicStream() (1 input parameters) Name: PlayMusicStream Return type: void Description: Start music playing Param[1]: music (type: Music) -Function 549: IsMusicStreamPlaying() (1 input parameters) +Function 548: IsMusicStreamPlaying() (1 input parameters) Name: IsMusicStreamPlaying Return type: bool Description: Check if music is playing Param[1]: music (type: Music) -Function 550: UpdateMusicStream() (1 input parameters) +Function 549: UpdateMusicStream() (1 input parameters) Name: UpdateMusicStream Return type: void Description: Updates buffers for music streaming Param[1]: music (type: Music) -Function 551: StopMusicStream() (1 input parameters) +Function 550: StopMusicStream() (1 input parameters) Name: StopMusicStream Return type: void Description: Stop music playing Param[1]: music (type: Music) -Function 552: PauseMusicStream() (1 input parameters) +Function 551: PauseMusicStream() (1 input parameters) Name: PauseMusicStream Return type: void Description: Pause music playing Param[1]: music (type: Music) -Function 553: ResumeMusicStream() (1 input parameters) +Function 552: ResumeMusicStream() (1 input parameters) Name: ResumeMusicStream Return type: void Description: Resume playing paused music Param[1]: music (type: Music) -Function 554: SeekMusicStream() (2 input parameters) +Function 553: 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 555: SetMusicVolume() (2 input parameters) +Function 554: 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 556: SetMusicPitch() (2 input parameters) +Function 555: 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 557: SetMusicPan() (2 input parameters) +Function 556: 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 558: GetMusicTimeLength() (1 input parameters) +Function 557: GetMusicTimeLength() (1 input parameters) Name: GetMusicTimeLength Return type: float Description: Get music time length (in seconds) Param[1]: music (type: Music) -Function 559: GetMusicTimePlayed() (1 input parameters) +Function 558: GetMusicTimePlayed() (1 input parameters) Name: GetMusicTimePlayed Return type: float Description: Get current music time played (in seconds) Param[1]: music (type: Music) -Function 560: LoadAudioStream() (3 input parameters) +Function 559: 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 561: IsAudioStreamReady() (1 input parameters) +Function 560: IsAudioStreamReady() (1 input parameters) Name: IsAudioStreamReady Return type: bool Description: Checks if an audio stream is ready Param[1]: stream (type: AudioStream) -Function 562: UnloadAudioStream() (1 input parameters) +Function 561: UnloadAudioStream() (1 input parameters) Name: UnloadAudioStream Return type: void Description: Unload audio stream and free memory Param[1]: stream (type: AudioStream) -Function 563: UpdateAudioStream() (3 input parameters) +Function 562: 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 564: IsAudioStreamProcessed() (1 input parameters) +Function 563: IsAudioStreamProcessed() (1 input parameters) Name: IsAudioStreamProcessed Return type: bool Description: Check if any audio stream buffers requires refill Param[1]: stream (type: AudioStream) -Function 565: PlayAudioStream() (1 input parameters) +Function 564: PlayAudioStream() (1 input parameters) Name: PlayAudioStream Return type: void Description: Play audio stream Param[1]: stream (type: AudioStream) -Function 566: PauseAudioStream() (1 input parameters) +Function 565: PauseAudioStream() (1 input parameters) Name: PauseAudioStream Return type: void Description: Pause audio stream Param[1]: stream (type: AudioStream) -Function 567: ResumeAudioStream() (1 input parameters) +Function 566: ResumeAudioStream() (1 input parameters) Name: ResumeAudioStream Return type: void Description: Resume audio stream Param[1]: stream (type: AudioStream) -Function 568: IsAudioStreamPlaying() (1 input parameters) +Function 567: IsAudioStreamPlaying() (1 input parameters) Name: IsAudioStreamPlaying Return type: bool Description: Check if audio stream is playing Param[1]: stream (type: AudioStream) -Function 569: StopAudioStream() (1 input parameters) +Function 568: StopAudioStream() (1 input parameters) Name: StopAudioStream Return type: void Description: Stop audio stream Param[1]: stream (type: AudioStream) -Function 570: SetAudioStreamVolume() (2 input parameters) +Function 569: 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 571: SetAudioStreamPitch() (2 input parameters) +Function 570: 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 572: SetAudioStreamPan() (2 input parameters) +Function 571: 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 573: SetAudioStreamBufferSizeDefault() (1 input parameters) +Function 572: SetAudioStreamBufferSizeDefault() (1 input parameters) Name: SetAudioStreamBufferSizeDefault Return type: void Description: Default size for new audio streams Param[1]: size (type: int) -Function 574: SetAudioStreamCallback() (2 input parameters) +Function 573: 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 575: AttachAudioStreamProcessor() (2 input parameters) +Function 574: AttachAudioStreamProcessor() (2 input parameters) Name: AttachAudioStreamProcessor Return type: void Description: Attach audio stream processor to stream, receives the samples as 'float' Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 576: DetachAudioStreamProcessor() (2 input parameters) +Function 575: 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 577: AttachAudioMixedProcessor() (1 input parameters) +Function 576: AttachAudioMixedProcessor() (1 input parameters) Name: AttachAudioMixedProcessor Return type: void Description: Attach audio stream processor to the entire audio pipeline, receives the samples as 'float' Param[1]: processor (type: AudioCallback) -Function 578: DetachAudioMixedProcessor() (1 input parameters) +Function 577: DetachAudioMixedProcessor() (1 input parameters) Name: DetachAudioMixedProcessor Return type: void Description: Detach audio stream processor from the entire audio pipeline diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index 895680f2c..73ce0dae7 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -675,7 +675,7 @@ - + @@ -1699,11 +1699,6 @@ - - - - - From 59417636ca956d64800e7e26d4f4ec331cf1b412 Mon Sep 17 00:00:00 2001 From: Anand Swaroop <72886192+Anut-py@users.noreply.github.com> Date: Sat, 12 Oct 2024 07:14:35 -0400 Subject: [PATCH 081/115] Update BINDINGS.md (#4378) --- BINDINGS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BINDINGS.md b/BINDINGS.md index e79d39c36..576d9b463 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -31,7 +31,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers | [raylib-go](https://github.com/gen2brain/raylib-go) | **5.0** | [Go](https://golang.org) | Zlib | | [raylib-guile](https://github.com/petelliott/raylib-guile) | **auto** | [Guile](https://www.gnu.org/software/guile) | Zlib | | [gforth-raylib](https://github.com/ArnautDaniel/gforth-raylib) | 3.5 | [Gforth](https://gforth.org) | **???** | -| [h-raylib](https://github.com/Anut-py/h-raylib) | **5.1-dev** | [Haskell](https://haskell.org) | Apache-2.0 | +| [h-raylib](https://github.com/Anut-py/h-raylib) | **5.5-dev** | [Haskell](https://haskell.org) | Apache-2.0 | | [raylib-hx](https://github.com/foreignsasquatch/raylib-hx) | 4.2 | [Haxe](https://haxe.org) | Zlib | | [hb-raylib](https://github.com/MarcosLeonardoMendezGerencir/hb-raylib) | 3.5 | [Harbour](https://harbour.github.io) | MIT | | [jaylib](https://github.com/janet-lang/jaylib) | **5.0** | [Janet](https://janet-lang.org) | MIT | From bac3798ad368c7e89edfd7fa647a4e7a2a71b9bd Mon Sep 17 00:00:00 2001 From: Sage Hane Date: Mon, 14 Oct 2024 01:58:42 +0900 Subject: [PATCH 082/115] build.zig: Fix `@src` logic and a few things (#4380) --- src/build.zig | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/src/build.zig b/src/build.zig index 8944c7087..1fdbca8a3 100644 --- a/src/build.zig +++ b/src/build.zig @@ -1,8 +1,14 @@ const std = @import("std"); const builtin = @import("builtin"); +/// Minimum supported version of Zig +const min_ver = "0.12.0"; + comptime { - if (builtin.zig_version.minor < 12) @compileError("Raylib requires zig version 0.12.0"); + const order = std.SemanticVersion.order; + const parse = std.SemanticVersion.parse; + if (order(builtin.zig_version, parse(min_ver) catch unreachable) == .lt) + @compileError("Raylib requires zig version " ++ min_ver); } // NOTE(freakmangd): I don't like using a global here, but it prevents having to @@ -28,6 +34,7 @@ pub fn addRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. .shared = options.shared, .linux_display_backend = options.linux_display_backend, .opengl_version = options.opengl_version, + // TODO: Fix the type mismatch caused here due to unsupported `?[]const u8`. .config = options.config, }); const raylib = raylib_dep.artifact("raylib"); @@ -51,8 +58,19 @@ fn setDesktopPlatform(raylib: *std.Build.Step.Compile, platform: PlatformBackend } } -fn srcDir() []const u8 { - return std.fs.path.dirname(@src().file) orelse "."; +/// TODO: Once the minimum supported version is bumped to 0.14.0, it can be simplified again: +/// https://github.com/raysan5/raylib/pull/4375#issuecomment-2408998315 +/// https://github.com/raysan5/raylib/blob/9b9c72eb0dc705cde194b053a366a40396acfb67/src/build.zig#L54-L56 +fn srcDir(b: *std.Build) []const u8 { + comptime { + const order = std.SemanticVersion.order; + const parse = std.SemanticVersion.parse; + if (order(min_ver, parse("0.14.0") catch unreachable) != .lt) + @compileError("Please take a look at this function again"); + } + + const src_file = std.fs.path.relative(b.allocator, @src().file, ".") catch @panic("OOM"); + return std.fs.path.dirname(src_file) orelse "."; } fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile { @@ -69,7 +87,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. "-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/3674 }); if (options.config) |config| { - const file = b.pathJoin(&.{ srcDir(), "config.h" }); + const file = b.pathJoin(&.{ srcDir(b), "config.h" }); const content = try std.fs.cwd().readFileAlloc(b.allocator, file, std.math.maxInt(usize)); defer b.allocator.free(content); @@ -118,7 +136,8 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. // No GLFW required on PLATFORM_DRM if (options.platform != .drm) { - raylib.addIncludePath(b.path(b.pathJoin(&.{ srcDir(), "external/glfw/include" }))); + _ = std.debug.print("\n\n{s}\n\n", .{@src().file}); + raylib.addIncludePath(b.path(b.pathJoin(&.{ srcDir(b), "external/glfw/include" }))); } var c_source_files = try std.ArrayList([]const u8).initCapacity(b.allocator, 2); @@ -231,7 +250,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. // On macos rglfw.c include Objective-C files. try raylib_flags_arr.append(b.allocator, "-ObjC"); raylib.root_module.addCSourceFile(.{ - .file = b.path(b.pathJoin(&.{ srcDir(), "rglfw.c" })), + .file = b.path(b.pathJoin(&.{ srcDir(b), "rglfw.c" })), .flags = raylib_flags_arr.items, }); _ = raylib_flags_arr.pop(); @@ -265,7 +284,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. } raylib.root_module.addCSourceFiles(.{ - .root = b.path(srcDir()), + .root = b.path(srcDir(b)), .files = c_source_files.items, .flags = raylib_flags_arr.items, }); @@ -366,14 +385,14 @@ pub fn build(b: *std.Build) !void { .shared = b.option(bool, "shared", "Compile as shared library") orelse defaults.shared, .linux_display_backend = b.option(LinuxDisplayBackend, "linux_display_backend", "Linux display backend to use") orelse defaults.linux_display_backend, .opengl_version = b.option(OpenglVersion, "opengl_version", "OpenGL version to use") orelse defaults.opengl_version, - .config = b.option([]const u8, "config", "Compile with custom define macros overriding config.h") orelse null, + .config = b.option([]const u8, "config", "Compile with custom define macros overriding config.h"), }; const lib = try compileRaylib(b, target, optimize, options); - lib.installHeader(b.path(b.pathJoin(&.{ srcDir(), "raylib.h" })), "raylib.h"); - lib.installHeader(b.path(b.pathJoin(&.{ srcDir(), "raymath.h" })), "raymath.h"); - lib.installHeader(b.path(b.pathJoin(&.{ srcDir(), "rlgl.h" })), "rlgl.h"); + lib.installHeader(b.path(b.pathJoin(&.{ srcDir(b), "raylib.h" })), "raylib.h"); + lib.installHeader(b.path(b.pathJoin(&.{ srcDir(b), "raymath.h" })), "raymath.h"); + lib.installHeader(b.path(b.pathJoin(&.{ srcDir(b), "rlgl.h" })), "rlgl.h"); b.installArtifact(lib); } @@ -384,7 +403,7 @@ fn waylandGenerate( comptime protocol: []const u8, comptime basename: []const u8, ) void { - const waylandDir = b.pathJoin(&.{ srcDir(), "external/glfw/deps/wayland" }); + const waylandDir = b.pathJoin(&.{ srcDir(b), "external/glfw/deps/wayland" }); const protocolDir = b.pathJoin(&.{ waylandDir, protocol }); const clientHeader = basename ++ ".h"; const privateCode = basename ++ "-code.h"; From 735308f8eb7433e9850a28846461a996b6905ae1 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 13 Oct 2024 20:02:40 +0200 Subject: [PATCH 083/115] REVIEWED: `CodepointToUTF8()`, clean static buffer #4379 --- src/rtext.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/rtext.c b/src/rtext.c index e4c89d5f1..0595e7fbe 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -1302,15 +1302,15 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing { byteCounter++; - int next = 0; - letter = GetCodepointNext(&text[i], &next); + int codepointByteCount = 0; + letter = GetCodepointNext(&text[i], &codepointByteCount); index = GetGlyphIndex(font, letter); - i += next; + i += codepointByteCount; if (letter != '\n') { - if (font.glyphs[index].advanceX != 0) textWidth += font.glyphs[index].advanceX; + if (font.glyphs[index].advanceX > 0) textWidth += font.glyphs[index].advanceX; else textWidth += (font.recs[index].width + font.glyphs[index].offsetX); } else @@ -1930,7 +1930,8 @@ int GetCodepointCount(const char *text) const char *CodepointToUTF8(int codepoint, int *utf8Size) { static char utf8[6] = { 0 }; - int size = 0; // Byte size of codepoint + memset(utf8, 0, 6); // Clear static array + int size = 0; // Byte size of codepoint if (codepoint <= 0x7f) { From c18677e70ffc978456262696d66c15443c9f4c41 Mon Sep 17 00:00:00 2001 From: Sage Hane Date: Mon, 14 Oct 2024 03:24:39 +0900 Subject: [PATCH 084/115] build.zig: Very minor fixes (#4381) --- src/build.zig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/build.zig b/src/build.zig index 1fdbca8a3..40a506fd5 100644 --- a/src/build.zig +++ b/src/build.zig @@ -65,7 +65,7 @@ fn srcDir(b: *std.Build) []const u8 { comptime { const order = std.SemanticVersion.order; const parse = std.SemanticVersion.parse; - if (order(min_ver, parse("0.14.0") catch unreachable) != .lt) + if (order(parse(min_ver) catch unreachable, parse("0.14.0") catch unreachable) != .lt) @compileError("Please take a look at this function again"); } @@ -136,7 +136,6 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. // No GLFW required on PLATFORM_DRM if (options.platform != .drm) { - _ = std.debug.print("\n\n{s}\n\n", .{@src().file}); raylib.addIncludePath(b.path(b.pathJoin(&.{ srcDir(b), "external/glfw/include" }))); } From 99ff770edce0cf025a77f8bf1923b6a072f8a44e Mon Sep 17 00:00:00 2001 From: yuval_dev <47389924+yuval-herman@users.noreply.github.com> Date: Tue, 15 Oct 2024 20:02:20 +0300 Subject: [PATCH 085/115] Fix the type mismatch caused due to unsupported `?[]const u8` (#4383) Co-authored-by: Yuval Herman --- src/build.zig | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/build.zig b/src/build.zig index 40a506fd5..2a8b88262 100644 --- a/src/build.zig +++ b/src/build.zig @@ -34,7 +34,6 @@ pub fn addRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. .shared = options.shared, .linux_display_backend = options.linux_display_backend, .opengl_version = options.opengl_version, - // TODO: Fix the type mismatch caused here due to unsupported `?[]const u8`. .config = options.config, }); const raylib = raylib_dep.artifact("raylib"); @@ -86,7 +85,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. "-DGL_SILENCE_DEPRECATION=199309L", "-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/3674 }); - if (options.config) |config| { + if (options.config.len > 0) { const file = b.pathJoin(&.{ srcDir(b), "config.h" }); const content = try std.fs.cwd().readFileAlloc(b.allocator, file, std.math.maxInt(usize)); defer b.allocator.free(content); @@ -104,14 +103,14 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. flag = try std.fmt.allocPrint(b.allocator, "-D{s}", .{flag}); // Prepend with -D // If user specifies the flag skip it - if (std.mem.containsAtLeast(u8, config, 1, flag)) continue; + if (std.mem.containsAtLeast(u8, options.config, 1, flag)) continue; // Append default value from config.h to compile flags try raylib_flags_arr.append(b.allocator, flag); } // Append config flags supplied by user to compile flags - try raylib_flags_arr.append(b.allocator, config); + try raylib_flags_arr.append(b.allocator, options.config); try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS"); } @@ -321,7 +320,7 @@ pub const Options = struct { linux_display_backend: LinuxDisplayBackend = .Both, opengl_version: OpenglVersion = .auto, /// config should be a list of cflags, eg, "-DSUPPORT_CUSTOM_FRAME_CONTROL" - config: ?[]const u8 = null, + config: []const u8 = &.{}, raygui_dependency_name: []const u8 = "raygui", }; @@ -384,7 +383,7 @@ pub fn build(b: *std.Build) !void { .shared = b.option(bool, "shared", "Compile as shared library") orelse defaults.shared, .linux_display_backend = b.option(LinuxDisplayBackend, "linux_display_backend", "Linux display backend to use") orelse defaults.linux_display_backend, .opengl_version = b.option(OpenglVersion, "opengl_version", "OpenGL version to use") orelse defaults.opengl_version, - .config = b.option([]const u8, "config", "Compile with custom define macros overriding config.h"), + .config = b.option([]const u8, "config", "Compile with custom define macros overriding config.h") orelse &.{}, }; const lib = try compileRaylib(b, target, optimize, options); From 8d267aaf236fa919b10ea380eac7476d8273936b Mon Sep 17 00:00:00 2001 From: R-YaTian <47445484+R-YaTian@users.noreply.github.com> Date: Wed, 16 Oct 2024 01:03:17 +0800 Subject: [PATCH 086/115] qoi: Added support for image of channels 3 (#4384) --- src/rtextures.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rtextures.c b/src/rtextures.c index 43d16dc7b..84264369d 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -506,10 +506,10 @@ Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, i if (fileData != NULL) { qoi_desc desc = { 0 }; - image.data = qoi_decode(fileData, dataSize, &desc, 4); + image.data = qoi_decode(fileData, dataSize, &desc, (int) fileData[12]); image.width = desc.width; image.height = desc.height; - image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + image.format = desc.channels == 4 ? PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 : PIXELFORMAT_UNCOMPRESSED_R8G8B8; image.mipmaps = 1; } } From c9c830cb971d7aa744fe3c7444b768ccd5176c4c Mon Sep 17 00:00:00 2001 From: Jojaby Date: Wed, 16 Oct 2024 04:04:30 +1100 Subject: [PATCH 087/115] Fix rectangle width and height check to account for squares (#4382) --- src/rshapes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rshapes.c b/src/rshapes.c index 66dfbf3b6..e9b5ca87b 100644 --- a/src/rshapes.c +++ b/src/rshapes.c @@ -828,8 +828,8 @@ void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color) { if ((lineThick > rec.width) || (lineThick > rec.height)) { - if (rec.width > rec.height) lineThick = rec.height/2; - else if (rec.width < rec.height) lineThick = rec.width/2; + if (rec.width >= rec.height) lineThick = rec.height/2; + else if (rec.width <= rec.height) lineThick = rec.width/2; } // When rec = { x, y, 8.0f, 6.0f } and lineThick = 2, the following From 361b0e85c10fb20e69c35d0304d64d891a8964f2 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 16 Oct 2024 16:49:50 +0200 Subject: [PATCH 088/115] ADDED: Utility functions: `ComputeCRC32()` and `ComputeMD5()` --- src/raylib.h | 2 + src/rcore.c | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) diff --git a/src/raylib.h b/src/raylib.h index e0c74af30..0ac4b603c 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1144,6 +1144,8 @@ RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int * RLAPI unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // Decompress data (DEFLATE algorithm), memory must be MemFree() RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize); // Encode data to Base64 string, memory must be MemFree() RLAPI unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize); // Decode Base64 string data, memory must be MemFree() +RLAPI unsigned int ComputeCRC32(unsigned char *data, int dataSize); // Compute CRC32 hash code +RLAPI unsigned int *ComputeMD5(unsigned char *data, int dataSize); // Compute MD5 hash code, returns static int[4] (16 bytes) // Automation events functionality RLAPI AutomationEventList LoadAutomationEventList(const char *fileName); // Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS diff --git a/src/rcore.c b/src/rcore.c index e154d6173..8ba72f715 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -2577,6 +2577,169 @@ unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize) return decodedData; } +// Compute CRC32 hash code +unsigned int ComputeCRC32(unsigned char *data, int dataSize) +{ + static unsigned int crcTable[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + }; + + unsigned int crc = ~0u; + + for (int i = 0; i < dataSize; i++) crc = (crc >> 8) ^ crcTable[data[i] ^ (crc & 0xff)]; + + return ~crc; +} + +// Compute MD5 hash code +// NOTE: Returns a static int[4] array (16 bytes) +unsigned int *ComputeMD5(unsigned char *data, int dataSize) +{ + #define ROTATE_LEFT(x, c) (((x) << (c)) | ((x) >> (32 - (c)))) + + static unsigned int hash[4] = { 0 }; // Hash to be returned + + // WARNING: All variables are unsigned 32 bit and wrap modulo 2^32 when calculating + + // NOTE: r specifies the per-round shift amounts + unsigned int r[] = { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + + // Using binary integer part of the sines of integers (in radians) as constants + unsigned int k[] = { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + + hash[0] = 0x67452301; + hash[1] = 0xefcdab89; + hash[2] = 0x98badcfe; + hash[3] = 0x10325476; + + // Pre-processing: adding a single 1 bit + // Append '1' bit to message + // NOTE: The input bytes are considered as bits strings, + // where the first bit is the most significant bit of the byte + + // Pre-processing: padding with zeros + // Append '0' bit until message length in bit 448 (mod 512) + // Append length mod (2 pow 64) to message + + int newDataSize = ((((dataSize + 8)/64) + 1)*64) - 8; + + unsigned char *msg = RL_CALLOC(newDataSize + 64, 1); // Initialize with '0' bits, allocating 64 extra bytes + memcpy(msg, data, dataSize); + msg[dataSize] = 128; // Write the '1' bit + + unsigned int bitsLen = 8*dataSize; + memcpy(msg + newDataSize, &bitsLen, 4); // Append the len in bits at the end of the buffer + + // Process the message in successive 512-bit chunks for each 512-bit chunk of message + for (int offset = 0; offset < newDataSize; offset += (512/8)) + { + // Break chunk into sixteen 32-bit words w[j], 0 <= j <= 15 + unsigned int *w = (unsigned int *)(msg + offset); + + // Initialize hash value for this chunk + unsigned int a = hash[0]; + unsigned int b = hash[1]; + unsigned int c = hash[2]; + unsigned int d = hash[3]; + + for (int i = 0; i < 64; i++) + { + unsigned int f = 0; + unsigned int g = 0; + + if (i < 16) + { + f = (b & c) | ((~b) & d); + g = i; + } + else if (i < 32) + { + f = (d & b) | ((~d) & c); + g = (5*i + 1)%16; + } + else if (i < 48) + { + f = b ^ c ^ d; + g = (3*i + 5)%16; + } + else + { + f = c ^ (b | (~d)); + g = (7*i)%16; + } + + unsigned int temp = d; + d = c; + c = b; + b = b + ROTATE_LEFT((a + f + k[i] + w[g]), r[i]); + a = temp; + } + + // Add chunk's hash to result so far + hash[0] += a; + hash[1] += b; + hash[2] += c; + hash[3] += d; + } + + RL_FREE(msg); + + return hash; +} + //---------------------------------------------------------------------------------- // Module Functions Definition: Automation Events Recording and Playing //---------------------------------------------------------------------------------- From 9b3d0195022012b3d805cd11125f61d2abbb482b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 16 Oct 2024 14:50:42 +0000 Subject: [PATCH 089/115] Update raylib_api.* by CI --- parser/output/raylib_api.json | 30 ++ parser/output/raylib_api.lua | 18 + parser/output/raylib_api.txt | 872 +++++++++++++++++----------------- parser/output/raylib_api.xml | 10 +- 4 files changed, 499 insertions(+), 431 deletions(-) diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json index 2c8fe31e9..f735853fb 100644 --- a/parser/output/raylib_api.json +++ b/parser/output/raylib_api.json @@ -4691,6 +4691,36 @@ } ] }, + { + "name": "ComputeCRC32", + "description": "Compute CRC32 hash code", + "returnType": "unsigned int", + "params": [ + { + "type": "unsigned char *", + "name": "data" + }, + { + "type": "int", + "name": "dataSize" + } + ] + }, + { + "name": "ComputeMD5", + "description": "Compute MD5 hash code, returns static int[4] (16 bytes)", + "returnType": "unsigned int *", + "params": [ + { + "type": "unsigned char *", + "name": "data" + }, + { + "type": "int", + "name": "dataSize" + } + ] + }, { "name": "LoadAutomationEventList", "description": "Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS", diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua index 6c287b7a4..4c0dd5a03 100644 --- a/parser/output/raylib_api.lua +++ b/parser/output/raylib_api.lua @@ -4190,6 +4190,24 @@ return { {type = "int *", name = "outputSize"} } }, + { + name = "ComputeCRC32", + description = "Compute CRC32 hash code", + returnType = "unsigned int", + params = { + {type = "unsigned char *", name = "data"}, + {type = "int", name = "dataSize"} + } + }, + { + name = "ComputeMD5", + description = "Compute MD5 hash code, returns static int[4] (16 bytes)", + returnType = "unsigned int *", + params = { + {type = "unsigned char *", name = "data"}, + {type = "int", name = "dataSize"} + } + }, { name = "LoadAutomationEventList", description = "Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS", diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt index 9764769a7..865e5ae78 100644 --- a/parser/output/raylib_api.txt +++ b/parser/output/raylib_api.txt @@ -989,7 +989,7 @@ Callback 006: AudioCallback() (2 input parameters) Param[1]: bufferData (type: void *) Param[2]: frames (type: unsigned int) -Functions found: 577 +Functions found: 579 Function 001: InitWindow() (3 input parameters) Name: InitWindow @@ -1788,294 +1788,306 @@ Function 148: DecodeDataBase64() (2 input parameters) Description: Decode Base64 string data, memory must be MemFree() Param[1]: data (type: const unsigned char *) Param[2]: outputSize (type: int *) -Function 149: LoadAutomationEventList() (1 input parameters) +Function 149: ComputeCRC32() (2 input parameters) + Name: ComputeCRC32 + Return type: unsigned int + Description: Compute CRC32 hash code + Param[1]: data (type: unsigned char *) + Param[2]: dataSize (type: int) +Function 150: ComputeMD5() (2 input parameters) + Name: ComputeMD5 + Return type: unsigned int * + Description: Compute MD5 hash code, returns static int[4] (16 bytes) + Param[1]: data (type: unsigned char *) + Param[2]: dataSize (type: int) +Function 151: LoadAutomationEventList() (1 input parameters) Name: LoadAutomationEventList Return type: AutomationEventList Description: Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS Param[1]: fileName (type: const char *) -Function 150: UnloadAutomationEventList() (1 input parameters) +Function 152: UnloadAutomationEventList() (1 input parameters) Name: UnloadAutomationEventList Return type: void Description: Unload automation events list from file Param[1]: list (type: AutomationEventList) -Function 151: ExportAutomationEventList() (2 input parameters) +Function 153: ExportAutomationEventList() (2 input parameters) Name: ExportAutomationEventList Return type: bool Description: Export automation events list as text file Param[1]: list (type: AutomationEventList) Param[2]: fileName (type: const char *) -Function 152: SetAutomationEventList() (1 input parameters) +Function 154: SetAutomationEventList() (1 input parameters) Name: SetAutomationEventList Return type: void Description: Set automation event list to record to Param[1]: list (type: AutomationEventList *) -Function 153: SetAutomationEventBaseFrame() (1 input parameters) +Function 155: SetAutomationEventBaseFrame() (1 input parameters) Name: SetAutomationEventBaseFrame Return type: void Description: Set automation event internal base frame to start recording Param[1]: frame (type: int) -Function 154: StartAutomationEventRecording() (0 input parameters) +Function 156: StartAutomationEventRecording() (0 input parameters) Name: StartAutomationEventRecording Return type: void Description: Start recording automation events (AutomationEventList must be set) No input parameters -Function 155: StopAutomationEventRecording() (0 input parameters) +Function 157: StopAutomationEventRecording() (0 input parameters) Name: StopAutomationEventRecording Return type: void Description: Stop recording automation events No input parameters -Function 156: PlayAutomationEvent() (1 input parameters) +Function 158: PlayAutomationEvent() (1 input parameters) Name: PlayAutomationEvent Return type: void Description: Play a recorded automation event Param[1]: event (type: AutomationEvent) -Function 157: IsKeyPressed() (1 input parameters) +Function 159: IsKeyPressed() (1 input parameters) Name: IsKeyPressed Return type: bool Description: Check if a key has been pressed once Param[1]: key (type: int) -Function 158: IsKeyPressedRepeat() (1 input parameters) +Function 160: IsKeyPressedRepeat() (1 input parameters) Name: IsKeyPressedRepeat Return type: bool Description: Check if a key has been pressed again (Only PLATFORM_DESKTOP) Param[1]: key (type: int) -Function 159: IsKeyDown() (1 input parameters) +Function 161: IsKeyDown() (1 input parameters) Name: IsKeyDown Return type: bool Description: Check if a key is being pressed Param[1]: key (type: int) -Function 160: IsKeyReleased() (1 input parameters) +Function 162: IsKeyReleased() (1 input parameters) Name: IsKeyReleased Return type: bool Description: Check if a key has been released once Param[1]: key (type: int) -Function 161: IsKeyUp() (1 input parameters) +Function 163: IsKeyUp() (1 input parameters) Name: IsKeyUp Return type: bool Description: Check if a key is NOT being pressed Param[1]: key (type: int) -Function 162: GetKeyPressed() (0 input parameters) +Function 164: 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 163: GetCharPressed() (0 input parameters) +Function 165: 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 164: SetExitKey() (1 input parameters) +Function 166: 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 165: IsGamepadAvailable() (1 input parameters) +Function 167: IsGamepadAvailable() (1 input parameters) Name: IsGamepadAvailable Return type: bool Description: Check if a gamepad is available Param[1]: gamepad (type: int) -Function 166: GetGamepadName() (1 input parameters) +Function 168: GetGamepadName() (1 input parameters) Name: GetGamepadName Return type: const char * Description: Get gamepad internal name id Param[1]: gamepad (type: int) -Function 167: IsGamepadButtonPressed() (2 input parameters) +Function 169: 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 168: IsGamepadButtonDown() (2 input parameters) +Function 170: 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 169: IsGamepadButtonReleased() (2 input parameters) +Function 171: 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 170: IsGamepadButtonUp() (2 input parameters) +Function 172: 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 171: GetGamepadButtonPressed() (0 input parameters) +Function 173: GetGamepadButtonPressed() (0 input parameters) Name: GetGamepadButtonPressed Return type: int Description: Get the last gamepad button pressed No input parameters -Function 172: GetGamepadAxisCount() (1 input parameters) +Function 174: GetGamepadAxisCount() (1 input parameters) Name: GetGamepadAxisCount Return type: int Description: Get gamepad axis count for a gamepad Param[1]: gamepad (type: int) -Function 173: GetGamepadAxisMovement() (2 input parameters) +Function 175: 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 174: SetGamepadMappings() (1 input parameters) +Function 176: SetGamepadMappings() (1 input parameters) Name: SetGamepadMappings Return type: int Description: Set internal gamepad mappings (SDL_GameControllerDB) Param[1]: mappings (type: const char *) -Function 175: SetGamepadVibration() (3 input parameters) +Function 177: SetGamepadVibration() (3 input parameters) Name: SetGamepadVibration Return type: void Description: Set gamepad vibration for both motors Param[1]: gamepad (type: int) Param[2]: leftMotor (type: float) Param[3]: rightMotor (type: float) -Function 176: IsMouseButtonPressed() (1 input parameters) +Function 178: 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 177: IsMouseButtonDown() (1 input parameters) +Function 179: IsMouseButtonDown() (1 input parameters) Name: IsMouseButtonDown Return type: bool Description: Check if a mouse button is being pressed Param[1]: button (type: int) -Function 178: IsMouseButtonReleased() (1 input parameters) +Function 180: 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 179: IsMouseButtonUp() (1 input parameters) +Function 181: 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 180: GetMouseX() (0 input parameters) +Function 182: GetMouseX() (0 input parameters) Name: GetMouseX Return type: int Description: Get mouse position X No input parameters -Function 181: GetMouseY() (0 input parameters) +Function 183: GetMouseY() (0 input parameters) Name: GetMouseY Return type: int Description: Get mouse position Y No input parameters -Function 182: GetMousePosition() (0 input parameters) +Function 184: GetMousePosition() (0 input parameters) Name: GetMousePosition Return type: Vector2 Description: Get mouse position XY No input parameters -Function 183: GetMouseDelta() (0 input parameters) +Function 185: GetMouseDelta() (0 input parameters) Name: GetMouseDelta Return type: Vector2 Description: Get mouse delta between frames No input parameters -Function 184: SetMousePosition() (2 input parameters) +Function 186: 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 185: SetMouseOffset() (2 input parameters) +Function 187: SetMouseOffset() (2 input parameters) Name: SetMouseOffset Return type: void Description: Set mouse offset Param[1]: offsetX (type: int) Param[2]: offsetY (type: int) -Function 186: SetMouseScale() (2 input parameters) +Function 188: SetMouseScale() (2 input parameters) Name: SetMouseScale Return type: void Description: Set mouse scaling Param[1]: scaleX (type: float) Param[2]: scaleY (type: float) -Function 187: GetMouseWheelMove() (0 input parameters) +Function 189: 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 188: GetMouseWheelMoveV() (0 input parameters) +Function 190: GetMouseWheelMoveV() (0 input parameters) Name: GetMouseWheelMoveV Return type: Vector2 Description: Get mouse wheel movement for both X and Y No input parameters -Function 189: SetMouseCursor() (1 input parameters) +Function 191: SetMouseCursor() (1 input parameters) Name: SetMouseCursor Return type: void Description: Set mouse cursor Param[1]: cursor (type: int) -Function 190: GetTouchX() (0 input parameters) +Function 192: 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 191: GetTouchY() (0 input parameters) +Function 193: 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 192: GetTouchPosition() (1 input parameters) +Function 194: 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 193: GetTouchPointId() (1 input parameters) +Function 195: GetTouchPointId() (1 input parameters) Name: GetTouchPointId Return type: int Description: Get touch point identifier for given index Param[1]: index (type: int) -Function 194: GetTouchPointCount() (0 input parameters) +Function 196: GetTouchPointCount() (0 input parameters) Name: GetTouchPointCount Return type: int Description: Get number of touch points No input parameters -Function 195: SetGesturesEnabled() (1 input parameters) +Function 197: SetGesturesEnabled() (1 input parameters) Name: SetGesturesEnabled Return type: void Description: Enable a set of gestures using flags Param[1]: flags (type: unsigned int) -Function 196: IsGestureDetected() (1 input parameters) +Function 198: IsGestureDetected() (1 input parameters) Name: IsGestureDetected Return type: bool Description: Check if a gesture have been detected Param[1]: gesture (type: unsigned int) -Function 197: GetGestureDetected() (0 input parameters) +Function 199: GetGestureDetected() (0 input parameters) Name: GetGestureDetected Return type: int Description: Get latest detected gesture No input parameters -Function 198: GetGestureHoldDuration() (0 input parameters) +Function 200: GetGestureHoldDuration() (0 input parameters) Name: GetGestureHoldDuration Return type: float Description: Get gesture hold time in milliseconds No input parameters -Function 199: GetGestureDragVector() (0 input parameters) +Function 201: GetGestureDragVector() (0 input parameters) Name: GetGestureDragVector Return type: Vector2 Description: Get gesture drag vector No input parameters -Function 200: GetGestureDragAngle() (0 input parameters) +Function 202: GetGestureDragAngle() (0 input parameters) Name: GetGestureDragAngle Return type: float Description: Get gesture drag angle No input parameters -Function 201: GetGesturePinchVector() (0 input parameters) +Function 203: GetGesturePinchVector() (0 input parameters) Name: GetGesturePinchVector Return type: Vector2 Description: Get gesture pinch delta No input parameters -Function 202: GetGesturePinchAngle() (0 input parameters) +Function 204: GetGesturePinchAngle() (0 input parameters) Name: GetGesturePinchAngle Return type: float Description: Get gesture pinch angle No input parameters -Function 203: UpdateCamera() (2 input parameters) +Function 205: UpdateCamera() (2 input parameters) Name: UpdateCamera Return type: void Description: Update camera position for selected mode Param[1]: camera (type: Camera *) Param[2]: mode (type: int) -Function 204: UpdateCameraPro() (4 input parameters) +Function 206: UpdateCameraPro() (4 input parameters) Name: UpdateCameraPro Return type: void Description: Update camera movement/rotation @@ -2083,36 +2095,36 @@ Function 204: UpdateCameraPro() (4 input parameters) Param[2]: movement (type: Vector3) Param[3]: rotation (type: Vector3) Param[4]: zoom (type: float) -Function 205: SetShapesTexture() (2 input parameters) +Function 207: 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 206: GetShapesTexture() (0 input parameters) +Function 208: GetShapesTexture() (0 input parameters) Name: GetShapesTexture Return type: Texture2D Description: Get texture that is used for shapes drawing No input parameters -Function 207: GetShapesTextureRectangle() (0 input parameters) +Function 209: GetShapesTextureRectangle() (0 input parameters) Name: GetShapesTextureRectangle Return type: Rectangle Description: Get texture source rectangle that is used for shapes drawing No input parameters -Function 208: DrawPixel() (3 input parameters) +Function 210: DrawPixel() (3 input parameters) Name: DrawPixel Return type: void Description: Draw a pixel using geometry [Can be slow, use with care] Param[1]: posX (type: int) Param[2]: posY (type: int) Param[3]: color (type: Color) -Function 209: DrawPixelV() (2 input parameters) +Function 211: DrawPixelV() (2 input parameters) Name: DrawPixelV Return type: void Description: Draw a pixel using geometry (Vector version) [Can be slow, use with care] Param[1]: position (type: Vector2) Param[2]: color (type: Color) -Function 210: DrawLine() (5 input parameters) +Function 212: DrawLine() (5 input parameters) Name: DrawLine Return type: void Description: Draw a line @@ -2121,14 +2133,14 @@ Function 210: DrawLine() (5 input parameters) Param[3]: endPosX (type: int) Param[4]: endPosY (type: int) Param[5]: color (type: Color) -Function 211: DrawLineV() (3 input parameters) +Function 213: DrawLineV() (3 input parameters) Name: DrawLineV Return type: void Description: Draw a line (using gl lines) Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: color (type: Color) -Function 212: DrawLineEx() (4 input parameters) +Function 214: DrawLineEx() (4 input parameters) Name: DrawLineEx Return type: void Description: Draw a line (using triangles/quads) @@ -2136,14 +2148,14 @@ Function 212: DrawLineEx() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 213: DrawLineStrip() (3 input parameters) +Function 215: DrawLineStrip() (3 input parameters) Name: DrawLineStrip Return type: void Description: Draw lines sequence (using gl lines) Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 214: DrawLineBezier() (4 input parameters) +Function 216: DrawLineBezier() (4 input parameters) Name: DrawLineBezier Return type: void Description: Draw line segment cubic-bezier in-out interpolation @@ -2151,7 +2163,7 @@ Function 214: DrawLineBezier() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 215: DrawCircle() (4 input parameters) +Function 217: DrawCircle() (4 input parameters) Name: DrawCircle Return type: void Description: Draw a color-filled circle @@ -2159,7 +2171,7 @@ Function 215: DrawCircle() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 216: DrawCircleSector() (6 input parameters) +Function 218: DrawCircleSector() (6 input parameters) Name: DrawCircleSector Return type: void Description: Draw a piece of a circle @@ -2169,7 +2181,7 @@ Function 216: DrawCircleSector() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 217: DrawCircleSectorLines() (6 input parameters) +Function 219: DrawCircleSectorLines() (6 input parameters) Name: DrawCircleSectorLines Return type: void Description: Draw circle sector outline @@ -2179,7 +2191,7 @@ Function 217: DrawCircleSectorLines() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 218: DrawCircleGradient() (5 input parameters) +Function 220: DrawCircleGradient() (5 input parameters) Name: DrawCircleGradient Return type: void Description: Draw a gradient-filled circle @@ -2188,14 +2200,14 @@ Function 218: DrawCircleGradient() (5 input parameters) Param[3]: radius (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 219: DrawCircleV() (3 input parameters) +Function 221: 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 220: DrawCircleLines() (4 input parameters) +Function 222: DrawCircleLines() (4 input parameters) Name: DrawCircleLines Return type: void Description: Draw circle outline @@ -2203,14 +2215,14 @@ Function 220: DrawCircleLines() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 221: DrawCircleLinesV() (3 input parameters) +Function 223: DrawCircleLinesV() (3 input parameters) Name: DrawCircleLinesV Return type: void Description: Draw circle outline (Vector version) Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 222: DrawEllipse() (5 input parameters) +Function 224: DrawEllipse() (5 input parameters) Name: DrawEllipse Return type: void Description: Draw ellipse @@ -2219,7 +2231,7 @@ Function 222: DrawEllipse() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 223: DrawEllipseLines() (5 input parameters) +Function 225: DrawEllipseLines() (5 input parameters) Name: DrawEllipseLines Return type: void Description: Draw ellipse outline @@ -2228,7 +2240,7 @@ Function 223: DrawEllipseLines() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 224: DrawRing() (7 input parameters) +Function 226: DrawRing() (7 input parameters) Name: DrawRing Return type: void Description: Draw ring @@ -2239,7 +2251,7 @@ Function 224: DrawRing() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 225: DrawRingLines() (7 input parameters) +Function 227: DrawRingLines() (7 input parameters) Name: DrawRingLines Return type: void Description: Draw ring outline @@ -2250,7 +2262,7 @@ Function 225: DrawRingLines() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 226: DrawRectangle() (5 input parameters) +Function 228: DrawRectangle() (5 input parameters) Name: DrawRectangle Return type: void Description: Draw a color-filled rectangle @@ -2259,20 +2271,20 @@ Function 226: DrawRectangle() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 227: DrawRectangleV() (3 input parameters) +Function 229: 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 228: DrawRectangleRec() (2 input parameters) +Function 230: 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 229: DrawRectanglePro() (4 input parameters) +Function 231: DrawRectanglePro() (4 input parameters) Name: DrawRectanglePro Return type: void Description: Draw a color-filled rectangle with pro parameters @@ -2280,7 +2292,7 @@ Function 229: DrawRectanglePro() (4 input parameters) Param[2]: origin (type: Vector2) Param[3]: rotation (type: float) Param[4]: color (type: Color) -Function 230: DrawRectangleGradientV() (6 input parameters) +Function 232: DrawRectangleGradientV() (6 input parameters) Name: DrawRectangleGradientV Return type: void Description: Draw a vertical-gradient-filled rectangle @@ -2290,7 +2302,7 @@ Function 230: DrawRectangleGradientV() (6 input parameters) Param[4]: height (type: int) Param[5]: top (type: Color) Param[6]: bottom (type: Color) -Function 231: DrawRectangleGradientH() (6 input parameters) +Function 233: DrawRectangleGradientH() (6 input parameters) Name: DrawRectangleGradientH Return type: void Description: Draw a horizontal-gradient-filled rectangle @@ -2300,7 +2312,7 @@ Function 231: DrawRectangleGradientH() (6 input parameters) Param[4]: height (type: int) Param[5]: left (type: Color) Param[6]: right (type: Color) -Function 232: DrawRectangleGradientEx() (5 input parameters) +Function 234: DrawRectangleGradientEx() (5 input parameters) Name: DrawRectangleGradientEx Return type: void Description: Draw a gradient-filled rectangle with custom vertex colors @@ -2309,7 +2321,7 @@ Function 232: DrawRectangleGradientEx() (5 input parameters) Param[3]: bottomLeft (type: Color) Param[4]: topRight (type: Color) Param[5]: bottomRight (type: Color) -Function 233: DrawRectangleLines() (5 input parameters) +Function 235: DrawRectangleLines() (5 input parameters) Name: DrawRectangleLines Return type: void Description: Draw rectangle outline @@ -2318,14 +2330,14 @@ Function 233: DrawRectangleLines() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 234: DrawRectangleLinesEx() (3 input parameters) +Function 236: 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 235: DrawRectangleRounded() (4 input parameters) +Function 237: DrawRectangleRounded() (4 input parameters) Name: DrawRectangleRounded Return type: void Description: Draw rectangle with rounded edges @@ -2333,7 +2345,7 @@ Function 235: DrawRectangleRounded() (4 input parameters) Param[2]: roundness (type: float) Param[3]: segments (type: int) Param[4]: color (type: Color) -Function 236: DrawRectangleRoundedLines() (4 input parameters) +Function 238: DrawRectangleRoundedLines() (4 input parameters) Name: DrawRectangleRoundedLines Return type: void Description: Draw rectangle lines with rounded edges @@ -2341,7 +2353,7 @@ Function 236: DrawRectangleRoundedLines() (4 input parameters) Param[2]: roundness (type: float) Param[3]: segments (type: int) Param[4]: color (type: Color) -Function 237: DrawRectangleRoundedLinesEx() (5 input parameters) +Function 239: DrawRectangleRoundedLinesEx() (5 input parameters) Name: DrawRectangleRoundedLinesEx Return type: void Description: Draw rectangle with rounded edges outline @@ -2350,7 +2362,7 @@ Function 237: DrawRectangleRoundedLinesEx() (5 input parameters) Param[3]: segments (type: int) Param[4]: lineThick (type: float) Param[5]: color (type: Color) -Function 238: DrawTriangle() (4 input parameters) +Function 240: DrawTriangle() (4 input parameters) Name: DrawTriangle Return type: void Description: Draw a color-filled triangle (vertex in counter-clockwise order!) @@ -2358,7 +2370,7 @@ Function 238: DrawTriangle() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 239: DrawTriangleLines() (4 input parameters) +Function 241: DrawTriangleLines() (4 input parameters) Name: DrawTriangleLines Return type: void Description: Draw triangle outline (vertex in counter-clockwise order!) @@ -2366,21 +2378,21 @@ Function 239: DrawTriangleLines() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 240: DrawTriangleFan() (3 input parameters) +Function 242: DrawTriangleFan() (3 input parameters) Name: DrawTriangleFan Return type: void Description: Draw a triangle fan defined by points (first vertex is the center) Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 241: DrawTriangleStrip() (3 input parameters) +Function 243: DrawTriangleStrip() (3 input parameters) Name: DrawTriangleStrip Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 242: DrawPoly() (5 input parameters) +Function 244: DrawPoly() (5 input parameters) Name: DrawPoly Return type: void Description: Draw a regular polygon (Vector version) @@ -2389,7 +2401,7 @@ Function 242: DrawPoly() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 243: DrawPolyLines() (5 input parameters) +Function 245: DrawPolyLines() (5 input parameters) Name: DrawPolyLines Return type: void Description: Draw a polygon outline of n sides @@ -2398,7 +2410,7 @@ Function 243: DrawPolyLines() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 244: DrawPolyLinesEx() (6 input parameters) +Function 246: DrawPolyLinesEx() (6 input parameters) Name: DrawPolyLinesEx Return type: void Description: Draw a polygon outline of n sides with extended parameters @@ -2408,7 +2420,7 @@ Function 244: DrawPolyLinesEx() (6 input parameters) Param[4]: rotation (type: float) Param[5]: lineThick (type: float) Param[6]: color (type: Color) -Function 245: DrawSplineLinear() (4 input parameters) +Function 247: DrawSplineLinear() (4 input parameters) Name: DrawSplineLinear Return type: void Description: Draw spline: Linear, minimum 2 points @@ -2416,7 +2428,7 @@ Function 245: DrawSplineLinear() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 246: DrawSplineBasis() (4 input parameters) +Function 248: DrawSplineBasis() (4 input parameters) Name: DrawSplineBasis Return type: void Description: Draw spline: B-Spline, minimum 4 points @@ -2424,7 +2436,7 @@ Function 246: DrawSplineBasis() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 247: DrawSplineCatmullRom() (4 input parameters) +Function 249: DrawSplineCatmullRom() (4 input parameters) Name: DrawSplineCatmullRom Return type: void Description: Draw spline: Catmull-Rom, minimum 4 points @@ -2432,7 +2444,7 @@ Function 247: DrawSplineCatmullRom() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 248: DrawSplineBezierQuadratic() (4 input parameters) +Function 250: DrawSplineBezierQuadratic() (4 input parameters) Name: DrawSplineBezierQuadratic Return type: void Description: Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...] @@ -2440,7 +2452,7 @@ Function 248: DrawSplineBezierQuadratic() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 249: DrawSplineBezierCubic() (4 input parameters) +Function 251: DrawSplineBezierCubic() (4 input parameters) Name: DrawSplineBezierCubic Return type: void Description: Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...] @@ -2448,7 +2460,7 @@ Function 249: DrawSplineBezierCubic() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 250: DrawSplineSegmentLinear() (4 input parameters) +Function 252: DrawSplineSegmentLinear() (4 input parameters) Name: DrawSplineSegmentLinear Return type: void Description: Draw spline segment: Linear, 2 points @@ -2456,7 +2468,7 @@ Function 250: DrawSplineSegmentLinear() (4 input parameters) Param[2]: p2 (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 251: DrawSplineSegmentBasis() (6 input parameters) +Function 253: DrawSplineSegmentBasis() (6 input parameters) Name: DrawSplineSegmentBasis Return type: void Description: Draw spline segment: B-Spline, 4 points @@ -2466,7 +2478,7 @@ Function 251: DrawSplineSegmentBasis() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 252: DrawSplineSegmentCatmullRom() (6 input parameters) +Function 254: DrawSplineSegmentCatmullRom() (6 input parameters) Name: DrawSplineSegmentCatmullRom Return type: void Description: Draw spline segment: Catmull-Rom, 4 points @@ -2476,7 +2488,7 @@ Function 252: DrawSplineSegmentCatmullRom() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 253: DrawSplineSegmentBezierQuadratic() (5 input parameters) +Function 255: DrawSplineSegmentBezierQuadratic() (5 input parameters) Name: DrawSplineSegmentBezierQuadratic Return type: void Description: Draw spline segment: Quadratic Bezier, 2 points, 1 control point @@ -2485,7 +2497,7 @@ Function 253: DrawSplineSegmentBezierQuadratic() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: thick (type: float) Param[5]: color (type: Color) -Function 254: DrawSplineSegmentBezierCubic() (6 input parameters) +Function 256: DrawSplineSegmentBezierCubic() (6 input parameters) Name: DrawSplineSegmentBezierCubic Return type: void Description: Draw spline segment: Cubic Bezier, 2 points, 2 control points @@ -2495,14 +2507,14 @@ Function 254: DrawSplineSegmentBezierCubic() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 255: GetSplinePointLinear() (3 input parameters) +Function 257: GetSplinePointLinear() (3 input parameters) Name: GetSplinePointLinear Return type: Vector2 Description: Get (evaluate) spline point: Linear Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: t (type: float) -Function 256: GetSplinePointBasis() (5 input parameters) +Function 258: GetSplinePointBasis() (5 input parameters) Name: GetSplinePointBasis Return type: Vector2 Description: Get (evaluate) spline point: B-Spline @@ -2511,7 +2523,7 @@ Function 256: GetSplinePointBasis() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 257: GetSplinePointCatmullRom() (5 input parameters) +Function 259: GetSplinePointCatmullRom() (5 input parameters) Name: GetSplinePointCatmullRom Return type: Vector2 Description: Get (evaluate) spline point: Catmull-Rom @@ -2520,7 +2532,7 @@ Function 257: GetSplinePointCatmullRom() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 258: GetSplinePointBezierQuad() (4 input parameters) +Function 260: GetSplinePointBezierQuad() (4 input parameters) Name: GetSplinePointBezierQuad Return type: Vector2 Description: Get (evaluate) spline point: Quadratic Bezier @@ -2528,7 +2540,7 @@ Function 258: GetSplinePointBezierQuad() (4 input parameters) Param[2]: c2 (type: Vector2) Param[3]: p3 (type: Vector2) Param[4]: t (type: float) -Function 259: GetSplinePointBezierCubic() (5 input parameters) +Function 261: GetSplinePointBezierCubic() (5 input parameters) Name: GetSplinePointBezierCubic Return type: Vector2 Description: Get (evaluate) spline point: Cubic Bezier @@ -2537,13 +2549,13 @@ Function 259: GetSplinePointBezierCubic() (5 input parameters) Param[3]: c3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 260: CheckCollisionRecs() (2 input parameters) +Function 262: 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 261: CheckCollisionCircles() (4 input parameters) +Function 263: CheckCollisionCircles() (4 input parameters) Name: CheckCollisionCircles Return type: bool Description: Check collision between two circles @@ -2551,27 +2563,27 @@ Function 261: CheckCollisionCircles() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector2) Param[4]: radius2 (type: float) -Function 262: CheckCollisionCircleRec() (3 input parameters) +Function 264: 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 263: CheckCollisionPointRec() (2 input parameters) +Function 265: 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 264: CheckCollisionPointCircle() (3 input parameters) +Function 266: 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 265: CheckCollisionPointTriangle() (4 input parameters) +Function 267: CheckCollisionPointTriangle() (4 input parameters) Name: CheckCollisionPointTriangle Return type: bool Description: Check if point is inside a triangle @@ -2579,14 +2591,14 @@ Function 265: CheckCollisionPointTriangle() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: p3 (type: Vector2) -Function 266: CheckCollisionPointPoly() (3 input parameters) +Function 268: CheckCollisionPointPoly() (3 input parameters) Name: CheckCollisionPointPoly Return type: bool Description: Check if point is within a polygon described by array of vertices Param[1]: point (type: Vector2) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) -Function 267: CheckCollisionLines() (5 input parameters) +Function 269: 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 @@ -2595,7 +2607,7 @@ Function 267: CheckCollisionLines() (5 input parameters) Param[3]: startPos2 (type: Vector2) Param[4]: endPos2 (type: Vector2) Param[5]: collisionPoint (type: Vector2 *) -Function 268: CheckCollisionPointLine() (4 input parameters) +Function 270: 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] @@ -2603,7 +2615,7 @@ Function 268: CheckCollisionPointLine() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: threshold (type: int) -Function 269: CheckCollisionCircleLine() (4 input parameters) +Function 271: CheckCollisionCircleLine() (4 input parameters) Name: CheckCollisionCircleLine Return type: bool Description: Check if circle collides with a line created betweeen two points [p1] and [p2] @@ -2611,18 +2623,18 @@ Function 269: CheckCollisionCircleLine() (4 input parameters) Param[2]: radius (type: float) Param[3]: p1 (type: Vector2) Param[4]: p2 (type: Vector2) -Function 270: GetCollisionRec() (2 input parameters) +Function 272: 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 271: LoadImage() (1 input parameters) +Function 273: 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 272: LoadImageRaw() (5 input parameters) +Function 274: LoadImageRaw() (5 input parameters) Name: LoadImageRaw Return type: Image Description: Load image from RAW file data @@ -2631,13 +2643,13 @@ Function 272: LoadImageRaw() (5 input parameters) Param[3]: height (type: int) Param[4]: format (type: int) Param[5]: headerSize (type: int) -Function 273: LoadImageAnim() (2 input parameters) +Function 275: 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 274: LoadImageAnimFromMemory() (4 input parameters) +Function 276: LoadImageAnimFromMemory() (4 input parameters) Name: LoadImageAnimFromMemory Return type: Image Description: Load image sequence from memory buffer @@ -2645,60 +2657,60 @@ Function 274: LoadImageAnimFromMemory() (4 input parameters) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) Param[4]: frames (type: int *) -Function 275: LoadImageFromMemory() (3 input parameters) +Function 277: 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 276: LoadImageFromTexture() (1 input parameters) +Function 278: LoadImageFromTexture() (1 input parameters) Name: LoadImageFromTexture Return type: Image Description: Load image from GPU texture data Param[1]: texture (type: Texture2D) -Function 277: LoadImageFromScreen() (0 input parameters) +Function 279: LoadImageFromScreen() (0 input parameters) Name: LoadImageFromScreen Return type: Image Description: Load image from screen buffer and (screenshot) No input parameters -Function 278: IsImageReady() (1 input parameters) +Function 280: IsImageReady() (1 input parameters) Name: IsImageReady Return type: bool Description: Check if an image is ready Param[1]: image (type: Image) -Function 279: UnloadImage() (1 input parameters) +Function 281: UnloadImage() (1 input parameters) Name: UnloadImage Return type: void Description: Unload image from CPU memory (RAM) Param[1]: image (type: Image) -Function 280: ExportImage() (2 input parameters) +Function 282: 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 281: ExportImageToMemory() (3 input parameters) +Function 283: ExportImageToMemory() (3 input parameters) Name: ExportImageToMemory Return type: unsigned char * Description: Export image to memory buffer Param[1]: image (type: Image) Param[2]: fileType (type: const char *) Param[3]: fileSize (type: int *) -Function 282: ExportImageAsCode() (2 input parameters) +Function 284: 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 283: GenImageColor() (3 input parameters) +Function 285: 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 284: GenImageGradientLinear() (5 input parameters) +Function 286: GenImageGradientLinear() (5 input parameters) Name: GenImageGradientLinear Return type: Image Description: Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient @@ -2707,7 +2719,7 @@ Function 284: GenImageGradientLinear() (5 input parameters) Param[3]: direction (type: int) Param[4]: start (type: Color) Param[5]: end (type: Color) -Function 285: GenImageGradientRadial() (5 input parameters) +Function 287: GenImageGradientRadial() (5 input parameters) Name: GenImageGradientRadial Return type: Image Description: Generate image: radial gradient @@ -2716,7 +2728,7 @@ Function 285: GenImageGradientRadial() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 286: GenImageGradientSquare() (5 input parameters) +Function 288: GenImageGradientSquare() (5 input parameters) Name: GenImageGradientSquare Return type: Image Description: Generate image: square gradient @@ -2725,7 +2737,7 @@ Function 286: GenImageGradientSquare() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 287: GenImageChecked() (6 input parameters) +Function 289: GenImageChecked() (6 input parameters) Name: GenImageChecked Return type: Image Description: Generate image: checked @@ -2735,14 +2747,14 @@ Function 287: GenImageChecked() (6 input parameters) Param[4]: checksY (type: int) Param[5]: col1 (type: Color) Param[6]: col2 (type: Color) -Function 288: GenImageWhiteNoise() (3 input parameters) +Function 290: 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 289: GenImagePerlinNoise() (5 input parameters) +Function 291: GenImagePerlinNoise() (5 input parameters) Name: GenImagePerlinNoise Return type: Image Description: Generate image: perlin noise @@ -2751,45 +2763,45 @@ Function 289: GenImagePerlinNoise() (5 input parameters) Param[3]: offsetX (type: int) Param[4]: offsetY (type: int) Param[5]: scale (type: float) -Function 290: GenImageCellular() (3 input parameters) +Function 292: 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 291: GenImageText() (3 input parameters) +Function 293: 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 292: ImageCopy() (1 input parameters) +Function 294: ImageCopy() (1 input parameters) Name: ImageCopy Return type: Image Description: Create an image duplicate (useful for transformations) Param[1]: image (type: Image) -Function 293: ImageFromImage() (2 input parameters) +Function 295: ImageFromImage() (2 input parameters) Name: ImageFromImage Return type: Image Description: Create an image from another image piece Param[1]: image (type: Image) Param[2]: rec (type: Rectangle) -Function 294: ImageFromChannel() (2 input parameters) +Function 296: ImageFromChannel() (2 input parameters) Name: ImageFromChannel Return type: Image Description: Create an image from a selected channel of another image (GRAYSCALE) Param[1]: image (type: Image) Param[2]: selectedChannel (type: int) -Function 295: ImageText() (3 input parameters) +Function 297: ImageText() (3 input parameters) Name: ImageText Return type: Image Description: Create an image from text (default font) Param[1]: text (type: const char *) Param[2]: fontSize (type: int) Param[3]: color (type: Color) -Function 296: ImageTextEx() (5 input parameters) +Function 298: ImageTextEx() (5 input parameters) Name: ImageTextEx Return type: Image Description: Create an image from text (custom sprite font) @@ -2798,76 +2810,76 @@ Function 296: ImageTextEx() (5 input parameters) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) Param[5]: tint (type: Color) -Function 297: ImageFormat() (2 input parameters) +Function 299: ImageFormat() (2 input parameters) Name: ImageFormat Return type: void Description: Convert image data to desired format Param[1]: image (type: Image *) Param[2]: newFormat (type: int) -Function 298: ImageToPOT() (2 input parameters) +Function 300: ImageToPOT() (2 input parameters) Name: ImageToPOT Return type: void Description: Convert image to POT (power-of-two) Param[1]: image (type: Image *) Param[2]: fill (type: Color) -Function 299: ImageCrop() (2 input parameters) +Function 301: ImageCrop() (2 input parameters) Name: ImageCrop Return type: void Description: Crop an image to a defined rectangle Param[1]: image (type: Image *) Param[2]: crop (type: Rectangle) -Function 300: ImageAlphaCrop() (2 input parameters) +Function 302: ImageAlphaCrop() (2 input parameters) Name: ImageAlphaCrop Return type: void Description: Crop image depending on alpha value Param[1]: image (type: Image *) Param[2]: threshold (type: float) -Function 301: ImageAlphaClear() (3 input parameters) +Function 303: ImageAlphaClear() (3 input parameters) Name: ImageAlphaClear Return type: void Description: Clear alpha channel to desired color Param[1]: image (type: Image *) Param[2]: color (type: Color) Param[3]: threshold (type: float) -Function 302: ImageAlphaMask() (2 input parameters) +Function 304: ImageAlphaMask() (2 input parameters) Name: ImageAlphaMask Return type: void Description: Apply alpha mask to image Param[1]: image (type: Image *) Param[2]: alphaMask (type: Image) -Function 303: ImageAlphaPremultiply() (1 input parameters) +Function 305: ImageAlphaPremultiply() (1 input parameters) Name: ImageAlphaPremultiply Return type: void Description: Premultiply alpha channel Param[1]: image (type: Image *) -Function 304: ImageBlurGaussian() (2 input parameters) +Function 306: 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 305: ImageKernelConvolution() (3 input parameters) +Function 307: ImageKernelConvolution() (3 input parameters) Name: ImageKernelConvolution Return type: void Description: Apply custom square convolution kernel to image Param[1]: image (type: Image *) Param[2]: kernel (type: const float *) Param[3]: kernelSize (type: int) -Function 306: ImageResize() (3 input parameters) +Function 308: 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 307: ImageResizeNN() (3 input parameters) +Function 309: 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 308: ImageResizeCanvas() (6 input parameters) +Function 310: ImageResizeCanvas() (6 input parameters) Name: ImageResizeCanvas Return type: void Description: Resize canvas and fill with color @@ -2877,12 +2889,12 @@ Function 308: ImageResizeCanvas() (6 input parameters) Param[4]: offsetX (type: int) Param[5]: offsetY (type: int) Param[6]: fill (type: Color) -Function 309: ImageMipmaps() (1 input parameters) +Function 311: ImageMipmaps() (1 input parameters) Name: ImageMipmaps Return type: void Description: Compute all mipmap levels for a provided image Param[1]: image (type: Image *) -Function 310: ImageDither() (5 input parameters) +Function 312: ImageDither() (5 input parameters) Name: ImageDither Return type: void Description: Dither image data to 16bpp or lower (Floyd-Steinberg dithering) @@ -2891,109 +2903,109 @@ Function 310: ImageDither() (5 input parameters) Param[3]: gBpp (type: int) Param[4]: bBpp (type: int) Param[5]: aBpp (type: int) -Function 311: ImageFlipVertical() (1 input parameters) +Function 313: ImageFlipVertical() (1 input parameters) Name: ImageFlipVertical Return type: void Description: Flip image vertically Param[1]: image (type: Image *) -Function 312: ImageFlipHorizontal() (1 input parameters) +Function 314: ImageFlipHorizontal() (1 input parameters) Name: ImageFlipHorizontal Return type: void Description: Flip image horizontally Param[1]: image (type: Image *) -Function 313: ImageRotate() (2 input parameters) +Function 315: ImageRotate() (2 input parameters) Name: ImageRotate Return type: void Description: Rotate image by input angle in degrees (-359 to 359) Param[1]: image (type: Image *) Param[2]: degrees (type: int) -Function 314: ImageRotateCW() (1 input parameters) +Function 316: ImageRotateCW() (1 input parameters) Name: ImageRotateCW Return type: void Description: Rotate image clockwise 90deg Param[1]: image (type: Image *) -Function 315: ImageRotateCCW() (1 input parameters) +Function 317: ImageRotateCCW() (1 input parameters) Name: ImageRotateCCW Return type: void Description: Rotate image counter-clockwise 90deg Param[1]: image (type: Image *) -Function 316: ImageColorTint() (2 input parameters) +Function 318: 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 317: ImageColorInvert() (1 input parameters) +Function 319: ImageColorInvert() (1 input parameters) Name: ImageColorInvert Return type: void Description: Modify image color: invert Param[1]: image (type: Image *) -Function 318: ImageColorGrayscale() (1 input parameters) +Function 320: ImageColorGrayscale() (1 input parameters) Name: ImageColorGrayscale Return type: void Description: Modify image color: grayscale Param[1]: image (type: Image *) -Function 319: ImageColorContrast() (2 input parameters) +Function 321: 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 320: ImageColorBrightness() (2 input parameters) +Function 322: 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 321: ImageColorReplace() (3 input parameters) +Function 323: 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 322: LoadImageColors() (1 input parameters) +Function 324: 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 323: LoadImagePalette() (3 input parameters) +Function 325: 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 324: UnloadImageColors() (1 input parameters) +Function 326: UnloadImageColors() (1 input parameters) Name: UnloadImageColors Return type: void Description: Unload color data loaded with LoadImageColors() Param[1]: colors (type: Color *) -Function 325: UnloadImagePalette() (1 input parameters) +Function 327: UnloadImagePalette() (1 input parameters) Name: UnloadImagePalette Return type: void Description: Unload colors palette loaded with LoadImagePalette() Param[1]: colors (type: Color *) -Function 326: GetImageAlphaBorder() (2 input parameters) +Function 328: 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 327: GetImageColor() (3 input parameters) +Function 329: 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 328: ImageClearBackground() (2 input parameters) +Function 330: 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 329: ImageDrawPixel() (4 input parameters) +Function 331: ImageDrawPixel() (4 input parameters) Name: ImageDrawPixel Return type: void Description: Draw pixel within an image @@ -3001,14 +3013,14 @@ Function 329: ImageDrawPixel() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: color (type: Color) -Function 330: ImageDrawPixelV() (3 input parameters) +Function 332: 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 331: ImageDrawLine() (6 input parameters) +Function 333: ImageDrawLine() (6 input parameters) Name: ImageDrawLine Return type: void Description: Draw line within an image @@ -3018,7 +3030,7 @@ Function 331: ImageDrawLine() (6 input parameters) Param[4]: endPosX (type: int) Param[5]: endPosY (type: int) Param[6]: color (type: Color) -Function 332: ImageDrawLineV() (4 input parameters) +Function 334: ImageDrawLineV() (4 input parameters) Name: ImageDrawLineV Return type: void Description: Draw line within an image (Vector version) @@ -3026,7 +3038,7 @@ Function 332: ImageDrawLineV() (4 input parameters) Param[2]: start (type: Vector2) Param[3]: end (type: Vector2) Param[4]: color (type: Color) -Function 333: ImageDrawLineEx() (5 input parameters) +Function 335: ImageDrawLineEx() (5 input parameters) Name: ImageDrawLineEx Return type: void Description: Draw a line defining thickness within an image @@ -3035,7 +3047,7 @@ Function 333: ImageDrawLineEx() (5 input parameters) Param[3]: end (type: Vector2) Param[4]: thick (type: int) Param[5]: color (type: Color) -Function 334: ImageDrawCircle() (5 input parameters) +Function 336: ImageDrawCircle() (5 input parameters) Name: ImageDrawCircle Return type: void Description: Draw a filled circle within an image @@ -3044,7 +3056,7 @@ Function 334: ImageDrawCircle() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 335: ImageDrawCircleV() (4 input parameters) +Function 337: ImageDrawCircleV() (4 input parameters) Name: ImageDrawCircleV Return type: void Description: Draw a filled circle within an image (Vector version) @@ -3052,7 +3064,7 @@ Function 335: ImageDrawCircleV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 336: ImageDrawCircleLines() (5 input parameters) +Function 338: ImageDrawCircleLines() (5 input parameters) Name: ImageDrawCircleLines Return type: void Description: Draw circle outline within an image @@ -3061,7 +3073,7 @@ Function 336: ImageDrawCircleLines() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 337: ImageDrawCircleLinesV() (4 input parameters) +Function 339: ImageDrawCircleLinesV() (4 input parameters) Name: ImageDrawCircleLinesV Return type: void Description: Draw circle outline within an image (Vector version) @@ -3069,7 +3081,7 @@ Function 337: ImageDrawCircleLinesV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 338: ImageDrawRectangle() (6 input parameters) +Function 340: ImageDrawRectangle() (6 input parameters) Name: ImageDrawRectangle Return type: void Description: Draw rectangle within an image @@ -3079,7 +3091,7 @@ Function 338: ImageDrawRectangle() (6 input parameters) Param[4]: width (type: int) Param[5]: height (type: int) Param[6]: color (type: Color) -Function 339: ImageDrawRectangleV() (4 input parameters) +Function 341: ImageDrawRectangleV() (4 input parameters) Name: ImageDrawRectangleV Return type: void Description: Draw rectangle within an image (Vector version) @@ -3087,14 +3099,14 @@ Function 339: ImageDrawRectangleV() (4 input parameters) Param[2]: position (type: Vector2) Param[3]: size (type: Vector2) Param[4]: color (type: Color) -Function 340: ImageDrawRectangleRec() (3 input parameters) +Function 342: 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 341: ImageDrawRectangleLines() (4 input parameters) +Function 343: ImageDrawRectangleLines() (4 input parameters) Name: ImageDrawRectangleLines Return type: void Description: Draw rectangle lines within an image @@ -3102,7 +3114,7 @@ Function 341: ImageDrawRectangleLines() (4 input parameters) Param[2]: rec (type: Rectangle) Param[3]: thick (type: int) Param[4]: color (type: Color) -Function 342: ImageDrawTriangle() (5 input parameters) +Function 344: ImageDrawTriangle() (5 input parameters) Name: ImageDrawTriangle Return type: void Description: Draw triangle within an image @@ -3111,7 +3123,7 @@ Function 342: ImageDrawTriangle() (5 input parameters) Param[3]: v2 (type: Vector2) Param[4]: v3 (type: Vector2) Param[5]: color (type: Color) -Function 343: ImageDrawTriangleEx() (7 input parameters) +Function 345: ImageDrawTriangleEx() (7 input parameters) Name: ImageDrawTriangleEx Return type: void Description: Draw triangle with interpolated colors within an image @@ -3122,7 +3134,7 @@ Function 343: ImageDrawTriangleEx() (7 input parameters) Param[5]: c1 (type: Color) Param[6]: c2 (type: Color) Param[7]: c3 (type: Color) -Function 344: ImageDrawTriangleLines() (5 input parameters) +Function 346: ImageDrawTriangleLines() (5 input parameters) Name: ImageDrawTriangleLines Return type: void Description: Draw triangle outline within an image @@ -3131,7 +3143,7 @@ Function 344: ImageDrawTriangleLines() (5 input parameters) Param[3]: v2 (type: Vector2) Param[4]: v3 (type: Vector2) Param[5]: color (type: Color) -Function 345: ImageDrawTriangleFan() (4 input parameters) +Function 347: ImageDrawTriangleFan() (4 input parameters) Name: ImageDrawTriangleFan Return type: void Description: Draw a triangle fan defined by points within an image (first vertex is the center) @@ -3139,7 +3151,7 @@ Function 345: ImageDrawTriangleFan() (4 input parameters) Param[2]: points (type: Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 346: ImageDrawTriangleStrip() (4 input parameters) +Function 348: ImageDrawTriangleStrip() (4 input parameters) Name: ImageDrawTriangleStrip Return type: void Description: Draw a triangle strip defined by points within an image @@ -3147,7 +3159,7 @@ Function 346: ImageDrawTriangleStrip() (4 input parameters) Param[2]: points (type: Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 347: ImageDraw() (5 input parameters) +Function 349: ImageDraw() (5 input parameters) Name: ImageDraw Return type: void Description: Draw a source image within a destination image (tint applied to source) @@ -3156,7 +3168,7 @@ Function 347: ImageDraw() (5 input parameters) Param[3]: srcRec (type: Rectangle) Param[4]: dstRec (type: Rectangle) Param[5]: tint (type: Color) -Function 348: ImageDrawText() (6 input parameters) +Function 350: ImageDrawText() (6 input parameters) Name: ImageDrawText Return type: void Description: Draw text (using default font) within an image (destination) @@ -3166,7 +3178,7 @@ Function 348: ImageDrawText() (6 input parameters) Param[4]: posY (type: int) Param[5]: fontSize (type: int) Param[6]: color (type: Color) -Function 349: ImageDrawTextEx() (7 input parameters) +Function 351: ImageDrawTextEx() (7 input parameters) Name: ImageDrawTextEx Return type: void Description: Draw text (custom sprite font) within an image (destination) @@ -3177,79 +3189,79 @@ Function 349: ImageDrawTextEx() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 350: LoadTexture() (1 input parameters) +Function 352: 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 351: LoadTextureFromImage() (1 input parameters) +Function 353: LoadTextureFromImage() (1 input parameters) Name: LoadTextureFromImage Return type: Texture2D Description: Load texture from image data Param[1]: image (type: Image) -Function 352: LoadTextureCubemap() (2 input parameters) +Function 354: 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 353: LoadRenderTexture() (2 input parameters) +Function 355: 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 354: IsTextureReady() (1 input parameters) +Function 356: IsTextureReady() (1 input parameters) Name: IsTextureReady Return type: bool Description: Check if a texture is ready Param[1]: texture (type: Texture2D) -Function 355: UnloadTexture() (1 input parameters) +Function 357: UnloadTexture() (1 input parameters) Name: UnloadTexture Return type: void Description: Unload texture from GPU memory (VRAM) Param[1]: texture (type: Texture2D) -Function 356: IsRenderTextureReady() (1 input parameters) +Function 358: IsRenderTextureReady() (1 input parameters) Name: IsRenderTextureReady Return type: bool Description: Check if a render texture is ready Param[1]: target (type: RenderTexture2D) -Function 357: UnloadRenderTexture() (1 input parameters) +Function 359: UnloadRenderTexture() (1 input parameters) Name: UnloadRenderTexture Return type: void Description: Unload render texture from GPU memory (VRAM) Param[1]: target (type: RenderTexture2D) -Function 358: UpdateTexture() (2 input parameters) +Function 360: 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 359: UpdateTextureRec() (3 input parameters) +Function 361: 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 360: GenTextureMipmaps() (1 input parameters) +Function 362: GenTextureMipmaps() (1 input parameters) Name: GenTextureMipmaps Return type: void Description: Generate GPU mipmaps for a texture Param[1]: texture (type: Texture2D *) -Function 361: SetTextureFilter() (2 input parameters) +Function 363: 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 362: SetTextureWrap() (2 input parameters) +Function 364: 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 363: DrawTexture() (4 input parameters) +Function 365: DrawTexture() (4 input parameters) Name: DrawTexture Return type: void Description: Draw a Texture2D @@ -3257,14 +3269,14 @@ Function 363: DrawTexture() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: tint (type: Color) -Function 364: DrawTextureV() (3 input parameters) +Function 366: 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 365: DrawTextureEx() (5 input parameters) +Function 367: DrawTextureEx() (5 input parameters) Name: DrawTextureEx Return type: void Description: Draw a Texture2D with extended parameters @@ -3273,7 +3285,7 @@ Function 365: DrawTextureEx() (5 input parameters) Param[3]: rotation (type: float) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 366: DrawTextureRec() (4 input parameters) +Function 368: DrawTextureRec() (4 input parameters) Name: DrawTextureRec Return type: void Description: Draw a part of a texture defined by a rectangle @@ -3281,7 +3293,7 @@ Function 366: DrawTextureRec() (4 input parameters) Param[2]: source (type: Rectangle) Param[3]: position (type: Vector2) Param[4]: tint (type: Color) -Function 367: DrawTexturePro() (6 input parameters) +Function 369: DrawTexturePro() (6 input parameters) Name: DrawTexturePro Return type: void Description: Draw a part of a texture defined by a rectangle with 'pro' parameters @@ -3291,7 +3303,7 @@ Function 367: DrawTexturePro() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 368: DrawTextureNPatch() (6 input parameters) +Function 370: DrawTextureNPatch() (6 input parameters) Name: DrawTextureNPatch Return type: void Description: Draws a texture (or part of it) that stretches or shrinks nicely @@ -3301,119 +3313,119 @@ Function 368: DrawTextureNPatch() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 369: ColorIsEqual() (2 input parameters) +Function 371: ColorIsEqual() (2 input parameters) Name: ColorIsEqual Return type: bool Description: Check if two colors are equal Param[1]: col1 (type: Color) Param[2]: col2 (type: Color) -Function 370: Fade() (2 input parameters) +Function 372: Fade() (2 input parameters) Name: Fade Return type: Color Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f Param[1]: color (type: Color) Param[2]: alpha (type: float) -Function 371: ColorToInt() (1 input parameters) +Function 373: ColorToInt() (1 input parameters) Name: ColorToInt Return type: int Description: Get hexadecimal value for a Color (0xRRGGBBAA) Param[1]: color (type: Color) -Function 372: ColorNormalize() (1 input parameters) +Function 374: ColorNormalize() (1 input parameters) Name: ColorNormalize Return type: Vector4 Description: Get Color normalized as float [0..1] Param[1]: color (type: Color) -Function 373: ColorFromNormalized() (1 input parameters) +Function 375: ColorFromNormalized() (1 input parameters) Name: ColorFromNormalized Return type: Color Description: Get Color from normalized values [0..1] Param[1]: normalized (type: Vector4) -Function 374: ColorToHSV() (1 input parameters) +Function 376: ColorToHSV() (1 input parameters) Name: ColorToHSV Return type: Vector3 Description: Get HSV values for a Color, hue [0..360], saturation/value [0..1] Param[1]: color (type: Color) -Function 375: ColorFromHSV() (3 input parameters) +Function 377: ColorFromHSV() (3 input parameters) Name: ColorFromHSV Return type: Color Description: Get a Color from HSV values, hue [0..360], saturation/value [0..1] Param[1]: hue (type: float) Param[2]: saturation (type: float) Param[3]: value (type: float) -Function 376: ColorTint() (2 input parameters) +Function 378: 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 377: ColorBrightness() (2 input parameters) +Function 379: 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 378: ColorContrast() (2 input parameters) +Function 380: 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 379: ColorAlpha() (2 input parameters) +Function 381: 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 380: ColorAlphaBlend() (3 input parameters) +Function 382: 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 381: ColorLerp() (3 input parameters) +Function 383: ColorLerp() (3 input parameters) Name: ColorLerp Return type: Color Description: Get color lerp interpolation between two colors, factor [0.0f..1.0f] Param[1]: color1 (type: Color) Param[2]: color2 (type: Color) Param[3]: factor (type: float) -Function 382: GetColor() (1 input parameters) +Function 384: GetColor() (1 input parameters) Name: GetColor Return type: Color Description: Get Color structure from hexadecimal value Param[1]: hexValue (type: unsigned int) -Function 383: GetPixelColor() (2 input parameters) +Function 385: 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 384: SetPixelColor() (3 input parameters) +Function 386: 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 385: GetPixelDataSize() (3 input parameters) +Function 387: 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 386: GetFontDefault() (0 input parameters) +Function 388: GetFontDefault() (0 input parameters) Name: GetFontDefault Return type: Font Description: Get the default Font No input parameters -Function 387: LoadFont() (1 input parameters) +Function 389: 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 388: LoadFontEx() (4 input parameters) +Function 390: LoadFontEx() (4 input parameters) Name: LoadFontEx Return type: Font Description: Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height @@ -3421,14 +3433,14 @@ Function 388: LoadFontEx() (4 input parameters) Param[2]: fontSize (type: int) Param[3]: codepoints (type: int *) Param[4]: codepointCount (type: int) -Function 389: LoadFontFromImage() (3 input parameters) +Function 391: 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 390: LoadFontFromMemory() (6 input parameters) +Function 392: LoadFontFromMemory() (6 input parameters) Name: LoadFontFromMemory Return type: Font Description: Load font from memory buffer, fileType refers to extension: i.e. '.ttf' @@ -3438,12 +3450,12 @@ Function 390: LoadFontFromMemory() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: codepoints (type: int *) Param[6]: codepointCount (type: int) -Function 391: IsFontReady() (1 input parameters) +Function 393: IsFontReady() (1 input parameters) Name: IsFontReady Return type: bool Description: Check if a font is ready Param[1]: font (type: Font) -Function 392: LoadFontData() (6 input parameters) +Function 394: LoadFontData() (6 input parameters) Name: LoadFontData Return type: GlyphInfo * Description: Load font data for further use @@ -3453,7 +3465,7 @@ Function 392: LoadFontData() (6 input parameters) Param[4]: codepoints (type: int *) Param[5]: codepointCount (type: int) Param[6]: type (type: int) -Function 393: GenImageFontAtlas() (6 input parameters) +Function 395: GenImageFontAtlas() (6 input parameters) Name: GenImageFontAtlas Return type: Image Description: Generate image font atlas using chars info @@ -3463,30 +3475,30 @@ Function 393: GenImageFontAtlas() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: padding (type: int) Param[6]: packMethod (type: int) -Function 394: UnloadFontData() (2 input parameters) +Function 396: UnloadFontData() (2 input parameters) Name: UnloadFontData Return type: void Description: Unload font chars info data (RAM) Param[1]: glyphs (type: GlyphInfo *) Param[2]: glyphCount (type: int) -Function 395: UnloadFont() (1 input parameters) +Function 397: UnloadFont() (1 input parameters) Name: UnloadFont Return type: void Description: Unload font from GPU memory (VRAM) Param[1]: font (type: Font) -Function 396: ExportFontAsCode() (2 input parameters) +Function 398: 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 397: DrawFPS() (2 input parameters) +Function 399: DrawFPS() (2 input parameters) Name: DrawFPS Return type: void Description: Draw current FPS Param[1]: posX (type: int) Param[2]: posY (type: int) -Function 398: DrawText() (5 input parameters) +Function 400: DrawText() (5 input parameters) Name: DrawText Return type: void Description: Draw text (using default font) @@ -3495,7 +3507,7 @@ Function 398: DrawText() (5 input parameters) Param[3]: posY (type: int) Param[4]: fontSize (type: int) Param[5]: color (type: Color) -Function 399: DrawTextEx() (6 input parameters) +Function 401: DrawTextEx() (6 input parameters) Name: DrawTextEx Return type: void Description: Draw text using font and additional parameters @@ -3505,7 +3517,7 @@ Function 399: DrawTextEx() (6 input parameters) Param[4]: fontSize (type: float) Param[5]: spacing (type: float) Param[6]: tint (type: Color) -Function 400: DrawTextPro() (8 input parameters) +Function 402: DrawTextPro() (8 input parameters) Name: DrawTextPro Return type: void Description: Draw text using Font and pro parameters (rotation) @@ -3517,7 +3529,7 @@ Function 400: DrawTextPro() (8 input parameters) Param[6]: fontSize (type: float) Param[7]: spacing (type: float) Param[8]: tint (type: Color) -Function 401: DrawTextCodepoint() (5 input parameters) +Function 403: DrawTextCodepoint() (5 input parameters) Name: DrawTextCodepoint Return type: void Description: Draw one character (codepoint) @@ -3526,7 +3538,7 @@ Function 401: DrawTextCodepoint() (5 input parameters) Param[3]: position (type: Vector2) Param[4]: fontSize (type: float) Param[5]: tint (type: Color) -Function 402: DrawTextCodepoints() (7 input parameters) +Function 404: DrawTextCodepoints() (7 input parameters) Name: DrawTextCodepoints Return type: void Description: Draw multiple character (codepoint) @@ -3537,18 +3549,18 @@ Function 402: DrawTextCodepoints() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 403: SetTextLineSpacing() (1 input parameters) +Function 405: SetTextLineSpacing() (1 input parameters) Name: SetTextLineSpacing Return type: void Description: Set vertical line spacing when drawing with line-breaks Param[1]: spacing (type: int) -Function 404: MeasureText() (2 input parameters) +Function 406: 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 405: MeasureTextEx() (4 input parameters) +Function 407: MeasureTextEx() (4 input parameters) Name: MeasureTextEx Return type: Vector2 Description: Measure string size for Font @@ -3556,195 +3568,195 @@ Function 405: MeasureTextEx() (4 input parameters) Param[2]: text (type: const char *) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) -Function 406: GetGlyphIndex() (2 input parameters) +Function 408: 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 407: GetGlyphInfo() (2 input parameters) +Function 409: 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 408: GetGlyphAtlasRec() (2 input parameters) +Function 410: 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 409: LoadUTF8() (2 input parameters) +Function 411: 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 410: UnloadUTF8() (1 input parameters) +Function 412: UnloadUTF8() (1 input parameters) Name: UnloadUTF8 Return type: void Description: Unload UTF-8 text encoded from codepoints array Param[1]: text (type: char *) -Function 411: LoadCodepoints() (2 input parameters) +Function 413: 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 412: UnloadCodepoints() (1 input parameters) +Function 414: UnloadCodepoints() (1 input parameters) Name: UnloadCodepoints Return type: void Description: Unload codepoints data from memory Param[1]: codepoints (type: int *) -Function 413: GetCodepointCount() (1 input parameters) +Function 415: 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 414: GetCodepoint() (2 input parameters) +Function 416: 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 415: GetCodepointNext() (2 input parameters) +Function 417: 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 416: GetCodepointPrevious() (2 input parameters) +Function 418: 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 417: CodepointToUTF8() (2 input parameters) +Function 419: 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 418: TextCopy() (2 input parameters) +Function 420: 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 419: TextIsEqual() (2 input parameters) +Function 421: 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 420: TextLength() (1 input parameters) +Function 422: 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 421: TextFormat() (2 input parameters) +Function 423: 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 422: TextSubtext() (3 input parameters) +Function 424: 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 423: TextReplace() (3 input parameters) +Function 425: TextReplace() (3 input parameters) Name: TextReplace Return type: char * Description: Replace text string (WARNING: memory must be freed!) Param[1]: text (type: const char *) Param[2]: replace (type: const char *) Param[3]: by (type: const char *) -Function 424: TextInsert() (3 input parameters) +Function 426: 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 425: TextJoin() (3 input parameters) +Function 427: 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 426: TextSplit() (3 input parameters) +Function 428: 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 427: TextAppend() (3 input parameters) +Function 429: 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 428: TextFindIndex() (2 input parameters) +Function 430: 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 429: TextToUpper() (1 input parameters) +Function 431: 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 430: TextToLower() (1 input parameters) +Function 432: 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 431: TextToPascal() (1 input parameters) +Function 433: 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 432: TextToSnake() (1 input parameters) +Function 434: TextToSnake() (1 input parameters) Name: TextToSnake Return type: const char * Description: Get Snake case notation version of provided string Param[1]: text (type: const char *) -Function 433: TextToCamel() (1 input parameters) +Function 435: TextToCamel() (1 input parameters) Name: TextToCamel Return type: const char * Description: Get Camel case notation version of provided string Param[1]: text (type: const char *) -Function 434: TextToInteger() (1 input parameters) +Function 436: 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 435: TextToFloat() (1 input parameters) +Function 437: TextToFloat() (1 input parameters) Name: TextToFloat Return type: float Description: Get float value from text (negative values not supported) Param[1]: text (type: const char *) -Function 436: DrawLine3D() (3 input parameters) +Function 438: 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 437: DrawPoint3D() (2 input parameters) +Function 439: 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 438: DrawCircle3D() (5 input parameters) +Function 440: DrawCircle3D() (5 input parameters) Name: DrawCircle3D Return type: void Description: Draw a circle in 3D world space @@ -3753,7 +3765,7 @@ Function 438: DrawCircle3D() (5 input parameters) Param[3]: rotationAxis (type: Vector3) Param[4]: rotationAngle (type: float) Param[5]: color (type: Color) -Function 439: DrawTriangle3D() (4 input parameters) +Function 441: DrawTriangle3D() (4 input parameters) Name: DrawTriangle3D Return type: void Description: Draw a color-filled triangle (vertex in counter-clockwise order!) @@ -3761,14 +3773,14 @@ Function 439: DrawTriangle3D() (4 input parameters) Param[2]: v2 (type: Vector3) Param[3]: v3 (type: Vector3) Param[4]: color (type: Color) -Function 440: DrawTriangleStrip3D() (3 input parameters) +Function 442: DrawTriangleStrip3D() (3 input parameters) Name: DrawTriangleStrip3D Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector3 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 441: DrawCube() (5 input parameters) +Function 443: DrawCube() (5 input parameters) Name: DrawCube Return type: void Description: Draw cube @@ -3777,14 +3789,14 @@ Function 441: DrawCube() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 442: DrawCubeV() (3 input parameters) +Function 444: 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 443: DrawCubeWires() (5 input parameters) +Function 445: DrawCubeWires() (5 input parameters) Name: DrawCubeWires Return type: void Description: Draw cube wires @@ -3793,21 +3805,21 @@ Function 443: DrawCubeWires() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 444: DrawCubeWiresV() (3 input parameters) +Function 446: 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 445: DrawSphere() (3 input parameters) +Function 447: 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 446: DrawSphereEx() (5 input parameters) +Function 448: DrawSphereEx() (5 input parameters) Name: DrawSphereEx Return type: void Description: Draw sphere with extended parameters @@ -3816,7 +3828,7 @@ Function 446: DrawSphereEx() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 447: DrawSphereWires() (5 input parameters) +Function 449: DrawSphereWires() (5 input parameters) Name: DrawSphereWires Return type: void Description: Draw sphere wires @@ -3825,7 +3837,7 @@ Function 447: DrawSphereWires() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 448: DrawCylinder() (6 input parameters) +Function 450: DrawCylinder() (6 input parameters) Name: DrawCylinder Return type: void Description: Draw a cylinder/cone @@ -3835,7 +3847,7 @@ Function 448: DrawCylinder() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 449: DrawCylinderEx() (6 input parameters) +Function 451: DrawCylinderEx() (6 input parameters) Name: DrawCylinderEx Return type: void Description: Draw a cylinder with base at startPos and top at endPos @@ -3845,7 +3857,7 @@ Function 449: DrawCylinderEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 450: DrawCylinderWires() (6 input parameters) +Function 452: DrawCylinderWires() (6 input parameters) Name: DrawCylinderWires Return type: void Description: Draw a cylinder/cone wires @@ -3855,7 +3867,7 @@ Function 450: DrawCylinderWires() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 451: DrawCylinderWiresEx() (6 input parameters) +Function 453: DrawCylinderWiresEx() (6 input parameters) Name: DrawCylinderWiresEx Return type: void Description: Draw a cylinder wires with base at startPos and top at endPos @@ -3865,7 +3877,7 @@ Function 451: DrawCylinderWiresEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 452: DrawCapsule() (6 input parameters) +Function 454: DrawCapsule() (6 input parameters) Name: DrawCapsule Return type: void Description: Draw a capsule with the center of its sphere caps at startPos and endPos @@ -3875,7 +3887,7 @@ Function 452: DrawCapsule() (6 input parameters) Param[4]: slices (type: int) Param[5]: rings (type: int) Param[6]: color (type: Color) -Function 453: DrawCapsuleWires() (6 input parameters) +Function 455: DrawCapsuleWires() (6 input parameters) Name: DrawCapsuleWires Return type: void Description: Draw capsule wireframe with the center of its sphere caps at startPos and endPos @@ -3885,51 +3897,51 @@ Function 453: DrawCapsuleWires() (6 input parameters) Param[4]: slices (type: int) Param[5]: rings (type: int) Param[6]: color (type: Color) -Function 454: DrawPlane() (3 input parameters) +Function 456: 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 455: DrawRay() (2 input parameters) +Function 457: 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 456: DrawGrid() (2 input parameters) +Function 458: 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 457: LoadModel() (1 input parameters) +Function 459: LoadModel() (1 input parameters) Name: LoadModel Return type: Model Description: Load model from files (meshes and materials) Param[1]: fileName (type: const char *) -Function 458: LoadModelFromMesh() (1 input parameters) +Function 460: LoadModelFromMesh() (1 input parameters) Name: LoadModelFromMesh Return type: Model Description: Load model from generated mesh (default material) Param[1]: mesh (type: Mesh) -Function 459: IsModelReady() (1 input parameters) +Function 461: IsModelReady() (1 input parameters) Name: IsModelReady Return type: bool Description: Check if a model is ready Param[1]: model (type: Model) -Function 460: UnloadModel() (1 input parameters) +Function 462: 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 461: GetModelBoundingBox() (1 input parameters) +Function 463: GetModelBoundingBox() (1 input parameters) Name: GetModelBoundingBox Return type: BoundingBox Description: Compute model bounding box limits (considers all meshes) Param[1]: model (type: Model) -Function 462: DrawModel() (4 input parameters) +Function 464: DrawModel() (4 input parameters) Name: DrawModel Return type: void Description: Draw a model (with texture if set) @@ -3937,7 +3949,7 @@ Function 462: DrawModel() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 463: DrawModelEx() (6 input parameters) +Function 465: DrawModelEx() (6 input parameters) Name: DrawModelEx Return type: void Description: Draw a model with extended parameters @@ -3947,7 +3959,7 @@ Function 463: DrawModelEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 464: DrawModelWires() (4 input parameters) +Function 466: DrawModelWires() (4 input parameters) Name: DrawModelWires Return type: void Description: Draw a model wires (with texture if set) @@ -3955,7 +3967,7 @@ Function 464: DrawModelWires() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 465: DrawModelWiresEx() (6 input parameters) +Function 467: DrawModelWiresEx() (6 input parameters) Name: DrawModelWiresEx Return type: void Description: Draw a model wires (with texture if set) with extended parameters @@ -3965,7 +3977,7 @@ Function 465: DrawModelWiresEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 466: DrawModelPoints() (4 input parameters) +Function 468: DrawModelPoints() (4 input parameters) Name: DrawModelPoints Return type: void Description: Draw a model as points @@ -3973,7 +3985,7 @@ Function 466: DrawModelPoints() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 467: DrawModelPointsEx() (6 input parameters) +Function 469: DrawModelPointsEx() (6 input parameters) Name: DrawModelPointsEx Return type: void Description: Draw a model as points with extended parameters @@ -3983,13 +3995,13 @@ Function 467: DrawModelPointsEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 468: DrawBoundingBox() (2 input parameters) +Function 470: 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 469: DrawBillboard() (5 input parameters) +Function 471: DrawBillboard() (5 input parameters) Name: DrawBillboard Return type: void Description: Draw a billboard texture @@ -3998,7 +4010,7 @@ Function 469: DrawBillboard() (5 input parameters) Param[3]: position (type: Vector3) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 470: DrawBillboardRec() (6 input parameters) +Function 472: DrawBillboardRec() (6 input parameters) Name: DrawBillboardRec Return type: void Description: Draw a billboard texture defined by source @@ -4008,7 +4020,7 @@ Function 470: DrawBillboardRec() (6 input parameters) Param[4]: position (type: Vector3) Param[5]: size (type: Vector2) Param[6]: tint (type: Color) -Function 471: DrawBillboardPro() (9 input parameters) +Function 473: DrawBillboardPro() (9 input parameters) Name: DrawBillboardPro Return type: void Description: Draw a billboard texture defined by source and rotation @@ -4021,13 +4033,13 @@ Function 471: DrawBillboardPro() (9 input parameters) Param[7]: origin (type: Vector2) Param[8]: rotation (type: float) Param[9]: tint (type: Color) -Function 472: UploadMesh() (2 input parameters) +Function 474: 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 473: UpdateMeshBuffer() (5 input parameters) +Function 475: UpdateMeshBuffer() (5 input parameters) Name: UpdateMeshBuffer Return type: void Description: Update mesh vertex data in GPU for a specific buffer index @@ -4036,19 +4048,19 @@ Function 473: UpdateMeshBuffer() (5 input parameters) Param[3]: data (type: const void *) Param[4]: dataSize (type: int) Param[5]: offset (type: int) -Function 474: UnloadMesh() (1 input parameters) +Function 476: UnloadMesh() (1 input parameters) Name: UnloadMesh Return type: void Description: Unload mesh data from CPU and GPU Param[1]: mesh (type: Mesh) -Function 475: DrawMesh() (3 input parameters) +Function 477: 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 476: DrawMeshInstanced() (4 input parameters) +Function 478: DrawMeshInstanced() (4 input parameters) Name: DrawMeshInstanced Return type: void Description: Draw multiple mesh instances with material and different transforms @@ -4056,35 +4068,35 @@ Function 476: DrawMeshInstanced() (4 input parameters) Param[2]: material (type: Material) Param[3]: transforms (type: const Matrix *) Param[4]: instances (type: int) -Function 477: GetMeshBoundingBox() (1 input parameters) +Function 479: GetMeshBoundingBox() (1 input parameters) Name: GetMeshBoundingBox Return type: BoundingBox Description: Compute mesh bounding box limits Param[1]: mesh (type: Mesh) -Function 478: GenMeshTangents() (1 input parameters) +Function 480: GenMeshTangents() (1 input parameters) Name: GenMeshTangents Return type: void Description: Compute mesh tangents Param[1]: mesh (type: Mesh *) -Function 479: ExportMesh() (2 input parameters) +Function 481: 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 480: ExportMeshAsCode() (2 input parameters) +Function 482: ExportMeshAsCode() (2 input parameters) Name: ExportMeshAsCode Return type: bool Description: Export mesh as code file (.h) defining multiple arrays of vertex attributes Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 481: GenMeshPoly() (2 input parameters) +Function 483: GenMeshPoly() (2 input parameters) Name: GenMeshPoly Return type: Mesh Description: Generate polygonal mesh Param[1]: sides (type: int) Param[2]: radius (type: float) -Function 482: GenMeshPlane() (4 input parameters) +Function 484: GenMeshPlane() (4 input parameters) Name: GenMeshPlane Return type: Mesh Description: Generate plane mesh (with subdivisions) @@ -4092,42 +4104,42 @@ Function 482: GenMeshPlane() (4 input parameters) Param[2]: length (type: float) Param[3]: resX (type: int) Param[4]: resZ (type: int) -Function 483: GenMeshCube() (3 input parameters) +Function 485: 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 484: GenMeshSphere() (3 input parameters) +Function 486: 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 485: GenMeshHemiSphere() (3 input parameters) +Function 487: 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 486: GenMeshCylinder() (3 input parameters) +Function 488: 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 487: GenMeshCone() (3 input parameters) +Function 489: 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 488: GenMeshTorus() (4 input parameters) +Function 490: GenMeshTorus() (4 input parameters) Name: GenMeshTorus Return type: Mesh Description: Generate torus mesh @@ -4135,7 +4147,7 @@ Function 488: GenMeshTorus() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 489: GenMeshKnot() (4 input parameters) +Function 491: GenMeshKnot() (4 input parameters) Name: GenMeshKnot Return type: Mesh Description: Generate trefoil knot mesh @@ -4143,91 +4155,91 @@ Function 489: GenMeshKnot() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 490: GenMeshHeightmap() (2 input parameters) +Function 492: 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 491: GenMeshCubicmap() (2 input parameters) +Function 493: 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 492: LoadMaterials() (2 input parameters) +Function 494: 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 493: LoadMaterialDefault() (0 input parameters) +Function 495: LoadMaterialDefault() (0 input parameters) Name: LoadMaterialDefault Return type: Material Description: Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) No input parameters -Function 494: IsMaterialReady() (1 input parameters) +Function 496: IsMaterialReady() (1 input parameters) Name: IsMaterialReady Return type: bool Description: Check if a material is ready Param[1]: material (type: Material) -Function 495: UnloadMaterial() (1 input parameters) +Function 497: UnloadMaterial() (1 input parameters) Name: UnloadMaterial Return type: void Description: Unload material from GPU memory (VRAM) Param[1]: material (type: Material) -Function 496: SetMaterialTexture() (3 input parameters) +Function 498: 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 497: SetModelMeshMaterial() (3 input parameters) +Function 499: 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 498: LoadModelAnimations() (2 input parameters) +Function 500: LoadModelAnimations() (2 input parameters) Name: LoadModelAnimations Return type: ModelAnimation * Description: Load model animations from file Param[1]: fileName (type: const char *) Param[2]: animCount (type: int *) -Function 499: UpdateModelAnimation() (3 input parameters) +Function 501: 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 500: UnloadModelAnimation() (1 input parameters) +Function 502: UnloadModelAnimation() (1 input parameters) Name: UnloadModelAnimation Return type: void Description: Unload animation data Param[1]: anim (type: ModelAnimation) -Function 501: UnloadModelAnimations() (2 input parameters) +Function 503: UnloadModelAnimations() (2 input parameters) Name: UnloadModelAnimations Return type: void Description: Unload animation array data Param[1]: animations (type: ModelAnimation *) Param[2]: animCount (type: int) -Function 502: IsModelAnimationValid() (2 input parameters) +Function 504: 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 503: UpdateModelAnimationBoneMatrices() (3 input parameters) +Function 505: UpdateModelAnimationBoneMatrices() (3 input parameters) Name: UpdateModelAnimationBoneMatrices Return type: void Description: Update model animation mesh bone matrices (Note GPU skinning does not work on Mac) Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) Param[3]: frame (type: int) -Function 504: CheckCollisionSpheres() (4 input parameters) +Function 506: CheckCollisionSpheres() (4 input parameters) Name: CheckCollisionSpheres Return type: bool Description: Check collision between two spheres @@ -4235,40 +4247,40 @@ Function 504: CheckCollisionSpheres() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector3) Param[4]: radius2 (type: float) -Function 505: CheckCollisionBoxes() (2 input parameters) +Function 507: 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 506: CheckCollisionBoxSphere() (3 input parameters) +Function 508: 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 507: GetRayCollisionSphere() (3 input parameters) +Function 509: 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 508: GetRayCollisionBox() (2 input parameters) +Function 510: 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 509: GetRayCollisionMesh() (3 input parameters) +Function 511: 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 510: GetRayCollisionTriangle() (4 input parameters) +Function 512: GetRayCollisionTriangle() (4 input parameters) Name: GetRayCollisionTriangle Return type: RayCollision Description: Get collision info between ray and triangle @@ -4276,7 +4288,7 @@ Function 510: GetRayCollisionTriangle() (4 input parameters) Param[2]: p1 (type: Vector3) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) -Function 511: GetRayCollisionQuad() (5 input parameters) +Function 513: GetRayCollisionQuad() (5 input parameters) Name: GetRayCollisionQuad Return type: RayCollision Description: Get collision info between ray and quad @@ -4285,158 +4297,158 @@ Function 511: GetRayCollisionQuad() (5 input parameters) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) Param[5]: p4 (type: Vector3) -Function 512: InitAudioDevice() (0 input parameters) +Function 514: InitAudioDevice() (0 input parameters) Name: InitAudioDevice Return type: void Description: Initialize audio device and context No input parameters -Function 513: CloseAudioDevice() (0 input parameters) +Function 515: CloseAudioDevice() (0 input parameters) Name: CloseAudioDevice Return type: void Description: Close the audio device and context No input parameters -Function 514: IsAudioDeviceReady() (0 input parameters) +Function 516: IsAudioDeviceReady() (0 input parameters) Name: IsAudioDeviceReady Return type: bool Description: Check if audio device has been initialized successfully No input parameters -Function 515: SetMasterVolume() (1 input parameters) +Function 517: SetMasterVolume() (1 input parameters) Name: SetMasterVolume Return type: void Description: Set master volume (listener) Param[1]: volume (type: float) -Function 516: GetMasterVolume() (0 input parameters) +Function 518: GetMasterVolume() (0 input parameters) Name: GetMasterVolume Return type: float Description: Get master volume (listener) No input parameters -Function 517: LoadWave() (1 input parameters) +Function 519: LoadWave() (1 input parameters) Name: LoadWave Return type: Wave Description: Load wave data from file Param[1]: fileName (type: const char *) -Function 518: LoadWaveFromMemory() (3 input parameters) +Function 520: 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 519: IsWaveReady() (1 input parameters) +Function 521: IsWaveReady() (1 input parameters) Name: IsWaveReady Return type: bool Description: Checks if wave data is ready Param[1]: wave (type: Wave) -Function 520: LoadSound() (1 input parameters) +Function 522: LoadSound() (1 input parameters) Name: LoadSound Return type: Sound Description: Load sound from file Param[1]: fileName (type: const char *) -Function 521: LoadSoundFromWave() (1 input parameters) +Function 523: LoadSoundFromWave() (1 input parameters) Name: LoadSoundFromWave Return type: Sound Description: Load sound from wave data Param[1]: wave (type: Wave) -Function 522: LoadSoundAlias() (1 input parameters) +Function 524: LoadSoundAlias() (1 input parameters) Name: LoadSoundAlias Return type: Sound Description: Create a new sound that shares the same sample data as the source sound, does not own the sound data Param[1]: source (type: Sound) -Function 523: IsSoundReady() (1 input parameters) +Function 525: IsSoundReady() (1 input parameters) Name: IsSoundReady Return type: bool Description: Checks if a sound is ready Param[1]: sound (type: Sound) -Function 524: UpdateSound() (3 input parameters) +Function 526: 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 525: UnloadWave() (1 input parameters) +Function 527: UnloadWave() (1 input parameters) Name: UnloadWave Return type: void Description: Unload wave data Param[1]: wave (type: Wave) -Function 526: UnloadSound() (1 input parameters) +Function 528: UnloadSound() (1 input parameters) Name: UnloadSound Return type: void Description: Unload sound Param[1]: sound (type: Sound) -Function 527: UnloadSoundAlias() (1 input parameters) +Function 529: UnloadSoundAlias() (1 input parameters) Name: UnloadSoundAlias Return type: void Description: Unload a sound alias (does not deallocate sample data) Param[1]: alias (type: Sound) -Function 528: ExportWave() (2 input parameters) +Function 530: 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 529: ExportWaveAsCode() (2 input parameters) +Function 531: 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 530: PlaySound() (1 input parameters) +Function 532: PlaySound() (1 input parameters) Name: PlaySound Return type: void Description: Play a sound Param[1]: sound (type: Sound) -Function 531: StopSound() (1 input parameters) +Function 533: StopSound() (1 input parameters) Name: StopSound Return type: void Description: Stop playing a sound Param[1]: sound (type: Sound) -Function 532: PauseSound() (1 input parameters) +Function 534: PauseSound() (1 input parameters) Name: PauseSound Return type: void Description: Pause a sound Param[1]: sound (type: Sound) -Function 533: ResumeSound() (1 input parameters) +Function 535: ResumeSound() (1 input parameters) Name: ResumeSound Return type: void Description: Resume a paused sound Param[1]: sound (type: Sound) -Function 534: IsSoundPlaying() (1 input parameters) +Function 536: IsSoundPlaying() (1 input parameters) Name: IsSoundPlaying Return type: bool Description: Check if a sound is currently playing Param[1]: sound (type: Sound) -Function 535: SetSoundVolume() (2 input parameters) +Function 537: 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 536: SetSoundPitch() (2 input parameters) +Function 538: 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 537: SetSoundPan() (2 input parameters) +Function 539: 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 538: WaveCopy() (1 input parameters) +Function 540: WaveCopy() (1 input parameters) Name: WaveCopy Return type: Wave Description: Copy a wave to a new wave Param[1]: wave (type: Wave) -Function 539: WaveCrop() (3 input parameters) +Function 541: WaveCrop() (3 input parameters) Name: WaveCrop Return type: void Description: Crop a wave to defined frames range Param[1]: wave (type: Wave *) Param[2]: initFrame (type: int) Param[3]: finalFrame (type: int) -Function 540: WaveFormat() (4 input parameters) +Function 542: WaveFormat() (4 input parameters) Name: WaveFormat Return type: void Description: Convert wave data to desired format @@ -4444,203 +4456,203 @@ Function 540: WaveFormat() (4 input parameters) Param[2]: sampleRate (type: int) Param[3]: sampleSize (type: int) Param[4]: channels (type: int) -Function 541: LoadWaveSamples() (1 input parameters) +Function 543: 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 542: UnloadWaveSamples() (1 input parameters) +Function 544: UnloadWaveSamples() (1 input parameters) Name: UnloadWaveSamples Return type: void Description: Unload samples data loaded with LoadWaveSamples() Param[1]: samples (type: float *) -Function 543: LoadMusicStream() (1 input parameters) +Function 545: LoadMusicStream() (1 input parameters) Name: LoadMusicStream Return type: Music Description: Load music stream from file Param[1]: fileName (type: const char *) -Function 544: LoadMusicStreamFromMemory() (3 input parameters) +Function 546: 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 545: IsMusicReady() (1 input parameters) +Function 547: IsMusicReady() (1 input parameters) Name: IsMusicReady Return type: bool Description: Checks if a music stream is ready Param[1]: music (type: Music) -Function 546: UnloadMusicStream() (1 input parameters) +Function 548: UnloadMusicStream() (1 input parameters) Name: UnloadMusicStream Return type: void Description: Unload music stream Param[1]: music (type: Music) -Function 547: PlayMusicStream() (1 input parameters) +Function 549: PlayMusicStream() (1 input parameters) Name: PlayMusicStream Return type: void Description: Start music playing Param[1]: music (type: Music) -Function 548: IsMusicStreamPlaying() (1 input parameters) +Function 550: IsMusicStreamPlaying() (1 input parameters) Name: IsMusicStreamPlaying Return type: bool Description: Check if music is playing Param[1]: music (type: Music) -Function 549: UpdateMusicStream() (1 input parameters) +Function 551: UpdateMusicStream() (1 input parameters) Name: UpdateMusicStream Return type: void Description: Updates buffers for music streaming Param[1]: music (type: Music) -Function 550: StopMusicStream() (1 input parameters) +Function 552: StopMusicStream() (1 input parameters) Name: StopMusicStream Return type: void Description: Stop music playing Param[1]: music (type: Music) -Function 551: PauseMusicStream() (1 input parameters) +Function 553: PauseMusicStream() (1 input parameters) Name: PauseMusicStream Return type: void Description: Pause music playing Param[1]: music (type: Music) -Function 552: ResumeMusicStream() (1 input parameters) +Function 554: ResumeMusicStream() (1 input parameters) Name: ResumeMusicStream Return type: void Description: Resume playing paused music Param[1]: music (type: Music) -Function 553: SeekMusicStream() (2 input parameters) +Function 555: 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 554: SetMusicVolume() (2 input parameters) +Function 556: 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 555: SetMusicPitch() (2 input parameters) +Function 557: 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 556: SetMusicPan() (2 input parameters) +Function 558: 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 557: GetMusicTimeLength() (1 input parameters) +Function 559: GetMusicTimeLength() (1 input parameters) Name: GetMusicTimeLength Return type: float Description: Get music time length (in seconds) Param[1]: music (type: Music) -Function 558: GetMusicTimePlayed() (1 input parameters) +Function 560: GetMusicTimePlayed() (1 input parameters) Name: GetMusicTimePlayed Return type: float Description: Get current music time played (in seconds) Param[1]: music (type: Music) -Function 559: LoadAudioStream() (3 input parameters) +Function 561: 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 560: IsAudioStreamReady() (1 input parameters) +Function 562: IsAudioStreamReady() (1 input parameters) Name: IsAudioStreamReady Return type: bool Description: Checks if an audio stream is ready Param[1]: stream (type: AudioStream) -Function 561: UnloadAudioStream() (1 input parameters) +Function 563: UnloadAudioStream() (1 input parameters) Name: UnloadAudioStream Return type: void Description: Unload audio stream and free memory Param[1]: stream (type: AudioStream) -Function 562: UpdateAudioStream() (3 input parameters) +Function 564: 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 563: IsAudioStreamProcessed() (1 input parameters) +Function 565: IsAudioStreamProcessed() (1 input parameters) Name: IsAudioStreamProcessed Return type: bool Description: Check if any audio stream buffers requires refill Param[1]: stream (type: AudioStream) -Function 564: PlayAudioStream() (1 input parameters) +Function 566: PlayAudioStream() (1 input parameters) Name: PlayAudioStream Return type: void Description: Play audio stream Param[1]: stream (type: AudioStream) -Function 565: PauseAudioStream() (1 input parameters) +Function 567: PauseAudioStream() (1 input parameters) Name: PauseAudioStream Return type: void Description: Pause audio stream Param[1]: stream (type: AudioStream) -Function 566: ResumeAudioStream() (1 input parameters) +Function 568: ResumeAudioStream() (1 input parameters) Name: ResumeAudioStream Return type: void Description: Resume audio stream Param[1]: stream (type: AudioStream) -Function 567: IsAudioStreamPlaying() (1 input parameters) +Function 569: IsAudioStreamPlaying() (1 input parameters) Name: IsAudioStreamPlaying Return type: bool Description: Check if audio stream is playing Param[1]: stream (type: AudioStream) -Function 568: StopAudioStream() (1 input parameters) +Function 570: StopAudioStream() (1 input parameters) Name: StopAudioStream Return type: void Description: Stop audio stream Param[1]: stream (type: AudioStream) -Function 569: SetAudioStreamVolume() (2 input parameters) +Function 571: 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 570: SetAudioStreamPitch() (2 input parameters) +Function 572: 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 571: SetAudioStreamPan() (2 input parameters) +Function 573: 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 572: SetAudioStreamBufferSizeDefault() (1 input parameters) +Function 574: SetAudioStreamBufferSizeDefault() (1 input parameters) Name: SetAudioStreamBufferSizeDefault Return type: void Description: Default size for new audio streams Param[1]: size (type: int) -Function 573: SetAudioStreamCallback() (2 input parameters) +Function 575: 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 574: AttachAudioStreamProcessor() (2 input parameters) +Function 576: AttachAudioStreamProcessor() (2 input parameters) Name: AttachAudioStreamProcessor Return type: void Description: Attach audio stream processor to stream, receives the samples as 'float' Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 575: DetachAudioStreamProcessor() (2 input parameters) +Function 577: 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 576: AttachAudioMixedProcessor() (1 input parameters) +Function 578: AttachAudioMixedProcessor() (1 input parameters) Name: AttachAudioMixedProcessor Return type: void Description: Attach audio stream processor to the entire audio pipeline, receives the samples as 'float' Param[1]: processor (type: AudioCallback) -Function 577: DetachAudioMixedProcessor() (1 input parameters) +Function 579: DetachAudioMixedProcessor() (1 input parameters) Name: DetachAudioMixedProcessor Return type: void Description: Detach audio stream processor from the entire audio pipeline diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index 73ce0dae7..25b253224 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -675,7 +675,7 @@ - + @@ -1126,6 +1126,14 @@ + + + + + + + + From 8cbf34ddc495e2bca42245f786915c27210b0507 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 16 Oct 2024 19:26:12 +0200 Subject: [PATCH 090/115] WARNING: BREAKING: Renamed several functions for data validation #3930 --- src/raudio.c | 16 ++++++++-------- src/raylib.h | 22 +++++++++++----------- src/rcore.c | 6 +++--- src/rlgl.h | 1 - src/rmodels.c | 30 ++++++++++++++++++++++++------ src/rtext.c | 11 +++++------ src/rtextures.c | 30 +++++++++++++++--------------- 7 files changed, 66 insertions(+), 50 deletions(-) diff --git a/src/raudio.c b/src/raudio.c index 79d53b565..15859a661 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -892,8 +892,8 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int return wave; } -// Checks if wave data is ready -bool IsWaveReady(Wave wave) +// Checks if wave data is valid (data loaded and parameters) +bool IsWaveValid(Wave wave) { bool result = false; @@ -993,8 +993,8 @@ Sound LoadSoundAlias(Sound source) } -// Checks if a sound is ready -bool IsSoundReady(Sound sound) +// Checks if a sound is valid (data loaded and buffers initialized) +bool IsSoundValid(Sound sound) { bool result = false; @@ -1726,8 +1726,8 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, return music; } -// Checks if a music stream is ready -bool IsMusicReady(Music music) +// Checks if a music stream is valid (context and buffers initialized) +bool IsMusicValid(Music music) { return ((music.ctxData != NULL) && // Validate context loaded (music.frameCount > 0) && // Validate audio frame count @@ -2119,8 +2119,8 @@ AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, un return stream; } -// Checks if an audio stream is ready -bool IsAudioStreamReady(AudioStream stream) +// Checks if an audio stream is valid (buffers initialized) +bool IsAudioStreamValid(AudioStream stream) { return ((stream.buffer != NULL) && // Validate stream buffer (stream.sampleRate > 0) && // Validate sample rate is supported diff --git a/src/raylib.h b/src/raylib.h index 0ac4b603c..12a9e9fd2 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1044,7 +1044,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 bool IsShaderValid(Shader shader); // Check if a shader is valid (loaded on GPU) 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 @@ -1319,7 +1319,7 @@ RLAPI Image LoadImageAnimFromMemory(const char *fileType, const unsigned char *f 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 bool IsImageValid(Image image); // Check if an image is valid (data and parameters) 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 unsigned char *ExportImageToMemory(Image image, const char *fileType, int *fileSize); // Export image to memory buffer @@ -1405,9 +1405,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 bool IsTextureValid(Texture2D texture); // Check if a texture is valid (loaded in GPU) RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM) -RLAPI bool IsRenderTextureReady(RenderTexture2D target); // Check if a render texture is ready +RLAPI bool IsRenderTextureValid(RenderTexture2D target); // Check if a render texture is valid (loaded in GPU) 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 @@ -1454,7 +1454,7 @@ RLAPI Font LoadFont(const char *fileName); RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height 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 *codepoints, int codepointCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf' -RLAPI bool IsFontReady(Font font); // Check if a font is ready +RLAPI bool IsFontValid(Font font); // Check if a font is valid (font data loaded, WARNING: GPU texture not checked) RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount, int type); // Load font data for further use RLAPI Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info RLAPI void UnloadFontData(GlyphInfo *glyphs, int glyphCount); // Unload font chars info data (RAM) @@ -1544,7 +1544,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 bool IsModelValid(Model model); // Check if a model is valid (loaded in GPU, VAO/VBOs) RLAPI void UnloadModel(Model model); // Unload model (including meshes) from memory (RAM and/or VRAM) RLAPI BoundingBox GetModelBoundingBox(Model model); // Compute model bounding box limits (considers all meshes) @@ -1587,7 +1587,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 bool IsMaterialValid(Material material); // Check if a material is valid (shader assigned, map textures loaded in GPU) 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 @@ -1625,11 +1625,11 @@ RLAPI float GetMasterVolume(void); // Get 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 bool IsWaveValid(Wave wave); // Checks if wave data is valid (data loaded and parameters) RLAPI Sound LoadSound(const char *fileName); // Load sound from file RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data RLAPI Sound LoadSoundAlias(Sound source); // Create a new sound that shares the same sample data as the source sound, does not own the sound data -RLAPI bool IsSoundReady(Sound sound); // Checks if a sound is ready +RLAPI bool IsSoundValid(Sound sound); // Checks if a sound is valid (data loaded and buffers initialized) 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 @@ -1655,7 +1655,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 bool IsMusicValid(Music music); // Checks if a music stream is valid (context and buffers initialized) 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 @@ -1672,7 +1672,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 bool IsAudioStreamValid(AudioStream stream); // Checks if an audio stream is valid (buffers initialized) 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 8ba72f715..8fa4217fb 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1342,10 +1342,10 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode) return shader; } -// Check if a shader is ready -bool IsShaderReady(Shader shader) +// Check if a shader is valid (loaded on GPU) +bool IsShaderValid(Shader shader) { - return ((shader.id > 0) && // Validate shader id (loaded successfully) + return ((shader.id > 0) && // Validate shader id (GPU 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), diff --git a/src/rlgl.h b/src/rlgl.h index 1695c2f56..e4e659ac9 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -347,7 +347,6 @@ #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6 #endif - #ifdef RL_SUPPORT_MESH_GPU_SKINNING #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 7 diff --git a/src/rmodels.c b/src/rmodels.c index 92be04fca..9d9c47519 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1155,8 +1155,8 @@ Model LoadModelFromMesh(Mesh mesh) return model; } -// Check if a model is ready -bool IsModelReady(Model model) +// Check if a model is valid (loaded in GPU, VAO/VBOs) +bool IsModelValid(Model model) { bool result = false; @@ -1165,8 +1165,24 @@ bool IsModelReady(Model model) (model.meshMaterial != NULL) && // Validate mesh-material linkage (model.meshCount > 0) && // Validate mesh count (model.materialCount > 0)) result = true; // Validate material count - - // NOTE: This is a very general model validation, many elements could be validated from a model... + + // NOTE: Many elements could be validated from a model, including every model mesh VAO/VBOs + // but some VBOs could not be used, it depends on Mesh vertex data + for (int i = 0; i < model.meshCount; i++) + { + if ((model.meshes[i].vertices != NULL) && (model.meshes[i].vboId[0] == 0)) { result = false; break; } // Vertex position buffer not uploaded to GPU + if ((model.meshes[i].texcoords != NULL) && (model.meshes[i].vboId[1] == 0)) { result = false; break; } // Vertex textcoords buffer not uploaded to GPU + if ((model.meshes[i].normals != NULL) && (model.meshes[i].vboId[2] == 0)) { result = false; break; } // Vertex normals buffer not uploaded to GPU + if ((model.meshes[i].colors != NULL) && (model.meshes[i].vboId[3] == 0)) { result = false; break; } // Vertex colors buffer not uploaded to GPU + if ((model.meshes[i].tangents != NULL) && (model.meshes[i].vboId[4] == 0)) { result = false; break; } // Vertex tangents buffer not uploaded to GPU + if ((model.meshes[i].texcoords2 != NULL) && (model.meshes[i].vboId[5] == 0)) { result = false; break; } // Vertex texcoords2 buffer not uploaded to GPU + if ((model.meshes[i].indices != NULL) && (model.meshes[i].vboId[6] == 0)) { result = false; break; } // Vertex indices buffer not uploaded to GPU + if ((model.meshes[i].boneIds != NULL) && (model.meshes[i].vboId[7] == 0)) { result = false; break; } // Vertex boneIds buffer not uploaded to GPU + if ((model.meshes[i].boneWeights != NULL) && (model.meshes[i].vboId[8] == 0)) { result = false; break; } // Vertex boneWeights buffer not uploaded to GPU + + // NOTE: Some OpenGL versions do not support VAO, so we don't check it + //if (model.meshes[i].vaoId == 0) { result = false; break } + } return result; } @@ -2182,13 +2198,15 @@ Material LoadMaterialDefault(void) return material; } -// Check if a material is ready -bool IsMaterialReady(Material material) +// Check if a material is valid (map textures loaded in GPU) +bool IsMaterialValid(Material material) { bool result = false; if ((material.maps != NULL) && // Validate material contain some map (material.shader.id > 0)) result = true; // Validate material shader is valid + + // TODO: Check if available maps contain loaded textures return result; } diff --git a/src/rtext.c b/src/rtext.c index 0595e7fbe..86aeb0047 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -581,17 +581,16 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int return font; } -// Check if a font is ready -bool IsFontReady(Font font) +// Check if a font is valid (font data loaded) +// WARNING: GPU texture not checked +bool IsFontValid(Font font) { - return ((font.texture.id > 0) && // Validate OpenGL id for font texture atlas - (font.baseSize > 0) && // Validate font size + return ((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...) + // NOTE: Further validations could be done to verify if recs and glyphs contain valid data (glyphs values, metrics...) } // Load font data for further use diff --git a/src/rtextures.c b/src/rtextures.c index 84264369d..294eeb6ad 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -600,15 +600,15 @@ Image LoadImageFromScreen(void) } // Check if an image is ready -bool IsImageReady(Image image) +bool IsImageValid(Image image) { bool result = false; if ((image.data != NULL) && // Validate pixel data available - (image.width > 0) && - (image.height > 0) && // Validate image size + (image.width > 0) && // Validate image width + (image.height > 0) && // Validate image height (image.format > 0) && // Validate image format - (image.mipmaps > 0)) result = true; // Validate image mipmaps (at least 1 for basic mipmap level) + (image.mipmaps > 0)) result = true; // Validate image mipmaps (at least 1 for basic mipmap level) return result; } @@ -4224,16 +4224,16 @@ RenderTexture2D LoadRenderTexture(int width, int height) return target; } -// Check if a texture is ready -bool IsTextureReady(Texture2D texture) +// Check if a texture is valid (loaded in GPU) +bool IsTextureValid(Texture2D texture) { bool result = false; - // TODO: Validate maximum texture size supported by GPU? + // TODO: Validate maximum texture size supported by GPU - if ((texture.id > 0) && // Validate OpenGL id - (texture.width > 0) && - (texture.height > 0) && // Validate texture size + if ((texture.id > 0) && // Validate OpenGL id (texture uplaoded to GPU) + (texture.width > 0) && // Validate texture width + (texture.height > 0) && // Validate texture height (texture.format > 0) && // Validate texture pixel format (texture.mipmaps > 0)) result = true; // Validate texture mipmaps (at least 1 for basic mipmap level) @@ -4251,14 +4251,14 @@ void UnloadTexture(Texture2D texture) } } -// Check if a render texture is ready -bool IsRenderTextureReady(RenderTexture2D target) +// Check if a render texture is valid (loaded in GPU) +bool IsRenderTextureValid(RenderTexture2D target) { bool result = false; - if ((target.id > 0) && // Validate OpenGL id - IsTextureReady(target.depth) && // Validate FBO depth texture/renderbuffer - IsTextureReady(target.texture)) result = true; // Validate FBO texture + if ((target.id > 0) && // Validate OpenGL id (loaded on GPU) + IsTextureValid(target.depth) && // Validate FBO depth texture/renderbuffer attachment + IsTextureValid(target.texture)) result = true; // Validate FBO texture attachment return result; } From d6399622a0280bc8ea458104b946f1860d928156 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 16 Oct 2024 17:26:49 +0000 Subject: [PATCH 091/115] Update raylib_api.* by CI --- parser/output/raylib_api.json | 44 +++++++++++------------ parser/output/raylib_api.lua | 44 +++++++++++------------ parser/output/raylib_api.txt | 66 +++++++++++++++++------------------ parser/output/raylib_api.xml | 22 ++++++------ 4 files changed, 88 insertions(+), 88 deletions(-) diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json index f735853fb..1a2b49259 100644 --- a/parser/output/raylib_api.json +++ b/parser/output/raylib_api.json @@ -3763,8 +3763,8 @@ ] }, { - "name": "IsShaderReady", - "description": "Check if a shader is ready", + "name": "IsShaderValid", + "description": "Check if a shader is valid (loaded on GPU)", "returnType": "bool", "params": [ { @@ -6919,8 +6919,8 @@ "returnType": "Image" }, { - "name": "IsImageReady", - "description": "Check if an image is ready", + "name": "IsImageValid", + "description": "Check if an image is valid (data and parameters)", "returnType": "bool", "params": [ { @@ -8383,8 +8383,8 @@ ] }, { - "name": "IsTextureReady", - "description": "Check if a texture is ready", + "name": "IsTextureValid", + "description": "Check if a texture is valid (loaded in GPU)", "returnType": "bool", "params": [ { @@ -8405,8 +8405,8 @@ ] }, { - "name": "IsRenderTextureReady", - "description": "Check if a render texture is ready", + "name": "IsRenderTextureValid", + "description": "Check if a render texture is valid (loaded in GPU)", "returnType": "bool", "params": [ { @@ -9000,8 +9000,8 @@ ] }, { - "name": "IsFontReady", - "description": "Check if a font is ready", + "name": "IsFontValid", + "description": "Check if a font is valid (font data loaded, WARNING: GPU texture not checked)", "returnType": "bool", "params": [ { @@ -10292,8 +10292,8 @@ ] }, { - "name": "IsModelReady", - "description": "Check if a model is ready", + "name": "IsModelValid", + "description": "Check if a model is valid (loaded in GPU, VAO/VBOs)", "returnType": "bool", "params": [ { @@ -10979,8 +10979,8 @@ "returnType": "Material" }, { - "name": "IsMaterialReady", - "description": "Check if a material is ready", + "name": "IsMaterialValid", + "description": "Check if a material is valid (shader assigned, map textures loaded in GPU)", "returnType": "bool", "params": [ { @@ -11354,8 +11354,8 @@ ] }, { - "name": "IsWaveReady", - "description": "Checks if wave data is ready", + "name": "IsWaveValid", + "description": "Checks if wave data is valid (data loaded and parameters)", "returnType": "bool", "params": [ { @@ -11398,8 +11398,8 @@ ] }, { - "name": "IsSoundReady", - "description": "Checks if a sound is ready", + "name": "IsSoundValid", + "description": "Checks if a sound is valid (data loaded and buffers initialized)", "returnType": "bool", "params": [ { @@ -11696,8 +11696,8 @@ ] }, { - "name": "IsMusicReady", - "description": "Checks if a music stream is ready", + "name": "IsMusicValid", + "description": "Checks if a music stream is valid (context and buffers initialized)", "returnType": "bool", "params": [ { @@ -11885,8 +11885,8 @@ ] }, { - "name": "IsAudioStreamReady", - "description": "Checks if an audio stream is ready", + "name": "IsAudioStreamValid", + "description": "Checks if an audio stream is valid (buffers initialized)", "returnType": "bool", "params": [ { diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua index 4c0dd5a03..5bb0e3200 100644 --- a/parser/output/raylib_api.lua +++ b/parser/output/raylib_api.lua @@ -3589,8 +3589,8 @@ return { } }, { - name = "IsShaderReady", - description = "Check if a shader is ready", + name = "IsShaderValid", + description = "Check if a shader is valid (loaded on GPU)", returnType = "bool", params = { {type = "Shader", name = "shader"} @@ -5401,8 +5401,8 @@ return { returnType = "Image" }, { - name = "IsImageReady", - description = "Check if an image is ready", + name = "IsImageValid", + description = "Check if an image is valid (data and parameters)", returnType = "bool", params = { {type = "Image", name = "image"} @@ -6166,8 +6166,8 @@ return { } }, { - name = "IsTextureReady", - description = "Check if a texture is ready", + name = "IsTextureValid", + description = "Check if a texture is valid (loaded in GPU)", returnType = "bool", params = { {type = "Texture2D", name = "texture"} @@ -6182,8 +6182,8 @@ return { } }, { - name = "IsRenderTextureReady", - description = "Check if a render texture is ready", + name = "IsRenderTextureValid", + description = "Check if a render texture is valid (loaded in GPU)", returnType = "bool", params = { {type = "RenderTexture2D", name = "target"} @@ -6513,8 +6513,8 @@ return { } }, { - name = "IsFontReady", - description = "Check if a font is ready", + name = "IsFontValid", + description = "Check if a font is valid (font data loaded, WARNING: GPU texture not checked)", returnType = "bool", params = { {type = "Font", name = "font"} @@ -7193,8 +7193,8 @@ return { } }, { - name = "IsModelReady", - description = "Check if a model is ready", + name = "IsModelValid", + description = "Check if a model is valid (loaded in GPU, VAO/VBOs)", returnType = "bool", params = { {type = "Model", name = "model"} @@ -7547,8 +7547,8 @@ return { returnType = "Material" }, { - name = "IsMaterialReady", - description = "Check if a material is ready", + name = "IsMaterialValid", + description = "Check if a material is valid (shader assigned, map textures loaded in GPU)", returnType = "bool", params = { {type = "Material", name = "material"} @@ -7766,8 +7766,8 @@ return { } }, { - name = "IsWaveReady", - description = "Checks if wave data is ready", + name = "IsWaveValid", + description = "Checks if wave data is valid (data loaded and parameters)", returnType = "bool", params = { {type = "Wave", name = "wave"} @@ -7798,8 +7798,8 @@ return { } }, { - name = "IsSoundReady", - description = "Checks if a sound is ready", + name = "IsSoundValid", + description = "Checks if a sound is valid (data loaded and buffers initialized)", returnType = "bool", params = { {type = "Sound", name = "sound"} @@ -7988,8 +7988,8 @@ return { } }, { - name = "IsMusicReady", - description = "Checks if a music stream is ready", + name = "IsMusicValid", + description = "Checks if a music stream is valid (context and buffers initialized)", returnType = "bool", params = { {type = "Music", name = "music"} @@ -8114,8 +8114,8 @@ return { } }, { - name = "IsAudioStreamReady", - description = "Checks if an audio stream is ready", + name = "IsAudioStreamValid", + description = "Checks if an audio stream is valid (buffers initialized)", returnType = "bool", params = { {type = "AudioStream", name = "stream"} diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt index 865e5ae78..9893eb4c6 100644 --- a/parser/output/raylib_api.txt +++ b/parser/output/raylib_api.txt @@ -1378,10 +1378,10 @@ Function 075: LoadShaderFromMemory() (2 input parameters) Description: Load shader from code strings and bind default locations Param[1]: vsCode (type: const char *) Param[2]: fsCode (type: const char *) -Function 076: IsShaderReady() (1 input parameters) - Name: IsShaderReady +Function 076: IsShaderValid() (1 input parameters) + Name: IsShaderValid Return type: bool - Description: Check if a shader is ready + Description: Check if a shader is valid (loaded on GPU) Param[1]: shader (type: Shader) Function 077: GetShaderLocation() (2 input parameters) Name: GetShaderLocation @@ -2674,10 +2674,10 @@ Function 279: LoadImageFromScreen() (0 input parameters) Return type: Image Description: Load image from screen buffer and (screenshot) No input parameters -Function 280: IsImageReady() (1 input parameters) - Name: IsImageReady +Function 280: IsImageValid() (1 input parameters) + Name: IsImageValid Return type: bool - Description: Check if an image is ready + Description: Check if an image is valid (data and parameters) Param[1]: image (type: Image) Function 281: UnloadImage() (1 input parameters) Name: UnloadImage @@ -3211,20 +3211,20 @@ Function 355: LoadRenderTexture() (2 input parameters) Description: Load texture for rendering (framebuffer) Param[1]: width (type: int) Param[2]: height (type: int) -Function 356: IsTextureReady() (1 input parameters) - Name: IsTextureReady +Function 356: IsTextureValid() (1 input parameters) + Name: IsTextureValid Return type: bool - Description: Check if a texture is ready + Description: Check if a texture is valid (loaded in GPU) Param[1]: texture (type: Texture2D) Function 357: UnloadTexture() (1 input parameters) Name: UnloadTexture Return type: void Description: Unload texture from GPU memory (VRAM) Param[1]: texture (type: Texture2D) -Function 358: IsRenderTextureReady() (1 input parameters) - Name: IsRenderTextureReady +Function 358: IsRenderTextureValid() (1 input parameters) + Name: IsRenderTextureValid Return type: bool - Description: Check if a render texture is ready + Description: Check if a render texture is valid (loaded in GPU) Param[1]: target (type: RenderTexture2D) Function 359: UnloadRenderTexture() (1 input parameters) Name: UnloadRenderTexture @@ -3450,10 +3450,10 @@ Function 392: LoadFontFromMemory() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: codepoints (type: int *) Param[6]: codepointCount (type: int) -Function 393: IsFontReady() (1 input parameters) - Name: IsFontReady +Function 393: IsFontValid() (1 input parameters) + Name: IsFontValid Return type: bool - Description: Check if a font is ready + Description: Check if a font is valid (font data loaded, WARNING: GPU texture not checked) Param[1]: font (type: Font) Function 394: LoadFontData() (6 input parameters) Name: LoadFontData @@ -3926,10 +3926,10 @@ Function 460: LoadModelFromMesh() (1 input parameters) Return type: Model Description: Load model from generated mesh (default material) Param[1]: mesh (type: Mesh) -Function 461: IsModelReady() (1 input parameters) - Name: IsModelReady +Function 461: IsModelValid() (1 input parameters) + Name: IsModelValid Return type: bool - Description: Check if a model is ready + Description: Check if a model is valid (loaded in GPU, VAO/VBOs) Param[1]: model (type: Model) Function 462: UnloadModel() (1 input parameters) Name: UnloadModel @@ -4178,10 +4178,10 @@ Function 495: LoadMaterialDefault() (0 input parameters) Return type: Material Description: Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) No input parameters -Function 496: IsMaterialReady() (1 input parameters) - Name: IsMaterialReady +Function 496: IsMaterialValid() (1 input parameters) + Name: IsMaterialValid Return type: bool - Description: Check if a material is ready + Description: Check if a material is valid (shader assigned, map textures loaded in GPU) Param[1]: material (type: Material) Function 497: UnloadMaterial() (1 input parameters) Name: UnloadMaterial @@ -4334,10 +4334,10 @@ Function 520: LoadWaveFromMemory() (3 input parameters) Param[1]: fileType (type: const char *) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 521: IsWaveReady() (1 input parameters) - Name: IsWaveReady +Function 521: IsWaveValid() (1 input parameters) + Name: IsWaveValid Return type: bool - Description: Checks if wave data is ready + Description: Checks if wave data is valid (data loaded and parameters) Param[1]: wave (type: Wave) Function 522: LoadSound() (1 input parameters) Name: LoadSound @@ -4354,10 +4354,10 @@ Function 524: LoadSoundAlias() (1 input parameters) Return type: Sound Description: Create a new sound that shares the same sample data as the source sound, does not own the sound data Param[1]: source (type: Sound) -Function 525: IsSoundReady() (1 input parameters) - Name: IsSoundReady +Function 525: IsSoundValid() (1 input parameters) + Name: IsSoundValid Return type: bool - Description: Checks if a sound is ready + Description: Checks if a sound is valid (data loaded and buffers initialized) Param[1]: sound (type: Sound) Function 526: UpdateSound() (3 input parameters) Name: UpdateSound @@ -4478,10 +4478,10 @@ Function 546: LoadMusicStreamFromMemory() (3 input parameters) Param[1]: fileType (type: const char *) Param[2]: data (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 547: IsMusicReady() (1 input parameters) - Name: IsMusicReady +Function 547: IsMusicValid() (1 input parameters) + Name: IsMusicValid Return type: bool - Description: Checks if a music stream is ready + Description: Checks if a music stream is valid (context and buffers initialized) Param[1]: music (type: Music) Function 548: UnloadMusicStream() (1 input parameters) Name: UnloadMusicStream @@ -4559,10 +4559,10 @@ Function 561: LoadAudioStream() (3 input parameters) Param[1]: sampleRate (type: unsigned int) Param[2]: sampleSize (type: unsigned int) Param[3]: channels (type: unsigned int) -Function 562: IsAudioStreamReady() (1 input parameters) - Name: IsAudioStreamReady +Function 562: IsAudioStreamValid() (1 input parameters) + Name: IsAudioStreamValid Return type: bool - Description: Checks if an audio stream is ready + Description: Checks if an audio stream is valid (buffers initialized) Param[1]: stream (type: AudioStream) Function 563: UnloadAudioStream() (1 input parameters) Name: UnloadAudioStream diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index 25b253224..eb53437eb 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -871,7 +871,7 @@ - + @@ -1727,7 +1727,7 @@ - + @@ -2112,13 +2112,13 @@ - + - + @@ -2276,7 +2276,7 @@ - + @@ -2616,7 +2616,7 @@ - + @@ -2797,7 +2797,7 @@ - + @@ -2899,7 +2899,7 @@ - + @@ -2911,7 +2911,7 @@ - + @@ -2991,7 +2991,7 @@ - + @@ -3042,7 +3042,7 @@ - + From a2e31c4e1ba7b2ab0c4b87c70e88fa365b02f652 Mon Sep 17 00:00:00 2001 From: Asdqwe Date: Thu, 17 Oct 2024 10:35:49 -0300 Subject: [PATCH 092/115] Fix #4388 (#4392) --- src/platforms/rcore_desktop_sdl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 90372c2f6..b4ceb78eb 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -1609,7 +1609,6 @@ int InitPlatform(void) //---------------------------------------------------------------------------- // Define base path for storage CORE.Storage.basePath = SDL_GetBasePath(); // Alternative: GetWorkingDirectory(); - CHDIR(CORE.Storage.basePath); //---------------------------------------------------------------------------- TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL): Initialized successfully"); From b201b74c3fcc4d146b67dd7f9bbd61a3f490e28e Mon Sep 17 00:00:00 2001 From: Alan Arrecis Date: Thu, 17 Oct 2024 17:08:07 -0600 Subject: [PATCH 093/115] Fix VSCode Makefile to support multiple .c files (#4391) Updated the VSCode Makefile to allow compilation of multiple .c files instead of just one (main.c). - Replaced `SRC` and `OBJS` definitions to dynamically include all .c and .h files in the project. - This change enables automatic handling of any number of source files specifically in the VSCode setup. --- projects/VSCode/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/VSCode/Makefile b/projects/VSCode/Makefile index 2f43c9ead..86febfba0 100644 --- a/projects/VSCode/Makefile +++ b/projects/VSCode/Makefile @@ -352,9 +352,9 @@ SRC_DIR = src OBJ_DIR = obj # Define all object files from source files -SRC = $(call rwildcard, *.c, *.h) +SRC = $(call rwildcard, ./, *.c, *.h) #OBJS = $(SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o) -OBJS ?= main.c +OBJS = $(patsubst %.c,%.o,$(filter %.c,$(SRC))) # For Android platform we call a custom Makefile.Android ifeq ($(PLATFORM),PLATFORM_ANDROID) From 80393c0fb692f1042ae446a8a06df924cfa0fd70 Mon Sep 17 00:00:00 2001 From: Anthony Carbajal <5776225+CrackedPixel@users.noreply.github.com> Date: Thu, 17 Oct 2024 18:15:19 -0500 Subject: [PATCH 094/115] [rcore] added sha1 implementation (#4390) * added sha1 implementation * added missing part * fixed issue * fix to match other implementations --- src/raylib.h | 2 ++ src/rcore.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/src/raylib.h b/src/raylib.h index 12a9e9fd2..5ae45fa9d 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1146,6 +1146,8 @@ RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outpu RLAPI unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize); // Decode Base64 string data, memory must be MemFree() RLAPI unsigned int ComputeCRC32(unsigned char *data, int dataSize); // Compute CRC32 hash code RLAPI unsigned int *ComputeMD5(unsigned char *data, int dataSize); // Compute MD5 hash code, returns static int[4] (16 bytes) +RLAPI unsigned int *ComputeSHA1(unsigned char *data, int dataSize); // Compute SHA1 hash code, returns static int[5] (20 bytes) + // Automation events functionality RLAPI AutomationEventList LoadAutomationEventList(const char *fileName); // Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS diff --git a/src/rcore.c b/src/rcore.c index 8fa4217fb..9b3eeee80 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -2740,6 +2740,102 @@ unsigned int *ComputeMD5(unsigned char *data, int dataSize) return hash; } +// Compute SHA-1 hash code +// NOTE: Returns a static int[5] array (20 bytes) +unsigned int *ComputeSHA1(unsigned char *data, int dataSize) { + #define ROTATE_LEFT(x, c) (((x) << (c)) | ((x) >> (32 - (c)))) + + static unsigned int hash[5] = { 0 }; // Hash to be returned + + // Initialize hash values + hash[0] = 0x67452301; + hash[1] = 0xEFCDAB89; + hash[2] = 0x98BADCFE; + hash[3] = 0x10325476; + hash[4] = 0xC3D2E1F0; + + // Pre-processing: adding a single 1 bit + // Append '1' bit to message + // NOTE: The input bytes are considered as bits strings, + // where the first bit is the most significant bit of the byte + + // Pre-processing: padding with zeros + // Append '0' bit until message length in bit 448 (mod 512) + // Append length mod (2 pow 64) to message + + int newDataSize = ((((dataSize + 8)/64) + 1)*64); + + unsigned char *msg = RL_CALLOC(newDataSize, 1); // Initialize with '0' bits + memcpy(msg, data, dataSize); + msg[dataSize] = 128; // Write the '1' bit + + unsigned int bitsLen = 8*dataSize; + msg[newDataSize-1] = bitsLen; + + // Process the message in successive 512-bit chunks + for (int offset = 0; offset < newDataSize; offset += (512/8)) + { + // Break chunk into sixteen 32-bit words w[j], 0 <= j <= 15 + unsigned int w[80] = {0}; + for (int i = 0; i < 16; i++) { + w[i] = (msg[offset + (i * 4) + 0] << 24) | + (msg[offset + (i * 4) + 1] << 16) | + (msg[offset + (i * 4) + 2] << 8) | + (msg[offset + (i * 4) + 3]); + } + + // Message schedule: extend the sixteen 32-bit words into eighty 32-bit words: + for (int i = 16; i < 80; ++i) { + w[i] = ROTATE_LEFT(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1); + } + + // Initialize hash value for this chunk + unsigned int a = hash[0]; + unsigned int b = hash[1]; + unsigned int c = hash[2]; + unsigned int d = hash[3]; + unsigned int e = hash[4]; + + for (int i = 0; i < 80; i++) + { + unsigned int f = 0; + unsigned int k = 0; + + if (i < 20) { + f = (b & c) | ((~b) & d); + k = 0x5A827999; + } else if (i < 40) { + f = b ^ c ^ d; + k = 0x6ED9EBA1; + } else if (i < 60) { + f = (b & c) | (b & d) | (c & d); + k = 0x8F1BBCDC; + } else { + f = b ^ c ^ d; + k = 0xCA62C1D6; + } + + unsigned int temp = ROTATE_LEFT(a, 5) + f + e + k + w[i]; + e = d; + d = c; + c = ROTATE_LEFT(b, 30); + b = a; + a = temp; + } + + // Add this chunk's hash to result so far + hash[0] += a; + hash[1] += b; + hash[2] += c; + hash[3] += d; + hash[4] += e; + } + + free(msg); + + return hash; +} + //---------------------------------------------------------------------------------- // Module Functions Definition: Automation Events Recording and Playing //---------------------------------------------------------------------------------- From c6d67f006d05760d69a40ac6bcdc9ecb8e30373f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 17 Oct 2024 23:15:33 +0000 Subject: [PATCH 095/115] Update raylib_api.* by CI --- parser/output/raylib_api.json | 15 + parser/output/raylib_api.lua | 9 + parser/output/raylib_api.txt | 866 +++++++++++++++++----------------- parser/output/raylib_api.xml | 6 +- 4 files changed, 465 insertions(+), 431 deletions(-) diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json index 1a2b49259..fca3ef72c 100644 --- a/parser/output/raylib_api.json +++ b/parser/output/raylib_api.json @@ -4721,6 +4721,21 @@ } ] }, + { + "name": "ComputeSHA1", + "description": "Compute SHA1 hash code, returns static int[5] (20 bytes)", + "returnType": "unsigned int *", + "params": [ + { + "type": "unsigned char *", + "name": "data" + }, + { + "type": "int", + "name": "dataSize" + } + ] + }, { "name": "LoadAutomationEventList", "description": "Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS", diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua index 5bb0e3200..572b4332a 100644 --- a/parser/output/raylib_api.lua +++ b/parser/output/raylib_api.lua @@ -4208,6 +4208,15 @@ return { {type = "int", name = "dataSize"} } }, + { + name = "ComputeSHA1", + description = "Compute SHA1 hash code, returns static int[5] (20 bytes)", + returnType = "unsigned int *", + params = { + {type = "unsigned char *", name = "data"}, + {type = "int", name = "dataSize"} + } + }, { name = "LoadAutomationEventList", description = "Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS", diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt index 9893eb4c6..1fd591151 100644 --- a/parser/output/raylib_api.txt +++ b/parser/output/raylib_api.txt @@ -989,7 +989,7 @@ Callback 006: AudioCallback() (2 input parameters) Param[1]: bufferData (type: void *) Param[2]: frames (type: unsigned int) -Functions found: 579 +Functions found: 580 Function 001: InitWindow() (3 input parameters) Name: InitWindow @@ -1800,294 +1800,300 @@ Function 150: ComputeMD5() (2 input parameters) Description: Compute MD5 hash code, returns static int[4] (16 bytes) Param[1]: data (type: unsigned char *) Param[2]: dataSize (type: int) -Function 151: LoadAutomationEventList() (1 input parameters) +Function 151: ComputeSHA1() (2 input parameters) + Name: ComputeSHA1 + Return type: unsigned int * + Description: Compute SHA1 hash code, returns static int[5] (20 bytes) + Param[1]: data (type: unsigned char *) + Param[2]: dataSize (type: int) +Function 152: LoadAutomationEventList() (1 input parameters) Name: LoadAutomationEventList Return type: AutomationEventList Description: Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS Param[1]: fileName (type: const char *) -Function 152: UnloadAutomationEventList() (1 input parameters) +Function 153: UnloadAutomationEventList() (1 input parameters) Name: UnloadAutomationEventList Return type: void Description: Unload automation events list from file Param[1]: list (type: AutomationEventList) -Function 153: ExportAutomationEventList() (2 input parameters) +Function 154: ExportAutomationEventList() (2 input parameters) Name: ExportAutomationEventList Return type: bool Description: Export automation events list as text file Param[1]: list (type: AutomationEventList) Param[2]: fileName (type: const char *) -Function 154: SetAutomationEventList() (1 input parameters) +Function 155: SetAutomationEventList() (1 input parameters) Name: SetAutomationEventList Return type: void Description: Set automation event list to record to Param[1]: list (type: AutomationEventList *) -Function 155: SetAutomationEventBaseFrame() (1 input parameters) +Function 156: SetAutomationEventBaseFrame() (1 input parameters) Name: SetAutomationEventBaseFrame Return type: void Description: Set automation event internal base frame to start recording Param[1]: frame (type: int) -Function 156: StartAutomationEventRecording() (0 input parameters) +Function 157: StartAutomationEventRecording() (0 input parameters) Name: StartAutomationEventRecording Return type: void Description: Start recording automation events (AutomationEventList must be set) No input parameters -Function 157: StopAutomationEventRecording() (0 input parameters) +Function 158: StopAutomationEventRecording() (0 input parameters) Name: StopAutomationEventRecording Return type: void Description: Stop recording automation events No input parameters -Function 158: PlayAutomationEvent() (1 input parameters) +Function 159: PlayAutomationEvent() (1 input parameters) Name: PlayAutomationEvent Return type: void Description: Play a recorded automation event Param[1]: event (type: AutomationEvent) -Function 159: IsKeyPressed() (1 input parameters) +Function 160: IsKeyPressed() (1 input parameters) Name: IsKeyPressed Return type: bool Description: Check if a key has been pressed once Param[1]: key (type: int) -Function 160: IsKeyPressedRepeat() (1 input parameters) +Function 161: IsKeyPressedRepeat() (1 input parameters) Name: IsKeyPressedRepeat Return type: bool Description: Check if a key has been pressed again (Only PLATFORM_DESKTOP) Param[1]: key (type: int) -Function 161: IsKeyDown() (1 input parameters) +Function 162: IsKeyDown() (1 input parameters) Name: IsKeyDown Return type: bool Description: Check if a key is being pressed Param[1]: key (type: int) -Function 162: IsKeyReleased() (1 input parameters) +Function 163: IsKeyReleased() (1 input parameters) Name: IsKeyReleased Return type: bool Description: Check if a key has been released once Param[1]: key (type: int) -Function 163: IsKeyUp() (1 input parameters) +Function 164: IsKeyUp() (1 input parameters) Name: IsKeyUp Return type: bool Description: Check if a key is NOT being pressed Param[1]: key (type: int) -Function 164: GetKeyPressed() (0 input parameters) +Function 165: 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 165: GetCharPressed() (0 input parameters) +Function 166: 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 166: SetExitKey() (1 input parameters) +Function 167: 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 167: IsGamepadAvailable() (1 input parameters) +Function 168: IsGamepadAvailable() (1 input parameters) Name: IsGamepadAvailable Return type: bool Description: Check if a gamepad is available Param[1]: gamepad (type: int) -Function 168: GetGamepadName() (1 input parameters) +Function 169: GetGamepadName() (1 input parameters) Name: GetGamepadName Return type: const char * Description: Get gamepad internal name id Param[1]: gamepad (type: int) -Function 169: IsGamepadButtonPressed() (2 input parameters) +Function 170: 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 170: IsGamepadButtonDown() (2 input parameters) +Function 171: 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 171: IsGamepadButtonReleased() (2 input parameters) +Function 172: 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 172: IsGamepadButtonUp() (2 input parameters) +Function 173: 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 173: GetGamepadButtonPressed() (0 input parameters) +Function 174: GetGamepadButtonPressed() (0 input parameters) Name: GetGamepadButtonPressed Return type: int Description: Get the last gamepad button pressed No input parameters -Function 174: GetGamepadAxisCount() (1 input parameters) +Function 175: GetGamepadAxisCount() (1 input parameters) Name: GetGamepadAxisCount Return type: int Description: Get gamepad axis count for a gamepad Param[1]: gamepad (type: int) -Function 175: GetGamepadAxisMovement() (2 input parameters) +Function 176: 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 176: SetGamepadMappings() (1 input parameters) +Function 177: SetGamepadMappings() (1 input parameters) Name: SetGamepadMappings Return type: int Description: Set internal gamepad mappings (SDL_GameControllerDB) Param[1]: mappings (type: const char *) -Function 177: SetGamepadVibration() (3 input parameters) +Function 178: SetGamepadVibration() (3 input parameters) Name: SetGamepadVibration Return type: void Description: Set gamepad vibration for both motors Param[1]: gamepad (type: int) Param[2]: leftMotor (type: float) Param[3]: rightMotor (type: float) -Function 178: IsMouseButtonPressed() (1 input parameters) +Function 179: 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 179: IsMouseButtonDown() (1 input parameters) +Function 180: IsMouseButtonDown() (1 input parameters) Name: IsMouseButtonDown Return type: bool Description: Check if a mouse button is being pressed Param[1]: button (type: int) -Function 180: IsMouseButtonReleased() (1 input parameters) +Function 181: 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 181: IsMouseButtonUp() (1 input parameters) +Function 182: 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 182: GetMouseX() (0 input parameters) +Function 183: GetMouseX() (0 input parameters) Name: GetMouseX Return type: int Description: Get mouse position X No input parameters -Function 183: GetMouseY() (0 input parameters) +Function 184: GetMouseY() (0 input parameters) Name: GetMouseY Return type: int Description: Get mouse position Y No input parameters -Function 184: GetMousePosition() (0 input parameters) +Function 185: GetMousePosition() (0 input parameters) Name: GetMousePosition Return type: Vector2 Description: Get mouse position XY No input parameters -Function 185: GetMouseDelta() (0 input parameters) +Function 186: GetMouseDelta() (0 input parameters) Name: GetMouseDelta Return type: Vector2 Description: Get mouse delta between frames No input parameters -Function 186: SetMousePosition() (2 input parameters) +Function 187: 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 187: SetMouseOffset() (2 input parameters) +Function 188: SetMouseOffset() (2 input parameters) Name: SetMouseOffset Return type: void Description: Set mouse offset Param[1]: offsetX (type: int) Param[2]: offsetY (type: int) -Function 188: SetMouseScale() (2 input parameters) +Function 189: SetMouseScale() (2 input parameters) Name: SetMouseScale Return type: void Description: Set mouse scaling Param[1]: scaleX (type: float) Param[2]: scaleY (type: float) -Function 189: GetMouseWheelMove() (0 input parameters) +Function 190: 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 190: GetMouseWheelMoveV() (0 input parameters) +Function 191: GetMouseWheelMoveV() (0 input parameters) Name: GetMouseWheelMoveV Return type: Vector2 Description: Get mouse wheel movement for both X and Y No input parameters -Function 191: SetMouseCursor() (1 input parameters) +Function 192: SetMouseCursor() (1 input parameters) Name: SetMouseCursor Return type: void Description: Set mouse cursor Param[1]: cursor (type: int) -Function 192: GetTouchX() (0 input parameters) +Function 193: 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 193: GetTouchY() (0 input parameters) +Function 194: 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 194: GetTouchPosition() (1 input parameters) +Function 195: 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 195: GetTouchPointId() (1 input parameters) +Function 196: GetTouchPointId() (1 input parameters) Name: GetTouchPointId Return type: int Description: Get touch point identifier for given index Param[1]: index (type: int) -Function 196: GetTouchPointCount() (0 input parameters) +Function 197: GetTouchPointCount() (0 input parameters) Name: GetTouchPointCount Return type: int Description: Get number of touch points No input parameters -Function 197: SetGesturesEnabled() (1 input parameters) +Function 198: SetGesturesEnabled() (1 input parameters) Name: SetGesturesEnabled Return type: void Description: Enable a set of gestures using flags Param[1]: flags (type: unsigned int) -Function 198: IsGestureDetected() (1 input parameters) +Function 199: IsGestureDetected() (1 input parameters) Name: IsGestureDetected Return type: bool Description: Check if a gesture have been detected Param[1]: gesture (type: unsigned int) -Function 199: GetGestureDetected() (0 input parameters) +Function 200: GetGestureDetected() (0 input parameters) Name: GetGestureDetected Return type: int Description: Get latest detected gesture No input parameters -Function 200: GetGestureHoldDuration() (0 input parameters) +Function 201: GetGestureHoldDuration() (0 input parameters) Name: GetGestureHoldDuration Return type: float Description: Get gesture hold time in milliseconds No input parameters -Function 201: GetGestureDragVector() (0 input parameters) +Function 202: GetGestureDragVector() (0 input parameters) Name: GetGestureDragVector Return type: Vector2 Description: Get gesture drag vector No input parameters -Function 202: GetGestureDragAngle() (0 input parameters) +Function 203: GetGestureDragAngle() (0 input parameters) Name: GetGestureDragAngle Return type: float Description: Get gesture drag angle No input parameters -Function 203: GetGesturePinchVector() (0 input parameters) +Function 204: GetGesturePinchVector() (0 input parameters) Name: GetGesturePinchVector Return type: Vector2 Description: Get gesture pinch delta No input parameters -Function 204: GetGesturePinchAngle() (0 input parameters) +Function 205: GetGesturePinchAngle() (0 input parameters) Name: GetGesturePinchAngle Return type: float Description: Get gesture pinch angle No input parameters -Function 205: UpdateCamera() (2 input parameters) +Function 206: UpdateCamera() (2 input parameters) Name: UpdateCamera Return type: void Description: Update camera position for selected mode Param[1]: camera (type: Camera *) Param[2]: mode (type: int) -Function 206: UpdateCameraPro() (4 input parameters) +Function 207: UpdateCameraPro() (4 input parameters) Name: UpdateCameraPro Return type: void Description: Update camera movement/rotation @@ -2095,36 +2101,36 @@ Function 206: UpdateCameraPro() (4 input parameters) Param[2]: movement (type: Vector3) Param[3]: rotation (type: Vector3) Param[4]: zoom (type: float) -Function 207: SetShapesTexture() (2 input parameters) +Function 208: 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 208: GetShapesTexture() (0 input parameters) +Function 209: GetShapesTexture() (0 input parameters) Name: GetShapesTexture Return type: Texture2D Description: Get texture that is used for shapes drawing No input parameters -Function 209: GetShapesTextureRectangle() (0 input parameters) +Function 210: GetShapesTextureRectangle() (0 input parameters) Name: GetShapesTextureRectangle Return type: Rectangle Description: Get texture source rectangle that is used for shapes drawing No input parameters -Function 210: DrawPixel() (3 input parameters) +Function 211: DrawPixel() (3 input parameters) Name: DrawPixel Return type: void Description: Draw a pixel using geometry [Can be slow, use with care] Param[1]: posX (type: int) Param[2]: posY (type: int) Param[3]: color (type: Color) -Function 211: DrawPixelV() (2 input parameters) +Function 212: DrawPixelV() (2 input parameters) Name: DrawPixelV Return type: void Description: Draw a pixel using geometry (Vector version) [Can be slow, use with care] Param[1]: position (type: Vector2) Param[2]: color (type: Color) -Function 212: DrawLine() (5 input parameters) +Function 213: DrawLine() (5 input parameters) Name: DrawLine Return type: void Description: Draw a line @@ -2133,14 +2139,14 @@ Function 212: DrawLine() (5 input parameters) Param[3]: endPosX (type: int) Param[4]: endPosY (type: int) Param[5]: color (type: Color) -Function 213: DrawLineV() (3 input parameters) +Function 214: DrawLineV() (3 input parameters) Name: DrawLineV Return type: void Description: Draw a line (using gl lines) Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: color (type: Color) -Function 214: DrawLineEx() (4 input parameters) +Function 215: DrawLineEx() (4 input parameters) Name: DrawLineEx Return type: void Description: Draw a line (using triangles/quads) @@ -2148,14 +2154,14 @@ Function 214: DrawLineEx() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 215: DrawLineStrip() (3 input parameters) +Function 216: DrawLineStrip() (3 input parameters) Name: DrawLineStrip Return type: void Description: Draw lines sequence (using gl lines) Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 216: DrawLineBezier() (4 input parameters) +Function 217: DrawLineBezier() (4 input parameters) Name: DrawLineBezier Return type: void Description: Draw line segment cubic-bezier in-out interpolation @@ -2163,7 +2169,7 @@ Function 216: DrawLineBezier() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 217: DrawCircle() (4 input parameters) +Function 218: DrawCircle() (4 input parameters) Name: DrawCircle Return type: void Description: Draw a color-filled circle @@ -2171,7 +2177,7 @@ Function 217: DrawCircle() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 218: DrawCircleSector() (6 input parameters) +Function 219: DrawCircleSector() (6 input parameters) Name: DrawCircleSector Return type: void Description: Draw a piece of a circle @@ -2181,7 +2187,7 @@ Function 218: DrawCircleSector() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 219: DrawCircleSectorLines() (6 input parameters) +Function 220: DrawCircleSectorLines() (6 input parameters) Name: DrawCircleSectorLines Return type: void Description: Draw circle sector outline @@ -2191,7 +2197,7 @@ Function 219: DrawCircleSectorLines() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 220: DrawCircleGradient() (5 input parameters) +Function 221: DrawCircleGradient() (5 input parameters) Name: DrawCircleGradient Return type: void Description: Draw a gradient-filled circle @@ -2200,14 +2206,14 @@ Function 220: DrawCircleGradient() (5 input parameters) Param[3]: radius (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 221: DrawCircleV() (3 input parameters) +Function 222: 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 222: DrawCircleLines() (4 input parameters) +Function 223: DrawCircleLines() (4 input parameters) Name: DrawCircleLines Return type: void Description: Draw circle outline @@ -2215,14 +2221,14 @@ Function 222: DrawCircleLines() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 223: DrawCircleLinesV() (3 input parameters) +Function 224: DrawCircleLinesV() (3 input parameters) Name: DrawCircleLinesV Return type: void Description: Draw circle outline (Vector version) Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 224: DrawEllipse() (5 input parameters) +Function 225: DrawEllipse() (5 input parameters) Name: DrawEllipse Return type: void Description: Draw ellipse @@ -2231,7 +2237,7 @@ Function 224: DrawEllipse() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 225: DrawEllipseLines() (5 input parameters) +Function 226: DrawEllipseLines() (5 input parameters) Name: DrawEllipseLines Return type: void Description: Draw ellipse outline @@ -2240,7 +2246,7 @@ Function 225: DrawEllipseLines() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 226: DrawRing() (7 input parameters) +Function 227: DrawRing() (7 input parameters) Name: DrawRing Return type: void Description: Draw ring @@ -2251,7 +2257,7 @@ Function 226: DrawRing() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 227: DrawRingLines() (7 input parameters) +Function 228: DrawRingLines() (7 input parameters) Name: DrawRingLines Return type: void Description: Draw ring outline @@ -2262,7 +2268,7 @@ Function 227: DrawRingLines() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 228: DrawRectangle() (5 input parameters) +Function 229: DrawRectangle() (5 input parameters) Name: DrawRectangle Return type: void Description: Draw a color-filled rectangle @@ -2271,20 +2277,20 @@ Function 228: DrawRectangle() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 229: DrawRectangleV() (3 input parameters) +Function 230: 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 230: DrawRectangleRec() (2 input parameters) +Function 231: 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 231: DrawRectanglePro() (4 input parameters) +Function 232: DrawRectanglePro() (4 input parameters) Name: DrawRectanglePro Return type: void Description: Draw a color-filled rectangle with pro parameters @@ -2292,7 +2298,7 @@ Function 231: DrawRectanglePro() (4 input parameters) Param[2]: origin (type: Vector2) Param[3]: rotation (type: float) Param[4]: color (type: Color) -Function 232: DrawRectangleGradientV() (6 input parameters) +Function 233: DrawRectangleGradientV() (6 input parameters) Name: DrawRectangleGradientV Return type: void Description: Draw a vertical-gradient-filled rectangle @@ -2302,7 +2308,7 @@ Function 232: DrawRectangleGradientV() (6 input parameters) Param[4]: height (type: int) Param[5]: top (type: Color) Param[6]: bottom (type: Color) -Function 233: DrawRectangleGradientH() (6 input parameters) +Function 234: DrawRectangleGradientH() (6 input parameters) Name: DrawRectangleGradientH Return type: void Description: Draw a horizontal-gradient-filled rectangle @@ -2312,7 +2318,7 @@ Function 233: DrawRectangleGradientH() (6 input parameters) Param[4]: height (type: int) Param[5]: left (type: Color) Param[6]: right (type: Color) -Function 234: DrawRectangleGradientEx() (5 input parameters) +Function 235: DrawRectangleGradientEx() (5 input parameters) Name: DrawRectangleGradientEx Return type: void Description: Draw a gradient-filled rectangle with custom vertex colors @@ -2321,7 +2327,7 @@ Function 234: DrawRectangleGradientEx() (5 input parameters) Param[3]: bottomLeft (type: Color) Param[4]: topRight (type: Color) Param[5]: bottomRight (type: Color) -Function 235: DrawRectangleLines() (5 input parameters) +Function 236: DrawRectangleLines() (5 input parameters) Name: DrawRectangleLines Return type: void Description: Draw rectangle outline @@ -2330,14 +2336,14 @@ Function 235: DrawRectangleLines() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 236: DrawRectangleLinesEx() (3 input parameters) +Function 237: 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 237: DrawRectangleRounded() (4 input parameters) +Function 238: DrawRectangleRounded() (4 input parameters) Name: DrawRectangleRounded Return type: void Description: Draw rectangle with rounded edges @@ -2345,7 +2351,7 @@ Function 237: DrawRectangleRounded() (4 input parameters) Param[2]: roundness (type: float) Param[3]: segments (type: int) Param[4]: color (type: Color) -Function 238: DrawRectangleRoundedLines() (4 input parameters) +Function 239: DrawRectangleRoundedLines() (4 input parameters) Name: DrawRectangleRoundedLines Return type: void Description: Draw rectangle lines with rounded edges @@ -2353,7 +2359,7 @@ Function 238: DrawRectangleRoundedLines() (4 input parameters) Param[2]: roundness (type: float) Param[3]: segments (type: int) Param[4]: color (type: Color) -Function 239: DrawRectangleRoundedLinesEx() (5 input parameters) +Function 240: DrawRectangleRoundedLinesEx() (5 input parameters) Name: DrawRectangleRoundedLinesEx Return type: void Description: Draw rectangle with rounded edges outline @@ -2362,7 +2368,7 @@ Function 239: DrawRectangleRoundedLinesEx() (5 input parameters) Param[3]: segments (type: int) Param[4]: lineThick (type: float) Param[5]: color (type: Color) -Function 240: DrawTriangle() (4 input parameters) +Function 241: DrawTriangle() (4 input parameters) Name: DrawTriangle Return type: void Description: Draw a color-filled triangle (vertex in counter-clockwise order!) @@ -2370,7 +2376,7 @@ Function 240: DrawTriangle() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 241: DrawTriangleLines() (4 input parameters) +Function 242: DrawTriangleLines() (4 input parameters) Name: DrawTriangleLines Return type: void Description: Draw triangle outline (vertex in counter-clockwise order!) @@ -2378,21 +2384,21 @@ Function 241: DrawTriangleLines() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 242: DrawTriangleFan() (3 input parameters) +Function 243: DrawTriangleFan() (3 input parameters) Name: DrawTriangleFan Return type: void Description: Draw a triangle fan defined by points (first vertex is the center) Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 243: DrawTriangleStrip() (3 input parameters) +Function 244: DrawTriangleStrip() (3 input parameters) Name: DrawTriangleStrip Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 244: DrawPoly() (5 input parameters) +Function 245: DrawPoly() (5 input parameters) Name: DrawPoly Return type: void Description: Draw a regular polygon (Vector version) @@ -2401,7 +2407,7 @@ Function 244: DrawPoly() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 245: DrawPolyLines() (5 input parameters) +Function 246: DrawPolyLines() (5 input parameters) Name: DrawPolyLines Return type: void Description: Draw a polygon outline of n sides @@ -2410,7 +2416,7 @@ Function 245: DrawPolyLines() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 246: DrawPolyLinesEx() (6 input parameters) +Function 247: DrawPolyLinesEx() (6 input parameters) Name: DrawPolyLinesEx Return type: void Description: Draw a polygon outline of n sides with extended parameters @@ -2420,7 +2426,7 @@ Function 246: DrawPolyLinesEx() (6 input parameters) Param[4]: rotation (type: float) Param[5]: lineThick (type: float) Param[6]: color (type: Color) -Function 247: DrawSplineLinear() (4 input parameters) +Function 248: DrawSplineLinear() (4 input parameters) Name: DrawSplineLinear Return type: void Description: Draw spline: Linear, minimum 2 points @@ -2428,7 +2434,7 @@ Function 247: DrawSplineLinear() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 248: DrawSplineBasis() (4 input parameters) +Function 249: DrawSplineBasis() (4 input parameters) Name: DrawSplineBasis Return type: void Description: Draw spline: B-Spline, minimum 4 points @@ -2436,7 +2442,7 @@ Function 248: DrawSplineBasis() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 249: DrawSplineCatmullRom() (4 input parameters) +Function 250: DrawSplineCatmullRom() (4 input parameters) Name: DrawSplineCatmullRom Return type: void Description: Draw spline: Catmull-Rom, minimum 4 points @@ -2444,7 +2450,7 @@ Function 249: DrawSplineCatmullRom() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 250: DrawSplineBezierQuadratic() (4 input parameters) +Function 251: DrawSplineBezierQuadratic() (4 input parameters) Name: DrawSplineBezierQuadratic Return type: void Description: Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...] @@ -2452,7 +2458,7 @@ Function 250: DrawSplineBezierQuadratic() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 251: DrawSplineBezierCubic() (4 input parameters) +Function 252: DrawSplineBezierCubic() (4 input parameters) Name: DrawSplineBezierCubic Return type: void Description: Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...] @@ -2460,7 +2466,7 @@ Function 251: DrawSplineBezierCubic() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 252: DrawSplineSegmentLinear() (4 input parameters) +Function 253: DrawSplineSegmentLinear() (4 input parameters) Name: DrawSplineSegmentLinear Return type: void Description: Draw spline segment: Linear, 2 points @@ -2468,7 +2474,7 @@ Function 252: DrawSplineSegmentLinear() (4 input parameters) Param[2]: p2 (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 253: DrawSplineSegmentBasis() (6 input parameters) +Function 254: DrawSplineSegmentBasis() (6 input parameters) Name: DrawSplineSegmentBasis Return type: void Description: Draw spline segment: B-Spline, 4 points @@ -2478,7 +2484,7 @@ Function 253: DrawSplineSegmentBasis() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 254: DrawSplineSegmentCatmullRom() (6 input parameters) +Function 255: DrawSplineSegmentCatmullRom() (6 input parameters) Name: DrawSplineSegmentCatmullRom Return type: void Description: Draw spline segment: Catmull-Rom, 4 points @@ -2488,7 +2494,7 @@ Function 254: DrawSplineSegmentCatmullRom() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 255: DrawSplineSegmentBezierQuadratic() (5 input parameters) +Function 256: DrawSplineSegmentBezierQuadratic() (5 input parameters) Name: DrawSplineSegmentBezierQuadratic Return type: void Description: Draw spline segment: Quadratic Bezier, 2 points, 1 control point @@ -2497,7 +2503,7 @@ Function 255: DrawSplineSegmentBezierQuadratic() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: thick (type: float) Param[5]: color (type: Color) -Function 256: DrawSplineSegmentBezierCubic() (6 input parameters) +Function 257: DrawSplineSegmentBezierCubic() (6 input parameters) Name: DrawSplineSegmentBezierCubic Return type: void Description: Draw spline segment: Cubic Bezier, 2 points, 2 control points @@ -2507,14 +2513,14 @@ Function 256: DrawSplineSegmentBezierCubic() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 257: GetSplinePointLinear() (3 input parameters) +Function 258: GetSplinePointLinear() (3 input parameters) Name: GetSplinePointLinear Return type: Vector2 Description: Get (evaluate) spline point: Linear Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: t (type: float) -Function 258: GetSplinePointBasis() (5 input parameters) +Function 259: GetSplinePointBasis() (5 input parameters) Name: GetSplinePointBasis Return type: Vector2 Description: Get (evaluate) spline point: B-Spline @@ -2523,7 +2529,7 @@ Function 258: GetSplinePointBasis() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 259: GetSplinePointCatmullRom() (5 input parameters) +Function 260: GetSplinePointCatmullRom() (5 input parameters) Name: GetSplinePointCatmullRom Return type: Vector2 Description: Get (evaluate) spline point: Catmull-Rom @@ -2532,7 +2538,7 @@ Function 259: GetSplinePointCatmullRom() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 260: GetSplinePointBezierQuad() (4 input parameters) +Function 261: GetSplinePointBezierQuad() (4 input parameters) Name: GetSplinePointBezierQuad Return type: Vector2 Description: Get (evaluate) spline point: Quadratic Bezier @@ -2540,7 +2546,7 @@ Function 260: GetSplinePointBezierQuad() (4 input parameters) Param[2]: c2 (type: Vector2) Param[3]: p3 (type: Vector2) Param[4]: t (type: float) -Function 261: GetSplinePointBezierCubic() (5 input parameters) +Function 262: GetSplinePointBezierCubic() (5 input parameters) Name: GetSplinePointBezierCubic Return type: Vector2 Description: Get (evaluate) spline point: Cubic Bezier @@ -2549,13 +2555,13 @@ Function 261: GetSplinePointBezierCubic() (5 input parameters) Param[3]: c3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 262: CheckCollisionRecs() (2 input parameters) +Function 263: 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 263: CheckCollisionCircles() (4 input parameters) +Function 264: CheckCollisionCircles() (4 input parameters) Name: CheckCollisionCircles Return type: bool Description: Check collision between two circles @@ -2563,27 +2569,27 @@ Function 263: CheckCollisionCircles() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector2) Param[4]: radius2 (type: float) -Function 264: CheckCollisionCircleRec() (3 input parameters) +Function 265: 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 265: CheckCollisionPointRec() (2 input parameters) +Function 266: 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 266: CheckCollisionPointCircle() (3 input parameters) +Function 267: 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 267: CheckCollisionPointTriangle() (4 input parameters) +Function 268: CheckCollisionPointTriangle() (4 input parameters) Name: CheckCollisionPointTriangle Return type: bool Description: Check if point is inside a triangle @@ -2591,14 +2597,14 @@ Function 267: CheckCollisionPointTriangle() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: p3 (type: Vector2) -Function 268: CheckCollisionPointPoly() (3 input parameters) +Function 269: CheckCollisionPointPoly() (3 input parameters) Name: CheckCollisionPointPoly Return type: bool Description: Check if point is within a polygon described by array of vertices Param[1]: point (type: Vector2) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) -Function 269: CheckCollisionLines() (5 input parameters) +Function 270: 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 @@ -2607,7 +2613,7 @@ Function 269: CheckCollisionLines() (5 input parameters) Param[3]: startPos2 (type: Vector2) Param[4]: endPos2 (type: Vector2) Param[5]: collisionPoint (type: Vector2 *) -Function 270: CheckCollisionPointLine() (4 input parameters) +Function 271: 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] @@ -2615,7 +2621,7 @@ Function 270: CheckCollisionPointLine() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: threshold (type: int) -Function 271: CheckCollisionCircleLine() (4 input parameters) +Function 272: CheckCollisionCircleLine() (4 input parameters) Name: CheckCollisionCircleLine Return type: bool Description: Check if circle collides with a line created betweeen two points [p1] and [p2] @@ -2623,18 +2629,18 @@ Function 271: CheckCollisionCircleLine() (4 input parameters) Param[2]: radius (type: float) Param[3]: p1 (type: Vector2) Param[4]: p2 (type: Vector2) -Function 272: GetCollisionRec() (2 input parameters) +Function 273: 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 273: LoadImage() (1 input parameters) +Function 274: 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 274: LoadImageRaw() (5 input parameters) +Function 275: LoadImageRaw() (5 input parameters) Name: LoadImageRaw Return type: Image Description: Load image from RAW file data @@ -2643,13 +2649,13 @@ Function 274: LoadImageRaw() (5 input parameters) Param[3]: height (type: int) Param[4]: format (type: int) Param[5]: headerSize (type: int) -Function 275: LoadImageAnim() (2 input parameters) +Function 276: 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 276: LoadImageAnimFromMemory() (4 input parameters) +Function 277: LoadImageAnimFromMemory() (4 input parameters) Name: LoadImageAnimFromMemory Return type: Image Description: Load image sequence from memory buffer @@ -2657,60 +2663,60 @@ Function 276: LoadImageAnimFromMemory() (4 input parameters) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) Param[4]: frames (type: int *) -Function 277: LoadImageFromMemory() (3 input parameters) +Function 278: 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 278: LoadImageFromTexture() (1 input parameters) +Function 279: LoadImageFromTexture() (1 input parameters) Name: LoadImageFromTexture Return type: Image Description: Load image from GPU texture data Param[1]: texture (type: Texture2D) -Function 279: LoadImageFromScreen() (0 input parameters) +Function 280: LoadImageFromScreen() (0 input parameters) Name: LoadImageFromScreen Return type: Image Description: Load image from screen buffer and (screenshot) No input parameters -Function 280: IsImageValid() (1 input parameters) +Function 281: IsImageValid() (1 input parameters) Name: IsImageValid Return type: bool Description: Check if an image is valid (data and parameters) Param[1]: image (type: Image) -Function 281: UnloadImage() (1 input parameters) +Function 282: UnloadImage() (1 input parameters) Name: UnloadImage Return type: void Description: Unload image from CPU memory (RAM) Param[1]: image (type: Image) -Function 282: ExportImage() (2 input parameters) +Function 283: 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 283: ExportImageToMemory() (3 input parameters) +Function 284: ExportImageToMemory() (3 input parameters) Name: ExportImageToMemory Return type: unsigned char * Description: Export image to memory buffer Param[1]: image (type: Image) Param[2]: fileType (type: const char *) Param[3]: fileSize (type: int *) -Function 284: ExportImageAsCode() (2 input parameters) +Function 285: 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 285: GenImageColor() (3 input parameters) +Function 286: 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 286: GenImageGradientLinear() (5 input parameters) +Function 287: GenImageGradientLinear() (5 input parameters) Name: GenImageGradientLinear Return type: Image Description: Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient @@ -2719,7 +2725,7 @@ Function 286: GenImageGradientLinear() (5 input parameters) Param[3]: direction (type: int) Param[4]: start (type: Color) Param[5]: end (type: Color) -Function 287: GenImageGradientRadial() (5 input parameters) +Function 288: GenImageGradientRadial() (5 input parameters) Name: GenImageGradientRadial Return type: Image Description: Generate image: radial gradient @@ -2728,7 +2734,7 @@ Function 287: GenImageGradientRadial() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 288: GenImageGradientSquare() (5 input parameters) +Function 289: GenImageGradientSquare() (5 input parameters) Name: GenImageGradientSquare Return type: Image Description: Generate image: square gradient @@ -2737,7 +2743,7 @@ Function 288: GenImageGradientSquare() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 289: GenImageChecked() (6 input parameters) +Function 290: GenImageChecked() (6 input parameters) Name: GenImageChecked Return type: Image Description: Generate image: checked @@ -2747,14 +2753,14 @@ Function 289: GenImageChecked() (6 input parameters) Param[4]: checksY (type: int) Param[5]: col1 (type: Color) Param[6]: col2 (type: Color) -Function 290: GenImageWhiteNoise() (3 input parameters) +Function 291: 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 291: GenImagePerlinNoise() (5 input parameters) +Function 292: GenImagePerlinNoise() (5 input parameters) Name: GenImagePerlinNoise Return type: Image Description: Generate image: perlin noise @@ -2763,45 +2769,45 @@ Function 291: GenImagePerlinNoise() (5 input parameters) Param[3]: offsetX (type: int) Param[4]: offsetY (type: int) Param[5]: scale (type: float) -Function 292: GenImageCellular() (3 input parameters) +Function 293: 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 293: GenImageText() (3 input parameters) +Function 294: 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 294: ImageCopy() (1 input parameters) +Function 295: ImageCopy() (1 input parameters) Name: ImageCopy Return type: Image Description: Create an image duplicate (useful for transformations) Param[1]: image (type: Image) -Function 295: ImageFromImage() (2 input parameters) +Function 296: ImageFromImage() (2 input parameters) Name: ImageFromImage Return type: Image Description: Create an image from another image piece Param[1]: image (type: Image) Param[2]: rec (type: Rectangle) -Function 296: ImageFromChannel() (2 input parameters) +Function 297: ImageFromChannel() (2 input parameters) Name: ImageFromChannel Return type: Image Description: Create an image from a selected channel of another image (GRAYSCALE) Param[1]: image (type: Image) Param[2]: selectedChannel (type: int) -Function 297: ImageText() (3 input parameters) +Function 298: ImageText() (3 input parameters) Name: ImageText Return type: Image Description: Create an image from text (default font) Param[1]: text (type: const char *) Param[2]: fontSize (type: int) Param[3]: color (type: Color) -Function 298: ImageTextEx() (5 input parameters) +Function 299: ImageTextEx() (5 input parameters) Name: ImageTextEx Return type: Image Description: Create an image from text (custom sprite font) @@ -2810,76 +2816,76 @@ Function 298: ImageTextEx() (5 input parameters) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) Param[5]: tint (type: Color) -Function 299: ImageFormat() (2 input parameters) +Function 300: ImageFormat() (2 input parameters) Name: ImageFormat Return type: void Description: Convert image data to desired format Param[1]: image (type: Image *) Param[2]: newFormat (type: int) -Function 300: ImageToPOT() (2 input parameters) +Function 301: ImageToPOT() (2 input parameters) Name: ImageToPOT Return type: void Description: Convert image to POT (power-of-two) Param[1]: image (type: Image *) Param[2]: fill (type: Color) -Function 301: ImageCrop() (2 input parameters) +Function 302: ImageCrop() (2 input parameters) Name: ImageCrop Return type: void Description: Crop an image to a defined rectangle Param[1]: image (type: Image *) Param[2]: crop (type: Rectangle) -Function 302: ImageAlphaCrop() (2 input parameters) +Function 303: ImageAlphaCrop() (2 input parameters) Name: ImageAlphaCrop Return type: void Description: Crop image depending on alpha value Param[1]: image (type: Image *) Param[2]: threshold (type: float) -Function 303: ImageAlphaClear() (3 input parameters) +Function 304: ImageAlphaClear() (3 input parameters) Name: ImageAlphaClear Return type: void Description: Clear alpha channel to desired color Param[1]: image (type: Image *) Param[2]: color (type: Color) Param[3]: threshold (type: float) -Function 304: ImageAlphaMask() (2 input parameters) +Function 305: ImageAlphaMask() (2 input parameters) Name: ImageAlphaMask Return type: void Description: Apply alpha mask to image Param[1]: image (type: Image *) Param[2]: alphaMask (type: Image) -Function 305: ImageAlphaPremultiply() (1 input parameters) +Function 306: ImageAlphaPremultiply() (1 input parameters) Name: ImageAlphaPremultiply Return type: void Description: Premultiply alpha channel Param[1]: image (type: Image *) -Function 306: ImageBlurGaussian() (2 input parameters) +Function 307: 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 307: ImageKernelConvolution() (3 input parameters) +Function 308: ImageKernelConvolution() (3 input parameters) Name: ImageKernelConvolution Return type: void Description: Apply custom square convolution kernel to image Param[1]: image (type: Image *) Param[2]: kernel (type: const float *) Param[3]: kernelSize (type: int) -Function 308: ImageResize() (3 input parameters) +Function 309: 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 309: ImageResizeNN() (3 input parameters) +Function 310: 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 310: ImageResizeCanvas() (6 input parameters) +Function 311: ImageResizeCanvas() (6 input parameters) Name: ImageResizeCanvas Return type: void Description: Resize canvas and fill with color @@ -2889,12 +2895,12 @@ Function 310: ImageResizeCanvas() (6 input parameters) Param[4]: offsetX (type: int) Param[5]: offsetY (type: int) Param[6]: fill (type: Color) -Function 311: ImageMipmaps() (1 input parameters) +Function 312: ImageMipmaps() (1 input parameters) Name: ImageMipmaps Return type: void Description: Compute all mipmap levels for a provided image Param[1]: image (type: Image *) -Function 312: ImageDither() (5 input parameters) +Function 313: ImageDither() (5 input parameters) Name: ImageDither Return type: void Description: Dither image data to 16bpp or lower (Floyd-Steinberg dithering) @@ -2903,109 +2909,109 @@ Function 312: ImageDither() (5 input parameters) Param[3]: gBpp (type: int) Param[4]: bBpp (type: int) Param[5]: aBpp (type: int) -Function 313: ImageFlipVertical() (1 input parameters) +Function 314: ImageFlipVertical() (1 input parameters) Name: ImageFlipVertical Return type: void Description: Flip image vertically Param[1]: image (type: Image *) -Function 314: ImageFlipHorizontal() (1 input parameters) +Function 315: ImageFlipHorizontal() (1 input parameters) Name: ImageFlipHorizontal Return type: void Description: Flip image horizontally Param[1]: image (type: Image *) -Function 315: ImageRotate() (2 input parameters) +Function 316: ImageRotate() (2 input parameters) Name: ImageRotate Return type: void Description: Rotate image by input angle in degrees (-359 to 359) Param[1]: image (type: Image *) Param[2]: degrees (type: int) -Function 316: ImageRotateCW() (1 input parameters) +Function 317: ImageRotateCW() (1 input parameters) Name: ImageRotateCW Return type: void Description: Rotate image clockwise 90deg Param[1]: image (type: Image *) -Function 317: ImageRotateCCW() (1 input parameters) +Function 318: ImageRotateCCW() (1 input parameters) Name: ImageRotateCCW Return type: void Description: Rotate image counter-clockwise 90deg Param[1]: image (type: Image *) -Function 318: ImageColorTint() (2 input parameters) +Function 319: 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 319: ImageColorInvert() (1 input parameters) +Function 320: ImageColorInvert() (1 input parameters) Name: ImageColorInvert Return type: void Description: Modify image color: invert Param[1]: image (type: Image *) -Function 320: ImageColorGrayscale() (1 input parameters) +Function 321: ImageColorGrayscale() (1 input parameters) Name: ImageColorGrayscale Return type: void Description: Modify image color: grayscale Param[1]: image (type: Image *) -Function 321: ImageColorContrast() (2 input parameters) +Function 322: 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 322: ImageColorBrightness() (2 input parameters) +Function 323: 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 323: ImageColorReplace() (3 input parameters) +Function 324: 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 324: LoadImageColors() (1 input parameters) +Function 325: 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 325: LoadImagePalette() (3 input parameters) +Function 326: 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 326: UnloadImageColors() (1 input parameters) +Function 327: UnloadImageColors() (1 input parameters) Name: UnloadImageColors Return type: void Description: Unload color data loaded with LoadImageColors() Param[1]: colors (type: Color *) -Function 327: UnloadImagePalette() (1 input parameters) +Function 328: UnloadImagePalette() (1 input parameters) Name: UnloadImagePalette Return type: void Description: Unload colors palette loaded with LoadImagePalette() Param[1]: colors (type: Color *) -Function 328: GetImageAlphaBorder() (2 input parameters) +Function 329: 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 329: GetImageColor() (3 input parameters) +Function 330: 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 330: ImageClearBackground() (2 input parameters) +Function 331: 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 331: ImageDrawPixel() (4 input parameters) +Function 332: ImageDrawPixel() (4 input parameters) Name: ImageDrawPixel Return type: void Description: Draw pixel within an image @@ -3013,14 +3019,14 @@ Function 331: ImageDrawPixel() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: color (type: Color) -Function 332: ImageDrawPixelV() (3 input parameters) +Function 333: 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 333: ImageDrawLine() (6 input parameters) +Function 334: ImageDrawLine() (6 input parameters) Name: ImageDrawLine Return type: void Description: Draw line within an image @@ -3030,7 +3036,7 @@ Function 333: ImageDrawLine() (6 input parameters) Param[4]: endPosX (type: int) Param[5]: endPosY (type: int) Param[6]: color (type: Color) -Function 334: ImageDrawLineV() (4 input parameters) +Function 335: ImageDrawLineV() (4 input parameters) Name: ImageDrawLineV Return type: void Description: Draw line within an image (Vector version) @@ -3038,7 +3044,7 @@ Function 334: ImageDrawLineV() (4 input parameters) Param[2]: start (type: Vector2) Param[3]: end (type: Vector2) Param[4]: color (type: Color) -Function 335: ImageDrawLineEx() (5 input parameters) +Function 336: ImageDrawLineEx() (5 input parameters) Name: ImageDrawLineEx Return type: void Description: Draw a line defining thickness within an image @@ -3047,7 +3053,7 @@ Function 335: ImageDrawLineEx() (5 input parameters) Param[3]: end (type: Vector2) Param[4]: thick (type: int) Param[5]: color (type: Color) -Function 336: ImageDrawCircle() (5 input parameters) +Function 337: ImageDrawCircle() (5 input parameters) Name: ImageDrawCircle Return type: void Description: Draw a filled circle within an image @@ -3056,7 +3062,7 @@ Function 336: ImageDrawCircle() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 337: ImageDrawCircleV() (4 input parameters) +Function 338: ImageDrawCircleV() (4 input parameters) Name: ImageDrawCircleV Return type: void Description: Draw a filled circle within an image (Vector version) @@ -3064,7 +3070,7 @@ Function 337: ImageDrawCircleV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 338: ImageDrawCircleLines() (5 input parameters) +Function 339: ImageDrawCircleLines() (5 input parameters) Name: ImageDrawCircleLines Return type: void Description: Draw circle outline within an image @@ -3073,7 +3079,7 @@ Function 338: ImageDrawCircleLines() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 339: ImageDrawCircleLinesV() (4 input parameters) +Function 340: ImageDrawCircleLinesV() (4 input parameters) Name: ImageDrawCircleLinesV Return type: void Description: Draw circle outline within an image (Vector version) @@ -3081,7 +3087,7 @@ Function 339: ImageDrawCircleLinesV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 340: ImageDrawRectangle() (6 input parameters) +Function 341: ImageDrawRectangle() (6 input parameters) Name: ImageDrawRectangle Return type: void Description: Draw rectangle within an image @@ -3091,7 +3097,7 @@ Function 340: ImageDrawRectangle() (6 input parameters) Param[4]: width (type: int) Param[5]: height (type: int) Param[6]: color (type: Color) -Function 341: ImageDrawRectangleV() (4 input parameters) +Function 342: ImageDrawRectangleV() (4 input parameters) Name: ImageDrawRectangleV Return type: void Description: Draw rectangle within an image (Vector version) @@ -3099,14 +3105,14 @@ Function 341: ImageDrawRectangleV() (4 input parameters) Param[2]: position (type: Vector2) Param[3]: size (type: Vector2) Param[4]: color (type: Color) -Function 342: ImageDrawRectangleRec() (3 input parameters) +Function 343: 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 343: ImageDrawRectangleLines() (4 input parameters) +Function 344: ImageDrawRectangleLines() (4 input parameters) Name: ImageDrawRectangleLines Return type: void Description: Draw rectangle lines within an image @@ -3114,7 +3120,7 @@ Function 343: ImageDrawRectangleLines() (4 input parameters) Param[2]: rec (type: Rectangle) Param[3]: thick (type: int) Param[4]: color (type: Color) -Function 344: ImageDrawTriangle() (5 input parameters) +Function 345: ImageDrawTriangle() (5 input parameters) Name: ImageDrawTriangle Return type: void Description: Draw triangle within an image @@ -3123,7 +3129,7 @@ Function 344: ImageDrawTriangle() (5 input parameters) Param[3]: v2 (type: Vector2) Param[4]: v3 (type: Vector2) Param[5]: color (type: Color) -Function 345: ImageDrawTriangleEx() (7 input parameters) +Function 346: ImageDrawTriangleEx() (7 input parameters) Name: ImageDrawTriangleEx Return type: void Description: Draw triangle with interpolated colors within an image @@ -3134,7 +3140,7 @@ Function 345: ImageDrawTriangleEx() (7 input parameters) Param[5]: c1 (type: Color) Param[6]: c2 (type: Color) Param[7]: c3 (type: Color) -Function 346: ImageDrawTriangleLines() (5 input parameters) +Function 347: ImageDrawTriangleLines() (5 input parameters) Name: ImageDrawTriangleLines Return type: void Description: Draw triangle outline within an image @@ -3143,7 +3149,7 @@ Function 346: ImageDrawTriangleLines() (5 input parameters) Param[3]: v2 (type: Vector2) Param[4]: v3 (type: Vector2) Param[5]: color (type: Color) -Function 347: ImageDrawTriangleFan() (4 input parameters) +Function 348: ImageDrawTriangleFan() (4 input parameters) Name: ImageDrawTriangleFan Return type: void Description: Draw a triangle fan defined by points within an image (first vertex is the center) @@ -3151,7 +3157,7 @@ Function 347: ImageDrawTriangleFan() (4 input parameters) Param[2]: points (type: Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 348: ImageDrawTriangleStrip() (4 input parameters) +Function 349: ImageDrawTriangleStrip() (4 input parameters) Name: ImageDrawTriangleStrip Return type: void Description: Draw a triangle strip defined by points within an image @@ -3159,7 +3165,7 @@ Function 348: ImageDrawTriangleStrip() (4 input parameters) Param[2]: points (type: Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 349: ImageDraw() (5 input parameters) +Function 350: ImageDraw() (5 input parameters) Name: ImageDraw Return type: void Description: Draw a source image within a destination image (tint applied to source) @@ -3168,7 +3174,7 @@ Function 349: ImageDraw() (5 input parameters) Param[3]: srcRec (type: Rectangle) Param[4]: dstRec (type: Rectangle) Param[5]: tint (type: Color) -Function 350: ImageDrawText() (6 input parameters) +Function 351: ImageDrawText() (6 input parameters) Name: ImageDrawText Return type: void Description: Draw text (using default font) within an image (destination) @@ -3178,7 +3184,7 @@ Function 350: ImageDrawText() (6 input parameters) Param[4]: posY (type: int) Param[5]: fontSize (type: int) Param[6]: color (type: Color) -Function 351: ImageDrawTextEx() (7 input parameters) +Function 352: ImageDrawTextEx() (7 input parameters) Name: ImageDrawTextEx Return type: void Description: Draw text (custom sprite font) within an image (destination) @@ -3189,79 +3195,79 @@ Function 351: ImageDrawTextEx() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 352: LoadTexture() (1 input parameters) +Function 353: 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 353: LoadTextureFromImage() (1 input parameters) +Function 354: LoadTextureFromImage() (1 input parameters) Name: LoadTextureFromImage Return type: Texture2D Description: Load texture from image data Param[1]: image (type: Image) -Function 354: LoadTextureCubemap() (2 input parameters) +Function 355: 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 355: LoadRenderTexture() (2 input parameters) +Function 356: 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 356: IsTextureValid() (1 input parameters) +Function 357: IsTextureValid() (1 input parameters) Name: IsTextureValid Return type: bool Description: Check if a texture is valid (loaded in GPU) Param[1]: texture (type: Texture2D) -Function 357: UnloadTexture() (1 input parameters) +Function 358: UnloadTexture() (1 input parameters) Name: UnloadTexture Return type: void Description: Unload texture from GPU memory (VRAM) Param[1]: texture (type: Texture2D) -Function 358: IsRenderTextureValid() (1 input parameters) +Function 359: IsRenderTextureValid() (1 input parameters) Name: IsRenderTextureValid Return type: bool Description: Check if a render texture is valid (loaded in GPU) Param[1]: target (type: RenderTexture2D) -Function 359: UnloadRenderTexture() (1 input parameters) +Function 360: UnloadRenderTexture() (1 input parameters) Name: UnloadRenderTexture Return type: void Description: Unload render texture from GPU memory (VRAM) Param[1]: target (type: RenderTexture2D) -Function 360: UpdateTexture() (2 input parameters) +Function 361: 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 361: UpdateTextureRec() (3 input parameters) +Function 362: 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 362: GenTextureMipmaps() (1 input parameters) +Function 363: GenTextureMipmaps() (1 input parameters) Name: GenTextureMipmaps Return type: void Description: Generate GPU mipmaps for a texture Param[1]: texture (type: Texture2D *) -Function 363: SetTextureFilter() (2 input parameters) +Function 364: 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 364: SetTextureWrap() (2 input parameters) +Function 365: 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 365: DrawTexture() (4 input parameters) +Function 366: DrawTexture() (4 input parameters) Name: DrawTexture Return type: void Description: Draw a Texture2D @@ -3269,14 +3275,14 @@ Function 365: DrawTexture() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: tint (type: Color) -Function 366: DrawTextureV() (3 input parameters) +Function 367: 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 367: DrawTextureEx() (5 input parameters) +Function 368: DrawTextureEx() (5 input parameters) Name: DrawTextureEx Return type: void Description: Draw a Texture2D with extended parameters @@ -3285,7 +3291,7 @@ Function 367: DrawTextureEx() (5 input parameters) Param[3]: rotation (type: float) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 368: DrawTextureRec() (4 input parameters) +Function 369: DrawTextureRec() (4 input parameters) Name: DrawTextureRec Return type: void Description: Draw a part of a texture defined by a rectangle @@ -3293,7 +3299,7 @@ Function 368: DrawTextureRec() (4 input parameters) Param[2]: source (type: Rectangle) Param[3]: position (type: Vector2) Param[4]: tint (type: Color) -Function 369: DrawTexturePro() (6 input parameters) +Function 370: DrawTexturePro() (6 input parameters) Name: DrawTexturePro Return type: void Description: Draw a part of a texture defined by a rectangle with 'pro' parameters @@ -3303,7 +3309,7 @@ Function 369: DrawTexturePro() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 370: DrawTextureNPatch() (6 input parameters) +Function 371: DrawTextureNPatch() (6 input parameters) Name: DrawTextureNPatch Return type: void Description: Draws a texture (or part of it) that stretches or shrinks nicely @@ -3313,119 +3319,119 @@ Function 370: DrawTextureNPatch() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 371: ColorIsEqual() (2 input parameters) +Function 372: ColorIsEqual() (2 input parameters) Name: ColorIsEqual Return type: bool Description: Check if two colors are equal Param[1]: col1 (type: Color) Param[2]: col2 (type: Color) -Function 372: Fade() (2 input parameters) +Function 373: Fade() (2 input parameters) Name: Fade Return type: Color Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f Param[1]: color (type: Color) Param[2]: alpha (type: float) -Function 373: ColorToInt() (1 input parameters) +Function 374: ColorToInt() (1 input parameters) Name: ColorToInt Return type: int Description: Get hexadecimal value for a Color (0xRRGGBBAA) Param[1]: color (type: Color) -Function 374: ColorNormalize() (1 input parameters) +Function 375: ColorNormalize() (1 input parameters) Name: ColorNormalize Return type: Vector4 Description: Get Color normalized as float [0..1] Param[1]: color (type: Color) -Function 375: ColorFromNormalized() (1 input parameters) +Function 376: ColorFromNormalized() (1 input parameters) Name: ColorFromNormalized Return type: Color Description: Get Color from normalized values [0..1] Param[1]: normalized (type: Vector4) -Function 376: ColorToHSV() (1 input parameters) +Function 377: ColorToHSV() (1 input parameters) Name: ColorToHSV Return type: Vector3 Description: Get HSV values for a Color, hue [0..360], saturation/value [0..1] Param[1]: color (type: Color) -Function 377: ColorFromHSV() (3 input parameters) +Function 378: ColorFromHSV() (3 input parameters) Name: ColorFromHSV Return type: Color Description: Get a Color from HSV values, hue [0..360], saturation/value [0..1] Param[1]: hue (type: float) Param[2]: saturation (type: float) Param[3]: value (type: float) -Function 378: ColorTint() (2 input parameters) +Function 379: 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 379: ColorBrightness() (2 input parameters) +Function 380: 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 380: ColorContrast() (2 input parameters) +Function 381: 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 381: ColorAlpha() (2 input parameters) +Function 382: 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 382: ColorAlphaBlend() (3 input parameters) +Function 383: 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 383: ColorLerp() (3 input parameters) +Function 384: ColorLerp() (3 input parameters) Name: ColorLerp Return type: Color Description: Get color lerp interpolation between two colors, factor [0.0f..1.0f] Param[1]: color1 (type: Color) Param[2]: color2 (type: Color) Param[3]: factor (type: float) -Function 384: GetColor() (1 input parameters) +Function 385: GetColor() (1 input parameters) Name: GetColor Return type: Color Description: Get Color structure from hexadecimal value Param[1]: hexValue (type: unsigned int) -Function 385: GetPixelColor() (2 input parameters) +Function 386: 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 386: SetPixelColor() (3 input parameters) +Function 387: 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 387: GetPixelDataSize() (3 input parameters) +Function 388: 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 388: GetFontDefault() (0 input parameters) +Function 389: GetFontDefault() (0 input parameters) Name: GetFontDefault Return type: Font Description: Get the default Font No input parameters -Function 389: LoadFont() (1 input parameters) +Function 390: 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 390: LoadFontEx() (4 input parameters) +Function 391: LoadFontEx() (4 input parameters) Name: LoadFontEx Return type: Font Description: Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height @@ -3433,14 +3439,14 @@ Function 390: LoadFontEx() (4 input parameters) Param[2]: fontSize (type: int) Param[3]: codepoints (type: int *) Param[4]: codepointCount (type: int) -Function 391: LoadFontFromImage() (3 input parameters) +Function 392: 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 392: LoadFontFromMemory() (6 input parameters) +Function 393: LoadFontFromMemory() (6 input parameters) Name: LoadFontFromMemory Return type: Font Description: Load font from memory buffer, fileType refers to extension: i.e. '.ttf' @@ -3450,12 +3456,12 @@ Function 392: LoadFontFromMemory() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: codepoints (type: int *) Param[6]: codepointCount (type: int) -Function 393: IsFontValid() (1 input parameters) +Function 394: IsFontValid() (1 input parameters) Name: IsFontValid Return type: bool Description: Check if a font is valid (font data loaded, WARNING: GPU texture not checked) Param[1]: font (type: Font) -Function 394: LoadFontData() (6 input parameters) +Function 395: LoadFontData() (6 input parameters) Name: LoadFontData Return type: GlyphInfo * Description: Load font data for further use @@ -3465,7 +3471,7 @@ Function 394: LoadFontData() (6 input parameters) Param[4]: codepoints (type: int *) Param[5]: codepointCount (type: int) Param[6]: type (type: int) -Function 395: GenImageFontAtlas() (6 input parameters) +Function 396: GenImageFontAtlas() (6 input parameters) Name: GenImageFontAtlas Return type: Image Description: Generate image font atlas using chars info @@ -3475,30 +3481,30 @@ Function 395: GenImageFontAtlas() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: padding (type: int) Param[6]: packMethod (type: int) -Function 396: UnloadFontData() (2 input parameters) +Function 397: UnloadFontData() (2 input parameters) Name: UnloadFontData Return type: void Description: Unload font chars info data (RAM) Param[1]: glyphs (type: GlyphInfo *) Param[2]: glyphCount (type: int) -Function 397: UnloadFont() (1 input parameters) +Function 398: UnloadFont() (1 input parameters) Name: UnloadFont Return type: void Description: Unload font from GPU memory (VRAM) Param[1]: font (type: Font) -Function 398: ExportFontAsCode() (2 input parameters) +Function 399: 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 399: DrawFPS() (2 input parameters) +Function 400: DrawFPS() (2 input parameters) Name: DrawFPS Return type: void Description: Draw current FPS Param[1]: posX (type: int) Param[2]: posY (type: int) -Function 400: DrawText() (5 input parameters) +Function 401: DrawText() (5 input parameters) Name: DrawText Return type: void Description: Draw text (using default font) @@ -3507,7 +3513,7 @@ Function 400: DrawText() (5 input parameters) Param[3]: posY (type: int) Param[4]: fontSize (type: int) Param[5]: color (type: Color) -Function 401: DrawTextEx() (6 input parameters) +Function 402: DrawTextEx() (6 input parameters) Name: DrawTextEx Return type: void Description: Draw text using font and additional parameters @@ -3517,7 +3523,7 @@ Function 401: DrawTextEx() (6 input parameters) Param[4]: fontSize (type: float) Param[5]: spacing (type: float) Param[6]: tint (type: Color) -Function 402: DrawTextPro() (8 input parameters) +Function 403: DrawTextPro() (8 input parameters) Name: DrawTextPro Return type: void Description: Draw text using Font and pro parameters (rotation) @@ -3529,7 +3535,7 @@ Function 402: DrawTextPro() (8 input parameters) Param[6]: fontSize (type: float) Param[7]: spacing (type: float) Param[8]: tint (type: Color) -Function 403: DrawTextCodepoint() (5 input parameters) +Function 404: DrawTextCodepoint() (5 input parameters) Name: DrawTextCodepoint Return type: void Description: Draw one character (codepoint) @@ -3538,7 +3544,7 @@ Function 403: DrawTextCodepoint() (5 input parameters) Param[3]: position (type: Vector2) Param[4]: fontSize (type: float) Param[5]: tint (type: Color) -Function 404: DrawTextCodepoints() (7 input parameters) +Function 405: DrawTextCodepoints() (7 input parameters) Name: DrawTextCodepoints Return type: void Description: Draw multiple character (codepoint) @@ -3549,18 +3555,18 @@ Function 404: DrawTextCodepoints() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 405: SetTextLineSpacing() (1 input parameters) +Function 406: SetTextLineSpacing() (1 input parameters) Name: SetTextLineSpacing Return type: void Description: Set vertical line spacing when drawing with line-breaks Param[1]: spacing (type: int) -Function 406: MeasureText() (2 input parameters) +Function 407: 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 407: MeasureTextEx() (4 input parameters) +Function 408: MeasureTextEx() (4 input parameters) Name: MeasureTextEx Return type: Vector2 Description: Measure string size for Font @@ -3568,195 +3574,195 @@ Function 407: MeasureTextEx() (4 input parameters) Param[2]: text (type: const char *) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) -Function 408: GetGlyphIndex() (2 input parameters) +Function 409: 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 409: GetGlyphInfo() (2 input parameters) +Function 410: 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 410: GetGlyphAtlasRec() (2 input parameters) +Function 411: 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 411: LoadUTF8() (2 input parameters) +Function 412: 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 412: UnloadUTF8() (1 input parameters) +Function 413: UnloadUTF8() (1 input parameters) Name: UnloadUTF8 Return type: void Description: Unload UTF-8 text encoded from codepoints array Param[1]: text (type: char *) -Function 413: LoadCodepoints() (2 input parameters) +Function 414: 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 414: UnloadCodepoints() (1 input parameters) +Function 415: UnloadCodepoints() (1 input parameters) Name: UnloadCodepoints Return type: void Description: Unload codepoints data from memory Param[1]: codepoints (type: int *) -Function 415: GetCodepointCount() (1 input parameters) +Function 416: 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 416: GetCodepoint() (2 input parameters) +Function 417: 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 417: GetCodepointNext() (2 input parameters) +Function 418: 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 418: GetCodepointPrevious() (2 input parameters) +Function 419: 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 419: CodepointToUTF8() (2 input parameters) +Function 420: 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 420: TextCopy() (2 input parameters) +Function 421: 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 421: TextIsEqual() (2 input parameters) +Function 422: 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 422: TextLength() (1 input parameters) +Function 423: 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 423: TextFormat() (2 input parameters) +Function 424: 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 424: TextSubtext() (3 input parameters) +Function 425: 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 425: TextReplace() (3 input parameters) +Function 426: TextReplace() (3 input parameters) Name: TextReplace Return type: char * Description: Replace text string (WARNING: memory must be freed!) Param[1]: text (type: const char *) Param[2]: replace (type: const char *) Param[3]: by (type: const char *) -Function 426: TextInsert() (3 input parameters) +Function 427: 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 427: TextJoin() (3 input parameters) +Function 428: 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 428: TextSplit() (3 input parameters) +Function 429: 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 429: TextAppend() (3 input parameters) +Function 430: 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 430: TextFindIndex() (2 input parameters) +Function 431: 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 431: TextToUpper() (1 input parameters) +Function 432: 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 432: TextToLower() (1 input parameters) +Function 433: 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 433: TextToPascal() (1 input parameters) +Function 434: 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 434: TextToSnake() (1 input parameters) +Function 435: TextToSnake() (1 input parameters) Name: TextToSnake Return type: const char * Description: Get Snake case notation version of provided string Param[1]: text (type: const char *) -Function 435: TextToCamel() (1 input parameters) +Function 436: TextToCamel() (1 input parameters) Name: TextToCamel Return type: const char * Description: Get Camel case notation version of provided string Param[1]: text (type: const char *) -Function 436: TextToInteger() (1 input parameters) +Function 437: 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 437: TextToFloat() (1 input parameters) +Function 438: TextToFloat() (1 input parameters) Name: TextToFloat Return type: float Description: Get float value from text (negative values not supported) Param[1]: text (type: const char *) -Function 438: DrawLine3D() (3 input parameters) +Function 439: 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 439: DrawPoint3D() (2 input parameters) +Function 440: 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 440: DrawCircle3D() (5 input parameters) +Function 441: DrawCircle3D() (5 input parameters) Name: DrawCircle3D Return type: void Description: Draw a circle in 3D world space @@ -3765,7 +3771,7 @@ Function 440: DrawCircle3D() (5 input parameters) Param[3]: rotationAxis (type: Vector3) Param[4]: rotationAngle (type: float) Param[5]: color (type: Color) -Function 441: DrawTriangle3D() (4 input parameters) +Function 442: DrawTriangle3D() (4 input parameters) Name: DrawTriangle3D Return type: void Description: Draw a color-filled triangle (vertex in counter-clockwise order!) @@ -3773,14 +3779,14 @@ Function 441: DrawTriangle3D() (4 input parameters) Param[2]: v2 (type: Vector3) Param[3]: v3 (type: Vector3) Param[4]: color (type: Color) -Function 442: DrawTriangleStrip3D() (3 input parameters) +Function 443: DrawTriangleStrip3D() (3 input parameters) Name: DrawTriangleStrip3D Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector3 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 443: DrawCube() (5 input parameters) +Function 444: DrawCube() (5 input parameters) Name: DrawCube Return type: void Description: Draw cube @@ -3789,14 +3795,14 @@ Function 443: DrawCube() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 444: DrawCubeV() (3 input parameters) +Function 445: 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 445: DrawCubeWires() (5 input parameters) +Function 446: DrawCubeWires() (5 input parameters) Name: DrawCubeWires Return type: void Description: Draw cube wires @@ -3805,21 +3811,21 @@ Function 445: DrawCubeWires() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 446: DrawCubeWiresV() (3 input parameters) +Function 447: 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 447: DrawSphere() (3 input parameters) +Function 448: 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 448: DrawSphereEx() (5 input parameters) +Function 449: DrawSphereEx() (5 input parameters) Name: DrawSphereEx Return type: void Description: Draw sphere with extended parameters @@ -3828,7 +3834,7 @@ Function 448: DrawSphereEx() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 449: DrawSphereWires() (5 input parameters) +Function 450: DrawSphereWires() (5 input parameters) Name: DrawSphereWires Return type: void Description: Draw sphere wires @@ -3837,7 +3843,7 @@ Function 449: DrawSphereWires() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 450: DrawCylinder() (6 input parameters) +Function 451: DrawCylinder() (6 input parameters) Name: DrawCylinder Return type: void Description: Draw a cylinder/cone @@ -3847,7 +3853,7 @@ Function 450: DrawCylinder() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 451: DrawCylinderEx() (6 input parameters) +Function 452: DrawCylinderEx() (6 input parameters) Name: DrawCylinderEx Return type: void Description: Draw a cylinder with base at startPos and top at endPos @@ -3857,7 +3863,7 @@ Function 451: DrawCylinderEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 452: DrawCylinderWires() (6 input parameters) +Function 453: DrawCylinderWires() (6 input parameters) Name: DrawCylinderWires Return type: void Description: Draw a cylinder/cone wires @@ -3867,7 +3873,7 @@ Function 452: DrawCylinderWires() (6 input parameters) Param[4]: height (type: float) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 453: DrawCylinderWiresEx() (6 input parameters) +Function 454: DrawCylinderWiresEx() (6 input parameters) Name: DrawCylinderWiresEx Return type: void Description: Draw a cylinder wires with base at startPos and top at endPos @@ -3877,7 +3883,7 @@ Function 453: DrawCylinderWiresEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 454: DrawCapsule() (6 input parameters) +Function 455: DrawCapsule() (6 input parameters) Name: DrawCapsule Return type: void Description: Draw a capsule with the center of its sphere caps at startPos and endPos @@ -3887,7 +3893,7 @@ Function 454: DrawCapsule() (6 input parameters) Param[4]: slices (type: int) Param[5]: rings (type: int) Param[6]: color (type: Color) -Function 455: DrawCapsuleWires() (6 input parameters) +Function 456: DrawCapsuleWires() (6 input parameters) Name: DrawCapsuleWires Return type: void Description: Draw capsule wireframe with the center of its sphere caps at startPos and endPos @@ -3897,51 +3903,51 @@ Function 455: DrawCapsuleWires() (6 input parameters) Param[4]: slices (type: int) Param[5]: rings (type: int) Param[6]: color (type: Color) -Function 456: DrawPlane() (3 input parameters) +Function 457: 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 457: DrawRay() (2 input parameters) +Function 458: 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 458: DrawGrid() (2 input parameters) +Function 459: 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 459: LoadModel() (1 input parameters) +Function 460: LoadModel() (1 input parameters) Name: LoadModel Return type: Model Description: Load model from files (meshes and materials) Param[1]: fileName (type: const char *) -Function 460: LoadModelFromMesh() (1 input parameters) +Function 461: LoadModelFromMesh() (1 input parameters) Name: LoadModelFromMesh Return type: Model Description: Load model from generated mesh (default material) Param[1]: mesh (type: Mesh) -Function 461: IsModelValid() (1 input parameters) +Function 462: IsModelValid() (1 input parameters) Name: IsModelValid Return type: bool Description: Check if a model is valid (loaded in GPU, VAO/VBOs) Param[1]: model (type: Model) -Function 462: UnloadModel() (1 input parameters) +Function 463: 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 463: GetModelBoundingBox() (1 input parameters) +Function 464: GetModelBoundingBox() (1 input parameters) Name: GetModelBoundingBox Return type: BoundingBox Description: Compute model bounding box limits (considers all meshes) Param[1]: model (type: Model) -Function 464: DrawModel() (4 input parameters) +Function 465: DrawModel() (4 input parameters) Name: DrawModel Return type: void Description: Draw a model (with texture if set) @@ -3949,7 +3955,7 @@ Function 464: DrawModel() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 465: DrawModelEx() (6 input parameters) +Function 466: DrawModelEx() (6 input parameters) Name: DrawModelEx Return type: void Description: Draw a model with extended parameters @@ -3959,7 +3965,7 @@ Function 465: DrawModelEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 466: DrawModelWires() (4 input parameters) +Function 467: DrawModelWires() (4 input parameters) Name: DrawModelWires Return type: void Description: Draw a model wires (with texture if set) @@ -3967,7 +3973,7 @@ Function 466: DrawModelWires() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 467: DrawModelWiresEx() (6 input parameters) +Function 468: DrawModelWiresEx() (6 input parameters) Name: DrawModelWiresEx Return type: void Description: Draw a model wires (with texture if set) with extended parameters @@ -3977,7 +3983,7 @@ Function 467: DrawModelWiresEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 468: DrawModelPoints() (4 input parameters) +Function 469: DrawModelPoints() (4 input parameters) Name: DrawModelPoints Return type: void Description: Draw a model as points @@ -3985,7 +3991,7 @@ Function 468: DrawModelPoints() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 469: DrawModelPointsEx() (6 input parameters) +Function 470: DrawModelPointsEx() (6 input parameters) Name: DrawModelPointsEx Return type: void Description: Draw a model as points with extended parameters @@ -3995,13 +4001,13 @@ Function 469: DrawModelPointsEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 470: DrawBoundingBox() (2 input parameters) +Function 471: 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 471: DrawBillboard() (5 input parameters) +Function 472: DrawBillboard() (5 input parameters) Name: DrawBillboard Return type: void Description: Draw a billboard texture @@ -4010,7 +4016,7 @@ Function 471: DrawBillboard() (5 input parameters) Param[3]: position (type: Vector3) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 472: DrawBillboardRec() (6 input parameters) +Function 473: DrawBillboardRec() (6 input parameters) Name: DrawBillboardRec Return type: void Description: Draw a billboard texture defined by source @@ -4020,7 +4026,7 @@ Function 472: DrawBillboardRec() (6 input parameters) Param[4]: position (type: Vector3) Param[5]: size (type: Vector2) Param[6]: tint (type: Color) -Function 473: DrawBillboardPro() (9 input parameters) +Function 474: DrawBillboardPro() (9 input parameters) Name: DrawBillboardPro Return type: void Description: Draw a billboard texture defined by source and rotation @@ -4033,13 +4039,13 @@ Function 473: DrawBillboardPro() (9 input parameters) Param[7]: origin (type: Vector2) Param[8]: rotation (type: float) Param[9]: tint (type: Color) -Function 474: UploadMesh() (2 input parameters) +Function 475: 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 475: UpdateMeshBuffer() (5 input parameters) +Function 476: UpdateMeshBuffer() (5 input parameters) Name: UpdateMeshBuffer Return type: void Description: Update mesh vertex data in GPU for a specific buffer index @@ -4048,19 +4054,19 @@ Function 475: UpdateMeshBuffer() (5 input parameters) Param[3]: data (type: const void *) Param[4]: dataSize (type: int) Param[5]: offset (type: int) -Function 476: UnloadMesh() (1 input parameters) +Function 477: UnloadMesh() (1 input parameters) Name: UnloadMesh Return type: void Description: Unload mesh data from CPU and GPU Param[1]: mesh (type: Mesh) -Function 477: DrawMesh() (3 input parameters) +Function 478: 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 478: DrawMeshInstanced() (4 input parameters) +Function 479: DrawMeshInstanced() (4 input parameters) Name: DrawMeshInstanced Return type: void Description: Draw multiple mesh instances with material and different transforms @@ -4068,35 +4074,35 @@ Function 478: DrawMeshInstanced() (4 input parameters) Param[2]: material (type: Material) Param[3]: transforms (type: const Matrix *) Param[4]: instances (type: int) -Function 479: GetMeshBoundingBox() (1 input parameters) +Function 480: GetMeshBoundingBox() (1 input parameters) Name: GetMeshBoundingBox Return type: BoundingBox Description: Compute mesh bounding box limits Param[1]: mesh (type: Mesh) -Function 480: GenMeshTangents() (1 input parameters) +Function 481: GenMeshTangents() (1 input parameters) Name: GenMeshTangents Return type: void Description: Compute mesh tangents Param[1]: mesh (type: Mesh *) -Function 481: ExportMesh() (2 input parameters) +Function 482: 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 482: ExportMeshAsCode() (2 input parameters) +Function 483: ExportMeshAsCode() (2 input parameters) Name: ExportMeshAsCode Return type: bool Description: Export mesh as code file (.h) defining multiple arrays of vertex attributes Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 483: GenMeshPoly() (2 input parameters) +Function 484: GenMeshPoly() (2 input parameters) Name: GenMeshPoly Return type: Mesh Description: Generate polygonal mesh Param[1]: sides (type: int) Param[2]: radius (type: float) -Function 484: GenMeshPlane() (4 input parameters) +Function 485: GenMeshPlane() (4 input parameters) Name: GenMeshPlane Return type: Mesh Description: Generate plane mesh (with subdivisions) @@ -4104,42 +4110,42 @@ Function 484: GenMeshPlane() (4 input parameters) Param[2]: length (type: float) Param[3]: resX (type: int) Param[4]: resZ (type: int) -Function 485: GenMeshCube() (3 input parameters) +Function 486: 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 486: GenMeshSphere() (3 input parameters) +Function 487: 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 487: GenMeshHemiSphere() (3 input parameters) +Function 488: 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 488: GenMeshCylinder() (3 input parameters) +Function 489: 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 489: GenMeshCone() (3 input parameters) +Function 490: 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 490: GenMeshTorus() (4 input parameters) +Function 491: GenMeshTorus() (4 input parameters) Name: GenMeshTorus Return type: Mesh Description: Generate torus mesh @@ -4147,7 +4153,7 @@ Function 490: GenMeshTorus() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 491: GenMeshKnot() (4 input parameters) +Function 492: GenMeshKnot() (4 input parameters) Name: GenMeshKnot Return type: Mesh Description: Generate trefoil knot mesh @@ -4155,91 +4161,91 @@ Function 491: GenMeshKnot() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 492: GenMeshHeightmap() (2 input parameters) +Function 493: 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 493: GenMeshCubicmap() (2 input parameters) +Function 494: 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 494: LoadMaterials() (2 input parameters) +Function 495: 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 495: LoadMaterialDefault() (0 input parameters) +Function 496: LoadMaterialDefault() (0 input parameters) Name: LoadMaterialDefault Return type: Material Description: Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) No input parameters -Function 496: IsMaterialValid() (1 input parameters) +Function 497: IsMaterialValid() (1 input parameters) Name: IsMaterialValid Return type: bool Description: Check if a material is valid (shader assigned, map textures loaded in GPU) Param[1]: material (type: Material) -Function 497: UnloadMaterial() (1 input parameters) +Function 498: UnloadMaterial() (1 input parameters) Name: UnloadMaterial Return type: void Description: Unload material from GPU memory (VRAM) Param[1]: material (type: Material) -Function 498: SetMaterialTexture() (3 input parameters) +Function 499: 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 499: SetModelMeshMaterial() (3 input parameters) +Function 500: 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 500: LoadModelAnimations() (2 input parameters) +Function 501: LoadModelAnimations() (2 input parameters) Name: LoadModelAnimations Return type: ModelAnimation * Description: Load model animations from file Param[1]: fileName (type: const char *) Param[2]: animCount (type: int *) -Function 501: UpdateModelAnimation() (3 input parameters) +Function 502: 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 502: UnloadModelAnimation() (1 input parameters) +Function 503: UnloadModelAnimation() (1 input parameters) Name: UnloadModelAnimation Return type: void Description: Unload animation data Param[1]: anim (type: ModelAnimation) -Function 503: UnloadModelAnimations() (2 input parameters) +Function 504: UnloadModelAnimations() (2 input parameters) Name: UnloadModelAnimations Return type: void Description: Unload animation array data Param[1]: animations (type: ModelAnimation *) Param[2]: animCount (type: int) -Function 504: IsModelAnimationValid() (2 input parameters) +Function 505: 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 505: UpdateModelAnimationBoneMatrices() (3 input parameters) +Function 506: UpdateModelAnimationBoneMatrices() (3 input parameters) Name: UpdateModelAnimationBoneMatrices Return type: void Description: Update model animation mesh bone matrices (Note GPU skinning does not work on Mac) Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) Param[3]: frame (type: int) -Function 506: CheckCollisionSpheres() (4 input parameters) +Function 507: CheckCollisionSpheres() (4 input parameters) Name: CheckCollisionSpheres Return type: bool Description: Check collision between two spheres @@ -4247,40 +4253,40 @@ Function 506: CheckCollisionSpheres() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector3) Param[4]: radius2 (type: float) -Function 507: CheckCollisionBoxes() (2 input parameters) +Function 508: 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 508: CheckCollisionBoxSphere() (3 input parameters) +Function 509: 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 509: GetRayCollisionSphere() (3 input parameters) +Function 510: 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 510: GetRayCollisionBox() (2 input parameters) +Function 511: 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 511: GetRayCollisionMesh() (3 input parameters) +Function 512: 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 512: GetRayCollisionTriangle() (4 input parameters) +Function 513: GetRayCollisionTriangle() (4 input parameters) Name: GetRayCollisionTriangle Return type: RayCollision Description: Get collision info between ray and triangle @@ -4288,7 +4294,7 @@ Function 512: GetRayCollisionTriangle() (4 input parameters) Param[2]: p1 (type: Vector3) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) -Function 513: GetRayCollisionQuad() (5 input parameters) +Function 514: GetRayCollisionQuad() (5 input parameters) Name: GetRayCollisionQuad Return type: RayCollision Description: Get collision info between ray and quad @@ -4297,158 +4303,158 @@ Function 513: GetRayCollisionQuad() (5 input parameters) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) Param[5]: p4 (type: Vector3) -Function 514: InitAudioDevice() (0 input parameters) +Function 515: InitAudioDevice() (0 input parameters) Name: InitAudioDevice Return type: void Description: Initialize audio device and context No input parameters -Function 515: CloseAudioDevice() (0 input parameters) +Function 516: CloseAudioDevice() (0 input parameters) Name: CloseAudioDevice Return type: void Description: Close the audio device and context No input parameters -Function 516: IsAudioDeviceReady() (0 input parameters) +Function 517: IsAudioDeviceReady() (0 input parameters) Name: IsAudioDeviceReady Return type: bool Description: Check if audio device has been initialized successfully No input parameters -Function 517: SetMasterVolume() (1 input parameters) +Function 518: SetMasterVolume() (1 input parameters) Name: SetMasterVolume Return type: void Description: Set master volume (listener) Param[1]: volume (type: float) -Function 518: GetMasterVolume() (0 input parameters) +Function 519: GetMasterVolume() (0 input parameters) Name: GetMasterVolume Return type: float Description: Get master volume (listener) No input parameters -Function 519: LoadWave() (1 input parameters) +Function 520: LoadWave() (1 input parameters) Name: LoadWave Return type: Wave Description: Load wave data from file Param[1]: fileName (type: const char *) -Function 520: LoadWaveFromMemory() (3 input parameters) +Function 521: 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 521: IsWaveValid() (1 input parameters) +Function 522: IsWaveValid() (1 input parameters) Name: IsWaveValid Return type: bool Description: Checks if wave data is valid (data loaded and parameters) Param[1]: wave (type: Wave) -Function 522: LoadSound() (1 input parameters) +Function 523: LoadSound() (1 input parameters) Name: LoadSound Return type: Sound Description: Load sound from file Param[1]: fileName (type: const char *) -Function 523: LoadSoundFromWave() (1 input parameters) +Function 524: LoadSoundFromWave() (1 input parameters) Name: LoadSoundFromWave Return type: Sound Description: Load sound from wave data Param[1]: wave (type: Wave) -Function 524: LoadSoundAlias() (1 input parameters) +Function 525: LoadSoundAlias() (1 input parameters) Name: LoadSoundAlias Return type: Sound Description: Create a new sound that shares the same sample data as the source sound, does not own the sound data Param[1]: source (type: Sound) -Function 525: IsSoundValid() (1 input parameters) +Function 526: IsSoundValid() (1 input parameters) Name: IsSoundValid Return type: bool Description: Checks if a sound is valid (data loaded and buffers initialized) Param[1]: sound (type: Sound) -Function 526: UpdateSound() (3 input parameters) +Function 527: 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 527: UnloadWave() (1 input parameters) +Function 528: UnloadWave() (1 input parameters) Name: UnloadWave Return type: void Description: Unload wave data Param[1]: wave (type: Wave) -Function 528: UnloadSound() (1 input parameters) +Function 529: UnloadSound() (1 input parameters) Name: UnloadSound Return type: void Description: Unload sound Param[1]: sound (type: Sound) -Function 529: UnloadSoundAlias() (1 input parameters) +Function 530: UnloadSoundAlias() (1 input parameters) Name: UnloadSoundAlias Return type: void Description: Unload a sound alias (does not deallocate sample data) Param[1]: alias (type: Sound) -Function 530: ExportWave() (2 input parameters) +Function 531: 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 531: ExportWaveAsCode() (2 input parameters) +Function 532: 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 532: PlaySound() (1 input parameters) +Function 533: PlaySound() (1 input parameters) Name: PlaySound Return type: void Description: Play a sound Param[1]: sound (type: Sound) -Function 533: StopSound() (1 input parameters) +Function 534: StopSound() (1 input parameters) Name: StopSound Return type: void Description: Stop playing a sound Param[1]: sound (type: Sound) -Function 534: PauseSound() (1 input parameters) +Function 535: PauseSound() (1 input parameters) Name: PauseSound Return type: void Description: Pause a sound Param[1]: sound (type: Sound) -Function 535: ResumeSound() (1 input parameters) +Function 536: ResumeSound() (1 input parameters) Name: ResumeSound Return type: void Description: Resume a paused sound Param[1]: sound (type: Sound) -Function 536: IsSoundPlaying() (1 input parameters) +Function 537: IsSoundPlaying() (1 input parameters) Name: IsSoundPlaying Return type: bool Description: Check if a sound is currently playing Param[1]: sound (type: Sound) -Function 537: SetSoundVolume() (2 input parameters) +Function 538: 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 538: SetSoundPitch() (2 input parameters) +Function 539: 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 539: SetSoundPan() (2 input parameters) +Function 540: 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 540: WaveCopy() (1 input parameters) +Function 541: WaveCopy() (1 input parameters) Name: WaveCopy Return type: Wave Description: Copy a wave to a new wave Param[1]: wave (type: Wave) -Function 541: WaveCrop() (3 input parameters) +Function 542: WaveCrop() (3 input parameters) Name: WaveCrop Return type: void Description: Crop a wave to defined frames range Param[1]: wave (type: Wave *) Param[2]: initFrame (type: int) Param[3]: finalFrame (type: int) -Function 542: WaveFormat() (4 input parameters) +Function 543: WaveFormat() (4 input parameters) Name: WaveFormat Return type: void Description: Convert wave data to desired format @@ -4456,203 +4462,203 @@ Function 542: WaveFormat() (4 input parameters) Param[2]: sampleRate (type: int) Param[3]: sampleSize (type: int) Param[4]: channels (type: int) -Function 543: LoadWaveSamples() (1 input parameters) +Function 544: 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 544: UnloadWaveSamples() (1 input parameters) +Function 545: UnloadWaveSamples() (1 input parameters) Name: UnloadWaveSamples Return type: void Description: Unload samples data loaded with LoadWaveSamples() Param[1]: samples (type: float *) -Function 545: LoadMusicStream() (1 input parameters) +Function 546: LoadMusicStream() (1 input parameters) Name: LoadMusicStream Return type: Music Description: Load music stream from file Param[1]: fileName (type: const char *) -Function 546: LoadMusicStreamFromMemory() (3 input parameters) +Function 547: 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 547: IsMusicValid() (1 input parameters) +Function 548: IsMusicValid() (1 input parameters) Name: IsMusicValid Return type: bool Description: Checks if a music stream is valid (context and buffers initialized) Param[1]: music (type: Music) -Function 548: UnloadMusicStream() (1 input parameters) +Function 549: UnloadMusicStream() (1 input parameters) Name: UnloadMusicStream Return type: void Description: Unload music stream Param[1]: music (type: Music) -Function 549: PlayMusicStream() (1 input parameters) +Function 550: PlayMusicStream() (1 input parameters) Name: PlayMusicStream Return type: void Description: Start music playing Param[1]: music (type: Music) -Function 550: IsMusicStreamPlaying() (1 input parameters) +Function 551: IsMusicStreamPlaying() (1 input parameters) Name: IsMusicStreamPlaying Return type: bool Description: Check if music is playing Param[1]: music (type: Music) -Function 551: UpdateMusicStream() (1 input parameters) +Function 552: UpdateMusicStream() (1 input parameters) Name: UpdateMusicStream Return type: void Description: Updates buffers for music streaming Param[1]: music (type: Music) -Function 552: StopMusicStream() (1 input parameters) +Function 553: StopMusicStream() (1 input parameters) Name: StopMusicStream Return type: void Description: Stop music playing Param[1]: music (type: Music) -Function 553: PauseMusicStream() (1 input parameters) +Function 554: PauseMusicStream() (1 input parameters) Name: PauseMusicStream Return type: void Description: Pause music playing Param[1]: music (type: Music) -Function 554: ResumeMusicStream() (1 input parameters) +Function 555: ResumeMusicStream() (1 input parameters) Name: ResumeMusicStream Return type: void Description: Resume playing paused music Param[1]: music (type: Music) -Function 555: SeekMusicStream() (2 input parameters) +Function 556: 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 556: SetMusicVolume() (2 input parameters) +Function 557: 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 557: SetMusicPitch() (2 input parameters) +Function 558: 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 558: SetMusicPan() (2 input parameters) +Function 559: 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 559: GetMusicTimeLength() (1 input parameters) +Function 560: GetMusicTimeLength() (1 input parameters) Name: GetMusicTimeLength Return type: float Description: Get music time length (in seconds) Param[1]: music (type: Music) -Function 560: GetMusicTimePlayed() (1 input parameters) +Function 561: GetMusicTimePlayed() (1 input parameters) Name: GetMusicTimePlayed Return type: float Description: Get current music time played (in seconds) Param[1]: music (type: Music) -Function 561: LoadAudioStream() (3 input parameters) +Function 562: 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 562: IsAudioStreamValid() (1 input parameters) +Function 563: IsAudioStreamValid() (1 input parameters) Name: IsAudioStreamValid Return type: bool Description: Checks if an audio stream is valid (buffers initialized) Param[1]: stream (type: AudioStream) -Function 563: UnloadAudioStream() (1 input parameters) +Function 564: UnloadAudioStream() (1 input parameters) Name: UnloadAudioStream Return type: void Description: Unload audio stream and free memory Param[1]: stream (type: AudioStream) -Function 564: UpdateAudioStream() (3 input parameters) +Function 565: 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 565: IsAudioStreamProcessed() (1 input parameters) +Function 566: IsAudioStreamProcessed() (1 input parameters) Name: IsAudioStreamProcessed Return type: bool Description: Check if any audio stream buffers requires refill Param[1]: stream (type: AudioStream) -Function 566: PlayAudioStream() (1 input parameters) +Function 567: PlayAudioStream() (1 input parameters) Name: PlayAudioStream Return type: void Description: Play audio stream Param[1]: stream (type: AudioStream) -Function 567: PauseAudioStream() (1 input parameters) +Function 568: PauseAudioStream() (1 input parameters) Name: PauseAudioStream Return type: void Description: Pause audio stream Param[1]: stream (type: AudioStream) -Function 568: ResumeAudioStream() (1 input parameters) +Function 569: ResumeAudioStream() (1 input parameters) Name: ResumeAudioStream Return type: void Description: Resume audio stream Param[1]: stream (type: AudioStream) -Function 569: IsAudioStreamPlaying() (1 input parameters) +Function 570: IsAudioStreamPlaying() (1 input parameters) Name: IsAudioStreamPlaying Return type: bool Description: Check if audio stream is playing Param[1]: stream (type: AudioStream) -Function 570: StopAudioStream() (1 input parameters) +Function 571: StopAudioStream() (1 input parameters) Name: StopAudioStream Return type: void Description: Stop audio stream Param[1]: stream (type: AudioStream) -Function 571: SetAudioStreamVolume() (2 input parameters) +Function 572: 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 572: SetAudioStreamPitch() (2 input parameters) +Function 573: 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 573: SetAudioStreamPan() (2 input parameters) +Function 574: 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 574: SetAudioStreamBufferSizeDefault() (1 input parameters) +Function 575: SetAudioStreamBufferSizeDefault() (1 input parameters) Name: SetAudioStreamBufferSizeDefault Return type: void Description: Default size for new audio streams Param[1]: size (type: int) -Function 575: SetAudioStreamCallback() (2 input parameters) +Function 576: 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 576: AttachAudioStreamProcessor() (2 input parameters) +Function 577: AttachAudioStreamProcessor() (2 input parameters) Name: AttachAudioStreamProcessor Return type: void Description: Attach audio stream processor to stream, receives the samples as 'float' Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 577: DetachAudioStreamProcessor() (2 input parameters) +Function 578: 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 578: AttachAudioMixedProcessor() (1 input parameters) +Function 579: AttachAudioMixedProcessor() (1 input parameters) Name: AttachAudioMixedProcessor Return type: void Description: Attach audio stream processor to the entire audio pipeline, receives the samples as 'float' Param[1]: processor (type: AudioCallback) -Function 579: DetachAudioMixedProcessor() (1 input parameters) +Function 580: DetachAudioMixedProcessor() (1 input parameters) Name: DetachAudioMixedProcessor Return type: void Description: Detach audio stream processor from the entire audio pipeline diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index eb53437eb..17d5a81e3 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -675,7 +675,7 @@ - + @@ -1134,6 +1134,10 @@ + + + + From dc5e6e0ad089f8eda932efb4646d6bbafe0713cc Mon Sep 17 00:00:00 2001 From: Sage Hane Date: Sat, 19 Oct 2024 04:03:27 +0900 Subject: [PATCH 096/115] build.zig: Clean up my mess (#4387) --- src/build.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/build.zig b/src/build.zig index 2a8b88262..3ca1e4c6a 100644 --- a/src/build.zig +++ b/src/build.zig @@ -68,7 +68,7 @@ fn srcDir(b: *std.Build) []const u8 { @compileError("Please take a look at this function again"); } - const src_file = std.fs.path.relative(b.allocator, @src().file, ".") catch @panic("OOM"); + const src_file = std.fs.path.relative(b.allocator, ".", @src().file) catch @panic("OOM"); return std.fs.path.dirname(src_file) orelse "."; } From 902d3c92e369bb66613c363833287e9220579ee4 Mon Sep 17 00:00:00 2001 From: Nikolas Date: Mon, 21 Oct 2024 01:25:33 +0300 Subject: [PATCH 097/115] [rl_gputex] Correctly load mipmaps from DDS files (#4399) --- src/external/rl_gputex.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/external/rl_gputex.h b/src/external/rl_gputex.h index 6b26d1c8d..4043a9239 100644 --- a/src/external/rl_gputex.h +++ b/src/external/rl_gputex.h @@ -185,6 +185,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ if (header->ddspf.flags == 0x40) // No alpha channel { int data_size = image_pixel_size*sizeof(unsigned short); + if (header->mipmap_count > 1) data_size = data_size + data_size / 3; image_data = RL_MALLOC(data_size); memcpy(image_data, file_data_ptr, data_size); @@ -196,6 +197,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ if (header->ddspf.a_bit_mask == 0x8000) // 1bit alpha { int data_size = image_pixel_size*sizeof(unsigned short); + if (header->mipmap_count > 1) data_size = data_size + data_size / 3; image_data = RL_MALLOC(data_size); memcpy(image_data, file_data_ptr, data_size); @@ -215,6 +217,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ else if (header->ddspf.a_bit_mask == 0xf000) // 4bit alpha { int data_size = image_pixel_size*sizeof(unsigned short); + if (header->mipmap_count > 1) data_size = data_size + data_size / 3; image_data = RL_MALLOC(data_size); memcpy(image_data, file_data_ptr, data_size); @@ -236,6 +239,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ else if ((header->ddspf.flags == 0x40) && (header->ddspf.rgb_bit_count == 24)) // DDS_RGB, no compressed { int data_size = image_pixel_size*3*sizeof(unsigned char); + if (header->mipmap_count > 1) data_size = data_size + data_size / 3; image_data = RL_MALLOC(data_size); memcpy(image_data, file_data_ptr, data_size); @@ -245,6 +249,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ else if ((header->ddspf.flags == 0x41) && (header->ddspf.rgb_bit_count == 32)) // DDS_RGBA, no compressed { int data_size = image_pixel_size*4*sizeof(unsigned char); + if (header->mipmap_count > 1) data_size = data_size + data_size / 3; image_data = RL_MALLOC(data_size); memcpy(image_data, file_data_ptr, data_size); @@ -265,9 +270,11 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ } else if (((header->ddspf.flags == 0x04) || (header->ddspf.flags == 0x05)) && (header->ddspf.fourcc > 0)) // Compressed { - // NOTE: This forces only 1 mipmap to be loaded which is not really correct but it works - int data_size = (header->pitch_or_linear_size < file_size - 0x80) ? header->pitch_or_linear_size : file_size - 0x80; - *mips = 1; + int data_size = 0; + + // Calculate data size, including all mipmaps + if (header->mipmap_count > 1) data_size = header->pitch_or_linear_size + header->pitch_or_linear_size / 3; + else data_size = header->pitch_or_linear_size; image_data = RL_MALLOC(data_size*sizeof(unsigned char)); From 23354e1551ebf4987d4bba7bdbf2627b6e09e8ba Mon Sep 17 00:00:00 2001 From: Le Juez Victor <90587919+Bigfoot71@users.noreply.github.com> Date: Mon, 21 Oct 2024 00:26:15 +0200 Subject: [PATCH 098/115] correction of comments (#4400) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The indication of locations for bone ids and bone weights did not correspond to their default values ​​in config.h --- src/rmodels.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index 9d9c47519..e7208e1aa 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1362,7 +1362,7 @@ void UploadMesh(Mesh *mesh, bool dynamic) #ifdef RL_SUPPORT_MESH_GPU_SKINNING if (mesh->boneIds != NULL) { - // Enable vertex attribute: boneIds (shader-location = 6) + // Enable vertex attribute: boneIds (shader-location = 7) mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS] = rlLoadVertexBuffer(mesh->boneIds, mesh->vertexCount*4*sizeof(unsigned char), dynamic); rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, 4, RL_UNSIGNED_BYTE, 0, 0, 0); rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS); @@ -1378,7 +1378,7 @@ void UploadMesh(Mesh *mesh, bool dynamic) if (mesh->boneWeights != NULL) { - // Enable vertex attribute: boneWeights (shader-location = 7) + // Enable vertex attribute: boneWeights (shader-location = 8) mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = rlLoadVertexBuffer(mesh->boneWeights, mesh->vertexCount*4*sizeof(float), dynamic); rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, 4, RL_FLOAT, 0, 0, 0); rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS); From ce9259cd02e719fcef38e919cf69814d0973136a Mon Sep 17 00:00:00 2001 From: Sage Hane Date: Mon, 21 Oct 2024 07:27:25 +0900 Subject: [PATCH 099/115] build.zig: Fix various issues around `-Dconfig` (#4398) * build.zig: Fix various issues around `-Dconfig` * build.zig: Parse all relevant flags from `src/config.h` at comptime --- src/build.zig | 112 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 38 deletions(-) diff --git a/src/build.zig b/src/build.zig index 3ca1e4c6a..23b4d66b7 100644 --- a/src/build.zig +++ b/src/build.zig @@ -72,6 +72,36 @@ fn srcDir(b: *std.Build) []const u8 { return std.fs.path.dirname(src_file) orelse "."; } +/// A list of all flags from `src/config.h` that one may override +const config_h_flags = outer: { + // Set this value higher if compile errors happen as `src/config.h` gets larger + @setEvalBranchQuota(1 << 20); + + const config_h = @embedFile("config.h"); + var flags: [std.mem.count(u8, config_h, "\n") + 1][]const u8 = undefined; + + var i = 0; + var lines = std.mem.tokenizeScalar(u8, config_h, '\n'); + while (lines.next()) |line| { + if (!std.mem.containsAtLeast(u8, line, 1, "SUPPORT")) continue; + if (std.mem.startsWith(u8, line, "//")) continue; + if (std.mem.startsWith(u8, line, "#if")) continue; + + var flag = std.mem.trimLeft(u8, line, " \t"); // Trim whitespace + flag = flag["#define ".len - 1 ..]; // Remove #define + flag = std.mem.trimLeft(u8, flag, " \t"); // Trim whitespace + flag = flag[0 .. std.mem.indexOf(u8, flag, " ") orelse continue]; // Flag is only one word, so capture till space + flag = "-D" ++ flag; // Prepend with -D + + flags[i] = flag; + i += 1; + } + + // Uncomment this to check what flags normally get passed + //@compileLog(flags[0..i].*); + break :outer flags[0..i].*; +}; + fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile { raylib_flags_arr.clearRetainingCapacity(); @@ -86,33 +116,36 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. "-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/3674 }); if (options.config.len > 0) { - const file = b.pathJoin(&.{ srcDir(b), "config.h" }); - const content = try std.fs.cwd().readFileAlloc(b.allocator, file, std.math.maxInt(usize)); - defer b.allocator.free(content); + // Sets a flag indiciating the use of a custom `config.h` + try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS"); - var lines = std.mem.splitScalar(u8, content, '\n'); - while (lines.next()) |line| { - if (!std.mem.containsAtLeast(u8, line, 1, "SUPPORT")) continue; - if (std.mem.startsWith(u8, line, "//")) continue; - if (std.mem.startsWith(u8, line, "#if")) continue; + // Splits a space-separated list of config flags into multiple flags + // + // Note: This means certain flags like `-x c++` won't be processed properly. + // `-xc++` or similar should be used when possible + var config_iter = std.mem.tokenizeScalar(u8, options.config, ' '); - var flag = std.mem.trimLeft(u8, line, " \t"); // Trim whitespace - flag = flag["#define ".len - 1 ..]; // Remove #define - flag = std.mem.trimLeft(u8, flag, " \t"); // Trim whitespace - flag = flag[0 .. std.mem.indexOf(u8, flag, " ") orelse continue]; // Flag is only one word, so capture till space - flag = try std.fmt.allocPrint(b.allocator, "-D{s}", .{flag}); // Prepend with -D + // Apply config flags supplied by the user + while (config_iter.next()) |config_flag| + try raylib_flags_arr.append(b.allocator, config_flag); - // If user specifies the flag skip it - if (std.mem.containsAtLeast(u8, options.config, 1, flag)) continue; + // Apply all relevant configs from `src/config.h` *except* the user-specified ones + // + // Note: Currently using a suboptimal `O(m*n)` time algorithm where: + // `m` corresponds roughly to the number of lines in `src/config.h` + // `n` corresponds to the number of user-specified flags + outer: for (config_h_flags) |flag| { + // If a user already specified the flag, skip it + while (config_iter.next()) |config_flag| { + // For a user-specified flag to match, it must share the same prefix and have the + // same length or be followed by an equals sign + if (!std.mem.startsWith(u8, config_flag, flag)) continue; + if (config_flag.len == flag.len or config_flag[flag.len] == '=') continue :outer; + } - // Append default value from config.h to compile flags + // Otherwise, append default value from config.h to compile flags try raylib_flags_arr.append(b.allocator, flag); } - - // Append config flags supplied by user to compile flags - try raylib_flags_arr.append(b.allocator, options.config); - - try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS"); } if (options.shared) { @@ -319,10 +352,28 @@ pub const Options = struct { shared: bool = false, linux_display_backend: LinuxDisplayBackend = .Both, opengl_version: OpenglVersion = .auto, - /// config should be a list of cflags, eg, "-DSUPPORT_CUSTOM_FRAME_CONTROL" + /// config should be a list of space-separated cflags, eg, "-DSUPPORT_CUSTOM_FRAME_CONTROL" config: []const u8 = &.{}, raygui_dependency_name: []const u8 = "raygui", + + const defaults = Options{}; + + fn getOptions(b: *std.Build) Options { + return .{ + .platform = b.option(PlatformBackend, "platform", "Choose the platform backedn for desktop target") orelse defaults.platform, + .raudio = b.option(bool, "raudio", "Compile with audio support") orelse defaults.raudio, + .raygui = b.option(bool, "raygui", "Compile with raygui support") orelse defaults.raygui, + .rmodels = b.option(bool, "rmodels", "Compile with models support") orelse defaults.rmodels, + .rtext = b.option(bool, "rtext", "Compile with text support") orelse defaults.rtext, + .rtextures = b.option(bool, "rtextures", "Compile with textures support") orelse defaults.rtextures, + .rshapes = b.option(bool, "rshapes", "Compile with shapes support") orelse defaults.rshapes, + .shared = b.option(bool, "shared", "Compile as shared library") orelse defaults.shared, + .linux_display_backend = b.option(LinuxDisplayBackend, "linux_display_backend", "Linux display backend to use") orelse defaults.linux_display_backend, + .opengl_version = b.option(OpenglVersion, "opengl_version", "OpenGL version to use") orelse defaults.opengl_version, + .config = b.option([]const u8, "config", "Compile with custom define macros overriding config.h") orelse &.{}, + }; + } }; pub const OpenglVersion = enum { @@ -371,22 +422,7 @@ pub fn build(b: *std.Build) !void { // set a preferred release mode, allowing the user to decide how to optimize. const optimize = b.standardOptimizeOption(.{}); - const defaults = Options{}; - const options = Options{ - .platform = b.option(PlatformBackend, "platform", "Choose the platform backedn for desktop target") orelse defaults.platform, - .raudio = b.option(bool, "raudio", "Compile with audio support") orelse defaults.raudio, - .raygui = b.option(bool, "raygui", "Compile with raygui support") orelse defaults.raygui, - .rmodels = b.option(bool, "rmodels", "Compile with models support") orelse defaults.rmodels, - .rtext = b.option(bool, "rtext", "Compile with text support") orelse defaults.rtext, - .rtextures = b.option(bool, "rtextures", "Compile with textures support") orelse defaults.rtextures, - .rshapes = b.option(bool, "rshapes", "Compile with shapes support") orelse defaults.rshapes, - .shared = b.option(bool, "shared", "Compile as shared library") orelse defaults.shared, - .linux_display_backend = b.option(LinuxDisplayBackend, "linux_display_backend", "Linux display backend to use") orelse defaults.linux_display_backend, - .opengl_version = b.option(OpenglVersion, "opengl_version", "OpenGL version to use") orelse defaults.opengl_version, - .config = b.option([]const u8, "config", "Compile with custom define macros overriding config.h") orelse &.{}, - }; - - const lib = try compileRaylib(b, target, optimize, options); + const lib = try compileRaylib(b, target, optimize, Options.getOptions(b)); lib.installHeader(b.path(b.pathJoin(&.{ srcDir(b), "raylib.h" })), "raylib.h"); lib.installHeader(b.path(b.pathJoin(&.{ srcDir(b), "raymath.h" })), "raymath.h"); From 3dbbe60376e4f6055bfc11e28b069f61ab37525c Mon Sep 17 00:00:00 2001 From: Asdqwe Date: Sun, 20 Oct 2024 19:29:32 -0300 Subject: [PATCH 100/115] Adds MaximizeWindow() and RestoreWindow() implementation for PLATFORM_WEB (#4397) --- src/platforms/rcore_web.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c index 35c15a6b6..73513d8e4 100644 --- a/src/platforms/rcore_web.c +++ b/src/platforms/rcore_web.c @@ -74,6 +74,8 @@ typedef struct { GLFWwindow *handle; // GLFW window handle (graphic device) bool ourFullscreen; // Internal var to filter our handling of fullscreen vs the user handling of fullscreen + int unmaximizedWidth; // Internal var to store the unmaximized window (canvas) width + int unmaximizedHeight; // Internal var to store the unmaximized window (canvas) height } PlatformData; //---------------------------------------------------------------------------------- @@ -317,7 +319,16 @@ void ToggleBorderlessWindowed(void) // Set window state: maximized, if resizable void MaximizeWindow(void) { - TRACELOG(LOG_WARNING, "MaximizeWindow() not available on target platform"); + if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) + { + platform.unmaximizedWidth = CORE.Window.screen.width; + platform.unmaximizedHeight = CORE.Window.screen.height; + + const int tabWidth = EM_ASM_INT( { return window.innerWidth; }, 0); + const int tabHeight = EM_ASM_INT( { return window.innerHeight; }, 0); + + if (tabWidth && tabHeight) glfwSetWindowSize(platform.handle, tabWidth, tabHeight); + } } // Set window state: minimized @@ -329,7 +340,10 @@ void MinimizeWindow(void) // Set window state: not minimized/maximized void RestoreWindow(void) { - TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform"); + if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) + { + if (platform.unmaximizedWidth && platform.unmaximizedHeight) glfwSetWindowSize(platform.handle, platform.unmaximizedWidth, platform.unmaximizedHeight); + } } // Set window configuration state using flags From 51ff6586f441314b49be3bf686bf3880040d0be9 Mon Sep 17 00:00:00 2001 From: Nikolas Date: Mon, 21 Oct 2024 01:31:01 +0300 Subject: [PATCH 101/115] [rtextures] ImageDraw(): Don't try to blend images without alpha (#4395) --- src/rtextures.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/rtextures.c b/src/rtextures.c index 294eeb6ad..9fc633274 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -3969,13 +3969,21 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color // [-] GetPixelColor(): Get Vector4 instead of Color, easier for ColorAlphaBlend() // [ ] Support f32bit channels drawing - // TODO: Support PIXELFORMAT_UNCOMPRESSED_R32, PIXELFORMAT_UNCOMPRESSED_R32G32B32, PIXELFORMAT_UNCOMPRESSED_R32G32B32A32 and 16-bit equivalents + // TODO: Support PIXELFORMAT_UNCOMPRESSED_R32G32B32A32 and PIXELFORMAT_UNCOMPRESSED_R1616B16A16 Color colSrc, colDst, blend; bool blendRequired = true; // Fast path: Avoid blend if source has no alpha to blend - if ((tint.a == 255) && ((srcPtr->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) || (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) || (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R5G6B5))) blendRequired = false; + if ((tint.a == 255) && + ((srcPtr->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) || + (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R5G6B5) || + (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) || + (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R32) || + (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R32G32B32) || + (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R16) || + (srcPtr->format == PIXELFORMAT_UNCOMPRESSED_R16G16B16))) + blendRequired = false; int strideDst = GetPixelDataSize(dst->width, 1, dst->format); int bytesPerPixelDst = strideDst/(dst->width); From 680238689baf4d88153173d18c855337706b2e4e Mon Sep 17 00:00:00 2001 From: Anthony Carbajal <5776225+CrackedPixel@users.noreply.github.com> Date: Sun, 20 Oct 2024 18:03:01 -0500 Subject: [PATCH 102/115] removed extra update command (#4401) --- examples/models/models_gpu_skinning.c | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/models/models_gpu_skinning.c b/examples/models/models_gpu_skinning.c index 846f0a890..b6296c96a 100644 --- a/examples/models/models_gpu_skinning.c +++ b/examples/models/models_gpu_skinning.c @@ -81,7 +81,6 @@ int main(void) // Update model animation ModelAnimation anim = modelAnimations[animIndex]; animCurrentFrame = (animCurrentFrame + 1)%anim.frameCount; - UpdateModelAnimationBoneMatrices(characterModel, anim, animCurrentFrame); //---------------------------------------------------------------------------------- // Draw From 4290a0d9f21bbca118c2bba0c910fbe9a28366bd Mon Sep 17 00:00:00 2001 From: Asdqwe Date: Sun, 20 Oct 2024 20:04:32 -0300 Subject: [PATCH 103/115] [rcore] [web] Updates `SetWindowState()` and `ClearWindowState()` to handle `FLAG_WINDOW_MAXIMIZED` for `PLATFORM_WEB` (#4402) * Updates SetWindowState() and ClearWindowState() to handle FLAG_WINDOW_MAXIMIZED for PLATFORM_WEB * Update MaximizeWindow() and RestoreWindow() to set/unset the FLAG_WINDOW_MAXIMIZED --- src/platforms/rcore_web.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c index 73513d8e4..70623166d 100644 --- a/src/platforms/rcore_web.c +++ b/src/platforms/rcore_web.c @@ -328,6 +328,8 @@ void MaximizeWindow(void) const int tabHeight = EM_ASM_INT( { return window.innerHeight; }, 0); if (tabWidth && tabHeight) glfwSetWindowSize(platform.handle, tabWidth, tabHeight); + + CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; } } @@ -343,6 +345,8 @@ void RestoreWindow(void) if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) { if (platform.unmaximizedWidth && platform.unmaximizedHeight) glfwSetWindowSize(platform.handle, platform.unmaximizedWidth, platform.unmaximizedHeight); + + CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED; } } @@ -412,9 +416,20 @@ void SetWindowState(unsigned int flags) } // State change: FLAG_WINDOW_MAXIMIZED - if ((flags & FLAG_WINDOW_MAXIMIZED) > 0) + if (((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) != (flags & FLAG_WINDOW_MAXIMIZED)) && ((flags & FLAG_WINDOW_MAXIMIZED) > 0)) { - TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_MAXIMIZED) not available on target platform"); + if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) + { + platform.unmaximizedWidth = CORE.Window.screen.width; + platform.unmaximizedHeight = CORE.Window.screen.height; + + const int tabWidth = EM_ASM_INT( { return window.innerWidth; }, 0); + const int tabHeight = EM_ASM_INT( { return window.innerHeight; }, 0); + + if (tabWidth && tabHeight) glfwSetWindowSize(platform.handle, tabWidth, tabHeight); + + CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; + } } // State change: FLAG_WINDOW_UNFOCUSED @@ -530,9 +545,14 @@ void ClearWindowState(unsigned int flags) } // State change: FLAG_WINDOW_MAXIMIZED - if ((flags & FLAG_WINDOW_MAXIMIZED) > 0) + if (((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) && ((flags & FLAG_WINDOW_MAXIMIZED) > 0)) { - TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_MAXIMIZED) not available on target platform"); + if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) + { + if (platform.unmaximizedWidth && platform.unmaximizedHeight) glfwSetWindowSize(platform.handle, platform.unmaximizedWidth, platform.unmaximizedHeight); + + CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED; + } } // State change: FLAG_WINDOW_UNDECORATED From cb21fe88d3cc10f9c4c5ec83a5ad0a8c90c934da Mon Sep 17 00:00:00 2001 From: Asdqwe Date: Mon, 21 Oct 2024 04:45:46 -0300 Subject: [PATCH 104/115] Fix MaximizeWindow() for PLATFORM_WEB (#4404) --- src/platforms/rcore_web.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c index 70623166d..c41094446 100644 --- a/src/platforms/rcore_web.c +++ b/src/platforms/rcore_web.c @@ -319,7 +319,7 @@ void ToggleBorderlessWindowed(void) // Set window state: maximized, if resizable void MaximizeWindow(void) { - if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) + if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE && !(CORE.Window.flags & FLAG_WINDOW_MAXIMIZED)) { platform.unmaximizedWidth = CORE.Window.screen.width; platform.unmaximizedHeight = CORE.Window.screen.height; @@ -342,7 +342,7 @@ void MinimizeWindow(void) // Set window state: not minimized/maximized void RestoreWindow(void) { - if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) + if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE && (CORE.Window.flags & FLAG_WINDOW_MAXIMIZED)) { if (platform.unmaximizedWidth && platform.unmaximizedHeight) glfwSetWindowSize(platform.handle, platform.unmaximizedWidth, platform.unmaximizedHeight); From 9d0b1f0171b2f072a573143c68f3a589de70efd5 Mon Sep 17 00:00:00 2001 From: Asdqwe Date: Mon, 21 Oct 2024 04:47:19 -0300 Subject: [PATCH 105/115] Adds SetWindowOpacity() implementation for PLATFORM_WEB (#4403) --- src/platforms/rcore_web.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c index c41094446..36af66a47 100644 --- a/src/platforms/rcore_web.c +++ b/src/platforms/rcore_web.c @@ -673,7 +673,9 @@ void SetWindowSize(int width, int height) // Set window opacity, value opacity is between 0.0 and 1.0 void SetWindowOpacity(float opacity) { - TRACELOG(LOG_WARNING, "SetWindowOpacity() not available on target platform"); + if (opacity >= 1.0f) opacity = 1.0f; + else if (opacity <= 0.0f) opacity = 0.0f; + EM_ASM({ document.getElementById('canvas').style.opacity = $0; }, opacity); } // Set window focused From 110ee74875412beb41ffb53330b47ec9cb052b2d Mon Sep 17 00:00:00 2001 From: Sage Hane Date: Mon, 21 Oct 2024 19:57:11 +0900 Subject: [PATCH 106/115] build.zig: Merge `src/build.zig` to `build.zig` (#4393) * build.zig: Move `src/build.zig` to `build.zig` * build.zig: Remove uses of `@src` * build.zig: Update entry point --- build.zig | 438 +++++++++++++++++++++++++++++++++++++++++++++++- src/build.zig | 455 -------------------------------------------------- 2 files changed, 429 insertions(+), 464 deletions(-) delete mode 100644 src/build.zig diff --git a/build.zig b/build.zig index 029482608..56e69caf4 100644 --- a/build.zig +++ b/build.zig @@ -1,14 +1,434 @@ const std = @import("std"); -const raylib = @import("src/build.zig"); +const builtin = @import("builtin"); -// This has been tested to work with zig 0.12.0 -pub fn build(b: *std.Build) !void { - try raylib.build(b); +/// Minimum supported version of Zig +const min_ver = "0.12.0"; + +comptime { + const order = std.SemanticVersion.order; + const parse = std.SemanticVersion.parse; + if (order(builtin.zig_version, parse(min_ver) catch unreachable) == .lt) + @compileError("Raylib requires zig version " ++ min_ver); } -// expose helper functions to user's build.zig -pub const addRaylib = raylib.addRaylib; -pub const addRaygui = raylib.addRaygui; +// NOTE(freakmangd): I don't like using a global here, but it prevents having to +// get the flags a second time when adding raygui +var raylib_flags_arr: std.ArrayListUnmanaged([]const u8) = .{}; -// expose options for compiling -pub const RaylibOptions = raylib.Options; +// This has been tested with zig version 0.12.0 +pub fn addRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile { + const raylib_dep = b.dependencyFromBuildZig(@This(), .{ + .target = target, + .optimize = optimize, + .raudio = options.raudio, + .rmodels = options.rmodels, + .rshapes = options.rshapes, + .rtext = options.rtext, + .rtextures = options.rtextures, + .platform = options.platform, + .shared = options.shared, + .linux_display_backend = options.linux_display_backend, + .opengl_version = options.opengl_version, + .config = options.config, + }); + const raylib = raylib_dep.artifact("raylib"); + + if (options.raygui) { + const raygui_dep = b.dependency(options.raygui_dependency_name, .{}); + addRaygui(b, raylib, raygui_dep); + } + + return raylib; +} + +fn setDesktopPlatform(raylib: *std.Build.Step.Compile, platform: PlatformBackend) void { + raylib.defineCMacro("PLATFORM_DESKTOP", null); + + switch (platform) { + .glfw => raylib.defineCMacro("PLATFORM_DESKTOP_GLFW", null), + .rgfw => raylib.defineCMacro("PLATFORM_DESKTOP_RGFW", null), + .sdl => raylib.defineCMacro("PLATFORM_DESKTOP_SDL", null), + else => {}, + } +} + +/// A list of all flags from `src/config.h` that one may override +const config_h_flags = outer: { + // Set this value higher if compile errors happen as `src/config.h` gets larger + @setEvalBranchQuota(1 << 20); + + const config_h = @embedFile("src/config.h"); + var flags: [std.mem.count(u8, config_h, "\n") + 1][]const u8 = undefined; + + var i = 0; + var lines = std.mem.tokenizeScalar(u8, config_h, '\n'); + while (lines.next()) |line| { + if (!std.mem.containsAtLeast(u8, line, 1, "SUPPORT")) continue; + if (std.mem.startsWith(u8, line, "//")) continue; + if (std.mem.startsWith(u8, line, "#if")) continue; + + var flag = std.mem.trimLeft(u8, line, " \t"); // Trim whitespace + flag = flag["#define ".len - 1 ..]; // Remove #define + flag = std.mem.trimLeft(u8, flag, " \t"); // Trim whitespace + flag = flag[0 .. std.mem.indexOf(u8, flag, " ") orelse continue]; // Flag is only one word, so capture till space + flag = "-D" ++ flag; // Prepend with -D + + flags[i] = flag; + i += 1; + } + + // Uncomment this to check what flags normally get passed + //@compileLog(flags[0..i].*); + break :outer flags[0..i].*; +}; + +fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile { + raylib_flags_arr.clearRetainingCapacity(); + + const shared_flags = &[_][]const u8{ + "-fPIC", + "-DBUILD_LIBTYPE_SHARED", + }; + try raylib_flags_arr.appendSlice(b.allocator, &[_][]const u8{ + "-std=gnu99", + "-D_GNU_SOURCE", + "-DGL_SILENCE_DEPRECATION=199309L", + "-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/3674 + }); + if (options.config.len > 0) { + // Sets a flag indiciating the use of a custom `config.h` + try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS"); + + // Splits a space-separated list of config flags into multiple flags + // + // Note: This means certain flags like `-x c++` won't be processed properly. + // `-xc++` or similar should be used when possible + var config_iter = std.mem.tokenizeScalar(u8, options.config, ' '); + + // Apply config flags supplied by the user + while (config_iter.next()) |config_flag| + try raylib_flags_arr.append(b.allocator, config_flag); + + // Apply all relevant configs from `src/config.h` *except* the user-specified ones + // + // Note: Currently using a suboptimal `O(m*n)` time algorithm where: + // `m` corresponds roughly to the number of lines in `src/config.h` + // `n` corresponds to the number of user-specified flags + outer: for (config_h_flags) |flag| { + // If a user already specified the flag, skip it + while (config_iter.next()) |config_flag| { + // For a user-specified flag to match, it must share the same prefix and have the + // same length or be followed by an equals sign + if (!std.mem.startsWith(u8, config_flag, flag)) continue; + if (config_flag.len == flag.len or config_flag[flag.len] == '=') continue :outer; + } + + // Otherwise, append default value from config.h to compile flags + try raylib_flags_arr.append(b.allocator, flag); + } + } + + if (options.shared) { + try raylib_flags_arr.appendSlice(b.allocator, shared_flags); + } + + const raylib = if (options.shared) + b.addSharedLibrary(.{ + .name = "raylib", + .target = target, + .optimize = optimize, + }) + else + b.addStaticLibrary(.{ + .name = "raylib", + .target = target, + .optimize = optimize, + }); + raylib.linkLibC(); + + // No GLFW required on PLATFORM_DRM + if (options.platform != .drm) { + raylib.addIncludePath(b.path("src/external/glfw/include")); + } + + var c_source_files = try std.ArrayList([]const u8).initCapacity(b.allocator, 2); + c_source_files.appendSliceAssumeCapacity(&.{ "src/rcore.c", "src/utils.c" }); + + if (options.raudio) { + try c_source_files.append("src/raudio.c"); + } + if (options.rmodels) { + try c_source_files.append("src/rmodels.c"); + } + if (options.rshapes) { + try c_source_files.append("src/rshapes.c"); + } + if (options.rtext) { + try c_source_files.append("src/rtext.c"); + } + if (options.rtextures) { + try c_source_files.append("src/rtextures.c"); + } + + if (options.opengl_version != .auto) { + raylib.defineCMacro(options.opengl_version.toCMacroStr(), null); + } + + switch (target.result.os.tag) { + .windows => { + try c_source_files.append("src/rglfw.c"); + raylib.linkSystemLibrary("winmm"); + raylib.linkSystemLibrary("gdi32"); + raylib.linkSystemLibrary("opengl32"); + + setDesktopPlatform(raylib, options.platform); + }, + .linux => { + if (options.platform != .drm) { + try c_source_files.append("src/rglfw.c"); + raylib.linkSystemLibrary("GL"); + raylib.linkSystemLibrary("rt"); + raylib.linkSystemLibrary("dl"); + raylib.linkSystemLibrary("m"); + + raylib.addLibraryPath(.{ .cwd_relative = "/usr/lib" }); + raylib.addIncludePath(.{ .cwd_relative = "/usr/include" }); + if (options.linux_display_backend == .X11 or options.linux_display_backend == .Both) { + raylib.defineCMacro("_GLFW_X11", null); + raylib.linkSystemLibrary("X11"); + } + + if (options.linux_display_backend == .Wayland or options.linux_display_backend == .Both) { + _ = b.findProgram(&.{"wayland-scanner"}, &.{}) catch { + std.log.err( + \\ `wayland-scanner` may not be installed on the system. + \\ You can switch to X11 in your `build.zig` by changing `Options.linux_display_backend` + , .{}); + @panic("`wayland-scanner` not found"); + }; + raylib.defineCMacro("_GLFW_WAYLAND", null); + raylib.linkSystemLibrary("wayland-client"); + raylib.linkSystemLibrary("wayland-cursor"); + raylib.linkSystemLibrary("wayland-egl"); + raylib.linkSystemLibrary("xkbcommon"); + waylandGenerate(b, raylib, "wayland.xml", "wayland-client-protocol"); + waylandGenerate(b, raylib, "xdg-shell.xml", "xdg-shell-client-protocol"); + waylandGenerate(b, raylib, "xdg-decoration-unstable-v1.xml", "xdg-decoration-unstable-v1-client-protocol"); + waylandGenerate(b, raylib, "viewporter.xml", "viewporter-client-protocol"); + waylandGenerate(b, raylib, "relative-pointer-unstable-v1.xml", "relative-pointer-unstable-v1-client-protocol"); + waylandGenerate(b, raylib, "pointer-constraints-unstable-v1.xml", "pointer-constraints-unstable-v1-client-protocol"); + waylandGenerate(b, raylib, "fractional-scale-v1.xml", "fractional-scale-v1-client-protocol"); + waylandGenerate(b, raylib, "xdg-activation-v1.xml", "xdg-activation-v1-client-protocol"); + waylandGenerate(b, raylib, "idle-inhibit-unstable-v1.xml", "idle-inhibit-unstable-v1-client-protocol"); + } + setDesktopPlatform(raylib, options.platform); + } else { + if (options.opengl_version == .auto) { + raylib.linkSystemLibrary("GLESv2"); + raylib.defineCMacro("GRAPHICS_API_OPENGL_ES2", null); + } + + raylib.linkSystemLibrary("EGL"); + raylib.linkSystemLibrary("drm"); + raylib.linkSystemLibrary("gbm"); + raylib.linkSystemLibrary("pthread"); + raylib.linkSystemLibrary("rt"); + raylib.linkSystemLibrary("m"); + raylib.linkSystemLibrary("dl"); + raylib.addIncludePath(.{ .cwd_relative = "/usr/include/libdrm" }); + + raylib.defineCMacro("PLATFORM_DRM", null); + raylib.defineCMacro("EGL_NO_X11", null); + raylib.defineCMacro("DEFAULT_BATCH_BUFFER_ELEMENT", "2048"); + } + }, + .freebsd, .openbsd, .netbsd, .dragonfly => { + try c_source_files.append("rglfw.c"); + raylib.linkSystemLibrary("GL"); + raylib.linkSystemLibrary("rt"); + raylib.linkSystemLibrary("dl"); + raylib.linkSystemLibrary("m"); + raylib.linkSystemLibrary("X11"); + raylib.linkSystemLibrary("Xrandr"); + raylib.linkSystemLibrary("Xinerama"); + raylib.linkSystemLibrary("Xi"); + raylib.linkSystemLibrary("Xxf86vm"); + raylib.linkSystemLibrary("Xcursor"); + + setDesktopPlatform(raylib, options.platform); + }, + .macos => { + // On macos rglfw.c include Objective-C files. + try raylib_flags_arr.append(b.allocator, "-ObjC"); + raylib.root_module.addCSourceFile(.{ + .file = b.path("src/rglfw.c"), + .flags = raylib_flags_arr.items, + }); + _ = raylib_flags_arr.pop(); + raylib.linkFramework("Foundation"); + raylib.linkFramework("CoreServices"); + raylib.linkFramework("CoreGraphics"); + raylib.linkFramework("AppKit"); + raylib.linkFramework("IOKit"); + + setDesktopPlatform(raylib, options.platform); + }, + .emscripten => { + raylib.defineCMacro("PLATFORM_WEB", null); + if (options.opengl_version == .auto) { + raylib.defineCMacro("GRAPHICS_API_OPENGL_ES2", null); + } + + if (b.sysroot == null) { + @panic("Pass '--sysroot \"$EMSDK/upstream/emscripten\"'"); + } + + const cache_include = b.pathJoin(&.{ b.sysroot.?, "cache", "sysroot", "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(.{ .cwd_relative = cache_include }); + }, + else => { + @panic("Unsupported OS"); + }, + } + + raylib.root_module.addCSourceFiles(.{ + .files = c_source_files.items, + .flags = raylib_flags_arr.items, + }); + + return raylib; +} + +/// This function does not need to be called if you passed .raygui = true to addRaylib +pub fn addRaygui(b: *std.Build, raylib: *std.Build.Step.Compile, raygui_dep: *std.Build.Dependency) void { + if (raylib_flags_arr.items.len == 0) { + @panic( + \\argument 2 `raylib` in `addRaygui` must come from b.dependency("raylib", ...).artifact("raylib") + ); + } + + var gen_step = b.addWriteFiles(); + raylib.step.dependOn(&gen_step.step); + + const raygui_c_path = gen_step.add("raygui.c", "#define RAYGUI_IMPLEMENTATION\n#include \"raygui.h\"\n"); + raylib.addCSourceFile(.{ .file = raygui_c_path, .flags = raylib_flags_arr.items }); + raylib.addIncludePath(raygui_dep.path("src")); + + raylib.installHeader(raygui_dep.path("src/raygui.h"), "raygui.h"); +} + +pub const Options = struct { + raudio: bool = true, + rmodels: bool = true, + rshapes: bool = true, + rtext: bool = true, + rtextures: bool = true, + raygui: bool = false, + platform: PlatformBackend = .glfw, + shared: bool = false, + linux_display_backend: LinuxDisplayBackend = .Both, + opengl_version: OpenglVersion = .auto, + /// config should be a list of space-separated cflags, eg, "-DSUPPORT_CUSTOM_FRAME_CONTROL" + config: []const u8 = &.{}, + + raygui_dependency_name: []const u8 = "raygui", + + const defaults = Options{}; + + fn getOptions(b: *std.Build) Options { + return .{ + .platform = b.option(PlatformBackend, "platform", "Choose the platform backedn for desktop target") orelse defaults.platform, + .raudio = b.option(bool, "raudio", "Compile with audio support") orelse defaults.raudio, + .raygui = b.option(bool, "raygui", "Compile with raygui support") orelse defaults.raygui, + .rmodels = b.option(bool, "rmodels", "Compile with models support") orelse defaults.rmodels, + .rtext = b.option(bool, "rtext", "Compile with text support") orelse defaults.rtext, + .rtextures = b.option(bool, "rtextures", "Compile with textures support") orelse defaults.rtextures, + .rshapes = b.option(bool, "rshapes", "Compile with shapes support") orelse defaults.rshapes, + .shared = b.option(bool, "shared", "Compile as shared library") orelse defaults.shared, + .linux_display_backend = b.option(LinuxDisplayBackend, "linux_display_backend", "Linux display backend to use") orelse defaults.linux_display_backend, + .opengl_version = b.option(OpenglVersion, "opengl_version", "OpenGL version to use") orelse defaults.opengl_version, + .config = b.option([]const u8, "config", "Compile with custom define macros overriding config.h") orelse &.{}, + }; + } +}; + +pub const OpenglVersion = enum { + auto, + gl_1_1, + gl_2_1, + gl_3_3, + gl_4_3, + gles_2, + gles_3, + + pub fn toCMacroStr(self: @This()) []const u8 { + switch (self) { + .auto => @panic("OpenglVersion.auto cannot be turned into a C macro string"), + .gl_1_1 => return "GRAPHICS_API_OPENGL_11", + .gl_2_1 => return "GRAPHICS_API_OPENGL_21", + .gl_3_3 => return "GRAPHICS_API_OPENGL_33", + .gl_4_3 => return "GRAPHICS_API_OPENGL_43", + .gles_2 => return "GRAPHICS_API_OPENGL_ES2", + .gles_3 => return "GRAPHICS_API_OPENGL_ES3", + } + } +}; + +pub const LinuxDisplayBackend = enum { + X11, + Wayland, + Both, +}; + +pub const PlatformBackend = enum { + glfw, + rgfw, + sdl, + drm, +}; + +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 = try compileRaylib(b, target, optimize, Options.getOptions(b)); + + lib.installHeader(b.path("src/raylib.h"), "raylib.h"); + lib.installHeader(b.path("src/raymath.h"), "raymath.h"); + lib.installHeader(b.path("src/rlgl.h"), "rlgl.h"); + + b.installArtifact(lib); +} + +fn waylandGenerate( + b: *std.Build, + raylib: *std.Build.Step.Compile, + comptime protocol: []const u8, + comptime basename: []const u8, +) void { + const waylandDir = "src/external/glfw/deps/wayland"; + const protocolDir = b.pathJoin(&.{ waylandDir, protocol }); + const clientHeader = basename ++ ".h"; + const privateCode = basename ++ "-code.h"; + + const client_step = b.addSystemCommand(&.{ "wayland-scanner", "client-header" }); + client_step.addFileArg(b.path(protocolDir)); + raylib.addIncludePath(client_step.addOutputFileArg(clientHeader).dirname()); + + const private_step = b.addSystemCommand(&.{ "wayland-scanner", "private-code" }); + private_step.addFileArg(b.path(protocolDir)); + raylib.addIncludePath(private_step.addOutputFileArg(privateCode).dirname()); + + raylib.step.dependOn(&client_step.step); + raylib.step.dependOn(&private_step.step); +} diff --git a/src/build.zig b/src/build.zig deleted file mode 100644 index 23b4d66b7..000000000 --- a/src/build.zig +++ /dev/null @@ -1,455 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); - -/// Minimum supported version of Zig -const min_ver = "0.12.0"; - -comptime { - const order = std.SemanticVersion.order; - const parse = std.SemanticVersion.parse; - if (order(builtin.zig_version, parse(min_ver) catch unreachable) == .lt) - @compileError("Raylib requires zig version " ++ min_ver); -} - -// NOTE(freakmangd): I don't like using a global here, but it prevents having to -// get the flags a second time when adding raygui -var raylib_flags_arr: std.ArrayListUnmanaged([]const u8) = .{}; - -/// we're not inside the actual build script recognized by the -/// zig build system; use this type where one would otherwise -/// use `@This()` when inside the actual entrypoint file. -const BuildScript = @import("../build.zig"); - -// This has been tested with zig version 0.12.0 -pub fn addRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile { - const raylib_dep = b.dependencyFromBuildZig(BuildScript, .{ - .target = target, - .optimize = optimize, - .raudio = options.raudio, - .rmodels = options.rmodels, - .rshapes = options.rshapes, - .rtext = options.rtext, - .rtextures = options.rtextures, - .platform = options.platform, - .shared = options.shared, - .linux_display_backend = options.linux_display_backend, - .opengl_version = options.opengl_version, - .config = options.config, - }); - const raylib = raylib_dep.artifact("raylib"); - - if (options.raygui) { - const raygui_dep = b.dependency(options.raygui_dependency_name, .{}); - addRaygui(b, raylib, raygui_dep); - } - - return raylib; -} - -fn setDesktopPlatform(raylib: *std.Build.Step.Compile, platform: PlatformBackend) void { - raylib.defineCMacro("PLATFORM_DESKTOP", null); - - switch (platform) { - .glfw => raylib.defineCMacro("PLATFORM_DESKTOP_GLFW", null), - .rgfw => raylib.defineCMacro("PLATFORM_DESKTOP_RGFW", null), - .sdl => raylib.defineCMacro("PLATFORM_DESKTOP_SDL", null), - else => {}, - } -} - -/// TODO: Once the minimum supported version is bumped to 0.14.0, it can be simplified again: -/// https://github.com/raysan5/raylib/pull/4375#issuecomment-2408998315 -/// https://github.com/raysan5/raylib/blob/9b9c72eb0dc705cde194b053a366a40396acfb67/src/build.zig#L54-L56 -fn srcDir(b: *std.Build) []const u8 { - comptime { - const order = std.SemanticVersion.order; - const parse = std.SemanticVersion.parse; - if (order(parse(min_ver) catch unreachable, parse("0.14.0") catch unreachable) != .lt) - @compileError("Please take a look at this function again"); - } - - const src_file = std.fs.path.relative(b.allocator, ".", @src().file) catch @panic("OOM"); - return std.fs.path.dirname(src_file) orelse "."; -} - -/// A list of all flags from `src/config.h` that one may override -const config_h_flags = outer: { - // Set this value higher if compile errors happen as `src/config.h` gets larger - @setEvalBranchQuota(1 << 20); - - const config_h = @embedFile("config.h"); - var flags: [std.mem.count(u8, config_h, "\n") + 1][]const u8 = undefined; - - var i = 0; - var lines = std.mem.tokenizeScalar(u8, config_h, '\n'); - while (lines.next()) |line| { - if (!std.mem.containsAtLeast(u8, line, 1, "SUPPORT")) continue; - if (std.mem.startsWith(u8, line, "//")) continue; - if (std.mem.startsWith(u8, line, "#if")) continue; - - var flag = std.mem.trimLeft(u8, line, " \t"); // Trim whitespace - flag = flag["#define ".len - 1 ..]; // Remove #define - flag = std.mem.trimLeft(u8, flag, " \t"); // Trim whitespace - flag = flag[0 .. std.mem.indexOf(u8, flag, " ") orelse continue]; // Flag is only one word, so capture till space - flag = "-D" ++ flag; // Prepend with -D - - flags[i] = flag; - i += 1; - } - - // Uncomment this to check what flags normally get passed - //@compileLog(flags[0..i].*); - break :outer flags[0..i].*; -}; - -fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile { - raylib_flags_arr.clearRetainingCapacity(); - - const shared_flags = &[_][]const u8{ - "-fPIC", - "-DBUILD_LIBTYPE_SHARED", - }; - try raylib_flags_arr.appendSlice(b.allocator, &[_][]const u8{ - "-std=gnu99", - "-D_GNU_SOURCE", - "-DGL_SILENCE_DEPRECATION=199309L", - "-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/3674 - }); - if (options.config.len > 0) { - // Sets a flag indiciating the use of a custom `config.h` - try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS"); - - // Splits a space-separated list of config flags into multiple flags - // - // Note: This means certain flags like `-x c++` won't be processed properly. - // `-xc++` or similar should be used when possible - var config_iter = std.mem.tokenizeScalar(u8, options.config, ' '); - - // Apply config flags supplied by the user - while (config_iter.next()) |config_flag| - try raylib_flags_arr.append(b.allocator, config_flag); - - // Apply all relevant configs from `src/config.h` *except* the user-specified ones - // - // Note: Currently using a suboptimal `O(m*n)` time algorithm where: - // `m` corresponds roughly to the number of lines in `src/config.h` - // `n` corresponds to the number of user-specified flags - outer: for (config_h_flags) |flag| { - // If a user already specified the flag, skip it - while (config_iter.next()) |config_flag| { - // For a user-specified flag to match, it must share the same prefix and have the - // same length or be followed by an equals sign - if (!std.mem.startsWith(u8, config_flag, flag)) continue; - if (config_flag.len == flag.len or config_flag[flag.len] == '=') continue :outer; - } - - // Otherwise, append default value from config.h to compile flags - try raylib_flags_arr.append(b.allocator, flag); - } - } - - if (options.shared) { - try raylib_flags_arr.appendSlice(b.allocator, shared_flags); - } - - const raylib = if (options.shared) - b.addSharedLibrary(.{ - .name = "raylib", - .target = target, - .optimize = optimize, - }) - else - b.addStaticLibrary(.{ - .name = "raylib", - .target = target, - .optimize = optimize, - }); - raylib.linkLibC(); - - // No GLFW required on PLATFORM_DRM - if (options.platform != .drm) { - raylib.addIncludePath(b.path(b.pathJoin(&.{ srcDir(b), "external/glfw/include" }))); - } - - var c_source_files = try std.ArrayList([]const u8).initCapacity(b.allocator, 2); - c_source_files.appendSliceAssumeCapacity(&.{ "rcore.c", "utils.c" }); - - if (options.raudio) { - try c_source_files.append("raudio.c"); - } - if (options.rmodels) { - try c_source_files.append("rmodels.c"); - } - if (options.rshapes) { - try c_source_files.append("rshapes.c"); - } - if (options.rtext) { - try c_source_files.append("rtext.c"); - } - if (options.rtextures) { - try c_source_files.append("rtextures.c"); - } - - if (options.opengl_version != .auto) { - raylib.defineCMacro(options.opengl_version.toCMacroStr(), null); - } - - switch (target.result.os.tag) { - .windows => { - try c_source_files.append("rglfw.c"); - raylib.linkSystemLibrary("winmm"); - raylib.linkSystemLibrary("gdi32"); - raylib.linkSystemLibrary("opengl32"); - - setDesktopPlatform(raylib, options.platform); - }, - .linux => { - if (options.platform != .drm) { - try c_source_files.append("rglfw.c"); - raylib.linkSystemLibrary("GL"); - raylib.linkSystemLibrary("rt"); - raylib.linkSystemLibrary("dl"); - raylib.linkSystemLibrary("m"); - - raylib.addLibraryPath(.{ .cwd_relative = "/usr/lib" }); - raylib.addIncludePath(.{ .cwd_relative = "/usr/include" }); - if (options.linux_display_backend == .X11 or options.linux_display_backend == .Both) { - raylib.defineCMacro("_GLFW_X11", null); - raylib.linkSystemLibrary("X11"); - } - - if (options.linux_display_backend == .Wayland or options.linux_display_backend == .Both) { - _ = b.findProgram(&.{"wayland-scanner"}, &.{}) catch { - std.log.err( - \\ `wayland-scanner` may not be installed on the system. - \\ You can switch to X11 in your `build.zig` by changing `Options.linux_display_backend` - , .{}); - @panic("`wayland-scanner` not found"); - }; - raylib.defineCMacro("_GLFW_WAYLAND", null); - raylib.linkSystemLibrary("wayland-client"); - raylib.linkSystemLibrary("wayland-cursor"); - raylib.linkSystemLibrary("wayland-egl"); - raylib.linkSystemLibrary("xkbcommon"); - waylandGenerate(b, raylib, "wayland.xml", "wayland-client-protocol"); - waylandGenerate(b, raylib, "xdg-shell.xml", "xdg-shell-client-protocol"); - waylandGenerate(b, raylib, "xdg-decoration-unstable-v1.xml", "xdg-decoration-unstable-v1-client-protocol"); - waylandGenerate(b, raylib, "viewporter.xml", "viewporter-client-protocol"); - waylandGenerate(b, raylib, "relative-pointer-unstable-v1.xml", "relative-pointer-unstable-v1-client-protocol"); - waylandGenerate(b, raylib, "pointer-constraints-unstable-v1.xml", "pointer-constraints-unstable-v1-client-protocol"); - waylandGenerate(b, raylib, "fractional-scale-v1.xml", "fractional-scale-v1-client-protocol"); - waylandGenerate(b, raylib, "xdg-activation-v1.xml", "xdg-activation-v1-client-protocol"); - waylandGenerate(b, raylib, "idle-inhibit-unstable-v1.xml", "idle-inhibit-unstable-v1-client-protocol"); - } - setDesktopPlatform(raylib, options.platform); - } else { - if (options.opengl_version == .auto) { - raylib.linkSystemLibrary("GLESv2"); - raylib.defineCMacro("GRAPHICS_API_OPENGL_ES2", null); - } - - raylib.linkSystemLibrary("EGL"); - raylib.linkSystemLibrary("drm"); - raylib.linkSystemLibrary("gbm"); - raylib.linkSystemLibrary("pthread"); - raylib.linkSystemLibrary("rt"); - raylib.linkSystemLibrary("m"); - raylib.linkSystemLibrary("dl"); - raylib.addIncludePath(.{ .cwd_relative = "/usr/include/libdrm" }); - - raylib.defineCMacro("PLATFORM_DRM", null); - raylib.defineCMacro("EGL_NO_X11", null); - raylib.defineCMacro("DEFAULT_BATCH_BUFFER_ELEMENT", "2048"); - } - }, - .freebsd, .openbsd, .netbsd, .dragonfly => { - try c_source_files.append("rglfw.c"); - raylib.linkSystemLibrary("GL"); - raylib.linkSystemLibrary("rt"); - raylib.linkSystemLibrary("dl"); - raylib.linkSystemLibrary("m"); - raylib.linkSystemLibrary("X11"); - raylib.linkSystemLibrary("Xrandr"); - raylib.linkSystemLibrary("Xinerama"); - raylib.linkSystemLibrary("Xi"); - raylib.linkSystemLibrary("Xxf86vm"); - raylib.linkSystemLibrary("Xcursor"); - - setDesktopPlatform(raylib, options.platform); - }, - .macos => { - // On macos rglfw.c include Objective-C files. - try raylib_flags_arr.append(b.allocator, "-ObjC"); - raylib.root_module.addCSourceFile(.{ - .file = b.path(b.pathJoin(&.{ srcDir(b), "rglfw.c" })), - .flags = raylib_flags_arr.items, - }); - _ = raylib_flags_arr.pop(); - raylib.linkFramework("Foundation"); - raylib.linkFramework("CoreServices"); - raylib.linkFramework("CoreGraphics"); - raylib.linkFramework("AppKit"); - raylib.linkFramework("IOKit"); - - setDesktopPlatform(raylib, options.platform); - }, - .emscripten => { - raylib.defineCMacro("PLATFORM_WEB", null); - if (options.opengl_version == .auto) { - raylib.defineCMacro("GRAPHICS_API_OPENGL_ES2", null); - } - - if (b.sysroot == null) { - @panic("Pass '--sysroot \"$EMSDK/upstream/emscripten\"'"); - } - - const cache_include = b.pathJoin(&.{ b.sysroot.?, "cache", "sysroot", "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(.{ .cwd_relative = cache_include }); - }, - else => { - @panic("Unsupported OS"); - }, - } - - raylib.root_module.addCSourceFiles(.{ - .root = b.path(srcDir(b)), - .files = c_source_files.items, - .flags = raylib_flags_arr.items, - }); - - return raylib; -} - -/// This function does not need to be called if you passed .raygui = true to addRaylib -pub fn addRaygui(b: *std.Build, raylib: *std.Build.Step.Compile, raygui_dep: *std.Build.Dependency) void { - if (raylib_flags_arr.items.len == 0) { - @panic( - \\argument 2 `raylib` in `addRaygui` must come from b.dependency("raylib", ...).artifact("raylib") - ); - } - - var gen_step = b.addWriteFiles(); - raylib.step.dependOn(&gen_step.step); - - const raygui_c_path = gen_step.add("raygui.c", "#define RAYGUI_IMPLEMENTATION\n#include \"raygui.h\"\n"); - raylib.addCSourceFile(.{ .file = raygui_c_path, .flags = raylib_flags_arr.items }); - raylib.addIncludePath(raygui_dep.path("src")); - - raylib.installHeader(raygui_dep.path("src/raygui.h"), "raygui.h"); -} - -pub const Options = struct { - raudio: bool = true, - rmodels: bool = true, - rshapes: bool = true, - rtext: bool = true, - rtextures: bool = true, - raygui: bool = false, - platform: PlatformBackend = .glfw, - shared: bool = false, - linux_display_backend: LinuxDisplayBackend = .Both, - opengl_version: OpenglVersion = .auto, - /// config should be a list of space-separated cflags, eg, "-DSUPPORT_CUSTOM_FRAME_CONTROL" - config: []const u8 = &.{}, - - raygui_dependency_name: []const u8 = "raygui", - - const defaults = Options{}; - - fn getOptions(b: *std.Build) Options { - return .{ - .platform = b.option(PlatformBackend, "platform", "Choose the platform backedn for desktop target") orelse defaults.platform, - .raudio = b.option(bool, "raudio", "Compile with audio support") orelse defaults.raudio, - .raygui = b.option(bool, "raygui", "Compile with raygui support") orelse defaults.raygui, - .rmodels = b.option(bool, "rmodels", "Compile with models support") orelse defaults.rmodels, - .rtext = b.option(bool, "rtext", "Compile with text support") orelse defaults.rtext, - .rtextures = b.option(bool, "rtextures", "Compile with textures support") orelse defaults.rtextures, - .rshapes = b.option(bool, "rshapes", "Compile with shapes support") orelse defaults.rshapes, - .shared = b.option(bool, "shared", "Compile as shared library") orelse defaults.shared, - .linux_display_backend = b.option(LinuxDisplayBackend, "linux_display_backend", "Linux display backend to use") orelse defaults.linux_display_backend, - .opengl_version = b.option(OpenglVersion, "opengl_version", "OpenGL version to use") orelse defaults.opengl_version, - .config = b.option([]const u8, "config", "Compile with custom define macros overriding config.h") orelse &.{}, - }; - } -}; - -pub const OpenglVersion = enum { - auto, - gl_1_1, - gl_2_1, - gl_3_3, - gl_4_3, - gles_2, - gles_3, - - pub fn toCMacroStr(self: @This()) []const u8 { - switch (self) { - .auto => @panic("OpenglVersion.auto cannot be turned into a C macro string"), - .gl_1_1 => return "GRAPHICS_API_OPENGL_11", - .gl_2_1 => return "GRAPHICS_API_OPENGL_21", - .gl_3_3 => return "GRAPHICS_API_OPENGL_33", - .gl_4_3 => return "GRAPHICS_API_OPENGL_43", - .gles_2 => return "GRAPHICS_API_OPENGL_ES2", - .gles_3 => return "GRAPHICS_API_OPENGL_ES3", - } - } -}; - -pub const LinuxDisplayBackend = enum { - X11, - Wayland, - Both, -}; - -pub const PlatformBackend = enum { - glfw, - rgfw, - sdl, - drm, -}; - -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 = try compileRaylib(b, target, optimize, Options.getOptions(b)); - - lib.installHeader(b.path(b.pathJoin(&.{ srcDir(b), "raylib.h" })), "raylib.h"); - lib.installHeader(b.path(b.pathJoin(&.{ srcDir(b), "raymath.h" })), "raymath.h"); - lib.installHeader(b.path(b.pathJoin(&.{ srcDir(b), "rlgl.h" })), "rlgl.h"); - - b.installArtifact(lib); -} - -fn waylandGenerate( - b: *std.Build, - raylib: *std.Build.Step.Compile, - comptime protocol: []const u8, - comptime basename: []const u8, -) void { - const waylandDir = b.pathJoin(&.{ srcDir(b), "external/glfw/deps/wayland" }); - const protocolDir = b.pathJoin(&.{ waylandDir, protocol }); - const clientHeader = basename ++ ".h"; - const privateCode = basename ++ "-code.h"; - - const client_step = b.addSystemCommand(&.{ "wayland-scanner", "client-header" }); - client_step.addFileArg(b.path(protocolDir)); - raylib.addIncludePath(client_step.addOutputFileArg(clientHeader).dirname()); - - const private_step = b.addSystemCommand(&.{ "wayland-scanner", "private-code" }); - private_step.addFileArg(b.path(protocolDir)); - raylib.addIncludePath(private_step.addOutputFileArg(privateCode).dirname()); - - raylib.step.dependOn(&client_step.step); - raylib.step.dependOn(&private_step.step); -} From 72f8c354b0a7a701a17448aad8b216aacb682846 Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Mon, 21 Oct 2024 07:17:50 -0700 Subject: [PATCH 107/115] [Raymath] Add C++ operator overloads for common math function (#4385) * Update raylib_api.* by CI * Add math operators for C++ to raymath * better #define for disabling C++ operators --------- Co-authored-by: github-actions[bot] --- src/raymath.h | 319 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 318 insertions(+), 1 deletion(-) diff --git a/src/raymath.h b/src/raymath.h index 62d52f8fd..84e1ff806 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -26,7 +26,9 @@ * #define RAYMATH_STATIC_INLINE * Define static inline functions code, so #include header suffices for use. * This may use up lots of memory. -* +* +* #define RAYMATH_DISABLE_OPERATORS +* Disables C++ operator overloads for raymath types. * * LICENSE: zlib/libpng * @@ -2580,4 +2582,319 @@ RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotatio } } + +// optional C++ math operators +// define RAYLIB_DISABLE_VECTOR_OPERATORS to disable +#if defined(__cplusplus) && !defined(RAYMATH_DISABLE_OPERATORS) + +//------------------Vector2-----------------// +static constexpr Vector2 Vector2Zeros = { 0, 0 }; +static constexpr Vector2 Vector2Ones = { 1, 1 }; +static constexpr Vector2 Vector2UnitX = { 1, 0 }; +static constexpr Vector2 Vector2UnitY = { 0, 1 }; + +inline Vector2 operator + (const Vector2& lhs, const Vector2& rhs) +{ + return Vector2Add(lhs, rhs); +} + +inline const Vector2& operator += (Vector2& lhs, const Vector2& rhs) +{ + lhs = Vector2Add(lhs, rhs); + return lhs; +} + +inline Vector2 operator - (const Vector2& lhs, const Vector2& rhs) +{ + return Vector2Subtract(lhs, rhs); +} + +inline const Vector2& operator -= (Vector2& lhs, const Vector2& rhs) +{ + lhs = Vector2Subtract(lhs, rhs); + return lhs; +} + +inline Vector2 operator * (const Vector2& lhs, const float& rhs) +{ + return Vector2Scale(lhs, rhs); +} + +inline const Vector2& operator *= (Vector2& lhs, const float& rhs) +{ + lhs = Vector2Scale(lhs, rhs); + return lhs; +} + +inline Vector2 operator * (const Vector2& lhs, const Vector2& rhs) +{ + return Vector2Multiply(lhs, rhs); +} + +inline const Vector2& operator *= (Vector2& lhs, const Vector2& rhs) +{ + lhs = Vector2Multiply(lhs, rhs); + return lhs; +} + +inline Vector2 operator * (const Vector2& lhs, const Matrix& rhs) +{ + return Vector2Transform(lhs, rhs); +} + +inline const Vector2& operator -= (Vector2& lhs, const Matrix& rhs) +{ + lhs = Vector2Transform(lhs, rhs); + return lhs; +} + +inline Vector2 operator / (const Vector2& lhs, const float& rhs) +{ + return Vector2Scale(lhs, 1.0f / rhs); +} + +inline const Vector2& operator /= (Vector2& lhs, const float& rhs) +{ + lhs = Vector2Scale(lhs, rhs); + return lhs; +} + +inline Vector2 operator / (const Vector2& lhs, const Vector2& rhs) +{ + return Vector2Divide(lhs, rhs); +} + +inline const Vector2& operator /= (Vector2& lhs, const Vector2& rhs) +{ + lhs = Vector2Divide(lhs, rhs); + return lhs; +} + +inline bool operator == (const Vector2& lhs, const Vector2& rhs) +{ + return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y); +} + +inline bool operator != (const Vector2& lhs, const Vector2& rhs) +{ + return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y); +} + +//------------------Vector3-----------------// +static constexpr Vector3 Vector3Zeros = { 0, 0, 0 }; +static constexpr Vector3 Vector3Ones = { 1, 1, 1 }; +static constexpr Vector3 Vector3UnitX = { 1, 0, 0 }; +static constexpr Vector3 Vector3UnitY = { 0, 1, 0 }; +static constexpr Vector3 Vector3UnitZ = { 0, 0, 1 }; + +inline Vector3 operator + (const Vector3& lhs, const Vector3& rhs) +{ + return Vector3Add(lhs, rhs); +} + +inline const Vector3& operator += (Vector3& lhs, const Vector3& rhs) +{ + lhs = Vector3Add(lhs, rhs); + return lhs; +} + +inline Vector3 operator - (const Vector3& lhs, const Vector3& rhs) +{ + return Vector3Subtract(lhs, rhs); +} + +inline const Vector3& operator -= (Vector3& lhs, const Vector3& rhs) +{ + lhs = Vector3Subtract(lhs, rhs); + return lhs; +} + +inline Vector3 operator * (const Vector3& lhs, const float& rhs) +{ + return Vector3Scale(lhs, rhs); +} + +inline const Vector3& operator *= (Vector3& lhs, const float& rhs) +{ + lhs = Vector3Scale(lhs, rhs); + return lhs; +} + +inline Vector3 operator * (const Vector3& lhs, const Vector3& rhs) +{ + return Vector3Multiply(lhs, rhs); +} + +inline const Vector3& operator *= (Vector3& lhs, const Vector3& rhs) +{ + lhs = Vector3Multiply(lhs, rhs); + return lhs; +} + +inline Vector3 operator * (const Vector3& lhs, const Matrix& rhs) +{ + return Vector3Transform(lhs, rhs); +} + +inline const Vector3& operator -= (Vector3& lhs, const Matrix& rhs) +{ + lhs = Vector3Transform(lhs, rhs); + return lhs; +} + +inline Vector3 operator / (const Vector3& lhs, const float& rhs) +{ + return Vector3Scale(lhs, 1.0f / rhs); +} + +inline const Vector3& operator /= (Vector3& lhs, const float& rhs) +{ + lhs = Vector3Scale(lhs, rhs); + return lhs; +} + +inline Vector3 operator / (const Vector3& lhs, const Vector3& rhs) +{ + return Vector3Divide(lhs, rhs); +} + +inline const Vector3& operator /= (Vector3& lhs, const Vector3& rhs) +{ + lhs = Vector3Divide(lhs, rhs); + return lhs; +} + +inline bool operator == (const Vector3& lhs, const Vector3& rhs) +{ + return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y) && FloatEquals(lhs.z, rhs.z); +} + +inline bool operator != (const Vector3& lhs, const Vector3& rhs) +{ + return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y) || !FloatEquals(lhs.z, rhs.z); +} + +//------------------Vector4-----------------// +static constexpr Vector4 Vector4Zeros = { 0, 0, 0, 0 }; +static constexpr Vector4 Vector4Ones = { 1, 1, 1, 1 }; +static constexpr Vector4 Vector4UnitX = { 1, 0, 0, 0 }; +static constexpr Vector4 Vector4UnitY = { 0, 1, 0, 0 }; +static constexpr Vector4 Vector4UnitZ = { 0, 0, 1, 0 }; +static constexpr Vector4 Vector4UnitW = { 0, 0, 0, 1 }; + +inline Vector4 operator + (const Vector4& lhs, const Vector4& rhs) +{ + return Vector4Add(lhs, rhs); +} + +inline const Vector4& operator += (Vector4& lhs, const Vector4& rhs) +{ + lhs = Vector4Add(lhs, rhs); + return lhs; +} + +inline Vector4 operator - (const Vector4& lhs, const Vector4& rhs) +{ + return Vector4Subtract(lhs, rhs); +} + +inline const Vector4& operator -= (Vector4& lhs, const Vector4& rhs) +{ + lhs = Vector4Subtract(lhs, rhs); + return lhs; +} + +inline Vector4 operator * (const Vector4& lhs, const float& rhs) +{ + return Vector4Scale(lhs, rhs); +} + +inline const Vector4& operator *= (Vector4& lhs, const float& rhs) +{ + lhs = Vector4Scale(lhs, rhs); + return lhs; +} + +inline Vector4 operator * (const Vector4& lhs, const Vector4& rhs) +{ + return Vector4Multiply(lhs, rhs); +} + +inline const Vector4& operator *= (Vector4& lhs, const Vector4& rhs) +{ + lhs = Vector4Multiply(lhs, rhs); + return lhs; +} + +inline Vector4 operator / (const Vector4& lhs, const float& rhs) +{ + return Vector4Scale(lhs, 1.0f / rhs); +} + +inline const Vector4& operator /= (Vector4& lhs, const float& rhs) +{ + lhs = Vector4Scale(lhs, rhs); + return lhs; +} + +inline Vector4 operator / (const Vector4& lhs, const Vector4& rhs) +{ + return Vector4Divide(lhs, rhs); +} + +inline const Vector4& operator /= (Vector4& lhs, const Vector4& rhs) +{ + lhs = Vector4Divide(lhs, rhs); + return lhs; +} + +inline bool operator == (const Vector4& lhs, const Vector4& rhs) +{ + return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y) && FloatEquals(lhs.z, rhs.z) && FloatEquals(lhs.w, rhs.w); +} + +inline bool operator != (const Vector4& lhs, const Vector4& rhs) +{ + return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y) || !FloatEquals(lhs.z, rhs.z) || !FloatEquals(lhs.w, rhs.w); +} + +//------------------Quaternion-----------------// +static constexpr Quaternion QuaternionZeros = { 0, 0, 0, 0 }; +static constexpr Quaternion QuaternionOnes = { 1, 1, 1, 1 }; +static constexpr Quaternion QuaternionUnitX = { 0, 0, 0, 1 }; + +inline Quaternion operator + (const Quaternion& lhs, const float& rhs) +{ + return QuaternionAddValue(lhs, rhs); +} + +inline const Quaternion& operator += (Quaternion& lhs, const float& rhs) +{ + lhs = QuaternionAddValue(lhs, rhs); + return lhs; +} + +inline Quaternion operator - (const Quaternion& lhs, const float& rhs) +{ + return QuaternionSubtractValue(lhs, rhs); +} + +inline const Quaternion& operator -= (Quaternion& lhs, const float& rhs) +{ + lhs = QuaternionSubtractValue(lhs, rhs); + return lhs; +} + +inline Quaternion operator * (const Quaternion& lhs, const Matrix& rhs) +{ + return QuaternionTransform(lhs, rhs); +} + +inline const Quaternion& operator *= (Quaternion& lhs, const Matrix& rhs) +{ + lhs = QuaternionTransform(lhs, rhs); + return lhs; +} +#endif // C++ operators + #endif // RAYMATH_H From 760146821144cd2c5f4828431aee15cc8c9903f9 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 21 Oct 2024 16:25:45 +0200 Subject: [PATCH 108/115] REVIEWED: Formatting and raymath version #4385 --- src/raymath.h | 174 +++++++++++++++++++++++++------------------------- 1 file changed, 88 insertions(+), 86 deletions(-) diff --git a/src/raymath.h b/src/raymath.h index 84e1ff806..835ce8126 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -1,6 +1,6 @@ /********************************************************************************************** * -* raymath v1.5 - Math functions to work with Vector2, Vector3, Matrix and Quaternions +* raymath v2.0 - Math functions to work with Vector2, Vector3, Matrix and Quaternions * * CONVENTIONS: * - Matrix structure is defined as row-major (memory layout) but parameters naming AND all @@ -12,7 +12,7 @@ * - Functions are always self-contained, no function use another raymath function inside, * required code is directly re-implemented inside * - Functions input parameters are always received by value (2 unavoidable exceptions) -* - Functions use always a "result" variable for return +* - Functions use always a "result" variable for return (except C++ operators) * - Functions are always defined inline * - Angles are always in radians (DEG2RAD/RAD2DEG macros provided for convenience) * - No compound literals used to make sure libray is compatible with C++ @@ -27,7 +27,7 @@ * Define static inline functions code, so #include header suffices for use. * This may use up lots of memory. * -* #define RAYMATH_DISABLE_OPERATORS +* #define RAYMATH_DISABLE_CPP_OPERATORS * Disables C++ operator overloads for raymath types. * * LICENSE: zlib/libpng @@ -2582,12 +2582,12 @@ RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotatio } } +#if defined(__cplusplus) && !defined(RAYMATH_DISABLE_CPP_OPERATORS) -// optional C++ math operators -// define RAYLIB_DISABLE_VECTOR_OPERATORS to disable -#if defined(__cplusplus) && !defined(RAYMATH_DISABLE_OPERATORS) +// Optional C++ math operators +//------------------------------------------------------------------------------- -//------------------Vector2-----------------// +// Vector2 operators static constexpr Vector2 Vector2Zeros = { 0, 0 }; static constexpr Vector2 Vector2Ones = { 1, 1 }; static constexpr Vector2 Vector2UnitX = { 1, 0 }; @@ -2595,92 +2595,92 @@ static constexpr Vector2 Vector2UnitY = { 0, 1 }; inline Vector2 operator + (const Vector2& lhs, const Vector2& rhs) { - return Vector2Add(lhs, rhs); + return Vector2Add(lhs, rhs); } inline const Vector2& operator += (Vector2& lhs, const Vector2& rhs) { - lhs = Vector2Add(lhs, rhs); - return lhs; + lhs = Vector2Add(lhs, rhs); + return lhs; } inline Vector2 operator - (const Vector2& lhs, const Vector2& rhs) { - return Vector2Subtract(lhs, rhs); + return Vector2Subtract(lhs, rhs); } inline const Vector2& operator -= (Vector2& lhs, const Vector2& rhs) { - lhs = Vector2Subtract(lhs, rhs); - return lhs; + lhs = Vector2Subtract(lhs, rhs); + return lhs; } inline Vector2 operator * (const Vector2& lhs, const float& rhs) { - return Vector2Scale(lhs, rhs); + return Vector2Scale(lhs, rhs); } inline const Vector2& operator *= (Vector2& lhs, const float& rhs) { - lhs = Vector2Scale(lhs, rhs); - return lhs; + lhs = Vector2Scale(lhs, rhs); + return lhs; } inline Vector2 operator * (const Vector2& lhs, const Vector2& rhs) { - return Vector2Multiply(lhs, rhs); + return Vector2Multiply(lhs, rhs); } inline const Vector2& operator *= (Vector2& lhs, const Vector2& rhs) { - lhs = Vector2Multiply(lhs, rhs); - return lhs; + lhs = Vector2Multiply(lhs, rhs); + return lhs; } inline Vector2 operator * (const Vector2& lhs, const Matrix& rhs) { - return Vector2Transform(lhs, rhs); + return Vector2Transform(lhs, rhs); } inline const Vector2& operator -= (Vector2& lhs, const Matrix& rhs) { - lhs = Vector2Transform(lhs, rhs); - return lhs; + lhs = Vector2Transform(lhs, rhs); + return lhs; } inline Vector2 operator / (const Vector2& lhs, const float& rhs) { - return Vector2Scale(lhs, 1.0f / rhs); + return Vector2Scale(lhs, 1.0f / rhs); } inline const Vector2& operator /= (Vector2& lhs, const float& rhs) { - lhs = Vector2Scale(lhs, rhs); - return lhs; + lhs = Vector2Scale(lhs, rhs); + return lhs; } inline Vector2 operator / (const Vector2& lhs, const Vector2& rhs) { - return Vector2Divide(lhs, rhs); + return Vector2Divide(lhs, rhs); } inline const Vector2& operator /= (Vector2& lhs, const Vector2& rhs) { - lhs = Vector2Divide(lhs, rhs); - return lhs; + lhs = Vector2Divide(lhs, rhs); + return lhs; } inline bool operator == (const Vector2& lhs, const Vector2& rhs) { - return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y); + return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y); } inline bool operator != (const Vector2& lhs, const Vector2& rhs) { - return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y); + return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y); } -//------------------Vector3-----------------// +// Vector3 operators static constexpr Vector3 Vector3Zeros = { 0, 0, 0 }; static constexpr Vector3 Vector3Ones = { 1, 1, 1 }; static constexpr Vector3 Vector3UnitX = { 1, 0, 0 }; @@ -2689,92 +2689,92 @@ static constexpr Vector3 Vector3UnitZ = { 0, 0, 1 }; inline Vector3 operator + (const Vector3& lhs, const Vector3& rhs) { - return Vector3Add(lhs, rhs); + return Vector3Add(lhs, rhs); } inline const Vector3& operator += (Vector3& lhs, const Vector3& rhs) { - lhs = Vector3Add(lhs, rhs); - return lhs; + lhs = Vector3Add(lhs, rhs); + return lhs; } inline Vector3 operator - (const Vector3& lhs, const Vector3& rhs) { - return Vector3Subtract(lhs, rhs); + return Vector3Subtract(lhs, rhs); } inline const Vector3& operator -= (Vector3& lhs, const Vector3& rhs) { - lhs = Vector3Subtract(lhs, rhs); - return lhs; + lhs = Vector3Subtract(lhs, rhs); + return lhs; } inline Vector3 operator * (const Vector3& lhs, const float& rhs) { - return Vector3Scale(lhs, rhs); + return Vector3Scale(lhs, rhs); } inline const Vector3& operator *= (Vector3& lhs, const float& rhs) { - lhs = Vector3Scale(lhs, rhs); - return lhs; + lhs = Vector3Scale(lhs, rhs); + return lhs; } inline Vector3 operator * (const Vector3& lhs, const Vector3& rhs) { - return Vector3Multiply(lhs, rhs); + return Vector3Multiply(lhs, rhs); } inline const Vector3& operator *= (Vector3& lhs, const Vector3& rhs) { - lhs = Vector3Multiply(lhs, rhs); - return lhs; + lhs = Vector3Multiply(lhs, rhs); + return lhs; } inline Vector3 operator * (const Vector3& lhs, const Matrix& rhs) { - return Vector3Transform(lhs, rhs); + return Vector3Transform(lhs, rhs); } inline const Vector3& operator -= (Vector3& lhs, const Matrix& rhs) { - lhs = Vector3Transform(lhs, rhs); - return lhs; + lhs = Vector3Transform(lhs, rhs); + return lhs; } inline Vector3 operator / (const Vector3& lhs, const float& rhs) { - return Vector3Scale(lhs, 1.0f / rhs); + return Vector3Scale(lhs, 1.0f / rhs); } inline const Vector3& operator /= (Vector3& lhs, const float& rhs) { - lhs = Vector3Scale(lhs, rhs); - return lhs; + lhs = Vector3Scale(lhs, rhs); + return lhs; } inline Vector3 operator / (const Vector3& lhs, const Vector3& rhs) { - return Vector3Divide(lhs, rhs); + return Vector3Divide(lhs, rhs); } inline const Vector3& operator /= (Vector3& lhs, const Vector3& rhs) { - lhs = Vector3Divide(lhs, rhs); - return lhs; + lhs = Vector3Divide(lhs, rhs); + return lhs; } inline bool operator == (const Vector3& lhs, const Vector3& rhs) { - return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y) && FloatEquals(lhs.z, rhs.z); + return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y) && FloatEquals(lhs.z, rhs.z); } inline bool operator != (const Vector3& lhs, const Vector3& rhs) { - return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y) || !FloatEquals(lhs.z, rhs.z); + return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y) || !FloatEquals(lhs.z, rhs.z); } -//------------------Vector4-----------------// +// Vector4 operators static constexpr Vector4 Vector4Zeros = { 0, 0, 0, 0 }; static constexpr Vector4 Vector4Ones = { 1, 1, 1, 1 }; static constexpr Vector4 Vector4UnitX = { 1, 0, 0, 0 }; @@ -2784,117 +2784,119 @@ static constexpr Vector4 Vector4UnitW = { 0, 0, 0, 1 }; inline Vector4 operator + (const Vector4& lhs, const Vector4& rhs) { - return Vector4Add(lhs, rhs); + return Vector4Add(lhs, rhs); } inline const Vector4& operator += (Vector4& lhs, const Vector4& rhs) { - lhs = Vector4Add(lhs, rhs); - return lhs; + lhs = Vector4Add(lhs, rhs); + return lhs; } inline Vector4 operator - (const Vector4& lhs, const Vector4& rhs) { - return Vector4Subtract(lhs, rhs); + return Vector4Subtract(lhs, rhs); } inline const Vector4& operator -= (Vector4& lhs, const Vector4& rhs) { - lhs = Vector4Subtract(lhs, rhs); - return lhs; + lhs = Vector4Subtract(lhs, rhs); + return lhs; } inline Vector4 operator * (const Vector4& lhs, const float& rhs) { - return Vector4Scale(lhs, rhs); + return Vector4Scale(lhs, rhs); } inline const Vector4& operator *= (Vector4& lhs, const float& rhs) { - lhs = Vector4Scale(lhs, rhs); - return lhs; + lhs = Vector4Scale(lhs, rhs); + return lhs; } inline Vector4 operator * (const Vector4& lhs, const Vector4& rhs) { - return Vector4Multiply(lhs, rhs); + return Vector4Multiply(lhs, rhs); } inline const Vector4& operator *= (Vector4& lhs, const Vector4& rhs) { - lhs = Vector4Multiply(lhs, rhs); - return lhs; + lhs = Vector4Multiply(lhs, rhs); + return lhs; } inline Vector4 operator / (const Vector4& lhs, const float& rhs) { - return Vector4Scale(lhs, 1.0f / rhs); + return Vector4Scale(lhs, 1.0f / rhs); } inline const Vector4& operator /= (Vector4& lhs, const float& rhs) { - lhs = Vector4Scale(lhs, rhs); - return lhs; + lhs = Vector4Scale(lhs, rhs); + return lhs; } inline Vector4 operator / (const Vector4& lhs, const Vector4& rhs) { - return Vector4Divide(lhs, rhs); + return Vector4Divide(lhs, rhs); } inline const Vector4& operator /= (Vector4& lhs, const Vector4& rhs) { - lhs = Vector4Divide(lhs, rhs); - return lhs; + lhs = Vector4Divide(lhs, rhs); + return lhs; } inline bool operator == (const Vector4& lhs, const Vector4& rhs) { - return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y) && FloatEquals(lhs.z, rhs.z) && FloatEquals(lhs.w, rhs.w); + return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y) && FloatEquals(lhs.z, rhs.z) && FloatEquals(lhs.w, rhs.w); } inline bool operator != (const Vector4& lhs, const Vector4& rhs) { - return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y) || !FloatEquals(lhs.z, rhs.z) || !FloatEquals(lhs.w, rhs.w); + return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y) || !FloatEquals(lhs.z, rhs.z) || !FloatEquals(lhs.w, rhs.w); } -//------------------Quaternion-----------------// +// Quaternion operators static constexpr Quaternion QuaternionZeros = { 0, 0, 0, 0 }; static constexpr Quaternion QuaternionOnes = { 1, 1, 1, 1 }; static constexpr Quaternion QuaternionUnitX = { 0, 0, 0, 1 }; inline Quaternion operator + (const Quaternion& lhs, const float& rhs) { - return QuaternionAddValue(lhs, rhs); + return QuaternionAddValue(lhs, rhs); } inline const Quaternion& operator += (Quaternion& lhs, const float& rhs) { - lhs = QuaternionAddValue(lhs, rhs); - return lhs; + lhs = QuaternionAddValue(lhs, rhs); + return lhs; } inline Quaternion operator - (const Quaternion& lhs, const float& rhs) { - return QuaternionSubtractValue(lhs, rhs); + return QuaternionSubtractValue(lhs, rhs); } inline const Quaternion& operator -= (Quaternion& lhs, const float& rhs) { - lhs = QuaternionSubtractValue(lhs, rhs); - return lhs; + lhs = QuaternionSubtractValue(lhs, rhs); + return lhs; } inline Quaternion operator * (const Quaternion& lhs, const Matrix& rhs) { - return QuaternionTransform(lhs, rhs); + return QuaternionTransform(lhs, rhs); } inline const Quaternion& operator *= (Quaternion& lhs, const Matrix& rhs) { - lhs = QuaternionTransform(lhs, rhs); - return lhs; + lhs = QuaternionTransform(lhs, rhs); + return lhs; } -#endif // C++ operators +//------------------------------------------------------------------------------- +#endif // C++ operators + #endif // RAYMATH_H From f402147a6388608853e9b5ca7b509e4723d455b1 Mon Sep 17 00:00:00 2001 From: Rapha <134700614+rapha-s@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:56:19 -0300 Subject: [PATCH 109/115] Updated instanced rendering support loading (#4408) --- src/rlgl.h | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index e4e659ac9..3d211d8c8 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -2472,25 +2472,37 @@ void rlLoadExtensions(void *loader) } // Check instanced rendering support - if (strcmp(extList[i], (const char *)"GL_ANGLE_instanced_arrays") == 0) // Web ANGLE - { - glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedANGLE"); - glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedANGLE"); - glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorANGLE"); - - if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true; - } - else - { - if ((strcmp(extList[i], (const char *)"GL_EXT_draw_instanced") == 0) && // Standard EXT - (strcmp(extList[i], (const char *)"GL_EXT_instanced_arrays") == 0)) - { + if (strstr(extList[i], (const char*)"instanced_arrays") != NULL) { //Broad check for instanced_arrays + //Specific check + if (strcmp(extList[i], (const char*)"GL_ANGLE_instanced_arrays") == 0) { //ANGLE + glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedANGLE"); + glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedANGLE"); + glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorANGLE"); + } + else if (strcmp(extList[i], (const char*)"GL_EXT_instanced_arrays") == 0) { //EXT glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedEXT"); glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedEXT"); glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorEXT"); - - if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true; + } else if (strcmp(extList[i], (const char*)"GL_NV_instanced_arrays") == 0) { //NVIDIA GLES + glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedNV"); + glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedNV"); + glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorNV"); } + //The feature will only be marked as supported if the elements from GL_XXX_instanced_arrays are present + if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true; + } else if (strstr(extList[i], (const char*)"draw_instanced") != NULL) { + + //GL_ANGLE_draw_instanced doesn't exist + if (strcmp(extList[i], (const char*)"GL_EXT_draw_instanced") == 0) { + glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedEXT"); + glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedEXT"); + } else if (strcmp(extList[i], (const char*)"GL_NV_draw_instanced") == 0) { + glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedNV"); + glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedNV"); + } + + //But the functions will at least be loaded if only GL_XX_EXT_draw_instanced exist + if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true; } // Check NPOT textures support From c935ca3168795415972fb30ef60765746867b3e7 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 21 Oct 2024 16:59:55 +0200 Subject: [PATCH 110/115] Reviewed formatting #4408 --- src/rlgl.h | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 3d211d8c8..e0c667303 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -2472,37 +2472,47 @@ void rlLoadExtensions(void *loader) } // Check instanced rendering support - if (strstr(extList[i], (const char*)"instanced_arrays") != NULL) { //Broad check for instanced_arrays - //Specific check - if (strcmp(extList[i], (const char*)"GL_ANGLE_instanced_arrays") == 0) { //ANGLE + if (strstr(extList[i], (const char*)"instanced_arrays") != NULL) // Broad check for instanced_arrays + { + // Specific check + if (strcmp(extList[i], (const char *)"GL_ANGLE_instanced_arrays") == 0) // ANGLE + { glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedANGLE"); glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedANGLE"); glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorANGLE"); } - else if (strcmp(extList[i], (const char*)"GL_EXT_instanced_arrays") == 0) { //EXT + else if (strcmp(extList[i], (const char *)"GL_EXT_instanced_arrays") == 0) // EXT + { glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedEXT"); glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedEXT"); glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorEXT"); - } else if (strcmp(extList[i], (const char*)"GL_NV_instanced_arrays") == 0) { //NVIDIA GLES + } + else if (strcmp(extList[i], (const char *)"GL_NV_instanced_arrays") == 0) // NVIDIA GLES + { glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedNV"); - glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedNV"); - glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorNV"); + glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedNV"); + glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorNV"); } - //The feature will only be marked as supported if the elements from GL_XXX_instanced_arrays are present + + // The feature will only be marked as supported if the elements from GL_XXX_instanced_arrays are present if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true; - } else if (strstr(extList[i], (const char*)"draw_instanced") != NULL) { - - //GL_ANGLE_draw_instanced doesn't exist - if (strcmp(extList[i], (const char*)"GL_EXT_draw_instanced") == 0) { + } + else if (strstr(extList[i], (const char *)"draw_instanced") != NULL) + { + // GL_ANGLE_draw_instanced doesn't exist + if (strcmp(extList[i], (const char *)"GL_EXT_draw_instanced") == 0) + { glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedEXT"); glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedEXT"); - } else if (strcmp(extList[i], (const char*)"GL_NV_draw_instanced") == 0) { + } + else if (strcmp(extList[i], (const char*)"GL_NV_draw_instanced") == 0) + { glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedNV"); glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedNV"); } - //But the functions will at least be loaded if only GL_XX_EXT_draw_instanced exist - if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true; + // But the functions will at least be loaded if only GL_XX_EXT_draw_instanced exist + if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true; } // Check NPOT textures support From f141c75cde8da26515bef8c52ab635bc57e47d47 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 21 Oct 2024 17:00:52 +0200 Subject: [PATCH 111/115] Removed trailing spaces --- src/platforms/rcore_desktop_glfw.c | 6 ++-- src/raymath.h | 2 +- src/rcore.c | 6 ++-- src/rlgl.h | 10 +++--- src/rmodels.c | 58 +++++++++++++++--------------- src/rtext.c | 2 +- src/rtextures.c | 10 +++--- 7 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index d42274d14..0bc52ac9e 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -149,7 +149,7 @@ void ToggleFullscreen(void) { // Store previous window position (in case we exit fullscreen) CORE.Window.previousPosition = CORE.Window.position; - + int monitorCount = 0; int monitorIndex = GetCurrentMonitor(); GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); @@ -1289,7 +1289,7 @@ int InitPlatform(void) // Disable GlFW auto iconify behaviour // Auto Iconify automatically minimizes (iconifies) the window if the window loses focus // additionally auto iconify restores the hardware resolution of the monitor if the window that loses focus is a fullscreen window - glfwWindowHint(GLFW_AUTO_ICONIFY, 0); + glfwWindowHint(GLFW_AUTO_ICONIFY, 0); // Check window creation flags if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) CORE.Window.fullscreen = true; @@ -1579,7 +1579,7 @@ int InitPlatform(void) int monitorWidth = 0; int monitorHeight = 0; glfwGetMonitorWorkarea(monitor, &monitorX, &monitorY, &monitorWidth, &monitorHeight); - + // Here CORE.Window.render.width/height should be used instead of CORE.Window.screen.width/height to center the window correctly when the high dpi flag is enabled. int posX = monitorX + (monitorWidth - (int)CORE.Window.render.width)/2; int posY = monitorY + (monitorHeight - (int)CORE.Window.render.height)/2; diff --git a/src/raymath.h b/src/raymath.h index 835ce8126..b1e0f1af0 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -26,7 +26,7 @@ * #define RAYMATH_STATIC_INLINE * Define static inline functions code, so #include header suffices for use. * This may use up lots of memory. -* +* * #define RAYMATH_DISABLE_CPP_OPERATORS * Disables C++ operator overloads for raymath types. * diff --git a/src/rcore.c b/src/rcore.c index 9b3eeee80..a1771d18e 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -691,7 +691,7 @@ void InitWindow(int width, int height, const char *title) // Initialize random seed SetRandomSeed((unsigned int)time(NULL)); - + TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", GetWorkingDirectory()); } @@ -3716,14 +3716,14 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi break; } } - else + else { if ((filter != NULL) && (TextFindIndex(filter, DIRECTORY_FILTER_TAG) >= 0)) { strcpy(files->paths[files->count], path); files->count++; } - + if (files->count >= files->capacity) { TRACELOG(LOG_WARNING, "FILEIO: Maximum filepath scan capacity reached (%i files)", files->capacity); diff --git a/src/rlgl.h b/src/rlgl.h index e0c667303..6cfc2dcfb 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -2486,17 +2486,17 @@ void rlLoadExtensions(void *loader) glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedEXT"); glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedEXT"); glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorEXT"); - } + } else if (strcmp(extList[i], (const char *)"GL_NV_instanced_arrays") == 0) // NVIDIA GLES { glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedNV"); glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedNV"); glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorNV"); } - + // The feature will only be marked as supported if the elements from GL_XXX_instanced_arrays are present if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true; - } + } else if (strstr(extList[i], (const char *)"draw_instanced") != NULL) { // GL_ANGLE_draw_instanced doesn't exist @@ -2504,13 +2504,13 @@ void rlLoadExtensions(void *loader) { glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedEXT"); glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedEXT"); - } + } else if (strcmp(extList[i], (const char*)"GL_NV_draw_instanced") == 0) { glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedNV"); glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedNV"); } - + // But the functions will at least be loaded if only GL_XX_EXT_draw_instanced exist if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true; } diff --git a/src/rmodels.c b/src/rmodels.c index e7208e1aa..30130d9e0 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -426,14 +426,14 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color { #if 0 // Basic implementation, do not use it! - // For a sphere with 16 rings and 16 slices it requires 8640 cos()/sin() function calls! + // For a sphere with 16 rings and 16 slices it requires 8640 cos()/sin() function calls! // New optimized version below only requires 4 cos()/sin() calls - + rlPushMatrix(); // NOTE: Transformation is applied in inverse order (scale -> translate) rlTranslatef(centerPos.x, centerPos.y, centerPos.z); rlScalef(radius, radius, radius); - + rlBegin(RL_TRIANGLES); rlColor4ub(color.r, color.g, color.b, color.a); @@ -488,7 +488,7 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color for (int i = 0; i < rings + 1; i++) { - for (int j = 0; j < slices; j++) + for (int j = 0; j < slices; j++) { vertices[0] = vertices[2]; // Rotate around y axis to set up vertices for next face vertices[1] = vertices[3]; @@ -1165,7 +1165,7 @@ bool IsModelValid(Model model) (model.meshMaterial != NULL) && // Validate mesh-material linkage (model.meshCount > 0) && // Validate mesh count (model.materialCount > 0)) result = true; // Validate material count - + // NOTE: Many elements could be validated from a model, including every model mesh VAO/VBOs // but some VBOs could not be used, it depends on Mesh vertex data for (int i = 0; i < model.meshCount; i++) @@ -1179,7 +1179,7 @@ bool IsModelValid(Model model) if ((model.meshes[i].indices != NULL) && (model.meshes[i].vboId[6] == 0)) { result = false; break; } // Vertex indices buffer not uploaded to GPU if ((model.meshes[i].boneIds != NULL) && (model.meshes[i].vboId[7] == 0)) { result = false; break; } // Vertex boneIds buffer not uploaded to GPU if ((model.meshes[i].boneWeights != NULL) && (model.meshes[i].vboId[8] == 0)) { result = false; break; } // Vertex boneWeights buffer not uploaded to GPU - + // NOTE: Some OpenGL versions do not support VAO, so we don't check it //if (model.meshes[i].vaoId == 0) { result = false; break } } @@ -1375,7 +1375,7 @@ void UploadMesh(Mesh *mesh, bool dynamic) rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, value, SHADER_ATTRIB_VEC4, 4); rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS); } - + if (mesh->boneWeights != NULL) { // Enable vertex attribute: boneWeights (shader-location = 8) @@ -1507,7 +1507,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel))); #ifdef RL_SUPPORT_MESH_GPU_SKINNING - // Upload Bone Transforms + // Upload Bone Transforms if (material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1 && mesh.boneMatrices) { rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount); @@ -1600,7 +1600,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS], 4, RL_UNSIGNED_BYTE, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS]); } - + // Bind mesh VBO data: vertex bone weights (shader-location = 7, if available) if (material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] != -1) { @@ -1751,15 +1751,15 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i // Upload model normal matrix (if locations available) if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel))); - + #ifdef RL_SUPPORT_MESH_GPU_SKINNING - // Upload Bone Transforms + // Upload Bone Transforms if (material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1 && mesh.boneMatrices) { rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount); } #endif - + //----------------------------------------------------- // Bind active texture maps (if available) @@ -1845,7 +1845,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS], 4, RL_UNSIGNED_BYTE, 0, 0, 0); rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS]); } - + // Bind mesh VBO data: vertex bone weights (shader-location = 7, if available) if (material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] != -1) { @@ -2205,7 +2205,7 @@ bool IsMaterialValid(Material material) if ((material.maps != NULL) && // Validate material contain some map (material.shader.id > 0)) result = true; // Validate material shader is valid - + // TODO: Check if available maps contain loaded textures return result; @@ -2368,20 +2368,20 @@ void UpdateModelAnimationBoneMatrices(Model model, ModelAnimation anim, int fram { if ((anim.frameCount > 0) && (anim.bones != NULL) && (anim.framePoses != NULL)) { - if (frame >= anim.frameCount) frame = frame%anim.frameCount; - + if (frame >= anim.frameCount) frame = frame%anim.frameCount; + for (int i = 0; i < model.meshCount; i++) { if (model.meshes[i].boneMatrices) { assert(model.meshes[i].boneCount == anim.boneCount); - + for (int boneId = 0; boneId < model.meshes[i].boneCount; boneId++) { Vector3 inTranslation = model.bindPose[boneId].translation; Quaternion inRotation = model.bindPose[boneId].rotation; Vector3 inScale = model.bindPose[boneId].scale; - + Vector3 outTranslation = anim.framePoses[frame][boneId].translation; Quaternion outRotation = anim.framePoses[frame][boneId].rotation; Vector3 outScale = anim.framePoses[frame][boneId].scale; @@ -2392,15 +2392,15 @@ void UpdateModelAnimationBoneMatrices(Model model, ModelAnimation anim, int fram Vector3 boneTranslation = Vector3Add( Vector3RotateByQuaternion(Vector3Multiply(outScale, invTranslation), - outRotation), outTranslation); + outRotation), outTranslation); Quaternion boneRotation = QuaternionMultiply(outRotation, invRotation); Vector3 boneScale = Vector3Multiply(outScale, invScale); - + Matrix boneMatrix = MatrixMultiply(MatrixMultiply( QuaternionToMatrix(boneRotation), MatrixTranslate(boneTranslation.x, boneTranslation.y, boneTranslation.z)), MatrixScale(boneScale.x, boneScale.y, boneScale.z)); - + model.meshes[i].boneMatrices[boneId] = boneMatrix; } } @@ -4824,12 +4824,12 @@ static Model LoadIQM(const char *fileName) } BuildPoseFromParentJoints(model.bones, model.boneCount, model.bindPose); - + for (int i = 0; i < model.meshCount; i++) { model.meshes[i].boneCount = model.boneCount; model.meshes[i].boneMatrices = RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix)); - + for (int j = 0; j < model.meshes[i].boneCount; j++) { model.meshes[i].boneMatrices[j] = MatrixIdentity(); @@ -5244,7 +5244,7 @@ static Model LoadGLTF(const char *fileName) ***********************************************************************************************/ // Macro to simplify attributes loading code - #define LOAD_ATTRIBUTE(accesor, numComp, srcType, dstPtr) LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, srcType) + #define LOAD_ATTRIBUTE(accesor, numComp, srcType, dstPtr) LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, srcType) #define LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, dstType) \ { \ @@ -5732,7 +5732,7 @@ static Model LoadGLTF(const char *fileName) TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data converted from u32 to u16, possible loss of data", fileName); } - else + else { TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data format not supported, use u16", fileName); } @@ -5920,11 +5920,11 @@ static Model LoadGLTF(const char *fileName) { memcpy(model.meshes[meshIndex].animNormals, model.meshes[meshIndex].normals, model.meshes[meshIndex].vertexCount*3*sizeof(float)); } - + // Bone Transform Matrices model.meshes[meshIndex].boneCount = model.boneCount; model.meshes[meshIndex].boneMatrices = RL_CALLOC(model.meshes[meshIndex].boneCount, sizeof(Matrix)); - + for (int j = 0; j < model.meshes[meshIndex].boneCount; j++) { model.meshes[meshIndex].boneMatrices[j] = MatrixIdentity(); @@ -6245,7 +6245,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo RL_FREE(boneChannels); } } - + if (data->skins_count > 1) { TRACELOG(LOG_WARNING, "MODEL: [%s] expected exactly one skin to load animation data from, but found %i", fileName, data->skins_count); @@ -6701,7 +6701,7 @@ static Model LoadM3D(const char *fileName) { memcpy(model.meshes[i].animVertices, model.meshes[i].vertices, model.meshes[i].vertexCount*3*sizeof(float)); memcpy(model.meshes[i].animNormals, model.meshes[i].normals, model.meshes[i].vertexCount*3*sizeof(float)); - + model.meshes[i].boneCount = model.boneCount; model.meshes[i].boneMatrices = RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix)); for (j = 0; j < model.meshes[i].boneCount; j++) diff --git a/src/rtext.c b/src/rtext.c index 86aeb0047..3510671be 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -676,7 +676,7 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz { stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL); chars[i].advanceX = (int)((float)chars[i].advanceX*scaleFactor); - + if (chh > fontSize) TRACELOG(LOG_WARNING, "FONT: Character [0x%08x] size is bigger than expected font size", ch); // Load characters images diff --git a/src/rtextures.c b/src/rtextures.c index 9fc633274..a4534a7a2 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -1007,7 +1007,7 @@ Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float // Apply aspect ratio compensation to wider side if (width > height) nx *= aspectRatio; else ny /= aspectRatio; - + // Basic perlin noise implementation (not used) //float p = (stb_perlin_noise3(nx, ny, 0.0f, 0, 0, 0); @@ -4457,7 +4457,7 @@ void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 if (source.width < 0) { flipX = true; source.width *= -1; } if (source.height < 0) source.y -= source.height; - + if (dest.width < 0) dest.width *= -1; if (dest.height < 0) dest.height *= -1; @@ -5079,10 +5079,10 @@ Color ColorAlphaBlend(Color dst, Color src, Color tint) } // Get color lerp interpolation between two colors, factor [0.0f..1.0f] -Color ColorLerp(Color color1, Color color2, float factor) -{ +Color ColorLerp(Color color1, Color color2, float factor) +{ Color color = { 0 }; - + if (factor < 0.0f) factor = 0.0f; else if (factor > 1.0f) factor = 1.0f; From f60c6d472c05212d02c715a77e068c75b0534233 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 21 Oct 2024 17:26:42 +0200 Subject: [PATCH 112/115] Update raymath.h --- src/raymath.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/raymath.h b/src/raymath.h index b1e0f1af0..71b17cc2e 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -2898,5 +2898,4 @@ inline const Quaternion& operator *= (Quaternion& lhs, const Matrix& rhs) //------------------------------------------------------------------------------- #endif // C++ operators - #endif // RAYMATH_H From a2fcbc94fd38a2703a75fbb6310a3827f97c09d5 Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Mon, 21 Oct 2024 09:38:42 -0700 Subject: [PATCH 113/115] [Raymath] Add matrix operators to raymath for C++ (#4409) * Add matrix operators to raymath for C++ * Fix spaces --- src/raymath.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/raymath.h b/src/raymath.h index 71b17cc2e..d1b5ab01e 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -2895,6 +2895,40 @@ inline const Quaternion& operator *= (Quaternion& lhs, const Matrix& rhs) lhs = QuaternionTransform(lhs, rhs); return lhs; } + +// Matrix operators +inline Matrix operator + (const Matrix& lhs, const Matrix& rhs) +{ + return MatrixAdd(lhs, rhs); +} + +inline const Matrix& operator += (Matrix& lhs, const Matrix& rhs) +{ + lhs = MatrixAdd(lhs, rhs); + return lhs; +} + +inline Matrix operator - (const Matrix& lhs, const Matrix& rhs) +{ + return MatrixSubtract(lhs, rhs); +} + +inline const Matrix& operator -= (Matrix& lhs, const Matrix& rhs) +{ + lhs = MatrixSubtract(lhs, rhs); + return lhs; +} + +inline Matrix operator * (const Matrix& lhs, const Matrix& rhs) +{ + return MatrixMultiply(lhs, rhs); +} + +inline const Matrix& operator *= (Matrix& lhs, const Matrix& rhs) +{ + lhs = MatrixMultiply(lhs, rhs); + return lhs; +} //------------------------------------------------------------------------------- #endif // C++ operators From f4cbc1fbaebfc92cf5a6786c8639d3788de12163 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 21 Oct 2024 20:47:08 +0200 Subject: [PATCH 114/115] REVIEWED: `GetGestureHoldDuration()` comments --- src/raylib.h | 2 +- src/rgestures.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index 5ae45fa9d..25ee6943f 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1215,7 +1215,7 @@ RLAPI int GetTouchPointCount(void); // Get number of t RLAPI void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags RLAPI bool IsGestureDetected(unsigned int gesture); // Check if a gesture have been detected RLAPI int GetGestureDetected(void); // Get latest detected gesture -RLAPI float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds +RLAPI float GetGestureHoldDuration(void); // Get gesture hold time in seconds RLAPI Vector2 GetGestureDragVector(void); // Get gesture drag vector RLAPI float GetGestureDragAngle(void); // Get gesture drag angle RLAPI Vector2 GetGesturePinchVector(void); // Get gesture pinch delta diff --git a/src/rgestures.h b/src/rgestures.h index 664a6e1cc..b5624be56 100644 --- a/src/rgestures.h +++ b/src/rgestures.h @@ -434,7 +434,7 @@ int GetGestureDetected(void) return (GESTURES.enabledFlags & GESTURES.current); } -// Hold time measured in ms +// Hold time measured in seconds float GetGestureHoldDuration(void) { // NOTE: time is calculated on current gesture HOLD @@ -517,7 +517,7 @@ static double rgGetCurrentTime(void) #if defined(_WIN32) unsigned long long int clockFrequency, currentTime; - QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation! + QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation! QueryPerformanceCounter(¤tTime); time = (double)currentTime/clockFrequency; // Time in seconds From ae150e9640bfa5696f63d7cbc76f8504a05bb341 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 21 Oct 2024 18:47:41 +0000 Subject: [PATCH 115/115] Update raylib_api.* by CI --- parser/output/raylib_api.json | 2 +- parser/output/raylib_api.lua | 2 +- parser/output/raylib_api.txt | 2 +- parser/output/raylib_api.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json index fca3ef72c..591fef737 100644 --- a/parser/output/raylib_api.json +++ b/parser/output/raylib_api.json @@ -5231,7 +5231,7 @@ }, { "name": "GetGestureHoldDuration", - "description": "Get gesture hold time in milliseconds", + "description": "Get gesture hold time in seconds", "returnType": "float" }, { diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua index 572b4332a..b84e3c08c 100644 --- a/parser/output/raylib_api.lua +++ b/parser/output/raylib_api.lua @@ -4577,7 +4577,7 @@ return { }, { name = "GetGestureHoldDuration", - description = "Get gesture hold time in milliseconds", + description = "Get gesture hold time in seconds", returnType = "float" }, { diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt index 1fd591151..e0d5f36b4 100644 --- a/parser/output/raylib_api.txt +++ b/parser/output/raylib_api.txt @@ -2065,7 +2065,7 @@ Function 200: GetGestureDetected() (0 input parameters) Function 201: GetGestureHoldDuration() (0 input parameters) Name: GetGestureHoldDuration Return type: float - Description: Get gesture hold time in milliseconds + Description: Get gesture hold time in seconds No input parameters Function 202: GetGestureDragVector() (0 input parameters) Name: GetGestureDragVector diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index 17d5a81e3..f59faf754 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -1281,7 +1281,7 @@ - +