terrain.cpp

来自「x3d_new.rar」· C++ 代码 · 共 497 行 · 第 1/2 页

CPP
497
字号
#include "StdAfx.h"
#include ".\terrain.h"

#include "xUtil.h"

#include <d3dx9tex.h>

#define TEXTURE_SIZE 256

CTerrain::CTerrain(void)
    : m_pTexture(NULL)
	, m_Patchs(NULL)
    , m_bDrawNormal(false)
    , m_fHeightScale(0.2f)
	, m_nSize(0)
	, m_nPatchSize(0)
{
}

CTerrain::~CTerrain(void)
{    
    Destroy();
}

bool CTerrain::Create(int nSize)
{        
    assert(m_pDevice);
	assert(m_pDeviceCaps);

	m_nSize = nSize;

	// 计算片区尺寸最大值
	int nMaxPatchSize = (int)sqrt((double)m_pDeviceCaps->MaxVertexIndex);
	m_nPatchSize = m_nSize;

	while(m_nPatchSize > nMaxPatchSize)
		m_nPatchSize >>= 1;

    // 创建"米"字索引模板
    if(!m_RiceIndicesMng.Create())return false;

    // 创建地形数据
    if(!m_field.Create(m_nSize))return false;
    assert(m_field.IsValid());
	
	// 创建地形块数组
	int nTierCount  = m_nSize / m_nPatchSize;
	int nPatchCount = nTierCount * nTierCount;
	
	m_Patchs = new SPatch[nPatchCount];
	if(!m_Patchs)return false;

	// 开始创建创建模型、索引
	int nPatchBorderSize = m_nPatchSize + 1;
	int nPatchVertexCount = nPatchBorderSize * nPatchBorderSize;
	int nMaxTilesNum = CField::CalculateMaxTileNum(m_nPatchSize);

	D3DFORMAT index_format; // 索引格式
	int nBytePerIndex;      // 单位索引占用字节数

	if(m_pDeviceCaps->MaxVertexIndex > 65536)
	{
		index_format = D3DFMT_INDEX32;
		nBytePerIndex = 4;
	}
	else
	{
		index_format = D3DFMT_INDEX16;
		nBytePerIndex = 2;
	}

	for(int iz = 0; iz < nTierCount; ++iz)
	{
		for(int ix = 0; ix < nTierCount; ++ix)
		{
			SPatch& rPatch = m_Patchs[iz * nTierCount + ix];

			// 创建模型
			if(FAILED(m_pDevice->CreateVertexBuffer(sizeof(SVertexData) * nPatchVertexCount, 
			   0, SVertexData::FVF, D3DPOOL_DEFAULT, &rPatch.m_pVB, NULL)))
			return false;

			 // 创建法线模型
			if(FAILED(m_pDevice->CreateVertexBuffer(sizeof(SNormalVertexData) * (nPatchVertexCount * 2), 
			    0, SNormalVertexData::FVF, D3DPOOL_DEFAULT, &rPatch.m_pVBNormal, NULL)))
			return false;

			 // 创建索引缓冲 (每个"块" 最多有8个三角形,所以共24个顶点)
			if(FAILED(m_pDevice->CreateIndexBuffer(
			    nMaxTilesNum * 24 * nBytePerIndex, 0, index_format, D3DPOOL_DEFAULT, &rPatch.m_pIB, NULL)))
			return false;
		}
	}

    // 读取细节纹理
    if(FAILED(D3DXCreateTextureFromFileEx(m_pDevice, "detailMap.tga", D3DX_DEFAULT, D3DX_DEFAULT, 
        0, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &m_pDetailTexture )))
    return false;
    
    // 设置材质
    SetupMaterial();

    // 创建纹理
    assert(m_pDevice);
    if(FAILED(m_pDevice->CreateTexture(
        TEXTURE_SIZE, TEXTURE_SIZE, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_pTexture, NULL)))
    return false;

    // 读取纹理文件
    m_TexturePainter.SetDevice(m_pDevice);
    m_TexturePainter.SetField(&m_field);
    m_TexturePainter.SetSize(TEXTURE_SIZE);
    m_TexturePainter.AddElement("lowestTile.tga", 5);
    m_TexturePainter.AddElement("lowTile.tga", 5);
    m_TexturePainter.AddElement("HighTile.tga", 5);
    m_TexturePainter.AddElement("highestTile.tga", 20);

    return true;
}

void CTerrain::Destroy()
{
    // 纹理
    release_ptr(m_pTexture);
    release_ptr(m_pDetailTexture);

    // 片区
	int nTierCount  = m_nSize / m_nPatchSize;
	int nPatchCount = nTierCount * nTierCount;
	for(int i = 0; i < nPatchCount; ++i)
	{    
		release_ptr(m_Patchs[i].m_pIB);
		release_ptr(m_Patchs[i].m_pVB);
		release_ptr(m_Patchs[i].m_pVBNormal);
	}
	delete_ary(m_Patchs);

    // 工具
    m_RiceIndicesMng.Destroy();
    m_field.Destroy();
    m_TexturePainter.ClearElement();
}

void CTerrain::SetupMaterial()
{
    // 设置材质
    m_Material.Power = 0.3f;

    m_Material.Diffuse  = D3DXCOLOR(0.2f, 0.2f, 0.2f, 0.2f);
    m_Material.Specular = D3DXCOLOR(0.1f, 0.1f, 0.1f, 0.1f);
    m_Material.Ambient  = D3DXCOLOR(0.0f, 0.0f, 0.0f, 0.0f);
    m_Material.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.0f, 0.0f);
}

HRESULT CTerrain::SetupGeometry()
{    
    assert(m_pDevice);
    assert(m_field.IsValid());

    const unsigned char* byHeights = m_field.GetHeights();
	int nTierCount = m_nSize / m_nPatchSize;
	int nPatchBorderSize = m_nPatchSize + 1;
	int nPatchVertexCount = nPatchBorderSize * nPatchBorderSize;

	for(int ipz = 0; ipz < nTierCount; ++ipz)
	{
		for(int ipx = 0; ipx < nTierCount; ++ipx)
		{
			SPatch& rPatch = m_Patchs[ipz * nTierCount + ipx];
            assert(rPatch.m_pVB);

			SVertexData* pVertices = NULL;
			if(FAILED(rPatch.m_pVB->Lock(0, nPatchVertexCount, (LPVOID*)&pVertices, 0)))return E_FAIL;

            // 开始设置顶点数据

			int iIndex = 0;
			for(int iz = 0; iz < nPatchBorderSize; ++iz)
			{
				for(int ix = 0; ix < nPatchBorderSize; ++ix)
				{
					int itx = ipx * m_nPatchSize + ix;
					int ity = ipz * m_nPatchSize + iz;

					pVertices[iIndex].position.x	= (float)itx;
					pVertices[iIndex].position.y	= m_field.GetHeight(itx, ity) * m_fHeightScale;
					pVertices[iIndex].position.z	= (float)ity;
		            
					pVertices[iIndex].tu			= (float)itx / m_field.GetBorderSize();
					pVertices[iIndex].tv			= (float)ity / m_field.GetBorderSize();
					pVertices[iIndex].tu1			= itx * 0.1f;
					pVertices[iIndex].tv1			= ity * 0.1f;

					++iIndex;
				}
			}

			// ..根据定点设置法线(近似值)
			for(int i = 0; i < nPatchVertexCount; ++i)
			{
				pVertices[i].normal.x = 0.0f;
				pVertices[i].normal.y = 1.0f;
				pVertices[i].normal.z = 0.0f;
			}

			// ..根据定点设置法线(近似值)
			for(int iz = 1; iz < nPatchBorderSize - 1; ++iz)
			{
				for(int ix = 1; ix < nPatchBorderSize - 1; ++ix)
				{
					int iIndex = iz * nPatchBorderSize + ix;

					D3DXVECTOR3 vNormal;
					vNormal.x	= pVertices[iIndex - 1].position.y - pVertices[iIndex + 1].position.y;
					vNormal.y	= 1.0f;
					vNormal.z	= pVertices[iIndex - nPatchBorderSize].position.y - pVertices[iIndex + nPatchBorderSize].position.y;
					
					D3DXVec3Normalize(&pVertices[iIndex].normal, &vNormal);
				}
			}

			if(FAILED(rPatch.m_pVB->Unlock()))return E_FAIL;
		}
	}

    return D3D_OK;
}

HRESULT CTerrain::SetupNormalGeometry(void)
{    
    assert(m_pDevice);
    assert(m_field.IsValid());

	int nTierCount = m_nSize / m_nPatchSize;
	int nPatchBorderSize = m_nPatchSize + 1;
	int nPatchVertexCount = nPatchBorderSize * nPatchBorderSize;
	int nNormalVertexCount = nPatchVertexCount * 2;

	for(int ipz = 0; ipz < nTierCount; ++ipz)
	{
		for(int ipx = 0; ipx < nTierCount; ++ipx)
		{
			SPatch& rPatch = m_Patchs[ipz * nTierCount + ipx];
            assert(rPatch.m_pVB);
            assert(rPatch.m_pVBNormal);

			SNormalVertexData* pNormalVertices = NULL;
			if(FAILED(rPatch.m_pVBNormal->Lock(0, nNormalVertexCount, (LPVOID*)&pNormalVertices, 0)))return E_FAIL;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?