/* Copyright (C) 2009 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ /* * Raw description of a skeleton animation */ #include "precompiled.h" #include "SkeletonAnimDef.h" #include "maths/MathUtil.h" #include "maths/Matrix3D.h" #include "ps/CStr.h" #include "ps/FileIo.h" /////////////////////////////////////////////////////////////////////////////////////////// // CSkeletonAnimDef constructor CSkeletonAnimDef::CSkeletonAnimDef() : m_FrameTime(0), m_NumKeys(0), m_NumFrames(0), m_Keys(0) { } /////////////////////////////////////////////////////////////////////////////////////////// // CSkeletonAnimDef destructor CSkeletonAnimDef::~CSkeletonAnimDef() { delete[] m_Keys; } /////////////////////////////////////////////////////////////////////////////////////////// // BuildBoneMatrices: build matrices for all bones at the given time (in MS) in this // animation void CSkeletonAnimDef::BuildBoneMatrices(float time, CMatrix3D* matrices, bool loop) const { float fstartframe = time/m_FrameTime; size_t startframe = (size_t)(int)(time/m_FrameTime); float deltatime = fstartframe-startframe; startframe %= m_NumFrames; size_t endframe = startframe + 1; endframe %= m_NumFrames; if (!loop && endframe == 0) { // This might be something like a death animation, and interpolating // between the final frame and the initial frame is wrong, because they're // totally different. So if we've looped around to endframe==0, just display // the animation's final frame with no interpolation. for (size_t i = 0; i < m_NumKeys; i++) { const Key& key = GetKey(startframe, i); matrices[i].SetIdentity(); matrices[i].Rotate(key.m_Rotation); matrices[i].Translate(key.m_Translation); } } else { for (size_t i = 0; i < m_NumKeys; i++) { const Key& startkey = GetKey(startframe, i); const Key& endkey = GetKey(endframe, i); CVector3D trans = Interpolate(startkey.m_Translation, endkey.m_Translation, deltatime); // TODO: is slerp the best thing to use here? CQuaternion rot; rot.Slerp(startkey.m_Rotation, endkey.m_Rotation, deltatime); rot.ToMatrix(matrices[i]); matrices[i].Translate(trans); } } } /////////////////////////////////////////////////////////////////////////////////////////// // Load: try to load the anim from given file; return a new anim if successful CSkeletonAnimDef* CSkeletonAnimDef::Load(const VfsPath& filename) { CFileUnpacker unpacker; unpacker.Read(filename,"PSSA"); // check version if (unpacker.GetVersion()m_FrameTime,sizeof(anim->m_FrameTime)); anim->m_NumKeys = unpacker.UnpackSize(); anim->m_NumFrames = unpacker.UnpackSize(); anim->m_Keys=new Key[anim->m_NumKeys*anim->m_NumFrames]; unpacker.UnpackRaw(anim->m_Keys,anim->m_NumKeys*anim->m_NumFrames*sizeof(Key)); } catch (PSERROR_File&) { delete anim; throw; } return anim; } /////////////////////////////////////////////////////////////////////////////////////////// // Save: try to save anim to file void CSkeletonAnimDef::Save(const VfsPath& pathname,const CSkeletonAnimDef* anim) { CFilePacker packer(FILE_VERSION, "PSSA"); // pack up all the data packer.PackString(""); packer.PackRaw(&anim->m_FrameTime,sizeof(anim->m_FrameTime)); const size_t numKeys = anim->m_NumKeys; packer.PackSize(numKeys); const size_t numFrames = anim->m_NumFrames; packer.PackSize(numFrames); packer.PackRaw(anim->m_Keys,numKeys*numFrames*sizeof(Key)); // now write it packer.Write(pathname); }