skinnedmeshexport.cpp
上传用户:qccn516
上传日期:2013-05-02
资源大小:3382k
文件大小:14k
源码类别:

游戏引擎

开发平台:

Visual C++

  1. /* Skinned Mesh Export plugin for 3DStudio
  2.  *
  3.  * Copyright (C) 2003-2004, Alexander Zaprjagaev <frustum@frustum.org>
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  */
  19. #include <vector>
  20. #include "max.h"
  21. #include "iparamm2.h"
  22. #include "modstack.h"
  23. #include "iskin.h"
  24. #pragma comment(lib, "core.lib")
  25. #pragma comment(lib, "maxutil.lib")
  26. #pragma comment(lib, "geom.lib")
  27. #pragma comment(lib, "mesh.lib")
  28. /*****************************************************************************/
  29. /*                                                                           */
  30. /* Mesh Enum Proc                                                            */
  31. /*                                                                           */
  32. /*****************************************************************************/
  33. class SkinnedMeshEnumProc : public ITreeEnumProc {
  34. public:
  35. SkinnedMeshEnumProc(const char *name,IScene *scene,Interface *i,DWORD options);
  36. ~SkinnedMeshEnumProc() { }
  37. int callback(INode *node);
  38. void export(FILE *file);
  39. Interface *inf;
  40. int selected;
  41. std::vector<INode*> bones;
  42. std::vector<INode*> surfaces;
  43. std::vector<Modifier*> modifiers;
  44. int total_vertex;
  45. int total_triangles;
  46. enum {
  47. MAX_WEIGHTS = 32,
  48. };
  49. struct Weight {
  50. int bone;
  51. float weight;
  52. Point3 xyz;
  53. Point3 normal;
  54. };
  55. struct Vertex {
  56. Point3 xyz;
  57. Point3 normal;
  58. Point3 texcoord;
  59. int num_weights;
  60. Weight weights[MAX_WEIGHTS];
  61. int flag;
  62. };
  63. struct Triangle {
  64. int v[3];
  65. };
  66. };
  67. SkinnedMeshEnumProc::SkinnedMeshEnumProc(const char *name,IScene *scene,Interface *i,DWORD options) {
  68. FILE *file = fopen(name,"wb");
  69. if(!file) {
  70. char error[1024];
  71. sprintf(error,"error create "%s" file",name);
  72. MessageBox(NULL,error,"Skinned Mesh Export error",MB_OK);
  73. return;
  74. }
  75. inf = i;
  76. selected = (options & SCENE_EXPORT_SELECTED) ? TRUE : FALSE;
  77. total_vertex = 0;
  78. total_triangles = 0;
  79. scene->EnumTree(this);
  80. export(file);
  81. fclose(file);
  82. char buffer[1024];
  83. sprintf(buffer,"OKnbones %dnsurfaces %dnvertexes %dntriangles %dn",bones.size(),surfaces.size(),total_vertex,total_triangles);
  84. MessageBox(NULL,buffer,"Skinned Mesh Export",MB_OK);
  85. }
  86. /*
  87.  */
  88. int SkinnedMeshEnumProc::callback(INode *node) {
  89. if(selected && node->Selected() == FALSE) return TREE_CONTINUE;
  90. Object *obj = node->GetObjectRef();
  91. if(!obj) return TREE_CONTINUE;
  92. if(obj->SuperClassID() != GEN_DERIVOB_CLASS_ID) return TREE_CONTINUE;
  93. IDerivedObject *dobj = static_cast<IDerivedObject*>(obj);
  94. for(int i = 0; i < dobj->NumModifiers(); i++) {
  95. Modifier *modifier = dobj->GetModifier(i);
  96. if(modifier->ClassID() == SKIN_CLASSID) {
  97. surfaces.push_back(node);
  98. modifiers.push_back(modifier);
  99. return TREE_CONTINUE;
  100. }
  101. }
  102. return TREE_CONTINUE;
  103. }
  104. /*
  105.  */
  106. void SkinnedMeshEnumProc::export(FILE *file) {
  107. // find all bones
  108. for(int i = 0; i < (int)modifiers.size(); i++) {
  109. ISkin *skin = (ISkin*)modifiers[i]->GetInterface(I_SKIN);
  110. if(skin == NULL) {
  111. MessageBox(NULL,"skin is NULL","Skinned Mesh Export error",MB_OK);
  112. return;
  113. }
  114. for(int i = 0; i < skin->GetNumBones(); i++) {
  115. INode *bone = skin->GetBone(i);
  116. int j;
  117. for(j = 0; j < (int)bones.size(); j++) if(bones[j] == bone) break; // it`s very slowly, but works :)
  118. if(j != bones.size()) continue;
  119. bones.push_back(bone);
  120. }
  121. }
  122. // export bones
  123. fprintf(file,"bones %d {n",bones.size());
  124. for(int i = 0; i < (int)bones.size(); i++) {
  125. fprintf(file,"t"%s" ",bones[i]->GetName());
  126. INode *parent = bones[i]->GetParentNode();
  127. int j;
  128. for(j = 0; j < (int)bones.size(); j++) if(bones[j] == parent) break;
  129. if(j == bones.size()) fprintf(file,"-1n");
  130. else fprintf(file,"%dn",j);
  131. }
  132. fprintf(file,"}n");
  133. // export surfaces
  134. for(int i = 0; i < (int)surfaces.size(); i++) {
  135. Object *obj = surfaces[i]->EvalWorldState(inf->GetTime()).obj;
  136. if(obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID,0)) == 0) continue;
  137. TriObject *tri = (TriObject*)obj->ConvertToType(inf->GetTime(),Class_ID(TRIOBJ_CLASS_ID,0));
  138. Mesh* mesh = &tri->GetMesh();
  139. ISkin *skin = (ISkin*)modifiers[i]->GetInterface(I_SKIN);
  140. ISkinContextData *skin_data = skin->GetContextInterface(surfaces[i]);
  141. mesh->buildNormals();
  142. Matrix3 transform = surfaces[i]->GetObjTMAfterWSM(inf->GetTime());
  143. Matrix3 rotate = transform;
  144. rotate.NoTrans();
  145. rotate.NoScale();
  146. // create geometry
  147. int num_vertex = mesh->numVerts;
  148. int num_triangles = mesh->numFaces;
  149. Vertex *vertex = new Vertex[num_triangles * 3];
  150. int *vertex_to_verts = new int[num_triangles * 3];
  151. Triangle *triangles = new Triangle[num_triangles];
  152. for(int j = 0; j < num_triangles * 3; j++) vertex_to_verts[j] = -1;
  153. // vertexes and normals
  154. for(int j = 0; j < num_vertex; j++) vertex[j].flag = 0;
  155. int start_num_vertex = num_vertex;
  156. for(int j = 0; j < num_triangles; j++) {
  157. Face *f = &mesh->faces[j];
  158. for(int k = 0; k < 3; k++) {
  159. Vertex v;
  160. // xyz
  161. v.xyz = transform * mesh->verts[f->v[k]];
  162. // normal
  163. RVertex *rv = mesh->getRVertPtr(f->v[k]);
  164. int num_normals;
  165. if(rv->rFlags & SPECIFIED_NORMAL) v.normal = rotate * rv->rn.getNormal();
  166. else if((num_normals = rv->rFlags & NORCT_MASK) && f->smGroup) {
  167. if(num_normals == 1) v.normal = rotate * rv->rn.getNormal();
  168. else for(int l = 0; l < num_normals; l++) {
  169. if(rv->ern[l].getSmGroup() & f->smGroup) v.normal = rotate * rv->ern[l].getNormal();
  170. }
  171. } else v.normal = rotate * mesh->getFaceNormal(j);
  172. // texture coords
  173. v.texcoord = Point3(0,0,0);
  174. v.num_weights = 0;
  175. v.flag = 1;
  176. // add vertex
  177. if(vertex[f->v[k]].flag == 0) { // new vertex
  178. vertex[f->v[k]] = v;
  179. vertex_to_verts[f->v[k]] = f->v[k];
  180. triangles[j].v[k] = f->v[k];
  181. } else {
  182. if(vertex[f->v[k]].normal == v.normal) { // same normals
  183. triangles[j].v[k] = f->v[k];
  184. } else { // different normals
  185. int l;
  186. for(l = start_num_vertex; l < num_vertex; l++) { // try to find same vertex
  187. if(vertex[l].xyz == v.xyz && vertex[l].normal == v.normal) break;
  188. }
  189. if(l == num_vertex) { // add new vertex
  190. vertex[num_vertex] = v;
  191. vertex_to_verts[num_vertex] = f->v[k];
  192. triangles[j].v[k] = num_vertex++;
  193. } else {
  194. triangles[j].v[k] = l;
  195. }
  196. }
  197. }
  198. }
  199. }
  200. // texture coords
  201. if(mesh->numTVerts) {
  202. for(int j = 0; j < num_vertex; j++) vertex[j].flag = 0;
  203. start_num_vertex = num_vertex;
  204. for(int j = 0; j < num_triangles; j++) {
  205. TVFace *t = &mesh->tvFace[j];
  206. for(int k = 0; k < 3; k++) {
  207. Vertex *v = &vertex[triangles[j].v[k]];
  208. Point3 texcoord = mesh->tVerts[t->t[k]];
  209. texcoord.y = 1.0f - texcoord.y;
  210. if(v->flag == 0) { // new texture coord
  211. v->texcoord = texcoord;
  212. v->flag = 1;
  213. } else {
  214. if(v->texcoord != texcoord) { // different texture coords
  215. int l;
  216. for(l = start_num_vertex; l < num_vertex; l++) { // try to find same vertex
  217. if(vertex[l].xyz == v->xyz && vertex[l].normal == v->normal && vertex[l].texcoord == texcoord) break;
  218. }
  219. if(l == num_vertex) { // add new vertex
  220. vertex[num_vertex] = *v;
  221. vertex[num_vertex].texcoord = texcoord;
  222. vertex_to_verts[num_vertex] = vertex_to_verts[triangles[j].v[k]];
  223. triangles[j].v[k] = num_vertex++;
  224. } else {
  225. triangles[j].v[k] = l;
  226. }
  227. }
  228. }
  229. }
  230. }
  231. }
  232. if(mesh->numVerts > skin_data->GetNumPoints()) {
  233. char error[1024];
  234. sprintf(error,"bad surface "%s"nnnumVerts is %dnskin num points is %d",
  235. surfaces[i]->GetName(),mesh->numVerts,skin_data->GetNumPoints());
  236. MessageBox(NULL,error,"Skinned Mesh Export error",MB_OK);
  237. continue;
  238. }
  239. // weights
  240. for(int j = 0; j < num_vertex; j++) {
  241. int v = vertex_to_verts[j];
  242. if(v == -1) {
  243. char error[1024];
  244. sprintf(error,"bad surface "%s"",surfaces[i]->GetName());
  245. MessageBox(NULL,error,"Skinned Mesh Export error",MB_OK);
  246. break;
  247. }
  248. vertex[j].num_weights = skin_data->GetNumAssignedBones(v);
  249. for(int k = 0; k < vertex[j].num_weights; k++) {
  250. INode *bone = skin->GetBone(skin_data->GetAssignedBone(v,k));
  251. // find number of the bone
  252. int l;
  253. for(l = 0; l < (int)bones.size(); l++) if(bones[l] == bone) break;
  254. vertex[j].weights[k].bone = l;
  255. // weights of the bone
  256. vertex[j].weights[k].weight = skin_data->GetBoneWeight(v,k);
  257. // xyz and normal
  258. Matrix3 transform = bone->GetObjTMAfterWSM(inf->GetTime());
  259. if(transform.Parity()) {
  260. transform.Invert();
  261. Matrix3 m;
  262. m = transform;
  263. transform.Zero();
  264. transform -= m;
  265. } else {
  266. transform.Invert();
  267. }
  268. Matrix3 rotate = transform;
  269. rotate.Orthogonalize();
  270. rotate.NoScale();
  271. rotate.NoTrans();
  272. vertex[j].weights[k].xyz = transform * vertex[j].xyz;
  273. vertex[j].weights[k].normal = rotate * vertex[j].normal;
  274. }
  275. }
  276. // mirrored traingles
  277. if(transform.Parity()) {
  278. for(int j = 0; j < num_triangles; j++) {
  279. int v;
  280. v = triangles[j].v[0];
  281. triangles[j].v[0] = triangles[j].v[2];
  282. triangles[j].v[2] = v;
  283. }
  284. }
  285. // new surface
  286. fprintf(file,"surface "%s" {ntvertex %d {n",surfaces[i]->GetName(),num_vertex);
  287. for(int j = 0; j < num_vertex; j++) {
  288. fprintf(file,"tt%f %fnttweights %d {n",vertex[j].texcoord.x,vertex[j].texcoord.y,vertex[j].num_weights);
  289. for(int k = 0; k < vertex[j].num_weights; k++) {
  290. Weight *w = &vertex[j].weights[k];
  291. fprintf(file,"ttt%d %f %f %f %f %f %f %fn",w->bone,w->weight,w->xyz.x,w->xyz.y,w->xyz.z,w->normal.x,w->normal.y,w->normal.z);
  292. }
  293. fprintf(file,"tt}n");
  294. }
  295. fprintf(file,"t}nttriangles %d {n",num_triangles);
  296. for(int j = 0; j < num_triangles; j++) {
  297. fprintf(file,"tt%d %d %dn",triangles[j].v[0],triangles[j].v[1],triangles[j].v[2]);
  298. }
  299. fprintf(file,"t}n}n");
  300. delete triangles;
  301. delete vertex_to_verts;
  302. delete vertex;
  303. if(obj != tri) delete tri;
  304. total_vertex += num_vertex;
  305. total_triangles += num_triangles;
  306. }
  307. // export animation
  308. Interval interval = inf->GetAnimRange();
  309. int start_time = interval.Start();
  310. int end_time = interval.End();
  311. int ticks_per_frame = GetTicksPerFrame();
  312. fprintf(file,"animation %d {n",(end_time - start_time) / ticks_per_frame);
  313. for(int time = start_time; time < end_time; time += ticks_per_frame) {
  314. for(int i = 0; i < (int)bones.size(); i++) {
  315. INode *bone = bones[i];
  316. Matrix3 transform = bone->GetObjTMAfterWSM(time);
  317. Point3 xyz = Point3(0,0,0) * transform;
  318. transform.Orthogonalize();
  319. transform.NoScale();
  320. transform.NoTrans();
  321. transform.Invert();
  322. Quat rot(transform);
  323. /*
  324. Point3 axis;
  325. float ang;
  326. AngAxisFromQ(rot,&ang,axis);
  327. if(fabs(fabs(rot.x) - 1.0) < 1e-6) {
  328. axis.x = 0;
  329. axis.y = 1;
  330. }
  331. rot = rot * QFromAngAxis(PI,axis);
  332. */
  333. fprintf(file,"t%f %f %f %f %f %f %fn",xyz.x,xyz.y,xyz.z,rot.x,rot.y,rot.z,rot.w);
  334. }
  335. }
  336. fprintf(file,"}n");
  337. }
  338. /*****************************************************************************/
  339. /*                                                                           */
  340. /* Skinned Mesh Export                                                       */
  341. /*                                                                           */
  342. /*****************************************************************************/
  343. class SkinnedMeshExport : public SceneExport {
  344. public:
  345. SkinnedMeshExport() { }
  346. ~SkinnedMeshExport() { }
  347. int ExtCount() { return 1; }
  348. const TCHAR *Ext(int i) { return (i == 0) ? "txt" : ""; }
  349. const TCHAR *LongDesc() { return "Skinned Mesh Export plugin http://frustum.org"; }
  350. const TCHAR *ShortDesc() { return "Skinned Mesh Export"; }
  351. const TCHAR *AuthorName() { return "Alexander Zaprjagaev"; }
  352. const TCHAR *CopyrightMessage() { return ""; }
  353. const TCHAR *OtherMessage1() { return ""; }
  354. const TCHAR *OtherMessage2() { return ""; }
  355. unsigned int Version() { return 100; }
  356. void ShowAbout(HWND hWnd) { MessageBox(hWnd,"Skinned Mesh Export pluginnhttp://frustum.org","about",MB_OK); }
  357. BOOL SupportsOptions(int ext,DWORD options) { return (options == SCENE_EXPORT_SELECTED) ? TRUE : FALSE; }
  358. int DoExport(const TCHAR *name,ExpInterface *ei,Interface *i,BOOL suppressPrompts = FALSE,DWORD options = 0);
  359. };
  360. int SkinnedMeshExport::DoExport(const TCHAR *name,ExpInterface *ei,Interface *i,BOOL suppressPrompts,DWORD options) {
  361. SkinnedMeshEnumProc smesh(name,ei->theScene,i,options);
  362. return 1;
  363. }
  364. /*****************************************************************************/
  365. /*                                                                           */
  366. /* DllMain                                                                   */
  367. /*                                                                           */
  368. /*****************************************************************************/
  369. HINSTANCE hInstance;
  370. int controlsInit = FALSE;
  371. BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved) {
  372. hInstance = hinstDLL;
  373. if(!controlsInit) {
  374. controlsInit = TRUE;
  375. InitCustomControls(hInstance);
  376. InitCommonControls();
  377. }
  378. return TRUE;
  379. }
  380. class SkinnedMeshClassDesc : public ClassDesc {
  381. public:
  382. int IsPublic() { return 1; }
  383. void *Create(BOOL loading = FALSE) { return new SkinnedMeshExport; }
  384. const TCHAR *ClassName() { return "Skinned Mesh Export"; }
  385. SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; }
  386. Class_ID ClassID() { return Class_ID(0xdeadbeef,0x7b5a93eb); }
  387. const TCHAR *Category() { return ""; }
  388. };
  389. static SkinnedMeshClassDesc SkinnedMeshDesc;
  390. __declspec(dllexport) const TCHAR *LibDescription() {
  391. return "Skinned Mesh Export Plugin";
  392. }
  393. __declspec(dllexport) int LibNumberClasses() {
  394. return 1;
  395. }
  396. __declspec(dllexport) ClassDesc *LibClassDesc(int i) {
  397. return (i == 0) ? &SkinnedMeshDesc : 0;
  398. }
  399. __declspec(dllexport) ULONG LibVersion() {
  400. return VERSION_3DSMAX;
  401. }
  402. __declspec(dllexport )ULONG CanAutoDefer() {
  403. return 1;
  404. }