www.pudn.com > notWow.rar > Map.cpp
#include "Map.h"
#include "time.h"
#include "ModelMgr.h"
#include "TexMgr.h"
#include "ResLoader.h"
#include "Camera.h"
#include "HeroCtrl.h"
extern ResLoader g_ResLdr;
extern TexturesManager g_TexMgr;
extern ModelsManager g_MdlMgr;
extern Camera g_Camera;
extern HeroController g_HeroCtrl;
bool Map::Init(LPDIRECT3DDEVICE9 pd3dDevice,const char *Name,const char *SkyName,ScriptID ID)
{
Free();
if(pd3dDevice != NULL)
m_pd3dDevice = pd3dDevice;
m_ScriptID = ID;
int types,i,j,m,n,l,k,t;
char* pFile,*pOrg;
int Size;
pOrg = pFile = (char*)g_ResLdr.GetFile(Name,Size,RES_MAP);
TextureID* pID;
memcpy(&types,pFile,sizeof(int));
pFile += sizeof(int);
pID = new TextureID[types];
char name[128];
int len;
for(i = 0 ; i < types ; ++ i)
{
memcpy(&len,pFile,sizeof(int));
pFile += sizeof(int);
memcpy(name,pFile,sizeof(char)*(len+1));
pFile += sizeof(char)*(len+1);
pID[i] = g_TexMgr.AddTexture(name);
}
memcpy(&m_TerriansWidth,pFile,sizeof(int));
pFile += sizeof(int);
memcpy(&m_TerriansHeight,pFile,sizeof(int));
pFile += sizeof(int);
m_TexturesHeight = m_TerriansHeight / 4;
m_TexturesWidth = m_TerriansWidth / 4 ;
m_fTextureSize = 4.0;
m_fTerrianSize = 1.0;
m_nTerrianVertices = m_TexturesWidth * m_TexturesHeight * 25;
int TexTotal = m_TexturesWidth*m_TexturesHeight;
m_pTerrians = new TERRIAN[m_TerriansWidth*m_TerriansHeight];
m_pHeights = new float[(m_TerriansWidth+1)*(m_TerriansHeight+1)];
m_pMaxHeights = new float[m_TexturesWidth * m_TexturesHeight];
m_pMinHeights = new float[m_TexturesWidth * m_TexturesHeight];
m_pTerrianDraw = new bool[m_TexturesWidth * m_TexturesHeight];
m_pTextureID = new TextureID[TexTotal];
memcpy(m_pTerrians,pFile,m_TerriansWidth*m_TerriansHeight*sizeof(TERRIAN));
pFile += m_TerriansWidth*m_TerriansHeight*sizeof(TERRIAN);
memcpy(m_pHeights,pFile,(m_TerriansWidth+1)*(m_TerriansHeight+1)*sizeof(float));
pFile += (m_TerriansWidth+1)*(m_TerriansHeight+1)*sizeof(float);
memcpy(m_pTextureID,pFile,TexTotal*sizeof(short));
pFile += TexTotal*sizeof(short);
for(i = 0 ; i < TexTotal ; ++ i)
m_pTextureID[i] = pID[m_pTextureID[i]];
int count;
memcpy(&count,pFile,sizeof(int));
pFile += sizeof(int);
WorldObject Obj;
for(i = 0 ; i < count ; ++ i)
{
memcpy(&Obj.m_ObjectID,pFile,sizeof(short));
pFile += sizeof(short);
memcpy(&Obj.m_SignID,pFile,sizeof(short));
pFile += sizeof(short);
memcpy(Obj.m_Name,pFile,sizeof(char)*32);
pFile += sizeof(char)*32;
memcpy(&Obj.m_fPosX,pFile,sizeof(float));
pFile += sizeof(float);
memcpy(&Obj.m_fPosY,pFile,sizeof(float));
pFile += sizeof(float);
memcpy(&Obj.m_fPosZ,pFile,sizeof(float));
pFile += sizeof(float);
memcpy(&Obj.m_Dir,pFile,sizeof(short));
pFile += sizeof(short);
Obj.m_ModelID = g_MdlMgr.AddModel(Obj.m_ObjectID);
m_ObjectsList.push_back(Obj);
}
delete [] pID;
delete [] pOrg;
//int nObj = m_ObjectsList.size();
m_NearPtrs.resize(m_ObjectsList.size() );
m_FarPtrs.resize(m_ObjectsList.size());
uint16* pIB;
// Create the Index buffer
// 32 * 3 + 2 * 3
if( FAILED( m_pd3dDevice->CreateIndexBuffer( 102 * sizeof(uint16),
0, D3DFMT_INDEX16,
D3DPOOL_MANAGED, &m_pIB, NULL ) ) )
{
Free();
return false;
}
if( FAILED( m_pIB->Lock( 0, 0, (VOID**)&pIB, 0 ) ) )
{
Free();
return false;
}
for( i = 0 ; i < 4 ; ++ i)
{
for( j = 0 ; j < 4 ; ++ j)
{
k = 6 * ( i * 4 + j);
uint16 v1 = i * 5 + j;
uint16 v2 = (i + 1) * 5 + j;
uint16 v3 = (i + 1) * 5 + j + 1;
uint16 v4 = i * 5 + j + 1;
pIB[k] = v1;
pIB[k+1] = v2;
pIB[k+2] = v3;
pIB[k+3] = v1;
pIB[k+4] = v3;
pIB[k+5] = v4;
}
}
pIB[96] = 0;
pIB[97] = 20;
pIB[98] = 24;
pIB[99] = 0;
pIB[100] = 24;
pIB[101] = 4;
m_pIB->Unlock();
if( FAILED(m_pd3dDevice->CreateVertexBuffer( m_nTerrianVertices * sizeof(TERRIANVERTEX),
0, TERRIANVERTEX::FVF ,
D3DPOOL_MANAGED, &m_pTerriansVB, NULL ) ) )
{
Free();
return false;
}
TERRIANVERTEX* pVBVertices;
if( FAILED(m_pTerriansVB->Lock( 0, 0, (VOID**)&pVBVertices, 0 ) ) )
{
Free();
return false;
}
float Min = 0,Max = 0;
float basew ;
float baseh ;
int iw ;
int ih ;
for(i = 0 ; i < m_TexturesHeight ; ++ i)
{
for(j = 0 ; j < m_TexturesWidth ; ++ j)
{
k = 25 * (i * m_TexturesWidth + j);
t = i * m_TexturesWidth + j;
basew = j * m_fTextureSize;
baseh = i * m_fTextureSize;
iw = j * 4;
ih = i * 4;
Min = Max = 0;
for(m = 0 ; m < 5 ; ++ m)
{
for(n = 0 ; n < 5 ; ++ n)
{
l = k + 4 * m + m + n;
float Height = m_pHeights[(ih + m) * (m_TerriansWidth+1) + iw + n];
if(Min > Height)
Min = Height;
if(Max < Height)
Max = Height;
pVBVertices[l].Pos = D3DXVECTOR3(basew + (float)n ,Height , baseh + (float)m);
pVBVertices[l].Texcoord = D3DXVECTOR2(1.0f - 0.25f * m,0.25f * n);
}
}
m_pMaxHeights[t] = Max;
m_pMinHeights[t] = Min;
}
}
m_pTerriansVB->Unlock();
if( FAILED(m_pd3dDevice->CreateVertexBuffer( 4 * sizeof(SKYVERTEX),
0, SKYVERTEX::FVF ,
D3DPOOL_MANAGED, &m_pSkyVB, NULL ) ) )
{
Free();
return false;
}
SKYVERTEX* pSkyVB;
if( FAILED(m_pSkyVB->Lock( 0, 0, (VOID**)&pSkyVB, 0 ) ) )
{
Free();
return false;
}
pSkyVB[0].Pos.x = -g_Camera.GetSkyHalfWidth();
pSkyVB[0].Pos.y = g_Camera.GetSkyY();
pSkyVB[0].Pos.z = 0;
pSkyVB[0].Color = 0xFF0000E0;
pSkyVB[1].Pos.x = g_Camera.GetSkyHalfWidth();
pSkyVB[1].Pos.y = g_Camera.GetSkyY();
pSkyVB[1].Pos.z = 0;
pSkyVB[1].Color = 0xFF0000E0;
pSkyVB[2].Pos.x = -g_Camera.GetSkyHalfWidth();
pSkyVB[2].Pos.y = g_Camera.GetSkyY() + g_Camera.GetSkyHeight();
pSkyVB[2].Pos.z = 0;
pSkyVB[2].Color = 0xFF0000E0;
pSkyVB[3].Pos.x = g_Camera.GetSkyHalfWidth();
pSkyVB[3].Pos.y = g_Camera.GetSkyY() + g_Camera.GetSkyHeight();
pSkyVB[3].Pos.z = 0;
pSkyVB[3].Color = 0xFF0000E0;
m_pSkyVB->Unlock();
if( FAILED(m_pd3dDevice->CreateVertexBuffer( 6 * sizeof(BACKVERTEX),
0, BACKVERTEX::FVF ,
D3DPOOL_MANAGED, &m_pBackVB, NULL ) ) )
{
Free();
return false;
}
BACKVERTEX* pBackVB;
if( FAILED(m_pBackVB->Lock( 0, 0, (VOID**)&pBackVB, 0 ) ) )
{
Free();
return false;
}
pBackVB[0].Pos.x = 0;
pBackVB[0].Pos.y = -0.2;
pBackVB[0].Pos.z = g_Camera.GetBGHalfWidth();
pBackVB[0].Color = 0xFF808080;
pBackVB[1].Pos.x = 0;
pBackVB[1].Pos.y = -0.2;
pBackVB[1].Pos.z = -g_Camera.GetBGHalfWidth();
pBackVB[1].Color = 0xFF808080;
pBackVB[2].Pos.x = 0;
pBackVB[2].Pos.y = g_Camera.GetBGHeight();
pBackVB[2].Pos.z = g_Camera.GetBGHalfWidth();
pBackVB[2].Color = 0xFF808080;
pBackVB[3].Pos.x = 0;
pBackVB[3].Pos.y = g_Camera.GetBGHeight();
pBackVB[3].Pos.z = -g_Camera.GetBGHalfWidth();
pBackVB[3].Color = 0xFF808080;
pBackVB[4].Pos.x = 0;
pBackVB[4].Pos.y = g_Camera.GetBGHeight() * 1.2;
pBackVB[4].Pos.z = g_Camera.GetBGHalfWidth();
pBackVB[4].Color = 0x00808080;
pBackVB[5].Pos.x = 0;
pBackVB[5].Pos.y = g_Camera.GetBGHeight() * 1.2;
pBackVB[5].Pos.z = -g_Camera.GetBGHalfWidth();
pBackVB[5].Color = 0x00808080;
m_pBackVB->Unlock();
m_Effect.Init(pd3dDevice);
m_SkyTexture = g_TexMgr.AddTexture(SkyName);
SAFE_DELETE(m_pRootNode);
CreateTree(NULL,&m_pRootNode,m_TerriansWidth * m_fTerrianSize / 2 , 0 , m_TerriansWidth * m_fTerrianSize / 2,
m_TerriansWidth * m_fTerrianSize / 2);
return true;
}
bool Map::Reset()
{
m_Effect.Reset();
return true;
}
void Map::Lost()
{
m_Effect.Lost();
}
void Map::Free()
{
m_LastID = -1;
// for(list::iterator Itr = m_ObjectsList.begin() ; Itr != m_ObjectsList.end(); Itr ++)
// g_MdlMgr.Delete(Itr->m_ModelID);
SAFE_DELETE(m_pRootNode);
SAFE_RELEASE(m_pTerriansVB);
SAFE_RELEASE(m_pIB);
SAFE_RELEASE(m_pSkyVB);
SAFE_RELEASE(m_pBackVB);
m_Effect.Free();
SAFE_DELETE_A(m_pTerrianDraw);
SAFE_DELETE_A(m_pMaxHeights);
SAFE_DELETE_A(m_pMinHeights);
SAFE_DELETE_A(m_pHeights);
SAFE_DELETE_A(m_pTerrians);
SAFE_DELETE_A(m_pTextureID);
m_ObjectsList.clear();
}
void Map::Render()
{
float Start = g_Camera.GetFogStart();
float End = g_Camera.GetFogEnd();
m_pd3dDevice->SetTransform(D3DTS_VIEW,g_Camera.GetView());
m_pd3dDevice->SetTransform(D3DTS_PROJECTION,g_Camera.GetProj());
m_pd3dDevice->SetRenderState(D3DRS_FOGENABLE,TRUE);
m_pd3dDevice->SetRenderState(D3DRS_FOGCOLOR,0x00808080);
m_pd3dDevice->SetRenderState(D3DRS_FOGTABLEMODE,D3DFOG_LINEAR);
m_pd3dDevice->SetRenderState(D3DRS_FOGSTART,*(DWORD*)(&Start));
m_pd3dDevice->SetRenderState(D3DRS_FOGEND,*(DWORD*)(&End));
int k;
UINT nPasses,iPass;
HRESULT hr;
m_pd3dDevice->SetFVF( TERRIANVERTEX::FVF );
m_pd3dDevice->SetStreamSource( 0, m_pTerriansVB,0 ,sizeof(TERRIANVERTEX) );
m_pd3dDevice->SetIndices( m_pIB );
m_Effect.SetTechnique(EFFECT_TERRIAN);
m_Effect.Begin(&nPasses, 0);
m_Effect.SetViewProjMatrix(g_Camera.GetViewProj());
for (iPass = 0; iPass < nPasses; ++ iPass)
{
m_Effect.BeginPass(iPass);
m_pd3dDevice->SetIndices( m_pIB );
while(!m_NearDrawList.empty())
{
k = m_NearDrawList.front();
m_NearDrawList.pop_front();
m_Effect.SetTexture(g_TexMgr.GetTexture(m_pTextureID[k]));
m_Effect.CommitChanges();
hr = m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST,
k * 25, // index base
0,
25,
0,
32);
}
m_Effect.EndPass();
}
m_Effect.End();
m_Effect.SetTechnique(EFFECT_TERRIAN);
m_Effect.Begin(&nPasses, 0);
for (iPass = 0; iPass < nPasses; ++ iPass)
{
m_Effect.BeginPass(iPass);
while(!m_FarDrawList.empty())
{
k = m_FarDrawList.front();
m_FarDrawList.pop_front();
m_Effect.SetTexture(g_TexMgr.GetTexture(m_pTextureID[k]));
m_Effect.CommitChanges();
hr = m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST,
k * 25, // index base
0,
25,
0,
32);
//hr = m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST,
// k * 25, // index base
// 0,
// 25,
// 96,
// 2);
}
m_Effect.EndPass();
}
m_Effect.End();
vector::iterator Itr;
for(Itr = m_NearPtrs.begin() ; Itr != m_NearCurItr ; ++ Itr)
{
Itr->Ptr->Render(g_Camera.GetViewProj());
}
for(Itr = m_FarPtrs.begin() ; Itr != m_FarCurItr ; ++ Itr)
{
Itr->Ptr->Render(g_Camera.GetViewProj(),true);
}
if(g_Camera.IsFPView())
{
m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
float sinDir = Math::Sin(g_Camera.GetBGDir());
float cosDir = Math::Cos(g_Camera.GetBGDir());
m_Effect.SetPosition(&D3DXVECTOR4(g_Camera.GetBGX(),0,g_Camera.GetBGZ(),0));
m_Effect.SetDirection(&D3DXVECTOR4(sinDir,cosDir,0,0));
m_Effect.SetViewProjMatrix(g_Camera.GetViewProj());
m_Effect.SetTechnique(EFFECT_BG);
m_Effect.Begin(&nPasses, 0);
m_pd3dDevice->SetFVF( BACKVERTEX::FVF );
m_pd3dDevice->SetStreamSource( 0, m_pBackVB,0 ,sizeof(BACKVERTEX) );
for (iPass = 0; iPass < nPasses; ++ iPass)
{
m_Effect.BeginPass(iPass);
hr = m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP,0,4);
m_Effect.EndPass();
}
m_Effect.End();
m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
}
m_pd3dDevice->SetRenderState(D3DRS_FOGENABLE,FALSE);
}
void Map::Update()
{
// Map Trigger
int x = (int)g_HeroCtrl.GetHero()->m_fPosX;
int z = (int)g_HeroCtrl.GetHero()->m_fPosZ;
TERRIAN Trr = m_pTerrians[z * m_TerriansWidth + x];
if((Trr & 0xFF00) == TRR_SPECIAL)
{
int id = (int)(Trr & 0x00FF);
if(id != m_LastID)
{
// MapScript* pScript = (MapScript*)g_ScriptSys.GetScript(m_ScriptID);
// pScript->OnSpecial(id);
m_LastID = id;
}
}
FILE* fp = fopen("F:\\NewTest.txt","w");
int time = timeGetTime();
m_NearDrawList.clear();
m_FarDrawList.clear();
m_FarCurItr = m_FarPtrs.begin();
m_NearCurItr = m_NearPtrs.begin();
m_FarCurPos = m_NearCurPos = 0;
memset(m_pTerrianDraw,0,sizeof(bool)*m_TexturesWidth*m_TexturesHeight);
fprintf(fp,"memset time : %d\n",timeGetTime()-time);
time = timeGetTime();
if(g_Camera.IsFPView())
{
AddTreeNode(g_Camera.GetVisibityFrustum(),true,m_pRootNode);
AddTreeNode(g_Camera.GetBackgroundFrustum(),false,m_pRootNode);
}
else
{
AddTreeNode(g_Camera.GetFrustum(),true,m_pRootNode);
}
fprintf(fp,"frustum time : %d\n",timeGetTime()-time);
time = timeGetTime();
vector::iterator Itr;
for(Itr = m_NearPtrs.begin() ; Itr != m_NearCurItr ; ++ Itr)
{
Itr->Ptr->m_fViewZ = Itr->Ptr->m_fPosX * g_Camera.GetView()->_13 +
Itr->Ptr->m_fPosY * g_Camera.GetView()->_23 +
Itr->Ptr->m_fPosZ * g_Camera.GetView()->_33 + g_Camera.GetView()->_43;
}
sort(m_NearPtrs.begin(),m_NearCurItr);
fprintf(fp,"sort time : %d\n",timeGetTime()-time);
time = timeGetTime();
fprintf(fp,"Terrian:%d\nObject:%d\n",m_NearDrawList.size(),
m_NearCurPos);
fprintf(fp,"Far Terrian:%d\nFar Object:%d\n",m_FarDrawList.size(),
m_FarCurPos);
fclose(fp);
}
void Map::AddTreeNode(Frustum* pFrustum,bool bNear,Node *Node)
{
if(Node == NULL)
return;
int Count = 0;
bool CompletelyContained = false;
// the node is out of the frustum
if(!pFrustum->CheckRectangle(Node->XPos,Node->YPos,Node->ZPos,
Node->Size,Node->Size,Node->Size ,
&CompletelyContained))
return;
if(!CompletelyContained)
{
for(int i = 0 ; i < 8; ++ i)
{
if(Node->Nodes[i] != NULL)
{
AddTreeNode(pFrustum,bNear,Node->Nodes[i]);
Count ++;
}
}
if(Count)
return;
}
list::iterator TrrItr;
for(TrrItr = Node->TerrianList.begin() ; TrrItr != Node->TerrianList.end(); ++ TrrItr)
{
if(!m_pTerrianDraw[*TrrItr])
{
if(bNear)
m_NearDrawList.push_back(*TrrItr);
else
m_FarDrawList.push_back(*TrrItr);
m_pTerrianDraw[*TrrItr] = true;
}
}
list::iterator>::iterator ObjItr;
for(ObjItr = Node->ObjectsList.begin() ; ObjItr != Node->ObjectsList.end() ; ++ ObjItr)
{
if((*ObjItr)->m_bRender)
continue;
(*ObjItr)->m_bRender = true;
if(bNear)
{
m_NearCurItr->Ptr = &(*(*ObjItr));
m_NearCurItr ++;
m_NearCurPos ++;
}
else
{
m_FarCurItr->Ptr = &(*(*ObjItr));
m_FarCurItr ++;
m_FarCurPos ++;
}
}
}
void Map::CreateTree(Node* pParent,Node** ppNode,float XPos,float YPos,float ZPos,float Size)
{
int i,j;
float XOff, YOff, ZOff;
*ppNode = new Node;
// Store node coordinates and size
(*ppNode)->XPos = XPos;
(*ppNode)->YPos = YPos;
(*ppNode)->ZPos = ZPos;
(*ppNode)->Size = Size;
// Add Object
if(pParent == NULL)
{
list::iterator Itr;
for(Itr = m_ObjectsList.begin() ; Itr != m_ObjectsList.end() ; ++ Itr)
{
if(Itr->m_ModelID < 0)
continue;
g_MdlMgr.GetModel(Itr->m_ModelID)->GetBoundBox(Itr->m_fPosX,Itr->m_fPosY,Itr->m_fPosZ,Itr->m_Dir,
&Itr->m_vMin,&Itr->m_vMax);
if((*ppNode)->CheckRectangle(Itr->m_vMin,Itr->m_vMax))
(*ppNode)->ObjectsList.push_back(Itr);
}
}
else
{
list::iterator>::iterator Itr;
for(Itr = pParent->ObjectsList.begin(); Itr != pParent->ObjectsList.end() ; ++ Itr)
{
if((*ppNode)->CheckRectangle((*Itr)->m_vMin,(*Itr)->m_vMax))
(*ppNode)->ObjectsList.push_back((*Itr));
}
}
// Add Terrian
int xs = (XPos - Size) / 4;
int xe = (XPos + Size) / 4;
int zs = (ZPos - Size) / 4;
int ze = (ZPos + Size) / 4;
float txs,txe,tzs,tze;
for(i = zs ; i < ze ; ++ i)
{
for(j = xs; j < xe ; ++ j)
{
int k = i * m_TexturesWidth + j;
txs = j * m_fTextureSize;
tzs = i * m_fTextureSize;
txe = txs + m_fTextureSize;
tze = tzs + m_fTextureSize;
D3DXVECTOR3 vMin(txs,m_pMinHeights[k],tzs);
D3DXVECTOR3 vMax(txe,m_pMaxHeights[k],tze);
if((*ppNode)->CheckRectangle(vMin,vMax))
(*ppNode)->TerrianList.push_back(k);
}
}
// delete emtpy node
if((*ppNode)->ObjectsList.empty() && (*ppNode)->TerrianList.empty())
{
delete (*ppNode);
(*ppNode) = NULL;
return;
}
// Split node if size > maximum
if(Size > 4.0)
{
for( i = 0; i < 8 ; ++ i)
{
XOff = (((i % 2) < 1) ? -1.0f : 1.0f) * (Size / 2.0f);
ZOff = (((i % 4) < 2) ? -1.0f : 1.0f) * (Size / 2.0f);
YOff = (((i % 8) < 4) ? -1.0f : 1.0f) * (Size / 2.0f);
// Sort the polygons with the new child node
CreateTree(*ppNode,&((*ppNode)->Nodes[i]),XPos+XOff,YPos+YOff,ZPos+ZOff,Size/2.0f);
}
}
}
float Map::GetY(float fX,float fZ)
{
int iX = (int)fX;
int iZ = (int)fZ;
if(iX < 0 || iX > m_TerriansWidth || iZ < 0 || iZ > m_TerriansHeight)
return 0.0f;
float fFX = fX - (float)iX;
float fFZ = fZ - (float)iZ;
float fHeights[4];
fHeights[0] = m_pHeights[(m_TerriansWidth + 1) * iZ + iX];
fHeights[1] = m_pHeights[(m_TerriansWidth + 1) * (iZ + 1) + iX];
fHeights[2] = m_pHeights[(m_TerriansWidth + 1) * (iZ + 1) + iX + 1];
fHeights[3] = m_pHeights[(m_TerriansWidth + 1) * iZ + iX + 1];
float t1,t2;
t1 = (fHeights[3] - fHeights[0]) * fFZ + fHeights[0];
t2 = (fHeights[2] - fHeights[1]) * fFZ + fHeights[1];
float fY = (t2 - t1) * fFZ + t1;
return fY;
}