#include "StdAfx.h" #include "Map.h" #include "TagStream.h" #include "Water.h" #include "Effect/WaterEffect.h" #include "ClientState.h" #include "ClientApp.h" #include "ResourceManager.h" #include "LightManager.h" #include "ShadowGeometry.h" #include "TerrainShader.h" #define DEFAULT_SKY ("Data\\Sky\\alpha_sky.nif") CMap* CMap::ms_pkMap; CMap::CMap(Festival_Flag Festival) :m_bLoaded(false) ,m_uiRenderFrame(1) ,m_uiCollisionFrame(1) ,m_Festival(Festival) { NIASSERT( ms_pkMap == NULL ); ms_pkMap = this; m_uiMapId = 0; Init(); Reset(); } CMap::~CMap() { Unload(); Shutdown(); ms_pkMap = NULL; } void CMap::Reset() { memset(m_iTileFlags, 0, sizeof(m_iTileFlags)); memset(m_pkTiles, 0, sizeof(m_pkTiles)); memset(m_pkCurrentTiles, 0, sizeof(m_pkCurrentTiles)); memset(m_pkWaterShaders, 0, sizeof(m_pkWaterShaders)); } int CMap::GetTileFlag(int x, int y) const { if( IsValidTileIndex(x, y) ) { return m_iTileFlags[x][y]; } return 0; } float CMap::GetWaterHeight(float x, float y) { float h; if( GetWaterHeight(x, y, h) ) return h; return 10.f; } bool CMap::GetWaterHeight(float x, float y, float& h) { CChunk* chunk = GetChunk(x, y); if( chunk ) return chunk->GetWaterHeight(x, y, h); return false; } bool CMap::GetWaterFlag(float x, float y) { CChunk* chunk; chunk = GetChunk(x, y); if( chunk ) return chunk->GetWaterFlag(x, y); //Water Flag 没有和其他的Chunk连接 //不需要考虑边界点 return false; } void CMap::UpdateWaterShaders(const NiColor& kAmbientColor, const NiColor& kDiffuseColor) { for(int i = 0; i < MAX_WATER_COUNT; ++i) { if(m_pkWaterShaders[i]) { m_pkWaterShaders[i]->Update(kAmbientColor, kDiffuseColor); } } CWater::GetDefaultWaterShader()->Update(kAmbientColor, kDiffuseColor); } CWaterShader* CMap::GetWaterShader(unsigned int uiIndex) { NIASSERT(uiIndex < MAX_WATER_COUNT); return m_pkWaterShaders[uiIndex]; } bool CMap::GetFlyGridInfo(float x, float y) { CChunk* chunk; chunk = GetChunk(x, y); if( chunk ) return chunk->GetFlyGridInfo(x, y); return false; } bool CMap::GetFlyGridInfo(float x, float y, bool& flag) { CChunk* chunk = GetChunk(x, y); if( chunk ) return chunk->GetFlyGridInfo(x, y, flag); return false; } bool CMap::GetGridInfo(float x, float y, bool bIsFly) { CChunk* chunk; chunk = GetChunk(x, y); if( chunk ) { //if ( bIsFly ) //{ // bool bf = chunk->GetFlyGridInfo(x, y); // bool bw = chunk->GetGridInfo(x, y); // return (bf); //} //else return chunk->GetGridInfo(x, y); } return false; } bool CMap::GetGridInfo(float x, float y,bool bIsFly, bool& flag ) { CChunk* chunk = GetChunk(x, y); if( chunk ) { //if ( bIsFly ) //{ // bool bf = chunk->GetFlyGridInfo(x, y); // bool bw = chunk->GetGridInfo(x, y); // flag = (bf && bw); // return flag; //} //else return chunk->GetGridInfo(x, y, flag); } return false; } //从一个其他的地图传送过来 void CMap::Transport(const NiFixedString& kMapName) { if( m_kMapName == kMapName ) return; Unload();//释放之前的地图 Reset(); m_bLoaded = false; m_kMapName = kMapName; Load();//装载新的地图 } unsigned int CMap::GetAreaId(float x, float y) { CChunk* pkChunk = GetChunk(x, y); if(pkChunk) return pkChunk->GetAreaId(); return 0; } //不使用后台读取 bool CMap::Load() { char acFilename[NI_MAX_PATH]; //合成绝对路径 NiSprintf(acFilename, NI_MAX_PATH, "Data\\World\\Maps\\%s\\%s.map", (const char*)m_kMapName, (const char*)m_kMapName); NiFile* pkFile = NiFile::GetFile(acFilename, NiFile::READ_ONLY); if( !pkFile || !(*pkFile) ) { NiDelete pkFile; return false; } CTagStream kTagStream; NiFixedString kSkyName = DEFAULT_SKY; while( kTagStream.ReadFromStream( pkFile ) ) { switch( kTagStream.GetTag() ) { case 'MAIN': { kTagStream.Read(m_iTileFlags, sizeof(m_iTileFlags)); } break; case 'SKY': { kTagStream.ReadFixedString(kSkyName); } break; case 'WTMT'://water material { NiBool bHasWater; for(int i = 0; i < MAX_WATER_COUNT; ++i) { kTagStream.Read(&bHasWater, sizeof(bHasWater)); if(bHasWater) { m_pkWaterShaders[i] = NiNew CWaterShader; m_pkWaterShaders[i]->IncRefCount(); m_pkWaterShaders[i]->Load(kTagStream); m_pkWaterShaders[i]->Init(); } else { m_pkWaterShaders[i] = NULL; } } } break; case 'GRTX': //grass texture { unsigned int uiXCount; unsigned int uiYCount; NiFixedString kGrassTexture; kTagStream.ReadFixedString(kGrassTexture); kTagStream.Read(&uiXCount, sizeof(uiXCount)); kTagStream.Read(&uiYCount, sizeof(uiYCount)); m_kGrassMesh.SetTextureName(kGrassTexture); m_kGrassMesh.SetXYCount(uiXCount, uiYCount); } break; default: { //NIASSERT( false ); } break; } } m_kSky.Load(kSkyName); NiDelete pkFile; int iMinX = TILE_COUNT; int iMinY = TILE_COUNT; int iMaxX = 0; int iMaxY = 0; for(int x = 0; x < TILE_COUNT; ++x) { for(int y = 0; y < TILE_COUNT; ++y) { if(GetTileFlag(x, y)) { iMinX = NiMin(iMinX, x); iMinY = NiMin(iMinY, y); iMaxX = NiMax(iMaxX, x); iMaxY = NiMax(iMaxY, y); } } } if(iMinX > iMaxX || iMinY > iMaxY) { m_kBoundBox.m_kMin = m_kBoundBox.m_kMax = NiPoint3(0.f, 0.f, 0.f); } else { m_kBoundBox.m_kMin = NiPoint3(float(iMinX*TILE_SIZE), float(iMinY*TILE_SIZE), -50.f); m_kBoundBox.m_kMax = NiPoint3(float(iMaxX*TILE_SIZE + TILE_SIZE), float(iMaxY*TILE_SIZE + TILE_SIZE), 100.f); } m_kPathNodeManager.Load(m_kMapName); return true; } void CMap::Unload() { m_kSoundEmitterManager.RemoveAll(); for(int i = 0; i < CURRENT_TILE_SIZE; i++) { if( m_pkCurrentTiles[i] ) { if(m_pkCurrentTiles[i]->IsLoaded()) NiDelete m_pkCurrentTiles[i]; else m_pkCurrentTiles[i]->SetNeedDelete(true); m_pkCurrentTiles[i] = NULL; } } for(int i = 0; i DecRefCount(); m_pkWaterShaders[i] = NULL; } } m_kMapName = ""; m_kGrassMesh.SetTextureName(NULL); g_ResMgr->ResetTexturePalette(); g_ResMgr->DumpNif(); g_ResMgr->DumpKfm(); g_ResMgr->DumpTexture(); } CTile* CMap::GetTile(float x, float y) { return GetTileByIndex(TILE_INDEX(x), TILE_INDEX(y)); } bool CMap::EnterTile(float x, float y) { x = (m_kBoundBox.m_kMin.x + m_kBoundBox.m_kMax.x)/2.f; y = (m_kBoundBox.m_kMin.y + m_kBoundBox.m_kMax.y)/2.f; int X = TILE_INDEX(x); int Y = TILE_INDEX(y); m_bLoaded = false; for(int i = -2; i <= 2; i++) { for(int j = -2; j <= 2; j++) { LoadTile(X + i, Y + j); } } return true; } //装载中区 void CMap::LoadTile(int x, int y) { //越界或者不存在Tile if( GetTileFlag(x, y) == 0 ) return; //已经存在 if( m_pkTiles[x][y] ) return; int i = 0; for(; i < CURRENT_TILE_SIZE; ++i) { if(m_pkCurrentTiles[i] == NULL) break; } if(i >= CURRENT_TILE_SIZE) return; m_pkCurrentTiles[i] = m_pkTiles[x][y] = NiNew CTile(x, y, m_Festival); //进行后台装载 m_pkCurrentTiles[i]->BeginBackLoad(); } bool CMap::CheckLoaded() { for(int i = 0; i < CURRENT_TILE_SIZE; ++i) { if(m_pkCurrentTiles[i] && !m_pkCurrentTiles[i]->IsLoaded()) return false; } return true; } bool CMap::IsLoaded() { if( m_bLoaded ) return true; m_bLoaded = CheckLoaded(); return m_bLoaded; } bool CMap::CollideLine(const NiPoint3 &start, const NiPoint3 &end, float& fTime) { ++m_uiCollisionFrame; float deltaX = end.x - start.x; float deltaY = end.y - start.y; int XDir = deltaX < 0.0f ? -1:1; int YDir = deltaY < 0.0f ? -1:1; int XStart, XEnd, YStart, YEnd; int XMin = int(m_kBoundBox.m_kMin.x); int XMax = int(m_kBoundBox.m_kMax.x); int YMin = int(m_kBoundBox.m_kMin.y); int YMax = int(m_kBoundBox.m_kMax.y); XStart = XDir > 0 ? ALIGN(start.x, CHUNK_SIZE) : ALIGN(start.x + CHUNK_SIZE, CHUNK_SIZE); XEnd = XDir > 0 ? ALIGN(end.x + CHUNK_SIZE, CHUNK_SIZE) : ALIGN(end.x, CHUNK_SIZE); XStart = XDir > 0 ? NiMax(XStart, XMin) : NiMin(XStart, XMax); XEnd = XDir > 0 ? NiMin(XEnd, XMax) : NiMax(XEnd, XMin); if( XStart*XDir >= XEnd*XDir ) return false; int x, y; CChunk *chunk; if(XEnd == XStart + XDir*CHUNK_SIZE)//此时DeltaX可能为0 { YStart = YDir > 0 ? ALIGN(start.y, CHUNK_SIZE) : ALIGN(start.y + CHUNK_SIZE, CHUNK_SIZE); YEnd = YDir > 0 ? ALIGN(end.y + CHUNK_SIZE, CHUNK_SIZE) : ALIGN(end.y, CHUNK_SIZE); YStart = YDir > 0 ? NiMax(YStart, YMin) : NiMin(YStart, YMax); YEnd = YDir > 0 ? NiMin(YEnd, YMax) : NiMax(YEnd, YMin); for( y = YStart; y*YDir < YEnd*YDir; y += CHUNK_SIZE * YDir) { chunk = GetChunk(float(XStart + XDir), float(y + YDir)); if( chunk && chunk->CollideLine(start, end, fTime) ) { return true; } } return false; } //Y = mX + c; float m = deltaY / deltaX; float c = end.y - end.x*m; float y1, y2; for( x = XStart; x*XDir < XEnd*XDir; x += CHUNK_SIZE*XDir ) { y1 = m*x + c; y2 = y1 + CHUNK_SIZE*XDir*m; YStart = YDir > 0 ? ALIGN(y1, CHUNK_SIZE) : ALIGN(y1 + CHUNK_SIZE, CHUNK_SIZE); YEnd = YDir > 0 ? ALIGN(y2 + CHUNK_SIZE, CHUNK_SIZE) : ALIGN(y2, CHUNK_SIZE); YStart = YDir > 0 ? NiMax(YStart, YMin) : NiMin(YStart, YMax); YEnd = YDir > 0 ? NiMin(YEnd, YMax) : NiMax(YEnd, YMin); for( y = YStart; y*YDir < YEnd*YDir; y += CHUNK_SIZE*YDir ) { chunk = GetChunk(float(x + XDir), float(y + YDir)); if( chunk && chunk->CollideLine(start, end, fTime) ) { return true; } } } return false; } void CMap::Init() { CChunk::_SDMInit(); CWater::_SDMInit(); CWaterShader::_SDMInit(); CWaterEffect::_SDMInit(); CTagStream::_SDMInit(); CShadowGeometry::_SDMInit(); CTerrainShader::_SDMInit(); } void CMap::Shutdown() { CTerrainShader::_SDMShutdown(); CShadowGeometry::_SDMShutdown(); CTagStream::_SDMShutdown(); CWaterEffect::_SDMShutdown(); CWaterShader::_SDMShutdown(); CWater::_SDMShutdown(); CChunk::_SDMShutdown(); } void CMap::Update(float fTime, float fFrameTime) { m_fTime = fTime; CLightManager* pkLightManager = CLightManager::Get(); UpdateWaterShaders(pkLightManager->GetWaterAmbientColor(), pkLightManager->GetWaterDiffuseColor()); m_kSoundEmitterManager.Update(fFrameTime); } void CMap::BuildVisibleSet(CCullingProcess* pkCuller) { if( !IsLoaded() ) return; m_uiRenderFrame++; const NiCamera* pkCamera = pkCuller->GetCamera(); const NiPoint3& kCenter = pkCamera->GetWorldLocation(); const NiPoint3& kDir = pkCamera->GetWorldDirection(); const NiPoint3& kRight = pkCamera->GetWorldRightVector(); const NiPoint3& kUp = pkCamera->GetWorldUpVector(); const NiFrustum& kFrustum = pkCamera->GetViewFrustum(); float fNearFarRatio = kFrustum.m_fFar / kFrustum.m_fNear; static CBox kBox; kBox.Reset(); NiPoint3 p1(kDir); p1 *= kFrustum.m_fNear; NiPoint3 p2(kRight); p2 *= kFrustum.m_fRight; NiPoint3 p3(kUp); p3 *= kFrustum.m_fTop; NiPoint3 p4(kUp); p4 *= kFrustum.m_fBottom; NiPoint3 p5(kRight); p5 *= kFrustum.m_fLeft; kBox.Intersect(kCenter.x + p1.x + p2.x + p3.x, kCenter.y + p1.y + p2.y + p3.y, kCenter.z + p1.z + p2.z + p3.z ); kBox.Intersect(kCenter.x + p1.x + p2.x + p4.x, kCenter.y + p1.y + p2.y + p4.y, kCenter.z + p1.z + p2.z + p4.z ); kBox.Intersect(kCenter.x + p1.x + p5.x + p3.x, kCenter.y + p1.y + p5.y + p3.y, kCenter.z + p1.z + p5.z + p3.z ); kBox.Intersect(kCenter.x + p1.x + p5.x + p4.x, kCenter.y + p1.y + p5.y + p4.y, kCenter.z + p1.z + p5.z + p4.z );; float x = (p1.x + p2.x + p3.x) * fNearFarRatio; float y = (p1.y + p2.y + p3.y) * fNearFarRatio; float z = (p1.z + p2.z + p3.z) * fNearFarRatio; kBox.Intersect( kCenter.x + x, kCenter.y + y, kCenter.z + z ); x = (p1.x + p2.x + p4.x) * fNearFarRatio; y = (p1.y + p2.y + p4.y) * fNearFarRatio; z = (p1.z + p2.z + p4.z) * fNearFarRatio; kBox.Intersect( kCenter.x + x, kCenter.y + y, kCenter.z + z ); x = (p1.x + p5.x + p3.x) * fNearFarRatio; y = (p1.y + p5.y + p3.y) * fNearFarRatio; z = (p1.z + p5.z + p3.z) * fNearFarRatio; kBox.Intersect( kCenter.x + x, kCenter.y + y, kCenter.z + z ); x = (p1.x + p5.x + p4.x) * fNearFarRatio; y = (p1.y + p5.y + p4.y) * fNearFarRatio; z = (p1.z + p5.z + p4.z) * fNearFarRatio; kBox.Intersect( kCenter.x + x, kCenter.y + y, kCenter.z + z ); CLIENT_METRIC_SCOPETIMER(TERRAIN_CULLTIME); CChunk* pkChunk; static CBox kChunkBox; kChunkBox.Reset(); //static NiTPrimitiveArray kVisibleChunks(256, 32); //kVisibleChunks.RemoveAll(); std::multimap sort_chunks; for( float x = kBox.m_kMin.x; x < kBox.m_kMax.x + CHUNK_SIZE; x += CHUNK_SIZE ) { for( float y = kBox.m_kMin.y; y < kBox.m_kMax.y + CHUNK_SIZE; y += CHUNK_SIZE ) { pkChunk = GetChunk(x, y); if(pkChunk && pkChunk->GetGeometry()) { kChunkBox = pkChunk->GetBoundBox(); kChunkBox.m_kMax.z += 100.f; //假设建筑物最高是100米 if(kBox.IsOverlapped(kChunkBox) && kChunkBox.TestVisible(pkCuller->GetFrustumPlanes())) { //kVisibleChunks.Add(pkChunk); sort_chunks.insert( std::make_pair( (pkChunk->GetBoundBox().GetCenter() - kCenter).SqrLength(), pkChunk ) ); } } } } /* //按照离摄像机的距离排序 for( unsigned int i = 0; i < kVisibleChunks.GetSize(); i++ ) { for( unsigned int j = i + 1; j < kVisibleChunks.GetSize(); j++ ) { if( (kVisibleChunks.GetAt(j)->GetBoundBox().GetCenter() - kCenter).SqrLength() < (kVisibleChunks.GetAt(i)->GetBoundBox().GetCenter() - kCenter).SqrLength() ) { pkChunk = kVisibleChunks.GetAt(i); kVisibleChunks.SetAt(i, kVisibleChunks.GetAt(j)); kVisibleChunks.SetAt(j, pkChunk); } } } */ //for( unsigned int i = 0; i < kVisibleChunks.GetSize(); ++i ) int i = 0; for( std::multimap::iterator it = sort_chunks.begin(); it != sort_chunks.end(); ++it ) { //pkChunk = kVisibleChunks.GetAt(i); pkChunk = it->second; pkChunk->BuildVisibleSet(pkCuller, i++ < 42); const CGrassInfo& kGrassInfo = pkChunk->GetGrassInfo(); if(kGrassInfo.GetGrassCount() > 0) m_kGrassMesh.AddGrassVertex(kGrassInfo.GetGrassVertex(), kGrassInfo.GetGrassCount()*12); } pkCuller->BuildReflectVisibleSet(); } void CMap::BuildReflectVisibleSet(CCullingProcess* pkCuller) { if( !IsLoaded() ) return; m_uiRenderFrame++; const NiCamera* pkCamera = pkCuller->GetReflectCamera(); const NiPoint3& kCenter = pkCamera->GetWorldLocation(); const NiPoint3& kDir = pkCamera->GetWorldDirection(); const NiPoint3& kRight = pkCamera->GetWorldRightVector(); const NiPoint3& kUp = pkCamera->GetWorldUpVector(); const NiFrustum& kFrustum = pkCamera->GetViewFrustum(); float fNearFarRatio = kFrustum.m_fFar / kFrustum.m_fNear; /* CBox kBox; kBox.Reset(); kBox.Intersect(kCenter + kDir*kFrustum.m_fNear + kRight*kFrustum.m_fRight + kUp*kFrustum.m_fTop); kBox.Intersect(kCenter + kDir*kFrustum.m_fNear + kRight*kFrustum.m_fRight + kUp*kFrustum.m_fBottom); kBox.Intersect(kCenter + kDir*kFrustum.m_fNear + kRight*kFrustum.m_fLeft + kUp*kFrustum.m_fTop); kBox.Intersect(kCenter + kDir*kFrustum.m_fNear + kRight*kFrustum.m_fLeft + kUp*kFrustum.m_fBottom); kBox.Intersect(kCenter + (kDir*kFrustum.m_fNear + kRight*kFrustum.m_fRight + kUp*kFrustum.m_fTop) * fNearFarRatio); kBox.Intersect(kCenter + (kDir*kFrustum.m_fNear + kRight*kFrustum.m_fRight + kUp*kFrustum.m_fBottom) * fNearFarRatio); kBox.Intersect(kCenter + (kDir*kFrustum.m_fNear + kRight*kFrustum.m_fLeft + kUp*kFrustum.m_fTop) * fNearFarRatio); kBox.Intersect(kCenter + (kDir*kFrustum.m_fNear + kRight*kFrustum.m_fLeft + kUp*kFrustum.m_fBottom) * fNearFarRatio); */ static CBox kBox; kBox.Reset(); NiPoint3 p1(kDir); p1 *= kFrustum.m_fNear; NiPoint3 p2(kRight); p2 *= kFrustum.m_fRight; NiPoint3 p3(kUp); p3 *= kFrustum.m_fTop; NiPoint3 p4(kUp); p4 *= kFrustum.m_fBottom; NiPoint3 p5(kRight); p5 *= kFrustum.m_fLeft; kBox.Intersect(kCenter.x + p1.x + p2.x + p3.x, kCenter.y + p1.y + p2.y + p3.y, kCenter.z + p1.z + p2.z + p3.z ); kBox.Intersect(kCenter.x + p1.x + p2.x + p4.x, kCenter.y + p1.y + p2.y + p4.y, kCenter.z + p1.z + p2.z + p4.z ); kBox.Intersect(kCenter.x + p1.x + p5.x + p3.x, kCenter.y + p1.y + p5.y + p3.y, kCenter.z + p1.z + p5.z + p3.z ); kBox.Intersect(kCenter.x + p1.x + p5.x + p4.x, kCenter.y + p1.y + p5.y + p4.y, kCenter.z + p1.z + p5.z + p4.z );; float x = (p1.x + p2.x + p3.x) * fNearFarRatio; float y = (p1.y + p2.y + p3.y) * fNearFarRatio; float z = (p1.z + p2.z + p3.z) * fNearFarRatio; kBox.Intersect( kCenter.x + x, kCenter.y + y, kCenter.z + z ); x = (p1.x + p2.x + p4.x) * fNearFarRatio; y = (p1.y + p2.y + p4.y) * fNearFarRatio; z = (p1.z + p2.z + p4.z) * fNearFarRatio; kBox.Intersect( kCenter.x + x, kCenter.y + y, kCenter.z + z ); x = (p1.x + p5.x + p3.x) * fNearFarRatio; y = (p1.y + p5.y + p3.y) * fNearFarRatio; z = (p1.z + p5.z + p3.z) * fNearFarRatio; kBox.Intersect( kCenter.x + x, kCenter.y + y, kCenter.z + z ); x = (p1.x + p5.x + p4.x) * fNearFarRatio; y = (p1.y + p5.y + p4.y) * fNearFarRatio; z = (p1.z + p5.z + p4.z) * fNearFarRatio; kBox.Intersect( kCenter.x + x, kCenter.y + y, kCenter.z + z ); CLIENT_METRIC_SCOPETIMER(TERRAIN_CULLTIME); CChunk* pkChunk; static CBox kChunkBox; kChunkBox.Reset(); //static NiTPrimitiveArray kVisibleChunks(256, 32); //kVisibleChunks.RemoveAll(); std::multimap sort_chunks; for( float x = kBox.m_kMin.x; x < kBox.m_kMax.x + CHUNK_SIZE; x += CHUNK_SIZE ) { for( float y = kBox.m_kMin.y; y < kBox.m_kMax.y + CHUNK_SIZE; y += CHUNK_SIZE ) { pkChunk = GetChunk(x, y); if(pkChunk && pkChunk->GetGeometry()) { kChunkBox = pkChunk->GetBoundBox(); kChunkBox.m_kMax.z += 100.f; //假设建筑物最高是100米 if(kBox.IsOverlapped(kChunkBox) && kChunkBox.TestVisible(pkCuller->GetReflectFrustumPlanes())) { //kVisibleChunks.Add(pkChunk); sort_chunks.insert( std::make_pair( (pkChunk->GetBoundBox().m_kMin - kCenter).SqrLength(), pkChunk ) ); } } } } /* //按照离摄像机的距离排序 for( unsigned int i = 0; i < kVisibleChunks.GetSize(); i++ ) { for( unsigned int j = i + 1; j < kVisibleChunks.GetSize(); j++ ) { if( (kVisibleChunks.GetAt(j)->GetBoundBox().m_kMin - kCenter).SqrLength() < (kVisibleChunks.GetAt(i)->GetBoundBox().m_kMin - kCenter).SqrLength() ) { pkChunk = kVisibleChunks.GetAt(i); kVisibleChunks.SetAt(i, kVisibleChunks.GetAt(j)); kVisibleChunks.SetAt(j, pkChunk); } } } */ //for( unsigned int i = 0; i < kVisibleChunks.GetSize(); ++i ) //{ // kVisibleChunks.GetAt(i)->BuildReflectVisibleSet(pkCuller); //} for( std::multimap::iterator it = sort_chunks.begin(); it != sort_chunks.end(); ++it ) { pkChunk = it->second; pkChunk->BuildReflectVisibleSet( pkCuller ); } } CModelInstance* CMap::GetModelInstance(const ModelRef& kModelRef) { CTile* pkTile = GetTileByIndex(kModelRef.iTileX, kModelRef.iTileY); if( pkTile ) return pkTile->GetModelInstance(kModelRef.uiIndex); return NULL; } //返回所有碰撞的结果 bool CMap::MultiCollideBox(const NiPoint3& start, const NiPoint3& end, const NiPoint3& extent, ResultList& resultList) { ++m_uiCollisionFrame; float deltaX = end.x - start.x; float deltaY = end.y - start.y; int XDir = deltaX < 0.0f ? -1:1; int YDir = deltaY < 0.0f ? -1:1; int XStart, XEnd, YStart, YEnd; int XMin = int(m_kBoundBox.m_kMin.x); int XMax = int(m_kBoundBox.m_kMax.x); int YMin = int(m_kBoundBox.m_kMin.y); int YMax = int(m_kBoundBox.m_kMax.y); XStart = XDir > 0 ? ALIGN(start.x - extent.x, CHUNK_SIZE) : ALIGN(start.x + extent.x + CHUNK_SIZE, CHUNK_SIZE); XEnd = XDir > 0 ? ALIGN(end.x + extent.x + CHUNK_SIZE, CHUNK_SIZE) : ALIGN(end.x - extent.x, CHUNK_SIZE); XStart = NiClamp(XStart, XMin, XMax); XEnd = NiClamp(XEnd, XMin, XMax); if( XStart*XDir >= XEnd*XDir ) return false; int x, y; CChunk *chunk; if(NiAbs(deltaX) < 0.01f || XEnd == XStart + XDir*CHUNK_SIZE)//此时DeltaX可能为0 { YStart = YDir > 0 ? ALIGN(start.y - extent.y, CHUNK_SIZE) : ALIGN(start.y + extent.y + CHUNK_SIZE, CHUNK_SIZE); YEnd = YDir > 0 ? ALIGN(end.y + extent.y + CHUNK_SIZE, CHUNK_SIZE) : ALIGN(end.y - extent.y, CHUNK_SIZE); YStart = NiClamp(YStart, YMin, YMax); YEnd = NiClamp(YEnd, YMin, YMax); for( x = XStart; x*XDir < XEnd*XDir; x += CHUNK_SIZE * XDir ) { for( y = YStart; y*YDir < YEnd*YDir; y += CHUNK_SIZE * YDir) { chunk = GetChunk(float(x + XDir), float(y + YDir)); if( chunk ) chunk->MultiCollideBox(start, end, extent, resultList); } } } else { //Y = mX + c; float m = deltaY / deltaX; float c = end.y - end.x*m; float y1, y2; for( x = XStart; x*XDir < XEnd*XDir; x += CHUNK_SIZE*XDir ) { y1 = m*x + c; y2 = y1 + CHUNK_SIZE*XDir*m; YStart = YDir > 0 ? ALIGN(y1 - extent.y, CHUNK_SIZE) : ALIGN(y1 + extent.y + CHUNK_SIZE, CHUNK_SIZE); YEnd = YDir > 0 ? ALIGN(y2 + extent.y + CHUNK_SIZE, CHUNK_SIZE) : ALIGN(y2 - extent.y, CHUNK_SIZE); YStart = NiClamp(YStart, YMin, YMax); YEnd = NiClamp(YEnd, YMin, YMax); for( y = YStart; y*YDir < YEnd*YDir; y += CHUNK_SIZE*YDir ) { chunk = GetChunk(float(x + XDir), float(y + YDir)); if( chunk ) chunk->MultiCollideBox(start, end, extent, resultList); } } } if( resultList.size() > 0 ) { resultList.Sort(false); return true; } return false; } //Returns 1 if some movement occured, 0 if no movement occured. bool CMap::MoveObject(NiPoint3& start, const NiPoint3& delta, const NiPoint3& extent, Result& result) { if( delta.SqrLength() == 0.f ) { result.fTime = 0.f; result.kNormal = NiPoint3(0.f, 0.f, 0.f); return false; } NiPoint3 kDelta = delta; kDelta.Unitize(); NiPoint3 kStart = start + kDelta*0.01f; ResultList resultList; if( MultiCollideBox(kStart, kStart + delta, extent, resultList) ) { result = resultList[0]; } else { result.fTime = 1.0f; result.kNormal = NiPoint3(0.f, 0.f, 0.f); } start += delta * result.fTime; return result.fTime > 0.f; } void CMap::BoxCheck(const CBox& kBox, NiTPrimitiveArray& kModelList) { ++m_uiCollisionFrame; NiPoint3 kCenter = (kBox.m_kMin + kBox.m_kMax)*0.5f; CChunk* pkChunk = GetChunk(kCenter.x, kCenter.y); if( pkChunk ) pkChunk->BoxCheck(kBox, kModelList); } void CMap::DrawSky(const NiCamera& kCamera, bool bRefectPass) { m_kSky.Draw(kCamera, bRefectPass); } void CMap::DrawGrass(const NiPoint3& kOrigin) { m_kGrassMesh.Draw(kOrigin); }