#include "StdAfx.h" #include "SceneManager.h" #include "Player.h" #include "LightManager.h" #include "ClientApp.h" #include "Creature.h" #include "ObjectManager.h" #include "SceneProperty.h" #include "Effect/DecalManager.h" #include "Effect/EffectManager.h" #include "NiFont.h" #include "Map/Water.h" #include "Map/Festival_Flag.h" #include "Utils/MapInfoDB.h" #include "Utils/MersenneTwister.h" #include "Console.h" #include "ResourceManager.h" CCollisionManager::CCollisionManager() { } CCollisionManager::~CCollisionManager() { } void CCollisionManager::InitPick() { m_Picker.SetIntersectType(NiPick::BOUND_INTERSECT); // 必须使用这个,否则会带来额外性能开销. m_Picker.SetReturnTexture( false ); m_Picker.SetReturnNormal( false ); m_Picker.SetReturnSmoothNormal(false); m_Picker.SetReturnColor( false ); m_Picker.SetCoordinateType(NiPick::WORLD_COORDINATES); } bool CCollisionManager::PickScene(ScenePickGroup* Group, const NiPoint3& kStart,const NiPoint3& kDir, CGameObject**Result, NiPoint3* PickPos, bool bNormals, bool bFrontOnly, bool bFindFirst) { m_Picker.SetReturnNormal(bNormals); m_Picker.SetFrontOnly(bFrontOnly); m_Picker.SetCoordinateType(NiPick::WORLD_COORDINATES); if (bFindFirst) { m_Picker.SetPickType(NiPick::FIND_FIRST); m_Picker.SetSortType(NiPick::NO_SORT); } else { m_Picker.SetPickType(NiPick::FIND_ALL); m_Picker.SetSortType(NiPick::SORT); } ObjectList& PickTargets = Group->Objects; ObjectList::const_iterator End = PickTargets.end(); NiAVObject* Target = NULL; CGameObject* ResultObject = NULL; NiPoint3 IntersectPoint; NiPoint3 ResultIntersectPoint; float MinDistance = FLT_MAX; for (ObjectList::iterator it = PickTargets.begin(); it != End; ++it) { CGameObject* TargetObj = *it; if( TargetObj == NULL ) continue; Target = TargetObj->GetSceneNode(); if (Target == NULL || Target->GetAppCulled()) { continue; } // 设置为目标 m_Picker.SetTarget(Target); //D3DXBoxBoundProbe(D3DXVECTOR3(0.0f, 0.0f, 0.0f), ) // RAY-TRACE if (m_Picker.PickObjects(kStart, kDir)) { NiPick::Record* pkRecord = m_Picker.GetResults().GetAt(0); if (pkRecord != NULL) { IntersectPoint = pkRecord->GetIntersection(); float Distance = (IntersectPoint - kStart).SqrLength(); if (Distance < MinDistance) { MinDistance = Distance; ResultIntersectPoint = IntersectPoint; ResultObject = TargetObj; } } } } if (ResultObject != NULL) { if (Result) { *Result = ResultObject; } if (PickPos) { *PickPos = ResultIntersectPoint; } } return ResultObject != NULL; } bool CCollisionManager::PickScene(const NiPoint3& kStart,const NiPoint3& kDir,UINT Groups, CGameObject**Result, NiPoint3* PickPos, bool bNormals, bool bFrontOnly, bool bFindFirst) { bool Ret = false; if (Groups & SPG_PLAYER) { Ret = PickScene(&m_SPG[GT_PLAYER], kStart, kDir,Result, PickPos, bNormals, bFrontOnly, bFindFirst); } if (!Ret && (Groups & SPG_ITEM)) { Ret = PickScene(&m_SPG[GT_ITEM], kStart, kDir,Result, PickPos, bNormals, bFrontOnly, bFindFirst); } if (!Ret && (Groups & SPG_CREATURE)) { Ret = PickScene(&m_SPG[GT_CREATURE], kStart, kDir, Result, PickPos, bNormals, bFrontOnly, bFindFirst); } return Ret; } BOOL CCollisionManager::AddToGroup(ScenePickGroup* Group, CGameObject* ObjectID) { Group->Objects.Add(ObjectID, ObjectID); return TRUE; } void CCollisionManager::RemoveFromGroup(ScenePickGroup* Group,CGameObject* ObjectID) { Group->Objects.Remove(ObjectID, NULL); } BOOL CCollisionManager::AttachToPickGroup(EScenePickGroup PickGroupFlags , CGameObject* Object) { NIASSERT(Object && Object->GetSceneNode()); ScenePickGroup* DestGroup = NULL; switch(PickGroupFlags) { case SPG_PLAYER: DestGroup = &m_SPG[GT_PLAYER]; break; case SPG_ITEM: DestGroup = &m_SPG[GT_ITEM]; break; case SPG_CREATURE: DestGroup = &m_SPG[GT_CREATURE]; break; } if (DestGroup != NULL) { return AddToGroup(DestGroup, Object); } return FALSE; } BOOL CCollisionManager::DetachFromPickGroup(EScenePickGroup PickGroupFlags, CGameObject* Object) { if (Object == NULL) { return TRUE; } ScenePickGroup* DestGroup = NULL; switch(PickGroupFlags) { case SPG_PLAYER: DestGroup = &m_SPG[GT_PLAYER]; break; case SPG_ITEM: DestGroup = &m_SPG[GT_ITEM]; break; case SPG_CREATURE: DestGroup = &m_SPG[GT_CREATURE]; break; } if (DestGroup != NULL) { RemoveFromGroup(DestGroup, Object); } return TRUE; } ////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////// CSceneManager::CSceneManager(void) { m_CollisionMgr = NULL; m_pkLightManager = NULL; m_pkMap = NULL; m_SceneProperty = NULL; memset(m_ObjectPool,0,sizeof(void*)*OBJECT_MAX); m_PoolMaxValidIndex = 1; m_pkDecalManager = NULL; m_spBoundBoxRender = NULL; m_bShowBoundBoxRender = false; m_pBoundBoxRenderObject = NULL; m_ptrWaterSound = NULL; m_uiLastTime = 0; } CSceneManager::~CSceneManager(void) { } BOOL CSceneManager::Initialize() { m_spAlphaSorter = NiNew NiAlphaAccumulator(); m_spEffectAS = NiNew NiAlphaAccumulator(); m_spCuller = NiNew CCullingProcess(); if (!m_spCuller) return FALSE; // Light m_pkLightManager = NiNew CLightManager; if (!m_pkLightManager) return FALSE; // m_SceneProperty = NiNew CSceneProperty; NIASSERT(m_SceneProperty); if (!m_SceneProperty) return FALSE; m_CollisionMgr = new CCollisionManager; NIASSERT(m_CollisionMgr); if (!m_CollisionMgr) return FALSE; m_pkDecalManager = NiNew CDecalManager; NIASSERT(m_pkDecalManager); if (!m_pkDecalManager) return FALSE; if (!m_pkDecalManager->Initialize()) return FALSE; if ( !m_spBoundBoxRender ) CreateBoundBoxRender(); //SetWaterBubbleCount(MAX_WATERBUBBLE_COUNT); m_pRandomMize = new CRandomMersenne(generate_seed()); return TRUE; } void CSceneManager::Destroy() { if (m_pkMap) { NiDelete m_pkMap; m_pkMap = NULL; } if (m_pkLightManager) { NiDelete m_pkLightManager; m_pkLightManager = NULL; } if(m_SceneProperty) { NiDelete m_SceneProperty; m_SceneProperty = NULL; } if(m_pkDecalManager) { NiDelete m_pkDecalManager; m_pkDecalManager = NULL; } if (m_CollisionMgr) { delete m_CollisionMgr; m_CollisionMgr = NULL; } if ( m_ptrWaterSound ) { m_ptrWaterSound = 0; } } BOOL CSceneManager::CanRender() const { return (m_pkMap != NULL); } bool CSceneManager::RenderObject(NiAVObject* pkAVObject) { return m_spCuller->ProcessObject(pkAVObject, CCullingProcess::CullSceneObj); } extern bool g_bHiddenPlayer; void CSceneManager::RenderScene(const NiCamera& Camera) { if (!CanRender()) { return; } CPlayerLocal* pLocal = ObjectMgr->GetLocalPlayer(); NiRenderer* pkRenderer = SYState()->Render; NIASSERT(pkRenderer ); pkRenderer->SetCameraData(&Camera); NiD3DRenderer* pkD3DRenderer = (NiD3DRenderer*)NiRenderer::GetRenderer(); NiD3DRenderState* pkRenderState = pkD3DRenderer->GetRenderState(); if ( pLocal->GetCamera().IsInWater() ) { if ( !m_ptrWaterSound ) { m_ptrWaterSound = NiNew ALAudioSource(AudioSource::TYPE_DEFAULT ); } if ( m_ptrWaterSound && m_ptrWaterSound->GetPlayState() != 1 && ( m_ptrWaterSound->GetStatus() != AudioSource::PLAYING ) ) { m_ptrWaterSound->SetMinMaxDistance(5.0f, 50.0f); m_ptrWaterSound->SetGain(2.f); m_ptrWaterSound->SetLoopCount( 9999 ); SYState()->IAudio->PlaySound(m_ptrWaterSound, "Sound/UnderWaterSwim.wav" ); } m_SceneProperty->ApplyWaterFog(pkRenderState); } else { if ( m_ptrWaterSound && m_ptrWaterSound->GetPlayState() != 1 && ( m_ptrWaterSound->GetStatus() == AudioSource::PLAYING ) ) { m_ptrWaterSound->Stop(); m_ptrWaterSound = NULL; } m_SceneProperty->ApplySceneFog(pkRenderState, true); } float fValue = -0.5f; pkRenderState->SetSamplerState(0, D3DSAMP_MIPMAPLODBIAS, F2DW(fValue)); pkRenderState->SetSamplerState(1, D3DSAMP_MIPMAPLODBIAS, F2DW(fValue)); pkRenderState->SetSamplerState(2, D3DSAMP_MIPMAPLODBIAS, F2DW(fValue)); pkRenderState->SetSamplerState(3, D3DSAMP_MIPMAPLODBIAS, F2DW(fValue)); pkRenderer->SetSorter(NULL); m_spCuller->Reset((NiCamera*)&Camera); m_pkMap->DrawSky(Camera, false); // 渲染动态物体. // 打开光照 for (int i = 0; i < OBJECT_MAX && i < m_PoolMaxValidIndex; i++) { CGameObject* Object = m_ObjectPool[i]; if (Object) { CPlayer* plr = Object->GetAsPlayer(); if(g_bHiddenPlayer && plr && pLocal != plr) { //隐藏其他玩家状态,只显示名字 plr->DrawName((NiCamera*)&Camera); continue; } Object->Draw(m_spCuller); } } if ( m_spBoundBoxRender && m_bShowBoundBoxRender ) { UpdateBoundBoxRender(); m_spCuller->ProcessObject( m_spBoundBoxRender , CCullingProcess::CullSceneObj); } pkRenderer->SetSorter(m_spAlphaSorter); m_spAlphaSorter->StartAccumulating(const_cast(&Camera)); m_pkMap->BuildVisibleSet(m_spCuller); m_spCuller->DrawCullObj( pkRenderer, CCullingProcess::CullTerMesh); //地形 m_spCuller->Remove(CCullingProcess::CullTerMesh); m_spCuller->DrawCullObj(pkRenderer, CCullingProcess::CullTerObject); //地形上的物件 包括普通水 m_spCuller->Remove(CCullingProcess::CullTerObject); m_spCuller->DrawCullObj(pkRenderer, CCullingProcess::CullGameObj); //逻辑对象 人,NPC,以及可以交互的物体 m_spCuller->Remove(CCullingProcess::CullGameObj); m_spCuller->DrawCullObj(pkRenderer, CCullingProcess::CullOtherObj); //其他对象。如 高亮对象 等 m_spCuller->Remove(CCullingProcess::CullOtherObj); m_pkMap->DrawGrass(Camera.GetWorldLocation()); pkRenderer->SetSorter(NULL); RenderShadows(); RenderReflectWater(); if (m_pkDecalManager) m_pkDecalManager->Render(&Camera); m_spCuller->DrawCullObj(pkRenderer, CCullingProcess::CullSceneObj); m_spCuller->Remove(CCullingProcess::CullSceneObj); pkRenderer->SetSorter(m_spEffectAS); m_spEffectAS->StartAccumulating(const_cast(&Camera)); if (m_pkDecalManager) m_pkDecalManager->PostRender(&Camera); EffectMgr->RenderSceneEffects(&Camera); m_spCuller->DrawCullObj(pkRenderer, CCullingProcess::CullSceneObj); m_spCuller->Remove(CCullingProcess::CullSceneObj); m_spAlphaSorter->FinishAccumulating(); m_spEffectAS->FinishAccumulating(); m_SceneProperty->ApplySceneFog(pkRenderState, false); } void CSceneManager::RenderShadows() { NiTPrimitiveArray& kShadowGeometrys = m_spCuller->GetShadowGeometrys(); if(kShadowGeometrys.GetSize() == 0) return; NiD3DRenderer* pkRenderer = (NiD3DRenderer*)NiRenderer::GetRenderer(); // Backup current render target group. const NiRenderTargetGroup* pkCurRenderTarget = pkRenderer->GetCurrentRenderTargetGroup(); if(pkCurRenderTarget == NULL) // 最小化的时候会出现 return; pkRenderer->EndUsingRenderTargetGroup(); for(unsigned int i = 0; i < kShadowGeometrys.GetSize(); ++i) { kShadowGeometrys.GetAt(i)->RenderTexture(); } pkRenderer->BeginUsingRenderTargetGroup((NiRenderTargetGroup*)pkCurRenderTarget, NiRenderer::CLEAR_NONE); // Set up the renderer's camera data. pkRenderer->SetCameraData(m_spCuller->GetCamera()); for(unsigned int i = 0; i < kShadowGeometrys.GetSize(); ++i) { kShadowGeometrys.GetAt(i)->GetShadowGeometry()->RenderImmediate(pkRenderer); } } void CSceneManager::RenderReflectTexture() { NiD3DRenderer* pkRenderer = (NiD3DRenderer*)NiRenderer::GetRenderer(); NiD3DRenderState* pkRenderState = pkRenderer->GetRenderState(); // Backup current render target group. const NiRenderTargetGroup* pkCurRenderTarget = pkRenderer->GetCurrentRenderTargetGroup(); NIASSERT(pkCurRenderTarget != NULL); pkRenderer->EndUsingRenderTargetGroup(); //------------------------------------------------------------------------------------------------------------------------- pkRenderer->BeginUsingRenderTargetGroup(CWaterShader::GetReflectTarget(), NiRenderer::CLEAR_ALL); pkRenderer->SetCameraData(m_spCuller->GetReflectCamera()); //天空体 m_pkMap->DrawSky(*m_spCuller->GetReflectCamera(), true); pkRenderState->SetRenderState(D3DRS_CLIPPLANEENABLE, D3DCLIPPLANE0); //Todo 使用Oblique Frustum Clipping 把水面以下的东西Clip掉 D3DXMATRIX kView = pkRenderer->GetD3DView(); D3DXMATRIX kProj = pkRenderer->GetD3DProj(); D3DXMATRIX kViewProj = kView*kProj; D3DXMatrixTranspose(&kViewProj, &kViewProj); D3DXMatrixInverse(&kViewProj, NULL, &kViewProj); D3DXPLANE kPlane = D3DXPLANE(0.f, 0.f, 1.f, m_spCuller->GetReflectCamera()->GetWorldLocation().z - m_spCuller->GetRRWaterHeight() + 0.5f); D3DXPlaneTransform(&kPlane, &kPlane, &kViewProj); pkRenderer->GetD3DDevice()->SetClipPlane(0, &kPlane.a); //地形 NiDrawVisibleArray(m_spCuller->GetReflectCamera(), *m_spCuller->GetReflectChunkSet()); float d = m_spCuller->GetReflectCamera()->GetWorldLocation().z - m_spCuller->GetRRWaterHeight(); //注意摄像机在原点 kPlane = D3DXPLANE(0.f, 0.f, 1.f, d); D3DXPlaneTransform(&kPlane, &kPlane, &kViewProj); pkRenderer->GetD3DDevice()->SetClipPlane(0, &kPlane.a); NiDrawVisibleArray(m_spCuller->GetReflectCamera(), *m_spCuller->GetReflectModelSet()); //test //static int i = 0; //if( i++ > 2000 ) //{ // i = 0; // NiDX92DBufferData* pkBuffData = NiDynamicCast(NiDX92DBufferData, (NiDX92DBufferData*)CWaterShader::GetReflectTarget()->GetBufferRendererData(0)); // D3DXSaveSurfaceToFileA("E:\\1.jpg", D3DXIFF_JPG, pkBuffData->GetSurface(), NULL, NULL); //} pkRenderer->EndUsingRenderTargetGroup(); pkRenderState->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); pkRenderer->BeginUsingRenderTargetGroup((NiRenderTargetGroup *)pkCurRenderTarget, NiRenderer::CLEAR_NONE); // Set up the renderer's camera data. pkRenderer->SetCameraData(m_spCuller->GetCamera()); } void CSceneManager::RenderRefractTexture() { NiD3DRenderer* pkRenderer = (NiD3DRenderer*)NiRenderer::GetRenderer(); NiD3DRenderState* pkRenderState = pkRenderer->GetRenderState(); //Copy to texture Ni2DBuffer* pkBackBuffer = pkRenderer->GetCurrentRenderTargetGroup()->GetBuffer(0); Ni2DBuffer* pkRefractBuffer = CWaterShader::GetRefractTexture()->GetBuffer(); pkBackBuffer->FastCopy(pkRefractBuffer); const NiRenderTargetGroup* pkCurRenderTarget = pkRenderer->GetCurrentRenderTargetGroup(); NIASSERT(pkCurRenderTarget != NULL); pkRenderer->EndUsingRenderTargetGroup(); NiColorA kOldColor; pkRenderer->GetBackgroundColor(kOldColor); pkRenderer->SetBackgroundColor(NiColor(1.f, 1.f, 1.f)); pkRenderer->BeginUsingRenderTargetGroup(CWaterShader::GetRefractAlphaTarget(), NiRenderer::CLEAR_BACKBUFFER); CWaterShader::SetRefractPass(true); pkRenderState->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); pkRenderState->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); pkRenderState->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); NiDrawVisibleArray(m_spCuller->GetCamera(), *m_spCuller->GetWaterSet()); pkRenderer->GetRenderState()->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); CWaterShader::SetRefractPass(false); pkRenderer->EndUsingRenderTargetGroup(); pkRenderer->SetBackgroundColor(kOldColor); pkRenderer->BeginUsingRenderTargetGroup((NiRenderTargetGroup *)pkCurRenderTarget, NiRenderer::CLEAR_NONE); //pkBackBuffer = pkRenderer->GetCurrentRenderTargetGroup()->GetBuffer(0); //Ni2DBuffer* pkRefractAlphaBuffer = CWaterShader::GetRefractAlphaTexture()->GetBuffer(); //pkBackBuffer->FastCopy(pkRefractAlphaBuffer); } void CSceneManager::RenderReflectWater() { NiD3DRenderer* pkRenderer = ((NiD3DRenderer*)NiRenderer::GetRenderer()); if(pkRenderer->GetCurrentRenderTargetGroup() == NULL) return; if(!m_spCuller->HasRRWater()) return; RenderReflectTexture(); RenderRefractTexture(); NiD3DRenderState* pkD3DRenderState = pkRenderer->GetRenderState(); pkD3DRenderState->SetSamplerState(0, NiD3DRenderState::NISAMP_ADDRESSU, D3DTADDRESS_WRAP); pkD3DRenderState->SetSamplerState(0, NiD3DRenderState::NISAMP_ADDRESSV, D3DTADDRESS_WRAP); pkD3DRenderState->SetSamplerState(0, NiD3DRenderState::NISAMP_MAGFILTER, D3DTEXF_LINEAR); pkD3DRenderState->SetSamplerState(0, NiD3DRenderState::NISAMP_MINFILTER, D3DTEXF_LINEAR); pkD3DRenderState->SetSamplerState(0, NiD3DRenderState::NISAMP_MIPFILTER, D3DTEXF_LINEAR); pkD3DRenderState->SetSamplerState(1, NiD3DRenderState::NISAMP_ADDRESSU, D3DTADDRESS_WRAP); pkD3DRenderState->SetSamplerState(1, NiD3DRenderState::NISAMP_ADDRESSV, D3DTADDRESS_WRAP); pkD3DRenderState->SetSamplerState(1, NiD3DRenderState::NISAMP_MAGFILTER, D3DTEXF_LINEAR); pkD3DRenderState->SetSamplerState(1, NiD3DRenderState::NISAMP_MINFILTER, D3DTEXF_LINEAR); pkD3DRenderState->SetSamplerState(1, NiD3DRenderState::NISAMP_MIPFILTER, D3DTEXF_LINEAR); pkD3DRenderState->SetSamplerState(2, NiD3DRenderState::NISAMP_ADDRESSU, D3DTADDRESS_WRAP); pkD3DRenderState->SetSamplerState(2, NiD3DRenderState::NISAMP_ADDRESSV, D3DTADDRESS_WRAP); pkD3DRenderState->SetSamplerState(2, NiD3DRenderState::NISAMP_MAGFILTER, D3DTEXF_LINEAR); pkD3DRenderState->SetSamplerState(2, NiD3DRenderState::NISAMP_MINFILTER, D3DTEXF_LINEAR); pkD3DRenderState->SetSamplerState(2, NiD3DRenderState::NISAMP_MIPFILTER, D3DTEXF_LINEAR); pkD3DRenderState->SetSamplerState(3, NiD3DRenderState::NISAMP_ADDRESSU, D3DTADDRESS_WRAP); pkD3DRenderState->SetSamplerState(3, NiD3DRenderState::NISAMP_ADDRESSV, D3DTADDRESS_WRAP); pkD3DRenderState->SetSamplerState(3, NiD3DRenderState::NISAMP_MAGFILTER, D3DTEXF_LINEAR); pkD3DRenderState->SetSamplerState(3, NiD3DRenderState::NISAMP_MINFILTER, D3DTEXF_LINEAR); pkD3DRenderState->SetSamplerState(3, NiD3DRenderState::NISAMP_MIPFILTER, D3DTEXF_LINEAR); pkD3DRenderState->SetSamplerState(4, NiD3DRenderState::NISAMP_ADDRESSU, D3DTADDRESS_WRAP); pkD3DRenderState->SetSamplerState(4, NiD3DRenderState::NISAMP_ADDRESSV, D3DTADDRESS_WRAP); pkD3DRenderState->SetSamplerState(4, NiD3DRenderState::NISAMP_MAGFILTER, D3DTEXF_LINEAR); pkD3DRenderState->SetSamplerState(4, NiD3DRenderState::NISAMP_MINFILTER, D3DTEXF_LINEAR); pkD3DRenderState->SetSamplerState(4, NiD3DRenderState::NISAMP_MIPFILTER, D3DTEXF_LINEAR); pkD3DRenderState->SetSamplerState(5, NiD3DRenderState::NISAMP_ADDRESSU, D3DTADDRESS_CLAMP); pkD3DRenderState->SetSamplerState(5, NiD3DRenderState::NISAMP_ADDRESSV, D3DTADDRESS_CLAMP); pkD3DRenderState->SetSamplerState(5, NiD3DRenderState::NISAMP_MAGFILTER, D3DTEXF_LINEAR); pkD3DRenderState->SetSamplerState(5, NiD3DRenderState::NISAMP_MINFILTER, D3DTEXF_LINEAR); pkD3DRenderState->SetSamplerState(5, NiD3DRenderState::NISAMP_MIPFILTER, D3DTEXF_LINEAR); pkD3DRenderState->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW); pkD3DRenderState->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); pkD3DRenderState->SetRenderState(D3DRS_ZENABLE, TRUE); pkD3DRenderState->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); pkD3DRenderState->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); pkD3DRenderState->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); pkD3DRenderState->SetRenderState(D3DRS_FOGENABLE, FALSE); NiDrawVisibleArray(m_spCuller->GetCamera(), *m_spCuller->GetWaterSet()); pkD3DRenderState->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); } void CSceneManager::Update(float dt) { CPlayer* pkPlayer = ObjectMgr->GetLocalPlayer(); if( !pkPlayer ) return; float AccumTime = SYState()->ClientApp->GetAccumTime(); CLIENT_METRIC_TIMER(NiMetricsClockTimer, kTimer1, TERRAIN_UPDATETIME); CLIENT_METRIC_STARTTIMER(kTimer1); if( m_pkMap && m_pkMap->IsLoaded() ) { m_pkLightManager->Update(AccumTime); m_pkMap->Update(AccumTime, dt); } CLIENT_METRIC_ENDTIMER(kTimer1); CLIENT_METRIC_TIMER(NiMetricsClockTimer, kTimer, SCENE_UPDATETIME); CLIENT_METRIC_STARTTIMER(kTimer); CCamera& camera = pkPlayer->GetCamera(); camera.UpdateFrustumPlanes(); for (int i =0; i < m_PoolMaxValidIndex && i < OBJECT_MAX; ++i) { CGameObject* Object = m_ObjectPool[i]; if (Object && Object != pkPlayer) { //Object->SetAUpdate(pkPlayer->CanSeeObject( Object )); Object->Update(dt); } } if (pkPlayer) pkPlayer->Update(dt); UpdateWaterBubble(); //更新水底泡泡 if(m_pkDecalManager) { m_pkDecalManager->Update(dt); } CLIENT_METRIC_ENDTIMER(kTimer); } BOOL CSceneManager::EnterLevel(unsigned int uiMapID, float x, float y) { CMapInfoDB::MapInfoEntry stMapInfoEntry; if (!g_pkMapInfoDB->GetMapInfo(uiMapID, stMapInfoEntry)) { return FALSE; } const char* LevelName = stMapInfoEntry.name.c_str(); CLIENT_METRIC_TIMER(NiMetricsClockTimer, kTimer, MAP_LOAD_TIME); CLIENT_METRIC_STARTTIMER(kTimer); m_pkLightManager->Load(LevelName); if( !m_pkMap ) { m_pkMap = NiNew CMap(Festival_None); //只创建一次 } m_pkMap->SetMapId(uiMapID); m_pkMap->Transport(LevelName); //const NiPoint3& kPos = ObjectMgr->GetLocalPlayer()->GetPosition(); m_pkMap->EnterTile( x, y); m_CollisionMgr->InitPick(); CPlayerLocal* pPlayer = ObjectMgr->GetLocalPlayer(); if ( pPlayer ) { pPlayer->GetCamera().LookPlayer(); } CLIENT_METRIC_ENDTIMER(kTimer); return TRUE; } void CSceneManager::ResetLevel() { NiRenderer* pkRenderer = NiRenderer::GetRenderer(); if (m_pkLightManager != NULL) m_pkLightManager->Unload(); if (m_pkMap != NULL) m_pkMap->Unload(); } INT CSceneManager::FindFreeIndex() { int i; for (i= 0 ; i < OBJECT_MAX ; ++i) { if (m_ObjectPool[i] == NULL) { break; } } if ( i == OBJECT_MAX) { return -1; }else if( i >= m_PoolMaxValidIndex) { m_PoolMaxValidIndex = i+1; } return i; } #define RENDERBOX_VERTEX_COUNT 8 void CSceneManager::CreateBoundBoxRender() { //Create the arrays we'll need for the NiTriShapeDynamicData object NiPoint3* pkVerts = NiNew NiPoint3[RENDERBOX_VERTEX_COUNT]; NiColorA* pkColors = NiNew NiColorA[RENDERBOX_VERTEX_COUNT]; for (int i=0; iGetModelData()->MarkAsChanged(NiGeometryData::VERTEX_MASK); NiMaterialProperty* pkMaterail = NiNew NiMaterialProperty; pkMaterail->SetDiffuseColor(NiColor::BLACK); pkMaterail->SetEmittance(NiColor(0.0f, 1.0f, 0.0f)); m_spBoundBoxRender->AttachProperty(pkMaterail); m_spBoundBoxRender->Update(0.0f); m_spBoundBoxRender->UpdateProperties(); } void CSceneManager::SetBoundBoxRenderObject(CGameObject* pObject) { m_pBoundBoxRenderObject = pObject; } void CSceneManager::UpdateWaterBubble() { CPlayerLocal* pkLocalPlayer = ObjectMgr->GetLocalPlayer(); if ( !pkLocalPlayer ) return; if ( pkLocalPlayer->CheckInWater() != WL_UNDER_WATER ) return; uint32 mst = float2int32(NiGetCurrentTimeInSec() * 1000); unsigned int uiDelayTime = mst - m_uiLastTime; if ( uiDelayTime > 1000 ) //大于10秒 { m_uiLastTime = mst; int nID = rand() % 3; char buff[MAX_PATH]; sprintf(buff, "Effect_bubble0%d.nif", nID); CSceneEffect* pSceneEffect = (CSceneEffect*)EffectMgr->CreateSceneEffect(buff, true, true); pSceneEffect->SetMaxLife(15.0f); ResetWaterBubble( pSceneEffect, pkLocalPlayer->GetPosition()); } } void CSceneManager::UpdateBoundBoxRender() { if ( m_pBoundBoxRenderObject ) { NiBound kBound; kBound.SetRadius(0.0f); m_pBoundBoxRenderObject->GetPickBound(kBound); NiPoint3* kVertex = m_spBoundBoxRender->GetVertices(); NiPoint3 kMin, kMax; kBound.GetAABB(kMin, kMax); kVertex[0] = NiPoint3(kMin.x, kMin.y, kMax.z); kVertex[1] = NiPoint3(kMax.x, kMin.y, kMax.z); kVertex[2] = NiPoint3(kMax.x, kMax.y, kMax.z); kVertex[3] = NiPoint3(kMin.x, kMax.y, kMax.z); kVertex[4] = NiPoint3(kMin.x, kMin.y, kMin.z); kVertex[5] = NiPoint3(kMax.x, kMin.y, kMin.z); kVertex[6] = NiPoint3(kMax.x, kMax.y, kMin.z); kVertex[7] = NiPoint3(kMin.x, kMax.y, kMin.z); m_spBoundBoxRender->GetModelData()->MarkAsChanged(NiGeometryData::VERTEX_MASK); m_spBoundBoxRender->Update(0.0f); m_spBoundBoxRender->UpdateProperties(); m_spBoundBoxRender->UpdateNodeBound(); NiBound kWorldBound = m_spBoundBoxRender->GetWorldBound(); kWorldBound.ComputeFromData(RENDERBOX_VERTEX_COUNT, kVertex); m_spBoundBoxRender->SetWorldBound(kWorldBound); } } void CSceneManager::ResetWaterBubble( CSceneEffect* pEffect, const NiPoint3& kPos ) { //重新生成一个新的位置 if ( !pEffect ) return; int nRandX = m_pRandomMize->IRandom(-20, 20); int nRandY = m_pRandomMize->IRandom(-20, 20); float x = (float)kPos.x + nRandX; float y = (float)kPos.y + nRandY; CMap* pkMap = CMap::Get(); float fTH = pkMap->GetHeight(x, y); float fWH = pkMap->GetWaterHeight(x, y); int nOffset = int(fWH - fTH) - 2; //获取2个高度之间的高度 if ( nOffset <= 0 ) { pEffect->Deactivate(); return; } int nRandZ = (float)(rand() % nOffset) + fTH; float z = (float)nRandZ; pEffect->SetTranslate( NiPoint3(x, y, z) ); } INT CSceneManager::FindSceneObjectByID(ui64 ObjectID) { SceneObjectMap::const_iterator it = m_ObjectMap.find(ObjectID); if (it != m_ObjectMap.end()) { return it->second; } return -1; } BOOL CSceneManager::AttachSceneObject(CGameObject* Object, bool bNetObject) { NIASSERT(Object); if(bNetObject) { ui64 ObjectID = Object->GetGUID(); if (FindSceneObjectByID(ObjectID) != -1) { return TRUE; } INT FreeIndex = FindFreeIndex(); if (FreeIndex == -1) { return FALSE; } m_ObjectPool[FreeIndex] = Object; m_ObjectMap.insert(SceneObjectMap::value_type(ObjectID, FreeIndex)); EGAMEOBJ_TYPE ObjType = Object->GetGameObjectType(); switch(ObjType) { case GOT_SCENEOBJECT: // Items索引 m_vItems.push_back(FreeIndex); break; default: break; } } else { ui64 ObjectID = Object->GetGUID(); if( !ObjectID ) { ObjectID = ObjectMgr->GenClientGuid(); Object->SetGUID(ObjectID); } INT FreeIndex = FindFreeIndex(); if(FreeIndex == -1) { return FALSE; } m_ObjectPool[FreeIndex] = Object; m_ClientObjectMap.insert(SceneObjectMap::value_type(ObjectID, FreeIndex)); } return TRUE; } void CSceneManager::DetachSceneObject(CGameObject* Object, bool bNetObject) { if (Object == NULL) { return; } SceneObjectMap::iterator it; INT Index = -1; if(bNetObject) { it = m_ObjectMap.find(Object->GetGUID()); if (it != m_ObjectMap.end()) { Index = it->second; if(m_ObjectPool[Index] != Object) { //__asm int 3 return; } m_ObjectPool[Index] = NULL; m_ObjectMap.erase(it); for (int i = (m_PoolMaxValidIndex - 1) ; i >= 0; i--) { if (m_ObjectPool[i] != NULL) { m_PoolMaxValidIndex = i + 1; break; } } } } else { it = m_ClientObjectMap.find(Object->GetGUID()); if (it != m_ClientObjectMap.end()) { Index = it->second; if(m_ObjectPool[Index] != Object) { //__asm int 3 return; } m_ObjectPool[Index] = NULL; m_ClientObjectMap.erase(it); for (int i = (m_PoolMaxValidIndex - 1) ; i >= 0; i--) { if (m_ObjectPool[i] != NULL) { m_PoolMaxValidIndex = i + 1; break; } } } } EGAMEOBJ_TYPE ObjType = Object->GetGameObjectType(); switch(ObjType) { case GOT_SCENEOBJECT: // Items索引 //m_vItems.erase(m_vItems.begin() + Index); { std::vector::iterator it2 = m_vItems.begin(); for( ; it2 != m_vItems.end(); ++it2) { if((*it2) == Index) { m_vItems.erase(it2); break; } } } break; default: break; } } BOOL CSceneManager::AttachToPickGroup(EScenePickGroup PickGroupFlag , CGameObject* Object) { NIASSERT(Object && Object->GetSceneNode()); return m_CollisionMgr->AttachToPickGroup(PickGroupFlag, Object); } BOOL CSceneManager::DetachFromPickGroup(EScenePickGroup PickGroupFlag, CGameObject* Object) { NIASSERT(Object); m_CollisionMgr->DetachFromPickGroup(PickGroupFlag, Object); return TRUE; } #define TRACE_DISTANCE 400.f BOOL CSceneManager::FindMoveTarget(const NiPoint3& kStart,const NiPoint3& kDir, NiPoint3* Target) { CMap* pkMap = CMap::Get(); if( pkMap ) { NiPoint3 kEnd = kStart + kDir * TRACE_DISTANCE; float fTime = 2.f; ResultList collList; if( pkMap->MultiCollideBox( kStart, kEnd, NiPoint3(0.001f,0.001f,0.001f), collList ) ) { NIASSERT(collList.size() > 0); if(Target) *Target = kStart + kDir * (TRACE_DISTANCE * collList[0].fTime); return true; } } return false; } CGameObject* CSceneManager::FindNearByObj(CGameObject* pkLocalPlayer, float fRadius, UINT Groups, float& fDistance) { NiPoint3 kPos = pkLocalPlayer->GetPosition(); CGameObject* pkReturnObj = NULL; CGameObject* pkGameObj = NULL; switch(Groups) { case GOT_SCENEOBJECT: { for(unsigned int ui = 0; ui < m_vItems.size(); ui++) { pkGameObj = m_ObjectPool[m_vItems[ui]]; if(pkGameObj == NULL || pkLocalPlayer == pkGameObj) continue; fDistance = (kPos - pkGameObj->GetPosition()).Length(); if(fDistance < fRadius) { fRadius = fDistance; pkReturnObj = pkGameObj; } } } break; default: fDistance = -FLT_MAX; } return pkReturnObj; }