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