nuclear@73: #include nuclear@73: #include nuclear@73: #include nuclear@73: #include nuclear@73: #include nuclear@73: #include nuclear@73: #include nuclear@73: #include nuclear@73: #include nuclear@73: #include "max.h" nuclear@73: #include "impexp.h" // SceneExport nuclear@73: #include "iparamb2.h" // ClassDesc2 nuclear@73: #include "plugapi.h" nuclear@73: #include "IGame.h" nuclear@73: #include "IGameExport.h" nuclear@73: #include "IGameControl.h" nuclear@73: #include "IConversionmanager.h" nuclear@73: #include "goat3d.h" nuclear@73: #include "config.h" nuclear@73: #include "logger.h" nuclear@73: #include "resource.h" nuclear@73: nuclear@73: nuclear@73: #pragma comment (lib, "core.lib") nuclear@73: #pragma comment (lib, "geom.lib") nuclear@73: #pragma comment (lib, "gfx.lib") nuclear@73: #pragma comment (lib, "mesh.lib") nuclear@73: #pragma comment (lib, "maxutil.lib") nuclear@73: #pragma comment (lib, "maxscrpt.lib") nuclear@73: #pragma comment (lib, "paramblk2.lib") nuclear@73: #pragma comment (lib, "msxml2.lib") nuclear@73: #pragma comment (lib, "igame.lib") nuclear@73: #pragma comment (lib, "comctl32.lib") nuclear@73: nuclear@73: nuclear@73: #define COPYRIGHT \ nuclear@73: L"Copyright 2014 (C) John Tsiombikas - GNU General Public License v3, see COPYING for details." nuclear@73: #define VERSION(major, minor) \ nuclear@73: ((major) * 100 + ((minor) < 10 ? (minor) * 10 : (minor))) nuclear@73: nuclear@73: static INT_PTR CALLBACK scene_gui_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam); nuclear@73: static INT_PTR CALLBACK anim_gui_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam); nuclear@73: static void get_position_keys(IGameControl *ctrl, goat3d_node *node); nuclear@73: static void get_xyz_position_keys(IGameControl *ctrl, goat3d_node *node); nuclear@73: static void get_rotation_keys(IGameControl *ctrl, goat3d_node *node); nuclear@73: static void get_euler_keys(IGameControl *ctrl, goat3d_node *node); nuclear@73: static void get_scaling_keys(IGameControl *ctrl, goat3d_node *node); nuclear@73: static const char *max_string(const MCHAR *wstr); nuclear@73: nuclear@73: HINSTANCE hinst; nuclear@73: nuclear@73: class GoatExporter : public SceneExport { nuclear@73: private: nuclear@73: std::map mtlmap; nuclear@73: std::map nodemap; nuclear@73: nuclear@73: public: nuclear@73: IGameScene *igame; nuclear@73: nuclear@73: int DoExport(const MCHAR *name, ExpInterface *eiface, Interface *iface, BOOL silent = FALSE, DWORD opt = 0); nuclear@73: nuclear@73: void process_materials(goat3d *goat); nuclear@73: nuclear@73: void process_node(goat3d *goat, goat3d_node *parent, IGameNode *maxnode); nuclear@73: nuclear@73: void process_mesh(goat3d *goat, goat3d_mesh *mesh, IGameObject *maxobj); nuclear@73: void process_light(goat3d *goat, goat3d_light *light, IGameObject *maxobj); nuclear@73: void process_camera(goat3d *goat, goat3d_camera *cam, IGameObject *maxobj); nuclear@73: nuclear@73: nuclear@73: int ExtCount() { return 1; } nuclear@73: const TCHAR *Ext(int n) { return L"goatsce"; } nuclear@73: const TCHAR *LongDesc() { return L"Goat3D scene file"; } nuclear@73: const TCHAR *ShortDesc() { return L"Goat3D"; } nuclear@73: const TCHAR *AuthorName() { return L"John Tsiombikas"; } nuclear@73: const TCHAR *CopyrightMessage() { return COPYRIGHT; } nuclear@73: const TCHAR *OtherMessage1() { return L"other1"; } nuclear@73: const TCHAR *OtherMessage2() { return L"other2"; } nuclear@73: unsigned int Version() { return VERSION(VER_MAJOR, VER_MINOR); } nuclear@73: void ShowAbout(HWND win) { MessageBoxA(win, "Goat3D exporter plugin", "About this plugin", 0); } nuclear@73: }; nuclear@73: nuclear@73: class GoatAnimExporter : public GoatExporter { nuclear@73: private: nuclear@73: public: nuclear@73: int DoExport(const MCHAR *name, ExpInterface *eiface, Interface *iface, BOOL silent = FALSE, DWORD opt = 0); nuclear@73: nuclear@73: const TCHAR *Ext(int n) { return L"goatanm"; } nuclear@73: const TCHAR *LongDesc() { return L"Goat3D animation file"; } nuclear@73: }; nuclear@73: nuclear@73: nuclear@73: // ---- GoatExporter implementation ---- nuclear@73: nuclear@73: int GoatExporter::DoExport(const MCHAR *name, ExpInterface *eiface, Interface *iface, nuclear@73: BOOL non_interactive, DWORD opt) nuclear@73: { nuclear@73: if(!DialogBox(hinst, MAKEINTRESOURCE(IDD_GOAT_SCE), 0, scene_gui_handler)) { nuclear@73: return IMPEXP_CANCEL; nuclear@73: } nuclear@73: nuclear@73: mtlmap.clear(); nuclear@73: nodemap.clear(); nuclear@73: nuclear@73: char fname[512]; nuclear@73: wcstombs(fname, name, sizeof fname - 1); nuclear@73: for(int i=0; fname[i]; i++) { nuclear@73: fname[i] = tolower(fname[i]); nuclear@73: } nuclear@73: char *basename = (char*)alloca(strlen(fname) + 1); nuclear@73: strcpy(basename, fname); nuclear@73: char *suffix = strrchr(basename, '.'); nuclear@73: if(suffix) *suffix = 0; nuclear@73: nuclear@73: maxlog("Exporting Goat3D Scene (text) file: %s\n", fname); nuclear@73: if(!(igame = GetIGameInterface())) { nuclear@73: maxlog("failed to get the igame interface\n"); nuclear@73: return IMPEXP_FAIL; nuclear@73: } nuclear@73: IGameConversionManager *cm = GetConversionManager(); nuclear@73: cm->SetCoordSystem(IGameConversionManager::IGAME_OGL); nuclear@73: igame->InitialiseIGame(); nuclear@73: nuclear@73: goat3d *goat = goat3d_create(); nuclear@73: goat3d_set_name(goat, basename); nuclear@73: nuclear@73: process_materials(goat); nuclear@73: nuclear@73: // process all nodes nuclear@73: for(int i=0; iGetTopLevelNodeCount(); i++) { nuclear@73: IGameNode *node = igame->GetTopLevelNode(i); nuclear@73: process_node(goat, 0, node); nuclear@73: } nuclear@73: nuclear@73: if(goat3d_save(goat, fname) == -1) { nuclear@73: goat3d_free(goat); nuclear@73: return IMPEXP_FAIL; nuclear@73: } nuclear@73: nuclear@73: goat3d_free(goat); nuclear@73: return IMPEXP_SUCCESS; nuclear@73: } nuclear@73: nuclear@73: void GoatExporter::process_materials(goat3d *goat) nuclear@73: { nuclear@73: IGameProperty *prop; nuclear@73: nuclear@73: int num_mtl = igame->GetRootMaterialCount(); nuclear@73: for(int i=0; iGetRootMaterial(i); nuclear@73: if(maxmtl) { nuclear@73: goat3d_material *mtl = goat3d_create_mtl(); nuclear@73: nuclear@73: const char *name = max_string(maxmtl->GetMaterialName()); nuclear@73: if(name) { nuclear@73: goat3d_set_mtl_name(mtl, name); nuclear@73: } nuclear@73: nuclear@73: // diffuse nuclear@73: if((prop = maxmtl->GetDiffuseData())) { nuclear@73: Point3 diffuse(1, 1, 1); nuclear@73: prop->GetPropertyValue(diffuse); nuclear@73: goat3d_set_mtl_attrib3f(mtl, GOAT3D_MAT_ATTR_DIFFUSE, diffuse[0], nuclear@73: diffuse[1], diffuse[2]); nuclear@73: } nuclear@73: // specular nuclear@73: if((prop = maxmtl->GetSpecularData())) { nuclear@73: Point3 specular(0, 0, 0); nuclear@73: prop->GetPropertyValue(specular); nuclear@73: nuclear@73: float sstr = 1.0; nuclear@73: if((prop = maxmtl->GetSpecularLevelData())) { nuclear@73: prop->GetPropertyValue(sstr); nuclear@73: } nuclear@73: goat3d_set_mtl_attrib3f(mtl, GOAT3D_MAT_ATTR_SPECULAR, specular[0] * sstr, nuclear@73: specular[1] * sstr, specular[2] * sstr); nuclear@73: } nuclear@73: // shininess nuclear@73: if((prop = maxmtl->GetGlossinessData())) { nuclear@73: float shin; nuclear@73: prop->GetPropertyValue(shin); nuclear@73: goat3d_set_mtl_attrib1f(mtl, GOAT3D_MAT_ATTR_SHININESS, shin * 100.0); nuclear@73: } nuclear@73: nuclear@73: // textures nuclear@73: for(int j=0; jGetNumberOfTextureMaps(); j++) { nuclear@73: IGameTextureMap *tex = maxmtl->GetIGameTextureMap(j); nuclear@73: nuclear@73: const char *fname = max_string(tex->GetBitmapFileName()); nuclear@73: if(!fname) { nuclear@73: continue; nuclear@73: } nuclear@73: nuclear@73: int slot = tex->GetStdMapSlot(); nuclear@73: switch(slot) { nuclear@73: case ID_DI: // diffuse nuclear@73: goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_DIFFUSE, fname); nuclear@73: break; nuclear@73: nuclear@73: case ID_SP: nuclear@73: case ID_SS: nuclear@73: goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_SPECULAR, fname); nuclear@73: break; nuclear@73: nuclear@73: case ID_SH: nuclear@73: goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_SHININESS, fname); nuclear@73: break; nuclear@73: nuclear@73: case ID_BU: nuclear@73: goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_NORMAL, fname); nuclear@73: break; nuclear@73: nuclear@73: case ID_RL: nuclear@73: goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_REFLECTION, fname); nuclear@73: break; nuclear@73: nuclear@73: case ID_RR: nuclear@73: goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_TRANSMISSION, fname); nuclear@73: break; nuclear@73: nuclear@73: default: nuclear@73: break; nuclear@73: } nuclear@73: } nuclear@73: nuclear@73: goat3d_add_mtl(goat, mtl); nuclear@73: mtlmap[maxmtl] = mtl; nuclear@73: } nuclear@73: } nuclear@73: } nuclear@73: nuclear@73: void GoatExporter::process_node(goat3d *goat, goat3d_node *parent, IGameNode *maxnode) nuclear@73: { nuclear@73: goat3d_node *node = goat3d_create_node(); nuclear@73: goat3d_add_node(goat, node); nuclear@73: nuclear@73: if(parent) { nuclear@73: goat3d_add_node_child(parent, node); nuclear@73: } nuclear@73: nuclear@73: const char *name = max_string(maxnode->GetName()); nuclear@73: if(name) { nuclear@73: goat3d_set_node_name(node, name); nuclear@73: } nuclear@73: nuclear@73: IGameObject *maxobj = maxnode->GetIGameObject(); nuclear@73: IGameObject::ObjectTypes type = maxobj->GetIGameType(); nuclear@73: nuclear@73: switch(type) { nuclear@73: case IGameObject::IGAME_MESH: nuclear@73: { nuclear@73: goat3d_mesh *mesh = goat3d_create_mesh(); nuclear@73: if(name) goat3d_set_mesh_name(mesh, name); nuclear@73: goat3d_set_node_object(node, GOAT3D_NODE_MESH, mesh); nuclear@73: nuclear@73: // get the node material and assign it to the mesh nuclear@73: IGameMaterial *maxmtl = maxnode->GetNodeMaterial(); nuclear@73: goat3d_material *mtl = mtlmap[maxmtl]; nuclear@73: if(mtl) { nuclear@73: goat3d_set_mesh_mtl(mesh, mtl); nuclear@73: } nuclear@73: nuclear@73: process_mesh(goat, mesh, maxobj); nuclear@73: goat3d_add_mesh(goat, mesh); nuclear@73: } nuclear@73: break; nuclear@73: nuclear@73: case IGameObject::IGAME_LIGHT: nuclear@73: { nuclear@73: goat3d_light *light = goat3d_create_light(); nuclear@73: //if(name) goat3d_set_light_name(light, name); nuclear@73: goat3d_set_node_object(node, GOAT3D_NODE_LIGHT, light); nuclear@73: nuclear@73: process_light(goat, light, maxobj); nuclear@73: goat3d_add_light(goat, light); nuclear@73: } nuclear@73: break; nuclear@73: nuclear@73: case IGameObject::IGAME_CAMERA: nuclear@73: { nuclear@73: goat3d_camera *cam = goat3d_create_camera(); nuclear@73: //if(name) goat3d_set_camera_name(camera, name); nuclear@73: goat3d_set_node_object(node, GOAT3D_NODE_CAMERA, cam); nuclear@73: nuclear@73: process_camera(goat, cam, maxobj); nuclear@73: goat3d_add_camera(goat, cam); nuclear@73: } nuclear@73: break; nuclear@73: nuclear@73: default: nuclear@73: // otherwise don't assign an object, essentially treating it as a null node nuclear@73: break; nuclear@73: } nuclear@73: nuclear@73: // grab the animation data nuclear@73: if(!dynamic_cast(this)) { nuclear@73: // no animation, just get the static PRS nuclear@73: GMatrix maxmatrix = maxnode->GetObjectTM(); nuclear@73: Point3 trans = maxmatrix.Translation(); nuclear@73: Quat rot = maxmatrix.Rotation(); nuclear@73: Point3 scale = maxmatrix.Scaling(); nuclear@73: nuclear@73: goat3d_set_node_position(node, trans.x, trans.y, trans.z, 0); nuclear@73: goat3d_set_node_rotation(node, rot.x, rot.y, rot.z, rot.w, 0); nuclear@73: goat3d_set_node_scaling(node, scale.x, scale.y, scale.z, 0); nuclear@73: nuclear@73: } else { nuclear@73: // exporting animations (if available) nuclear@73: // TODO sample keys if requested nuclear@73: IGameControl *ctrl = maxnode->GetIGameControl(); nuclear@73: if(ctrl) { nuclear@73: if(ctrl->IsAnimated(IGAME_POS) || ctrl->IsAnimated(IGAME_POS_X) || nuclear@73: ctrl->IsAnimated(IGAME_POS_Y) || ctrl->IsAnimated(IGAME_POS_Z)) { nuclear@73: get_position_keys(ctrl, node); nuclear@73: } nuclear@73: if(ctrl->IsAnimated(IGAME_ROT) || ctrl->IsAnimated(IGAME_EULER_X) || nuclear@73: ctrl->IsAnimated(IGAME_EULER_Y) || ctrl->IsAnimated(IGAME_EULER_Z)) { nuclear@73: get_rotation_keys(ctrl, node); nuclear@73: } nuclear@73: if(ctrl->IsAnimated(IGAME_SCALE)) { nuclear@73: get_scaling_keys(ctrl, node); nuclear@73: } nuclear@73: } else { nuclear@73: maxlog("%s: failed to get IGameControl for node: %s\n", __FUNCTION__, name); nuclear@73: } nuclear@73: } nuclear@73: nuclear@73: for(int i=0; iGetChildCount(); i++) { nuclear@73: process_node(goat, node, maxnode->GetNodeChild(i)); nuclear@73: } nuclear@73: } nuclear@73: nuclear@73: #define KEY_TIME(key) ((long)(TicksToSec(key.t) * 1000.0)) nuclear@73: nuclear@73: static void get_position_keys(IGameControl *ctrl, goat3d_node *node) nuclear@73: { nuclear@73: const char *nodename = goat3d_get_node_name(node); nuclear@73: IGameKeyTab keys; nuclear@73: nuclear@73: if(ctrl->GetLinearKeys(keys, IGAME_POS)) { nuclear@73: maxlog("node %s: getting %d linear position keys\n", nodename, keys.Count()); nuclear@73: for(int i=0; iGetBezierKeys(keys, IGAME_POS)) { nuclear@73: maxlog("node %s: getting %d bezier position keys\n", nodename, keys.Count()); nuclear@73: for(int i=0; iGetTCBKeys(keys, IGAME_POS)) { nuclear@73: maxlog("node %s: getting %d tcb position keys\n", nodename, keys.Count()); nuclear@73: for(int i=0; i pos; nuclear@73: nuclear@73: for(int i=0; i<3; i++) { nuclear@73: if(ctrl->GetLinearKeys(keys, postype[i])) { nuclear@73: maxlog("node %s: getting %d linear position %c keys\n", nodename, keys.Count(), "xyz"[i]); nuclear@73: for(int j=0; jGetBezierKeys(keys, postype[i])) { nuclear@73: maxlog("node %s: getting %d bezier position %c keys\n", nodename, keys.Count(), "xyz"[i]); nuclear@73: for(int j=0; jGetTCBKeys(keys, postype[i])) { nuclear@73: maxlog("node %s: getting %d tcb position %c keys\n", nodename, keys.Count(), "xyz"[i]); nuclear@73: for(int j=0; j::iterator it = pos.begin(); nuclear@73: while(it != pos.end()) { nuclear@73: Point3 p = it->second; nuclear@73: goat3d_set_node_position(node, p.x, p.y, p.z, it->first); nuclear@73: ++it; nuclear@73: } nuclear@73: } nuclear@73: nuclear@73: static void get_rotation_keys(IGameControl *ctrl, goat3d_node *node) nuclear@73: { nuclear@73: const char *nodename = goat3d_get_node_name(node); nuclear@73: IGameKeyTab rkeys; nuclear@73: nuclear@73: if(ctrl->GetLinearKeys(rkeys, IGAME_ROT)) { nuclear@73: maxlog("node %s: getting %d linear rotation keys\n", nodename, rkeys.Count()); nuclear@73: for(int i=0; iGetBezierKeys(rkeys, IGAME_ROT)) { nuclear@73: maxlog("node %s: getting %d bezier rotation keys\n", nodename, rkeys.Count()); nuclear@73: for(int i=0; iGetTCBKeys(rkeys, IGAME_ROT)) { nuclear@73: maxlog("node %s: getting %d TCB rotation keys\n", nodename, rkeys.Count()); nuclear@73: for(int i=0; i euler; nuclear@73: nuclear@73: for(int i=0; i<3; i++) { nuclear@73: if(ctrl->GetLinearKeys(keys, eulertype[i])) { nuclear@73: maxlog("node %s: getting %d linear euler %c keys\n", nodename, keys.Count(), "xyz"[i]); nuclear@73: for(int j=0; jGetBezierKeys(keys, eulertype[i])) { nuclear@73: maxlog("node %s: getting %d bezier euler %c keys\n", nodename, keys.Count(), "xyz"[i]); nuclear@73: for(int j=0; jGetTCBKeys(keys, eulertype[i])) { nuclear@73: maxlog("node %s: getting %d tcb euler %c keys\n", nodename, keys.Count(), "xyz"[i]); nuclear@73: for(int j=0; jGetEulerOrder(); nuclear@73: std::map::iterator it = euler.begin(); nuclear@73: while(it != euler.end()) { nuclear@73: Quat q; nuclear@73: EulerToQuat(it->second, q, order); nuclear@73: goat3d_set_node_rotation(node, q.x, q.y, q.z, q.w, it->first); nuclear@73: ++it; nuclear@73: } nuclear@73: } nuclear@73: nuclear@73: static void get_scaling_keys(IGameControl *ctrl, goat3d_node *node) nuclear@73: { nuclear@73: const char *nodename = goat3d_get_node_name(node); nuclear@73: IGameKeyTab keys; nuclear@73: nuclear@73: // XXX the way I'm using the ScaleValue is wrong, but fuck it... nuclear@73: nuclear@73: if(ctrl->GetLinearKeys(keys, IGAME_SCALE)) { nuclear@73: maxlog("node %s: getting %d linear scaling keys\n", nodename, keys.Count()); nuclear@73: for(int i=0; iGetBezierKeys(keys, IGAME_SCALE)) { nuclear@73: maxlog("node %s: getting %d bezier scaling keys\n", nodename, keys.Count()); nuclear@73: for(int i=0; iGetTCBKeys(keys, IGAME_SCALE)) { nuclear@73: maxlog("node %s: getting %d tcb scaling keys\n", nodename, keys.Count()); nuclear@73: for(int i=0; iGetTopLevelNodeCount(); nuclear@73: for(int i=0; iGetTopLevelNode(i), &t0, &t1)) { nuclear@73: if(t0 < tmin) tmin = t0; nuclear@73: if(t1 > tmax) tmax = t1; nuclear@73: } nuclear@73: } nuclear@73: nuclear@73: if(tmin != LONG_MAX) { nuclear@73: *tstart = tmin; nuclear@73: *tend = tmax; nuclear@73: return true; nuclear@73: } nuclear@73: return false; nuclear@73: } nuclear@73: nuclear@73: static bool get_anim_bounds(IGameNode *node, long *tstart, long *tend) nuclear@73: { nuclear@73: long tmin = LONG_MAX; nuclear@73: long tmax = LONG_MIN; nuclear@73: nuclear@73: get_node_anim_bounds(node, &tmin, &tmax); nuclear@73: nuclear@73: int num_children = node->GetChildCount(); nuclear@73: for(int i=0; iGetNodeChild(i), &t0, &t1)) { nuclear@73: if(t0 < tmin) tmin = t0; nuclear@73: if(t1 > tmax) tmax = t1; nuclear@73: } nuclear@73: } nuclear@73: nuclear@73: if(tmin != LONG_MAX) { nuclear@73: *tstart = tmin; nuclear@73: *tend = tmax; nuclear@73: return true; nuclear@73: } nuclear@73: return false; nuclear@73: } nuclear@73: nuclear@73: static bool get_node_anim_bounds(IGameNode *node, long *tstart, long *tend) nuclear@73: { nuclear@73: static const IGameControlType ctypes[] = { nuclear@73: IGAME_POS, IGAME_POS_X, IGAME_POS_Y, IGAME_POS_Z, nuclear@73: IGAME_ROT, IGAME_EULER_X, IGAME_EULER_Y, IGAME_EULER_Z, nuclear@73: IGAME_SCALE nuclear@73: }; nuclear@73: nuclear@73: // NOTE: apparently if I don't call GetIGameObject, then GetIGameControl always returns null... nuclear@73: node->GetIGameObject(); nuclear@73: IGameControl *ctrl = node->GetIGameControl(); nuclear@73: if(!ctrl) { nuclear@73: maxlog("%s: failed to get IGameControl for node: %s\n", __FUNCTION__, max_string(node->GetName())); nuclear@73: return false; nuclear@73: } nuclear@73: nuclear@73: IGameKeyTab keys; nuclear@73: long t0, t1; nuclear@73: long tmin = LONG_MAX; nuclear@73: long tmax = LONG_MIN; nuclear@73: nuclear@73: for(int i=0; iGetBezierKeys(keys, ctypes[i]) && keys.Count()) { nuclear@73: t0 = KEY_TIME(keys[0]); nuclear@73: t1 = KEY_TIME(keys[keys.Count() - 1]); nuclear@73: if(t0 < tmin) tmin = t0; nuclear@73: if(t1 > tmax) tmax = t1; nuclear@73: } nuclear@73: if(ctrl->GetLinearKeys(keys, ctypes[i]) && keys.Count()) { nuclear@73: t0 = KEY_TIME(keys[0]); nuclear@73: t1 = KEY_TIME(keys[keys.Count() - 1]); nuclear@73: if(t0 < tmin) tmin = t0; nuclear@73: if(t1 > tmax) tmax = t1; nuclear@73: } nuclear@73: if(ctrl->GetTCBKeys(keys, ctypes[i]) && keys.Count()) { nuclear@73: t0 = KEY_TIME(keys[0]); nuclear@73: t1 = KEY_TIME(keys[keys.Count() - 1]); nuclear@73: if(t0 < tmin) tmin = t0; nuclear@73: if(t1 > tmax) tmax = t1; nuclear@73: } nuclear@73: } nuclear@73: nuclear@73: if(tmin != LONG_MAX) { nuclear@73: *tstart = tmin; nuclear@73: *tend = tmax; nuclear@73: return true; nuclear@73: } nuclear@73: return false; nuclear@73: } nuclear@73: nuclear@73: void GoatExporter::process_mesh(goat3d *goat, goat3d_mesh *mesh, IGameObject *maxobj) nuclear@73: { nuclear@73: IGameMesh *maxmesh = (IGameMesh*)maxobj; nuclear@73: nuclear@73: maxmesh->SetCreateOptimizedNormalList(); // not needed any more according to docs nuclear@73: maxobj->InitializeData(); nuclear@73: nuclear@73: int num_verts = maxmesh->GetNumberOfVerts(); nuclear@73: int num_faces = maxmesh->GetNumberOfFaces(); nuclear@73: //assert(maxmesh->GetNumberOfTexVerts() == num_verts); nuclear@73: nuclear@73: float *vertices = new float[num_verts * 3]; nuclear@73: float *normals = new float[num_verts * 3]; nuclear@73: //float *texcoords = new float[num_verts * 2]; nuclear@73: int *indices = new int[num_faces * 3]; nuclear@73: nuclear@73: for(int i=0; iGetVertex(i, true); nuclear@73: vertices[i * 3] = v.x; nuclear@73: vertices[i * 3 + 1] = v.y; nuclear@73: vertices[i * 3 + 2] = v.z; nuclear@73: } nuclear@73: nuclear@73: for(int i=0; iGetNumberOfNormals(); i++) { nuclear@73: Point3 norm = maxmesh->GetNormal(i); nuclear@73: nuclear@73: int vidx = maxmesh->GetNormalVertexIndex(i); nuclear@73: normals[vidx * 3] = norm.x; nuclear@73: normals[vidx * 3 + 1] = norm.y; nuclear@73: normals[vidx * 3 + 2] = norm.z; nuclear@73: } nuclear@73: nuclear@73: /*for(int i=0; iGetNumberOfTexVerts(); i++) { nuclear@73: Point3 tex = maxmesh->GetTexVertex(i); nuclear@73: nuclear@73: texcoords[i * 2] = tex.x; nuclear@73: texcoords[i * 2 + 1] = tex.y; nuclear@73: }*/ nuclear@73: nuclear@73: // get the faces nuclear@73: for(int i=0; iGetFace(i); nuclear@73: indices[i * 3] = face->vert[0]; nuclear@73: indices[i * 3 + 1] = face->vert[1]; nuclear@73: indices[i * 3 + 2] = face->vert[2]; nuclear@73: // TODO at some point I'll have to split based on normal/texcoord indices nuclear@73: } nuclear@73: nuclear@73: goat3d_set_mesh_attribs(mesh, GOAT3D_MESH_ATTR_VERTEX, vertices, num_verts); nuclear@73: goat3d_set_mesh_attribs(mesh, GOAT3D_MESH_ATTR_NORMAL, normals, num_verts); nuclear@73: //goat3d_set_mesh_attribs(mesh, GOAT3D_MESH_ATTR_TEXCOORD, texcoords, num_verts); nuclear@73: goat3d_set_mesh_faces(mesh, indices, num_faces); nuclear@73: nuclear@73: delete [] vertices; nuclear@73: delete [] normals; nuclear@73: //delete [] texcoords; nuclear@73: delete [] indices; nuclear@73: } nuclear@73: nuclear@73: void GoatExporter::process_light(goat3d *goat, goat3d_light *light, IGameObject *maxobj) nuclear@73: { nuclear@73: // TODO nuclear@73: } nuclear@73: nuclear@73: void GoatExporter::process_camera(goat3d *goat, goat3d_camera *cam, IGameObject *maxobj) nuclear@73: { nuclear@73: // TODO nuclear@73: } nuclear@73: nuclear@73: static INT_PTR CALLBACK scene_gui_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam) nuclear@73: { nuclear@73: switch(msg) { nuclear@73: case WM_INITDIALOG: nuclear@73: CheckDlgButton(win, IDC_GOAT_NODES, 1); nuclear@73: CheckDlgButton(win, IDC_GOAT_MESHES, 1); nuclear@73: CheckDlgButton(win, IDC_GOAT_LIGHTS, 1); nuclear@73: CheckDlgButton(win, IDC_GOAT_CAMERAS, 1); nuclear@73: break; nuclear@73: nuclear@73: case WM_COMMAND: nuclear@73: switch(LOWORD(wparam)) { nuclear@73: case IDOK: nuclear@73: EndDialog(win, 1); nuclear@73: break; nuclear@73: nuclear@73: case IDCANCEL: nuclear@73: EndDialog(win, 0); nuclear@73: break; nuclear@73: nuclear@73: default: nuclear@73: return 0; nuclear@73: } nuclear@73: break; nuclear@73: nuclear@73: default: nuclear@73: return 0; nuclear@73: } nuclear@73: nuclear@73: return 1; nuclear@73: } nuclear@73: nuclear@73: nuclear@73: nuclear@73: // ---- GoatAnimExporter implementation ---- nuclear@73: static long tstart, tend; nuclear@73: nuclear@73: int GoatAnimExporter::DoExport(const MCHAR *name, ExpInterface *eiface, Interface *iface, BOOL silent, DWORD opt) nuclear@73: { nuclear@73: if(!(igame = GetIGameInterface())) { nuclear@73: maxlog("failed to get the igame interface\n"); nuclear@73: return IMPEXP_FAIL; nuclear@73: } nuclear@73: IGameConversionManager *cm = GetConversionManager(); nuclear@73: cm->SetCoordSystem(IGameConversionManager::IGAME_OGL); nuclear@73: igame->InitialiseIGame(); nuclear@73: igame->SetStaticFrame(0); nuclear@73: nuclear@73: tstart = tend = 0; nuclear@73: get_anim_bounds(igame, &tstart, &tend); nuclear@73: nuclear@73: if(!DialogBox(hinst, MAKEINTRESOURCE(IDD_GOAT_ANM), 0, anim_gui_handler)) { nuclear@73: igame->ReleaseIGame(); nuclear@73: return IMPEXP_CANCEL; nuclear@73: } nuclear@73: nuclear@73: char fname[512]; nuclear@73: wcstombs(fname, name, sizeof fname - 1); nuclear@73: for(int i=0; fname[i]; i++) { nuclear@73: fname[i] = tolower(fname[i]); nuclear@73: } nuclear@73: nuclear@73: maxlog("Exporting Goat3D Animation (text) file: %s\n", fname); nuclear@73: nuclear@73: goat3d *goat = goat3d_create(); nuclear@73: nuclear@73: // process all nodes nuclear@73: for(int i=0; iGetTopLevelNodeCount(); i++) { nuclear@73: IGameNode *node = igame->GetTopLevelNode(i); nuclear@73: process_node(goat, 0, node); nuclear@73: } nuclear@73: nuclear@73: if(goat3d_save_anim(goat, fname) == -1) { nuclear@73: goat3d_free(goat); nuclear@73: igame->ReleaseIGame(); nuclear@73: return IMPEXP_FAIL; nuclear@73: } nuclear@73: nuclear@73: goat3d_free(goat); nuclear@73: igame->ReleaseIGame(); nuclear@73: return IMPEXP_SUCCESS; nuclear@73: } nuclear@73: nuclear@73: static INT_PTR CALLBACK anim_gui_handler(HWND win, unsigned int msg, WPARAM wparam, LPARAM lparam) nuclear@73: { nuclear@73: switch(msg) { nuclear@73: case WM_INITDIALOG: nuclear@73: { nuclear@73: wchar_t buf[128]; nuclear@73: CheckDlgButton(win, IDC_GOAT_ANM_FULL, BST_CHECKED); nuclear@73: CheckDlgButton(win, IDC_RAD_KEYS_ORIG, BST_CHECKED); nuclear@73: wsprintf(buf, L"%ld", tstart); nuclear@73: SetDlgItemText(win, IDC_EDIT_TSTART, buf); nuclear@73: wsprintf(buf, L"%ld", tend); nuclear@73: SetDlgItemText(win, IDC_EDIT_TEND, buf); nuclear@73: } nuclear@73: break; nuclear@73: nuclear@73: case WM_COMMAND: nuclear@73: switch(LOWORD(wparam)) { nuclear@73: case IDOK: nuclear@73: EndDialog(win, 1); nuclear@73: break; nuclear@73: nuclear@73: case IDCANCEL: nuclear@73: EndDialog(win, 0); nuclear@73: break; nuclear@73: nuclear@73: default: nuclear@73: return 0; nuclear@73: } nuclear@73: break; nuclear@73: nuclear@73: default: nuclear@73: return 0; nuclear@73: } nuclear@73: nuclear@73: return 1; nuclear@73: } nuclear@73: nuclear@73: // ------------------------------------------ nuclear@73: nuclear@73: class GoatClassDesc : public ClassDesc2 { nuclear@73: public: nuclear@73: int IsPublic() { return TRUE; } nuclear@73: void *Create(BOOL loading = FALSE) { return new GoatExporter; } nuclear@73: const TCHAR *ClassName() { return L"GoatExporter"; } nuclear@73: SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; } nuclear@73: Class_ID ClassID() { return Class_ID(0x77050f0d, 0x7d4c5ab5); } nuclear@73: const TCHAR *Category() { return L"Mutant Stargoat"; } nuclear@73: nuclear@73: const TCHAR *InternalName() { return L"GoatExporter"; } nuclear@73: HINSTANCE HInstance() { return hinst; } nuclear@73: }; nuclear@73: nuclear@73: class GoatAnimClassDesc : public ClassDesc2 { nuclear@73: public: nuclear@73: int IsPublic() { return TRUE; } nuclear@73: void *Create(BOOL loading = FALSE) { return new GoatAnimExporter; } nuclear@73: const TCHAR *ClassName() { return L"GoatAnimExporter"; } nuclear@73: SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; } nuclear@73: Class_ID ClassID() { return Class_ID(0x51b94924, 0x2e0332f3); } nuclear@73: const TCHAR *Category() { return L"Mutant Stargoat"; } nuclear@73: nuclear@73: const TCHAR *InternalName() { return L"GoatAnimExporter"; } nuclear@73: HINSTANCE HInstance() { return hinst; } nuclear@73: }; nuclear@73: nuclear@73: // TODO: make 2 class descriptors, one for goat3d, one for goat3danim nuclear@73: static GoatClassDesc class_desc; nuclear@73: static GoatAnimClassDesc anim_class_desc; nuclear@73: nuclear@73: BOOL WINAPI DllMain(HINSTANCE inst_handle, ULONG reason, void *reserved) nuclear@73: { nuclear@73: if(reason == DLL_PROCESS_ATTACH) { nuclear@73: hinst = inst_handle; nuclear@73: DisableThreadLibraryCalls(hinst); nuclear@73: } nuclear@73: return TRUE; nuclear@73: } nuclear@73: nuclear@73: extern "C" { nuclear@73: nuclear@73: __declspec(dllexport) const TCHAR *LibDescription() nuclear@73: { nuclear@73: return L"test exporter"; nuclear@73: } nuclear@73: nuclear@73: __declspec(dllexport) int LibNumberClasses() nuclear@73: { nuclear@73: return 1; nuclear@73: } nuclear@73: nuclear@73: __declspec(dllexport) ClassDesc *LibClassDesc(int i) nuclear@73: { nuclear@73: switch(i) { nuclear@73: case 0: nuclear@73: return &class_desc; nuclear@73: case 1: nuclear@73: return &anim_class_desc; nuclear@73: default: nuclear@73: break; nuclear@73: } nuclear@73: return 0; nuclear@73: } nuclear@73: nuclear@73: __declspec(dllexport) ULONG LibVersion() nuclear@73: { nuclear@73: return Get3DSMAXVersion(); nuclear@73: } nuclear@73: nuclear@73: __declspec(dllexport) int LibInitialize() nuclear@73: { nuclear@73: static char path[1024]; nuclear@73: nuclear@73: SHGetFolderPathA(0, CSIDL_PERSONAL, 0, 0, path); nuclear@73: strcat(path, "/testexp.log"); nuclear@73: nuclear@73: maxlog_open(path); nuclear@73: return TRUE; nuclear@73: } nuclear@73: nuclear@73: __declspec(dllexport) int LibShutdown() nuclear@73: { nuclear@73: maxlog_close(); nuclear@73: return TRUE; nuclear@73: } nuclear@73: nuclear@73: } // extern "C" nuclear@73: nuclear@73: nuclear@73: static const char *max_string(const MCHAR *wstr) nuclear@73: { nuclear@73: if(!wstr) return 0; nuclear@73: static char str[512]; nuclear@73: wcstombs(str, wstr, sizeof str - 1); nuclear@73: return str; nuclear@73: }