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