goat3d
diff exporters/maxgoat/src/maxgoat.cc @ 73:9862541fdcf5
- build qt goatview on linux
- fixed line endings in a bunch of files
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Tue, 06 May 2014 03:57:11 +0300 |
parents | 36e39632db75 |
children | 8b156bc5205b |
line diff
1.1 --- a/exporters/maxgoat/src/maxgoat.cc Tue May 06 03:31:35 2014 +0300 1.2 +++ b/exporters/maxgoat/src/maxgoat.cc Tue May 06 03:57:11 2014 +0300 1.3 @@ -1,892 +1,892 @@ 1.4 -#include <stdio.h> 1.5 -#include <string.h> 1.6 -#include <stdlib.h> 1.7 -#include <ctype.h> 1.8 -#include <errno.h> 1.9 -#include <map> 1.10 -#include <vector> 1.11 -#include <windows.h> 1.12 -#include <shlobj.h> 1.13 -#include "max.h" 1.14 -#include "impexp.h" // SceneExport 1.15 -#include "iparamb2.h" // ClassDesc2 1.16 -#include "plugapi.h" 1.17 -#include "IGame.h" 1.18 -#include "IGameExport.h" 1.19 -#include "IGameControl.h" 1.20 -#include "IConversionmanager.h" 1.21 -#include "goat3d.h" 1.22 -#include "config.h" 1.23 -#include "logger.h" 1.24 -#include "resource.h" 1.25 - 1.26 - 1.27 -#pragma comment (lib, "core.lib") 1.28 -#pragma comment (lib, "geom.lib") 1.29 -#pragma comment (lib, "gfx.lib") 1.30 -#pragma comment (lib, "mesh.lib") 1.31 -#pragma comment (lib, "maxutil.lib") 1.32 -#pragma comment (lib, "maxscrpt.lib") 1.33 -#pragma comment (lib, "paramblk2.lib") 1.34 -#pragma comment (lib, "msxml2.lib") 1.35 -#pragma comment (lib, "igame.lib") 1.36 -#pragma comment (lib, "comctl32.lib") 1.37 - 1.38 - 1.39 -#define COPYRIGHT \ 1.40 - L"Copyright 2014 (C) John Tsiombikas - GNU General Public License v3, see COPYING for details." 1.41 -#define VERSION(major, minor) \ 1.42 - ((major) * 100 + ((minor) < 10 ? (minor) * 10 : (minor))) 1.43 - 1.44 -static INT_PTR CALLBACK scene_gui_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam); 1.45 -static INT_PTR CALLBACK anim_gui_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam); 1.46 -static void get_position_keys(IGameControl *ctrl, goat3d_node *node); 1.47 -static void get_xyz_position_keys(IGameControl *ctrl, goat3d_node *node); 1.48 -static void get_rotation_keys(IGameControl *ctrl, goat3d_node *node); 1.49 -static void get_euler_keys(IGameControl *ctrl, goat3d_node *node); 1.50 -static void get_scaling_keys(IGameControl *ctrl, goat3d_node *node); 1.51 -static const char *max_string(const MCHAR *wstr); 1.52 - 1.53 -HINSTANCE hinst; 1.54 - 1.55 -class GoatExporter : public SceneExport { 1.56 -private: 1.57 - std::map<IGameMaterial*, goat3d_material*> mtlmap; 1.58 - std::map<IGameNode*, goat3d_node*> nodemap; 1.59 - 1.60 -public: 1.61 - IGameScene *igame; 1.62 - 1.63 - int DoExport(const MCHAR *name, ExpInterface *eiface, Interface *iface, BOOL silent = FALSE, DWORD opt = 0); 1.64 - 1.65 - void process_materials(goat3d *goat); 1.66 - 1.67 - void process_node(goat3d *goat, goat3d_node *parent, IGameNode *maxnode); 1.68 - 1.69 - void process_mesh(goat3d *goat, goat3d_mesh *mesh, IGameObject *maxobj); 1.70 - void process_light(goat3d *goat, goat3d_light *light, IGameObject *maxobj); 1.71 - void process_camera(goat3d *goat, goat3d_camera *cam, IGameObject *maxobj); 1.72 - 1.73 - 1.74 - int ExtCount() { return 1; } 1.75 - const TCHAR *Ext(int n) { return L"goatsce"; } 1.76 - const TCHAR *LongDesc() { return L"Goat3D scene file"; } 1.77 - const TCHAR *ShortDesc() { return L"Goat3D"; } 1.78 - const TCHAR *AuthorName() { return L"John Tsiombikas"; } 1.79 - const TCHAR *CopyrightMessage() { return COPYRIGHT; } 1.80 - const TCHAR *OtherMessage1() { return L"other1"; } 1.81 - const TCHAR *OtherMessage2() { return L"other2"; } 1.82 - unsigned int Version() { return VERSION(VER_MAJOR, VER_MINOR); } 1.83 - void ShowAbout(HWND win) { MessageBoxA(win, "Goat3D exporter plugin", "About this plugin", 0); } 1.84 -}; 1.85 - 1.86 -class GoatAnimExporter : public GoatExporter { 1.87 -private: 1.88 -public: 1.89 - int DoExport(const MCHAR *name, ExpInterface *eiface, Interface *iface, BOOL silent = FALSE, DWORD opt = 0); 1.90 - 1.91 - const TCHAR *Ext(int n) { return L"goatanm"; } 1.92 - const TCHAR *LongDesc() { return L"Goat3D animation file"; } 1.93 -}; 1.94 - 1.95 - 1.96 -// ---- GoatExporter implementation ---- 1.97 - 1.98 -int GoatExporter::DoExport(const MCHAR *name, ExpInterface *eiface, Interface *iface, 1.99 - BOOL non_interactive, DWORD opt) 1.100 -{ 1.101 - if(!DialogBox(hinst, MAKEINTRESOURCE(IDD_GOAT_SCE), 0, scene_gui_handler)) { 1.102 - return IMPEXP_CANCEL; 1.103 - } 1.104 - 1.105 - mtlmap.clear(); 1.106 - nodemap.clear(); 1.107 - 1.108 - char fname[512]; 1.109 - wcstombs(fname, name, sizeof fname - 1); 1.110 - for(int i=0; fname[i]; i++) { 1.111 - fname[i] = tolower(fname[i]); 1.112 - } 1.113 - char *basename = (char*)alloca(strlen(fname) + 1); 1.114 - strcpy(basename, fname); 1.115 - char *suffix = strrchr(basename, '.'); 1.116 - if(suffix) *suffix = 0; 1.117 - 1.118 - maxlog("Exporting Goat3D Scene (text) file: %s\n", fname); 1.119 - if(!(igame = GetIGameInterface())) { 1.120 - maxlog("failed to get the igame interface\n"); 1.121 - return IMPEXP_FAIL; 1.122 - } 1.123 - IGameConversionManager *cm = GetConversionManager(); 1.124 - cm->SetCoordSystem(IGameConversionManager::IGAME_OGL); 1.125 - igame->InitialiseIGame(); 1.126 - 1.127 - goat3d *goat = goat3d_create(); 1.128 - goat3d_set_name(goat, basename); 1.129 - 1.130 - process_materials(goat); 1.131 - 1.132 - // process all nodes 1.133 - for(int i=0; i<igame->GetTopLevelNodeCount(); i++) { 1.134 - IGameNode *node = igame->GetTopLevelNode(i); 1.135 - process_node(goat, 0, node); 1.136 - } 1.137 - 1.138 - if(goat3d_save(goat, fname) == -1) { 1.139 - goat3d_free(goat); 1.140 - return IMPEXP_FAIL; 1.141 - } 1.142 - 1.143 - goat3d_free(goat); 1.144 - return IMPEXP_SUCCESS; 1.145 -} 1.146 - 1.147 -void GoatExporter::process_materials(goat3d *goat) 1.148 -{ 1.149 - IGameProperty *prop; 1.150 - 1.151 - int num_mtl = igame->GetRootMaterialCount(); 1.152 - for(int i=0; i<num_mtl; i++) { 1.153 - IGameMaterial *maxmtl = igame->GetRootMaterial(i); 1.154 - if(maxmtl) { 1.155 - goat3d_material *mtl = goat3d_create_mtl(); 1.156 - 1.157 - const char *name = max_string(maxmtl->GetMaterialName()); 1.158 - if(name) { 1.159 - goat3d_set_mtl_name(mtl, name); 1.160 - } 1.161 - 1.162 - // diffuse 1.163 - if((prop = maxmtl->GetDiffuseData())) { 1.164 - Point3 diffuse(1, 1, 1); 1.165 - prop->GetPropertyValue(diffuse); 1.166 - goat3d_set_mtl_attrib3f(mtl, GOAT3D_MAT_ATTR_DIFFUSE, diffuse[0], 1.167 - diffuse[1], diffuse[2]); 1.168 - } 1.169 - // specular 1.170 - if((prop = maxmtl->GetSpecularData())) { 1.171 - Point3 specular(0, 0, 0); 1.172 - prop->GetPropertyValue(specular); 1.173 - 1.174 - float sstr = 1.0; 1.175 - if((prop = maxmtl->GetSpecularLevelData())) { 1.176 - prop->GetPropertyValue(sstr); 1.177 - } 1.178 - goat3d_set_mtl_attrib3f(mtl, GOAT3D_MAT_ATTR_SPECULAR, specular[0] * sstr, 1.179 - specular[1] * sstr, specular[2] * sstr); 1.180 - } 1.181 - // shininess 1.182 - if((prop = maxmtl->GetGlossinessData())) { 1.183 - float shin; 1.184 - prop->GetPropertyValue(shin); 1.185 - goat3d_set_mtl_attrib1f(mtl, GOAT3D_MAT_ATTR_SHININESS, shin * 100.0); 1.186 - } 1.187 - 1.188 - // textures 1.189 - for(int j=0; j<maxmtl->GetNumberOfTextureMaps(); j++) { 1.190 - IGameTextureMap *tex = maxmtl->GetIGameTextureMap(j); 1.191 - 1.192 - const char *fname = max_string(tex->GetBitmapFileName()); 1.193 - if(!fname) { 1.194 - continue; 1.195 - } 1.196 - 1.197 - int slot = tex->GetStdMapSlot(); 1.198 - switch(slot) { 1.199 - case ID_DI: // diffuse 1.200 - goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_DIFFUSE, fname); 1.201 - break; 1.202 - 1.203 - case ID_SP: 1.204 - case ID_SS: 1.205 - goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_SPECULAR, fname); 1.206 - break; 1.207 - 1.208 - case ID_SH: 1.209 - goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_SHININESS, fname); 1.210 - break; 1.211 - 1.212 - case ID_BU: 1.213 - goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_NORMAL, fname); 1.214 - break; 1.215 - 1.216 - case ID_RL: 1.217 - goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_REFLECTION, fname); 1.218 - break; 1.219 - 1.220 - case ID_RR: 1.221 - goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_TRANSMISSION, fname); 1.222 - break; 1.223 - 1.224 - default: 1.225 - break; 1.226 - } 1.227 - } 1.228 - 1.229 - goat3d_add_mtl(goat, mtl); 1.230 - mtlmap[maxmtl] = mtl; 1.231 - } 1.232 - } 1.233 -} 1.234 - 1.235 -void GoatExporter::process_node(goat3d *goat, goat3d_node *parent, IGameNode *maxnode) 1.236 -{ 1.237 - goat3d_node *node = goat3d_create_node(); 1.238 - goat3d_add_node(goat, node); 1.239 - 1.240 - if(parent) { 1.241 - goat3d_add_node_child(parent, node); 1.242 - } 1.243 - 1.244 - const char *name = max_string(maxnode->GetName()); 1.245 - if(name) { 1.246 - goat3d_set_node_name(node, name); 1.247 - } 1.248 - 1.249 - IGameObject *maxobj = maxnode->GetIGameObject(); 1.250 - IGameObject::ObjectTypes type = maxobj->GetIGameType(); 1.251 - 1.252 - switch(type) { 1.253 - case IGameObject::IGAME_MESH: 1.254 - { 1.255 - goat3d_mesh *mesh = goat3d_create_mesh(); 1.256 - if(name) goat3d_set_mesh_name(mesh, name); 1.257 - goat3d_set_node_object(node, GOAT3D_NODE_MESH, mesh); 1.258 - 1.259 - // get the node material and assign it to the mesh 1.260 - IGameMaterial *maxmtl = maxnode->GetNodeMaterial(); 1.261 - goat3d_material *mtl = mtlmap[maxmtl]; 1.262 - if(mtl) { 1.263 - goat3d_set_mesh_mtl(mesh, mtl); 1.264 - } 1.265 - 1.266 - process_mesh(goat, mesh, maxobj); 1.267 - goat3d_add_mesh(goat, mesh); 1.268 - } 1.269 - break; 1.270 - 1.271 - case IGameObject::IGAME_LIGHT: 1.272 - { 1.273 - goat3d_light *light = goat3d_create_light(); 1.274 - //if(name) goat3d_set_light_name(light, name); 1.275 - goat3d_set_node_object(node, GOAT3D_NODE_LIGHT, light); 1.276 - 1.277 - process_light(goat, light, maxobj); 1.278 - goat3d_add_light(goat, light); 1.279 - } 1.280 - break; 1.281 - 1.282 - case IGameObject::IGAME_CAMERA: 1.283 - { 1.284 - goat3d_camera *cam = goat3d_create_camera(); 1.285 - //if(name) goat3d_set_camera_name(camera, name); 1.286 - goat3d_set_node_object(node, GOAT3D_NODE_CAMERA, cam); 1.287 - 1.288 - process_camera(goat, cam, maxobj); 1.289 - goat3d_add_camera(goat, cam); 1.290 - } 1.291 - break; 1.292 - 1.293 - default: 1.294 - // otherwise don't assign an object, essentially treating it as a null node 1.295 - break; 1.296 - } 1.297 - 1.298 - // grab the animation data 1.299 - if(!dynamic_cast<GoatAnimExporter*>(this)) { 1.300 - // no animation, just get the static PRS 1.301 - GMatrix maxmatrix = maxnode->GetObjectTM(); 1.302 - Point3 trans = maxmatrix.Translation(); 1.303 - Quat rot = maxmatrix.Rotation(); 1.304 - Point3 scale = maxmatrix.Scaling(); 1.305 - 1.306 - goat3d_set_node_position(node, trans.x, trans.y, trans.z, 0); 1.307 - goat3d_set_node_rotation(node, rot.x, rot.y, rot.z, rot.w, 0); 1.308 - goat3d_set_node_scaling(node, scale.x, scale.y, scale.z, 0); 1.309 - 1.310 - } else { 1.311 - // exporting animations (if available) 1.312 - // TODO sample keys if requested 1.313 - IGameControl *ctrl = maxnode->GetIGameControl(); 1.314 - if(ctrl) { 1.315 - if(ctrl->IsAnimated(IGAME_POS) || ctrl->IsAnimated(IGAME_POS_X) || 1.316 - ctrl->IsAnimated(IGAME_POS_Y) || ctrl->IsAnimated(IGAME_POS_Z)) { 1.317 - get_position_keys(ctrl, node); 1.318 - } 1.319 - if(ctrl->IsAnimated(IGAME_ROT) || ctrl->IsAnimated(IGAME_EULER_X) || 1.320 - ctrl->IsAnimated(IGAME_EULER_Y) || ctrl->IsAnimated(IGAME_EULER_Z)) { 1.321 - get_rotation_keys(ctrl, node); 1.322 - } 1.323 - if(ctrl->IsAnimated(IGAME_SCALE)) { 1.324 - get_scaling_keys(ctrl, node); 1.325 - } 1.326 - } else { 1.327 - maxlog("%s: failed to get IGameControl for node: %s\n", __FUNCTION__, name); 1.328 - } 1.329 - } 1.330 - 1.331 - for(int i=0; i<maxnode->GetChildCount(); i++) { 1.332 - process_node(goat, node, maxnode->GetNodeChild(i)); 1.333 - } 1.334 -} 1.335 - 1.336 -#define KEY_TIME(key) ((long)(TicksToSec(key.t) * 1000.0)) 1.337 - 1.338 -static void get_position_keys(IGameControl *ctrl, goat3d_node *node) 1.339 -{ 1.340 - const char *nodename = goat3d_get_node_name(node); 1.341 - IGameKeyTab keys; 1.342 - 1.343 - if(ctrl->GetLinearKeys(keys, IGAME_POS)) { 1.344 - maxlog("node %s: getting %d linear position keys\n", nodename, keys.Count()); 1.345 - for(int i=0; i<keys.Count(); i++) { 1.346 - Point3 p = keys[i].linearKey.pval; 1.347 - goat3d_set_node_position(node, p.x, p.y, p.z, KEY_TIME(keys[i])); 1.348 - } 1.349 - } else if(ctrl->GetBezierKeys(keys, IGAME_POS)) { 1.350 - maxlog("node %s: getting %d bezier position keys\n", nodename, keys.Count()); 1.351 - for(int i=0; i<keys.Count(); i++) { 1.352 - Point3 p = keys[i].bezierKey.pval; 1.353 - goat3d_set_node_position(node, p.x, p.y, p.z, KEY_TIME(keys[i])); 1.354 - } 1.355 - } else if(ctrl->GetTCBKeys(keys, IGAME_POS)) { 1.356 - maxlog("node %s: getting %d tcb position keys\n", nodename, keys.Count()); 1.357 - for(int i=0; i<keys.Count(); i++) { 1.358 - Point3 p = keys[i].tcbKey.pval; 1.359 - goat3d_set_node_position(node, p.x, p.y, p.z, KEY_TIME(keys[i])); 1.360 - } 1.361 - } else { 1.362 - get_xyz_position_keys(ctrl, node); 1.363 - } 1.364 -} 1.365 - 1.366 -static void get_xyz_position_keys(IGameControl *ctrl, goat3d_node *node) 1.367 -{ 1.368 - const char *nodename = goat3d_get_node_name(node); 1.369 - IGameKeyTab keys; 1.370 - IGameControlType postype[] = {IGAME_POS_X, IGAME_POS_Y, IGAME_POS_Z}; 1.371 - std::map<long, Point3> pos; 1.372 - 1.373 - for(int i=0; i<3; i++) { 1.374 - if(ctrl->GetLinearKeys(keys, postype[i])) { 1.375 - maxlog("node %s: getting %d linear position %c keys\n", nodename, keys.Count(), "xyz"[i]); 1.376 - for(int j=0; j<keys.Count(); j++) { 1.377 - long tm = KEY_TIME(keys[j]); 1.378 - Point3 v = pos[tm]; 1.379 - v[i] = keys[j].linearKey.fval; 1.380 - pos[tm] = v; 1.381 - } 1.382 - } else if(ctrl->GetBezierKeys(keys, postype[i])) { 1.383 - maxlog("node %s: getting %d bezier position %c keys\n", nodename, keys.Count(), "xyz"[i]); 1.384 - for(int j=0; j<keys.Count(); j++) { 1.385 - long tm = KEY_TIME(keys[j]); 1.386 - Point3 v = pos[tm]; 1.387 - v[i] = keys[j].bezierKey.fval; 1.388 - pos[tm] = v; 1.389 - } 1.390 - } else if(ctrl->GetTCBKeys(keys, postype[i])) { 1.391 - maxlog("node %s: getting %d tcb position %c keys\n", nodename, keys.Count(), "xyz"[i]); 1.392 - for(int j=0; j<keys.Count(); j++) { 1.393 - long tm = KEY_TIME(keys[j]); 1.394 - Point3 v = pos[tm]; 1.395 - v[i] = keys[j].tcbKey.fval; 1.396 - pos[tm] = v; 1.397 - } 1.398 - } 1.399 - } 1.400 - 1.401 - std::map<long, Point3>::iterator it = pos.begin(); 1.402 - while(it != pos.end()) { 1.403 - Point3 p = it->second; 1.404 - goat3d_set_node_position(node, p.x, p.y, p.z, it->first); 1.405 - ++it; 1.406 - } 1.407 -} 1.408 - 1.409 -static void get_rotation_keys(IGameControl *ctrl, goat3d_node *node) 1.410 -{ 1.411 - const char *nodename = goat3d_get_node_name(node); 1.412 - IGameKeyTab rkeys; 1.413 - 1.414 - if(ctrl->GetLinearKeys(rkeys, IGAME_ROT)) { 1.415 - maxlog("node %s: getting %d linear rotation keys\n", nodename, rkeys.Count()); 1.416 - for(int i=0; i<rkeys.Count(); i++) { 1.417 - Quat q = rkeys[i].linearKey.qval; 1.418 - goat3d_set_node_rotation(node, q.x, q.y, q.z, q.w, KEY_TIME(rkeys[i])); 1.419 - } 1.420 - } else if(ctrl->GetBezierKeys(rkeys, IGAME_ROT)) { 1.421 - maxlog("node %s: getting %d bezier rotation keys\n", nodename, rkeys.Count()); 1.422 - for(int i=0; i<rkeys.Count(); i++) { 1.423 - Quat q = rkeys[i].bezierKey.qval; 1.424 - goat3d_set_node_rotation(node, q.x, q.y, q.z, q.w, KEY_TIME(rkeys[i])); 1.425 - } 1.426 - } else if(ctrl->GetTCBKeys(rkeys, IGAME_ROT)) { 1.427 - maxlog("node %s: getting %d TCB rotation keys\n", nodename, rkeys.Count()); 1.428 - for(int i=0; i<rkeys.Count(); i++) { 1.429 - Quat q(rkeys[i].tcbKey.aval); 1.430 - goat3d_set_node_rotation(node, q.x, q.y, q.z, q.w, KEY_TIME(rkeys[i])); 1.431 - } 1.432 - } else { 1.433 - get_euler_keys(ctrl, node); 1.434 - } 1.435 -} 1.436 - 1.437 -static void get_euler_keys(IGameControl *ctrl, goat3d_node *node) 1.438 -{ 1.439 - const char *nodename = goat3d_get_node_name(node); 1.440 - IGameKeyTab keys; 1.441 - IGameControlType eulertype[] = {IGAME_EULER_X, IGAME_EULER_Y, IGAME_EULER_Z}; 1.442 - std::map<long, Point3> euler; 1.443 - 1.444 - for(int i=0; i<3; i++) { 1.445 - if(ctrl->GetLinearKeys(keys, eulertype[i])) { 1.446 - maxlog("node %s: getting %d linear euler %c keys\n", nodename, keys.Count(), "xyz"[i]); 1.447 - for(int j=0; j<keys.Count(); j++) { 1.448 - long tm = KEY_TIME(keys[j]); 1.449 - Point3 v = euler[tm]; 1.450 - v[i] = keys[j].linearKey.fval; 1.451 - euler[tm] = v; 1.452 - } 1.453 - } else if(ctrl->GetBezierKeys(keys, eulertype[i])) { 1.454 - maxlog("node %s: getting %d bezier euler %c keys\n", nodename, keys.Count(), "xyz"[i]); 1.455 - for(int j=0; j<keys.Count(); j++) { 1.456 - long tm = KEY_TIME(keys[j]); 1.457 - Point3 v = euler[tm]; 1.458 - v[i] = keys[j].bezierKey.fval; 1.459 - euler[tm] = v; 1.460 - } 1.461 - } else if(ctrl->GetTCBKeys(keys, eulertype[i])) { 1.462 - maxlog("node %s: getting %d tcb euler %c keys\n", nodename, keys.Count(), "xyz"[i]); 1.463 - for(int j=0; j<keys.Count(); j++) { 1.464 - long tm = KEY_TIME(keys[j]); 1.465 - Point3 v = euler[tm]; 1.466 - v[i] = keys[j].tcbKey.fval; 1.467 - euler[tm] = v; 1.468 - } 1.469 - } 1.470 - } 1.471 - 1.472 - int order = ctrl->GetEulerOrder(); 1.473 - std::map<long, Point3>::iterator it = euler.begin(); 1.474 - while(it != euler.end()) { 1.475 - Quat q; 1.476 - EulerToQuat(it->second, q, order); 1.477 - goat3d_set_node_rotation(node, q.x, q.y, q.z, q.w, it->first); 1.478 - ++it; 1.479 - } 1.480 -} 1.481 - 1.482 -static void get_scaling_keys(IGameControl *ctrl, goat3d_node *node) 1.483 -{ 1.484 - const char *nodename = goat3d_get_node_name(node); 1.485 - IGameKeyTab keys; 1.486 - 1.487 - // XXX the way I'm using the ScaleValue is wrong, but fuck it... 1.488 - 1.489 - if(ctrl->GetLinearKeys(keys, IGAME_SCALE)) { 1.490 - maxlog("node %s: getting %d linear scaling keys\n", nodename, keys.Count()); 1.491 - for(int i=0; i<keys.Count(); i++) { 1.492 - ScaleValue s = keys[i].linearKey.sval; 1.493 - goat3d_set_node_scaling(node, s.s.x, s.s.y, s.s.z, KEY_TIME(keys[i])); 1.494 - } 1.495 - } else if(ctrl->GetBezierKeys(keys, IGAME_SCALE)) { 1.496 - maxlog("node %s: getting %d bezier scaling keys\n", nodename, keys.Count()); 1.497 - for(int i=0; i<keys.Count(); i++) { 1.498 - ScaleValue s = keys[i].bezierKey.sval; 1.499 - goat3d_set_node_scaling(node, s.s.x, s.s.y, s.s.z, KEY_TIME(keys[i])); 1.500 - } 1.501 - } else if(ctrl->GetTCBKeys(keys, IGAME_SCALE)) { 1.502 - maxlog("node %s: getting %d tcb scaling keys\n", nodename, keys.Count()); 1.503 - for(int i=0; i<keys.Count(); i++) { 1.504 - ScaleValue s = keys[i].tcbKey.sval; 1.505 - goat3d_set_node_scaling(node, s.s.x, s.s.y, s.s.z, KEY_TIME(keys[i])); 1.506 - } 1.507 - } 1.508 -} 1.509 - 1.510 -static bool get_anim_bounds(IGameNode *node, long *tstart, long *tend); 1.511 -static bool get_node_anim_bounds(IGameNode *node, long *tstart, long *tend); 1.512 - 1.513 -static bool get_anim_bounds(IGameScene *igame, long *tstart, long *tend) 1.514 -{ 1.515 - long tmin = LONG_MAX; 1.516 - long tmax = LONG_MIN; 1.517 - 1.518 - int num_nodes = igame->GetTopLevelNodeCount(); 1.519 - for(int i=0; i<num_nodes; i++) { 1.520 - long t0, t1; 1.521 - if(get_anim_bounds(igame->GetTopLevelNode(i), &t0, &t1)) { 1.522 - if(t0 < tmin) tmin = t0; 1.523 - if(t1 > tmax) tmax = t1; 1.524 - } 1.525 - } 1.526 - 1.527 - if(tmin != LONG_MAX) { 1.528 - *tstart = tmin; 1.529 - *tend = tmax; 1.530 - return true; 1.531 - } 1.532 - return false; 1.533 -} 1.534 - 1.535 -static bool get_anim_bounds(IGameNode *node, long *tstart, long *tend) 1.536 -{ 1.537 - long tmin = LONG_MAX; 1.538 - long tmax = LONG_MIN; 1.539 - 1.540 - get_node_anim_bounds(node, &tmin, &tmax); 1.541 - 1.542 - int num_children = node->GetChildCount(); 1.543 - for(int i=0; i<num_children; i++) { 1.544 - long t0, t1; 1.545 - if(get_anim_bounds(node->GetNodeChild(i), &t0, &t1)) { 1.546 - if(t0 < tmin) tmin = t0; 1.547 - if(t1 > tmax) tmax = t1; 1.548 - } 1.549 - } 1.550 - 1.551 - if(tmin != LONG_MAX) { 1.552 - *tstart = tmin; 1.553 - *tend = tmax; 1.554 - return true; 1.555 - } 1.556 - return false; 1.557 -} 1.558 - 1.559 -static bool get_node_anim_bounds(IGameNode *node, long *tstart, long *tend) 1.560 -{ 1.561 - static const IGameControlType ctypes[] = { 1.562 - IGAME_POS, IGAME_POS_X, IGAME_POS_Y, IGAME_POS_Z, 1.563 - IGAME_ROT, IGAME_EULER_X, IGAME_EULER_Y, IGAME_EULER_Z, 1.564 - IGAME_SCALE 1.565 - }; 1.566 - 1.567 - // NOTE: apparently if I don't call GetIGameObject, then GetIGameControl always returns null... 1.568 - node->GetIGameObject(); 1.569 - IGameControl *ctrl = node->GetIGameControl(); 1.570 - if(!ctrl) { 1.571 - maxlog("%s: failed to get IGameControl for node: %s\n", __FUNCTION__, max_string(node->GetName())); 1.572 - return false; 1.573 - } 1.574 - 1.575 - IGameKeyTab keys; 1.576 - long t0, t1; 1.577 - long tmin = LONG_MAX; 1.578 - long tmax = LONG_MIN; 1.579 - 1.580 - for(int i=0; i<sizeof ctypes / sizeof *ctypes; i++) { 1.581 - if(ctrl->GetBezierKeys(keys, ctypes[i]) && keys.Count()) { 1.582 - t0 = KEY_TIME(keys[0]); 1.583 - t1 = KEY_TIME(keys[keys.Count() - 1]); 1.584 - if(t0 < tmin) tmin = t0; 1.585 - if(t1 > tmax) tmax = t1; 1.586 - } 1.587 - if(ctrl->GetLinearKeys(keys, ctypes[i]) && keys.Count()) { 1.588 - t0 = KEY_TIME(keys[0]); 1.589 - t1 = KEY_TIME(keys[keys.Count() - 1]); 1.590 - if(t0 < tmin) tmin = t0; 1.591 - if(t1 > tmax) tmax = t1; 1.592 - } 1.593 - if(ctrl->GetTCBKeys(keys, ctypes[i]) && keys.Count()) { 1.594 - t0 = KEY_TIME(keys[0]); 1.595 - t1 = KEY_TIME(keys[keys.Count() - 1]); 1.596 - if(t0 < tmin) tmin = t0; 1.597 - if(t1 > tmax) tmax = t1; 1.598 - } 1.599 - } 1.600 - 1.601 - if(tmin != LONG_MAX) { 1.602 - *tstart = tmin; 1.603 - *tend = tmax; 1.604 - return true; 1.605 - } 1.606 - return false; 1.607 -} 1.608 - 1.609 -void GoatExporter::process_mesh(goat3d *goat, goat3d_mesh *mesh, IGameObject *maxobj) 1.610 -{ 1.611 - IGameMesh *maxmesh = (IGameMesh*)maxobj; 1.612 - 1.613 - maxmesh->SetCreateOptimizedNormalList(); // not needed any more according to docs 1.614 - maxobj->InitializeData(); 1.615 - 1.616 - int num_verts = maxmesh->GetNumberOfVerts(); 1.617 - int num_faces = maxmesh->GetNumberOfFaces(); 1.618 - //assert(maxmesh->GetNumberOfTexVerts() == num_verts); 1.619 - 1.620 - float *vertices = new float[num_verts * 3]; 1.621 - float *normals = new float[num_verts * 3]; 1.622 - //float *texcoords = new float[num_verts * 2]; 1.623 - int *indices = new int[num_faces * 3]; 1.624 - 1.625 - for(int i=0; i<num_verts; i++) { 1.626 - Point3 v = maxmesh->GetVertex(i, true); 1.627 - vertices[i * 3] = v.x; 1.628 - vertices[i * 3 + 1] = v.y; 1.629 - vertices[i * 3 + 2] = v.z; 1.630 - } 1.631 - 1.632 - for(int i=0; i<maxmesh->GetNumberOfNormals(); i++) { 1.633 - Point3 norm = maxmesh->GetNormal(i); 1.634 - 1.635 - int vidx = maxmesh->GetNormalVertexIndex(i); 1.636 - normals[vidx * 3] = norm.x; 1.637 - normals[vidx * 3 + 1] = norm.y; 1.638 - normals[vidx * 3 + 2] = norm.z; 1.639 - } 1.640 - 1.641 - /*for(int i=0; i<maxmesh->GetNumberOfTexVerts(); i++) { 1.642 - Point3 tex = maxmesh->GetTexVertex(i); 1.643 - 1.644 - texcoords[i * 2] = tex.x; 1.645 - texcoords[i * 2 + 1] = tex.y; 1.646 - }*/ 1.647 - 1.648 - // get the faces 1.649 - for(int i=0; i<num_faces; i++) { 1.650 - FaceEx *face = maxmesh->GetFace(i); 1.651 - indices[i * 3] = face->vert[0]; 1.652 - indices[i * 3 + 1] = face->vert[1]; 1.653 - indices[i * 3 + 2] = face->vert[2]; 1.654 - // TODO at some point I'll have to split based on normal/texcoord indices 1.655 - } 1.656 - 1.657 - goat3d_set_mesh_attribs(mesh, GOAT3D_MESH_ATTR_VERTEX, vertices, num_verts); 1.658 - goat3d_set_mesh_attribs(mesh, GOAT3D_MESH_ATTR_NORMAL, normals, num_verts); 1.659 - //goat3d_set_mesh_attribs(mesh, GOAT3D_MESH_ATTR_TEXCOORD, texcoords, num_verts); 1.660 - goat3d_set_mesh_faces(mesh, indices, num_faces); 1.661 - 1.662 - delete [] vertices; 1.663 - delete [] normals; 1.664 - //delete [] texcoords; 1.665 - delete [] indices; 1.666 -} 1.667 - 1.668 -void GoatExporter::process_light(goat3d *goat, goat3d_light *light, IGameObject *maxobj) 1.669 -{ 1.670 - // TODO 1.671 -} 1.672 - 1.673 -void GoatExporter::process_camera(goat3d *goat, goat3d_camera *cam, IGameObject *maxobj) 1.674 -{ 1.675 - // TODO 1.676 -} 1.677 - 1.678 -static INT_PTR CALLBACK scene_gui_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam) 1.679 -{ 1.680 - switch(msg) { 1.681 - case WM_INITDIALOG: 1.682 - CheckDlgButton(win, IDC_GOAT_NODES, 1); 1.683 - CheckDlgButton(win, IDC_GOAT_MESHES, 1); 1.684 - CheckDlgButton(win, IDC_GOAT_LIGHTS, 1); 1.685 - CheckDlgButton(win, IDC_GOAT_CAMERAS, 1); 1.686 - break; 1.687 - 1.688 - case WM_COMMAND: 1.689 - switch(LOWORD(wparam)) { 1.690 - case IDOK: 1.691 - EndDialog(win, 1); 1.692 - break; 1.693 - 1.694 - case IDCANCEL: 1.695 - EndDialog(win, 0); 1.696 - break; 1.697 - 1.698 - default: 1.699 - return 0; 1.700 - } 1.701 - break; 1.702 - 1.703 - default: 1.704 - return 0; 1.705 - } 1.706 - 1.707 - return 1; 1.708 -} 1.709 - 1.710 - 1.711 - 1.712 -// ---- GoatAnimExporter implementation ---- 1.713 -static long tstart, tend; 1.714 - 1.715 -int GoatAnimExporter::DoExport(const MCHAR *name, ExpInterface *eiface, Interface *iface, BOOL silent, DWORD opt) 1.716 -{ 1.717 - if(!(igame = GetIGameInterface())) { 1.718 - maxlog("failed to get the igame interface\n"); 1.719 - return IMPEXP_FAIL; 1.720 - } 1.721 - IGameConversionManager *cm = GetConversionManager(); 1.722 - cm->SetCoordSystem(IGameConversionManager::IGAME_OGL); 1.723 - igame->InitialiseIGame(); 1.724 - igame->SetStaticFrame(0); 1.725 - 1.726 - tstart = tend = 0; 1.727 - get_anim_bounds(igame, &tstart, &tend); 1.728 - 1.729 - if(!DialogBox(hinst, MAKEINTRESOURCE(IDD_GOAT_ANM), 0, anim_gui_handler)) { 1.730 - igame->ReleaseIGame(); 1.731 - return IMPEXP_CANCEL; 1.732 - } 1.733 - 1.734 - char fname[512]; 1.735 - wcstombs(fname, name, sizeof fname - 1); 1.736 - for(int i=0; fname[i]; i++) { 1.737 - fname[i] = tolower(fname[i]); 1.738 - } 1.739 - 1.740 - maxlog("Exporting Goat3D Animation (text) file: %s\n", fname); 1.741 - 1.742 - goat3d *goat = goat3d_create(); 1.743 - 1.744 - // process all nodes 1.745 - for(int i=0; i<igame->GetTopLevelNodeCount(); i++) { 1.746 - IGameNode *node = igame->GetTopLevelNode(i); 1.747 - process_node(goat, 0, node); 1.748 - } 1.749 - 1.750 - if(goat3d_save_anim(goat, fname) == -1) { 1.751 - goat3d_free(goat); 1.752 - igame->ReleaseIGame(); 1.753 - return IMPEXP_FAIL; 1.754 - } 1.755 - 1.756 - goat3d_free(goat); 1.757 - igame->ReleaseIGame(); 1.758 - return IMPEXP_SUCCESS; 1.759 -} 1.760 - 1.761 -static INT_PTR CALLBACK anim_gui_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam) 1.762 -{ 1.763 - switch(msg) { 1.764 - case WM_INITDIALOG: 1.765 - { 1.766 - wchar_t buf[128]; 1.767 - CheckDlgButton(win, IDC_GOAT_ANM_FULL, BST_CHECKED); 1.768 - CheckDlgButton(win, IDC_RAD_KEYS_ORIG, BST_CHECKED); 1.769 - wsprintf(buf, L"%ld", tstart); 1.770 - SetDlgItemText(win, IDC_EDIT_TSTART, buf); 1.771 - wsprintf(buf, L"%ld", tend); 1.772 - SetDlgItemText(win, IDC_EDIT_TEND, buf); 1.773 - } 1.774 - break; 1.775 - 1.776 - case WM_COMMAND: 1.777 - switch(LOWORD(wparam)) { 1.778 - case IDOK: 1.779 - EndDialog(win, 1); 1.780 - break; 1.781 - 1.782 - case IDCANCEL: 1.783 - EndDialog(win, 0); 1.784 - break; 1.785 - 1.786 - default: 1.787 - return 0; 1.788 - } 1.789 - break; 1.790 - 1.791 - default: 1.792 - return 0; 1.793 - } 1.794 - 1.795 - return 1; 1.796 -} 1.797 - 1.798 -// ------------------------------------------ 1.799 - 1.800 -class GoatClassDesc : public ClassDesc2 { 1.801 -public: 1.802 - int IsPublic() { return TRUE; } 1.803 - void *Create(BOOL loading = FALSE) { return new GoatExporter; } 1.804 - const TCHAR *ClassName() { return L"GoatExporter"; } 1.805 - SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; } 1.806 - Class_ID ClassID() { return Class_ID(0x77050f0d, 0x7d4c5ab5); } 1.807 - const TCHAR *Category() { return L"Mutant Stargoat"; } 1.808 - 1.809 - const TCHAR *InternalName() { return L"GoatExporter"; } 1.810 - HINSTANCE HInstance() { return hinst; } 1.811 -}; 1.812 - 1.813 -class GoatAnimClassDesc : public ClassDesc2 { 1.814 -public: 1.815 - int IsPublic() { return TRUE; } 1.816 - void *Create(BOOL loading = FALSE) { return new GoatAnimExporter; } 1.817 - const TCHAR *ClassName() { return L"GoatAnimExporter"; } 1.818 - SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; } 1.819 - Class_ID ClassID() { return Class_ID(0x51b94924, 0x2e0332f3); } 1.820 - const TCHAR *Category() { return L"Mutant Stargoat"; } 1.821 - 1.822 - const TCHAR *InternalName() { return L"GoatAnimExporter"; } 1.823 - HINSTANCE HInstance() { return hinst; } 1.824 -}; 1.825 - 1.826 -// TODO: make 2 class descriptors, one for goat3d, one for goat3danim 1.827 -static GoatClassDesc class_desc; 1.828 -static GoatAnimClassDesc anim_class_desc; 1.829 - 1.830 -BOOL WINAPI DllMain(HINSTANCE inst_handle, ULONG reason, void *reserved) 1.831 -{ 1.832 - if(reason == DLL_PROCESS_ATTACH) { 1.833 - hinst = inst_handle; 1.834 - DisableThreadLibraryCalls(hinst); 1.835 - } 1.836 - return TRUE; 1.837 -} 1.838 - 1.839 -extern "C" { 1.840 - 1.841 -__declspec(dllexport) const TCHAR *LibDescription() 1.842 -{ 1.843 - return L"test exporter"; 1.844 -} 1.845 - 1.846 -__declspec(dllexport) int LibNumberClasses() 1.847 -{ 1.848 - return 1; 1.849 -} 1.850 - 1.851 -__declspec(dllexport) ClassDesc *LibClassDesc(int i) 1.852 -{ 1.853 - switch(i) { 1.854 - case 0: 1.855 - return &class_desc; 1.856 - case 1: 1.857 - return &anim_class_desc; 1.858 - default: 1.859 - break; 1.860 - } 1.861 - return 0; 1.862 -} 1.863 - 1.864 -__declspec(dllexport) ULONG LibVersion() 1.865 -{ 1.866 - return Get3DSMAXVersion(); 1.867 -} 1.868 - 1.869 -__declspec(dllexport) int LibInitialize() 1.870 -{ 1.871 - static char path[1024]; 1.872 - 1.873 - SHGetFolderPathA(0, CSIDL_PERSONAL, 0, 0, path); 1.874 - strcat(path, "/testexp.log"); 1.875 - 1.876 - maxlog_open(path); 1.877 - return TRUE; 1.878 -} 1.879 - 1.880 -__declspec(dllexport) int LibShutdown() 1.881 -{ 1.882 - maxlog_close(); 1.883 - return TRUE; 1.884 -} 1.885 - 1.886 -} // extern "C" 1.887 - 1.888 - 1.889 -static const char *max_string(const MCHAR *wstr) 1.890 -{ 1.891 - if(!wstr) return 0; 1.892 - static char str[512]; 1.893 - wcstombs(str, wstr, sizeof str - 1); 1.894 - return str; 1.895 -} 1.896 \ No newline at end of file 1.897 +#include <stdio.h> 1.898 +#include <string.h> 1.899 +#include <stdlib.h> 1.900 +#include <ctype.h> 1.901 +#include <errno.h> 1.902 +#include <map> 1.903 +#include <vector> 1.904 +#include <windows.h> 1.905 +#include <shlobj.h> 1.906 +#include "max.h" 1.907 +#include "impexp.h" // SceneExport 1.908 +#include "iparamb2.h" // ClassDesc2 1.909 +#include "plugapi.h" 1.910 +#include "IGame.h" 1.911 +#include "IGameExport.h" 1.912 +#include "IGameControl.h" 1.913 +#include "IConversionmanager.h" 1.914 +#include "goat3d.h" 1.915 +#include "config.h" 1.916 +#include "logger.h" 1.917 +#include "resource.h" 1.918 + 1.919 + 1.920 +#pragma comment (lib, "core.lib") 1.921 +#pragma comment (lib, "geom.lib") 1.922 +#pragma comment (lib, "gfx.lib") 1.923 +#pragma comment (lib, "mesh.lib") 1.924 +#pragma comment (lib, "maxutil.lib") 1.925 +#pragma comment (lib, "maxscrpt.lib") 1.926 +#pragma comment (lib, "paramblk2.lib") 1.927 +#pragma comment (lib, "msxml2.lib") 1.928 +#pragma comment (lib, "igame.lib") 1.929 +#pragma comment (lib, "comctl32.lib") 1.930 + 1.931 + 1.932 +#define COPYRIGHT \ 1.933 + L"Copyright 2014 (C) John Tsiombikas - GNU General Public License v3, see COPYING for details." 1.934 +#define VERSION(major, minor) \ 1.935 + ((major) * 100 + ((minor) < 10 ? (minor) * 10 : (minor))) 1.936 + 1.937 +static INT_PTR CALLBACK scene_gui_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam); 1.938 +static INT_PTR CALLBACK anim_gui_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam); 1.939 +static void get_position_keys(IGameControl *ctrl, goat3d_node *node); 1.940 +static void get_xyz_position_keys(IGameControl *ctrl, goat3d_node *node); 1.941 +static void get_rotation_keys(IGameControl *ctrl, goat3d_node *node); 1.942 +static void get_euler_keys(IGameControl *ctrl, goat3d_node *node); 1.943 +static void get_scaling_keys(IGameControl *ctrl, goat3d_node *node); 1.944 +static const char *max_string(const MCHAR *wstr); 1.945 + 1.946 +HINSTANCE hinst; 1.947 + 1.948 +class GoatExporter : public SceneExport { 1.949 +private: 1.950 + std::map<IGameMaterial*, goat3d_material*> mtlmap; 1.951 + std::map<IGameNode*, goat3d_node*> nodemap; 1.952 + 1.953 +public: 1.954 + IGameScene *igame; 1.955 + 1.956 + int DoExport(const MCHAR *name, ExpInterface *eiface, Interface *iface, BOOL silent = FALSE, DWORD opt = 0); 1.957 + 1.958 + void process_materials(goat3d *goat); 1.959 + 1.960 + void process_node(goat3d *goat, goat3d_node *parent, IGameNode *maxnode); 1.961 + 1.962 + void process_mesh(goat3d *goat, goat3d_mesh *mesh, IGameObject *maxobj); 1.963 + void process_light(goat3d *goat, goat3d_light *light, IGameObject *maxobj); 1.964 + void process_camera(goat3d *goat, goat3d_camera *cam, IGameObject *maxobj); 1.965 + 1.966 + 1.967 + int ExtCount() { return 1; } 1.968 + const TCHAR *Ext(int n) { return L"goatsce"; } 1.969 + const TCHAR *LongDesc() { return L"Goat3D scene file"; } 1.970 + const TCHAR *ShortDesc() { return L"Goat3D"; } 1.971 + const TCHAR *AuthorName() { return L"John Tsiombikas"; } 1.972 + const TCHAR *CopyrightMessage() { return COPYRIGHT; } 1.973 + const TCHAR *OtherMessage1() { return L"other1"; } 1.974 + const TCHAR *OtherMessage2() { return L"other2"; } 1.975 + unsigned int Version() { return VERSION(VER_MAJOR, VER_MINOR); } 1.976 + void ShowAbout(HWND win) { MessageBoxA(win, "Goat3D exporter plugin", "About this plugin", 0); } 1.977 +}; 1.978 + 1.979 +class GoatAnimExporter : public GoatExporter { 1.980 +private: 1.981 +public: 1.982 + int DoExport(const MCHAR *name, ExpInterface *eiface, Interface *iface, BOOL silent = FALSE, DWORD opt = 0); 1.983 + 1.984 + const TCHAR *Ext(int n) { return L"goatanm"; } 1.985 + const TCHAR *LongDesc() { return L"Goat3D animation file"; } 1.986 +}; 1.987 + 1.988 + 1.989 +// ---- GoatExporter implementation ---- 1.990 + 1.991 +int GoatExporter::DoExport(const MCHAR *name, ExpInterface *eiface, Interface *iface, 1.992 + BOOL non_interactive, DWORD opt) 1.993 +{ 1.994 + if(!DialogBox(hinst, MAKEINTRESOURCE(IDD_GOAT_SCE), 0, scene_gui_handler)) { 1.995 + return IMPEXP_CANCEL; 1.996 + } 1.997 + 1.998 + mtlmap.clear(); 1.999 + nodemap.clear(); 1.1000 + 1.1001 + char fname[512]; 1.1002 + wcstombs(fname, name, sizeof fname - 1); 1.1003 + for(int i=0; fname[i]; i++) { 1.1004 + fname[i] = tolower(fname[i]); 1.1005 + } 1.1006 + char *basename = (char*)alloca(strlen(fname) + 1); 1.1007 + strcpy(basename, fname); 1.1008 + char *suffix = strrchr(basename, '.'); 1.1009 + if(suffix) *suffix = 0; 1.1010 + 1.1011 + maxlog("Exporting Goat3D Scene (text) file: %s\n", fname); 1.1012 + if(!(igame = GetIGameInterface())) { 1.1013 + maxlog("failed to get the igame interface\n"); 1.1014 + return IMPEXP_FAIL; 1.1015 + } 1.1016 + IGameConversionManager *cm = GetConversionManager(); 1.1017 + cm->SetCoordSystem(IGameConversionManager::IGAME_OGL); 1.1018 + igame->InitialiseIGame(); 1.1019 + 1.1020 + goat3d *goat = goat3d_create(); 1.1021 + goat3d_set_name(goat, basename); 1.1022 + 1.1023 + process_materials(goat); 1.1024 + 1.1025 + // process all nodes 1.1026 + for(int i=0; i<igame->GetTopLevelNodeCount(); i++) { 1.1027 + IGameNode *node = igame->GetTopLevelNode(i); 1.1028 + process_node(goat, 0, node); 1.1029 + } 1.1030 + 1.1031 + if(goat3d_save(goat, fname) == -1) { 1.1032 + goat3d_free(goat); 1.1033 + return IMPEXP_FAIL; 1.1034 + } 1.1035 + 1.1036 + goat3d_free(goat); 1.1037 + return IMPEXP_SUCCESS; 1.1038 +} 1.1039 + 1.1040 +void GoatExporter::process_materials(goat3d *goat) 1.1041 +{ 1.1042 + IGameProperty *prop; 1.1043 + 1.1044 + int num_mtl = igame->GetRootMaterialCount(); 1.1045 + for(int i=0; i<num_mtl; i++) { 1.1046 + IGameMaterial *maxmtl = igame->GetRootMaterial(i); 1.1047 + if(maxmtl) { 1.1048 + goat3d_material *mtl = goat3d_create_mtl(); 1.1049 + 1.1050 + const char *name = max_string(maxmtl->GetMaterialName()); 1.1051 + if(name) { 1.1052 + goat3d_set_mtl_name(mtl, name); 1.1053 + } 1.1054 + 1.1055 + // diffuse 1.1056 + if((prop = maxmtl->GetDiffuseData())) { 1.1057 + Point3 diffuse(1, 1, 1); 1.1058 + prop->GetPropertyValue(diffuse); 1.1059 + goat3d_set_mtl_attrib3f(mtl, GOAT3D_MAT_ATTR_DIFFUSE, diffuse[0], 1.1060 + diffuse[1], diffuse[2]); 1.1061 + } 1.1062 + // specular 1.1063 + if((prop = maxmtl->GetSpecularData())) { 1.1064 + Point3 specular(0, 0, 0); 1.1065 + prop->GetPropertyValue(specular); 1.1066 + 1.1067 + float sstr = 1.0; 1.1068 + if((prop = maxmtl->GetSpecularLevelData())) { 1.1069 + prop->GetPropertyValue(sstr); 1.1070 + } 1.1071 + goat3d_set_mtl_attrib3f(mtl, GOAT3D_MAT_ATTR_SPECULAR, specular[0] * sstr, 1.1072 + specular[1] * sstr, specular[2] * sstr); 1.1073 + } 1.1074 + // shininess 1.1075 + if((prop = maxmtl->GetGlossinessData())) { 1.1076 + float shin; 1.1077 + prop->GetPropertyValue(shin); 1.1078 + goat3d_set_mtl_attrib1f(mtl, GOAT3D_MAT_ATTR_SHININESS, shin * 100.0); 1.1079 + } 1.1080 + 1.1081 + // textures 1.1082 + for(int j=0; j<maxmtl->GetNumberOfTextureMaps(); j++) { 1.1083 + IGameTextureMap *tex = maxmtl->GetIGameTextureMap(j); 1.1084 + 1.1085 + const char *fname = max_string(tex->GetBitmapFileName()); 1.1086 + if(!fname) { 1.1087 + continue; 1.1088 + } 1.1089 + 1.1090 + int slot = tex->GetStdMapSlot(); 1.1091 + switch(slot) { 1.1092 + case ID_DI: // diffuse 1.1093 + goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_DIFFUSE, fname); 1.1094 + break; 1.1095 + 1.1096 + case ID_SP: 1.1097 + case ID_SS: 1.1098 + goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_SPECULAR, fname); 1.1099 + break; 1.1100 + 1.1101 + case ID_SH: 1.1102 + goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_SHININESS, fname); 1.1103 + break; 1.1104 + 1.1105 + case ID_BU: 1.1106 + goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_NORMAL, fname); 1.1107 + break; 1.1108 + 1.1109 + case ID_RL: 1.1110 + goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_REFLECTION, fname); 1.1111 + break; 1.1112 + 1.1113 + case ID_RR: 1.1114 + goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_TRANSMISSION, fname); 1.1115 + break; 1.1116 + 1.1117 + default: 1.1118 + break; 1.1119 + } 1.1120 + } 1.1121 + 1.1122 + goat3d_add_mtl(goat, mtl); 1.1123 + mtlmap[maxmtl] = mtl; 1.1124 + } 1.1125 + } 1.1126 +} 1.1127 + 1.1128 +void GoatExporter::process_node(goat3d *goat, goat3d_node *parent, IGameNode *maxnode) 1.1129 +{ 1.1130 + goat3d_node *node = goat3d_create_node(); 1.1131 + goat3d_add_node(goat, node); 1.1132 + 1.1133 + if(parent) { 1.1134 + goat3d_add_node_child(parent, node); 1.1135 + } 1.1136 + 1.1137 + const char *name = max_string(maxnode->GetName()); 1.1138 + if(name) { 1.1139 + goat3d_set_node_name(node, name); 1.1140 + } 1.1141 + 1.1142 + IGameObject *maxobj = maxnode->GetIGameObject(); 1.1143 + IGameObject::ObjectTypes type = maxobj->GetIGameType(); 1.1144 + 1.1145 + switch(type) { 1.1146 + case IGameObject::IGAME_MESH: 1.1147 + { 1.1148 + goat3d_mesh *mesh = goat3d_create_mesh(); 1.1149 + if(name) goat3d_set_mesh_name(mesh, name); 1.1150 + goat3d_set_node_object(node, GOAT3D_NODE_MESH, mesh); 1.1151 + 1.1152 + // get the node material and assign it to the mesh 1.1153 + IGameMaterial *maxmtl = maxnode->GetNodeMaterial(); 1.1154 + goat3d_material *mtl = mtlmap[maxmtl]; 1.1155 + if(mtl) { 1.1156 + goat3d_set_mesh_mtl(mesh, mtl); 1.1157 + } 1.1158 + 1.1159 + process_mesh(goat, mesh, maxobj); 1.1160 + goat3d_add_mesh(goat, mesh); 1.1161 + } 1.1162 + break; 1.1163 + 1.1164 + case IGameObject::IGAME_LIGHT: 1.1165 + { 1.1166 + goat3d_light *light = goat3d_create_light(); 1.1167 + //if(name) goat3d_set_light_name(light, name); 1.1168 + goat3d_set_node_object(node, GOAT3D_NODE_LIGHT, light); 1.1169 + 1.1170 + process_light(goat, light, maxobj); 1.1171 + goat3d_add_light(goat, light); 1.1172 + } 1.1173 + break; 1.1174 + 1.1175 + case IGameObject::IGAME_CAMERA: 1.1176 + { 1.1177 + goat3d_camera *cam = goat3d_create_camera(); 1.1178 + //if(name) goat3d_set_camera_name(camera, name); 1.1179 + goat3d_set_node_object(node, GOAT3D_NODE_CAMERA, cam); 1.1180 + 1.1181 + process_camera(goat, cam, maxobj); 1.1182 + goat3d_add_camera(goat, cam); 1.1183 + } 1.1184 + break; 1.1185 + 1.1186 + default: 1.1187 + // otherwise don't assign an object, essentially treating it as a null node 1.1188 + break; 1.1189 + } 1.1190 + 1.1191 + // grab the animation data 1.1192 + if(!dynamic_cast<GoatAnimExporter*>(this)) { 1.1193 + // no animation, just get the static PRS 1.1194 + GMatrix maxmatrix = maxnode->GetObjectTM(); 1.1195 + Point3 trans = maxmatrix.Translation(); 1.1196 + Quat rot = maxmatrix.Rotation(); 1.1197 + Point3 scale = maxmatrix.Scaling(); 1.1198 + 1.1199 + goat3d_set_node_position(node, trans.x, trans.y, trans.z, 0); 1.1200 + goat3d_set_node_rotation(node, rot.x, rot.y, rot.z, rot.w, 0); 1.1201 + goat3d_set_node_scaling(node, scale.x, scale.y, scale.z, 0); 1.1202 + 1.1203 + } else { 1.1204 + // exporting animations (if available) 1.1205 + // TODO sample keys if requested 1.1206 + IGameControl *ctrl = maxnode->GetIGameControl(); 1.1207 + if(ctrl) { 1.1208 + if(ctrl->IsAnimated(IGAME_POS) || ctrl->IsAnimated(IGAME_POS_X) || 1.1209 + ctrl->IsAnimated(IGAME_POS_Y) || ctrl->IsAnimated(IGAME_POS_Z)) { 1.1210 + get_position_keys(ctrl, node); 1.1211 + } 1.1212 + if(ctrl->IsAnimated(IGAME_ROT) || ctrl->IsAnimated(IGAME_EULER_X) || 1.1213 + ctrl->IsAnimated(IGAME_EULER_Y) || ctrl->IsAnimated(IGAME_EULER_Z)) { 1.1214 + get_rotation_keys(ctrl, node); 1.1215 + } 1.1216 + if(ctrl->IsAnimated(IGAME_SCALE)) { 1.1217 + get_scaling_keys(ctrl, node); 1.1218 + } 1.1219 + } else { 1.1220 + maxlog("%s: failed to get IGameControl for node: %s\n", __FUNCTION__, name); 1.1221 + } 1.1222 + } 1.1223 + 1.1224 + for(int i=0; i<maxnode->GetChildCount(); i++) { 1.1225 + process_node(goat, node, maxnode->GetNodeChild(i)); 1.1226 + } 1.1227 +} 1.1228 + 1.1229 +#define KEY_TIME(key) ((long)(TicksToSec(key.t) * 1000.0)) 1.1230 + 1.1231 +static void get_position_keys(IGameControl *ctrl, goat3d_node *node) 1.1232 +{ 1.1233 + const char *nodename = goat3d_get_node_name(node); 1.1234 + IGameKeyTab keys; 1.1235 + 1.1236 + if(ctrl->GetLinearKeys(keys, IGAME_POS)) { 1.1237 + maxlog("node %s: getting %d linear position keys\n", nodename, keys.Count()); 1.1238 + for(int i=0; i<keys.Count(); i++) { 1.1239 + Point3 p = keys[i].linearKey.pval; 1.1240 + goat3d_set_node_position(node, p.x, p.y, p.z, KEY_TIME(keys[i])); 1.1241 + } 1.1242 + } else if(ctrl->GetBezierKeys(keys, IGAME_POS)) { 1.1243 + maxlog("node %s: getting %d bezier position keys\n", nodename, keys.Count()); 1.1244 + for(int i=0; i<keys.Count(); i++) { 1.1245 + Point3 p = keys[i].bezierKey.pval; 1.1246 + goat3d_set_node_position(node, p.x, p.y, p.z, KEY_TIME(keys[i])); 1.1247 + } 1.1248 + } else if(ctrl->GetTCBKeys(keys, IGAME_POS)) { 1.1249 + maxlog("node %s: getting %d tcb position keys\n", nodename, keys.Count()); 1.1250 + for(int i=0; i<keys.Count(); i++) { 1.1251 + Point3 p = keys[i].tcbKey.pval; 1.1252 + goat3d_set_node_position(node, p.x, p.y, p.z, KEY_TIME(keys[i])); 1.1253 + } 1.1254 + } else { 1.1255 + get_xyz_position_keys(ctrl, node); 1.1256 + } 1.1257 +} 1.1258 + 1.1259 +static void get_xyz_position_keys(IGameControl *ctrl, goat3d_node *node) 1.1260 +{ 1.1261 + const char *nodename = goat3d_get_node_name(node); 1.1262 + IGameKeyTab keys; 1.1263 + IGameControlType postype[] = {IGAME_POS_X, IGAME_POS_Y, IGAME_POS_Z}; 1.1264 + std::map<long, Point3> pos; 1.1265 + 1.1266 + for(int i=0; i<3; i++) { 1.1267 + if(ctrl->GetLinearKeys(keys, postype[i])) { 1.1268 + maxlog("node %s: getting %d linear position %c keys\n", nodename, keys.Count(), "xyz"[i]); 1.1269 + for(int j=0; j<keys.Count(); j++) { 1.1270 + long tm = KEY_TIME(keys[j]); 1.1271 + Point3 v = pos[tm]; 1.1272 + v[i] = keys[j].linearKey.fval; 1.1273 + pos[tm] = v; 1.1274 + } 1.1275 + } else if(ctrl->GetBezierKeys(keys, postype[i])) { 1.1276 + maxlog("node %s: getting %d bezier position %c keys\n", nodename, keys.Count(), "xyz"[i]); 1.1277 + for(int j=0; j<keys.Count(); j++) { 1.1278 + long tm = KEY_TIME(keys[j]); 1.1279 + Point3 v = pos[tm]; 1.1280 + v[i] = keys[j].bezierKey.fval; 1.1281 + pos[tm] = v; 1.1282 + } 1.1283 + } else if(ctrl->GetTCBKeys(keys, postype[i])) { 1.1284 + maxlog("node %s: getting %d tcb position %c keys\n", nodename, keys.Count(), "xyz"[i]); 1.1285 + for(int j=0; j<keys.Count(); j++) { 1.1286 + long tm = KEY_TIME(keys[j]); 1.1287 + Point3 v = pos[tm]; 1.1288 + v[i] = keys[j].tcbKey.fval; 1.1289 + pos[tm] = v; 1.1290 + } 1.1291 + } 1.1292 + } 1.1293 + 1.1294 + std::map<long, Point3>::iterator it = pos.begin(); 1.1295 + while(it != pos.end()) { 1.1296 + Point3 p = it->second; 1.1297 + goat3d_set_node_position(node, p.x, p.y, p.z, it->first); 1.1298 + ++it; 1.1299 + } 1.1300 +} 1.1301 + 1.1302 +static void get_rotation_keys(IGameControl *ctrl, goat3d_node *node) 1.1303 +{ 1.1304 + const char *nodename = goat3d_get_node_name(node); 1.1305 + IGameKeyTab rkeys; 1.1306 + 1.1307 + if(ctrl->GetLinearKeys(rkeys, IGAME_ROT)) { 1.1308 + maxlog("node %s: getting %d linear rotation keys\n", nodename, rkeys.Count()); 1.1309 + for(int i=0; i<rkeys.Count(); i++) { 1.1310 + Quat q = rkeys[i].linearKey.qval; 1.1311 + goat3d_set_node_rotation(node, q.x, q.y, q.z, q.w, KEY_TIME(rkeys[i])); 1.1312 + } 1.1313 + } else if(ctrl->GetBezierKeys(rkeys, IGAME_ROT)) { 1.1314 + maxlog("node %s: getting %d bezier rotation keys\n", nodename, rkeys.Count()); 1.1315 + for(int i=0; i<rkeys.Count(); i++) { 1.1316 + Quat q = rkeys[i].bezierKey.qval; 1.1317 + goat3d_set_node_rotation(node, q.x, q.y, q.z, q.w, KEY_TIME(rkeys[i])); 1.1318 + } 1.1319 + } else if(ctrl->GetTCBKeys(rkeys, IGAME_ROT)) { 1.1320 + maxlog("node %s: getting %d TCB rotation keys\n", nodename, rkeys.Count()); 1.1321 + for(int i=0; i<rkeys.Count(); i++) { 1.1322 + Quat q(rkeys[i].tcbKey.aval); 1.1323 + goat3d_set_node_rotation(node, q.x, q.y, q.z, q.w, KEY_TIME(rkeys[i])); 1.1324 + } 1.1325 + } else { 1.1326 + get_euler_keys(ctrl, node); 1.1327 + } 1.1328 +} 1.1329 + 1.1330 +static void get_euler_keys(IGameControl *ctrl, goat3d_node *node) 1.1331 +{ 1.1332 + const char *nodename = goat3d_get_node_name(node); 1.1333 + IGameKeyTab keys; 1.1334 + IGameControlType eulertype[] = {IGAME_EULER_X, IGAME_EULER_Y, IGAME_EULER_Z}; 1.1335 + std::map<long, Point3> euler; 1.1336 + 1.1337 + for(int i=0; i<3; i++) { 1.1338 + if(ctrl->GetLinearKeys(keys, eulertype[i])) { 1.1339 + maxlog("node %s: getting %d linear euler %c keys\n", nodename, keys.Count(), "xyz"[i]); 1.1340 + for(int j=0; j<keys.Count(); j++) { 1.1341 + long tm = KEY_TIME(keys[j]); 1.1342 + Point3 v = euler[tm]; 1.1343 + v[i] = keys[j].linearKey.fval; 1.1344 + euler[tm] = v; 1.1345 + } 1.1346 + } else if(ctrl->GetBezierKeys(keys, eulertype[i])) { 1.1347 + maxlog("node %s: getting %d bezier euler %c keys\n", nodename, keys.Count(), "xyz"[i]); 1.1348 + for(int j=0; j<keys.Count(); j++) { 1.1349 + long tm = KEY_TIME(keys[j]); 1.1350 + Point3 v = euler[tm]; 1.1351 + v[i] = keys[j].bezierKey.fval; 1.1352 + euler[tm] = v; 1.1353 + } 1.1354 + } else if(ctrl->GetTCBKeys(keys, eulertype[i])) { 1.1355 + maxlog("node %s: getting %d tcb euler %c keys\n", nodename, keys.Count(), "xyz"[i]); 1.1356 + for(int j=0; j<keys.Count(); j++) { 1.1357 + long tm = KEY_TIME(keys[j]); 1.1358 + Point3 v = euler[tm]; 1.1359 + v[i] = keys[j].tcbKey.fval; 1.1360 + euler[tm] = v; 1.1361 + } 1.1362 + } 1.1363 + } 1.1364 + 1.1365 + int order = ctrl->GetEulerOrder(); 1.1366 + std::map<long, Point3>::iterator it = euler.begin(); 1.1367 + while(it != euler.end()) { 1.1368 + Quat q; 1.1369 + EulerToQuat(it->second, q, order); 1.1370 + goat3d_set_node_rotation(node, q.x, q.y, q.z, q.w, it->first); 1.1371 + ++it; 1.1372 + } 1.1373 +} 1.1374 + 1.1375 +static void get_scaling_keys(IGameControl *ctrl, goat3d_node *node) 1.1376 +{ 1.1377 + const char *nodename = goat3d_get_node_name(node); 1.1378 + IGameKeyTab keys; 1.1379 + 1.1380 + // XXX the way I'm using the ScaleValue is wrong, but fuck it... 1.1381 + 1.1382 + if(ctrl->GetLinearKeys(keys, IGAME_SCALE)) { 1.1383 + maxlog("node %s: getting %d linear scaling keys\n", nodename, keys.Count()); 1.1384 + for(int i=0; i<keys.Count(); i++) { 1.1385 + ScaleValue s = keys[i].linearKey.sval; 1.1386 + goat3d_set_node_scaling(node, s.s.x, s.s.y, s.s.z, KEY_TIME(keys[i])); 1.1387 + } 1.1388 + } else if(ctrl->GetBezierKeys(keys, IGAME_SCALE)) { 1.1389 + maxlog("node %s: getting %d bezier scaling keys\n", nodename, keys.Count()); 1.1390 + for(int i=0; i<keys.Count(); i++) { 1.1391 + ScaleValue s = keys[i].bezierKey.sval; 1.1392 + goat3d_set_node_scaling(node, s.s.x, s.s.y, s.s.z, KEY_TIME(keys[i])); 1.1393 + } 1.1394 + } else if(ctrl->GetTCBKeys(keys, IGAME_SCALE)) { 1.1395 + maxlog("node %s: getting %d tcb scaling keys\n", nodename, keys.Count()); 1.1396 + for(int i=0; i<keys.Count(); i++) { 1.1397 + ScaleValue s = keys[i].tcbKey.sval; 1.1398 + goat3d_set_node_scaling(node, s.s.x, s.s.y, s.s.z, KEY_TIME(keys[i])); 1.1399 + } 1.1400 + } 1.1401 +} 1.1402 + 1.1403 +static bool get_anim_bounds(IGameNode *node, long *tstart, long *tend); 1.1404 +static bool get_node_anim_bounds(IGameNode *node, long *tstart, long *tend); 1.1405 + 1.1406 +static bool get_anim_bounds(IGameScene *igame, long *tstart, long *tend) 1.1407 +{ 1.1408 + long tmin = LONG_MAX; 1.1409 + long tmax = LONG_MIN; 1.1410 + 1.1411 + int num_nodes = igame->GetTopLevelNodeCount(); 1.1412 + for(int i=0; i<num_nodes; i++) { 1.1413 + long t0, t1; 1.1414 + if(get_anim_bounds(igame->GetTopLevelNode(i), &t0, &t1)) { 1.1415 + if(t0 < tmin) tmin = t0; 1.1416 + if(t1 > tmax) tmax = t1; 1.1417 + } 1.1418 + } 1.1419 + 1.1420 + if(tmin != LONG_MAX) { 1.1421 + *tstart = tmin; 1.1422 + *tend = tmax; 1.1423 + return true; 1.1424 + } 1.1425 + return false; 1.1426 +} 1.1427 + 1.1428 +static bool get_anim_bounds(IGameNode *node, long *tstart, long *tend) 1.1429 +{ 1.1430 + long tmin = LONG_MAX; 1.1431 + long tmax = LONG_MIN; 1.1432 + 1.1433 + get_node_anim_bounds(node, &tmin, &tmax); 1.1434 + 1.1435 + int num_children = node->GetChildCount(); 1.1436 + for(int i=0; i<num_children; i++) { 1.1437 + long t0, t1; 1.1438 + if(get_anim_bounds(node->GetNodeChild(i), &t0, &t1)) { 1.1439 + if(t0 < tmin) tmin = t0; 1.1440 + if(t1 > tmax) tmax = t1; 1.1441 + } 1.1442 + } 1.1443 + 1.1444 + if(tmin != LONG_MAX) { 1.1445 + *tstart = tmin; 1.1446 + *tend = tmax; 1.1447 + return true; 1.1448 + } 1.1449 + return false; 1.1450 +} 1.1451 + 1.1452 +static bool get_node_anim_bounds(IGameNode *node, long *tstart, long *tend) 1.1453 +{ 1.1454 + static const IGameControlType ctypes[] = { 1.1455 + IGAME_POS, IGAME_POS_X, IGAME_POS_Y, IGAME_POS_Z, 1.1456 + IGAME_ROT, IGAME_EULER_X, IGAME_EULER_Y, IGAME_EULER_Z, 1.1457 + IGAME_SCALE 1.1458 + }; 1.1459 + 1.1460 + // NOTE: apparently if I don't call GetIGameObject, then GetIGameControl always returns null... 1.1461 + node->GetIGameObject(); 1.1462 + IGameControl *ctrl = node->GetIGameControl(); 1.1463 + if(!ctrl) { 1.1464 + maxlog("%s: failed to get IGameControl for node: %s\n", __FUNCTION__, max_string(node->GetName())); 1.1465 + return false; 1.1466 + } 1.1467 + 1.1468 + IGameKeyTab keys; 1.1469 + long t0, t1; 1.1470 + long tmin = LONG_MAX; 1.1471 + long tmax = LONG_MIN; 1.1472 + 1.1473 + for(int i=0; i<sizeof ctypes / sizeof *ctypes; i++) { 1.1474 + if(ctrl->GetBezierKeys(keys, ctypes[i]) && keys.Count()) { 1.1475 + t0 = KEY_TIME(keys[0]); 1.1476 + t1 = KEY_TIME(keys[keys.Count() - 1]); 1.1477 + if(t0 < tmin) tmin = t0; 1.1478 + if(t1 > tmax) tmax = t1; 1.1479 + } 1.1480 + if(ctrl->GetLinearKeys(keys, ctypes[i]) && keys.Count()) { 1.1481 + t0 = KEY_TIME(keys[0]); 1.1482 + t1 = KEY_TIME(keys[keys.Count() - 1]); 1.1483 + if(t0 < tmin) tmin = t0; 1.1484 + if(t1 > tmax) tmax = t1; 1.1485 + } 1.1486 + if(ctrl->GetTCBKeys(keys, ctypes[i]) && keys.Count()) { 1.1487 + t0 = KEY_TIME(keys[0]); 1.1488 + t1 = KEY_TIME(keys[keys.Count() - 1]); 1.1489 + if(t0 < tmin) tmin = t0; 1.1490 + if(t1 > tmax) tmax = t1; 1.1491 + } 1.1492 + } 1.1493 + 1.1494 + if(tmin != LONG_MAX) { 1.1495 + *tstart = tmin; 1.1496 + *tend = tmax; 1.1497 + return true; 1.1498 + } 1.1499 + return false; 1.1500 +} 1.1501 + 1.1502 +void GoatExporter::process_mesh(goat3d *goat, goat3d_mesh *mesh, IGameObject *maxobj) 1.1503 +{ 1.1504 + IGameMesh *maxmesh = (IGameMesh*)maxobj; 1.1505 + 1.1506 + maxmesh->SetCreateOptimizedNormalList(); // not needed any more according to docs 1.1507 + maxobj->InitializeData(); 1.1508 + 1.1509 + int num_verts = maxmesh->GetNumberOfVerts(); 1.1510 + int num_faces = maxmesh->GetNumberOfFaces(); 1.1511 + //assert(maxmesh->GetNumberOfTexVerts() == num_verts); 1.1512 + 1.1513 + float *vertices = new float[num_verts * 3]; 1.1514 + float *normals = new float[num_verts * 3]; 1.1515 + //float *texcoords = new float[num_verts * 2]; 1.1516 + int *indices = new int[num_faces * 3]; 1.1517 + 1.1518 + for(int i=0; i<num_verts; i++) { 1.1519 + Point3 v = maxmesh->GetVertex(i, true); 1.1520 + vertices[i * 3] = v.x; 1.1521 + vertices[i * 3 + 1] = v.y; 1.1522 + vertices[i * 3 + 2] = v.z; 1.1523 + } 1.1524 + 1.1525 + for(int i=0; i<maxmesh->GetNumberOfNormals(); i++) { 1.1526 + Point3 norm = maxmesh->GetNormal(i); 1.1527 + 1.1528 + int vidx = maxmesh->GetNormalVertexIndex(i); 1.1529 + normals[vidx * 3] = norm.x; 1.1530 + normals[vidx * 3 + 1] = norm.y; 1.1531 + normals[vidx * 3 + 2] = norm.z; 1.1532 + } 1.1533 + 1.1534 + /*for(int i=0; i<maxmesh->GetNumberOfTexVerts(); i++) { 1.1535 + Point3 tex = maxmesh->GetTexVertex(i); 1.1536 + 1.1537 + texcoords[i * 2] = tex.x; 1.1538 + texcoords[i * 2 + 1] = tex.y; 1.1539 + }*/ 1.1540 + 1.1541 + // get the faces 1.1542 + for(int i=0; i<num_faces; i++) { 1.1543 + FaceEx *face = maxmesh->GetFace(i); 1.1544 + indices[i * 3] = face->vert[0]; 1.1545 + indices[i * 3 + 1] = face->vert[1]; 1.1546 + indices[i * 3 + 2] = face->vert[2]; 1.1547 + // TODO at some point I'll have to split based on normal/texcoord indices 1.1548 + } 1.1549 + 1.1550 + goat3d_set_mesh_attribs(mesh, GOAT3D_MESH_ATTR_VERTEX, vertices, num_verts); 1.1551 + goat3d_set_mesh_attribs(mesh, GOAT3D_MESH_ATTR_NORMAL, normals, num_verts); 1.1552 + //goat3d_set_mesh_attribs(mesh, GOAT3D_MESH_ATTR_TEXCOORD, texcoords, num_verts); 1.1553 + goat3d_set_mesh_faces(mesh, indices, num_faces); 1.1554 + 1.1555 + delete [] vertices; 1.1556 + delete [] normals; 1.1557 + //delete [] texcoords; 1.1558 + delete [] indices; 1.1559 +} 1.1560 + 1.1561 +void GoatExporter::process_light(goat3d *goat, goat3d_light *light, IGameObject *maxobj) 1.1562 +{ 1.1563 + // TODO 1.1564 +} 1.1565 + 1.1566 +void GoatExporter::process_camera(goat3d *goat, goat3d_camera *cam, IGameObject *maxobj) 1.1567 +{ 1.1568 + // TODO 1.1569 +} 1.1570 + 1.1571 +static INT_PTR CALLBACK scene_gui_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam) 1.1572 +{ 1.1573 + switch(msg) { 1.1574 + case WM_INITDIALOG: 1.1575 + CheckDlgButton(win, IDC_GOAT_NODES, 1); 1.1576 + CheckDlgButton(win, IDC_GOAT_MESHES, 1); 1.1577 + CheckDlgButton(win, IDC_GOAT_LIGHTS, 1); 1.1578 + CheckDlgButton(win, IDC_GOAT_CAMERAS, 1); 1.1579 + break; 1.1580 + 1.1581 + case WM_COMMAND: 1.1582 + switch(LOWORD(wparam)) { 1.1583 + case IDOK: 1.1584 + EndDialog(win, 1); 1.1585 + break; 1.1586 + 1.1587 + case IDCANCEL: 1.1588 + EndDialog(win, 0); 1.1589 + break; 1.1590 + 1.1591 + default: 1.1592 + return 0; 1.1593 + } 1.1594 + break; 1.1595 + 1.1596 + default: 1.1597 + return 0; 1.1598 + } 1.1599 + 1.1600 + return 1; 1.1601 +} 1.1602 + 1.1603 + 1.1604 + 1.1605 +// ---- GoatAnimExporter implementation ---- 1.1606 +static long tstart, tend; 1.1607 + 1.1608 +int GoatAnimExporter::DoExport(const MCHAR *name, ExpInterface *eiface, Interface *iface, BOOL silent, DWORD opt) 1.1609 +{ 1.1610 + if(!(igame = GetIGameInterface())) { 1.1611 + maxlog("failed to get the igame interface\n"); 1.1612 + return IMPEXP_FAIL; 1.1613 + } 1.1614 + IGameConversionManager *cm = GetConversionManager(); 1.1615 + cm->SetCoordSystem(IGameConversionManager::IGAME_OGL); 1.1616 + igame->InitialiseIGame(); 1.1617 + igame->SetStaticFrame(0); 1.1618 + 1.1619 + tstart = tend = 0; 1.1620 + get_anim_bounds(igame, &tstart, &tend); 1.1621 + 1.1622 + if(!DialogBox(hinst, MAKEINTRESOURCE(IDD_GOAT_ANM), 0, anim_gui_handler)) { 1.1623 + igame->ReleaseIGame(); 1.1624 + return IMPEXP_CANCEL; 1.1625 + } 1.1626 + 1.1627 + char fname[512]; 1.1628 + wcstombs(fname, name, sizeof fname - 1); 1.1629 + for(int i=0; fname[i]; i++) { 1.1630 + fname[i] = tolower(fname[i]); 1.1631 + } 1.1632 + 1.1633 + maxlog("Exporting Goat3D Animation (text) file: %s\n", fname); 1.1634 + 1.1635 + goat3d *goat = goat3d_create(); 1.1636 + 1.1637 + // process all nodes 1.1638 + for(int i=0; i<igame->GetTopLevelNodeCount(); i++) { 1.1639 + IGameNode *node = igame->GetTopLevelNode(i); 1.1640 + process_node(goat, 0, node); 1.1641 + } 1.1642 + 1.1643 + if(goat3d_save_anim(goat, fname) == -1) { 1.1644 + goat3d_free(goat); 1.1645 + igame->ReleaseIGame(); 1.1646 + return IMPEXP_FAIL; 1.1647 + } 1.1648 + 1.1649 + goat3d_free(goat); 1.1650 + igame->ReleaseIGame(); 1.1651 + return IMPEXP_SUCCESS; 1.1652 +} 1.1653 + 1.1654 +static INT_PTR CALLBACK anim_gui_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam) 1.1655 +{ 1.1656 + switch(msg) { 1.1657 + case WM_INITDIALOG: 1.1658 + { 1.1659 + wchar_t buf[128]; 1.1660 + CheckDlgButton(win, IDC_GOAT_ANM_FULL, BST_CHECKED); 1.1661 + CheckDlgButton(win, IDC_RAD_KEYS_ORIG, BST_CHECKED); 1.1662 + wsprintf(buf, L"%ld", tstart); 1.1663 + SetDlgItemText(win, IDC_EDIT_TSTART, buf); 1.1664 + wsprintf(buf, L"%ld", tend); 1.1665 + SetDlgItemText(win, IDC_EDIT_TEND, buf); 1.1666 + } 1.1667 + break; 1.1668 + 1.1669 + case WM_COMMAND: 1.1670 + switch(LOWORD(wparam)) { 1.1671 + case IDOK: 1.1672 + EndDialog(win, 1); 1.1673 + break; 1.1674 + 1.1675 + case IDCANCEL: 1.1676 + EndDialog(win, 0); 1.1677 + break; 1.1678 + 1.1679 + default: 1.1680 + return 0; 1.1681 + } 1.1682 + break; 1.1683 + 1.1684 + default: 1.1685 + return 0; 1.1686 + } 1.1687 + 1.1688 + return 1; 1.1689 +} 1.1690 + 1.1691 +// ------------------------------------------ 1.1692 + 1.1693 +class GoatClassDesc : public ClassDesc2 { 1.1694 +public: 1.1695 + int IsPublic() { return TRUE; } 1.1696 + void *Create(BOOL loading = FALSE) { return new GoatExporter; } 1.1697 + const TCHAR *ClassName() { return L"GoatExporter"; } 1.1698 + SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; } 1.1699 + Class_ID ClassID() { return Class_ID(0x77050f0d, 0x7d4c5ab5); } 1.1700 + const TCHAR *Category() { return L"Mutant Stargoat"; } 1.1701 + 1.1702 + const TCHAR *InternalName() { return L"GoatExporter"; } 1.1703 + HINSTANCE HInstance() { return hinst; } 1.1704 +}; 1.1705 + 1.1706 +class GoatAnimClassDesc : public ClassDesc2 { 1.1707 +public: 1.1708 + int IsPublic() { return TRUE; } 1.1709 + void *Create(BOOL loading = FALSE) { return new GoatAnimExporter; } 1.1710 + const TCHAR *ClassName() { return L"GoatAnimExporter"; } 1.1711 + SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; } 1.1712 + Class_ID ClassID() { return Class_ID(0x51b94924, 0x2e0332f3); } 1.1713 + const TCHAR *Category() { return L"Mutant Stargoat"; } 1.1714 + 1.1715 + const TCHAR *InternalName() { return L"GoatAnimExporter"; } 1.1716 + HINSTANCE HInstance() { return hinst; } 1.1717 +}; 1.1718 + 1.1719 +// TODO: make 2 class descriptors, one for goat3d, one for goat3danim 1.1720 +static GoatClassDesc class_desc; 1.1721 +static GoatAnimClassDesc anim_class_desc; 1.1722 + 1.1723 +BOOL WINAPI DllMain(HINSTANCE inst_handle, ULONG reason, void *reserved) 1.1724 +{ 1.1725 + if(reason == DLL_PROCESS_ATTACH) { 1.1726 + hinst = inst_handle; 1.1727 + DisableThreadLibraryCalls(hinst); 1.1728 + } 1.1729 + return TRUE; 1.1730 +} 1.1731 + 1.1732 +extern "C" { 1.1733 + 1.1734 +__declspec(dllexport) const TCHAR *LibDescription() 1.1735 +{ 1.1736 + return L"test exporter"; 1.1737 +} 1.1738 + 1.1739 +__declspec(dllexport) int LibNumberClasses() 1.1740 +{ 1.1741 + return 1; 1.1742 +} 1.1743 + 1.1744 +__declspec(dllexport) ClassDesc *LibClassDesc(int i) 1.1745 +{ 1.1746 + switch(i) { 1.1747 + case 0: 1.1748 + return &class_desc; 1.1749 + case 1: 1.1750 + return &anim_class_desc; 1.1751 + default: 1.1752 + break; 1.1753 + } 1.1754 + return 0; 1.1755 +} 1.1756 + 1.1757 +__declspec(dllexport) ULONG LibVersion() 1.1758 +{ 1.1759 + return Get3DSMAXVersion(); 1.1760 +} 1.1761 + 1.1762 +__declspec(dllexport) int LibInitialize() 1.1763 +{ 1.1764 + static char path[1024]; 1.1765 + 1.1766 + SHGetFolderPathA(0, CSIDL_PERSONAL, 0, 0, path); 1.1767 + strcat(path, "/testexp.log"); 1.1768 + 1.1769 + maxlog_open(path); 1.1770 + return TRUE; 1.1771 +} 1.1772 + 1.1773 +__declspec(dllexport) int LibShutdown() 1.1774 +{ 1.1775 + maxlog_close(); 1.1776 + return TRUE; 1.1777 +} 1.1778 + 1.1779 +} // extern "C" 1.1780 + 1.1781 + 1.1782 +static const char *max_string(const MCHAR *wstr) 1.1783 +{ 1.1784 + if(!wstr) return 0; 1.1785 + static char str[512]; 1.1786 + wcstombs(str, wstr, sizeof str - 1); 1.1787 + return str; 1.1788 +}