#include "Max.h"
#include "resource.h"
#include "export.h"
#include "istdplug.h"
#include "decomp.h"
#include "helpsys.h"
#include "buildver.h"
#include <plugapi.h>
#include <stdmat.h>
#include <mesh.h>
#include <vector>
#include <algorithm>
#include <modstack.h>
#include "ISkinCodes.h"
#include <iparamb2.h>
#include <iskin.h>
#include <d3dx9.h>
#include <Phyexp.h>
using namespace std;
bool isExportSelect;
TCHAR *GetString(int id)
{
static TCHAR buf[256];
if (hInstance)
return LoadString(hInstance, id, buf, sizeof(buf)) buf : NULL;
return NULL;
}
class d3export :public SceneExport
{
public:
int ExtCount();
const TCHAR *AuthorName();
const TCHAR * CopyrightMessage();
int DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts=FALSE, DWORD options=0);
const TCHAR*Ext(int n);
const TCHAR*LongDesc();//这些实现我都删了,这个很简单吧,根据你的需要自己写吧
const TCHAR*ShortDesc() ;
const TCHAR*OtherMessage1() ;
const TCHAR*OtherMessage2() ;
void ShowAbout(HWND hWnd);
unsigned int Version();
protected:
private:
};
DWORD meshOff=0;
DWORD boneOff=0;
DWORD animationOff=0;
bool isIncludeNormalData=true;
bool isIncludeVertexColor=0;
bool isIncludeTexCoord=0;
bool isOptimized=0;//是否优化
DWORD vertexNum=0;
DWORD faceNum=0;
DWORD materialNum=0;
vector<POSITION>vertPosVec;
vector<Point3>normalVec;
vector<DWORD>colorVec;
vector<TEXCOORD>texcoordVec;
vector<FACE>faceVec;
DWORD attributeSize=0;//=FACE
vector<DWORD>attributeBufferVec;
vector<MAT_TEX>materialVec;
//
DWORD g_boneNum;
vector<Bone_st>g_BoneList;
DWORD frameNum;
float inter;
vector<D3DXMATRIX>matrixList;
vector<NODE_MESH> meshVec;
vector<TCHAR*>texNameV;
void WriteFile(char*content)
{
FILE*pF=fopen( "D://log.txt","at");
fseek(pF,0,SEEK_END);
fwrite(content,sizeof(char),strlen(content),pF);
char end='/n';
fwrite( &end,1,1,pF);
fclose(pF);
}
};
class SceneEnumProc: public ITreeEnumProc
{
public:
int callback( INode *node );
};
int SceneEnumProc::callback(INode *node )
{
if((isExportSelect&& node->Selected()) == FALSE)
return TREE_CONTINUE;
if (node->IsHidden())
return TREE_CONTINUE;
//Object*pObject=node->GetObjectRef();
ObjectState pObjectState=node->EvalWorldState(0);
Object*pObject=pObjectState.obj;
TriObject*pTriObject=NULL;
Class_ID meshID=Class_ID(TRIOBJ_CLASS_ID,0);
if (pObject->SuperClassID()==GEOMOBJECT_CLASS_ID)
{
if (pObject- >CanConvertToType(meshID)&&pObject->IsRenderable())
{
pTriObject=(TriObject*)pObject- >ConvertToType(0,meshID);
meshVec.push_back(NODE_MESH(node, &pTriObject->mesh));
}
}
return TREE_CONTINUE;
}
void GetShortName(TCHAR*fileName,TCHAR*shortName)
{
TCHAR*dest=_tcsrchr(fileName,'//');
if (!dest)
{
dest=fileName;
}
else
{
dest++;
}
_tcscpy(shortName,dest);
}
void FillMat(Mtl*nodeMtl , MAT_TEX&theM)
{
MATERIAL& mat=theM.mat;
TCHAR*fileN=theM.texName;
ZeroMemory(&theM,sizeof(theM));
Texmap *tmap =nodeMtl->GetSubTexmap(ID_DI);
TCHAR*fileName=NULL;
if(tmap)
{
if (tmap- >ClassID() == Class_ID(BMTEX_CLASS_ID, 0))
{
BitmapTex*pBitMapT=(BitmapTex*)tmap;
if (pBitMapT)
{
fileName=pBitMapT- >GetMapName();
}
}
}
StdMat * stdM=(StdMat*)nodeMtl;
Color diff=stdM->GetDiffuse(0);//没要自发光
Color spe=stdM-> GetSpecular(0);
Color amb =stdM->GetAmbient(0);
float power=stdM->GetShinStr(0);
mat.Ambient=COLOR(amb.r,amb.g,amb.b);
mat.Diffuse=COLOR(diff.r,diff.g,diff.b);
mat.Specular=COLOR(spe.r,spe.g,spe.b);
mat.Power=power;
if(fileName)
{
texNameV.push_back(fileName);
GetShortName(fileName,fileN);
}
}
bool isMatIn(MAT_TEX&mt,int&index)
{
int mNum=(int)materialVec.size();
for (index=0;index <mNum;index++)
{
if (!_tcscmp(mt.texName,materialVec[index].texName))
{
//如果有相同的材质(以纹理文件作为标准)
return true;
}
}
return false;
}
void AddDefaultMtl( vector<MAT_TEX>&theM)
{
theM.push_back(MAT_TEX());
ZeroMemory(&theM[0],sizeof(MAT_TEX));
theM[0].mat.Diffuse=COLOR(0.7f,0.7f,0.7f,1.0f);
}
void GetIndexList(vector<MAT_TEX>theMat,vector<int>&intVec )
{
int tempSize=(int)theMat.size();
for (int i=0;i<tempSize;i++)
{
int index;
if (!isMatIn(theMat[i],index))
{
materialVec.push_back(theMat[i]);
}
intVec.push_back(index);
}
}
bool fEq(float a,float b)
{
return fabs(a-b)<0.00001f;
}
void AddExtV(DWORD vertexIn,DWORD faceIn,DWORD i,float&u,float&v,float newU,float newV,vector<ExtV>&meshExV)
{
if (fEq(u, -1.0f)&&fEq(v,-1.0f))
{
u=newU;
v=newV;
return;
}
if (fEq(u,newU)&&fEq(v,newV) )
{
return;
}
else
{
//增加一个顶点
ExtV ex(vertexIn,newU,newV);
vector <ExtV>::iterator ite=find(meshExV.begin(),meshExV.end(),ex);
if (ite==meshExV.end())
{//不存在这个元素
meshExV.push_back(ExtV(vertexIn,newU,newV,faceIn,i));
}
else
{
(*ite).fniV.push_back(FNI(faceIn,i));
}
return ;
}
}
void FillmeshUV(NODE_MESH &mesh_node,vector<TEXCOORD>&tempV,vector<ExtV>&extV)
{
int faceNum=mesh_node.pM->getNumFaces();
for (int i=0;i<faceNum;i++)
{
for (int j=0;j <3;j++)
{
DWORD vertexIndex=mesh_node.pM- >faces[i].getVert(j);
//tempV[vertexIndex]//要被输入的;
int tVerNum=mesh_node.pM- >numTVerts;
if (tVerNum >0)
{
DWORD tVertexIndex=mesh_node.pM- >tvFace[i].getTVert(j);
Point3 uvw=mesh_node.pM- >tVerts[tVertexIndex];
Matrix3 m;
m.IdentityMatrix();
m.Scale(Point3(1,-1,1));
m.Translate(Point3(0,1,0));
uvw=uvw*m;
//EXV ABOUT
float &tU=tempV[vertexIndex].u;
float &tV=tempV[vertexIndex].v;
AddExtV(vertexIndex,i,j,tU,tV,uvw.x,uvw.y,extV);
}
}
}
}
void boneProcess(NODE_MESH&nodeMesh,int meshVerNum,int beforeVN);
void NormalProcess(Mesh *ms,vector<Point3>&normalV )
{//我自己来生成发现MD
//此函数根据定点位置和面索引生成发现//基于MAX的发现计算
int vertN=ms->getNumVerts();
int faceN=ms->getNumFaces();
normalV.resize(vertN);
for (vector<Point3>::iterator ini=normalV.begin();ini!=normalV.end();ini++)
{
(*ini)=Point3(0.0f,0.0f,0.0f);
}
for (int i=0;i<faceN;i++)
{
Face &_face=ms->faces[i];
DWORD vI1=_face.v[0];
DWORD vI2=_face.v[1];
DWORD vI3=_face.v[2];
Point3 & firV=ms->verts[vI1];
Point3 & secV=ms->verts[vI2];
Point3 & thiV=ms->verts[vI3];
Point3 normal_=(secV-firV)^(thiV-firV);
normal_=normal_.Normalize();
normalV[vI1]+=normal_;
normalV[vI2]+=normal_;
normalV[vI3]+=normal_;
}
}
void ProcessExt(vector<ExtV>&ext,NODE_MESH&mesh_node,DWORD beforeV);
static void meshProcess(NODE_MESH mesh_node)
{
mylog.WriteFile("bone process");
//下一步是保存到全局里面
DWORD meshVertNum=mesh_node.pM->getNumVerts();
DWORD meshFaceNum=mesh_node.pM->getNumFaces();
if (meshFaceNum<=0||meshVertNum<=0)
{
return;
}
DWORD beforeVN=vertexNum;
DWORD beforeFN=faceNum;
Matrix3 mt=mesh_node.pN->GetObjectTM(0);
//mesh_node.pN->GetObjectTM()
for (DWORD i=0;i<meshVertNum;i++)
{
Point3 vPos=mesh_node.pM- >verts[i];
vPos=mt.PointTransform(vPos);//这段计算出世界位置
vertPosVec.push_back(POSITION(vPos.x,vPos.z,vPos.y));
//Z-Y互换MAX- >DX
}
///
vector<Point3>normalMeshV;
NormalProcess(mesh_node.pM,normalMeshV);
for(vector<Point3>::iterator it=normalMeshV.begin();it!=normalMeshV.end();it++)
{
(*it)=mt.VectorTransform(*it);
(*it)=Point3((*it).x,(*it).z,(*it).y);
(*it)=(*it).Normalize();
Point3 ss=(*it);
}
normalVec.insert(normalVec.end(),normalMeshV.begin(),normalMeshV.end());
/
for (DWORD j=0;j<meshFaceNum;j++)
{
Face &tFace=mesh_node.pM->faces[j];
faceVec.push_back(FACE((WORD)tFace.v[2]+vertexNum,(WORD)tFace.v[1]+vertexNum,(WORD)tFace.v[0]+vertexNum));
}
vertexNum+=meshVertNum;
faceNum+=meshFaceNum;
/
vector< MAT_TEX> theM;
bool isMuti=false;
if (isIncludeTexCoord)
{
Mtl*nodeMtl=mesh_node.pN- >GetMtl();
if (nodeMtl)
{
if (nodeMtl- >ClassID()==Class_ID(DMTL_CLASS_ID,0))
{
theM.push_back(MAT_TEX());
FillMat(nodeMtl,theM[0]);
}
else if (nodeMtl- >ClassID()==Class_ID(MULTI_CLASS_ID,0))
{
int numSub=nodeMtl- >NumSubMtls();
if (numSub >0)
{
isMuti=true;
for (int indexM=0;indexM <numSub;indexM++)
{
Mtl*subMtl=nodeMtl- >GetSubMtl(indexM);
if(subMtl- >ClassID()==Class_ID(DMTL_CLASS_ID,0))
{
theM.push_back(MAT_TEX());
FillMat(subMtl,theM[indexM]);
}
}
}
}
}
}
if (theM.size()==0)
{
AddDefaultMtl(theM);
}
vector<int>indexL;
GetIndexList(theM,indexL);
vector<DWORD>tempA(meshFaceNum);
if (theM.size()==1)
{
for (int er=0;er <meshFaceNum;er++)
{
tempA[er]=indexL[0];
}
}
else
{
for (int we=0;we <meshFaceNum;we++)
{
tempA[we]= indexL[mesh_node.pM- >getFaceMtlIndex(we)];
}
}
attributeBufferVec.insert(attributeBufferVec.end(),tempA.begin(),tempA.end());
//创建一个临时的TEXCORRD列表
vector<TEXCOORD>tempV;
for (int v=0;v<meshVertNum;v++)
{
tempV.push_back(TEXCOORD(-1.0f,-1.0f));
}
//填充这个列表
vector<ExtV>extV;
FillmeshUV(mesh_node,tempV,extV);
texcoordVec.insert(texcoordVec.end(),tempV.begin(),tempV.end());
//abcdefg
//EXTV便是分裂的点
///蒙皮信息
/*int _boneNum;
vector<Bone_st>boneL;
vector<INode*>boneInterL;*/
boneProcess(mesh_node,meshVertNum,beforeVN);
ProcessExt(extV,mesh_node,beforeVN);
}
void ProcessExt(vector<ExtV>&ext,NODE_MESH&mesh_node,DWORD beforeV)
{
int BoneNum=(int)g_BoneList.size();
int extN=(int)ext.size();
vertexNum+=extN;
int allFn=(int)faceVec.size();//现在所有的面数
int meshFn=mesh_node.pM->getNumFaces();//当前MESH面数
int beforeFN=allFn-meshFn;//之前面数;
for (int i=0;i<extN;i++)
{
DWORD orgIndex=beforeV+ext[i].meshVertexIndex;
Point3 pos=mesh_node.pM->verts[ ext[i].meshVertexIndex ];
int RealIndex=(int)vertPosVec.size();
vertPosVec.push_back(vertPosVec[orgIndex] );//顶点搞定
int fN=(int)ext[i].fniV.size();
for (int fI=0;fI <fN;fI++)
{
int FNN=beforeFN+ext[i].fniV[fI].faceIndex;
int p=2-ext[i].fniV[fI].i;
faceVec[FNN].i[p]=RealIndex;
//面索引搞定
}
if(isIncludeNormalData)
normalVec.push_back(normalVec[orgIndex]);
if(isIncludeVertexColor)
colorVec.push_back(colorVec[ orgIndex]) ;
if(isIncludeTexCoord)
texcoordVec.push_back( TEXCOORD(ext[i].u,ext[i].v) );
for (int boI=0;boI <BoneNum;boI++)
{//我认为是我的权重裂变出错了
int bInd=(int)g_BoneList.size()-BoneNum+boI;
vector <DWORD>& inI=g_BoneList[bInd].iniIndex;
vector <DWORD>::iterator iti=find(inI.begin(),inI.end(),orgIndex);
if (iti!= inI.end() )
{
DWORD locat=iti-inI.begin();
float weightt=g_BoneList[bInd].weight[locat];
g_BoneList[bInd].addOneVertex(RealIndex,weightt);
}
}
}
}
Modifier* GetMo(NODE_MESH&nodeMesh)
{
Object*pObj=nodeMesh.pN->GetObjectRef();
while (pObj->SuperClassID()==GEN_DERIVOB_CLASS_ID)
{
IDerivedObject *pDerObject = (IDerivedObject *)pObj;
int moNum=pDerObject- >NumModifiers();
for (int moIndex=0;moIndex <moNum;moIndex++)
{
Modifier*pMo=pDerObject- >GetModifier(moIndex);
if (pMo- >ClassID()==SKIN_CLASSID)
{
return pMo;
}
}
pObj=pDerObject- >GetObjRef();
}
return NULL;
}
void ProcessFrame(Interface *ip)
{
int BoneNum=(int)g_BoneList.size();
vector<Matrix3>boneInitML;
for (int i=0;i<BoneNum;i++)
{
Matrix3 initM=g_BoneList[i].pNode- >GetObjectTM(0);
initM.NoScale();
initM.Invert();
boneInitML.push_back(initM);
}
int tn=GetTicksPerFrame();
float interTime=TicksToSec(tn);
inter=interTime;
int startTick=ip->GetAnimRange().Start()/tn;
int endTick=ip->GetAnimRange().End()/tn;
frameNum=endTick-startTick+1;
for (int s=startTick;s<=endTick;s++)
{
for (int b=0;b <BoneNum;b++)
{
TimeValue t;
t=s*tn;
Matrix3 boneM= g_BoneList[b].pNode- >GetObjectTM(t);
boneM.NoScale();
Matrix3 finalM= boneInitML[b]*boneM;
finalM.NoScale();
Point3 transP= finalM.GetTrans();
Quat romate(finalM);
D3DXQUATERNION qua(romate.x,romate.z,romate.y,romate.w);
D3DXMATRIX romateMatrix;
D3DXMatrixRotationQuaternion( &romateMatrix,&qua);
romateMatrix._41=transP.x;
romateMatrix._43=transP.y;
romateMatrix._42=transP.z;
matrixList.push_back(romateMatrix);
}
}
}
bool isBone(INode*thisBone)
{
ObjectState pObs=thisBone->EvalWorldState(0);
if (pObs.obj->ClassID()==Class_ID(BONE_CLASS_ID,0))
{
return true;
}
if (pObs.obj->ClassID()==BONE_OBJ_CLASSID)
{
return true;
}
return false;
}
void AddBoneInfo(DWORD vertexIndex,float weight,INode*pNode)
{
Bone_st bst(pNode);
vector<Bone_st>::iterator loc=find(g_BoneList.begin(),g_BoneList.end(),bst);
if (loc==g_BoneList.end())
{
g_BoneList.push_back(bst);
g_BoneList[g_BoneList.size()-1].addOneVertex(vertexIndex,weight);
}
else
{
(*loc).addOneVertex(vertexIndex,weight);
}
}
Modifier* GetPSMo(NODE_MESH&nodeMesh)
{
INode*nodePtr=nodeMesh.pN;
Object* ObjectPtr = nodePtr->GetObjectRef();
if (!ObjectPtr) return NULL;
// Is derived object
while (ObjectPtr->SuperClassID() == GEN_DERIVOB_CLASS_ID && ObjectPtr)
{
// Yes - > Cast.
IDerivedObject *DerivedObjectPtr = (IDerivedObject *)(ObjectPtr);
// Iterate over all entries of the modifier stack.
int ModStackIndex = 0;
while (ModStackIndex < DerivedObjectPtr->NumModifiers())
{
// Get current modifier.
Modifier* ModifierPtr = DerivedObjectPtr- >GetModifier(ModStackIndex);
// Is this Physique
if (ModifierPtr->ClassID() == Class_ID(PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B))
{
// Yes - > Exit.
return ModifierPtr;
}
// Next modifier stack entry.
ModStackIndex++;
}
ObjectPtr = DerivedObjectPtr- >GetObjRef();
}
// Not found.
return NULL;
}
void boneProcessByPS(NODE_MESH&nodeMesh,int meshVerNum,int beforeVN)
{
Modifier*pM=GetPSMo(nodeMesh);
if (pM)
{
IPhysiqueExport *phyExport =(IPhysiqueExport*)pM- >GetInterface(I_PHYINTERFACE);
if (phyExport)
{
IPhyContextExport*pContextEx=phyExport- >GetContextInterface(nodeMesh.pN);
if (pContextEx)
{
pContextEx- >ConvertToRigid(TRUE);
for (int i=0;i <meshVerNum;i++)
{
IPhyVertexExport *vtxExport = pContextEx- >GetVertexInterface(i);
int vertexStyle=vtxExport- >GetVertexType();
if (vertexStyle==RIGID_TYPE)
{//只跟一个骨骼有联系
IPhyRigidVertex *vtxNoBlend = (IPhyRigidVertex *)vtxExport;
INode*pOneNode=vtxNoBlend- >GetNode();
float weight=1.0f;
AddBoneInfo(i+beforeVN,weight,pOneNode);
}
else if (vertexStyle==RIGID_BLENDED_TYPE)
{//混合型
IPhyBlendedRigidVertex *vtxBlend = (IPhyBlendedRigidVertex *)vtxExport;
int blendNum=vtxBlend- >GetNumberNodes();
for (int b=0;b <blendNum;b++)
{
INode*pN=vtxBlend- >GetNode(b);
float weight=vtxBlend- >GetWeight(b);
AddBoneInfo(i+beforeVN,weight,pN);
}
}
}
}
}
}
}
void boneProcessBySkin(NODE_MESH&nodeMesh,int meshVerNum,int beforeVN)
{
Modifier*pMo=GetMo(nodeMesh);
if (pMo)
{
ISkin*pSkin=(ISkin*)pMo- >GetInterface(I_SKIN);
if(pSkin)
{
ISkinContextData*pSkinData=pSkin- >GetContextInterface(nodeMesh.pN);
if (!pSkinData)
{
return;
}
for (int verIndex=0;verIndex <meshVerNum;verIndex++)
{
int BoneNum_infi_vert=pSkinData- >GetNumAssignedBones(verIndex);//得到顶点受到影响的骨骼数
for (int i=0;i <BoneNum_infi_vert;i++)
{
int boneIndex=pSkinData- >GetAssignedBone(verIndex,i);
INode*thisBone=pSkin- >GetBone(boneIndex);
float weight=0.0f;
if (isBone(thisBone))
{
weight=pSkinData- >GetBoneWeight(verIndex,i);
//向骨骼里列表里添加我们相应的顶点
AddBoneInfo(verIndex+beforeVN,weight,thisBone);
}
}
}
}
}
}
static void boneProcess(NODE_MESH &nodeMesh,int vn,int beforeVN)
{
boneProcessBySkin(nodeMesh,vn,beforeVN);
boneProcessByPS(nodeMesh,vn,beforeVN);
}
Interface*ip=NULL;
void CreateData()
{
if (meshVec.size()<=0)
{
return;
}
for_each(meshVec.begin(),meshVec.end(),meshProcess);
ProcessFrame(ip);
}
static INT_PTR CALLBACK ExportOptionsDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG:
CenterWindow(hDlg,GetParent(hDlg));
SetFocus(hDlg); // For some reason this was necessary. DS-3/4/96
CheckDlgButton(hDlg,IDC_CHECK1, TRUE);
return FALSE;
case WM_DESTROY:
return FALSE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
isIncludeTexCoord = (IsDlgButtonChecked(hDlg,IDC_CHECK1)>0);
EndDialog(hDlg, 1);
return TRUE;
case IDCANCEL:
EndDialog(hDlg, 0);
return TRUE;
}
}
return FALSE;
}
void Reset()
{
meshOff=0;
boneOff=0;
animationOff=0;
isIncludeNormalData=true;
isIncludeVertexColor=0;
isIncludeTexCoord=0;
isOptimized=0;//是否优化
vertexNum=0;
faceNum=0;
materialNum=0;
vertPosVec.resize(0);
normalVec.resize(0);
colorVec.resize(0);
texcoordVec.resize(0);
faceVec.resize(0);
attributeSize=0;//=FACE
attributeBufferVec.resize(0);
materialVec.resize(0);
g_BoneList.resize(0);
matrixList.resize(0);
meshVec.resize(0);
texNameV.resize(0);
ip=NULL;
}
int d3export::DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts, DWORD options)
{
Reset();
int result=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),i->GetMAXHWnd(),ExportOptionsDlgProc,0);
if (result<=0)
{
return 0;
}
mylog.WriteFile("DO export!");
ip=i;
isExportSelect=true;
SceneEnumProc sep;
ei->theScene->EnumTree(&sep);//这个方法会调用SEP类的CALLBACK//这样MESHVEC里面就保存了所要的MESH了
CreateData();
/*
我将写文件的的部分删掉了;你可以按照你的格式写自己的文件
数据就在我上面的全局变量里;
*/
return IMPEXP_SUCCESS;
}
HINSTANCE hInstance;
class d3exportDesc :public ClassDesc
{
public:
int IsPublic()
{
return true;
}
void * Create(BOOL loading=FALSE)
{
return new d3export();
}
const TCHAR* ClassName()
{
return GetString(IDS_CLASSNAME);
}
SClass_ID SuperClassID()
{
return SCENE_EXPORT_CLASS_ID;
}
Class_ID ClassID()
{
return Class_ID(0x59290607, 0x3e1b6d46);
}
const TCHAR* Category()
{
return _T( "");
}
};
d3exportDesc d3Desc;
BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved)
{
hInstance=hinstDLL;
return TRUE;
}