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 // Just for logging
00035 #include "OgreAnimationTrack.h"
00036 #include "OgreKeyFrame.h"
00037 #include "OgreTagPoint.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         mNextTagPointAutoHandle = 0;
00050 
00051         // Indicate root has not been derived yet
00052         mRootBone = 0;
00053         // set animation blending to weighted, not cumulative
00054         mBlendState = ANIMBLEND_AVERAGE;
00055 
00056     }
00057     //---------------------------------------------------------------------
00058     Skeleton::~Skeleton()
00059     {
00060         unload();
00061     }
00062     //---------------------------------------------------------------------
00063     void Skeleton::load(void)
00064     {
00065         // Load from specified 'name'
00066         if (mIsLoaded)
00067         {
00068             unload();
00069         }
00070 
00071         SkeletonSerializer serializer;
00072         char msg[100];
00073         sprintf(msg, "Skeleton: Loading %s .", mName.c_str());
00074         LogManager::getSingleton().logMessage(msg);
00075 
00076         DataChunk chunk;
00077         SkeletonManager::getSingleton()._findResourceData(mName, chunk);
00078 
00079         // Determine file type
00080         std::vector<String> extVec = mName.split(".");
00081 
00082         String& ext = extVec[extVec.size() - 1];
00083         ext.toLowerCase();
00084 
00085         if (ext == "skeleton")
00086         {
00087             serializer.importSkeleton(chunk, this);
00088         }
00089         else
00090         {
00091             // Unsupported format
00092             chunk.clear();
00093             Except(999, "Unsupported skeleton file format.",
00094                 "Skeleton::load");
00095         }
00096 
00097         chunk.clear();
00098 
00099         // Mark resource as loaded
00100         mIsLoaded = true;
00101 
00102     }
00103     //---------------------------------------------------------------------
00104     void Skeleton::unload(void)
00105     {
00106         // destroy bones
00107         BoneList::iterator i;
00108         for (i = mBoneList.begin(); i != mBoneList.end(); ++i)
00109         {
00110             delete i->second;
00111         }
00112         mBoneList.clear();
00113 
00114         // destroy TagPoints
00115         TagPointList::iterator itp;
00116         for (itp = mTagPointList.begin(); itp != mTagPointList.end(); ++itp)
00117         {
00118             delete itp->second;
00119         }
00120         mTagPointList.clear();
00121 
00122         // Destroy animations
00123         AnimationList::iterator ai;
00124         for (ai = mAnimationsList.begin(); ai != mAnimationsList.end(); ++ai)
00125         {
00126             delete ai->second;
00127         }
00128         mAnimationsList.clear();
00129 
00130         // Mark resource as not loaded
00131         mIsLoaded = false;
00132     }
00133     //---------------------------------------------------------------------
00134     Bone* Skeleton::createBone(void)
00135     {
00136         // use autohandle
00137         return createBone(mNextAutoHandle++);
00138     }
00139     //---------------------------------------------------------------------
00140     Bone* Skeleton::createBone(const String& name)
00141     {
00142         if (mBoneList.size() == OGRE_MAX_NUM_BONES)
00143         {
00144             Except(Exception::ERR_INVALIDPARAMS, "Exceeded the maximum number of bones per skeleton.",
00145                 "Skeleton::createBone");
00146         }
00147         Bone* ret = new Bone(name, mNextAutoHandle++, this);
00148         mBoneList[ret->getHandle()] = ret;
00149         mBoneListByName[name] = ret;
00150         return ret;
00151     }
00152     //---------------------------------------------------------------------
00153     Bone* Skeleton::createBone(unsigned short handle)
00154     {
00155         if (mBoneList.size() == OGRE_MAX_NUM_BONES)
00156         {
00157             Except(Exception::ERR_INVALIDPARAMS, "Exceeded the maximum number of bones per skeleton.",
00158                 "Skeleton::createBone");
00159         }
00160         Bone* ret = new Bone(handle, this);
00161         mBoneList[handle] = ret;
00162         mBoneListByName[ret->getName()] = ret;
00163         return ret;
00164 
00165     }
00166     //---------------------------------------------------------------------
00167     Bone* Skeleton::createBone(const String& name, unsigned short handle)
00168     {
00169         if (mBoneList.size() == OGRE_MAX_NUM_BONES)
00170         {
00171             Except(Exception::ERR_INVALIDPARAMS, "Exceeded the maximum number of bones per skeleton.",
00172                 "Skeleton::createBone");
00173         }
00174         Bone* ret = new Bone(name, handle, this);
00175         mBoneList[handle] = ret;
00176         mBoneListByName[name] = ret;
00177         return ret;
00178     }
00179 
00180     TagPoint* Skeleton::createTagPoint(const Quaternion &offsetOrientation, const Vector3 &offsetPosition)
00181     {
00182         TagPoint* ret = new TagPoint(mNextTagPointAutoHandle++, this);
00183         mTagPointList[mNextTagPointAutoHandle] = ret;
00184         
00185         ret->translate(offsetPosition);
00186         ret->rotate(offsetOrientation);
00187         ret->setBindingPose();
00188 
00189         return ret;
00190     }
00191 
00192     void Skeleton::setCurrentEntity(Entity *pCurrentEntity)
00193     {
00194         mCurrentEntity = pCurrentEntity;
00195     }
00196 
00197     Entity *Skeleton::getCurrentEntity(void)
00198     {
00199         return mCurrentEntity;
00200     }
00201 
00202 
00203     //---------------------------------------------------------------------
00204     Bone* Skeleton::getRootBone(void) const
00205     {
00206         if (mRootBone == 0)
00207         {
00208             deriveRootBone();
00209         }
00210 
00211         return mRootBone;
00212     }
00213     //---------------------------------------------------------------------
00214     void Skeleton::setAnimationState(const AnimationStateSet& animSet)
00215     {
00216         /* 
00217         Algorithm:
00218           1. Check if animation state is any different from last, if not do nothing
00219           2. Reset all bone positions
00220           3. Iterate per AnimationState, if enabled get Animation and call Animation::apply
00221         */
00222 
00223         if (mLastAnimationState.size() == animSet.size())
00224         {
00225             // Same size, may be able to skip update
00226             bool different = false;
00227             AnimationStateSet::iterator i;
00228             AnimationStateSet::const_iterator j;
00229             i = mLastAnimationState.begin();
00230             j = animSet.begin();
00231             for (; i != mLastAnimationState.end(); ++i, ++j)
00232             {
00233                 if (i->second != j->second)
00234                 {
00235                     different = true;
00236                     break;
00237                 }
00238             }
00239             // Check any differences?
00240             if (!different)
00241             {
00242                 // No, no need to update
00243                 return;
00244             }
00245         }
00246 
00247         // Ok, we've established the animation state is different
00248 
00249         // Reset bones
00250         reset();
00251 
00252         // Per animation state
00253         AnimationStateSet::const_iterator istate;
00254         for (istate = animSet.begin(); istate != animSet.end(); ++istate)
00255         {
00256             // Apply if enabled
00257             const AnimationState& animState = istate->second;
00258             if (animState.getEnabled())
00259             {
00260                 Animation* anim = getAnimation(animState.getAnimationName());
00261                 anim->apply(animState.getTimePosition(), animState.getWeight(), mBlendState == ANIMBLEND_CUMULATIVE);
00262             }
00263         }
00264 
00265         mLastAnimationState = animSet;
00266 
00267 
00268     }
00269     //---------------------------------------------------------------------
00270     void Skeleton::setBindingPose(void)
00271     {
00272         // Update the derived transforms
00273         getRootBone()->_update(true, false);
00274 
00275 
00276         BoneList::iterator i;
00277         for (i = mBoneList.begin(); i != mBoneList.end(); ++i)
00278         {            
00279             i->second->setBindingPose();
00280         }
00281     }
00282     //---------------------------------------------------------------------
00283     void Skeleton::reset(void)
00284     {
00285         BoneList::iterator i;
00286         for (i = mBoneList.begin(); i != mBoneList.end(); ++i)
00287         {
00288             if(!i->second->isManuallyControlled())
00289                 i->second->reset();
00290         }
00291     }
00292     //---------------------------------------------------------------------
00293     Animation* Skeleton::createAnimation(const String& name, Real length)
00294     {
00295         Animation* ret = new Animation(name, length);
00296 
00297         // Add to list
00298         mAnimationsList[name] = ret;
00299 
00300         // Also add to state
00301         mLastAnimationState[name] = AnimationState(name, 0, length);
00302 
00303         return ret;
00304 
00305     }
00306     //---------------------------------------------------------------------
00307     Animation* Skeleton::getAnimation(const String& name) const
00308     {
00309         AnimationList::const_iterator i = mAnimationsList.find(name);
00310 
00311         if (i == mAnimationsList.end())
00312         {
00313             Except(Exception::ERR_ITEM_NOT_FOUND, "No animation entry found named " + name, 
00314             "Skeleton::getAnimation");
00315         }
00316 
00317         return i->second;
00318     }
00319     //---------------------------------------------------------------------
00320     void Skeleton::removeAnimation(const String& name)
00321     {
00322         AnimationList::iterator i = mAnimationsList.find(name);
00323 
00324         if (i == mAnimationsList.end())
00325         {
00326             Except(Exception::ERR_ITEM_NOT_FOUND, "No animation entry found named " + name, 
00327             "Skeleton::getAnimation");
00328         }
00329 
00330         delete i->second;
00331 
00332         mAnimationsList.erase(i);
00333 
00334     }
00335     //---------------------------------------------------------------------
00336     const AnimationStateSet& Skeleton::getAnimationState(void) const
00337     {
00338         return mLastAnimationState;
00339     }
00340     //-----------------------------------------------------------------------
00341     void Skeleton::_initAnimationState(AnimationStateSet* animSet)
00342     {
00343         animSet->clear();
00344            
00345         AnimationList::iterator i;
00346         for (i = mAnimationsList.begin(); i != mAnimationsList.end(); ++i)
00347         {
00348             Animation* anim = i->second;
00349             // Create animation at time index 0, default params mean this has weight 1 and is disabled
00350             String animName = anim->getName();
00351             (*animSet)[animName] = AnimationState(animName, 0.0, anim->getLength());
00352         }
00353     }
00354     //-----------------------------------------------------------------------
00355     unsigned short Skeleton::getNumBones(void) const
00356     {
00357         return (unsigned short)mBoneList.size();
00358     }
00359     //-----------------------------------------------------------------------
00360     void Skeleton::_getBoneMatrices(Matrix4* pMatrices)
00361     {
00362         // Update derived transforms
00363         getRootBone()->_update(true, false);
00364 
00365         /* 
00366             Calculating the bone matrices
00367             -----------------------------
00368             Now that we have the derived orientations & positions in the Bone nodes, we have
00369             to compute the Matrix4 to apply to the vertices of a mesh.
00370             Because any modification of a vertex has to be relative to the bone, we must first
00371             reverse transform by the Bone's original derived position/orientation, then transform
00372             by the new derived position / orientation.
00373         */
00374 
00375         BoneList::iterator i, boneend;
00376         boneend = mBoneList.end();
00377         
00378        
00379         for(i = mBoneList.begin();i != boneend; ++i)
00380         {
00381             Bone* pBone = i->second;
00382             *pMatrices = pBone->_getFullTransform() *  pBone->_getBindingPoseInverseTransform();
00383             pMatrices++;
00384         }
00385 
00386     }
00387     //---------------------------------------------------------------------
00388     unsigned short Skeleton::getNumAnimations(void) const
00389     {
00390         return (unsigned short)mAnimationsList.size();
00391     }
00392     //---------------------------------------------------------------------
00393     Animation* Skeleton::getAnimation(unsigned short index) const
00394     {
00395         // If you hit this assert, then the index is out of bounds.
00396         assert( index < mAnimationsList.size() );
00397 
00398         AnimationList::const_iterator i = mAnimationsList.begin();
00399 
00400         while (index--)
00401             ++i;
00402 
00403         return i->second;
00404     }
00405     //---------------------------------------------------------------------
00406     Bone* Skeleton::getBone(unsigned short handle) const
00407     {
00408         BoneList::const_iterator i = mBoneList.find(handle);
00409 
00410         if (i == mBoneList.end())
00411         {
00412             Except(Exception::ERR_ITEM_NOT_FOUND, "Bone with specified handle not found.", 
00413                 "Skeleton::getBone");
00414         }
00415 
00416         return i->second;
00417 
00418     }
00419     //---------------------------------------------------------------------
00420     Bone* Skeleton::getBone(const String& name) const
00421     {
00422         BoneListByName::const_iterator i = mBoneListByName.find(name);
00423 
00424         if (i == mBoneListByName.end())
00425         {
00426             Except(Exception::ERR_ITEM_NOT_FOUND, "Bone named '" + name + "' not found.", 
00427                 "Skeleton::getBone");
00428         }
00429 
00430         return i->second;
00431 
00432     }
00433     //---------------------------------------------------------------------
00434     void Skeleton::deriveRootBone(void) const
00435     {
00436         // Start at the first bone and work up
00437         if (mBoneList.empty())
00438         {
00439             Except(Exception::ERR_INVALIDPARAMS, "Cannot derive root bone as this "
00440                 "skeleton has no bones!", "Skeleton::deriveRootBone");
00441         }
00442 
00443         Bone* currentBone;
00444         BoneList::const_iterator i = mBoneList.begin();
00445 
00446         currentBone = i->second;
00447         while (currentBone->getParent() != 0)
00448         {
00449             // Keep going up the tree
00450             currentBone = (Bone*)currentBone->getParent();
00451         }
00452 
00453         // No more parents, this must be the root
00454         mRootBone = currentBone;
00455     }
00456     //---------------------------------------------------------------------
00457     void Skeleton::_dumpContents(const String& filename)
00458     {
00459         std::ofstream of;
00460 
00461         Quaternion q;
00462         Real angle;
00463         Vector3 axis;
00464         of.open(filename);
00465 
00466         of << "-= Debug output of skeleton " << mName << " =-" << std::endl << std::endl;
00467         of << "== Bones ==" << std::endl;
00468         of << "Number of bones: " << (unsigned int)mBoneList.size() << std::endl;
00469         
00470         BoneList::iterator bi;
00471         for (bi = mBoneList.begin(); bi != mBoneList.end(); ++bi)
00472         {
00473             Bone* bone = bi->second;
00474 
00475             of << "-- Bone " << bone->getHandle() << " --" << std::endl;
00476             of << "Position: " << bone->getPosition();
00477             q = bone->getOrientation();
00478             of << "Rotation: " << q;
00479             q.ToAngleAxis(angle, axis);
00480             of << " = " << angle << " radians around axis " << axis << std::endl << std::endl;
00481         }
00482 
00483         of << "== Animations ==" << std::endl;
00484         of << "Number of animations: " << (unsigned int)mAnimationsList.size() << std::endl;
00485 
00486         AnimationList::iterator ai;
00487         for (ai = mAnimationsList.begin(); ai != mAnimationsList.end(); ++ai)
00488         {
00489             Animation* anim = ai->second;
00490 
00491             of << "-- Animation '" << anim->getName() << "' (length " << anim->getLength() << ") --" << std::endl;
00492             of << "Number of tracks: " << anim->getNumTracks() << std::endl;
00493 
00494             int ti;
00495             for (ti = 0; ti < anim->getNumTracks(); ++ti)
00496             {
00497                 AnimationTrack* track = anim->getTrack(ti);
00498                 of << "  -- AnimationTrack " << ti << " --" << std::endl;
00499                 of << "  Affects bone: " << ((Bone*)track->getAssociatedNode())->getHandle() << std::endl;
00500                 of << "  Number of keyframes: " << track->getNumKeyFrames() << std::endl;
00501 
00502                 int ki;
00503                 
00504                 for (ki = 0; ki < track->getNumKeyFrames(); ++ki)
00505                 {
00506                     KeyFrame* key = track->getKeyFrame(ki);
00507                     of << "    -- KeyFrame " << ki << " --" << std::endl;
00508                     of << "    Time index: " << key->getTime(); 
00509                     of << "    Translation: " << key->getTranslate() << std::endl;
00510                     q = key->getRotation();
00511                     of << "    Rotation: " << q;
00512                     q.ToAngleAxis(angle, axis);
00513                     of << " = " << angle << " radians around axis " << axis << std::endl;
00514                 }
00515 
00516             }
00517 
00518 
00519 
00520         }
00521 
00522     }
00523     //---------------------------------------------------------------------
00524     SkeletonAnimationBlendMode Skeleton::getBlendMode() 
00525     {
00526         return mBlendState;
00527     }
00528     //---------------------------------------------------------------------
00529     void Skeleton::setBlendMode(SkeletonAnimationBlendMode state) 
00530     {
00531         mBlendState = state;
00532     }
00533 
00534 }
00535 

Copyright © 2002-2003 by The OGRE Team
Last modified Wed Jan 21 00:10:28 2004