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

📄 nvcomplexmesh.cpp

📁 游戏编程精华02-含有几十个游戏编程例子
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/* Copyright (C) Chris Maughan, 2001. 
 * All rights reserved worldwide.
 *
 * This software is provided "as is" without express or implied
 * warranties. You may freely copy and compile this source into
 * applications you distribute provided that the copyright text
 * below is included in the resulting source code, for example:
 * "Portions Copyright (C) Chris Maughan, 2001"
 */
#include "nvcomplexmesh.h"
#include "nvresourcemanager.h"
#include "nvtextureresource.h"
#include <algorithm>
using namespace std;
namespace nv_objects
{

NVComplexMesh::NVComplexMesh()
: m_dwNumVertices(0),
 m_dwStride(0),
 m_pVB(NULL)
{
}

NVComplexMesh::~NVComplexMesh()
{
	Release();
}

void NVComplexMesh::Release()
{
	tMeshPass::iterator itrPasses = m_Passes.begin();
	while(itrPasses != m_Passes.end())
	{
		SAFE_DELETE(*itrPasses);
		itrPasses++;
	}
	m_Passes.clear();

	// Remove the vertex data associated with this mesh
	tVertexDataMap::iterator itrVertex = m_VertexData.begin();
	while(itrVertex != m_VertexData.end())
	{
		NVComplexMeshVertexData& VertexData = itrVertex->second;
		VertexData.Release();
		itrVertex++;
	}
	m_dwNumVertices = 0;

	tIndexBufferArray::iterator itrIndices = m_IndexBuffers.begin();
	while (itrIndices != m_IndexBuffers.end())
	{
		SAFE_RELEASE(*itrIndices);
		itrIndices++;
	}
	m_IndexBuffers.clear();

	SAFE_RELEASE(m_pVB);
}

bool NVComplexMesh::FlipNormals()
{
	NVComplexMeshVertexData* pNormalData = FindVertexData("normal");
	if (!pNormalData)
		return false;

	tVec3Array& Normal = pNormalData->GetVec3Array();
	tVec3Array::iterator itrData;

	// Clear the normals
	itrData = Normal.begin();
	while (itrData != Normal.end())
	{
		*itrData = -*itrData;
		itrData++;
	}

	return true;
}


bool NVComplexMesh::GenerateNormals()
{
	NVComplexMeshVertexData* pPositionData = FindVertexData("position");
	NVComplexMeshVertexData* pNormalData = FindVertexData("normal");

	if (!pPositionData || !pNormalData ||
		(pPositionData->GetDataType() != NVCOMPLEXMESH_FLOAT3) ||
		(pNormalData->GetDataType() != NVCOMPLEXMESH_FLOAT3))
	{
		return false;
	}
	tVec3Array& Position = pPositionData->GetVec3Array();
	tVec3Array& Normal = pNormalData->GetVec3Array();
	tVec3Array::iterator itrData;
	tIndexArray::iterator itrIndices;
	D3DXVECTOR3 norm;

	// Clear the normals
	itrData = Normal.begin();
	while (itrData != Normal.end())
	{
		*itrData = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
		itrData++;
	}

	// Generate normals
	itrIndices = m_Indices.begin();
	while (itrIndices != m_Indices.end())
	{
		D3DXVECTOR3 vec1 = Position[*(itrIndices + 0)] - Position[*(itrIndices + 1)];
		D3DXVECTOR3 vec2 = Position[*(itrIndices + 0)] - Position[*(itrIndices + 2)];
				
		D3DXVec3Cross(&norm, &vec1, &vec2);
		Normal[*(itrIndices + 0)] += norm;
		Normal[*(itrIndices + 1)] += norm;
		Normal[*(itrIndices + 2)] += norm;

		itrIndices += 3;
	}

	// Normalize
	itrData = Normal.begin();
	while (itrData != Normal.end())
	{
		// I have no idea why D3DXVec3Normalize failed here with the bunny...
		float Length;
		Length = D3DXVec3Length(&(*itrData));
		*itrData = *itrData / Length;
		
		itrData++;
	}
	return true;
}

bool NVComplexMesh::UnIndex()
{
	NVASSERT(0, "Broken when triangles could be different types per section - FIXME!");
	NVComplexMeshVertexData* pPositionData = FindVertexData("position");

	if (!pPositionData)
		return false;

	if (pPositionData->GetDataType() != NVCOMPLEXMESH_FLOAT3)
		return false;

	tVertexDataMap::iterator itrVertexData = m_VertexData.begin();
	while (itrVertexData != m_VertexData.end())
	{
		((*itrVertexData).second).UnIndex(m_Indices);
		itrVertexData++;
	}

	m_Indices.resize(pPositionData->GetVec3Array().size());
	for (DWORD i = 0; i < pPositionData->GetVec3Array().size(); i++)
	{
		m_Indices[i] = i;
	}

	SetNumVertices(pPositionData->GetVec3Array().size());

	return true;
}


bool NVComplexMesh::GenerateBasis(DWORD dwTexture)
{
	DWORD i;
	NVComplexMeshVertexData* pPositionData = FindVertexData("position");
	NVComplexMeshVertexData* pNormalData = FindVertexData("normal");
	NVComplexMeshVertexData* pTextureData;
	NVComplexMeshVertexData* pSBasisData;
	NVComplexMeshVertexData* pTBasisData;
	NVComplexMeshVertexData* pSxTBasisData;

	// Find the texture data
	string strBuff;
	strBuff.resize(2);
	ultoa(dwTexture, &strBuff[0], 2);
	string texname = "texture" + strBuff;
	texname = texname.substr(0, strlen(texname.c_str()));
	pTextureData = FindVertexData(texname);

	// Find the basis vectors if available
	string sbasis = "sbasis" + strBuff;
	sbasis = sbasis.substr(0, strlen(sbasis.c_str()));
	pSBasisData = FindVertexData(sbasis);

	string tbasis = "tbasis" + strBuff;
	tbasis = tbasis.substr(0, strlen(tbasis.c_str()));
	pTBasisData = FindVertexData(tbasis);

	string sxtbasis = "sxtbasis" + strBuff;
	sxtbasis = sxtbasis.substr(0, strlen(sxtbasis.c_str()));
	pSxTBasisData = FindVertexData(sxtbasis);

	if (!pPositionData || !pTextureData || !pSBasisData || !pTBasisData ||
		(pPositionData->GetDataType() != NVCOMPLEXMESH_FLOAT3) ||
		(pTextureData->GetDataType() != NVCOMPLEXMESH_FLOAT2) ||
		(pSBasisData->GetDataType() != NVCOMPLEXMESH_FLOAT3) || 
		(pTBasisData->GetDataType() != NVCOMPLEXMESH_FLOAT3))
	{
		return false;
	}

	if (pSxTBasisData && !pNormalData)
	{
		// Need normal stream if generating SxTBasis.
		return false;
	}

	tVec3Array& Position = pPositionData->GetVec3Array();
	tVec2Array& Texture = pTextureData->GetVec2Array();
	tVec3Array& Normal = pNormalData->GetVec3Array();
	tVec3Array& SBasis = pSBasisData->GetVec3Array();
	tVec3Array& TBasis = pTBasisData->GetVec3Array();

	// Pick up SxT if needed
	tVec3Array* pSxTBasis = NULL;
	if (pSxTBasisData)
	{
		pSxTBasis = &pSxTBasisData->GetVec3Array();
	}

	tIndexArray::iterator itrIndices;
	
	// Clear the basis vectors
	for (i = 0; i < m_dwNumVertices; i++)
	{
		SBasis[i] = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
		TBasis[i] = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
	}

	// Walk through the triangle list and calculate gradiants for each triangle.
	// Sum the results into the S and T components.
	itrIndices = m_Indices.begin();
	while (itrIndices != m_Indices.end())
	{
		DWORD TriIndex[3];
		D3DXVECTOR3 du, dv;
		D3DXVECTOR3 edge01;
		D3DXVECTOR3 edge02;
		D3DXVECTOR3 cp;
				
		TriIndex[0] = *(itrIndices + 0);
		TriIndex[1] = *(itrIndices + 1);
		TriIndex[2] = *(itrIndices + 2);
		itrIndices += 3;

		NVASSERT((TriIndex[0] < m_dwNumVertices) && (TriIndex[1] < m_dwNumVertices) && (TriIndex[2] < m_dwNumVertices), "Index exceeds vertex count");

		// Position locations
		D3DXVECTOR3& v0 = Position[TriIndex[0]];
		D3DXVECTOR3& v1 = Position[TriIndex[1]];
		D3DXVECTOR3& v2 = Position[TriIndex[2]];

		// Texture locations
		D3DXVECTOR2& t0 = Texture[TriIndex[0]];
		D3DXVECTOR2& t1 = Texture[TriIndex[1]];
		D3DXVECTOR2& t2 = Texture[TriIndex[2]];
		
		// Basis locations
		D3DXVECTOR3& sb0 = SBasis[TriIndex[0]];
		D3DXVECTOR3& tb0 = TBasis[TriIndex[0]];
		D3DXVECTOR3& sb1 = SBasis[TriIndex[1]];
		D3DXVECTOR3& tb1 = TBasis[TriIndex[1]];
		D3DXVECTOR3& sb2 = SBasis[TriIndex[2]];
		D3DXVECTOR3& tb2 = TBasis[TriIndex[2]];

		// x, s, t
		edge01 = D3DXVECTOR3( v1.x - v0.x, t1.x - t0.x, t1.y - t0.y );
		edge02 = D3DXVECTOR3( v2.x - v0.x, t2.x - t0.x, t2.y - t0.y );

		D3DXVec3Cross(&cp, &edge01, &edge02);
		if ( fabs(cp.x) > SMALL_FLOAT )
		{
			sb0.x += -cp.y / cp.x;
			tb0.x += -cp.z / cp.x;

			sb1.x += -cp.y / cp.x;
			tb1.x += -cp.z / cp.x;
			
			sb2.x += -cp.y / cp.x;
			tb2.x += -cp.z / cp.x;
		}

		// y, s, t
		edge01 = D3DXVECTOR3( v1.y - v0.y, t1.x - t0.x, t1.y - t0.y );
		edge02 = D3DXVECTOR3( v2.y - v0.y, t2.x - t0.x, t2.y - t0.y );

		D3DXVec3Cross(&cp, &edge01, &edge02);
		if ( fabs(cp.x) > SMALL_FLOAT )
		{
			sb0.y += -cp.y / cp.x;
			tb0.y += -cp.z / cp.x;

			sb1.y += -cp.y / cp.x;
			tb1.y += -cp.z / cp.x;
			
			sb2.y += -cp.y / cp.x;
			tb2.y += -cp.z / cp.x;
		}

		// z, s, t
		edge01 = D3DXVECTOR3( v1.z - v0.z, t1.x - t0.x, t1.y - t0.y );
		edge02 = D3DXVECTOR3( v2.z - v0.z, t2.x - t0.x, t2.y - t0.y );

		D3DXVec3Cross(&cp, &edge01, &edge02);
		if ( fabs(cp.x) > SMALL_FLOAT )
		{
			sb0.z += -cp.y / cp.x;
			tb0.z += -cp.z / cp.x;

			sb1.z += -cp.y / cp.x;
			tb1.z += -cp.z / cp.x;
			
			sb2.z += -cp.y / cp.x;
			tb2.z += -cp.z / cp.x;
		}

    }

    // Calculate the SxT vector
  	for(i = 0; i < m_dwNumVertices; i++)
  	{		
  		// Normalize the S, T vectors
  		D3DXVec3Normalize(&SBasis[i], &SBasis[i]);
  		D3DXVec3Normalize(&TBasis[i], &TBasis[i]);

		if (pSxTBasis)
		{
			D3DXVECTOR3 NormalizedNormal;

  			// Get the cross of the S and T vectors
  			D3DXVec3Cross(&(*pSxTBasis)[i], &SBasis[i], &TBasis[i]);
 			D3DXVec3Normalize(&(*pSxTBasis)[i], &(*pSxTBasis)[i]);


			// Need a normalized normal
  			D3DXVec3Normalize(&NormalizedNormal, &Normal[i]);

	  		// v coordinates go in opposite direction from the texture v increase in xyz
	 		TBasis[i] = -TBasis[i];

			// Get the direction of the SxT vector
  			if (D3DXVec3Dot(&(*pSxTBasis)[i], &NormalizedNormal) < 0.0f)
  			{
  				(*pSxTBasis)[i] = -(*pSxTBasis)[i];
  			}
		}
  	}

	return true;

}

bool NVComplexMesh::CreateFromXFile(LPDIRECT3DDEVICE8 pDevice, const char* fileName)
{
	HRESULT hr;
	DWORD i;
	DWORD dwTexCount;
	LPD3DXMESH tempMesh, tempMeshOpt;
	LPD3DXBUFFER pMaterials;
	DWORD dwNumAttributes;
	DWORD dwNumMaterials;
	LPDIRECT3DVERTEXBUFFER8 pVB;
	LPDIRECT3DINDEXBUFFER8 pIB;
	D3DVERTEXBUFFER_DESC vbdesc;
	D3DINDEXBUFFER_DESC ibdesc;
	
	Release();
	m_Passes.push_back(new NVComplexMeshPass(this));

	// If there's a path to this file, jump to this directory to ensure correct loading of textures, etc.
	std::string strDirectory = fileName;
	std::string::size_type Pos = strDirectory.find_last_of("\\", strDirectory.size());
	if (Pos != strDirectory.npos)
	{
		strDirectory = strDirectory.substr(0, Pos);
	}										
	else
	{
		strDirectory = ".";
	}

	// Load the mesh into system memory
	hr = D3DXLoadMeshFromX(const_cast<char*>(fileName), D3DXMESH_SYSTEMMEM, pDevice, NULL, (ID3DXBuffer**)&pMaterials, &dwNumMaterials, &tempMesh);
	if (FAILED(hr))
		return false;

	// Sort the attributes.
	hr = tempMesh->Optimize(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL, &tempMeshOpt);
	if (FAILED(hr))
		return false;
	
	hr = tempMeshOpt->GetAttributeTable(NULL, &dwNumAttributes);
	if (FAILED(hr))
		return false;

	D3DXATTRIBUTERANGE* pAttributes = (D3DXATTRIBUTERANGE*)HeapAlloc(GetProcessHeap(), 0, dwNumAttributes * sizeof(D3DXATTRIBUTERANGE));

	hr = tempMeshOpt->GetAttributeTable(pAttributes, &dwNumAttributes);

	hr = tempMeshOpt->GetVertexBuffer(&pVB);
	if (FAILED(hr))
	{
	  	SAFE_RELEASE(tempMesh);
		SAFE_RELEASE(tempMeshOpt);
		SAFE_RELEASE(pMaterials);
		return false;
	}

	hr = tempMeshOpt->GetIndexBuffer(&pIB);
	if (FAILED(hr))
	{
		SAFE_RELEASE(pVB);
		SAFE_RELEASE(pMaterials);
	  	SAFE_RELEASE(tempMesh);
		SAFE_RELEASE(tempMeshOpt);
			
		return false;
	}

	pIB->GetDesc(&ibdesc);
	pVB->GetDesc(&vbdesc);

	// First store the material data
	for (i = 0; i < dwNumMaterials; i++)
	{
		NVComplexMeshSection Attrib;
		NVMaterialResource* pMaterial = new NVMaterialResource;
		NVASSERT(pMaterials->GetBufferSize() >= (dwNumMaterials * sizeof(D3DXMATERIAL)), "Materials buffer is too small");
		D3DXMATERIAL* pMat = (D3DXMATERIAL*)pMaterials->GetBufferPointer();
		
		// Create named constants for this mesh
		pMaterial->AddConstant("diffuse", *(D3DXVECTOR4*)&pMat[i].MatD3D.Diffuse);
		pMaterial->AddConstant("ambient", *(D3DXVECTOR4*)&pMat[i].MatD3D.Ambient);
		pMaterial->AddConstant("emissive", *(D3DXVECTOR4*)&pMat[i].MatD3D.Emissive);

		// Only add specular if there's a specular power
		if (pMat[i].MatD3D.Power != 0.0f)
		{
			pMaterial->AddConstant("power", D3DXVECTOR4(0.0f, 0.0f, 0.0f, pMat[i].MatD3D.Power));
			pMaterial->AddConstant("specular", *(D3DXVECTOR4*)&pMat[i].MatD3D.Specular);
		}

		if (pMat[i].pTextureFilename)
		{
			string strFilePath = strDirectory + "\\" + pMat[i].pTextureFilename;
			HANDLE hFile = CreateFile(strFilePath.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
			if (hFile == INVALID_HANDLE_VALUE) 
			{
				DISPDBG(0, "Couldn't find: " << strFilePath);
				pMaterial->AddOriginalTexture(0, NVINVALID_RESOURCEID);
			}
			else
			{
				CloseHandle(hFile);

				// Add this texture to the resource manager
				NVTextureFileResource* pTexture = new NVTextureFileResource(pDevice, strDirectory + "\\" + pMat[i].pTextureFilename);
				pMaterial->AddOriginalTexture(0, NVRESOURCEMANAGER.AddResource(pTexture));
			}
			
		}			
		else
		{
			pMaterial->AddOriginalTexture(0, NVINVALID_RESOURCEID);

⌨️ 快捷键说明

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