⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 simpleterrain.cpp

📁 游戏编程精粹2第四章源码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
		// 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 + -