From 7bde76ca2c649213546f412c28b7b05260338ad4 Mon Sep 17 00:00:00 2001 From: Reese Gallagher Date: Sat, 24 Aug 2024 12:42:38 -0400 Subject: [PATCH 01/71] [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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 UrvOg;fdBvi07*qoM6N<$g6mpWr2qf` 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 02/71] 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 03/71] (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 04/71] 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 05/71] 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 06/71] 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 07/71] [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 08/71] [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 09/71] 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 10/71] 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 11/71] 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 12/71] 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 13/71] 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 14/71] 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 15/71] [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 16/71] 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 17/71] 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 18/71] 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 19/71] 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 20/71] 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 21/71] 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 22/71] fix vld1q_f16 undeclared in arm on stb_image_resize2.h v2.10 (#4309) --- src/external/stb_image_resize2.h | 1657 +++++++++++++++++------------- 1 file changed, 963 insertions(+), 694 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__ ) - #define STBIR_STREAMOUT_PTR( star ) star __restrict__ - #define STBIR_NO_UNROLL( ptr ) __asm__ (""::"r"(ptr)) -#elif defined( __GNUC__ ) + #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)) + #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 23/71] 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 24/71] 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 25/71] 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 26/71] [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 27/71] 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 28/71] 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 29/71] 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 30/71] 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 31/71] [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 32/71] 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 33/71] 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 34/71] 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 35/71] 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 36/71] 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 37/71] 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 38/71] [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 39/71] [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 40/71] 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 41/71] 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 42/71] 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 43/71] 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 44/71] 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 45/71] 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 46/71] `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 47/71] 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 48/71] 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 49/71] 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 50/71] 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 51/71] 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 52/71] 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 53/71] 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 54/71] 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 55/71] [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 56/71] 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 57/71] [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 58/71] 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 59/71] 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 60/71] [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 61/71] [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 62/71] 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 63/71] 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 64/71] [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 65/71] 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 66/71] 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 67/71] 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 68/71] [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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 bk Date: Sun, 6 Oct 2024 08:52:01 -0500 Subject: [PATCH 69/71] [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 70/71] 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 71/71] 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) -------------------------------------------------------------------------