Files
FC1/CryAnimation/CryBoneInfo.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

175 lines
6.1 KiB
C++

#include "stdafx.h"
#include "CryBoneInfo.h"
#include <StlUtils.h>
#include "ControllerManager.h"
#include "StringUtils.h"
CryBoneInfo::CryBoneInfo()
//:m_arrControllers ("CryBoneInfo.Controllers")
{
}
CryBoneInfo::~CryBoneInfo()
{
IPhysicalWorld *pIPhysicalWorld = GetPhysicalWorld();
IGeomManager* pPhysGeomManager = pIPhysicalWorld?pIPhysicalWorld->GetGeomManager():NULL;
for(int nLod=0; nLod<2; nLod++)
if (m_PhysInfo[nLod].pPhysGeom && (INT_PTR)m_PhysInfo[nLod].pPhysGeom!=-1)
{
if ((INT_PTR)m_PhysInfo[nLod].pPhysGeom<0x400)
{
TRACE("Error: trying to release wrong bone phys geometry");
}
else if (pPhysGeomManager)
{
phys_geometry* pPhysGeom = m_PhysInfo[nLod].pPhysGeom;
pPhysGeomManager->UnregisterGeometry(pPhysGeom);
}
else
TRACE("todo: delete bones phys");
}
}
//////////////////////////////////////////////////////////////////////////
// binds this bone to a controller from the specified animation, using
// the controller manager
// NOT RECURSIVE anymore
// PARAMETERS:
// nAnimID - local for this bone animation ID (will be used when
// subsequently referring to the animation)
// nGlobalAnimID - global animation id, identifies the animation within
// the controller manager context
// RETURNS:
// The binded controller, if the bind was successful, or NULL if there's
// no such controller (animation is missing)
//////////////////////////////////////////////////////////////////////////
IController* CryBoneInfo::BindController(CControllerManager::Animation& GlobalAnim, unsigned nAnimID)
{
if (m_arrControllers.size() <= nAnimID)
// this is an autopointer array, so there's no need to re-initialize the autopointers after construction
m_arrControllers.resize (nAnimID+1/*, NULL*/);
IController* pController = m_arrControllers[nAnimID] = GlobalAnim.GetController (m_nControllerID);
return pController;
}
// unbinds the bone from the given animation's controller
void CryBoneInfo::UnbindController (unsigned nAnimID)
{
if (m_arrControllers.size() > nAnimID)
m_arrControllers[nAnimID] = NULL;
}
unsigned CryBoneInfo::sizeofThis()const
{
unsigned nSize = sizeof(*this);
nSize += sizeofVector(m_arrControllers);
return nSize;
}
//////////////////////////////////////////////////////////////////////////
// Updates the given lod level bone physics info from the bones found in
// the given chunk.
// THis is required to update the dead body physics info from the lod1 geometry
// without rebuilding the new bone structure. If the lod1 has another bone structure,
// then the bones are mapped to the lod0 ones using controller ids. Matching bones'
// physics info is updated
void CryBoneInfo::UpdateHierarchyPhysics (const BONEANIM_CHUNK_DESC* pChunk, unsigned nChunkSize, int nLodLevel)
{
UnsignedToCryBoneMap mapCtrlId;
AddHierarchyToControllerIdMap(mapCtrlId);
// the first bone entity
const BONE_ENTITY* pBoneEntity = (const BONE_ENTITY*)(pChunk+1);
// the actual end of the chunk
const BONE_ENTITY* pBoneEntityEnd = (const BONE_ENTITY*)(((const char*)pChunk)+nChunkSize);
// if you get this assert, it means the lod 1 file is corrupted
if (pBoneEntity + pChunk->nBones > pBoneEntityEnd)
{
assert (0);
return;
}
// update physics for each bone entity
for (; pBoneEntity < pBoneEntityEnd; ++pBoneEntity)
{
CryBoneInfo* pBone = find_in_map(mapCtrlId, pBoneEntity->ControllerID, (CryBoneInfo*)NULL);
if (pBone)
pBone->UpdatePhysics(*pBoneEntity, nLodLevel);
}
}
//////////////////////////////////////////////////////////////////////////
// adds this bone and all its children to the given map controller id-> bone ptr
void CryBoneInfo::AddHierarchyToControllerIdMap (UnsignedToCryBoneMap& mapControllerIdToCryBone)
{
mapControllerIdToCryBone.insert (UnsignedToCryBoneMap::value_type(m_nControllerID, this));
for (unsigned nChild = 0; nChild < numChildren(); ++nChild)
{
getChild(nChild)->AddHierarchyToControllerIdMap(mapControllerIdToCryBone);
}
}
//! Performs post-initialization. This step is requred to initialize the pPhysGeom of the bones
//! After the bone has been loaded but before it is first used. When the bone is first loaded, pPhysGeom
//! is set to the value equal to the chunk id in the file where the physical geometry (BoneMesh) chunk is kept.
//! After those chunks are loaded, and chunk ids are mapped to the registered physical geometry objects,
//! call this function to replace pPhysGeom chunk ids with the actual physical geometry object pointers.
//! RETURNS:
// true if the corresponding physical geometry object has been found
//! NOTE:
//! The entries of the map that were used are deleted
bool CryBoneInfo::PostInitPhysGeom (ChunkIdToPhysGeomMap& mapChunkIdToPhysGeom, int nLodLevel)
{
phys_geometry*& pPhysGeom = m_PhysInfo[nLodLevel].pPhysGeom;
ChunkIdToPhysGeomMap::iterator it = mapChunkIdToPhysGeom.find ((INT_PTR)pPhysGeom);
if (it != mapChunkIdToPhysGeom.end())
{
// remap the chunk id to the actual pointer to the geometry
pPhysGeom = it->second;
mapChunkIdToPhysGeom.erase (it);
return true;
}
else
{
pPhysGeom = NULL;
return false;
}
}
void CryBoneInfo::PostInitialize()
{
if (getParent())
{
CryQuat qrel = CryQuat((matrix3x3in4x4Tf&)getParent()->getInvDefGlobal() * ((matrix3x3in4x4Tf&)getInvDefGlobal()).T());
m_pqDefRelTransform.vRotLog = -log(qrel).v; // '-' since pqTransform.buildMtarix assumes flipped quaternion
m_pqDefRelTransform.vPos = getParent()->getInvDefGlobal().TransformPointOLD(
(matrix3x3in4x4f&)getInvDefGlobal() * -getInvDefGlobal().GetTranslationOLD());
CryBoneInfo *pParent,*pPhysParent;
for(int nLod=0; nLod<2; nLod++)
{
for(pParent=pPhysParent=getParent(); pPhysParent && !pPhysParent->m_PhysInfo[nLod].pPhysGeom; pPhysParent=pPhysParent->getParent());
if (pPhysParent)
m_qRelPhysParent[nLod] = CryQuat((matrix3x3in4x4Tf&)pParent->getInvDefGlobal() * (matrix3x3in4x4f&)pPhysParent->getInvDefGlobal());
else
m_qRelPhysParent[nLod].SetIdentity();
}
}
else
{
m_pqDefRelTransform.vRotLog.Set(0,0,0);
m_pqDefRelTransform.vPos.Set(0,0,0);
}
}
CryBoneInfo& CryBoneInfo::operator = (const CryBoneDesc& rThat)
{
*static_cast<CryBoneDesc*>(this) = rThat;
m_arrControllers.clear();
return *this;
}