goat3d

view exporters/maxgoat/src/maxgoat.cc @ 68:8ecaf9cd3ce7

progress on the exporter
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 20 Apr 2014 12:43:26 +0300
parents 3751aabbc5b3
children 66cd8266f078
line source
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <ctype.h>
5 #include <errno.h>
6 #include <map>
7 #include <vector>
8 #include <windows.h>
9 #include <shlobj.h>
10 #include "max.h"
11 #include "impexp.h" // SceneExport
12 #include "iparamb2.h" // ClassDesc2
13 #include "plugapi.h"
14 #include "IGame.h"
15 #include "IGameExport.h"
16 #include "IGameControl.h"
17 #include "IConversionmanager.h"
18 #include "goat3d.h"
19 #include "config.h"
20 #include "logger.h"
21 #include "resource.h"
24 #pragma comment (lib, "core.lib")
25 #pragma comment (lib, "geom.lib")
26 #pragma comment (lib, "gfx.lib")
27 #pragma comment (lib, "mesh.lib")
28 #pragma comment (lib, "maxutil.lib")
29 #pragma comment (lib, "maxscrpt.lib")
30 #pragma comment (lib, "paramblk2.lib")
31 #pragma comment (lib, "msxml2.lib")
32 #pragma comment (lib, "igame.lib")
33 #pragma comment (lib, "comctl32.lib")
36 #define COPYRIGHT \
37 L"Copyright 2014 (C) John Tsiombikas - GNU General Public License v3, see COPYING for details."
38 #define VERSION(major, minor) \
39 ((major) * 100 + ((minor) < 10 ? (minor) * 10 : (minor)))
41 static INT_PTR CALLBACK scene_gui_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam);
42 static INT_PTR CALLBACK anim_gui_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam);
43 static void get_position_keys(IGameControl *ctrl, goat3d_node *node);
44 static void get_xyz_position_keys(IGameControl *ctrl, goat3d_node *node);
45 static void get_rotation_keys(IGameControl *ctrl, goat3d_node *node);
46 static void get_euler_keys(IGameControl *ctrl, goat3d_node *node);
47 static void get_scaling_keys(IGameControl *ctrl, goat3d_node *node);
48 static const char *max_string(const MCHAR *wstr);
50 HINSTANCE hinst;
52 class GoatExporter : public SceneExport {
53 private:
54 std::map<IGameMaterial*, goat3d_material*> mtlmap;
55 std::map<IGameNode*, goat3d_node*> nodemap;
57 public:
58 IGameScene *igame;
60 int DoExport(const MCHAR *name, ExpInterface *eiface, Interface *iface, BOOL silent = FALSE, DWORD opt = 0);
62 void process_materials(goat3d *goat);
64 void process_node(goat3d *goat, goat3d_node *parent, IGameNode *maxnode);
66 void process_mesh(goat3d *goat, goat3d_mesh *mesh, IGameObject *maxobj);
67 void process_light(goat3d *goat, goat3d_light *light, IGameObject *maxobj);
68 void process_camera(goat3d *goat, goat3d_camera *cam, IGameObject *maxobj);
71 int ExtCount() { return 1; }
72 const TCHAR *Ext(int n) { return L"goatsce"; }
73 const TCHAR *LongDesc() { return L"Goat3D scene file"; }
74 const TCHAR *ShortDesc() { return L"Goat3D"; }
75 const TCHAR *AuthorName() { return L"John Tsiombikas"; }
76 const TCHAR *CopyrightMessage() { return COPYRIGHT; }
77 const TCHAR *OtherMessage1() { return L"other1"; }
78 const TCHAR *OtherMessage2() { return L"other2"; }
79 unsigned int Version() { return VERSION(VER_MAJOR, VER_MINOR); }
80 void ShowAbout(HWND win) { MessageBoxA(win, "Goat3D exporter plugin", "About this plugin", 0); }
81 };
83 class GoatAnimExporter : public GoatExporter {
84 private:
85 public:
86 int DoExport(const MCHAR *name, ExpInterface *eiface, Interface *iface, BOOL silent = FALSE, DWORD opt = 0);
88 const TCHAR *Ext(int n) { return L"goatanm"; }
89 const TCHAR *LongDesc() { return L"Goat3D animation file"; }
90 };
93 // ---- GoatExporter implementation ----
95 int GoatExporter::DoExport(const MCHAR *name, ExpInterface *eiface, Interface *iface,
96 BOOL non_interactive, DWORD opt)
97 {
98 if(!DialogBox(hinst, MAKEINTRESOURCE(IDD_GOAT_SCE), 0, scene_gui_handler)) {
99 return IMPEXP_CANCEL;
100 }
102 mtlmap.clear();
103 nodemap.clear();
105 char fname[512];
106 wcstombs(fname, name, sizeof fname - 1);
107 for(int i=0; fname[i]; i++) {
108 fname[i] = tolower(fname[i]);
109 }
111 maxlog("Exporting Goat3D Scene (text) file: %s\n", fname);
112 if(!(igame = GetIGameInterface())) {
113 maxlog("failed to get the igame interface\n");
114 return IMPEXP_FAIL;
115 }
116 IGameConversionManager *cm = GetConversionManager();
117 cm->SetCoordSystem(IGameConversionManager::IGAME_OGL);
118 igame->InitialiseIGame();
120 goat3d *goat = goat3d_create();
122 process_materials(goat);
124 // process all nodes
125 for(int i=0; i<igame->GetTopLevelNodeCount(); i++) {
126 IGameNode *node = igame->GetTopLevelNode(i);
127 process_node(goat, 0, node);
128 }
130 if(goat3d_save(goat, fname) == -1) {
131 goat3d_free(goat);
132 return IMPEXP_FAIL;
133 }
135 goat3d_free(goat);
136 return IMPEXP_SUCCESS;
137 }
139 void GoatExporter::process_materials(goat3d *goat)
140 {
141 IGameProperty *prop;
143 int num_mtl = igame->GetRootMaterialCount();
144 for(int i=0; i<num_mtl; i++) {
145 IGameMaterial *maxmtl = igame->GetRootMaterial(i);
146 if(maxmtl) {
147 goat3d_material *mtl = goat3d_create_mtl();
149 const char *name = max_string(maxmtl->GetMaterialName());
150 if(name) {
151 goat3d_set_mtl_name(mtl, name);
152 }
154 // diffuse
155 if((prop = maxmtl->GetDiffuseData())) {
156 Point3 diffuse(1, 1, 1);
157 prop->GetPropertyValue(diffuse);
158 goat3d_set_mtl_attrib3f(mtl, GOAT3D_MAT_ATTR_DIFFUSE, diffuse[0],
159 diffuse[1], diffuse[2]);
160 }
161 // specular
162 if((prop = maxmtl->GetSpecularData())) {
163 Point3 specular(0, 0, 0);
164 prop->GetPropertyValue(specular);
166 float sstr = 1.0;
167 if((prop = maxmtl->GetSpecularLevelData())) {
168 prop->GetPropertyValue(sstr);
169 }
170 goat3d_set_mtl_attrib3f(mtl, GOAT3D_MAT_ATTR_SPECULAR, specular[0] * sstr,
171 specular[1] * sstr, specular[2] * sstr);
172 }
173 // shininess
174 if((prop = maxmtl->GetGlossinessData())) {
175 float shin;
176 prop->GetPropertyValue(shin);
177 goat3d_set_mtl_attrib1f(mtl, GOAT3D_MAT_ATTR_SHININESS, shin * 100.0);
178 }
180 // textures
181 for(int j=0; j<maxmtl->GetNumberOfTextureMaps(); j++) {
182 IGameTextureMap *tex = maxmtl->GetIGameTextureMap(j);
184 const char *fname = max_string(tex->GetBitmapFileName());
185 if(!fname) {
186 continue;
187 }
189 int slot = tex->GetStdMapSlot();
190 switch(slot) {
191 case ID_DI: // diffuse
192 goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_DIFFUSE, fname);
193 break;
195 case ID_SP:
196 case ID_SS:
197 goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_SPECULAR, fname);
198 break;
200 case ID_SH:
201 goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_SHININESS, fname);
202 break;
204 case ID_BU:
205 goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_NORMAL, fname);
206 break;
208 case ID_RL:
209 goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_REFLECTION, fname);
210 break;
212 case ID_RR:
213 goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_TRANSMISSION, fname);
214 break;
216 default:
217 break;
218 }
219 }
221 goat3d_add_mtl(goat, mtl);
222 mtlmap[maxmtl] = mtl;
223 }
224 }
225 }
227 void GoatExporter::process_node(goat3d *goat, goat3d_node *parent, IGameNode *maxnode)
228 {
229 goat3d_node *node = goat3d_create_node();
230 goat3d_add_node(goat, node);
232 if(parent) {
233 goat3d_add_node_child(parent, node);
234 }
236 const char *name = max_string(maxnode->GetName());
237 if(name) {
238 goat3d_set_node_name(node, name);
239 }
241 // no animation yet, just get the static PRS
242 GMatrix maxmatrix = maxnode->GetObjectTM();
243 Point3 trans = maxmatrix.Translation();
244 Quat rot = maxmatrix.Rotation();
245 Point3 scale = maxmatrix.Scaling();
247 goat3d_set_node_position(node, trans.x, trans.y, trans.z, 0);
248 goat3d_set_node_rotation(node, rot.x, rot.y, rot.z, rot.w, 0);
249 goat3d_set_node_scaling(node, scale.x, scale.y, scale.z, 0);
251 IGameObject *maxobj = maxnode->GetIGameObject();
252 IGameObject::ObjectTypes type = maxobj->GetIGameType();
254 switch(type) {
255 case IGameObject::IGAME_MESH:
256 {
257 goat3d_mesh *mesh = goat3d_create_mesh();
258 if(name) goat3d_set_mesh_name(mesh, name);
259 goat3d_set_node_object(node, GOAT3D_NODE_MESH, mesh);
261 // get the node material and assign it to the mesh
262 IGameMaterial *maxmtl = maxnode->GetNodeMaterial();
263 goat3d_material *mtl = mtlmap[maxmtl];
264 if(mtl) {
265 goat3d_set_mesh_mtl(mesh, mtl);
266 }
268 process_mesh(goat, mesh, maxobj);
269 goat3d_add_mesh(goat, mesh);
270 }
271 break;
273 case IGameObject::IGAME_LIGHT:
274 {
275 goat3d_light *light = goat3d_create_light();
276 //if(name) goat3d_set_light_name(light, name);
277 goat3d_set_node_object(node, GOAT3D_NODE_LIGHT, light);
279 process_light(goat, light, maxobj);
280 goat3d_add_light(goat, light);
281 }
282 break;
284 case IGameObject::IGAME_CAMERA:
285 {
286 goat3d_camera *cam = goat3d_create_camera();
287 //if(name) goat3d_set_camera_name(camera, name);
288 goat3d_set_node_object(node, GOAT3D_NODE_CAMERA, cam);
290 process_camera(goat, cam, maxobj);
291 goat3d_add_camera(goat, cam);
292 }
293 break;
295 default:
296 // otherwise don't assign an object, essentially treating it as a null node
297 break;
298 }
300 // grab the animation data
301 IGameControl *ctrl = maxnode->GetIGameControl();
303 // TODO sample keys if requested
305 if(ctrl->IsAnimated(IGAME_POS) || ctrl->IsAnimated(IGAME_POS_X) ||
306 ctrl->IsAnimated(IGAME_POS_Y) || ctrl->IsAnimated(IGAME_POS_Z)) {
307 get_position_keys(ctrl, node);
308 }
309 if(ctrl->IsAnimated(IGAME_ROT) || ctrl->IsAnimated(IGAME_EULER_X) ||
310 ctrl->IsAnimated(IGAME_EULER_Y) || ctrl->IsAnimated(IGAME_EULER_Z)) {
311 get_rotation_keys(ctrl, node);
312 }
313 if(ctrl->IsAnimated(IGAME_SCALE)) {
314 get_scaling_keys(ctrl, node);
315 }
317 for(int i=0; i<maxnode->GetChildCount(); i++) {
318 process_node(goat, node, maxnode->GetNodeChild(i));
319 }
320 }
322 #define KEY_TIME(key) ((long)(TicksToSec(key.t) * 1000.0))
324 static void get_position_keys(IGameControl *ctrl, goat3d_node *node)
325 {
326 const char *nodename = goat3d_get_node_name(node);
327 IGameKeyTab keys;
329 if(ctrl->GetLinearKeys(keys, IGAME_POS)) {
330 maxlog("node %s: getting %d linear position keys\n", nodename, keys.Count());
331 for(int i=0; i<keys.Count(); i++) {
332 Point3 p = keys[i].linearKey.pval;
333 goat3d_set_node_position(node, p.x, p.y, p.z, KEY_TIME(keys[i]));
334 }
335 } else if(ctrl->GetBezierKeys(keys, IGAME_POS)) {
336 maxlog("node %s: getting %d bezier position keys\n", nodename, keys.Count());
337 for(int i=0; i<keys.Count(); i++) {
338 Point3 p = keys[i].bezierKey.pval;
339 goat3d_set_node_position(node, p.x, p.y, p.z, KEY_TIME(keys[i]));
340 }
341 } else if(ctrl->GetTCBKeys(keys, IGAME_POS)) {
342 maxlog("node %s: getting %d tcb position keys\n", nodename, keys.Count());
343 for(int i=0; i<keys.Count(); i++) {
344 Point3 p = keys[i].tcbKey.pval;
345 goat3d_set_node_position(node, p.x, p.y, p.z, KEY_TIME(keys[i]));
346 }
347 } else {
348 get_xyz_position_keys(ctrl, node);
349 }
350 }
352 static void get_xyz_position_keys(IGameControl *ctrl, goat3d_node *node)
353 {
354 const char *nodename = goat3d_get_node_name(node);
355 IGameKeyTab keys;
356 IGameControlType postype[] = {IGAME_POS_X, IGAME_POS_Y, IGAME_POS_Z};
357 std::map<long, Point3> pos;
359 for(int i=0; i<3; i++) {
360 if(ctrl->GetLinearKeys(keys, postype[i])) {
361 maxlog("node %s: getting %d linear position %c keys\n", nodename, keys.Count(), "xyz"[i]);
362 for(int j=0; j<keys.Count(); j++) {
363 long tm = KEY_TIME(keys[j]);
364 Point3 v = pos[tm];
365 v[i] = keys[j].linearKey.fval;
366 pos[tm] = v;
367 }
368 } else if(ctrl->GetBezierKeys(keys, postype[i])) {
369 maxlog("node %s: getting %d bezier position %c keys\n", nodename, keys.Count(), "xyz"[i]);
370 for(int j=0; j<keys.Count(); j++) {
371 long tm = KEY_TIME(keys[j]);
372 Point3 v = pos[tm];
373 v[i] = keys[j].bezierKey.fval;
374 pos[tm] = v;
375 }
376 } else if(ctrl->GetTCBKeys(keys, postype[i])) {
377 maxlog("node %s: getting %d tcb position %c keys\n", nodename, keys.Count(), "xyz"[i]);
378 for(int j=0; j<keys.Count(); j++) {
379 long tm = KEY_TIME(keys[j]);
380 Point3 v = pos[tm];
381 v[i] = keys[j].tcbKey.fval;
382 pos[tm] = v;
383 }
384 }
385 }
387 std::map<long, Point3>::iterator it = pos.begin();
388 while(it != pos.end()) {
389 Point3 p = it->second;
390 goat3d_set_node_position(node, p.x, p.y, p.z, it->first);
391 ++it;
392 }
393 }
395 static void get_rotation_keys(IGameControl *ctrl, goat3d_node *node)
396 {
397 const char *nodename = goat3d_get_node_name(node);
398 IGameKeyTab rkeys;
400 if(ctrl->GetLinearKeys(rkeys, IGAME_ROT)) {
401 maxlog("node %s: getting %d linear rotation keys\n", nodename, rkeys.Count());
402 for(int i=0; i<rkeys.Count(); i++) {
403 Quat q = rkeys[i].linearKey.qval;
404 goat3d_set_node_rotation(node, q.x, q.y, q.z, q.w, KEY_TIME(rkeys[i]));
405 }
406 } else if(ctrl->GetBezierKeys(rkeys, IGAME_ROT)) {
407 maxlog("node %s: getting %d bezier rotation keys\n", nodename, rkeys.Count());
408 for(int i=0; i<rkeys.Count(); i++) {
409 Quat q = rkeys[i].bezierKey.qval;
410 goat3d_set_node_rotation(node, q.x, q.y, q.z, q.w, KEY_TIME(rkeys[i]));
411 }
412 } else if(ctrl->GetTCBKeys(rkeys, IGAME_ROT)) {
413 maxlog("node %s: getting %d TCB rotation keys\n", nodename, rkeys.Count());
414 for(int i=0; i<rkeys.Count(); i++) {
415 Quat q(rkeys[i].tcbKey.aval);
416 goat3d_set_node_rotation(node, q.x, q.y, q.z, q.w, KEY_TIME(rkeys[i]));
417 }
418 } else {
419 get_euler_keys(ctrl, node);
420 }
421 }
423 static void get_euler_keys(IGameControl *ctrl, goat3d_node *node)
424 {
425 const char *nodename = goat3d_get_node_name(node);
426 IGameKeyTab keys;
427 IGameControlType eulertype[] = {IGAME_EULER_X, IGAME_EULER_Y, IGAME_EULER_Z};
428 std::map<long, Point3> euler;
430 for(int i=0; i<3; i++) {
431 if(ctrl->GetLinearKeys(keys, eulertype[i])) {
432 maxlog("node %s: getting %d linear euler %c keys\n", nodename, keys.Count(), "xyz"[i]);
433 for(int j=0; j<keys.Count(); j++) {
434 long tm = KEY_TIME(keys[j]);
435 Point3 v = euler[tm];
436 v[i] = keys[j].linearKey.fval;
437 euler[tm] = v;
438 }
439 } else if(ctrl->GetBezierKeys(keys, eulertype[i])) {
440 maxlog("node %s: getting %d bezier euler %c keys\n", nodename, keys.Count(), "xyz"[i]);
441 for(int j=0; j<keys.Count(); j++) {
442 long tm = KEY_TIME(keys[j]);
443 Point3 v = euler[tm];
444 v[i] = keys[j].bezierKey.fval;
445 euler[tm] = v;
446 }
447 } else if(ctrl->GetTCBKeys(keys, eulertype[i])) {
448 maxlog("node %s: getting %d tcb euler %c keys\n", nodename, keys.Count(), "xyz"[i]);
449 for(int j=0; j<keys.Count(); j++) {
450 long tm = KEY_TIME(keys[j]);
451 Point3 v = euler[tm];
452 v[i] = keys[j].tcbKey.fval;
453 euler[tm] = v;
454 }
455 }
456 }
458 int order = ctrl->GetEulerOrder();
459 std::map<long, Point3>::iterator it = euler.begin();
460 while(it != euler.end()) {
461 Quat q;
462 EulerToQuat(it->second, q, order);
463 goat3d_set_node_rotation(node, q.x, q.y, q.z, q.w, it->first);
464 ++it;
465 }
466 }
468 static void get_scaling_keys(IGameControl *ctrl, goat3d_node *node)
469 {
470 const char *nodename = goat3d_get_node_name(node);
471 IGameKeyTab keys;
473 // XXX the way I'm using the ScaleValue is wrong, but fuck it...
475 if(ctrl->GetLinearKeys(keys, IGAME_SCALE)) {
476 maxlog("node %s: getting %d linear scaling keys\n", nodename, keys.Count());
477 for(int i=0; i<keys.Count(); i++) {
478 ScaleValue s = keys[i].linearKey.sval;
479 goat3d_set_node_scaling(node, s.s.x, s.s.y, s.s.z, KEY_TIME(keys[i]));
480 }
481 } else if(ctrl->GetBezierKeys(keys, IGAME_SCALE)) {
482 maxlog("node %s: getting %d bezier scaling keys\n", nodename, keys.Count());
483 for(int i=0; i<keys.Count(); i++) {
484 ScaleValue s = keys[i].bezierKey.sval;
485 goat3d_set_node_scaling(node, s.s.x, s.s.y, s.s.z, KEY_TIME(keys[i]));
486 }
487 } else if(ctrl->GetTCBKeys(keys, IGAME_SCALE)) {
488 maxlog("node %s: getting %d tcb scaling keys\n", nodename, keys.Count());
489 for(int i=0; i<keys.Count(); i++) {
490 ScaleValue s = keys[i].tcbKey.sval;
491 goat3d_set_node_scaling(node, s.s.x, s.s.y, s.s.z, KEY_TIME(keys[i]));
492 }
493 }
494 }
496 void GoatExporter::process_mesh(goat3d *goat, goat3d_mesh *mesh, IGameObject *maxobj)
497 {
498 IGameMesh *maxmesh = (IGameMesh*)maxobj;
500 maxmesh->SetCreateOptimizedNormalList(); // not needed any more according to docs
501 maxobj->InitializeData();
503 int num_verts = maxmesh->GetNumberOfVerts();
504 int num_faces = maxmesh->GetNumberOfFaces();
505 //assert(maxmesh->GetNumberOfTexVerts() == num_verts);
507 float *vertices = new float[num_verts * 3];
508 float *normals = new float[num_verts * 3];
509 //float *texcoords = new float[num_verts * 2];
510 int *indices = new int[num_faces * 3];
512 for(int i=0; i<num_verts; i++) {
513 Point3 v = maxmesh->GetVertex(i, true);
514 vertices[i * 3] = v.x;
515 vertices[i * 3 + 1] = v.y;
516 vertices[i * 3 + 2] = v.z;
517 }
519 for(int i=0; i<maxmesh->GetNumberOfNormals(); i++) {
520 Point3 norm = maxmesh->GetNormal(i);
522 int vidx = maxmesh->GetNormalVertexIndex(i);
523 normals[vidx * 3] = norm.x;
524 normals[vidx * 3 + 1] = norm.y;
525 normals[vidx * 3 + 2] = norm.z;
526 }
528 /*for(int i=0; i<maxmesh->GetNumberOfTexVerts(); i++) {
529 Point3 tex = maxmesh->GetTexVertex(i);
531 texcoords[i * 2] = tex.x;
532 texcoords[i * 2 + 1] = tex.y;
533 }*/
535 // get the faces
536 for(int i=0; i<num_faces; i++) {
537 FaceEx *face = maxmesh->GetFace(i);
538 indices[i * 3] = face->vert[0];
539 indices[i * 3 + 1] = face->vert[1];
540 indices[i * 3 + 2] = face->vert[2];
541 // TODO at some point I'll have to split based on normal/texcoord indices
542 }
544 goat3d_set_mesh_attribs(mesh, GOAT3D_MESH_ATTR_VERTEX, vertices, num_verts);
545 goat3d_set_mesh_attribs(mesh, GOAT3D_MESH_ATTR_NORMAL, normals, num_verts);
546 //goat3d_set_mesh_attribs(mesh, GOAT3D_MESH_ATTR_TEXCOORD, texcoords, num_verts);
547 goat3d_set_mesh_faces(mesh, indices, num_faces);
549 delete [] vertices;
550 delete [] normals;
551 //delete [] texcoords;
552 delete [] indices;
553 }
555 void GoatExporter::process_light(goat3d *goat, goat3d_light *light, IGameObject *maxobj)
556 {
557 // TODO
558 }
560 void GoatExporter::process_camera(goat3d *goat, goat3d_camera *cam, IGameObject *maxobj)
561 {
562 // TODO
563 }
565 static INT_PTR CALLBACK scene_gui_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam)
566 {
567 switch(msg) {
568 case WM_INITDIALOG:
569 CheckDlgButton(win, IDC_GOAT_NODES, 1);
570 CheckDlgButton(win, IDC_GOAT_MESHES, 1);
571 CheckDlgButton(win, IDC_GOAT_LIGHTS, 1);
572 CheckDlgButton(win, IDC_GOAT_CAMERAS, 1);
573 break;
575 case WM_COMMAND:
576 switch(LOWORD(wparam)) {
577 case IDOK:
578 EndDialog(win, 1);
579 break;
581 case IDCANCEL:
582 EndDialog(win, 0);
583 break;
585 default:
586 return 0;
587 }
588 break;
590 default:
591 return 0;
592 }
594 return 1;
595 }
599 // ---- GoatAnimExporter implementation ----
601 int GoatAnimExporter::DoExport(const MCHAR *name, ExpInterface *eiface, Interface *iface, BOOL silent, DWORD opt)
602 {
603 if(!DialogBox(hinst, MAKEINTRESOURCE(IDD_GOAT_ANM), 0, anim_gui_handler)) {
604 return IMPEXP_CANCEL;
605 }
607 char fname[512];
608 wcstombs(fname, name, sizeof fname - 1);
609 for(int i=0; fname[i]; i++) {
610 fname[i] = tolower(fname[i]);
611 }
613 maxlog("Exporting Goat3D Animation (text) file: %s\n", fname);
614 if(!(igame = GetIGameInterface())) {
615 maxlog("failed to get the igame interface\n");
616 return IMPEXP_FAIL;
617 }
618 IGameConversionManager *cm = GetConversionManager();
619 cm->SetCoordSystem(IGameConversionManager::IGAME_OGL);
620 igame->InitialiseIGame();
621 igame->SetStaticFrame(0);
623 goat3d *goat = goat3d_create();
625 // process all nodes
626 for(int i=0; i<igame->GetTopLevelNodeCount(); i++) {
627 IGameNode *node = igame->GetTopLevelNode(i);
628 process_node(goat, 0, node);
629 }
631 if(goat3d_save_anim(goat, fname) == -1) {
632 goat3d_free(goat);
633 return IMPEXP_FAIL;
634 }
636 goat3d_free(goat);
637 return IMPEXP_SUCCESS;
638 }
640 static INT_PTR CALLBACK anim_gui_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam)
641 {
642 switch(msg) {
643 case WM_INITDIALOG:
644 CheckDlgButton(win, IDC_GOAT_ANM_FULL, 1);
645 break;
647 case WM_COMMAND:
648 switch(LOWORD(wparam)) {
649 case IDOK:
650 EndDialog(win, 1);
651 break;
653 case IDCANCEL:
654 EndDialog(win, 0);
655 break;
657 default:
658 return 0;
659 }
660 break;
662 default:
663 return 0;
664 }
666 return 1;
667 }
669 // ------------------------------------------
671 class GoatClassDesc : public ClassDesc2 {
672 public:
673 int IsPublic() { return TRUE; }
674 void *Create(BOOL loading = FALSE) { return new GoatExporter; }
675 const TCHAR *ClassName() { return L"GoatExporter"; }
676 SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; }
677 Class_ID ClassID() { return Class_ID(0x77050f0d, 0x7d4c5ab5); }
678 const TCHAR *Category() { return L"Mutant Stargoat"; }
680 const TCHAR *InternalName() { return L"GoatExporter"; }
681 HINSTANCE HInstance() { return hinst; }
682 };
684 class GoatAnimClassDesc : public ClassDesc2 {
685 public:
686 int IsPublic() { return TRUE; }
687 void *Create(BOOL loading = FALSE) { return new GoatAnimExporter; }
688 const TCHAR *ClassName() { return L"GoatAnimExporter"; }
689 SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; }
690 Class_ID ClassID() { return Class_ID(0x51b94924, 0x2e0332f3); }
691 const TCHAR *Category() { return L"Mutant Stargoat"; }
693 const TCHAR *InternalName() { return L"GoatAnimExporter"; }
694 HINSTANCE HInstance() { return hinst; }
695 };
697 // TODO: make 2 class descriptors, one for goat3d, one for goat3danim
698 static GoatClassDesc class_desc;
699 static GoatAnimClassDesc anim_class_desc;
701 BOOL WINAPI DllMain(HINSTANCE inst_handle, ULONG reason, void *reserved)
702 {
703 if(reason == DLL_PROCESS_ATTACH) {
704 hinst = inst_handle;
705 DisableThreadLibraryCalls(hinst);
706 }
707 return TRUE;
708 }
710 extern "C" {
712 __declspec(dllexport) const TCHAR *LibDescription()
713 {
714 return L"test exporter";
715 }
717 __declspec(dllexport) int LibNumberClasses()
718 {
719 return 1;
720 }
722 __declspec(dllexport) ClassDesc *LibClassDesc(int i)
723 {
724 switch(i) {
725 case 0:
726 return &class_desc;
727 case 1:
728 return &anim_class_desc;
729 default:
730 break;
731 }
732 return 0;
733 }
735 __declspec(dllexport) ULONG LibVersion()
736 {
737 return Get3DSMAXVersion();
738 }
740 __declspec(dllexport) int LibInitialize()
741 {
742 static char path[1024];
744 SHGetFolderPathA(0, CSIDL_PERSONAL, 0, 0, path);
745 strcat(path, "/testexp.log");
747 maxlog_open(path);
748 return TRUE;
749 }
751 __declspec(dllexport) int LibShutdown()
752 {
753 maxlog_close();
754 return TRUE;
755 }
757 } // extern "C"
760 static const char *max_string(const MCHAR *wstr)
761 {
762 if(!wstr) return 0;
763 static char str[512];
764 wcstombs(str, wstr, sizeof str - 1);
765 return str;