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