client/GameLib/AreaTerrain.cpp

1194 lines
33 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "StdAfx.h"
#include "../PRTerrainLib/StdAfx.h"
#include "../eterLib/ResourceManager.h"
#include "../eterlib/StateManager.h"
#include "../EterPack/EterPackManager.h"
#include "AreaTerrain.h"
#include "MapOutdoor.h"
CDynamicPool<CTerrain> CTerrain::ms_kPool;
void CTerrain::DestroySystem()
{
ms_kPool.Destroy();
}
CTerrain* CTerrain::New()
{
return ms_kPool.Alloc();
}
void CTerrain::Delete(CTerrain* pkTerrain)
{
pkTerrain->Clear();
ms_kPool.Free(pkTerrain);
}
CTerrain::CTerrain()
{
memset(&m_lpAlphaTexture, 0, sizeof(m_lpAlphaTexture));
memset(&m_lpMarkedTexture, 0, sizeof(m_lpMarkedTexture));
Initialize();
}
CTerrain::~CTerrain()
{
DeallocateMarkedSplats();
RAW_DeallocateSplats();
Clear();
}
void CTerrain::SetMapOutDoor(CMapOutdoor * pOwnerOutdoorMap)
{
m_pOwnerOutdoorMap=pOwnerOutdoorMap;
}
void CTerrain::Clear()
{
DeallocateMarkedSplats();
CTerrainImpl::Clear();
Initialize();
}
bool CTerrain::Initialize()
{
SetReady(false);
m_strName = "";
m_wX = m_wY = 0xFFFF;
m_bReady = false;
m_bMarked = false;
for (BYTE byY = 0; byY < PATCH_YCOUNT; ++byY)
for (BYTE byX = 0; byX < PATCH_XCOUNT; ++byX)
m_TerrainPatchList[byY * PATCH_XCOUNT + byX].Clear();
return true;
}
void CTerrain::LoadMiniMapTexture(const char * c_pchMiniMapFileName)
{
DWORD dwStart = ELTimer_GetMSec();
CGraphicImage * pImage = (CGraphicImage *) CResourceManager::Instance().GetResourcePointer(c_pchMiniMapFileName);
m_MiniMapGraphicImageInstance.SetImagePointer(pImage);
if (!m_MiniMapGraphicImageInstance.GetTexturePointer()->IsEmpty())
{
m_lpMiniMapTexture = m_MiniMapGraphicImageInstance.GetTexturePointer()->GetD3DTexture();
Tracef("CTerrain::LoadMiniMapTexture %d ms\n", ELTimer_GetMSec() - dwStart);
}
else
{
Tracef(" CTerrain::LoadMiniMapTexture - MiniMapTexture Error");
m_lpMiniMapTexture = NULL;
}
}
void CTerrain::LoadShadowTexture(const char * ShadowFileName)
{
DWORD dwStart = ELTimer_GetMSec();
CGraphicImage * pImage = (CGraphicImage *) CResourceManager::Instance().GetResourcePointer(ShadowFileName);
m_ShadowGraphicImageInstance.SetImagePointer(pImage);
if (!m_ShadowGraphicImageInstance.GetTexturePointer()->IsEmpty())
m_lpShadowTexture = m_ShadowGraphicImageInstance.GetTexturePointer()->GetD3DTexture();
else
{
TraceError(" CTerrain::LoadShadowTexture - ShadowTexture is Empty");
m_lpShadowTexture = NULL;
}
Tracef("CTerrain::LoadShadowTexture %d ms\n", ELTimer_GetMSec() - dwStart);
}
bool CTerrain::LoadShadowMap(const char * c_pszFileName)
{
DWORD dwStart = ELTimer_GetMSec();
Tracef("LoadShadowMap %s ", c_pszFileName);
CMappedFile file;
LPCVOID c_pvData;
if (!CEterPackManager::Instance().Get(file, c_pszFileName, &c_pvData))
{
TraceError(" CTerrain::LoadShadowMap - %s OPEN ERROR", c_pszFileName);
return false;
}
DWORD dwShadowMapSize = sizeof(WORD) * 256 * 256;
if (file.Size() != dwShadowMapSize)
{
TraceError(" CTerrain::LoadShadowMap - %s SIZE ERROR", c_pszFileName);
return false;
}
memcpy(m_awShadowMap, c_pvData, dwShadowMapSize);
Tracef("%d ms\n", ELTimer_GetMSec() - dwStart);
return true;
}
//////////////////////////////////////////////////////////////////////////
// Seamless<73><73> <20><><EFBFBD>ο<EFBFBD> <20>Լ<EFBFBD><D4BC><EFBFBD>...
//////////////////////////////////////////////////////////////////////////
void CTerrain::CopySettingFromGlobalSetting()
{
m_lViewRadius = m_pOwnerOutdoorMap->GetViewRadius();
m_fHeightScale = m_pOwnerOutdoorMap->GetHeightScale();
}
WORD CTerrain::WE_GetHeightMapValue(short sX, short sY)
{
if (sX>=-1 && sY>=-1 && sX<HEIGHTMAP_RAW_XSIZE-1 && sY<HEIGHTMAP_RAW_YSIZE-1)
return GetHeightMapValue(sX,sY);
BYTE byTerrainNum;
if ( !m_pOwnerOutdoorMap->GetTerrainNumFromCoord(m_wX, m_wY, &byTerrainNum) )
{
Tracef("CTerrain::WE_GetHeightMapValue : Can't Get TerrainNum from Coord %d, %d", m_wX, m_wY);
byTerrainNum = 4;
}
short sTerrainCouuntX, sTerrainCouuntY;
m_pOwnerOutdoorMap->GetTerrainCount(&sTerrainCouuntX, &sTerrainCouuntY);
CTerrain * pTerrain = NULL;
if (sY < -1)
{
if (m_wY <= 0)
{
if ( sX < -1)
{
if (m_wX <= 0)
return GetHeightMapValue(-1, -1);
else
{
if (!m_pOwnerOutdoorMap->GetTerrainPointer(byTerrainNum - 1, &pTerrain))
return GetHeightMapValue(-1, -1);
else
return pTerrain->GetHeightMapValue(sX + XSIZE, -1);
}
}
else if (sX >= HEIGHTMAP_RAW_XSIZE - 1)
{
if (m_wX >= sTerrainCouuntX - 1)
return GetHeightMapValue(HEIGHTMAP_RAW_XSIZE - 1, -1);
else
{
if (!m_pOwnerOutdoorMap->GetTerrainPointer(byTerrainNum + 1, &pTerrain))
return GetHeightMapValue(HEIGHTMAP_RAW_XSIZE - 1, -1);
else
return pTerrain->GetHeightMapValue(sX - XSIZE, -1);
}
}
else
return GetHeightMapValue(sX, -1);
}
else
{
if (sX < -1)
{
if (m_wX <= 0)
{
if (!m_pOwnerOutdoorMap->GetTerrainPointer(byTerrainNum - 3, &pTerrain))
return GetHeightMapValue(-1, -1);
else
return pTerrain->GetHeightMapValue(-1, sY + YSIZE);
}
else
{
if (!m_pOwnerOutdoorMap->GetTerrainPointer(byTerrainNum - 4, &pTerrain))
return GetHeightMapValue(-1, -1);
else
return pTerrain->GetHeightMapValue(sX + XSIZE, sY + YSIZE);
}
}
else if (sX >= HEIGHTMAP_RAW_XSIZE - 1)
{
if (m_wX >= sTerrainCouuntX)
{
if (!m_pOwnerOutdoorMap->GetTerrainPointer(byTerrainNum - 3, &pTerrain))
return GetHeightMapValue(HEIGHTMAP_RAW_XSIZE - 1, -1);
else
return pTerrain->GetHeightMapValue(HEIGHTMAP_RAW_XSIZE - 1, sY + YSIZE);
}
else
{
if (!m_pOwnerOutdoorMap->GetTerrainPointer(byTerrainNum - 2, &pTerrain))
return GetHeightMapValue(HEIGHTMAP_RAW_XSIZE - 1, -1);
else
return pTerrain->GetHeightMapValue(sX - XSIZE, sY + YSIZE);
}
}
else
{
if (!m_pOwnerOutdoorMap->GetTerrainPointer(byTerrainNum - 3, &pTerrain))
return GetHeightMapValue(sX, -1);
else
return pTerrain->GetHeightMapValue(sX, sY + YSIZE);
}
}
}
else if (sY >= HEIGHTMAP_RAW_YSIZE - 1)
{
if (m_wY >= sTerrainCouuntY - 1)
{
if (sX < -1)
{
if (m_wX <= 0)
return GetHeightMapValue(-1, HEIGHTMAP_RAW_XSIZE - 1);
else
{
if (!m_pOwnerOutdoorMap->GetTerrainPointer(byTerrainNum - 1, &pTerrain))
return GetHeightMapValue(-1, HEIGHTMAP_RAW_XSIZE - 1);
else
return pTerrain->GetHeightMapValue(sX + XSIZE, HEIGHTMAP_RAW_YSIZE - 1);
}
}
else if (sX >= HEIGHTMAP_RAW_XSIZE - 1)
{
if (m_wX >= sTerrainCouuntX - 1)
return GetHeightMapValue(HEIGHTMAP_RAW_XSIZE - 1, HEIGHTMAP_RAW_YSIZE - 1);
else
{
if (!m_pOwnerOutdoorMap->GetTerrainPointer(byTerrainNum + 1, &pTerrain))
return GetHeightMapValue(HEIGHTMAP_RAW_XSIZE - 1, HEIGHTMAP_RAW_YSIZE - 1);
else
return pTerrain->GetHeightMapValue(sX - XSIZE, HEIGHTMAP_RAW_YSIZE - 1);
}
}
else
return GetHeightMapValue(sX, HEIGHTMAP_RAW_YSIZE - 1);
}
else
{
if (sX < -1)
{
if (m_wX <= 0)
{
if (!m_pOwnerOutdoorMap->GetTerrainPointer(byTerrainNum + 3, &pTerrain))
return GetHeightMapValue(-1, HEIGHTMAP_RAW_YSIZE - 1);
else
return pTerrain->GetHeightMapValue(-1, sY - YSIZE);
}
else
{
if (!m_pOwnerOutdoorMap->GetTerrainPointer(byTerrainNum + 2, &pTerrain))
return GetHeightMapValue(-1, HEIGHTMAP_RAW_XSIZE - 1);
else
return pTerrain->GetHeightMapValue(sX + XSIZE, sY - YSIZE);
}
}
else if (sX >= HEIGHTMAP_RAW_XSIZE - 1)
{
if (m_wX >= sTerrainCouuntX - 1)
{
if (!m_pOwnerOutdoorMap->GetTerrainPointer(byTerrainNum + 3, &pTerrain))
return GetHeightMapValue(HEIGHTMAP_RAW_XSIZE - 1, HEIGHTMAP_RAW_YSIZE - 1);
else
return pTerrain->GetHeightMapValue(HEIGHTMAP_RAW_XSIZE - 1, sY - YSIZE);
}
else
{
if (!m_pOwnerOutdoorMap->GetTerrainPointer(byTerrainNum + 4, &pTerrain))
return GetHeightMapValue(HEIGHTMAP_RAW_XSIZE - 1, HEIGHTMAP_RAW_YSIZE - 1);
else
return pTerrain->GetHeightMapValue(sX - XSIZE, sY - YSIZE);
}
}
else
{
if (!m_pOwnerOutdoorMap->GetTerrainPointer(byTerrainNum + 3, &pTerrain))
return GetHeightMapValue(sX, HEIGHTMAP_RAW_YSIZE - 1);
else
return pTerrain->GetHeightMapValue(sX, sY - YSIZE);
}
}
}
else
{
if (sX < -1)
{
if (m_wX <= 0)
return GetHeightMapValue(-1, sY);
else
{
if (!m_pOwnerOutdoorMap->GetTerrainPointer(byTerrainNum - 1, &pTerrain))
return GetHeightMapValue(-1, sY);
else
return pTerrain->GetHeightMapValue(sX + XSIZE, sY);
}
}
else if (sX >= HEIGHTMAP_RAW_XSIZE - 1)
{
if (m_wX >= sTerrainCouuntX - 1)
return GetHeightMapValue(HEIGHTMAP_RAW_XSIZE - 1, sY);
else
{
if (!m_pOwnerOutdoorMap->GetTerrainPointer(byTerrainNum + 1, &pTerrain))
return GetHeightMapValue(HEIGHTMAP_RAW_XSIZE - 1, sY);
else
return pTerrain->GetHeightMapValue(sX - XSIZE, sY);
}
}
else
return GetHeightMapValue(sX, sY);
}
}
bool CTerrain::GetNormal(int ix, int iy, D3DXVECTOR3 * pv3Normal)
{
long lMapWidth = XSIZE * CELLSCALE;
long lMapHeight = YSIZE * CELLSCALE;
while (ix < 0)
ix += lMapWidth;
while (iy < 0)
iy += lMapHeight;
while (ix > lMapWidth)
ix -= lMapWidth;
while (iy > lMapHeight)
iy -= lMapHeight;
ix /= CELLSCALE;
iy /= CELLSCALE;
D3DXVECTOR3 v3Noraml;
char * n = (char*) &m_acNormalMap[(iy * NORMALMAP_XSIZE + ix)*3];
pv3Normal->x = -((float)*n++) * 0.007874016f;
pv3Normal->y = ((float)*n++) * 0.007874016f;
pv3Normal->z = ((float)*n++) * 0.007874016f;
return true;
}
// Returns the height of the terrain at the given world coordinate
float CTerrain::GetHeight(int x, int y)
{
//if (0 == CELLSCALE)
//return 0.0f;
x -= m_wX * XSIZE * CELLSCALE;
y -= m_wY * YSIZE * CELLSCALE;
if (x < 0 || y < 0 || x > XSIZE * CELLSCALE || y > XSIZE * CELLSCALE)
return 0.0f;
long xdist; /* x mod size of tile */
long ydist; /* y mod size of tile */
float xslope, yslope; /* slopes of heights between vertices */
float h1, h2, h3;
long x2, y2;
float ooscale;
/* Find out the distance relative to the top left vertex of a tile */
xdist = x % CELLSCALE;
ydist = y % CELLSCALE;
/* Convert into pixel coordinates */
ooscale = 1.0f / ((float)CELLSCALE);
x /= CELLSCALE;
y /= CELLSCALE;
x2 = x; y2 = y;
/* Get the height and color of the pixel at the top left corner */
h1 = (float) GetHeightMapValue(x2, y2) * m_fHeightScale;
/* Get the height and color of the pixel at the bottom right corner */
x2 = x + 1;
y2 = y + 1;
h2 = (float) GetHeightMapValue(x2, y2) * m_fHeightScale;
/* Left triangle */
if (xdist <= ydist)
{
x2 = x;
y2 = y + 1;
h3 = (float) GetHeightMapValue(x2, y2) * m_fHeightScale;
/* Get the height of the pixel at the bottom left corner */
xslope = (h2 - h3) * ooscale;
yslope = (h3 - h1) * ooscale;
return (h1 + (xdist * xslope + ydist * yslope));
}
/* Right triangle */
x2 = x + 1;
y2 = y;
h3 = (float) GetHeightMapValue(x2, y2) * m_fHeightScale;
/* Get the height of the pixel at the top right corner */
xslope = (h3 - h1) * ooscale;
yslope = (h2 - h3) * ooscale;
return (h1 + (xdist * xslope + ydist * yslope));
}
//////////////////////////////////////////////////////////////////////////
// HeightMapCoord -> TileMapCoord
void CTerrain::CalculateNormal(long x, long y)
{
D3DXVECTOR3 normal;
normal.x = -m_fHeightScale * ((float)GetHeightMapValue((x-1),y)-(float)GetHeightMapValue((x+1),y));
normal.y = -m_fHeightScale * ((float)GetHeightMapValue(x,(y-1))-(float)GetHeightMapValue(x,(y+1)));
normal.z = 2.0f * CELLSCALE;
normal *= 127.0f / D3DXVec3Length(&normal);
int ix, iy, iz;
PR_FLOAT_TO_INT(normal.x, ix);
PR_FLOAT_TO_INT(normal.y, iy);
PR_FLOAT_TO_INT(normal.z, iz);
char * n = (char*) &m_acNormalMap[(y * NORMALMAP_XSIZE + x)*3];
*n++ = (char) ix;
*n++ = (char) iy;
*n++ = (char) iz;
}
bool CTerrain::RAW_LoadTileMap(const char * c_pszFileName, bool bBGLoading)
{
CTerrainImpl::RAW_LoadTileMap(c_pszFileName);
DWORD dwStart = ELTimer_GetMSec();
RAW_AllocateSplats(bBGLoading);
Tracef("CTerrain::RAW_AllocateSplats %d\n", ELTimer_GetMSec() - dwStart);
return true;
}
bool CTerrain::LoadHeightMap(const char * c_pszFileName)
{
CTerrainImpl::LoadHeightMap(c_pszFileName);
DWORD dwStart = ELTimer_GetMSec();
for (WORD y = 0; y < NORMALMAP_YSIZE; ++y)
for (WORD x = 0; x < NORMALMAP_XSIZE; ++x)
CalculateNormal(x, y);
Tracef("LoadHeightMap::CalculateNormal %d ms\n", ELTimer_GetMSec() - dwStart);
return true;
}
bool CTerrain::LoadAttrMap(const char *c_pszFileName)
{
return CTerrainImpl::LoadAttrMap(c_pszFileName);
}
bool CTerrain::isAttrOn(WORD wCoordX, WORD wCoordY, BYTE byAttrFlag)
{
if (wCoordX >= ATTRMAP_XSIZE || wCoordY >= ATTRMAP_YSIZE)
{
Tracef("CTerrain::isAttrOn Coordiante Error! Return false... Input Coord - X : %d, Y : %d ( Limit X : %d, Y : %d)", wCoordX, wCoordY, ATTRMAP_XSIZE, ATTRMAP_YSIZE);
return false;
}
BYTE byMapAttr = m_abyAttrMap[wCoordY * ATTRMAP_XSIZE + wCoordX];
if ( byAttrFlag < 16 )
return (byMapAttr & byAttrFlag) ? true : false;
else
{
if ( byAttrFlag/16 == byMapAttr/16)
return true;
else
return false;
}
}
BYTE CTerrain::GetAttr(WORD wCoordX, WORD wCoordY)
{
if (wCoordX >= ATTRMAP_XSIZE || wCoordY >= ATTRMAP_YSIZE)
{
Tracef("CTerrain::GetAttr Coordiante Error! Return 0... Input Coord - X : %d, Y : %d ( Limit X : %d, Y : %d)", wCoordX, wCoordY, ATTRMAP_XSIZE, ATTRMAP_YSIZE);
return 0;
}
return m_abyAttrMap[wCoordY * ATTRMAP_XSIZE + wCoordX];
}
void CTerrain::GetWaterHeight(BYTE byWaterNum, long * plWaterHeight)
{
if (byWaterNum > m_byNumWater)
{
Tracef("CTerrain::GetWaterHeight WaterNum %d(Total Num %d) ERROR!", byWaterNum, m_byNumWater);
return;
}
*plWaterHeight = m_lWaterHeight[byWaterNum];
}
bool CTerrain::GetWaterHeight(WORD wCoordX, WORD wCoordY, long * plWaterHeight)
{
BYTE byWaterNum = *(m_abyWaterMap + (wCoordY * WATERMAP_XSIZE) + wCoordX);
if (byWaterNum > m_byNumWater)
{
Tracef("CTerrain::GetWaterHeight (X %d, Y %d) ERROR!", wCoordX, wCoordY, m_byNumWater);
return false;
}
*plWaterHeight = m_lWaterHeight[byWaterNum] / 2;
return true;
}
void CTerrain::RAW_DeallocateSplats(bool bBGLoading)
{
for (DWORD i = 1; i < GetTextureSet()->GetTextureCount(); ++i)
{
TTerainSplat & rSplat = m_TerrainSplatPatch.Splats[i];
if (m_lpAlphaTexture[i])
{
ULONG ulRef;
do
{
ulRef = m_lpAlphaTexture[i]->Release();
} while(ulRef > 0);
}
rSplat.pd3dTexture = m_lpAlphaTexture[i] = NULL;
}
memset(&m_TerrainSplatPatch, 0, sizeof(m_TerrainSplatPatch));
}
void CTerrain::RAW_AllocateSplats(bool bBGLoading)
{
RAW_DeallocateSplats(bBGLoading);
DWORD dwTexCount = GetTextureSet()->GetTextureCount();
m_TerrainSplatPatch.m_bNeedsUpdate = true;
for (DWORD t = 0; t < dwTexCount; ++t)
m_TerrainSplatPatch.Splats[t].NeedsUpdate = 1;
RAW_CountTiles();
// if ( WAIT_OBJECT_0 == LockDataWrite() )
RAW_GenerateSplat(bBGLoading);
// UnlockDataWrite();
m_TerrainSplatPatch.m_bNeedsUpdate = false;
}
void CTerrain::RAW_CountTiles()
{
for (long y = 0; y < TILEMAP_RAW_YSIZE; ++y)
{
long lPatchIndexY = min(max((y-1)/PATCH_TILE_YSIZE,0), PATCH_YCOUNT - 1);
for (long x = 0; x < TILEMAP_RAW_XSIZE; ++x)
{
long lPatchIndexX = min(max((x-1)/(PATCH_TILE_XSIZE), 0), PATCH_XCOUNT - 1);
BYTE tilenum = m_abyTileMap[y * TILEMAP_RAW_XSIZE + x];
++m_TerrainSplatPatch.PatchTileCount[lPatchIndexY * PATCH_XCOUNT + lPatchIndexX][tilenum];
if ( 0 == y % PATCH_TILE_YSIZE && 0 != y && (TILEMAP_RAW_YSIZE - 2) != y)
{
++m_TerrainSplatPatch.PatchTileCount[min(PATCH_YCOUNT - 1, lPatchIndexY + 1) * PATCH_XCOUNT + lPatchIndexX][tilenum];
if ( 0 == x % PATCH_TILE_XSIZE && 0 != x && (TILEMAP_RAW_XSIZE - 2) != x)
{
++m_TerrainSplatPatch.PatchTileCount[lPatchIndexY * PATCH_XCOUNT + min(PATCH_XCOUNT - 1, lPatchIndexX + 1)][tilenum];
++m_TerrainSplatPatch.PatchTileCount[min(PATCH_YCOUNT - 1, lPatchIndexY + 1) * PATCH_XCOUNT + min(PATCH_XCOUNT - 1, lPatchIndexX + 1)][tilenum];
}
else if ( 1 == x % PATCH_TILE_XSIZE && (TILEMAP_RAW_XSIZE -1) != x && 1 != x)
{
++m_TerrainSplatPatch.PatchTileCount[lPatchIndexY * PATCH_XCOUNT + max(0, lPatchIndexX - 1)][tilenum];
++m_TerrainSplatPatch.PatchTileCount[min(PATCH_YCOUNT - 1, lPatchIndexY + 1) * PATCH_XCOUNT + max(0, lPatchIndexX - 1)][tilenum];
}
}
else if ( 1 == y % PATCH_TILE_YSIZE && (TILEMAP_RAW_YSIZE -1) != y && 1 != y)
{
++m_TerrainSplatPatch.PatchTileCount[max(0, lPatchIndexY - 1) * PATCH_XCOUNT + lPatchIndexX][tilenum];
if ( 0 == x % PATCH_TILE_XSIZE && 0 != x && (TILEMAP_RAW_XSIZE - 2) != x)
{
++m_TerrainSplatPatch.PatchTileCount[lPatchIndexY * PATCH_XCOUNT + min(PATCH_XCOUNT - 1, lPatchIndexX + 1)][tilenum];
++m_TerrainSplatPatch.PatchTileCount[max(0, lPatchIndexY - 1) * PATCH_XCOUNT + min(PATCH_XCOUNT - 1, lPatchIndexX + 1)][tilenum];
}
else if ( 1 == x % PATCH_TILE_XSIZE && (TILEMAP_RAW_XSIZE -1) != x && 1 != x)
{
++m_TerrainSplatPatch.PatchTileCount[lPatchIndexY * PATCH_XCOUNT + max(0, lPatchIndexX - 1)][tilenum];
++m_TerrainSplatPatch.PatchTileCount[max(0, lPatchIndexY - 1) * PATCH_XCOUNT + max(0, lPatchIndexX - 1)][tilenum];
}
}
else
{
if ( 0 == x % PATCH_TILE_XSIZE && 0 != x && (TILEMAP_RAW_XSIZE - 2) != x)
++m_TerrainSplatPatch.PatchTileCount[lPatchIndexY * PATCH_XCOUNT + min(PATCH_XCOUNT - 1, lPatchIndexX + 1)][tilenum];
else if ( 1 == x % PATCH_TILE_XSIZE && (TILEMAP_RAW_XSIZE -1) != x && 1 != x)
++m_TerrainSplatPatch.PatchTileCount[lPatchIndexY * PATCH_XCOUNT + max(0, lPatchIndexX - 1)][tilenum];
}
++m_TerrainSplatPatch.TileCount[tilenum];
}
}
}
void CTerrain::RAW_GenerateSplat(bool bBGLoading)
{
if (!m_TerrainSplatPatch.m_bNeedsUpdate)
return;
m_TerrainSplatPatch.m_bNeedsUpdate = false;
BYTE abyAlphaMap[SPLATALPHA_RAW_XSIZE * SPLATALPHA_RAW_YSIZE];
BYTE * aptr;
for (DWORD i = 1; i < GetTextureSet()->GetTextureCount(); ++i)
{
TTerainSplat & rSplat = m_TerrainSplatPatch.Splats[i];
if (rSplat.NeedsUpdate)
{
if (m_TerrainSplatPatch.TileCount[i] > 0)
{
if (rSplat.Active) // We already have an alpha map which needs to be updated
{
if (m_lpAlphaTexture[i])
{
ULONG ulRef;
do
{
ulRef = m_lpAlphaTexture[i]->Release();
if (ulRef > 0)
TraceError(" CTerrain::RAW_GenerateSplat - TileCount > 0 : Alpha Texture Release(%d) ERROR", ulRef);
} while(ulRef > 0);
}
rSplat.pd3dTexture = m_lpAlphaTexture[i] = NULL;
}
rSplat.Active = 1;
rSplat.NeedsUpdate = 0;
aptr = abyAlphaMap;
for (long y = 0; y < SPLATALPHA_RAW_YSIZE; ++y)
{
for (long x = 0; x < SPLATALPHA_RAW_XSIZE; ++x)
{
long lTileMapOffset = y * TILEMAP_RAW_XSIZE + x;
BYTE byTileNum = m_abyTileMap[lTileMapOffset];
if (byTileNum == i)
*aptr = 0xFF;
else if (byTileNum > i)
{
BYTE byTileTL, byTileTR, byTileBL, byTileBR, byTileT, byTileB, byTileL, byTileR;
if ( x > 0 && y > 0 )
byTileTL = m_abyTileMap[lTileMapOffset - TILEMAP_RAW_YSIZE - 1];
else
byTileTL = 0;
if ( x < (SPLATALPHA_RAW_XSIZE - 1) && y > 0 )
byTileTR = m_abyTileMap[lTileMapOffset - TILEMAP_RAW_YSIZE + 1];
else
byTileTR = 0;
if ( x > 0 && y < (SPLATALPHA_RAW_YSIZE - 1) )
byTileBL = m_abyTileMap[lTileMapOffset + TILEMAP_RAW_YSIZE - 1];
else
byTileBL = 0;
if ( x < (SPLATALPHA_RAW_XSIZE - 1) && y < (SPLATALPHA_RAW_YSIZE - 1) )
byTileBR = m_abyTileMap[lTileMapOffset + TILEMAP_RAW_YSIZE + 1];
else
byTileBR = 0;
if ( y > 0 )
byTileT = m_abyTileMap[lTileMapOffset - TILEMAP_RAW_YSIZE];
else
byTileT = 0;
if ( y < (SPLATALPHA_RAW_YSIZE - 1) )
byTileB = m_abyTileMap[lTileMapOffset + TILEMAP_RAW_YSIZE];
else
byTileB = 0;
if ( x > 0 )
byTileL = m_abyTileMap[lTileMapOffset - 1];
else
byTileL = 0;
if ( x < (SPLATALPHA_RAW_XSIZE - 1) )
byTileR = m_abyTileMap[lTileMapOffset + 1];
else
byTileR = 0;
if (byTileTL == i || byTileTR == i || byTileBL == i || byTileBR == i ||
byTileT == i || byTileB == i || byTileL == i || byTileR == i)
*aptr = 0xFF;
else
*aptr = 0x00;
}
else
*aptr = 0x00;
++aptr;
}
}
rSplat.pd3dTexture = AddTexture32(i, abyAlphaMap, SPLATALPHA_RAW_XSIZE, SPLATALPHA_RAW_YSIZE);
}
else
{
if (rSplat.Active)
{
if (m_lpAlphaTexture[i])
{
ULONG ulRef;
do
{
ulRef = m_lpAlphaTexture[i]->Release();
if (ulRef > 0)
TraceError(" CTerrain::RAW_GenerateSplat - TileDount 0 : Alpha Texture Release(%d) ERROR", ulRef);
} while(ulRef > 0);
}
rSplat.pd3dTexture = m_lpAlphaTexture[i] = NULL;
}
rSplat.NeedsUpdate = 0;
rSplat.Active = 0;
}
}
}
}
LPDIRECT3DTEXTURE8 CTerrain::AddTexture32(BYTE byImageNum, BYTE * pbyImage, long lTextureWidth, long lTextureHeight)
{
assert(NULL==m_lpAlphaTexture[byImageNum]);
if (m_lpAlphaTexture[byImageNum])
m_lpAlphaTexture[byImageNum]->Release();
m_lpAlphaTexture[byImageNum]=NULL;
HRESULT hr;
D3DFORMAT format;
if(ms_bSupportDXT)
format = D3DFMT_A8R8G8B8;
else
format = D3DFMT_A4R4G4B4;
bool bResizedAndSuccess = false;
IDirect3DTexture8* pkTex=NULL;
UINT uiNewWidth = 256;
UINT uiNewHeight = 256;
hr = ms_lpd3dDevice->CreateTexture(
uiNewWidth, uiNewHeight, 5, 0,
format, D3DPOOL_MANAGED, &pkTex);
if (FAILED(hr))
{
TraceError("CTerrain::AddTexture32 - CreateTexture Error");
return NULL;
}
BYTE abResizeImage[256*256];
{
BYTE* pbDstPixel=abResizeImage;
BYTE* pbSrcPixel;
BYTE* abCurLine=pbyImage;
for (UINT y=0; y<256; ++y, abCurLine+=258)
{
for (UINT x=0; x<256; ++x)
{
pbSrcPixel=abCurLine+x;
*pbDstPixel++=
((( pbSrcPixel[0]+pbSrcPixel[1]+pbSrcPixel[2]+
pbSrcPixel[258]+pbSrcPixel[260]+
pbSrcPixel[258*2]+pbSrcPixel[258*2+1]+pbSrcPixel[258*2+2])
>>3)+pbSrcPixel[259])>>1;
}
}
D3DLOCKED_RECT d3dlr;
hr = pkTex->LockRect(0, &d3dlr, 0, 0);
if (FAILED(hr))
{
pkTex->Release();
return NULL;
}
if(ms_bSupportDXT)
PutImage32(abResizeImage, (BYTE*) d3dlr.pBits, 256, d3dlr.Pitch, 256, 256, bResizedAndSuccess);
else
PutImage16(abResizeImage, (BYTE*) d3dlr.pBits, 256, d3dlr.Pitch, 256, 256, bResizedAndSuccess);
pkTex->UnlockRect(0);
}
BYTE abResizeImage2[128*128];
BYTE* pbSrcBuffer=abResizeImage;
BYTE* pbDstBuffer=abResizeImage2;
UINT uSrcSize=256;
for (UINT uMipMapLevel=1; uMipMapLevel!=pkTex->GetLevelCount(); ++uMipMapLevel)
{
UINT uDstSize=uSrcSize>>1;
BYTE* pbDstPixel=pbDstBuffer;
BYTE* pbSrcPixel;
BYTE* abCurLine=pbSrcBuffer;
for (UINT y=0; y!=uSrcSize; y+=2, abCurLine+=uSrcSize*2)
{
for (UINT x=0; x!=uSrcSize; x+=2)
{
pbSrcPixel=abCurLine+x;
*pbDstPixel++=(pbSrcPixel[0]+pbSrcPixel[1]+pbSrcPixel[uSrcSize+0]+pbSrcPixel[uSrcSize+1])>>2;
}
}
D3DLOCKED_RECT d3dlr;
hr = pkTex->LockRect(uMipMapLevel, &d3dlr, 0, 0);
if (FAILED(hr))
continue;
if(ms_bSupportDXT)
PutImage32(pbDstBuffer, (BYTE*) d3dlr.pBits, uDstSize, d3dlr.Pitch, uDstSize, uDstSize, bResizedAndSuccess);
else
PutImage16(pbDstBuffer, (BYTE*) d3dlr.pBits, uDstSize, d3dlr.Pitch, uDstSize, uDstSize, bResizedAndSuccess);
hr = pkTex->UnlockRect(uMipMapLevel);
std::swap(pbSrcBuffer, pbDstBuffer);
uSrcSize=uDstSize;
}
m_lpAlphaTexture[byImageNum]=pkTex;
return pkTex;
}
void CTerrain::PutImage32(BYTE *src, BYTE *dst, long src_pitch, long dst_pitch, long texturewidth, long textureheight, bool bResize)
{
for (int y = 0; y < textureheight; ++y)
{
for (int x = 0; x < texturewidth; ++x)
{
DWORD packed_pixel = src[x] << 24;
*((DWORD*)(dst+x*4)) = packed_pixel;
}
dst += dst_pitch;
src += src_pitch;
}
}
void CTerrain::PutImage16(BYTE *src, BYTE *dst, long src_pitch, long dst_pitch, long texturewidth, long textureheight, bool bResize)
{
for (int y = 0; y < textureheight; ++y)
{
for (int x = 0; x < texturewidth; ++x)
{
WORD packed_pixel = src[x] << 8;
//& <20><><EFBFBD><EFBFBD> <20>ѹ<EFBFBD><D1B9><EFBFBD> <20>Ʊ<EFBFBD><C6B1><EFBFBD>
//WORD packed_pixel = (src[x]&0xF0) << 8;
*((WORD*)(dst+x*2)) = packed_pixel;
}
dst += dst_pitch;
src += src_pitch;
}
}
void CTerrain::SetCoordinate(WORD wCoordX, WORD wCoordY)
{
m_wX = wCoordX;
m_wY = wCoordY;
}
void CTerrain::CalculateTerrainPatch()
{
for (BYTE byPatchNumY = 0; byPatchNumY < PATCH_YCOUNT; ++byPatchNumY)
for (BYTE byPatchNumX = 0; byPatchNumX < PATCH_XCOUNT; ++byPatchNumX)
_CalculateTerrainPatch(byPatchNumX, byPatchNumY);
}
CTerrainPatch * CTerrain::GetTerrainPatchPtr(BYTE byPatchNumX, BYTE byPatchNumY)
{
if (byPatchNumX < 0 || byPatchNumX >= PATCH_XCOUNT || byPatchNumY < 0 || byPatchNumY >= PATCH_YCOUNT)
return NULL;
return &m_TerrainPatchList[byPatchNumY * PATCH_XCOUNT + byPatchNumX];
}
void CTerrain::_CalculateTerrainPatch(BYTE byPatchNumX, BYTE byPatchNumY)
{
if (!m_awRawHeightMap || !m_acNormalMap || !m_abyWaterMap)
return;
DWORD dwPatchNum = byPatchNumY * PATCH_XCOUNT + byPatchNumX;
CTerrainPatch& rkTerrainPatch=m_TerrainPatchList[dwPatchNum];
if (!rkTerrainPatch.NeedUpdate())
return;
const float fOpaqueWaterDepth = m_pOwnerOutdoorMap->GetOpaqueWaterDepth();
const float fOOOpaqueWaterDepth = 1.0f/fOpaqueWaterDepth;
const float fTransparentWaterDepth = 0.8f * fOpaqueWaterDepth;
rkTerrainPatch.Clear();
HardwareTransformPatch_SSourceVertex akSrcTerrainVertex[CTerrainPatch::TERRAIN_VERTEX_COUNT];
SWaterVertex akSrcWaterVertex[PATCH_XSIZE * PATCH_YSIZE * 6];
DWORD dwNormalWidth = CTerrainImpl::NORMALMAP_XSIZE * 3;
DWORD dwStartX = byPatchNumX * PATCH_XSIZE;
DWORD dwStartY = byPatchNumY * PATCH_YSIZE;
WORD * wOrigRawHeightPtr = m_awRawHeightMap + ((dwStartY+1) * HEIGHTMAP_RAW_XSIZE) + dwStartX+1;
char * chOrigNormalPtr = m_acNormalMap + (dwStartY * dwNormalWidth) + dwStartX * 3;
BYTE * byOrigWaterPtr = m_abyWaterMap + (dwStartY * WATERMAP_XSIZE) + dwStartX;
float fX, fY, fOrigX, fOrigY;
fOrigX = fX = (float)(m_wX * XSIZE * CELLSCALE) + (float)(dwStartX * CELLSCALE);
fOrigY = fY = (float)(m_wY * YSIZE * CELLSCALE) + (float)(dwStartY * CELLSCALE);
rkTerrainPatch.SetMinX(fX);
rkTerrainPatch.SetMaxX(fX + (float)(PATCH_XSIZE*CELLSCALE));
rkTerrainPatch.SetMinY(fY);
rkTerrainPatch.SetMaxY(fY + (float)(PATCH_YSIZE*CELLSCALE));
float fMinZ = 999999.0f;
float fMaxZ = -999999.0f;
WORD wNumPlainType = 0;
WORD wNumHillType = 0;
WORD wNumCliffType = 0;
bool bWaterExist=false;
SWaterVertex* lpWaterVertex=akSrcWaterVertex;
UINT uWaterVertexCount=0;
HardwareTransformPatch_SSourceVertex* lpTerrainVertex=akSrcTerrainVertex;
UINT uTerrainVertexCount=0;
D3DXVECTOR3 kNormal;
D3DXVECTOR3 kPosition;
for (DWORD dwY = dwStartY; dwY <= dwStartY + PATCH_YSIZE; ++dwY)
{
WORD * pwRawHeight = wOrigRawHeightPtr;
char * pchNormal = chOrigNormalPtr;
BYTE * pbyWater = byOrigWaterPtr;
fX = fOrigX;
for (DWORD dwX = dwStartX; dwX <= dwStartX + PATCH_XSIZE; ++dwX)
{
WORD hgt = (*pwRawHeight++);
kNormal.x = -(*pchNormal++) * 0.0078740f;
kNormal.y = (*pchNormal++) * 0.0078740f;
kNormal.z = (*pchNormal++) * 0.0078740f;
kPosition.x = +fX;
kPosition.y = -fY;
kPosition.z = (float)(hgt) * m_fHeightScale;
lpTerrainVertex->kPosition = kPosition;
lpTerrainVertex->kNormal = kNormal;
if (0.5f > kNormal.z) // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> 30<33><30> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ִ<EFBFBD>. Cliff type<70><65><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
++wNumCliffType;
else if (0.8660254f > kNormal.z) // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> 60<36><30> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ִ<EFBFBD>. Hill type<70><65><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
++wNumHillType;
else // <20><> <20>̻<EFBFBD><CCBB><EFBFBD> plain Ÿ<><C5B8>
++wNumPlainType;
if (kPosition.z > fMaxZ)
fMaxZ = kPosition.z;
if (kPosition.z < fMinZ)
fMinZ = kPosition.z;
if (0 <= dwX && 0 <= dwY && XSIZE > dwX && YSIZE > dwY &&
(dwStartX + PATCH_XSIZE) != dwX && (dwStartY + PATCH_YSIZE) != dwY)
{
BYTE byNumWater = (*pbyWater++);
if (byNumWater != 0xFF)
{
long lWaterHeight = m_lWaterHeight[byNumWater];
if (-1 != lWaterHeight)
{
float fWaterTerrainHeightDifference0 = (float)(lWaterHeight - (long)hgt);
if (fWaterTerrainHeightDifference0 >= fTransparentWaterDepth)
fWaterTerrainHeightDifference0 = fTransparentWaterDepth;
if (fWaterTerrainHeightDifference0 <= 0.0f)
fWaterTerrainHeightDifference0 = 0.0f;
float fWaterTerrainHeightDifference1 = (float)(lWaterHeight - (long)(*(pwRawHeight + CTerrainImpl::HEIGHTMAP_RAW_XSIZE - 1)));
if (fWaterTerrainHeightDifference1 >= fTransparentWaterDepth)
fWaterTerrainHeightDifference1 = fTransparentWaterDepth;
if (fWaterTerrainHeightDifference1 <= 0.0f)
fWaterTerrainHeightDifference1 = 0.0f;
float fWaterTerrainHeightDifference2 = (float)(lWaterHeight - (long)(*(pwRawHeight)));
if (fWaterTerrainHeightDifference2 >= fTransparentWaterDepth)
fWaterTerrainHeightDifference2 = fTransparentWaterDepth;
if (fWaterTerrainHeightDifference2 <= 0.0f)
fWaterTerrainHeightDifference2 = 0.0f;
float fWaterTerrainHeightDifference3 = (float)(lWaterHeight - (long)(*(pwRawHeight + CTerrainImpl::HEIGHTMAP_RAW_XSIZE)));
if (fWaterTerrainHeightDifference3 >= fTransparentWaterDepth)
fWaterTerrainHeightDifference3 = fTransparentWaterDepth;
if (fWaterTerrainHeightDifference3 <= 0.0f)
fWaterTerrainHeightDifference3 = 0.0f;
DWORD dwAlpha0;
DWORD dwAlpha1;
DWORD dwAlpha2;
DWORD dwAlpha3;
PR_FLOAT_TO_INT(fWaterTerrainHeightDifference0 * fOOOpaqueWaterDepth * 255.0f, dwAlpha0);
PR_FLOAT_TO_INT(fWaterTerrainHeightDifference1 * fOOOpaqueWaterDepth * 255.0f, dwAlpha1);
PR_FLOAT_TO_INT(fWaterTerrainHeightDifference2 * fOOOpaqueWaterDepth * 255.0f, dwAlpha2);
PR_FLOAT_TO_INT(fWaterTerrainHeightDifference3 * fOOOpaqueWaterDepth * 255.0f, dwAlpha3);
DWORD dwAlphaKey=(dwAlpha0<<24)|(dwAlpha1<<16)|(dwAlpha2<<8)|dwAlpha3;
if (dwAlphaKey!=0)
{
assert(lpWaterVertex<akSrcWaterVertex+PATCH_XSIZE * PATCH_YSIZE * 6);
lpWaterVertex->x = fX;
lpWaterVertex->y = -fY;
lpWaterVertex->z = (float)lWaterHeight * m_fHeightScale;
lpWaterVertex->dwDiffuse = ((dwAlpha0 << 24) & 0xFF000000) | 0x000000FF;// 0x000F939B
lpWaterVertex++;
lpWaterVertex->x = fX;
lpWaterVertex->y = -fY - float(CELLSCALE);
lpWaterVertex->z = (float)lWaterHeight * m_fHeightScale;
lpWaterVertex->dwDiffuse = ((dwAlpha1 << 24) & 0xFF000000) | 0x00FFFFFF;
lpWaterVertex++;
lpWaterVertex->x = fX + float(CELLSCALE);
lpWaterVertex->y = -fY;
lpWaterVertex->z = (float)lWaterHeight * m_fHeightScale;
lpWaterVertex->dwDiffuse = ((dwAlpha2 << 24) & 0xFF000000) | 0x00FFFFFF;
lpWaterVertex++;
lpWaterVertex->x = fX + float(CELLSCALE);
lpWaterVertex->y = -fY;
lpWaterVertex->z = (float)lWaterHeight * m_fHeightScale;
lpWaterVertex->dwDiffuse = ((dwAlpha2 << 24) & 0xFF000000) | 0x00FFFFFF;
lpWaterVertex++;
lpWaterVertex->x = fX;
lpWaterVertex->y = -fY - float(CELLSCALE);
lpWaterVertex->z = (float)lWaterHeight * m_fHeightScale;
lpWaterVertex->dwDiffuse = ((dwAlpha1 << 24) & 0xFF000000) | 0x00FFFFFF;
lpWaterVertex++;
lpWaterVertex->x = fX + float(CELLSCALE);
lpWaterVertex->y = -fY - float(CELLSCALE);
lpWaterVertex->z = (float)lWaterHeight * m_fHeightScale;
lpWaterVertex->dwDiffuse = ((dwAlpha3 << 24) & 0xFF0000FF) | 0x00FFFFFF;
lpWaterVertex++;
uWaterVertexCount+=6;
bWaterExist = true;
}
}
}
}
++lpTerrainVertex;
++uTerrainVertexCount;
fX += float(CELLSCALE);
}
wOrigRawHeightPtr += CTerrainImpl::HEIGHTMAP_RAW_XSIZE;
chOrigNormalPtr += dwNormalWidth;
byOrigWaterPtr += CTerrainImpl::XSIZE;
fY += float(CELLSCALE);
}
if (wNumPlainType <= max(wNumHillType, wNumCliffType))
{
if (wNumCliffType <= wNumHillType)
rkTerrainPatch.SetType(CTerrainPatch::PATCH_TYPE_HILL);
else
rkTerrainPatch.SetType(CTerrainPatch::PATCH_TYPE_CLIFF);
}
rkTerrainPatch.SetWaterExist(bWaterExist);
rkTerrainPatch.SetMinZ(fMinZ);
rkTerrainPatch.SetMaxZ(fMaxZ);
assert((PATCH_XSIZE+1)*(PATCH_YSIZE+1)==uTerrainVertexCount);
rkTerrainPatch.BuildTerrainVertexBuffer(akSrcTerrainVertex);
if (bWaterExist)
rkTerrainPatch.BuildWaterVertexBuffer(akSrcWaterVertex, uWaterVertexCount);
rkTerrainPatch.NeedUpdate(false);
}
void CTerrain::AllocateMarkedSplats(BYTE * pbyAlphaMap)
{
TTerainSplat & rAttrSplat = m_MarkedSplatPatch.Splats[0];
HRESULT hr;
if (m_lpMarkedTexture)
{
ULONG ulRef;
do
{
ulRef = m_lpMarkedTexture->Release();
} while(ulRef > 0);
}
do
{
hr = ms_lpd3dDevice->CreateTexture(ATTRMAP_XSIZE, ATTRMAP_YSIZE, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_lpMarkedTexture);
} while(FAILED(hr));
D3DLOCKED_RECT d3dlr;
do
{
hr = m_lpMarkedTexture->LockRect(0, &d3dlr, 0, 0);
} while(FAILED(hr));
PutImage32(pbyAlphaMap, (BYTE*) d3dlr.pBits, ATTRMAP_XSIZE, d3dlr.Pitch, ATTRMAP_XSIZE, ATTRMAP_YSIZE);
do
{
hr = m_lpMarkedTexture->UnlockRect(0);
} while(FAILED(hr));
rAttrSplat.pd3dTexture = m_lpMarkedTexture;
m_bMarked = true;
}
void CTerrain::DeallocateMarkedSplats()
{
TTerainSplat & rSplat = m_MarkedSplatPatch.Splats[0];
if (m_lpMarkedTexture)
{
ULONG ulRef;
do
{
ulRef = m_lpMarkedTexture->Release();
} while(ulRef > 0);
}
rSplat.pd3dTexture = NULL;
m_lpMarkedTexture = NULL;
m_bMarked = FALSE;
memset(&m_MarkedSplatPatch, 0, sizeof(m_MarkedSplatPatch));
}