i'm working on a simple .x loader and now i'm trying to push a bit of speed. Here's the source:
Header:
struct MESH_VERTEX {
D3DVECTOR pos;
D3DVECTOR normal;
float s,t;
};
#define MESH_FVF (D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_NORMAL)
class CModel{
public:
CModel();
~CModel();
bool Load(const char *filename, const char *path, LPDIRECT3DDEVICE9 pDevice);
int Render(LPDIRECT3DDEVICE9 pDevice, bool Textures = true);
int GetNumFaces() { return Mesh->GetNumFaces(); }
DWORD GetNumMaterials() { return NumMaterials; }
LPDIRECT3DTEXTURE9 GetTexture(int i) {
if(pMeshTextures && pMeshTextures)
return pMeshTextures;
return NULL;
}
LPD3DXMESH GetMesh() { return Mesh; }
LPD3DXPMESH GetProgMesh() { return ppPMesh; }
D3DXVECTOR3 minBounds,maxBounds;
private:
bool OptimizeMesh();
LPD3DXMESH Mesh;
LPD3DXPMESH ppPMesh;
D3DMATERIAL9* pMeshMaterials ;
LPDIRECT3DTEXTURE9* pMeshTextures ;
DWORD NumMaterials ;
LPD3DXBUFFER AdjBuffer;
};
And the .cpp:
CModel::CModel() {
Mesh = NULL;
ppPMesh = NULL;
pMeshMaterials = NULL;
pMeshTextures = NULL;
NumMaterials = 0;
}
CModel::~CModel(){
if(pMeshTextures){
for( DWORD i=0; i<NumMaterials; i++ ) {
if(pMeshTextures)
pMeshTextures->Release();
}
delete [] pMeshTextures;
}
}
bool CModel::Load(const char *filename, const char *path, LPDIRECT3DDEVICE9 pDevice){
DWORD Options = D3DXMESH_SYSTEMMEM ;
LPD3DXBUFFER ppMaterials = NULL;
LPD3DXBUFFER effectInstance = NULL;
HRESULT hr = D3DXLoadMeshFromX(filename,Options,pDevice,&AdjBuffer,
&ppMaterials,&effectInstance,&NumMaterials,&Mesh);
if( FAILED(hr) )
return false;
D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)ppMaterials->GetBufferPointer();
pMeshTextures = new LPDIRECT3DTEXTURE9[NumMaterials];
if( pMeshTextures == NULL )
return false;
D3DXEFFECTINSTANCE* Effects = (D3DXEFFECTINSTANCE*)effectInstance->GetBufferPointer();
char temp[256];
for( DWORD i=0; i<NumMaterials; i++ ) {
pMeshTextures = NULL;
sprintf(temp,"%s",Effects.pEffectFilename); // leggo il nome dello shader
if( d3dxMaterials.pTextureFilename != NULL && lstrlen(d3dxMaterials.pTextureFilename) > 0 ){
sprintf(temp,"%s%s",path,d3dxMaterials.pTextureFilename); // leggo il nome della texture
D3DXCreateTextureFromFile( pDevice, temp , &pMeshTextures ) ;
}
}
ppMaterials->Release();
DWORD dwFVF = Mesh->GetFVF();
if(!dwFVF){
LPD3DXMESH tempMesh = NULL;
Mesh->CloneMeshFVF(Mesh->GetOptions(),MESH_FVF,pDevice,&tempMesh);
if(tempMesh->GetFVF() != MESH_FVF)
return false;
Mesh->Release();
Mesh = tempMesh;
}
//Mesh->GetVertexBuffer(&m_pVertexBuffer);
D3DXComputeNormals(Mesh,NULL);
OptimizeMesh( );
D3DXATTRIBUTERANGE pAttribTable;
DWORD AttribTableSize = 0;
Mesh->GetAttributeTable(&pAttribTable,&AttribTableSize);
// calcolo la bounding box di TUTTO il modello
BYTE* pVertices=NULL;
hr = Mesh->LockVertexBuffer(D3DLOCK_READONLY, (LPVOID*)&pVertices);
if (FAILED(hr))
return FALSE;
D3DXComputeBoundingBox((D3DXVECTOR3*)pVertices, Mesh->GetNumVertices(),
D3DXGetFVFVertexSize(Mesh->GetFVF()), &minBounds, &maxBounds);
Mesh->UnlockVertexBuffer();
return true;
}
bool CModel::OptimizeMesh(){
HRESULT hr = S_OK;
// LISTA DELLE FACCE ADIACENTI
D3DXCreateBuffer((Mesh->GetNumFaces())*sizeof(DWORD)*3, &AdjBuffer);
hr = Mesh->GenerateAdjacency(0.0f, (DWORD*)AdjBuffer->GetBufferPointer());
if( FAILED(hr) )
return false;
// PREPARO LA MESH X LA SEMPLIFICAZIONE
hr = D3DXCleanMesh(D3DXCLEAN_SIMPLIFICATION ,Mesh,(DWORD*)AdjBuffer->GetBufferPointer(),
&Mesh,(DWORD*)AdjBuffer->GetBufferPointer(),NULL);
if( FAILED(hr) )
return false;
// ottimizzo per il rendering
hr = Mesh->Optimize( D3DXMESHOPT_VERTEXCACHE | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT,
(DWORD*)AdjBuffer->GetBufferPointer(), NULL, NULL, NULL, &Mesh );
if( FAILED(hr) )
return false;
AdjBuffer->Release();
D3DXCreateBuffer((Mesh->GetNumFaces())*sizeof(DWORD)*3, &AdjBuffer);
hr = Mesh->GenerateAdjacency(0.0f, (DWORD*)AdjBuffer->GetBufferPointer());
if( FAILED(hr) )
return false;
// PREPARO LA MESH X LA SEMPLIFICAZIONE
hr = D3DXCleanMesh(D3DXCLEAN_SIMPLIFICATION ,Mesh,(DWORD*)AdjBuffer->GetBufferPointer(),
&Mesh,(DWORD*)AdjBuffer->GetBufferPointer(),NULL);
if( FAILED(hr) )
return false;
// controllo eventuali errori
LPD3DXBUFFER errors;
if(FAILED(D3DXValidMesh(Mesh, (DWORD*)AdjBuffer->GetBufferPointer(), &errors))){
char asda[2048];
strcpy(asda,(char*)errors->GetBufferPointer());
return false;
}
// unisco i vertici troppo vicini
D3DXWELDEPSILONS Epsilons;
DWORD *pFaceRemap[65536];
Epsilons.Normal = 0.001;
Epsilons.Position = 0.1;
for(int i=0; i < 65536; i++ )
pFaceRemap = 0;
hr = D3DXWeldVertices ( Mesh,D3DXWELDEPSILONS_WELDPARTIALMATCHES, &Epsilons,
(DWORD*)AdjBuffer->GetBufferPointer(),(DWORD*)AdjBuffer->GetBufferPointer(),(DWORD*)pFaceRemap, NULL );
if( FAILED(hr) )
return false;
// genero la mesh progressiva
hr = D3DXGeneratePMesh(Mesh,(DWORD*)AdjBuffer->GetBufferPointer(), NULL, NULL, 100,D3DXMESHSIMP_FACE ,&ppPMesh);
if( FAILED(hr) )
ppPMesh = NULL;
else
ppPMesh->OptimizeBaseLOD(D3DXMESHOPT_VERTEXCACHE | D3DXMESHOPT_ATTRSORT|D3DXMESHOPT_COMPACT,NULL);
return true;
}
int CModel::Render(LPDIRECT3DDEVICE9 pDevice, bool Textures){
for( DWORD i=0; i<NumMaterials; i++ ) {
if(!pMeshTextures)
continue;
if(Textures)
pDevice->SetTexture( 0, pMeshTextures );
else
pDevice->SetTexture( 0, NULL );
Mesh->DrawSubset( i );
}
return 1;
}
This code works perfectly...now i would like to know how i could improve it to get more speed :)
As you may notice, i load the model using the D3DXMESH_SYSTEMMEM flag. Is there a better way? I've used also D3DPOOL_DEFAULT, but nothing seems to change..