goat3d

annotate exporters/maxgoat/src/maxgoat.cc @ 69:66cd8266f078

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