/********************************************************************** DESCRIPTION: .MOD file export CREATED BY: Boujemaa **********************************************************************/ #include "StdAfx.h" #include "resource.h" #include "ModExp.h" #include "modobject.h" HINSTANCE hInstance; int controlsInit = FALSE; CModExport* g_Eporter = NULL; TCHAR* GetString(int id) { static TCHAR stBuf[ERROR_MSG_MAX_LEN]; if (hInstance) return LoadString(hInstance, id, stBuf, ERROR_MSG_MAX_LEN) ? stBuf : NULL; return NULL; } static int Alert(int s1, int s2 = IDS_MODEXP, int option = MB_OK) { return MessageBox(g_Eporter->m_Gi->GetMAXHWnd(), GetString(s1), GetString(s2), option); } BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved) { // Hang on to this DLL's instance handle. hInstance = hinstDLL; if ( !controlsInit ) { controlsInit = TRUE; // Initialize 3ds Max's custom controls InitCustomControls(hInstance); // Initialize Windows controls InitCommonControls(); } return(TRUE); } static CModExpClassDesc _ModExpDesc; __declspec( dllexport ) const TCHAR * LibDescription() { return GetString(IDS_MODEXPDLL); } __declspec( dllexport ) int LibNumberClasses() { return 1; } __declspec( dllexport ) ClassDesc * LibClassDesc(int i) { switch(i) { case 0: return &_ModExpDesc; break; default: return 0; break; } } // Return version so can detect obsolete DLLs __declspec( dllexport ) ULONG LibVersion() { return VERSION_3DSMAX; } inline const TCHAR* CModExpClassDesc::Category() { return GetString(IDS_SCENEEXPORT); } inline SClass_ID CModExpClassDesc::SuperClassID() { return SCENE_EXPORT_CLASS_ID; } inline Class_ID CModExpClassDesc::ClassID() { return Class_ID(0x7d285801, 0x3c7b4aaa); } inline const TCHAR * CModExpClassDesc::ClassName() { return GetString(IDS_UBIMOD); } inline int CModExpClassDesc::IsPublic() { return 1; } inline void * CModExpClassDesc::Create(BOOL loading) { g_Eporter = new CModExport; return g_Eporter; } CModExport::CModExport() { m_exportSelected = 0; m_showPrompts = 1; m_Gi = NULL; m_ei = NULL; } CModExport::~CModExport() { } int CModExport::GetExportOptions(DWORD _options, BOOL _suppressPrompts) { m_showPrompts = _suppressPrompts ? FALSE : TRUE; m_exportSelected = (_options & SCENE_EXPORT_SELECTED) ? TRUE : FALSE; return 1; } int CModExport::DumpHeader(WorkFile &modFile, BOOL _isSpo) { char currentCmd[MAX_MOD_COMMAND_LEN]; { modFile.OutLine("; (c) Ubi Casablanca"); } { char filename[MAX_FILE_NAME]; _splitpath(modFile.GetFileName(), NULL, NULL, filename, NULL); if (_isSpo) { strcat(filename, ".SPO"); sprintf(currentCmd, ";.SPO (graphic Module) : %s", filename); } else { strcat(filename, ".MOD"); sprintf(currentCmd, ";.MOD (graphic Module) : %s", filename); } modFile.SetShortfName(filename); modFile.OutLine(currentCmd); } { assert(m_Gi != NULL); sprintf(currentCmd, ";Generated from file %s", m_Gi->GetCurFileName()); modFile.OutLine(currentCmd); } { struct tm *newtime; time_t aclock; time( &aclock ); // Get time in seconds newtime = localtime( &aclock ); // Convert time to struct tm form /* Print local time as a string */ sprintf( currentCmd, ";Creation date : %s", asctime( newtime ) ); modFile.OutLine(currentCmd); } /* ;Version directive, the version number is stored in file result 0 $SetCurrentFileDouble(0,"5.20") ;Unit directive, the unit is stored in file result 1 ;And correspond to the value of one unit exprimed in meter $SetCurrentFileDouble(1,1) */ modFile.OutLine(";Version directive, the version number is stored in file result 0"); modFile.OutLine("$SetCurrentFileDouble(0,\"5.20\")\n"); modFile.OutLine(";Unit directive, the unit is stored in file result 1"); modFile.OutLine(";And correspond to the value of one unit exprimed in meter"); modFile.OutLine("$SetCurrentFileDouble(1,1)\n"); return 1; } int CModExport::DumpData(WorkFile &_modFile,WorkFile &_spoFile) { // Make sure there are nodes we're interested in! // Ask the scene to enumerate all its nodes so we can determine if there are any we can use SceneEnumProc myScene(g_Eporter->m_Gi->GetTime()); m_ei->theScene->EnumTree(&myScene); // Any useful nodes? if(myScene.Count() == 0) { if(m_showPrompts) Alert(IDS_NODATATOEXPORT); return 1; } myScene.DumpGeoms(_modFile); myScene.DumpMtls(_modFile); myScene.DumpRoot(_spoFile); return 1; } int CModExport::ExportFile(const TCHAR *_filename) { TSTR LvlName; TSTR LvlPath; SplitFilename((TSTR)_filename, &LvlPath, &LvlName, NULL); strcat(LvlPath, "\\"); strcat(LvlPath, LvlName); strcat(LvlPath, ".SPO"); WorkFile modFile(_filename,"wt"); WorkFile spoFile(LvlPath,"wt"); DumpHeader(modFile); DumpHeader(spoFile, true); DumpData(modFile,spoFile); return 1; } int CModExport::DoExport(const TCHAR *filename,ExpInterface *ei,Interface *gi, BOOL suppressPrompts, DWORD options) { int result; m_Gi = gi; m_ei = ei; result = GetExportOptions(options, suppressPrompts); if (!result) return 0; result = ExportFile(filename); return result; } void CModExport::ShowAbout(HWND hWnd) { // Optional } unsigned int CModExport::Version() { // Version number * 100 (i.e. v3.01 = 301) return 100; } int CModExport::ExtCount() { return 1; } const TCHAR * CModExport::Ext(int n) { // Extensions supported for import/export modules switch(n) { case 0: return _T("MOD"); } return _T(""); } const TCHAR * CModExport::LongDesc() { // Long ASCII description (i.e. "Targa 2.0 Image File") return GetString(IDS_MODSCENEFILE); } const TCHAR * CModExport::ShortDesc() { // Short ASCII description (i.e. "Targa") return GetString(IDS_MODFILE); } const TCHAR * CModExport::AuthorName() { // ASCII Author name return GetString(IDS_UBICASA); } const TCHAR * CModExport::OtherMessage1() { // Other message #1 return _T(""); } const TCHAR * CModExport::OtherMessage2() { // Other message #2 return _T(""); } const TCHAR * CModExport::CopyrightMessage() { // ASCII Copyright message return GetString(IDS_COPYRIGHT_UBI); } void WorkFile::OutLine(char* _txtLine) { fprintf(stream, "%s\n", _txtLine); } SceneEnumProc::SceneEnumProc(TimeValue time) { m_time = time; m_count = 0; m_root = new CSuperObject(NULL); } SceneEnumProc::~SceneEnumProc() { m_GeomList.clear(); m_MatList.clear(); delete m_root; } int SceneEnumProc::callback(INode *node) { if(g_Eporter->m_exportSelected && node->Selected() == FALSE) return TREE_CONTINUE; Append(node); return TREE_CONTINUE; } void SceneEnumProc::Append(INode *_node) { if (_node->IsRootNode()) return; // find parent INode * Parentnode = _node->GetParentNode(); CSuperObject *ParentSpo; if (Parentnode->IsRootNode()) ParentSpo = m_root; else ParentSpo = m_root->findSpo(Parentnode); if (ParentSpo == NULL) { ParentSpo = m_root; } if (ParentSpo == m_root) { char NodeName[MAX_NAME_OBJ]; strcpy(NodeName,_node->GetName()); strlwr(NodeName); if ((NodeName[0] != 's') || (NodeName[1] != 'c') || (NodeName[2] != 't')) { // object not linked to any dumy assert(0); return; } } // create sop CSuperObject *NewSpo = new CSuperObject(_node); ParentSpo->AddNode(NewSpo); Object *obj = _node->EvalWorldState(m_time).obj; if (obj->CanConvertToType(triObjectClassID)) { m_GeomList.push_back(NewSpo); m_count ++; } } void SceneEnumProc::AppendMat(Mtl *_mtl) { std::list ::iterator Iter; for ( Iter = m_MatList.begin( ); Iter != m_MatList.end( ); Iter++ ) { Mtl *current = *Iter; if (current == _mtl) { return; } } m_MatList.push_back(_mtl); } void SceneEnumProc::DumpGeoms(WorkFile &modFile) { std::list ::iterator Iter; for ( Iter = m_GeomList.begin( ); Iter != m_GeomList.end( ); Iter++ ) { DumpOneGeom(modFile, *Iter); } } void SceneEnumProc::DumpRoot(WorkFile &_spoFile) { m_root->DumpSpo(_spoFile, m_time); } void SceneEnumProc::DumpMtls(WorkFile &modFile) { std::list ::iterator Iter; for ( Iter = m_MatList.begin( ); Iter != m_MatList.end( ); Iter++ ) { DumpOneMtl(modFile, *Iter); } } void SceneEnumProc::DumpOneGeom(WorkFile &modFile, CSuperObject *_node) { char currentCmd[MAX_MOD_COMMAND_LEN]; int i = 0; std::vector ::iterator IterElem; std::vector ::iterator IterFace; std::vector ::iterator IterUV; CModObject curObj(_node->m_maxNode, m_time); if (!curObj.m_ValidObj) return; int nbrElems = 0; for ( IterElem = curObj.m_elements.begin( ); IterElem != curObj.m_elements.end( ); IterElem++ ) { CModElem* elem = *IterElem; if (elem->m_Faces.size() != 0) { SceneEnumProc::AppendMat(elem->m_material); nbrElems++; } } // set spo link sprintf(currentCmd, "Geometric(\"%s^Geometric:%s\")", modFile.GetShortfName(), curObj.m_name); _node->SetGeomLink(currentCmd); // geom sprintf(currentCmd, "{Geometric:%s(%d,0,%d)", curObj.m_name, curObj.m_nbrVrtx, nbrElems); modFile.OutLine(currentCmd); // vertxs for (i = 0; i < curObj.m_Vertxs.size(); i++) { sprintf(currentCmd, "\tAddVertex(%d,\"%g\",\"%g\",\"%g\",\"%g\",\"%g\",\"%g\",0,0,0)", i, curObj.m_Vertxs[i].x, curObj.m_Vertxs[i].y, curObj.m_Vertxs[i].z, curObj.m_Vertxs[i].nx, curObj.m_Vertxs[i].ny, curObj.m_Vertxs[i].nz); modFile.OutLine(currentCmd); } // Geomelem i=0; for ( IterElem = curObj.m_elements.begin( ); IterElem != curObj.m_elements.end( ); IterElem++ ) { CModElem* elem = *IterElem; if (elem->m_Faces.size() != 0) { sprintf(currentCmd, "\tAddElement(%d,IndexedTriangles,\"*^ElementIndexedTriangles:%s_%s\")",i, curObj.m_name, elem->m_name); modFile.OutLine(currentCmd); i++; } } modFile.OutLine("}"); // elems for ( IterElem = curObj.m_elements.begin( ); IterElem != curObj.m_elements.end( ); IterElem++ ) { CModElem* elem = *IterElem; if (elem->m_Faces.size() != 0) { sprintf(currentCmd, "{ElementIndexedTriangles:%s_%s(%d,%d)", curObj.m_name, elem->m_name,elem->m_Faces.size(),elem->m_UVs.size()); modFile.OutLine(currentCmd); sprintf(currentCmd, "\tMaterial(\"*^Material:%s\")", elem->m_name); modFile.OutLine(currentCmd); i = 0; for (IterFace = elem->m_Faces.begin(); IterFace != elem->m_Faces.end(); IterFace++) { CFace* face =&(*IterFace); sprintf(currentCmd, "\tAddFaceUV(%d,%d,%d,%d,\"%g\",\"%g\",\"%g\",%d,%d,%d)", i, face->I, face->J,face->K, face->nx, face->ny,face->nz, face->IUV, face->JUV,face->KUV); modFile.OutLine(currentCmd); i++; } i = 0; for (IterUV = elem->m_UVs.begin(); IterUV != elem->m_UVs.end(); IterUV++) { CUV* uv =&(*IterUV); sprintf(currentCmd, "\tAddUV(%d,\"%g\",\"%g\")", i, uv->U, uv->V); modFile.OutLine(currentCmd); i++; } modFile.OutLine("}"); } } } void SceneEnumProc::DumpOneMtl(WorkFile &modFile, Mtl *_mtl) { char currentCmd[MAX_MOD_COMMAND_LEN]; sprintf(currentCmd, "{Material:%s", _mtl->GetName()); modFile.OutLine(currentCmd); sprintf(currentCmd, "\tType(Gouraud)"); modFile.OutLine(currentCmd); sprintf(currentCmd, "\tAmbientColor(\"%g\",\"%g\",\"%g\")", _mtl->GetAmbient().r, _mtl->GetAmbient().g, _mtl->GetAmbient().b); modFile.OutLine(currentCmd); sprintf(currentCmd, "\tDiffuseColor(\"%g\",\"%g\",\"%g\")", _mtl->GetDiffuse().r, _mtl->GetDiffuse().g, _mtl->GetDiffuse().b); modFile.OutLine(currentCmd); sprintf(currentCmd, "\tSpecularColor(\"%g\",\"%g\",\"%g\",\"%g\")", _mtl->GetSpecular().r, _mtl->GetSpecular().g, _mtl->GetSpecular().b, _mtl->GetShinStr()); modFile.OutLine(currentCmd); { BitmapTex *tx = (BitmapTex*)_mtl->GetSubTexmap(ID_DI);//ID_DI : diffuse char filename[MAX_FILE_NAME]; char ext[5]; _splitpath((char*)(tx->GetMapName()), NULL, NULL, filename, ext); sprintf(currentCmd, "\tTexture(\"%s%s\")",filename, ext); modFile.OutLine(currentCmd); } { if (((StdMat *)_mtl)->GetTwoSided()) sprintf(currentCmd, "\tBackface(OFF)"); else sprintf(currentCmd, "\tBackface(ON)"); modFile.OutLine(currentCmd); } modFile.OutLine("}"); } void CSuperObject::AddNode(CSuperObject *_node) { m_childs.push_back(_node); _node->m_Parent = this; } CSuperObject::CSuperObject(INode *_node) { if (_node != NULL) { sprintf(m_name, "SPO_%s", _node->GetName()); } else strcpy(m_name, "Root"); m_maxNode = _node; m_GeomLink = NULL; m_Parent = NULL; } CSuperObject::~CSuperObject() { std::list ::iterator Iter; for ( Iter = m_childs.begin( ); Iter != m_childs.end( ); Iter++ ) { CSuperObject *spo = *Iter; delete spo; } m_childs.clear(); if (m_GeomLink) delete m_GeomLink; } void CSuperObject::SetGeomLink(char* _GeomLink) { if (m_GeomLink == NULL) m_GeomLink = new char[MAX_MOD_COMMAND_LEN]; strcpy(m_GeomLink, _GeomLink); } char* CSuperObject::GetGeomLink() { return m_GeomLink; } CSuperObject* CSuperObject::findSpo(INode *_node) { if (m_maxNode == _node) return this; else { std::list ::iterator Iter; for ( Iter = m_childs.begin( ); Iter != m_childs.end( ); Iter++ ) { CSuperObject *spo = *Iter; CSuperObject *retSpo = spo->findSpo(_node); if (retSpo != NULL) return retSpo; } } return NULL; } void CSuperObject::DumpSpo(WorkFile &_spoFile, TimeValue _time) { char currentCmd[MAX_MOD_COMMAND_LEN]; std::list ::iterator Iter; // dump obj sprintf(currentCmd, "{SuperObject:%s", m_name); _spoFile.OutLine(currentCmd); sprintf(currentCmd, "\tPutMatrix(\"*^Matrix:%s\")", m_name); _spoFile.OutLine(currentCmd); if (GetGeomLink()) { sprintf(currentCmd, "\t%s", GetGeomLink()); _spoFile.OutLine(currentCmd); } for ( Iter = m_childs.begin( ); Iter != m_childs.end( ); Iter++ ) { CSuperObject *spo = *Iter; sprintf(currentCmd, "\tAddChild(\"*^SuperObject:%s\")", spo->m_name); _spoFile.OutLine(currentCmd); } _spoFile.OutLine("}\n"); // dump matrix sprintf(currentCmd, "{Matrix:%s", m_name); _spoFile.OutLine(currentCmd); Matrix3 NodMat; GetLocalMatrix(NodMat, _time); Point3 pos = NodMat.GetTrans(); sprintf(currentCmd, "\tMatrixTranslation(\"%g\",\"%g\",\"%g\")", pos.x, pos.y, pos.z); _spoFile.OutLine(currentCmd); /* Quat quat = node->GetObjOffsetRot(); Matrix3 RotMat; quat.MakeMatrix(RotMat); ScaleValue scaleValue = node->GetObjOffsetScale(); */ _spoFile.OutLine("}\n"); // dump childs for ( Iter = m_childs.begin( ); Iter != m_childs.end( ); Iter++ ) { CSuperObject *spo = *Iter; spo->DumpSpo(_spoFile, _time); } } void CSuperObject::GetLocalMatrix(Matrix3 &_NodMat, TimeValue _time) { if (m_maxNode != NULL) { _NodMat = m_maxNode->GetNodeTM(_time); } else { _NodMat = Matrix3(true); } if ((m_Parent != NULL) && (m_Parent->m_maxNode != NULL)) { Matrix3 temp = _NodMat; Matrix3 ip = Inverse(m_Parent->m_maxNode->GetNodeTM(_time)); _NodMat = ip * temp; } }