LCOV - code coverage report
Current view: top level - source/graphics - ModelDef.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 59 236 25.0 %
Date: 2023-01-19 00:18:29 Functions: 6 16 37.5 %

          Line data    Source code
       1             : /* Copyright (C) 2022 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             : #include "precompiled.h"
      19             : 
      20             : #include "ModelDef.h"
      21             : 
      22             : #include "graphics/SkeletonAnimDef.h"
      23             : #include "lib/sysdep/arch/x86_x64/simd.h"
      24             : #include "maths/Vector4D.h"
      25             : #include "ps/FileIo.h"
      26             : 
      27             : #if COMPILER_HAS_SSE
      28             : # include <xmmintrin.h>
      29             : #endif
      30             : 
      31           0 : void CModelDef::GetMaxBounds(CSkeletonAnimDef* anim, bool loop, CBoundingBoxAligned& result)
      32             : {
      33           0 :     const u32 animIndex = anim ? anim->m_UID : 0;
      34             : 
      35           0 :     std::unordered_map<u32, CBoundingBoxAligned>::const_iterator it = m_MaxBoundsPerAnimDef.find(animIndex);
      36           0 :     if (it != m_MaxBoundsPerAnimDef.end())
      37             :     {
      38           0 :         result = it->second;
      39           0 :         return;
      40             :     }
      41             : 
      42           0 :     size_t numverts = GetNumVertices();
      43           0 :     SModelVertex* verts = GetVertices();
      44             : 
      45           0 :     if (!anim)
      46             :     {
      47           0 :         for (size_t i = 0; i < numverts; ++i)
      48           0 :             result += verts[i].m_Coords;
      49           0 :         m_MaxBoundsPerAnimDef[animIndex] = result;
      50           0 :         return;
      51             :     }
      52           0 :     ENSURE(animIndex != 0);
      53           0 :     CMatrix3D* inverseBindBoneMatrix = GetInverseBindBoneMatrices();
      54           0 :     std::vector<CMatrix3D> boneMatrix(anim->GetNumKeys());
      55             : 
      56           0 :     const size_t numFrames = anim->GetNumFrames();
      57           0 :     const float frameTime = anim->GetFrameTime();
      58           0 :     const size_t numBones = GetNumBones();
      59             : 
      60             :     // NB: by using frames, the bounds are technically pessimistic,
      61             :     // since interpolation between frames can put vertices farther.
      62           0 :     for (size_t j = 0; j < numFrames; ++j)
      63             :     {
      64           0 :         anim->BuildBoneMatrices(j * frameTime, boneMatrix.data(), loop);
      65           0 :         for (size_t i = 0; i < numBones; ++i)
      66           0 :             boneMatrix[i] = boneMatrix[i] * inverseBindBoneMatrix[i];
      67           0 :         for (size_t i = 0; i < numverts; ++i)
      68           0 :             result += SkinPoint(verts[i], boneMatrix.data());
      69             :     }
      70           0 :     m_MaxBoundsPerAnimDef[animIndex] = result;
      71             : }
      72             : 
      73           0 : CVector3D CModelDef::SkinPoint(const SModelVertex& vtx,
      74             :                                const CMatrix3D newPoseMatrices[])
      75             : {
      76           0 :     CVector3D result (0, 0, 0);
      77             : 
      78           0 :     for (int i = 0; i < SVertexBlend::SIZE && vtx.m_Blend.m_Bone[i] != 0xff; ++i)
      79             :     {
      80           0 :         result += newPoseMatrices[vtx.m_Blend.m_Bone[i]].Transform(vtx.m_Coords) * vtx.m_Blend.m_Weight[i];
      81             :     }
      82             : 
      83           0 :     return result;
      84             : }
      85             : 
      86           0 : CVector3D CModelDef::SkinNormal(const SModelVertex& vtx,
      87             :                                 const CMatrix3D newPoseMatrices[])
      88             : {
      89             :     // To be correct, the normal vectors apparently need to be multiplied by the
      90             :     // inverse of the transpose. Unfortunately inverses are slow.
      91             :     // If a matrix is orthogonal, M * M^T = I and so the inverse of the transpose
      92             :     // is the original matrix. But that's not entirely relevant here, because
      93             :     // the bone matrices include translation components and so they're not
      94             :     // orthogonal.
      95             :     // But that's okay because we have
      96             :     //   M = T * R
      97             :     // and want to find
      98             :     //   n' = (M^T^-1) * n
      99             :     //      = (T * R)^T^-1 * n
     100             :     //      = (R^T * T^T)^-1 * n
     101             :     //      = (T^T^-1 * R^T^-1) * n
     102             :     // R is indeed orthogonal so R^T^-1 = R. T isn't orthogonal at all.
     103             :     // But n is only a 3-vector, and from the forms of T and R (which have
     104             :     // lots of zeroes) I can convince myself that replacing T with T^T^-1 has no
     105             :     // effect on anything but the fourth component of M^T^-1 - and the fourth
     106             :     // component is discarded since it has no effect on n', and so we can happily
     107             :     // use n' = M*n.
     108             :     //
     109             :     // (This isn't very good as a proof, but it's better than assuming M is
     110             :     // orthogonal when it's clearly not.)
     111             : 
     112           0 :     CVector3D result (0, 0, 0);
     113             : 
     114           0 :     for (int i = 0; i < SVertexBlend::SIZE && vtx.m_Blend.m_Bone[i] != 0xff; ++i)
     115             :     {
     116           0 :         result += newPoseMatrices[vtx.m_Blend.m_Bone[i]].Rotate(vtx.m_Norm) * vtx.m_Blend.m_Weight[i];
     117             :     }
     118             : 
     119             :     // If there was more than one influence, the result is probably not going
     120             :     // to be of unit length (since it's a weighted sum of several independent
     121             :     // unit vectors), so we need to normalise it.
     122             :     // (It's fairly common to only have one influence, so it seems sensible to
     123             :     // optimise that case a bit.)
     124           0 :     if (vtx.m_Blend.m_Bone[1] != 0xff) // if more than one influence
     125           0 :         result.Normalize();
     126             : 
     127           0 :     return result;
     128             : }
     129             : 
     130             : void(*CModelDef::SkinPointsAndNormals)(
     131             :     size_t numVertices,
     132             :     const VertexArrayIterator<CVector3D>& Position,
     133             :     const VertexArrayIterator<CVector3D>& Normal,
     134             :     const SModelVertex* vertices,
     135             :     const size_t* blendIndices,
     136             :     const CMatrix3D newPoseMatrices[]) {};
     137             : 
     138             : 
     139           0 : static void SkinPointsAndNormalsFallback(
     140             :         size_t numVertices,
     141             :         const VertexArrayIterator<CVector3D>& Position,
     142             :         const VertexArrayIterator<CVector3D>& Normal,
     143             :         const SModelVertex* vertices,
     144             :         const size_t* blendIndices,
     145             :         const CMatrix3D newPoseMatrices[])
     146             : {
     147             :     // To avoid some performance overhead, get the raw vertex array pointers
     148           0 :     char* PositionData = Position.GetData();
     149           0 :     size_t PositionStride = Position.GetStride();
     150           0 :     char* NormalData = Normal.GetData();
     151           0 :     size_t NormalStride = Normal.GetStride();
     152             : 
     153           0 :     for (size_t j = 0; j < numVertices; ++j)
     154             :     {
     155           0 :         const SModelVertex& vtx = vertices[j];
     156             : 
     157           0 :         CVector3D pos = newPoseMatrices[blendIndices[j]].Transform(vtx.m_Coords);
     158           0 :         CVector3D norm = newPoseMatrices[blendIndices[j]].Rotate(vtx.m_Norm);
     159             : 
     160             :         // If there was more than one influence, the result is probably not going
     161             :         // to be of unit length (since it's a weighted sum of several independent
     162             :         // unit vectors), so we need to normalise it.
     163             :         // (It's fairly common to only have one influence, so it seems sensible to
     164             :         // optimise that case a bit.)
     165           0 :         if (vtx.m_Blend.m_Bone[1] != 0xff) // if more than one influence
     166           0 :             norm.Normalize();
     167             : 
     168           0 :         memcpy(PositionData + PositionStride*j, &pos.X, 3*sizeof(float));
     169           0 :         memcpy(NormalData + NormalStride*j, &norm.X, 3*sizeof(float));
     170             :     }
     171           0 : }
     172             : 
     173             : #if COMPILER_HAS_SSE
     174           0 : static void SkinPointsAndNormalsSSE(
     175             :         size_t numVertices,
     176             :         const VertexArrayIterator<CVector3D>& Position,
     177             :         const VertexArrayIterator<CVector3D>& Normal,
     178             :         const SModelVertex* vertices,
     179             :         const size_t* blendIndices,
     180             :         const CMatrix3D newPoseMatrices[])
     181             : {
     182             :     // To avoid some performance overhead, get the raw vertex array pointers
     183           0 :     char* PositionData = Position.GetData();
     184           0 :     size_t PositionStride = Position.GetStride();
     185           0 :     char* NormalData = Normal.GetData();
     186           0 :     size_t NormalStride = Normal.GetStride();
     187             : 
     188             :     // Must be aligned correctly for SSE
     189           0 :     ASSERT((intptr_t)newPoseMatrices % 16 == 0);
     190           0 :     ASSERT((intptr_t)PositionData % 16 == 0);
     191           0 :     ASSERT((intptr_t)PositionStride % 16 == 0);
     192           0 :     ASSERT((intptr_t)NormalData % 16 == 0);
     193           0 :     ASSERT((intptr_t)NormalStride % 16 == 0);
     194             : 
     195             :     __m128 col0, col1, col2, col3, vec0, vec1, vec2;
     196             : 
     197           0 :     for (size_t j = 0; j < numVertices; ++j)
     198             :     {
     199           0 :         const SModelVertex& vtx = vertices[j];
     200           0 :         const CMatrix3D& mtx = newPoseMatrices[blendIndices[j]];
     201             : 
     202             :         // Loads matrix to xmm registers.
     203           0 :         const float* data = mtx.AsFloatArray().data();
     204           0 :         col0 = _mm_load_ps(data);
     205           0 :         col1 = _mm_load_ps(data + 4);
     206           0 :         col2 = _mm_load_ps(data + 8);
     207           0 :         col3 = _mm_load_ps(data + 12);
     208             : 
     209             :         // Loads and computes vertex coordinates.
     210           0 :         vec0 = _mm_load1_ps(&vtx.m_Coords.X);   // v0 = [x, x, x, x]
     211           0 :         vec0 = _mm_mul_ps(col0, vec0);          // v0 = [_11*x, _21*x, _31*x, _41*x]
     212           0 :         vec1 = _mm_load1_ps(&vtx.m_Coords.Y);   // v1 = [y, y, y, y]
     213           0 :         vec1 = _mm_mul_ps(col1, vec1);          // v1 = [_12*y, _22*y, _32*y, _42*y]
     214           0 :         vec0 = _mm_add_ps(vec0, vec1);          // v0 = [_11*x + _12*y, ...]
     215           0 :         vec1 = _mm_load1_ps(&vtx.m_Coords.Z);   // v1 = [z, z, z, z]
     216           0 :         vec1 = _mm_mul_ps(col2, vec1);          // v1 = [_13*z, _23*z, _33*z, _43*z]
     217           0 :         vec1 = _mm_add_ps(vec1, col3);          // v1 = [_13*z + _14, ...]
     218           0 :         vec0 = _mm_add_ps(vec0, vec1);          // v0 = [_11*x + _12*y + _13*z + _14, ...]
     219           0 :         _mm_store_ps((float*)(PositionData + PositionStride*j), vec0);
     220             : 
     221             :         // Loads and computes normal vectors.
     222           0 :         vec0 = _mm_load1_ps(&vtx.m_Norm.X);     // v0 = [x, x, x, x]
     223           0 :         vec0 = _mm_mul_ps(col0, vec0);          // v0 = [_11*x, _21*x, _31*x, _41*x]
     224           0 :         vec1 = _mm_load1_ps(&vtx.m_Norm.Y);     // v1 = [y, y, y, y]
     225           0 :         vec1 = _mm_mul_ps(col1, vec1);          // v1 = [_12*y, _22*y, _32*y, _42*y]
     226           0 :         vec0 = _mm_add_ps(vec0, vec1);          // v0 = [_11*x + _12*y, ...]
     227           0 :         vec1 = _mm_load1_ps(&vtx.m_Norm.Z);     // v1 = [z, z, z, z]
     228           0 :         vec1 = _mm_mul_ps(col2, vec1);          // v1 = [_13*z, _23*z, _33*z, _43*z]
     229           0 :         vec0 = _mm_add_ps(vec0, vec1);          // v0 = [_11*x + _12*y + _13*z, ...]
     230             : 
     231             :         // If there was more than one influence, the result is probably not going
     232             :         // to be of unit length (since it's a weighted sum of several independent
     233             :         // unit vectors), so we need to normalise it.
     234             :         // (It's fairly common to only have one influence, so it seems sensible to
     235             :         // optimise that case a bit.)
     236           0 :         if (vtx.m_Blend.m_Bone[1] != 0xff) // if more than one influence
     237             :         {
     238             :             // Normalization.
     239             :             // vec1 = [x*x, y*y, z*z, ?*?]
     240           0 :             vec1 = _mm_mul_ps(vec0, vec0);
     241             :             // vec2 = [y*y, z*z, x*x, ?*?]
     242           0 :             vec2 = _mm_shuffle_ps(vec1, vec1, _MM_SHUFFLE(3, 0, 2, 1));
     243           0 :             vec1 = _mm_add_ps(vec1, vec2);
     244             :             // vec2 = [z*z, x*x, y*y, ?*?]
     245           0 :             vec2 = _mm_shuffle_ps(vec2, vec2, _MM_SHUFFLE(3, 0, 2, 1));
     246           0 :             vec1 = _mm_add_ps(vec1, vec2);
     247             :             // rsqrt(a) = 1 / sqrt(a)
     248           0 :             vec1 = _mm_rsqrt_ps(vec1);
     249           0 :             vec0 = _mm_mul_ps(vec0, vec1);
     250             :         }
     251           0 :         _mm_store_ps((float*)(NormalData + NormalStride*j), vec0);
     252             :     }
     253           0 : }
     254             : #endif
     255             : 
     256           0 : void CModelDef::BlendBoneMatrices(
     257             :         CMatrix3D boneMatrices[])
     258             : {
     259           0 :     for (size_t i = 0; i < m_NumBlends; ++i)
     260             :     {
     261           0 :         const SVertexBlend& blend = m_pBlends[i];
     262           0 :         CMatrix3D& boneMatrix = boneMatrices[m_NumBones + 1 + i];
     263             : 
     264             :         // Note: there is a special case of joint influence, in which the vertex
     265             :         //  is influenced by the bind-shape matrix instead of a particular bone,
     266             :         //  which we indicate by setting the bone ID to the total number of bones.
     267             :         //  It should be blended with the world space transform and we have already
     268             :         //  set up this matrix in boneMatrices.
     269             :         //  (see http://trac.wildfiregames.com/ticket/1012)
     270             : 
     271           0 :         boneMatrix.Blend(boneMatrices[blend.m_Bone[0]], blend.m_Weight[0]);
     272           0 :         for (size_t j = 1; j < SVertexBlend::SIZE && blend.m_Bone[j] != 0xFF; ++j)
     273           0 :             boneMatrix.AddBlend(boneMatrices[blend.m_Bone[j]], blend.m_Weight[j]);
     274             :     }
     275           0 : }
     276             : 
     277             : // CModelDef Constructor
     278           6 : CModelDef::CModelDef() :
     279             :     m_NumVertices(0), m_NumUVsPerVertex(0), m_pVertices(0), m_NumFaces(0), m_pFaces(0),
     280             :     m_NumBones(0), m_Bones(0), m_InverseBindBoneMatrices(NULL),
     281             :     m_NumBlends(0), m_pBlends(0), m_pBlendIndices(0),
     282           6 :     m_Name(L"[not loaded]")
     283             : {
     284           6 : }
     285             : 
     286             : // CModelDef Destructor
     287          12 : CModelDef::~CModelDef()
     288             : {
     289           6 :     for(RenderDataMap::iterator it = m_RenderData.begin(); it != m_RenderData.end(); ++it)
     290           0 :         delete it->second;
     291           6 :     delete[] m_pVertices;
     292           6 :     delete[] m_pFaces;
     293           6 :     delete[] m_Bones;
     294           6 :     delete[] m_InverseBindBoneMatrices;
     295           6 :     delete[] m_pBlends;
     296           6 :     delete[] m_pBlendIndices;
     297           6 : }
     298             : 
     299             : // FindPropPoint: find and return pointer to prop point matching given name;
     300             : // return null if no match (case insensitive search)
     301           0 : const SPropPoint* CModelDef::FindPropPoint(const char* name) const
     302             : {
     303           0 :     for (size_t i = 0; i < m_PropPoints.size(); ++i)
     304           0 :         if (m_PropPoints[i].m_Name == name)
     305           0 :             return &m_PropPoints[i];
     306             : 
     307           0 :     return 0;
     308             : }
     309             : 
     310             : // Load: read and return a new CModelDef initialised with data from given file
     311           6 : CModelDef* CModelDef::Load(const VfsPath& filename, const VfsPath& name)
     312             : {
     313          12 :     CFileUnpacker unpacker;
     314             : 
     315             :     // read everything in from file
     316           6 :     unpacker.Read(filename,"PSMD");
     317             : 
     318             :     // check version
     319           6 :     if (unpacker.GetVersion()<FILE_READ_VERSION) {
     320           0 :         throw PSERROR_File_InvalidVersion();
     321             :     }
     322             : 
     323          12 :     std::unique_ptr<CModelDef> mdef = std::make_unique<CModelDef>();
     324           6 :     mdef->m_Name = name;
     325             : 
     326             :     // now unpack everything
     327           6 :     mdef->m_NumVertices = unpacker.UnpackSize();
     328             : 
     329             :     // versions prior to 4 only support 1 UV set, 4 and later store it here
     330           6 :     if (unpacker.GetVersion() <= 3)
     331             :     {
     332           3 :         mdef->m_NumUVsPerVertex = 1;
     333             :     }
     334             :     else
     335             :     {
     336           3 :         mdef->m_NumUVsPerVertex = unpacker.UnpackSize();
     337             :     }
     338             : 
     339           6 :     mdef->m_pVertices = new SModelVertex[mdef->m_NumVertices];
     340           6 :     mdef->m_UVCoordinates.reserve(mdef->m_NumVertices * mdef->m_NumUVsPerVertex);
     341             : 
     342         752 :     for (size_t i = 0; i < mdef->m_NumVertices; ++i)
     343             :     {
     344         746 :         unpacker.UnpackRaw(&mdef->m_pVertices[i].m_Coords, 12);
     345         746 :         unpacker.UnpackRaw(&mdef->m_pVertices[i].m_Norm, 12);
     346             : 
     347        1492 :         for (size_t s = 0; s < mdef->m_NumUVsPerVertex; ++s)
     348             :         {
     349             :             float uv[2];
     350         746 :             unpacker.UnpackRaw(&uv[0], 8);
     351         746 :             mdef->m_UVCoordinates.emplace_back(uv[0], uv[1]);
     352             :         }
     353             : 
     354         746 :         unpacker.UnpackRaw(&mdef->m_pVertices[i].m_Blend, sizeof(SVertexBlend));
     355             :     }
     356             : 
     357           6 :     mdef->m_NumFaces = unpacker.UnpackSize();
     358           6 :     mdef->m_pFaces=new SModelFace[mdef->m_NumFaces];
     359           6 :     unpacker.UnpackRaw(mdef->m_pFaces,sizeof(SModelFace)*mdef->m_NumFaces);
     360             : 
     361           6 :     mdef->m_NumBones = unpacker.UnpackSize();
     362           6 :     if (mdef->m_NumBones)
     363             :     {
     364           0 :         mdef->m_Bones=new CBoneState[mdef->m_NumBones];
     365           0 :         unpacker.UnpackRaw(mdef->m_Bones,mdef->m_NumBones*sizeof(CBoneState));
     366             : 
     367           0 :         mdef->m_pBlendIndices = new size_t[mdef->m_NumVertices];
     368           0 :         std::vector<SVertexBlend> blends;
     369           0 :         for (size_t i = 0; i < mdef->m_NumVertices; i++)
     370             :         {
     371           0 :             const SVertexBlend &blend = mdef->m_pVertices[i].m_Blend;
     372           0 :             if (blend.m_Bone[1] == 0xFF)
     373             :             {
     374           0 :                 mdef->m_pBlendIndices[i] = blend.m_Bone[0];
     375             :             }
     376             :             else
     377             :             {
     378             :                 // If there's already a vertex using the same blend as this, then
     379             :                 // reuse its entry from blends; otherwise add the new one to blends
     380             :                 size_t j;
     381           0 :                 for (j = 0; j < blends.size(); j++)
     382             :                 {
     383           0 :                     if (blend == blends[j]) break;
     384             :                 }
     385           0 :                 if (j >= blends.size())
     386           0 :                     blends.push_back(blend);
     387             :                 // This index is offset by one to allow the special case of a
     388             :                 //  weighted influence relative to the bind-shape rather than
     389             :                 //  a particular bone. See comment in BlendBoneMatrices.
     390           0 :                 mdef->m_pBlendIndices[i] = mdef->m_NumBones + 1 + j;
     391             :             }
     392             :         }
     393             : 
     394           0 :         mdef->m_NumBlends = blends.size();
     395           0 :         mdef->m_pBlends = new SVertexBlend[mdef->m_NumBlends];
     396           0 :         std::copy(blends.begin(), blends.end(), mdef->m_pBlends);
     397             :     }
     398             : 
     399           6 :     if (unpacker.GetVersion() >= 2)
     400             :     {
     401             :         // versions >=2 also have prop point data
     402           6 :         size_t numPropPoints = unpacker.UnpackSize();
     403           6 :         mdef->m_PropPoints.resize(numPropPoints);
     404           6 :         if (numPropPoints)
     405             :         {
     406           6 :             for (size_t i = 0; i < numPropPoints; i++)
     407             :             {
     408           3 :                 unpacker.UnpackString(mdef->m_PropPoints[i].m_Name);
     409           3 :                 unpacker.UnpackRaw(&mdef->m_PropPoints[i].m_Position.X, sizeof(mdef->m_PropPoints[i].m_Position));
     410           3 :                 unpacker.UnpackRaw(&mdef->m_PropPoints[i].m_Rotation.m_V.X, sizeof(mdef->m_PropPoints[i].m_Rotation));
     411           3 :                 unpacker.UnpackRaw(&mdef->m_PropPoints[i].m_BoneIndex, sizeof(mdef->m_PropPoints[i].m_BoneIndex));
     412             : 
     413             :                 // build prop point transform
     414           3 :                 mdef->m_PropPoints[i].m_Transform.SetIdentity();
     415           3 :                 mdef->m_PropPoints[i].m_Transform.Rotate(mdef->m_PropPoints[i].m_Rotation);
     416           3 :                 mdef->m_PropPoints[i].m_Transform.Translate(mdef->m_PropPoints[i].m_Position);
     417             :             }
     418             :         }
     419             :     }
     420             : 
     421           6 :     if (unpacker.GetVersion() <= 2)
     422             :     {
     423             :         // Versions <=2 don't include the default 'root' prop point, so add it here
     424             : 
     425           0 :         SPropPoint prop;
     426           0 :         prop.m_Name = "root";
     427           0 :         prop.m_Transform.SetIdentity();
     428           0 :         prop.m_BoneIndex = 0xFF;
     429             : 
     430           0 :         mdef->m_PropPoints.push_back(prop);
     431             :     }
     432             : 
     433           6 :     if (unpacker.GetVersion() <= 2)
     434             :     {
     435             :         // Versions <=2 store the vertexes relative to the bind pose. That
     436             :         // isn't useful when you want to do correct skinning, so later versions
     437             :         // store them in world space. So, fix the old models by skinning each
     438             :         // vertex:
     439             : 
     440           0 :         if (mdef->m_NumBones) // only do skinned models
     441             :         {
     442           0 :             std::vector<CMatrix3D> bindPose (mdef->m_NumBones);
     443             : 
     444           0 :             for (size_t i = 0; i < mdef->m_NumBones; ++i)
     445             :             {
     446           0 :                 bindPose[i].SetIdentity();
     447           0 :                 bindPose[i].Rotate(mdef->m_Bones[i].m_Rotation);
     448           0 :                 bindPose[i].Translate(mdef->m_Bones[i].m_Translation);
     449             :             }
     450             : 
     451           0 :             for (size_t i = 0; i < mdef->m_NumVertices; ++i)
     452             :             {
     453           0 :                 mdef->m_pVertices[i].m_Coords = SkinPoint(mdef->m_pVertices[i], &bindPose[0]);
     454           0 :                 mdef->m_pVertices[i].m_Norm = SkinNormal(mdef->m_pVertices[i], &bindPose[0]);
     455             :             }
     456             :         }
     457             :     }
     458             : 
     459             :     // Compute the inverse bind-pose matrices, needed by the skinning code
     460           6 :     mdef->m_InverseBindBoneMatrices = new CMatrix3D[mdef->m_NumBones];
     461           6 :     CBoneState* defpose = mdef->GetBones();
     462           6 :     for (size_t i = 0; i < mdef->m_NumBones; ++i)
     463             :     {
     464           0 :         mdef->m_InverseBindBoneMatrices[i].SetIdentity();
     465           0 :         mdef->m_InverseBindBoneMatrices[i].Translate(-defpose[i].m_Translation);
     466           0 :         mdef->m_InverseBindBoneMatrices[i].Rotate(defpose[i].m_Rotation.GetInverse());
     467             :     }
     468             : 
     469          12 :     return mdef.release();
     470             : }
     471             : 
     472             : // Save: write the given CModelDef to the given file
     473           0 : void CModelDef::Save(const VfsPath& filename, const CModelDef* mdef)
     474             : {
     475           0 :     CFilePacker packer(FILE_VERSION, "PSMD");
     476             : 
     477             :     // pack everything up
     478           0 :     const size_t numVertices = mdef->GetNumVertices();
     479           0 :     packer.PackSize(numVertices);
     480           0 :     packer.PackRaw(mdef->GetVertices(), sizeof(SModelVertex) * numVertices);
     481             : 
     482           0 :     const size_t numFaces = mdef->GetNumFaces();
     483           0 :     packer.PackSize(numFaces);
     484           0 :     packer.PackRaw(mdef->GetFaces(), sizeof(SModelFace) * numFaces);
     485             : 
     486           0 :     const size_t numBones = mdef->m_NumBones;
     487           0 :     packer.PackSize(numBones);
     488           0 :     if (numBones)
     489           0 :         packer.PackRaw(mdef->m_Bones, sizeof(CBoneState) * numBones);
     490             : 
     491           0 :     const size_t numPropPoints = mdef->m_PropPoints.size();
     492           0 :     packer.PackSize(numPropPoints);
     493           0 :     for (size_t i = 0; i < numPropPoints; i++)
     494             :     {
     495           0 :         packer.PackString(mdef->m_PropPoints[i].m_Name);
     496           0 :         packer.PackRaw(&mdef->m_PropPoints[i].m_Position.X, sizeof(mdef->m_PropPoints[i].m_Position));
     497           0 :         packer.PackRaw(&mdef->m_PropPoints[i].m_Rotation.m_V.X, sizeof(mdef->m_PropPoints[i].m_Rotation));
     498           0 :         packer.PackRaw(&mdef->m_PropPoints[i].m_BoneIndex, sizeof(mdef->m_PropPoints[i].m_BoneIndex));
     499             :     }
     500             : 
     501             :     // flush everything out to file
     502           0 :     packer.Write(filename);
     503           0 : }
     504             : 
     505             : // SetRenderData: Set the render data object for the given key,
     506           0 : void CModelDef::SetRenderData(const void* key, CModelDefRPrivate* data)
     507             : {
     508           0 :     delete m_RenderData[key];
     509           0 :     m_RenderData[key] = data;
     510           0 : }
     511             : 
     512             : // GetRenderData: Get the render data object for the given key,
     513             : // or 0 if no such object exists.
     514             : // Reference count of the render data object is automatically increased.
     515           0 : CModelDefRPrivate* CModelDef::GetRenderData(const void* key) const
     516             : {
     517           0 :     RenderDataMap::const_iterator it = m_RenderData.find(key);
     518             : 
     519           0 :     if (it != m_RenderData.end())
     520           0 :         return it->second;
     521             : 
     522           0 :     return 0;
     523             : }
     524             : 
     525           6 : void ModelDefActivateFastImpl()
     526             : {
     527             : #if COMPILER_HAS_SSE
     528           6 :     if (HostHasSSE())
     529             :     {
     530           6 :         CModelDef::SkinPointsAndNormals = SkinPointsAndNormalsSSE;
     531           6 :         return;
     532             :     }
     533             : #endif
     534           0 :     CModelDef::SkinPointsAndNormals = SkinPointsAndNormalsFallback;
     535           3 : }

Generated by: LCOV version 1.13