Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/ogre/Tools/XSIExport/src/OgreXSIExport.cpp @ 42

Last change on this file since 42 was 6, checked in by anonymous, 17 years ago

=…

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