source: OGRE/trunk/ogrenew/Tools/XSIExport/src/OgreXSIExport.cpp @ 692

Revision 692, 32.1 KB checked in by mattausch, 19 years ago (diff)

adding ogre 1.2 and dependencies

Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4(Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25#include <xsi_value.h>
26#include <xsi_status.h>
27#include <xsi_application.h>
28#include <xsi_plugin.h>
29#include <xsi_pluginitem.h>
30#include <xsi_pluginregistrar.h>
31#include <xsi_pluginitem.h>
32#include <xsi_command.h>
33#include <xsi_argument.h>
34#include <xsi_context.h>
35#include <xsi_menuitem.h>
36#include <xsi_menu.h>
37#include <xsi_model.h>
38#include <xsi_customproperty.h>
39#include <xsi_ppglayout.h>
40#include <xsi_ppgeventcontext.h>
41#include <xsi_selection.h>
42#include <xsi_comapihandler.h>
43#include <xsi_uitoolkit.h>
44#include <xsi_time.h>
45#include <xsi_griddata.h>
46#include <xsi_gridwidget.h>
47#include <xsi_mixer.h>
48#include <xsi_source.h>
49#include <xsi_timecontrol.h>
50
51#include "OgreXSIMeshExporter.h"
52#include "OgreXSISkeletonExporter.h"
53#include "OgreXSIMaterialExporter.h"
54#include "OgreLogManager.h"
55#include "OgreException.h"
56#include "OgreXSIHelper.h"
57#include "OgreProgressiveMesh.h"
58#include "OgreString.h"
59#include "OgreLogManager.h"
60#include "OgreMeshManager.h"
61#include "OgreSkeletonManager.h"
62#include "OgreDefaultHardwareBufferManager.h"
63#include "OgreMaterialManager.h"
64
65using namespace XSI;
66
67#define OGRE_XSI_EXPORTER_VERSION L"1.2.0"
68
69// define columns of animations list
70#define ANIMATION_LIST_EXPORT_COL 0
71#define ANIMATION_LIST_NAME_COL 1
72#define ANIMATION_LIST_START_COL 2
73#define ANIMATION_LIST_END_COL 3
74#define ANIMATION_LIST_IKFREQ_COL 4
75
76/** This is the main file for the OGRE XSI plugin.
77The purpose of the methods in this file are as follows:
78
79XSILoadPlugin
80  registers the export command, the menu item, and the option dialog
81
82XSIUnloadPlugin
83  cleans up
84
85OgreMeshExportCommand_Init
86  Defines the arguments to the export command
87
88OgreMeshExportCommand_Execute
89  Runs the exporter using arguments obtained from a context object
90  (I assume this is to allow general access to this export rather than using
91   the property dialog)
92
93OgreMeshExportMenu_Init
94  Defines the menu text and the event callback to execute (OnOgreMeshExportMenu)
95
96OnOgreMeshExportMenu
97  Callback event when clicking the export menu option. Adds an instance of the
98  options dialog as a property, then uses the InspectObj XSI command to pop it up
99  in a modal dialog. If it wasn't cancelled, performs an export.
100
101OgreMeshExportOptions_Define
102  Defines the persistable parameters on the options dialog
103
104OgreMeshExportOptions_DefineLayout
105  Defines the visual layout of the options dialog
106
107OgreMeshExportOptions_PPGEvent
108  Event handler for when the options dialog is interacted with
109*/
110
111CString GetUserSelectedObject();
112CStatus Popup( const CString& in_inputobjs, const CString& in_keywords, const CString& in_title, const CValue& in_mode, bool in_throw );
113void DeleteObj( const CValue& in_inputobj );
114
115Ogre::AnimationList animList;
116
117
118#ifdef unix
119extern "C"
120#endif
121/** Registers the export command, the menu item, and the option dialog */
122CStatus XSILoadPlugin( XSI::PluginRegistrar& registrar )
123{
124        registrar.PutAuthor( L"Steve Streeting" );
125        registrar.PutName( L"OGRE Exporter Plugin" );   
126    registrar.PutVersion( 1, 0 );
127    registrar.PutURL(L"http://www.ogre3d.org");
128   
129
130        // register the mesh export command
131        registrar.RegisterCommand( L"OgreMeshExportCommand", L"OgreMeshExportCommand" );
132
133    // register the menu under File > Export
134        registrar.RegisterMenu(siMenuMainFileExportID, L"OgreMeshExportMenu", false, false);
135
136        // register the export dialog properties factory
137        registrar.RegisterProperty( L"OgreMeshExportOptions" );
138
139#ifdef _DEBUG
140    Application app;
141    app.LogMessage( registrar.GetName() + L" has been loaded.");
142#endif
143
144    return XSI::CStatus::OK;   
145}
146
147#ifdef unix
148extern "C"
149#endif
150/** Cleans up */
151XSI::CStatus XSIUnloadPlugin( const XSI::PluginRegistrar& registrar )
152{
153#ifdef _DEBUG
154    Application app;
155        app.LogMessage(registrar.GetName() + L" has been unloaded.");
156#endif
157
158        return XSI::CStatus::OK;
159}
160
161#ifdef unix
162extern "C"
163#endif
164/** Defines the arguments to the export command */
165XSI::CStatus OgreMeshExportCommand_Init( const XSI::CRef& context )
166{
167        Context ctx(context);
168        Command cmd(ctx.GetSource());
169
170        Application app;
171        app.LogMessage( L"Defining: " + cmd.GetName() );
172
173        ArgumentArray args = cmd.GetArguments();
174
175    args.Add( L"objectName", L"" );
176        args.Add( L"targetMeshFileName", L"c:/default.mesh" );
177        args.Add( L"calculateEdgeLists", L"true" );
178    args.Add( L"calculateTangents", L"false" );
179    args.Add( L"exportSkeleton", L"true" );
180        args.Add( L"exportVertexAnimation", L"true" );
181    args.Add( L"targetSkeletonFileName", L"c:/default.skeleton" );
182    args.Add( L"fps", L"24" );
183    args.Add( L"animationList", L"" );
184        return XSI::CStatus::OK;
185
186}
187
188#ifdef unix
189extern "C"
190#endif
191/** Runs the exporter using arguments obtained from a context object
192  (I assume this is to allow general access to this export rather than using
193   the property dialog)
194*/
195XSI::CStatus OgreMeshExportCommand_Execute( XSI::CRef& in_context )
196{
197        Application app;
198        Context ctxt(in_context);
199        CValueArray args = ctxt.GetAttribute( L"Arguments" );
200
201#ifdef _DEBUG
202        for (long i=0; i<args.GetCount(); i++)
203        {
204                app.LogMessage( L"Arg" + CValue(i).GetAsText() + L": " +
205                        args[i].GetAsText() );                 
206        }
207#endif
208
209        if ( args.GetCount() != 9 )
210        {
211                // Arguments of the command might not be properly registered
212                return CStatus::InvalidArgument ;
213        }
214
215    // TODO - perform the export!
216
217    return XSI::CStatus::OK;
218}
219
220
221#ifdef unix
222extern "C"
223#endif
224/** Defines the menu text and the event callback to execute (OnOgreMeshExportMenu) */
225XSI::CStatus OgreMeshExportMenu_Init( XSI::CRef& in_ref )
226{
227        Context ctxt = in_ref;
228        Menu menu = ctxt.GetSource();
229
230        CStatus st;
231        MenuItem item;
232        menu.AddCallbackItem(L"OGRE Mesh / Skeleton...", L"OnOgreMeshExportMenu", item);
233
234        return CStatus::OK;     
235}
236
237CString exportPropertyDialogName = L"OgreMeshExportOptions";
238
239#ifdef unix
240extern "C"
241#endif
242/** Callback event when clicking the export menu option. Adds an instance of the
243    options dialog as a property, then uses the InspectObj XSI command to pop it up
244    in a modal dialog. If it wasn't cancelled, performs an export.
245*/
246XSI::CStatus OnOgreMeshExportMenu( XSI::CRef& in_ref )
247{       
248        Ogre::LogManager logMgr;
249        logMgr.createLog("OgreXSIExporter.log", true);
250        CString msg(L"OGRE Exporter Version ");
251        msg += OGRE_XSI_EXPORTER_VERSION;
252        LogOgreAndXSI(msg);
253
254        Application app;
255        CStatus st(CStatus::OK);
256        Property prop = app.GetActiveSceneRoot().GetProperties().GetItem(exportPropertyDialogName);
257        if (prop.IsValid())
258        {
259                // Check version number
260                CString currVersion(prop.GetParameterValue(L"version"));
261                if (!currVersion.IsEqualNoCase(OGRE_XSI_EXPORTER_VERSION))
262                {
263                        DeleteObj(exportPropertyDialogName);
264                        prop.ResetObject();
265                }
266        }
267        if (!prop.IsValid())
268        {
269                prop = app.GetActiveSceneRoot().AddProperty(exportPropertyDialogName);
270                prop.PutParameterValue(L"version", CString(OGRE_XSI_EXPORTER_VERSION));
271        }
272       
273        try
274        {
275                // Popup Returns true if the command was cancelled otherwise it returns false.
276                CStatus ret = Popup(exportPropertyDialogName,CValue(),L"OGRE Mesh / Skeleton Export",(long)siModal,true);
277                if (ret == CStatus::OK)
278                {
279                        Ogre::XsiMeshExporter meshExporter;
280                        Ogre::XsiSkeletonExporter skelExporter;
281
282                        // retrieve the parameters
283                        Parameter param = prop.GetParameters().GetItem(L"objectName");
284                        CString objectName = param.GetValue();
285                        param = prop.GetParameters().GetItem( L"targetMeshFileName" );
286                        Ogre::String meshFileName = XSItoOgre(param.GetValue());
287                        if (meshFileName.empty())
288                        {
289                                OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS,
290                                        "You must supply a mesh file name",
291                                        "OGRE Exporter");
292                        }
293                        param = prop.GetParameters().GetItem( L"mergeSubmeshes" );
294                        bool mergeSubmeshes = param.GetValue();
295                        param = prop.GetParameters().GetItem( L"exportChildren" );
296                        bool exportChildren = param.GetValue();
297                        param = prop.GetParameters().GetItem( L"calculateEdgeLists" );
298                        bool edgeLists = param.GetValue();
299                        param = prop.GetParameters().GetItem( L"calculateTangents" );
300                        bool tangents = param.GetValue();
301                        param = prop.GetParameters().GetItem( L"numLodLevels" );
302                        long numlods = param.GetValue();
303                        Ogre::XsiMeshExporter::LodData* lodData = 0;
304                        if (numlods > 0)
305                        {
306                                param = prop.GetParameters().GetItem( L"lodDistanceIncrement" );
307                                float distanceInc = param.GetValue();
308
309                                param = prop.GetParameters().GetItem(L"lodQuota");
310                                CString quota = param.GetValue();
311
312                                param = prop.GetParameters().GetItem(L"lodReduction");
313                                float reduction = param.GetValue();
314
315                                lodData = new Ogre::XsiMeshExporter::LodData;
316                                float currentInc = distanceInc;
317                                for (int l = 0; l < numlods; ++l)
318                                {
319                                        lodData->distances.push_back(currentInc);
320                                        currentInc += distanceInc;
321                                }
322                                lodData->quota = (quota == L"p") ?
323                                        Ogre::ProgressiveMesh::VRQ_PROPORTIONAL : Ogre::ProgressiveMesh::VRQ_CONSTANT;
324                                if (lodData->quota == Ogre::ProgressiveMesh::VRQ_PROPORTIONAL)
325                                        lodData->reductionValue = reduction * 0.01;
326                                else
327                                        lodData->reductionValue = reduction;
328
329                        }
330
331                        param = prop.GetParameters().GetItem( L"exportSkeleton" );
332                        bool exportSkeleton = param.GetValue();
333                        param = prop.GetParameters().GetItem( L"exportVertexAnimation" );
334                        bool exportVertexAnimation = param.GetValue();
335                        param = prop.GetParameters().GetItem( L"exportMaterials" );
336                        bool exportMaterials = param.GetValue();
337                        param = prop.GetParameters().GetItem( L"copyTextures" );
338                        bool copyTextures = param.GetValue();
339
340                        // create singletons
341                        Ogre::ResourceGroupManager rgm;
342                        Ogre::MeshManager meshMgr;
343                        Ogre::SkeletonManager skelMgr;
344                        Ogre::MaterialManager matMgr;
345                        Ogre::DefaultHardwareBufferManager hardwareBufMgr;
346
347                       
348                        // determine number of exportsteps
349                        size_t numSteps = 3 + OGRE_XSI_NUM_MESH_STEPS;
350                        if (numlods > 0)
351                                numSteps++;
352                        if (edgeLists)
353                                numSteps++;
354                        if (tangents)
355                                numSteps++;
356                        if (exportSkeleton)
357                                numSteps += 3;
358
359                        Ogre::ProgressManager progressMgr(numSteps);
360                       
361                        // Any material prefix? We need that for mesh linking too
362                        param = prop.GetParameters().GetItem( L"materialPrefix" );
363                        Ogre::String materialPrefix = XSItoOgre(param.GetValue());
364
365                        param = prop.GetParameters().GetItem( L"fps" );
366                        float fps = param.GetValue();
367                        if (fps == 0.0f)
368                        {
369                                OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS,
370                                        "You must supply a valid value for 'FPS'",
371                                        "OGRE Export");
372                        }
373
374                        Ogre::AnimationList selAnimList;
375                        if (exportSkeleton || exportVertexAnimation)
376                        {
377
378                                param = prop.GetParameters().GetItem( L"animationList" );
379                                GridData gd(param.GetValue());
380                                for (int a = 0; a < gd.GetRowCount(); ++a)
381                                {
382                                        if (gd.GetCell(ANIMATION_LIST_EXPORT_COL, a) == true)
383                                        {
384                                                Ogre::AnimationEntry ae;
385                                                ae.animationName = XSItoOgre(gd.GetCell(ANIMATION_LIST_NAME_COL, a));
386                                                ae.ikSampleInterval = gd.GetCell(ANIMATION_LIST_IKFREQ_COL, a);
387                                                ae.startFrame = gd.GetCell(ANIMATION_LIST_START_COL, a);
388                                                ae.endFrame = gd.GetCell(ANIMATION_LIST_END_COL, a);
389                                                selAnimList.push_back(ae);
390                                        }
391                                }
392                        }
393
394                        if (exportSkeleton)
395                        {
396                                param = prop.GetParameters().GetItem( L"targetSkeletonFileName" );
397                                Ogre::String skeletonFileName = XSItoOgre(param.GetValue());
398                                if (skeletonFileName.empty())
399                                {
400                                        OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS,
401                                                "You must supply a skeleton file name",
402                                                "OGRE Exporter");
403                                }
404
405                                // Truncate the skeleton filename to just the name (no path)
406                                Ogre::String skelName = skeletonFileName;
407                                int pos = skeletonFileName.find_last_of("\\");
408                                if (pos == Ogre::String::npos)
409                                {
410                                        pos = skeletonFileName.find_last_of("/");
411                                }
412                                if (pos != Ogre::String::npos)
413                                {
414                                        skelName = skelName.substr(pos+1, skelName.size() - pos - 1);
415                                }
416
417
418                                // Do the mesh
419                                Ogre::DeformerMap& deformers =
420                                        meshExporter.exportMesh(meshFileName, mergeSubmeshes,
421                                                exportChildren, edgeLists, tangents, exportVertexAnimation,
422                                                selAnimList, fps, materialPrefix,
423                                                lodData, skelName);
424                                // do the skeleton
425                                skelExporter.exportSkeleton(skeletonFileName, deformers, fps, selAnimList);
426                        }
427                        else
428                        {
429                                // No skeleton
430                                meshExporter.exportMesh(meshFileName, mergeSubmeshes,
431                                        exportChildren, edgeLists, tangents, exportVertexAnimation,
432                                        selAnimList, fps, materialPrefix, lodData);
433                        }
434
435                       
436                        delete lodData;
437
438                        // Do we want to export materials too?
439                        if (exportMaterials)
440                        {
441                                param = prop.GetParameters().GetItem( L"targetMaterialFileName" );
442                                Ogre::String materialFileName = XSItoOgre(param.GetValue());
443                               
444                                Ogre::XsiMaterialExporter matExporter;
445                                try
446                                {
447                                        matExporter.exportMaterials(meshExporter.getMaterials(),
448                                                meshExporter.getTextureProjectionMap(),
449                                                materialFileName, copyTextures);
450                                }
451                                catch (Ogre::Exception& e)
452                                {
453                                        // ignore, non-fatal and will be in log
454                                }
455                        }
456
457                }
458
459        }
460        catch (Ogre::Exception& e)
461        {
462                // Will already have been logged to the Ogre log manager
463                // Tell XSI
464                app.LogMessage(OgretoXSI(e.getDescription()), XSI::siFatalMsg);
465                app.LogMessage(OgretoXSI(e.getFullDescription()), XSI::siInfoMsg);
466        }
467
468        //DeleteObj( L"OgreMeshExportOptions" );
469        return st;     
470}
471
472
473#ifdef unix
474extern "C"
475#endif
476/** Defines the persistable parameters on the options dialog */
477CStatus OgreMeshExportOptions_Define( const CRef & in_Ctx )
478{
479        // Here is where we add all the parameters to the
480        // Custom Property.  This will be called each time
481        // an new instance of the Custom Property is called.
482        // It is not called when an persisted Custom Property is loaded.
483
484    Application app ;
485        CustomProperty prop = Context(in_Ctx).GetSource();
486        Parameter param ;
487
488        // Default capabilities for most of these parameters
489        int caps = siPersistable  ;
490        CValue nullValue;       // Used for arguments we don't want to set
491
492        prop.AddParameter(     
493                L"version",CValue::siString, caps,
494                L"Version", L"",
495                nullValue, param) ;     
496    prop.AddParameter( 
497        L"objectName",CValue::siString, caps,
498        L"Object Name", L"",
499        nullValue, param) ;     
500        prop.AddParameter(     
501                L"objects",CValue::siRefArray, caps,
502                L"Collection of selected objects", L"",
503                nullValue, param) ;     
504        prop.AddParameter(     
505        L"targetMeshFileName",CValue::siString, caps,
506                L"Mesh Filename", L"",
507                nullValue, param) ;     
508        prop.AddParameter(
509                L"mergeSubmeshes",CValue::siBool, caps,
510                L"Merge objects with same material?",
511                L"If false, a separate named SubMesh will be created for every PolygonMesh "
512                L"preserving your model divisions. If true, the exporter will merge all "
513                L"PolygonMesh objects with the same material, which is more efficient, but "
514                L"does not preserve your modelling divisions.",
515                CValue(true), param) ; 
516        prop.AddParameter(
517                L"exportChildren",CValue::siBool, caps,
518                L"Export Children",
519                L"If true, children of all selected objects will be exported.",
520                CValue(true), param) ; 
521    prop.AddParameter( 
522        L"calculateEdgeLists",CValue::siBool, caps,
523        L"Calculate Edge Lists (stencil shadows)", L"",
524        CValue(true), param) ; 
525    prop.AddParameter( 
526        L"calculateTangents",CValue::siBool, caps,
527        L"Calculate Tangents (normal mapping)", L"",
528        CValue(false), param) ;
529        prop.AddParameter(     
530                L"numLodLevels",CValue::siInt2, caps,
531                L"Levels of Detail", L"",
532                CValue(0L), param) ;   
533        prop.AddParameter(     
534                L"lodDistanceIncrement",CValue::siFloat, caps,
535                L"Distance Increment", L"",
536                CValue(2000L), //default
537                CValue(1L), // hard min
538                CValue(1000000L), // hard max
539                CValue(50L), // suggested min
540                CValue(10000L), // suggested max
541                param) ;       
542        prop.AddParameter(     
543                L"lodQuota",CValue::siString, caps,
544                L"Reduction Style", L"",
545                L"p", param) ; 
546        prop.AddParameter(     
547                L"lodReduction",CValue::siFloat, caps,
548                L"Reduction Value", L"",
549                CValue(50.0f), param) ;
550    prop.AddParameter( 
551        L"exportSkeleton",CValue::siBool, caps,
552        L"Export Skeleton", L"",
553        CValue(true), param) ; 
554        prop.AddParameter(     
555                L"exportVertexAnimation",CValue::siBool, caps,
556                L"Export Vertex Animation", L"",
557                CValue(true), param) ; 
558    prop.AddParameter( 
559        L"targetSkeletonFileName",CValue::siString, caps,
560        L"Skeleton Filename", L"",
561        nullValue, param) ;     
562    prop.AddParameter(
563        L"fps",CValue::siInt2, caps,
564        L"Frames per second", L"",
565        CValue(24l), param) ;   
566        prop.AddGridParameter(L"animationList");       
567        prop.AddParameter(
568                L"exportMaterials", CValue::siBool, caps,
569                L"Export Materials", L"",
570                CValue(true), param);
571        prop.AddParameter(
572                L"copyTextures", CValue::siBool, caps,
573                L"Copy Textures To Folder", L"",
574                CValue(true), param);
575    prop.AddParameter( 
576        L"targetMaterialFileName",CValue::siString, caps,
577        L"Material Filename", L"",
578        nullValue, param) ;     
579        prop.AddParameter(     
580                L"materialPrefix",CValue::siString, caps,
581                L"Material Prefix", L"",
582                nullValue, param) ;     
583               
584
585
586        return CStatus::OK;     
587}
588
589#ifdef unix
590extern "C"
591#endif
592/** Defines the visual layout of the options dialog */
593CStatus OgreMeshExportOptions_DefineLayout( const CRef & in_Ctx )
594{
595        // XSI will call this to define the visual appearance of the CustomProperty
596        // The layout is shared between all instances of the CustomProperty
597        // and is CACHED!!!.  You can force the code to re-execute by using the
598        // XSIUtils.Reload feature, or right-clicking the property page and selecting 'Refresh'
599
600        PPGLayout oLayout = Context( in_Ctx ).GetSource() ;
601        PPGItem item ;
602
603        oLayout.Clear() ;
604
605        // Mesh tab
606        oLayout.AddTab(L"Basic");
607    // Object
608
609        oLayout.AddGroup(L"Object(s) to export");
610        item = oLayout.AddItem(L"objectName");
611    item.PutAttribute( siUINoLabel, true );
612        oLayout.EndGroup();
613       
614        oLayout.AddGroup(L"Mesh");
615    item = oLayout.AddItem(L"targetMeshFileName", L"Target", siControlFilePath);
616        item.PutAttribute( siUINoLabel, true );
617        item.PutAttribute( siUIFileFilter, L"OGRE Mesh format (*.mesh)|*.mesh|All Files (*.*)|*.*||" );
618        item = oLayout.AddItem(L"mergeSubmeshes") ;
619        item = oLayout.AddItem(L"exportChildren") ;
620
621
622    item = oLayout.AddItem(L"calculateEdgeLists");
623    item = oLayout.AddItem(L"calculateTangents");
624        oLayout.AddGroup(L"Level of Detail Reduction");
625    item = oLayout.AddItem(L"numLodLevels");
626        item = oLayout.AddItem(L"lodDistanceIncrement");
627        CValueArray vals;
628        vals.Add(L"Percentage");
629        vals.Add(L"p");
630        vals.Add(L"Constant");
631        vals.Add(L"c");
632        item = oLayout.AddEnumControl(L"lodQuota", vals, L"Quota", XSI::siControlCombo);
633        item = oLayout.AddItem(L"lodReduction");
634        oLayout.EndGroup();
635        oLayout.EndGroup();
636
637        oLayout.AddTab(L"Materials");
638        // Material Tab
639    item = oLayout.AddItem(L"exportMaterials") ;
640    item = oLayout.AddItem(L"targetMaterialFileName", L"Target", siControlFilePath) ;
641        item.PutAttribute( siUINoLabel, true );
642        item.PutAttribute( siUIFileFilter, L"OGRE Material script (*.material)|*.material|All Files (*.*)|*.*||" );
643        item = oLayout.AddItem(L"materialPrefix");
644    item = oLayout.AddItem(L"copyTextures");
645       
646       
647        // Skeleton Tab
648        oLayout.AddTab(L"Animation");
649
650        item = oLayout.AddItem(L"exportVertexAnimation");
651        item = oLayout.AddItem(L"exportSkeleton");
652        item = oLayout.AddItem(L"targetSkeletonFileName", L"Target", siControlFilePath);
653        item.PutAttribute( siUINoLabel, true );
654        item.PutAttribute( siUIFileFilter, L"OGRE Skeleton format (*.skeleton)|*.skeleton|All Files (*.*)|*.*||" );
655        item = oLayout.AddItem(L"fps");
656
657        oLayout.AddGroup(L"Animations");
658        item = oLayout.AddItem(L"animationList", L"Animations", siControlGrid);
659        item.PutAttribute( siUINoLabel, true );
660        item.PutAttribute(siUIGridColumnWidths, L"0:15:250:30:30:75");
661        item.PutAttribute(siUIGridHideRowHeader, true);
662
663        oLayout.AddRow();
664        item = oLayout.AddButton(L"refreshAnimation", L"Refresh");
665        item = oLayout.AddButton(L"addAnimation", L"Add");
666        item = oLayout.AddButton(L"removeAnimation", L"Remove");
667        oLayout.EndRow();
668        oLayout.EndGroup();
669
670
671        // Make animatino name read-only (not any more)
672        //item.PutAttribute(siUIGridReadOnlyColumns, L"1:0:0:0");
673
674
675
676
677
678
679
680        return CStatus::OK;     
681}
682
683
684bool hasSkeleton(X3DObject& si, bool recurse)
685{
686        if (si.GetEnvelopes().GetCount() > 0)
687        {
688                return true;
689        }
690
691        if (recurse)
692        {
693
694                CRefArray children = si.GetChildren();
695
696                for(long i = 0; i < children.GetCount(); i++)
697                {
698                        X3DObject child(children[i]);
699                        bool ret = hasSkeleton(child, recurse);
700                        if (ret)
701                                return ret;
702                }
703        }
704
705        return false;
706       
707}
708
709bool hasSkeleton(Selection& sel, bool recurse)
710{
711        // iterate over selection
712        for (int i = 0; i < sel.GetCount(); ++i)
713        {
714                X3DObject obj(sel[i]);
715                bool ret = hasSkeleton(obj, recurse);
716                if (ret)
717                        return ret;
718        }
719
720        return false;
721}
722
723
724
725void findAnimations(XSI::Model& model, Ogre::AnimationList& animList)
726{
727
728        if (model.HasMixer())
729        {
730                // Scan the mixer for all clips
731                // At this point we're only interested in the top-level and do not
732                // cascade into all clip containers, since we're interested in the
733                // top-level timeline splits
734                XSI::Mixer mixer = model.GetMixer();
735                CRefArray clips = mixer.GetClips();
736                for (int c = 0; c < clips.GetCount(); ++c)
737                {
738                        XSI::Clip clip(clips[c]);
739                        XSI::CString clipType = clip.GetType();
740                        if (clipType == siClipAnimationType ||
741                                clipType == siClipShapeType  ||
742                                clipType == siClipAnimCompoundType || // nested fcurves
743                                clipType == siClipShapeCompoundType) // nested shape
744                        {
745                                XSI::TimeControl timeControl = clip.GetTimeControl();
746                                Ogre::AnimationEntry anim;
747                                anim.animationName = XSItoOgre(clip.GetName());
748                                anim.startFrame = timeControl.GetStartOffset();
749                                long length = (1.0 / timeControl.GetScale()) *
750                                        (timeControl.GetClipOut() - timeControl.GetClipIn() + 1);
751                                anim.endFrame = anim.startFrame + length - 1;
752                                anim.ikSampleInterval = 5.0f;
753                                animList.push_back(anim);
754
755                        }
756
757                }
758               
759        }
760
761}
762
763void getAnimations(XSI::Model& root, Ogre::AnimationList& animList)
764{
765        animList.clear();
766
767        findAnimations(root, animList);
768
769        // Find all children (recursively)
770        XSI::CRefArray children = root.FindChildren(L"", siModelType, XSI::CStringArray());
771        for (int c = 0; c < children.GetCount(); ++c)
772        {
773                XSI::Model child(children[c]);
774                findAnimations(child, animList);
775        }
776
777        // Now iterate over the list and eliminate overlapping elements
778        for (Ogre::AnimationList::iterator i = animList.begin();
779                i != animList.end(); ++i)
780        {
781                Ogre::AnimationList::iterator j = i;
782                ++j;
783                for (; j != animList.end();)
784                {
785                        bool remove = false;
786                        if (j->endFrame >= i->startFrame)
787                        {
788                                // Merge this one into i, extend i's start to j
789                                remove = true;
790                                i->startFrame = j->startFrame;
791                        }
792                        if (j->startFrame <= i->endFrame)
793                        {
794                                remove = true;
795                                i->endFrame = j->endFrame;
796                        }
797                        if (remove)
798                        {
799                                j = animList.erase(j);
800                        }
801                        else
802                        {
803                                ++j;
804                        }
805                }
806        }
807
808
809}
810
811void populateAnimationsList(XSI::GridData gd)
812{
813        // 5 columns
814        gd.PutColumnCount(5);
815
816        // Export column is a check box
817        gd.PutColumnType(ANIMATION_LIST_EXPORT_COL, siColumnBool);
818
819        // Labels
820        gd.PutColumnLabel(ANIMATION_LIST_EXPORT_COL, L"");
821        gd.PutColumnLabel(ANIMATION_LIST_NAME_COL, L"Name");
822        gd.PutColumnLabel(ANIMATION_LIST_START_COL, L"Start");
823        gd.PutColumnLabel(ANIMATION_LIST_END_COL, L"End");
824        gd.PutColumnLabel(ANIMATION_LIST_IKFREQ_COL, L"Sample Freq");
825
826
827        Application app;
828        Model appRoot(app.GetActiveSceneRoot());
829        getAnimations(appRoot, animList);
830        gd.PutRowCount(animList.size());
831        long row = 0;
832        for (Ogre::AnimationList::iterator a = animList.begin();
833                        a != animList.end(); ++a, ++row)
834        {
835                gd.PutCell(ANIMATION_LIST_NAME_COL, row, OgretoXSI(a->animationName));
836                // default to export
837                gd.PutCell(ANIMATION_LIST_EXPORT_COL, row, true);
838                gd.PutCell(ANIMATION_LIST_START_COL, row, a->startFrame);
839                gd.PutCell(ANIMATION_LIST_END_COL, row, a->endFrame);
840                gd.PutCell(ANIMATION_LIST_IKFREQ_COL, row, a->ikSampleInterval);
841        }
842}
843
844
845#ifdef unix
846extern "C"
847#endif
848/** Event handler for when the options dialog is interacted with */
849CStatus OgreMeshExportOptions_PPGEvent( const CRef& io_Ctx )
850{
851        // This callback is called when events happen in the user interface
852        // This is where you implement the "logic" code.
853
854        Application app ;
855        static bool hasSkel = false;
856
857        PPGEventContext ctx( io_Ctx ) ;
858
859        PPGEventContext::PPGEvent eventID = ctx.GetEventID() ;
860
861        CustomProperty prop = ctx.GetSource() ;
862        Parameter objectNameParam = prop.GetParameters().GetItem( L"objectName" ) ;
863    // On open dialog
864    if ( eventID == PPGEventContext::siOnInit )
865        {
866        // Pre-populate object with currently selected item(s)
867                Selection sel(app.GetSelection());
868                if (sel.GetCount() > 0)
869                {
870                        CString val;
871                        for (int i = 0; i < sel.GetCount(); ++i)
872                        {
873                                val += SIObject(sel[i]).GetName();
874                                if (i < sel.GetCount() - 1)
875                                        val += L", ";
876                        }
877                        prop.PutParameterValue(L"objectName", val);
878                }
879                else
880                {
881                        // no selection, assume entire scene
882                        prop.PutParameterValue(L"objectName", CString(L"[Entire Scene]"));
883                }
884        // Make the selection read-only
885                objectNameParam.PutCapabilityFlag( siReadOnly, true );
886
887                // default the frame rate to that selected in animation panel
888                prop.PutParameterValue(L"fps", CTime().GetFrameRate());
889
890                // enable / disable the skeleton export based on envelopes
891                if (!hasSkeleton(sel, true))
892                {
893                        prop.PutParameterValue(L"exportSkeleton", false);
894                        Parameter param = prop.GetParameters().GetItem(L"exportSkeleton");
895                        param.PutCapabilityFlag(siReadOnly, true);
896                        param = prop.GetParameters().GetItem(L"targetSkeletonFileName");
897                        param.PutCapabilityFlag(siReadOnly, true);
898                        hasSkel = false;
899                }
900                else
901                {
902                        prop.PutParameterValue(L"exportSkeleton", true);
903                        Parameter param = prop.GetParameters().GetItem(L"exportSkeleton");
904                        param.PutCapabilityFlag(siReadOnly, false);
905                        param = prop.GetParameters().GetItem(L"targetSkeletonFileName");
906                        param.PutCapabilityFlag(siReadOnly, false);
907                        hasSkel = true;
908                }
909                // value of param is a griddata object
910                // initialise it with all detected animations if it's empty
911                Parameter param = prop.GetParameters().GetItem(L"animationList");
912                GridData gd(param.GetValue());
913                if (gd.GetRowCount() == 0 || gd.GetCell(0,0) == L"No data has been set")
914                {
915                        populateAnimationsList(gd);
916                }
917                       
918        }
919    // On clicking a button
920        else if ( eventID == PPGEventContext::siButtonClicked )
921        {
922                CValue buttonPressed = ctx.GetAttribute( L"Button" );   
923        // Clicked the refresh animation button
924                if ( buttonPressed.GetAsText() == L"refreshAnimation" )
925                {
926                        long btn;
927                        CStatus ret = app.GetUIToolkit().MsgBox(
928                                L"Are you sure you want to lose the current contents "
929                                L"of the animations list and to refresh it from mixers?",
930                                siMsgYesNo,
931                                L"Confirm",
932                                btn);
933                        if (btn == 6)
934                        {
935                                Parameter param = prop.GetParameters().GetItem(L"animationList");
936                                GridData gd(param.GetValue());
937                                populateAnimationsList(gd);
938                        }
939                       
940                }
941                else if( buttonPressed.GetAsText() == L"addAnimation" )
942                {
943                        Parameter param = prop.GetParameters().GetItem(L"animationList");
944                        GridData gd(param.GetValue());
945
946                        gd.PutRowCount(gd.GetRowCount() + 1);
947                        // default export to true and sample rate
948                        gd.PutCell(ANIMATION_LIST_EXPORT_COL, gd.GetRowCount()-1, true);
949                        gd.PutCell(ANIMATION_LIST_IKFREQ_COL, gd.GetRowCount()-1, 5L);
950                }
951                else if( buttonPressed.GetAsText() == L"removeAnimation" )
952                {
953                        Parameter param = prop.GetParameters().GetItem(L"animationList");
954                        GridData gd(param.GetValue());
955                        GridWidget gw = gd.GetGridWidget();
956
957                        // cell-level selection, so have to search for selection in every cell
958                        long selRow = -1;
959                        for (long row = 0; row < gd.GetRowCount() && selRow == -1; ++row)
960                        {
961                                for (long col = 0; col < gd.GetColumnCount() && selRow == -1; ++col)
962                                {
963                                        if (gw.IsCellSelected(col, row))
964                                        {
965                                                selRow = row;
966                                        }
967                                }
968                        }
969
970                        if (selRow != -1)
971                        {
972                                long btn;
973                                CStatus ret = app.GetUIToolkit().MsgBox(
974                                        L"Are you sure you want to remove this animation entry?",
975                                        siMsgYesNo,
976                                        L"Confirm",
977                                        btn);
978                                if (btn == 6)
979                                {
980                                        // Move all the contents up one
981                                        for (long row = selRow; row < gd.GetRowCount(); ++row)
982                                        {
983                                                for (long col = 0; col < gd.GetColumnCount(); ++col)
984                                                {
985                                                        gd.PutCell(col, row, gd.GetCell(col, row+1));
986                                                }
987                                        }
988                                        // remove last row
989                                        gd.PutRowCount(gd.GetRowCount() - 1);
990                                }
991
992                        }
993
994                }
995        }
996    // Changed a parameter
997        else if ( eventID == PPGEventContext::siParameterChange )
998        {
999                Parameter changed = ctx.GetSource() ;   
1000                CustomProperty prop = changed.GetParent() ;     
1001                CString   paramName = changed.GetScriptName() ;
1002
1003        // Check paramName against parameter names, perform custom onChanged event
1004                if (paramName == L"targetMeshFileName")
1005                {
1006                        // Default skeleton name if blank
1007                        Ogre::String meshName = XSItoOgre(changed.GetValue());
1008                        if (hasSkel && Ogre::StringUtil::endsWith(meshName, "mesh") &&
1009                                prop.GetParameterValue(L"targetSkeletonFileName") == L"")
1010                        {
1011                                Ogre::String skelName = meshName.substr(0, meshName.size() - 4) + "skeleton";
1012                                CString xsiSkelName = OgretoXSI(skelName);
1013                                prop.PutParameterValue(L"targetSkeletonFileName", xsiSkelName);
1014                        }
1015                        if (Ogre::StringUtil::endsWith(meshName, "mesh") &&
1016                                prop.GetParameterValue(L"targetMaterialFileName") == L"")
1017                        {
1018                                // default material script name if blank
1019                                Ogre::String matName = meshName.substr(0, meshName.size() - 4) + "material";
1020                                CString xsiMatName = OgretoXSI(matName);
1021                                prop.PutParameterValue(L"targetMaterialFileName", xsiMatName);
1022                        }
1023
1024                       
1025                }
1026        }
1027
1028
1029        return CStatus::OK;     
1030
1031}
1032
1033CString GetUserSelectedObject()
1034{
1035        Application app;
1036        Model root(app.GetActiveSceneRoot());
1037        CStringArray emptyArray;
1038        CRefArray cRefArray = root.FindChildren( L"", L"", emptyArray, true );
1039
1040        CStringArray nameArray(cRefArray.GetCount());
1041        for ( long i=0; i < cRefArray.GetCount(); i++ )
1042        {
1043                nameArray[i] = SIObject(cRefArray[i]).GetName();
1044        }
1045        //todo qsort the nameArray
1046
1047        // Using the COMAPIHandler for creating a "XSIDial.XSIDialog"
1048        CComAPIHandler xsidialog;
1049        xsidialog.CreateInstance( L"XSIDial.XSIDialog");
1050        CValue index;
1051        CValueArray args(cRefArray.GetCount());
1052        for (long y=0; y < cRefArray.GetCount(); y++)
1053                args[y]=nameArray[y];
1054
1055        xsidialog.Call(L"Combo",index,L"Select Item",args );
1056
1057        long ind = (long)index;
1058        return args[ind];
1059}
1060
1061
1062CStatus Popup( const CString& in_inputobjs, const CString& in_keywords, const CString& in_title, const CValue& /*number*/ in_mode, bool in_throw )
1063{
1064        Application app;
1065        CValueArray args(5);
1066        CValue retval;
1067        long i(0);
1068
1069        args[i++]= in_inputobjs;
1070        args[i++]= in_keywords;
1071        args[i++]= in_title;
1072        args[i++]= in_mode;
1073        args[i++]= in_throw;
1074
1075        return app.ExecuteCommand( L"InspectObj", args, retval );
1076
1077}
1078
1079void DeleteObj( const CValue& in_inputobj )
1080{
1081        Application app;
1082        CValueArray args(1);
1083        CValue retval;
1084        long i(0);
1085
1086        args[i++]= in_inputobj;
1087
1088        CStatus st = app.ExecuteCommand( L"DeleteObj", args, retval );
1089
1090        return;
1091}
Note: See TracBrowser for help on using the repository browser.