#include "StdAfx.h" #include "AnimObject.h" #include "ClientApp.h" #include "SceneManager.h" #include "ResourceManager.h" #include "ObjectManager.h" #include "Console.h" #include "ItemManager.h" NiFixedString ANIMSEQ_IDLE; NiFixedString ANIMSEQ_WALK; NiFixedString ANIMSEQ_RUN; NiFixedString ANIMSEQ_DEATH; float CAnimObject::ms_fLODDist[3] = { 20.0f * 20.0f, 30.0f * 30.0f, 40.0f * 40.0f, }; void CAnimObject::StaticInitAnimNames() { ANIMSEQ_IDLE = ("Stand_100"); ANIMSEQ_WALK = ("Walk_100"); ANIMSEQ_RUN = ("Run_100"); ANIMSEQ_DEATH = ("Death"); } void CAnimObject::StaticDeInitAnimNames() { ANIMSEQ_IDLE = NULL; ANIMSEQ_WALK = NULL; ANIMSEQ_RUN = NULL; ANIMSEQ_DEATH = NULL; } CAnimObject::CAnimObject(void) : m_fInitBoundRadius(0.0f) { //第0个必须得是模型Node //由于模型延后加载,这里放一个NiNode 用来占位 m_spSceneNode->SetAt(0, NiNew NiNode); m_SequenceMap.clear(); m_CurAnimation = NULL; m_pkLODCtrl = 0; m_eShadowType = CShadowGeometry::ST_STATIC; m_uiWaitSeqNum = 0; m_bClientObject = false; m_uiAvatarReversion = 0; m_bActorLoading = false; } CAnimObject::~CAnimObject(void) { m_SequenceMap.clear(); m_pkLODCtrl = 0; g_ResMgr->FreeKfm(m_spActorManager); m_spActorManager = NULL; m_spShadowGeometry = NULL; //有可能主模型还没有装载完,对象就被删除了 CAvatarModel* pkAvatarModel; for(unsigned int i = 0; i < m_kAvatarModels.GetSize(); ++i) { //切记,没有装载完的装备,不能在这里删除 pkAvatarModel = m_kAvatarModels.GetAt(i); if(pkAvatarModel->IsFinished()) NiDelete m_kAvatarModels.GetAt(i); } m_kBoundBoxList.RemoveAll(); m_kAvatarModels.RemoveAll(); } void CAnimObject::RecursiveSetBones(NiNode* pkNode, int i) { NiIntegerExtraData* pkData = 0; pkData = (NiIntegerExtraData*)pkNode->GetExtraData("prior"); if (pkData) { pkData->SetValue(i); } else { pkData = NiNew NiIntegerExtraData(i); bool bret = pkNode->AddExtraData("prior", pkData); NIASSERT(bret); } for (unsigned int ui = 0; ui < pkNode->GetArrayCount(); ui++) { NiAVObject* pkChild = pkNode->GetAt(ui); if (NiIsKindOf(NiNode, pkChild)) { RecursiveSetBones((NiNode*)pkChild, i); } } } BOOL CAnimObject::CreateActor(const char* KfmName, bool bAsync) { NIASSERT(KfmName && m_spSceneNode); NIASSERT(!m_spActorManager); NIASSERT(!m_bActorLoading); m_bActorLoading = true; if(bAsync) { //异步后台线程装载 CAnimModel* pkAnimModel = NiNew CAnimModel(GetGUID(), KfmName, IsClientObject()); g_pkTaskManager->PushTask(pkAnimModel); } else { //同步装载 NiActorManager* pkActorManager = g_ResMgr->LoadKfm(KfmName); OnActorLoaded(pkActorManager); } return TRUE; } void CAnimObject::OnActorLoaded(NiActorManager* pkActorManager) { m_bActorLoading = false; m_spActorManager = pkActorManager; ++m_uiAvatarReversion; RemapSequenceID(); RegistTextKey(); // init time AnimationID eInitID = GetAnimationIDByName("stand"); m_spActorManager->SetTargetAnimation(eInitID); m_spActorManager->Update(0.0f); m_uiCurrAnimID = NiActorManager::INVALID_SEQUENCE_ID; //这里不需要和初始动作ID一致 m_uiSecAnim = NiActorManager::INVALID_SEQUENCE_ID; m_fNextEndTime = NiActorManager::INVALID_TIME; m_fNextEndTime2 = NiActorManager::INVALID_TIME; m_bNotUpdateTime = false; NiNode* ActorRoot = NiDynamicCast(NiNode, m_spSceneNode); NIASSERT(ActorRoot); ActorRoot->SetAt(0, m_spActorManager->GetNIFRoot()); bool bSelectedUpdate = true; bool bRigid = false; ActorRoot->SetSelectiveUpdateFlags(bSelectedUpdate, true, bRigid); m_spSceneNode->UpdateNodeBound(); m_spSceneNode->UpdateProperties(); m_spSceneNode->UpdateEffects(); m_spSceneNode->Update(0.0f); CaculateBoundBox(); NIASSERT(m_pkLODCtrl == 0); m_pkLODCtrl = m_spActorManager->GetBoneLODController(); if (m_pkLODCtrl) { //NiBoneLODController::NiTriBasedGeomSet geoset; //NiBoneLODController::NiSkinInstanceSet instset; //m_pkLODCtrl->GetSkinData(geoset, instset); m_pkLODCtrl->SetBoneLOD(0); } CreateShadow(); //处理换装 OnEquipmentChanged(); //ReSetAlpha(); //恢复动作 SetCurAnimation(m_kCurAnimationParam.kName, m_kCurAnimationParam.fFreq, m_kCurAnimationParam.bLoop, m_kCurAnimationParam.bForceStart, m_kCurAnimationParam.iPriority); } bool CAnimObject::HasAnimBound() { return m_kBoundBoxList.GetSize() > 0; } bool CAnimObject::GetPickBound(NiBound& kBound) { if (!GetSceneNode()) return false; kBound.SetRadius(0.0f); int nBoundBoxSize = m_kBoundBoxList.GetSize(); //if (nBoundBoxSize > 0) //{ // for (int ui = 0; ui < nBoundBoxSize; ui++) // { // NiAVObject* pkObj = m_kBoundBoxList.GetAt(ui); // if (!pkObj) // { // continue ; // } // if ( pkObj ) // { // // bool bIsEquals = pkObj->GetName().Equals("Dummy01"); // if ( GetName().Equals(_TRAN("任务公告板")) ) // bIsEquals = false; // if ( bIsEquals )//GetUInt32Value(UNIT_FIELD_PETNUMBER) || // continue; // if (pkObj&& pkObj->IsVisualObject()) // { // if (kBound.GetRadius() == 0.0f) // { // kBound = pkObj->GetWorldBound(); // } // else // { // kBound.Merge(&pkObj->GetWorldBound()); // } // } // } // } //} //else //旧资源 { kBound.SetRadius(0.f); NiNode* pkNode = NiDynamicCast(NiNode,GetSceneNode()->GetObjectByName("Scene Root")); if (!pkNode) return false; unsigned int ui = 0; for (ui; ui < pkNode->GetArrayCount(); ui++) { NiAVObject* pkObj = pkNode->GetAt(ui); if (!pkObj || ( pkObj->GetName().Contains("Dummy01")&&(GetGameObjectType() != GOT_SCENEOBJECT) ) ) { continue ; } if ( pkObj ) { bool bIsEquals = false; if ( GetName().Equals(_TRAN("任务公告板")) ) bIsEquals = false; if ( bIsEquals )//GetUInt32Value(UNIT_FIELD_PETNUMBER) || continue; if (pkObj&& pkObj->IsVisualObject()) { if (kBound.GetRadius() == 0.0f) { kBound = pkObj->GetWorldBound(); } else { kBound.Merge(&pkObj->GetWorldBound()); } } } } } return kBound.GetRadius() != 0.0f; } bool CAnimObject::IsPick(NiPick& kPicker,const NiPoint3& kOrig,const NiPoint3& kDir) { unsigned int nSize = m_kBoundBoxList.GetSize(); if ( !nSize ) return false; NiNode* pkNode = NiDynamicCast(NiNode,GetSceneNode()->GetObjectByName("Scene Root")); if (!pkNode) return false; unsigned int ui = 0; for (ui; ui < m_kBoundBoxList.GetSize(); ui++) { NiAVObject* pkObj = m_kBoundBoxList.GetAt(ui); if (!pkObj) { continue ; } if ( pkObj ) { bool bIsEquals = pkObj->GetName().Equals("Dummy01"); if ( GetName().Equals(_TRAN("任务公告板")) ) bIsEquals = false; if ( bIsEquals )//GetUInt32Value(UNIT_FIELD_PETNUMBER)|| continue; kPicker.SetTarget(pkObj); if ( kPicker.PickObjects(kOrig, kDir) ) return true; } } return false; } void CAnimObject::CaculateBoundBox() { NiNode* pDummy01 = (NiNode*)m_spSceneNode->GetObjectByName("Dummy01"); if ( pDummy01 ) CollectBoundBox(pDummy01); } void CAnimObject::CollectBoundBox(NiAVObject* pObject) { if (!pObject) return; if ( pObject->GetName().Contains("NDLCD") ) { m_kBoundBoxList.Add( pObject ); //NiNode* pParentNode = (NiNode*)pObject; //if ( pParentNode->GetArrayCount() > 0 ) //{ // NiAVObject* pChild = pParentNode->GetAt(0); // //if ( pChild ) // //pChild->SetAppCulled(false); //} } else { if( NiIsKindOf(NiNode, pObject) ) { NiNode* pkNode = NiDynamicCast(NiNode, pObject); if (pkNode) { if ( !pkNode->GetAppCulled() ) { for( UINT i = 0; i < pkNode->GetArrayCount(); ++i ) { CollectBoundBox(pkNode->GetAt( i )); } } } } } } void CAnimObject::OnEquipmentChanged() { if(!IsActorLoaded()) return; //主模型还没有装载完 //保证按照服务器端发下来的换装顺序 //进行实际的换装工作 CAvatarModel* pkAvatarModel; for(unsigned int i = 0; i < m_kAvatarModels.GetSize(); ++i) { pkAvatarModel = m_kAvatarModels.GetAt(i); if(!pkAvatarModel || !pkAvatarModel->IsFinished()) break; ItemMgr->OnEquipmentChangeReal((CPlayer*)this, pkAvatarModel->GetItemId(), pkAvatarModel->GetSlotIndex(), pkAvatarModel->GetAttachmentSlot()); NiDelete pkAvatarModel; m_kAvatarModels.SetAt(i, NULL); ++m_uiAvatarReversion; } m_kAvatarModels.Compact(); //ReSetAlpha(); } void CAnimObject::RegistTextKey() { m_spActorManager->SetCallbackObject(this); unsigned int* puiSequenceIDs; unsigned int uiNumIDs; m_spActorManager->GetKFMTool()->GetSequenceIDs(puiSequenceIDs, uiNumIDs); NiControllerSequence* pkSequence; NiTextKeyExtraData* pkExtraData; for(unsigned int ui = 0; ui < uiNumIDs; ++ui) { pkSequence = m_spActorManager->GetSequence(puiSequenceIDs[ui]); if( pkSequence == NULL ) continue; pkExtraData = pkSequence->GetTextKeys(); if(pkExtraData) { unsigned int uiNumKeys; NiTextKey* pKeys = pkExtraData->GetKeys(uiNumKeys); for(unsigned int uiK = 0; uiK < uiNumKeys; ++uiK) { m_spActorManager->RegisterCallback(NiActorManager::TEXT_KEY_EVENT, puiSequenceIDs[ui], pKeys[uiK].GetText()); /* if(pKeys[uiK].GetText().Equals("footstep")) { m_spActorManager->RegisterCallback(NiActorManager::TEXT_KEY_EVENT, puiSequenceIDs[ui], ""); }*/ } } } NiFree(puiSequenceIDs); } AnimationID CAnimObject::GetAnimationIDByName(const NiFixedString& AnimName) const { SequenceMap::const_iterator it = m_SequenceMap.find(AnimName); if (it != m_SequenceMap.end()) { return it->second; } //char szBuffer[256]; //sprintf(szBuffer, "player %s cannot find anim seq %s\n", this->GetName(), AnimName); //MessageBox(NULL, szBuffer, "warning", MB_OK | MB_ICONWARNING); return NiActorManager::INVALID_SEQUENCE_ID; } void CAnimObject::RemapSequenceID() { m_uiWaitSeqNum = 0; m_SequenceMap.clear(); unsigned int* puiSequenceIDs; unsigned int uiNumIDs; NiControllerSequence* pkSequence; m_spActorManager->GetKFMTool()->GetSequenceIDs(puiSequenceIDs, uiNumIDs); for(unsigned int ui = 0; ui < uiNumIDs; ++ui) { AnimationID AnimID = puiSequenceIDs[ui]; pkSequence = m_spActorManager->GetSequence(AnimID); if( pkSequence ) { const NiFixedString seqName = pkSequence->GetName(); m_SequenceMap.insert(SequenceMap::value_type(seqName, AnimID)); if (seqName.Contains("wait")) { m_uiWaitSeqNum++; } } } NiFree(puiSequenceIDs); } void CAnimObject::Update(float dt) { CPlayerLocal* pkLocalPlayer = ObjectMgr->GetLocalPlayer(); if (m_pkLODCtrl && pkLocalPlayer) { CCamera& kCamera = pkLocalPlayer->GetCamera();//.GetTranslate(); const NiCamera& kNiCamera = kCamera.GetNiCamera(); NiPoint3 kDist = GetPosition() - kNiCamera.GetWorldLocation(); float dist = kDist.SqrLength(); bool bPast = false; int iLODLvl = m_pkLODCtrl->GetBoneLOD(); if (iLODLvl == 0) { if (dist > ms_fLODDist[iLODLvl] + 2.0f) { bPast = true; } } else if (iLODLvl == 2) { if (dist < ms_fLODDist[iLODLvl-1] - 2.0f) { bPast = true; } } else { if (dist > ms_fLODDist[iLODLvl] + 2.0f || dist < ms_fLODDist[iLODLvl - 1] - 2.0f) { bPast = true; } } if (bPast) { if (dist > ms_fLODDist[1]) { m_pkLODCtrl->SetBoneLOD(2); } else if (dist > ms_fLODDist[0]) { m_pkLODCtrl->SetBoneLOD(1); } else { m_pkLODCtrl->SetBoneLOD(0); } } } /* if (SYState()->ClientApp->GetAccumTime() - m_fTime > 3.f) { if (m_pkLODCtrl) { int iBoneLOD = m_pkLODCtrl->GetBoneLOD(); iBoneLOD++; m_pkLODCtrl->SetBoneLOD(iBoneLOD%3); } m_fTime = SYState()->ClientApp->GetAccumTime(); } */ UpdateCurAnimation(); } NiControllerSequence* CAnimObject::SetCurAnimation(const char* AnimName, float Frequence /*= 1.0f*/, BOOL bLoop /*= FALSE*/, BOOL bForceStart /*= FALSE*/, int iPriority /*= 0*/) { m_kCurAnimationParam.kName = AnimName; m_kCurAnimationParam.fFreq = Frequence; m_kCurAnimationParam.bLoop = (bool)bLoop; m_kCurAnimationParam.bForceStart = (bool)bForceStart; m_kCurAnimationParam.iPriority = iPriority; if(!IsActorLoaded()) return NULL; AnimationID AnimID = GetAnimationIDByName(AnimName); if(AnimID == NiActorManager::INVALID_SEQUENCE_ID) { //char szBuffer[256]; //sprintf(szBuffer, "Gameobject can't find sequence\n"); //::NiOutputDebugString(szBuffer); return NULL; } return SetCurAnimation(AnimID, Frequence, bLoop, bForceStart, iPriority); } NiControllerSequence* CAnimObject::SetCurAnimation(AnimationID Anim, float Frequence /*= 1.0f*/, BOOL bLoop /*= FALSE*/, BOOL bForceStart /*= FALSE*/, int iPriority /*= 0*/) { if (Anim == NiActorManager::INVALID_SEQUENCE_ID) return NULL; if (bForceStart) { NiActorManager::TransitionState eTransState = m_spActorManager->GetTransitionState(); if (eTransState != NiActorManager::NO_TRANSITION) { NiActorManager::SequenceID eNextID = m_spActorManager->GetNextAnimation(); NiActorManager::SequenceID eCurID = m_spActorManager->GetCurAnimation(); NiControllerSequence* pkSourceSeq = m_spActorManager->GetSequence(eCurID); NiControllerSequence* pkDestSeq = m_spActorManager->GetSequence(eNextID); NIASSERT(pkSourceSeq && pkDestSeq); if (pkSourceSeq != NULL && pkDestSeq != NULL) { bool bRet = m_spActorManager->GetControllerManager()->StopBlendFromSequence(pkSourceSeq, pkDestSeq); NIASSERT(bRet); m_spActorManager->Update(NI_INFINITY); } } m_spActorManager->SetTargetAnimation(NiActorManager::INVALID_SEQUENCE_ID, -1); m_spActorManager->Update(0.0f); m_uiCurrAnimID = m_spActorManager->GetCurAnimation(); } if (m_uiCurrAnimID != Anim) { m_uiCurrAnimID = Anim; m_spActorManager->SetTargetAnimation(Anim, iPriority); NiControllerSequence* pkCurSeq = m_spActorManager->GetSequence(Anim); NIASSERT(pkCurSeq != NULL); if (bLoop) { pkCurSeq->SetCycleType(NiTimeController::LOOP); } else { pkCurSeq->SetCycleType(NiTimeController::CLAMP); } m_CurAnimation = pkCurSeq; } else { NiControllerSequence* pkCurSeq = m_spActorManager->GetSequence(m_uiCurrAnimID); NiTimeController::CycleType eCycleType = bLoop?NiTimeController::LOOP:NiTimeController::CLAMP; if (pkCurSeq->GetCycleType() != eCycleType) { pkCurSeq->SetCycleType(eCycleType); } } if (m_CurAnimation) m_CurAnimation->SetFrequency(Frequence); m_bNotUpdateTime = true; return m_CurAnimation; } //--------------------------------------------------------------------------- NiBoneLODController* CAnimObject::FindBoneLODController( NiAVObject* pkObject) { NiBoneLODController* pkBoneLOD = NiGetController(NiBoneLODController, pkObject); if (pkBoneLOD) { return pkBoneLOD; } NiNode* pkNode = NiDynamicCast(NiNode, pkObject); if (pkNode) { for (unsigned int ui = 0; ui < pkNode->GetArrayCount(); ui++) { NiAVObject* pkChild = pkNode->GetAt(ui); if (pkChild) { pkBoneLOD = FindBoneLODController(pkChild); if (pkBoneLOD) { return pkBoneLOD; } } } } return NULL; } float CAnimObject::UpdateCurAnimation() { if(m_spActorManager) { m_textKeys.RemoveAll(); float fCurTime = SYState()->ClientApp->GetAccumTime(); m_spActorManager->Update(fCurTime); } return 0.0f; } // Animation callback function void CAnimObject::AnimActivated(NiActorManager* pkManager, NiActorManager::SequenceID eSequenceID, float fCurrentTime, float fEventTime) { } void CAnimObject::AnimDeactivated(NiActorManager* pkManager, NiActorManager::SequenceID eSequenceID, float fCurrentTime, float fEventTime) { } void CAnimObject::TextKeyEvent(NiActorManager* pkManager, NiActorManager::SequenceID eSequenceID, const NiFixedString& kTextKey, const NiTextKeyMatch* pkMatchObject, float fCurrentTime, float fEventTime) { if (kTextKey == "end") { m_textKeys.Add(kTextKey); } if (kTextKey.Contains("effect")) { m_textKeys.Add(kTextKey); } //"hide_arm" //"draw_arm" if (kTextKey.Contains("hide_arm") || kTextKey.Contains("draw_arm")) { m_textKeys.Add(kTextKey); } //"leftfoot" //"rightfoot" if (kTextKey.ContainsNoCase("leftfoot") || kTextKey.ContainsNoCase("rightfoot")) { m_textKeys.Add(kTextKey); } if (kTextKey.ContainsNoCase("bossdragon _leftfront") || kTextKey.ContainsNoCase("bossdragon _rightfront")) { m_textKeys.Add(kTextKey); } } void CAnimObject::EndOfSequence(NiActorManager* pkManager, NiActorManager::SequenceID eSequenceID, float fCurrentTime, float fEventTime) { DeactivateAnimation(eSequenceID, 0.1f); } NiControllerSequence* CAnimObject::ActivateAnimation(const char* AnimName, int iPriority /* = 1 */, int ip2 /*= 0*/, float fEaseInTime /* = 0.25f */, AnimationID eSync /* = NiKFMTool::SYNC_SEQUENCE_ID_NONE */, bool bLoop /*= false*/, bool bEndSeq /*= true*/, bool bDeactivateAll /*= false*/) { AnimationID AnimID = GetAnimationIDByName(AnimName); if(AnimID == NiActorManager::INVALID_SEQUENCE_ID) { //char szBuffer[256]; //sprintf(szBuffer, "Gameobject can't find sequence\n"); //::NiOutputDebugString(szBuffer); return NULL; } return ActivateAnimation(AnimID, iPriority, ip2, fEaseInTime, eSync, bLoop, bEndSeq, bDeactivateAll); } void CAnimObject::DeactivateAllLayerAnims() { for ( unsigned int ui = 0; ui < m_kLayerAnimations.GetSize(); ui++ ) { AnimationID eCode = m_kLayerAnimations.GetAt(ui); DeactivateAnimation(eCode, 0.0f, true); } m_kLayerAnimations.RemoveAll(); } // For activating secondary (layered) animations NiControllerSequence* CAnimObject::ActivateAnimation(AnimationID eCode, int iPriority /* = 1 */, int ip2 /*= 0*/, float fEaseInTime /* = 0.25f */, AnimationID eSync /* = NiKFMTool::SYNC_SEQUENCE_ID_NONE */, bool bLoop /*= false*/, bool bEndSeq /*= true*/, bool bDeactivateAll /*=false*/) { if( !m_spActorManager ) return 0; if (bDeactivateAll) { DeactivateAllLayerAnims(); } else { if (eCode != INVALID_ANIMID) DeactivateAnimation(eCode, 0.0f, true); } NIASSERT(eCode != INVALID_ANIMID); if (eCode == INVALID_ANIMID) return 0; bool bret = m_spActorManager->ActivateSequence(eCode, ip2, true, 1.0f, fEaseInTime, eSync, iPriority); NIASSERT(bret); NiControllerSequence* pkCurSeq = m_spActorManager->GetSequence(eCode); if (!pkCurSeq) return 0; m_uiSecAnim = eCode; if (bLoop) { pkCurSeq->SetCycleType(NiTimeController::LOOP); } if (bEndSeq) { m_spActorManager->RegisterCallback(NiActorManager::END_OF_SEQUENCE, eCode); } m_fNextEndTime2 = m_spActorManager->GetNextEventTime(NiActorManager::TEXT_KEY_EVENT, m_uiSecAnim, "end"); int iIndex = m_kLayerAnimations.Find(eCode); if (iIndex == -1) { m_kLayerAnimations.Add(eCode); } return pkCurSeq; } bool CAnimObject::DeactivateAnimation(AnimationID eCode, float fEaseOutTime /* = 0.0f */, bool bForce /*= false*/) { if (eCode == INVALID_ANIMID) return false; NiControllerSequence* pkCurSeq = m_spActorManager->GetSequence(eCode); if (!pkCurSeq) return false; if (bForce) { pkCurSeq->Deactivate(0.0f, false); return true; } bool bSucc = m_spActorManager->DeactivateSequence(eCode, fEaseOutTime); return bSucc; } void CAnimObject::DeactivateSecAnimation(float fEaseOutTime) { if (m_uiSecAnim != INVALID_ANIMID) { NiControllerSequence* pkSeq = m_spActorManager->GetSequence(m_uiSecAnim); if (pkSeq->GetState() == NiControllerSequence::INACTIVE) return; NIVERIFY(pkSeq->GetState() == NiControllerSequence::ANIMATING); DeactivateAnimation(m_uiSecAnim, fEaseOutTime); m_uiSecAnim = INVALID_ANIMID; } } void CAnimObject::ProcessAnimation(DWORD dwDeltaTime) { } bool CAnimObject::Draw(CCullingProcess* pkCuller) { if(CGameObject::Draw(pkCuller)) { if(m_spShadowGeometry )//&& m_fAlpha >= 1.0f { m_spShadowGeometry->Click(GetPosition()); if(m_spShadowGeometry->IsDynamicShadow()) pkCuller->OnDynmicShadowVisible(m_spShadowGeometry); else pkCuller->ProcessObject(m_spShadowGeometry->GetShadowGeometry(), CCullingProcess::CullTerObject); } return true; } return false; } void CAnimObject::ReflashShadowCaster() { if(m_spShadowGeometry) m_spShadowGeometry->ResetCaster(m_spSceneNode); } void CAnimObject::ChangeShadowType(CShadowGeometry::ShadowType eShadowType) { if(m_eShadowType == eShadowType) return; m_eShadowType = eShadowType; CreateShadow(); } void CAnimObject::CreateShadow() { m_spShadowGeometry = CShadowGeometry::Create(m_eShadowType); if(m_spShadowGeometry) m_spShadowGeometry->ResetCaster(m_spSceneNode); }