xrefutil.cpp Source File

DllEntry / xfrefutil

Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

xrefutil.cpp

Go to the documentation of this file.
00001 // Copyright (C) 2000 by Autodesk, Inc.
00002 //
00003 // Permission to use, copy, modify, and distribute this software in
00004 // object code form for any purpose and without fee is hereby granted,
00005 // provided that the above copyright notice appears in all copies and
00006 // that both that copyright notice and the limited warranty and
00007 // restricted rights notice below appear in all supporting
00008 // documentation.
00009 //
00010 // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
00011 // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
00012 // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.  AUTODESK, INC.
00013 // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
00014 // UNINTERRUPTED OR ERROR FREE.
00015 //
00016 // Use, duplication, or disclosure by the U.S. Government is subject to
00017 // restrictions set forth in FAR 52.227-19 (Commercial Computer
00018 // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
00019 // (Rights in Technical Data and Computer Software), as applicable.
00021 // XREFUTIL.CPP
00022 //
00023 // DESCR:
00024 //     Simple Utility plug-in sample that shows how to do some of the MAX
00025 //     XRef Scene and Object functionality via SDK APIs.  
00026 //
00027 //     Does not do:
00028 //     -- undo/redo handling
00029 //     -- extensive error checking
00030 //     
00031 //
00032 // CHANGE LOG:
00033 //     03/2000 : DY : Created 
00034 //
00036 
00037 #include "xrefutil.h"
00038 
00039 #define ERROR_TITLE "XRef Util Error"
00040 
00042 // XrefutilClassDesc -- our required ClassDesc
00044 
00045 class XrefutilClassDesc:public ClassDesc2 
00046 {
00047 public:
00048     int             IsPublic()                    { return 1; }
00049     void *          Create(BOOL loading = FALSE)  { return &theXrefutil; }
00050     const TCHAR *   ClassName()                   { return GetString(IDS_CLASS_NAME); }
00051     SClass_ID       SuperClassID()                { return UTILITY_CLASS_ID; }
00052     Class_ID        ClassID()                     { return XREFUTIL_CLASS_ID; }
00053     const TCHAR *   Category()                    { return GetString(IDS_CATEGORY); }
00054     const TCHAR *   InternalName()                { return _T("Xrefutil"); }
00055     HINSTANCE       HInstance()                   { return hInstance; }
00056 };
00057 
00058 static XrefutilClassDesc XrefutilDesc;
00059 
00060 ClassDesc2* GetXrefutilDesc() 

00061 {
00062     return &XrefutilDesc;
00063 }
00064 
00065 static BOOL CALLBACK XrefutilDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)

00066 {
00067     switch (msg) {
00068     case WM_INITDIALOG:
00069         theXrefutil.Init(hWnd);
00070         break;
00071 
00072     case WM_DESTROY:
00073         theXrefutil.Destroy(hWnd);
00074         break;
00075 
00076     case WM_COMMAND:
00077         switch (LOWORD(wParam)) {
00078 
00079         case IDC_CMD_XS_ADD:
00080             // -- Add a new XRef Scene into the current scene --
00081             theXrefutil.AddNewXrefScene(hWnd);
00082             break;
00083 
00084         case IDC_CMD_XS_CNV:
00085             // -- Convert selected nodes into an XRef'd scene --
00086             theXrefutil.ConvertSelectedToXrefScene(hWnd);
00087             break;
00088 
00089         case IDC_CMD_XS_RFS:
00090             // -- Refresh/reload all scene xrefs --
00091             theXrefutil.RefreshAllXrefScenes(hWnd);
00092             break;
00093 
00094         case IDC_CMD_XS_MRG:
00095             // -- merge in all scene xrefs --
00096             theXrefutil.MergeAllXrefScenes(hWnd);
00097             break;
00098 
00099 
00100         case IDC_CMD_XO_ADD:
00101             // -- Add a new XRef Object into the current scene --
00102             theXrefutil.AddNewXrefObject(hWnd);
00103             break;
00104 
00105         case IDC_CMD_XO_CNVSEL:
00106             // -- Convert selected object into an XRef Object --
00107             theXrefutil.ConvertSelectedToXrefObject(hWnd);
00108             break;
00109 
00110         case IDC_CMD_XO_EXP:
00111             // -- fake "export" of all xref objects in scene --
00112             theXrefutil.ExportXrefObjects(hWnd);
00113             break;
00114 
00115         
00116         case IDC_CLOSE:
00117             theXrefutil.m_pUtil->CloseUtility();
00118             break;
00119 
00120         }
00121 
00122 
00123         break;
00124 
00125     default:
00126         return FALSE;
00127     }
00128     return TRUE;
00129 }
00130 
00132 // some more (Xrefutil specific) NodeEnumerator derivations
00134 
00135 class UnflaggedNodeNamer : public NodeEnumerator
00136 {
00137 public:
00138     Tab<TSTR *> * m_namelist;
00139 
00140     UnflaggedNodeNamer() : m_namelist(NULL) {};
00141     virtual bool Proc(INode * pNode);
00142 };
00143 
00144 
00145 bool UnflaggedNodeNamer::Proc(INode * pNode)

00146 {
00147     if (!m_namelist) return false;
00148     // otherwise, grab the list of node names and stick them in namelist
00149     if (! pNode->TestAFlag(A_WORK1)) {
00150         TSTR * pName = new TSTR(pNode->GetName()); // consumer must delete
00151         m_namelist->Append(1, &pName, 5);
00152     }
00153     return true;
00154 }
00155 
00156 class UnflaggedNodeDeleter : public NodeEnumerator
00157 {
00158 public:
00159     virtual bool Proc(INode * pNode);
00160 };
00161 
00162 
00163 bool UnflaggedNodeDeleter::Proc(INode * pNode)

00164 {
00165     // NOTE: should be called with Enumerate(procfirst = false) !
00166     // Always do safety check so that we don't delete root accidentally
00167     if (!pNode->IsRootNode() && !pNode->TestAFlag(A_WORK1)) {
00168         // pNode->DeleteThis();
00169         // theXrefutil.m_pInterface->DeleteNode(pnode, FALSE);
00170         pNode->Delete(0,TRUE);
00171     }
00172 
00173     return true;
00174 }
00175 
00176 class XRefObjFinder : public NodeEnumerator
00177 {
00178 public:
00179     TSTR * m_buffer;
00180 
00181     XRefObjFinder() : m_buffer(NULL) {};
00182     virtual bool Proc(INode * pNode);
00183 };
00184 
00185 bool XRefObjFinder::Proc(INode * pNode)

00186 {
00187     TSTR workstring;
00188 
00189     // NOTE: We dump all info into one big string
00190     // Not super realistic, and probably won't work with
00191     // a scene with lots of XRef objects, but in a real exporter
00192     // situation, you'd be dumping out to a file pointer anyway
00193 
00194     if (!pNode || !m_buffer) return false;
00195     Object *obj = pNode->GetObjectRef();
00196     if (obj && obj->SuperClassID()==SYSTEM_CLASS_ID && 
00197                obj->ClassID()==Class_ID(XREFOBJ_CLASS_ID,0)) {
00198         IXRefObject *ix = (IXRefObject *)obj;
00199         // if pNode refs an XRef object, let's pull some info out of it
00200         workstring.printf("Node <%s> XREF <%s> filename:<%s> proxy:<%s> anim-off:<%s> update-mats:<%s> \x0D\x0A",
00201             pNode->GetName(), ix->GetCurObjName(), ix->GetCurFileName(), 
00202             (ix->GetUseProxy()) ? "T" : "F",
00203             (ix->GetIgnoreAnim()) ? "T" : "F",
00204             (ix->GetUpdateMats()) ? "T" : "F");
00205         m_buffer->append(workstring);
00206     }
00207     return true;
00208 }
00209 
00210 
00211 // Helper class derived from AnimEnum used to delete (keyframed) animation info
00212 
00213 class DeleteAllAnimEnum : public AnimEnum 
00214 {
00215 public: 
00216     BOOL delAtFrame0;
00217 
00218     DeleteAllAnimEnum(BOOL delAt0) : AnimEnum(SCOPE_ALL) {delAtFrame0 = delAt0;}
00219     int proc(Animatable *anim, Animatable *client, int subNum) {
00220         if (delAtFrame0) {
00221             // Evaluate the controller at frame 0 before
00222             // deleting. This will cause its cache to take on
00223             // its value at frame 0.
00224             Control *cont = GetControlInterface(anim);
00225             if (cont) {
00226                 Point3 p;
00227                 Quat q;
00228                 ScaleValue s;
00229                 float f;
00230                 Interval valid;
00231                 switch (cont->SuperClassID()) {
00232                 case CTRL_FLOAT_CLASS_ID:
00233                     cont->GetValue(0,&f,valid); break;
00234                 case CTRL_POSITION_CLASS_ID:
00235                     cont->GetValue(0,&p,valid); break;
00236                 case CTRL_ROTATION_CLASS_ID:
00237                     cont->GetValue(0,&q,valid); break;
00238                 case CTRL_SCALE_CLASS_ID:
00239                     cont->GetValue(0,&s,valid); break;
00240                 case CTRL_POINT3_CLASS_ID:
00241                     cont->GetValue(0,&p,valid); break;
00242                 }
00243                 cont->SetORT(ORT_CONSTANT,ORT_BEFORE);
00244                 cont->SetORT(ORT_CONSTANT,ORT_AFTER);
00245             }
00246         }
00247         anim->DeleteTime(FOREVER,0);
00248         anim->EditTimeRange(Interval(0,0),EDITRANGE_LINKTOKEYS);
00249         return ANIM_ENUM_PROCEED;
00250     }
00251 };
00252 
00253 
00255 // Xrefutil class implementation -- our main utility plugin class
00257 
00259 // Construction/destruction
00260 
00261 Xrefutil::Xrefutil()
00262 : m_pUtil(NULL)
00263 , m_pInterface(NULL)
00264 , m_hPanel(NULL)
00265 , m_proxyholder(false)
00266 , m_ignoreanimholder(false)

00267 {
00268 }
00269 
00270 Xrefutil::~Xrefutil()

00271 {
00272     
00273 }
00274 
00276 // UtilityObj overrides
00277 
00278 void Xrefutil::BeginEditParams(Interface *ip,IUtil *iu) 

00279 {
00280     m_pUtil = iu;
00281     m_pInterface = ip;
00282     m_hPanel = ip->AddRollupPage(hInstance,
00283                                MAKEINTRESOURCE(IDD_PANEL),
00284                                XrefutilDlgProc,
00285                                GetString(IDS_PARAMS),
00286                                0);
00287 }
00288     
00289 void Xrefutil::EndEditParams(Interface *ip,IUtil *iu) 

00290 {
00291     m_pUtil = NULL;
00292     m_pInterface = NULL;
00293     ip->DeleteRollupPage(m_hPanel);
00294     m_hPanel = NULL;
00295 }
00296 
00297 void Xrefutil::DeleteThis()

00298 {
00299     // since there's only one static instance of the
00300     // UtilityObj, we don't do anything here
00301 }
00302 
00303 
00305 // utility methods
00306 
00307 void Xrefutil::Init(HWND hWnd)

00308 {
00309 }
00310 
00311 void Xrefutil::Destroy(HWND hWnd)

00312 {
00313 }
00314 
00315 bool Xrefutil::DoOpenSaveDialog(TSTR &fileName, bool bOpen)

00316 {
00317 
00318     // Does a standard Win32 CommonDlg Save-As or Open dialog
00319     // for a .MAX file
00320     //
00321     // (doesn't use registered custom dlg in MAX, as
00322     // in truth, only MAX can access this cache currently,
00323     // although you'll get any registered dialog if
00324     // you call Interface::FileSave or something similar,
00325     // but we just want to get a filename, not save yet)
00326 
00327     OPENFILENAME    ofn;
00328     TCHAR           szFilter[]=__TEXT("3D Studio MAX (*.MAX)\0*.MAX\0\0");     
00329     TCHAR           fname[512];
00330 
00331     _tcscpy(fname,fileName);
00332     
00333     // set up that OPENFILENAME struct
00334     ::memset(&ofn, 0, sizeof(OPENFILENAME));
00335     ofn.lStructSize      = sizeof(OPENFILENAME);
00336     ofn.hwndOwner        = m_hPanel;
00337     ofn.nFilterIndex     = 1L;
00338     ofn.lpstrFilter      = szFilter;
00339     ofn.lpstrCustomFilter = (LPTSTR)NULL;
00340     ofn.lpstrFile        = fname;
00341     ofn.nMaxFile         = sizeof(fname) / sizeof(TCHAR);
00342     ofn.lpstrFileTitle   = NULL;
00343     ofn.nMaxFileTitle    = 0;
00344     ofn.lpstrInitialDir  = m_pInterface->GetDir(APP_SCENE_DIR);
00345     ofn.lpstrTitle       = (LPCSTR)NULL;
00346     if (bOpen) {
00347         ofn.Flags            = OFN_HIDEREADONLY | OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_LONGNAMES;
00348     } else {
00349         ofn.Flags            = OFN_HIDEREADONLY | OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_LONGNAMES | OFN_OVERWRITEPROMPT;
00350     }
00351     ofn.lpstrDefExt      = _TEXT("MAX");
00352 
00353     if (bOpen) {
00354         if (GetOpenFileName(&ofn)) {
00355 
00356             // NOTE: More error checking needs to be done for this
00357             // to be practical -- e.g. we shouldn't allow the user to
00358             // select the currently open file.  
00359              
00360             fileName = TSTR(ofn.lpstrFile); // full path and file 
00361             return true; // success
00362 
00363         } else {
00364             // user canceled
00365             return false;
00366         }
00367 
00368     } else {   
00369         if (GetSaveFileName(&ofn)) {
00370 
00371             // NOTE: More error checking needs to be done for this
00372             // to be practical -- e.g. we shouldn't allow the user to
00373             // select the currently open file.  
00374              
00375             fileName = TSTR(ofn.lpstrFile); // full path and file 
00376             return true; // success
00377 
00378         } else {
00379             // user canceled
00380             return false;
00381         }
00382     }
00383     return false; // failure
00384 }
00385 
00386 
00387 extern HINSTANCE hInstance;
00388 
00389 static BOOL CALLBACK PickObjDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

00390 {
00391     int i, ix;
00392     UINT chkval;
00393 
00394     switch (message) {
00395 
00396     case WM_INITDIALOG: 
00397         // (populate the listbox)
00398         SendDlgItemMessage(hWnd,IDC_LIST_NODES,LB_RESETCONTENT,0,0);
00399         for (i = 0; i < theXrefutil.m_objnamesholder.Count(); i++) {
00400             TSTR oname = *(theXrefutil.m_objnamesholder[i]);
00401             ix = SendDlgItemMessage(hWnd,IDC_LIST_NODES,LB_ADDSTRING,0,(LPARAM)(TCHAR*)oname);
00402             SendDlgItemMessage(hWnd,IDC_LIST_NODES,LB_SETITEMDATA,ix,i);
00403         }
00404         CenterWindow(hWnd,GetParent(hWnd));
00405         theXrefutil.m_picknameholder = "";
00406         break;
00407 
00408     case WM_COMMAND:
00409 
00410         switch (LOWORD(wParam)) {
00411 
00412         case IDCANCEL:
00413             theXrefutil.m_picknameholder = "";
00414             EndDialog(hWnd,0);
00415             break;
00416 
00417         case IDOK:
00418             // on okay, we just copy over user-picked info into our
00419             // utility object -- slightly unusual, but it's a modal dialog
00420             // and the sample continues the xref object logic fully in
00421             // AddNewXrefObject
00422             ix = ::SendDlgItemMessage(hWnd,IDC_LIST_NODES,LB_GETCURSEL,0,0);
00423             if (ix != LB_ERR) {
00424                 theXrefutil.m_picknameholder = *(theXrefutil.m_objnamesholder[ix]);
00425             }
00426             chkval = ::IsDlgButtonChecked(hWnd, IDC_CHK_PROXY);
00427             if (chkval == BST_CHECKED) theXrefutil.m_proxyholder = true;
00428             else theXrefutil.m_proxyholder = false;
00429             chkval = ::IsDlgButtonChecked(hWnd, IDC_CHK_NOANIM);
00430             if (chkval == BST_CHECKED) theXrefutil.m_ignoreanimholder = true;
00431             else theXrefutil.m_ignoreanimholder = false;
00432 
00433             EndDialog(hWnd,1);
00434             break;
00435 
00436         default:
00437             return FALSE;
00438 
00439         }
00440 
00441     default:
00442         return FALSE;
00443     }
00444 
00445     return TRUE;
00446 
00447 }
00448 
00449 
00450 bool Xrefutil::DoPickObjDialog()

00451 {
00452     // populate IDD_PICKOBJ IDC_LIST_NODES with objnames,
00453     // show dialog modal, get and return results
00454     int dlgres = 0;
00455     
00456     dlgres = DialogBox(hInstance, 
00457                        MAKEINTRESOURCE(IDD_PICKOBJ),
00458                        m_hPanel,
00459                        PickObjDlgProc);
00460     if (dlgres == 1) return true;
00461     return false; // failure
00462 }
00463 
00464 
00465 static BOOL CALLBACK ExportDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

00466 {
00467     TSTR * contents = NULL;
00468 
00469     switch (message) {
00470 
00471     case WM_INITDIALOG: 
00472         // (populate the editbox)
00473         contents = (TSTR *) lParam;
00474         ::SetDlgItemText(hWnd, IDC_EDIT_EXPRES, (TCHAR*)(*contents));
00475         CenterWindow(hWnd,GetParent(hWnd));
00476         break;
00477 
00478     case WM_COMMAND:
00479 
00480         switch (LOWORD(wParam)) {
00481 
00482         case IDOK:
00483             EndDialog(hWnd,1);
00484             break;
00485 
00486         default:
00487             return FALSE;
00488 
00489         }
00490 
00491     default:
00492         return FALSE;
00493     }
00494 
00495     return TRUE;
00496 
00497 }
00498 
00499 
00501 // xref methods
00502 
00503 // (XRef Scene methods)
00504 
00505 void Xrefutil::AddNewXrefScene(HWND hWnd)

00506 {
00507     // *** AddNewXrefScene ***
00508     //
00509     // Add new XRef'd Scene to current scene -- simply get the
00510     // name of the .MAX file, and use RootNode::AddNewXRefFile
00511     // to hook that xref'd scene into the current scene hierarchy
00512     //
00513     // Note: Don't confuse XRef scenes with XRef objects.
00514     // XRef scenes live as special children of the (single) root
00515     // node of the current scene, basically as "XRef'd root nodes"
00516     // of the external scene.  Note that merged-in XRef Root Nodes
00517     // can come from original scenes that already had another scene
00518     // xref'd in, and so-on.  See the SDK documentation on the 
00519     // various XRef Scene APIs on the INode object, keeping in mind
00520     // that these APIs only function when the INode is in fact the
00521     // root node of the scene.
00522     //
00523     
00524     TSTR filename = "";
00525     INode * pRootNode = m_pInterface->GetRootNode();
00526     if (!pRootNode) {
00527         // well, this is actually _really_ bad, but we just exit
00528         return;
00529     }
00530     if (!DoOpenSaveDialog(filename, true)) {
00531         // either cancel or fail, just return
00532         return;
00533     }    
00534     pRootNode->AddNewXRefFile(filename, TRUE);
00535     m_pInterface->RedrawViews(m_pInterface->GetTime());
00536 }
00537 
00538 
00539 void Xrefutil::ConvertSelectedToXrefScene(HWND hWnd)

00540 {
00541     // *** ConvertSelectedToXrefScene ***
00542     //
00543     // Relatively simple -- take the selected nodes, save them out
00544     // to a new .MAX file, delete the selected nodes from the 
00545     // current scene, and then do a RootNode->AddNewXRefFile
00546     // with the just-saved MAX file.
00547 
00548     INode * pNode = NULL;
00549     TSTR filename = "";
00550     int i;
00551 
00552     INode * pRootNode = m_pInterface->GetRootNode();
00553     if (!pRootNode) {
00554         // well, this is actually _really_ bad, but we just exit
00555         return;
00556     }
00557     if (m_pInterface->GetSelNodeCount() == 0) {
00558         ::MessageBox(hWnd, GetString(IDS_ERR3), ERROR_TITLE, MB_ICONSTOP | MB_OK);
00559         return;
00560     }
00561 
00562     Tab<INode *> nodetab;
00563     nodetab.ZeroCount();
00564         nodetab.Shrink();
00565     for (i = 0; i < m_pInterface->GetSelNodeCount(); i++) {
00566         pNode = m_pInterface->GetSelNode(i);
00567         nodetab.Append(1, &pNode, 5);
00568     }
00569 
00570     if (!DoOpenSaveDialog(filename)) {
00571         // either cancel or fail, just return
00572         return;
00573     }
00574 
00575     m_pInterface->FileSaveSelected(filename);
00576 
00577     // delete selected nodes, don't refresh yet
00578     for (i = 0; i < nodetab.Count(); i++) {
00579         nodetab[i]->Delete(0,TRUE);
00580     }
00581 
00582     // add in the nodes we saved out as an xref'd scene
00583     pRootNode->AddNewXRefFile(filename, TRUE);
00584     
00585     m_pInterface->RedrawViews(m_pInterface->GetTime());
00586 
00587 }
00588 
00589 
00590 void Xrefutil::RefreshAllXrefScenes(HWND hWnd)

00591 {
00592     // *** RefreshAllXrefScenes ***
00593     // 
00594     // Refreshes all Xref'd Scenes -- mimics 
00595     // MAX's "Update Now" button on XRef Scene dialog,
00596     // with all xref'd scenes selected.
00597     //
00598     // Simply walk through all XRef'd scenes (hanging off root)
00599     // and use RootNode::ReloadXRef() to reload each one.
00600 
00601     INode * pNode = NULL;
00602     int i, numxrefscenes;
00603 
00604     INode * pRootNode = m_pInterface->GetRootNode();
00605     if (!pRootNode) {
00606         // well, this is actually _really_ bad, but we just exit
00607         return;
00608     }
00609     numxrefscenes = pRootNode->GetXRefFileCount();
00610     for (i = 0; i < numxrefscenes; i++) {
00611         pRootNode->ReloadXRef(i);
00612     }
00613 }
00614 
00615 
00616 void Xrefutil::MergeAllXrefScenes(HWND hWnd)

00617 {
00618     // *** MergeAllXrefScenes ***
00619     //
00620     // Merges ("binds") all XRef Scenes into the
00621     // current scene.  Just using RootNode::BindXRefFile
00622     // will merge in the real scene objects from the xref'd
00623     // scene as real modifiable objects, and delete the
00624     // xref scene link from the scene hierarchy.
00625 
00626     INode * pNode = NULL;
00627     int i, numxrefscenes;
00628 
00629     INode * pRootNode = m_pInterface->GetRootNode();
00630     if (!pRootNode) {
00631         // well, this is actually _really_ bad, but we just exit
00632         return;
00633     }
00634     numxrefscenes = pRootNode->GetXRefFileCount();
00635     for (i = 0; i < numxrefscenes; i++) {
00636         pRootNode->BindXRefFile(i);
00637     }
00638 
00639 }
00640 
00641 
00642 // (XRef Object methods)
00643 
00644 
00645 void Xrefutil::NodeToXref(INode * pNode, TSTR &filename, bool bProxy, bool bIgnoreAnim)

00646 {
00647     IXRefObject * pXRef = (IXRefObject *)m_pInterface->CreateInstance(SYSTEM_CLASS_ID, 
00648         Class_ID(XREFOBJ_CLASS_ID,0));
00649     TSTR obName = TSTR(pNode->GetName());
00650     pXRef->Init(filename, obName, pNode->GetObjectRef(), bProxy);
00651     pNode->SetObjectRef(pXRef);
00652     // also, set visual queue that we're ignoring anim if we did
00653     if (bIgnoreAnim)
00654         pXRef->SetIgnoreAnim(TRUE,FALSE);
00655 }
00656 
00657 void Xrefutil::DeleteAllAnimation(ReferenceTarget *ref)

00658 {
00659     DeleteAllAnimEnum en(TRUE);
00660     ref->EnumAnimTree(&en,NULL,0);
00661 }
00662 
00663 
00664 void Xrefutil::AddNewXrefObject(HWND hWnd)

00665 {
00666     // *** AddNewXrefObject ***
00667     //
00668     // Tries to mimic the functionality of MAX's Add New XRef Object
00669     // 
00670     // Does the following:
00671     // 1) Gets a source .MAX filename from user to get the XRef Object from
00672     // 1.5) Flags current nodes for later
00673     // 2) Merges in this file, but doesn't display end results (yet)
00674     // 3) Walks list of file nodes (not flagged), and lets user pick one to XRef
00675     // 4) Blows away all merged (not flagged) nodes except picked node.  Converts
00676     //    the chosen node into an XRef node (see ConvertSelectedToXrefObject below)
00677     //    with default settings
00678 
00679     INode * pNode = NULL;
00680     TSTR filename = "";
00681     TSTR pickedname = "";
00682     TSTR * workname = NULL;
00683 
00684     INode * pRootNode = m_pInterface->GetRootNode();
00685     if (!pRootNode) {
00686         // well, this is actually _really_ bad, but we just exit
00687         return;
00688     }
00689     if (!DoOpenSaveDialog(filename, true)) {
00690         // either cancel or fail, just return
00691         return;
00692     }
00693 
00694     // in preparation for merge, flag current scene nodes
00695     NodeFlagger newFlagger(A_WORK1);
00696     newFlagger.Enumerate(pRootNode);
00697 
00698     // merge in user-picked file into current scene
00699     // NOTE: We just skip anything in xref'd file that has the same name
00700     // as an object in the current scene
00701     if (! m_pInterface->MergeFromFile(filename, TRUE, FALSE, FALSE, MERGE_DUPS_SKIP, NULL)) {
00702         // error, merge failed
00703         newFlagger.set_clear(true);
00704         newFlagger.Enumerate(pRootNode);
00705         return;
00706     }
00707 
00708     // walk scene and build list of non-flagged nodes
00709     m_objnamesholder.ZeroCount();
00710         m_objnamesholder.Shrink();
00711     UnflaggedNodeNamer newNamer;
00712     newNamer.m_namelist = &m_objnamesholder;
00713     newNamer.Enumerate(pRootNode);
00714     UnflaggedNodeDeleter newDeleter;
00715 
00716     // present list of nodes to user, sep. modal dialog
00717     if (DoPickObjDialog() && m_picknameholder.length() > 0) {
00718         pNode = m_pInterface->GetINodeByName(m_picknameholder);
00719         if (pNode) {
00720             if (m_ignoreanimholder && pNode->IsAnimated()) {
00721                 // if animation is ignored, we basically go through
00722                 // the node and delete all the keys for the node's controllers
00723                 // Note that this won't remove animation for procedural controllers
00724                 DeleteAllAnimation(pNode);
00725             }
00726             NodeToXref(pNode, filename, m_proxyholder, m_ignoreanimholder);
00727             // flag this converted node so we keep it
00728             pNode->SetAFlag(A_WORK1);
00729         }
00730     }
00731 
00732     // deleted non-flagged nodes, un-flag original nodes, and return
00733     newDeleter.Enumerate(pRootNode);
00734     newFlagger.set_clear(true);
00735     newFlagger.Enumerate(pRootNode);
00736     for (int delme = 0; delme < m_objnamesholder.Count(); delme++) { 
00737         // (clean up TSTRs)
00738         delete m_objnamesholder[delme];
00739     }
00740 
00741     m_pInterface->RedrawViews(m_pInterface->GetTime());
00742 
00743 }
00744 
00745 
00746 void Xrefutil::ConvertSelectedToXrefObject(HWND hWnd)

00747 {
00748     // *** ConvertSelectedToXrefObject ***
00749     //
00750     // Takes single selection of scene object and
00751     // "converts" it to XRef Object with default settings.  This is 
00752     // done via the following steps:
00753     //
00754     // 1) Save selected object into new MAX file of user's specification
00755     // 2) Create a new XRefObject
00756     // 3) XRefObject makes reference to the objectref of the selected node (OSM-level only)
00757     // 4) INode object reference changed to XRefObject
00758     //
00759     // converting multiple selected objects is left as an exercise
00760     // but should be quite straight-forward...
00761 
00762     INode * pNode = NULL;
00763     TSTR filename = "";
00764 
00765     if (m_pInterface->GetSelNodeCount() != 1) {
00766         ::MessageBox(hWnd, GetString(IDS_ERR1), ERROR_TITLE, MB_ICONSTOP | MB_OK);
00767         return;
00768     }
00769     pNode = m_pInterface->GetSelNode(0);
00770     if (!pNode) {
00771         ::MessageBox(hWnd, GetString(IDS_ERR2), ERROR_TITLE, MB_ICONSTOP | MB_OK);
00772         return;
00773     }
00774 
00775     if (!DoOpenSaveDialog(filename)) {
00776         // either cancel or fail, just return
00777         return;
00778     }
00779     m_pInterface->FileSaveSelected(filename);
00780 
00781     // One caveat : If the object (not node) has any ReferenceMakers watching it
00782     // that are expecting geom pipeline msgs, you may need to remove/reset these
00783     // references.  After the conversion, the original object is effectively
00784     // hidden from the pipeline.
00785 
00786     NodeToXref(pNode, filename, false);
00787 
00788     // leave all XRef settings at defaults for this sample
00789 
00790     m_pInterface->RedrawViews(m_pInterface->GetTime());
00791 
00792 }
00793 
00794 
00795 void Xrefutil::ExportXrefObjects(HWND hWnd)

00796 {
00797     // *** ExportXrefObjects ***
00798     //
00799     // Does a "fake" export of all the XRef objects in the scene.
00800     // Basically, walks the scene looking for XRef objects, pulls
00801     // some information from them, and spits this out into a text
00802     // format, which is then displayed in a modal dialog.
00803     //
00804     // In reality, this sort of process would be more applicable
00805     // to a MAX Exporter plug-in. During SceneExport::DoExport
00806     // the INodes would be walked, looking for XRef objects, and
00807     // the exporter could then export whatever was needed from
00808     // them.
00809     //
00810     // The important distinction between XRef scenes and XRef
00811     // objects is again shown here -- XRef objects, to be manipulated
00812     // must be found in the scene via ClassID (like any typical
00813     // scene object), and then treated as IXRefObject pointers.
00814     // Do NOT use the XRef methods off of INode, since these only
00815     // apply to xref scenes and only work from the scene root INode.
00816 
00817     TSTR * resbuffer = NULL;
00818 
00819     // walk the scene starting at the root, looking for xref objects
00820     INode * pRootNode = m_pInterface->GetRootNode();
00821     if (!pRootNode) {
00822         // well, this is actually _really_ bad, but we just exit
00823         return;
00824     }
00825     resbuffer = new TSTR; 
00826     if (!resbuffer) return;
00827 
00828     XRefObjFinder newfinder;
00829     newfinder.m_buffer = resbuffer;
00830     // (see XRefObjFinder::Proc above for details)
00831     newfinder.Enumerate(pRootNode);
00832 
00833     // finally, display results in dialog
00834     int dlgres = DialogBoxParam(hInstance, 
00835                        MAKEINTRESOURCE(IDD_DLGEXPORT),
00836                        m_hPanel,
00837                        ExportDlgProc,
00838                        (LPARAM)resbuffer);
00839 
00840     delete resbuffer;
00841 }

Generated at Mon Nov 6 14:11:58 2000 by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000