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

1446 lines
45 KiB
C++

//////////////////////////////////////////////////////////////////////
//
// CryEngine Source code
//
// File:CryCharInstance.cpp
// Implementation of CryCharInstance class
//
// History:
// August 16, 2002: Created by Sergiy Migdalskiy <sergiy@crytek.de>
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
//#include "CryAnimation.h"
#include <CryAnimationScriptCommands.h>
#include <Cry_Camera.h>
#include <I3DEngine.h>
#include <IEntityRenderState.h>
#include "CryModelState.h"
#include "CryCharInstance.h"
#include "CryCharManager.h"
#include "ControllerManager.h"
#include "cvars.h"
#include "CryCharBody.h"
#include "StringUtils.h"
#include "DebugUtils.h"
#include "MathUtils.h"
#include "CryModelSubmesh.h"
#include "CryCharAnimationParams.h"
#include "CryCharMorphParams.h"
#include "CryCharFxTrail.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
using namespace CryStringUtils;
CryCharInstance::CryCharInstance (CryCharBody * pBody):
m_pCryCharBody (pBody),
m_fLastAnimUpdateTime (0),
m_bEnableStartAnimation (true)
{
m_sShaderTemplateName[0][0] = 0;
m_sShaderTemplateName[1][0] = 0;
m_nShaderTemplateFlags = 0;
m_Color = CFColor(1.0f);
m_pModelState = m_pCryCharBody->GetModel()->m_pDefaultModelState->MakeCopy();
if(!m_pModelState)
{
g_GetLog()->LogToFile(" Unable To Copy DefaultModelState For Model [%s]", pBody->GetFilePathCStr());
return;
}
m_v3pvSpitFirePos(0,0,0);
m_v3pvSpitFirePosTranslated(0,0,0);
ResetAnimations();
m_nFlags = 0;
m_fAnimSpeedScale = 1;
// m_matAttachedObjectMatrix.Clear();
pBody->RegisterInstance (this);
}
CryCharInstance::~CryCharInstance()
{
// GetRenderer()->DeleteModelState(m_pModelState);
delete m_pModelState;
m_pModelState = NULL;
m_pCryCharBody->UnregisterInstance(this);
}
std::vector<String> AnimStrings;
std::vector<uint32> FrameID;
std::vector<uint32> LayerID;
bool CryCharInstance::StartAnimation (const char* szAnimName, const struct CryCharAnimationParams& Params)
{
FUNCTION_PROFILER( g_GetISystem(),PROFILE_ANIMATION );
/*
float fColor[4] = {0,1,0,1};
String TestName = "objects\\characters\\story_characters\\valerie\\valeri.cgf";
String ModelName = GetBody()->GetFileName();
if (TestName==ModelName) {
float fColor[4] = {1,0,1,1};
// String TestName = "awalkfwd";
String TestName = "aidle";
String AnimName = szAnimName;
//if (TestName==AnimName) {
FrameID.push_back(g_nFrameID);
LayerID.push_back(Params.nLayerID);
AnimStrings.push_back(AnimName);
//}
}*/
if (!m_bEnableStartAnimation)
{
// this error happens extremely rarely, and it leads to unpleasant results: dead characters standing etc.
// so we try to find all places where it was called from
g_GetLog()->LogError ("\002%d. %p->StartAnimation(file=%s): %s, Layer=%u, blending:in=%.2f,out=%.2f - called while StartAnimation is disabled", g_nFrameID, this, m_pCryCharBody->GetNameCStr(), szAnimName, Params.nLayerID, Params.fBlendInTime, Params.fBlendOutTime);
//GetSystem()->LogCallStack();
}
if(g_GetCVars()->ca_Debug())
g_GetLog()->Log("\002%p->StartAnimation(file=%s): %s, Layer=%u, blending:in=%.2f,out=%.2f", this, m_pCryCharBody->GetNameCStr(), szAnimName, Params.nLayerID, Params.fBlendInTime, Params.fBlendOutTime);
if (Params.nLayerID & ~0xF)
{
g_GetLog()->LogError("\002%p->StartAnimation(file=%s): %s, Layer=%u, blending:in=%.2f,out=%.2f: Layer is out of range", this, m_pCryCharBody->GetNameCStr(), szAnimName, Params.nLayerID, Params.fBlendInTime, Params.fBlendOutTime);
return false;
}
bool bOk = false;
if (m_pModelState->RunAnimation(szAnimName, Params, m_fAnimSpeedScale * g_GetCVars()->ca_UpdateSpeed()))
{
strncpy (m_sCurAnimation,szAnimName,sizeof(m_sCurAnimation));
bOk = true;
}
if (Params.nFlags & Params.FLAGS_RECURSIVE)
{
for (BindArray::iterator it = m_arrBinds.begin(); it != m_arrBinds.end(); ++it)
if ((*it)->pObj->StartAnimation (szAnimName, Params))
bOk = true;
}
return true;
}
// FOR TEST ONLY enables/disables StartAnimation* calls; puts warning into the log if StartAnimation* is called while disabled
void CryCharInstance::EnableStartAnimation (bool bEnable)
{
m_bEnableStartAnimation = bEnable;
}
//! Start the specified by parameters morph target
void CryCharInstance::StartMorph (const char* szMorphTarget,const CryCharMorphParams& Params)
{
m_pModelState->RunMorph (szMorphTarget, Params);
if (Params.nFlags & CryCharMorphParams::FLAGS_RECURSIVE)
{
for (BindArray::iterator it = m_arrBinds.begin(); it != m_arrBinds.end(); ++it)
(*it)->pObj->StartMorph(szMorphTarget, Params);
}
}
//! Start the specified by parameters morph target
void CryCharInstance::StartMorph (int nMorphTargetId, const CryCharMorphParams& Params)
{
m_pModelState->GetSubmesh(0)->StartMorph (nMorphTargetId, Params);
}
//! Finds the morph with the given id and sets its relative time.
//! Returns false if the operation can't be performed (no morph)
bool CryCharInstance::SetMorphTime (int nMorphTargetId, float fTime)
{
return m_pModelState->GetSubmesh(0)->SetMorphTime (nMorphTargetId, fTime);
}
//! Stops the animation at the specified layer. Returns true if there was some animation on that layer, and false otherwise
bool CryCharInstance::StopAnimation (int nLayer)
{
if (g_GetCVars()->ca_OverrideLayer())
nLayer = g_GetCVars()->ca_OverrideLayer();
if (nLayer & ~0xF)
{
g_GetLog()->LogError("\002%d. %p->StopAnimation(file=%s): Layer=%u: Layer is out of range", g_nFrameID, this, m_pCryCharBody->GetNameCStr(), nLayer);
return false;
}
if(g_GetCVars()->ca_Debug())
g_GetLog()->Log("\004%d. %p->StopAnimation(layer=%u): model %s", g_nFrameID, this, nLayer, m_pCryCharBody->GetNameCStr());
return m_pModelState->StopAnimation (nLayer);
}
bool CryCharInstance::StopMorph (int nMorphTargetId)
{
return m_pModelState->GetSubmesh(0)->StopMorph(nMorphTargetId);
}
void CryCharInstance::StopAllMorphs()
{
m_pModelState->StopAllMorphs();
for (BindArray::iterator it = m_arrBinds.begin(); it != m_arrBinds.end(); ++it)
(*it)->pObj->StopAllMorphs();
}
//! freezes all currently playing morphs at the point they're at
void CryCharInstance::FreezeAllMorphs()
{
m_pModelState->FreezeAllMorphs();
for (BindArray::iterator it = m_arrBinds.begin(); it != m_arrBinds.end(); ++it)
(*it)->pObj->FreezeAllMorphs();
}
//! Enables/Disables the Default Idle Animation restart.
//! If this feature is enabled, then the last looped animation will be played back after the current (non-loop) animation is finished.
//! Only those animations started with the flag bTreatAsDefaultIdleAnimation == true will be taken into account
void CryCharInstance::EnableLastIdleAnimationRestart (unsigned nLayer, bool bEnable)
{
m_pModelState->EnableIdleAnimationRestart (nLayer, bEnable);
}
// sets the given aniimation to the given layer as the default
void CryCharInstance::SetDefaultIdleAnimation (unsigned nLayer, const char* szAnimName)
{
m_pModelState->SetDefaultIdleAnimation(nLayer, szAnimName);
}
// Checks if the animation with the given name exists, returns true if it does
bool CryCharInstance::IsAnimationPresent(const char* szAnimName)
{
return m_pCryCharBody->GetModel()->findAnimation(szAnimName) >= 0;
}
const char * CryCharInstance::GetCurAnimation()
{
if(m_pModelState->IsAnimStopped())
return 0;
return m_sCurAnimation;
}
//! Returns the current animation in the layer or -1 if no animation is being played
//! in this layer (or if there's no such layer)
int CryCharInstance::GetCurrentAnimation (unsigned nLayer)
{
return m_pModelState->GetCurrentAnimation (nLayer);
}
const Vec3d CryCharInstance::GetCenter()
{
return m_pModelState->GetCenter();
}
const float CryCharInstance::GetRadius()
{
Vec3d vSize = m_pModelState->m_BBox.getSize();
if(vSize.z>=32)
g_GetLog()->LogWarning ("CryCharInstance::GetRadius: bbox is very big: %s (%.2f)",
m_pCryCharBody->GetNameCStr(), vSize.z);
return max(vSize.x,max(vSize.y,vSize.z))*0.5f;
}
/////////////////////////////////////////////////////////////////////////////////
// Attaches a static object to the bone (given the bone name) or detaches previous object from the bone.
// Only one static object can be attached to one bone at a time.
// If pWeaponModel is NULL, detaches any object from the given bone
// Does nothing if there is no bone with the given name.
ICryCharInstance::ObjectBindingHandle CryCharInstance::AttachObjectToBone(IBindable * pWeaponModel, const char * szBoneName, bool bUseRelativeToDefPoseMatrix, unsigned nFlags )
{
if(!szBoneName)
{
// if you find this assert, this means someone passed here a model and NO bone to attach it to. What should it mean anyway??
assert (!pWeaponModel);
// just detach everything
DetachAll();
return nInvalidObjectBindingHandle;
}
int nBone = m_pCryCharBody->GetModel()->findBone (szBoneName);
if(nBone < 0)
{
if (!pWeaponModel)
{
// this is a severe bug if the bone name is invalid and someone tries to detach the model
// if we find such a situation, we should try to detach the model, as it might be destructed already
// but now we just detach everything, as it's simpler
//m_arrBoundObjects.clear();
//m_arrBoundObjectIndices.clear();
g_GetLog()->LogError ("\002AttachObjectToBone is called for bone \"%s\", which is not in the model \"%s\". Ignoring, but this may cause a crash because the corresponding object won't be detached after it's destroyed", szBoneName, m_pCryCharBody->GetFilePathCStr());
#ifdef _DEBUG
// this assert will only happen if the ca_NoAttachAssert is off
// assert (g_GetCVars()->ca_NoAttachAssert());
#endif
}
return nInvalidObjectBindingHandle; // bone not found, do nothing
}
// detach all objects from this bone before creating a new one
DetachAllFromBone(nBone);
if(pWeaponModel == NULL)
{
// we didn't create a new binding, so return invalid handle
return nInvalidObjectBindingHandle;
}
else
{
return AttachToBone(pWeaponModel, nBone, nFlags);
}
}
//////////////////////////////////////////////////////////////////////////
// detaches all objects from bones; returns the nubmer of bindings deleted
unsigned CryCharInstanceBase::DetachAll()
{
unsigned numDetached = (unsigned)m_arrBinds.size();
for (BindArray::iterator it = m_arrBinds.begin(); it != m_arrBinds.end(); ++it)
delete *it;
m_arrBinds.clear();
return numDetached;
}
//////////////////////////////////////////////////////////////////////////
// detach all bindings to the given bone; returns the nubmer of bindings deleted
unsigned CryCharInstanceBase::DetachAllFromBone(unsigned nBone)
{
unsigned numDetached = 0;
for (BindArray::iterator it = m_arrBinds.begin(); it != m_arrBinds.end(); )
if ((*it)->nBone == nBone)
{
delete *it;
it = m_arrBinds.erase (it);
++numDetached;
}
else
++it; // keep it
return numDetached;
}
//////////////////////////////////////////////////////////////////////////
// attaches the object to the given bone. The returned value is the handle of the binding,
// that can be used to examine the binding and delete it
CryCharInstanceBase::ObjectBindingHandle CryCharInstanceBase::AttachToBone (IBindable*pObj, unsigned nBone, unsigned nFlags)
{
// create a new binding
if (pObj)
{
StatObjBind* pNewBind = new StatObjBind(pObj, nBone,nFlags);
m_arrBinds.push_back(pNewBind);
return (ObjectBindingHandle)pNewBind;
}
else
{
return nInvalidObjectBindingHandle;
}
}
//////////////////////////////////////////////////////////////////////////
// detaches the given binding; if it returns false, the binding handle is invalid
// the binding becomes invalid immediately after detach
bool CryCharInstanceBase::Detach (ObjectBindingHandle nHandle)
{
assert (IsHeapValid());
for (BindArray::iterator it = m_arrBinds.begin(); it != m_arrBinds.end(); )
if (nHandle == (ObjectBindingHandle)*it)
{
delete *it;
it = m_arrBinds.erase (it);
assert (IsHeapValid());
return true;
}
else
++it;
return false;
}
//////////////////////////////////////////////////////////////////////////
// checks if the given binding is valid
bool CryCharInstanceBase::IsBindingValid (ObjectBindingHandle nHandle)
{
for (BindArray::iterator it = m_arrBinds.begin(); it != m_arrBinds.end(); ++it)
if (nHandle == (ObjectBindingHandle)*it)
return true;
return false;
}
//////////////////////////////////////////////////////////////////////////
//! attach a light to a bone
ICryCharInstance::LightHandle CryCharInstance::AttachLight (CDLight* pDLight, unsigned nBone, bool bCopyLight)
{
if (nBone < m_pCryCharBody->GetModel()->numBoneInfos())
return (LightHandle)m_pModelState->AddDynBoundLight(this, pDLight, nBone, bCopyLight);
return InvalidLightHandle;
}
//////////////////////////////////////////////////////////////////////////
//! detach the light from the bone
void CryCharInstance::DetachLight (CDLight* pDLight)
{
m_pModelState->RemoveDynBoundLight (pDLight);
}
//////////////////////////////////////////////////////////////////////////
//! Attach a light (copying the light actually) to the bone
//! Returns the handle identifying the light. With this handle, you can either
//! Retrieve the light information or detach it.
ICryCharInstance::LightHandle CryCharInstance::AttachLight (const CDLight& rDLight, const char* szBoneName)
{
int nBone = m_pCryCharBody->GetModel()->findBone (szBoneName);
if (nBone >= 0)
// the rDLight doesn't get modified because we pass true for copy light; it gets copied
return (LightHandle)m_pModelState->AddDynBoundLight(this, (CDLight*)&rDLight, nBone, true);
else
return InvalidLightHandle;
}
//////////////////////////////////////////////////////////////////////////
//! Detaches the light by the handle retuned by AttachLight
void CryCharInstance::DetachLight (LightHandle nHandle)
{
m_pModelState->RemoveDynBoundLight ((CDLight*)nHandle);
}
//////////////////////////////////////////////////////////////////////////
//! Returns the light by the light handle; returns NULL if no such light found
CDLight* CryCharInstance::GetLight(LightHandle nHandle)
{
if (m_pModelState->IsDynLightBound ((CDLight*)nHandle))
return (CDLight*)nHandle;
else
return NULL;
}
ICryCharInstance::LightHandle CryCharInstance::GetLightHandle (CDLight* pLight)
{
if (m_pModelState->IsDynLightBound(pLight))
return (LightHandle)pLight;
else
return InvalidLightHandle;
}
void CryCharInstance::ResetAnimations()
{
if (g_GetCVars()->ca_Debug())
g_GetLog()->Log ("\002%d. %p->ResetAnimations (file=%s)", g_nFrameID, this, m_pCryCharBody->GetNameCStr());
m_sCurAnimation[0] = 0;
m_pModelState->ResetAllAnimations();
m_fLastAnimUpdateTime = -1;
for (BindArray::iterator it = m_arrBinds.begin(); it != m_arrBinds.end(); ++it)
(*it)->pObj->ResetAnimations();
}
ICryBone * CryCharInstance::GetBoneByName(const char * szName)
{
return m_pModelState->GetBoneByName(szName);
}
CLeafBuffer * CryCharInstance::GetLeafBuffer()
{
return m_pModelState->GetLeafBuffer();
}
//! Returns position of specified helper ( exported into cgf file )
//! Actually returns the given bone's position
//! Default implementation: 000
Vec3d CryCharInstance::GetHelperPos(const char * szHelperName)
{
int nBone = m_pCryCharBody->GetModel()->findBone(szHelperName);
if (nBone < 0)
return Vec3d(0,0,0);
return m_pModelState->getBoneMatrixGlobal(nBone).GetTranslationOLD();
}
//! Returns the matrix of the specified helper ( exported into cgf file )
//! Actually returns the given bone's matrix
const Matrix44 * CryCharInstance::GetHelperMatrixByName(const char * szHelperName)
{
int nBone = m_pCryCharBody->GetModel()->findBone(szHelperName);
if (nBone < 0)
#ifdef _DEBUG
return NULL;
#else
{
static Matrix44 mtxDefault;
// for reliability, in release/profile builds, we return a valid pointer for now; in the future, it may change
return &mtxDefault;
}
#endif
return &m_pModelState->getBoneMatrixGlobal(nBone);
}
Vec3d CryCharInstance::GetTPVWeaponHelper(const char * szHelperName, ObjectBindingHandle nHandle)
{
if (!IsBindingValid(nHandle))
{
if (nHandle!= nInvalidObjectBindingHandle)
g_GetLog()->LogWarning ("\003CryCharInstance::GetTPVWeaponHelper(%s,0x%0X): Invalid binding handle", szHelperName, nHandle);
return Vec3d(0,0,0);
}
IBindable* pBoundObject = ((StatObjBind*)nHandle)->pObj;
unsigned nBone = ((StatObjBind*)nHandle)->nBone;
assert (nBone < m_pModelState->numBones());
assert (pBoundObject);
Vec3d vPos = pBoundObject->GetHelperPos (szHelperName);
//Matrix t (m_matTranRotMatrix);
const Matrix44& matAttachedObjectMatrix = m_pModelState->getBoneMatrixGlobal(nBone); // *t
Matrix34 m34=Matrix34(GetTransposed44(matAttachedObjectMatrix));
if (g_GetCVars()->ca_Debug()){
CryAABB caabb;
pBoundObject->GetBBox(caabb.vMin, caabb.vMax);
debugDrawBBox (m34, caabb, 4);
}
return m34*vPos;
}
bool CryCharInstance::GetTPVWeaponHelperMatrix(const char * szHelperName, ObjectBindingHandle nHandle, Matrix44& matOut)
{
if (!IsBindingValid(nHandle))
{
assert (0);// the binding handle is invalid!
return false;
}
IBindable* pBoundObject = ((StatObjBind*)nHandle)->pObj;
unsigned nBone = ((StatObjBind*)nHandle)->nBone;
assert (nBone < m_pModelState->numBones());
assert (pBoundObject);
const Matrix44* pHelperMatrix = pBoundObject->GetHelperMatrixByName(szHelperName);
const Matrix44& matAttachedObjectMatrix = m_pModelState->getBoneMatrixGlobal(nBone); // *t
if (g_GetCVars()->ca_Debug()){
Matrix34 m34=Matrix34(GetTransposed44(matAttachedObjectMatrix));
CryAABB caabb;
pBoundObject->GetBBox(caabb.vMin, caabb.vMax);
debugDrawBBox (m34, caabb, 4);
}
matOut = *pHelperMatrix * matAttachedObjectMatrix;
return true;
}
//////////////////////////////////////////////////////////////////////
void CryCharInstance::RenderShadowVolumes(const SRendParams *rParams, int nLimitLOD)
{
DEFINE_PROFILER_FUNCTION();
if (g_GetCVars()->ca_NoDrawShadowVolumes())
return;
if (m_pModelState && g_GetCVars()->ca_EnableCharacterShadowVolume())
//if (m_pModelState && (!(rParams->dwFlags & RPF_NOANIMSHADOWS)) && g_GetCVars()->ca_EnableCharacterShadowVolume())
m_pModelState->RenderShadowVolumes(rParams, nLimitLOD);
if (!m_arrBinds.empty())
{
DEFINE_PROFILER_SECTION("BoundObjectShadowVolumes");
//render binded object's shadow volumes
for (BindArray::iterator it = m_arrBinds.begin(); it != m_arrBinds.end(); ++it)
{
unsigned nBone = (*it)->nBone;
assert (nBone < m_pCryCharBody->GetModel()->numBoneInfos());
IBindable* pBoundObject = (*it)->pObj;
assert (pBoundObject);
if (pBoundObject)
{ // get weapon position
Matrix44 t = Matrix34::CreateRotationXYZ( Deg2Rad(rParams->vAngles), rParams->vPos + m_pModelState->m_vOffset );
t = GetTransposed44(t); //TODO: remove this after E3 and use Matrix34 instead of Matrix44
Matrix44 matAttachedObjectMatrix = m_pModelState->getBoneMatrixGlobal(nBone) * t;
SRendParams rBindParms (*rParams);
rBindParms.pMatrix = &matAttachedObjectMatrix;
if (g_GetCVars()->ca_DrawBBox()) {
Matrix34 m34=Matrix34(GetTransposed44(matAttachedObjectMatrix));
CryAABB caabb;
pBoundObject->GetBBox(caabb.vMin, caabb.vMax);
debugDrawBBox (m34, caabb, g_GetCVars()->ca_DrawBBox());
}
pBoundObject->RenderShadowVolumes (&rBindParms);
}
} //i
}
}
void CryCharInstance::GetBBox(Vec3d& vMin, Vec3d& vMax)
{
m_pModelState->GetBoundingBox(vMin, vMax);
}
/*
void CryCharInstance::SetAnimationSinkForInstance (const char * szAnimName, ICharInstanceSink * pCharInstanceSink)
{
m_pModelState->SetAnimationSinkInstance (szAnimName, pCharInstanceSink);
}
*/
void CryCharInstance::BuildPhysicalEntity(IPhysicalEntity *pent,float mass,int surface_idx,float stiffness_scale, int nLod)
{
m_pModelState->BuildPhysicalEntity(pent,mass,surface_idx,stiffness_scale, 1.0f,m_pModelState->m_vOffset, nLod);
}
IPhysicalEntity *CryCharInstance::CreateCharacterPhysics(IPhysicalEntity *pHost, float mass,int surface_idx,float stiffness_scale, int nLod)
{
return m_pModelState->CreateCharacterPhysics(pHost,mass,surface_idx,stiffness_scale, 1.0f,m_pModelState->m_vOffset, nLod);
}
int CryCharInstance::CreateAuxilaryPhysics(IPhysicalEntity *pHost, int nLod)
{
return m_pModelState->CreateAuxilaryPhysics(pHost,1.0f,m_pModelState->m_vOffset,nLod);
}
void CryCharInstance::SynchronizeWithPhysicalEntity(IPhysicalEntity *pent, const Vec3& posMaster,const Quat& qMaster)
{
#if defined(LINUX)
if(!pent || !m_pModelState)
return;
#endif
m_pModelState->SynchronizeWithPhysicalEntity(pent, posMaster,qMaster,m_pModelState->m_vOffset);
m_pModelState->UpdateBBox();
}
IPhysicalEntity *CryCharInstance::RelinquishCharacterPhysics()
{
return m_pModelState->RelinquishCharacterPhysics();
}
void CryCharInstance::SetCharacterPhysParams(float mass,int surface_idx)
{
m_pModelState->SetCharacterPhysParams(mass,surface_idx,1.0f);
}
void CryCharInstance::SetLimbIKGoal(int limbid, vectorf ptgoal, int ik_flags, float addlen, vectorf goal_normal)
{
m_pModelState->SetLimbIKGoal(limbid,1.0f, ptgoal,ik_flags,addlen,goal_normal);
}
vectorf CryCharInstance::GetLimbEndPos(int limbid)
{
return m_pModelState->GetLimbEndPos(limbid, 1.0f);
}
void CryCharInstance::AddImpact(int partid, vectorf point,vectorf impact)
{
m_pModelState->AddImpact(partid,point,impact, 1.0f);
}
int CryCharInstance::TranslatePartIdToDeadBody(int partid)
{
return m_pModelState->TranslatePartIdToDeadBody(partid);
}
bool CryCharInstance::IsAnimStopped()
{
return m_pModelState->IsAnimStopped();
}
vectorf CryCharInstance::GetOffset()
{
return (vectorf)m_pModelState->m_vOffset;
}
void CryCharInstance::SetOffset(vectorf offset)
{
m_pModelState->m_vOffset = (Vec3d)offset;
}
void CryCharInstance::SetTwiningMode (AnimTwinMode eTwinMode)
{
}
int CryCharInstance::GetDamageTableValue(int nId)
{
return m_pModelState->GetDamageTableValue(nId);
}
//! Enable object animation time update. If the bUpdate flag is false, subsequent calls to Update will not animate the character
void CryCharInstance::EnableTimeUpdate (bool bUpdate)
{
if (bUpdate)
m_fAnimSpeedScale = 1;
else
m_fAnimSpeedScale = 0;
}
//! Set the current time of the given layer, in seconds
void CryCharInstance::SetLayerTime (int nLayer, float fTimeSeconds)
{
m_pModelState->SetLayerTime (nLayer, fTimeSeconds);
}
//////////////////////////////////////////////////////////////////////////
float CryCharInstance::GetLayerTime (int nLayer)
{
return m_pModelState->GetLayerTime(nLayer);
}
// calculates the mask ANDed with the frame id that's used to determine whether to skin the character on this frame or not.
int CryCharInstance::GetUpdateFrequencyMask(Vec3 vPos, float fRadius)
{
//float red[4] = {1,0,0,1};
//debugDrawSphere(Matrix34::CreateTranslationMat(vPos), fRadius*4,red);
// on dedicated server, this path will always be taken;
// on normal clients, this will always be rejected
if(g_bUpdateBonesAlways)
return 0;
float fZoomFactor = 0.01f+0.99f*(RAD2DEG(GetViewCamera().GetFov())/90.f);
float fScaledDist = GetDistance(vPos,GetViewCamera().GetPos())*fZoomFactor;
int iMask = 7; //don't update bones
if( fRadius==0 || (fScaledDist<(64.f+fRadius) && GetViewCamera().IsSphereVisibleFast( Sphere(vPos,fRadius*4) )))
iMask = 0; //if close to camera AND is frustum
else
if(fScaledDist<64.f) iMask = 3; //close to camera but outside of frustum
// float col[4] = {0,1,0,1};
// extern float g_YLine;
// g_pIRenderer->Draw2dLabel( 1,g_YLine, 1.3f, col, false,"fZoomFactor:%15.10f fScaledDist:%15.10f iMask: %d",fZoomFactor,fScaledDist,iMask ); g_YLine+=16.0f;
// Matrix44 m44 = m_pModelState->m_ModelMatrix44;
// Vec3 t=m44.GetTranslationOLD();
// g_pIRenderer->Draw2dLabel( 1,g_YLine, 1.3f, col, false,"vPos:(%15.10f,%15.10f,%15.10f) t:(%15.10f,%15.10f,%15.10f)",vPos.x,vPos.y,vPos.z, t.x,t.y,t.z); g_YLine+=16.0f;
return iMask;
}
//! Updates the bones and the bounding box. Should be called if animation update
//! cycle in EntityUpdate has already passed but you need the result of new animatmions
//! started after Update right now.
void CryCharInstance::ForceUpdate()
{
m_pModelState->ResetBBoxCache();
m_pModelState->ProcessAnimations(0, true,this);
}
void CryCharInstance::Update(Vec3d vPos, float fRadius, unsigned uFlags)
{
DEFINE_PROFILER_FUNCTION();
SelfValidate();
// the current time
float fAnimUpdateTime = g_GetTimer()->GetCurrTime();
// the current delta time to add to the current animation time
float fFrameTime;
// for the first-time call, pretend that the last time it was called with exactly the same time
if (m_fLastAnimUpdateTime <= 0)
{
// the first update must be 0-time-range
fFrameTime = 0;
}
else
{
// calculate the delta
fFrameTime = (fAnimUpdateTime - m_fLastAnimUpdateTime) * m_fAnimSpeedScale;
// the time should actually go forward
//assert(fFrameTime >= 0);
if (fFrameTime <= 0) {
//just in case we reset the timer
//in the next frame everything will be ok
m_fLastAnimUpdateTime = fAnimUpdateTime;
return; // no need to update twice
}
}
// calculate dampering factors for optimization: depending on how far the character from the player is,
// the bones may be updated once per several frames
#ifndef _DEBUG
int nFrameID = g_GetIRenderer()->GetFrameID();
int nUFM = GetUpdateFrequencyMask(vPos,fRadius);
bool update=(nFrameID & nUFM)==(m_pModelState->getInstanceNumber()&nUFM);
//float fColor[4] = {0,1,0,1};
//g_pIRenderer->Draw2dLabel( 1,g_YLine, 1.3f, fColor, false,"InstanceNum:%d nFrameID:%d (%01d %01d) fRadius:%15.10f ",m_pModelState->getInstanceNumber(), nFrameID, update,nUFM, fRadius ); g_YLine+=16.0f;
if ( update || (fFrameTime>0.25f) )
#endif
{
m_pModelState->ProcessAnimations(fFrameTime * g_GetCVars()->ca_UpdateSpeed(), (uFlags & flagDontUpdateBones) == 0, this);
/*
{
char str[256];
sprintf(str,"%p m_fLastAnimUpdateTime=%.2f \n",this,fAnimUpdateTime);
OutputDebugString(str);
}
*/
m_fLastAnimUpdateTime = fAnimUpdateTime;
}
if (0==(uFlags & flagDontUpdateAttachments))
{
for (BindArray::iterator it = m_arrBinds.begin(); it != m_arrBinds.end(); ++it)
(*it)->pObj->Update(vPos, fRadius, uFlags);
}
}
void CryCharInstance::UpdatePhysics( float fScale )
{
//PROFILE_FRAME(CharacterPhysicsUpdate);
if (fabsf(g_GetTimer()->GetCurrTime()-m_fLastAnimUpdateTime)<0.001f) // animation was updated this frame, so update physics as well
{
m_pModelState->ProcessPhysics(0.01f, (int)m_pModelState->m_arrAnimationLayers.size());
m_pModelState->UpdateBBox();
}
}
// checks for possible memory corruptions in this object and its children
void CryCharInstance::SelfValidate ()const
{
#ifdef _DEBUG
m_pModelState->SelfValidate();
#endif
}
//////////////////////////////////////////////////////////////////////
// todo: get rid of it or implement it
bool CryCharInstance::SetAnimationFrame(const char * szString, int nFrame)
{
return m_pModelState->SetAnimationFrame(szString, nFrame);
}
bool CryCharInstance::IsCharacterActive()
{
return m_pModelState->IsCharacterActive();
}
void CryCharInstance::SetShaderFloat(const char *Name, float Val, const char *ShaderName)
{
m_pModelState->SetShaderFloat(Name, Val, ShaderName);
}
void CryCharInstance::SetColor(float fR, float fG, float fB, float fA)
{
m_Color.r = fR;
m_Color.g = fG;
m_Color.b = fB;
m_Color.a = fA;
}
const char * CryCharInstance::GetShaderTemplateName()
{
list2<CMatInfo>* pMats = m_pModelState->getLeafBufferMaterials();
if(pMats && pMats->size())
{
SShaderItem si = (*pMats)[0].shaderItem;
if (si.m_pShader)
return si.m_pShader->GetTemplate(0)->GetName();
}
return "";
}
bool CryCharInstance::SetShaderTemplateName (const char *TemplName, int Id, const char *ShaderName,IMatInfo *pCustomMaterial,unsigned nFlags)
{
assert (Id <= 1);
if(TemplName)
{
if (!strcmp (m_sShaderTemplateName[Id], TemplName))
return true;
strncpy (m_sShaderTemplateName[Id], TemplName, sizeof(m_sShaderTemplateName[0]));
}
else
m_sShaderTemplateName[Id][0] = 0;
assert (Id <= 1);
m_nShaderTemplateFlags = nFlags;
//--------------------------------------------------------------------
bool val=m_pModelState->SetShaderTemplateName (TemplName, Id, ShaderName, pCustomMaterial,nFlags);
//--------------------------------------------------------------------
if(nFlags & FLAGS_SET_SHADER_RECURSIVE)
{
for (BindArray::iterator it = m_arrBinds.begin(); it != m_arrBinds.end(); ++it)
(*it)->pObj->SetShaderTemplateName(TemplName, Id, ShaderName, pCustomMaterial, nFlags);
}
return val;
}
//! Sets shader template for rendering
bool CryCharInstance::SetShaderTemplate(int nTemplate, const char *TemplName, const char *ShaderName, bool bOnlyRegister, int * pnNewTemplateId)
{
// This gets called when character are attached recursively to each other's bones
// What to do?
return true;
}
//! returns the leaf buffer materials in this character (as they are used in the renderer)
const list2<CMatInfo>*CryCharInstance::getLeafBufferMaterials()
{
return m_pModelState->getLeafBufferMaterials();
}
void CryCharInstance::Draw(const SRendParams& RendParams, const Vec3& translation)
{
//Vec3 trans=RendParams.vPos;
//float fColor[4] = {0,1,0,1};
//extern float g_YLine;
//g_pIRenderer->Draw2dLabel( 1,g_YLine, 1.3f, fColor, false,"draw: %15.10f %15.10f %15.10f %08x",trans.x,trans.y,trans.z,RendParams.pMatrix ); g_YLine+=16.0f;
//g_YLine+=16.0f;
Render (RendParams,translation,0);
}
//! Render object ( register render elements into renderer )
void CryCharInstance::Render(const struct SRendParams& RendParams, const Vec3& translation, int nLodLevel)
{
m_pModelState->CalculateLOD(RendParams.fDistance);
Vec3d vPos = RendParams.vPos;
Vec3d vAngles = RendParams.vAngles;
/*{
//debug code --- debug code --- debug code --- debug code ---
String TestName = "objects\\characters\\animals\\greatwhiteshark\\greatwhiteshark_dead.cgf";
// String TestName = "objects\\characters\\story_characters\\valerie\\valeri.cgf";
String ModelName = GetBody()->GetFileName();
if (TestName==ModelName) {
float fColor[4] = {1,0,1,1};
}
float fColor[4] = {0,1,0,1};
extern float g_YLine;
g_pIRenderer->Draw2dLabel( 1,g_YLine, 1.3f, fColor, false,"vPos:(%15.10f %15.10f %15.10f) ModelName: %s",vPos.x,vPos.y,vPos.z,ModelName.c_str() ); g_YLine+=16.0f;
}*/
/*
float fColor[4] = {0,1,0,1};
extern float g_YLine;
g_pIRenderer->Draw2dLabel( 1,g_YLine, 1.3f, fColor, false,"ModelName: %s",ModelName ); g_YLine+=16.0f;
g_YLine+=16.0f;
*/
// make tran&rot matrix
if (RendParams.pMatrix)
m_matTranRotMatrix = *RendParams.pMatrix;
else
{
//OPTIMIZED_BY_IVO
m_matTranRotMatrix = Matrix34::CreateRotationXYZ( Deg2Rad(vAngles), vPos + m_pModelState->m_vOffset );
m_matTranRotMatrix = GetTransposed44(m_matTranRotMatrix); //TODO: remove this after E3 and use Matrix34 instead of Matrix44
}
if (m_pModelState)
{
Matrix44 mtxObjMatrix;
//check for a ready to be used matrix
if (RendParams.pMatrix)
mtxObjMatrix = *RendParams.pMatrix;
else
mathCalcMatrix(mtxObjMatrix, RendParams.vPos+m_pModelState->m_vOffset, vAngles, Vec3d(1,1,1), g_CpuFlags);
// Vec3 trans=mtxObjMatrix.GetTranslationOLD();
/* Vec3 trans=RendParams.vPos+m_pModelState->m_vOffset;
float fColor[4] = {0,1,0,1};
extern float g_YLine;
g_pIRenderer->Draw2dLabel( 1,g_YLine, 1.3f, fColor, false,"render trans: %15.10f %15.10f %15.10f %08x",trans.x,trans.y,trans.z,RendParams.pMatrix ); g_YLine+=16.0f;
g_YLine+=16.0f;*/
m_pModelState->Render (RendParams, mtxObjMatrix, *this, translation );
if (g_GetCVars()->ca_DrawBones())
m_pModelState->debugDrawBones (&m_matTranRotMatrix);
if (int nBBoxSegments = g_GetCVars()->ca_DrawBBox())
m_pModelState->debugDrawBoundingBox(&m_matTranRotMatrix, nBBoxSegments);
// draw weapon and binded objects
DrawBoundObjects(RendParams,m_matTranRotMatrix, /*FIXME:nLodLevel*/m_pModelState->m_nLodLevel);
}
if (g_GetCVars()->ca_DebugShaders())
g_GetIRenderer()->DrawLabel (m_matTranRotMatrix.GetRow(3), 4, "Shaders: \"%s\", \"%s\"",m_sShaderTemplateName[0], m_sShaderTemplateName[1]);
}
//! marks all LODs as needed to be reskinned
void CryCharInstance::ForceReskin ()
{
m_pModelState->ForceReskin();
}
// Interface for the renderer - returns the CDLight describing the light in this character;
// returns NULL if there's no light with such index
const CDLight* CryCharInstance::GetBoundLight (int nIndex)
{
CDLight *pDL = NULL;
if (m_pModelState && nIndex >= 0)
{
unsigned numGlobalLights = m_pCryCharBody->GetModel()->numGlobalBoneLights();
if ((unsigned)nIndex < numGlobalLights)
{
pDL = (CDLight *)m_pModelState->getGlobalBoundLight (nIndex);
}
/* else
{
unsigned numDynLights = m_pModelState->numDynBoundLights();
if (nIndex-numGlobalLights < numDynLights)
{
pDL = m_pModelState->getDynBoundLight(nIndex-numGlobalLights);
}
}*/
}
return pDL;
}
void CryCharInstance::DrawBoundObjects(const SRendParams & rRendParams, Matrix44 &inmatTranRotMatrix, int nLOD)
{
static const float fColorBBoxAttached[4] = {0.5,1,1,0.75};
if (g_GetCVars()->ca_NoDrawBound())
return;
BindArray::iterator it, itEnd = m_arrBinds.end();
for (it = m_arrBinds.begin(); it != itEnd; ++it)
{
int nBone = (*it)->nBone;
CryBone& rBone = m_pModelState->getBone(nBone);
IBindable* pBoundObject = (*it)->pObj;
if (!pBoundObject)
continue;
Matrix44 matAttachedObjectMatrix = rBone.GetGlobalMatrix() * inmatTranRotMatrix;
if ((*it)->nFlags & FLAGS_ATTACH_ZOFFSET && !(rRendParams.dwFObjFlags&FOB_RENDER_INTO_SHADOWMAP))
{
// this is the offset to apply
Vec3 vDelta = g_GetISystem()->GetViewCamera().GetPos() - matAttachedObjectMatrix.GetTranslationOLD();
matAttachedObjectMatrix.AddTranslationOLD(vDelta * g_GetCVars()->ca_BoundZOffset());
}
SRendParams rParams (rRendParams);
rParams.pMatrix = &matAttachedObjectMatrix;
// this is required to avoid the attachments using the parent character material (this is the material that overrides the default material in the attachment)
rParams.pMaterial = NULL;
if (m_nFlags & CS_FLAG_DRAW_NEAR)
{
rParams.dwFObjFlags |= FOB_NEAREST;
}
if (g_GetCVars()->ca_DrawBBox()>1) {
Matrix34 m34=Matrix34(GetTransposed44(matAttachedObjectMatrix));
CryAABB caabb;
pBoundObject->GetBBox(caabb.vMin, caabb.vMax);
debugDrawBBox (m34, caabb, g_GetCVars()->ca_DrawBBox()-1,fColorBBoxAttached);
}
if( rParams.nShaderTemplate<0 && // if this is not special rendering pass like render into shadow map
m_sShaderTemplateName[0][0] && // if some shader template is set for this character
m_nShaderTemplateFlags & FLAGS_SET_SHADER_RECURSIVE) // if it allowed to be set also to attachments
{ // register this template into bound object and use for rendering
int nTemplateId=rParams.nShaderTemplate;
pBoundObject->SetShaderTemplate( rParams.nShaderTemplate, m_sShaderTemplateName[0] , 0, false, &nTemplateId );
rParams.nShaderTemplate = nTemplateId;
}
pBoundObject->Render(rParams,Vec3(zero), nLOD);
}
}
IPhysicalEntity *CryCharInstance::GetCharacterPhysics()
{
return m_pModelState->GetCharacterPhysics();
}
IPhysicalEntity *CryCharInstance::GetCharacterPhysics(const char *pRootBoneName)
{
return m_pModelState->GetCharacterPhysics(pRootBoneName);
}
IPhysicalEntity *CryCharInstance::GetCharacterPhysics(int iAuxPhys)
{
return m_pModelState->GetCharacterPhysics(iAuxPhys);
}
void CryCharInstance::DestroyCharacterPhysics(int iMode)
{
m_pModelState->DestroyCharacterPhysics(iMode);
}
// Spawn decal on the character
void CryCharInstance::CreateDecal(CryEngineDecalInfo& DecalLCS)
{
if (g_GetCVars()->ca_EnableDecals() && DecalLCS.fSize > 0.001f)
{
// The decal info in the local coordinate system
CryEngineDecalInfo DecalLocal = DecalLCS;
DecalLocal.fSize *= g_GetCVars()->ca_DecalSizeMultiplier() * float(0.4 + (rand()&0x7F)*0.001953125);
DecalLocal.fAngle = (rand()&0xFF)*float(2*gPi/256.0f);
/*
#if 1
Matrix matCharacter;
matCharacter.Identity();
matCharacter.SetTranslation (Decal.pDecalOwner->GetPos());
Rotate (matCharacter, m_vAngles);
Matrix matInvCharacter;
//matInvCharacter.AssignInverseOf(matCharacter);
matInvCharacter=GetInverted44(matCharacter);
#else
Matrix matInvCharacter;
matInvCharacter.Identity();
RotateInv (matInvCharacter, m_vAngles);
Vec3d ptWCS = Decal.pDecalOwner->GetPos();
DecalLCS.vPos -= ptWCS;
DecalLCS.vHitDirection -= ptWCS;
#endif
DecalLCS.vPos = matInvCharacter.TransformPoint(DecalLCS.vPos);
DecalLCS.vHitDirection = matInvCharacter.TransformVector(DecalLCS.vHitDirection);
*/
m_pModelState->AddDecal (DecalLocal);
}
}
//! Returns the model interface
ICryCharModel* CryCharInstance::GetModel()
{
return m_pCryCharBody;
}
//! Enables receiving OnStart/OnEnd of all animations from this character instance
//! THe specified sink also receives the additional animation events specified through AddAnimationEvent interface
void CryCharInstance::AddAnimationEventSink(ICharInstanceSink * pCharInstanceSink)
{
// not supported yet
}
// removes the event sink for all animations
void CryCharInstance::RemoveAnimationEventSink(ICharInstanceSink * pCharInstanceSink)
{
m_pModelState->removeAnimationEventSink(pCharInstanceSink);
}
void CryCharInstance::RemoveAllAnimationEvents()
{
m_pModelState->removeAllAnimationEvents();
}
//////////////////////////////////////////////////////////////////////////
//! Enables receiving OnStart/OnEnd of specified animation from this character instance
//! The specified sink also receives the additional animation events specified through AddAnimationEvent interface for this animation
void CryCharInstance::AddAnimationEventSink(const char* szAnimName, ICharInstanceSink * pCharInstanceSink)
{
int nAnimId = m_pCryCharBody->GetModel()->findAnimation(szAnimName);
if (nAnimId < 0)
{
if (g_GetCVars()->ca_AnimWarningLevel() >= 2)
g_GetLog()->LogWarning("CryCharInstance(0x%p)::AddAnimationEventSink(\"%s\",0x%p) - animation not found (model \"%s\")", this, szAnimName, pCharInstanceSink, m_pCryCharBody->GetFilePathCStr());
}
else
{
//g_GetLog()->LogToFile("\005CryCharInstance(0x%p)::AddAnimationEventSink(\"%s\",0x%p) - animation not found (model \"%s\")", this, szAnimName, pCharInstanceSink, m_pCryCharBody->GetFilePathCStr());
m_pModelState->setAnimationEventSink (nAnimId, pCharInstanceSink);
}
}
void CryCharInstance::RemoveAnimationEventSink(const char* szAnimName, ICharInstanceSink * pCharInstanceSink)
{
int nAnimId = m_pCryCharBody->GetModel()->findAnimation(szAnimName);
if (nAnimId < 0)
g_GetLog()->LogError("CryCharInstance(0x%p)::RemoveAnimationEventSink(\"%s\",0x%p) - animation not found (model \"%s\")", this, szAnimName, pCharInstanceSink, m_pCryCharBody->GetFilePathCStr());
else
{
//g_GetLog()->LogToFile("\005CryCharInstance(0x%p)::RemoveAnimationEventSink(\"%s\",0x%p) - animation not found (model \"%s\")", this, szAnimName, pCharInstanceSink, m_pCryCharBody->GetFilePathCStr());
assert (m_pModelState->getAnimationEventSink (nAnimId) == pCharInstanceSink);
m_pModelState->setAnimationEventSink (nAnimId, NULL);
}
}
//! Adds an animation event; whenever the character plays the specified frame of the specified animation,
//! it calls back the animation event sinkreceiving OnEvent notification of specified animation for all instances using this model
bool CryCharInstance::AddAnimationEvent(const char * szAnimName, int nFrameID, AnimSinkEventData UserData)
{
int nAnimId = m_pCryCharBody->GetModel()->findAnimation(szAnimName);
m_pModelState->addAnimEvent(nAnimId, nFrameID, UserData);
return true;
}
//! Deletes the animation event; from now on the sink won't be receiving the animation this event
bool CryCharInstance::RemoveAnimationEvent (const char* szAnimName, int nFrameID, AnimSinkEventData UserData)
{
int nAnimId = m_pCryCharBody->GetModel()->findAnimation(szAnimName);
m_pModelState->removeAnimEvent(nAnimId, nFrameID,UserData);
return false;
}
// Returns true if this character was created from the file the path refers to.
// If this is true, then there's no need to reload the character if you need to change its model to this one.
bool CryCharInstance::IsModelFileEqual (const char* szFileName)
{
string strPath = szFileName;
UnifyFilePath(strPath);
#if defined(LINUX)
return !stricmp (strPath.c_str(), m_pCryCharBody->GetFilePathCStr());
#else
return !strcmp (strPath.c_str(), m_pCryCharBody->GetFilePathCStr());
#endif
}
void CryCharInstance::GetMemoryUsage(ICrySizer* pSizer)const
{
#if ENABLE_GET_MEMORY_USAGE
SIZER_SUBCOMPONENT_NAME(pSizer, "Characters");
if (!pSizer->Add (*this))
return;
pSizer->AddContainer (m_arrBinds);
m_pModelState->GetSize (pSizer);
#endif
}
//! Sets up particle spawning. After this funtion is called, every subsequenc frame,
//! During the character deformation, particles will be spawned in the given characteristics.
//! The returned handle is to be used to stop particle spawning
int CryCharInstance::AddParticleEmitter(ParticleParams& rInfo, const CryParticleSpawnInfo& rSpawnInfo)
{
return m_pModelState->getParticleManager()->add (rInfo, rSpawnInfo);
}
//! Stops particle spawning started with StartParticleSpawn that returned the parameter
//! Returns true if the particle spawn was stopped, or false if the handle is invalid
bool CryCharInstance::RemoveParticleEmitter(int nHandle)
{
return m_pModelState->getParticleManager()->remove (nHandle);
}
void CryCharInstance::SetAnimationSpeed(int nLayer, float fSpeed)
{
m_pModelState->setAnimationSpeed (nLayer, fSpeed);
}
//! Set morph speed scale
//! Finds the morph target with the given id, sets its morphing speed and returns true;
//! if there's no such morph target currently playing, returns false
bool CryCharInstance::SetMorphSpeed (int nMorphTargetId, float fSpeed)
{
return m_pModelState->GetSubmesh(0)->SetMorphSpeed(nMorphTargetId, fSpeed);
}
//! Sets the character scale relative to the model
void CryCharInstance::SetScale (const Vec3d& vScale)
{
m_pModelState->setScale (vScale);
}
//! cleans up all decals in this character
void CryCharInstance::ClearDecals()
{
m_pModelState->ClearDecals();
}
//Executes a per-character script command
bool CryCharInstance::ExecScriptCommand (int nCommand, void* pParams, void* pResult)
{
switch (nCommand)
{
case CASCMD_CLEAR_DECALS:
m_pModelState->ClearDecals();
break;
case CASCMD_DUMP_DECALS:
g_GetLog()->Log("\001Instance 0x%p", this);
m_pModelState->DumpDecals();
break;
case CASCMD_DUMP_STATES:
g_GetLog()->LogToFile("\001 Instance 0x%p, state 0x%p", this, m_pModelState);
#if defined(LINUX)
g_GetLog()->LogToFile("\001 %d binds, speed %f, matrix:{%f,%f,%f,%f}{%f,%f,%f,%f}{%f,%f,%f,%f}{%f,%f,%f,%f}", m_arrBinds.size(), m_fAnimSpeedScale, m_matTranRotMatrix.GetData());
#else
g_GetLog()->LogToFile("\001 %d binds, speed %f, matrix:{%g,%g,%g,%g}{%g,%g,%g,%g}{%g,%g,%g,%g}{%g,%g,%g,%g}", m_arrBinds.size(), m_fAnimSpeedScale, m_matTranRotMatrix);
#endif
m_pModelState->DumpState();
break;
case CASCMD_START_MANY_ANIMS:
{
const CASCmdStartMultiAnims& ma = *(CASCmdStartMultiAnims*)(pParams);
for (int i = 0; i < ma.numAnims; ++i)
{
const CASCmdStartAnim& sa = ma.pAnims[i];
g_GetLog()->LogToConsole("\001Starting \"%s\" @ %d", sa.szAnimName, sa.nLayer);
StartAnimation (sa.szAnimName, CryCharAnimationParams(ma.fBlendTime, ma.fBlendTime, sa.nLayer));
}
}
break;
case CASCMD_DEBUG_DRAW:
m_pModelState->debugDrawBones();
m_pModelState->debugDrawBoundingBox(NULL, 4);
break;
}
return true;
}
// notifies the renderer that the character will soon be rendered
void CryCharInstance::PreloadResources ( float fDistance, float fTime, int nFlags )
{
FUNCTION_PROFILER( g_GetISystem(),PROFILE_3DENGINE );
if (m_pModelState)
m_pModelState->PreloadResources(fDistance, fTime, nFlags);
CryCharInstanceBase::PreloadResources (fDistance, fTime, nFlags);
}
void CryCharInstanceBase::PreloadResources ( float fDistance, float fTime, int nFlags )
{
for (BindArray::iterator it = m_arrBinds.begin(); it != m_arrBinds.end(); ++it)
{
StatObjBind * pBind = (*it);
if(pBind && pBind->pObj)
pBind->pObj->PreloadResources(fDistance, fTime, nFlags);
}
}
// adds a submesh, returns handle to it which can be used to delete the submesh
// submesh is created either visible or invisible
// submesh creation/destruction is heavy operations, so the clients must use they rarely,
// and set visible/invisible when they need to turn them on/off
// But creating many submeshes is memory-consuming so the number of them must be kept low at all times
ICryCharSubmesh* CryCharInstance::NewSubmesh (ICryCharModel* pModel, bool bVisible)
{
return m_pModelState->AddSubmesh (pModel, bVisible);
}
// adds submesh to the specified slot; replaces submesh if there's some there
ICryCharSubmesh* CryCharInstance::NewSubmesh (unsigned nSlot, ICryCharModel* pModel, bool bVisible)
{
return m_pModelState->SetSubmesh(nSlot, pModel, bVisible);
}
// removes submesh from the character
void CryCharInstance::RemoveSubmesh (ICryCharSubmesh* pSubmesh)
{
return m_pModelState->RemoveSubmesh(pSubmesh);
}
void CryCharInstance::RemoveSubmesh (unsigned nSlot)
{
return m_pModelState->RemoveSubmesh(nSlot);
}
// enumeration of submeshes
size_t CryCharInstance::NumSubmeshes()
{
return m_pModelState->NumSubmeshes();
}
ICryCharSubmesh* CryCharInstance::GetSubmesh(unsigned i)
{
return m_pModelState->GetSubmesh(i);
}
ICryCharFxTrail* CryCharInstance::NewFxTrail (unsigned nSlot, const struct CryCharFxTrailParams& rParams)
{
return m_pModelState->NewFxTrail(nSlot, rParams);
}
void CryCharInstance::RemoveFxTrail(unsigned nSlot)
{
m_pModelState->RemoveFxTrail(nSlot);
}
// returns the number of bindings; valid until the next attach/detach operation
size_t CryCharInstance::GetBindingCount()
{
return m_arrBinds.size();
}
// fills the given array with GetBindingCount() pointers to IBindable
void CryCharInstance::EnumBindables(IBindable** pResult)
{
for (size_t i = 0; i < m_arrBinds.size(); ++i)
pResult[i] = m_arrBinds[i]->pObj;
}