📄 nvcomplexmesh.cpp
字号:
/* 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 + -