📄 simpleterrain.cpp
字号:
// we turn off backface culling for this example - so you can flip the terrain over
m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
// draw our terrain
DrawTerrain();
// output our stats
// Calculate and show triangles per sec, a reasonable throughput number
fTrisPerSec = m_fFPS * m_FacesDrawn;
// Output statistics
wsprintf( strInfo, _T("%ld tris per sec, %ld triangles"),
(DWORD)fTrisPerSec,
m_FacesDrawn);
m_pFont->DrawText( 2, 0, D3DCOLOR_ARGB(255,255,255,0), m_strFrameStats );
m_pFont->DrawText( 2, 20, D3DCOLOR_ARGB(255,255,255,0), m_strDeviceStats );
m_pFont->DrawText( 2, 40, D3DCOLOR_ARGB(255,255,255,0), strInfo);
m_pd3dDevice->EndScene();
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: InitDeviceObjects()
// Desc: Initialize scene objects.
//-----------------------------------------------------------------------------
HRESULT SimpleTerrain::InitDeviceObjects()
{
// load our sample texture
D3DXCreateTextureFromFile( m_pd3dDevice, _T("Grass.bmp"), &m_pMeshTexture);
if (SUCCEEDED(m_pd3dDevice->CreateImageSurface(256,256, D3DFMT_R8G8B8, &m_pHeightData)))
{
D3DXLoadSurfaceFromFile( m_pHeightData, 0, 0, _T("HeightMap.bmp"), 0, D3DX_FILTER_NONE, 0, 0);
}
m_vObjectCenter.x=0.0f;
m_vObjectCenter.y=0.0f;
m_vObjectCenter.z=0.0f;
m_fObjectRadius = VERTEX_COUNT/2.0f;
// Initialize the font
m_pFont->InitDeviceObjects( m_pd3dDevice );
// create the tile vertices
GenerateTiles();
GenerateDetailLevels();
return D3D_OK;
}
//-----------------------------------------------------------------------------
// Name: RestoreDeviceObjects()
// Desc: Initialize scene objects.
//-----------------------------------------------------------------------------
HRESULT SimpleTerrain::RestoreDeviceObjects()
{
m_pFont->RestoreDeviceObjects();
// Setup render state
m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
m_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE, TRUE );
m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
// Setup the light
D3DLIGHT8 light;
light.Type = D3DLIGHT_DIRECTIONAL;
light.Diffuse.r = light.Diffuse.g = light.Diffuse.b = 1.0f;
light.Specular.r = light.Specular.g = light.Specular.b = 0.0f;
light.Ambient.r = light.Ambient.g = light.Ambient.b = 0.3f;
light.Position = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &D3DXVECTOR3( 0.3f, -1.0f, 1.0f ) );
light.Attenuation0 = light.Attenuation1 = light.Attenuation2 = 0.0f;
light.Range = sqrtf(FLT_MAX);
m_pd3dDevice->SetLight(0, &light );
m_pd3dDevice->LightEnable(0, TRUE );
m_ArcBall.SetWindow( m_d3dsdBackBuffer.Width, m_d3dsdBackBuffer.Height, 0.85f );
m_ArcBall.SetRadius( m_fObjectRadius );
FLOAT fAspect = m_d3dsdBackBuffer.Width / (FLOAT)m_d3dsdBackBuffer.Height;
D3DXMATRIX matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, fAspect, m_fObjectRadius/64.0f,
m_fObjectRadius*200.0f);
m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: InvalidateDeviceObjects()
// Desc:
//-----------------------------------------------------------------------------
HRESULT SimpleTerrain::InvalidateDeviceObjects()
{
m_pFont->InvalidateDeviceObjects();
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DeleteDeviceObjects()
// Desc: Called when the app is exiting, or the device is being changed,
// this function deletes any device dependent objects.
//-----------------------------------------------------------------------------
HRESULT SimpleTerrain::DeleteDeviceObjects()
{
m_pFont->DeleteDeviceObjects();
SAFE_RELEASE( m_pMeshTexture);
SAFE_RELEASE(m_pHeightData);
// release the detail levels
int i,j,k,l;
for (i=0;i<TOTAL_LEVELS;++i)
{
for (j=0;j<16;++j)
{
SAFE_RELEASE(m_DetailLevel[i].TileBodies[j].pIndexBuffer);
}
for (k=0;k<TOTAL_SIDES;++k)
{
for (l=0;l<TOTAL_LEVELS;++l)
{
SAFE_RELEASE(m_DetailLevel[i].TileConnectors[k][l].pIndexBuffer);
}
}
}
// release the tiles
for (i=0;i<TILE_COUNT;++i)
{
for (j=0;j<TILE_COUNT;++j)
{
SAFE_RELEASE(m_TerrainTile[i][j].VBuffer);
}
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: FinalCleanup()
// Desc: Called during initial app startup, this function performs all the
// permanent initialization.
//-----------------------------------------------------------------------------
HRESULT SimpleTerrain::FinalCleanup()
{
SAFE_DELETE( m_pFont );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: Message proc function to handle key and menu input
//-----------------------------------------------------------------------------
LRESULT SimpleTerrain::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam,
LPARAM lParam )
{
// Pass mouse messages to the ArcBall so it can build internal matrices
m_ArcBall.HandleMouseMessages( hWnd, uMsg, wParam, lParam );
// Trap the context menu
if( WM_CONTEXTMENU==uMsg )
return 0;
if( uMsg == WM_COMMAND )
{
// Toggle mesh drawing mode
if( LOWORD(wParam) == IDM_SHOWWIREFRAME )
{
m_bWireframe = !m_bWireframe;
if( m_bWireframe )
CheckMenuItem( GetMenu(hWnd), IDM_SHOWWIREFRAME, MF_CHECKED );
else
CheckMenuItem( GetMenu(hWnd), IDM_SHOWWIREFRAME, MF_UNCHECKED );
}
}
return CD3DApplication::MsgProc( hWnd, uMsg, wParam, lParam );
}
void SimpleTerrain::DrawTerrain()
{
m_FacesDrawn = 0;
if (SUCCEEDED(m_pd3dDevice->SetVertexShader(FVF)))
{
// render each tile
for (int i=0;i<TILE_COUNT;++i)
{
for (int j=0;j<TILE_COUNT;++j)
{
// activate the vertex buffer for this tile
if (SUCCEEDED(m_pd3dDevice->SetStreamSource(0,m_TerrainTile[i][j].VBuffer, sizeof(TERRAIN_VERTEX))))
{
int body_tile = 0;
LEVEL MyLevel = m_TerrainTile[i][j].DetailLevel;
// examine the tile above this tile
if (i && m_TerrainTile[i-1][j].DetailLevel < MyLevel)
{
LEVEL ThisLevel = m_TerrainTile[i-1][j].DetailLevel;
body_tile |= 1<<TOP;
// draw the connecting piece needed
if (SUCCEEDED(m_pd3dDevice->SetIndices(m_DetailLevel[MyLevel].TileConnectors[TOP][ThisLevel].pIndexBuffer, 0)))
{
m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 81, 0, m_DetailLevel[MyLevel].TileConnectors[TOP][ThisLevel].TriangleCount);
m_FacesDrawn += m_DetailLevel[MyLevel].TileConnectors[TOP][ThisLevel].TriangleCount;
}
}
// examine the tile below this tile
if (i<(TILE_COUNT-1) && m_TerrainTile[i+1][j].DetailLevel < MyLevel)
{
LEVEL ThisLevel = m_TerrainTile[i+1][j].DetailLevel;
body_tile |= 1<<BOTTOM;
// draw the connecting piece needed
if (SUCCEEDED(m_pd3dDevice->SetIndices(m_DetailLevel[MyLevel].TileConnectors[BOTTOM][ThisLevel].pIndexBuffer, 0)))
{
m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 81, 0, m_DetailLevel[MyLevel].TileConnectors[BOTTOM][ThisLevel].TriangleCount);
m_FacesDrawn += m_DetailLevel[MyLevel].TileConnectors[BOTTOM][ThisLevel].TriangleCount;
}
}
// examine the tile to the left this tile
if (j && m_TerrainTile[i][j-1].DetailLevel < MyLevel)
{
LEVEL ThisLevel = m_TerrainTile[i][j-1].DetailLevel;
body_tile |= 1<<LEFT;
// draw the connecting piece needed
if (SUCCEEDED(m_pd3dDevice->SetIndices(m_DetailLevel[MyLevel].TileConnectors[LEFT][ThisLevel].pIndexBuffer, 0)))
{
m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 81, 0, m_DetailLevel[MyLevel].TileConnectors[LEFT][ThisLevel].TriangleCount);
m_FacesDrawn += m_DetailLevel[MyLevel].TileConnectors[LEFT][ThisLevel].TriangleCount;
}
}
// examine the tile to the right this tile
if (j<(TILE_COUNT-1) && m_TerrainTile[i][j+1].DetailLevel < MyLevel)
{
LEVEL ThisLevel = m_TerrainTile[i][j+1].DetailLevel;
body_tile |= 1<<RIGHT;
// draw the connecting piece needed
if (SUCCEEDED(m_pd3dDevice->SetIndices(m_DetailLevel[MyLevel].TileConnectors[RIGHT][ThisLevel].pIndexBuffer, 0)))
{
m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 81, 0, m_DetailLevel[MyLevel].TileConnectors[RIGHT][ThisLevel].TriangleCount);
m_FacesDrawn += m_DetailLevel[MyLevel].TileConnectors[RIGHT][ThisLevel].TriangleCount;
}
}
// finally, draw the body tile needed
if (m_DetailLevel[MyLevel].TileBodies[body_tile].pIndexBuffer)
{
if (SUCCEEDED(m_pd3dDevice->SetIndices(m_DetailLevel[MyLevel].TileBodies[body_tile].pIndexBuffer, 0)))
{
m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 81, 0, m_DetailLevel[MyLevel].TileBodies[body_tile].TriangleCount);
m_FacesDrawn += m_DetailLevel[MyLevel].TileBodies[body_tile].TriangleCount;
}
}
}
}
}
}
}
void SimpleTerrain::GenerateTiles()
{
//
// Generate tiles based on the values in the height map
//
TERRAIN_VERTEX TerrainVerts[VERTEX_COUNT][VERTEX_COUNT];
int i,j;
float x= -VERTEX_COUNT/2.0f;
float y= -VERTEX_COUNT/2.0f;
// lock the height map
D3DLOCKED_RECT LockedRect;
if (m_pHeightData && SUCCEEDED(m_pHeightData->LockRect(&LockedRect, 0, D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY )))
{
BYTE* pNextRow = (BYTE*)LockedRect.pBits;
for (i=0;i<VERTEX_COUNT;++i)
{
BYTE* pPixel = pNextRow;
pNextRow = pPixel + LockedRect.Pitch;
for (j=0;j<VERTEX_COUNT;++j)
{
BYTE height_value = *pPixel;
float height = (float)height_value/ 16.0f;
pPixel += 3; // assuming a 24 bit heightmap
// set the vertex position
TerrainVerts[i][j].vert.x = x;
TerrainVerts[i][j].vert.y = y;
TerrainVerts[i][j].vert.z = height;
// set the texture coordinates
TerrainVerts[i][j].tu = (i / 32.0f);
TerrainVerts[i][j].tv = (j / 32.0f);
// calc the normal from the last pixel and row
D3DXVECTOR3 RowVector(-1.0f, 0.0f, 0.0f);
D3DXVECTOR3 CollumnVector(0.0f, -1.0f, 0.0f);
D3DXVECTOR3 TempNorm;
if (i)
{
RowVector = TerrainVerts[i-1][j].vert - TerrainVerts[i][j].vert;
}
if (j)
{
CollumnVector = TerrainVerts[i][j-1].vert - TerrainVerts[i][j].vert;
}
D3DXVec3Cross(&TempNorm, &RowVector, &CollumnVector);
D3DXVec3Normalize(&TerrainVerts[i][j].norm, &TempNorm);
x += 1.0f;
}
y += 1.0f;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -