#ifndef __TerrainH__
#define __TerrainH__
#include <d3d9.h>
#include <d3dx9.h>
#include <vector>
using namespace std;
struct TERRAIN_CUSTOMVERTEX
{
FLOAT x, y, z;
FLOAT a, b, c;
FLOAT u, v;
FLOAT tu, tv;
};
#define TERRAIN_D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX2)
class CTerrain
{
public:
LPDIRECT3DDEVICE9 m_pDevice;
LPD3DXMESH m_pMesh;
LPDIRECT3DTEXTURE9 m_pDTex;
LPDIRECT3DTEXTURE9 m_pHeightMap;
LPDIRECT3DTEXTURE9 m_pDetailTexture;
D3DSURFACE_DESC m_HeightMapDesc;
float m_fMaxHeight;
float m_fTileLength;
UINT m_uiNumXTile;
UINT m_uiNumZTile;
UINT m_uiNumTiles;
UINT m_uiNumVertices;
UINT m_uiNumFaces;
UINT m_uiNumIndices;
UINT m_uiDetail;
vector<unsigned char> m_vucHeight;
public:
CTerrain() : m_pDevice(NULL), m_pMesh(NULL), m_pDTex(NULL), m_pHeightMap(NULL), m_pDetailTexture(NULL), m_fMaxHeight(0.0f), m_fTileLength(0.0f),
m_uiNumXTile(0), m_uiNumZTile(0), m_uiNumTiles(0), m_uiNumVertices(0), m_uiNumIndices(0)
{
ZeroMemory(&m_HeightMapDesc, sizeof(m_HeightMapDesc));
m_vucHeight.clear();
}
~CTerrain()
{
}
void Init(IDirect3DDevice9* pDevice, char* sTexMapName, char* sHeightMapName, char* sDetailedMapName, float fMaxHeight, float fTileLength, UINT uiDetail)
{
m_pDevice = pDevice;
D3DXCreateTextureFromFileA(m_pDevice, sTexMapName, &m_pDTex);
D3DXCreateTextureFromFileA(m_pDevice, sHeightMapName, &m_pHeightMap);
D3DXCreateTextureFromFileA(m_pDevice, sDetailedMapName, &m_pDetailTexture);
m_fMaxHeight = fMaxHeight;
m_fTileLength = fTileLength;
m_uiDetail = uiDetail;
m_pHeightMap->GetLevelDesc(2, &m_HeightMapDesc);
m_uiNumXTile = m_HeightMapDesc.Width - 1;
m_uiNumZTile = m_HeightMapDesc.Height - 1;
m_uiNumTiles = m_uiNumXTile * m_uiNumZTile;
m_uiNumVertices = m_HeightMapDesc.Width * m_HeightMapDesc.Height;
m_uiNumFaces = m_uiNumTiles * 2;
D3DXCreateMeshFVF(m_uiNumFaces, m_uiNumVertices, D3DXMESH_MANAGED, TERRAIN_D3DFVF_CUSTOMVERTEX, m_pDevice, &m_pMesh);
m_vucHeight.resize(m_uiNumVertices);
D3DLOCKED_RECT LockedRect;
m_pHeightMap->LockRect(2, &LockedRect, NULL, 0);
memcpy(&m_vucHeight[0], LockedRect.pBits, m_HeightMapDesc.Width * m_HeightMapDesc.Height);
m_pHeightMap->UnlockRect(2);
TERRAIN_CUSTOMVERTEX* pVertex;
m_pMesh->LockVertexBuffer(0, (void**)&pVertex);
UINT z, x, i, tz, tx;
float fDetailPitch = 1.0f / m_uiDetail;
float fTempBase = m_fMaxHeight / 256.0f;
for(z = 0; z <= m_uiNumZTile; z ++)
{
for(x = 0; x <= m_uiNumXTile; x ++)
{
i = z * (m_uiNumZTile + 1) + x;
pVertex[i].x = x * m_fTileLength;
pVertex[i].z = (m_uiNumZTile - z) * m_fTileLength;
pVertex[i].y = m_vucHeight[i] * fTempBase;
pVertex[i].a = pVertex[i].c = 0.0f;
pVertex[i].b = 1.0f;
pVertex[i].u = (float)x / (float)m_uiNumXTile;
pVertex[i].v = (float)z / (float)m_uiNumZTile;
tx = x % m_uiDetail;
tz = z % m_uiDetail;
pVertex[i].tu = tx * fDetailPitch;
pVertex[i].tv = tz * fDetailPitch;
}
}
m_pMesh->UnlockVertexBuffer();
short* pIndex;
m_pMesh->LockIndexBuffer(0, (void**)&pIndex);
for(z = 0; z < m_uiNumZTile; z ++)
{
for(x = 0; x < m_uiNumXTile; x ++)
{
i = (z * m_uiNumXTile + x) * 6;
pIndex[i+0] = z * (m_uiNumXTile + 1) + x;
pIndex[i+1] = pIndex[i+4] = z * (m_uiNumXTile + 1) + x + 1;
pIndex[i+2] = pIndex[i+3] = (z + 1) * (m_uiNumXTile + 1) + x;
pIndex[i+5] = (z + 1) * (m_uiNumXTile + 1) + x + 1;
}
}
m_pMesh->UnlockIndexBuffer();
}
void Render(float fElapsedTime)
{
m_pDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
m_pDevice->SetRenderState(D3DRS_SPECULARENABLE, TRUE);
m_pDevice->SetRenderState(D3DRS_NORMALIZENORMALS, TRUE);
m_pDevice->SetTexture(0, m_pDTex);
m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
m_pDevice->SetTexture(1, m_pDetailTexture);
m_pDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_pDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
m_pDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
m_pMesh->DrawSubset(0);
m_pDevice->SetTexture(0,NULL);
m_pDevice->SetTexture(1,NULL);
}
};
#endif