Main Page Namespace List Class Hierarchy Alphabetical List Compound List File List Namespace Members Compound Members File Members Related Pages

# OgreSkeleton.cpp

Go to the documentation of this file.

    00001 /*
    00002 -----------------------------------------------------------------------------
    00003 This source file is part of OGRE
    00004     (Object-oriented Graphics Rendering Engine)
    00005 For the latest info, see http://www.ogre3d.org/
    00006
    00007 Copyright © 2000-2002 The OGRE Team
    00008 Also see acknowledgements in Readme.html
    00009
    00010 This program is free software; you can redistribute it and/or modify it under
    00011 the terms of the GNU Lesser General Public License as published by the Free Software
    00012 Foundation; either version 2 of the License, or (at your option) any later
    00013 version.
    00014
    00015 This program is distributed in the hope that it will be useful, but WITHOUT
    00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
    00018
    00019 You should have received a copy of the GNU Lesser General Public License along with
    00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
    00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
    00022 http://www.gnu.org/copyleft/lesser.txt.
    00023 -----------------------------------------------------------------------------
    00024 */
    00025 #include "OgreStableHeaders.h"
    00026 #include "OgreSkeleton.h"
    00027 #include "OgreBone.h"
    00028 #include "OgreAnimation.h"
    00029 #include "OgreAnimationState.h"
    00030 #include "OgreException.h"
    00031 #include "OgreLogManager.h"
    00032 #include "OgreSkeletonManager.h"
    00033 #include "OgreSkeletonSerializer.h"
    00034 #include "OgreStringConverter.h"
    00035 // Just for logging
    00036 #include "OgreAnimationTrack.h"
    00037 #include "OgreKeyFrame.h"
    00038
    00039
    00040 namespace Ogre {
    00041
    00042     //---------------------------------------------------------------------
    00043     Skeleton::Skeleton(const String& name)
    00044     {
    00045         mName = name;
    00046
    00047         // Start next handle
    00048         mNextAutoHandle = 0;
    00049
    00050         // set animation blending to weighted, not cumulative
    00051         mBlendState = ANIMBLEND_AVERAGE;
    00052
    00053     }
    00054     //---------------------------------------------------------------------
    00055     Skeleton::~Skeleton()
    00056     {
    00057         unload();
    00058     }
    00059     //---------------------------------------------------------------------
    00060     void Skeleton::load(void)
    00061     {
    00062         // Load from specified 'name'
    00063         if (mIsLoaded)
    00064         {
    00065             unload();
    00066         }
    00067
    00068         SkeletonSerializer serializer;
    00069         char msg[100];
    00070         sprintf(msg, "Skeleton: Loading %s .", mName.c_str());
    00071         LogManager::getSingleton().logMessage(msg);
    00072
    00073         DataChunk chunk;
    00074         SkeletonManager::getSingleton()._findResourceData(mName, chunk);
    00075
    00076         // Determine file type
    00077         std::vector<String> extVec = StringUtil::split(mName, ".");
    00078
    00079         String& ext = extVec[extVec.size() - 1];
    00080         StringUtil::toLowerCase(ext);
    00081
    00082         if (ext == "skeleton")
    00083         {
    00084             serializer.importSkeleton(chunk, this);
    00085         }
    00086         else
    00087         {
    00088             // Unsupported format
    00089             chunk.clear();
    00090             Except(999, "Unsupported skeleton file format.",
    00091                 "Skeleton::load");
    00092         }
    00093
    00094         chunk.clear();
    00095
    00096         // Mark resource as loaded
    00097         mIsLoaded = true;
    00098
    00099     }
    00100     //---------------------------------------------------------------------
    00101     void Skeleton::unload(void)
    00102     {
    00103         // destroy bones
    00104         BoneList::iterator i;
    00105         for (i = mBoneList.begin(); i != mBoneList.end(); ++i)
    00106         {
    00107             delete *i;
    00108         }
    00109         mBoneList.clear();
    00110         mBoneListByName.clear();
    00111
    00112
    00113         // Destroy animations
    00114         AnimationList::iterator ai;
    00115         for (ai = mAnimationsList.begin(); ai != mAnimationsList.end(); ++ai)
    00116         {
    00117             delete ai->second;
    00118         }
    00119         mAnimationsList.clear();
    00120
    00121         // Mark resource as not loaded
    00122         mIsLoaded = false;
    00123     }
    00124     //---------------------------------------------------------------------
    00125     Bone* Skeleton::createBone(void)
    00126     {
    00127         // use autohandle
    00128         return createBone(mNextAutoHandle++);
    00129     }
    00130     //---------------------------------------------------------------------
    00131     Bone* Skeleton::createBone(const String& name)
    00132     {
    00133         return createBone(name, mNextAutoHandle++);
    00134     }
    00135     //---------------------------------------------------------------------
    00136     Bone* Skeleton::createBone(unsigned short handle)
    00137     {
    00138         if (handle >= OGRE_MAX_NUM_BONES)
    00139         {
    00140             Except(Exception::ERR_INVALIDPARAMS, "Exceeded the maximum number of bones per skeleton.",
    00141                 "Skeleton::createBone");
    00142         }
    00143         // Check handle not used
    00144         if (handle < mBoneList.size() && mBoneList[handle] != NULL)
    00145         {
    00146             Except(
    00147                 Exception::ERR_DUPLICATE_ITEM,
    00148                 "A bone with the handle " + StringConverter::toString(handle) + " already exists",
    00149                 "Skeleton::createBone" );
    00150         }
    00151         Bone* ret = new Bone(handle, this);
    00152         assert(mBoneListByName.find(ret->getName()) == mBoneListByName.end());
    00153         if (mBoneList.size() <= handle)
    00154         {
    00155             mBoneList.resize(handle+1);
    00156         }
    00157         mBoneList[handle] = ret;
    00158         mBoneListByName[ret->getName()] = ret;
    00159         return ret;
    00160
    00161     }
    00162     //---------------------------------------------------------------------
    00163     Bone* Skeleton::createBone(const String& name, unsigned short handle)
    00164     {
    00165         if (handle >= OGRE_MAX_NUM_BONES)
    00166         {
    00167             Except(Exception::ERR_INVALIDPARAMS, "Exceeded the maximum number of bones per skeleton.",
    00168                 "Skeleton::createBone");
    00169         }
    00170         // Check handle not used
    00171         if (handle < mBoneList.size() && mBoneList[handle] != NULL)
    00172         {
    00173             Except(
    00174                 Exception::ERR_DUPLICATE_ITEM,
    00175                 "A bone with the handle " + StringConverter::toString(handle) + " already exists",
    00176                 "Skeleton::createBone" );
    00177         }
    00178         // Check name not used
    00179         if (mBoneListByName.find(name) != mBoneListByName.end())
    00180         {
    00181             Except(
    00182                 Exception::ERR_DUPLICATE_ITEM,
    00183                 "A bone with the name " + name + " already exists",
    00184                 "Skeleton::createBone" );
    00185         }
    00186         Bone* ret = new Bone(name, handle, this);
    00187         if (mBoneList.size() <= handle)
    00188         {
    00189             mBoneList.resize(handle+1);
    00190         }
    00191         mBoneList[handle] = ret;
    00192         mBoneListByName[name] = ret;
    00193         return ret;
    00194     }
    00195
    00196
    00197
    00198     //---------------------------------------------------------------------
    00199     Bone* Skeleton::getRootBone(void) const
    00200     {
    00201         if (mRootBones.empty())
    00202         {
    00203             deriveRootBone();
    00204         }
    00205
    00206         return mRootBones[0];
    00207     }
    00208     //---------------------------------------------------------------------
    00209     void Skeleton::setAnimationState(const AnimationStateSet& animSet)
    00210     {
    00211         /*
    00212         Algorithm:
    00213           1. Check if animation state is any different from last, if not do nothing
    00214           2. Reset all bone positions
    00215           3. Iterate per AnimationState, if enabled get Animation and call Animation::apply
    00216         */
    00217
    00218         if (mLastAnimationState.size() == animSet.size())
    00219         {
    00220             // Same size, may be able to skip update
    00221             bool different = false;
    00222             AnimationStateSet::iterator i;
    00223             AnimationStateSet::const_iterator j;
    00224             i = mLastAnimationState.begin();
    00225             j = animSet.begin();
    00226             for (; i != mLastAnimationState.end(); ++i, ++j)
    00227             {
    00228                 if (i->second != j->second)
    00229                 {
    00230                     different = true;
    00231                     break;
    00232                 }
    00233             }
    00234             // Check any differences?
    00235             if (!different)
    00236             {
    00237                 // No, no need to update
    00238                 return;
    00239             }
    00240         }
    00241
    00242         // Ok, we've established the animation state is different
    00243
    00244         // Reset bones
    00245         reset();
    00246
    00247         // Per animation state
    00248         AnimationStateSet::const_iterator istate;
    00249         for (istate = animSet.begin(); istate != animSet.end(); ++istate)
    00250         {
    00251             // Apply if enabled
    00252             const AnimationState& animState = istate->second;
    00253             if (animState.getEnabled())
    00254             {
    00255                 Animation* anim = getAnimation(animState.getAnimationName());
    00256                 anim->apply(this, animState.getTimePosition(), animState.getWeight(), mBlendState == ANIMBLEND_CUMULATIVE);
    00257             }
    00258         }
    00259
    00260         mLastAnimationState = animSet;
    00261
    00262
    00263     }
    00264     //---------------------------------------------------------------------
    00265     void Skeleton::setBindingPose(void)
    00266     {
    00267         // Update the derived transforms
    00268         _updateTransforms();
    00269
    00270
    00271         BoneList::iterator i;
    00272         for (i = mBoneList.begin(); i != mBoneList.end(); ++i)
    00273         {
    00274             (*i)->setBindingPose();
    00275         }
    00276     }
    00277     //---------------------------------------------------------------------
    00278     void Skeleton::reset(bool resetManualBones)
    00279     {
    00280         BoneList::iterator i;
    00281         for (i = mBoneList.begin(); i != mBoneList.end(); ++i)
    00282         {
    00283             if(!(*i)->isManuallyControlled() || resetManualBones)
    00284                 (*i)->reset();
    00285         }
    00286     }
    00287     //---------------------------------------------------------------------
    00288     Animation* Skeleton::createAnimation(const String& name, Real length)
    00289     {
    00290         // Check name not used
    00291         if (mAnimationsList.find(name) != mAnimationsList.end())
    00292         {
    00293             Except(
    00294                 Exception::ERR_DUPLICATE_ITEM,
    00295                 "An animation with the name " + name + " already exists",
    00296                 "Skeleton::createAnimation");
    00297         }
    00298
    00299         Animation* ret = new Animation(name, length);
    00300
    00301         // Add to list
    00302         mAnimationsList[name] = ret;
    00303
    00304         // Also add to state
    00305         mLastAnimationState[name] = AnimationState(name, 0, length);
    00306
    00307         return ret;
    00308
    00309     }
    00310     //---------------------------------------------------------------------
    00311     Animation* Skeleton::getAnimation(const String& name) const
    00312     {
    00313         AnimationList::const_iterator i = mAnimationsList.find(name);
    00314
    00315         if (i == mAnimationsList.end())
    00316         {
    00317             Except(Exception::ERR_ITEM_NOT_FOUND, "No animation entry found named " + name,
    00318             "Skeleton::getAnimation");
    00319         }
    00320
    00321         return i->second;
    00322     }
    00323     //---------------------------------------------------------------------
    00324     void Skeleton::removeAnimation(const String& name)
    00325     {
    00326         AnimationList::iterator i = mAnimationsList.find(name);
    00327
    00328         if (i == mAnimationsList.end())
    00329         {
    00330             Except(Exception::ERR_ITEM_NOT_FOUND, "No animation entry found named " + name,
    00331             "Skeleton::getAnimation");
    00332         }
    00333
    00334         delete i->second;
    00335
    00336         mAnimationsList.erase(i);
    00337
    00338     }
    00339     //---------------------------------------------------------------------
    00340     const AnimationStateSet& Skeleton::getAnimationState(void) const
    00341     {
    00342         return mLastAnimationState;
    00343     }
    00344     //-----------------------------------------------------------------------
    00345     void Skeleton::_initAnimationState(AnimationStateSet* animSet)
    00346     {
    00347         animSet->clear();
    00348
    00349         AnimationList::iterator i;
    00350         for (i = mAnimationsList.begin(); i != mAnimationsList.end(); ++i)
    00351         {
    00352             Animation* anim = i->second;
    00353             // Create animation at time index 0, default params mean this has weight 1 and is disabled
    00354             String animName = anim->getName();
    00355             (*animSet)[animName] = AnimationState(animName, 0.0, anim->getLength());
    00356         }
    00357     }
    00358     //-----------------------------------------------------------------------
    00359     unsigned short Skeleton::getNumBones(void) const
    00360     {
    00361         return (unsigned short)mBoneList.size();
    00362     }
    00363     //-----------------------------------------------------------------------
    00364     void Skeleton::_getBoneMatrices(Matrix4* pMatrices)
    00365     {
    00366         // Update derived transforms
    00367         _updateTransforms();
    00368
    00369         /*
    00370             Calculating the bone matrices
    00371             -----------------------------
    00372             Now that we have the derived orientations & positions in the Bone nodes, we have
    00373             to compute the Matrix4 to apply to the vertices of a mesh.
    00374             Because any modification of a vertex has to be relative to the bone, we must first
    00375             reverse transform by the Bone's original derived position/orientation, then transform
    00376             by the new derived position / orientation.
    00377         */
    00378
    00379         BoneList::iterator i, boneend;
    00380         boneend = mBoneList.end();
    00381
    00382
    00383         for(i = mBoneList.begin();i != boneend; ++i)
    00384         {
    00385             Bone* pBone = *i;
    00386             *pMatrices = pBone->_getFullTransform() *  pBone->_getBindingPoseInverseTransform();
    00387             pMatrices++;
    00388         }
    00389
    00390     }
    00391     //---------------------------------------------------------------------
    00392     unsigned short Skeleton::getNumAnimations(void) const
    00393     {
    00394         return (unsigned short)mAnimationsList.size();
    00395     }
    00396     //---------------------------------------------------------------------
    00397     Animation* Skeleton::getAnimation(unsigned short index) const
    00398     {
    00399         // If you hit this assert, then the index is out of bounds.
    00400         assert( index < mAnimationsList.size() );
    00401
    00402         AnimationList::const_iterator i = mAnimationsList.begin();
    00403
    00404         while (index--)
    00405             ++i;
    00406
    00407         return i->second;
    00408     }
    00409     //---------------------------------------------------------------------
    00410     Bone* Skeleton::getBone(unsigned short handle) const
    00411     {
    00412         assert(handle < mBoneList.size() && "Index out of bounds");
    00413         return mBoneList[handle];
    00414     }
    00415     //---------------------------------------------------------------------
    00416     Bone* Skeleton::getBone(const String& name) const
    00417     {
    00418         BoneListByName::const_iterator i = mBoneListByName.find(name);
    00419
    00420         if (i == mBoneListByName.end())
    00421         {
    00422             Except(Exception::ERR_ITEM_NOT_FOUND, "Bone named '" + name + "' not found.",
    00423                 "Skeleton::getBone");
    00424         }
    00425
    00426         return i->second;
    00427
    00428     }
    00429     //---------------------------------------------------------------------
    00430     void Skeleton::deriveRootBone(void) const
    00431     {
    00432         // Start at the first bone and work up
    00433         if (mBoneList.empty())
    00434         {
    00435             Except(Exception::ERR_INVALIDPARAMS, "Cannot derive root bone as this "
    00436                 "skeleton has no bones!", "Skeleton::deriveRootBone");
    00437         }
    00438
    00439         mRootBones.empty();
    00440
    00441         Bone* currentBone;
    00442         BoneList::const_iterator i;
    00443         BoneList::const_iterator iend = mBoneList.end();
    00444         for (i = mBoneList.begin(); i != iend; ++i)
    00445         {
    00446             currentBone = *i;
    00447             if (currentBone->getParent() == 0)
    00448             {
    00449                 // This is a root
    00450                 mRootBones.push_back(currentBone);
    00451             }
    00452         }
    00453     }
    00454     //---------------------------------------------------------------------
    00455     void Skeleton::_dumpContents(const String& filename)
    00456     {
    00457         std::ofstream of;
    00458
    00459         Quaternion q;
    00460         Radian angle;
    00461         Vector3 axis;
    00462         of.open(filename.c_str());
    00463
    00464         of << "-= Debug output of skeleton " << mName << " =-" << std::endl << std::endl;
    00465         of << "== Bones ==" << std::endl;
    00466         of << "Number of bones: " << (unsigned int)mBoneList.size() << std::endl;
    00467
    00468         BoneList::iterator bi;
    00469         for (bi = mBoneList.begin(); bi != mBoneList.end(); ++bi)
    00470         {
    00471             Bone* bone = *bi;
    00472
    00473             of << "-- Bone " << bone->getHandle() << " --" << std::endl;
    00474             of << "Position: " << bone->getPosition();
    00475             q = bone->getOrientation();
    00476             of << "Rotation: " << q;
    00477             q.ToAngleAxis(angle, axis);
    00478             of << " = " << angle.valueRadians() << " radians around axis " << axis << std::endl << std::endl;
    00479         }
    00480
    00481         of << "== Animations ==" << std::endl;
    00482         of << "Number of animations: " << (unsigned int)mAnimationsList.size() << std::endl;
    00483
    00484         AnimationList::iterator ai;
    00485         for (ai = mAnimationsList.begin(); ai != mAnimationsList.end(); ++ai)
    00486         {
    00487             Animation* anim = ai->second;
    00488
    00489             of << "-- Animation '" << anim->getName() << "' (length " << anim->getLength() << ") --" << std::endl;
    00490             of << "Number of tracks: " << anim->getNumTracks() << std::endl;
    00491
    00492             int ti;
    00493             for (ti = 0; ti < anim->getNumTracks(); ++ti)
    00494             {
    00495                 AnimationTrack* track = anim->getTrack(ti);
    00496                 of << "  -- AnimationTrack " << ti << " --" << std::endl;
    00497                 of << "  Affects bone: " << ((Bone*)track->getAssociatedNode())->getHandle() << std::endl;
    00498                 of << "  Number of keyframes: " << track->getNumKeyFrames() << std::endl;
    00499
    00500                 int ki;
    00501
    00502                 for (ki = 0; ki < track->getNumKeyFrames(); ++ki)
    00503                 {
    00504                     KeyFrame* key = track->getKeyFrame(ki);
    00505                     of << "    -- KeyFrame " << ki << " --" << std::endl;
    00506                     of << "    Time index: " << key->getTime();
    00507                     of << "    Translation: " << key->getTranslate() << std::endl;
    00508                     q = key->getRotation();
    00509                     of << "    Rotation: " << q;
    00510                     q.ToAngleAxis(angle, axis);
    00511                     of << " = " << angle.valueRadians() << " radians around axis " << axis << std::endl;
    00512                 }
    00513
    00514             }
    00515
    00516
    00517
    00518         }
    00519
    00520     }
    00521     //---------------------------------------------------------------------
    00522     SkeletonAnimationBlendMode Skeleton::getBlendMode()
    00523     {
    00524         return mBlendState;
    00525     }
    00526     //---------------------------------------------------------------------
    00527     void Skeleton::setBlendMode(SkeletonAnimationBlendMode state)
    00528     {
    00529         mBlendState = state;
    00530     }
    00531     //---------------------------------------------------------------------
    00532     Skeleton::BoneIterator Skeleton::getRootBoneIterator(void)
    00533     {
    00534         if (mRootBones.empty())
    00535         {
    00536             deriveRootBone();
    00537         }
    00538         return BoneIterator(mRootBones.begin(), mRootBones.end());
    00539     }
    00540     //---------------------------------------------------------------------
    00541     Skeleton::BoneIterator Skeleton::getBoneIterator(void)
    00542     {
    00543         return BoneIterator(mBoneList.begin(), mBoneList.end());
    00544     }
    00545     //---------------------------------------------------------------------
    00546     void Skeleton::_updateTransforms(void)
    00547     {
    00548         BoneList::iterator i, iend;
    00549         iend = mRootBones.end();
    00550         for (i = mRootBones.begin(); i != iend; ++i)
    00551         {
    00552             (*i)->_update(true, false);
    00553         }
    00554     }
    00555 }
    00556

Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:47 2004