diff --git a/src/models.c b/src/models.c index 5c54902a9..b92228556 100644 --- a/src/models.c +++ b/src/models.c @@ -3719,11 +3719,11 @@ static Model LoadGLTF(const char *fileName) model.boneCount = (int)data->nodes_count; model.bones = RL_CALLOC(model.boneCount, sizeof(BoneInfo)); model.bindPose = RL_CALLOC(model.boneCount, sizeof(Transform)); - + for (unsigned int j = 0; j < data->nodes_count; j++) { strcpy(model.bones[j].name, data->nodes[j].name == 0 ? "ANIMJOINT" : data->nodes[j].name); - model.bones[j].parent = (int)((j != 0 && data->nodes[j].parent != NULL) ? data->nodes[j].parent - data->nodes : 0); + model.bones[j].parent = (data->nodes[j].parent != NULL) ? data->nodes[j].parent - data->nodes : -1; } for (unsigned int i = 0; i < data->nodes_count; i++) @@ -3739,22 +3739,41 @@ static Model LoadGLTF(const char *fileName) if (data->nodes[i].has_scale) memcpy(&model.bindPose[i].scale, data->nodes[i].scale, 3 * sizeof(float)); else model.bindPose[i].scale = Vector3One(); } - - for (int i = 0; i < model.boneCount; i++) + { - Transform *currentTransform = model.bindPose + i; - BoneInfo *currentBone = model.bones + i; - int root = currentBone->parent; - if (root >= model.boneCount) root = 0; - Transform *parentTransform = model.bindPose + root; - - if (currentBone->parent >= 0) - { - currentTransform->rotation = QuaternionMultiply(parentTransform->rotation, currentTransform->rotation); - currentTransform->translation = Vector3RotateByQuaternion(currentTransform->translation, parentTransform->rotation); - currentTransform->translation = Vector3Add(currentTransform->translation, parentTransform->translation); - currentTransform->scale = Vector3Multiply(parentTransform->scale, parentTransform->scale); + bool* completedBones = RL_CALLOC(model.boneCount, sizeof(bool)); + int numberCompletedBones = 0; + + while (numberCompletedBones < model.boneCount) { + for (int i = 0; i < model.boneCount; i++) + { + if (completedBones[i]) continue; + + if (model.bones[i].parent < 0) { + completedBones[i] = true; + numberCompletedBones++; + continue; + } + + if (!completedBones[model.bones[i].parent]) continue; + + Transform* currentTransform = &model.bindPose[i]; + BoneInfo* currentBone = &model.bones[i]; + int root = currentBone->parent; + if (root >= model.boneCount) + root = 0; + Transform* parentTransform = &model.bindPose[root]; + + currentTransform->rotation = QuaternionMultiply(parentTransform->rotation, currentTransform->rotation); + currentTransform->translation = Vector3RotateByQuaternion(currentTransform->translation, parentTransform->rotation); + currentTransform->translation = Vector3Add(currentTransform->translation, parentTransform->translation); + currentTransform->scale = Vector3Multiply(parentTransform->scale, parentTransform->scale); + completedBones[i] = true; + numberCompletedBones++; + } } + + RL_FREE(completedBones); } for (int i = 0; i < model.materialCount - 1; i++) @@ -3879,7 +3898,28 @@ static Model LoadGLTF(const char *fileName) short* bones = RL_MALLOC(sizeof(short) * acc->count * 4); LOAD_ACCESSOR(short, 4, acc, bones); - for (unsigned int a = 0; a < acc->count * 4; a ++) + for (unsigned int a = 0; a < acc->count * 4; a++) + { + cgltf_node* skinJoint = data->skins->joints[bones[a]]; + + for (unsigned int k = 0; k < data->nodes_count; k++) + { + if (&(data->nodes[k]) == skinJoint) + { + model.meshes[primitiveIndex].boneIds[a] = k; + break; + } + } + } + RL_FREE(bones); + } + else if (acc->component_type == cgltf_component_type_r_8u) + { + model.meshes[primitiveIndex].boneIds = RL_MALLOC(sizeof(int) * acc->count * 4); + unsigned char* bones = RL_MALLOC(sizeof(unsigned char) * acc->count * 4); + + LOAD_ACCESSOR(unsigned char, 4, acc, bones); + for (unsigned int a = 0; a < acc->count * 4; a++) { cgltf_node* skinJoint = data->skins->joints[bones[a]]; @@ -4009,6 +4049,9 @@ static ModelAnimation* LoadGLTFModelAnimations(const char *fileName, int *animCo { TRACELOG(LOG_INFO, "MODEL: [%s] glTF animations (%s) count: %i", fileName, (data->file_type == 2)? "glb" : "gltf", data->animations_count); + + result = cgltf_load_buffers(&options, data, fileName); + if (result != cgltf_result_success) TRACELOG(LOG_WARNING, "MODEL: [%s] unable to load glTF animations data", fileName); animations = RL_MALLOC(data->animations_count*sizeof(ModelAnimation)); @@ -4054,7 +4097,7 @@ static ModelAnimation* LoadGLTFModelAnimations(const char *fileName, int *animCo for (unsigned int j = 0; j < data->nodes_count; j++) { strcpy(output->bones[j].name, data->nodes[j].name == 0 ? "ANIMJOINT" : data->nodes[j].name); - output->bones[j].parent = j != 0 ? (int)(data->nodes[j].parent - data->nodes) : 0; + output->bones[j].parent = (data->nodes[j].parent != NULL) ? (int)(data->nodes[j].parent - data->nodes) : -1; } // Allocate data for frames @@ -4099,11 +4142,11 @@ static ModelAnimation* LoadGLTFModelAnimations(const char *fileName, int *animCo if (frameTime < inputFrameTime) { shouldSkipFurtherTransformation = false; - outputMin = j - 1; + outputMin = (j == 0) ? 0 : j - 1; outputMax = j; float previousInputTime = 0.0f; - if (GltfReadFloat(sampler->input, j - 1, (float*)&previousInputTime, 1)) + if (GltfReadFloat(sampler->input, outputMin, (float*)&previousInputTime, 1)) { lerpPercent = (frameTime - previousInputTime) / (inputFrameTime - previousInputTime); } @@ -4163,16 +4206,32 @@ static ModelAnimation* LoadGLTFModelAnimations(const char *fileName, int *animCo // Build frameposes for (int frame = 0; frame < output->frameCount; frame++) { - for (int i = 0; i < output->boneCount; i++) - { - if (output->bones[i].parent >= 0) + bool* completedBones = RL_CALLOC(output->boneCount, sizeof(bool)); + int numberCompletedBones = 0; + + while (numberCompletedBones < output->boneCount) { + for (int i = 0; i < output->boneCount; i++) { + if (completedBones[i]) continue; + + if (output->bones[i].parent < 0) { + completedBones[i] = true; + numberCompletedBones++; + continue; + } + + if (!completedBones[output->bones[i].parent]) continue; + output->framePoses[frame][i].rotation = QuaternionMultiply(output->framePoses[frame][output->bones[i].parent].rotation, output->framePoses[frame][i].rotation); output->framePoses[frame][i].translation = Vector3RotateByQuaternion(output->framePoses[frame][i].translation, output->framePoses[frame][output->bones[i].parent].rotation); output->framePoses[frame][i].translation = Vector3Add(output->framePoses[frame][i].translation, output->framePoses[frame][output->bones[i].parent].translation); output->framePoses[frame][i].scale = Vector3Multiply(output->framePoses[frame][i].scale, output->framePoses[frame][output->bones[i].parent].scale); + completedBones[i] = true; + numberCompletedBones++; } } + + RL_FREE(completedBones); } }