diff --git a/examples/models/models_animation.c b/examples/models/models_animation.c index 7f38b7f55..5e7c8cf54 100644 --- a/examples/models/models_animation.c +++ b/examples/models/models_animation.c @@ -9,8 +9,15 @@ * * Copyright (c) 2019 Culacant (@culacant) and Ramon Santamaria (@raysan5) * +******************************************************************************************** +* +* To export a model from blender, make sure it is not posed, the vertices need to be in the +* same position as they would be in edit mode. +* and that the scale of your models is set to 0. Scaling can be done from the export menu. +* ********************************************************************************************/ +#include #include "raylib.h" int main(void) @@ -93,6 +100,7 @@ int main(void) //-------------------------------------------------------------------------------------- // Unload model animations data for (int i = 0; i < animsCount; i++) UnloadModelAnimation(anims[i]); + RL_FREE(anims); UnloadModel(model); // Unload model diff --git a/src/models.c b/src/models.c index ee625906e..f848e0abc 100644 --- a/src/models.c +++ b/src/models.c @@ -867,9 +867,6 @@ void SetModelMeshMaterial(Model *model, int meshId, int materialId) // Load model animations from file ModelAnimation *LoadModelAnimations(const char *filename, int *animCount) { - ModelAnimation *animations = (ModelAnimation *)RL_MALLOC(1*sizeof(ModelAnimation)); - int count = 1; - #define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number #define IQM_VERSION 2 // only IQM version 2 supported @@ -904,8 +901,6 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount) unsigned int flags; } IQMAnim; - ModelAnimation animation = { 0 }; - FILE *iqmFile; IQMHeader iqm; @@ -931,153 +926,156 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount) fclose(iqmFile); } - // header - if (iqm.num_anims > 1) TraceLog(LOG_WARNING, "More than 1 animation in file, only the first one will be loaded"); - // bones IQMPose *poses; poses = RL_MALLOC(sizeof(IQMPose)*iqm.num_poses); fseek(iqmFile, iqm.ofs_poses, SEEK_SET); fread(poses, sizeof(IQMPose)*iqm.num_poses, 1, iqmFile); - animation.boneCount = iqm.num_poses; - animation.bones = RL_MALLOC(sizeof(BoneInfo)*iqm.num_poses); - - for (int j = 0; j < iqm.num_poses; j++) - { - strcpy(animation.bones[j].name, "ANIMJOINTNAME"); - animation.bones[j].parent = poses[j].parent; - } - // animations - IQMAnim anim = {0}; + *animCount = iqm.num_anims; + IQMAnim *anim = RL_MALLOC(iqm.num_anims*sizeof(IQMAnim)); fseek(iqmFile, iqm.ofs_anims, SEEK_SET); - fread(&anim, sizeof(IQMAnim), 1, iqmFile); + fread(anim, iqm.num_anims*sizeof(IQMAnim), 1, iqmFile); + ModelAnimation *animations = RL_MALLOC(iqm.num_anims*sizeof(ModelAnimation)); - animation.frameCount = anim.num_frames; - //animation.framerate = anim.framerate; // frameposes unsigned short *framedata = RL_MALLOC(sizeof(unsigned short)*iqm.num_frames*iqm.num_framechannels); fseek(iqmFile, iqm.ofs_frames, SEEK_SET); fread(framedata, sizeof(unsigned short)*iqm.num_frames*iqm.num_framechannels, 1, iqmFile); - animation.framePoses = RL_MALLOC(sizeof(Transform*)*anim.num_frames); - for (int j = 0; j < anim.num_frames; j++) animation.framePoses[j] = RL_MALLOC(sizeof(Transform)*iqm.num_poses); - - int dcounter = anim.first_frame*iqm.num_framechannels; - - for (int frame = 0; frame < anim.num_frames; frame++) + for(int a=0;a= 0) + for (int i = 0; i < iqm.num_poses; i++) { - animation.framePoses[frame][i].rotation = QuaternionMultiply(animation.framePoses[frame][animation.bones[i].parent].rotation, animation.framePoses[frame][i].rotation); - animation.framePoses[frame][i].translation = Vector3RotateByQuaternion(animation.framePoses[frame][i].translation, animation.framePoses[frame][animation.bones[i].parent].rotation); - animation.framePoses[frame][i].translation = Vector3Add(animation.framePoses[frame][i].translation, animation.framePoses[frame][animation.bones[i].parent].translation); - animation.framePoses[frame][i].scale = Vector3MultiplyV(animation.framePoses[frame][i].scale, animation.framePoses[frame][animation.bones[i].parent].scale); + animations[a].framePoses[frame][i].translation.x = poses[i].channeloffset[0]; + + if (poses[i].mask & 0x01) + { + animations[a].framePoses[frame][i].translation.x += framedata[dcounter]*poses[i].channelscale[0]; + dcounter++; + } + + animations[a].framePoses[frame][i].translation.y = poses[i].channeloffset[1]; + + if (poses[i].mask & 0x02) + { + animations[a].framePoses[frame][i].translation.y += framedata[dcounter]*poses[i].channelscale[1]; + dcounter++; + } + + animations[a].framePoses[frame][i].translation.z = poses[i].channeloffset[2]; + + if (poses[i].mask & 0x04) + { + animations[a].framePoses[frame][i].translation.z += framedata[dcounter]*poses[i].channelscale[2]; + dcounter++; + } + + animations[a].framePoses[frame][i].rotation.x = poses[i].channeloffset[3]; + + if (poses[i].mask & 0x08) + { + animations[a].framePoses[frame][i].rotation.x += framedata[dcounter]*poses[i].channelscale[3]; + dcounter++; + } + + animations[a].framePoses[frame][i].rotation.y = poses[i].channeloffset[4]; + + if (poses[i].mask & 0x10) + { + animations[a].framePoses[frame][i].rotation.y += framedata[dcounter]*poses[i].channelscale[4]; + dcounter++; + } + + animations[a].framePoses[frame][i].rotation.z = poses[i].channeloffset[5]; + + if (poses[i].mask & 0x20) + { + animations[a].framePoses[frame][i].rotation.z += framedata[dcounter]*poses[i].channelscale[5]; + dcounter++; + } + + animations[a].framePoses[frame][i].rotation.w = poses[i].channeloffset[6]; + + if (poses[i].mask & 0x40) + { + animations[a].framePoses[frame][i].rotation.w += framedata[dcounter]*poses[i].channelscale[6]; + dcounter++; + } + + animations[a].framePoses[frame][i].scale.x = poses[i].channeloffset[7]; + + if (poses[i].mask & 0x80) + { + animations[a].framePoses[frame][i].scale.x += framedata[dcounter]*poses[i].channelscale[7]; + dcounter++; + } + + animations[a].framePoses[frame][i].scale.y = poses[i].channeloffset[8]; + + if (poses[i].mask & 0x100) + { + animations[a].framePoses[frame][i].scale.y += framedata[dcounter]*poses[i].channelscale[8]; + dcounter++; + } + + animations[a].framePoses[frame][i].scale.z = poses[i].channeloffset[9]; + + if (poses[i].mask & 0x200) + { + animations[a].framePoses[frame][i].scale.z += framedata[dcounter]*poses[i].channelscale[9]; + dcounter++; + } + + animations[a].framePoses[frame][i].rotation = QuaternionNormalize(animations[a].framePoses[frame][i].rotation); + } + } + + // Build frameposes + for (int frame = 0; frame < anim[a].num_frames; frame++) + { + for (int i = 0; i < animations[a].boneCount; i++) + { + if (animations[a].bones[i].parent >= 0) + { + animations[a].framePoses[frame][i].rotation = QuaternionMultiply(animations[a].framePoses[frame][animations[a].bones[i].parent].rotation, animations[a].framePoses[frame][i].rotation); + animations[a].framePoses[frame][i].translation = Vector3RotateByQuaternion(animations[a].framePoses[frame][i].translation, animations[a].framePoses[frame][animations[a].bones[i].parent].rotation); + animations[a].framePoses[frame][i].translation = Vector3Add(animations[a].framePoses[frame][i].translation, animations[a].framePoses[frame][animations[a].bones[i].parent].translation); + animations[a].framePoses[frame][i].scale = Vector3MultiplyV(animations[a].framePoses[frame][i].scale, animations[a].framePoses[frame][animations[a].bones[i].parent].scale); + } } } } RL_FREE(framedata); RL_FREE(poses); + RL_FREE(anim); fclose(iqmFile); - animations[0] = animation; - *animCount = count; return animations; }