Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreSkeleton.cpp @ 3

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

=update

File size: 36.0 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 "OgreStableHeaders.h"
30#include "OgreSkeleton.h"
31#include "OgreBone.h"
32#include "OgreAnimation.h"
33#include "OgreAnimationState.h"
34#include "OgreException.h"
35#include "OgreLogManager.h"
36#include "OgreSkeletonManager.h"
37#include "OgreSkeletonSerializer.h"
38#include "OgreStringConverter.h"
39// Just for logging
40#include "OgreAnimationTrack.h"
41#include "OgreKeyFrame.h"
42
43
44namespace Ogre {
45
46    //---------------------------------------------------------------------
47        Skeleton::Skeleton()
48                : Resource(),
49        mBlendState(ANIMBLEND_AVERAGE),
50                mNextAutoHandle(0),
51                mManualBonesDirty(false)
52        {
53        }
54        //---------------------------------------------------------------------
55    Skeleton::Skeleton(ResourceManager* creator, const String& name, ResourceHandle handle,
56        const String& group, bool isManual, ManualResourceLoader* loader) 
57        : Resource(creator, name, handle, group, isManual, loader), 
58        mBlendState(ANIMBLEND_AVERAGE), mNextAutoHandle(0)
59        // set animation blending to weighted, not cumulative
60    {
61        if (createParamDictionary("Skeleton"))
62        {
63            // no custom params
64        }
65    }
66    //---------------------------------------------------------------------
67    Skeleton::~Skeleton()
68    {
69        // have to call this here reather than in Resource destructor
70        // since calling virtual methods in base destructors causes crash
71        unload(); 
72    }
73    //---------------------------------------------------------------------
74    void Skeleton::loadImpl(void)
75    {
76        SkeletonSerializer serializer;
77                StringUtil::StrStreamType msg;
78                msg << "Skeleton: Loading " << mName;
79        LogManager::getSingleton().logMessage(msg.str());
80
81        DataStreamPtr stream = 
82            ResourceGroupManager::getSingleton().openResource(
83                                mName, mGroup, true, this);
84
85        serializer.importSkeleton(stream, this);
86
87                // Load any linked skeletons
88                LinkedSkeletonAnimSourceList::iterator i;
89                for (i = mLinkedSkeletonAnimSourceList.begin(); 
90                        i != mLinkedSkeletonAnimSourceList.end(); ++i)
91                {
92                        i->pSkeleton = SkeletonManager::getSingleton().load(
93                                i->skeletonName, mGroup);
94                }
95
96
97    }
98    //---------------------------------------------------------------------
99    void Skeleton::unloadImpl(void)
100    {
101        // destroy bones
102        BoneList::iterator i;
103        for (i = mBoneList.begin(); i != mBoneList.end(); ++i)
104        {
105            delete *i;
106        }
107        mBoneList.clear();
108        mBoneListByName.clear();
109                mRootBones.clear();
110        mManualBones.clear();
111        mManualBonesDirty = false;
112
113        // Destroy animations
114        AnimationList::iterator ai;
115        for (ai = mAnimationsList.begin(); ai != mAnimationsList.end(); ++ai)
116        {
117            delete ai->second;
118        }
119        mAnimationsList.clear();
120
121        // Remove all linked skeletons
122        mLinkedSkeletonAnimSourceList.clear();
123    }
124    //---------------------------------------------------------------------
125    Bone* Skeleton::createBone(void)
126    {
127        // use autohandle
128        return createBone(mNextAutoHandle++);
129    }
130    //---------------------------------------------------------------------
131    Bone* Skeleton::createBone(const String& name)
132    {
133        return createBone(name, mNextAutoHandle++);
134    }
135    //---------------------------------------------------------------------
136    Bone* Skeleton::createBone(unsigned short handle)
137    {
138        if (handle >= OGRE_MAX_NUM_BONES)
139        {
140            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Exceeded the maximum number of bones per skeleton.",
141                "Skeleton::createBone");
142        }
143        // Check handle not used
144        if (handle < mBoneList.size() && mBoneList[handle] != NULL)
145        {
146            OGRE_EXCEPT(
147                Exception::ERR_DUPLICATE_ITEM,
148                "A bone with the handle " + StringConverter::toString(handle) + " already exists",
149                "Skeleton::createBone" );
150        }
151        Bone* ret = new Bone(handle, this);
152        assert(mBoneListByName.find(ret->getName()) == mBoneListByName.end());
153        if (mBoneList.size() <= handle)
154        {
155            mBoneList.resize(handle+1);
156        }
157        mBoneList[handle] = ret;
158        mBoneListByName[ret->getName()] = ret;
159        return ret;
160
161    }
162    //---------------------------------------------------------------------
163    Bone* Skeleton::createBone(const String& name, unsigned short handle)
164    {
165        if (handle >= OGRE_MAX_NUM_BONES)
166        {
167            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Exceeded the maximum number of bones per skeleton.",
168                "Skeleton::createBone");
169        }
170        // Check handle not used
171        if (handle < mBoneList.size() && mBoneList[handle] != NULL)
172        {
173            OGRE_EXCEPT(
174                Exception::ERR_DUPLICATE_ITEM,
175                "A bone with the handle " + StringConverter::toString(handle) + " already exists",
176                "Skeleton::createBone" );
177        }
178        // Check name not used
179        if (mBoneListByName.find(name) != mBoneListByName.end())
180        {
181            OGRE_EXCEPT(
182                Exception::ERR_DUPLICATE_ITEM,
183                "A bone with the name " + name + " already exists",
184                "Skeleton::createBone" );
185        }
186        Bone* ret = new Bone(name, handle, this);
187        if (mBoneList.size() <= handle)
188        {
189            mBoneList.resize(handle+1);
190        }
191        mBoneList[handle] = ret;
192        mBoneListByName[name] = ret;
193        return ret;
194    }
195
196
197
198    //---------------------------------------------------------------------
199    Bone* Skeleton::getRootBone(void) const
200    {
201        if (mRootBones.empty())
202        {
203            deriveRootBone();
204        }
205
206        return mRootBones[0];
207    }
208    //---------------------------------------------------------------------
209    void Skeleton::setAnimationState(const AnimationStateSet& animSet)
210    {
211        /*
212        Algorithm:
213          1. Reset all bone positions
214          2. Iterate per AnimationState, if enabled get Animation and call Animation::apply
215        */
216
217        // Reset bones
218        reset();
219
220                Real weightFactor = 1.0f;
221                if (mBlendState == ANIMBLEND_AVERAGE)
222                {
223                        // Derive total weights so we can rebalance if > 1.0f
224                        Real totalWeights = 0.0f;
225                        ConstEnabledAnimationStateIterator stateIt = 
226                                animSet.getEnabledAnimationStateIterator();
227                        while (stateIt.hasMoreElements())
228                        {
229                                const AnimationState* animState = stateIt.getNext();
230                                // Make sure we have an anim to match implementation
231                                const LinkedSkeletonAnimationSource* linked = 0;
232                                if (_getAnimationImpl(animState->getAnimationName(), &linked))
233                                {
234                                        totalWeights += animState->getWeight();
235                                }
236                        }
237
238                        // Allow < 1.0f, allows fade out of all anims if required
239                        if (totalWeights > 1.0f)
240                        {
241                                weightFactor = 1.0f / totalWeights;
242                        }
243                }
244
245        // Per enabled animation state
246        ConstEnabledAnimationStateIterator stateIt = 
247            animSet.getEnabledAnimationStateIterator();
248        while (stateIt.hasMoreElements())
249        {
250            const AnimationState* animState = stateIt.getNext();
251            const LinkedSkeletonAnimationSource* linked = 0;
252            Animation* anim = _getAnimationImpl(animState->getAnimationName(), &linked);
253            // tolerate state entries for animations we're not aware of
254            if (anim)
255            {
256                if (linked)
257                {
258                    anim->apply(this, animState->getTimePosition(), 
259                                                animState->getWeight() * weightFactor, linked->scale);
260                }
261                else
262                {
263                    anim->apply(this, animState->getTimePosition(), 
264                                                animState->getWeight() * weightFactor);
265                }
266            }
267        }
268
269
270    }
271    //---------------------------------------------------------------------
272    void Skeleton::setBindingPose(void)
273    {
274        // Update the derived transforms
275        _updateTransforms();
276
277
278        BoneList::iterator i;
279        for (i = mBoneList.begin(); i != mBoneList.end(); ++i)
280        {           
281            (*i)->setBindingPose();
282        }
283    }
284    //---------------------------------------------------------------------
285    void Skeleton::reset(bool resetManualBones)
286    {
287        BoneList::iterator i;
288        for (i = mBoneList.begin(); i != mBoneList.end(); ++i)
289        {
290            if(!(*i)->isManuallyControlled() || resetManualBones)
291                (*i)->reset();
292        }
293    }
294    //---------------------------------------------------------------------
295    Animation* Skeleton::createAnimation(const String& name, Real length)
296    {
297        // Check name not used
298        if (mAnimationsList.find(name) != mAnimationsList.end())
299        {
300            OGRE_EXCEPT(
301                Exception::ERR_DUPLICATE_ITEM,
302                "An animation with the name " + name + " already exists",
303                "Skeleton::createAnimation");
304        }
305
306        Animation* ret = new Animation(name, length);
307
308        // Add to list
309        mAnimationsList[name] = ret;
310
311        return ret;
312
313    }
314        //---------------------------------------------------------------------
315        Animation* Skeleton::getAnimation(const String& name, 
316                const LinkedSkeletonAnimationSource** linker) const
317        {
318                Animation* ret = _getAnimationImpl(name, linker);
319                if (!ret)
320                {
321                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "No animation entry found named " + name, 
322                                "Skeleton::getAnimation");
323                }
324
325                return ret;
326        }
327        //---------------------------------------------------------------------
328        bool Skeleton::hasAnimation(const String& name)
329        {
330                return _getAnimationImpl(name) != 0;
331        }
332    //---------------------------------------------------------------------
333    Animation* Skeleton::_getAnimationImpl(const String& name, 
334                const LinkedSkeletonAnimationSource** linker) const
335    {
336                Animation* ret = 0;
337        AnimationList::const_iterator i = mAnimationsList.find(name);
338
339        if (i == mAnimationsList.end())
340        {
341                        LinkedSkeletonAnimSourceList::const_iterator i;
342                        for (i = mLinkedSkeletonAnimSourceList.begin(); 
343                                i != mLinkedSkeletonAnimSourceList.end() && !ret; ++i)
344                        {
345                                if (!i->pSkeleton.isNull())
346                                {
347                                        ret = i->pSkeleton->_getAnimationImpl(name);
348                                        if (ret && linker)
349                                        {
350                                                *linker = &(*i);
351                                        }
352
353                                }
354                        }
355
356        }
357                else
358                {
359                        if (linker)
360                                *linker = 0;
361                        ret = i->second;
362                }
363
364                return ret;
365
366    }
367    //---------------------------------------------------------------------
368    void Skeleton::removeAnimation(const String& name)
369    {
370        AnimationList::iterator i = mAnimationsList.find(name);
371
372        if (i == mAnimationsList.end())
373        {
374            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "No animation entry found named " + name, 
375            "Skeleton::getAnimation");
376        }
377
378        delete i->second;
379
380        mAnimationsList.erase(i);
381
382    }
383    //-----------------------------------------------------------------------
384    void Skeleton::_initAnimationState(AnimationStateSet* animSet)
385    {
386        animSet->removeAllAnimationStates();
387           
388        AnimationList::iterator i;
389        for (i = mAnimationsList.begin(); i != mAnimationsList.end(); ++i)
390        {
391            Animation* anim = i->second;
392            // Create animation at time index 0, default params mean this has weight 1 and is disabled
393            const String& animName = anim->getName();
394            animSet->createAnimationState(animName, 0.0, anim->getLength());
395        }
396
397                // Also iterate over linked animation
398                LinkedSkeletonAnimSourceList::iterator li;
399                for (li = mLinkedSkeletonAnimSourceList.begin(); 
400                        li != mLinkedSkeletonAnimSourceList.end(); ++li)
401                {
402                        if (!li->pSkeleton.isNull())
403                        {
404                                li->pSkeleton->_refreshAnimationState(animSet);
405                        }
406                }
407
408    }
409        //-----------------------------------------------------------------------
410        void Skeleton::_refreshAnimationState(AnimationStateSet* animSet)
411        {
412                // Merge in any new animations
413                AnimationList::iterator i;
414                for (i = mAnimationsList.begin(); i != mAnimationsList.end(); ++i)
415                {
416                        Animation* anim = i->second;
417                        // Create animation at time index 0, default params mean this has weight 1 and is disabled
418                        const String& animName = anim->getName();
419                        if (!animSet->hasAnimationState(animName))
420                        {
421                                animSet->createAnimationState(animName, 0.0, anim->getLength());
422                        }
423                        else
424                        {
425                                // Update length incase changed
426                                AnimationState* animState = animSet->getAnimationState(animName);
427                                animState->setLength(anim->getLength());
428                                animState->setTimePosition(std::min(anim->getLength(), animState->getTimePosition()));
429                        }
430                }
431                // Also iterate over linked animation
432                LinkedSkeletonAnimSourceList::iterator li;
433                for (li = mLinkedSkeletonAnimSourceList.begin(); 
434                        li != mLinkedSkeletonAnimSourceList.end(); ++li)
435                {
436                        if (!li->pSkeleton.isNull())
437                        {
438                                li->pSkeleton->_refreshAnimationState(animSet);
439                        }
440                }
441        }
442        //-----------------------------------------------------------------------
443        void Skeleton::_notifyManualBonesDirty(void)
444        {
445                mManualBonesDirty = true;
446        }
447        //-----------------------------------------------------------------------
448        void Skeleton::_notifyManualBoneStateChange(Bone* bone)
449        {
450                if (bone->isManuallyControlled())
451                        mManualBones.insert(bone);
452                else
453                        mManualBones.erase(bone);
454        }
455    //-----------------------------------------------------------------------
456    unsigned short Skeleton::getNumBones(void) const
457    {
458        return (unsigned short)mBoneList.size();
459    }
460    //-----------------------------------------------------------------------
461    void Skeleton::_getBoneMatrices(Matrix4* pMatrices)
462    {
463        // Update derived transforms
464        _updateTransforms();
465
466        /*
467            Calculating the bone matrices
468            -----------------------------
469            Now that we have the derived scaling factors, orientations & positions in the
470            Bone nodes, we have to compute the Matrix4 to apply to the vertices of a mesh.
471            Because any modification of a vertex has to be relative to the bone, we must
472            first reverse transform by the Bone's original derived position/orientation/scale,
473            then transform by the new derived position/orientation/scale.
474            Also note we combine scale as equivalent axes, no shearing.
475        */
476
477        BoneList::const_iterator i, boneend;
478        boneend = mBoneList.end();
479        for (i = mBoneList.begin();i != boneend; ++i)
480        {
481            Bone* pBone = *i;
482            pBone->_getOffsetTransform(*pMatrices);
483            pMatrices++;
484        }
485
486    }
487    //---------------------------------------------------------------------
488    unsigned short Skeleton::getNumAnimations(void) const
489    {
490        return (unsigned short)mAnimationsList.size();
491    }
492    //---------------------------------------------------------------------
493    Animation* Skeleton::getAnimation(unsigned short index) const
494    {
495                // If you hit this assert, then the index is out of bounds.
496        assert( index < mAnimationsList.size() );
497
498        AnimationList::const_iterator i = mAnimationsList.begin();
499
500                std::advance(i, index);
501
502        return i->second;
503    }
504    //---------------------------------------------------------------------
505    Bone* Skeleton::getBone(unsigned short handle) const
506    {
507        assert(handle < mBoneList.size() && "Index out of bounds");
508        return mBoneList[handle];
509    }
510    //---------------------------------------------------------------------
511    Bone* Skeleton::getBone(const String& name) const
512    {
513        BoneListByName::const_iterator i = mBoneListByName.find(name);
514
515        if (i == mBoneListByName.end())
516        {
517            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Bone named '" + name + "' not found.", 
518                "Skeleton::getBone");
519        }
520
521        return i->second;
522
523    }
524    //---------------------------------------------------------------------
525    void Skeleton::deriveRootBone(void) const
526    {
527        // Start at the first bone and work up
528        if (mBoneList.empty())
529        {
530            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Cannot derive root bone as this "
531                "skeleton has no bones!", "Skeleton::deriveRootBone");
532        }
533
534        mRootBones.clear();
535
536        Bone* currentBone;
537        BoneList::const_iterator i;
538        BoneList::const_iterator iend = mBoneList.end();
539        for (i = mBoneList.begin(); i != iend; ++i)
540        {
541            currentBone = *i;
542            if (currentBone->getParent() == 0)
543            {
544                // This is a root
545                mRootBones.push_back(currentBone);
546            }
547        }
548    }
549    //---------------------------------------------------------------------
550    void Skeleton::_dumpContents(const String& filename)
551    {
552        std::ofstream of;
553
554        Quaternion q;
555        Radian angle;
556        Vector3 axis;
557        of.open(filename.c_str());
558
559        of << "-= Debug output of skeleton " << mName << " =-" << std::endl << std::endl;
560        of << "== Bones ==" << std::endl;
561        of << "Number of bones: " << (unsigned int)mBoneList.size() << std::endl;
562       
563        BoneList::iterator bi;
564        for (bi = mBoneList.begin(); bi != mBoneList.end(); ++bi)
565        {
566            Bone* bone = *bi;
567
568            of << "-- Bone " << bone->getHandle() << " --" << std::endl;
569            of << "Position: " << bone->getPosition();
570            q = bone->getOrientation();
571            of << "Rotation: " << q;
572            q.ToAngleAxis(angle, axis);
573            of << " = " << angle.valueRadians() << " radians around axis " << axis << std::endl << std::endl;
574        }
575
576        of << "== Animations ==" << std::endl;
577        of << "Number of animations: " << (unsigned int)mAnimationsList.size() << std::endl;
578
579        AnimationList::iterator ai;
580        for (ai = mAnimationsList.begin(); ai != mAnimationsList.end(); ++ai)
581        {
582            Animation* anim = ai->second;
583
584            of << "-- Animation '" << anim->getName() << "' (length " << anim->getLength() << ") --" << std::endl;
585            of << "Number of tracks: " << anim->getNumNodeTracks() << std::endl;
586
587            int ti;
588            for (ti = 0; ti < anim->getNumNodeTracks(); ++ti)
589            {
590                NodeAnimationTrack* track = anim->getNodeTrack(ti);
591                of << "  -- AnimationTrack " << ti << " --" << std::endl;
592                of << "  Affects bone: " << ((Bone*)track->getAssociatedNode())->getHandle() << std::endl;
593                of << "  Number of keyframes: " << track->getNumKeyFrames() << std::endl;
594
595                int ki;
596               
597                for (ki = 0; ki < track->getNumKeyFrames(); ++ki)
598                {
599                    TransformKeyFrame* key = track->getNodeKeyFrame(ki);
600                    of << "    -- KeyFrame " << ki << " --" << std::endl;
601                    of << "    Time index: " << key->getTime(); 
602                    of << "    Translation: " << key->getTranslate() << std::endl;
603                    q = key->getRotation();
604                    of << "    Rotation: " << q;
605                    q.ToAngleAxis(angle, axis);
606                    of << " = " << angle.valueRadians() << " radians around axis " << axis << std::endl;
607                }
608
609            }
610
611
612
613        }
614
615    }
616    //---------------------------------------------------------------------
617        SkeletonAnimationBlendMode Skeleton::getBlendMode() const
618    {
619                return mBlendState;
620        }
621    //---------------------------------------------------------------------
622        void Skeleton::setBlendMode(SkeletonAnimationBlendMode state) 
623    {
624                mBlendState = state;
625        }
626    //---------------------------------------------------------------------
627    Skeleton::BoneIterator Skeleton::getRootBoneIterator(void)
628    {
629        if (mRootBones.empty())
630        {
631            deriveRootBone();
632        }
633        return BoneIterator(mRootBones.begin(), mRootBones.end());
634    }
635    //---------------------------------------------------------------------
636    Skeleton::BoneIterator Skeleton::getBoneIterator(void)
637    {
638        return BoneIterator(mBoneList.begin(), mBoneList.end());
639    }
640    //---------------------------------------------------------------------
641    void Skeleton::_updateTransforms(void)
642    {
643        BoneList::iterator i, iend;
644        iend = mRootBones.end();
645        for (i = mRootBones.begin(); i != iend; ++i)
646        {
647            (*i)->_update(true, false);
648        }
649                mManualBonesDirty = false;
650    }
651    //---------------------------------------------------------------------
652        void Skeleton::optimiseAllAnimations(bool preservingIdentityNodeTracks)
653        {
654        AnimationList::iterator ai, aiend;
655        aiend = mAnimationsList.end();
656
657        if (!preservingIdentityNodeTracks)
658        {
659            Animation::TrackHandleList tracksToDestroy;
660
661            // Assume all node tracks are identity
662            ushort numBones = getNumBones();
663            for (ushort h = 0; h < numBones; ++h)
664            {
665                tracksToDestroy.insert(h);
666            }
667
668            // Collect identity node tracks for all animations
669            for (ai = mAnimationsList.begin(); ai != aiend; ++ai)
670            {
671                ai->second->_collectIdentityNodeTracks(tracksToDestroy);
672            }
673
674            // Destroy identity node tracks
675            for (ai = mAnimationsList.begin(); ai != aiend; ++ai)
676            {
677                ai->second->_destroyNodeTracks(tracksToDestroy);
678            }
679        }
680
681        for (ai = mAnimationsList.begin(); ai != aiend; ++ai)
682        {
683            // Don't discard identity node tracks here
684                        ai->second->optimise(false);
685                }
686        }
687        //---------------------------------------------------------------------
688        void Skeleton::addLinkedSkeletonAnimationSource(const String& skelName, 
689                Real scale)
690        {
691                // Check not already linked
692                LinkedSkeletonAnimSourceList::iterator i;
693                for (i = mLinkedSkeletonAnimSourceList.begin(); 
694                        i != mLinkedSkeletonAnimSourceList.end(); ++i)
695                {
696                        if (skelName == i->skeletonName)
697                                return; // don't bother
698                }
699
700                if (isLoaded())
701                {
702                        // Load immediately
703                        SkeletonPtr skelPtr = 
704                                SkeletonManager::getSingleton().load(skelName, mGroup);
705                        mLinkedSkeletonAnimSourceList.push_back(
706                                LinkedSkeletonAnimationSource(skelName, scale, skelPtr));
707
708                }
709                else
710                {
711                        // Load later
712                        mLinkedSkeletonAnimSourceList.push_back(
713                                LinkedSkeletonAnimationSource(skelName, scale));
714                }
715
716        }
717        //---------------------------------------------------------------------
718        void Skeleton::removeAllLinkedSkeletonAnimationSources(void)
719        {
720                mLinkedSkeletonAnimSourceList.clear();
721        }
722        //---------------------------------------------------------------------
723        Skeleton::LinkedSkeletonAnimSourceIterator
724        Skeleton::getLinkedSkeletonAnimationSourceIterator(void) const
725        {
726                return LinkedSkeletonAnimSourceIterator(
727                        mLinkedSkeletonAnimSourceList.begin(), 
728                        mLinkedSkeletonAnimSourceList.end());
729        }
730        //---------------------------------------------------------------------
731    struct DeltaTransform
732    {
733        Vector3 translate;
734        Quaternion rotate;
735        Vector3 scale;
736        bool isIdentity;
737    };
738    void Skeleton::_mergeSkeletonAnimations(const Skeleton* src,
739        const BoneHandleMap& boneHandleMap,
740        const StringVector& animations)
741    {
742        ushort handle;
743
744        ushort numSrcBones = src->getNumBones();
745        ushort numDstBones = this->getNumBones();
746
747        if (boneHandleMap.size() != numSrcBones)
748        {
749            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
750                "Number of bones in the bone handle map must equal to "
751                "number of bones in the source skeleton.",
752                "Skeleton::_mergeSkeletonAnimations");
753        }
754
755        bool existsMissingBone = false;
756
757        // Check source skeleton structures compatible with ourself (that means
758        // identically bones with identical handles, and with same hierarchy, but
759        // not necessary to have same number of bones and bone names).
760        for (handle = 0; handle < numSrcBones; ++handle)
761        {
762            const Bone* srcBone = src->getBone(handle);
763            ushort dstHandle = boneHandleMap[handle];
764
765            // Does it exists in target skeleton?
766            if (dstHandle < numDstBones)
767            {
768                Bone* destBone = this->getBone(dstHandle);
769
770                // Check both bones have identical parent, or both are root bone.
771                const Bone* srcParent = static_cast<Bone*>(srcBone->getParent());
772                Bone* destParent = static_cast<Bone*>(destBone->getParent());
773                if ((srcParent || destParent) &&
774                    (!srcParent || !destParent ||
775                     boneHandleMap[srcParent->getHandle()] != destParent->getHandle()))
776                {
777                    OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
778                        "Source skeleton incompatible with this skeleton: "
779                        "difference hierarchy between bone '" + srcBone->getName() +
780                        "' and '" + destBone->getName() + "'.",
781                        "Skeleton::_mergeSkeletonAnimations");
782                }
783            }
784            else
785            {
786                existsMissingBone = true;
787            }
788        }
789
790        // Clone bones if need
791        if (existsMissingBone)
792        {
793            // Create missing bones
794            for (handle = 0; handle < numSrcBones; ++handle)
795            {
796                const Bone* srcBone = src->getBone(handle);
797                ushort dstHandle = boneHandleMap[handle];
798
799                // The bone is missing in target skeleton?
800                if (dstHandle >= numDstBones)
801                {
802                    Bone* dstBone = this->createBone(srcBone->getName(), dstHandle);
803                    // Sets initial transform
804                    dstBone->setPosition(srcBone->getInitialPosition());
805                    dstBone->setOrientation(srcBone->getInitialOrientation());
806                    dstBone->setScale(srcBone->getInitialScale());
807                    dstBone->setInitialState();
808                }
809            }
810
811            // Link new bones to parent
812            for (handle = 0; handle < numSrcBones; ++handle)
813            {
814                const Bone* srcBone = src->getBone(handle);
815                ushort dstHandle = boneHandleMap[handle];
816
817                // Is new bone?
818                if (dstHandle >= numDstBones)
819                {
820                    const Bone* srcParent = static_cast<Bone*>(srcBone->getParent());
821                    if (srcParent)
822                    {
823                        Bone* destParent = this->getBone(boneHandleMap[srcParent->getHandle()]);
824                        Bone* dstBone = this->getBone(dstHandle);
825                        destParent->addChild(dstBone);
826                    }
827                }
828            }
829
830            // Derive root bones in case it was changed
831            this->deriveRootBone();
832
833            // Reset binding pose for new bones
834            this->reset(true);
835            this->setBindingPose();
836        }
837
838        //
839        // We need to adapt animations from source to target skeleton, but since source
840        // and target skeleton bones bind transform might difference, so we need to alter
841        // keyframes in source to suit to target skeleton.
842        //
843        // For any given animation time, formula:
844        //
845        //      LocalTransform = BindTransform * KeyFrame;
846        //      DerivedTransform = ParentDerivedTransform * LocalTransform
847        //
848        // And all derived transforms should be keep identically after adapt to
849        // target skeleton, Then:
850        //
851        //      DestDerivedTransform == SrcDerivedTransform
852        //      DestParentDerivedTransform == SrcParentDerivedTransform
853        // ==>
854        //      DestLocalTransform = SrcLocalTransform
855        // ==>
856        //      DestBindTransform * DestKeyFrame = SrcBindTransform * SrcKeyFrame
857        // ==>
858        //      DestKeyFrame = inverse(DestBindTransform) * SrcBindTransform * SrcKeyFrame
859        //
860        // We define (inverse(DestBindTransform) * SrcBindTransform) as 'delta-transform' here.
861        //
862
863        // Calculate delta-transforms for all source bones.
864        std::vector<DeltaTransform> deltaTransforms(numSrcBones);
865        for (handle = 0; handle < numSrcBones; ++handle)
866        {
867            const Bone* srcBone = src->getBone(handle);
868            DeltaTransform& deltaTransform = deltaTransforms[handle];
869            ushort dstHandle = boneHandleMap[handle];
870
871            if (dstHandle < numDstBones)
872            {
873                // Common bone, calculate delta-transform
874
875                Bone* dstBone = this->getBone(dstHandle);
876
877                deltaTransform.translate = srcBone->getInitialPosition() - dstBone->getInitialPosition();
878                deltaTransform.rotate = dstBone->getInitialOrientation().Inverse() * srcBone->getInitialOrientation();
879                deltaTransform.scale = srcBone->getInitialScale() / dstBone->getInitialScale();
880
881                // Check whether or not delta-transform is identity
882                const Real tolerance = 1e-3f;
883                Vector3 axis;
884                Radian angle;
885                deltaTransform.rotate.ToAngleAxis(angle, axis);
886                deltaTransform.isIdentity =
887                    deltaTransform.translate.positionEquals(Vector3::ZERO, tolerance) &&
888                    deltaTransform.scale.positionEquals(Vector3::UNIT_SCALE, tolerance) &&
889                    Math::RealEqual(angle.valueRadians(), 0.0f, tolerance);
890            }
891            else
892            {
893                // New bone, the delta-transform is identity
894
895                deltaTransform.translate = Vector3::ZERO;
896                deltaTransform.rotate = Quaternion::IDENTITY;
897                deltaTransform.scale = Vector3::UNIT_SCALE;
898                deltaTransform.isIdentity = true;
899            }
900        }
901
902        // Now copy animations
903
904        ushort numAnimations;
905        if (animations.empty())
906            numAnimations = src->getNumAnimations();
907        else
908            numAnimations = static_cast<ushort>(animations.size());
909        for (ushort i = 0; i < numAnimations; ++i)
910        {
911            const Animation* srcAnimation;
912            if (animations.empty())
913            {
914                // Get animation of source skeleton by the given index
915                srcAnimation = src->getAnimation(i);
916            }
917            else
918            {
919                // Get animation of source skeleton by the given name
920                const LinkedSkeletonAnimationSource* linker;
921                srcAnimation = src->_getAnimationImpl(animations[i], &linker);
922                if (!srcAnimation || linker)
923                {
924                    OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
925                        "No animation entry found named " + animations[i],
926                        "Skeleton::_mergeSkeletonAnimations");
927                }
928            }
929
930            // Create target animation
931            Animation* dstAnimation = this->createAnimation(srcAnimation->getName(), srcAnimation->getLength());
932
933            // Copy interpolation modes
934            dstAnimation->setInterpolationMode(srcAnimation->getInterpolationMode());
935            dstAnimation->setRotationInterpolationMode(srcAnimation->getRotationInterpolationMode());
936
937            // Copy track for each bone
938            for (handle = 0; handle < numSrcBones; ++handle)
939            {
940                const DeltaTransform& deltaTransform = deltaTransforms[handle];
941                ushort dstHandle = boneHandleMap[handle];
942
943                if (srcAnimation->hasNodeTrack(handle))
944                {
945                    // Clone track from source animation
946
947                    const NodeAnimationTrack* srcTrack = srcAnimation->getNodeTrack(handle);
948                    NodeAnimationTrack* dstTrack = dstAnimation->createNodeTrack(dstHandle, this->getBone(dstHandle));
949                    dstTrack->setUseShortestRotationPath(srcTrack->getUseShortestRotationPath());
950
951                    ushort numKeyFrames = srcTrack->getNumKeyFrames();
952                    for (ushort k = 0; k < numKeyFrames; ++k)
953                    {
954                        const TransformKeyFrame* srcKeyFrame = srcTrack->getNodeKeyFrame(k);
955                        TransformKeyFrame* dstKeyFrame = dstTrack->createNodeKeyFrame(srcKeyFrame->getTime());
956
957                        // Adjust keyframes to match target binding pose
958                        if (deltaTransform.isIdentity)
959                        {
960                            dstKeyFrame->setTranslate(srcKeyFrame->getTranslate());
961                            dstKeyFrame->setRotation(srcKeyFrame->getRotation());
962                            dstKeyFrame->setScale(srcKeyFrame->getScale());
963                        }
964                        else
965                        {
966                            dstKeyFrame->setTranslate(deltaTransform.translate + srcKeyFrame->getTranslate());
967                            dstKeyFrame->setRotation(deltaTransform.rotate * srcKeyFrame->getRotation());
968                            dstKeyFrame->setScale(deltaTransform.scale * srcKeyFrame->getScale());
969                        }
970                    }
971                }
972                else if (!deltaTransform.isIdentity)
973                {
974                    // Create 'static' track for this bone
975
976                    NodeAnimationTrack* dstTrack = dstAnimation->createNodeTrack(dstHandle, this->getBone(dstHandle));
977                    TransformKeyFrame* dstKeyFrame;
978
979                    dstKeyFrame = dstTrack->createNodeKeyFrame(0);
980                    dstKeyFrame->setTranslate(deltaTransform.translate);
981                    dstKeyFrame->setRotation(deltaTransform.rotate);
982                    dstKeyFrame->setScale(deltaTransform.scale);
983
984                    dstKeyFrame = dstTrack->createNodeKeyFrame(dstAnimation->getLength());
985                    dstKeyFrame->setTranslate(deltaTransform.translate);
986                    dstKeyFrame->setRotation(deltaTransform.rotate);
987                    dstKeyFrame->setScale(deltaTransform.scale);
988                }
989            }
990        }
991    }
992    //---------------------------------------------------------------------
993    void Skeleton::_buildMapBoneByHandle(const Skeleton* src,
994        BoneHandleMap& boneHandleMap) const
995    {
996        ushort numSrcBones = src->getNumBones();
997        boneHandleMap.resize(numSrcBones);
998
999        for (ushort handle = 0; handle < numSrcBones; ++handle)
1000        {
1001            boneHandleMap[handle] = handle;
1002        }
1003    }
1004    //---------------------------------------------------------------------
1005    void Skeleton::_buildMapBoneByName(const Skeleton* src,
1006        BoneHandleMap& boneHandleMap) const
1007    {
1008        ushort numSrcBones = src->getNumBones();
1009        boneHandleMap.resize(numSrcBones);
1010
1011        ushort newBoneHandle = this->getNumBones();
1012        for (ushort handle = 0; handle < numSrcBones; ++handle)
1013        {
1014            const Bone* srcBone = src->getBone(handle);
1015            BoneListByName::const_iterator i = this->mBoneListByName.find(srcBone->getName());
1016            if (i == mBoneListByName.end())
1017                boneHandleMap[handle] = newBoneHandle++;
1018            else
1019                boneHandleMap[handle] = i->second->getHandle();
1020        }
1021    }
1022
1023}
1024
Note: See TracBrowser for help on using the repository browser.