A simple class to load .X, advices needed

Started by
3 comments, last by DXnut 17 years, 11 months ago
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..
Advertisement
bump...
There are a lot of variables that define speed. What size models are you trying to load? How long is it taking? Are you loading MS sample models like tiny or tiny_4anim? How long is it taking?
3DMUVE is an amateur game development team, and the designer and developer of a new gaming technology “MUVE” for the gaming industry.
basically i need to load "big" models (from ~5k and up), without partitioning (maybe only a bit of lod). I don't need partitioning because i know that ALL the mesh will be on the screen..like a 3d background of a game like Resident Evil or Alone in the dark. The models are made with blender. I don't particularly care about the loading time, i need to get all the fps i can :D (it's easy to talk...)
Using D3DXMESH_MANAGED and D3DXMESH_WRITEONLY will give you the fastest rendering performance.
--------------------------Most of what I know came from Frank D. Luna's DirectX books

This topic is closed to new replies.

Advertisement