source: OGRE/trunk/ogrenew/OgreMain/src/OgreSkeleton.cpp @ 657

Revision 657, 22.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 "OgreStableHeaders.h"
26#include "OgreSkeleton.h"
27#include "OgreBone.h"
28#include "OgreAnimation.h"
29#include "OgreAnimationState.h"
30#include "OgreException.h"
31#include "OgreLogManager.h"
32#include "OgreSkeletonManager.h"
33#include "OgreSkeletonSerializer.h"
34#include "OgreStringConverter.h"
35// Just for logging
36#include "OgreAnimationTrack.h"
37#include "OgreKeyFrame.h"
38
39
40namespace Ogre {
41
42    //---------------------------------------------------------------------
43        Skeleton::Skeleton()
44                : Resource(),
45        mBlendState(ANIMBLEND_AVERAGE),
46                mNextAutoHandle(0)
47        {
48        }
49        //---------------------------------------------------------------------
50    Skeleton::Skeleton(ResourceManager* creator, const String& name, ResourceHandle handle,
51        const String& group, bool isManual, ManualResourceLoader* loader)
52        : Resource(creator, name, handle, group, isManual, loader),
53        mBlendState(ANIMBLEND_AVERAGE), mNextAutoHandle(0)
54        // set animation blending to weighted, not cumulative
55    {
56        if (createParamDictionary("Skeleton"))
57        {
58            // no custom params
59        }
60    }
61    //---------------------------------------------------------------------
62    Skeleton::~Skeleton()
63    {
64        // have to call this here reather than in Resource destructor
65        // since calling virtual methods in base destructors causes crash
66        unload();
67    }
68    //---------------------------------------------------------------------
69    void Skeleton::loadImpl(void)
70    {
71        SkeletonSerializer serializer;
72                StringUtil::StrStreamType msg;
73                msg << "Skeleton: Loading " << mName;
74        LogManager::getSingleton().logMessage(msg.str());
75
76        DataStreamPtr stream =
77            ResourceGroupManager::getSingleton().openResource(mName, mGroup);
78
79        serializer.importSkeleton(stream, this);
80
81                // Load any linked skeletons
82                LinkedSkeletonAnimSourceList::iterator i;
83                for (i = mLinkedSkeletonAnimSourceList.begin();
84                        i != mLinkedSkeletonAnimSourceList.end(); ++i)
85                {
86                        i->pSkeleton = SkeletonManager::getSingleton().load(
87                                i->skeletonName, mGroup);
88                }
89
90
91    }
92    //---------------------------------------------------------------------
93    void Skeleton::unloadImpl(void)
94    {
95        // destroy bones
96        BoneList::iterator i;
97        for (i = mBoneList.begin(); i != mBoneList.end(); ++i)
98        {
99            delete *i;
100        }
101        mBoneList.clear();
102        mBoneListByName.clear();
103                mRootBones.clear();
104
105
106        // Destroy animations
107        AnimationList::iterator ai;
108        for (ai = mAnimationsList.begin(); ai != mAnimationsList.end(); ++ai)
109        {
110            delete ai->second;
111        }
112        mAnimationsList.clear();
113
114                LinkedSkeletonAnimSourceList::iterator li;
115                for (li = mLinkedSkeletonAnimSourceList.begin();
116                        li != mLinkedSkeletonAnimSourceList.end(); ++li)
117                {
118                        li->pSkeleton.setNull();
119                }
120    }
121    //---------------------------------------------------------------------
122    Bone* Skeleton::createBone(void)
123    {
124        // use autohandle
125        return createBone(mNextAutoHandle++);
126    }
127    //---------------------------------------------------------------------
128    Bone* Skeleton::createBone(const String& name)
129    {
130        return createBone(name, mNextAutoHandle++);
131    }
132    //---------------------------------------------------------------------
133    Bone* Skeleton::createBone(unsigned short handle)
134    {
135        if (handle >= OGRE_MAX_NUM_BONES)
136        {
137            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Exceeded the maximum number of bones per skeleton.",
138                "Skeleton::createBone");
139        }
140        // Check handle not used
141        if (handle < mBoneList.size() && mBoneList[handle] != NULL)
142        {
143            OGRE_EXCEPT(
144                Exception::ERR_DUPLICATE_ITEM,
145                "A bone with the handle " + StringConverter::toString(handle) + " already exists",
146                "Skeleton::createBone" );
147        }
148        Bone* ret = new Bone(handle, this);
149        assert(mBoneListByName.find(ret->getName()) == mBoneListByName.end());
150        if (mBoneList.size() <= handle)
151        {
152            mBoneList.resize(handle+1);
153        }
154        mBoneList[handle] = ret;
155        mBoneListByName[ret->getName()] = ret;
156        return ret;
157
158    }
159    //---------------------------------------------------------------------
160    Bone* Skeleton::createBone(const String& name, unsigned short handle)
161    {
162        if (handle >= OGRE_MAX_NUM_BONES)
163        {
164            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Exceeded the maximum number of bones per skeleton.",
165                "Skeleton::createBone");
166        }
167        // Check handle not used
168        if (handle < mBoneList.size() && mBoneList[handle] != NULL)
169        {
170            OGRE_EXCEPT(
171                Exception::ERR_DUPLICATE_ITEM,
172                "A bone with the handle " + StringConverter::toString(handle) + " already exists",
173                "Skeleton::createBone" );
174        }
175        // Check name not used
176        if (mBoneListByName.find(name) != mBoneListByName.end())
177        {
178            OGRE_EXCEPT(
179                Exception::ERR_DUPLICATE_ITEM,
180                "A bone with the name " + name + " already exists",
181                "Skeleton::createBone" );
182        }
183        Bone* ret = new Bone(name, handle, this);
184        if (mBoneList.size() <= handle)
185        {
186            mBoneList.resize(handle+1);
187        }
188        mBoneList[handle] = ret;
189        mBoneListByName[name] = ret;
190        return ret;
191    }
192
193
194
195    //---------------------------------------------------------------------
196    Bone* Skeleton::getRootBone(void) const
197    {
198        if (mRootBones.empty())
199        {
200            deriveRootBone();
201        }
202
203        return mRootBones[0];
204    }
205    //---------------------------------------------------------------------
206    void Skeleton::setAnimationState(const AnimationStateSet& animSet)
207    {
208        /*
209        Algorithm:
210          1. Check if animation state is any different from last, if not do nothing
211          2. Reset all bone positions
212          3. Iterate per AnimationState, if enabled get Animation and call Animation::apply
213        */
214
215        if (mLastAnimationState.size() == animSet.size())
216        {
217            // Same size, may be able to skip update
218            bool different = false;
219            AnimationStateSet::iterator i;
220            AnimationStateSet::const_iterator j;
221            i = mLastAnimationState.begin();
222            j = animSet.begin();
223            for (; i != mLastAnimationState.end(); ++i, ++j)
224            {
225                if (i->second != j->second)
226                {
227                    different = true;
228                    break;
229                }
230            }
231            // Check any differences?
232            if (!different)
233            {
234                // No, no need to update
235                return;
236            }
237        }
238
239        // Ok, we've established the animation state is different
240
241        // Reset bones
242        reset();
243
244        // Per animation state
245        AnimationStateSet::const_iterator istate;
246        for (istate = animSet.begin(); istate != animSet.end(); ++istate)
247        {
248            // Apply if enabled
249            const AnimationState& animState = istate->second;
250            if (animState.getEnabled())
251            {
252                                const LinkedSkeletonAnimationSource* linked = 0;
253                                Animation* anim = getAnimation(animState.getAnimationName(), &linked);
254                                if (linked)
255                                {
256                                        anim->apply(this, animState.getTimePosition(), animState.getWeight(),
257                                                mBlendState == ANIMBLEND_CUMULATIVE, linked->scale);
258                                }
259                                else
260                                {
261                                        anim->apply(this, animState.getTimePosition(), animState.getWeight(),
262                                                mBlendState == ANIMBLEND_CUMULATIVE);
263                                }
264            }
265        }
266
267        mLastAnimationState = animSet;
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        // Also add to state
312        mLastAnimationState[name] = AnimationState(name, 0, length);
313
314        return ret;
315
316    }
317    //---------------------------------------------------------------------
318    Animation* Skeleton::getAnimation(const String& name,
319                const LinkedSkeletonAnimationSource** linker) const
320    {
321        AnimationList::const_iterator i = mAnimationsList.find(name);
322
323        if (i == mAnimationsList.end())
324        {
325                        LinkedSkeletonAnimSourceList::const_iterator i;
326                        for (i = mLinkedSkeletonAnimSourceList.begin();
327                                i != mLinkedSkeletonAnimSourceList.end(); ++i)
328                        {
329                                try
330                                {
331                                        if (!i->pSkeleton.isNull())
332                                        {
333                                                if (linker)
334                                                {
335                                                        *linker = &(*i);
336                                                }
337
338                                                return i->pSkeleton->getAnimation(name);
339                                        }
340                                }
341                                catch(Exception&)
342                                {
343                                        // Ignore, keep looking - if we run out, we'll except below
344                                }
345                        }
346
347            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "No animation entry found named " + name,
348            "Skeleton::getAnimation");
349        }
350                else
351                {
352                        if (linker)
353                                *linker = 0;
354                        return i->second;
355                }
356
357    }
358    //---------------------------------------------------------------------
359    void Skeleton::removeAnimation(const String& name)
360    {
361        AnimationList::iterator i = mAnimationsList.find(name);
362
363        if (i == mAnimationsList.end())
364        {
365            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "No animation entry found named " + name,
366            "Skeleton::getAnimation");
367        }
368
369        delete i->second;
370
371        mAnimationsList.erase(i);
372
373    }
374    //---------------------------------------------------------------------
375    const AnimationStateSet& Skeleton::getAnimationState(void) const
376    {
377        return mLastAnimationState;
378    }
379    //-----------------------------------------------------------------------
380    void Skeleton::_initAnimationState(AnimationStateSet* animSet)
381    {
382        animSet->clear();
383           
384        AnimationList::iterator i;
385        for (i = mAnimationsList.begin(); i != mAnimationsList.end(); ++i)
386        {
387            Animation* anim = i->second;
388            // Create animation at time index 0, default params mean this has weight 1 and is disabled
389            String animName = anim->getName();
390            (*animSet)[animName] = AnimationState(animName, 0.0, anim->getLength());
391        }
392
393                // Also iterate over linked animation
394                LinkedSkeletonAnimSourceList::iterator li;
395                for (li = mLinkedSkeletonAnimSourceList.begin();
396                        li != mLinkedSkeletonAnimSourceList.end(); ++li)
397                {
398                        if (!li->pSkeleton.isNull())
399                        {
400                                li->pSkeleton->_refreshAnimationState(animSet);
401                        }
402                }
403
404    }
405        //-----------------------------------------------------------------------
406        void Skeleton::_refreshAnimationState(AnimationStateSet* animSet)
407        {
408                // Merge in any new animations
409                AnimationList::iterator i;
410                for (i = mAnimationsList.begin(); i != mAnimationsList.end(); ++i)
411                {
412                        Animation* anim = i->second;
413                        // Create animation at time index 0, default params mean this has weight 1 and is disabled
414                        String animName = anim->getName();
415                        if (animSet->find(animName) == animSet->end())
416                        {
417                                (*animSet)[animName] = AnimationState(animName, 0.0, anim->getLength());
418                        }
419                }
420                // Also iterate over linked animation
421                LinkedSkeletonAnimSourceList::iterator li;
422                for (li = mLinkedSkeletonAnimSourceList.begin();
423                        li != mLinkedSkeletonAnimSourceList.end(); ++li)
424                {
425                        if (!li->pSkeleton.isNull())
426                        {
427                                li->pSkeleton->_refreshAnimationState(animSet);
428                        }
429                }
430        }
431    //-----------------------------------------------------------------------
432    unsigned short Skeleton::getNumBones(void) const
433    {
434        return (unsigned short)mBoneList.size();
435    }
436    //-----------------------------------------------------------------------
437    void Skeleton::_getBoneMatrices(Matrix4* pMatrices)
438    {
439        // Update derived transforms
440        _updateTransforms();
441
442        /*
443            Calculating the bone matrices
444            -----------------------------
445            Now that we have the derived orientations & positions in the Bone nodes, we have
446            to compute the Matrix4 to apply to the vertices of a mesh.
447            Because any modification of a vertex has to be relative to the bone, we must first
448            reverse transform by the Bone's original derived position/orientation, then transform
449            by the new derived position / orientation.
450        */
451
452        BoneList::iterator i, boneend;
453        boneend = mBoneList.end();
454       
455       
456        for(i = mBoneList.begin();i != boneend; ++i)
457        {
458            Bone* pBone = *i;
459            *pMatrices = pBone->_getFullTransform() *  pBone->_getBindingPoseInverseTransform();
460            pMatrices++;
461        }
462
463    }
464    //---------------------------------------------------------------------
465    unsigned short Skeleton::getNumAnimations(void) const
466    {
467        return (unsigned short)mAnimationsList.size();
468    }
469    //---------------------------------------------------------------------
470    Animation* Skeleton::getAnimation(unsigned short index) const
471    {
472                // If you hit this assert, then the index is out of bounds.
473        assert( index < mAnimationsList.size() );
474
475        AnimationList::const_iterator i = mAnimationsList.begin();
476
477                std::advance(i, index);
478
479        return i->second;
480    }
481    //---------------------------------------------------------------------
482    Bone* Skeleton::getBone(unsigned short handle) const
483    {
484        assert(handle < mBoneList.size() && "Index out of bounds");
485        return mBoneList[handle];
486    }
487    //---------------------------------------------------------------------
488    Bone* Skeleton::getBone(const String& name) const
489    {
490        BoneListByName::const_iterator i = mBoneListByName.find(name);
491
492        if (i == mBoneListByName.end())
493        {
494            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Bone named '" + name + "' not found.",
495                "Skeleton::getBone");
496        }
497
498        return i->second;
499
500    }
501    //---------------------------------------------------------------------
502    void Skeleton::deriveRootBone(void) const
503    {
504        // Start at the first bone and work up
505        if (mBoneList.empty())
506        {
507            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Cannot derive root bone as this "
508                "skeleton has no bones!", "Skeleton::deriveRootBone");
509        }
510
511        mRootBones.clear();
512
513        Bone* currentBone;
514        BoneList::const_iterator i;
515        BoneList::const_iterator iend = mBoneList.end();
516        for (i = mBoneList.begin(); i != iend; ++i)
517        {
518            currentBone = *i;
519            if (currentBone->getParent() == 0)
520            {
521                // This is a root
522                mRootBones.push_back(currentBone);
523            }
524        }
525    }
526    //---------------------------------------------------------------------
527    void Skeleton::_dumpContents(const String& filename)
528    {
529        std::ofstream of;
530
531        Quaternion q;
532        Radian angle;
533        Vector3 axis;
534        of.open(filename.c_str());
535
536        of << "-= Debug output of skeleton " << mName << " =-" << std::endl << std::endl;
537        of << "== Bones ==" << std::endl;
538        of << "Number of bones: " << (unsigned int)mBoneList.size() << std::endl;
539       
540        BoneList::iterator bi;
541        for (bi = mBoneList.begin(); bi != mBoneList.end(); ++bi)
542        {
543            Bone* bone = *bi;
544
545            of << "-- Bone " << bone->getHandle() << " --" << std::endl;
546            of << "Position: " << bone->getPosition();
547            q = bone->getOrientation();
548            of << "Rotation: " << q;
549            q.ToAngleAxis(angle, axis);
550            of << " = " << angle.valueRadians() << " radians around axis " << axis << std::endl << std::endl;
551        }
552
553        of << "== Animations ==" << std::endl;
554        of << "Number of animations: " << (unsigned int)mAnimationsList.size() << std::endl;
555
556        AnimationList::iterator ai;
557        for (ai = mAnimationsList.begin(); ai != mAnimationsList.end(); ++ai)
558        {
559            Animation* anim = ai->second;
560
561            of << "-- Animation '" << anim->getName() << "' (length " << anim->getLength() << ") --" << std::endl;
562            of << "Number of tracks: " << anim->getNumTracks() << std::endl;
563
564            int ti;
565            for (ti = 0; ti < anim->getNumTracks(); ++ti)
566            {
567                AnimationTrack* track = anim->getTrack(ti);
568                of << "  -- AnimationTrack " << ti << " --" << std::endl;
569                of << "  Affects bone: " << ((Bone*)track->getAssociatedNode())->getHandle() << std::endl;
570                of << "  Number of keyframes: " << track->getNumKeyFrames() << std::endl;
571
572                int ki;
573               
574                for (ki = 0; ki < track->getNumKeyFrames(); ++ki)
575                {
576                    KeyFrame* key = track->getKeyFrame(ki);
577                    of << "    -- KeyFrame " << ki << " --" << std::endl;
578                    of << "    Time index: " << key->getTime();
579                    of << "    Translation: " << key->getTranslate() << std::endl;
580                    q = key->getRotation();
581                    of << "    Rotation: " << q;
582                    q.ToAngleAxis(angle, axis);
583                    of << " = " << angle.valueRadians() << " radians around axis " << axis << std::endl;
584                }
585
586            }
587
588
589
590        }
591
592    }
593    //---------------------------------------------------------------------
594        SkeletonAnimationBlendMode Skeleton::getBlendMode()
595    {
596                return mBlendState;
597        }
598    //---------------------------------------------------------------------
599        void Skeleton::setBlendMode(SkeletonAnimationBlendMode state)
600    {
601                mBlendState = state;
602        }
603    //---------------------------------------------------------------------
604    Skeleton::BoneIterator Skeleton::getRootBoneIterator(void)
605    {
606        if (mRootBones.empty())
607        {
608            deriveRootBone();
609        }
610        return BoneIterator(mRootBones.begin(), mRootBones.end());
611    }
612    //---------------------------------------------------------------------
613    Skeleton::BoneIterator Skeleton::getBoneIterator(void)
614    {
615        return BoneIterator(mBoneList.begin(), mBoneList.end());
616    }
617    //---------------------------------------------------------------------
618    void Skeleton::_updateTransforms(void)
619    {
620        BoneList::iterator i, iend;
621        iend = mRootBones.end();
622        for (i = mRootBones.begin(); i != iend; ++i)
623        {
624            (*i)->_update(true, false);
625        }
626    }
627    //---------------------------------------------------------------------
628        void Skeleton::optimiseAllAnimations(void)
629        {
630        AnimationList::iterator ai;
631        for (ai = mAnimationsList.begin(); ai != mAnimationsList.end(); ++ai)
632        {
633                        ai->second->optimise();
634                }
635        }
636        //---------------------------------------------------------------------
637        void Skeleton::addLinkedSkeletonAnimationSource(const String& skelName,
638                Real scale)
639        {
640                // Check not already linked
641                LinkedSkeletonAnimSourceList::iterator i;
642                for (i = mLinkedSkeletonAnimSourceList.begin();
643                        i != mLinkedSkeletonAnimSourceList.end(); ++i)
644                {
645                        if (skelName == i->skeletonName)
646                                return; // don't bother
647                }
648
649                if (mIsLoaded)
650                {
651                        // Load immediately
652                        SkeletonPtr skelPtr =
653                                SkeletonManager::getSingleton().load(skelName, mGroup);
654                        mLinkedSkeletonAnimSourceList.push_back(
655                                LinkedSkeletonAnimationSource(skelName, scale, skelPtr));
656
657                }
658                else
659                {
660                        // Load later
661                        mLinkedSkeletonAnimSourceList.push_back(
662                                LinkedSkeletonAnimationSource(skelName, scale));
663                }
664
665        }
666        //---------------------------------------------------------------------
667        void Skeleton::removeAllLinkedSkeletonAnimationSources(void)
668        {
669                mLinkedSkeletonAnimSourceList.clear();
670        }
671        //---------------------------------------------------------------------
672        Skeleton::LinkedSkeletonAnimSourceIterator
673        Skeleton::getLinkedSkeletonAnimationSourceIterator(void) const
674        {
675                return LinkedSkeletonAnimSourceIterator(
676                        mLinkedSkeletonAnimSourceList.begin(),
677                        mLinkedSkeletonAnimSourceList.end());
678        }
679        //---------------------------------------------------------------------
680
681}
682
Note: See TracBrowser for help on using the repository browser.