source: OGRE/trunk/ogrenew/Tools/XSIExport/src/OgreXSISkeletonExporter.cpp @ 657

Revision 657, 27.7 KB checked in by mattausch, 19 years ago (diff)

added ogre dependencies and patched ogre sources

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 "OgreXSISkeletonExporter.h"
26#include "OgreResourceGroupManager.h"
27#include "OgreSkeletonManager.h"
28#include "OgreSkeleton.h"
29#include "OgreBone.h"
30#include "OgreAnimation.h"
31#include "OgreAnimationTrack.h"
32#include "OgreKeyFrame.h"
33#include "OgreSkeletonSerializer.h"
34#include "OgreQuaternion.h"
35#include <xsi_model.h>
36#include <xsi_kinematics.h>
37#include <xsi_kinematicstate.h>
38#include <xsi_math.h>
39#include <xsi_rotation.h>
40#include <xsi_animationsourceitem.h>
41#include <xsi_source.h>
42#include <xsi_fcurve.h>
43#include <xsi_fcurvekey.h>
44#include <xsi_time.h>
45#include <xsi_chaineffector.h>
46#include <xsi_chainroot.h>
47#include <xsi_chainbone.h>
48#include <xsi_matrix4.h>
49#include <xsi_transformation.h>
50#include <xsi_vector3.h>
51#include <xsi_constraint.h>
52#include <xsi_track.h>
53#include <xsi_clip.h>
54#include <xsi_selection.h>
55#include <xsi_statickinematicstate.h>
56
57using namespace XSI;
58
59namespace Ogre
60{
61        //-----------------------------------------------------------------------------
62        XsiSkeletonExporter::XsiSkeletonExporter()
63        {
64                mXsiSceneRoot = X3DObject(mXsiApp.GetActiveSceneRoot());
65                mXSITrackTypeNames["posx"] = XTT_POS_X;
66                mXSITrackTypeNames["posy"] = XTT_POS_Y;
67                mXSITrackTypeNames["posz"] = XTT_POS_Z;
68                mXSITrackTypeNames["rotx"] = XTT_ROT_X;
69                mXSITrackTypeNames["roty"] = XTT_ROT_Y;
70                mXSITrackTypeNames["rotz"] = XTT_ROT_Z;
71                mXSITrackTypeNames["sclx"] = XTT_SCL_X;
72                mXSITrackTypeNames["scly"] = XTT_SCL_Y;
73                mXSITrackTypeNames["sclz"] = XTT_SCL_Z;
74        }
75        //-----------------------------------------------------------------------------
76        XsiSkeletonExporter::~XsiSkeletonExporter()
77        {
78        }
79        //-----------------------------------------------------------------------------
80        void XsiSkeletonExporter::exportSkeleton(const String& skeletonFileName,
81                DeformerMap& deformers, float framesPerSecond, AnimationList& animList)
82        {
83                LogOgreAndXSI(L"** Begin OGRE Skeleton Export **");
84
85                copyDeformerMap(deformers);
86
87                SkeletonPtr skeleton = SkeletonManager::getSingleton().create("export",
88                        ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
89                // construct the hierarchy
90                buildBoneHierarchy(skeleton.get(), deformers, animList);
91
92                // pre-parse all animations for lengths
93                determineAnimationLengths(animList);
94
95                // progress report
96                ProgressManager::getSingleton().progress();
97
98                establishInitialTransforms(deformers);
99
100                // create animations
101                createAnimations(skeleton.get(), deformers, framesPerSecond, animList);
102                // progress report
103                ProgressManager::getSingleton().progress();
104
105                // Optimise
106                skeleton->optimiseAllAnimations();
107
108                SkeletonSerializer ser;
109                ser.exportSkeleton(skeleton.get(), skeletonFileName);
110                // progress report
111                ProgressManager::getSingleton().progress();
112
113                LogOgreAndXSI(L"** OGRE Skeleton Export Complete **");
114
115                cleanup();
116
117        }
118        //-----------------------------------------------------------------------------
119        void XsiSkeletonExporter::copyDeformerMap(DeformerMap& deformers)
120        {
121                // Make lower-case version
122                // some XSI animations appear to like to use case insensitive references :(
123                for (DeformerMap::iterator i = deformers.begin(); i != deformers.end(); ++i)
124                {
125                        DeformerEntry* deformer = i->second;
126                        String name = XSItoOgre(deformer->obj.GetName());
127                        StringUtil::toLowerCase(name);
128                        mLowerCaseDeformerMap[name] = deformer;
129                }
130        }
131        //-----------------------------------------------------------------------------
132        void XsiSkeletonExporter::buildBoneHierarchy(Skeleton* pSkeleton,
133                DeformerMap& deformers, AnimationList& animList)
134        {
135                /// Copy all entries from map into a list so iterators won't get invalidated
136                std::list<DeformerEntry*> deformerList;
137                LogOgreAndXSI(L"-- Bones with vertex assignments:");
138                for (DeformerMap::iterator i = deformers.begin(); i != deformers.end(); ++i)
139                {
140                        DeformerEntry* deformer = i->second;
141                        deformerList.push_back(deformer);
142                        LogOgreAndXSI(deformer->obj.GetName());
143                }
144
145                /* XSI allows you to use any object at all as a bone, not just chain elements.
146                   A typical choice is a hierarchy of nulls, for example. In order to
147                   build a skeleton hierarchy which represents the actual one, we need
148                   to find the relationships between all the deformers that we found.
149                   
150                   Well do this by navigating up the scene tree from each bone, looking for
151                   a match in the existing bone list or creating a new one where we need it
152                   to reach the root. We add bones even if they're not assigned vertices
153                   because the animation may depend on them. If the
154                   traversal hits the scene root this bone is clearly a root bone
155                   (there may be more than one).
156           */
157                for (std::list<DeformerEntry*>::iterator i = deformerList.begin(); i != deformerList.end(); ++i)
158                {
159                        DeformerEntry* deformer = *i;
160                        if (deformer->parentName.empty())
161                        {
162                                linkBoneWithParent(deformer, deformers, deformerList);
163                        }
164                }
165
166                // Now eliminate all bones without any animated kine parameters
167                // Need to do this after we've determined all relationships
168                for (std::list<DeformerEntry*>::iterator i = deformerList.begin(); i != deformerList.end(); ++i)
169                {
170                        DeformerEntry* deformer = *i;
171                        validateAsBone(pSkeleton, deformer, deformers, deformerList, animList);
172                }
173
174                // Now link
175                for (DeformerMap::iterator i = deformers.begin(); i != deformers.end(); ++i)
176                {
177                        DeformerEntry* deformer = i->second;
178
179                        // link to parent
180                        if (!deformer->parentName.empty())
181                        {
182                                DeformerEntry* parent = getDeformer(deformer->parentName, deformers);
183                                assert (parent && "Parent not found");
184                                assert (deformer->pBone && "Child bone not created");
185                                assert(parent->pBone && "Parent bone not created");
186                                parent->pBone->addChild(deformer->pBone);
187
188                        }
189                }
190
191        }
192        //-----------------------------------------------------------------------------
193        DeformerEntry* XsiSkeletonExporter::getDeformer(const String& name,
194                DeformerMap& deformers)
195        {
196                // Look in case sensitive list first
197                DeformerMap::iterator i = deformers.find(name);
198                if (i == deformers.end())
199                {
200                        String lcaseName = name;
201                        StringUtil::toLowerCase(lcaseName);
202                        i = mLowerCaseDeformerMap.find(lcaseName);
203                        if (i == mLowerCaseDeformerMap.end())
204                        {
205                                return 0;
206                        }
207                        else
208                        {
209                                return i->second;
210                        }
211                }
212                else
213                {
214                        return i->second;
215                }
216
217        }
218        //-----------------------------------------------------------------------------
219        void XsiSkeletonExporter::linkBoneWithParent(DeformerEntry* child,
220                DeformerMap& deformers, std::list<DeformerEntry*>& deformerList)
221        {
222                X3DObject parent(child->obj.GetParent());
223                String childName = XSItoOgre(child->obj.GetName());
224
225                if (child->obj == mXsiSceneRoot /* safety check for start node */)
226                        return;
227
228                // Check for parenting by a chain end effector
229                // These are sneaky little buggers - we actually want to attach the
230                // child to the end of the final bone in the chain
231                if (parent.IsA(XSI::siChainEffectorID))
232                {
233                        ChainEffector effector(parent);
234                        CRefArray chainBones = effector.GetRoot().GetBones();
235                        // get the last
236                        parent = chainBones[chainBones.GetCount()-1];
237                        child->parentIsChainEndEffector = true;
238                       
239                }
240                // is the parent the scene root?
241                if (parent == mXsiSceneRoot)
242                {
243                        // we hit the root node
244                }
245                else
246                {
247
248                        String parentName = XSItoOgre(parent.GetName());
249                        // Otherwise, check to see if the parent is in the deformer list
250                        DeformerEntry* parentDeformer = getDeformer(parentName, deformers);
251                        if (!parentDeformer)
252                        {
253                                // not found, create entry for parent
254                                parentDeformer = new DeformerEntry(deformers.size(), parent);
255                                deformers[parentName] = parentDeformer;
256                                deformerList.push_back(parentDeformer);
257                                LogOgreAndXSI(CString(L"Added ") + parent.GetName() +
258                                        CString(L" as a parent of ") + child->obj.GetName() );
259                        }
260
261                        // Link child entry with parent (not bone yet)
262                        // link child to parent by name
263                        child->parentName = parentName;
264                        parentDeformer->childNames.push_back(childName);
265
266
267
268
269                }
270
271        }
272        //-----------------------------------------------------------------------------
273        void XsiSkeletonExporter::validateAsBone(Skeleton* pSkeleton,
274                DeformerEntry* deformer,
275                DeformerMap& deformers, std::list<DeformerEntry*>& deformerList,
276                AnimationList& animList)
277        {
278                /* The purpose of this method is to find out whether a node in the
279                   bone hierarchy is animated, and if not, to eliminate it and propagate
280                   it's static transform contribution to it's children.
281                   We do this because it's quite easy in XSI to build deep bone chains
282                   with intermediate points that are only used for manipulation. We
283                   don't want to include all of those.
284           */
285
286                // TODO
287
288
289                // if we weren't static, create bone
290                if (!deformer->pBone)
291                {
292                        String name = XSItoOgre(deformer->obj.GetName());
293                        deformer->pBone = pSkeleton->createBone(name, deformer->boneID);
294                        MATH::CTransformation trans;
295
296                        if (deformer->parentName.empty())
297                        {
298                                // set transform on bone to global transform since no parents
299                                trans = deformer->obj.GetKinematics().GetGlobal().GetTransform();
300                        }
301                        else
302                        {
303                                // set transform on bone to local transform (since child)
304                                trans = deformer->obj.GetKinematics().GetLocal().GetTransform();
305                        }
306                        deformer->pBone->setPosition(XSItoOgre(trans.GetTranslation()));
307                        deformer->pBone->setOrientation(XSItoOgre(trans.GetRotation().GetQuaternion()));
308                        deformer->pBone->setScale(XSItoOgre(trans.GetScaling()));
309
310                        // special case a bone which is parented by a chain end
311                        if (deformer->parentIsChainEndEffector)
312                        {
313                                ChainEffector effector(deformer->obj.GetParent());
314                                CRefArray chainBones = effector.GetRoot().GetBones();
315                                // get the last
316                                X3DObject endBone = chainBones[chainBones.GetCount()-1];
317                                // offset along X the length of the bone
318                                double boneLen = endBone.GetParameterValue(L"Length");
319                                deformer->pBone->setPosition(
320                                        deformer->pBone->getPosition() + Vector3::UNIT_X * boneLen);
321                        }
322
323                }
324
325        }
326        //-----------------------------------------------------------------------------
327        void XsiSkeletonExporter::processActionSource(const XSI::ActionSource& actSource,
328                DeformerMap& deformers)
329        {
330                // Clear existing deformer links
331                for(DeformerMap::iterator di = deformers.begin(); di != deformers.end(); ++di)
332                {
333                        for (int tt = XTT_POS_X; tt < XTT_COUNT; ++tt)
334                        {
335                                di->second->xsiTrack[tt].ResetObject();
336                        }
337                }
338                // Get all the items
339                CRefArray items = actSource.GetItems();
340                for (int i = 0; i < items.GetCount(); ++i)
341                {
342                        XSI::AnimationSourceItem item = items[i];
343
344                        // Check the target
345                        String target = XSItoOgre(item.GetTarget());
346                        size_t firstDotPos = target.find_first_of(".");
347                        size_t lastDotPos = target.find_last_of(".");
348                        if (firstDotPos != String::npos && lastDotPos != String::npos)
349                        {
350                                String targetName = target.substr(0, firstDotPos);
351                                String paramName = target.substr(lastDotPos+1,
352                                        target.size() - lastDotPos - 1);
353                                // locate deformer
354                                DeformerEntry* deformer = getDeformer(targetName, deformers);
355                                if (deformer)
356                                {
357                                        // determine parameter
358                                        std::map<String, int>::iterator pi = mXSITrackTypeNames.find(paramName);
359                                        if (pi != mXSITrackTypeNames.end())
360                                        {
361                                                deformer->xsiTrack[pi->second] = item;
362                                                deformer->hasAnyTracks = true;
363                                        }
364                                }
365                        }
366
367                }
368        }
369        //-----------------------------------------------------------------------------
370        void XsiSkeletonExporter::createAnimations(Skeleton* pSkel,
371                DeformerMap& deformers, float fps, AnimationList& animList)
372        {
373                for (AnimationList::iterator ai = animList.begin(); ai != animList.end(); ++ai)
374                {
375                        AnimationEntry& animEntry = *ai;
376
377                        float animLength = (float)(animEntry.endFrame - animEntry.startFrame) / fps;
378                        StringUtil::StrStreamType str;
379                        str << "Creating animation " << animEntry.animationName <<
380                                " with length " << animLength << " seconds";
381                        LogOgreAndXSI(str.str());
382                        Animation* anim = pSkel->createAnimation(animEntry.animationName, animLength);
383
384                        if (animEntry.ikSample)
385                        {
386                                createAnimationTracksSampled(anim, animEntry, deformers, fps);
387                        }
388                        else
389                        {
390                                createAnimationTracksDirect(anim, animEntry, deformers, fps);
391                        }
392                       
393                }
394        }
395        //-----------------------------------------------------------------------------
396        void XsiSkeletonExporter::determineAnimationLengths(AnimationList& animList)
397        {
398                for (AnimationList::iterator ai = animList.begin(); ai != animList.end(); ++ai)
399                {
400                        AnimationEntry& animEntry = *ai;
401                        determineAnimationLength(animEntry);
402                }
403        }
404        //-----------------------------------------------------------------------------
405        void XsiSkeletonExporter::determineAnimationLength(AnimationEntry& animEntry)
406        {
407                bool first = true;
408                CRefArray items = animEntry.source.GetItems();
409                for (int i = 0; i < items.GetCount(); ++i)
410                {
411                        XSI::AnimationSourceItem item = items[i];
412
413                        // skip invalid or non-FCurve items
414                        if (!item.IsValid() || !item.GetSource().IsA(XSI::siFCurveID))
415                                continue;
416
417                        FCurve fcurve = item.GetSource();
418                        CRefArray keys = fcurve.GetKeys();
419                        for (int k = 0; k < keys.GetCount(); ++k)
420                        {
421                                long currFrame = (long)(fcurve.GetKeyTime(k).GetTime());
422                                if (first)
423                                {
424                                        animEntry.startFrame = currFrame;
425                                        animEntry.endFrame = currFrame;
426                                        first = false;
427                                }
428                                else
429                                {
430                                        if (currFrame < animEntry.startFrame)
431                                        {
432                                                animEntry.startFrame = currFrame;
433                                        }
434                                        if (currFrame > animEntry.endFrame)
435                                        {
436                                                animEntry.endFrame = currFrame;
437                                        }
438                                }
439
440                        }
441                }
442
443
444
445        }
446        //-----------------------------------------------------------------------------
447        void XsiSkeletonExporter::buildKeyframeList(DeformerEntry* deformer,
448                AnimationEntry& animEntry)
449        {
450                bool first = true;
451                animEntry.frames.clear();
452                for (int tt = XTT_POS_X; tt < XTT_COUNT; ++tt)
453                {
454                        AnimationSourceItem item = deformer->xsiTrack[tt];
455                        // skip invalid or non-FCurve items
456                        if (!item.IsValid() || !item.GetSource().IsA(XSI::siFCurveID))
457                                continue;
458                       
459                        FCurve fcurve = item.GetSource();
460                        CRefArray keys = fcurve.GetKeys();
461                        for (int k = 0; k < keys.GetCount(); ++k)
462                        {
463                                long currFrame = (long)(fcurve.GetKeyTime(k).GetTime());
464                                if (first)
465                                {
466                                        animEntry.startFrame = currFrame;
467                                        animEntry.endFrame = currFrame;
468                                        first = false;
469                                }
470                                else
471                                {
472                                        if (currFrame < animEntry.startFrame)
473                                        {
474                                                animEntry.startFrame = currFrame;
475                                        }
476                                        if (currFrame > animEntry.endFrame)
477                                        {
478                                                animEntry.endFrame = currFrame;
479                                        }
480                                }
481                               
482                                animEntry.frames.insert(currFrame);
483                        }
484                }
485
486       
487
488
489        }
490        //-----------------------------------------------------------------------------
491        void XsiSkeletonExporter::createAnimationTracksSampled(Animation* pAnim,
492                AnimationEntry& animEntry, DeformerMap& deformers, float fps)
493        {
494                // Save the current selection
495                CString seltext(mXsiApp.GetSelection().GetAsText());
496
497                // Clear current animation
498                CValueArray args;
499                CValue dummy;
500                mXsiApp.ExecuteCommand(L"SelectAll", args, dummy);
501                mXsiApp.ExecuteCommand(L"RemoveAllAnimation", args, dummy);
502
503                // Reset selection
504                mXsiApp.GetSelection().SetAsText(seltext);
505
506
507                // Create all tracks first
508                std::vector<AnimationTrack*> deformerTracks;
509                deformerTracks.resize(deformers.size());
510                for (DeformerMap::iterator di = deformers.begin(); di != deformers.end(); ++di)
511                {
512                        DeformerEntry* deformer = di->second;
513                        AnimationTrack* track = pAnim->createTrack(deformer->boneID, deformer->pBone);
514                        deformerTracks[deformer->boneID] = track;
515                }
516
517                Model model = placeAnimationInMixer(animEntry);
518
519                // Iterate over frames, keying as we go
520                long numFrames = animEntry.endFrame - animEntry.startFrame;
521                if (animEntry.ikSampleInterval == 0)
522                {
523                        // Don't allow zero samplign frequency - infinite loop!
524                        animEntry.ikSampleInterval = 5.0f;
525                }
526
527                for (long frame = 0; frame < numFrames; frame += animEntry.ikSampleInterval)
528                {
529                        sampleAllBones(deformers, deformerTracks, frame, fps);
530
531                }
532                // sample final frame
533                sampleAllBones(deformers, deformerTracks,
534                        animEntry.endFrame - animEntry.startFrame, fps);
535
536                // remove the clip we added
537                Mixer mixer(model.GetMixer());
538                removeAllFromMixer(mixer);
539
540        }
541        //-----------------------------------------------------------------------------
542        void XsiSkeletonExporter::establishInitialTransforms(DeformerMap& deformers)
543        {
544                for (DeformerMap::iterator di = deformers.begin(); di != deformers.end(); ++di)
545                {
546                        DeformerEntry* deformer = di->second;
547                        if (deformer->pBone->getParent() == 0)
548                        {
549                                // Based on global
550                                deformer->initialXform =
551                                        deformer->obj.GetKinematics().GetGlobal().GetTransform();
552                        }
553                        else
554                        {
555                                // Based on local
556                                deformer->initialXform =
557                                        deformer->obj.GetKinematics().GetLocal().GetTransform();
558                        }
559
560                }
561        }
562        //-----------------------------------------------------------------------------
563        void XsiSkeletonExporter::sampleAllBones(DeformerMap& deformers,
564                std::vector<AnimationTrack*> deformerTracks, double frame, float fps)
565        {
566                CValueArray args;
567                CValue dummy;
568                args.Resize(2);
569                // set the playcontrol
570                args[0] = L"PlayControl.Key";
571                args[1] = frame;
572                mXsiApp.ExecuteCommand(L"SetValue", args, dummy);
573                args[0] = L"PlayControl.Current";
574                mXsiApp.ExecuteCommand(L"SetValue", args, dummy);
575
576                // Refresh
577                mXsiApp.ExecuteCommand(L"Refresh", CValueArray(), dummy);
578                // Sample all bones
579                for (DeformerMap::iterator di = deformers.begin(); di != deformers.end(); ++di)
580                {
581                        DeformerEntry* deformer = di->second;
582                        AnimationTrack* track = deformerTracks[deformer->boneID];
583
584                        double initposx, initposy, initposz;
585                        deformer->initialXform.GetTranslationValues(initposx, initposy, initposz);
586                        double initrotx, initroty, initrotz;
587                        deformer->initialXform.GetRotation().GetXYZAngles(initrotx, initroty, initrotz);
588                        double initsclx, initscly, initsclz;
589                        deformer->initialXform.GetScalingValues(initsclx, initscly, initsclz);
590                        XSI::MATH::CMatrix4 invTrans = deformer->initialXform.GetMatrix4();
591                        invTrans.InvertInPlace();
592
593                        XSI::MATH::CTransformation transformation;
594                        if (deformer->pBone->getParent() == 0)
595                        {
596                                // Based on global
597                                transformation =
598                                        deformer->obj.GetKinematics().GetGlobal().GetTransform();
599                        }
600                        else
601                        {
602                                // Based on local
603                                transformation =
604                                        deformer->obj.GetKinematics().GetLocal().GetTransform();
605                        }
606
607                        // Make relative to initial
608                        XSI::MATH::CMatrix4 transformationMatrix = transformation.GetMatrix4();
609                        transformationMatrix.MulInPlace(invTrans);
610                        transformation.SetMatrix4(transformationMatrix);
611
612                        double posx, posy, posz;
613                        transformation.GetTranslationValues(posx, posy, posz);
614
615                        // create keyframe
616                        KeyFrame* kf = track->createKeyFrame((float)frame / fps);
617                        // not sure why inverted transform doesn't work for position, but it doesn't
618                        // I thought XSI used same transform order as OGRE
619                        kf->setTranslate(XSItoOgre(transformation.GetTranslation()));
620                        //kf->setTranslate(Vector3(posx - initposx, posy - initposy, posz - initposz));
621                        kf->setRotation(XSItoOgre(transformation.GetRotationQuaternion()));
622                        kf->setScale(XSItoOgre(transformation.GetScaling()));
623
624                }
625
626        }
627        //-----------------------------------------------------------------------------
628        void XsiSkeletonExporter::createAnimationTracksDirect(Animation* pAnim,
629                AnimationEntry& animEntry, DeformerMap& deformers, float fps)
630        {
631
632                // tease out all the animation source items
633                processActionSource(animEntry.source, deformers);
634
635                /* We have to iterate over the list of deformers, and create a track
636                 * for each one. Since XSI stores keys for all 9 components separately,
637                 * we need to bake OGRE keyframes (which include position, rotation and
638                 * translation) by interpolation. We can merge the list of frames from all
639                 * action source item fcurves, then use the Eval method to get XSI to sample
640                 * the curve properly for us.
641                 * We will also use this to ensure there is a keyframe at the start and end of the
642                 * animation.
643                 */
644                for (DeformerMap::iterator di = deformers.begin(); di != deformers.end(); ++di)
645                {
646                        DeformerEntry* deformer = di->second;
647
648                        // Skip deformers which have no animated parameters
649                        if (!deformer->hasAnyTracks)
650                                continue;
651
652                        StringUtil::StrStreamType str;
653                        str << "Creating track for bone " << deformer->pBone->getName() <<
654                                "(" << deformer->boneID << ")";
655                        LogOgreAndXSI(str.str());
656                        // create track
657                        AnimationTrack* track = pAnim->createTrack(deformer->boneID, deformer->pBone);
658
659                        XSI::MATH::CTransformation initialTransformation;
660                        if (deformer->pBone->getParent() == 0)
661                        {
662                                // Based on global
663                                initialTransformation =
664                                        deformer->obj.GetKinematics().GetGlobal().GetTransform();
665                        }
666                        else
667                        {
668                                // Based on local
669                                initialTransformation =
670                                        deformer->obj.GetKinematics().GetLocal().GetTransform();
671                        }
672                        XSI::MATH::CMatrix4 invTrans = initialTransformation.GetMatrix4();
673                        invTrans.InvertInPlace();
674
675                        double initposx, initposy, initposz;
676                        initialTransformation.GetTranslationValues(initposx, initposy, initposz);
677                        double initrotx, initroty, initrotz;
678                        initialTransformation.GetRotation().GetXYZAngles(initrotx, initroty, initrotz);
679                        double initsclx, initscly, initsclz;
680                        initialTransformation.GetScalingValues(initsclx, initscly, initsclz);
681
682
683                        // Get the keyframe numbers from all XSI tracks
684                        // XSI tracks might be sparse
685                        buildKeyframeList(deformer, animEntry);
686
687                        // Iterate over the frames and pull out the values we need
688                        // bake keyframe for all
689                        for (std::set<long>::iterator fi = animEntry.frames.begin();
690                                fi != animEntry.frames.end(); ++fi)
691                        {
692                                double posx = deriveKeyFrameValue(deformer->xsiTrack[XTT_POS_X], *fi, initposx);
693                                double posy = deriveKeyFrameValue(deformer->xsiTrack[XTT_POS_Y], *fi, initposy);
694                                double posz = deriveKeyFrameValue(deformer->xsiTrack[XTT_POS_Z], *fi, initposz);
695                                double rotx = deriveKeyFrameValue(deformer->xsiTrack[XTT_ROT_X], *fi, initrotx);
696                                double roty = deriveKeyFrameValue(deformer->xsiTrack[XTT_ROT_Y], *fi, initroty);
697                                double rotz = deriveKeyFrameValue(deformer->xsiTrack[XTT_ROT_Z], *fi, initrotz);
698                                double sclx = deriveKeyFrameValue(deformer->xsiTrack[XTT_SCL_X], *fi, initsclx);
699                                double scly = deriveKeyFrameValue(deformer->xsiTrack[XTT_SCL_Y], *fi, initscly);
700                                double sclz = deriveKeyFrameValue(deformer->xsiTrack[XTT_SCL_Z], *fi, initsclz);
701
702
703                                // Build transformation relative to initial
704                                XSI::MATH::CTransformation transformation;
705                               
706                                XSI::MATH::CVector3 scaling(sclx, scly, sclz);
707                                transformation.SetScaling(scaling);
708                                transformation.SetRotationFromXYZAnglesValues(
709                                        XSI::MATH::DegreesToRadians(rotx),
710                                        XSI::MATH::DegreesToRadians(roty),
711                                        XSI::MATH::DegreesToRadians(rotz),
712                                        XSI::MATH::CRotation::siXYZ);
713                                transformation.SetTranslationFromValues(posx, posy, posz);
714
715
716                                XSI::MATH::CMatrix4 transformationMatrix = transformation.GetMatrix4();
717                                transformationMatrix.MulInPlace(invTrans);
718                                transformation.SetMatrix4(transformationMatrix);
719
720
721                                // create keyframe
722                                KeyFrame* kf = track->createKeyFrame((float)(*fi - animEntry.startFrame) / fps);
723                                // not sure why inverted transform doesn't work for position, but it doesn't
724                                // I thought XSI used same transform order as OGRE
725                                //kf->setTranslate(XSItoOgre(transformation.GetTranslation()));
726                                kf->setTranslate(Vector3(posx - initposx, posy - initposy, posz - initposz));
727                                kf->setRotation(XSItoOgre(transformation.GetRotationQuaternion()));
728                                kf->setScale(XSItoOgre(transformation.GetScaling()));
729
730
731                        }
732                }
733
734
735        }
736        //-----------------------------------------------------------------------------
737        double XsiSkeletonExporter::deriveKeyFrameValue(
738                XSI::AnimationSourceItem item, long frame, double defaultVal)
739        {
740                if (item.IsValid())
741                {
742                        FCurve curve(item.GetSource());
743                        // let fcurve evaluate
744                        return curve.Eval(CTime(frame));
745                }
746                else
747                {
748                        return defaultVal;
749                }
750        }
751        //-----------------------------------------------------------------------------
752        void XsiSkeletonExporter::cleanup(void)
753        {
754
755                mLowerCaseDeformerMap.clear();
756
757                CValueArray args;
758                CValue dummy;
759                args.Resize(1);
760
761                for (int i = 0; i < mIKSampledAnimations.GetCount(); ++i)
762                {
763                        args[0] = mIKSampledAnimations[i];
764                        mXsiApp.ExecuteCommand(L"DeleteObj", args, dummy);
765                }
766                mIKSampledAnimations.Clear();
767
768        }
769        //-----------------------------------------------------------------------------
770        void XsiSkeletonExporter::removeAllFromMixer(Mixer& mixer)
771        {
772                CRefArray tracks(mixer.GetTracks());
773                for (int t = 0; t < tracks.GetCount(); ++t)
774                {
775                        Track track(tracks[t]);
776                        CRefArray clips(track.GetClips());
777                        for (int c = 0; c < clips.GetCount(); ++c)
778                        {
779                                Clip clip(clips[c]);
780                                CValueArray args;
781                                CValue dummy;
782                                args.Add(clip.GetFullName());
783                                mXsiApp.ExecuteCommand(L"DeleteObj", args, dummy);
784                        }
785
786                }
787
788        }
789        //-----------------------------------------------------------------------------
790        XSI::Mixer XsiSkeletonExporter::getMixer(AnimationEntry& anim)
791        {
792                Model model(anim.source.GetModel());
793                if (!model.HasMixer())
794                {
795                        model = mXsiApp.GetActiveSceneRoot();
796                }
797                return model.GetMixer();
798        }
799        //-----------------------------------------------------------------------------
800        XSI::Model XsiSkeletonExporter::placeAnimationInMixer(AnimationEntry& anim)
801        {
802                Mixer mixer(getMixer(anim));
803                Model model(mixer.GetModel()) ;
804
805                removeAllFromMixer(mixer);
806
807                // Clear all clips from the mixer
808
809                CValueArray args;
810                CValue dummy;
811
812                // Add the new clip to the mixer
813                CRefArray tracks(mixer.GetTracks());
814                if (tracks.GetCount() == 0)
815                {
816                        // Must be at least one track
817                        args.Resize(3);
818                        args[0] = model.GetFullName();
819                        args[1] = mixer.GetFullName();
820                        args[2] = 0.0f;
821                        mXsiApp.ExecuteCommand(L"AddTrack", args, dummy);
822                        tracks = mixer.GetTracks();
823                }
824                Track instrack(tracks[0]);
825                args.Resize(5);
826                args[0] = model.GetFullName(); // target model
827                args[1] = anim.source.GetFullName(); // source
828                args[2] = L""; // compound clip
829                args[3] = instrack.GetFullName();
830                args[4] = 0.0f; // start frame
831                mXsiApp.ExecuteCommand(L"AddClip", args, dummy);
832
833
834                // Reset the animation to frame 0, such that following animations start with the initial bone transforms
835                args.Resize(2);
836                args[0] = L"PlayControl.Key";
837                args[1] = (long)0;
838                mXsiApp.ExecuteCommand(L"SetValue", args, dummy);
839                args[0] = L"PlayControl.Current";
840                args[1] = (long)0;
841                mXsiApp.ExecuteCommand(L"SetValue", args, dummy);
842                mXsiApp.ExecuteCommand(L"Refresh", CValueArray(), dummy);
843
844
845                return model;
846
847        }
848}
Note: See TracBrowser for help on using the repository browser.