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

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

adding ogre 1.2 and dependencies

Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25#include "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                mManualBonesDirty(false)
48        {
49        }
50        //---------------------------------------------------------------------
51    Skeleton::Skeleton(ResourceManager* creator, const String& name, ResourceHandle handle,
52        const String& group, bool isManual, ManualResourceLoader* loader)
53        : Resource(creator, name, handle, group, isManual, loader),
54        mBlendState(ANIMBLEND_AVERAGE), mNextAutoHandle(0)
55        // set animation blending to weighted, not cumulative
56    {
57        if (createParamDictionary("Skeleton"))
58        {
59            // no custom params
60        }
61    }
62    //---------------------------------------------------------------------
63    Skeleton::~Skeleton()
64    {
65        // have to call this here reather than in Resource destructor
66        // since calling virtual methods in base destructors causes crash
67        unload();
68    }
69    //---------------------------------------------------------------------
70    void Skeleton::loadImpl(void)
71    {
72        SkeletonSerializer serializer;
73                StringUtil::StrStreamType msg;
74                msg << "Skeleton: Loading " << mName;
75        LogManager::getSingleton().logMessage(msg.str());
76
77        DataStreamPtr stream =
78            ResourceGroupManager::getSingleton().openResource(
79                                mName, mGroup, true, this);
80
81        serializer.importSkeleton(stream, this);
82
83                // Load any linked skeletons
84                LinkedSkeletonAnimSourceList::iterator i;
85                for (i = mLinkedSkeletonAnimSourceList.begin();
86                        i != mLinkedSkeletonAnimSourceList.end(); ++i)
87                {
88                        i->pSkeleton = SkeletonManager::getSingleton().load(
89                                i->skeletonName, mGroup);
90                }
91
92
93    }
94    //---------------------------------------------------------------------
95    void Skeleton::unloadImpl(void)
96    {
97        // destroy bones
98        BoneList::iterator i;
99        for (i = mBoneList.begin(); i != mBoneList.end(); ++i)
100        {
101            delete *i;
102        }
103        mBoneList.clear();
104        mBoneListByName.clear();
105                mRootBones.clear();
106
107
108        // Destroy animations
109        AnimationList::iterator ai;
110        for (ai = mAnimationsList.begin(); ai != mAnimationsList.end(); ++ai)
111        {
112            delete ai->second;
113        }
114        mAnimationsList.clear();
115
116                LinkedSkeletonAnimSourceList::iterator li;
117                for (li = mLinkedSkeletonAnimSourceList.begin();
118                        li != mLinkedSkeletonAnimSourceList.end(); ++li)
119                {
120                        li->pSkeleton.setNull();
121                }
122    }
123    //---------------------------------------------------------------------
124    Bone* Skeleton::createBone(void)
125    {
126        // use autohandle
127        return createBone(mNextAutoHandle++);
128    }
129    //---------------------------------------------------------------------
130    Bone* Skeleton::createBone(const String& name)
131    {
132        return createBone(name, mNextAutoHandle++);
133    }
134    //---------------------------------------------------------------------
135    Bone* Skeleton::createBone(unsigned short handle)
136    {
137        if (handle >= OGRE_MAX_NUM_BONES)
138        {
139            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Exceeded the maximum number of bones per skeleton.",
140                "Skeleton::createBone");
141        }
142        // Check handle not used
143        if (handle < mBoneList.size() && mBoneList[handle] != NULL)
144        {
145            OGRE_EXCEPT(
146                Exception::ERR_DUPLICATE_ITEM,
147                "A bone with the handle " + StringConverter::toString(handle) + " already exists",
148                "Skeleton::createBone" );
149        }
150        Bone* ret = new Bone(handle, this);
151        assert(mBoneListByName.find(ret->getName()) == mBoneListByName.end());
152        if (mBoneList.size() <= handle)
153        {
154            mBoneList.resize(handle+1);
155        }
156        mBoneList[handle] = ret;
157        mBoneListByName[ret->getName()] = ret;
158        return ret;
159
160    }
161    //---------------------------------------------------------------------
162    Bone* Skeleton::createBone(const String& name, unsigned short handle)
163    {
164        if (handle >= OGRE_MAX_NUM_BONES)
165        {
166            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Exceeded the maximum number of bones per skeleton.",
167                "Skeleton::createBone");
168        }
169        // Check handle not used
170        if (handle < mBoneList.size() && mBoneList[handle] != NULL)
171        {
172            OGRE_EXCEPT(
173                Exception::ERR_DUPLICATE_ITEM,
174                "A bone with the handle " + StringConverter::toString(handle) + " already exists",
175                "Skeleton::createBone" );
176        }
177        // Check name not used
178        if (mBoneListByName.find(name) != mBoneListByName.end())
179        {
180            OGRE_EXCEPT(
181                Exception::ERR_DUPLICATE_ITEM,
182                "A bone with the name " + name + " already exists",
183                "Skeleton::createBone" );
184        }
185        Bone* ret = new Bone(name, handle, this);
186        if (mBoneList.size() <= handle)
187        {
188            mBoneList.resize(handle+1);
189        }
190        mBoneList[handle] = ret;
191        mBoneListByName[name] = ret;
192        return ret;
193    }
194
195
196
197    //---------------------------------------------------------------------
198    Bone* Skeleton::getRootBone(void) const
199    {
200        if (mRootBones.empty())
201        {
202            deriveRootBone();
203        }
204
205        return mRootBones[0];
206    }
207    //---------------------------------------------------------------------
208    void Skeleton::setAnimationState(const AnimationStateSet& animSet)
209    {
210        /*
211        Algorithm:
212          1. Reset all bone positions
213          2. Iterate per AnimationState, if enabled get Animation and call Animation::apply
214        */
215
216        // Reset bones
217        reset();
218
219        // Per enabled animation state
220        ConstEnabledAnimationStateIterator stateIt =
221            animSet.getEnabledAnimationStateIterator();
222        while (stateIt.hasMoreElements())
223        {
224            const AnimationState* animState = stateIt.getNext();
225            const LinkedSkeletonAnimationSource* linked = 0;
226            Animation* anim = getAnimation(animState->getAnimationName(), &linked);
227            // tolerate state entries for animations we're not aware of
228            if (anim)
229            {
230                if (linked)
231                {
232                    anim->apply(this, animState->getTimePosition(), animState->getWeight(),
233                        mBlendState == ANIMBLEND_CUMULATIVE, linked->scale);
234                }
235                else
236                {
237                    anim->apply(this, animState->getTimePosition(), animState->getWeight(),
238                        mBlendState == ANIMBLEND_CUMULATIVE);
239                }
240            }
241        }
242
243
244    }
245    //---------------------------------------------------------------------
246    void Skeleton::setBindingPose(void)
247    {
248        // Update the derived transforms
249        _updateTransforms();
250
251
252        BoneList::iterator i;
253        for (i = mBoneList.begin(); i != mBoneList.end(); ++i)
254        {           
255            (*i)->setBindingPose();
256        }
257    }
258    //---------------------------------------------------------------------
259    void Skeleton::reset(bool resetManualBones)
260    {
261        BoneList::iterator i;
262        for (i = mBoneList.begin(); i != mBoneList.end(); ++i)
263        {
264            if(!(*i)->isManuallyControlled() || resetManualBones)
265                (*i)->reset();
266        }
267    }
268    //---------------------------------------------------------------------
269    Animation* Skeleton::createAnimation(const String& name, Real length)
270    {
271        // Check name not used
272        if (mAnimationsList.find(name) != mAnimationsList.end())
273        {
274            OGRE_EXCEPT(
275                Exception::ERR_DUPLICATE_ITEM,
276                "An animation with the name " + name + " already exists",
277                "Skeleton::createAnimation");
278        }
279
280        Animation* ret = new Animation(name, length);
281
282        // Add to list
283        mAnimationsList[name] = ret;
284
285        return ret;
286
287    }
288        //---------------------------------------------------------------------
289        Animation* Skeleton::getAnimation(const String& name,
290                const LinkedSkeletonAnimationSource** linker) const
291        {
292                Animation* ret = _getAnimationImpl(name, linker);
293                if (!ret)
294                {
295                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "No animation entry found named " + name,
296                                "Skeleton::getAnimation");
297                }
298
299                return ret;
300        }
301        //---------------------------------------------------------------------
302        bool Skeleton::hasAnimation(const String& name)
303        {
304                return _getAnimationImpl(name) != 0;
305        }
306    //---------------------------------------------------------------------
307    Animation* Skeleton::_getAnimationImpl(const String& name,
308                const LinkedSkeletonAnimationSource** linker) const
309    {
310                Animation* ret = 0;
311        AnimationList::const_iterator i = mAnimationsList.find(name);
312
313        if (i == mAnimationsList.end())
314        {
315                        LinkedSkeletonAnimSourceList::const_iterator i;
316                        for (i = mLinkedSkeletonAnimSourceList.begin();
317                                i != mLinkedSkeletonAnimSourceList.end() && !ret; ++i)
318                        {
319                                if (!i->pSkeleton.isNull())
320                                {
321                                        ret = i->pSkeleton->_getAnimationImpl(name);
322                                        if (ret && linker)
323                                        {
324                                                *linker = &(*i);
325                                        }
326
327                                }
328                        }
329
330        }
331                else
332                {
333                        if (linker)
334                                *linker = 0;
335                        ret = i->second;
336                }
337
338                return ret;
339
340    }
341    //---------------------------------------------------------------------
342    void Skeleton::removeAnimation(const String& name)
343    {
344        AnimationList::iterator i = mAnimationsList.find(name);
345
346        if (i == mAnimationsList.end())
347        {
348            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "No animation entry found named " + name,
349            "Skeleton::getAnimation");
350        }
351
352        delete i->second;
353
354        mAnimationsList.erase(i);
355
356    }
357    //-----------------------------------------------------------------------
358    void Skeleton::_initAnimationState(AnimationStateSet* animSet)
359    {
360        animSet->removeAllAnimationStates();
361           
362        AnimationList::iterator i;
363        for (i = mAnimationsList.begin(); i != mAnimationsList.end(); ++i)
364        {
365            Animation* anim = i->second;
366            // Create animation at time index 0, default params mean this has weight 1 and is disabled
367            String animName = anim->getName();
368            animSet->createAnimationState(animName, 0.0, anim->getLength());
369        }
370
371                // Also iterate over linked animation
372                LinkedSkeletonAnimSourceList::iterator li;
373                for (li = mLinkedSkeletonAnimSourceList.begin();
374                        li != mLinkedSkeletonAnimSourceList.end(); ++li)
375                {
376                        if (!li->pSkeleton.isNull())
377                        {
378                                li->pSkeleton->_refreshAnimationState(animSet);
379                        }
380                }
381
382    }
383        //-----------------------------------------------------------------------
384        void Skeleton::_refreshAnimationState(AnimationStateSet* animSet)
385        {
386                // Merge in any new animations
387                AnimationList::iterator i;
388                for (i = mAnimationsList.begin(); i != mAnimationsList.end(); ++i)
389                {
390                        Animation* anim = i->second;
391                        // Create animation at time index 0, default params mean this has weight 1 and is disabled
392                        String animName = anim->getName();
393                        if (!animSet->hasAnimationState(animName))
394                        {
395                                animSet->createAnimationState(animName, 0.0, anim->getLength());
396                        }
397                }
398                // Also iterate over linked animation
399                LinkedSkeletonAnimSourceList::iterator li;
400                for (li = mLinkedSkeletonAnimSourceList.begin();
401                        li != mLinkedSkeletonAnimSourceList.end(); ++li)
402                {
403                        if (!li->pSkeleton.isNull())
404                        {
405                                li->pSkeleton->_refreshAnimationState(animSet);
406                        }
407                }
408        }
409        //-----------------------------------------------------------------------
410        void Skeleton::_notifyManualBonesDirty(void)
411        {
412                mManualBonesDirty = true;
413        }
414        //-----------------------------------------------------------------------
415        void Skeleton::_notifyManualBoneStateChange(Bone* bone)
416        {
417                if (bone->isManuallyControlled())
418                        mManualBones.insert(bone);
419                else
420                        mManualBones.erase(bone);
421        }
422    //-----------------------------------------------------------------------
423    unsigned short Skeleton::getNumBones(void) const
424    {
425        return (unsigned short)mBoneList.size();
426    }
427    //-----------------------------------------------------------------------
428    void Skeleton::_getBoneMatrices(Matrix4* pMatrices)
429    {
430        // Update derived transforms
431        _updateTransforms();
432
433        /*
434            Calculating the bone matrices
435            -----------------------------
436            Now that we have the derived orientations & positions in the Bone nodes, we have
437            to compute the Matrix4 to apply to the vertices of a mesh.
438            Because any modification of a vertex has to be relative to the bone, we must first
439            reverse transform by the Bone's original derived position/orientation, then transform
440            by the new derived position / orientation.
441        */
442
443        BoneList::iterator i, boneend;
444        boneend = mBoneList.end();
445       
446       
447        for(i = mBoneList.begin();i != boneend; ++i)
448        {
449            Bone* pBone = *i;
450            *pMatrices = pBone->_getFullTransform() *  pBone->_getBindingPoseInverseTransform();
451            pMatrices++;
452        }
453
454    }
455    //---------------------------------------------------------------------
456    unsigned short Skeleton::getNumAnimations(void) const
457    {
458        return (unsigned short)mAnimationsList.size();
459    }
460    //---------------------------------------------------------------------
461    Animation* Skeleton::getAnimation(unsigned short index) const
462    {
463                // If you hit this assert, then the index is out of bounds.
464        assert( index < mAnimationsList.size() );
465
466        AnimationList::const_iterator i = mAnimationsList.begin();
467
468                std::advance(i, index);
469
470        return i->second;
471    }
472    //---------------------------------------------------------------------
473    Bone* Skeleton::getBone(unsigned short handle) const
474    {
475        assert(handle < mBoneList.size() && "Index out of bounds");
476        return mBoneList[handle];
477    }
478    //---------------------------------------------------------------------
479    Bone* Skeleton::getBone(const String& name) const
480    {
481        BoneListByName::const_iterator i = mBoneListByName.find(name);
482
483        if (i == mBoneListByName.end())
484        {
485            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Bone named '" + name + "' not found.",
486                "Skeleton::getBone");
487        }
488
489        return i->second;
490
491    }
492    //---------------------------------------------------------------------
493    void Skeleton::deriveRootBone(void) const
494    {
495        // Start at the first bone and work up
496        if (mBoneList.empty())
497        {
498            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Cannot derive root bone as this "
499                "skeleton has no bones!", "Skeleton::deriveRootBone");
500        }
501
502        mRootBones.clear();
503
504        Bone* currentBone;
505        BoneList::const_iterator i;
506        BoneList::const_iterator iend = mBoneList.end();
507        for (i = mBoneList.begin(); i != iend; ++i)
508        {
509            currentBone = *i;
510            if (currentBone->getParent() == 0)
511            {
512                // This is a root
513                mRootBones.push_back(currentBone);
514            }
515        }
516    }
517    //---------------------------------------------------------------------
518    void Skeleton::_dumpContents(const String& filename)
519    {
520        std::ofstream of;
521
522        Quaternion q;
523        Radian angle;
524        Vector3 axis;
525        of.open(filename.c_str());
526
527        of << "-= Debug output of skeleton " << mName << " =-" << std::endl << std::endl;
528        of << "== Bones ==" << std::endl;
529        of << "Number of bones: " << (unsigned int)mBoneList.size() << std::endl;
530       
531        BoneList::iterator bi;
532        for (bi = mBoneList.begin(); bi != mBoneList.end(); ++bi)
533        {
534            Bone* bone = *bi;
535
536            of << "-- Bone " << bone->getHandle() << " --" << std::endl;
537            of << "Position: " << bone->getPosition();
538            q = bone->getOrientation();
539            of << "Rotation: " << q;
540            q.ToAngleAxis(angle, axis);
541            of << " = " << angle.valueRadians() << " radians around axis " << axis << std::endl << std::endl;
542        }
543
544        of << "== Animations ==" << std::endl;
545        of << "Number of animations: " << (unsigned int)mAnimationsList.size() << std::endl;
546
547        AnimationList::iterator ai;
548        for (ai = mAnimationsList.begin(); ai != mAnimationsList.end(); ++ai)
549        {
550            Animation* anim = ai->second;
551
552            of << "-- Animation '" << anim->getName() << "' (length " << anim->getLength() << ") --" << std::endl;
553            of << "Number of tracks: " << anim->getNumNodeTracks() << std::endl;
554
555            int ti;
556            for (ti = 0; ti < anim->getNumNodeTracks(); ++ti)
557            {
558                NodeAnimationTrack* track = anim->getNodeTrack(ti);
559                of << "  -- AnimationTrack " << ti << " --" << std::endl;
560                of << "  Affects bone: " << ((Bone*)track->getAssociatedNode())->getHandle() << std::endl;
561                of << "  Number of keyframes: " << track->getNumKeyFrames() << std::endl;
562
563                int ki;
564               
565                for (ki = 0; ki < track->getNumKeyFrames(); ++ki)
566                {
567                    TransformKeyFrame* key = track->getNodeKeyFrame(ki);
568                    of << "    -- KeyFrame " << ki << " --" << std::endl;
569                    of << "    Time index: " << key->getTime();
570                    of << "    Translation: " << key->getTranslate() << std::endl;
571                    q = key->getRotation();
572                    of << "    Rotation: " << q;
573                    q.ToAngleAxis(angle, axis);
574                    of << " = " << angle.valueRadians() << " radians around axis " << axis << std::endl;
575                }
576
577            }
578
579
580
581        }
582
583    }
584    //---------------------------------------------------------------------
585        SkeletonAnimationBlendMode Skeleton::getBlendMode() const
586    {
587                return mBlendState;
588        }
589    //---------------------------------------------------------------------
590        void Skeleton::setBlendMode(SkeletonAnimationBlendMode state)
591    {
592                mBlendState = state;
593        }
594    //---------------------------------------------------------------------
595    Skeleton::BoneIterator Skeleton::getRootBoneIterator(void)
596    {
597        if (mRootBones.empty())
598        {
599            deriveRootBone();
600        }
601        return BoneIterator(mRootBones.begin(), mRootBones.end());
602    }
603    //---------------------------------------------------------------------
604    Skeleton::BoneIterator Skeleton::getBoneIterator(void)
605    {
606        return BoneIterator(mBoneList.begin(), mBoneList.end());
607    }
608    //---------------------------------------------------------------------
609    void Skeleton::_updateTransforms(void)
610    {
611        BoneList::iterator i, iend;
612        iend = mRootBones.end();
613        for (i = mRootBones.begin(); i != iend; ++i)
614        {
615            (*i)->_update(true, false);
616        }
617                mManualBonesDirty = false;
618    }
619    //---------------------------------------------------------------------
620        void Skeleton::optimiseAllAnimations(void)
621        {
622        AnimationList::iterator ai;
623        for (ai = mAnimationsList.begin(); ai != mAnimationsList.end(); ++ai)
624        {
625                        ai->second->optimise();
626                }
627        }
628        //---------------------------------------------------------------------
629        void Skeleton::addLinkedSkeletonAnimationSource(const String& skelName,
630                Real scale)
631        {
632                // Check not already linked
633                LinkedSkeletonAnimSourceList::iterator i;
634                for (i = mLinkedSkeletonAnimSourceList.begin();
635                        i != mLinkedSkeletonAnimSourceList.end(); ++i)
636                {
637                        if (skelName == i->skeletonName)
638                                return; // don't bother
639                }
640
641                if (mIsLoaded)
642                {
643                        // Load immediately
644                        SkeletonPtr skelPtr =
645                                SkeletonManager::getSingleton().load(skelName, mGroup);
646                        mLinkedSkeletonAnimSourceList.push_back(
647                                LinkedSkeletonAnimationSource(skelName, scale, skelPtr));
648
649                }
650                else
651                {
652                        // Load later
653                        mLinkedSkeletonAnimSourceList.push_back(
654                                LinkedSkeletonAnimationSource(skelName, scale));
655                }
656
657        }
658        //---------------------------------------------------------------------
659        void Skeleton::removeAllLinkedSkeletonAnimationSources(void)
660        {
661                mLinkedSkeletonAnimSourceList.clear();
662        }
663        //---------------------------------------------------------------------
664        Skeleton::LinkedSkeletonAnimSourceIterator
665        Skeleton::getLinkedSkeletonAnimationSourceIterator(void) const
666        {
667                return LinkedSkeletonAnimSourceIterator(
668                        mLinkedSkeletonAnimSourceList.begin(),
669                        mLinkedSkeletonAnimSourceList.end());
670        }
671        //---------------------------------------------------------------------
672
673}
674
Note: See TracBrowser for help on using the repository browser.