1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
6 #include <Cry3DEngine/I3DEngine.h>
7 #include <CryAnimation/ICryAnimation.h>
11 #include "FacialAnimation/FaceAnimation.h"
12 #include "FacialAnimation/FacialModel.h"
13 #include "FacialAnimation/FaceEffectorLibrary.h"
14 #include "AnimEventLoader.h"
15 #include "CharacterManager.h"
16 #include <CryCore/Platform/IPlatformOS.h>
18 namespace CryCHRLoader_LoadNewCHR_Helpers
21 static bool FindFirstMesh(CMesh
*& pMesh
, CNodeCGF
*& pGFXNode
, CContentCGF
* pContent
, const char* filenameNoExt
, int lod
)
23 uint32 numNodes
= pContent
->GetNodeCount();
25 for (uint32 n
= 0; n
< numNodes
; n
++)
27 CNodeCGF
* pNode
= pContent
->GetNode(n
);
28 if (pNode
->type
== CNodeCGF::NODE_MESH
&& pNode
->pMesh
)
36 g_pISystem
->Warning(VALIDATOR_MODULE_ANIMATION
, VALIDATOR_WARNING
, VALIDATOR_FLAG_FILE
, filenameNoExt
, "Failed to Load Character file. GFXNode not found");
40 pMesh
= pGFXNode
->pMesh
;
41 if (pMesh
&& pMesh
->m_pBoneMapping
== 0)
43 g_pISystem
->Warning(VALIDATOR_MODULE_ANIMATION
, VALIDATOR_WARNING
, VALIDATOR_FLAG_FILE
, filenameNoExt
, "Failed to Load Character file. Skeleton-Initial-Positions are missing");
50 } // namespace CryCHRLoader_LoadNewCHR_Helpers
52 bool CryCHRLoader::BeginLoadCHRRenderMesh(CDefaultSkeleton
* pSkel
, const DynArray
<CCharInstance
*>& pCharInstances
, EStreamTaskPriority estp
)
54 const char* szFilePath
= pSkel
->GetModelFilePath();
56 LOADING_TIME_PROFILE_SECTION(g_pISystem
);
58 static_assert(sizeof(TFace
) == 6, "Invalid type size!");
60 MEMSTAT_CONTEXT_FMT(EMemStatContextTypes::MSC_CHR
, 0, "LoadCharacter %s", szFilePath
);
62 CRY_DEFINE_ASSET_SCOPE(CRY_SKEL_FILE_EXT
, szFilePath
);
64 const char* szExt
= PathUtil::GetExt(szFilePath
);
65 m_strGeomFileNameNoExt
.assign(szFilePath
, *szExt
? szExt
- 1 : szExt
);
67 if (m_strGeomFileNameNoExt
.empty())
69 g_pISystem
->Warning(VALIDATOR_MODULE_ANIMATION
, VALIDATOR_WARNING
, VALIDATOR_FLAG_FILE
, szFilePath
, "Wrong character filename");
73 //--------------------------------------------------------------------------------------------
75 CModelMesh
* pModelMesh
= pSkel
->GetModelMesh();
78 const stack_string filename
= stack_string(m_strGeomFileNameNoExt
.c_str()) + "." + szExt
;
79 const stack_string lodName
= (pModelMesh
->m_stream
.bHasMeshFile
) ? (filename
+ "m") : (filename
);
82 m_RefByInstances
= pCharInstances
;
84 StreamReadParams params
;
85 params
.nFlags
= 0;//IStreamEngine::FLAGS_NO_SYNC_CALLBACK;
86 params
.dwUserData
= 0;
87 params
.ePriority
= estp
;
88 IStreamEngine
* pStreamEngine
= gEnv
->pSystem
->GetStreamEngine();
89 m_pStream
= pStreamEngine
->StartRead(eStreamTaskTypeAnimation
, lodName
.c_str(), this, ¶ms
);
91 return m_pStream
!= NULL
;
94 void CryCHRLoader::AbortLoad()
100 void CryCHRLoader::StreamAsyncOnComplete(IReadStream
* pStream
, unsigned nError
)
106 EndStreamSkel(pStream
);
108 else if (m_pModelSkin
)
110 EndStreamSkinAsync(pStream
);
114 pStream
->FreeTemporaryMemory();
117 void CryCHRLoader::EndStreamSkel(IReadStream
* pStream
)
119 using namespace CryCHRLoader_LoadNewCHR_Helpers
;
121 const char* lodName
= pStream
->GetName();
123 SmartContentCGF pCGF
= g_pI3DEngine
->CreateChunkfileContent(lodName
);
124 bool bLoaded
= g_pI3DEngine
->LoadChunkFileContentFromMem(pCGF
, pStream
->GetBuffer(), pStream
->GetBytesRead(), IStatObj::ELoadingFlagsJustGeometry
, false, false);
126 if (!bLoaded
|| !pCGF
)
128 g_pISystem
->Warning(VALIDATOR_MODULE_ANIMATION
, VALIDATOR_WARNING
, VALIDATOR_FLAG_FILE
, lodName
, "%s: The Chunk-Loader failed to load the file.", __FUNCTION__
);
132 CContentCGF
* pLodContent
= pCGF
;
134 CNodeCGF
* pMeshNode
= 0;
136 if (!FindFirstMesh(pMesh
, pMeshNode
, pLodContent
, m_strGeomFileNameNoExt
.c_str(), 0))
139 CModelMesh
* pModelMesh
= m_pModelSkel
->GetModelMesh();
142 m_pNewRenderMesh
= pModelMesh
->InitRenderMeshAsync(pMesh
, m_pModelSkel
->GetModelFilePath(), 0, m_arrNewRenderChunks
);
145 void CryCHRLoader::StreamOnComplete(IReadStream
* pStream
, unsigned nError
)
149 CModelMesh
* pModelMesh
= m_pModelSkel
->GetModelMesh();
152 pModelMesh
->InitRenderMeshSync(m_arrNewRenderChunks
, m_pNewRenderMesh
);
153 m_pNewRenderMesh
= nullptr;
154 m_arrNewRenderChunks
.clear();
156 else if (m_pModelSkin
)
158 EndStreamSkinSync(pStream
);
160 int nRenderLod
= (int)pStream
->GetParams().dwUserData
;
166 // cleans up the resources allocated during load
167 void CryCHRLoader::ClearModel()
169 m_strGeomFileNameNoExt
= "";
171 m_arrNewRenderChunks
.clear();
172 m_pNewRenderMesh
= nullptr;
173 m_RefByInstances
.clear();
176 //----------------------------------------------------------------------------------
177 //----------------------------------------------------------------------------------
178 //----------------------------------------------------------------------------------
179 //---- this belongs into another file (i.e.CDefaultSkeleton) -------------------
180 //----------------------------------------------------------------------------------
181 //----------------------------------------------------------------------------------
182 //----------------------------------------------------------------------------------
183 namespace SkelLoader_Helpers
188 CContentCGF
* m_pContentCGF
;
189 CContentCGF
* m_pContentMeshCGF
;
194 m_pContentMeshCGF
= 0;
200 g_pI3DEngine
->ReleaseChunkfileContent(m_pContentCGF
), m_pContentCGF
= 0;
201 if (m_pContentMeshCGF
)
202 g_pI3DEngine
->ReleaseChunkfileContent(m_pContentMeshCGF
), m_pContentMeshCGF
= 0;
206 static bool InitializeBones(CDefaultSkeleton
* pDefaultSkeleton
, CSkinningInfo
* pSkinningInfo
, const char* szFilePath
)
209 uint32 numBones
= pSkinningInfo
->m_arrBonesDesc
.size();
211 if (numBones
>= MAX_JOINT_AMOUNT
)
213 g_pISystem
->Warning(VALIDATOR_MODULE_ANIMATION
, VALIDATOR_WARNING
, VALIDATOR_FLAG_FILE
, szFilePath
, "Too many Joints in model. Current Limit is: %d", MAX_JOINT_AMOUNT
);
219 g_pISystem
->Warning(VALIDATOR_MODULE_ANIMATION
, VALIDATOR_WARNING
, VALIDATOR_FLAG_FILE
, szFilePath
, "Model has no Joints.");
223 pDefaultSkeleton
->m_poseDefaultData
.Initialize(numBones
);
224 pDefaultSkeleton
->m_arrModelJoints
.resize(numBones
);
226 for (uint32 nBone
= 0; nBone
< numBones
; ++nBone
)
228 const CryBoneDescData
& boneDesc
= pSkinningInfo
->m_arrBonesDesc
[nBone
];
229 assert(boneDesc
.m_DefaultB2W
.IsOrthonormalRH());
230 if (!boneDesc
.m_DefaultB2W
.IsOrthonormalRH())
232 g_pISystem
->Warning(VALIDATOR_MODULE_ANIMATION
, VALIDATOR_WARNING
, VALIDATOR_FLAG_FILE
, szFilePath
, "Bone %d: B2W is not orthonormal RH in lod %d", nBone
, lod
);
236 CDefaultSkeleton::SJoint
& joint
= pDefaultSkeleton
->m_arrModelJoints
[nBone
];
237 joint
.m_idxParent
= -1;
238 int32 offset
= boneDesc
.m_nOffsetParent
;
240 joint
.m_idxParent
= int32(nBone
+ offset
);
242 joint
.m_strJointName
= &boneDesc
.m_arrBoneName
[0];
243 joint
.m_nJointCRC32Lower
= CCrc32::ComputeLowercase(&boneDesc
.m_arrBoneName
[0]);
244 joint
.m_nJointCRC32
= boneDesc
.m_nControllerID
;
245 joint
.m_PhysInfo
= boneDesc
.m_PhysInfo
[0];
246 joint
.m_fMass
= boneDesc
.m_fMass
;
248 pDefaultSkeleton
->m_poseDefaultData
.GetJointsAbsolute()[nBone
] = QuatT(boneDesc
.m_DefaultB2W
);
249 pDefaultSkeleton
->m_poseDefaultData
.GetJointsAbsolute()[nBone
].q
.Normalize();
250 pDefaultSkeleton
->m_poseDefaultData
.GetJointsRelative()[nBone
] = pDefaultSkeleton
->m_poseDefaultData
.GetJointsAbsolute()[nBone
];
251 if (joint
.m_idxParent
>= 0)
252 pDefaultSkeleton
->m_poseDefaultData
.GetJointsRelative()[nBone
] = pDefaultSkeleton
->m_poseDefaultData
.GetJointsAbsolute()[joint
.m_idxParent
].GetInverted() * pDefaultSkeleton
->m_poseDefaultData
.GetJointsAbsolute()[nBone
];
253 pDefaultSkeleton
->m_poseDefaultData
.GetJointsRelative()[nBone
].q
.Normalize();
256 uint32 nRootCounter
= 0;
257 for (uint32 j
= 0; j
< numBones
; j
++)
259 int32 idxParent
= pDefaultSkeleton
->m_arrModelJoints
[j
].m_idxParent
;
261 nRootCounter
++; //count the root joints
263 if (nRootCounter
!= 1)
265 //something went wrong. this model has multiple roots
266 for (uint32 j
= 0; j
< numBones
; j
++)
267 pDefaultSkeleton
->m_arrModelJoints
[j
].m_PhysInfo
.pPhysGeom
= 0; //delete all "Chunk-IDs" to prevent the FatalError in the destructor.
268 g_pISystem
->Warning(VALIDATOR_MODULE_ANIMATION
, VALIDATOR_WARNING
, VALIDATOR_FLAG_FILE
, szFilePath
, "CryAnimation: multiple root in skeleton. Please fix the model.");
272 const char* RootName
= pDefaultSkeleton
->m_arrModelJoints
[0].m_strJointName
.c_str();
273 if (RootName
[0] == 'B' && RootName
[1] == 'i' && RootName
[2] == 'p' && RootName
[3] == '0' && RootName
[4] == '1')
275 //This character-model is a biped and it was made in CharacterStudio.
276 //CharacterStudio is not allowing us to project the Bip01 on the ground and change its orientation; thats why we have to do it here.
277 pDefaultSkeleton
->m_poseDefaultData
.GetJointsAbsolute()[0].SetIdentity();
278 pDefaultSkeleton
->m_poseDefaultData
.GetJointsRelative()[0].SetIdentity();
279 uint32 numJoints
= pDefaultSkeleton
->m_arrModelJoints
.size();
280 for (uint32 bone
= 1; bone
< numJoints
; bone
++)
282 //adjust the pelvis (and all other joints directly linked Bip01)
283 int32 idxParent
= pDefaultSkeleton
->m_arrModelJoints
[bone
].m_idxParent
;
285 pDefaultSkeleton
->m_poseDefaultData
.GetJointsRelative()[bone
] = pDefaultSkeleton
->m_poseDefaultData
.GetJointsAbsolute()[bone
];
289 QuatT orientation
= pDefaultSkeleton
->m_poseDefaultData
.GetJointsAbsolute()[0];
290 uint32 IsIdentiy
= Quat::IsEquivalent(Quat(IDENTITY
), orientation
.q
, 0.14f
); // 0.14 radians == ~8.0 degrees
293 g_pISystem
->Warning(VALIDATOR_MODULE_ANIMATION
, VALIDATOR_WARNING
, VALIDATOR_FLAG_FILE
, szFilePath
, "CryAnimation: Default-Skeleton has wrong orientation. Please use the CryEngine conventions when building a model");
294 //CRY_ASSERT_MESSAGE(!"Inverted model orientation!", strGeomFileName);
301 static const char* FindFirstMesh(CMesh
*& pMesh
, CNodeCGF
*& pGFXNode
, CContentCGF
* pContent
)
303 uint32 numNodes
= pContent
->GetNodeCount();
305 for (uint32 n
= 0; n
< numNodes
; n
++)
307 CNodeCGF
* pNode
= pContent
->GetNode(n
);
308 if (pNode
->type
== CNodeCGF::NODE_MESH
&& pNode
->pMesh
)
316 return "Failed to Load Character file. GFXNode not found";
319 pMesh
= pGFXNode
->pMesh
;
320 if (pMesh
&& pMesh
->m_pBoneMapping
== 0)
322 return "Failed to Load Character file. Skeleton-Initial-Positions are missing";
328 static const char* FindFirstMeshAndMaterial(CMesh
*& pMesh
, CNodeCGF
*& pGFXNode
, _smart_ptr
<IMaterial
>& pMaterial
, CContentCGF
* pContent
, const char* filenameNoExt
)
331 for (int i
= 0, limit
= pContent
->GetNodeCount(); i
< limit
; ++i
)
333 CNodeCGF
* pNode
= pContent
->GetNode(i
);
334 if (pNode
->type
== CNodeCGF::NODE_MESH
)
342 return "Failed to Load Character file. GFXNode not found";
345 pMesh
= pGFXNode
->pMesh
;
346 if (pMesh
&& !pMesh
->m_pBoneMapping
)
348 return "Failed to Load Character file. Skeleton-Initial-Positions are missing";
353 if (pGFXNode
->pMaterial
)
354 pMaterial
= g_pI3DEngine
->GetMaterialManager()->LoadCGFMaterial(pGFXNode
->pMaterial
->name
, PathUtil::GetPathWithoutFilename(filenameNoExt
).c_str());
356 pMaterial
= g_pI3DEngine
->GetMaterialManager()->GetDefaultMaterial();
361 static const char* FindFirstMaterial(_smart_ptr
<IMaterial
>& pMaterial
, CContentCGF
* pContent
, const char* szFilenameNoExt
)
363 if (!pContent
->GetMaterialCount())
365 return "Failed to Load Character file. No material found for physicalization.";
368 pMaterial
= g_pI3DEngine
->GetMaterialManager()->LoadCGFMaterial(pContent
->GetMaterial(0)->name
, PathUtil::GetPathWithoutFilename(szFilenameNoExt
).c_str());
373 } // namespace SkelLoader_Helpers
375 bool CDefaultSkeleton::LoadNewSKEL(const char* szFilePath
, uint32 nLoadingFlags
)
377 using namespace SkelLoader_Helpers
;
379 LOADING_TIME_PROFILE_SECTION_ARGS(szFilePath
);
381 static_assert(sizeof(TFace
) == 6, "Invalid type size!");
383 MEMSTAT_CONTEXT_FMT(EMemStatContextTypes::MSC_CHR
, 0, "LoadCharacter %s", szFilePath
);
385 CRY_DEFINE_ASSET_SCOPE(CRY_SKEL_FILE_EXT
, szFilePath
);
387 const char* szExt
= PathUtil::GetExt(szFilePath
);
388 stack_string strGeomFileNameNoExt
;
389 strGeomFileNameNoExt
.assign(szFilePath
, *szExt
? szExt
- 1 : szExt
);
390 if (strGeomFileNameNoExt
.empty())
392 g_pISystem
->Warning(VALIDATOR_MODULE_ANIMATION
, VALIDATOR_WARNING
, VALIDATOR_FLAG_FILE
, szFilePath
, "Wrong character filename");
396 //--------------------------------------------------------------------------------------------
399 uint32 isSKEL
= stricmp(szExt
, CRY_SKEL_FILE_EXT
) == 0;
402 string strFilePathLOD1
= strGeomFileNameNoExt
+ "_lod1" + "." + szExt
;
403 bool exist
= g_pISystem
->GetIPak()->IsFileExist(strFilePathLOD1
.c_str());
405 g_pISystem
->Warning(VALIDATOR_MODULE_ANIMATION
, VALIDATOR_WARNING
, VALIDATOR_FLAG_FILE
, 0, "!CryAnimation: LODs in CHRs are not supported any more. Please remove them from the build: %s", strFilePathLOD1
.c_str());
410 //--------------------------------------------------------------------------------------------
412 LevelOfDetail cgfs
; //in case of early exit we call the destructor automatically and delete all CContentCGFs
413 cgfs
.m_pContentCGF
= g_pI3DEngine
->CreateChunkfileContent(szFilePath
);
414 if (cgfs
.m_pContentCGF
== 0)
415 CryFatalError("CryAnimation error: issue in Chunk-Loader");
416 bool bLoaded
= g_pI3DEngine
->LoadChunkFileContent(cgfs
.m_pContentCGF
, szFilePath
, 0);
419 g_pISystem
->Warning(VALIDATOR_MODULE_ANIMATION
, VALIDATOR_WARNING
, VALIDATOR_FLAG_FILE
, szFilePath
, "CryAnimation: The Chunk-Loader failed to load the file.");
423 if (!Console::GetInst().ca_StreamCHR
)
425 string lodmName
= string(szFilePath
) + "m";
426 bool bHasMeshFile
= gEnv
->pCryPak
->IsFileExist(lodmName
.c_str());
429 cgfs
.m_pContentMeshCGF
= g_pI3DEngine
->CreateChunkfileContent(lodmName
);
430 g_pI3DEngine
->LoadChunkFileContent(cgfs
.m_pContentMeshCGF
, lodmName
.c_str());
434 //----------------------------------------------------------------------------------------------------------------------
435 //--- initialize the ModelSkel
436 //----------------------------------------------------------------------------------------------------------------------
437 CSkinningInfo
* pSkinningInfo
= cgfs
.m_pContentCGF
->GetSkinningInfo();
438 if (pSkinningInfo
== 0)
440 g_pISystem
->Warning(VALIDATOR_MODULE_ANIMATION
, VALIDATOR_WARNING
, VALIDATOR_FLAG_FILE
, szFilePath
, "CryAnimation: Skinning info is missing in lod %d", 0);
444 //--------------------------------------------------------------------------
445 //---- initialize the default animation skeleton
446 //--------------------------------------------------------------------------
447 const uint32 isSkeletonValid
= InitializeBones(this, pSkinningInfo
, szFilePath
);
449 CMesh
* pMesh
= nullptr;
450 CNodeCGF
* pMeshNode
= nullptr;
451 _smart_ptr
<IMaterial
> pMaterial
= nullptr;
452 FindFirstMeshAndMaterial(pMesh
, pMeshNode
, pMaterial
, cgfs
.m_pContentCGF
, strGeomFileNameNoExt
.c_str());
456 const char* const szError
= FindFirstMaterial(pMaterial
, cgfs
.m_pContentCGF
, strGeomFileNameNoExt
.c_str());
459 g_pISystem
->Warning(VALIDATOR_MODULE_ANIMATION
, VALIDATOR_WARNING
, VALIDATOR_FLAG_FILE
, 0, "!CryAnimation: Error while loading material: %s", szError
);
463 //------------------------------------------------------------------------------------
464 //--- initialize Physical Proxies
465 //------------------------------------------------------------------------------------
468 uint32 numJoints
= m_arrModelJoints
.size();
469 m_arrBackupPhysInfo
.resize(numJoints
);
470 for (uint32 j
= 0; j
< numJoints
; j
++)
471 m_arrBackupPhysInfo
[j
] = m_arrModelJoints
[j
].m_PhysInfo
;
472 m_arrBackupPhyBoneMeshes
= pSkinningInfo
->m_arrPhyBoneMeshes
;
473 m_arrBackupBoneEntities
= pSkinningInfo
->m_arrBoneEntities
;
474 if (!SetupPhysicalProxies(m_arrBackupPhyBoneMeshes
, m_arrBackupBoneEntities
, pMaterial
, szFilePath
))
477 if (isSkeletonValid
== 0)
480 //------------------------------------------------------------------------------------
486 //----------------------------------------------------------------------------------------------------------------------------------
487 //--- initialize ModelMesh MorphTargets and RenderMesh
488 //--- There can be only one Render LOD in the Base-Model (Even this is optional. Usually the Base-Model has an empty skeleton)
489 //----------------------------------------------------------------------------------------------------------------------------------
491 if (cgfs
.m_pContentMeshCGF
)
493 const auto szError
= FindFirstMesh(pMesh
, pMeshNode
, cgfs
.m_pContentMeshCGF
);
496 g_pISystem
->Warning(VALIDATOR_MODULE_ANIMATION
, VALIDATOR_WARNING
, VALIDATOR_FLAG_FILE
, strGeomFileNameNoExt
.c_str(), szError
);
503 m_ModelMeshEnabled
= true;
505 CModelMesh
* pModelMesh
= GetModelMesh();
508 uint32 success
= pModelMesh
->InitMesh(pMesh
, pMeshNode
, pMaterial
, pSkinningInfo
, m_strFilePath
.c_str(), 0);
512 string meshFilename
= string(szFilePath
) + 'm';
513 pModelMesh
->m_stream
.bHasMeshFile
= gEnv
->pCryPak
->IsFileExist(meshFilename
.c_str());
517 //---------------------------------------------------------------------------------------------------------------
519 InitializeHardcodedJointsProperty();
520 RebuildJointLookupCaches();
521 stack_string paramFileName
= strGeomFileNameNoExt
+ "." + CRY_CHARACTER_PARAM_FILE_EXT
;
522 uint32 isPrevMode
= nLoadingFlags
& CA_PreviewMode
;
524 LoadCHRPARAMS(paramFileName
);
526 m_animListIDs
.clear();
530 void CDefaultSkeleton::LoadCHRPARAMS(const char* paramFileName
)
532 CParamLoader
& paramLoader
= g_pCharacterManager
->GetParamLoader();
533 #ifdef EDITOR_PCDEBUGCODE
534 bool hasInjectedParams
= paramLoader
.HasInjectedCHRPARAMS(paramFileName
);
536 bool hasInjectedParams
= false;
538 // If the new .params file exists, load it since it can be done much faster and the file is cleaner (all XML)
539 if (hasInjectedParams
|| g_pIPak
->IsFileExist(paramFileName
))
541 // this will be refilled by LoadXML
542 m_animListIDs
.clear();
544 bool ok
= paramLoader
.LoadXML(this, GetDefaultAnimDir(), paramFileName
, m_animListIDs
);
546 LoadAnimations(paramLoader
);
550 //------------------------------------------------------------------------------------------------------------
551 // loads animations for a model by composing a complete animation list and loading it into an AnimationSet
552 //------------------------------------------------------------------------------------------------------------
553 bool CDefaultSkeleton::LoadAnimations(CParamLoader
& paramLoader
)
555 //LOADING_TIME_PROFILE_SECTION(g_pISystem);
557 // the number of animations loaded
558 uint32 numAnimAssets
= 0;
562 CRY_PROFILE_FUNCTION(PROFILE_ANIMATION
);
564 if (m_animListIDs
.size() == 0)
569 // attributes of the compound list
570 // all those attributes have to be stored on a per list basis,
571 // keeping it for the topmost list in memory is not enough
572 // since another list might use it as a dependency which does not
574 DynArray
<string
> modelTracksDatabases
;
575 DynArray
<string
> lockedDatabases
;
576 string animEventDatabase
;
579 CAnimationSet::FacialAnimationSet::container_type facialAnimations
;
581 const int32 nListIDs
= m_animListIDs
.size();
582 for (int32 i
= nListIDs
- 1; i
>= 0; --i
) // by walking backwards the 'parent' lists come first
584 const uint32 animListID
= m_animListIDs
[i
];
585 if (animListID
< paramLoader
.GetParsedListNumber())
587 const SAnimListInfo
& animList
= paramLoader
.GetParsedList(animListID
);
588 numAnims
+= animList
.arrAnimFiles
.size();
589 modelTracksDatabases
.push_back(animList
.modelTracksDatabases
);
590 lockedDatabases
.push_back(animList
.lockedDatabases
);
592 if (animEventDatabase
.empty())
594 animEventDatabase
= animList
.animEventDatabase
; // first one wins --> so outermost animeventdb wins
597 if (faceLibFile
.empty())
599 faceLibFile
= animList
.faceLibFile
;
600 faceLibDir
= animList
.faceLibDir
;
605 m_pAnimationSet
->prepareLoadCAFs(numAnims
);
607 uint32 numTracksDataBases
= modelTracksDatabases
.size();
608 if (numTracksDataBases
)
609 g_AnimationManager
.CreateGlobalHeaderDBA(modelTracksDatabases
);
611 // Lock Persistent Databases
612 DynArray
<string
>::iterator it
;
613 for (it
= lockedDatabases
.begin(); it
!= lockedDatabases
.end(); ++it
)
615 g_AnimationManager
.DBA_LockStatus(it
->c_str(), 1, false);
618 if (!animEventDatabase
.empty())
620 SetModelAnimEventDatabase(animEventDatabase
);
623 if (!faceLibFile
.empty())
625 CreateFacialInstance();
626 LoadFaceLib(faceLibFile
, faceLibDir
, this);
629 for (int32 i
= nListIDs
- 1; i
>= 0; --i
)
631 const SAnimListInfo
& animList
= paramLoader
.GetParsedList(m_animListIDs
[i
]);
632 uint32 numAnimNames
= animList
.arrAnimFiles
.size();
634 // this is where the Animation List Cache kicks in
635 if (!animList
.headersLoaded
)
637 paramLoader
.ExpandWildcards(m_animListIDs
[i
]);
638 numAnimAssets
+= LoadAnimationFiles(paramLoader
, m_animListIDs
[i
]);
639 // this list has been processed, dont do it again!
640 paramLoader
.SetHeadersLoaded(m_animListIDs
[i
]);
644 numAnimAssets
+= ReuseAnimationFiles(paramLoader
, m_animListIDs
[i
]);
647 if (!animList
.facialAnimations
.empty())
648 facialAnimations
.insert(facialAnimations
.end(), animList
.facialAnimations
.begin(), animList
.facialAnimations
.end());
651 // Store the list of facial animations in the model animation set.
652 if (!facialAnimations
.empty())
653 m_pAnimationSet
->GetFacialAnimations().SwapElementsWithVector(facialAnimations
);
655 AnimEventLoader::LoadAnimationEventDatabase(this, GetModelAnimEventDatabaseCStr());
657 uint32 dddd
= g_AnimationManager
.m_arrGlobalCAF
.size();
659 if (numAnimAssets
> 1)
661 g_pILog
->UpdateLoadingScreen(" %u animation-assets loaded (total assets: %d)", numAnimAssets
, g_AnimationManager
.m_arrGlobalCAF
.size());
664 if (Console::GetInst().ca_MemoryUsageLog
)
666 CryModuleMemoryInfo info
;
667 CryGetMemoryInfoForModule(&info
);
668 g_pILog
->UpdateLoadingScreen("Memstat %i", (int)(info
.allocated
- info
.freed
));
671 // If there is a facial model, but no expression library, we should create an empty library for it.
672 // When we assign the library to the facial model it will automatically be assigned the morphs as expressions.
674 CFacialModel
* pFacialModel
= GetFacialModel();
675 CFacialEffectorsLibrary
* pEffectorsLibrary
= (pFacialModel
? pFacialModel
->GetFacialEffectorsLibrary() : 0);
676 if (pFacialModel
&& !pEffectorsLibrary
)
678 CFacialAnimation
* pFacialAnimationManager
= (g_pCharacterManager
? g_pCharacterManager
->GetFacialAnimation() : 0);
679 CFacialEffectorsLibrary
* pNewLibrary
= new CFacialEffectorsLibrary(pFacialAnimationManager
);
680 const string
& filePath
= GetModelFilePath();
681 if (!filePath
.empty())
683 string libraryFilePath
= PathUtil::ReplaceExtension(filePath
, ".fxl");
684 pNewLibrary
->SetName(libraryFilePath
);
686 if (pFacialModel
&& pNewLibrary
)
687 pFacialModel
->AssignLibrary(pNewLibrary
);
691 if (Console::GetInst().ca_PrecacheAnimationSets
)
693 CAnimationSet
& animSet
= *m_pAnimationSet
;
694 uint32 animCount
= animSet
.GetAnimationCount();
695 for (uint32 i
= 0; i
< animCount
; ++i
)
697 const ModelAnimationHeader
* pHeader
= animSet
.GetModelAnimationHeader(i
);
700 if (pHeader
->m_nAssetType
== CAF_File
)
702 uint32 globalID
= pHeader
->m_nGlobalAnimId
;
705 PREFAST_ASSUME(g_pCharacterManager
);
706 g_AnimationManager
.m_arrGlobalCAF
[globalID
].StartStreamingCAF();
713 m_pAnimationSet
->VerifyLMGs();
715 return m_arrModelJoints
.size() != 0;
718 void CDefaultSkeleton::LoadFaceLib(const char* faceLibFile
, const char* animDirName
, CDefaultSkeleton
* pDefaultSkeleton
)
720 const char* pFilePath
= GetModelFilePath();
721 const char* szExt
= PathUtil::GetExt(pFilePath
);
722 stack_string strGeomFileNameNoExt
;
723 strGeomFileNameNoExt
.assign(pFilePath
, *szExt
? szExt
- 1 : szExt
);
725 LOADING_TIME_PROFILE_SECTION(g_pISystem
);
726 // Facial expressions library.
727 _smart_ptr
<IFacialEffectorsLibrary
> pLib
;
729 pLib
= g_pCharacterManager
->GetIFacialAnimation()->LoadEffectorsLibrary(faceLibFile
);
732 // Search in animation directory .chr file directory.
733 pLib
= g_pCharacterManager
->GetIFacialAnimation()->LoadEffectorsLibrary(
734 PathUtil::Make(animDirName
, faceLibFile
));
738 // Search in .chr file directory.
739 pLib
= g_pCharacterManager
->GetIFacialAnimation()->LoadEffectorsLibrary(
740 PathUtil::Make(PathUtil::GetParentDirectory(strGeomFileNameNoExt
), stack_string(faceLibFile
)));
744 if (pDefaultSkeleton
->GetFacialModel())
746 pDefaultSkeleton
->GetFacialModel()->AssignLibrary(pLib
);
751 gEnv
->pLog
->LogError("CryAnimation: Facial Effector Library %s not found (when loading %s.chrparams)", faceLibFile
, strGeomFileNameNoExt
.c_str());
755 //-------------------------------------------------------------------------------------------------
756 #define MAX_STRING_LENGTH (256)
758 uint32
CDefaultSkeleton::ReuseAnimationFiles(CParamLoader
& paramLoader
, uint32 listID
)
760 LOADING_TIME_PROFILE_SECTION(g_pISystem
);
762 const SAnimListInfo
& animList
= paramLoader
.GetParsedList(listID
);
763 int32 numAnims
= animList
.arrLoadedAnimFiles
.size();
766 m_pAnimationSet
->PrepareToReuseAnimations(numAnims
);
768 for (int i
= 0; i
< numAnims
; ++i
)
770 const ModelAnimationHeader
& animHeader
= animList
.arrLoadedAnimFiles
[i
];
772 m_pAnimationSet
->ReuseAnimation(animHeader
);
779 uint32
CDefaultSkeleton::LoadAnimationFiles(CParamLoader
& paramLoader
, uint32 listID
)
781 const char* pFullFilePath
= GetModelFilePath();
782 const char* szExt
= PathUtil::GetExt(pFullFilePath
);
783 stack_string strGeomFileNameNoExt
;
784 strGeomFileNameNoExt
.assign(pFullFilePath
, *szExt
? szExt
- 1 : szExt
);
786 LOADING_TIME_PROFILE_SECTION(g_pISystem
);
787 // go through all Anims on stack and load them
791 const SAnimListInfo
& animList
= paramLoader
.GetParsedList(listID
);
793 #if BLENDSPACE_VISUALIZATION
794 const char* strInternalType_Para1D
= "InternalPara1D";
795 int32 nDefAnimID
= m_pAnimationSet
->GetAnimIDByName(strInternalType_Para1D
);
798 int32 nGAnimID
= m_pAnimationSet
->LoadFileLMG("InternalPara1D.LMG", strInternalType_Para1D
);
800 CryFatalError("The GlobalID of the default Para1D must be 0");
801 int nAnimID0
= m_pAnimationSet
->GetAnimIDByName(strInternalType_Para1D
);
804 ModelAnimationHeader
* pAnim
= (ModelAnimationHeader
*)m_pAnimationSet
->GetModelAnimationHeader(nAnimID0
);
808 paramLoader
.AddLoadedHeader(listID
, *pAnim
); // store ModelAnimationHeader to reuse it in the case that a second model will need it
814 numAnims
= animList
.arrAnimFiles
.size();
815 for (int i
= 0; i
< numAnims
; i
++)
817 const char* pFilePath
= animList
.arrAnimFiles
[i
].m_FilePathQ
;
818 const char* pAnimName
= animList
.arrAnimFiles
[i
].m_AnimNameQ
;
819 const char* fileExt
= PathUtil::GetExt(pFilePath
);
821 bool IsBAD
= (0 == stricmp(fileExt
, ""));
825 bool IsCHR
= (0 == stricmp(fileExt
, CRY_SKEL_FILE_EXT
));
828 bool IsSKIN
= (0 == stricmp(fileExt
, CRY_SKIN_FILE_EXT
));
831 bool IsCDF
= (0 == stricmp(fileExt
, "cdf"));
834 bool IsCGA
= (0 == stricmp(fileExt
, "cga"));
838 uint32 IsCAF
= (stricmp(fileExt
, "caf") == 0);
839 uint32 IsLMG
= (stricmp(fileExt
, "lmg") == 0) || (stricmp(fileExt
, "bspace") == 0) || (stricmp(fileExt
, "comb") == 0);
840 assert(IsCAF
+ IsLMG
);
846 uint32 numAimDB
= m_poseBlenderAimDesc
.m_blends
.size();
847 for (uint32 d
= 0; d
< numAimDB
; d
++)
849 const char* strAimIK_Token
= m_poseBlenderAimDesc
.m_blends
[d
].m_AnimToken
;
850 IsAimPose
= (CryStringUtils::stristr(pAnimName
, strAimIK_Token
) != 0);
854 uint32 numLookDB
= m_poseBlenderLookDesc
.m_blends
.size();
855 for (uint32 d
= 0; d
< numLookDB
; d
++)
857 const char* strLookIK_Token
= m_poseBlenderLookDesc
.m_blends
[d
].m_AnimToken
;
858 IsLookPose
= (CryStringUtils::stristr(pAnimName
, strLookIK_Token
) != 0);
864 if (IsCAF
&& IsAimPose
)
866 if (IsCAF
&& IsLookPose
)
869 // ben: it can happen that a AnimID is defined in a list and in one of its dependencies that
870 // was included after the definition of that animation, this is a different behavior than
871 // before, so errors might pop up that did not pop up before
872 CryFixedStringT
<256> standupAnimType
;
874 int32 nGlobalAnimID
= -1;
877 nGlobalAnimID
= m_pAnimationSet
->LoadFileCAF(pFilePath
, pAnimName
);
880 if (IsAimPose
|| IsLookPose
)
882 nGlobalAnimID
= m_pAnimationSet
->LoadFileAIM(pFilePath
, pAnimName
, this);
887 nGlobalAnimID
= m_pAnimationSet
->LoadFileLMG(pFilePath
, pAnimName
);
890 int nAnimID0
= m_pAnimationSet
->GetAnimIDByName(pAnimName
);
893 ModelAnimationHeader
* pAnim
= (ModelAnimationHeader
*)m_pAnimationSet
->GetModelAnimationHeader(nAnimID0
);
897 // store ModelAnimationHeader to reuse it in the case that a second model will need it
898 paramLoader
.AddLoadedHeader(listID
, *pAnim
);
903 gEnv
->pLog
->LogError("CryAnimation: Animation (caf) file \"%s\" could not be read (it's an animation of \"%s.%s\")", animList
.arrAnimFiles
[i
].m_FilePathQ
, strGeomFileNameNoExt
.c_str(), CRY_SKEL_FILE_EXT
);
910 const string
CDefaultSkeleton::GetDefaultAnimDir()
912 const char* pFilePath
= GetModelFilePath();
913 const char* szExt
= PathUtil::GetExt(pFilePath
);
914 stack_string strGeomFileNameNoExt
;
915 strGeomFileNameNoExt
.assign(pFilePath
, *szExt
? szExt
- 1 : szExt
);
917 stack_string animDirName
= PathUtil::GetParentDirectory(strGeomFileNameNoExt
, 3);
918 if (!animDirName
.empty())
919 return animDirName
+= "/animations";
921 return animDirName
+= "animations";