Jump to content
  • Advertisement
Sign in to follow this  
b3rs3rk

A simple class to load .X, advices needed

This topic is 4412 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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..

Share this post


Link to post
Share on other sites
Advertisement
Guest Anonymous Poster
bump...

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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...)

Share this post


Link to post
Share on other sites
Using D3DXMESH_MANAGED and D3DXMESH_WRITEONLY will give you the fastest rendering performance.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!