//************************************************************************** //* Max2Nmo.cpp - Virtools File Exporter //* //* Romain Sididris - Copyright (c) Virtools 2000 //* //* (Based on Ascii File Exporter source code //* By Christer Janson //* Kinetix Development //* Copyright (c) Kinetix 1997, All Rights Reserved. ) //* //* This module contains the DLL startup functions //* //*************************************************************************** #include "Precomp.h" #include "Max2Nmo.h" #include "float.h" #ifdef _USESCRIPTS_ #include "PropertiesEvaluator.h" #include "Special Parameter Registration.h" #include "Special Parameter Registration2.h" #endif #ifdef CK_LIB #include "CKLibIncludes.h" #endif HINSTANCE hInstance; int controlsInit = FALSE; BOOL VirtoolsPluginsParsed = FALSE; static BOOL exportSelected; #define MAX2NMO_CLASS_ID Class_ID(0x2dee0760, 0x75462793) //--------------------------------------- // Character Studio 3.12 headers are not // compatible with previous version need to // add a version check ! // // In Version 4.2 of 3dsMax we automatically consider that we use Character studio 3.2 BOOL g_CharacterStudio312; //---------------------------------------- //--------------- Add MAXScript Function #include "MAXScrpt.h" #include "definsfn.h" def_visible_primitive( Export2NMO,"export2nmo"); Value *Export2NMO_cf( Value** arg_list, int count ) { int CmdArgCnt=46; if(count<3) { TSTR usage; mprintf(_T("export2Nmo: Invalid Argument Count. Wanted %d and got only %d.\n"),CmdArgCnt, count); //The Max Script command arguments try to match the file save format... new arguments being add at the end usage.append( _T("usage: export2Nmo\n")); /*00*/ usage.append( _T("[string filename]\n")); /*01*/ usage.append( _T("[BOOL onlySelected]\n")); /*02*/ usage.append( _T("[int exportAs]\n")); /*03*/ usage.append( _T("[BOOL convertToSkin]\n")); /*04*/ usage.append( _T("[BOOL storeOnlyTextureFileName]\n")); /*05*/ usage.append( _T("[BOOL unitIsMeter]\n")); /*06*/ usage.append( _T("[int reportLevel]\n")); /*07*/ usage.append( _T("[int samplingStepForDeformables]\n")); /*08*/ usage.append( _T("[int samplingStepForKeyFrames]\n")); /*09*/ usage.append( _T("[string characterName]\n")); /*10*/ usage.append( _T("[string animationName]\n")); /*11*/ usage.append( _T("[BOOL groupToPlace]\n")); /*12*/ usage.append( _T("[BOOL saveBipedGeom]\n")); /*13*/ usage.append( _T("[int compressionLevel]\n")); /*14*/ usage.append( _T("[BOOL alignAnimOnZ]\n")); /*15*/ usage.append( _T("[BOOL reduceRedondantKeys]\n")); /*16*/ usage.append( _T("[BOOL shellMaterialExportBoth]\n")); /*17*/ usage.append( _T("[BOOL ignore1KeyAnimation]\n")); /*18*/ usage.append( _T("[BOOL exportAnimation]\n")); /*19*/ usage.append( _T("[float reduceKeysThreshold]\n")); /*20*/ usage.append( _T("[BOOL forceAllUVs]\n")); /*21*/ usage.append( _T("[BOOL splitMesh]\n")); /*22*/ usage.append( _T("[BOOL LOD]\n")); /*23*/ usage.append( _T("[BOOL splinesAsDummies]\n")); /*24*/ usage.append( _T("[BOOL exportAlphaMap]\n")); /*25*/ usage.append( _T("[BOOL usePower2]\n")); /*26*/ usage.append( _T("[BOOL force1x1Ratio]\n")); /*27*/ usage.append( _T("[int resizeMethod (NearestPowerOfTwo=0, LowerPowerOfTwo=1, HigherPowerOfTwo=2)]\n")); /*28*/ usage.append( _T("[BOOL deactivateMeshChannels]\n")); /*29*/ usage.append( _T("[BOOL hideHelpers]\n")); /*30*/ usage.append( _T("[BOOL DASIAnimation]\n")); /*31*/ usage.append( _T("[BOOL DASIMesh]\n")); /*32*/ usage.append( _T("[BOOL DASIMaterial]\n")); /*33*/ usage.append( _T("[BOOL DASITexture]\n")); /*34*/ usage.append( _T("[string startingCameraName]\n")); /*35*/ usage.append( _T("[BOOL SelectionAsGroup]\n")); //??????????????? was not saved /*36*/ usage.append( _T("[BOOL ReadChannels]\n")); /*37*/ usage.append( _T("[string ReadChannelsFilename]\n")); /*38*/ usage.append( _T("[BOOL ReportToFile]\n")); /*39*/ usage.append( _T("[string ReportFilename]\n")); /*40*/ usage.append( _T("[BOOL ExportBlendShapes]\n")); /*41*/ usage.append( _T("[BOOL ExportBlendShapeAnims]\n")); /*42*/ usage.append( _T("[BOOL IncludeBlendShapesInMorphController]\n")); /*43*/ usage.append( _T("[BOOL reduceRedondantBlendShapesKeys]\n")); /*44*/ usage.append( _T("[float reduceBlendShapesKeysThreshold]\n")); /*45*/ usage.append( _T("[int samplingStepForBlendShapes]\n")); mprintf(usage); return ∅ } int i=-1; // "filename" ++i; char *fileName = arg_list[i]->to_string();//00 // retrieve the extension of the file char fileExt[5]; if(strlen(fileName) > 4) memcpy(fileExt, fileName + strlen(fileName) -4, 5); else fileExt[0] = 0; if(stricmp(fileExt, ".nmo") && stricmp(fileExt, ".cmo") && stricmp(fileExt, ".vmo")) { mprintf(_T("export2Nmo: Invalid File Extension Type! (Waiting for .nmo, .cmo or .vmo)")); return ∅ } ClassDesc *aed = GetAsciiExpDesc(); Max2Nmo *exp = (Max2Nmo *)aed->Create(); // [BOOL onlySelected] ++i; BOOL exportSelected = arg_list[i]->to_bool();//01 // [int exportAs] ++i; int exportAs = arg_list[i]->to_int();//02 //if the max script user use an invalid number... use a default value if( exportAs<1 || exportAs>4) exportAs = 1; if(stricmp(fileExt, ".nmo") == 0 && exportAs == 4) { MessageBox(NULL, "Cannot export As Level in NMO !\nSwitching automatically to Export As Objects.", "Max2Nmo", MB_OK); exportAs = 1; } else if(stricmp(fileExt, ".nmo") && exportAs != 4) { MessageBox(NULL, "Can only export As Level in CMO or VMO !\nSwitching automatically to Export As Level.", "Max2Nmo", MB_OK); exportAs = 4; } exp->SetExportAsObjects( exportAs==1 ); exp->SetExportAsCharacter( exportAs==2 ); exp->SetExportAsAnimationOnly( exportAs==3 ); exp->SetExportAsLevel( exportAs==4 ); #define READ_BOOL_PARAM( fct ) ++i; if(ifct( arg_list[i]->to_bool() ); #define READ_INT_PARAM( fct ) ++i; if(ifct( arg_list[i]->to_int() ); #define READ_STRING_PARAM( fct )++i; if(ifct( arg_list[i]->to_string() ); #define READ_FLOAT_PARAM( fct ) ++i; if(ifct( arg_list[i]->to_float() ); READ_BOOL_PARAM( SetConvertPhysiqueToSkin );//03 READ_BOOL_PARAM( SetStoreOnlyFilenames ); READ_BOOL_PARAM( SetRescaleScene ); READ_INT_PARAM( SetReportLevel ); READ_INT_PARAM( SetMeshFrameStep ); READ_INT_PARAM( SetKeyFrameStep ); READ_STRING_PARAM( SetCharacterName ); READ_STRING_PARAM( SetAnimationName ); //10 READ_BOOL_PARAM( SetGroupAsPlace ); READ_BOOL_PARAM( SetSaveBipedGeom ); READ_INT_PARAM( SetCompressionLevel ); READ_BOOL_PARAM( SetbAlignAnimOnZ ); READ_BOOL_PARAM( SetReduceRedondantKeys ); READ_BOOL_PARAM( SetShellMaterialAsSingle ); READ_BOOL_PARAM( SetIgnore1Keyanimation ); READ_BOOL_PARAM( SetExportAnimation ); READ_FLOAT_PARAM( SetKeysThreshold ); //20 READ_BOOL_PARAM( SetForceAllUVs ); READ_BOOL_PARAM( SetSplitMesh ); READ_BOOL_PARAM( SetLOD ); READ_BOOL_PARAM( SetSplinesAsDummies ); READ_BOOL_PARAM( SetExportAlphaMap ); READ_BOOL_PARAM( SetUsePower2 ); READ_BOOL_PARAM( SetForce1x1Ratio ); READ_INT_PARAM( SetForce1x1RatioMethod ); READ_BOOL_PARAM( SetDeactivateMeshChannels ); READ_BOOL_PARAM( SetHideHelpers ); READ_BOOL_PARAM( SetDASIAnimation ); //30 READ_BOOL_PARAM( SetDASIMesh ); READ_BOOL_PARAM( SetDASIMaterial ); READ_BOOL_PARAM( SetDASITexture ); READ_STRING_PARAM( SetStartingCamera ); READ_BOOL_PARAM( SetSelectionAsGroup ); //36 READ_BOOL_PARAM( SetReadChannels ); READ_STRING_PARAM( SetReadChannelsFilename ); //38 READ_BOOL_PARAM( SetReport ); READ_STRING_PARAM( SetReportFilename ); //40 READ_BOOL_PARAM( SetExportBlendShapes ); //41 READ_BOOL_PARAM( SetExportBlendShapeAnims ); //42 READ_BOOL_PARAM( SetIncludeBlendShapesInMorphController ); //42 READ_BOOL_PARAM( SetReduceRedondantBlendShapesKeys ); // 43 READ_FLOAT_PARAM( SetBlendShapesKeysThreshold ); // 44 READ_INT_PARAM( SetBlendShapesStep ); // 45 //--- Really Do Export exp->SetShowProgressionBar( FALSE ); exp->ReallyDoExport( fileName, MAXScript_interface, exportSelected ); delete exp; return &ok; } //---------------------------------------- #ifdef _USESCRIPTS_ #undef new #undef delete //---------------------------------------- //--------------- Add Virtools Tool Button #include "Maxscrpt\Parser.h" #include "utilapi.h" #define VIRTOOLSTOOL_CLASS_ID Class_ID(0x6c7e7fe9,0x379a5550) class VirtoolsTool : public UtilityObj { public: XString m_ExportFileName; public: VirtoolsTool(); ~VirtoolsTool(); void BeginEditParams(Interface *ip,IUtil *iu); void EndEditParams(Interface *ip,IUtil *iu); void DeleteThis() {} }; static VirtoolsTool theVirtoolsTool; class VirtoolsToolClassDesc:public ClassDesc { public: int IsPublic() {return 1;} void * Create(BOOL loading = FALSE) {return &theVirtoolsTool;} const TCHAR * ClassName() {return _T("Virtools Exporter");} SClass_ID SuperClassID() {return UTILITY_CLASS_ID;} Class_ID ClassID() {return VIRTOOLSTOOL_CLASS_ID;} const TCHAR* Category() {return _T("");} }; static VirtoolsToolClassDesc VirtoolsToolDesc; ClassDesc* GetVirtoolsToolDesc(){ return &VirtoolsToolDesc; } VirtoolsTool::VirtoolsTool(){ m_ExportFileName = ""; } VirtoolsTool::~VirtoolsTool(){ } void VirtoolsTool::BeginEditParams(Interface *ip,IUtil *iu) { CharStream *out = thread_local(current_stdout); Parser *parser = new Parser (out); // First instruction to know where we came from XString initInst("global alreadyGivenFileName = "); StringStream *initSource = new StringStream; if( m_ExportFileName.Length() ){ initSource->init( (initInst + "\"" + m_ExportFileName + "\"").Str() ); } else { initSource->init( (initInst + "undefined").Str() ); } Value *code = parser->compile( initSource ); Value *result = code->eval(); delete initSource; XString maxScriptDir(ip->GetDir(APP_SCRIPTS_DIR)); FileStream *source = (new FileStream)->open( (maxScriptDir + "\\CKInstScripts\\VirtoolsUtility.ms").Str() , "rt"); BOOL quiet=TRUE; if (!quiet) source->log_to(out); // loop through file compiling and evaluating all expressions try { //source->flush_whitespace(); while (!source->at_eos()) { code = parser->compile(source); result = code->eval(); if (!quiet) result->print(); //source->flush_whitespace(); } source->close(); } catch (...) { // catch any errors and tell what file we are in if any out->printf("Error occurred in file: "); source->sprin1(out); out->printf("\n"); //throw; } /* code = parser->compile_all(source); result = code->eval(); source->close(); */ delete parser; m_ExportFileName = ""; } void VirtoolsTool::EndEditParams(Interface *ip,IUtil *iu) { } //---------------------------------------- #endif //_USESCRIPTS_ BOOL GetVersionInfo(char *file,DWORD& Version1,DWORD& Version2,DWORD& Version3,DWORD& Version4) { DWORD dwVerHnd; DWORD dwVerInfoSize; long resMOld = 327680; int ret = -1; dwVerInfoSize = GetFileVersionInfoSize(file, &dwVerHnd); if (dwVerInfoSize){ // If we were able to get the information, process it: HANDLE hMem; LPVOID lpvMem; BOOL fRet; UINT cchVer = 0; VS_FIXEDFILEINFO *vInfo; hMem = GlobalAlloc(GMEM_MOVEABLE, dwVerInfoSize); lpvMem = GlobalLock(hMem); GetFileVersionInfo(file, dwVerHnd, dwVerInfoSize, lpvMem); fRet = VerQueryValue(lpvMem, TEXT("\\"), (LPVOID*)&vInfo, &cchVer); if (fRet && cchVer && vInfo) { vInfo->dwFileVersionMS; vInfo->dwFileVersionLS; Version1 = HIWORD(vInfo->dwFileVersionMS); Version2 = LOWORD(vInfo->dwFileVersionMS); Version3 = HIWORD(vInfo->dwFileVersionLS); Version4 = LOWORD(vInfo->dwFileVersionLS); } GlobalUnlock(hMem); GlobalFree(hMem); return TRUE; } return FALSE; } BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved) { hInstance = hinstDLL; // Initialize the custom controls. This should be done only once. if (!controlsInit) { controlsInit = TRUE; InitCustomControls(hInstance); InitCommonControls(); //#pragma NOTE(__FILE__LINE__"Initialisation CK") DWORD fpu = VxGetFPUControlWord(); CKStartUp(hinstDLL); if (VxGetFPUControlWord()!=fpu) _control87(_CW_DEFAULT, 0xfffff); } switch(fdwReason) { case DLL_PROCESS_DETACH: CKShutdown(); default: return TRUE; } return (TRUE); } //-------- Presentation of functions to Max //-------- __declspec( dllexport ) const TCHAR* LibDescription() { return GetString(IDS_LIBDESCRIPTION); } __declspec( dllexport ) int LibNumberClasses() { #ifdef _USESCRIPTS_ return 2; #else return 1; #endif } __declspec( dllexport ) ClassDesc* LibClassDesc(int i) { switch(i) { case 0: return GetAsciiExpDesc(); #ifdef _USESCRIPTS_ case 1: return GetVirtoolsToolDesc(); #endif default: return 0; } } __declspec( dllexport ) ULONG LibVersion() { return VERSION_3DSMAX; } // Let the plug-in register itself for deferred loading __declspec( dllexport ) ULONG CanAutoDefer() { return 0; } static CKContext *g_VirtoolsContext = NULL; class AsciiExpClassDesc:public ClassDesc { public: int IsPublic() { return 1; } void* Create(BOOL loading = FALSE) { return new Max2Nmo; } const TCHAR* ClassName() { return GetString(IDS_ASCIIEXP); } SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; } Class_ID ClassID() { return MAX2NMO_CLASS_ID; } const TCHAR* Category() { return GetString(IDS_CATEGORY); } ~AsciiExpClassDesc(){ CKCloseContext(g_VirtoolsContext); g_VirtoolsContext = NULL; } }; static AsciiExpClassDesc AsciiExpDesc; ClassDesc* GetAsciiExpDesc() { return &AsciiExpDesc; } TCHAR *GetString(int id) { static TCHAR buf[256]; if (hInstance) return LoadString(hInstance, id, buf, sizeof(buf)) ? buf : NULL; return NULL; } Max2Nmo::Max2Nmo() { // These are the default values that will be active when // the exporter is ran the first time. // After the first session these options are sticky. InitDefaultValues(); } Max2Nmo::~Max2Nmo() { } void Max2Nmo::InitDefaultValues() { bShowProgressionBar = TRUE; bExportAsObjects = TRUE; bReduceRedondantKeys = TRUE; bExportAsCharacter = FALSE; bExportAsAnimationOnly = FALSE; bExportAsLevel = FALSE; bConvertPhysiqueToSkin = TRUE; bStoreOnlyTextureFilenames = FALSE; bRescaleScene = FALSE; bGroupAsPlace = FALSE; bSelectionAsGroup = FALSE; szCharacterName = "Character"; szAnimationName = "Animation"; nMeshFrameStep = 3; nKeyFrameStep = 3; nCompressionLevel = 0; nReportLevel = 0; GroupIndent = 0; bSaveBipedGeom = FALSE; bAlignAnimOnZ = FALSE; VirtoolsExporter = NULL; VirtoolsContext = NULL; bShellMaterialExportBoth = FALSE; bIgnore1KeyAnimation = TRUE; ReportBufferPos = 0; m_RescaleFactor = 1.0; bExportAnimation =TRUE; bForceSkinToMorph =FALSE; fKeysThreshold =TRUE; bForceAllUVs =FALSE; bSplitMesh =FALSE; bLOD =FALSE; bSplinesAsDummies =FALSE; bExportAlphaMap =FALSE; bUsePower2 =FALSE; bForce1x1Ratio =FALSE; nForce1x1RatioMethod =eNearestPowerOfTwo; bDeactivateMeshChannels =FALSE; bHideHelpers =FALSE; bDASIAnimation =FALSE; bDASIMesh =FALSE; bDASIMaterial =FALSE; bDASITexture =FALSE; sStartingCamera ="Camera01"; bReadChannels =FALSE; szReadChannelsFilename ="MyChannels.txt"; bReport =FALSE; szReportFilename ="Report.txt"; VirtoolsExporter = NULL; VirtoolsContext = NULL; bAlphaRef = TRUE; iAlphaRefValue = 1; bExportBlendShapes = FALSE; bExportBlendShapeAnims = FALSE; bIncludeBlendShapesInMorphController = TRUE; bReduceRedondantBlendShapesKeys = FALSE; bReduceRedondantBlendShapesKeys = TRUE; fBlendShapesKeysThreshold = 0.1f; nBlendShapesStep = 3; } void Max2Nmo::UpdateInterface(HWND hWnd) { Max2Nmo* exp = this; ISpinnerControl *spin; // retrieve the extension of the file XString sfileName = exp->GetExportFileName(); const char* fileName = sfileName.CStr(); char fileExt[5]; if(strlen(fileName) > 4) memcpy(fileExt, fileName + strlen(fileName)-4, 5); else fileExt[0] = 0; // ensure Export As mode is compatible with output file type if(stricmp(fileExt, ".nmo") == 0 && exp->GetExportAsLevel()) { // if NMO, avoid to Export As Level exp->SetExportAsObjects(true); exp->SetExportAsCharacter(false); exp->SetExportAsAnimationOnly(false); exp->SetExportAsLevel(false); } else if(stricmp(fileExt, ".nmo")) { // if not an NMO, force to Export As Level exp->SetExportAsObjects(false); exp->SetExportAsCharacter(false); exp->SetExportAsAnimationOnly(false); exp->SetExportAsLevel(true); } // check Export Type int RadioToEnable = IDC_RADIOEXPORTASOBJECTS; if (exp->GetExportAsLevel()) { RadioToEnable=IDC_RADIOEXPORTASLEVEL; EnableWindow(GetDlgItem(hWnd, IDC_RADIOEXPORTASOBJECTS), false); EnableWindow(GetDlgItem(hWnd, IDC_RADIOEXPORTASCHARACTER), false); EnableWindow(GetDlgItem(hWnd, IDC_RADIOEXPORTASANIMATION), false); EnableWindow(GetDlgItem(hWnd, IDC_RADIOEXPORTASLEVEL), true); } else { if (exp->GetExportAsObjects()) RadioToEnable=IDC_RADIOEXPORTASOBJECTS; else if (exp->GetExportAsCharacter()) RadioToEnable=IDC_RADIOEXPORTASCHARACTER; else if (exp->GetExportAsAnimationOnly()) RadioToEnable=IDC_RADIOEXPORTASANIMATION; EnableWindow(GetDlgItem(hWnd, IDC_RADIOEXPORTASOBJECTS), true); EnableWindow(GetDlgItem(hWnd, IDC_RADIOEXPORTASCHARACTER), true); EnableWindow(GetDlgItem(hWnd, IDC_RADIOEXPORTASANIMATION), true); EnableWindow(GetDlgItem(hWnd, IDC_RADIOEXPORTASLEVEL), false); } CheckRadioButton(hWnd, IDC_RADIOEXPORTASOBJECTS, IDC_RADIOEXPORTASLEVEL, RadioToEnable); CheckDlgButton(hWnd, IDC_CHECKSTOREFILENAMES, exp->GetStoreOnlyFilenames()); CheckDlgButton(hWnd, IDC_CHECKRESCALESCENE, exp->GetRescaleScene()); CheckDlgButton(hWnd, IDC_CHECKGROUPASPLACE, exp->GetGroupAsPlace()); CheckDlgButton(hWnd, IDC_CHECKBIPEDMESH, exp->GetSaveBipedGeom()); CheckDlgButton(hWnd, IDC_CHECKALIGNANIMATIONS, exp->GetAlignAnimOnZ()); CheckDlgButton(hWnd, IDC_CHECKREDUCEREDOUNDANTKEYS, exp->ReduceRedondantKeys()); CheckDlgButton(hWnd, IDC_CHECKSHELLMATERIALASSINGLE, exp->GetShellMaterialExportBoth()); CheckDlgButton(hWnd, IDC_CHECKEXPORTANIMATION , exp->GetExportAnimation()); CheckDlgButton(hWnd, IDC_CHECK_FORCESKINTOMORPH , exp->GetForceSkinToMorph()); CheckDlgButton(hWnd, IDC_CHECKFORCEUVS , exp->GetForceAllUVs()); CheckDlgButton(hWnd, IDC_CHECKLOD , exp->GetLOD() ); CheckDlgButton(hWnd, IDC_CHECKSPLINESASDUMMIES , exp->GetSplinesAsDummies()); CheckDlgButton(hWnd, IDC_CHECKSPLITMESH , exp->GetSplitMesh()); CheckDlgButton(hWnd, IDC_CHECKALPHAMAP , exp->GetExportAlphaMap()); CheckDlgButton(hWnd, IDC_CHECKPOWER2 , exp->GetUsePower2()); CheckDlgButton(hWnd, IDC_CHECKFORCERATIO , exp->GetForce1x1Ratio()); CheckDlgButton(hWnd, IDC_CHECKDEACTIVATEMESHCHANNELS , exp->GetDeactivateMeshChannels()); CheckDlgButton(hWnd, IDC_CHECKHIDEHELPERS , exp->GetHideHelpers()); CheckDlgButton(hWnd, IDC_CHECKCHANNELSETTINGS , exp->GetReadChannels()); CheckDlgButton(hWnd, IDC_CHECKREPORT , exp->GetReport()); //alpha ref //CheckDlgButton(hWnd, IDC_ALPHAREF_CHECK , exp->GetAlphaRef()); if (!exp->GetAlphaRef()) { EnableWindow(GetDlgItem(hWnd,IDC_ALPHAREF_STEP),FALSE); EnableWindow(GetDlgItem(hWnd,IDC_ALPHAREF_STEP_SPIN),FALSE); } // Blend shapes CheckDlgButton(hWnd, IDC_EXPORTBLENDSHAPES , exp->GetExportBlendShapes()); CheckDlgButton(hWnd, IDC_EXPORTBLENDSHAPEANIMS , exp->GetExportBlendShapeAnims()); CheckDlgButton(hWnd, IDC_INCLUDEBLENDSHAPESINMORPHCONTROLLER, exp->GetIncludeBlendShapesInMorphController()); CheckDlgButton(hWnd, IDC_CHECKREDUCEREDOUNDANTKEYS_BLENDSHAPES, exp->GetReduceRedondantBlendShapesKeys()); //PostExport Settings fo Detect and Share identical... //will be remove in BEExport CheckDlgButton(hWnd, IDC_CHECKDASIANIMATION , exp->GetDASIAnimation()); CheckDlgButton(hWnd, IDC_CHECKDASIMESH , exp->GetDASIMesh()); CheckDlgButton(hWnd, IDC_CHECKDASIMATERIAL , exp->GetDASIMaterial()); CheckDlgButton(hWnd, IDC_CHECKDASITEXTURE , exp->GetDASITexture()); //Force1x1RatioMethod: To acces the combobox, we use standard Win32 messages HWND combo=GetDlgItem(hWnd, IDC_COMBOFORCERATIOMETHOD); SendMessage( combo , CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) "Nearest Power of 2"); SendMessage( combo , CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) "Lower Power of 2"); SendMessage( combo , CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) "Higher Power of 2"); SendMessage( combo , CB_SETCURSEL , exp->GetForce1x1RatioMethod(), 0); //IDC_COMBOREPORTLEVEL: Report Level can be None, Low, Medium or High (0,1,2,3) combo=GetDlgItem(hWnd, IDC_COMBOREPORTLEVEL); SendMessage( combo , CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) "None"); SendMessage( combo , CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) "Steps"); SendMessage( combo , CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) "Detailed steps"); SendMessage( combo , CB_ADDSTRING, 0, (LPARAM) (LPCTSTR) "Verbose"); SendMessage( combo , CB_SETCURSEL , exp->GetReportLevel(), 0); CheckRadioButton(hWnd, IDC_RADIOSKIN, IDC_RADIOMORPH, exp->GetConvertPhysiqueToSkin() ? IDC_RADIOSKIN : IDC_RADIOMORPH); CheckDlgButton(hWnd, IDC_CHECK_IGNORE1KEYANIMATION, exp->GetIgnore1KeyAnimation()); // Setup the spinner controls for the controller key sample rate spin = GetISpinner(GetDlgItem(hWnd, IDC_CONT_STEP_SPIN)); spin->LinkToEdit(GetDlgItem(hWnd,IDC_CONT_STEP), EDITTYPE_INT ); spin->SetLimits(1, 100, TRUE); spin->SetScale(1.0f); spin->SetValue(exp->GetKeyFrameStep() ,FALSE); ReleaseISpinner(spin); // Setup the spinner controls for the compression level spin = GetISpinner(GetDlgItem(hWnd, IDC_CONT_COMPRESSIONSPIN)); spin->LinkToEdit(GetDlgItem(hWnd,IDC_CONT_COMPRESSION), EDITTYPE_INT ); spin->SetLimits(0, 9, TRUE); spin->SetScale(1.0f); spin->SetValue(exp->GetCompressionLevel() ,FALSE); ReleaseISpinner(spin); // Setup the spinner controls for alpharef spin = GetISpinner(GetDlgItem(hWnd, IDC_ALPHAREF_STEP_SPIN)); spin->LinkToEdit(GetDlgItem(hWnd,IDC_ALPHAREF_STEP), EDITTYPE_INT ); spin->SetLimits(0, 255, TRUE); spin->SetScale(1.0f); if (exp->GetAlphaRef()) spin->SetValue(exp->GetAlphaRefValue() ,FALSE); else spin->SetValue(1 ,FALSE); ReleaseISpinner(spin); // Setup the spinner controls for the mesh definition sample rate spin = GetISpinner(GetDlgItem(hWnd, IDC_MESH_STEP_SPIN)); spin->LinkToEdit(GetDlgItem(hWnd,IDC_MESH_STEP), EDITTYPE_INT ); spin->SetLimits(1, 100, TRUE); spin->SetScale(1.0f); spin->SetValue(exp->GetMeshFrameStep() ,FALSE); ReleaseISpinner(spin); // Setup the spinner controls for the Animation Reduce Keys Threshold spin = GetISpinner(GetDlgItem(hWnd, IDC_KEYSTHRESHOLDSPIN)); spin->LinkToEdit(GetDlgItem(hWnd,IDC_KEYSTHRESHOLD), EDITTYPE_FLOAT ); spin->SetLimits(0.0f, 100.0f, TRUE); spin->SetScale(0.0001f); spin->SetValue(exp->GetKeysThreshold() ,FALSE); ReleaseISpinner(spin); // Setup the spinner controls for the Animation Reduce Blend Shapes Keys Threshold spin = GetISpinner(GetDlgItem(hWnd, IDC_KEYSTHRESHOLDSPIN_BLENDSHAPES)); spin->LinkToEdit(GetDlgItem(hWnd,IDC_KEYSTHRESHOLD_BLENDSHAPES), EDITTYPE_FLOAT ); spin->SetLimits(0.0f, 1.0f, TRUE); spin->SetScale(0.0001f); spin->SetValue(exp->GetBlendShapesKeysThreshold() ,FALSE); ReleaseISpinner(spin); // Setup the spinner controls for the blend shape weights anims sampling step spin = GetISpinner(GetDlgItem(hWnd, IDC_BLENDSHAPES_STEP_SPIN)); spin->LinkToEdit(GetDlgItem(hWnd,IDC_BLENDSHAPES_STEP), EDITTYPE_INT ); spin->SetLimits(1, 100, TRUE); spin->SetScale(1.0f); spin->SetValue(exp->GetBlendShapesStep() ,FALSE); ReleaseISpinner(spin); SetWindowText(GetDlgItem(hWnd, IDC_EDITCHARACTERNAME),exp->GetCharacterName()); SetWindowText(GetDlgItem(hWnd, IDC_EDITANIMATIONNAME),exp->GetAnimationName()); SetWindowText(GetDlgItem(hWnd, IDC_EDITSTARTINGCAMERA),exp->GetStartingCamera()); SetWindowText(GetDlgItem(hWnd, IDC_EDITREADCHANNELSFILENAME),exp->GetReadChannelsFilename()); SetWindowText(GetDlgItem(hWnd, IDC_EDITREPORTFILENAME),exp->GetReportFilename()); //Setup ToolTips exp->UIToolTips(hWnd); //Set the state of all controls based on all values. exp->UIUpdate(hWnd); } int Max2Nmo::ExtCount() { return 3; } const TCHAR * Max2Nmo::Ext(int n) { switch(n) { case 0: return _T("Nmo"); case 1: return _T("Vmo"); case 2: return _T("Cmo"); } return _T(""); } const TCHAR * Max2Nmo::LongDesc() { return GetString(IDS_LONGDESC); } const TCHAR * Max2Nmo::ShortDesc() { return GetString(IDS_SHORTDESC); } const TCHAR * Max2Nmo::AuthorName() { return _T("Romain Sididris, Francisco Cabrita and Guillaume Laferriere"); } const TCHAR * Max2Nmo::CopyrightMessage() { return GetString(IDS_COPYRIGHT); } const TCHAR * Max2Nmo::OtherMessage1() { return _T(""); } const TCHAR * Max2Nmo::OtherMessage2() { return _T(""); } unsigned int Max2Nmo::Version() { return 100; } static BOOL CALLBACK AboutBoxDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: CenterWindow(hWnd, GetParent(hWnd)); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: EndDialog(hWnd, 1); break; } break; default: return FALSE; } return TRUE; } void Max2Nmo::ShowAbout(HWND hWnd) { DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, AboutBoxDlgProc, 0); } static BOOL CALLBACK ReportDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { Max2Nmo *exp = (Max2Nmo*)GetWindowLong(hWnd,GWL_USERDATA); switch (msg) { case WM_INITDIALOG: { exp = (Max2Nmo*)lParam; SetWindowLong(hWnd,GWL_USERDATA,lParam); CenterWindow(hWnd, GetParent(hWnd)); SetDlgItemText(hWnd,IDC_EDITREPORT,(const char*)exp->ReportBuffer.Begin()); break; } case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: { EndDialog(hWnd, 1); break; } break; } default: return FALSE; } return TRUE; } // Dialog proc static BOOL CALLBACK ExportDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { Interval animRange; ISpinnerControl *spin; char* CPtr; TCHAR CBuf[512]; int ret; Max2Nmo *exp = (Max2Nmo*)GetWindowLong(hWnd,GWL_USERDATA); switch (msg) { case WM_INITDIALOG: { exp = (Max2Nmo*)lParam; SetWindowLong(hWnd,GWL_USERDATA,lParam); CenterWindow(hWnd, GetParent(hWnd)); exp->UpdateInterface(hWnd); break; } case CC_SPINNER_CHANGE: spin = (ISpinnerControl*)lParam; break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_BUTTON_GETCHANNELFILE: CPtr=(char*)exp->UIGetFilename(hWnd, CBuf, sizeof(CBuf), "*.TXT", FALSE); if(CPtr){ exp->SetReadChannelsFilename(XString(CPtr).Str()); SetWindowText(GetDlgItem(hWnd, IDC_EDITREADCHANNELSFILENAME),exp->GetReadChannelsFilename()); } break; case IDC_BUTTON_GETREPORTFILE: CPtr=(char*)exp->UIGetFilename(hWnd, CBuf, sizeof(CBuf)); if(CPtr){ exp->SetReportFilename(XString(CPtr).Str()); SetWindowText(GetDlgItem(hWnd, IDC_EDITREPORTFILENAME),exp->GetReportFilename()); } break; case IDC_DEFAULT: { exp->InitDefaultValues(); exp->UpdateInterface(hWnd); } break; /* case IDC_ALPHAREF_CHECK: { UINT res = IsDlgButtonChecked(hWnd, IDC_ALPHAREF_CHECK); EnableWindow(GetDlgItem(hWnd,IDC_ALPHAREF_STEP),res); EnableWindow(GetDlgItem(hWnd,IDC_ALPHAREF_STEP_SPIN),res); exp->SetAlphaRef(TRUE); if (!res) { ISpinnerControl* spin = GetISpinner(GetDlgItem(hWnd, IDC_ALPHAREF_STEP_SPIN)); //spin->SetValue(255); exp->SetAlphaRef(FALSE); //exp->SetAlphaRefValue(255); } } break; */ case IDC_CHECKCHANNELSETTINGS: case IDC_RADIOEXPORTASANIMATION: case IDC_RADIOEXPORTASOBJECTS: case IDC_RADIOEXPORTASCHARACTER: case IDC_RADIOEXPORTASLEVEL: case IDC_CHECKEXPORTANIMATION: case IDC_CHECK_FORCESKINTOMORPH: case IDC_CHECKSTOREFILENAMES: case IDC_CHECKFORCEUVS: case IDC_CHECKPOWER2: case IDC_CHECKREPORT: case IDC_EXPORTBLENDSHAPES: case IDC_EXPORTBLENDSHAPEANIMS: exp->UIUpdate(hWnd); break; case IDOK: { exp->SetExportAsAnimationOnly(IsDlgButtonChecked(hWnd, IDC_RADIOEXPORTASANIMATION)); exp->SetExportAsCharacter(IsDlgButtonChecked(hWnd, IDC_RADIOEXPORTASCHARACTER)); exp->SetExportAsObjects(IsDlgButtonChecked(hWnd, IDC_RADIOEXPORTASOBJECTS)); exp->SetExportAsLevel(IsDlgButtonChecked(hWnd, IDC_RADIOEXPORTASLEVEL)); exp->SetConvertPhysiqueToSkin(IsDlgButtonChecked(hWnd, IDC_RADIOSKIN)); exp->SetRescaleScene(IsDlgButtonChecked(hWnd, IDC_CHECKRESCALESCENE)); exp->SetGroupAsPlace(IsDlgButtonChecked(hWnd, IDC_CHECKGROUPASPLACE)); exp->SetSaveBipedGeom(IsDlgButtonChecked(hWnd, IDC_CHECKBIPEDMESH)); exp->SetbAlignAnimOnZ(IsDlgButtonChecked(hWnd, IDC_CHECKALIGNANIMATIONS)); exp->SetStoreOnlyFilenames(IsDlgButtonChecked(hWnd, IDC_CHECKSTOREFILENAMES)); exp->SetReduceRedondantKeys(IsDlgButtonChecked(hWnd, IDC_CHECKREDUCEREDOUNDANTKEYS)); exp->SetShellMaterialAsSingle(IsDlgButtonChecked(hWnd, IDC_CHECKSHELLMATERIALASSINGLE)); exp->SetIgnore1Keyanimation(IsDlgButtonChecked(hWnd, IDC_CHECK_IGNORE1KEYANIMATION)); exp->SetExportAnimation(IsDlgButtonChecked(hWnd, IDC_CHECKEXPORTANIMATION)); exp->SetForceSkinToMorph(IsDlgButtonChecked(hWnd, IDC_CHECK_FORCESKINTOMORPH)); exp->SetForceAllUVs(IsDlgButtonChecked(hWnd, IDC_CHECKFORCEUVS)); exp->SetLOD(IsDlgButtonChecked(hWnd, IDC_CHECKLOD)); exp->SetSplinesAsDummies(IsDlgButtonChecked(hWnd, IDC_CHECKSPLINESASDUMMIES)); exp->SetSplitMesh(IsDlgButtonChecked(hWnd, IDC_CHECKSPLITMESH)); exp->SetExportAlphaMap(IsDlgButtonChecked(hWnd, IDC_CHECKALPHAMAP)); exp->SetUsePower2(IsDlgButtonChecked(hWnd, IDC_CHECKPOWER2)); exp->SetForce1x1Ratio(IsDlgButtonChecked(hWnd, IDC_CHECKFORCERATIO)); exp->SetDeactivateMeshChannels( IsDlgButtonChecked(hWnd, IDC_CHECKDEACTIVATEMESHCHANNELS) ); exp->SetHideHelpers( IsDlgButtonChecked(hWnd, IDC_CHECKHIDEHELPERS) ); exp->SetReadChannels( IsDlgButtonChecked(hWnd, IDC_CHECKCHANNELSETTINGS) ); exp->SetReport( IsDlgButtonChecked(hWnd, IDC_CHECKREPORT) ); exp->SetDASIAnimation(IsDlgButtonChecked(hWnd, IDC_CHECKDASIANIMATION)); exp->SetDASIMesh(IsDlgButtonChecked(hWnd, IDC_CHECKDASIMESH)); exp->SetDASIMaterial(IsDlgButtonChecked(hWnd, IDC_CHECKDASIMATERIAL)); exp->SetDASITexture(IsDlgButtonChecked(hWnd, IDC_CHECKDASITEXTURE)); // blend shapes exp->SetExportBlendShapes(IsDlgButtonChecked(hWnd, IDC_EXPORTBLENDSHAPES)); exp->SetExportBlendShapeAnims(IsDlgButtonChecked(hWnd, IDC_EXPORTBLENDSHAPEANIMS)); exp->SetIncludeBlendShapesInMorphController(IsDlgButtonChecked(hWnd, IDC_INCLUDEBLENDSHAPESINMORPHCONTROLLER)); exp->SetReduceRedondantBlendShapesKeys(IsDlgButtonChecked(hWnd, IDC_CHECKREDUCEREDOUNDANTKEYS_BLENDSHAPES)); //exp->SetAlphaRef(IsDlgButtonChecked(hWnd, IDC_ALPHAREF_CHECK)); char TempString[512]; GetDlgItemText(hWnd,IDC_EDITANIMATIONNAME,TempString,512); exp->SetAnimationName(TempString); GetDlgItemText(hWnd,IDC_EDITCHARACTERNAME,TempString,512); exp->SetCharacterName(TempString); GetDlgItemText(hWnd,IDC_EDITSTARTINGCAMERA,TempString,512); exp->SetStartingCamera(TempString); GetDlgItemText(hWnd,IDC_EDITREADCHANNELSFILENAME,TempString,512); exp->SetReadChannelsFilename(TempString); GetDlgItemText(hWnd,IDC_EDITREPORTFILENAME,TempString,512); exp->SetReportFilename(TempString); exp->SetForce1x1RatioMethod( (int) SendMessage( GetDlgItem(hWnd, IDC_COMBOFORCERATIOMETHOD) , CB_GETCURSEL , 0, 0)); spin = GetISpinner(GetDlgItem(hWnd, IDC_CONT_STEP_SPIN)); exp->SetKeyFrameStep(spin->GetIVal()); ReleaseISpinner(spin); ret=SendMessage(GetDlgItem(hWnd, IDC_COMBOREPORTLEVEL), CB_GETCURSEL,0,0); if(ret==CB_ERR) ret=0; exp->SetReportLevel(ret); spin = GetISpinner(GetDlgItem(hWnd, IDC_CONT_COMPRESSIONSPIN)); exp->SetCompressionLevel(spin->GetIVal()); ReleaseISpinner(spin); spin = GetISpinner(GetDlgItem(hWnd, IDC_ALPHAREF_STEP_SPIN)); exp->SetAlphaRefValue(spin->GetIVal()); ReleaseISpinner(spin); spin = GetISpinner(GetDlgItem(hWnd, IDC_MESH_STEP_SPIN)); exp->SetMeshFrameStep(spin->GetIVal()); ReleaseISpinner(spin); spin = GetISpinner(GetDlgItem(hWnd, IDC_KEYSTHRESHOLDSPIN)); exp->SetKeysThreshold( spin->GetFVal() ); ReleaseISpinner(spin); spin = GetISpinner(GetDlgItem(hWnd, IDC_KEYSTHRESHOLDSPIN_BLENDSHAPES)); exp->SetBlendShapesKeysThreshold( spin->GetFVal() ); ReleaseISpinner(spin); spin = GetISpinner(GetDlgItem(hWnd, IDC_BLENDSHAPES_STEP_SPIN)); exp->SetBlendShapesStep(spin->GetIVal()); ReleaseISpinner(spin); EndDialog(hWnd, 1); break; } case IDCANCEL: EndDialog(hWnd, 0); break; } break; default: return FALSE; } return TRUE; } // Dummy function for progress bar DWORD WINAPI fn(LPVOID arg) { return(0); } // Start the exporter! // This is the real entrypoint to the exporter. After the user has selected // the filename (and he's prompted for overwrite etc.) this method is called. int Max2Nmo::DoExport(const TCHAR *name,ExpInterface *ei,Interface *inf, BOOL suppressPrompts, DWORD options) { // Grab the interface pointer. ip = inf; #ifdef _USESCRIPTS_ if( name ){ theVirtoolsTool.m_ExportFileName = name; for( int a=0 ; aGetMAXHWnd(), ExportDlgProc, (LPARAM)this)) { return 1; } } // Araya: don't force this for max script command, but only for the dialog version this->bForceAllUVs=true; SetShowProgressionBar( TRUE ); int res = ReallyDoExport( name, ip, (options&SCENE_EXPORT_SELECTED)? TRUE:FALSE ); return res; #endif } // This method do the export job, and suppose all the parameters // has correctly been set (by the export UI, or with MAXScript) int Max2Nmo::ReallyDoExport( const TCHAR *name, Interface *inf, BOOL sel ) { ip = inf; exportSelected = sel; m_ExportFileName = name; // Virtools Engine initialization if (!VirtoolsPluginsParsed) { #ifndef MAX42 //------ Check the version of Physique installed... g_CharacterStudio312 = FALSE; // Parse every plugin dir to find Physique Version ! DWORD Version1,Version2,Version3,Version4; for (int k=0;kGetPlugInEntryCount();k++) { XString Path = ip->GetPlugInDir(k); Path << "Physique.dlm"; if (GetVersionInfo(Path.Str(),Version1,Version2,Version3,Version4)) { #ifdef MAX4 // For Max 4 incompatibility starts at version 3.0.2 if ((Version1 >= 3) && ( Version2 >= 1) && ( Version3 >= 2)) { g_CharacterStudio312 = TRUE; } #else // For Max 3 incompatibility starts at version 3.0.2 if ((Version1 >= 3) && ( Version2 >= 0) && ( Version3 >= 2)) { g_CharacterStudio312 = TRUE; } #endif break; } } #endif //------------------------------------------------------- #ifdef CK_LIB // Register static plugins that we use... CKPluginManager* pm = CKGetPluginManager(); // NULL Rasterizer RegisterRenderEngine(pm); // Image Plugins RegisterImageReader(pm); RegisterAVIReader(pm); RegisterPNGReader(pm); RegisterJPGReader(pm); RegisterDDSReader(pm); RegisterTIFFReader(pm); //--- Mesh Modifier Static RegisterMeshesBehaviors(pm); #else for (int j=0;jGetPlugInEntryCount();j++) CKGetPluginManager()->ParsePlugins(ip->GetPlugInDir(j)); #endif VirtoolsPluginsParsed = TRUE; } if( !g_VirtoolsContext ){ if (CKCreateContext(&VirtoolsContext,ip->GetMAXHWnd(),0) != CK_OK) { MessageBox(NULL, "CK Initialisation Problems", "Max2Nmo", MB_OK); return 1; } VirtoolsContext->GetVariableManager()->SetStringValue("Globals/StartingFlags","Disable Sound,Disable Input"); //-- Add Max Bitmap path to Virtools PathManager int BitmapPathCount = TheManager->GetMapDirCount(); for(int i=0;iGetPathManager()->AddPath(BITMAP_PATH_IDX,XString(TheManager->GetMapDir(i))); } RegisterAllSpecialParameters(); g_VirtoolsContext = VirtoolsContext; } else { VirtoolsContext = g_VirtoolsContext; } // Virtools Exporter context creation VirtoolsExporter = new Export2Virtools(VirtoolsContext, TRUE); //Start Log to file... all Report call are also redirected to the same file Ge2Virtools uses as log. if(GetReport()) { m_ReportGeLog= new GeFileLog( GetReportFilename() ); if( m_ReportGeLog->InitLog() == FALSE){ delete m_ReportGeLog; m_ReportGeLog=NULL; } } else { m_ReportGeLog=NULL; } VirtoolsExporter->m_FileLog=m_ReportGeLog; // Rescale Scene to 1 unit = 1 meter if asked if (GetRescaleScene()) { RescaleScene(); Report(REPORT_HLEVEL,"Scene rescaled to 1 unit = 1 meter\r\n"); } // First we write out a file header with global information. Interval range = ip->GetAnimRange(); m_StartFrame = (float)range.Start(); m_EndFrame = (float)range.End(); m_InvFrameRate = 1.0f/(float)GetTicksPerFrame(); // Startup the progress bar. this->SetShowProgressionBar(TRUE); if( GetShowProgressionBar() ){ ip->ProgressStart(GetString(IDS_PROGRESS_MSG), TRUE, fn, NULL); } // Get a total node count by traversing the scene // We don't really need to do this, but it doesn't take long, and // it is nice to have an accurate progress bar. nTotalNodeCount = 0; nCurNode = 0; PreProcess(ip->GetRootNode(), nTotalNodeCount); //-- Get the Level Settings if( this->GetExportAsLevel() ){ Report(REPORT_HLEVEL,"---------Exporting Environment and Atmosphere Settings----------\r\n"); ExportLevelSettings(); } //-- Export list of material definitions Report(REPORT_HLEVEL,"---------Exporting materials----------\r\n"); ExportMaterialList(); Report(REPORT_HLEVEL,"\r\n"); Report(REPORT_HLEVEL,"-----------Exporting objects-----------\r\n"); // Call our node enumerator. // The nodeEnum function will recurse into itself and // export each object found in the scene. ip->SetCancel(FALSE);//set cancel to false. int numChildren = ip->GetRootNode()->NumberOfChildren(); for (int idx=0; idxGetCancel()){//Give some feed back if it is cancel Report(REPORT_HLEVEL,"Canceled by user at object %d\r\n",idx); break; } nodeEnum(ip->GetRootNode()->GetChildNode(idx)); } Report(REPORT_HLEVEL,"\r\n"); Report(REPORT_HLEVEL,"------ Exporting animated meshes ------\r\n"); //-- Check if there are animated meshes (morph, skin, physique) PostProcess(ip->GetRootNode()); //--Remove unused channel materials if( this->GetForceAllUVs() ){ for(int i=0; i< MAX_UVCHANNEL_COUNT; i++){ if(UsedChannels[i]== false || i==0){ CKMaterial* m=VirtoolsExporter->GetMaterialByKey((void*)(i+1)); if(m!=NULL) VirtoolsExporter->DestroyObject(m,(void*)(i+1) ); } } } // We're done. Finish the progress bar. if( GetShowProgressionBar() ){ ip->ProgressEnd(); } // Write the current options to be used next time around. WriteConfig(); // Finish creating appropriate objects ///// What is this ?!?!?!? ///// it created a global animation ... see swap-meet post ///// http://www.theswapmeet-forum.com/viewtopic.php?t=5204&highlight=&sid=511000f9f2c4421d2db0a2ca10a0e991 ///// CKKeyedAnimation* GlobalAnim = VirtoolsExporter->CreateGlobalAnimation(GetAnimationName()); GlobalAnim->SetLength(FrameTime(m_EndFrame)); if (GetExportAsCharacter()) { Report(REPORT_HLEVEL,"\r\n"); Report(REPORT_HLEVEL,"Creating character : %s\r\n",GetCharacterName()); VirtoolsExporter->CreateCharacter(GetCharacterName()); } if (GetStoreOnlyFilenames()) VirtoolsContext->SetGlobalImagesSaveOptions(CKTEXTURE_EXTERNAL); else VirtoolsContext->SetGlobalImagesSaveOptions(CKTEXTURE_RAWDATA); //Activate or deactivate Split Mesh Algorithm VirtoolsExporter->SetSplitMesh( this->GetSplitMesh()==TRUE ); // Generate the final list containing all the CKObjects CKFile* VirtoolsFile = VirtoolsContext->CreateCKFile(); m_VirtoolsObjects = CreateCKObjectArray(); VirtoolsExporter->GenerateObjects(m_VirtoolsObjects,GetExportAsAnimationOnly(), GetExportAsLevel() ); // Create Groups for Named Selection Sets if( GetSelectionAsGroup() ){ Report(REPORT_HLEVEL,"\r\n"); Report(REPORT_HLEVEL,"----------- Exporting Named Selections -----------\r\n"); int namedSelCount = ip->GetNumNamedSelSets(); for( int a=0 ; aCreateObject( CKCID_GROUP, ip->GetNamedSelSetName(a) ); if( !grp ) continue; int selObjCount = ip->GetNamedSelSetItemCount(a); for( int b=0 ; bGetNamedSelSetItem( a, b); CK3dEntity *selEnt = VirtoolsExporter->GetEntityByKey( selNode ); if( !selEnt ){ selEnt = VirtoolsExporter->GetLightByKey( selNode ); if( !selEnt ){ selEnt = VirtoolsExporter->GetCameraByKey( selNode ); } } if( selEnt ){ grp->AddObject( selEnt ); } } if( grp->GetObjectCount() ){ m_VirtoolsObjects->InsertFront( grp ); } } } #ifdef _USESCRIPTS_ Report(REPORT_HLEVEL,"\r\n"); Report(REPORT_HLEVEL,"----------- Evaluating User Defined Properties -----------\r\n"); // Call our node user defined properties evaluator. // The nodeEnum function will recurse into itself and // evaluate each user defined properties for( idx=0; idxGetCancel()) break; evaluateNodeUserDefinedProperties( ip->GetRootNode()->GetChildNode(idx) ); } // If some scripts has been added // we must create a Level int behCount = VirtoolsContext->GetObjectsCountByClassID( CKCID_BEHAVIOR ); if( behCount ){ // create a level CKLevel *level = (CKLevel *)VirtoolsContext->CreateObject( CKCID_LEVEL ); CKScene* LevelScene = level->GetLevelScene(); VirtoolsContext->SetCurrentLevel(level); // add all objects to this level for( m_VirtoolsObjects->Reset() ; !m_VirtoolsObjects->EndOfList() ; ){ CKObject *tmpObj = m_VirtoolsObjects->GetData( VirtoolsContext ); // if their was already a scene or a level remove it if (CKIsChildClassOf(tmpObj,CKCID_SCENE) || CKIsChildClassOf(tmpObj,CKCID_LEVEL)) { m_VirtoolsObjects->RemoveAt(); // if it isn't a level (or scene) } else { DWORD SceneFlags = 0; CKSceneObject* ScnObj = NULL; // if the object is attached to a scene if (CKIsChildClassOf(tmpObj,CKCID_SCENEOBJECT)) { ScnObj = (CKSceneObject*)tmpObj; CKScene *Scene = ScnObj->GetSceneIn(0); if (Scene && Scene!=LevelScene) { // get the scripts activation states SceneFlags = Scene->GetObjectFlags(ScnObj); } } // add object to the created level level->AddObject( tmpObj ); if (SceneFlags) { // put scripts activation states LevelScene->SetObjectFlags( ScnObj, (CK_SCENEOBJECT_FLAGS)SceneFlags); } m_VirtoolsObjects->Next(); } } // add the created level to the list of objects to be saved // only for the web player (because it has no level and it need one) // but don't save the level if it's supposed to be loaded by some // application (like Dev) that already has a level (because it won't be loaded). // // if we save without level, the scripts activation states will be saved // into a special chunk XString fileName = name; CKPathSplitter splitter( fileName.Str() ); char *fileNameExtension = splitter.GetExtension(); if( strcmp(fileNameExtension, ".nmo") ){ // save the level only for ".cmo" and ".vmo" m_VirtoolsObjects->InsertFront( level ); } } #endif //--- Set Compression Level if( GetCompressionLevel() ){ VirtoolsContext->SetFileWriteMode( CKFILE_WHOLECOMPRESSED ); VirtoolsContext->SetCompressionLevel( GetCompressionLevel() ); } else { VirtoolsContext->SetFileWriteMode( CKFILE_UNCOMPRESSED ); } //---- Normalizing root anim Y orientation aligning it with the Z world if ((GetExportAsCharacter() || GetExportAsAnimationOnly()) && GetAlignAnimOnZ()) { CK_ID* pid = VirtoolsContext->GetObjectsListByClassID(CKCID_KEYEDANIMATION); CKKeyedAnimation* ka = (CKKeyedAnimation*) VirtoolsContext->GetObject(*pid); if (ka) { CKObjectAnimation* oa = ka->GetAnimation(ka->GetRootEntity()) ; if (oa) { CKAnimController* rctrl = oa->GetRotationController(); int rkeycount=0; if (rctrl && (rkeycount=rctrl->GetKeyCount())) { VxQuaternion diffy,first,dest; CKRotationKey* rotkey = NULL; VxMatrix or0; rotkey = (CKRotationKey*) rctrl->GetKey(0); first = rotkey->GetRotation(); first.ToMatrix(or0); VxVector dir0(or0[0][2],or0[1][2],or0[2][2]); dir0.y = 0.0f; dir0.Normalize(); float dot = DotProduct(dir0,VxVector::axisZ()); if (dot>1.0f) dot = 1.0f; if (dot<-1.0f) dot = -1.0f; float angle = acosf(dot); if (!_isnan(angle)) { diffy.FromRotation(VxVector(0.0f,1.0f,0.0f),-(PI/2 - angle)); for (int ki = 0; kiGetKey(ki); dest = rotkey->GetRotation(); dest.Multiply(diffy); dest.Normalize(); rotkey->SetRotation(dest); } } } } } } //---PostProcess Report(REPORT_HLEVEL,"\n---------- Post Process ------------\n"); if( this->m_RescaleFactor!= 1.0f) VirtoolsExporter->RescaleScene(m_RescaleFactor); if( this->GetUsePower2() ) VirtoolsExporter->ForceTextureResize( (ETextureResizeMethod) GetForce1x1RatioMethod(), GetForce1x1Ratio()==TRUE ); if( this->GetDASITexture() ) VirtoolsExporter->DASITexturesGlobal(); if( this->GetDASIMaterial() ) VirtoolsExporter->DASIMaterialsGlobal(); if( this->GetDASIMesh() ) VirtoolsExporter->DASIMeshesGlobal(); if( this->GetDASIAnimation() ) VirtoolsExporter->DASIAnimationsGlobal(); if( this->GetLOD() ) VirtoolsExporter->FindNamedLODGlobal("LOD",1); if( this->GetReadChannels() ) VirtoolsExporter->ReadChannels( (CKSTRING)this->GetReadChannelsFilename() ); if(this->GetIgnore1KeyAnimation() ) VirtoolsExporter->RemoveSingleKeyAnimation( VirtoolsExporter->GetGlobalAnimation() ); if( this->ReduceRedondantKeys() ) VirtoolsExporter->ReduceAnimKeys( VirtoolsExporter->GetGlobalAnimation(), this->GetKeysThreshold(), 1, eFileSize ); if( this->GetReduceRedondantBlendShapesKeys() ) VirtoolsExporter->ReduceAnimBlendShapesKeys( VirtoolsExporter->GetGlobalAnimation(), this->GetBlendShapesKeysThreshold(), 1, eFileSize ); // Comment Thomas Bucher - 03/08/2006 // // The helpers are already hidden in export.cpp l.509 // The AutoHideHierarchyGlobal does not do what it is supposed // to do... it should be removed. //if( this->GetHideHelpers() ) // VirtoolsExporter->AutoHideHierarchyGlobal(); // Write the file to hard drive CKERROR err = VirtoolsFile->StartSave((char *)name); if (err==CK_OK) { VirtoolsFile->SaveObjects(m_VirtoolsObjects); err = VirtoolsFile->EndSave(); } if (err==CK_OK) { Report(REPORT_HLEVEL,"\r\n"); Report(REPORT_HLEVEL,"File saved succesfully\r\n"); } else { Report(REPORT_HLEVEL,"\r\n"); Report(REPORT_HLEVEL,"Error while saving file: %s\r\n",CKErrorToString(err)); } if (GetReportLevel()) if (!DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_REPORT), ip->GetMAXHWnd(), ReportDlgProc, (LPARAM)this)) { return 1; } // Clean Up DeleteCKObjectArray(m_VirtoolsObjects); m_VirtoolsObjects = NULL; VirtoolsContext->DeleteCKFile(VirtoolsFile); if( m_ReportGeLog ){ m_ReportGeLog->CloseLog(); delete m_ReportGeLog; m_ReportGeLog=NULL; } delete VirtoolsExporter; VirtoolsExporter = NULL; VirtoolsContext->ClearAll(); return 1; } //////////////////////////////////// // Register All Special Parameters //////////////////////////////////// BOOL Max2Nmo::RegisterAllSpecialParameters() { CKParameterManager* pm = VirtoolsContext->GetParameterManager(); //Need to add the LOD Attribute #ifdef _USESCRIPTS_ RegisterSpecialParameters( pm ); RegisterSpecialParameters2( pm ); #endif return TRUE; } BOOL Max2Nmo::SupportsOptions(int ext, DWORD options) { //assert(ext == 0); return(options == SCENE_EXPORT_SELECTED) ? TRUE : FALSE; } #ifdef _USESCRIPTS_ // This method parse all the nodes (recursivly), and evaluates // the user defined properties buffer to execute some function // like: attaching a script, setting an attribute, setting a local parameter BOOL Max2Nmo::evaluateNodeUserDefinedProperties( INode* node ){ // Only export if exporting everything or it's selected if(!exportSelected || node->Selected()) { // Stop recursing if the user pressed Cancel if (ip->GetCancel()) return FALSE; // The ObjectState is a 'thing' that flows down the pipeline containing // all information about the object. By calling EvalWorldState() we tell // max to eveluate the object at end of the pipeline. ObjectState os = node->EvalWorldState(0); // The obj member of ObjectState is the actual object we will export. if (os.obj) { // We look at the super class ID to determine the type of the object. switch(os.obj->SuperClassID()) { case GEOMOBJECT_CLASS_ID: case CAMERA_CLASS_ID: case LIGHT_CLASS_ID: case SHAPE_CLASS_ID: case HELPER_CLASS_ID: { PropertiesEvaluator pe( VirtoolsExporter, node, this, m_VirtoolsObjects ); } break; } } // For each child of this node, we recurse into ourselves // until no more children are found. for (int c = 0; c < node->NumberOfChildren(); c++) { if (!evaluateNodeUserDefinedProperties(node->GetChildNode(c))) return FALSE; } } else { // node is not selected but one of its child may // For each child of this node, we recurse into ourselves // until no more children are found. for (int c = 0; c < node->NumberOfChildren(); c++) { if (!evaluateNodeUserDefinedProperties(node->GetChildNode(c))) return FALSE; } } return TRUE; } #endif // This method is the main object exporter. // It is called once of every node in the scene. The objects are // exported as they are encoutered. // Before recursing into the children of a node, we will export it. // The benefit of this is that a nodes parent is always before the // children in the resulting file. This is desired since a child's // transformation matrix is optionally relative to the parent. BOOL Max2Nmo::nodeEnum(INode* node) { // Only export if exporting everything or it's selected if(!exportSelected || node->Selected()) { nCurNode++; if( GetShowProgressionBar() ){ ip->ProgressUpdate((int)((float)nCurNode/nTotalNodeCount*100.0f)); } // Stop recursing if the user pressed Cancel if (ip->GetCancel()) return FALSE; // If this node is a group head, all children are // members of this group. The node will be a dummy node and the node name // is the actualy group name. if (node->IsGroupHead()) { // TODO if (!GetGroupAsPlace()) { CKGroup* group = VirtoolsExporter->AddGroup(node->GetName(),node); // If there was a group being parsed : Add the newly created group CKGroup* PrevGroup = CKGroups.Size() ? CKGroups.Back() : NULL; if (PrevGroup) { PrevGroup->AddObject(group); } CKGroups.PushBack(group); } } // The ObjectState is a 'thing' that flows down the pipeline containing // all information about the object. By calling EvalWorldState() we tell // max to eveluate the object at end of the pipeline. ObjectState os = node->EvalWorldState(0); // The obj member of ObjectState is the actual object we will export. if (os.obj) { // We look at the super class ID to determine the type of the object. switch(os.obj->SuperClassID()) { case GEOMOBJECT_CLASS_ID: ExportGeomObject(node); break; case CAMERA_CLASS_ID: ExportCameraObject(node); break; case LIGHT_CLASS_ID: ExportLightObject(node); break; case SHAPE_CLASS_ID: //Export the curve as a dummy if the checkbox is checked //or if it is a character. if(this->GetSplinesAsDummies()) ExportHelperObject(node); else ExportShapeObject(node); break; case HELPER_CLASS_ID: ExportHelperObject(node); break; } } // For each child of this node, we recurse into ourselves // until no more children are found. for (int c = 0; c < node->NumberOfChildren(); c++) { if (!nodeEnum(node->GetChildNode(c))) return FALSE; } // If this is true here, it is the end of the group we started above. if (node->IsGroupHead()) { if (!GetGroupAsPlace()) { CKGroups.PopBack(); } GroupIndent-=2; } } else { // node is not selected but one of its child may // For each child of this node, we recurse into ourselves // until no more children are found. for (int c = 0; c < node->NumberOfChildren(); c++) { if (!nodeEnum(node->GetChildNode(c))) return FALSE; } } return TRUE; } XString Max2Nmo::StrGroupIndent() { XString str = ""; for (int i=0;iSelected() == TRUE)) mtlList.AddMtl(node->GetMtl()); // For each child of this node, we recurse into ourselves // and increment the counter until no more children are found. for (int c = 0; c < node->NumberOfChildren(); c++) { PreProcess(node->GetChildNode(c), nodeCount); } } void Max2Nmo::PostProcess(INode* node) { if(!exportSelected || node->Selected()) { ExportAnimMesh(node); } // For each child of this node, we recurse into ourselves for (int c = 0; c < node->NumberOfChildren(); c++) { PostProcess(node->GetChildNode(c)); } } /**************************************************************************** Configuration. To make all options "sticky" across sessions, the options are read and written to a configuration file every time the exporter is executed. ****************************************************************************/ TSTR Max2Nmo::GetCfgFilename() { TSTR filename; filename += ip->GetDir(APP_PLUGCFG_DIR); filename += "\\"; filename += CFGFILENAME; return filename; } // NOTE: Update anytime the CFG file changes #define CFG_BEFORECOMPRESSVERSION 0x02 #define CFG_BEFOREOPTIONREDOUNDANT 0x03 #define CFG_BEFOREOPTIONSHELLASSINGLE 0x04 #define CFG_BEFOREOPTIONIGNORE1KEYANIM 0x05 #define CFG_BEFOREOPTIONSELECTIONASGROUP 0x06 //Had to add Selection as group at the end it was not there #define CFG_ALPHAREFADDED 0x07 #define CFG_OPTIONFORCESKINTOMORPHADDED 0x08 #define CFG_BLENDSHAPESEXPORT 0x09 #define CFG_VERSION 0x09 BOOL Max2Nmo::ReadConfig() { TSTR filename = GetCfgFilename(); FILE* cfgStream; cfgStream = fopen(filename, "rt"); if (!cfgStream) return FALSE; int version; char CharacterName[256]; char AnimationName[256]; char CameraName[256]; char ReadChannels[512]; CharacterName[0] = 0; AnimationName[0] = 0; CameraName[0] = 0; ReadChannels[0] = 0; //---- read Version fscanf(cfgStream,"%d",&version); //---- read settings if (version < CFG_BEFORECOMPRESSVERSION) { nCompressionLevel = 0; fscanf(cfgStream,"%d %d %d %d %d %d %d %d %d %s %s %d %d\n", &bExportAsObjects, &bExportAsCharacter, &bExportAsAnimationOnly, &bConvertPhysiqueToSkin, &bStoreOnlyTextureFilenames, &bRescaleScene, &nReportLevel, &nMeshFrameStep, &nKeyFrameStep, CharacterName, AnimationName, &bGroupAsPlace, &bSaveBipedGeom); } else //---- read settings if (version < CFG_BEFOREOPTIONREDOUNDANT) { fscanf(cfgStream,"%d %d %d %d %d %d %d %d %d %s %s %d %d %d %d\n", &bExportAsObjects, &bExportAsCharacter, &bExportAsAnimationOnly, &bConvertPhysiqueToSkin, &bStoreOnlyTextureFilenames, &bRescaleScene, &nReportLevel, &nMeshFrameStep, &nKeyFrameStep, CharacterName, AnimationName, &bGroupAsPlace, &bSaveBipedGeom, &nCompressionLevel, &bAlignAnimOnZ); } else { if (version < CFG_BEFOREOPTIONSHELLASSINGLE) fscanf(cfgStream,"%d %d %d %d %d %d %d %d %d %s %s %d %d %d %d %d\n", &bExportAsObjects, &bExportAsCharacter, &bExportAsAnimationOnly, &bConvertPhysiqueToSkin, &bStoreOnlyTextureFilenames, &bRescaleScene, &nReportLevel, &nMeshFrameStep, &nKeyFrameStep, CharacterName, AnimationName, &bGroupAsPlace, &bSaveBipedGeom, &nCompressionLevel, &bAlignAnimOnZ, &bReduceRedondantKeys); else { if (version < CFG_BEFOREOPTIONIGNORE1KEYANIM) { fscanf(cfgStream,"%d %d %d %d %d %d %d %d %d %s %s %d %d %d %d %d %d\n", &bExportAsObjects, &bExportAsCharacter, &bExportAsAnimationOnly, &bConvertPhysiqueToSkin, &bStoreOnlyTextureFilenames, &bRescaleScene, &nReportLevel, &nMeshFrameStep, &nKeyFrameStep, CharacterName, AnimationName, &bGroupAsPlace, &bSaveBipedGeom, &nCompressionLevel, &bAlignAnimOnZ, &bReduceRedondantKeys, &bShellMaterialExportBoth); } else { if(version < CFG_BEFOREOPTIONSELECTIONASGROUP) { fscanf(cfgStream,"%d %d %d %d %d %d %d %d %d %s %s %d %d %d %d %d %d %d\n", &bExportAsObjects, &bExportAsCharacter, &bExportAsAnimationOnly, &bConvertPhysiqueToSkin, &bStoreOnlyTextureFilenames, &bRescaleScene, &nReportLevel, &nMeshFrameStep, &nKeyFrameStep, CharacterName, AnimationName, &bGroupAsPlace, &bSaveBipedGeom, &nCompressionLevel, &bAlignAnimOnZ, &bReduceRedondantKeys, &bShellMaterialExportBoth, &bIgnore1KeyAnimation); } else { //Current Version //fscanf(cfgStream,"%d %d %d %d %d %d %d %d %d %s %s %d %d %d %d %d %d %d %d %d %f %d %d %d %d %d %d %d %d %d %d %d %d %d %d %s %d %d\n", fscanf(cfgStream,"%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %f %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", &bExportAsObjects, &bExportAsCharacter, &bExportAsAnimationOnly, &bConvertPhysiqueToSkin, &bStoreOnlyTextureFilenames, &bRescaleScene, &nReportLevel, &nMeshFrameStep, &nKeyFrameStep, //CharacterName, //AnimationName, &bGroupAsPlace, &bSaveBipedGeom, &nCompressionLevel, &bAlignAnimOnZ, &bReduceRedondantKeys, &bShellMaterialExportBoth, &bIgnore1KeyAnimation, &bExportAnimation, &bExportAsLevel, &fKeysThreshold, &bForceAllUVs, &bSplitMesh, &bLOD, &bSplinesAsDummies, &bExportAlphaMap, &bUsePower2, &bForce1x1Ratio, &nForce1x1RatioMethod, &bDeactivateMeshChannels, &bHideHelpers, &bDASIAnimation, &bDASIMesh, &bDASIMaterial, &bDASITexture, //CameraName, &bSelectionAsGroup, &bReadChannels ); fgets(CharacterName,256,cfgStream); fgets(AnimationName,256,cfgStream); fgets(CameraName,256,cfgStream); fgets(ReadChannels,512,cfgStream); if (version>=CFG_ALPHAREFADDED) { fscanf(cfgStream,"\n%d %d\n", &bAlphaRef, &iAlphaRefValue); } } } } } if (version >= CFG_OPTIONFORCESKINTOMORPHADDED) { fscanf(cfgStream,"%d \n", &bForceSkinToMorph); } if (version>=CFG_BLENDSHAPESEXPORT) { fscanf(cfgStream,"%d %d %d %d %f %d\n", &bExportBlendShapes, &bExportBlendShapeAnims, &bIncludeBlendShapesInMorphController, &bReduceRedondantBlendShapesKeys, &fBlendShapesKeysThreshold, &nBlendShapesStep ); } fclose(cfgStream); if(version >= CFG_BEFOREOPTIONSELECTIONASGROUP) { //Remove the \n character CharacterName[strlen(CharacterName)-1]='\0'; AnimationName[strlen(AnimationName)-1]='\0'; CameraName[strlen(CameraName)-1]='\0'; ReadChannels[strlen(ReadChannels)-1]='\0'; } SetCharacterName(CharacterName); SetAnimationName(AnimationName); SetStartingCamera(CameraName); SetReadChannelsFilename(ReadChannels); return TRUE; } void Max2Nmo::WriteConfig() { TSTR filename = GetCfgFilename(); FILE* cfgStream; cfgStream = fopen(filename, "wt"); if (!cfgStream) return; // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 fprintf(cfgStream,"%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %f %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n%s\n%s\n%s\n%s\n", //01 CFG_VERSION, GetExportAsObjects(), GetExportAsCharacter(), GetExportAsAnimationOnly(), GetConvertPhysiqueToSkin(), GetStoreOnlyFilenames(), GetRescaleScene(), GetReportLevel(), GetMeshFrameStep(), GetKeyFrameStep(), //11 bGroupAsPlace, bSaveBipedGeom, GetCompressionLevel(), bAlignAnimOnZ, bReduceRedondantKeys, bShellMaterialExportBoth, bIgnore1KeyAnimation, GetExportAnimation(), GetExportAsLevel(), GetKeysThreshold(), //21 GetForceAllUVs(), GetSplitMesh(), GetLOD(), GetSplinesAsDummies(), GetExportAlphaMap(), GetUsePower2(), GetForce1x1Ratio(), GetForce1x1RatioMethod(), //31 GetDeactivateMeshChannels(), GetHideHelpers(), GetDASIAnimation(), GetDASIMesh(), GetDASIMaterial(), GetDASITexture(), GetSelectionAsGroup(), GetReadChannels(), (char *)GetCharacterName(), (char *)GetAnimationName(), (char *)GetStartingCamera(), (char *)GetReadChannelsFilename() ); //alphra ref fprintf(cfgStream,"%d %d \n",GetAlphaRef(),GetAlphaRefValue()); fprintf(cfgStream,"%d \n", GetForceSkinToMorph()); // blend shapes fprintf(cfgStream,"%d %d %d %d %f %d\n", GetExportBlendShapes(), GetExportBlendShapeAnims(), GetIncludeBlendShapesInMorphController(), GetReduceRedondantBlendShapesKeys(), GetBlendShapesKeysThreshold(), GetBlendShapesStep() ); fclose(cfgStream); } void Max2Nmo::RescaleScene() { int type; float scale; float convertFactor=1.0f; //--- Araya: If the Unit's type is Generic then we never rescale the scene... which is wrong no ? ///// well anyway I commented this line... if (1){//UNITDISP_GENERIC != GetUnitDisplayType()) { GetMasterUnitInfo(&type, &scale); convertFactor=scale; switch(type) { case UNITS_INCHES: convertFactor*=0.0254f; break; case UNITS_FEET: convertFactor*=0.3048f; break; case UNITS_MILES: convertFactor*=1609.344f; break; case UNITS_MILLIMETERS: convertFactor*=0.001f; break; case UNITS_CENTIMETERS: convertFactor*=0.01f; break; case UNITS_METERS: convertFactor*=1.0f; break; case UNITS_KILOMETERS: convertFactor*=1000; break; } } this->m_RescaleFactor=convertFactor; /*Done in Post Process now if(convertFactor!=1.0f) { ip->RescaleWorldUnits(convertFactor, FALSE); SetMasterUnitInfo(UNITS_METERS,1.0f); ip->ForceCompleteRedraw(); }*/ } /**************************************************************************** User Interface. Functions for UI interactivity. ****************************************************************************/ void Max2Nmo::UIEnableAnimation(HWND hWnd, BOOL v) { EnableWindow( GetDlgItem(hWnd, IDC_CHECKALIGNANIMATIONS), v); EnableWindow( GetDlgItem(hWnd, IDC_CHECK_IGNORE1KEYANIMATION), v); EnableWindow( GetDlgItem(hWnd, IDC_CHECKREDUCEREDOUNDANTKEYS), v); EnableWindow( GetDlgItem(hWnd, IDC_KEYSTHRESHOLD), v); EnableWindow( GetDlgItem(hWnd, IDC_KEYSTHRESHOLDSPIN), v); EnableWindow( GetDlgItem(hWnd, IDC_MESH_STEP), v); EnableWindow( GetDlgItem(hWnd, IDC_MESH_STEP_SPIN), v); EnableWindow( GetDlgItem(hWnd, IDC_CONT_STEP), v); EnableWindow( GetDlgItem(hWnd, IDC_CONT_STEP_SPIN), v); EnableWindow( GetDlgItem(hWnd, IDC_EDITANIMATIONNAME), v); EnableWindow( GetDlgItem(hWnd, IDC_CHECK_FORCESKINTOMORPH), v); EnableWindow( GetDlgItem(hWnd, IDC_RADIOSKIN), v); EnableWindow( GetDlgItem(hWnd, IDC_RADIOMORPH), v); EnableWindow( GetDlgItem(hWnd, IDC_STATIC_PHYSIQUECONVERSION), v); EnableWindow( GetDlgItem(hWnd, IDC_STATIC_CONTROLLERSOUTPUT), v); EnableWindow( GetDlgItem(hWnd, IDC_STATIC_THRESHOLD), v); EnableWindow( GetDlgItem(hWnd, IDC_STATIC_CONTROLLERS1), v); EnableWindow( GetDlgItem(hWnd, IDC_STATIC_CONTROLLERS2), v); EnableWindow( GetDlgItem(hWnd, IDC_EXPORTBLENDSHAPEANIMS), v); EnableWindow( GetDlgItem(hWnd, IDC_KEYSTHRESHOLD_BLENDSHAPES), v); EnableWindow( GetDlgItem(hWnd, IDC_KEYSTHRESHOLDSPIN_BLENDSHAPES), v); EnableWindow( GetDlgItem(hWnd, IDC_STATIC_THRESHOLD_BLENDSHAPES), v); EnableWindow( GetDlgItem(hWnd, IDC_STATIC_THRESHOLD_RANGE_BLENDSHAPES), v); EnableWindow( GetDlgItem(hWnd, IDC_STATIC_CONTROLLERS3), v); EnableWindow( GetDlgItem(hWnd, IDC_BLENDSHAPES_STEP), v); EnableWindow( GetDlgItem(hWnd, IDC_BLENDSHAPES_STEP_SPIN), v); EnableWindow( GetDlgItem(hWnd, IDC_CHECKREDUCEREDOUNDANTKEYS_BLENDSHAPES), v); BOOL blendShapesOn = IsDlgButtonChecked(hWnd, IDC_EXPORTBLENDSHAPES) || IsDlgButtonChecked(hWnd, IDC_EXPORTBLENDSHAPEANIMS); EnableWindow(GetDlgItem(hWnd, IDC_INCLUDEBLENDSHAPESINMORPHCONTROLLER), !blendShapesOn && v); // converting physique or skin to morph is not compatible with separate blend shape export EnableWindow(GetDlgItem(hWnd, IDC_CHECK_FORCESKINTOMORPH), !blendShapesOn && v); EnableWindow(GetDlgItem(hWnd, IDC_STATIC_PHYSIQUECONVERSION), !blendShapesOn && v); EnableWindow(GetDlgItem(hWnd, IDC_RADIOSKIN), !blendShapesOn && v); EnableWindow(GetDlgItem(hWnd, IDC_RADIOMORPH), !blendShapesOn && v); } void Max2Nmo::UIEnableCharacter(HWND hWnd, BOOL v) { EnableWindow(GetDlgItem(hWnd, IDC_EDITCHARACTERNAME), v); } void Max2Nmo::UIEnableLevel(HWND hWnd, BOOL v) { EnableWindow(GetDlgItem(hWnd, IDC_EDITSTARTINGCAMERA), v); } void Max2Nmo::UIEnableTextureOptions(HWND hWnd, BOOL v) { if(!IsDlgButtonChecked(hWnd, IDC_RADIOEXPORTASANIMATION )){ EnableWindow(GetDlgItem(hWnd, IDC_CHECKPOWER2), v); EnableWindow(GetDlgItem(hWnd, IDC_CHECKFORCERATIO), v); EnableWindow(GetDlgItem(hWnd, IDC_COMBOFORCERATIOMETHOD), v); } } void Max2Nmo::UIAnimationOnly(HWND hWnd) { BOOL v= IsDlgButtonChecked(hWnd, IDC_RADIOEXPORTASANIMATION )==TRUE; //Force Export Anim if(v) { CheckDlgButton(hWnd, IDC_CHECKEXPORTANIMATION ,v ); } EnableWindow(GetDlgItem(hWnd, IDC_CHECKEXPORTANIMATION), !v ); //Disable unwanted settings EnableWindow(GetDlgItem(hWnd, IDC_CHECKGROUPASPLACE), !v); EnableWindow(GetDlgItem(hWnd, IDC_CHECKFORCEUVS), !v); EnableWindow(GetDlgItem(hWnd, IDC_CHECKSPLITMESH), !v); EnableWindow(GetDlgItem(hWnd, IDC_CHECKSHELLMATERIALASSINGLE), !v); EnableWindow(GetDlgItem(hWnd, IDC_CHECKALPHAMAP), !v); EnableWindow(GetDlgItem(hWnd, IDC_CHECKSTOREFILENAMES), !v); EnableWindow(GetDlgItem(hWnd, IDC_CHECKPOWER2), !v); EnableWindow(GetDlgItem(hWnd, IDC_CHECKFORCERATIO), !v); EnableWindow(GetDlgItem(hWnd, IDC_COMBOFORCERATIOMETHOD), !v); EnableWindow(GetDlgItem(hWnd, IDC_CHECKDEACTIVATEMESHCHANNELS), !v); EnableWindow(GetDlgItem(hWnd, IDC_CHECKCHANNELSETTINGS), !v); EnableWindow(GetDlgItem(hWnd, IDC_EDITREADCHANNELSFILENAME), !v); EnableWindow(GetDlgItem(hWnd, IDC_BUTTON_GETCHANNELFILE), !v); EnableWindow(GetDlgItem(hWnd, IDC_CHECKHIDEHELPERS), !v); EnableWindow(GetDlgItem(hWnd, IDC_CHECKDASIMESH), !v); EnableWindow(GetDlgItem(hWnd, IDC_CHECKDASIMATERIAL), !v); EnableWindow(GetDlgItem(hWnd, IDC_CHECKDASITEXTURE), !v); EnableWindow(GetDlgItem(hWnd, IDC_CHECKDEACTIVATEMESHCHANNELS), !v); EnableWindow(GetDlgItem(hWnd, IDC_CHECKBIPEDMESH), !v); //EnableWindow(GetDlgItem(hWnd, IDC_ALPHAREF_CHECK), !v); if (GetAlphaRef()) { EnableWindow(GetDlgItem(hWnd, IDC_ALPHAREF_STEP), !v); EnableWindow(GetDlgItem(hWnd, IDC_ALPHAREF_STEP_SPIN), !v); } } void Max2Nmo::UIEnableGeometryOptions(HWND hWnd, BOOL v ) { EnableWindow(GetDlgItem(hWnd, IDC_CHECKDEACTIVATEMESHCHANNELS), v); } void Max2Nmo::UIEnableResizeTexture(HWND hWnd, BOOL v ) { EnableWindow(GetDlgItem(hWnd, IDC_CHECKFORCERATIO), v); EnableWindow(GetDlgItem(hWnd, IDC_COMBOFORCERATIOMETHOD), v); } void Max2Nmo::UIEnableReadChannels(HWND hWnd, BOOL v ) { EnableWindow(GetDlgItem(hWnd, IDC_EDITREADCHANNELSFILENAME), v); EnableWindow(GetDlgItem(hWnd, IDC_BUTTON_GETCHANNELFILE), v); } void Max2Nmo::UIEnableReport(HWND hWnd, BOOL v ) { EnableWindow(GetDlgItem(hWnd, IDC_EDITREPORTFILENAME), v); EnableWindow(GetDlgItem(hWnd, IDC_BUTTON_GETREPORTFILE), v); } void Max2Nmo::UIUpdate(HWND hWnd) { UIAnimationOnly(hWnd); UIEnableAnimation(hWnd, IsDlgButtonChecked(hWnd, IDC_CHECKEXPORTANIMATION )==1 ); UIEnableCharacter(hWnd, IsDlgButtonChecked(hWnd, IDC_RADIOEXPORTASCHARACTER )==1); UIEnableLevel(hWnd, IsDlgButtonChecked(hWnd, IDC_RADIOEXPORTASLEVEL )==1); UIEnableTextureOptions(hWnd, IsDlgButtonChecked(hWnd, IDC_CHECKSTOREFILENAMES )==0); if( IsWindowEnabled(GetDlgItem(hWnd, IDC_CHECKFORCEUVS))) UIEnableGeometryOptions(hWnd, IsDlgButtonChecked(hWnd, IDC_CHECKFORCEUVS )==1 ); if( IsWindowEnabled(GetDlgItem(hWnd, IDC_CHECKPOWER2))) UIEnableResizeTexture(hWnd, IsDlgButtonChecked(hWnd, IDC_CHECKPOWER2 )==1 ); if( IsWindowEnabled(GetDlgItem(hWnd, IDC_CHECKCHANNELSETTINGS))) UIEnableReadChannels(hWnd, IsDlgButtonChecked(hWnd, IDC_CHECKCHANNELSETTINGS )==1 ); if( IsWindowEnabled(GetDlgItem(hWnd, IDC_CHECKREPORT))) UIEnableReport(hWnd, IsDlgButtonChecked(hWnd, IDC_CHECKREPORT )==1 ); BOOL b = IsDlgButtonChecked(hWnd, IDC_CHECKSTOREFILENAMES); EnableWindow(GetDlgItem(hWnd, IDC_CHECKALPHAMAP), !b); if (b) CheckDlgButton(hWnd, IDC_CHECKALPHAMAP,0); } void Max2Nmo::UIToolTips(HWND hWnd) { //UICreateToolTip( GetDlgItem(hWnd, IDC_RADIO_USEKEYS), (LPTSTR)"ToolTip1" ); //UICreateToolTip( GetDlgItem(hWnd, IDC_RADIO_SAMPLE), (LPTSTR)"ToolTip2" ); //UICreateToolTip( GetDlgItem(hWnd, IDC_IKJOINTS), (LPTSTR)"ToolTip3" ); //UICreateToolTip( GetDlgItem(hWnd, IDC_OBJ_LIGHT), (LPTSTR)"ToolTip4" ); //UICreateToolTip( GetDlgItem(hWnd, IDC_VERTEXCOLORS), (LPTSTR)"ToolTip5" ); UICreateToolTip( GetDlgItem(hWnd, IDC_RADIOEXPORTASOBJECTS), (LPTSTR)"Export scene to objects" ); UICreateToolTip( GetDlgItem(hWnd, IDC_RADIOEXPORTASCHARACTER), (LPTSTR)"Export scene as a character. Be sure there is only one root in the scene." ); UICreateToolTip( GetDlgItem(hWnd, IDC_RADIOEXPORTASANIMATION), (LPTSTR)"Export scene as animation only." ); UICreateToolTip( GetDlgItem(hWnd, IDC_RADIOEXPORTASLEVEL), (LPTSTR)"Export scene as a level. It produce a CMO and save ambient lighting and fog settings." ); UICreateToolTip( GetDlgItem(hWnd, IDC_EDITANIMATIONNAME), (LPTSTR)"Enter the animation name." ); UICreateToolTip( GetDlgItem(hWnd, IDC_EDITSTARTINGCAMERA), (LPTSTR)"The level starting camera name. You need a valid camera to export fog settings correctly since the Effect near and far camera planes influence how the fog is calculated by the 3DSMax renderer." ); //UICreateToolTip( GetDlgItem(hWnd, IDC_STATIC_ANIMNAME), (LPTSTR)"ToolTip11" ); //UICreateToolTip( GetDlgItem(hWnd, IDC_EDITCHARACTERNAME), (LPTSTR)"ToolTip12" ); UICreateToolTip( GetDlgItem(hWnd, IDC_RADIOSKIN), (LPTSTR)"Physique Deformation will be converted to a Virtools Skin and the bones' animations will be exported." ); UICreateToolTip( GetDlgItem(hWnd, IDC_RADIOMORPH), (LPTSTR)"Physique Deformation will be converted to Morph Animation. The bones won't be link to the mesh." ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKRESCALESCENE), (LPTSTR)"Enabling this will apply a scaling where 1 MAX unit = 1 Virtools (NOT SURE)" ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKSTOREFILENAMES), (LPTSTR)"Enabling this will save only the texture name. Otherwise textures are included in the file. If you see blank texture in Virtools check your ressources paths for a _marker or the Path Manager." ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKGROUPASPLACE), (LPTSTR)"Groups will be converted to places." ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKBIPEDMESH), (LPTSTR)"Checking this will export the Biped geometry" ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKALIGNANIMATIONS), (LPTSTR)"Align the character animation on the Z." ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKREDUCEREDOUNDANTKEYS), (LPTSTR)"When successive animation keys are equal, keys will be deleted to optimize the size of the animation." ); //UICreateToolTip( GetDlgItem(hWnd, IDC_MATERIAL_OPTIONSGROUP), (LPTSTR)"ToolTip21" ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKSHELLMATERIALASSINGLE), (LPTSTR)"A shell material has 2 submaterials, a render one and a viewport one. By default only the viewport one is exported. Check this if you want both." ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKFORCEUVS), (LPTSTR)"By default UVs are extracted every time a MAX material or a sub material (Std, MultiSubObject, Blend, Shell, Composite) has a bitmap map in its diffuse slot. Check this to force the export of all mapping channels even if there is no map applied." ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECK_IGNORE1KEYANIMATION), (LPTSTR)"Check this to ignore animation on object with only one keyframe. It is usfull if you want to make secondary animations" ); UICreateToolTip( GetDlgItem(hWnd, IDC_COMBOFORCERATIOMETHOD), (LPTSTR)"Select the method used when converting the size of textures." ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKALPHAMAP), (LPTSTR)"Export opacity map. If the alpha map is not the same as the opacity map, a copy of the texture is created." ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKPOWER2), (LPTSTR)"Force the texture size to a power of 2. (2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 or 2048)" ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKFORCERATIO), (LPTSTR)"Force textures to have the same weight and height." ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKDEACTIVATEMESHCHANNELS), (LPTSTR)"Deactive all the mesh channels. Usefull when using shaders because you don't want to use the fixed multipass pipeline."); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKHIDEHELPERS), (LPTSTR)"Only meshes will be visible. This is usefull for a character skin export when you don't want to see bones or curves."); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKLOD), (LPTSTR)"Meshes having the LOD1,LOD2,...LOD9 suffixes will be considered Level of Detail Meshes. A LOD object attribute is added to LOD 3DEntities and unwanted 3DEntities are removed." ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKSPLINESASDUMMIES), (LPTSTR)"Consider Spline as Dummies usefull when you have a character rig with spline controlling the bones. Only the transformation matrix of the spline is used and a 3DFrame is created." ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKEXPORTANIMATION), (LPTSTR)"Enable or Disable the Animation Export." ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECK_FORCESKINTOMORPH), (LPTSTR)"Force skin animations to be exported as mesh animations." ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKDASIANIMATION), (LPTSTR)"PostProcess: Detect and Share Identical Animations." ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKDASIMESH), (LPTSTR)"PostProcess: Detect and Share Identical Meshes." ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKDASIMATERIAL), (LPTSTR)"PostProcess: Detect and Share Identical Materials." ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKDASITEXTURE), (LPTSTR)"PostProcess: Detect and Share Identical Textures." ); UICreateToolTip( GetDlgItem(hWnd, IDC_CHECKSPLITMESH), (LPTSTR)"This options will split a mesh if more than one multilayer material(shell, blend, composite) is used by a MultiSubObject Material." ); UICreateToolTip( GetDlgItem(hWnd, IDC_CONT_STEP), (LPTSTR)"Change the sampling rate of unsupported controllers." ); UICreateToolTip( GetDlgItem(hWnd, IDC_CONT_STEP_SPIN), (LPTSTR)"Change the sampling rate of unsupported controllers." ); UICreateToolTip( GetDlgItem(hWnd, IDC_MESH_STEP), (LPTSTR)"Change the sampling rate use for morph animations." ); UICreateToolTip( GetDlgItem(hWnd, IDC_MESH_STEP_SPIN), (LPTSTR)"Change the sampling rate use for morph animations." ); //UICreateToolTip( GetDlgItem(hWnd, IDC_CONT_REPORT), (LPTSTR)"ToolTip48" ); //UICreateToolTip( GetDlgItem(hWnd, IDC_CONT_REPORTSPIN), (LPTSTR)"ToolTip49" ); //UICreateToolTip( GetDlgItem(hWnd, IDC_STATIC_FRAME), (LPTSTR)"ToolTip50" ); //UICreateToolTip( GetDlgItem(hWnd, IDC_CONT_COMPRESSION), (LPTSTR)"ToolTip51" ); //UICreateToolTip( GetDlgItem(hWnd, IDC_STATIC_FRAME_SPIN), (LPTSTR)"ToolTip52" ); //UICreateToolTip( GetDlgItem(hWnd, IDC_CONT_COMPRESSIONSPIN), (LPTSTR)"ToolTip53" ); //UICreateToolTip( GetDlgItem(hWnd, IDC_PREC), (LPTSTR)"ToolTip54" ); //UICreateToolTip( GetDlgItem(hWnd, IDC_KEYSTHRESHOLD), (LPTSTR)"ToolTip55" ); //UICreateToolTip( GetDlgItem(hWnd, IDC_PREC_SPIN), (LPTSTR)"ToolTip56" ); //UICreateToolTip( GetDlgItem(hWnd, IDC_KEYSTHRESHOLDSPIN), (LPTSTR)"ToolTip57" ); UICreateToolTip( GetDlgItem(hWnd, IDC_COMBOFORCERATIOMETHOD), (LPTSTR)"Set the report level." ); //UICreateToolTip( GetDlgItem(hWnd, IDC_ALPHAREF_CHECK), (LPTSTR)"Alpha ref value for materials." ); UICreateToolTip( GetDlgItem(hWnd, IDC_ALPHAREF_STEP), (LPTSTR)"Alpha ref value for materials." ); UICreateToolTip( GetDlgItem(hWnd, IDC_ALPHAREF_STEP_SPIN), (LPTSTR)"Alpha ref value for materials." ); } void Max2Nmo::UICreateToolTip(HWND hWnd, LPTSTR lptstr) { // struct specifying control classes to register INITCOMMONCONTROLSEX iccex; HWND hwndTT; // handle to the ToolTip control // struct specifying info about tool in ToolTip control TOOLINFO ti; unsigned int uid = 0; // for ti initialization RECT rect; // for client area coordinates /* INITIALIZE COMMON CONTROLS */ iccex.dwICC = ICC_WIN95_CLASSES; iccex.dwSize = sizeof(INITCOMMONCONTROLSEX); InitCommonControlsEx(&iccex); /* CREATE A TOOLTIP WINDOW */ hwndTT = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hWnd, NULL, hInstance, NULL ); SetWindowPos(hwndTT, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); /* GET COORDINATES OF THE MAIN CLIENT AREA */ GetClientRect (hWnd, &rect); /* INITIALIZE MEMBERS OF THE TOOLINFO STRUCTURE */ ti.cbSize = sizeof(TOOLINFO); ti.uFlags = TTF_SUBCLASS; ti.hwnd = hWnd; ti.hinst = hInstance; ti.uId = uid; ti.lpszText = lptstr; // ToolTip control will cover the whole window ti.rect.left = rect.left; ti.rect.top = rect.top; ti.rect.right = rect.right; ti.rect.bottom = rect.bottom; /* SEND AN ADDTOOL MESSAGE TO THE TOOLTIP CONTROL WINDOW */ SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti); //Set a Max Width for the tooltips SendMessage( // returns LRESULT in lResult (HWND) hwndTT, // handle to destination control (UINT) TTM_SETMAXTIPWIDTH, // message ID (WPARAM) 0, // = 0; not used, must be zero (LPARAM) 350 // = (LPARAM) (INT) iWidth; ); //Don't work... //Set the popup visible time delay to really high SendMessage( // returns LRESULT in lResult (HWND) hwndTT, // handle to destination control (UINT) TTM_SETDELAYTIME, // message ID TTDT_AUTOPOP, // = (WPARAM) (DWORD) dwDuration (LPARAM) MAKELONG(99999, 0) // = (LPARAM) MAKELONG(iTime, 0) ); } const char* Max2Nmo::UIGetFilename(HWND hWnd, TCHAR szFile[], DWORD iMaxLength, TCHAR* szFilter, BOOL iSave) { // Initialize the OPENFILENAME members. OPENFILENAME Ofn; if(!szFilter) szFilter = "All\0*.*\0"; szFile[0]='\0'; Ofn.lStructSize=sizeof(OPENFILENAME); Ofn.hwndOwner=hWnd; Ofn.hInstance=NULL; Ofn.lpstrFilter=NULL; Ofn.lpstrCustomFilter=NULL; Ofn.nMaxCustFilter; Ofn.nFilterIndex=1; Ofn.lpstrFile=szFile; Ofn.nMaxFile=iMaxLength; Ofn.lpstrFileTitle=NULL; Ofn.nMaxFileTitle; Ofn.lpstrInitialDir=NULL; Ofn.lpstrTitle=NULL; Ofn.Flags=0; Ofn.nFileOffset; Ofn.nFileExtension; Ofn.lpstrDefExt=NULL; Ofn.lCustData; Ofn.lpfnHook=NULL; Ofn.lpTemplateName=NULL; // Display the Filename common dialog box. if(iSave) { if(GetSaveFileName(&Ofn)) return szFile; } else { if(GetOpenFileName(&Ofn)) return szFile; } return NULL; } BOOL MtlKeeper::AddMtl(Mtl* mtl) { if (!mtl) { return FALSE; } int numMtls = mtlTab.Count(); for (int i=0; i