LCOV - code coverage report
Current view: top level - source/graphics - SkeletonAnimDef.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 1 59 1.7 %
Date: 2023-01-19 00:18:29 Functions: 2 7 28.6 %

          Line data    Source code
       1             : /* Copyright (C) 2021 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : /*
      19             :  * Raw description of a skeleton animation
      20             :  */
      21             : 
      22             : #include "precompiled.h"
      23             : 
      24             : #include "SkeletonAnimDef.h"
      25             : #include "maths/MathUtil.h"
      26             : #include "maths/Matrix3D.h"
      27             : #include "ps/CStr.h"
      28             : #include "ps/CLogger.h"
      29             : #include "ps/FileIo.h"
      30             : 
      31             : namespace
      32             : {
      33             : // Start IDs at 1 to leave 0 as a special value.
      34             : u32 g_NextSkeletonDefUID = 1;
      35             : }
      36             : 
      37             : ///////////////////////////////////////////////////////////////////////////////////////////
      38             : // CSkeletonAnimDef constructor
      39           0 : CSkeletonAnimDef::CSkeletonAnimDef() : m_FrameTime(0), m_NumKeys(0), m_NumFrames(0)
      40             : {
      41           0 :     m_UID = g_NextSkeletonDefUID++;
      42             :     // Log a warning if we ever overflow. Should that not result from a bug, bumping to u64 ought to suffice.
      43           0 :     if (g_NextSkeletonDefUID == 0)
      44             :     {
      45             :         // Reset to 1.
      46           0 :         g_NextSkeletonDefUID++;
      47           0 :         LOGWARNING("CSkeletonAnimDef unique ID overflowed to 0 - model-animation bounds may be incorrect.");
      48             :     }
      49           0 : }
      50             : 
      51             : ///////////////////////////////////////////////////////////////////////////////////////////
      52             : // CSkeletonAnimDef destructor
      53           0 : CSkeletonAnimDef::~CSkeletonAnimDef()
      54             : {
      55           0 : }
      56             : 
      57             : ///////////////////////////////////////////////////////////////////////////////////////////
      58             : // BuildBoneMatrices: build matrices for all bones at the given time (in MS) in this
      59             : // animation
      60           0 : void CSkeletonAnimDef::BuildBoneMatrices(float time, CMatrix3D* matrices, bool loop) const
      61             : {
      62           0 :     float fstartframe = time/m_FrameTime;
      63           0 :     size_t startframe = (size_t)(int)(time/m_FrameTime);
      64           0 :     float deltatime = fstartframe-startframe;
      65             : 
      66           0 :     startframe %= m_NumFrames;
      67             : 
      68           0 :     size_t endframe = startframe + 1;
      69           0 :     endframe %= m_NumFrames;
      70             : 
      71           0 :     if (!loop && endframe == 0)
      72             :     {
      73             :         // This might be something like a death animation, and interpolating
      74             :         // between the final frame and the initial frame is wrong, because they're
      75             :         // totally different. So if we've looped around to endframe==0, just display
      76             :         // the animation's final frame with no interpolation.
      77           0 :         for (size_t i = 0; i < m_NumKeys; i++)
      78             :         {
      79           0 :             const Key& key = GetKey(startframe, i);
      80           0 :             matrices[i].SetIdentity();
      81           0 :             matrices[i].Rotate(key.m_Rotation);
      82           0 :             matrices[i].Translate(key.m_Translation);
      83           0 :         }
      84             :     }
      85             :     else
      86             :     {
      87           0 :         for (size_t i = 0; i < m_NumKeys; i++)
      88             :         {
      89           0 :             const Key& startkey = GetKey(startframe, i);
      90           0 :             const Key& endkey = GetKey(endframe, i);
      91             : 
      92           0 :             CVector3D trans = Interpolate(startkey.m_Translation, endkey.m_Translation, deltatime);
      93             :             // TODO: is slerp the best thing to use here?
      94           0 :             CQuaternion rot;
      95           0 :             rot.Slerp(startkey.m_Rotation, endkey.m_Rotation, deltatime);
      96             : 
      97           0 :             rot.ToMatrix(matrices[i]);
      98           0 :             matrices[i].Translate(trans);
      99             :         }
     100             :     }
     101           0 : }
     102             : 
     103             : ///////////////////////////////////////////////////////////////////////////////////////////
     104             : // Load: try to load the anim from given file; return a new anim if successful
     105           0 : std::unique_ptr<CSkeletonAnimDef> CSkeletonAnimDef::Load(const VfsPath& filename)
     106             : {
     107           0 :     CFileUnpacker unpacker;
     108           0 :     unpacker.Read(filename,"PSSA");
     109             : 
     110             :     // check version
     111           0 :     if (unpacker.GetVersion()<FILE_READ_VERSION) {
     112           0 :         throw PSERROR_File_InvalidVersion();
     113             :     }
     114             : 
     115             :     // unpack the data
     116           0 :     auto anim = std::make_unique<CSkeletonAnimDef>();
     117             :     try {
     118           0 :         CStr name; // unused - just here to maintain compatibility with the animation files
     119           0 :         unpacker.UnpackString(name);
     120           0 :         unpacker.UnpackRaw(&anim->m_FrameTime,sizeof(anim->m_FrameTime));
     121           0 :         anim->m_NumKeys = unpacker.UnpackSize();
     122           0 :         anim->m_NumFrames = unpacker.UnpackSize();
     123           0 :         anim->m_Keys.resize(anim->m_NumKeys*anim->m_NumFrames);
     124           0 :         unpacker.UnpackRaw(anim->m_Keys.data(), anim->m_Keys.size() * sizeof(decltype(anim->m_Keys)::value_type));
     125           0 :     } catch (PSERROR_File&) {
     126           0 :         anim.reset();
     127           0 :         throw;
     128             :     }
     129             : 
     130           0 :     return anim;
     131             : }
     132             : 
     133             : ///////////////////////////////////////////////////////////////////////////////////////////
     134             : // Save: try to save anim to file
     135           0 : void CSkeletonAnimDef::Save(const VfsPath& pathname, const CSkeletonAnimDef& anim)
     136             : {
     137           0 :     CFilePacker packer(FILE_VERSION, "PSSA");
     138             : 
     139             :     // pack up all the data
     140           0 :     packer.PackString("");
     141           0 :     packer.PackRaw(&anim.m_FrameTime,sizeof(anim.m_FrameTime));
     142           0 :     const size_t numKeys = anim.m_NumKeys;
     143           0 :     packer.PackSize(numKeys);
     144           0 :     const size_t numFrames = anim.m_NumFrames;
     145           0 :     packer.PackSize(numFrames);
     146           0 :     packer.PackRaw(anim.m_Keys.data(), anim.m_Keys.size() * sizeof(decltype(anim.m_Keys)::value_type));
     147             : 
     148             :     // now write it
     149           0 :     packer.Write(pathname);
     150           3 : }

Generated by: LCOV version 1.13