fix brace alignment and replace asserts with log messages
This commit is contained in:
parent
6ad9e0b622
commit
068a0a897f
|
|
@ -55,11 +55,13 @@ int main(void)
|
|||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
ModelAnimation anim = modelAnimations[animIndex];
|
||||
if (IsKeyPressed(KEY_UP)) {
|
||||
if (IsKeyPressed(KEY_UP))
|
||||
{
|
||||
animIndex = (animIndex + 1) % animsCount;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KEY_DOWN)) {
|
||||
if (IsKeyPressed(KEY_DOWN))
|
||||
{
|
||||
animIndex = (animIndex + animsCount - 1) % animsCount;
|
||||
}
|
||||
|
||||
|
|
|
|||
148
src/rmodels.c
148
src/rmodels.c
|
|
@ -3829,14 +3829,17 @@ RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Ve
|
|||
return collision;
|
||||
}
|
||||
|
||||
static void BuildPoseFromParentJoints(BoneInfo *bones, int boneCount, Transform *transforms) {
|
||||
static void BuildPoseFromParentJoints(BoneInfo *bones, int boneCount, Transform *transforms)
|
||||
{
|
||||
for (int i = 0; i < boneCount; i++)
|
||||
{
|
||||
if (bones[i].parent >= 0)
|
||||
{
|
||||
// Assumes bones are topologically sorted and we've transformed
|
||||
// the parent before this node.
|
||||
assert(bones[i].parent < i);
|
||||
if (bones[i].parent > i)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "Assumes bones are toplogically sorted, but bone %d has parent %d. Skipping.", i, bones[i].parent);
|
||||
continue;
|
||||
}
|
||||
transforms[i].rotation = QuaternionMultiply(transforms[bones[i].parent].rotation, transforms[i].rotation);
|
||||
transforms[i].translation = Vector3RotateByQuaternion(transforms[i].translation, transforms[bones[i].parent].rotation);
|
||||
transforms[i].translation = Vector3Add(transforms[i].translation, transforms[bones[i].parent].translation);
|
||||
|
|
@ -4687,18 +4690,22 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat
|
|||
return image;
|
||||
}
|
||||
|
||||
static BoneInfo *LoadGLTFBoneInfo(cgltf_skin skin, int *boneCount) {
|
||||
static BoneInfo *LoadGLTFBoneInfo(cgltf_skin skin, int *boneCount)
|
||||
{
|
||||
*boneCount = skin.joints_count;
|
||||
BoneInfo *bones = RL_MALLOC(skin.joints_count*sizeof(BoneInfo));
|
||||
|
||||
for (unsigned int i = 0; i < skin.joints_count; i++) {
|
||||
for (unsigned int i = 0; i < skin.joints_count; i++)
|
||||
{
|
||||
cgltf_node node = *skin.joints[i];
|
||||
strncpy(bones[i].name, node.name, sizeof(bones[i].name));
|
||||
|
||||
// find parent bone index
|
||||
unsigned int parentIndex = -1;
|
||||
for (unsigned int j = 0; j < skin.joints_count; j++) {
|
||||
if (skin.joints[j] == node.parent) {
|
||||
for (unsigned int j = 0; j < skin.joints_count; j++)
|
||||
{
|
||||
if (skin.joints[j] == node.parent)
|
||||
{
|
||||
parentIndex = j;
|
||||
break;
|
||||
}
|
||||
|
|
@ -5074,12 +5081,14 @@ static Model LoadGLTF(const char *fileName)
|
|||
// REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skinned-mesh-attributes
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
||||
if (data->skins_count == 1) {
|
||||
if (data->skins_count == 1)
|
||||
{
|
||||
cgltf_skin skin = data->skins[0];
|
||||
model.bones = LoadGLTFBoneInfo(skin, &model.boneCount);
|
||||
model.bindPose = RL_MALLOC(model.boneCount*sizeof(Transform));
|
||||
|
||||
for (unsigned int i = 0; i < model.boneCount; i++) {
|
||||
for (unsigned int i = 0; i < model.boneCount; i++)
|
||||
{
|
||||
cgltf_node node = *skin.joints[i];
|
||||
model.bindPose[i].translation.x = node.translation[0];
|
||||
model.bindPose[i].translation.y = node.translation[1];
|
||||
|
|
@ -5096,7 +5105,9 @@ static Model LoadGLTF(const char *fileName)
|
|||
}
|
||||
|
||||
BuildPoseFromParentJoints(model.bones, model.boneCount, model.bindPose);
|
||||
} else if (data->skins_count > 1) {
|
||||
}
|
||||
else if (data->skins_count > 1)
|
||||
{
|
||||
TRACELOG(LOG_ERROR, "MODEL: [%s] can only load one skin (armature) per model, but gltf skins_count == %i", fileName, data->skins_count);
|
||||
}
|
||||
|
||||
|
|
@ -5121,7 +5132,6 @@ static Model LoadGLTF(const char *fileName)
|
|||
model.meshes[meshIndex].boneIds = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
|
||||
|
||||
// Load 4 components of unsigned char data type into mesh.boneIds
|
||||
// TODO: It seems LOAD_ATTRIBUTE() macro does not work as expected in some cases,
|
||||
// for cgltf_attribute_type_joints we have:
|
||||
// - data.meshes[0] (256 vertices)
|
||||
// - 256 values, provided as cgltf_type_vec4 of bytes (4 byte per joint, stride 4)
|
||||
|
|
@ -5170,20 +5180,24 @@ static Model LoadGLTF(const char *fileName)
|
|||
return model;
|
||||
}
|
||||
|
||||
static void GetGLTFPoseAtTime(cgltf_accessor* input, cgltf_accessor *output, float time, void *data) {
|
||||
assert(input->count == output->count);
|
||||
// Get interpolated pose for bone sampler at a specific time. Returns true on success.
|
||||
static bool GetGLTFPoseAtTime(cgltf_accessor* input, cgltf_accessor *output, float time, void *data)
|
||||
{
|
||||
// input and output should have the same count
|
||||
|
||||
float tstart = 0.0f;
|
||||
float tend = 0.0f;
|
||||
|
||||
int keyframe = 0; // defaults to first pose
|
||||
for (int i = 0; i < input->count - 1; i++) {
|
||||
for (int i = 0; i < input->count - 1; i++)
|
||||
{
|
||||
cgltf_bool r1 = cgltf_accessor_read_float(input, i, &tstart, 1);
|
||||
assert(r1);
|
||||
if (!r1) return false;
|
||||
cgltf_bool r2 = cgltf_accessor_read_float(input, i+1, &tend, 1);
|
||||
assert(r2);
|
||||
if (!r2) return false;
|
||||
|
||||
if ((tstart <= time) && (time < tend)) {
|
||||
if ((tstart <= time) && (time < tend))
|
||||
{
|
||||
keyframe = i;
|
||||
break;
|
||||
}
|
||||
|
|
@ -5193,8 +5207,10 @@ static void GetGLTFPoseAtTime(cgltf_accessor* input, cgltf_accessor *output, flo
|
|||
t = (t < 0.0f)? 0.0f : t;
|
||||
t = (t > 1.0f)? 1.0f : t;
|
||||
|
||||
assert(output->component_type == cgltf_component_type_r_32f);
|
||||
if (output->type == cgltf_type_vec3) {
|
||||
if (output->component_type != cgltf_component_type_r_32f) return false;
|
||||
|
||||
if (output->type == cgltf_type_vec3)
|
||||
{
|
||||
float tmp[3] = { 0.0f };
|
||||
cgltf_accessor_read_float(output, keyframe, tmp, 3);
|
||||
Vector3 v1 = {tmp[0], tmp[1], tmp[2]};
|
||||
|
|
@ -5202,7 +5218,9 @@ static void GetGLTFPoseAtTime(cgltf_accessor* input, cgltf_accessor *output, flo
|
|||
Vector3 v2 = {tmp[0], tmp[1], tmp[2]};
|
||||
Vector3 *r = data;
|
||||
*r = Vector3Lerp(v1, v2, t);
|
||||
} else if (output->type == cgltf_type_vec4) {
|
||||
}
|
||||
else if (output->type == cgltf_type_vec4)
|
||||
{
|
||||
float tmp[4] = { 0.0f };
|
||||
cgltf_accessor_read_float(output, keyframe, tmp, 4);
|
||||
Vector4 v1 = {tmp[0], tmp[1], tmp[2], tmp[3]};
|
||||
|
|
@ -5212,10 +5230,12 @@ static void GetGLTFPoseAtTime(cgltf_accessor* input, cgltf_accessor *output, flo
|
|||
// only v4 is for rotations, so we know it's a quat.
|
||||
*r = QuaternionSlerp(v1, v2, t);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#define GLTF_ANIMDELAY 17 // that's roughly ~1000 msec / 60 FPS (16.666666* msec)
|
||||
static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned int *animCount) {
|
||||
static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned int *animCount)
|
||||
{
|
||||
// glTF file loading
|
||||
unsigned int dataSize = 0;
|
||||
unsigned char *fileData = LoadFileData(fileName, &dataSize);
|
||||
|
|
@ -5225,7 +5245,8 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in
|
|||
cgltf_options options = { 0 };
|
||||
cgltf_data *data = NULL;
|
||||
cgltf_result result = cgltf_parse(&options, fileData, dataSize, &data);
|
||||
if(result != cgltf_result_success) {
|
||||
if (result != cgltf_result_success)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load glTF data", fileName);
|
||||
*animCount = 0;
|
||||
return NULL;
|
||||
|
|
@ -5234,12 +5255,15 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in
|
|||
result = cgltf_load_buffers(&options, data, fileName);
|
||||
if (result != cgltf_result_success) TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load animation buffers", fileName);
|
||||
|
||||
if (result == cgltf_result_success) {
|
||||
if (data->skins_count == 1) {
|
||||
if (result == cgltf_result_success)
|
||||
{
|
||||
if (data->skins_count == 1)
|
||||
{
|
||||
cgltf_skin skin = data->skins[0];
|
||||
*animCount = data->animations_count;
|
||||
animations = RL_MALLOC(data->animations_count*sizeof(ModelAnimation));
|
||||
for(unsigned int i = 0; i < data->animations_count; i++) {
|
||||
for (unsigned int i = 0; i < data->animations_count; i++)
|
||||
{
|
||||
animations[i].bones = LoadGLTFBoneInfo(skin, &animations[i].boneCount);
|
||||
|
||||
cgltf_animation animData = data->animations[i];
|
||||
|
|
@ -5252,36 +5276,52 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in
|
|||
|
||||
struct Channels *boneChannels = RL_CALLOC(animations[i].boneCount, sizeof(struct Channels));
|
||||
float animDuration = 0.0f;
|
||||
for (unsigned int j = 0; j < animData.channels_count; j++) {
|
||||
for (unsigned int j = 0; j < animData.channels_count; j++)
|
||||
{
|
||||
cgltf_animation_channel channel = animData.channels[j];
|
||||
int boneIndex = -1;
|
||||
for (unsigned int k = 0; k < skin.joints_count; k++) {
|
||||
if (animData.channels[j].target_node == skin.joints[k]) {
|
||||
for (unsigned int k = 0; k < skin.joints_count; k++)
|
||||
{
|
||||
if (animData.channels[j].target_node == skin.joints[k])
|
||||
{
|
||||
boneIndex = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (boneIndex == -1) {
|
||||
if (boneIndex == -1)
|
||||
{
|
||||
// animation channel for a node not in the armature.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (animData.channels[j].sampler->interpolation == cgltf_interpolation_type_linear) {
|
||||
if (channel.target_path == cgltf_animation_path_type_translation) {
|
||||
if (animData.channels[j].sampler->interpolation == cgltf_interpolation_type_linear)
|
||||
{
|
||||
if (channel.target_path == cgltf_animation_path_type_translation)
|
||||
{
|
||||
boneChannels[boneIndex].translate = &animData.channels[j];
|
||||
} else if (channel.target_path == cgltf_animation_path_type_rotation) {
|
||||
}
|
||||
else if (channel.target_path == cgltf_animation_path_type_rotation)
|
||||
{
|
||||
boneChannels[boneIndex].rotate = &animData.channels[j];
|
||||
} else if (channel.target_path == cgltf_animation_path_type_scale) {
|
||||
}
|
||||
else if (channel.target_path == cgltf_animation_path_type_scale)
|
||||
{
|
||||
boneChannels[boneIndex].scale = &animData.channels[j];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "MODEL: [%s] Unsupported target_path on channel %d's sampler for animation %d. Skipping.", fileName, j, i);
|
||||
}
|
||||
} else TRACELOG(LOG_WARNING, "MODEL: [%s] Only linear interpolation curves are supported for GLTF animation.", fileName);
|
||||
|
||||
float t = 0.0f;
|
||||
cgltf_bool r = cgltf_accessor_read_float(channel.sampler->input, channel.sampler->input->count - 1, &t, 1);
|
||||
assert(r);
|
||||
if (!r)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load input time", fileName);
|
||||
continue;
|
||||
}
|
||||
|
||||
animDuration = (t > animDuration)? t : animDuration;
|
||||
}
|
||||
|
|
@ -5289,32 +5329,46 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, unsigned in
|
|||
animations[i].frameCount = (int)(animDuration*1000.0f/GLTF_ANIMDELAY);
|
||||
animations[i].framePoses = RL_MALLOC(animations[i].frameCount*sizeof(Transform *));
|
||||
|
||||
for (unsigned int j = 0; j < animations[i].frameCount; j++) {
|
||||
for (unsigned int j = 0; j < animations[i].frameCount; j++)
|
||||
{
|
||||
animations[i].framePoses[j] = RL_MALLOC(animations[i].boneCount*sizeof(Transform));
|
||||
float time = ((float) j*GLTF_ANIMDELAY)/1000.0f;
|
||||
for (unsigned int k = 0; k < animations[i].boneCount; k++) {
|
||||
for (unsigned int k = 0; k < animations[i].boneCount; k++)
|
||||
{
|
||||
Vector3 translation = {0, 0, 0};
|
||||
Quaternion rotation = {0, 0, 0, 1};
|
||||
Vector3 scale = {1, 1, 1};
|
||||
if (boneChannels[k].translate) {
|
||||
GetGLTFPoseAtTime(boneChannels[k].translate->sampler->input,
|
||||
if (boneChannels[k].translate)
|
||||
{
|
||||
if (!GetGLTFPoseAtTime(boneChannels[k].translate->sampler->input,
|
||||
boneChannels[k].translate->sampler->output,
|
||||
time,
|
||||
&translation);
|
||||
&translation))
|
||||
{
|
||||
TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load translate pose data for bone %s", fileName, animations[i].bones[k].name);
|
||||
}
|
||||
}
|
||||
|
||||
if (boneChannels[k].rotate) {
|
||||
GetGLTFPoseAtTime(boneChannels[k].rotate->sampler->input,
|
||||
if (boneChannels[k].rotate)
|
||||
{
|
||||
if (!GetGLTFPoseAtTime(boneChannels[k].rotate->sampler->input,
|
||||
boneChannels[k].rotate->sampler->output,
|
||||
time,
|
||||
&rotation);
|
||||
&rotation))
|
||||
{
|
||||
TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load rotate pose data for bone %s", fileName, animations[i].bones[k].name);
|
||||
}
|
||||
}
|
||||
|
||||
if (boneChannels[k].scale) {
|
||||
GetGLTFPoseAtTime(boneChannels[k].scale->sampler->input,
|
||||
if (boneChannels[k].scale)
|
||||
{
|
||||
if (!GetGLTFPoseAtTime(boneChannels[k].scale->sampler->input,
|
||||
boneChannels[k].scale->sampler->output,
|
||||
time,
|
||||
&scale);
|
||||
&scale))
|
||||
{
|
||||
TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load scale pose data for bone %s", fileName, animations[i].bones[k].name);
|
||||
}
|
||||
}
|
||||
|
||||
animations[i].framePoses[j][k] = (Transform){
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user