int HSExport2::DoExport(const TCHAR *name,ExpInterface *ei,Interface *gi, BOOL suppressPrompts, DWORD options) { BOOL backupEnabled = gi->AutoBackupEnabled(); gi->EnableAutoBackup(FALSE); BOOL bmmSilentMode = TheManager->SilentMode(); TheManager->SetSilentMode(TRUE); bool mbSuppressPrompts = hsMessageBox_SuppressPrompts; hsMessageBox_SuppressPrompts = (suppressPrompts)?true:false; // Disable save so we don't crash in export or // otherwise screw database. SimpleExportExitCallback exitCB; gi->RegisterExitMAXCallback(&exitCB); gUserPropMgr.OpenQuickTable(); hsConverterUtils::Instance().CreateNodeSearchCache(); BroadcastNotification(NOTIFY_PRE_EXPORT); // get just the path (not the file) of where we are going to export to char out_path[256]; IGetPath(name, out_path); // Apparently this was implied by the open dialog, but not if you call Max's ExportToFile() func SetCurrentDirectory(out_path); // // Setup ErrorMsg // // Needs to be outside try/catch so it doesn't stack unwind... plExportErrorMsg hituser_errorMessage; // This is the errorMessage that slaps user TSTR filename = gi->GetCurFileName(); hsStrncpy(fName, filename, 128); char *dot = strrchr(fName, '.'); if (dot) *dot = 0; char ErrorLogName[512]; sprintf(ErrorLogName, "%s%s.err", out_path, fName); plExportLogErrorMsg logonly_errorMessage(ErrorLogName); // This errorMessage just writes it all to a file // now decide which errorMessage object to use plErrorMsg* errorMessage; if (suppressPrompts) errorMessage = &logonly_errorMessage; else errorMessage = &hituser_errorMessage; // For export time stats DWORD exportTime = timeGetTime(); _SYSTEMTIME tm; GetSystemTime(&tm); // // Let's get cracking! Convert the scene... // plConvertSettings settings; if (plExportDlg::Instance().IsExporting()) { settings.fDoPreshade = plExportDlg::Instance().GetDoPreshade(); settings.fPhysicalsOnly = plExportDlg::Instance().GetPhysicalsOnly(); settings.fDoLightMap = plExportDlg::Instance().GetDoLightMap(); settings.fExportPage = plExportDlg::Instance().GetExportPage(); } plConvert::Instance().Init(gi, errorMessage, &settings); // We want to incorporate any SDL changes since the last export, so we DeInit() // and re-initialize. char buf[MAX_PATH]; strcpy(buf, plMaxConfig::GetClientPath()); strcat(buf, "sdl"); plSDLMgr::GetInstance()->SetSDLDir(buf); plSDLMgr::GetInstance()->DeInit(); plSDLMgr::GetInstance()->Init(); // Add disk source for writing char datPath[MAX_PATH]; strcpy(datPath, out_path); plFileUtils::AddSlash(datPath); strcat(datPath, "dat\\"); CreateDirectory(datPath, NULL); plPluginResManager::ResMgr()->SetDataPath(datPath); if (hsgResMgr::Reset()) { plSimulationMgr::Init(); plAvatarMgr::GetInstance(); // Verify the pages here manually, since it's a separate step now plPluginResManager::ResMgr()->VerifyPages(); plPythonFileMod::SetAtConvertTime(); // Convert!!! bool convertOK = plConvert::Instance().Convert(); // Free the material cache. This will delete unused materials. hsMaterialConverter::Instance().FreeMaterialCache(out_path); if (convertOK) { // Optimize the drawables plOptimizeIterator optIterator; plPluginResManager::ResMgr()->IterateKeys( &optIterator ); // And save. plPluginResManager::ResMgr()->WriteAllPages(); // Write out a texture log file char textureLog[MAX_PATH]; sprintf(textureLog, "log\\exportedTextures_%s.log", fName); plTextureExportLog textureExportLog( textureLog ); plTextureLoggerCBack loggerCallback( &textureExportLog ); plPluginResManager::ResMgr()->IterateKeys( &loggerCallback ); textureExportLog.Write(); // Moving this to the end of writing the files out. Yes, this means that any unused mipmaps still get // written to disk, including ones loaded on preload, but it's the only way to get shared texture pages // to work without loading in the entire age worth of reffing objects. - 5.30.2002 mcn plBitmapCreator::Instance().DeInit(); } // Have the resMgr clean up after export. This includes paging out any converted pages plPluginResManager::ResMgr()->EndExport(); plSimulationMgr::Shutdown(); plAvatarMgr::ShutDown(); // Reset the resmgr so we free all the memory it allocated hsgResMgr::Reset(); } //---------------------------------------------- // Write a log entry to the Db file name for now //---------------------------------------------- hsUNIXStream dbLog; dbLog.Open(name,"at"); char str[256]; exportTime = (timeGetTime() - exportTime) / 1000; sprintf(str,"Export from Max File \"%s\" on %02d/%02d/%4d took %d:%02d\n",filename,tm.wMonth,tm.wDay,tm.wYear, exportTime/60, exportTime%60); dbLog.WriteString(str); dbLog.Close(); // Allow plugins to clean up after export BroadcastNotification(NOTIFY_POST_EXPORT); hsConverterUtils::Instance().DestroyNodeSearchCache(); gUserPropMgr.CloseQuickTable(); gi->UnRegisterExitMAXCallback(&exitCB); hsMessageBox_SuppressPrompts = mbSuppressPrompts; TheManager->SetSilentMode(bmmSilentMode); gi->EnableAutoBackup(backupEnabled); MessageBeep(MB_ICONASTERISK); return 1; }
void plMerge() { Interface *ip = GetCOREInterface(); // Get the Max filename to merge char file[MAX_PATH]; memset(&file, 0, sizeof(file)); OPENFILENAME ofn = {0}; ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = ip->GetMAXHWnd(); ofn.lpstrFilter = "3ds max (*.max)\0*.max\0\0"; ofn.nFilterIndex = 1; ofn.lpstrFile = file; ofn.nMaxFile = sizeof(file); // ofn.lpstrInitialDir = ip->GetDir(APP_SCENE_DIR); ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; ofn.lpstrTitle = "Merge"; if (!GetOpenFileName(&ofn)) return; // Don't actually merge yet, just get the names of every node in the file NameTab nodeNames; ip->MergeFromFile(file, TRUE, FALSE, FALSE, MERGE_LIST_NAMES, &nodeNames); // For each node name, search the current scene for a component with the same name. // If one is found, append "Merged" to it so its name won't cause a conflict during // the actual merge. std::vector<plMaxNode*> renamedNodes; int i; for (i = 0; i < nodeNames.Count(); i++) { plMaxNode *node = IFindComponentRecur((plMaxNode*)ip->GetRootNode(), nodeNames[i]); if (node) { char buf[256]; strcpy(buf, node->GetName()); strcat(buf, "Merged"); node->SetName(buf); renamedNodes.push_back(node); } } // Do the merge ip->MergeFromFile(file); // Rename the components back to their original names for (i = 0; i < renamedNodes.size(); i++) { char buf[256]; strcpy(buf, renamedNodes[i]->GetName()); buf[strlen(buf)-6] = '\0'; renamedNodes[i]->SetName(buf); } // Put all the components in the scene in a list std::vector<plComponentBase*> components; IFindComponentsRecur((plMaxNode*)ip->GetRootNode(), components); nodeNames.ZeroCount(); // For each component, search the scene for any other components with the same // name and type. If there are any, merge their target lists and delete one. for (i = 0; i < renamedNodes.size(); i++) { if (!renamedNodes[i]) continue; plComponentBase *oldComp = renamedNodes[i]->ConvertToComponent(); char *oldCompName = oldComp->GetINode()->GetName(); for (int j = 0; j < components.size(); j++) { plComponentBase *comp = components[j]; if (oldComp == comp) components[j] = nil; else if (comp) { const char *temp = comp->GetINode()->GetName(); if (!strcmp(oldCompName, comp->GetINode()->GetName()) && comp->ClassID() == comp->ClassID()) { IMergeComponents(comp, oldComp); nodeNames.AddName(oldCompName); continue; } } } } // Send out merge notifications again, so that the component dialog will be updated BroadcastNotification(NOTIFY_FILE_PRE_MERGE); BroadcastNotification(NOTIFY_FILE_POST_MERGE); #if 0 if (nodeNames.Count() == 0) return; // Actually calculate the size of all the merged component names, because // a static buffer could be too small in large merges uint32_t size = 0; for (i = 0; i < nodeNames.Count(); i++) size += strlen(nodeNames[i]) + 1; // Put all the component names in a list and show it to the user char *buf = new char[size+25]; strcpy(buf, "Components Merged:\n\n"); for (i = 0; i < nodeNames.Count(); i++) { strcat(buf, nodeNames[i]); strcat(buf, "\n"); } MessageBox(ip->GetMAXHWnd(), buf, "Components Merged", MB_OK); delete [] buf; #endif }