Merge branch 'master' into GPU_SKIN_ON_BY_DEFAULT

This commit is contained in:
Jeff Myers 2026-07-25 11:05:57 -07:00
commit 7905bc1234
76 changed files with 30760 additions and 9200 deletions

View file

@ -50,9 +50,9 @@
#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
#include "raymath.h" // Required for: Vector3, Quaternion and Matrix functionality
#include <stdio.h> // Required for: sprintf()
#include <stdio.h> // Required for: sprintf(), snprintf()
#include <stdlib.h> // Required for: malloc(), calloc(), free()
#include <string.h> // Required for: memcmp(), strlen(), strncpy()
#include <string.h> // Required for: strlen(), memcmp()
#include <math.h> // Required for: sinf(), cosf(), sqrtf(), fabsf()
#if SUPPORT_FILEFORMAT_OBJ || SUPPORT_FILEFORMAT_MTL
@ -503,7 +503,7 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color
rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a);
float ringangle = DEG2RAD*(180.0f/(rings + 1)); // Angle between latitudinal parallels
float ringangle = DEG2RAD*(180.0f/rings); // Angle between latitudinal parallels
float sliceangle = DEG2RAD*(360.0f/slices); // Angle between longitudinal meridians
float cosring = cosf(ringangle);
@ -515,7 +515,7 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color
vertices[2] = (Vector3){ 0, 1, 0 };
vertices[3] = (Vector3){ sinring, cosring, 0 };
for (int i = 0; i < rings + 1; i++)
for (int i = 0; i < rings; i++)
{
for (int j = 0; j < slices; j++)
{
@ -557,31 +557,42 @@ void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Col
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
for (int i = 0; i < (rings + 2); i++)
float ringangle = DEG2RAD*(180.0f/rings); // Angle between latitudinal parallels
float sliceangle = DEG2RAD*(360.0f/slices); // Angle between longitudinal meridians
float cosring = cosf(ringangle);
float sinring = sinf(ringangle);
float cosslice = cosf(sliceangle);
float sinslice = sinf(sliceangle);
Vector3 vertices[4] = { 0 }; // Required to store face vertices
vertices[2] = (Vector3){ 0, 1, 0 };
vertices[3] = (Vector3){ sinring, cosring, 0 };
for (int i = 0; i < rings; i++)
{
for (int j = 0; j < slices; j++)
{
rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)),
sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)),
cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices)));
rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)),
sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices)));
vertices[0] = vertices[2]; // Rotate around y axis to set up vertices for next face
vertices[1] = vertices[3];
vertices[2] = (Vector3){ cosslice*vertices[2].x - sinslice*vertices[2].z, vertices[2].y, sinslice*vertices[2].x + cosslice*vertices[2].z }; // Rotation matrix around y axis
vertices[3] = (Vector3){ cosslice*vertices[3].x - sinslice*vertices[3].z, vertices[3].y, sinslice*vertices[3].x + cosslice*vertices[3].z };
rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)),
sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices)));
rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*j/slices)),
sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*j/slices)));
// Longitude Lines
rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
rlVertex3f(vertices[1].x, vertices[1].y, vertices[1].z);
rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*j/slices)),
sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))),
cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*j/slices)));
rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)),
sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)),
cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices)));
// Latitude Lines
rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
rlVertex3f(vertices[2].x, vertices[2].y, vertices[2].z);
// Diagonal Lines
rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z);
}
vertices[2] = vertices[3]; // Rotate around z axis to set up starting vertices for next ring
vertices[3] = (Vector3){ cosring*vertices[3].x + sinring*vertices[3].y, -sinring*vertices[3].x + cosring*vertices[3].y, vertices[3].z }; // Rotation matrix around z axis
}
rlEnd();
rlPopMatrix();
@ -2088,7 +2099,7 @@ bool ExportMeshAsCode(Mesh mesh, const char *fileName)
// Get file name from path and convert variable name to uppercase
char varFileName[256] = { 0 };
strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1); // NOTE: Using function provided by [rcore] module
snprintf(varFileName, 256, "%s", GetFileNameWithoutExt(fileName)); // NOTE: Using function provided by [rcore] module
for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; }
// Add image information
@ -2333,7 +2344,7 @@ void UpdateModelAnimationBones(Model model, ModelAnimation anim, float frame)
Matrix currentPoseMatrix = { 0 };
// Update all bones and bone matrices of model
for (int boneIndex = 0; boneIndex < model.skeleton.boneCount; boneIndex++)
for (unsigned int boneIndex = 0; boneIndex < model.skeleton.boneCount; boneIndex++)
{
// Compute interpolated pose between current and next frame
// NOTE: Storing animation frame data in model.currentPose
@ -2413,7 +2424,7 @@ void UpdateModelAnimationBonesEx(Model model, ModelAnimation animA, float frameA
Matrix bindPoseMatrix = { 0 };
Matrix currentPoseMatrix = { 0 };
for (int boneIndex = 0; boneIndex < model.skeleton.boneCount; boneIndex++)
for (unsigned int boneIndex = 0; boneIndex < model.skeleton.boneCount; boneIndex++)
{
// Get frame-interpolation for first animation
Vector3 frameATranslation = Vector3Lerp(
@ -3189,6 +3200,8 @@ Mesh GenMeshCone(float radius, float height, int slices)
}
// Generate torus mesh
// NOTE: The distance between the center of the hole and the center of the
// tube is half size of the radius of the tube (radius*size/2)
Mesh GenMeshTorus(float radius, float size, int radSeg, int sides)
{
Mesh mesh = { 0 };
@ -4466,7 +4479,7 @@ static Model LoadOBJ(const char *fileName)
}
char currentDir[MAX_FILEPATH_LENGTH] = { 0 };
strncpy(currentDir, GetWorkingDirectory(), MAX_FILEPATH_LENGTH - 1); // Save current working directory
snprintf(currentDir, MAX_FILEPATH_LENGTH, "%s", GetWorkingDirectory()); // Save current working directory
const char *workingDir = GetDirectoryPath(fileName); // Switch to OBJ directory for material path correctness
if (CHDIR(workingDir) != 0) TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", workingDir);
@ -5051,7 +5064,7 @@ static Model LoadIQM(const char *fileName)
// Initialize runtime animation data: current pose and bone matrices
model.currentPose = (Transform *)RL_CALLOC(model.skeleton.boneCount, sizeof(Transform));
model.boneMatrices = (Matrix *)RL_CALLOC(model.skeleton.boneCount, sizeof(Matrix));
for (int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
for (unsigned int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
UnloadFileData(fileData);
@ -5279,7 +5292,7 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCou
// Build frameposes
for (unsigned int frame = 0; frame < anim[a].num_frames; frame++)
{
for (int i = 0; i < animations[a].boneCount; i++)
for (unsigned int i = 0; i < animations[a].boneCount; i++)
{
if (bones[i].parent >= 0)
{
@ -5354,8 +5367,8 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat
{
int base64Size = (int)strlen(cgltfImage->uri + i + 1);
while (cgltfImage->uri[i + base64Size] == '=') base64Size--; // Ignore optional paddings
int numberOfEncodedBits = base64Size*6 - (base64Size*6) % 8 ; // Encoded bits minus extra bits, so it becomes a multiple of 8 bits
int outSize = numberOfEncodedBits/8 ; // Actual encoded bytes
int numberOfEncodedBits = base64Size*6 - (base64Size*6)%8; // Encoded bits minus extra bits, so it becomes a multiple of 8 bits
int outSize = numberOfEncodedBits >> 3; // Actual encoded bytes
void *data = NULL;
cgltf_options options = { 0 };
@ -5407,15 +5420,15 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat
}
// Load bone info from GLTF skin data
static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, int *boneCount)
static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, unsigned int *boneCount)
{
*boneCount = (int)skin.joints_count;
*boneCount = (unsigned int)skin.joints_count;
BoneInfo *bones = (BoneInfo *)RL_CALLOC(skin.joints_count, sizeof(BoneInfo));
for (unsigned int i = 0; i < skin.joints_count; i++)
{
cgltf_node node = *skin.joints[i];
if (node.name != NULL) strncpy(bones[i].name, node.name, sizeof(bones[i].name) - 1);
if (node.name != NULL) snprintf(bones[i].name, sizeof(bones[i].name), "%s", node.name);
// Find parent bone index by walking up the node tree past any
// non-joint ancestors (intermediate transform nodes used by some
@ -6182,7 +6195,7 @@ static Model LoadGLTF(const char *fileName)
model.skeleton.bones = LoadBoneInfoGLTF(skin, &model.skeleton.boneCount);
model.skeleton.bindPose = (Transform *)RL_CALLOC(model.skeleton.boneCount, sizeof(Transform));
for (int i = 0; i < model.skeleton.boneCount; i++)
for (unsigned int i = 0; i < model.skeleton.boneCount; i++)
{
Matrix bindMatrix = { 0 };
cgltf_float inverseBindTransform[16] = { 0 };
@ -6347,7 +6360,7 @@ static Model LoadGLTF(const char *fileName)
if ((data->skins_count > 0) && !hasJoints && (node->parent != NULL) && (node->parent->mesh == NULL))
{
int parentBoneId = -1;
for (int joint = 0; joint < model.skeleton.boneCount; joint++)
for (unsigned int joint = 0; joint < model.skeleton.boneCount; joint++)
{
if (data->skins[0].joints[joint] == node->parent)
{
@ -6378,7 +6391,7 @@ static Model LoadGLTF(const char *fileName)
// Initialize runtime animation data: current pose and bone matrices
model.currentPose = (Transform *)RL_CALLOC(model.skeleton.boneCount, sizeof(Transform));
model.boneMatrices = (Matrix *)RL_CALLOC(model.skeleton.boneCount, sizeof(Matrix));
for (int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
for (unsigned int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
//----------------------------------------------------------------------------------------------------
// Free unused allocated memory in case of no bones defined
@ -6634,7 +6647,6 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
cgltf_animation_channel *translate;
cgltf_animation_channel *rotate;
cgltf_animation_channel *scale;
cgltf_interpolation_type interpolationType;
};
struct Channels *boneChannels = (struct Channels *)RL_CALLOC(animations[a].boneCount, sizeof(struct Channels));
@ -6656,8 +6668,6 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
if (boneIndex == -1) continue; // Animation channel for a node not in the skeleton
boneChannels[boneIndex].interpolationType = animData.channels[j].sampler->interpolation;
if (animData.channels[j].sampler->interpolation != cgltf_interpolation_type_max_enum)
{
if (channel.target_path == cgltf_animation_path_type_translation)
@ -6691,7 +6701,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
animDuration = (time > animDuration)? time : animDuration;
}
if (animData.name != NULL) strncpy(animations[a].name, animData.name, sizeof(animations[a].name) - 1);
if (animData.name != NULL) snprintf(animations[a].name, sizeof(animations[a].name), "%s", animData.name);
animations[a].keyframeCount = (int)(animDuration*GLTF_FRAMERATE) + 1;
animations[a].keyframePoses = (Transform **)RL_CALLOC(animations[a].keyframeCount, sizeof(Transform *));
@ -6701,7 +6711,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
animations[a].keyframePoses[j] = (Transform *)RL_CALLOC(animations[a].boneCount, sizeof(Transform));
float time = (float)j / GLTF_FRAMERATE;
for (int k = 0; k < animations[a].boneCount; k++)
for (unsigned int k = 0; k < animations[a].boneCount; k++)
{
Vector3 translation = {skin.joints[k]->translation[0], skin.joints[k]->translation[1], skin.joints[k]->translation[2]};
Quaternion rotation = {skin.joints[k]->rotation[0], skin.joints[k]->rotation[1], skin.joints[k]->rotation[2], skin.joints[k]->rotation[3]};
@ -6709,7 +6719,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
if (boneChannels[k].translate)
{
if (!GetPoseAtTimeGLTF(boneChannels[k].interpolationType, boneChannels[k].translate->sampler->input, boneChannels[k].translate->sampler->output, time, &translation))
if (!GetPoseAtTimeGLTF(boneChannels[k].translate->sampler->interpolation, boneChannels[k].translate->sampler->input, boneChannels[k].translate->sampler->output, time, &translation))
{
TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load translate pose data for bone %s", fileName, bones[k].name);
}
@ -6717,7 +6727,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
if (boneChannels[k].rotate)
{
if (!GetPoseAtTimeGLTF(boneChannels[k].interpolationType, boneChannels[k].rotate->sampler->input, boneChannels[k].rotate->sampler->output, time, &rotation))
if (!GetPoseAtTimeGLTF(boneChannels[k].rotate->sampler->interpolation, boneChannels[k].rotate->sampler->input, boneChannels[k].rotate->sampler->output, time, &rotation))
{
TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load rotate pose data for bone %s", fileName, bones[k].name);
}
@ -6725,7 +6735,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
if (boneChannels[k].scale)
{
if (!GetPoseAtTimeGLTF(boneChannels[k].interpolationType, boneChannels[k].scale->sampler->input, boneChannels[k].scale->sampler->output, time, &scale))
if (!GetPoseAtTimeGLTF(boneChannels[k].scale->sampler->interpolation, boneChannels[k].scale->sampler->input, boneChannels[k].scale->sampler->output, time, &scale))
{
TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load scale pose data for bone %s", fileName, bones[k].name);
}
@ -7177,7 +7187,7 @@ static Model LoadM3D(const char *fileName)
for (i = 0; i < (int)m3d->numbone; i++)
{
model.skeleton.bones[i].parent = m3d->bone[i].parent;
strncpy(model.skeleton.bones[i].name, m3d->bone[i].name, sizeof(model.skeleton.bones[i].name) - 1);
snprintf(model.skeleton.bones[i].name, sizeof(model.skeleton.bones[i].name), "%s", m3d->bone[i].name);
model.skeleton.bindPose[i].translation.x = m3d->vertex[m3d->bone[i].pos].x*m3d->scale;
model.skeleton.bindPose[i].translation.y = m3d->vertex[m3d->bone[i].pos].y*m3d->scale;
model.skeleton.bindPose[i].translation.z = m3d->vertex[m3d->bone[i].pos].z*m3d->scale;
@ -7225,7 +7235,7 @@ static Model LoadM3D(const char *fileName)
// Initialize runtime animation data: current pose and bone matrices
model.currentPose = (Transform *)RL_CALLOC(model.skeleton.boneCount, sizeof(Transform));
model.boneMatrices = (Matrix *)RL_CALLOC(model.skeleton.boneCount, sizeof(Matrix));
for (int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
for (unsigned int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity();
}
m3d_free(m3d);
@ -7235,7 +7245,7 @@ static Model LoadM3D(const char *fileName)
return model;
}
#define M3D_ANIMDELAY 17 // Animation frames delay, (~1000 ms/60 FPS = 16.666666* ms)
#define M3D_ANIMDELAY 17 // Animation frames delay, (~1000 ms/60 FPS = 16.666666 ms)
// Load M3D animation data
static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCount)
@ -7279,14 +7289,14 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCou
animations[a].keyframeCount = m3d->action[a].durationmsec/M3D_ANIMDELAY;
animations[a].keyframePoses = (Transform **)RL_CALLOC(animations[a].keyframeCount, sizeof(Transform *));
strncpy(animations[a].name, m3d->action[a].name, sizeof(animations[a].name) - 1);
snprintf(animations[a].name, sizeof(animations[a].name), "%s", m3d->action[a].name);
TRACELOG(LOG_INFO, "MODEL: [%s] Loaded animation: %s | Frames: %d | Duration: %fs", fileName, animations[a].name, animations[a].keyframeCount, m3d->action[a].durationmsec);
for (i = 0; i < (int)m3d->numbone; i++)
{
bones[i].parent = m3d->bone[i].parent;
strncpy(bones[i].name, m3d->bone[i].name, sizeof(bones[i].name) - 1);
snprintf(bones[i].name, sizeof(bones[i].name), "%s", m3d->bone[i].name);
}
// A special, never transformed "no bone" bone, used for boneless vertices