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