Create a mirror animation for each animation ending on .R or .L (#401)

floating-point
Armin Burgmeier 2010-09-09 22:40:07 +02:00
parent 8f0af13a62
commit 5819c34211
3 changed files with 99 additions and 1 deletions

View File

@ -177,8 +177,11 @@ bool C4DefGraphics::LoadMesh(C4Group &hGroup, StdMeshSkeletonLoader& loader)
else
return false;
delete[] buf;
// Create mirrored animations (#401)
Mesh->MirrorAnimations();
}
catch (const StdMeshLoader::LoaderException &ex)
catch (const std::runtime_error& ex)
{
DebugLogF("Failed to load mesh: %s", ex.what());
delete[] buf;

View File

@ -179,6 +179,35 @@ namespace
ClearAnimationListRecursively(list, node->GetRightChild());
}
}
// Mirror is wrt X axis
void MirrorKeyFrame(StdMeshKeyFrame& frame, const StdMeshTransformation& old_bone_transformation, const StdMeshTransformation& new_inverse_bone_transformation)//Bone& new_bone, const StdMeshBone& old_bone)
{
// frame was a keyframe of a track for old_bone and was now transplanted to new_bone.
frame.Transformation.rotate.y = -frame.Transformation.rotate.y;
frame.Transformation.rotate.z = -frame.Transformation.rotate.z;
// We might also want to do something like this... need to get feedback
// from modelers...
//StdMeshVector d = old_bone_transformation.scale * (old_bone_transformation.rotate * frame.Transformation.translate);
//d.x = -d.x;
//frame.Transformation.translate = new_inverse_bone_transformation.rotate * (new_inverse_bone_transformation.scale * d);
}
bool MirrorName(StdStrBuf& buf)
{
unsigned int len = buf.getLength();
if(buf.Compare_(".R", len-2) == 0)
buf.getMData()[len-1] = 'L';
else if(buf.Compare_(".L", len-2) == 0)
buf.getMData()[len-1] = 'R';
else
return false;
return true;
}
}
/* Boring Math stuff begins here */
@ -906,6 +935,66 @@ const StdMeshAnimation* StdMesh::GetAnimationByName(const StdStrBuf& name) const
return &iter->second;
}
void StdMesh::MirrorAnimation(const StdStrBuf& name, const StdMeshAnimation& animation)
{
StdCopyStrBuf name2(name);
assert(Animations.find(name2) == Animations.end());
StdMeshAnimation& new_anim = Animations.insert(std::make_pair(name2, animation)).first->second;
new_anim.Name = name2;
// Go through all bones
for(unsigned int i = 0; i < GetNumBones(); ++i)
{
// Only proceed if the bone is used in this animation
if(animation.Tracks[i] != NULL)
{
const StdMeshBone& bone = GetBone(i);
StdCopyStrBuf other_bone_name(bone.Name);
if(MirrorName(other_bone_name))
{
const StdMeshBone* other_bone = GetBoneByName(other_bone_name);
if(!other_bone)
throw std::runtime_error(std::string("No counterpart for bone ") + bone.Name.getData() + " found");
// Make sure to not swap tracks twice
if(other_bone->Index > bone.Index)
{
std::swap(new_anim.Tracks[i], new_anim.Tracks[other_bone->Index]);
StdMeshTransformation own_trans = bone.GetParent()->InverseTransformation * bone.Transformation;
StdMeshTransformation other_own_trans = other_bone->GetParent()->InverseTransformation * other_bone->Transformation;
// Mirror all the keyframes of both tracks
for(std::map<float, StdMeshKeyFrame>::iterator iter = new_anim.Tracks[i]->Frames.begin(); iter != new_anim.Tracks[i]->Frames.end(); ++iter)
MirrorKeyFrame(iter->second, own_trans, StdMeshTransformation::Inverse(other_own_trans));
for(std::map<float, StdMeshKeyFrame>::iterator iter = new_anim.Tracks[other_bone->Index]->Frames.begin(); iter != new_anim.Tracks[other_bone->Index]->Frames.end(); ++iter)
MirrorKeyFrame(iter->second, other_own_trans, StdMeshTransformation::Inverse(own_trans));
}
}
}
}
}
void StdMesh::MirrorAnimations()
{
// Mirror .R and .L animations without counterpart
for(std::map<StdCopyStrBuf, StdMeshAnimation>::iterator iter = Animations.begin(); iter != Animations.end(); ++iter)
{
// For debugging purposes:
//if(iter->second.Name == "Jump")
// MirrorAnimation(StdCopyStrBuf("Jump.Mirror"), iter->second);
StdCopyStrBuf buf = iter->second.Name;
if(MirrorName(buf))
{
if(Animations.find(buf) == Animations.end())
MirrorAnimation(buf, iter->second);
}
}
}
StdSubMeshInstance::StdSubMeshInstance(const StdSubMesh& submesh):
Vertices(submesh.GetNumVertices()), Faces(submesh.GetNumFaces()),
Material(NULL)

View File

@ -192,6 +192,7 @@ public:
// Animation track, specifies transformation for one bone for each keyframe
class StdMeshTrack
{
friend class StdMesh;
friend class StdMeshLoader;
public:
StdMeshTransformation GetTransformAt(float time) const;
@ -203,6 +204,7 @@ private:
// Animation, consists of one Track for each animated Bone
class StdMeshAnimation
{
friend class StdMesh;
friend class StdMeshLoader;
friend class StdMeshInstance;
public:
@ -273,6 +275,10 @@ public:
const StdMeshBox& GetBoundingBox() const { return BoundingBox; }
float GetBoundingRadius() const { return BoundingRadius; }
// TODO: This code should maybe better be placed in StdMeshLoader...
void MirrorAnimation(const StdStrBuf& name, const StdMeshAnimation& animation);
void MirrorAnimations();
private:
void AddMasterBone(StdMeshBone* bone);