📄 m2loader.cpp
字号:
//--------------------------------------------------
// 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 + -