#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