www.pudn.com > notWow.rar > Model.cpp


#include "Model.h" 
#include "Random.h" 
extern Random g_Random; 
int slotOrder[] =  
{	 
	CS_SHIRT, 
	CS_HEAD, 
	CS_NECK, 
	CS_SHOULDER, 
	CS_PANTS, 
	CS_BOOTS, 
	CS_CHEST, 
	CS_TABARD, 
	CS_BELT, 
	CS_BRACERS, 
	CS_GLOVES, 
	CS_HAND_RIGHT, 
	CS_HAND_LEFT, 
	CS_CAPE, 
	CS_QUIVER 
}; 
 
int slotOrderWithRobe[] =  
{ 
	CS_SHIRT, 
	CS_HEAD, 
	CS_NECK, 
	CS_SHOULDER, 
	CS_BOOTS, 
	CS_PANTS, 
	CS_BRACERS, 
	CS_CHEST, 
	CS_GLOVES, 
	CS_TABARD, 
	CS_BELT, 
	CS_HAND_RIGHT, 
	CS_HAND_LEFT, 
	CS_CAPE, 
	CS_QUIVER 
}; 
bool M2Model::InitCommom(char *M2File,int Size)	 
{ 
	uint32 i; 
	HRESULT hr; 
	 
	// get header 
	ModelHeader Header;		 
	memcpy(&Header,M2File,sizeof(Header)); 
 
	// get global sequences 
	if (Header.nGlobalSequences)  
	{ 
		m_nGlobalSequences = Header.nGlobalSequences; 
		m_pGlobalSequences = new int[Header.nGlobalSequences]; 
		memcpy(m_pGlobalSequences, (M2File + Header.ofsGlobalSequences),Header.nGlobalSequences * sizeof(int)); 
	} 
 
	// *********************************** 
	// Build Attachments 
	if ((m_nAttachments = Header.nAttachments) > 0)  
	{ 
		m_pAttachments = new ModelAttachment[m_nAttachments]; 
		ModelAttachmentDef *attachments = (ModelAttachmentDef*)(M2File + Header.ofsAttachments); 
		for ( i = 0; i < m_nAttachments; ++ i)  
		{ 
			m_pAttachments[i].Init(attachments[i],this); 
		} 
	} 
	if (Header.nAttachLookup)  
	{ 
		int16 *p = (int16*)(M2File + Header.ofsAttachLookup); 
		for ( i = 0; i < Header.nAttachLookup; ++ i)  
		{ 
			m_AttachmentLookup[i] = p[i]; 
		} 
	} 
	 
	// ************************************ 
	// Light 
	if ((m_nLights = Header.nLights) > 0 )  
	{ 
		m_pLights = new ModelLight[m_nLights]; 
		ModelLightDef *lDefs = (ModelLightDef*)(M2File + Header.ofsLights); 
		for ( i = 0; i < m_nLights ;  ++ i)  
			m_pLights[i].Init(M2File, lDefs[i], m_pGlobalSequences); 
	}	 
	 
	// ************************************ 
	// Colors 
	if ((m_nColors = Header.nColors) > 0 )  
	{ 
		m_pColors = new ModelColor[m_nColors]; 
		ModelColorDef *colorDefs = (ModelColorDef*)(M2File + Header.ofsColors); 
		for ( i = 0; i < m_nColors; ++ i)  
			m_pColors[i].Init(M2File, colorDefs[i], m_pGlobalSequences); 
	} 
 
	// ************************************ 
	// init transparency 
	if ((m_nTransparencies = Header.nTransparency) > 0 ) 
	{ 
		m_pTransparencies = new ModelTransparency[m_nTransparencies]; 
		ModelTransDef *trDefs = (ModelTransDef*)(M2File + Header.ofsTransparency); 
		for ( i = 0; i < m_nTransparencies ; ++ i)  
			m_pTransparencies[i].Init(M2File, trDefs[i], m_pGlobalSequences); 
	} 
 
	// *********************************** 
	// Bounds 
	if ( (m_nBoundVertices = Header.nBoundingVertices) > 0)  
	{ 
		m_pBoundVertices = new D3DXVECTOR3[m_nBoundVertices]; 
		D3DXVECTOR3 *b = (D3DXVECTOR3*)(M2File + Header.ofsBoundingVertices); 
		for ( i = 0; i < m_nBoundVertices ; ++ i)  
			m_pBoundVertices[i] = fixCoordSystem(b[i]); 
	} 
	if ( ( m_nBoundIndices = Header.nBoundingTriangles ) > 0)  
	{ 
		m_pBoundIndices = new uint16[m_nBoundIndices]; 
		memcpy(m_pBoundIndices, M2File + Header.ofsBoundingTriangles, m_nBoundIndices*sizeof(uint16)); 
	} 
 
	// *********************************** 
	// Particle systems 
	if ( (m_nPS = Header.nParticleEmitters) > 0)  
	{ 
		ModelParticleEmitterDef *pdefs = (ModelParticleEmitterDef *)(M2File + Header.ofsParticleEmitters); 
		m_pPS = new ParticleSystem[m_nPS]; 
		for ( i = 0; i < m_nPS ; ++ i)  
		{ 
			m_pPS[i].Init(M2File, pdefs[i], m_pGlobalSequences,this); 
		} 
	} 
	return true; 
} 
bool M2Model::InitStatic(char *M2File,int Size) 
{ 
	uint32 i; 
	HRESULT hr; 
 
	// get header 
	ModelHeader Header;		 
	memcpy(&Header,M2File,sizeof(Header)); 
 
 
	// get original/global vertices list and fix  
	MODELSTATICVERTEX* pOrigVertices = new MODELSTATICVERTEX [Header.nVertices]; 
	ModelVertex* ptOrigVertices = (ModelVertex*)(M2File + Header.ofsVertices); 
	int nOrigVertices = Header.nVertices;		 
	for (i = 0; i < nOrigVertices; ++ i)  
	{ 
		pOrigVertices[i].Pos    = fixCoordSystem(ptOrigVertices[i].Pos); 
		pOrigVertices[i].Normal = fixCoordSystem(ptOrigVertices[i].Normal); 
		pOrigVertices[i].Texcoord = ptOrigVertices[i].Texcoords;	 
	} 
	m_pBC = NULL; 
 
	// **************************************** 
	// Create Vertices and Indices from a View 
	 
	// the original vertices is global vertices list. 
	// in a view,it gives a vertex indices list and a   
	// triangle(face) indices list. 
	// the vertex index is to the global  
	// vertices list.the index is this vertex's offset in 
	// global vertices list 
	// and the face index is to the vertex 
	// indices in the view 
	ModelView* pViews = (ModelView*)(M2File+ Header.ofsViews); 
	// choose a view 
	// there one or more views,select the first one here 
	int iViewChose = 0; 
 
	// the index to global vertices list  
	uint16 *VertexIndex = (uint16*)(M2File + pViews[iViewChose].ofsIndex); 
	m_nVertices = pViews->nIndex; 
	// the triangles(face)'s three vertices index to VertexIndex 
	uint16 *Triangles = (uint16*)(M2File + pViews[iViewChose].ofsTris); 
	m_nIndices = pViews[iViewChose].nTris; 
	uint16* pIndices = new uint16[m_nIndices]; 
	for (i = 0; i < m_nIndices; ++ i)  
	{ 
        pIndices[i] = VertexIndex[Triangles[i]]; 
	} 
 
    // Create the vertex buffer 
    if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( m_nVertices * sizeof(MODELSTATICVERTEX), 
		                                               0, MODELSTATICVERTEX::FVF , 
                                                       D3DPOOL_MANAGED, &m_pVB, NULL ) ) ) 
	{ 
        return false; 
	} 
    // Create the Index buffer 
    if( FAILED( hr = m_pd3dDevice->CreateIndexBuffer( m_nIndices * sizeof(uint16), 
	                                                  0, D3DFMT_INDEX16, 
		                                              D3DPOOL_MANAGED, &m_pIB, NULL ) ) ) 
	{ 
		return false; 
	} 
 
	// fill the stream with original vertices info 
    MODELSTATICVERTEX* pVBVertices; 
    if( FAILED( hr = m_pVB->Lock( 0, 0, (VOID**)&pVBVertices, 0 ) ) ) 
        return hr; 
	memcpy(pVBVertices,pOrigVertices,sizeof(MODELSTATICVERTEX)*nOrigVertices); 
    m_pVB->Unlock(); 
 
	// Fill the index buffer 
    uint16* pIBIndex; 
    if( FAILED(m_pIB->Lock( 0, 0, (VOID**)&pIBIndex, 0 ) ) ) 
        return false; 
	memcpy(pIBIndex,pIndices,sizeof(uint16)*m_nIndices);  
    m_pIB->Unlock();	 
	delete [] pIndices; 
	delete [] pOrigVertices; 
	 
	// *********************************** 
	// Get the Geosets 
	m_pShowGeosets = new bool[pViews[iViewChose].nSub]; 
 
	// textures 
	ModelTextureDef *texdef = (ModelTextureDef*)(M2File + Header.ofsTextures); 
	if (Header.nTextures)  
	{ 
		m_pTexturesID = new TextureID[Header.nTextures]; 
		for (size_t i=0; i 0 ) 
	{ 
		m_pRenderPass = new ModelRenderPass[m_nRenderPass]; 
		for( i = 0 ; i < m_nRenderPass ; ++ i) 
		{ 
			m_pRenderPass[i].Init(M2File,pViews[iViewChose],Header,i); 
		} 
	} 

	// transparent parts come later
	//	std::sort(passes.begin(), passes.end()); 
 
	return true; 
} 
 
bool M2Model::InitVB(char *M2File,int Size) 
{ 
	uint32 i; 
	HRESULT hr; 
	 
	// get header 
	ModelHeader Header;		 
	memcpy(&Header,M2File,sizeof(Header)); 
 
 
	// ************************************ 
	// Initialize the BonesContainer 
	// the Matrix Pallette  
	int nBones; 
	nBones = Header.nBones; 
	assert(nBones < 128); 
 
	// if m_nBones is greater then 128 
	// the index will be change into unsigned char type 
	bool* bBone = new bool[nBones];		// is the bone used in vertices blending 
	memset(bBone,0,sizeof(bool)*nBones); 
 
	// get original/global vertices list and fix  
	MODELVBVERTEX* pOrigVertices = new MODELVBVERTEX [Header.nVertices]; 
	ModelVertex* ptOrigVertices = (ModelVertex*)(M2File + Header.ofsVertices); 
	int nOrigVertices = Header.nVertices; 
 
 
	for (i = 0; i < nOrigVertices; ++ i)  
	{ 
		pOrigVertices[i].Pos    = fixCoordSystem(ptOrigVertices[i].Pos); 
		pOrigVertices[i].Normal = fixCoordSystem(ptOrigVertices[i].Normal); 
		pOrigVertices[i].Texcoord = ptOrigVertices[i].Texcoords; 
		pOrigVertices[i].Blend1 = (float)ptOrigVertices[i].Weights[0] / 255.0f; 
		pOrigVertices[i].Blend2 = (float)ptOrigVertices[i].Weights[1] / 255.0f; 
		pOrigVertices[i].Blend3 = (float)ptOrigVertices[i].Weights[2] / 255.0f; 
		for(int j = 0 ; j < 4; ++ j) 
		{ 
			assert(ptOrigVertices[i].Bones[j] < 128); 
			bBone[ptOrigVertices[i].Bones[j]] = true; 
		} 
	} 
	 
	D3DXComputeBoundingSphere((D3DXVECTOR3*)pOrigVertices,nOrigVertices, 
			                  sizeof(MODELVBVERTEX),&m_vCenter,&m_fRadius ); 
	D3DXComputeBoundingBox(	(D3DXVECTOR3*)pOrigVertices, nOrigVertices,  
                            sizeof(MODELVBVERTEX),&m_vMin,&m_vMax); 
 
	// get the count of bones which referenced by vetex blending 
	// and fix the indices 
	int Count = 0; 
	char BlendIndex[128];	//128 is max bones count 
	memset(BlendIndex,-1,128*sizeof(char)); 
	for(int j = 0 ; j < nBones ; ++ j) 
	{ 
		if(bBone[j]) 
		{ 
			BlendIndex[j] = Count;		 
			++ Count; 
		} 
	} 
 
	// renumber the matrices pallette by BlendIndex 
	for (i = 0; i < nOrigVertices; ++ i)  
	{ 
		for(int j = 0 ; j < 4 ; ++ j) 
		{ 
			ptOrigVertices[i].Bones[j] = (uint8)BlendIndex[ptOrigVertices[i].Bones[j]]; 
		} 
		pOrigVertices[i].Indices = *((DWORD*)ptOrigVertices[i].Bones); 
	}	 
 
	m_pBC = new BonesContainer; 
	m_pBC->Init(nBones,Count,BlendIndex,M2File,Header,m_pGlobalSequences); 
	delete [] bBone; 
	 
	// **************************************** 
	// Create Vertices and Indices from a View 
	 
	// the original vertices is global vertices list. 
	// in a view,it gives a vertex indices list and a   
	// triangle(face) indices list. 
	// the vertex index is to the global  
	// vertices list.the index is this vertex's offset in 
	// global vertices list 
	// and the face index is to the vertex 
	// indices in the view 
	ModelView* pViews = (ModelView*)(M2File+ Header.ofsViews); 
	// choose a view 
	// there one or more views,select the first one here 
	int iViewChose = 0; 
 
	// the index to global vertices list  
	uint16 *VertexIndex = (uint16*)(M2File + pViews[iViewChose].ofsIndex); 
	m_nVertices = pViews->nIndex; 
	// the triangles(face)'s three vertices index to VertexIndex 
	uint16 *Triangles = (uint16*)(M2File + pViews[iViewChose].ofsTris); 
	m_nIndices = pViews[iViewChose].nTris; 
	uint16* pIndices = new uint16[m_nIndices]; 
	for (i = 0; i < m_nIndices; ++ i)  
	{ 
        pIndices[i] = VertexIndex[Triangles[i]]; 
	} 
 
    // Create the vertex buffer 
    if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( m_nVertices * sizeof(MODELVBVERTEX), 
		                                               0, MODELVBVERTEX::FVF , 
                                                       D3DPOOL_MANAGED, &m_pVB, NULL ) ) ) 
	{ 
        return false; 
	} 
    // Create the Index buffer 
    if( FAILED( hr = m_pd3dDevice->CreateIndexBuffer( m_nIndices * sizeof(uint16), 
	                                                  0, D3DFMT_INDEX16, 
		                                              D3DPOOL_MANAGED, &m_pIB, NULL ) ) ) 
	{ 
		return false; 
	} 
 
	// fill the stream with original vertices info 
    MODELVBVERTEX* pVBVertices; 
    if( FAILED( hr = m_pVB->Lock( 0, 0, (VOID**)&pVBVertices, 0 ) ) ) 
        return false; 
	memcpy(pVBVertices,pOrigVertices,sizeof(MODELVBVERTEX)*nOrigVertices); 
    m_pVB->Unlock(); 
 
	// Fill the index buffer 
    uint16* pIBIndex; 
    if( FAILED(m_pIB->Lock( 0, 0, (VOID**)&pIBIndex, 0 ) ) ) 
        return false; 
	memcpy(pIBIndex,pIndices,sizeof(uint16)*m_nIndices);  
    m_pIB->Unlock();	 
	delete [] pIndices; 
	delete [] pOrigVertices; 
	// *********************************** 
	// Get the Geosets 
	m_pShowGeosets = new bool[pViews[iViewChose].nSub]; 
 
	// textures 
	ModelTextureDef *texdef = (ModelTextureDef*)(M2File + Header.ofsTextures); 
	m_nTextures = Header.nTextures; 
	if (Header.nTextures)  
	{ 
		m_pTexturesID = new TextureID[Header.nTextures]; 
		for (size_t i=0; i 0 ) 
	{ 
		m_pRenderPass = new ModelRenderPass[m_nRenderPass]; 
		for( i = 0 ; i < m_nRenderPass ; ++ i) 
		{ 
			m_pRenderPass[i].Init(M2File,pViews[iViewChose],Header,i); 
		} 
	} 
	//	std::sort(passes.begin(), passes.end()); 
 
	return true; 
} 
 
bool M2Model::Init(char*  pFile,int Size,MODELTYPE Type,LPDIRECT3DDEVICE9 pd3dDevice) 
{ 
	if(pd3dDevice == NULL) 
		return false; 
	Free(); 
 
	m_pd3dDevice = pd3dDevice; 
	m_Type = Type; 
	m_Effect.Init(pd3dDevice); 
	 
	bool rs = InitCommom(pFile,Size); 
	if(Type == MODEL_CHARACTER || Type == MODEL_CREATURE) 
		rs &= InitVB(pFile,Size); 
	else 
		rs &= InitStatic(pFile,Size); 
	if(!rs) 
		Free(); 
	return rs; 
} 
void	M2Model::SetDetails(char Geosets[]) 
{ 
	// set geosets 
	for (int j = 0; j < m_nRenderPass ; ++ j)  
	{ 
		int id = m_pRenderPass[j].m_GeosetID; 
		//if(id == 0) 
		//	continue; 
		 
		// hide top-of-head if we have hair. 
		//if (id == 1)  
		//{	 
			// id为1是光头 
			//showGeosets[j] = bald; 
		//} 
 
		for (int i = 0; i < 16; ++ i)  
		{ 
			// 一个人物共有16种Geoset,他们的id是从 100*i -- 100*(i+1)的 
			// 100*i是它的基id,cd.geosets[i]是它的偏移id 
 
			// 好像就i = 0 (发型)可以有id = 0; 
			// 其他的都没有偏移id为0的 
 
			// 这个只要利用id的 起始号+cd.geosets[i]就可以得到 所选择的cd.geosets[i]的真正id 
			// 并标示showGeosets[i],来画geoset[i] 
			int a = i*100, b = (i+1) * 100; 
			if (id>a && idFree(); 
	if(m_pPS != NULL) 
	{ 
		for(i = 0 ; i < m_nPS ; ++ i) 
			m_pPS[i].Free();	 
	} 
	m_Effect.Free(); 
	for(int i = 0 ; i < m_nTextures ; ++ i) 
	{ 
		g_TexMgr.Delete(m_pTexturesID[i]); 
	} 
 
	SAFE_DELETE_A(m_pShowGeosets); 
	SAFE_DELETE_A(m_pGlobalSequences); 
	SAFE_DELETE_A(m_pAttachments); 
	SAFE_DELETE_A(m_pTexturesID); 
	SAFE_DELETE_A(m_pBoundVertices); 
	SAFE_DELETE_A(m_pBoundIndices); 
 
	SAFE_DELETE_A(m_pTransparencies); 
	SAFE_DELETE_A(m_pLights); 
	SAFE_DELETE_A(m_pColors); 
 
	SAFE_DELETE_A(m_pRenderPass); 
 
	SAFE_DELETE(m_pBC); 
	SAFE_DELETE_A(m_pPS); 
 
	SAFE_RELEASE(m_pVB); 
	SAFE_RELEASE(m_pIB); 
	m_pd3dDevice = NULL; 
} 
 
void M2Model::Update(D3DXMATRIX* pmatViewProj) 
{ 
/* 
//  software vertex blending 
	for(int i = 0 ; i < m_nOrigVertices ; ++ i) 
	{ 
		char index[4]; 
		memcpy(index,&pVBVertices[i].Indices,sizeof(DWORD)); 
		D3DXVECTOR3 v(0.0f,0.0f,0.0f); 
		D3DXVECTOR3 tv =  VxM(&pVBVertices[i].Pos ,&pMat[index[0]]); 
		v += tv * pVBVertices[i].Blend1; 
		tv = VxM(&pVBVertices[i].Pos ,&pMat[index[1]]); 
		v += tv * pVBVertices[i].Blend2; 
		tv = VxM(&pVBVertices[i].Pos ,&pMat[index[2]]); 
		v += tv * pVBVertices[i].Blend3; 
		tv = VxM(&pVBVertices[i].Pos ,&pMat[index[3]]); 
		v += tv * (1 - pVBVertices[i].Blend3 - pVBVertices[i].Blend2 - pVBVertices[i].Blend1); 
		pVBVertices[i].Pos = v; 
	} 
*/	 
	// Set Effect Parameter 
	m_Effect.SetViewProjMatrix(pmatViewProj ); 
 
	if(m_Type == MODEL_CHARACTER || m_Type == MODEL_CREATURE) 
	{ 
		m_Effect.SetMatrixPalette(m_pBC->GetMatrices(),m_pBC->GetBlendMatricesCount()); 
	} 
} 
 
bool M2Model::Render(float CameraDist,bool bFar) 
{ 
	UINT nPasses,iPass; 
	HRESULT hr; 
	bool    rs = true; 
//	m_pEffect->SetTexture(m_hTexture,g_TexMgr.GetTexture(0)); 
     
	DWORD FVF; 
	int   VertexSize; 
	if(m_Type == MODEL_CHARACTER || m_Type == MODEL_CREATURE) 
	{	 
		FVF = MODELVBVERTEX::FVF; 
		VertexSize = sizeof(MODELVBVERTEX); 
	} 
	else 
	{ 
		//FVF = MODELSTATICVERTEX::FVF; 
		//VertexSize = sizeof(MODELSTATICVERTEX); 
	} 
 
 
    m_pd3dDevice->SetFVF( FVF ); 
	m_pd3dDevice->SetIndices( m_pIB ); 
	m_pd3dDevice->SetStreamSource( 0, m_pVB,0,VertexSize ); 
 
	m_Effect.SetTechnique(m_Type); 
 
    m_Effect.Begin(&nPasses, 0); 
    for (iPass = 0; iPass < nPasses; iPass++) 
    { 
        m_Effect.BeginPass(iPass); 
		 
		for(int i = 0  ; i < m_nRenderPass ; ++ i) 
		{ 
			if(!m_pRenderPass[i].SetState(this)) 
				continue; 
			 
			hr = m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST,  
													0, 
													m_pRenderPass[i].m_VertexStart,  
													m_pRenderPass[i].m_VertexCount,		// number of vertices 
													m_pRenderPass[i].m_IndexStart,  
													m_pRenderPass[i].m_IndexCount/3);	// number of primitives 
			rs &= SUCCEEDED(hr); 
		} 
      
       m_Effect.EndPass(); 
    } 
    m_Effect.End(); 
	 
	return rs; 
} 
 
 
 
 
D3DXMATRIX* M2Model::SetupAttachment(int id) 
{ 
	int l = m_AttachmentLookup[id]; 
	if (l > -1) 
		return m_pAttachments[l].Setup(); 
	return NULL; 
} 
 
 
void M2Model::SetAnimation(int   Anim,int &Time) 
{ 
	if(m_Time == Time && m_Anim == Anim) 
		return; 
 
	m_Anim = Anim; 
	m_Time = m_pBC->GetAnimations()[m_Anim].timeEnd - m_pBC->GetAnimations()[m_Anim].timeStart; 
	m_Time = Time % m_Time;  
	Time = m_Time; 
 
	m_pBC->SetupBoneMatrices(m_Anim,m_Time); 
} 
 
bool M2Model::NewLoop(int Anim,int Time) 
{ 
	int LoopTime; 
	LoopTime = m_pBC->GetAnimations()[Anim].timeEnd - m_pBC->GetAnimations()[Anim].timeStart; 
	if(Time >= LoopTime) 
		return true; 
	else 
		return false; 
} 
 
 
void M2Model::Move(float x,float y,float z,int Dir) 
{ 
	float sinDir = Math::Sin(Dir); 
	float cosDir = Math::Cos(Dir); 
	m_Effect.SetPosition(&D3DXVECTOR4(x,y,z,0)); 
	m_Effect.SetDirection(&D3DXVECTOR4(sinDir,cosDir,0,0)); 
} 
 
bool M2Model::Reset() 
{ 
	return m_Effect.Reset(); 
} 
 
void  M2Model::Lost() 
{ 
	m_Effect.Lost(); 
} 
 
 
bool XModel::Init(char *M2File,int Size) 
{   
	LPD3DXPMESH  pPMesh = NULL; 
    LPD3DXBUFFER pAdjacencyBuffer = NULL; 
    LPD3DXBUFFER pMtrlBuffer = NULL; 
    HRESULT      hr; 
	DWORD		 nMat; 
	LPDIRECT3DVERTEXBUFFER9 pVB = NULL; 
    void*      pVertices = NULL; 
 
	// Load the mesh 
    if( FAILED(hr = D3DXLoadMeshFromXInMemory(M2File,Size,D3DXMESH_MANAGED,m_pd3dDevice,  
										&pAdjacencyBuffer, &pMtrlBuffer, NULL, 
										&nMat, &m_pMesh ) ) ) 
		goto End; 
 
	m_pMesh->OptimizeInplace(D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE, 
							(DWORD*)pAdjacencyBuffer->GetBufferPointer(), NULL, NULL, NULL ); 
 
	m_nTextures    = nMat; 
	m_pMtrls = new D3DXMATERIAL[nMat]; 
	memcpy(m_pMtrls,pMtrlBuffer->GetBufferPointer(),sizeof(D3DXMATERIAL)*nMat); 
    if( m_nTextures > 0 ) 
    { 
        m_pTexturesID = new TextureID[m_nTextures]; 
 
        // Copy each material and create its texture 
        for( int i = 0; i < m_nTextures; ++ i ) 
        { 
            if( m_pMtrls[i].pTextureFilename ) 
            { 
				m_pTexturesID[i] = g_TexMgr.AddTexture((LPCSTR)m_pMtrls[i].pTextureFilename); 
	        } 
        } 
    }  
  
    hr = m_pMesh->GetVertexBuffer( &pVB ); 
    if( FAILED(hr) ) 
        goto End; 
    hr = pVB->Lock( 0, 0, &pVertices, 0 ); 
    if( FAILED(hr) ) 
		goto End; 
 
    D3DXComputeBoundingSphere((D3DXVECTOR3*)pVertices,m_pMesh->GetNumVertices(), 
			                  D3DXGetFVFVertexSize(m_pMesh->GetFVF()), 
							  &m_vCenter,&m_fRadius ); 
	D3DXComputeBoundingBox(	(D3DXVECTOR3*)pVertices, m_pMesh->GetNumVertices(),  
                            D3DXGetFVFVertexSize(m_pMesh->GetFVF()), 
						    &m_vMin,&m_vMax); 
	pVB->Unlock(); 
	 
	// Generate progressive meshes 
    hr = D3DXGeneratePMesh( m_pMesh, (DWORD*)pAdjacencyBuffer->GetBufferPointer(), 
                            NULL, NULL, 1, D3DXMESHSIMP_VERTEX, &pPMesh ); 
	 
	if( FAILED(hr) ) 
	{	 
		m_ppPMeshes = NULL; 
		m_nPMeshes = 0; 
		hr = S_OK; 
		goto End; 
	} 
 
    DWORD cVerticesMin = pPMesh->GetMinVertices(); 
    DWORD cVerticesMax = pPMesh->GetMaxVertices(); 
 
    DWORD cVerticesPerMesh = ( cVerticesMax - cVerticesMin + 10 ) / 10; 
 
    m_nPMeshes = (DWORD)ceil( (cVerticesMax - cVerticesMin + 1) / (float)cVerticesPerMesh ); 
	if(m_nPMeshes <= 1) 
	{ 
		m_ppPMeshes = NULL; 
		m_nPMeshes = 0; 
		hr = S_OK; 
		goto End; 
	} 
    m_ppPMeshes = new LPD3DXPMESH[m_nPMeshes]; 
 
    ZeroMemory( m_ppPMeshes, sizeof(LPD3DXPMESH) * m_nPMeshes ); 
 
    // Clone all the separate pmeshes 
    for( int iPMesh = 0; iPMesh < m_nPMeshes; iPMesh++ ) 
    { 
        hr = pPMesh->ClonePMeshFVF( D3DXMESH_MANAGED | D3DXMESH_VB_SHARE, pPMesh->GetFVF(), m_pd3dDevice, &m_ppPMeshes[iPMesh] ); 
		if( FAILED(hr) ) 
			goto End; 
        hr = m_ppPMeshes[iPMesh]->TrimByVertices( cVerticesMin + cVerticesPerMesh * iPMesh, cVerticesMin + cVerticesPerMesh * (iPMesh+1), NULL, NULL); 
		if( FAILED(hr) ) 
			goto End; 
        hr = m_ppPMeshes[iPMesh]->OptimizeBaseLOD( D3DXMESHOPT_VERTEXCACHE, NULL ); 
		if( FAILED(hr) ) 
			goto End; 
    } 
 
    // Set current to be maximum number of vertices 
	int iPMeshCur = m_nPMeshes - 1; 
    hr = m_ppPMeshes[iPMeshCur]->SetNumVertices( cVerticesMax ); 
    if( FAILED(hr) ) 
        goto End; 
End: 
	SAFE_RELEASE( pPMesh); 
	SAFE_RELEASE( pVB ); 
    SAFE_RELEASE( pAdjacencyBuffer ); 
    SAFE_RELEASE( pMtrlBuffer ); 
 
	if( FAILED(hr) ) 
		return false; 
	else 
		return true; 
 
} 
 
bool XModel::Init(char*  pFile,int Size,MODELTYPE Type,LPDIRECT3DDEVICE9 pd3dDevice) 
{ 
	if(pd3dDevice == NULL) 
		return false; 
	Free(); 
 
	m_pd3dDevice = pd3dDevice; 
	m_Type = Type; 
	m_Effect.Init(pd3dDevice); 
 
	bool rs = Init(pFile,Size); 
	if(!rs) 
		Free(); 
	return rs; 
} 
 
void XModel::Free() 
{ 
	SAFE_RELEASE( m_pMesh ); 
    for( int i = 0; i < m_nPMeshes; i++ ) 
        SAFE_RELEASE( m_ppPMeshes[i] ); 
	m_nPMeshes = 0; 
	SAFE_DELETE_A(m_ppPMeshes); 
	SAFE_DELETE_A(m_pTexturesID); 
	SAFE_DELETE_A(m_pMtrls); 
	m_Effect.Free(); 
	m_pd3dDevice = NULL; 
} 
 
void XModel::Lost() 
{ 
	m_Effect.Lost(); 
} 
 
bool XModel::Reset() 
{ 
	m_Effect.Reset(); 
	return true; 
} 
 
void XModel::Move(float x,float y,float z,int Dir) 
{ 
	float sinDir = Math::Sin(Dir); 
	float cosDir = Math::Cos(Dir); 
	m_Effect.SetPosition(&D3DXVECTOR4(x,y,z,0)); 
	m_Effect.SetDirection(&D3DXVECTOR4(sinDir,cosDir,0,0)); 
} 
 
void XModel::Update(D3DXMATRIX* pmatViewProj) 
{ 
	m_Effect.SetViewProjMatrix(pmatViewProj); 
} 
 
bool XModel::Render(float CameraDist,bool bFar) 
{	 
	int Num = -1; 
	if(m_ppPMeshes != NULL) 
	{  
		//float Dist = 60.0f / (m_nPMeshes + 1); 
		//int n = (int)(CameraDist / Dist); 
		//if(n >= 1) 
		//	pPMesh = m_ppPMeshes[m_nPMeshes - n]; 
		Num = m_nPMeshes - 1; 
	} 
 
	if(m_Type & MODEL_DFACE) 
		m_pd3dDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);	 	 
	else 
		m_pd3dDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_CCW); 
 
	if(m_Type & MODEL_TRANS) 
		m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); 
	else 
		m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); 
 
	if(m_Type & MODEL_ATEST ) 
		m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE , TRUE);  
	else 
		m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE , FALSE);  
		 
		 
	UINT nPasses,iPass; 
	D3DXVECTOR4 Vec; 
	int i; 
	if((m_Type & MODEL_WORLD) && bFar) 
		m_Effect.SetTechnique(EFFECT_WORLD_FAR); 
	else 
		m_Effect.SetTechnique(m_Type); 
 
    m_Effect.Begin(&nPasses, 0); 
    for (iPass = 0; iPass < nPasses; iPass++) 
    { 
        m_Effect.BeginPass(iPass); 
		for( i = 0; i < m_nTextures; ++ i ) 
		{ 
			//m_pd3dDevice->SetTexture(0,g_TexMgr.GetTexture(m_pTexturesID[i])); 
			m_Effect.SetTexture(g_TexMgr.GetTexture(m_pTexturesID[i])); 
			Vec.x = m_pMtrls[i].MatD3D.Diffuse.r; 
			Vec.y = m_pMtrls[i].MatD3D.Diffuse.g; 
			Vec.z = m_pMtrls[i].MatD3D.Diffuse.b; 
			Vec.w = m_pMtrls[i].MatD3D.Diffuse.a; 
			m_Effect.SetDiffuse(&Vec); 
			//Vec.x = m_pMtrls[i].MatD3D.Ambient.r; 
			//Vec.y = m_pMtrls[i].MatD3D.Ambient.g; 
			//Vec.z = m_pMtrls[i].MatD3D.Ambient.b; 
			//Vec.w = m_pMtrls[i].MatD3D.Ambient.a; 
			//m_Effect.SetAmbient(&Vec); 
			Vec.x = m_pMtrls[i].MatD3D.Emissive.r; 
			Vec.y = m_pMtrls[i].MatD3D.Emissive.g; 
			Vec.z = m_pMtrls[i].MatD3D.Emissive.b; 
			Vec.w = m_pMtrls[i].MatD3D.Emissive.a; 
			m_Effect.SetEmissive(&Vec); 
			Vec.x = m_pMtrls[i].MatD3D.Specular.r; 
			Vec.y = m_pMtrls[i].MatD3D.Specular.g; 
			Vec.z = m_pMtrls[i].MatD3D.Specular.b; 
			Vec.w = m_pMtrls[i].MatD3D.Specular.a; 
			m_Effect.SetSpecular(&Vec); 
 
			m_Effect.CommitChanges(); 
			if(m_ppPMeshes != NULL) 
				m_ppPMeshes[Num]->DrawSubset( i ); 
			else 
				m_pMesh->DrawSubset( i ); 
		}  
       m_Effect.EndPass(); 
    } 
    m_Effect.End(); 
 
	return true; 
} 
 
 
// 
// 求得变换后的近似BoundBox 
// 
void IModel::GetBoundBox(float x,float y,float z,int Dir,D3DXVECTOR3* pMin,D3DXVECTOR3* pMax) 
{ 
	float sinDir = Math::Sin(Dir); 
	float cosDir = Math::Cos(Dir); 
	D3DXVECTOR3 vMin(m_vMin); 
	D3DXVECTOR3 vMax(m_vMax); 
	float fx[4],fz[4]; 
 
	fx[0] = cosDir * vMin.x + sinDir * vMax.z; 
	fz[0]= -sinDir * vMin.x + cosDir * vMax.z; 
	fx[1]= cosDir * m_vMin.x + sinDir * m_vMax.z; 
	fz[1] = -sinDir * m_vMin.x + cosDir * m_vMax.z; 
	fx[2] = cosDir * vMin.x + sinDir *vMin.z; 
	fz[2] = -sinDir * vMin.x + cosDir * vMin.z; 
	fx[3] = cosDir * m_vMax.x + sinDir * m_vMax.z; 
	fz[3] = -sinDir * m_vMax.x + cosDir * m_vMax.z; 
	 
	vMin.x = min(min(fx[0],fx[1]),min(fx[2],fx[3])); 
	vMin.z = min(min(fz[0],fz[1]),min(fz[2],fz[3])); 
	vMax.x = max(max(fx[0],fx[1]),max(fx[2],fx[3])); 
	vMax.z = max(max(fz[0],fz[1]),max(fz[2],fz[3])); 
 
	*pMin = D3DXVECTOR3(x,y,z) + vMin; 
	*pMax = D3DXVECTOR3(x,y,z) + vMax; 
}