⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 m2loader.cpp

📁 3D游戏展示程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//--------------------------------------------------
// WOW M2 Loader
//--------------------------------------------------

#include <algorithm>
#include "Common.h"
#include "M2Loader.h"
#include "M2Particle.h"
#include "M2CharTexture.h"
#include "M2AniController.h"

__forceinline D3DXVECTOR3 FixCoordSystem(const D3DXVECTOR3 &v)
{
	return D3DXVECTOR3(v.x, v.z, v.y);
}

//---------------------------------------------------------------------------
// 注意: CM2Loader不继承自GNode, 理由如下:
// 1, 模型间的绑定使用Attachment, 模型有绑定数据, GNode需要自行设置调节数据.
// 2, 多个绑定的模型当作一个GNode就可以了.
// 3, 要改变绑定中的某个节点只需设置某个Attachment.当前Attachment及其
//    子节点同时获得改变了的Attachment属性.
// 4, 要想改变某个节点但又不影响子节点很麻烦.
// 5, 要使用具用GNode属性的模型, 可以写继承自CM2Loader和GNode的类.
// 
//---------------------------------------------------------------------------

CM2Loader::CM2Loader()
{
	m_CurAnimation = 0;
	m_Radius = 0.1f;

	m_pGlobalSequences = NULL;
	m_pBone = NULL;
	m_pAni = NULL;
	m_pAniController = NULL;

	m_pData = NULL;

	m_pVertex = NULL;
	m_pVertexIndex = NULL;
	
	m_pBoundVertex = NULL;
	m_pBoundIndex = NULL;

	m_bShowSubMesh = NULL;
	m_SubMesh.clear();

	m_pColor = NULL;
	m_pTransparency = NULL;
	m_pTexture = NULL;

	m_pParticle = NULL;
	m_LastTime = 0;
	m_LastUpdate = 0;

	for(int i=0; i<32; i++)
	{
		m_SpecialTextureIndex[i] = -1;
		m_ReplaceTexture[i] = 0;
	}
	for(int i=0; i<40; i++)
	{
		m_AttachLookup[i] = -1;
	}
	for(int i=0; i<27; i++) 
	{
		m_BoneLookup[i] = -1;
	}
	m_bHasCamera = false;
	m_bHasParticle = false;
	m_bChar = false;
	m_bRender = true;

	m_RenderPass.clear();
}

CM2Loader::~CM2Loader()
{
	Destroy();
}

void CM2Loader::Destroy(void)
{
	if(g_pD3DDevice)
	{
		for(size_t i=0; i<m_RenderPass.size(); i++) 
		{
			M2RenderPass &pass = m_RenderPass[i];
			pass.CloseState();
		}
	}
		
	m_RenderPass.clear();
	S_DELETE_ARRAY(m_pGlobalSequences);
	S_DELETE_ARRAY(m_pBone);
	S_DELETE_ARRAY(m_pAni);
	S_DELETE(m_pAniController);

	S_DELETE_ARRAY(m_pData);

	S_DELETE_ARRAY(m_pVertex);
	S_DELETE_ARRAY(m_pVertexIndex);
	
	S_DELETE_ARRAY(m_pBoundVertex);
	S_DELETE_ARRAY(m_pBoundIndex);

	S_DELETE_ARRAY(m_bShowSubMesh);
	m_SubMesh.clear();

	S_DELETE_ARRAY(m_pColor);
	S_DELETE_ARRAY(m_pTransparency);
	S_DELETE_ARRAY(m_pTexture);

	S_DELETE_ARRAY(m_pParticle);
}

//----------------------------------------------------
// 加载M2模型
//----------------------------------------------------
bool CM2Loader::Load(const char *pFileName, bool forceAnim /* = false */)
{
	if(pFileName == NULL || pFileName[0] == 0)
		return false;
	FILE *fp = fopen(pFileName, "rb");
	if(fp == NULL)
	{
		WriteLog(INFO_ERROR, "Fail to open M2 file[%s]", pFileName);
		return false;
	}

	Destroy();

	fseek(fp, 0, SEEK_END);
	uint32 DataLen = ftell(fp);
	if(DataLen == 0)
		DataLen = 1;
	fseek(fp, 0, SEEK_SET);

	m_pData = new uint8[DataLen];
	if(m_pData == NULL)
	{
		fclose(fp);
		return false;
	}
	fread(m_pData, DataLen, 1, fp);
	fclose(fp);

	// Header
	memcpy(&m_Header, m_pData, sizeof(ModelHeader));
	// Global Sequence
	if(m_Header.nGlobalSequences) 
	{
		m_pGlobalSequences = new int[m_Header.nGlobalSequences];
		if(m_pGlobalSequences==NULL)	return false;
		memcpy(m_pGlobalSequences, (m_pData+m_Header.ofsGlobalSequences), m_Header.nGlobalSequences*sizeof(int));
	}

	strcpy(m_szModelName, (char*)(m_pData+m_Header.nameOfs));

	InitCommon();
	
	m_bAnimated = IsAnimation() || forceAnim;
	if(forceAnim) 	m_bAnimBones = true;

	if(m_bAnimated)
		InitAnimation();

	
	
	return true;
}

//----------------------------------------------------
// 初始化通用部分
//----------------------------------------------------
void CM2Loader::InitCommon(void)
{
	// Vertex
	ModelVertex *pVertex = (ModelVertex*)(m_pData+m_Header.ofsVertices);
	m_pVertex = new M2Vertex[m_Header.nVertices];
	if(m_pVertex == NULL)	return;
	for(uint32 i=0; i<m_Header.nVertices; i++)
	{
		// 后面顶点变换要用到
		pVertex[i].pos = FixCoordSystem(pVertex[i].pos);
		pVertex[i].normal = FixCoordSystem(pVertex[i].normal);

		m_pVertex[i].m_position = pVertex[i].pos;
		// 法线向量后面再标准化
		m_pVertex[i].m_normal = pVertex[i].normal;
		m_pVertex[i].m_texcoord = pVertex[i].texcoords;
		
		float flen = D3DXVec3LengthSq(&m_pVertex[i].m_position);
		if(flen > m_Radius)	m_Radius = flen;
	}
	m_Radius = sqrtf(m_Radius);
	// Vertex Index
	ModelView *pView = (ModelView*)(m_pData+m_Header.ofsViews);
	uint16 *pIndexLookup = (uint16*)(m_pData+pView->ofsIndex);	uint16 *pTriangles = (uint16*)(m_pData+pView->ofsTris);	m_pVertexIndex = new uint16[pView->nTris];	if(m_pVertexIndex == NULL)	return;	for(size_t i=0; i<pView->nTris/3; i++) 	{		for(int j=0; j<=2; j++)
		{
			m_pVertexIndex[i*3+(2-j)] = pIndexLookup[pTriangles[i*3+j]];
			//m_pVertexIndex[i*3+(2-j)] = pTriangles[i*3+j]; Is OK
		}	}

	// Bound Vertex
	D3DXVECTOR3 *pBoundVertex = (D3DXVECTOR3*)(m_pData+m_Header.ofsBoundingVertices);
	m_pBoundVertex = new M2BoundVertex[m_Header.nBoundingVertices];
	if(m_pBoundVertex == NULL)	return;
	for(uint32 i=0; i<m_Header.nBoundingVertices; i++)
	{
		m_pBoundVertex[i].SetVertex(FixCoordSystem(pBoundVertex[i]));
	}
	// Bound Vertex Index
	uint16 *pBoundIndex = (uint16*)(m_pData+m_Header.ofsBoundingTriangles);
	m_pBoundIndex = new uint16[m_Header.nBoundingTriangles];
	if(m_pBoundIndex == NULL)	return;
	for(uint32 i=0; i<m_Header.nBoundingTriangles/3; i++)
	{
		for(int j=0; j<=2; j++)
		{
			m_pBoundIndex[i*3+(2-j)] = pBoundIndex[i*3+j];
		}
	}

	// Texture
	ModelTextureDef *pTexdef = (ModelTextureDef*)(m_pData+m_Header.ofsTextures);
	if(m_Header.nTextures)
	{
		m_pTexture = new DWORD[m_Header.nTextures];
		for(uint32 i=0; i<m_Header.nTextures; i++)
		{
			char szTextureName[256];
			if(pTexdef[i].type == 0) 
			{
				strncpy(szTextureName, (const char*)m_pData+pTexdef[i].nameOfs, pTexdef[i].nameLen);
				szTextureName[pTexdef[i].nameLen] = 0;
				//std::string path(szTextureName);
				//fixname(path);
				//textures[i] = texturemanager.add(texname);
				m_pTexture[i] = 1003;
			} 
			else 
			{
				// special texture - only on characters and such...
				m_pTexture[i] = 0;
				m_SpecialTextureIndex[i] = pTexdef[i].type;
			}
		}
	}

	// Attachment
	ModelAttachmentDef *pAttachment = (ModelAttachmentDef*)(m_pData+m_Header.ofsAttachments);
	if(m_Header.nAttachments)
	{
		for(uint32 i=0; i<m_Header.nAttachments; i++)
		{
			M2Attachment attach;
			attach.Init(pAttachment[i]);
			m_Attachment.push_back(attach);
		}
	}

	// Attachment Lookup
	if(m_Header.nAttachLookup)
	{
		int16 *pLookup = (int16*)(m_pData+m_Header.ofsAttachLookup);
		for(uint32 i=0; i<m_Header.nAttachLookup; i++)
		{
			m_AttachLookup[i] = pLookup[i];
		}
	}

	// Color
	if(m_Header.nColors) 
	{
		m_pColor = new M2Color[m_Header.nColors];
		if(m_pColor == NULL)	return;
		ModelColorDef *pColorDef = (ModelColorDef*)(m_pData+m_Header.ofsColors);
		for(uint32 i=0; i<m_Header.nColors; i++) 
			m_pColor[i].Init(m_pData, pColorDef[i], m_pGlobalSequences);
	}

	// Transparency
	if(m_Header.nTransparency)
	{
		m_pTransparency = new M2Transparency[m_Header.nTransparency];
		if(m_pTransparency==NULL)	return;
		ModelTransDef *pTransDef = (ModelTransDef*)(m_pData+m_Header.ofsTransparency);
		for(uint32 i=0; i<m_Header.nTransparency; i++) 
			m_pTransparency[i].Init(m_pData, pTransDef[i], m_pGlobalSequences);
	}

	// Sub Mesh
	ModelGeoset *pMesh = (ModelGeoset*)(m_pData+pView->ofsSub);
	m_bShowSubMesh = new bool[pView->nSub];
	if(m_bShowSubMesh == NULL)	return;
	for(size_t i=0; i<pView->nSub; i++) 
	{
		m_SubMesh.push_back(pMesh[i]);
		m_bShowSubMesh[i] = true;
		// just for test--------------------------------------
		int a = 0;
		//----------------------------------------------------
	}
	
	// Render Pass	ModelTexUnit *pTex = (ModelTexUnit*)(m_pData+pView->ofsTex);	ModelRenderFlags *pRenderFlag = (ModelRenderFlags*)(m_pData+m_Header.ofsTexFlags);
	uint16 *pTexlookup = (uint16*)(m_pData+m_Header.ofsTexLookup);	uint16 *pTexanimlookup = (uint16*)(m_pData+m_Header.ofsTexAnimLookup);	int16 *pTexunitlookup = (int16*)(m_pData+m_Header.ofsTexUnitLookup);	int16 *pTransLookup = (int16*)(m_pData+m_Header.ofsTransparencyLookup);	for(uint32 j=0; j<pView->nTex; j++)	{		M2RenderPass pass;
		pass.useTex2 = false;
		pass.useEnvMap = false;
		pass.m_bTrans = false;
		pass.m_bUnLight = false;
		pass.m_bNoZWrite = false;

		size_t geoset = pTex[j].op;	// 对应的Sub Mesh
		pass.m_SubMeshIndex = (int)geoset;

		pass.m_IndexStart = pMesh[geoset].istart;
		pass.m_IndexCount = pMesh[geoset].icount;
		pass.m_VertexStart = pMesh[geoset].vstart;
		pass.m_VertexCount = pMesh[geoset].vcount;

		pass.m_RenderOrder = pTex[j].order;
		pass.m_TextureIndex = pTexlookup[pTex[j].textureid];

		pass.m_bSwrap = (pTexdef[pTexlookup[pTex[j].textureid]].flags & 1) != 0;
		pass.m_bTwrap = (pTexdef[pTexlookup[pTex[j].textureid]].flags & 2) != 0;

		ModelRenderFlags &rf = pRenderFlag[pTex[j].flagsIndex];
		pass.m_BlendMode = rf.blend;
		pass.m_bCull = false;
		pass.m_bUnLight = (rf.flags & 0x01) != 0;
		pass.m_Color = pTex[j].colorIndex;
		pass.m_Opacity = pTransLookup[pTex[j].transid];
		pass.m_bNoZWrite = (pass.m_BlendMode>1) && !(rf.blend==4 && rf.flags==17);
		pass.m_bTrans = (pass.m_BlendMode>0) && (pass.m_Opacity>0);

		/*pass.useEnvMap = (pTexunitlookup[pTex[j].texunit] == -1) && ((rf.flags & 0x10) !=0) && rf.blend>2; // Use environmental reflection effects?

		if (pass.useEnvMap==true && useEnvMapping==false)
			pass.useEnvMap = false;

		*/
		
		pass.p = pMesh[geoset].v.z;
		
		// 纹理动画
		if(m_bAnimTextures)
		{
			if(pTex[j].flags & 15)
			{
				pass.m_Texanim = -1; // no texture animation
			} 
			else
			{
				pass.m_Texanim = pTexanimlookup[pTex[j].texanimid];
			}
		} 
		else
		{
			pass.m_Texanim = -1; // no texture animation
		}
		

		m_RenderPass.push_back(pass);	}	// transparent parts come later	std::sort(m_RenderPass.begin(), m_RenderPass.end());
}

//----------------------------------------------------
// 初始化动画
//----------------------------------------------------
void CM2Loader::InitAnimation(void)
{
	// 初始化骨骼
	if(m_bAnimBones)
	{
		ModelBoneDef *pBone = (ModelBoneDef*)(m_pData+m_Header.ofsBones);
		m_pBone = new M2Bone[m_Header.nBones];
		if(m_pBone == NULL)	return;
		for(uint32 i=0; i<m_Header.nBones; i++) 
		{
			ModelBoneDef &pB = pBone[i];
			m_pBone[i].Init(m_pData, pBone[i], m_pGlobalSequences);
		}

		// Skeletal Bones查找表
		int16 *pF = (int16*)(m_pData+m_Header.ofsF);
		for(uint32 i=0; i<m_Header.nF; i++)
		{
			m_BoneLookup[i] = pF[i];
		}
	}
	// particle systems
	if(m_Header.nParticleEmitters)
	{
		ModelParticleEmitterDef *pdef = (ModelParticleEmitterDef*)(m_pData+m_Header.ofsParticleEmitters);
		m_pParticle = new M2ParticleSystem[m_Header.nParticleEmitters];
		if(m_pParticle == NULL)	return;
		m_bHasParticle = true;
		for(uint32 i=0; i<m_Header.nParticleEmitters; i++)
		{
			m_pParticle[i].m_pModel = this;
			m_pParticle[i].Init(m_pData, pdef[i], m_pGlobalSequences);
		}
	}

	// 只使用第一个镜头
	if(m_Header.nCameras > 0) 
	{
		ModelCameraDef *pCamera = (ModelCameraDef*)(m_pData+m_Header.ofsCameras);
		m_Camera.Init(m_pData, pCamera[0], m_pGlobalSequences);
		m_bHasCamera = true;
	}
	// 动画组
	if(m_Header.nAnimations > 0) 
	{
		m_pAni = new ModelAnimation[m_Header.nAnimations];
		if(m_pAni == NULL)	return;
		memcpy(m_pAni, m_pData+m_Header.ofsAnimations, m_Header.nAnimations*sizeof(ModelAnimation));
		m_pAniController = new M2AniController(m_pAni);
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -