Merge branch 'raysan5:master' into master
This commit is contained in:
commit
7ac4a2920a
|
|
@ -8,7 +8,7 @@ Here it is a list with the ones I'm aware of:
|
||||||
|:------------------:|:-------------: | :--------:|----------------------------------------------------------------------|
|
|:------------------:|:-------------: | :--------:|----------------------------------------------------------------------|
|
||||||
| raylib | **3.7** | [C](https://en.wikipedia.org/wiki/C_(programming_language)) | https://github.com/raysan5/raylib |
|
| raylib | **3.7** | [C](https://en.wikipedia.org/wiki/C_(programming_language)) | https://github.com/raysan5/raylib |
|
||||||
| raylib-cpp | 3.7 | [C++](https://en.wikipedia.org/wiki/C%2B%2B) | https://github.com/robloach/raylib-cpp |
|
| raylib-cpp | 3.7 | [C++](https://en.wikipedia.org/wiki/C%2B%2B) | https://github.com/robloach/raylib-cpp |
|
||||||
| Raylib-cs | 3.5 | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | https://github.com/ChrisDill/Raylib-cs |
|
| Raylib-cs | 3.7 | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | https://github.com/ChrisDill/Raylib-cs |
|
||||||
| raylib-cppsharp | 2.5 | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | https://github.com/phxvyper/raylib-cppsharp |
|
| raylib-cppsharp | 2.5 | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | https://github.com/phxvyper/raylib-cppsharp |
|
||||||
| raylib-boo | 3.7 | [Boo](http://boo-language.github.io/) | https://github.com/Rabios/raylib-boo |
|
| raylib-boo | 3.7 | [Boo](http://boo-language.github.io/) | https://github.com/Rabios/raylib-boo |
|
||||||
| RaylibFS | 2.5 | [F#](https://fsharp.org/) | https://github.com/dallinbeutler/RaylibFS |
|
| RaylibFS | 2.5 | [F#](https://fsharp.org/) | https://github.com/dallinbeutler/RaylibFS |
|
||||||
|
|
@ -16,7 +16,7 @@ Here it is a list with the ones I'm aware of:
|
||||||
| raylib-d | 3.0 | [D](https://dlang.org/) | https://github.com/onroundit/raylib-d |
|
| raylib-d | 3.0 | [D](https://dlang.org/) | https://github.com/onroundit/raylib-d |
|
||||||
| bindbc-raylib | 3.0 | [D](https://dlang.org/) | https://github.com/o3o/bindbc-raylib |
|
| bindbc-raylib | 3.0 | [D](https://dlang.org/) | https://github.com/o3o/bindbc-raylib |
|
||||||
| dray | 3.5 | [D](https://dlang.org/) | https://github.com/xdrie/dray |
|
| dray | 3.5 | [D](https://dlang.org/) | https://github.com/xdrie/dray |
|
||||||
| raylib-go | 3.0 | [Go](https://golang.org/) | https://github.com/gen2brain/raylib-go |
|
| raylib-go | 3.8-dev | [Go](https://golang.org/) | https://github.com/gen2brain/raylib-go |
|
||||||
| raylib-goplus | 2.6-dev | [Go](https://golang.org/) | https://github.com/Lachee/raylib-goplus |
|
| raylib-goplus | 2.6-dev | [Go](https://golang.org/) | https://github.com/Lachee/raylib-goplus |
|
||||||
| ray-go | 2.6-dev | [Go](https://golang.org/) | https://github.com/hecate-tech/ray-go |
|
| ray-go | 2.6-dev | [Go](https://golang.org/) | https://github.com/hecate-tech/ray-go |
|
||||||
| go-raylib | 3.5 | [Go](https://golang.org/) | https://github.com/chunqian/go-raylib |
|
| go-raylib | 3.5 | [Go](https://golang.org/) | https://github.com/chunqian/go-raylib |
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
|
|
||||||
if(USE_EXTERNAL_GLFW STREQUAL "ON")
|
if(USE_EXTERNAL_GLFW STREQUAL "ON")
|
||||||
find_package(glfw3 3.2.1 REQUIRED)
|
find_package(glfw3 3.3.3 REQUIRED)
|
||||||
elseif(USE_EXTERNAL_GLFW STREQUAL "IF_POSSIBLE")
|
elseif(USE_EXTERNAL_GLFW STREQUAL "IF_POSSIBLE")
|
||||||
find_package(glfw3 3.2.1 QUIET)
|
find_package(glfw3 3.3.3 QUIET)
|
||||||
endif()
|
endif()
|
||||||
if (glfw3_FOUND)
|
if (glfw3_FOUND)
|
||||||
set(LIBS_PRIVATE ${LIBS_PRIVATE} glfw)
|
set(LIBS_PRIVATE ${LIBS_PRIVATE} glfw)
|
||||||
|
|
|
||||||
|
|
@ -257,8 +257,8 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Define include paths for required headers
|
# Define include paths for required headers
|
||||||
# NOTE: Several external required libraries (stb and others)
|
# NOTE: Some external/extras libraries could be required (stb, physac, easings...)
|
||||||
INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external
|
INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external -I$(RAYLIB_PATH)/src/extras
|
||||||
|
|
||||||
# Define additional directories containing required header files
|
# Define additional directories containing required header files
|
||||||
ifeq ($(PLATFORM),PLATFORM_RPI)
|
ifeq ($(PLATFORM),PLATFORM_RPI)
|
||||||
|
|
@ -277,7 +277,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
|
||||||
INCLUDE_PATHS += -I/usr/local/include
|
INCLUDE_PATHS += -I/usr/local/include
|
||||||
endif
|
endif
|
||||||
ifeq ($(PLATFORM_OS),LINUX)
|
ifeq ($(PLATFORM_OS),LINUX)
|
||||||
INCLUDE_PATHS = -I$(RAYLIB_H_INSTALL_PATH) -I. -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external
|
INCLUDE_PATHS += -I$(RAYLIB_H_INSTALL_PATH)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ int main(void)
|
||||||
|
|
||||||
Ray ray = { 0 }; // Picking line ray
|
Ray ray = { 0 }; // Picking line ray
|
||||||
|
|
||||||
bool collision = false;
|
RayCollision collision = { 0 };
|
||||||
|
|
||||||
SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode
|
SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode
|
||||||
|
|
||||||
|
|
@ -49,16 +49,16 @@ int main(void)
|
||||||
|
|
||||||
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
|
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
|
||||||
{
|
{
|
||||||
if (!collision)
|
if (!collision.hit)
|
||||||
{
|
{
|
||||||
ray = GetMouseRay(GetMousePosition(), camera);
|
ray = GetMouseRay(GetMousePosition(), camera);
|
||||||
|
|
||||||
// Check collision between ray and box
|
// Check collision between ray and box
|
||||||
collision = CheckCollisionRayBox(ray,
|
collision = GetRayCollisionBox(ray,
|
||||||
(BoundingBox){(Vector3){ cubePosition.x - cubeSize.x/2, cubePosition.y - cubeSize.y/2, cubePosition.z - cubeSize.z/2 },
|
(BoundingBox){(Vector3){ cubePosition.x - cubeSize.x/2, cubePosition.y - cubeSize.y/2, cubePosition.z - cubeSize.z/2 },
|
||||||
(Vector3){ cubePosition.x + cubeSize.x/2, cubePosition.y + cubeSize.y/2, cubePosition.z + cubeSize.z/2 }});
|
(Vector3){ cubePosition.x + cubeSize.x/2, cubePosition.y + cubeSize.y/2, cubePosition.z + cubeSize.z/2 }});
|
||||||
}
|
}
|
||||||
else collision = false;
|
else collision.hit = false;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -70,7 +70,7 @@ int main(void)
|
||||||
|
|
||||||
BeginMode3D(camera);
|
BeginMode3D(camera);
|
||||||
|
|
||||||
if (collision)
|
if (collision.hit)
|
||||||
{
|
{
|
||||||
DrawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, RED);
|
DrawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, RED);
|
||||||
DrawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, MAROON);
|
DrawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, MAROON);
|
||||||
|
|
@ -90,7 +90,7 @@ int main(void)
|
||||||
|
|
||||||
DrawText("Try selecting the box with mouse!", 240, 10, 20, DARKGRAY);
|
DrawText("Try selecting the box with mouse!", 240, 10, 20, DARKGRAY);
|
||||||
|
|
||||||
if (collision) DrawText("BOX SELECTED", (screenWidth - MeasureText("BOX SELECTED", 30)) / 2, (int)(screenHeight * 0.1f), 30, GREEN);
|
if (collision.hit) DrawText("BOX SELECTED", (screenWidth - MeasureText("BOX SELECTED", 30)) / 2, (int)(screenHeight * 0.1f), 30, GREEN);
|
||||||
|
|
||||||
DrawFPS(10, 10);
|
DrawFPS(10, 10);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define MAX_MODELS 6
|
#define MAX_MODELS 7
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
|
@ -30,7 +30,7 @@ int main(void)
|
||||||
const int screenWidth = 800;
|
const int screenWidth = 800;
|
||||||
const int screenHeight = 450;
|
const int screenHeight = 450;
|
||||||
|
|
||||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - model animation");
|
InitWindow(screenWidth, screenHeight, "raylib [models] example - model");
|
||||||
|
|
||||||
// Define the camera to look into our 3d world
|
// Define the camera to look into our 3d world
|
||||||
Camera camera = { 0 };
|
Camera camera = { 0 };
|
||||||
|
|
@ -48,6 +48,7 @@ int main(void)
|
||||||
model[3] = LoadModel("resources/gltf/BoxAnimated.glb");
|
model[3] = LoadModel("resources/gltf/BoxAnimated.glb");
|
||||||
model[4] = LoadModel("resources/gltf/AnimatedTriangle.gltf");
|
model[4] = LoadModel("resources/gltf/AnimatedTriangle.gltf");
|
||||||
model[5] = LoadModel("resources/gltf/AnimatedMorphCube.glb");
|
model[5] = LoadModel("resources/gltf/AnimatedMorphCube.glb");
|
||||||
|
model[6] = LoadModel("resources/gltf/vertex_colored_object.glb");
|
||||||
|
|
||||||
int currentModel = 0;
|
int currentModel = 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ int main(void)
|
||||||
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
|
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
|
||||||
{
|
{
|
||||||
// Check collision between ray and box
|
// Check collision between ray and box
|
||||||
if (CheckCollisionRayBox(GetMouseRay(GetMousePosition(), camera), bounds)) selected = !selected;
|
if (GetRayCollisionBox(GetMouseRay(GetMousePosition(), camera), bounds).hit) selected = !selected;
|
||||||
else selected = false;
|
else selected = false;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -63,53 +63,53 @@ int main(void)
|
||||||
UpdateCamera(&camera); // Update camera
|
UpdateCamera(&camera); // Update camera
|
||||||
|
|
||||||
// Display information about closest hit
|
// Display information about closest hit
|
||||||
RayHitInfo nearestHit = { 0 };
|
RayCollision collision = { 0 };
|
||||||
char *hitObjectName = "None";
|
char *hitObjectName = "None";
|
||||||
nearestHit.distance = FLT_MAX;
|
collision.distance = FLT_MAX;
|
||||||
nearestHit.hit = false;
|
collision.hit = false;
|
||||||
Color cursorColor = WHITE;
|
Color cursorColor = WHITE;
|
||||||
|
|
||||||
// Get ray and test against ground, triangle, and mesh
|
// Get ray and test against ground, triangle, and mesh
|
||||||
ray = GetMouseRay(GetMousePosition(), camera);
|
ray = GetMouseRay(GetMousePosition(), camera);
|
||||||
|
|
||||||
// Check ray collision aginst ground plane
|
// Check ray collision aginst ground plane
|
||||||
RayHitInfo groundHitInfo = GetCollisionRayGround(ray, 0.0f);
|
RayCollision groundHitInfo = GetRayCollisionGround(ray, 0.0f);
|
||||||
|
|
||||||
if ((groundHitInfo.hit) && (groundHitInfo.distance < nearestHit.distance))
|
if ((groundHitInfo.hit) && (groundHitInfo.distance < collision.distance))
|
||||||
{
|
{
|
||||||
nearestHit = groundHitInfo;
|
collision = groundHitInfo;
|
||||||
cursorColor = GREEN;
|
cursorColor = GREEN;
|
||||||
hitObjectName = "Ground";
|
hitObjectName = "Ground";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check ray collision against test triangle
|
// Check ray collision against test triangle
|
||||||
RayHitInfo triHitInfo = GetCollisionRayTriangle(ray, ta, tb, tc);
|
RayCollision triHitInfo = GetRayCollisionTriangle(ray, ta, tb, tc);
|
||||||
|
|
||||||
if ((triHitInfo.hit) && (triHitInfo.distance < nearestHit.distance))
|
if ((triHitInfo.hit) && (triHitInfo.distance < collision.distance))
|
||||||
{
|
{
|
||||||
nearestHit = triHitInfo;
|
collision = triHitInfo;
|
||||||
cursorColor = PURPLE;
|
cursorColor = PURPLE;
|
||||||
hitObjectName = "Triangle";
|
hitObjectName = "Triangle";
|
||||||
|
|
||||||
bary = Vector3Barycenter(nearestHit.position, ta, tb, tc);
|
bary = Vector3Barycenter(collision.point, ta, tb, tc);
|
||||||
hitTriangle = true;
|
hitTriangle = true;
|
||||||
}
|
}
|
||||||
else hitTriangle = false;
|
else hitTriangle = false;
|
||||||
|
|
||||||
RayHitInfo meshHitInfo = { 0 };
|
RayCollision meshHitInfo = { 0 };
|
||||||
|
|
||||||
// Check ray collision against bounding box first, before trying the full ray-mesh test
|
// Check ray collision against bounding box first, before trying the full ray-mesh test
|
||||||
if (CheckCollisionRayBox(ray, towerBBox))
|
if (GetRayCollisionBox(ray, towerBBox).hit)
|
||||||
{
|
{
|
||||||
hitMeshBBox = true;
|
hitMeshBBox = true;
|
||||||
|
|
||||||
// Check ray collision against model
|
// Check ray collision against model
|
||||||
// NOTE: It considers model.transform matrix!
|
// NOTE: It considers model.transform matrix!
|
||||||
meshHitInfo = GetCollisionRayModel(ray, tower);
|
meshHitInfo = GetRayCollisionModel(ray, tower);
|
||||||
|
|
||||||
if ((meshHitInfo.hit) && (meshHitInfo.distance < nearestHit.distance))
|
if ((meshHitInfo.hit) && (meshHitInfo.distance < collision.distance))
|
||||||
{
|
{
|
||||||
nearestHit = meshHitInfo;
|
collision = meshHitInfo;
|
||||||
cursorColor = ORANGE;
|
cursorColor = ORANGE;
|
||||||
hitObjectName = "Mesh";
|
hitObjectName = "Mesh";
|
||||||
}
|
}
|
||||||
|
|
@ -128,7 +128,7 @@ int main(void)
|
||||||
|
|
||||||
// Draw the tower
|
// Draw the tower
|
||||||
// WARNING: If scale is different than 1.0f,
|
// WARNING: If scale is different than 1.0f,
|
||||||
// not considered by GetCollisionRayModel()
|
// not considered by GetRayCollisionModel()
|
||||||
DrawModel(tower, towerPos, 1.0f, WHITE);
|
DrawModel(tower, towerPos, 1.0f, WHITE);
|
||||||
|
|
||||||
// Draw the test triangle
|
// Draw the test triangle
|
||||||
|
|
@ -140,17 +140,17 @@ int main(void)
|
||||||
if (hitMeshBBox) DrawBoundingBox(towerBBox, LIME);
|
if (hitMeshBBox) DrawBoundingBox(towerBBox, LIME);
|
||||||
|
|
||||||
// If we hit something, draw the cursor at the hit point
|
// If we hit something, draw the cursor at the hit point
|
||||||
if (nearestHit.hit)
|
if (collision.hit)
|
||||||
{
|
{
|
||||||
DrawCube(nearestHit.position, 0.3f, 0.3f, 0.3f, cursorColor);
|
DrawCube(collision.point, 0.3f, 0.3f, 0.3f, cursorColor);
|
||||||
DrawCubeWires(nearestHit.position, 0.3f, 0.3f, 0.3f, RED);
|
DrawCubeWires(collision.point, 0.3f, 0.3f, 0.3f, RED);
|
||||||
|
|
||||||
Vector3 normalEnd;
|
Vector3 normalEnd;
|
||||||
normalEnd.x = nearestHit.position.x + nearestHit.normal.x;
|
normalEnd.x = collision.point.x + collision.normal.x;
|
||||||
normalEnd.y = nearestHit.position.y + nearestHit.normal.y;
|
normalEnd.y = collision.point.y + collision.normal.y;
|
||||||
normalEnd.z = nearestHit.position.z + nearestHit.normal.z;
|
normalEnd.z = collision.point.z + collision.normal.z;
|
||||||
|
|
||||||
DrawLine3D(nearestHit.position, normalEnd, RED);
|
DrawLine3D(collision.point, normalEnd, RED);
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawRay(ray, MAROON);
|
DrawRay(ray, MAROON);
|
||||||
|
|
@ -162,21 +162,21 @@ int main(void)
|
||||||
// Draw some debug GUI text
|
// Draw some debug GUI text
|
||||||
DrawText(TextFormat("Hit Object: %s", hitObjectName), 10, 50, 10, BLACK);
|
DrawText(TextFormat("Hit Object: %s", hitObjectName), 10, 50, 10, BLACK);
|
||||||
|
|
||||||
if (nearestHit.hit)
|
if (collision.hit)
|
||||||
{
|
{
|
||||||
int ypos = 70;
|
int ypos = 70;
|
||||||
|
|
||||||
DrawText(TextFormat("Distance: %3.2f", nearestHit.distance), 10, ypos, 10, BLACK);
|
DrawText(TextFormat("Distance: %3.2f", collision.distance), 10, ypos, 10, BLACK);
|
||||||
|
|
||||||
DrawText(TextFormat("Hit Pos: %3.2f %3.2f %3.2f",
|
DrawText(TextFormat("Hit Pos: %3.2f %3.2f %3.2f",
|
||||||
nearestHit.position.x,
|
collision.point.x,
|
||||||
nearestHit.position.y,
|
collision.point.y,
|
||||||
nearestHit.position.z), 10, ypos + 15, 10, BLACK);
|
collision.point.z), 10, ypos + 15, 10, BLACK);
|
||||||
|
|
||||||
DrawText(TextFormat("Hit Norm: %3.2f %3.2f %3.2f",
|
DrawText(TextFormat("Hit Norm: %3.2f %3.2f %3.2f",
|
||||||
nearestHit.normal.x,
|
collision.normal.x,
|
||||||
nearestHit.normal.y,
|
collision.normal.y,
|
||||||
nearestHit.normal.z), 10, ypos + 30, 10, BLACK);
|
collision.normal.z), 10, ypos + 30, 10, BLACK);
|
||||||
|
|
||||||
if (hitTriangle) DrawText(TextFormat("Barycenter: %3.2f %3.2f %3.2f", bary.x, bary.y, bary.z), 10, ypos + 45, 10, BLACK);
|
if (hitTriangle) DrawText(TextFormat("Barycenter: %3.2f %3.2f %3.2f", bary.x, bary.y, bary.z), 10, ypos + 45, 10, BLACK);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ int main(void)
|
||||||
Mesh cube = GenMeshCube(1.0f, 1.0f, 1.0f);
|
Mesh cube = GenMeshCube(1.0f, 1.0f, 1.0f);
|
||||||
Model skybox = LoadModelFromMesh(cube);
|
Model skybox = LoadModelFromMesh(cube);
|
||||||
|
|
||||||
bool useHDR = false;
|
bool useHDR = true;
|
||||||
|
|
||||||
// Load skybox shader and set required locations
|
// Load skybox shader and set required locations
|
||||||
// NOTE: Some locations are automatically set at shader loading
|
// NOTE: Some locations are automatically set at shader loading
|
||||||
|
|
@ -55,13 +55,15 @@ int main(void)
|
||||||
SetShaderValue(shdrCubemap, GetShaderLocation(shdrCubemap, "equirectangularMap"), (int[1]){ 0 }, SHADER_UNIFORM_INT);
|
SetShaderValue(shdrCubemap, GetShaderLocation(shdrCubemap, "equirectangularMap"), (int[1]){ 0 }, SHADER_UNIFORM_INT);
|
||||||
|
|
||||||
char skyboxFileName[256] = { 0 };
|
char skyboxFileName[256] = { 0 };
|
||||||
|
|
||||||
|
Texture2D panorama;
|
||||||
|
|
||||||
if (useHDR)
|
if (useHDR)
|
||||||
{
|
{
|
||||||
TextCopy(skyboxFileName, "resources/dresden_square_2k.hdr");
|
TextCopy(skyboxFileName, "resources/dresden_square_2k.hdr");
|
||||||
|
|
||||||
// Load HDR panorama (sphere) texture
|
// Load HDR panorama (sphere) texture
|
||||||
Texture2D panorama = panorama = LoadTexture(skyboxFileName);
|
panorama = LoadTexture(skyboxFileName);
|
||||||
|
|
||||||
// Generate cubemap (texture with 6 quads-cube-mapping) from panorama HDR texture
|
// Generate cubemap (texture with 6 quads-cube-mapping) from panorama HDR texture
|
||||||
// NOTE 1: New texture is generated rendering to texture, shader calculates the sphere->cube coordinates mapping
|
// NOTE 1: New texture is generated rendering to texture, shader calculates the sphere->cube coordinates mapping
|
||||||
|
|
@ -69,7 +71,7 @@ int main(void)
|
||||||
// despite texture can be successfully created.. so using PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 instead of PIXELFORMAT_UNCOMPRESSED_R32G32B32A32
|
// despite texture can be successfully created.. so using PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 instead of PIXELFORMAT_UNCOMPRESSED_R32G32B32A32
|
||||||
skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = GenTextureCubemap(shdrCubemap, panorama, 1024, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8);
|
skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = GenTextureCubemap(shdrCubemap, panorama, 1024, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8);
|
||||||
|
|
||||||
UnloadTexture(panorama); // Texture not required anymore, cubemap already generated
|
//UnloadTexture(panorama); // Texture not required anymore, cubemap already generated
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -143,11 +145,11 @@ int main(void)
|
||||||
DrawGrid(10, 1.0f);
|
DrawGrid(10, 1.0f);
|
||||||
|
|
||||||
EndMode3D();
|
EndMode3D();
|
||||||
|
|
||||||
|
//DrawTextureEx(panorama, (Vector2){ 0, 0 }, 0.0f, 0.5f, WHITE);
|
||||||
|
|
||||||
if (useHDR)
|
if (useHDR) DrawText(TextFormat("Panorama image from hdrihaven.com: %s", GetFileName(skyboxFileName)), 10, GetScreenHeight() - 20, 10, BLACK);
|
||||||
DrawText(TextFormat("Panorama image from hdrihaven.com: %s", GetFileName(skyboxFileName)), 10, GetScreenHeight() - 20, 10, BLACK);
|
else DrawText(TextFormat(": %s", GetFileName(skyboxFileName)), 10, GetScreenHeight() - 20, 10, BLACK);
|
||||||
else
|
|
||||||
DrawText(TextFormat(": %s", GetFileName(skyboxFileName)), 10, GetScreenHeight() - 20, 10, BLACK);
|
|
||||||
|
|
||||||
DrawFPS(10, 10);
|
DrawFPS(10, 10);
|
||||||
|
|
||||||
|
|
@ -208,18 +210,32 @@ static TextureCubemap GenTextureCubemap(Shader shader, Texture2D panorama, int s
|
||||||
};
|
};
|
||||||
|
|
||||||
rlViewport(0, 0, size, size); // Set viewport to current fbo dimensions
|
rlViewport(0, 0, size, size); // Set viewport to current fbo dimensions
|
||||||
|
|
||||||
|
// Activate and enable texture for drawing to cubemap faces
|
||||||
|
rlActiveTextureSlot(0);
|
||||||
|
rlEnableTexture(panorama.id);
|
||||||
|
|
||||||
for (int i = 0; i < 6; i++)
|
for (int i = 0; i < 6; i++)
|
||||||
{
|
{
|
||||||
|
// Set the view matrix for the current cube face
|
||||||
rlSetUniformMatrix(shader.locs[SHADER_LOC_MATRIX_VIEW], fboViews[i]);
|
rlSetUniformMatrix(shader.locs[SHADER_LOC_MATRIX_VIEW], fboViews[i]);
|
||||||
|
|
||||||
|
// Select the current cubemap face attachment for the fbo
|
||||||
|
// WARNING: This function by default enables->attach->disables fbo!!!
|
||||||
rlFramebufferAttach(fbo, cubemap.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X + i, 0);
|
rlFramebufferAttach(fbo, cubemap.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X + i, 0);
|
||||||
|
|
||||||
rlEnableFramebuffer(fbo);
|
rlEnableFramebuffer(fbo);
|
||||||
rlSetTexture(panorama.id); // WARNING: It must be called after enabling current framebuffer if using internal batch system!
|
|
||||||
|
|
||||||
|
// Load and draw a cube, it uses the current enabled texture
|
||||||
rlClearScreenBuffers();
|
rlClearScreenBuffers();
|
||||||
DrawCubeV(Vector3Zero(), Vector3One(), WHITE);
|
rlLoadDrawCube();
|
||||||
rlDrawRenderBatchActive();
|
|
||||||
|
// ALTERNATIVE: Try to use internal batch system to draw the cube instead of rlLoadDrawCube
|
||||||
|
// for some reason this method does not work, maybe due to cube triangles definition? normals pointing out?
|
||||||
|
// TODO: Investigate this issue...
|
||||||
|
//rlSetTexture(panorama.id); // WARNING: It must be called after enabling current framebuffer if using internal batch system!
|
||||||
|
//rlClearScreenBuffers();
|
||||||
|
//DrawCubeV(Vector3Zero(), Vector3One(), WHITE);
|
||||||
|
//rlDrawRenderBatchActive();
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -238,7 +254,7 @@ static TextureCubemap GenTextureCubemap(Shader shader, Texture2D panorama, int s
|
||||||
cubemap.width = size;
|
cubemap.width = size;
|
||||||
cubemap.height = size;
|
cubemap.height = size;
|
||||||
cubemap.mipmaps = 1;
|
cubemap.mipmaps = 1;
|
||||||
cubemap.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32;
|
cubemap.format = format;
|
||||||
|
|
||||||
return cubemap;
|
return cubemap;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
BIN
examples/models/resources/gltf/vertex_colored_object.glb
Normal file
BIN
examples/models/resources/gltf/vertex_colored_object.glb
Normal file
Binary file not shown.
BIN
examples/models/resources/models/vertex_colored_object.iqm
Normal file
BIN
examples/models/resources/models/vertex_colored_object.iqm
Normal file
Binary file not shown.
|
|
@ -1,16 +1,5 @@
|
||||||
/*******************************************************************************************
|
|
||||||
*
|
|
||||||
* BRDF LUT Generation - Bidirectional reflectance distribution function fragment shader
|
|
||||||
*
|
|
||||||
* REF: https://github.com/HectorMF/BRDFGenerator
|
|
||||||
*
|
|
||||||
* Copyright (c) 2017 Victor Fisac
|
|
||||||
*
|
|
||||||
**********************************************************************************************/
|
|
||||||
|
|
||||||
#version 330
|
#version 330
|
||||||
|
|
||||||
|
|
||||||
// Input vertex attributes (from vertex shader)
|
// Input vertex attributes (from vertex shader)
|
||||||
in vec2 fragTexCoord;
|
in vec2 fragTexCoord;
|
||||||
|
|
||||||
|
|
@ -86,6 +75,8 @@ float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
|
||||||
return ggx1*ggx2;
|
return ggx1*ggx2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bidirectional reflectance distribution function
|
||||||
|
// Ref: https://github.com/HectorMF/BRDFGenerator
|
||||||
vec2 IntegrateBRDF(float NdotV, float roughness)
|
vec2 IntegrateBRDF(float NdotV, float roughness)
|
||||||
{
|
{
|
||||||
float A = 0.0;
|
float A = 0.0;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,3 @@
|
||||||
/*******************************************************************************************
|
|
||||||
*
|
|
||||||
* rPBR [shader] - Bidirectional reflectance distribution function vertex shader
|
|
||||||
*
|
|
||||||
* Copyright (c) 2017 Victor Fisac
|
|
||||||
*
|
|
||||||
**********************************************************************************************/
|
|
||||||
|
|
||||||
#version 330
|
#version 330
|
||||||
|
|
||||||
// Input vertex attributes
|
// Input vertex attributes
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,3 @@
|
||||||
/*******************************************************************************************
|
|
||||||
*
|
|
||||||
* rPBR [shader] - Equirectangular to cubemap vertex shader
|
|
||||||
*
|
|
||||||
* Copyright (c) 2017 Victor Fisac
|
|
||||||
*
|
|
||||||
**********************************************************************************************/
|
|
||||||
|
|
||||||
#version 330
|
#version 330
|
||||||
|
|
||||||
// Input vertex attributes
|
// Input vertex attributes
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,3 @@
|
||||||
/*******************************************************************************************
|
|
||||||
*
|
|
||||||
* rPBR [shader] - Irradiance cubemap fragment shader
|
|
||||||
*
|
|
||||||
* Copyright (c) 2017 Victor Fisac
|
|
||||||
*
|
|
||||||
**********************************************************************************************/
|
|
||||||
|
|
||||||
#version 330
|
#version 330
|
||||||
|
|
||||||
// Input vertex attributes (from vertex shader)
|
// Input vertex attributes (from vertex shader)
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,3 @@
|
||||||
/*******************************************************************************************
|
|
||||||
*
|
|
||||||
* rPBR [shader] - Physically based rendering fragment shader
|
|
||||||
*
|
|
||||||
* Copyright (c) 2017 Victor Fisac
|
|
||||||
*
|
|
||||||
**********************************************************************************************/
|
|
||||||
|
|
||||||
#version 330
|
#version 330
|
||||||
|
|
||||||
#define MAX_REFLECTION_LOD 4.0
|
#define MAX_REFLECTION_LOD 4.0
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,3 @@
|
||||||
/*******************************************************************************************
|
|
||||||
*
|
|
||||||
* rPBR [shader] - Physically based rendering vertex shader
|
|
||||||
*
|
|
||||||
* Copyright (c) 2017 Victor Fisac
|
|
||||||
*
|
|
||||||
**********************************************************************************************/
|
|
||||||
|
|
||||||
#version 330
|
#version 330
|
||||||
|
|
||||||
// Input vertex attributes
|
// Input vertex attributes
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,7 @@
|
||||||
/*******************************************************************************************
|
|
||||||
*
|
|
||||||
* rPBR [shader] - Prefiltered environment for reflections fragment shader
|
|
||||||
*
|
|
||||||
* Copyright (c) 2017 Victor Fisac
|
|
||||||
*
|
|
||||||
**********************************************************************************************/
|
|
||||||
|
|
||||||
#version 330
|
#version 330
|
||||||
#define MAX_SAMPLES 1024u
|
|
||||||
#define CUBEMAP_RESOLUTION 1024.0
|
#define MAX_SAMPLES 1024u
|
||||||
|
#define CUBEMAP_RESOLUTION 1024.0
|
||||||
|
|
||||||
// Input vertex attributes (from vertex shader)
|
// Input vertex attributes (from vertex shader)
|
||||||
in vec3 fragPosition;
|
in vec3 fragPosition;
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,3 @@
|
||||||
/*******************************************************************************************
|
|
||||||
*
|
|
||||||
* rPBR [shader] - Background skybox fragment shader
|
|
||||||
*
|
|
||||||
* Copyright (c) 2017 Victor Fisac
|
|
||||||
*
|
|
||||||
* 19-Jun-2020 - modified by Giuseppe Mastrangelo (@peppemas) - VFlip Support
|
|
||||||
*
|
|
||||||
**********************************************************************************************/
|
|
||||||
|
|
||||||
#version 330
|
#version 330
|
||||||
|
|
||||||
// Input vertex attributes (from vertex shader)
|
// Input vertex attributes (from vertex shader)
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,3 @@
|
||||||
/*******************************************************************************************
|
|
||||||
*
|
|
||||||
* rPBR [shader] - Background skybox vertex shader
|
|
||||||
*
|
|
||||||
* Copyright (c) 2017 Victor Fisac
|
|
||||||
*
|
|
||||||
**********************************************************************************************/
|
|
||||||
|
|
||||||
#version 330
|
#version 330
|
||||||
|
|
||||||
// Input vertex attributes
|
// Input vertex attributes
|
||||||
|
|
|
||||||
|
|
@ -191,10 +191,10 @@ int main(void)
|
||||||
Ray ray = GetMouseRay(GetMousePosition(), camera);
|
Ray ray = GetMouseRay(GetMousePosition(), camera);
|
||||||
|
|
||||||
// Check collision between ray and box
|
// Check collision between ray and box
|
||||||
bool collision = CheckCollisionRayBox(ray,
|
RayCollision collision = GetRayCollisionBox(ray,
|
||||||
(BoundingBox){(Vector3){ cubePosition.x - cubeSize.x/2, cubePosition.y - cubeSize.y/2, cubePosition.z - cubeSize.z/2 },
|
(BoundingBox){(Vector3){ cubePosition.x - cubeSize.x/2, cubePosition.y - cubeSize.y/2, cubePosition.z - cubeSize.z/2 },
|
||||||
(Vector3){ cubePosition.x + cubeSize.x/2, cubePosition.y + cubeSize.y/2, cubePosition.z + cubeSize.z/2 }});
|
(Vector3){ cubePosition.x + cubeSize.x/2, cubePosition.y + cubeSize.y/2, cubePosition.z + cubeSize.z/2 }});
|
||||||
if (collision)
|
if (collision.hit)
|
||||||
{
|
{
|
||||||
// Generate new random colors
|
// Generate new random colors
|
||||||
light = GenerateRandomColor(0.5f, 0.78f);
|
light = GenerateRandomColor(0.5f, 0.78f);
|
||||||
|
|
|
||||||
58
parser/README.md
Normal file
58
parser/README.md
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
## raylib parser
|
||||||
|
|
||||||
|
This parser scans [`raylib.h`](../src/raylib.h) to get information about `structs`, `enums` and `functions`.
|
||||||
|
All data is separated into parts, usually as strings. The following types are used for data:
|
||||||
|
|
||||||
|
- `struct FunctionInfo`
|
||||||
|
- `struct StructInfo`
|
||||||
|
- `struct EnumInfo`
|
||||||
|
|
||||||
|
Check `raylib_parser.c` for details about those structs.
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
|
||||||
|
This parser is specifically designed to work with raylib.h, so, it has some constraints:
|
||||||
|
|
||||||
|
- Functions are expected as a single line with the following structure:
|
||||||
|
```
|
||||||
|
<retType> <name>(<paramType[0]> <paramName[0]>, <paramType[1]> <paramName[1]>); <desc>
|
||||||
|
```
|
||||||
|
Be careful with functions broken into several lines, it breaks the process!
|
||||||
|
|
||||||
|
- Structures are expected as several lines with the following form:
|
||||||
|
```
|
||||||
|
<desc>
|
||||||
|
typedef struct <name> {
|
||||||
|
<fieldType[0]> <fieldName[0]>; <fieldDesc[0]>
|
||||||
|
<fieldType[1]> <fieldName[1]>; <fieldDesc[1]>
|
||||||
|
<fieldType[2]> <fieldName[2]>; <fieldDesc[2]>
|
||||||
|
} <name>;
|
||||||
|
```
|
||||||
|
- Enums are expected as several lines with the following form:
|
||||||
|
```
|
||||||
|
<desc>
|
||||||
|
typedef enum {
|
||||||
|
<valueName[0]> = <valueInteger[0]>, <valueDesc[0]>
|
||||||
|
<valueName[1]>,
|
||||||
|
<valueName[2]>, <valueDesc[2]>
|
||||||
|
<valueName[3]> <valueDesc[3]>
|
||||||
|
} <name>;
|
||||||
|
```
|
||||||
|
|
||||||
|
_NOTE: For enums, multiple options are supported:_
|
||||||
|
|
||||||
|
- If value is not provided, (<valueInteger[i -1]> + 1) is assigned
|
||||||
|
- Value description can be provided or not
|
||||||
|
|
||||||
|
## Additional notes
|
||||||
|
|
||||||
|
This parser _could_ work with other C header files if mentioned constraints are followed.
|
||||||
|
|
||||||
|
This parser **does not require `<string.h>` library**, all data is parsed directly from char buffers.
|
||||||
|
|
||||||
|
### LICENSE: zlib/libpng
|
||||||
|
|
||||||
|
raylib-parser is licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||||
|
BSD-like license that allows static linking with closed source software:
|
||||||
|
|
||||||
|
Copyright (c) 2021 Ramon Santamaria (@raysan5)
|
||||||
684
parser/raylib_parser.c
Normal file
684
parser/raylib_parser.c
Normal file
|
|
@ -0,0 +1,684 @@
|
||||||
|
/**********************************************************************************************
|
||||||
|
|
||||||
|
raylib parser - raylib header parser
|
||||||
|
|
||||||
|
This parser scans raylib.h to get information about structs, enums and functions.
|
||||||
|
All data is separated into parts, usually as strings. The following types are used for data:
|
||||||
|
|
||||||
|
- struct FunctionInfo
|
||||||
|
- struct StructInfo
|
||||||
|
- struct EnumInfo
|
||||||
|
|
||||||
|
CONSTRAINTS:
|
||||||
|
|
||||||
|
This parser is specifically designed to work with raylib.h, so, it has some constraints:
|
||||||
|
|
||||||
|
- Functions are expected as a single line with the following structure:
|
||||||
|
|
||||||
|
<retType> <name>(<paramType[0]> <paramName[0]>, <paramType[1]> <paramName[1]>); <desc>
|
||||||
|
|
||||||
|
Be careful with functions broken into several lines, it breaks the process!
|
||||||
|
|
||||||
|
- Structures are expected as several lines with the following form:
|
||||||
|
|
||||||
|
<desc>
|
||||||
|
typedef struct <name> {
|
||||||
|
<fieldType[0]> <fieldName[0]>; <fieldDesc[0]>
|
||||||
|
<fieldType[1]> <fieldName[1]>; <fieldDesc[1]>
|
||||||
|
<fieldType[2]> <fieldName[2]>; <fieldDesc[2]>
|
||||||
|
} <name>;
|
||||||
|
|
||||||
|
- Enums are expected as several lines with the following form:
|
||||||
|
|
||||||
|
<desc>
|
||||||
|
typedef enum {
|
||||||
|
<valueName[0]> = <valueInteger[0]>, <valueDesc[0]>
|
||||||
|
<valueName[1]>,
|
||||||
|
<valueName[2]>, <valueDesc[2]>
|
||||||
|
<valueName[3]> <valueDesc[3]>
|
||||||
|
} <name>;
|
||||||
|
|
||||||
|
NOTE: Multiple options are supported:
|
||||||
|
- If value is not provided, (<valueInteger[i -1]> + 1) is assigned
|
||||||
|
- Value description can be provided or not
|
||||||
|
|
||||||
|
This parser could work with other C header files if mentioned constraints are followed.
|
||||||
|
|
||||||
|
This parser does not require <string.h> library, all data is parsed directly from char buffers.
|
||||||
|
|
||||||
|
LICENSE: zlib/libpng
|
||||||
|
|
||||||
|
raylib-parser is licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||||
|
BSD-like license that allows static linking with closed source software:
|
||||||
|
|
||||||
|
Copyright (c) 2021 Ramon Santamaria (@raysan5)
|
||||||
|
|
||||||
|
**********************************************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h> // Required for: malloc(), calloc(), realloc(), free(), atoi(), strtol()
|
||||||
|
#include <stdio.h> // Required for: printf(), fopen(), fseek(), ftell(), fread(), fclose()
|
||||||
|
#include <stdbool.h> // Required for: bool
|
||||||
|
|
||||||
|
#define MAX_FUNCS_TO_PARSE 512 // Maximum number of functions to parse
|
||||||
|
#define MAX_STRUCTS_TO_PARSE 64 // Maximum number of structures to parse
|
||||||
|
#define MAX_ENUMS_TO_PARSE 64 // Maximum number of enums to parse
|
||||||
|
|
||||||
|
#define MAX_LINE_LENGTH 512 // Maximum length of one line (including comments)
|
||||||
|
#define MAX_STRUCT_LINE_LENGTH 2048 // Maximum length of one struct (multiple lines)
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// Types and Structures Definition
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// Function info data
|
||||||
|
typedef struct FunctionInfo {
|
||||||
|
char name[64]; // Function name
|
||||||
|
char desc[128]; // Function description (comment at the end)
|
||||||
|
char retType[32]; // Return value type
|
||||||
|
int paramCount; // Number of function parameters
|
||||||
|
char paramType[12][32]; // Parameters type (max: 12 parameters)
|
||||||
|
char paramName[12][32]; // Parameters name (max: 12 parameters)
|
||||||
|
} FunctionInfo;
|
||||||
|
|
||||||
|
// Struct info data
|
||||||
|
typedef struct StructInfo {
|
||||||
|
char name[64]; // Struct name
|
||||||
|
char desc[64]; // Struct type description
|
||||||
|
int fieldCount; // Number of fields in the struct
|
||||||
|
char fieldType[16][32]; // Field type (max: 16 fields)
|
||||||
|
char fieldName[16][32]; // Field name (max: 16 fields)
|
||||||
|
char fieldDesc[16][128]; // Field description (max: 16 fields)
|
||||||
|
} StructInfo;
|
||||||
|
|
||||||
|
// Enum info data
|
||||||
|
typedef struct EnumInfo {
|
||||||
|
char name[64]; // Enum name
|
||||||
|
char desc[64]; // Enum description
|
||||||
|
int valueCount; // Number of values in enumerator
|
||||||
|
char valueName[128][64]; // Value name definition (max: 128 values)
|
||||||
|
int valueInteger[128]; // Value integer (max: 128 values)
|
||||||
|
char valueDesc[128][64]; // Value description (max: 128 values)
|
||||||
|
} EnumInfo;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// Module Functions Declaration
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
char *LoadFileText(const char *fileName, int *length);
|
||||||
|
char **GetTextLines(const char *buffer, int length, int *linesCount);
|
||||||
|
void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name);
|
||||||
|
bool IsTextEqual(const char *text1, const char *text2, unsigned int count);
|
||||||
|
void MemoryCopy(void *dest, const void *src, unsigned int count);
|
||||||
|
|
||||||
|
// Main entry point
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int length = 0;
|
||||||
|
char *buffer = LoadFileText("../src/raylib.h", &length);
|
||||||
|
|
||||||
|
// Preprocess buffer to get separate lines
|
||||||
|
// NOTE: GetTextLines() also removes leading spaces/tabs
|
||||||
|
int linesCount = 0;
|
||||||
|
char **lines = GetTextLines(buffer, length, &linesCount);
|
||||||
|
|
||||||
|
// Print buffer lines
|
||||||
|
//for (int i = 0; i < linesCount; i++) printf("_%s_\n", lines[i]);
|
||||||
|
|
||||||
|
// Function lines pointers, selected from buffer "lines"
|
||||||
|
int funcCount = 0;
|
||||||
|
char **funcLines = (char **)malloc(MAX_FUNCS_TO_PARSE*sizeof(char *));
|
||||||
|
|
||||||
|
// Structs data (multiple lines), selected from "buffer"
|
||||||
|
int structCount = 0;
|
||||||
|
char **structLines = (char **)malloc(MAX_STRUCTS_TO_PARSE*sizeof(char *));
|
||||||
|
for (int i = 0; i < MAX_STRUCTS_TO_PARSE; i++) structLines[i] = (char *)calloc(MAX_STRUCT_LINE_LENGTH, sizeof(char));
|
||||||
|
|
||||||
|
// Enums lines pointers, selected from buffer "lines"
|
||||||
|
int enumCount = 0;
|
||||||
|
int *enumLines = (int *)malloc(MAX_ENUMS_TO_PARSE*sizeof(int));
|
||||||
|
|
||||||
|
// Prepare required lines for parsing
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Read function lines
|
||||||
|
for (int i = 0; i < linesCount; i++)
|
||||||
|
{
|
||||||
|
// Read function line (starting with "RLAPI")
|
||||||
|
if (IsTextEqual(lines[i], "RLAPI", 5))
|
||||||
|
{
|
||||||
|
// Keep a pointer to the function line
|
||||||
|
funcLines[funcCount] = lines[i];
|
||||||
|
funcCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print function lines
|
||||||
|
//for (int i = 0; i < funcCount; i++) printf("%s\n", funcLines[i]);
|
||||||
|
|
||||||
|
// Read structs data (multiple lines, read directly from buffer)
|
||||||
|
// TODO: Parse structs data from "lines" instead of "buffer" -> Easier to get struct definition
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
// Read struct data (starting with "typedef struct", ending with '} ... ;')
|
||||||
|
// NOTE: We read it directly from buffer
|
||||||
|
if (IsTextEqual(buffer + i, "typedef struct", 14))
|
||||||
|
{
|
||||||
|
int j = 0;
|
||||||
|
bool validStruct = false;
|
||||||
|
|
||||||
|
// WARNING: Typedefs between types: typedef Vector4 Quaternion;
|
||||||
|
|
||||||
|
for (int c = 0; c < 128; c++)
|
||||||
|
{
|
||||||
|
if (buffer[i + c] == '{')
|
||||||
|
{
|
||||||
|
validStruct = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (buffer[i + j] == ';')
|
||||||
|
{
|
||||||
|
// Not valid struct:
|
||||||
|
// i.e typedef struct rAudioBuffer rAudioBuffer; -> Typedef and forward declaration
|
||||||
|
i += c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validStruct)
|
||||||
|
{
|
||||||
|
while (buffer[i + j] != '}')
|
||||||
|
{
|
||||||
|
structLines[structCount][j] = buffer[i + j];
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (buffer[i + j] != '}')
|
||||||
|
{
|
||||||
|
structLines[structCount][j] = buffer[i + j];
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (buffer[i + j] != '\n')
|
||||||
|
{
|
||||||
|
structLines[structCount][j] = buffer[i + j];
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
i += j;
|
||||||
|
structCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read enum lines
|
||||||
|
for (int i = 0; i < linesCount; i++)
|
||||||
|
{
|
||||||
|
// Read function line (starting with "RLAPI")
|
||||||
|
if (IsTextEqual(lines[i], "typedef enum {", 14))
|
||||||
|
{
|
||||||
|
// Keep the line position in the array of lines,
|
||||||
|
// so, we can scan that position and following lines
|
||||||
|
enumLines[enumCount] = i;
|
||||||
|
enumCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point we have all raylib structs, enums, functions lines data to start parsing
|
||||||
|
|
||||||
|
free(buffer); // Unload text buffer
|
||||||
|
|
||||||
|
// Parsing raylib data
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Structs info data
|
||||||
|
StructInfo *structs = (StructInfo *)calloc(MAX_STRUCTS_TO_PARSE, sizeof(StructInfo));
|
||||||
|
|
||||||
|
for (int i = 0; i < structCount; i++)
|
||||||
|
{
|
||||||
|
int structLineOffset = 0;
|
||||||
|
|
||||||
|
// Get struct name: typedef struct name {
|
||||||
|
for (int c = 15; c < 64 + 15; c++)
|
||||||
|
{
|
||||||
|
if (structLines[i][c] == '{')
|
||||||
|
{
|
||||||
|
structLineOffset = c + 2;
|
||||||
|
|
||||||
|
MemoryCopy(structs[i].name, &structLines[i][15], c - 15 - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get struct fields and count them -> fields finish with ;
|
||||||
|
int j = 0;
|
||||||
|
while (structLines[i][structLineOffset + j] != '}')
|
||||||
|
{
|
||||||
|
// WARNING: Some structs have empty spaces and comments -> OK, processed
|
||||||
|
|
||||||
|
int fieldStart = 0;
|
||||||
|
if ((structLines[i][structLineOffset + j] != ' ') && (structLines[i][structLineOffset + j] != '\n')) fieldStart = structLineOffset + j;
|
||||||
|
|
||||||
|
if (fieldStart != 0)
|
||||||
|
{
|
||||||
|
// Scan one field line
|
||||||
|
int c = 0;
|
||||||
|
int fieldEndPos = 0;
|
||||||
|
char fieldLine[256] = { 0 };
|
||||||
|
|
||||||
|
while (structLines[i][structLineOffset + j] != '\n')
|
||||||
|
{
|
||||||
|
if (structLines[i][structLineOffset + j] == ';') fieldEndPos = c;
|
||||||
|
fieldLine[c] = structLines[i][structLineOffset + j];
|
||||||
|
c++; j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldLine[0] != '/') // Field line is not a comment
|
||||||
|
{
|
||||||
|
//printf("Struct field: %s_\n", fieldLine); // OK!
|
||||||
|
|
||||||
|
// Get struct field type and name
|
||||||
|
GetDataTypeAndName(fieldLine, fieldEndPos, structs[i].fieldType[structs[i].fieldCount], structs[i].fieldName[structs[i].fieldCount]);
|
||||||
|
|
||||||
|
// Get the field description
|
||||||
|
// We start skipping spaces in front of description comment
|
||||||
|
int descStart = fieldEndPos;
|
||||||
|
while ((fieldLine[descStart] != '/') && (fieldLine[descStart] != '\0')) descStart++;
|
||||||
|
|
||||||
|
int k = 0;
|
||||||
|
while ((fieldLine[descStart + k] != '\0') && (fieldLine[descStart + k] != '\n'))
|
||||||
|
{
|
||||||
|
structs[i].fieldDesc[structs[i].fieldCount][k] = fieldLine[descStart + k];
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
|
||||||
|
structs[i].fieldCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_STRUCTS_TO_PARSE; i++) free(structLines[i]);
|
||||||
|
free(structLines);
|
||||||
|
|
||||||
|
// Enum info data
|
||||||
|
EnumInfo *enums = (EnumInfo *)calloc(MAX_ENUMS_TO_PARSE, sizeof(EnumInfo));
|
||||||
|
|
||||||
|
for (int i = 0; i < enumCount; i++)
|
||||||
|
{
|
||||||
|
// TODO: Get enum description from lines[enumLines[i] - 1]
|
||||||
|
|
||||||
|
for (int j = 1; j < 256; j++) // Maximum number of lines following enum first line
|
||||||
|
{
|
||||||
|
char *linePtr = lines[enumLines[i] + j];
|
||||||
|
|
||||||
|
if ((linePtr[0] >= 'A') && (linePtr[0] <= 'Z'))
|
||||||
|
{
|
||||||
|
// Parse enum value line, possible options:
|
||||||
|
//ENUM_VALUE_NAME,
|
||||||
|
//ENUM_VALUE_NAME
|
||||||
|
//ENUM_VALUE_NAME = 99
|
||||||
|
//ENUM_VALUE_NAME = 99,
|
||||||
|
//ENUM_VALUE_NAME = 0x00000040, // Value description
|
||||||
|
|
||||||
|
// We start reading the value name
|
||||||
|
int c = 0;
|
||||||
|
while ((linePtr[c] != ',') &&
|
||||||
|
(linePtr[c] != ' ') &&
|
||||||
|
(linePtr[c] != '=') &&
|
||||||
|
(linePtr[c] != '\0')) { enums[i].valueName[enums[i].valueCount][c] = linePtr[c]; c++; }
|
||||||
|
|
||||||
|
// After the name we can have:
|
||||||
|
// '=' -> value is provided
|
||||||
|
// ',' -> value is equal to previous + 1, there could be a description if not '\0'
|
||||||
|
// ' ' -> value is equal to previous + 1, there could be a description if not '\0'
|
||||||
|
// '\0' -> value is equal to previous + 1
|
||||||
|
|
||||||
|
// Let's start checking if the line is not finished
|
||||||
|
if ((linePtr[c] != ',') && (linePtr[c] != '\0'))
|
||||||
|
{
|
||||||
|
// Two options:
|
||||||
|
// '=' -> value is provided
|
||||||
|
// ' ' -> value is equal to previous + 1, there could be a description if not '\0'
|
||||||
|
bool foundValue = false;
|
||||||
|
while (linePtr[c] != '\0')
|
||||||
|
{
|
||||||
|
if (linePtr[c] == '=') { foundValue = true; break; }
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundValue)
|
||||||
|
{
|
||||||
|
if (linePtr[c + 1] == ' ') c += 2;
|
||||||
|
else c++;
|
||||||
|
|
||||||
|
// Parse integer value
|
||||||
|
int n = 0;
|
||||||
|
char integer[16] = { 0 };
|
||||||
|
|
||||||
|
while ((linePtr[c] != ',') && (linePtr[c] != ' ') && (linePtr[c] != '\0'))
|
||||||
|
{
|
||||||
|
integer[n] = linePtr[c];
|
||||||
|
c++; n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (integer[1] == 'x') enums[i].valueInteger[enums[i].valueCount] = (int)strtol(integer, NULL, 16);
|
||||||
|
else enums[i].valueInteger[enums[i].valueCount] = atoi(integer);
|
||||||
|
}
|
||||||
|
else enums[i].valueInteger[enums[i].valueCount] = (enums[i].valueInteger[enums[i].valueCount - 1] + 1);
|
||||||
|
|
||||||
|
// TODO: Parse value description if any
|
||||||
|
}
|
||||||
|
else enums[i].valueInteger[enums[i].valueCount] = (enums[i].valueInteger[enums[i].valueCount - 1] + 1);
|
||||||
|
|
||||||
|
enums[i].valueCount++;
|
||||||
|
}
|
||||||
|
else if (linePtr[0] == '}')
|
||||||
|
{
|
||||||
|
// Get enum name from typedef
|
||||||
|
int c = 0;
|
||||||
|
while (linePtr[2 + c] != ';') { enums[i].name[c] = linePtr[2 + c]; c++; }
|
||||||
|
|
||||||
|
break; // Enum ended, break for() loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions info data
|
||||||
|
FunctionInfo *funcs = (FunctionInfo *)calloc(MAX_FUNCS_TO_PARSE, sizeof(FunctionInfo));
|
||||||
|
|
||||||
|
for (int i = 0; i < funcCount; i++)
|
||||||
|
{
|
||||||
|
int funcParamsStart = 0;
|
||||||
|
int funcEnd = 0;
|
||||||
|
|
||||||
|
// Get return type and function name from func line
|
||||||
|
for (int c = 0; (c < MAX_LINE_LENGTH) && (funcLines[i][c] != '\n'); c++)
|
||||||
|
{
|
||||||
|
if (funcLines[i][c] == '(') // Starts function parameters
|
||||||
|
{
|
||||||
|
funcParamsStart = c + 1;
|
||||||
|
|
||||||
|
// At this point we have function return type and function name
|
||||||
|
char funcRetTypeName[128] = { 0 };
|
||||||
|
int funcRetTypeNameLen = c - 6; // Substract "RLAPI "
|
||||||
|
MemoryCopy(funcRetTypeName, &funcLines[i][6], funcRetTypeNameLen);
|
||||||
|
|
||||||
|
GetDataTypeAndName(funcRetTypeName, funcRetTypeNameLen, funcs[i].retType, funcs[i].name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get parameters from func line
|
||||||
|
for (int c = funcParamsStart; c < MAX_LINE_LENGTH; c++)
|
||||||
|
{
|
||||||
|
if (funcLines[i][c] == ',') // Starts function parameters
|
||||||
|
{
|
||||||
|
// Get parameter type + name, extract info
|
||||||
|
char funcParamTypeName[128] = { 0 };
|
||||||
|
int funcParamTypeNameLen = c - funcParamsStart;
|
||||||
|
MemoryCopy(funcParamTypeName, &funcLines[i][funcParamsStart], funcParamTypeNameLen);
|
||||||
|
|
||||||
|
GetDataTypeAndName(funcParamTypeName, funcParamTypeNameLen, funcs[i].paramType[funcs[i].paramCount], funcs[i].paramName[funcs[i].paramCount]);
|
||||||
|
|
||||||
|
funcParamsStart = c + 1;
|
||||||
|
if (funcLines[i][c + 1] == ' ') funcParamsStart += 1;
|
||||||
|
funcs[i].paramCount++; // Move to next parameter
|
||||||
|
}
|
||||||
|
else if (funcLines[i][c] == ')')
|
||||||
|
{
|
||||||
|
funcEnd = c + 2;
|
||||||
|
|
||||||
|
// Check if previous word is void
|
||||||
|
if ((funcLines[i][c - 4] == 'v') && (funcLines[i][c - 3] == 'o') && (funcLines[i][c - 2] == 'i') && (funcLines[i][c - 1] == 'd')) break;
|
||||||
|
|
||||||
|
// Get parameter type + name, extract info
|
||||||
|
char funcParamTypeName[128] = { 0 };
|
||||||
|
int funcParamTypeNameLen = c - funcParamsStart;
|
||||||
|
MemoryCopy(funcParamTypeName, &funcLines[i][funcParamsStart], funcParamTypeNameLen);
|
||||||
|
|
||||||
|
GetDataTypeAndName(funcParamTypeName, funcParamTypeNameLen, funcs[i].paramType[funcs[i].paramCount], funcs[i].paramName[funcs[i].paramCount]);
|
||||||
|
|
||||||
|
funcs[i].paramCount++; // Move to next parameter
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get function description
|
||||||
|
for (int c = funcEnd; c < MAX_LINE_LENGTH; c++)
|
||||||
|
{
|
||||||
|
if (funcLines[i][c] == '/')
|
||||||
|
{
|
||||||
|
MemoryCopy(funcs[i].desc, &funcLines[i][c], 127); // WARNING: Size could be too long for funcLines[i][c]?
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < linesCount; i++) free(lines[i]);
|
||||||
|
free(lines);
|
||||||
|
free(funcLines);
|
||||||
|
|
||||||
|
// At this point, all raylib data has been parsed!
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
// structs[] -> We have all the structs decomposed into pieces for further analysis
|
||||||
|
// enums[] -> We have all the enums decomposed into pieces for further analysis
|
||||||
|
// funcs[] -> We have all the functions decomposed into pieces for further analysis
|
||||||
|
|
||||||
|
// Print structs info
|
||||||
|
printf("\nStructures found: %i\n\n", structCount);
|
||||||
|
for (int i = 0; i < structCount; i++)
|
||||||
|
{
|
||||||
|
printf("Struct %02i: %s (%i fields)\n", i + 1, structs[i].name, structs[i].fieldCount);
|
||||||
|
//printf("Description: %s\n", structs[i].desc);
|
||||||
|
for (int f = 0; f < structs[i].fieldCount; f++) printf(" Fields %i: %s %s %s\n", f + 1, structs[i].fieldType[f], structs[i].fieldName[f], structs[i].fieldDesc[f]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print enums info
|
||||||
|
printf("\nEnums found: %i\n\n", enumCount);
|
||||||
|
for (int i = 0; i < enumCount; i++)
|
||||||
|
{
|
||||||
|
printf("Enum %02i: %s (%i values)\n", i + 1, enums[i].name, enums[i].valueCount);
|
||||||
|
//printf("Description: %s\n", enums[i].desc);
|
||||||
|
for (int e = 0; e < enums[i].valueCount; e++) printf(" Value %s: %i\n", enums[i].valueName[e], enums[i].valueInteger[e]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print function info
|
||||||
|
printf("\nFunctions found: %i\n\n", funcCount);
|
||||||
|
for (int i = 0; i < funcCount; i++)
|
||||||
|
{
|
||||||
|
printf("Function %03i: %s() (%i input parameters)\n", i + 1, funcs[i].name, funcs[i].paramCount);
|
||||||
|
printf(" Description: %s\n", funcs[i].desc);
|
||||||
|
printf(" Return type: %s\n", funcs[i].retType);
|
||||||
|
for (int p = 0; p < funcs[i].paramCount; p++) printf(" Param %i: %s (type: %s)\n", p + 1, funcs[i].paramName[p], funcs[i].paramType[p]);
|
||||||
|
if (funcs[i].paramCount == 0) printf(" No input parameters\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
free(funcs);
|
||||||
|
free(structs);
|
||||||
|
free(enums);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// Module Functions Definition
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Load text data from file, returns a '\0' terminated string
|
||||||
|
// NOTE: text chars array should be freed manually
|
||||||
|
char *LoadFileText(const char *fileName, int *length)
|
||||||
|
{
|
||||||
|
char *text = NULL;
|
||||||
|
|
||||||
|
if (fileName != NULL)
|
||||||
|
{
|
||||||
|
FILE *file = fopen(fileName, "rt");
|
||||||
|
|
||||||
|
if (file != NULL)
|
||||||
|
{
|
||||||
|
// WARNING: When reading a file as 'text' file,
|
||||||
|
// text mode causes carriage return-linefeed translation...
|
||||||
|
// ...but using fseek() should return correct byte-offset
|
||||||
|
fseek(file, 0, SEEK_END);
|
||||||
|
int size = ftell(file);
|
||||||
|
fseek(file, 0, SEEK_SET);
|
||||||
|
|
||||||
|
if (size > 0)
|
||||||
|
{
|
||||||
|
*length = size;
|
||||||
|
|
||||||
|
text = (char *)calloc((size + 1), sizeof(char));
|
||||||
|
unsigned int count = (unsigned int)fread(text, sizeof(char), size, file);
|
||||||
|
|
||||||
|
// WARNING: \r\n is converted to \n on reading, so,
|
||||||
|
// read bytes count gets reduced by the number of lines
|
||||||
|
if (count < (unsigned int)size) text = realloc(text, count + 1);
|
||||||
|
|
||||||
|
// Zero-terminate the string
|
||||||
|
text[count] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all lines from a text buffer (expecting lines ending with '\n')
|
||||||
|
char **GetTextLines(const char *buffer, int length, int *linesCount)
|
||||||
|
{
|
||||||
|
//#define MAX_LINE_LENGTH 512
|
||||||
|
|
||||||
|
// Get the number of lines in the text
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < length; i++) if (buffer[i] == '\n') count++;
|
||||||
|
|
||||||
|
//printf("Number of text lines in buffer: %i\n", count);
|
||||||
|
|
||||||
|
// Allocate as many pointers as lines
|
||||||
|
char **lines = (char **)malloc(count*sizeof(char **));
|
||||||
|
|
||||||
|
char *bufferPtr = (char *)buffer;
|
||||||
|
|
||||||
|
for (int i = 0; (i < count) || (bufferPtr[0] != '\0'); i++)
|
||||||
|
{
|
||||||
|
lines[i] = (char *)calloc(MAX_LINE_LENGTH, sizeof(char));
|
||||||
|
|
||||||
|
// Remove line leading spaces
|
||||||
|
// Find last index of space/tab character
|
||||||
|
int index = 0;
|
||||||
|
while ((bufferPtr[index] == ' ') || (bufferPtr[index] == '\t')) index++;
|
||||||
|
|
||||||
|
int j = 0;
|
||||||
|
while (bufferPtr[index + j] != '\n')
|
||||||
|
{
|
||||||
|
lines[i][j] = bufferPtr[index + j];
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufferPtr += (index + j + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
*linesCount = count;
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get data type and name from a string containing both
|
||||||
|
// NOTE: Useful to parse function parameters and struct fields
|
||||||
|
void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name)
|
||||||
|
{
|
||||||
|
for (int k = typeNameLen; k > 0; k--)
|
||||||
|
{
|
||||||
|
if (typeName[k] == ' ')
|
||||||
|
{
|
||||||
|
// Function name starts at this point (and ret type finishes at this point)
|
||||||
|
MemoryCopy(type, typeName, k);
|
||||||
|
MemoryCopy(name, typeName + k + 1, typeNameLen - k - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (typeName[k] == '*')
|
||||||
|
{
|
||||||
|
MemoryCopy(type, typeName, k + 1);
|
||||||
|
MemoryCopy(name, typeName + k + 1, typeNameLen - k - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom memcpy() to avoid <string.h>
|
||||||
|
void MemoryCopy(void *dest, const void *src, unsigned int count)
|
||||||
|
{
|
||||||
|
char *srcPtr = (char *)src;
|
||||||
|
char *destPtr = (char *)dest;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < count; i++) destPtr[i] = srcPtr[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare two text strings, requires number of characters to compare
|
||||||
|
bool IsTextEqual(const char *text1, const char *text2, unsigned int count)
|
||||||
|
{
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (text1[i] != text2[i])
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Replace text string
|
||||||
|
// REQUIRES: strlen(), strstr(), strncpy(), strcpy() -> TODO: Replace by custom implementations!
|
||||||
|
// WARNING: Returned buffer must be freed by the user (if return != NULL)
|
||||||
|
char *TextReplace(char *text, const char *replace, const char *by)
|
||||||
|
{
|
||||||
|
// Sanity checks and initialization
|
||||||
|
if (!text || !replace || !by) return NULL;
|
||||||
|
|
||||||
|
char *result;
|
||||||
|
|
||||||
|
char *insertPoint; // Next insert point
|
||||||
|
char *temp; // Temp pointer
|
||||||
|
int replaceLen; // Replace string length of (the string to remove)
|
||||||
|
int byLen; // Replacement length (the string to replace replace by)
|
||||||
|
int lastReplacePos; // Distance between replace and end of last replace
|
||||||
|
int count; // Number of replacements
|
||||||
|
|
||||||
|
replaceLen = strlen(replace);
|
||||||
|
if (replaceLen == 0) return NULL; // Empty replace causes infinite loop during count
|
||||||
|
|
||||||
|
byLen = strlen(by);
|
||||||
|
|
||||||
|
// Count the number of replacements needed
|
||||||
|
insertPoint = text;
|
||||||
|
for (count = 0; (temp = strstr(insertPoint, replace)); count++) insertPoint = temp + replaceLen;
|
||||||
|
|
||||||
|
// Allocate returning string and point temp to it
|
||||||
|
temp = result = (char *)malloc(strlen(text) + (byLen - replaceLen)*count + 1);
|
||||||
|
|
||||||
|
if (!result) return NULL; // Memory could not be allocated
|
||||||
|
|
||||||
|
// First time through the loop, all the variable are set correctly from here on,
|
||||||
|
// - 'temp' points to the end of the result string
|
||||||
|
// - 'insertPoint' points to the next occurrence of replace in text
|
||||||
|
// - 'text' points to the remainder of text after "end of replace"
|
||||||
|
while (count--)
|
||||||
|
{
|
||||||
|
insertPoint = strstr(text, replace);
|
||||||
|
lastReplacePos = (int)(insertPoint - text);
|
||||||
|
temp = strncpy(temp, text, lastReplacePos) + lastReplacePos;
|
||||||
|
temp = strcpy(temp, by) + byLen;
|
||||||
|
text += lastReplacePos + replaceLen; // Move to next "end of replace"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy remaind text part after replacement to result (pointed by moving temp)
|
||||||
|
strcpy(temp, text);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
@ -34,4 +34,11 @@ add_executable(${PROJECT_NAME} core_basic_window.c)
|
||||||
#set(raylib_VERBOSE 1)
|
#set(raylib_VERBOSE 1)
|
||||||
target_link_libraries(${PROJECT_NAME} raylib)
|
target_link_libraries(${PROJECT_NAME} raylib)
|
||||||
|
|
||||||
|
# Checks if OSX and links appropriate frameworks (Only required on MacOS)
|
||||||
|
if (APPLE)
|
||||||
|
target_link_libraries(${PROJECT_NAME} "-framework IOKit")
|
||||||
|
target_link_libraries(${PROJECT_NAME} "-framework Cocoa")
|
||||||
|
target_link_libraries(${PROJECT_NAME} "-framework OpenGL")
|
||||||
|
endif()
|
||||||
|
|
||||||
# That's it! You should have an example executable that you can run. Have fun!
|
# That's it! You should have an example executable that you can run. Have fun!
|
||||||
|
|
|
||||||
|
|
@ -252,6 +252,7 @@
|
||||||
<PreprocessorDefinitions>_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions);GRAPHICS_API_OPENGL_33;PLATFORM_DESKTOP</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions);GRAPHICS_API_OPENGL_33;PLATFORM_DESKTOP</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\src\external\glfw\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\src\external\glfw\include</AdditionalIncludeDirectories>
|
||||||
<CompileAs>CompileAsC</CompileAs>
|
<CompileAs>CompileAsC</CompileAs>
|
||||||
|
<DebugInformationFormat />
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
|
|
@ -291,6 +292,7 @@
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\src\external\glfw\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\src\external\glfw\include</AdditionalIncludeDirectories>
|
||||||
<CompileAs>CompileAsC</CompileAs>
|
<CompileAs>CompileAsC</CompileAs>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<DebugInformationFormat />
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
|
|
|
||||||
|
|
@ -252,6 +252,7 @@
|
||||||
<PreprocessorDefinitions>_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions);GRAPHICS_API_OPENGL_33;PLATFORM_DESKTOP</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions);GRAPHICS_API_OPENGL_33;PLATFORM_DESKTOP</PreprocessorDefinitions>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\src\external\glfw\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\src\external\glfw\include</AdditionalIncludeDirectories>
|
||||||
<CompileAs>CompileAsC</CompileAs>
|
<CompileAs>CompileAsC</CompileAs>
|
||||||
|
<DebugInformationFormat />
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
|
|
@ -291,6 +292,7 @@
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\src\external\glfw\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\src\external\glfw\include</AdditionalIncludeDirectories>
|
||||||
<CompileAs>CompileAsC</CompileAs>
|
<CompileAs>CompileAsC</CompileAs>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<DebugInformationFormat />
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ endif()
|
||||||
set(raylib_public_headers
|
set(raylib_public_headers
|
||||||
raylib.h
|
raylib.h
|
||||||
rlgl.h
|
rlgl.h
|
||||||
physac.h
|
|
||||||
raymath.h
|
raymath.h
|
||||||
raudio.h
|
raudio.h
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,8 @@
|
||||||
.PHONY: all clean install uninstall
|
.PHONY: all clean install uninstall
|
||||||
|
|
||||||
# Define required raylib variables
|
# Define required raylib variables
|
||||||
RAYLIB_VERSION = 3.7.0
|
RAYLIB_VERSION = 3.7.1
|
||||||
RAYLIB_API_VERSION = 370
|
RAYLIB_API_VERSION = 371
|
||||||
|
|
||||||
# Define raylib source code path
|
# Define raylib source code path
|
||||||
RAYLIB_SRC_PATH ?= ../src
|
RAYLIB_SRC_PATH ?= ../src
|
||||||
|
|
|
||||||
52
src/core.c
52
src/core.c
|
|
@ -270,12 +270,6 @@
|
||||||
#include <emscripten/html5.h> // Emscripten HTML5 library
|
#include <emscripten/html5.h> // Emscripten HTML5 library
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(SUPPORT_COMPRESSION_API)
|
|
||||||
// NOTE: Those declarations require stb_image and stb_image_write definitions, included in textures module
|
|
||||||
unsigned char *stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality);
|
|
||||||
char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Defines and Macros
|
// Defines and Macros
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -652,7 +646,7 @@ void InitWindow(int width, int height, const char *title)
|
||||||
#if defined(PLATFORM_UWP)
|
#if defined(PLATFORM_UWP)
|
||||||
if (!UWPIsConfigured())
|
if (!UWPIsConfigured())
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_ERROR, "UWP Functions have not been set yet, please set these before initializing raylib!");
|
TRACELOG(LOG_FATAL, "UWP Functions have not been set yet, please set these before initializing raylib!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -736,7 +730,12 @@ void InitWindow(int width, int height, const char *title)
|
||||||
// NOTE: returns true if window and graphic device has been initialized successfully
|
// NOTE: returns true if window and graphic device has been initialized successfully
|
||||||
CORE.Window.ready = InitGraphicsDevice(width, height);
|
CORE.Window.ready = InitGraphicsDevice(width, height);
|
||||||
|
|
||||||
if (!CORE.Window.ready) return;
|
// If graphic device is no properly initialized, we end program
|
||||||
|
if (!CORE.Window.ready)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_FATAL, "Failed to initialize Graphic Device");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Init hi-res timer
|
// Init hi-res timer
|
||||||
InitTimer();
|
InitTimer();
|
||||||
|
|
@ -2035,8 +2034,8 @@ void EndShaderMode(void)
|
||||||
rlSetShader(rlGetShaderDefault());
|
rlSetShader(rlGetShaderDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Begin blending mode (alpha, additive, multiplied)
|
// Begin blending mode (alpha, additive, multiplied, subtract, custom)
|
||||||
// NOTE: Only 3 blending modes supported, default blend mode is alpha
|
// NOTE: Blend modes supported are enumerated in BlendMode enum
|
||||||
void BeginBlendMode(int mode)
|
void BeginBlendMode(int mode)
|
||||||
{
|
{
|
||||||
rlSetBlendMode(mode);
|
rlSetBlendMode(mode);
|
||||||
|
|
@ -2179,8 +2178,8 @@ Shader LoadShader(const char *vsFileName, const char *fsFileName)
|
||||||
|
|
||||||
shader.id = rlLoadShaderCode(vShaderStr, fShaderStr);
|
shader.id = rlLoadShaderCode(vShaderStr, fShaderStr);
|
||||||
|
|
||||||
if (vShaderStr != NULL) RL_FREE(vShaderStr);
|
if (vShaderStr != NULL) UnloadFileText(vShaderStr);
|
||||||
if (fShaderStr != NULL) RL_FREE(fShaderStr);
|
if (fShaderStr != NULL) UnloadFileText(fShaderStr);
|
||||||
|
|
||||||
// After shader loading, we TRY to set default location names
|
// After shader loading, we TRY to set default location names
|
||||||
if (shader.id > 0)
|
if (shader.id > 0)
|
||||||
|
|
@ -2801,8 +2800,8 @@ char **GetDirectoryFiles(const char *dirPath, int *fileCount)
|
||||||
ClearDirectoryFiles();
|
ClearDirectoryFiles();
|
||||||
|
|
||||||
// Memory allocation for MAX_DIRECTORY_FILES
|
// Memory allocation for MAX_DIRECTORY_FILES
|
||||||
dirFilesPath = (char **)RL_MALLOC(sizeof(char *)*MAX_DIRECTORY_FILES);
|
dirFilesPath = (char **)RL_MALLOC(MAX_DIRECTORY_FILES*sizeof(char *));
|
||||||
for (int i = 0; i < MAX_DIRECTORY_FILES; i++) dirFilesPath[i] = (char *)RL_MALLOC(sizeof(char)*MAX_FILEPATH_LENGTH);
|
for (int i = 0; i < MAX_DIRECTORY_FILES; i++) dirFilesPath[i] = (char *)RL_MALLOC(MAX_FILEPATH_LENGTH*sizeof(char));
|
||||||
|
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
struct dirent *entity;
|
struct dirent *entity;
|
||||||
|
|
@ -3543,7 +3542,7 @@ static bool InitGraphicsDevice(int width, int height)
|
||||||
CORE.Window.display.width = mode->width;
|
CORE.Window.display.width = mode->width;
|
||||||
CORE.Window.display.height = mode->height;
|
CORE.Window.display.height = mode->height;
|
||||||
|
|
||||||
// Screen size security check
|
// Set screen width/height to the display width/height if they are 0
|
||||||
if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width;
|
if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width;
|
||||||
if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height;
|
if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height;
|
||||||
#endif // PLATFORM_DESKTOP
|
#endif // PLATFORM_DESKTOP
|
||||||
|
|
@ -4914,6 +4913,7 @@ static void SwapBuffers(void)
|
||||||
{
|
{
|
||||||
gbm_surface_release_buffer(CORE.Window.gbmSurface, CORE.Window.prevBO);
|
gbm_surface_release_buffer(CORE.Window.gbmSurface, CORE.Window.prevBO);
|
||||||
}
|
}
|
||||||
|
|
||||||
CORE.Window.prevBO = bo;
|
CORE.Window.prevBO = bo;
|
||||||
#endif // PLATFORM_DRM
|
#endif // PLATFORM_DRM
|
||||||
#endif // PLATFORM_ANDROID || PLATFORM_RPI || PLATFORM_DRM || PLATFORM_UWP
|
#endif // PLATFORM_ANDROID || PLATFORM_RPI || PLATFORM_DRM || PLATFORM_UWP
|
||||||
|
|
@ -5151,11 +5151,11 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths
|
||||||
{
|
{
|
||||||
ClearDroppedFiles();
|
ClearDroppedFiles();
|
||||||
|
|
||||||
CORE.Window.dropFilesPath = (char **)RL_MALLOC(sizeof(char *)*count);
|
CORE.Window.dropFilesPath = (char **)RL_MALLOC(count*sizeof(char *));
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
CORE.Window.dropFilesPath[i] = (char *)RL_MALLOC(sizeof(char)*MAX_FILEPATH_LENGTH);
|
CORE.Window.dropFilesPath[i] = (char *)RL_MALLOC(MAX_FILEPATH_LENGTH*sizeof(char));
|
||||||
strcpy(CORE.Window.dropFilesPath[i], paths[i]);
|
strcpy(CORE.Window.dropFilesPath[i], paths[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -6268,15 +6268,15 @@ bool UWPIsConfigured()
|
||||||
{
|
{
|
||||||
bool pass = true;
|
bool pass = true;
|
||||||
|
|
||||||
if (uwpQueryTimeFunc == NULL) { TRACELOG(LOG_ERROR, "UWP: UWPSetQueryTimeFunc() must be called with a valid function before InitWindow()"); pass = false; }
|
if (uwpQueryTimeFunc == NULL) { TRACELOG(LOG_WARNING, "UWP: UWPSetQueryTimeFunc() must be called with a valid function before InitWindow()"); pass = false; }
|
||||||
if (uwpSleepFunc == NULL) { TRACELOG(LOG_ERROR, "UWP: UWPSetSleepFunc() must be called with a valid function before InitWindow()"); pass = false; }
|
if (uwpSleepFunc == NULL) { TRACELOG(LOG_WARNING, "UWP: UWPSetSleepFunc() must be called with a valid function before InitWindow()"); pass = false; }
|
||||||
if (uwpDisplaySizeFunc == NULL) { TRACELOG(LOG_ERROR, "UWP: UWPSetDisplaySizeFunc() must be called with a valid function before InitWindow()"); pass = false; }
|
if (uwpDisplaySizeFunc == NULL) { TRACELOG(LOG_WARNING, "UWP: UWPSetDisplaySizeFunc() must be called with a valid function before InitWindow()"); pass = false; }
|
||||||
if (uwpMouseLockFunc == NULL) { TRACELOG(LOG_ERROR, "UWP: UWPSetMouseLockFunc() must be called with a valid function before InitWindow()"); pass = false; }
|
if (uwpMouseLockFunc == NULL) { TRACELOG(LOG_WARNING, "UWP: UWPSetMouseLockFunc() must be called with a valid function before InitWindow()"); pass = false; }
|
||||||
if (uwpMouseUnlockFunc == NULL) { TRACELOG(LOG_ERROR, "UWP: UWPSetMouseUnlockFunc() must be called with a valid function before InitWindow()"); pass = false; }
|
if (uwpMouseUnlockFunc == NULL) { TRACELOG(LOG_WARNING, "UWP: UWPSetMouseUnlockFunc() must be called with a valid function before InitWindow()"); pass = false; }
|
||||||
if (uwpMouseShowFunc == NULL) { TRACELOG(LOG_ERROR, "UWP: UWPSetMouseShowFunc() must be called with a valid function before InitWindow()"); pass = false; }
|
if (uwpMouseShowFunc == NULL) { TRACELOG(LOG_WARNING, "UWP: UWPSetMouseShowFunc() must be called with a valid function before InitWindow()"); pass = false; }
|
||||||
if (uwpMouseHideFunc == NULL) { TRACELOG(LOG_ERROR, "UWP: UWPSetMouseHideFunc() must be called with a valid function before InitWindow()"); pass = false; }
|
if (uwpMouseHideFunc == NULL) { TRACELOG(LOG_WARNING, "UWP: UWPSetMouseHideFunc() must be called with a valid function before InitWindow()"); pass = false; }
|
||||||
if (uwpMouseSetPosFunc == NULL) { TRACELOG(LOG_ERROR, "UWP: UWPSetMouseSetPosFunc() must be called with a valid function before InitWindow()"); pass = false; }
|
if (uwpMouseSetPosFunc == NULL) { TRACELOG(LOG_WARNING, "UWP: UWPSetMouseSetPosFunc() must be called with a valid function before InitWindow()"); pass = false; }
|
||||||
if (uwpCoreWindow == NULL) { TRACELOG(LOG_ERROR, "UWP: A pointer to the UWP core window must be set before InitWindow()"); pass = false; }
|
if (uwpCoreWindow == NULL) { TRACELOG(LOG_WARNING, "UWP: A pointer to the UWP core window must be set before InitWindow()"); pass = false; }
|
||||||
|
|
||||||
return pass;
|
return pass;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
199
src/models.c
199
src/models.c
|
|
@ -1027,7 +1027,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int ins
|
||||||
if (instancing)
|
if (instancing)
|
||||||
{
|
{
|
||||||
// Create instances buffer
|
// Create instances buffer
|
||||||
instanceTransforms = RL_MALLOC(instances*sizeof(float16));
|
instanceTransforms = (float16 *)RL_MALLOC(instances*sizeof(float16));
|
||||||
|
|
||||||
// Fill buffer with instances transformations as float16 arrays
|
// Fill buffer with instances transformations as float16 arrays
|
||||||
for (int i = 0; i < instances; i++) instanceTransforms[i] = MatrixToFloatV(transforms[i]);
|
for (int i = 0; i < instances; i++) instanceTransforms[i] = MatrixToFloatV(transforms[i]);
|
||||||
|
|
@ -1461,9 +1461,9 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
|
||||||
animVertex = Vector3Subtract(animVertex, inTranslation);
|
animVertex = Vector3Subtract(animVertex, inTranslation);
|
||||||
animVertex = Vector3RotateByQuaternion(animVertex, QuaternionMultiply(outRotation, QuaternionInvert(inRotation)));
|
animVertex = Vector3RotateByQuaternion(animVertex, QuaternionMultiply(outRotation, QuaternionInvert(inRotation)));
|
||||||
animVertex = Vector3Add(animVertex, outTranslation);
|
animVertex = Vector3Add(animVertex, outTranslation);
|
||||||
model.meshes[m].animVertices[vCounter] += animVertex.x * boneWeight;
|
model.meshes[m].animVertices[vCounter] += animVertex.x*boneWeight;
|
||||||
model.meshes[m].animVertices[vCounter + 1] += animVertex.y * boneWeight;
|
model.meshes[m].animVertices[vCounter + 1] += animVertex.y*boneWeight;
|
||||||
model.meshes[m].animVertices[vCounter + 2] += animVertex.z * boneWeight;
|
model.meshes[m].animVertices[vCounter + 2] += animVertex.z*boneWeight;
|
||||||
|
|
||||||
// Normals processing
|
// Normals processing
|
||||||
// NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
|
// NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
|
||||||
|
|
@ -1471,9 +1471,9 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
|
||||||
{
|
{
|
||||||
animNormal = (Vector3){ model.meshes[m].normals[vCounter], model.meshes[m].normals[vCounter + 1], model.meshes[m].normals[vCounter + 2] };
|
animNormal = (Vector3){ model.meshes[m].normals[vCounter], model.meshes[m].normals[vCounter + 1], model.meshes[m].normals[vCounter + 2] };
|
||||||
animNormal = Vector3RotateByQuaternion(animNormal, QuaternionMultiply(outRotation, QuaternionInvert(inRotation)));
|
animNormal = Vector3RotateByQuaternion(animNormal, QuaternionMultiply(outRotation, QuaternionInvert(inRotation)));
|
||||||
model.meshes[m].animNormals[vCounter] += animNormal.x * boneWeight;
|
model.meshes[m].animNormals[vCounter] += animNormal.x*boneWeight;
|
||||||
model.meshes[m].animNormals[vCounter + 1] += animNormal.y * boneWeight;
|
model.meshes[m].animNormals[vCounter + 1] += animNormal.y*boneWeight;
|
||||||
model.meshes[m].animNormals[vCounter + 2] += animNormal.z * boneWeight;
|
model.meshes[m].animNormals[vCounter + 2] += animNormal.z*boneWeight;
|
||||||
}
|
}
|
||||||
boneCounter += 1;
|
boneCounter += 1;
|
||||||
}
|
}
|
||||||
|
|
@ -2979,53 +2979,32 @@ bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius)
|
||||||
return collision;
|
return collision;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect collision between ray and sphere
|
// Get collision info between ray and sphere
|
||||||
bool CheckCollisionRaySphere(Ray ray, Vector3 center, float radius)
|
RayCollision GetRayCollisionSphere(Ray ray, Vector3 center, float radius)
|
||||||
{
|
{
|
||||||
bool collision = false;
|
RayCollision collision = { 0 };
|
||||||
|
|
||||||
Vector3 raySpherePos = Vector3Subtract(center, ray.position);
|
Vector3 raySpherePos = Vector3Subtract(center, ray.position);
|
||||||
float distance = Vector3Length(raySpherePos);
|
float distance = Vector3Length(raySpherePos);
|
||||||
float vector = Vector3DotProduct(raySpherePos, ray.direction);
|
float vector = Vector3DotProduct(raySpherePos, ray.direction);
|
||||||
float d = radius*radius - (distance*distance - vector*vector);
|
float d = radius*radius - (distance*distance - vector*vector);
|
||||||
|
|
||||||
if (d >= 0.0f) collision = true;
|
if (d >= 0.0f) collision.hit = true;
|
||||||
|
|
||||||
return collision;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detect collision between ray and sphere with extended parameters and collision point detection
|
|
||||||
bool CheckCollisionRaySphereEx(Ray ray, Vector3 center, float radius, Vector3 *collisionPoint)
|
|
||||||
{
|
|
||||||
bool collision = false;
|
|
||||||
|
|
||||||
Vector3 raySpherePos = Vector3Subtract(center, ray.position);
|
|
||||||
float distance = Vector3Length(raySpherePos);
|
|
||||||
float vector = Vector3DotProduct(raySpherePos, ray.direction);
|
|
||||||
float d = radius*radius - (distance*distance - vector*vector);
|
|
||||||
|
|
||||||
if (d >= 0.0f) collision = true;
|
|
||||||
|
|
||||||
// Check if ray origin is inside the sphere to calculate the correct collision point
|
// Check if ray origin is inside the sphere to calculate the correct collision point
|
||||||
float collisionDistance = 0;
|
if (distance < radius) collision.distance = vector + sqrtf(d);
|
||||||
|
else collision.distance = vector - sqrtf(d);
|
||||||
if (distance < radius) collisionDistance = vector + sqrtf(d);
|
|
||||||
else collisionDistance = vector - sqrtf(d);
|
|
||||||
|
|
||||||
// Calculate collision point
|
// Calculate collision point
|
||||||
Vector3 cPoint = Vector3Add(ray.position, Vector3Scale(ray.direction, collisionDistance));
|
collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, collision.distance));
|
||||||
|
|
||||||
collisionPoint->x = cPoint.x;
|
|
||||||
collisionPoint->y = cPoint.y;
|
|
||||||
collisionPoint->z = cPoint.z;
|
|
||||||
|
|
||||||
return collision;
|
return collision;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect collision between ray and bounding box
|
// Get collision info between ray and box
|
||||||
bool CheckCollisionRayBox(Ray ray, BoundingBox box)
|
RayCollision GetRayCollisionBox(Ray ray, BoundingBox box)
|
||||||
{
|
{
|
||||||
bool collision = false;
|
RayCollision collision = { 0 };
|
||||||
|
|
||||||
float t[8] = { 0 };
|
float t[8] = { 0 };
|
||||||
t[0] = (box.min.x - ray.position.x)/ray.direction.x;
|
t[0] = (box.min.x - ray.position.x)/ray.direction.x;
|
||||||
|
|
@ -3037,14 +3016,17 @@ bool CheckCollisionRayBox(Ray ray, BoundingBox box)
|
||||||
t[6] = (float)fmax(fmax(fmin(t[0], t[1]), fmin(t[2], t[3])), fmin(t[4], t[5]));
|
t[6] = (float)fmax(fmax(fmin(t[0], t[1]), fmin(t[2], t[3])), fmin(t[4], t[5]));
|
||||||
t[7] = (float)fmin(fmin(fmax(t[0], t[1]), fmax(t[2], t[3])), fmax(t[4], t[5]));
|
t[7] = (float)fmin(fmin(fmax(t[0], t[1]), fmax(t[2], t[3])), fmax(t[4], t[5]));
|
||||||
|
|
||||||
collision = !(t[7] < 0 || t[6] > t[7]);
|
collision.hit = !(t[7] < 0 || t[6] > t[7]);
|
||||||
|
|
||||||
|
// TODO: Calculate other RayCollision data
|
||||||
|
|
||||||
return collision;
|
return collision;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get collision info between ray and mesh
|
// Get collision info between ray and mesh
|
||||||
RayHitInfo GetCollisionRayMesh(Ray ray, Mesh mesh, Matrix transform)
|
RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform)
|
||||||
{
|
{
|
||||||
RayHitInfo result = { 0 };
|
RayCollision collision = { 0 };
|
||||||
|
|
||||||
// Check if mesh vertex data on CPU for testing
|
// Check if mesh vertex data on CPU for testing
|
||||||
if (mesh.vertices != NULL)
|
if (mesh.vertices != NULL)
|
||||||
|
|
@ -3074,47 +3056,49 @@ RayHitInfo GetCollisionRayMesh(Ray ray, Mesh mesh, Matrix transform)
|
||||||
b = Vector3Transform(b, transform);
|
b = Vector3Transform(b, transform);
|
||||||
c = Vector3Transform(c, transform);
|
c = Vector3Transform(c, transform);
|
||||||
|
|
||||||
RayHitInfo triHitInfo = GetCollisionRayTriangle(ray, a, b, c);
|
RayCollision triHitInfo = GetRayCollisionTriangle(ray, a, b, c);
|
||||||
|
|
||||||
if (triHitInfo.hit)
|
if (triHitInfo.hit)
|
||||||
{
|
{
|
||||||
// Save the closest hit triangle
|
// Save the closest hit triangle
|
||||||
if ((!result.hit) || (result.distance > triHitInfo.distance)) result = triHitInfo;
|
if ((!collision.hit) || (collision.distance > triHitInfo.distance)) collision = triHitInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
|
return collision;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get collision info between ray and model
|
// Get collision info between ray and model
|
||||||
RayHitInfo GetCollisionRayModel(Ray ray, Model model)
|
RayCollision GetRayCollisionModel(Ray ray, Model model)
|
||||||
{
|
{
|
||||||
RayHitInfo result = { 0 };
|
RayCollision collision = { 0 };
|
||||||
|
|
||||||
for (int m = 0; m < model.meshCount; m++)
|
for (int m = 0; m < model.meshCount; m++)
|
||||||
{
|
{
|
||||||
RayHitInfo meshHitInfo = GetCollisionRayMesh(ray, model.meshes[m], model.transform);
|
RayCollision meshHitInfo = GetRayCollisionMesh(ray, model.meshes[m], model.transform);
|
||||||
|
|
||||||
if (meshHitInfo.hit)
|
if (meshHitInfo.hit)
|
||||||
{
|
{
|
||||||
// Save the closest hit mesh
|
// Save the closest hit mesh
|
||||||
if ((!result.hit) || (result.distance > meshHitInfo.distance)) result = meshHitInfo;
|
if ((!collision.hit) || (collision.distance > meshHitInfo.distance)) collision = meshHitInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return collision;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get collision info between ray and triangle
|
// Get collision info between ray and triangle
|
||||||
// NOTE: Based on https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
|
// NOTE: Based on https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
|
||||||
RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3)
|
RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3)
|
||||||
{
|
{
|
||||||
#define EPSILON 0.000001 // A small number
|
#define EPSILON 0.000001 // A small number
|
||||||
|
|
||||||
Vector3 edge1, edge2;
|
RayCollision collision = { 0 };
|
||||||
|
Vector3 edge1 = { 0 };
|
||||||
|
Vector3 edge2 = { 0 };
|
||||||
Vector3 p, q, tv;
|
Vector3 p, q, tv;
|
||||||
float det, invDet, u, v, t;
|
float det, invDet, u, v, t;
|
||||||
RayHitInfo result = {0};
|
|
||||||
|
|
||||||
// Find vectors for two edges sharing V1
|
// Find vectors for two edges sharing V1
|
||||||
edge1 = Vector3Subtract(p2, p1);
|
edge1 = Vector3Subtract(p2, p1);
|
||||||
|
|
@ -3127,7 +3111,7 @@ RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3)
|
||||||
det = Vector3DotProduct(edge1, p);
|
det = Vector3DotProduct(edge1, p);
|
||||||
|
|
||||||
// Avoid culling!
|
// Avoid culling!
|
||||||
if ((det > -EPSILON) && (det < EPSILON)) return result;
|
if ((det > -EPSILON) && (det < EPSILON)) return collision;
|
||||||
|
|
||||||
invDet = 1.0f/det;
|
invDet = 1.0f/det;
|
||||||
|
|
||||||
|
|
@ -3138,7 +3122,7 @@ RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3)
|
||||||
u = Vector3DotProduct(tv, p)*invDet;
|
u = Vector3DotProduct(tv, p)*invDet;
|
||||||
|
|
||||||
// The intersection lies outside of the triangle
|
// The intersection lies outside of the triangle
|
||||||
if ((u < 0.0f) || (u > 1.0f)) return result;
|
if ((u < 0.0f) || (u > 1.0f)) return collision;
|
||||||
|
|
||||||
// Prepare to test v parameter
|
// Prepare to test v parameter
|
||||||
q = Vector3CrossProduct(tv, edge1);
|
q = Vector3CrossProduct(tv, edge1);
|
||||||
|
|
@ -3147,29 +3131,28 @@ RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3)
|
||||||
v = Vector3DotProduct(ray.direction, q)*invDet;
|
v = Vector3DotProduct(ray.direction, q)*invDet;
|
||||||
|
|
||||||
// The intersection lies outside of the triangle
|
// The intersection lies outside of the triangle
|
||||||
if ((v < 0.0f) || ((u + v) > 1.0f)) return result;
|
if ((v < 0.0f) || ((u + v) > 1.0f)) return collision;
|
||||||
|
|
||||||
t = Vector3DotProduct(edge2, q)*invDet;
|
t = Vector3DotProduct(edge2, q)*invDet;
|
||||||
|
|
||||||
if (t > EPSILON)
|
if (t > EPSILON)
|
||||||
{
|
{
|
||||||
// Ray hit, get hit point and normal
|
// Ray hit, get hit point and normal
|
||||||
result.hit = true;
|
collision.hit = true;
|
||||||
result.distance = t;
|
collision.distance = t;
|
||||||
result.hit = true;
|
collision.normal = Vector3Normalize(Vector3CrossProduct(edge1, edge2));
|
||||||
result.normal = Vector3Normalize(Vector3CrossProduct(edge1, edge2));
|
collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, t));
|
||||||
result.position = Vector3Add(ray.position, Vector3Scale(ray.direction, t));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return collision;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get collision info between ray and ground plane (Y-normal plane)
|
// Get collision info between ray and ground plane (Y-normal plane)
|
||||||
RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight)
|
RayCollision GetRayCollisionGround(Ray ray, float groundHeight)
|
||||||
{
|
{
|
||||||
#define EPSILON 0.000001 // A small number
|
#define EPSILON 0.000001 // A small number
|
||||||
|
|
||||||
RayHitInfo result = { 0 };
|
RayCollision collision = { 0 };
|
||||||
|
|
||||||
if (fabsf(ray.direction.y) > EPSILON)
|
if (fabsf(ray.direction.y) > EPSILON)
|
||||||
{
|
{
|
||||||
|
|
@ -3177,15 +3160,15 @@ RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight)
|
||||||
|
|
||||||
if (distance >= 0.0)
|
if (distance >= 0.0)
|
||||||
{
|
{
|
||||||
result.hit = true;
|
collision.hit = true;
|
||||||
result.distance = distance;
|
collision.distance = distance;
|
||||||
result.normal = (Vector3){ 0.0, 1.0, 0.0 };
|
collision.normal = (Vector3){ 0.0, 1.0, 0.0 };
|
||||||
result.position = Vector3Add(ray.position, Vector3Scale(ray.direction, distance));
|
collision.point = Vector3Add(ray.position, Vector3Scale(ray.direction, distance));
|
||||||
result.position.y = groundHeight;
|
collision.point.y = groundHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return collision;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -3205,11 +3188,11 @@ static Model LoadOBJ(const char *fileName)
|
||||||
tinyobj_material_t *materials = NULL;
|
tinyobj_material_t *materials = NULL;
|
||||||
unsigned int materialCount = 0;
|
unsigned int materialCount = 0;
|
||||||
|
|
||||||
char *fileData = LoadFileText(fileName);
|
char *fileText = LoadFileText(fileName);
|
||||||
|
|
||||||
if (fileData != NULL)
|
if (fileText != NULL)
|
||||||
{
|
{
|
||||||
unsigned int dataSize = (unsigned int)strlen(fileData);
|
unsigned int dataSize = (unsigned int)strlen(fileText);
|
||||||
char currentDir[1024] = { 0 };
|
char currentDir[1024] = { 0 };
|
||||||
strcpy(currentDir, GetWorkingDirectory());
|
strcpy(currentDir, GetWorkingDirectory());
|
||||||
const char *workingDir = GetDirectoryPath(fileName);
|
const char *workingDir = GetDirectoryPath(fileName);
|
||||||
|
|
@ -3219,7 +3202,7 @@ static Model LoadOBJ(const char *fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int flags = TINYOBJ_FLAG_TRIANGULATE;
|
unsigned int flags = TINYOBJ_FLAG_TRIANGULATE;
|
||||||
int ret = tinyobj_parse_obj(&attrib, &meshes, &meshCount, &materials, &materialCount, fileData, dataSize, flags);
|
int ret = tinyobj_parse_obj(&attrib, &meshes, &meshCount, &materials, &materialCount, fileText, dataSize, flags);
|
||||||
|
|
||||||
if (ret != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load OBJ data", fileName);
|
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);
|
else TRACELOG(LOG_INFO, "MODEL: [%s] OBJ data loaded successfully: %i meshes / %i materials", fileName, meshCount, materialCount);
|
||||||
|
|
@ -3346,9 +3329,9 @@ static Model LoadOBJ(const char *fileName)
|
||||||
tinyobj_shapes_free(meshes, meshCount);
|
tinyobj_shapes_free(meshes, meshCount);
|
||||||
tinyobj_materials_free(materials, materialCount);
|
tinyobj_materials_free(materials, materialCount);
|
||||||
|
|
||||||
RL_FREE(fileData);
|
UnloadFileText(fileText);
|
||||||
|
|
||||||
RL_FREE(matFaces);
|
RL_FREE(matFaces);
|
||||||
|
|
||||||
RL_FREE(vCount);
|
RL_FREE(vCount);
|
||||||
RL_FREE(vtCount);
|
RL_FREE(vtCount);
|
||||||
RL_FREE(vnCount);
|
RL_FREE(vnCount);
|
||||||
|
|
@ -3458,7 +3441,7 @@ static Model LoadIQM(const char *fileName)
|
||||||
IQM_TANGENT = 3, // NOTE: Tangents unused by default
|
IQM_TANGENT = 3, // NOTE: Tangents unused by default
|
||||||
IQM_BLENDINDEXES = 4,
|
IQM_BLENDINDEXES = 4,
|
||||||
IQM_BLENDWEIGHTS = 5,
|
IQM_BLENDWEIGHTS = 5,
|
||||||
IQM_COLOR = 6, // NOTE: Vertex colors unused by default
|
IQM_COLOR = 6,
|
||||||
IQM_CUSTOM = 0x10 // NOTE: Custom vertex values unused by default
|
IQM_CUSTOM = 0x10 // NOTE: Custom vertex values unused by default
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -3474,6 +3457,7 @@ static Model LoadIQM(const char *fileName)
|
||||||
float *text = NULL;
|
float *text = NULL;
|
||||||
char *blendi = NULL;
|
char *blendi = NULL;
|
||||||
unsigned char *blendw = NULL;
|
unsigned char *blendw = NULL;
|
||||||
|
unsigned char *color = NULL;
|
||||||
|
|
||||||
// In case file can not be read, return an empty model
|
// In case file can not be read, return an empty model
|
||||||
if (fileDataPtr == NULL) return model;
|
if (fileDataPtr == NULL) return model;
|
||||||
|
|
@ -3496,7 +3480,7 @@ static Model LoadIQM(const char *fileName)
|
||||||
//fileDataPtr += sizeof(IQMHeader); // Move file data pointer
|
//fileDataPtr += sizeof(IQMHeader); // Move file data pointer
|
||||||
|
|
||||||
// Meshes data processing
|
// Meshes data processing
|
||||||
imesh = RL_MALLOC(sizeof(IQMMesh)*iqmHeader->num_meshes);
|
imesh = RL_MALLOC(iqmHeader->num_meshes*sizeof(IQMMesh));
|
||||||
//fseek(iqmFile, iqmHeader->ofs_meshes, SEEK_SET);
|
//fseek(iqmFile, iqmHeader->ofs_meshes, SEEK_SET);
|
||||||
//fread(imesh, sizeof(IQMMesh)*iqmHeader->num_meshes, 1, iqmFile);
|
//fread(imesh, sizeof(IQMMesh)*iqmHeader->num_meshes, 1, iqmFile);
|
||||||
memcpy(imesh, fileDataPtr + iqmHeader->ofs_meshes, iqmHeader->num_meshes*sizeof(IQMMesh));
|
memcpy(imesh, fileDataPtr + iqmHeader->ofs_meshes, iqmHeader->num_meshes*sizeof(IQMMesh));
|
||||||
|
|
@ -3662,6 +3646,25 @@ static Model LoadIQM(const char *fileName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
case IQM_COLOR:
|
||||||
|
{
|
||||||
|
color = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
||||||
|
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||||
|
//fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
|
||||||
|
memcpy(color, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
||||||
|
|
||||||
|
for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
|
||||||
|
{
|
||||||
|
model.meshes[m].colors = RL_CALLOC(model.meshes[m].vertexCount*4, sizeof(unsigned char));
|
||||||
|
|
||||||
|
int vCounter = 0;
|
||||||
|
for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
|
||||||
|
{
|
||||||
|
model.meshes[m].colors[vCounter] = color[i];
|
||||||
|
vCounter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4301,6 +4304,40 @@ static Model LoadGLTF(const char *fileName)
|
||||||
TRACELOG(LOG_WARNING, "MODEL: [%s] glTF normals must be float or int", fileName);
|
TRACELOG(LOG_WARNING, "MODEL: [%s] glTF normals must be float or int", fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_color)
|
||||||
|
{
|
||||||
|
cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data;
|
||||||
|
model.meshes[primitiveIndex].colors = RL_MALLOC(acc->count*4*sizeof(unsigned char));
|
||||||
|
|
||||||
|
if (acc->component_type == cgltf_component_type_r_8u)
|
||||||
|
{
|
||||||
|
for (int a = 0; a < acc->count; a++)
|
||||||
|
{
|
||||||
|
GLTFReadValue(acc, a, model.meshes[primitiveIndex].colors + (a*4), 4, sizeof(unsigned char));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (acc->component_type == cgltf_component_type_r_16u)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_WARNING, "MODEL: [%s] converting glTF colors to unsigned char", fileName);
|
||||||
|
for (int a = 0; a < acc->count; a++)
|
||||||
|
{
|
||||||
|
unsigned short readValue[4];
|
||||||
|
for (int a = 0; a < acc->count; a++)
|
||||||
|
{
|
||||||
|
GLTFReadValue(acc, a, readValue, 4, sizeof(unsigned short));
|
||||||
|
// 257 = 65535/255
|
||||||
|
model.meshes[primitiveIndex].colors[(a*4) + 0] = (unsigned char)(readValue[0] / 257);
|
||||||
|
model.meshes[primitiveIndex].colors[(a*4) + 1] = (unsigned char)(readValue[1] / 257);
|
||||||
|
model.meshes[primitiveIndex].colors[(a*4) + 2] = (unsigned char)(readValue[2] / 257);
|
||||||
|
model.meshes[primitiveIndex].colors[(a*4) + 3] = (unsigned char)(readValue[3] / 257);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_WARNING, "MODEL: [%s] glTF colors must be uchar or ushort", fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cgltf_accessor *acc = data->meshes[i].primitives[p].indices;
|
cgltf_accessor *acc = data->meshes[i].primitives[p].indices;
|
||||||
|
|
@ -4466,8 +4503,8 @@ static void LoadGLTFBoneAttribute(Model* model, cgltf_accessor* jointsAccessor,
|
||||||
{
|
{
|
||||||
if (jointsAccessor->component_type == cgltf_component_type_r_16u)
|
if (jointsAccessor->component_type == cgltf_component_type_r_16u)
|
||||||
{
|
{
|
||||||
model->meshes[primitiveIndex].boneIds = RL_MALLOC(sizeof(int)*jointsAccessor->count*4);
|
model->meshes[primitiveIndex].boneIds = RL_MALLOC(jointsAccessor->count*4*sizeof(int));
|
||||||
short* bones = RL_MALLOC(sizeof(short)*jointsAccessor->count*4);
|
short* bones = RL_MALLOC(jointsAccessor->count*4*sizeof(short));
|
||||||
|
|
||||||
for (unsigned int a = 0; a < jointsAccessor->count; a++)
|
for (unsigned int a = 0; a < jointsAccessor->count; a++)
|
||||||
{
|
{
|
||||||
|
|
@ -4491,8 +4528,8 @@ static void LoadGLTFBoneAttribute(Model* model, cgltf_accessor* jointsAccessor,
|
||||||
}
|
}
|
||||||
else if (jointsAccessor->component_type == cgltf_component_type_r_8u)
|
else if (jointsAccessor->component_type == cgltf_component_type_r_8u)
|
||||||
{
|
{
|
||||||
model->meshes[primitiveIndex].boneIds = RL_MALLOC(sizeof(int)*jointsAccessor->count*4);
|
model->meshes[primitiveIndex].boneIds = RL_MALLOC(jointsAccessor->count*4*sizeof(int));
|
||||||
unsigned char* bones = RL_MALLOC(sizeof(unsigned char)*jointsAccessor->count*4);
|
unsigned char* bones = RL_MALLOC(jointsAccessor->count*4*sizeof(unsigned char));
|
||||||
|
|
||||||
for (unsigned int a = 0; a < jointsAccessor->count; a++)
|
for (unsigned int a = 0; a < jointsAccessor->count; a++)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
41
src/raudio.c
41
src/raudio.c
|
|
@ -276,25 +276,27 @@ typedef struct tagBITMAPINFOHEADER {
|
||||||
// NOTE: Depends on data structure provided by the library
|
// NOTE: Depends on data structure provided by the library
|
||||||
// in charge of reading the different file types
|
// in charge of reading the different file types
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MUSIC_AUDIO_NONE = 0,
|
MUSIC_AUDIO_NONE = 0, // No audio context loaded
|
||||||
MUSIC_AUDIO_WAV,
|
MUSIC_AUDIO_WAV, // WAV audio context
|
||||||
MUSIC_AUDIO_OGG,
|
MUSIC_AUDIO_OGG, // OGG audio context
|
||||||
MUSIC_AUDIO_FLAC,
|
MUSIC_AUDIO_FLAC, // FLAC audio context
|
||||||
MUSIC_AUDIO_MP3,
|
MUSIC_AUDIO_MP3, // MP3 audio context
|
||||||
MUSIC_MODULE_XM,
|
MUSIC_MODULE_XM, // XM module audio context
|
||||||
MUSIC_MODULE_MOD
|
MUSIC_MODULE_MOD // MOD module audio context
|
||||||
} MusicContextType;
|
} MusicContextType;
|
||||||
|
|
||||||
#if defined(RAUDIO_STANDALONE)
|
#if defined(RAUDIO_STANDALONE)
|
||||||
|
// Trace log level
|
||||||
|
// NOTE: Organized by priority level
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LOG_ALL,
|
LOG_ALL = 0, // Display all logs
|
||||||
LOG_TRACE,
|
LOG_TRACE, // Trace logging, intended for internal use only
|
||||||
LOG_DEBUG,
|
LOG_DEBUG, // Debug logging, used for internal debugging, it should be disabled on release builds
|
||||||
LOG_INFO,
|
LOG_INFO, // Info logging, used for program execution info
|
||||||
LOG_WARNING,
|
LOG_WARNING, // Warning logging, used on recoverable failures
|
||||||
LOG_ERROR,
|
LOG_ERROR, // Error logging, used on unrecoverable failures
|
||||||
LOG_FATAL,
|
LOG_FATAL, // Fatal logging, used to abort program: exit(EXIT_FAILURE)
|
||||||
LOG_NONE
|
LOG_NONE // Disable logging
|
||||||
} TraceLogLevel;
|
} TraceLogLevel;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -476,7 +478,7 @@ void InitAudioDevice(void)
|
||||||
// Init dummy audio buffers pool for multichannel sound playing
|
// Init dummy audio buffers pool for multichannel sound playing
|
||||||
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
|
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
|
||||||
{
|
{
|
||||||
// WARNING: An empty audioBuffer is created (data = 0)
|
// WARNING: An empty audio buffer is created (data = 0)
|
||||||
// AudioBuffer data just points to loaded sound data
|
// AudioBuffer data just points to loaded sound data
|
||||||
AUDIO.MultiChannel.pool[i] = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, 0, AUDIO_BUFFER_USAGE_STATIC);
|
AUDIO.MultiChannel.pool[i] = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, 0, AUDIO_BUFFER_USAGE_STATIC);
|
||||||
}
|
}
|
||||||
|
|
@ -1428,13 +1430,13 @@ Music LoadMusicStreamFromMemory(const char *fileType, unsigned char* data, int d
|
||||||
#if defined(SUPPORT_FILEFORMAT_MOD)
|
#if defined(SUPPORT_FILEFORMAT_MOD)
|
||||||
else if (TextIsEqual(fileExtLower, ".mod"))
|
else if (TextIsEqual(fileExtLower, ".mod"))
|
||||||
{
|
{
|
||||||
jar_mod_context_t *ctxMod = RL_MALLOC(sizeof(jar_mod_context_t));
|
jar_mod_context_t *ctxMod = (jar_mod_context_t *)RL_MALLOC(sizeof(jar_mod_context_t));
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
jar_mod_init(ctxMod);
|
jar_mod_init(ctxMod);
|
||||||
|
|
||||||
// copy data to allocated memory for default UnloadMusicStream
|
// Copy data to allocated memory for default UnloadMusicStream
|
||||||
unsigned char *newData = RL_MALLOC(dataSize);
|
unsigned char *newData = (unsigned char *)RL_MALLOC(dataSize);
|
||||||
int it = dataSize/sizeof(unsigned char);
|
int it = dataSize/sizeof(unsigned char);
|
||||||
for (int i = 0; i < it; i++){
|
for (int i = 0; i < it; i++){
|
||||||
newData[i] = data[i];
|
newData[i] = data[i];
|
||||||
|
|
@ -2073,6 +2075,7 @@ static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, f
|
||||||
|
|
||||||
|
|
||||||
// Sending audio data to device callback function
|
// Sending audio data to device callback function
|
||||||
|
// This function will be called when miniaudio needs more data
|
||||||
// NOTE: All the mixing takes place here
|
// NOTE: All the mixing takes place here
|
||||||
static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const void *pFramesInput, ma_uint32 frameCount)
|
static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const void *pFramesInput, ma_uint32 frameCount)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
333
src/raylib.h
333
src/raylib.h
|
|
@ -81,7 +81,7 @@
|
||||||
|
|
||||||
#include <stdarg.h> // Required for: va_list - Only used by TraceLogCallback
|
#include <stdarg.h> // Required for: va_list - Only used by TraceLogCallback
|
||||||
|
|
||||||
#define RAYLIB_VERSION "3.7.0"
|
#define RAYLIB_VERSION "3.8-dev"
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
// Microsoft attibutes to tell compiler that symbols are imported/exported from a .dll
|
// Microsoft attibutes to tell compiler that symbols are imported/exported from a .dll
|
||||||
|
|
@ -160,13 +160,14 @@
|
||||||
|
|
||||||
// Temporal hacks to avoid breaking old codebases using
|
// Temporal hacks to avoid breaking old codebases using
|
||||||
// deprecated raylib implementation or definitions
|
// deprecated raylib implementation or definitions
|
||||||
#define FormatText TextFormat
|
#define SpriteFont Font
|
||||||
#define LoadText LoadFileText
|
#define FormatText TextFormat
|
||||||
#define GetExtension GetFileExtension
|
#define LoadText LoadFileText
|
||||||
#define GetImageData LoadImageColors
|
#define GetExtension GetFileExtension
|
||||||
#define FILTER_POINT TEXTURE_FILTER_POINT
|
#define GetImageData LoadImageColors
|
||||||
#define FILTER_BILINEAR TEXTURE_FILTER_BILINEAR
|
#define FILTER_POINT TEXTURE_FILTER_POINT
|
||||||
#define MAP_DIFFUSE MATERIAL_MAP_DIFFUSE
|
#define FILTER_BILINEAR TEXTURE_FILTER_BILINEAR
|
||||||
|
#define MAP_DIFFUSE MATERIAL_MAP_DIFFUSE
|
||||||
#define UNCOMPRESSED_R8G8B8A8 PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
|
#define UNCOMPRESSED_R8G8B8A8 PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -176,59 +177,58 @@
|
||||||
#if defined(__STDC__) && __STDC_VERSION__ >= 199901L
|
#if defined(__STDC__) && __STDC_VERSION__ >= 199901L
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#elif !defined(__cplusplus) && !defined(bool)
|
#elif !defined(__cplusplus) && !defined(bool)
|
||||||
typedef enum { false, true } bool;
|
typedef enum bool { false, true } bool;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Vector2 type
|
// Vector2, 2 components
|
||||||
typedef struct Vector2 {
|
typedef struct Vector2 {
|
||||||
float x;
|
float x; // Vector x component
|
||||||
float y;
|
float y; // Vector y component
|
||||||
} Vector2;
|
} Vector2;
|
||||||
|
|
||||||
// Vector3 type
|
// Vector3, 3 components
|
||||||
typedef struct Vector3 {
|
typedef struct Vector3 {
|
||||||
float x;
|
float x; // Vector x component
|
||||||
float y;
|
float y; // Vector y component
|
||||||
float z;
|
float z; // Vector z component
|
||||||
} Vector3;
|
} Vector3;
|
||||||
|
|
||||||
// Vector4 type
|
// Vector4, 4 components
|
||||||
typedef struct Vector4 {
|
typedef struct Vector4 {
|
||||||
float x;
|
float x; // Vector x component
|
||||||
float y;
|
float y; // Vector y component
|
||||||
float z;
|
float z; // Vector z component
|
||||||
float w;
|
float w; // Vector w component
|
||||||
} Vector4;
|
} Vector4;
|
||||||
|
|
||||||
// Quaternion type, same as Vector4
|
// Quaternion, 4 components (Vector4 alias)
|
||||||
typedef Vector4 Quaternion;
|
typedef Vector4 Quaternion;
|
||||||
|
|
||||||
// Matrix type (OpenGL style 4x4 - right handed, column major)
|
// Matrix, 4x4 components, column major, OpenGL style, right handed
|
||||||
typedef struct Matrix {
|
typedef struct Matrix {
|
||||||
float m0, m4, m8, m12;
|
float m0, m4, m8, m12; // Matrix first row (4 components)
|
||||||
float m1, m5, m9, m13;
|
float m1, m5, m9, m13; // Matrix second row (4 components)
|
||||||
float m2, m6, m10, m14;
|
float m2, m6, m10, m14; // Matrix third row (4 components)
|
||||||
float m3, m7, m11, m15;
|
float m3, m7, m11, m15; // Matrix fourth row (4 components)
|
||||||
} Matrix;
|
} Matrix;
|
||||||
|
|
||||||
// Color type, RGBA (32bit)
|
// Color, 4 components, R8G8B8A8 (32bit)
|
||||||
typedef struct Color {
|
typedef struct Color {
|
||||||
unsigned char r;
|
unsigned char r; // Color red value
|
||||||
unsigned char g;
|
unsigned char g; // Color green value
|
||||||
unsigned char b;
|
unsigned char b; // Color blue value
|
||||||
unsigned char a;
|
unsigned char a; // Color alpha value
|
||||||
} Color;
|
} Color;
|
||||||
|
|
||||||
// Rectangle type
|
// Rectangle, 4 components
|
||||||
typedef struct Rectangle {
|
typedef struct Rectangle {
|
||||||
float x;
|
float x; // Rectangle top-left corner position x
|
||||||
float y;
|
float y; // Rectangle top-left corner position y
|
||||||
float width;
|
float width; // Rectangle width
|
||||||
float height;
|
float height; // Rectangle height
|
||||||
} Rectangle;
|
} Rectangle;
|
||||||
|
|
||||||
// Image type, bpp always RGBA (32bit)
|
// Image, pixel data stored in CPU memory (RAM)
|
||||||
// NOTE: Data stored in CPU memory (RAM)
|
|
||||||
typedef struct Image {
|
typedef struct Image {
|
||||||
void *data; // Image raw data
|
void *data; // Image raw data
|
||||||
int width; // Image base width
|
int width; // Image base width
|
||||||
|
|
@ -237,8 +237,7 @@ typedef struct Image {
|
||||||
int format; // Data format (PixelFormat type)
|
int format; // Data format (PixelFormat type)
|
||||||
} Image;
|
} Image;
|
||||||
|
|
||||||
// Texture type
|
// Texture, tex data stored in GPU memory (VRAM)
|
||||||
// NOTE: Data stored in GPU memory
|
|
||||||
typedef struct Texture {
|
typedef struct Texture {
|
||||||
unsigned int id; // OpenGL texture id
|
unsigned int id; // OpenGL texture id
|
||||||
int width; // Texture base width
|
int width; // Texture base width
|
||||||
|
|
@ -247,23 +246,23 @@ typedef struct Texture {
|
||||||
int format; // Data format (PixelFormat type)
|
int format; // Data format (PixelFormat type)
|
||||||
} Texture;
|
} Texture;
|
||||||
|
|
||||||
// Texture2D type, same as Texture
|
// Texture2D, same as Texture
|
||||||
typedef Texture Texture2D;
|
typedef Texture Texture2D;
|
||||||
|
|
||||||
// TextureCubemap type, actually, same as Texture
|
// TextureCubemap, same as Texture
|
||||||
typedef Texture TextureCubemap;
|
typedef Texture TextureCubemap;
|
||||||
|
|
||||||
// RenderTexture type, for texture rendering
|
// RenderTexture, fbo for texture rendering
|
||||||
typedef struct RenderTexture {
|
typedef struct RenderTexture {
|
||||||
unsigned int id; // OpenGL framebuffer object id
|
unsigned int id; // OpenGL framebuffer object id
|
||||||
Texture texture; // Color buffer attachment texture
|
Texture texture; // Color buffer attachment texture
|
||||||
Texture depth; // Depth buffer attachment texture
|
Texture depth; // Depth buffer attachment texture
|
||||||
} RenderTexture;
|
} RenderTexture;
|
||||||
|
|
||||||
// RenderTexture2D type, same as RenderTexture
|
// RenderTexture2D, same as RenderTexture
|
||||||
typedef RenderTexture RenderTexture2D;
|
typedef RenderTexture RenderTexture2D;
|
||||||
|
|
||||||
// N-Patch layout info
|
// NPatchInfo, n-patch layout info
|
||||||
typedef struct NPatchInfo {
|
typedef struct NPatchInfo {
|
||||||
Rectangle source; // Texture source rectangle
|
Rectangle source; // Texture source rectangle
|
||||||
int left; // Left border offset
|
int left; // Left border offset
|
||||||
|
|
@ -273,7 +272,7 @@ typedef struct NPatchInfo {
|
||||||
int layout; // Layout of the n-patch: 3x3, 1x3 or 3x1
|
int layout; // Layout of the n-patch: 3x3, 1x3 or 3x1
|
||||||
} NPatchInfo;
|
} NPatchInfo;
|
||||||
|
|
||||||
// Font character info
|
// CharInfo, font character info
|
||||||
typedef struct CharInfo {
|
typedef struct CharInfo {
|
||||||
int value; // Character value (Unicode)
|
int value; // Character value (Unicode)
|
||||||
int offsetX; // Character offset X when drawing
|
int offsetX; // Character offset X when drawing
|
||||||
|
|
@ -282,7 +281,7 @@ typedef struct CharInfo {
|
||||||
Image image; // Character image data
|
Image image; // Character image data
|
||||||
} CharInfo;
|
} CharInfo;
|
||||||
|
|
||||||
// Font type, includes texture and charSet array data
|
// Font, font texture and CharInfo array data
|
||||||
typedef struct Font {
|
typedef struct Font {
|
||||||
int baseSize; // Base size (default chars height)
|
int baseSize; // Base size (default chars height)
|
||||||
int charsCount; // Number of characters
|
int charsCount; // Number of characters
|
||||||
|
|
@ -292,9 +291,7 @@ typedef struct Font {
|
||||||
CharInfo *chars; // Characters info data
|
CharInfo *chars; // Characters info data
|
||||||
} Font;
|
} Font;
|
||||||
|
|
||||||
#define SpriteFont Font // SpriteFont type fallback, defaults to Font
|
// Camera, defines position/orientation in 3d space
|
||||||
|
|
||||||
// Camera type, defines a camera position/orientation in 3d space
|
|
||||||
typedef struct Camera3D {
|
typedef struct Camera3D {
|
||||||
Vector3 position; // Camera position
|
Vector3 position; // Camera position
|
||||||
Vector3 target; // Camera target it looks-at
|
Vector3 target; // Camera target it looks-at
|
||||||
|
|
@ -305,7 +302,7 @@ typedef struct Camera3D {
|
||||||
|
|
||||||
typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D
|
typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D
|
||||||
|
|
||||||
// Camera2D type, defines a 2d camera
|
// Camera2D, defines position/orientation in 2d space
|
||||||
typedef struct Camera2D {
|
typedef struct Camera2D {
|
||||||
Vector2 offset; // Camera offset (displacement from target)
|
Vector2 offset; // Camera offset (displacement from target)
|
||||||
Vector2 target; // Camera target (rotation and zoom origin)
|
Vector2 target; // Camera target (rotation and zoom origin)
|
||||||
|
|
@ -313,148 +310,145 @@ typedef struct Camera2D {
|
||||||
float zoom; // Camera zoom (scaling), should be 1.0f by default
|
float zoom; // Camera zoom (scaling), should be 1.0f by default
|
||||||
} Camera2D;
|
} Camera2D;
|
||||||
|
|
||||||
// Vertex data definning a mesh
|
// Mesh, vertex data and vao/vbo
|
||||||
// NOTE: Data stored in CPU memory (and GPU)
|
|
||||||
typedef struct Mesh {
|
typedef struct Mesh {
|
||||||
int vertexCount; // Number of vertices stored in arrays
|
int vertexCount; // Number of vertices stored in arrays
|
||||||
int triangleCount; // Number of triangles stored (indexed or not)
|
int triangleCount; // Number of triangles stored (indexed or not)
|
||||||
|
|
||||||
// Default vertex data
|
// Default vertex data
|
||||||
float *vertices; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0)
|
float *vertices; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0)
|
||||||
float *texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
|
float *texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
|
||||||
float *texcoords2; // Vertex second texture coordinates (useful for lightmaps) (shader-location = 5)
|
float *texcoords2; // Vertex second texture coordinates (useful for lightmaps) (shader-location = 5)
|
||||||
float *normals; // Vertex normals (XYZ - 3 components per vertex) (shader-location = 2)
|
float *normals; // Vertex normals (XYZ - 3 components per vertex) (shader-location = 2)
|
||||||
float *tangents; // Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4)
|
float *tangents; // Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4)
|
||||||
unsigned char *colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
|
unsigned char *colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
|
||||||
unsigned short *indices;// Vertex indices (in case vertex data comes indexed)
|
unsigned short *indices; // Vertex indices (in case vertex data comes indexed)
|
||||||
|
|
||||||
// Animation vertex data
|
// Animation vertex data
|
||||||
float *animVertices; // Animated vertex positions (after bones transformations)
|
float *animVertices; // Animated vertex positions (after bones transformations)
|
||||||
float *animNormals; // Animated normals (after bones transformations)
|
float *animNormals; // Animated normals (after bones transformations)
|
||||||
int *boneIds; // Vertex bone ids, up to 4 bones influence by vertex (skinning)
|
int *boneIds; // Vertex bone ids, up to 4 bones influence by vertex (skinning)
|
||||||
float *boneWeights; // Vertex bone weight, up to 4 bones influence by vertex (skinning)
|
float *boneWeights; // Vertex bone weight, up to 4 bones influence by vertex (skinning)
|
||||||
|
|
||||||
// OpenGL identifiers
|
// OpenGL identifiers
|
||||||
unsigned int vaoId; // OpenGL Vertex Array Object id
|
unsigned int vaoId; // OpenGL Vertex Array Object id
|
||||||
unsigned int *vboId; // OpenGL Vertex Buffer Objects id (default vertex data)
|
unsigned int *vboId; // OpenGL Vertex Buffer Objects id (default vertex data)
|
||||||
} Mesh;
|
} Mesh;
|
||||||
|
|
||||||
// Shader type (generic)
|
// Shader
|
||||||
typedef struct Shader {
|
typedef struct Shader {
|
||||||
unsigned int id; // Shader program id
|
unsigned int id; // Shader program id
|
||||||
int *locs; // Shader locations array (MAX_SHADER_LOCATIONS)
|
int *locs; // Shader locations array (MAX_SHADER_LOCATIONS)
|
||||||
} Shader;
|
} Shader;
|
||||||
|
|
||||||
// Material texture map
|
// MaterialMap
|
||||||
typedef struct MaterialMap {
|
typedef struct MaterialMap {
|
||||||
Texture2D texture; // Material map texture
|
Texture2D texture; // Material map texture
|
||||||
Color color; // Material map color
|
Color color; // Material map color
|
||||||
float value; // Material map value
|
float value; // Material map value
|
||||||
} MaterialMap;
|
} MaterialMap;
|
||||||
|
|
||||||
// Material type (generic)
|
// Material, includes shader and maps
|
||||||
typedef struct Material {
|
typedef struct Material {
|
||||||
Shader shader; // Material shader
|
Shader shader; // Material shader
|
||||||
MaterialMap *maps; // Material maps array (MAX_MATERIAL_MAPS)
|
MaterialMap *maps; // Material maps array (MAX_MATERIAL_MAPS)
|
||||||
float params[4]; // Material generic parameters (if required)
|
float params[4]; // Material generic parameters (if required)
|
||||||
} Material;
|
} Material;
|
||||||
|
|
||||||
// Transformation properties
|
// Transform, vectex transformation data
|
||||||
typedef struct Transform {
|
typedef struct Transform {
|
||||||
Vector3 translation; // Translation
|
Vector3 translation; // Translation
|
||||||
Quaternion rotation; // Rotation
|
Quaternion rotation; // Rotation
|
||||||
Vector3 scale; // Scale
|
Vector3 scale; // Scale
|
||||||
} Transform;
|
} Transform;
|
||||||
|
|
||||||
// Bone information
|
// Bone, skeletal animation bone
|
||||||
typedef struct BoneInfo {
|
typedef struct BoneInfo {
|
||||||
char name[32]; // Bone name
|
char name[32]; // Bone name
|
||||||
int parent; // Bone parent
|
int parent; // Bone parent
|
||||||
} BoneInfo;
|
} BoneInfo;
|
||||||
|
|
||||||
// Model type
|
// Model, meshes, materials and animation data
|
||||||
typedef struct Model {
|
typedef struct Model {
|
||||||
Matrix transform; // Local transform matrix
|
Matrix transform; // Local transform matrix
|
||||||
|
|
||||||
int meshCount; // Number of meshes
|
int meshCount; // Number of meshes
|
||||||
int materialCount; // Number of materials
|
int materialCount; // Number of materials
|
||||||
Mesh *meshes; // Meshes array
|
Mesh *meshes; // Meshes array
|
||||||
Material *materials; // Materials array
|
Material *materials; // Materials array
|
||||||
int *meshMaterial; // Mesh material number
|
int *meshMaterial; // Mesh material number
|
||||||
|
|
||||||
// Animation data
|
// Animation data
|
||||||
int boneCount; // Number of bones
|
int boneCount; // Number of bones
|
||||||
BoneInfo *bones; // Bones information (skeleton)
|
BoneInfo *bones; // Bones information (skeleton)
|
||||||
Transform *bindPose; // Bones base transformation (pose)
|
Transform *bindPose; // Bones base transformation (pose)
|
||||||
} Model;
|
} Model;
|
||||||
|
|
||||||
// Model animation
|
// ModelAnimation
|
||||||
typedef struct ModelAnimation {
|
typedef struct ModelAnimation {
|
||||||
int boneCount; // Number of bones
|
int boneCount; // Number of bones
|
||||||
int frameCount; // Number of animation frames
|
int frameCount; // Number of animation frames
|
||||||
BoneInfo *bones; // Bones information (skeleton)
|
BoneInfo *bones; // Bones information (skeleton)
|
||||||
Transform **framePoses; // Poses array by frame
|
Transform **framePoses; // Poses array by frame
|
||||||
} ModelAnimation;
|
} ModelAnimation;
|
||||||
|
|
||||||
// Ray type (useful for raycast)
|
// Ray, ray for raycasting
|
||||||
typedef struct Ray {
|
typedef struct Ray {
|
||||||
Vector3 position; // Ray position (origin)
|
Vector3 position; // Ray position (origin)
|
||||||
Vector3 direction; // Ray direction
|
Vector3 direction; // Ray direction
|
||||||
} Ray;
|
} Ray;
|
||||||
|
|
||||||
// Raycast hit information
|
// RayCollision, ray hit information
|
||||||
typedef struct RayHitInfo {
|
typedef struct RayCollision {
|
||||||
bool hit; // Did the ray hit something?
|
bool hit; // Did the ray hit something?
|
||||||
float distance; // Distance to nearest hit
|
float distance; // Distance to nearest hit
|
||||||
Vector3 position; // Position of nearest hit
|
Vector3 point; // Point of nearest hit
|
||||||
Vector3 normal; // Surface normal of hit
|
Vector3 normal; // Surface normal of hit
|
||||||
} RayHitInfo;
|
} RayCollision;
|
||||||
|
|
||||||
// Bounding box type
|
// BoundingBox
|
||||||
typedef struct BoundingBox {
|
typedef struct BoundingBox {
|
||||||
Vector3 min; // Minimum vertex box-corner
|
Vector3 min; // Minimum vertex box-corner
|
||||||
Vector3 max; // Maximum vertex box-corner
|
Vector3 max; // Maximum vertex box-corner
|
||||||
} BoundingBox;
|
} BoundingBox;
|
||||||
|
|
||||||
// Wave type, defines audio wave data
|
// Wave, audio wave data
|
||||||
typedef struct Wave {
|
typedef struct Wave {
|
||||||
unsigned int sampleCount; // Total number of samples (considering channels!)
|
unsigned int sampleCount; // Total number of samples (considering channels!)
|
||||||
unsigned int sampleRate; // Frequency (samples per second)
|
unsigned int sampleRate; // Frequency (samples per second)
|
||||||
unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported)
|
unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported)
|
||||||
unsigned int channels; // Number of channels (1-mono, 2-stereo)
|
unsigned int channels; // Number of channels (1-mono, 2-stereo)
|
||||||
void *data; // Buffer data pointer
|
void *data; // Buffer data pointer
|
||||||
} Wave;
|
} Wave;
|
||||||
|
|
||||||
typedef struct rAudioBuffer rAudioBuffer;
|
typedef struct rAudioBuffer rAudioBuffer;
|
||||||
|
|
||||||
// Audio stream type
|
// AudioStream, custom audio stream
|
||||||
// NOTE: Useful to create custom audio streams not bound to a specific file
|
|
||||||
typedef struct AudioStream {
|
typedef struct AudioStream {
|
||||||
rAudioBuffer *buffer; // Pointer to internal data used by the audio system
|
rAudioBuffer *buffer; // Pointer to internal data used by the audio system
|
||||||
|
|
||||||
unsigned int sampleRate; // Frequency (samples per second)
|
unsigned int sampleRate; // Frequency (samples per second)
|
||||||
unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported)
|
unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported)
|
||||||
unsigned int channels; // Number of channels (1-mono, 2-stereo)
|
unsigned int channels; // Number of channels (1-mono, 2-stereo)
|
||||||
} AudioStream;
|
} AudioStream;
|
||||||
|
|
||||||
// Sound source type
|
// Sound
|
||||||
typedef struct Sound {
|
typedef struct Sound {
|
||||||
AudioStream stream; // Audio stream
|
AudioStream stream; // Audio stream
|
||||||
unsigned int sampleCount; // Total number of samples
|
unsigned int sampleCount; // Total number of samples
|
||||||
} Sound;
|
} Sound;
|
||||||
|
|
||||||
// Music stream type (audio file streaming from memory)
|
// Music, audio stream, anything longer than ~10 seconds should be streamed
|
||||||
// NOTE: Anything longer than ~10 seconds should be streamed
|
|
||||||
typedef struct Music {
|
typedef struct Music {
|
||||||
AudioStream stream; // Audio stream
|
AudioStream stream; // Audio stream
|
||||||
unsigned int sampleCount; // Total number of samples
|
unsigned int sampleCount; // Total number of samples
|
||||||
bool looping; // Music looping enable
|
bool looping; // Music looping enable
|
||||||
|
|
||||||
int ctxType; // Type of music context (audio filetype)
|
int ctxType; // Type of music context (audio filetype)
|
||||||
void *ctxData; // Audio context data, depends on type
|
void *ctxData; // Audio context data, depends on type
|
||||||
} Music;
|
} Music;
|
||||||
|
|
||||||
// Head-Mounted-Display device parameters
|
// VrDeviceInfo, Head-Mounted-Display device parameters
|
||||||
typedef struct VrDeviceInfo {
|
typedef struct VrDeviceInfo {
|
||||||
int hResolution; // Horizontal resolution in pixels
|
int hResolution; // Horizontal resolution in pixels
|
||||||
int vResolution; // Vertical resolution in pixels
|
int vResolution; // Vertical resolution in pixels
|
||||||
|
|
@ -468,7 +462,7 @@ typedef struct VrDeviceInfo {
|
||||||
float chromaAbCorrection[4]; // Chromatic aberration correction parameters
|
float chromaAbCorrection[4]; // Chromatic aberration correction parameters
|
||||||
} VrDeviceInfo;
|
} VrDeviceInfo;
|
||||||
|
|
||||||
// VR Stereo rendering configuration for simulator
|
// VrStereoConfig, VR stereo rendering configuration for simulator
|
||||||
typedef struct VrStereoConfig {
|
typedef struct VrStereoConfig {
|
||||||
Matrix projection[2]; // VR projection matrices (per eye)
|
Matrix projection[2]; // VR projection matrices (per eye)
|
||||||
Matrix viewOffset[2]; // VR view offset matrices (per eye)
|
Matrix viewOffset[2]; // VR view offset matrices (per eye)
|
||||||
|
|
@ -504,14 +498,15 @@ typedef enum {
|
||||||
} ConfigFlags;
|
} ConfigFlags;
|
||||||
|
|
||||||
// Trace log level
|
// Trace log level
|
||||||
|
// NOTE: Organized by priority level
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LOG_ALL = 0, // Display all logs
|
LOG_ALL = 0, // Display all logs
|
||||||
LOG_TRACE,
|
LOG_TRACE, // Trace logging, intended for internal use only
|
||||||
LOG_DEBUG,
|
LOG_DEBUG, // Debug logging, used for internal debugging, it should be disabled on release builds
|
||||||
LOG_INFO,
|
LOG_INFO, // Info logging, used for program execution info
|
||||||
LOG_WARNING,
|
LOG_WARNING, // Warning logging, used on recoverable failures
|
||||||
LOG_ERROR,
|
LOG_ERROR, // Error logging, used on unrecoverable failures
|
||||||
LOG_FATAL,
|
LOG_FATAL, // Fatal logging, used to abort program: exit(EXIT_FAILURE)
|
||||||
LOG_NONE // Disable logging
|
LOG_NONE // Disable logging
|
||||||
} TraceLogLevel;
|
} TraceLogLevel;
|
||||||
|
|
||||||
|
|
@ -871,7 +866,7 @@ typedef enum {
|
||||||
GESTURE_SWIPE_DOWN = 128,
|
GESTURE_SWIPE_DOWN = 128,
|
||||||
GESTURE_PINCH_IN = 256,
|
GESTURE_PINCH_IN = 256,
|
||||||
GESTURE_PINCH_OUT = 512
|
GESTURE_PINCH_OUT = 512
|
||||||
} Gestures;
|
} Gesture;
|
||||||
|
|
||||||
// Camera system modes
|
// Camera system modes
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
@ -898,9 +893,9 @@ typedef enum {
|
||||||
// Callbacks to hook some internal functions
|
// Callbacks to hook some internal functions
|
||||||
// WARNING: This callbacks are intended for advance users
|
// WARNING: This callbacks are intended for advance users
|
||||||
typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args); // Logging: Redirect trace log messages
|
typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args); // Logging: Redirect trace log messages
|
||||||
typedef unsigned char* (*LoadFileDataCallback)(const char* fileName, unsigned int* bytesRead); // FileIO: Load binary data
|
typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, unsigned int *bytesRead); // FileIO: Load binary data
|
||||||
typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, unsigned int bytesToWrite); // FileIO: Save binary data
|
typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, unsigned int bytesToWrite); // FileIO: Save binary data
|
||||||
typedef char *(*LoadFileTextCallback)(const char* fileName); // FileIO: Load text data
|
typedef char *(*LoadFileTextCallback)(const char *fileName); // FileIO: Load text data
|
||||||
typedef bool (*SaveFileTextCallback)(const char *fileName, char *text); // FileIO: Save text data
|
typedef bool (*SaveFileTextCallback)(const char *fileName, char *text); // FileIO: Save text data
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -970,15 +965,15 @@ RLAPI bool IsCursorOnScreen(void); // Check if cu
|
||||||
RLAPI void ClearBackground(Color color); // Set background color (framebuffer clear color)
|
RLAPI void ClearBackground(Color color); // Set background color (framebuffer clear color)
|
||||||
RLAPI void BeginDrawing(void); // Setup canvas (framebuffer) to start drawing
|
RLAPI void BeginDrawing(void); // Setup canvas (framebuffer) to start drawing
|
||||||
RLAPI void EndDrawing(void); // End canvas drawing and swap buffers (double buffering)
|
RLAPI void EndDrawing(void); // End canvas drawing and swap buffers (double buffering)
|
||||||
RLAPI void BeginMode2D(Camera2D camera); // Initialize 2D mode with custom camera (2D)
|
RLAPI void BeginMode2D(Camera2D camera); // Begin 2D mode with custom camera (2D)
|
||||||
RLAPI void EndMode2D(void); // Ends 2D mode with custom camera
|
RLAPI void EndMode2D(void); // Ends 2D mode with custom camera
|
||||||
RLAPI void BeginMode3D(Camera3D camera); // Initializes 3D mode with custom camera (3D)
|
RLAPI void BeginMode3D(Camera3D camera); // Begin 3D mode with custom camera (3D)
|
||||||
RLAPI void EndMode3D(void); // Ends 3D mode and returns to default 2D orthographic mode
|
RLAPI void EndMode3D(void); // Ends 3D mode and returns to default 2D orthographic mode
|
||||||
RLAPI void BeginTextureMode(RenderTexture2D target); // Initializes render texture for drawing
|
RLAPI void BeginTextureMode(RenderTexture2D target); // Begin drawing to render texture
|
||||||
RLAPI void EndTextureMode(void); // Ends drawing to render texture
|
RLAPI void EndTextureMode(void); // Ends drawing to render texture
|
||||||
RLAPI void BeginShaderMode(Shader shader); // Begin custom shader drawing
|
RLAPI void BeginShaderMode(Shader shader); // Begin custom shader drawing
|
||||||
RLAPI void EndShaderMode(void); // End custom shader drawing (use default shader)
|
RLAPI void EndShaderMode(void); // End custom shader drawing (use default shader)
|
||||||
RLAPI void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied)
|
RLAPI void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied, subtract, custom)
|
||||||
RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending)
|
RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending)
|
||||||
RLAPI void BeginScissorMode(int x, int y, int width, int height); // Begin scissor mode (define screen area for following drawing)
|
RLAPI void BeginScissorMode(int x, int y, int width, int height); // Begin scissor mode (define screen area for following drawing)
|
||||||
RLAPI void EndScissorMode(void); // End scissor mode
|
RLAPI void EndScissorMode(void); // End scissor mode
|
||||||
|
|
@ -1021,7 +1016,7 @@ RLAPI int GetRandomValue(int min, int max); // Returns a r
|
||||||
RLAPI void TakeScreenshot(const char *fileName); // Takes a screenshot of current screen (filename extension defines format)
|
RLAPI void TakeScreenshot(const char *fileName); // Takes a screenshot of current screen (filename extension defines format)
|
||||||
RLAPI void SetConfigFlags(unsigned int flags); // Setup init configuration flags (view FLAGS)
|
RLAPI void SetConfigFlags(unsigned int flags); // Setup init configuration flags (view FLAGS)
|
||||||
|
|
||||||
RLAPI void TraceLog(int logLevel, const char *text, ...); // Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR)
|
RLAPI void TraceLog(int logLevel, const char *text, ...); // Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...)
|
||||||
RLAPI void SetTraceLogLevel(int logLevel); // Set the current threshold (minimum) log level
|
RLAPI void SetTraceLogLevel(int logLevel); // Set the current threshold (minimum) log level
|
||||||
RLAPI void *MemAlloc(int size); // Internal memory allocator
|
RLAPI void *MemAlloc(int size); // Internal memory allocator
|
||||||
RLAPI void *MemRealloc(void *ptr, int size); // Internal memory reallocator
|
RLAPI void *MemRealloc(void *ptr, int size); // Internal memory reallocator
|
||||||
|
|
@ -1040,12 +1035,12 @@ RLAPI unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead)
|
||||||
RLAPI void UnloadFileData(unsigned char *data); // Unload file data allocated by LoadFileData()
|
RLAPI void UnloadFileData(unsigned char *data); // Unload file data allocated by LoadFileData()
|
||||||
RLAPI bool SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite); // Save data to file from byte array (write), returns true on success
|
RLAPI bool SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite); // Save data to file from byte array (write), returns true on success
|
||||||
RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string
|
RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string
|
||||||
RLAPI void UnloadFileText(unsigned char *text); // Unload file text data allocated by LoadFileText()
|
RLAPI void UnloadFileText(char *text); // Unload file text data allocated by LoadFileText()
|
||||||
RLAPI bool SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success
|
RLAPI bool SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success
|
||||||
RLAPI bool FileExists(const char *fileName); // Check if file exists
|
RLAPI bool FileExists(const char *fileName); // Check if file exists
|
||||||
RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists
|
RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists
|
||||||
RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension (including point: .png, .wav)
|
RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension (including point: .png, .wav)
|
||||||
RLAPI const char *GetFileExtension(const char *fileName); // Get pointer to extension for a filename string (includes dot: ".png")
|
RLAPI const char *GetFileExtension(const char *fileName); // Get pointer to extension for a filename string (includes dot: '.png')
|
||||||
RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string
|
RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string
|
||||||
RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (uses static string)
|
RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (uses static string)
|
||||||
RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a given fileName with path (uses static string)
|
RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a given fileName with path (uses static string)
|
||||||
|
|
@ -1143,7 +1138,7 @@ RLAPI void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int ke
|
||||||
// Set texture and rectangle to be used on shapes drawing
|
// Set texture and rectangle to be used on shapes drawing
|
||||||
// NOTE: It can be useful when using basic shapes and one single font,
|
// NOTE: It can be useful when using basic shapes and one single font,
|
||||||
// defining a font char white rectangle would allow drawing everything in a single draw call
|
// defining a font char white rectangle would allow drawing everything in a single draw call
|
||||||
RLAPI void SetShapesTexture(Texture2D texture, Rectangle source);
|
RLAPI void SetShapesTexture(Texture2D texture, Rectangle source); // Set texture and rectangle to be used on shapes drawing
|
||||||
|
|
||||||
// Basic shapes drawing functions
|
// Basic shapes drawing functions
|
||||||
RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel
|
RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel
|
||||||
|
|
@ -1202,7 +1197,7 @@ RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2);
|
||||||
RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM)
|
RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM)
|
||||||
RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data
|
RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data
|
||||||
RLAPI Image LoadImageAnim(const char *fileName, int *frames); // Load image sequence from file (frames appended to image.data)
|
RLAPI Image LoadImageAnim(const char *fileName, int *frames); // Load image sequence from file (frames appended to image.data)
|
||||||
RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load image from memory buffer, fileType refers to extension: i.e. ".png"
|
RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load image from memory buffer, fileType refers to extension: i.e. '.png'
|
||||||
RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM)
|
RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM)
|
||||||
RLAPI bool ExportImage(Image image, const char *fileName); // Export image data to file, returns true on success
|
RLAPI bool ExportImage(Image image, const char *fileName); // Export image data to file, returns true on success
|
||||||
RLAPI bool ExportImageAsCode(Image image, const char *fileName); // Export image as code file defining an array of bytes, returns true on success
|
RLAPI bool ExportImageAsCode(Image image, const char *fileName); // Export image as code file defining an array of bytes, returns true on success
|
||||||
|
|
@ -1232,7 +1227,7 @@ RLAPI void ImageAlphaPremultiply(Image *image);
|
||||||
RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize image (Bicubic scaling algorithm)
|
RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize image (Bicubic scaling algorithm)
|
||||||
RLAPI void ImageResizeNN(Image *image, int newWidth,int newHeight); // Resize image (Nearest-Neighbor scaling algorithm)
|
RLAPI void ImageResizeNN(Image *image, int newWidth,int newHeight); // Resize image (Nearest-Neighbor scaling algorithm)
|
||||||
RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill); // Resize canvas and fill with color
|
RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill); // Resize canvas and fill with color
|
||||||
RLAPI void ImageMipmaps(Image *image); // Generate all mipmap levels for a provided image
|
RLAPI void ImageMipmaps(Image *image); // Compute all mipmap levels for a provided image
|
||||||
RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
|
RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
|
||||||
RLAPI void ImageFlipVertical(Image *image); // Flip image vertically
|
RLAPI void ImageFlipVertical(Image *image); // Flip image vertically
|
||||||
RLAPI void ImageFlipHorizontal(Image *image); // Flip image horizontally
|
RLAPI void ImageFlipHorizontal(Image *image); // Flip image horizontally
|
||||||
|
|
@ -1319,7 +1314,7 @@ RLAPI Font GetFontDefault(void);
|
||||||
RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM)
|
RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM)
|
||||||
RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCount); // Load font from file with extended parameters
|
RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCount); // Load font from file with extended parameters
|
||||||
RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style)
|
RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style)
|
||||||
RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int charsCount); // Load font from memory buffer, fileType refers to extension: i.e. ".ttf"
|
RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int charsCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf'
|
||||||
RLAPI CharInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int charsCount, int type); // Load font data for further use
|
RLAPI CharInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int charsCount, int type); // Load font data for further use
|
||||||
RLAPI Image GenImageFontAtlas(const CharInfo *chars, Rectangle **recs, int charsCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info
|
RLAPI Image GenImageFontAtlas(const CharInfo *chars, Rectangle **recs, int charsCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info
|
||||||
RLAPI void UnloadFontData(CharInfo *chars, int charsCount); // Unload font chars info data (RAM)
|
RLAPI void UnloadFontData(CharInfo *chars, int charsCount); // Unload font chars info data (RAM)
|
||||||
|
|
@ -1330,8 +1325,7 @@ RLAPI void DrawFPS(int posX, int posY);
|
||||||
RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font)
|
RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font)
|
||||||
RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters
|
RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters
|
||||||
RLAPI void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint); // Draw text using font inside rectangle limits
|
RLAPI void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint); // Draw text using font inside rectangle limits
|
||||||
RLAPI void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint,
|
RLAPI void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint); // Draw text using font inside rectangle limits with support for text selection
|
||||||
int selectStart, int selectLength, Color selectTint, Color selectBackTint); // Draw text using font inside rectangle limits with support for text selection
|
|
||||||
RLAPI void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint); // Draw one character (codepoint)
|
RLAPI void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint); // Draw one character (codepoint)
|
||||||
|
|
||||||
// Text misc. functions
|
// Text misc. functions
|
||||||
|
|
@ -1433,7 +1427,7 @@ RLAPI Mesh GenMeshHeightmap(Image heightmap, Vector3 size);
|
||||||
RLAPI Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize); // Generate cubes-based map mesh from image data
|
RLAPI Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize); // Generate cubes-based map mesh from image data
|
||||||
|
|
||||||
// Mesh manipulation functions
|
// Mesh manipulation functions
|
||||||
RLAPI BoundingBox GetMeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits
|
RLAPI BoundingBox GetMeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits
|
||||||
RLAPI void MeshTangents(Mesh *mesh); // Compute mesh tangents
|
RLAPI void MeshTangents(Mesh *mesh); // Compute mesh tangents
|
||||||
RLAPI void MeshBinormals(Mesh *mesh); // Compute mesh binormals
|
RLAPI void MeshBinormals(Mesh *mesh); // Compute mesh binormals
|
||||||
|
|
||||||
|
|
@ -1451,13 +1445,12 @@ RLAPI void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source,
|
||||||
RLAPI bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2); // Detect collision between two spheres
|
RLAPI bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2); // Detect collision between two spheres
|
||||||
RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Detect collision between two bounding boxes
|
RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Detect collision between two bounding boxes
|
||||||
RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius); // Detect collision between box and sphere
|
RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius); // Detect collision between box and sphere
|
||||||
RLAPI bool CheckCollisionRaySphere(Ray ray, Vector3 center, float radius); // Detect collision between ray and sphere
|
RLAPI RayCollision GetRayCollisionSphere(Ray ray, Vector3 center, float radius); // Get collision info between ray and sphere
|
||||||
RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 center, float radius, Vector3 *collisionPoint); // Detect collision between ray and sphere, returns collision point
|
RLAPI RayCollision GetRayCollisionBox(Ray ray, BoundingBox box); // Get collision info between ray and box
|
||||||
RLAPI bool CheckCollisionRayBox(Ray ray, BoundingBox box); // Detect collision between ray and box
|
RLAPI RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform); // Get collision info between ray and mesh
|
||||||
RLAPI RayHitInfo GetCollisionRayMesh(Ray ray, Mesh mesh, Matrix transform); // Get collision info between ray and mesh
|
RLAPI RayCollision GetRayCollisionModel(Ray ray, Model model); // Get collision info between ray and model
|
||||||
RLAPI RayHitInfo GetCollisionRayModel(Ray ray, Model model); // Get collision info between ray and model
|
RLAPI RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3); // Get collision info between ray and triangle
|
||||||
RLAPI RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3); // Get collision info between ray and triangle
|
RLAPI RayCollision GetRayCollisionGround(Ray ray, float groundHeight); // Get collision info between ray and ground plane (Y-normal plane)
|
||||||
RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight); // Get collision info between ray and ground plane (Y-normal plane)
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Audio Loading and Playing Functions (Module: audio)
|
// Audio Loading and Playing Functions (Module: audio)
|
||||||
|
|
@ -1471,7 +1464,7 @@ RLAPI void SetMasterVolume(float volume); // Set mas
|
||||||
|
|
||||||
// Wave/Sound loading/unloading functions
|
// Wave/Sound loading/unloading functions
|
||||||
RLAPI Wave LoadWave(const char *fileName); // Load wave data from file
|
RLAPI Wave LoadWave(const char *fileName); // Load wave data from file
|
||||||
RLAPI Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load wave from memory buffer, fileType refers to extension: i.e. ".wav"
|
RLAPI Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load wave from memory buffer, fileType refers to extension: i.e. '.wav'
|
||||||
RLAPI Sound LoadSound(const char *fileName); // Load sound from file
|
RLAPI Sound LoadSound(const char *fileName); // Load sound from file
|
||||||
RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data
|
RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data
|
||||||
RLAPI void UpdateSound(Sound sound, const void *data, int samplesCount);// Update sound buffer with new data
|
RLAPI void UpdateSound(Sound sound, const void *data, int samplesCount);// Update sound buffer with new data
|
||||||
|
|
|
||||||
|
|
@ -326,7 +326,7 @@ RMDEF Vector2 Vector2MoveTowards(Vector2 v, Vector2 target, float maxDistance)
|
||||||
float dy = target.y - v.y;
|
float dy = target.y - v.y;
|
||||||
float value = (dx*dx) + (dy*dy);
|
float value = (dx*dx) + (dy*dy);
|
||||||
|
|
||||||
if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance*maxDistance))) result = target;
|
if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance * maxDistance))) return target;
|
||||||
|
|
||||||
float dist = sqrtf(value);
|
float dist = sqrtf(value);
|
||||||
|
|
||||||
|
|
@ -1389,23 +1389,28 @@ RMDEF Quaternion QuaternionFromMatrix(Matrix mat)
|
||||||
RMDEF Matrix QuaternionToMatrix(Quaternion q)
|
RMDEF Matrix QuaternionToMatrix(Quaternion q)
|
||||||
{
|
{
|
||||||
Matrix result = MatrixIdentity();
|
Matrix result = MatrixIdentity();
|
||||||
|
|
||||||
|
float a2 = q.x*q.x;
|
||||||
|
float b2 = q.y*q.y;
|
||||||
|
float c2 = q.z*q.z;
|
||||||
|
float ac = q.x*q.z;
|
||||||
|
float ab = q.x*q.y;
|
||||||
|
float bc = q.y*q.z;
|
||||||
|
float ad = q.w*q.x;
|
||||||
|
float bd = q.w*q.y;
|
||||||
|
float cd = q.w*q.z;
|
||||||
|
|
||||||
float a2 = 2*(q.x*q.x), b2=2*(q.y*q.y), c2=2*(q.z*q.z); //, d2=2*(q.w*q.w);
|
result.m0 = 1 - 2*(b2 + c2);
|
||||||
|
result.m1 = 2*(ab + cd);
|
||||||
|
result.m2 = 2*(ac - bd);
|
||||||
|
|
||||||
float ab = 2*(q.x*q.y), ac=2*(q.x*q.z), bc=2*(q.y*q.z);
|
result.m4 = 2*(ab - cd);
|
||||||
float ad = 2*(q.x*q.w), bd=2*(q.y*q.w), cd=2*(q.z*q.w);
|
result.m5 = 1 - 2*(a2 + c2);
|
||||||
|
result.m6 = 2*(bc + ad);
|
||||||
|
|
||||||
result.m0 = 1 - b2 - c2;
|
result.m8 = 2*(ac + bd);
|
||||||
result.m1 = ab - cd;
|
result.m9 = 2*(bc - ad);
|
||||||
result.m2 = ac + bd;
|
result.m10 = 1 - 2*(a2 + b2);
|
||||||
|
|
||||||
result.m4 = ab + cd;
|
|
||||||
result.m5 = 1 - a2 - c2;
|
|
||||||
result.m6 = bc - ad;
|
|
||||||
|
|
||||||
result.m8 = ac - bd;
|
|
||||||
result.m9 = bc + ad;
|
|
||||||
result.m10 = 1 - a2 - b2;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
23
src/rlgl.h
23
src/rlgl.h
|
|
@ -329,16 +329,17 @@ typedef enum {
|
||||||
int *locs; // Shader locations array (MAX_SHADER_LOCATIONS)
|
int *locs; // Shader locations array (MAX_SHADER_LOCATIONS)
|
||||||
} Shader;
|
} Shader;
|
||||||
|
|
||||||
// TraceLog message types
|
// Trace log level
|
||||||
|
// NOTE: Organized by priority level
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LOG_ALL,
|
LOG_ALL = 0, // Display all logs
|
||||||
LOG_TRACE,
|
LOG_TRACE, // Trace logging, intended for internal use only
|
||||||
LOG_DEBUG,
|
LOG_DEBUG, // Debug logging, used for internal debugging, it should be disabled on release builds
|
||||||
LOG_INFO,
|
LOG_INFO, // Info logging, used for program execution info
|
||||||
LOG_WARNING,
|
LOG_WARNING, // Warning logging, used on recoverable failures
|
||||||
LOG_ERROR,
|
LOG_ERROR, // Error logging, used on unrecoverable failures
|
||||||
LOG_FATAL,
|
LOG_FATAL, // Fatal logging, used to abort program: exit(EXIT_FAILURE)
|
||||||
LOG_NONE
|
LOG_NONE // Disable logging
|
||||||
} TraceLogLevel;
|
} TraceLogLevel;
|
||||||
|
|
||||||
// Texture formats (support depends on OpenGL version)
|
// Texture formats (support depends on OpenGL version)
|
||||||
|
|
@ -1685,7 +1686,7 @@ void rlLoadExtensions(void *loader)
|
||||||
#if defined(SUPPORT_GL_DETAILS_INFO)
|
#if defined(SUPPORT_GL_DETAILS_INFO)
|
||||||
// Get supported extensions list
|
// Get supported extensions list
|
||||||
// WARNING: glGetStringi() not available on OpenGL 2.1
|
// WARNING: glGetStringi() not available on OpenGL 2.1
|
||||||
char **extList = RL_MALLOC(sizeof(char *)*numExt);
|
char **extList = RL_MALLOC(numExt*sizeof(char *));
|
||||||
TRACELOG(LOG_INFO, "GL: OpenGL extensions:");
|
TRACELOG(LOG_INFO, "GL: OpenGL extensions:");
|
||||||
for (int i = 0; i < numExt; i++)
|
for (int i = 0; i < numExt; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -1966,7 +1967,7 @@ RenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements)
|
||||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||||
// Initialize CPU (RAM) vertex buffers (position, texcoord, color data and indexes)
|
// Initialize CPU (RAM) vertex buffers (position, texcoord, color data and indexes)
|
||||||
//--------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------
|
||||||
batch.vertexBuffer = (VertexBuffer *)RL_MALLOC(sizeof(VertexBuffer)*numBuffers);
|
batch.vertexBuffer = (VertexBuffer *)RL_MALLOC(numBuffers*sizeof(VertexBuffer));
|
||||||
|
|
||||||
for (int i = 0; i < numBuffers; i++)
|
for (int i = 0; i < numBuffers; i++)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
12
src/text.c
12
src/text.c
|
|
@ -1272,7 +1272,7 @@ const char *TextSubtext(const char *text, int position, int length)
|
||||||
|
|
||||||
// Replace text string
|
// Replace text string
|
||||||
// REQUIRES: strstr(), strncpy(), strcpy()
|
// REQUIRES: strstr(), strncpy(), strcpy()
|
||||||
// WARNING: Internally allocated memory must be freed by the user (if return != NULL)
|
// WARNING: Returned buffer must be freed by the user (if return != NULL)
|
||||||
char *TextReplace(char *text, const char *replace, const char *by)
|
char *TextReplace(char *text, const char *replace, const char *by)
|
||||||
{
|
{
|
||||||
// Sanity checks and initialization
|
// Sanity checks and initialization
|
||||||
|
|
@ -1297,14 +1297,14 @@ char *TextReplace(char *text, const char *replace, const char *by)
|
||||||
for (count = 0; (temp = strstr(insertPoint, replace)); count++) insertPoint = temp + replaceLen;
|
for (count = 0; (temp = strstr(insertPoint, replace)); count++) insertPoint = temp + replaceLen;
|
||||||
|
|
||||||
// Allocate returning string and point temp to it
|
// Allocate returning string and point temp to it
|
||||||
temp = result = RL_MALLOC(TextLength(text) + (byLen - replaceLen)*count + 1);
|
temp = result = (char *)RL_MALLOC(TextLength(text) + (byLen - replaceLen)*count + 1);
|
||||||
|
|
||||||
if (!result) return NULL; // Memory could not be allocated
|
if (!result) return NULL; // Memory could not be allocated
|
||||||
|
|
||||||
// First time through the loop, all the variable are set correctly from here on,
|
// First time through the loop, all the variable are set correctly from here on,
|
||||||
// temp points to the end of the result string
|
// - 'temp' points to the end of the result string
|
||||||
// insertPoint points to the next occurrence of replace in text
|
// - 'insertPoint' points to the next occurrence of replace in text
|
||||||
// text points to the remainder of text after "end of replace"
|
// - 'text' points to the remainder of text after "end of replace"
|
||||||
while (count--)
|
while (count--)
|
||||||
{
|
{
|
||||||
insertPoint = strstr(text, replace);
|
insertPoint = strstr(text, replace);
|
||||||
|
|
@ -1865,7 +1865,7 @@ static Font LoadBMFont(const char *fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
UnloadImage(imFont);
|
UnloadImage(imFont);
|
||||||
RL_FREE(fileText);
|
UnloadFileText(fileText);
|
||||||
|
|
||||||
if (font.texture.id == 0)
|
if (font.texture.id == 0)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,7 @@
|
||||||
#include <stdlib.h> // Required for: malloc(), free()
|
#include <stdlib.h> // Required for: malloc(), free()
|
||||||
#include <string.h> // Required for: strlen() [Used in ImageTextEx()]
|
#include <string.h> // Required for: strlen() [Used in ImageTextEx()]
|
||||||
#include <math.h> // Required for: fabsf()
|
#include <math.h> // Required for: fabsf()
|
||||||
|
#include <stdio.h> // Required for: sprintf() [Used in ExportImageAsCode()]
|
||||||
|
|
||||||
#include "utils.h" // Required for: fopen() Android mapping
|
#include "utils.h" // Required for: fopen() Android mapping
|
||||||
|
|
||||||
|
|
@ -122,7 +123,7 @@
|
||||||
// NOTE: Used to read image data (multiple formats support)
|
// NOTE: Used to read image data (multiple formats support)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined(SUPPORT_IMAGE_EXPORT) || defined(SUPPORT_COMPRESSION_API))
|
#if defined(SUPPORT_IMAGE_EXPORT)
|
||||||
#define STBIW_MALLOC RL_MALLOC
|
#define STBIW_MALLOC RL_MALLOC
|
||||||
#define STBIW_FREE RL_FREE
|
#define STBIW_FREE RL_FREE
|
||||||
#define STBIW_REALLOC RL_REALLOC
|
#define STBIW_REALLOC RL_REALLOC
|
||||||
|
|
@ -459,6 +460,8 @@ bool ExportImageAsCode(Image image, const char *fileName)
|
||||||
{
|
{
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
|
#if defined(SUPPORT_IMAGE_EXPORT)
|
||||||
|
|
||||||
#ifndef TEXT_BYTES_PER_LINE
|
#ifndef TEXT_BYTES_PER_LINE
|
||||||
#define TEXT_BYTES_PER_LINE 20
|
#define TEXT_BYTES_PER_LINE 20
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -500,6 +503,11 @@ bool ExportImageAsCode(Image image, const char *fileName)
|
||||||
success = SaveFileText(fileName, txtData);
|
success = SaveFileText(fileName, txtData);
|
||||||
|
|
||||||
RL_FREE(txtData);
|
RL_FREE(txtData);
|
||||||
|
|
||||||
|
#endif // SUPPORT_IMAGE_EXPORT
|
||||||
|
|
||||||
|
if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image exported successfully", fileName);
|
||||||
|
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export image", fileName);
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
@ -1354,7 +1362,7 @@ void ImageResize(Image *image, int newWidth, int newHeight)
|
||||||
if (fastPath)
|
if (fastPath)
|
||||||
{
|
{
|
||||||
int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
|
int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
|
||||||
unsigned char *output = RL_MALLOC(newWidth*newHeight*bytesPerPixel);
|
unsigned char *output = (unsigned char *)RL_MALLOC(newWidth*newHeight*bytesPerPixel);
|
||||||
|
|
||||||
switch (image->format)
|
switch (image->format)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,7 @@ void TraceLog(int logType, const char *text, ...)
|
||||||
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
if (logType == LOG_ERROR) exit(1); // If error, exit program
|
if (logType == LOG_FATAL) exit(EXIT_FAILURE); // If fatal logging, exit program
|
||||||
|
|
||||||
#endif // SUPPORT_TRACELOG
|
#endif // SUPPORT_TRACELOG
|
||||||
}
|
}
|
||||||
|
|
@ -325,7 +325,7 @@ char *LoadFileText(const char *fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unload file text data allocated by LoadFileText()
|
// Unload file text data allocated by LoadFileText()
|
||||||
void UnloadFileText(unsigned char *text)
|
void UnloadFileText(char *text)
|
||||||
{
|
{
|
||||||
RL_FREE(text);
|
RL_FREE(text);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
*
|
*
|
||||||
* LICENSE: zlib/libpng
|
* LICENSE: zlib/libpng
|
||||||
*
|
*
|
||||||
* Copyright (c) 2020-2020 Reece Mackie (@Rover656)
|
* Copyright (c) 2020-2021 Reece Mackie (@Rover656)
|
||||||
*
|
*
|
||||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||||
* will the authors be held liable for any damages arising from the use of this software.
|
* will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user