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 00027 #include "OgreSkeletonFileFormat.h" 00028 #include "OgreSkeletonSerializer.h" 00029 #include "OgreSkeleton.h" 00030 #include "OgreAnimation.h" 00031 #include "OgreAnimationTrack.h" 00032 #include "OgreKeyFrame.h" 00033 #include "OgreBone.h" 00034 #include "OgreString.h" 00035 #include "OgreDataChunk.h" 00036 #include "OgreLogManager.h" 00037 00038 00039 00040 00041 namespace Ogre { 00043 const unsigned long CHUNK_OVERHEAD_SIZE = sizeof(unsigned short) + sizeof(unsigned long); 00044 //--------------------------------------------------------------------- 00045 SkeletonSerializer::SkeletonSerializer() 00046 { 00047 // Version number 00048 // NB changed to include bone names in 1.1 00049 mVersion = "[Serializer_v1.10]"; 00050 } 00051 //--------------------------------------------------------------------- 00052 SkeletonSerializer::~SkeletonSerializer() 00053 { 00054 } 00055 //--------------------------------------------------------------------- 00056 void SkeletonSerializer::exportSkeleton(const Skeleton* pSkeleton, const String& filename) 00057 { 00058 String msg; 00059 mpfFile = fopen(filename, "wb"); 00060 00061 writeFileHeader(); 00062 00063 // Write main skeleton data 00064 LogManager::getSingleton().logMessage("Exporting bones.."); 00065 writeSkeleton(pSkeleton); 00066 LogManager::getSingleton().logMessage("Bones exported."); 00067 00068 // Write all animations 00069 unsigned short numAnims = pSkeleton->getNumAnimations(); 00070 msg = "Exporting animations, count="; 00071 msg << numAnims; 00072 LogManager::getSingleton().logMessage(msg); 00073 for (unsigned short i = 0; i < numAnims; ++i) 00074 { 00075 Animation* pAnim = pSkeleton->getAnimation(i); 00076 msg = "Exporting animation: "; 00077 msg << pAnim->getName(); 00078 LogManager::getSingleton().logMessage(msg); 00079 writeAnimation(pAnim); 00080 LogManager::getSingleton().logMessage("Animation exported."); 00081 00082 } 00083 fclose(mpfFile); 00084 00085 } 00086 //--------------------------------------------------------------------- 00087 void SkeletonSerializer::importSkeleton(DataChunk& chunk, Skeleton* pDest) 00088 { 00089 mpSkeleton = pDest; 00090 00091 // Check header 00092 readFileHeader(chunk); 00093 00094 unsigned short chunkID; 00095 while(!chunk.isEOF()) 00096 { 00097 chunkID = readChunk(chunk); 00098 switch (chunkID) 00099 { 00100 case SKELETON_BONE: 00101 readBone(chunk); 00102 break; 00103 case SKELETON_BONE_PARENT: 00104 readBoneParent(chunk); 00105 break; 00106 case SKELETON_ANIMATION: 00107 readAnimation(chunk); 00108 } 00109 } 00110 00111 // Assume bones are stored in the binding pose 00112 mpSkeleton->setBindingPose(); 00113 00114 00115 } 00116 //--------------------------------------------------------------------- 00117 void SkeletonSerializer::writeSkeleton(const Skeleton* pSkel) 00118 { 00119 // Write each bone 00120 unsigned short numBones = pSkel->getNumBones(); 00121 unsigned short i; 00122 for (i = 0; i < numBones; ++i) 00123 { 00124 Bone* pBone = pSkel->getBone(i); 00125 writeBone(pBone); 00126 } 00127 // Write parents 00128 for (i = 0; i < numBones; ++i) 00129 { 00130 Bone* pBone = pSkel->getBone(i); 00131 unsigned short handle = pBone->getHandle(); 00132 Bone* pParent = (Bone*)pBone->getParent(); 00133 if (pParent != NULL) 00134 { 00135 writeBoneParent(handle, pParent->getHandle()); 00136 } 00137 } 00138 } 00139 //--------------------------------------------------------------------- 00140 void SkeletonSerializer::writeBone(const Bone* pBone) 00141 { 00142 writeChunkHeader(SKELETON_BONE, calcBoneSize(pBone)); 00143 00144 unsigned short handle = pBone->getHandle(); 00145 // char* name 00146 writeString(pBone->getName()); 00147 // unsigned short handle : handle of the bone, should be contiguous & start at 0 00148 writeShorts(&handle, 1); 00149 // Vector3 position : position of this bone relative to parent 00150 writeObject(pBone->getPosition()); 00151 // Quaternion orientation : orientation of this bone relative to parent 00152 writeObject(pBone->getOrientation()); 00153 } 00154 //--------------------------------------------------------------------- 00155 void SkeletonSerializer::writeBoneParent(unsigned short boneId, unsigned short parentId) 00156 { 00157 writeChunkHeader(SKELETON_BONE_PARENT, calcBoneParentSize()); 00158 00159 // unsigned short handle : child bone 00160 writeShorts(&boneId, 1); 00161 // unsigned short parentHandle : parent bone 00162 writeShorts(&parentId, 1); 00163 00164 } 00165 //--------------------------------------------------------------------- 00166 void SkeletonSerializer::writeAnimation(const Animation* anim) 00167 { 00168 writeChunkHeader(SKELETON_ANIMATION, calcAnimationSize(anim)); 00169 00170 // char* name : Name of the animation 00171 writeString(anim->getName()); 00172 // Real length : Length of the animation in seconds 00173 Real len = anim->getLength(); 00174 writeReals(&len, 1); 00175 00176 // Write all tracks 00177 for (unsigned short i = 0; i < anim->getNumTracks(); ++i) 00178 { 00179 writeAnimationTrack(anim->getTrack(i)); 00180 } 00181 00182 } 00183 //--------------------------------------------------------------------- 00184 void SkeletonSerializer::writeAnimationTrack(const AnimationTrack* track) 00185 { 00186 writeChunkHeader(SKELETON_ANIMATION_TRACK, calcAnimationTrackSize(track)); 00187 00188 // unsigned short boneIndex : Index of bone to apply to 00189 Bone* bone = (Bone*)track->getAssociatedNode(); 00190 unsigned short boneid = bone->getHandle(); 00191 writeShorts(&boneid, 1); 00192 00193 // Write all keyframes 00194 for (unsigned short i = 0; i < track->getNumKeyFrames(); ++i) 00195 { 00196 writeKeyFrame(track->getKeyFrame(i)); 00197 } 00198 00199 } 00200 //--------------------------------------------------------------------- 00201 void SkeletonSerializer::writeKeyFrame(const KeyFrame* key) 00202 { 00203 00204 writeChunkHeader(SKELETON_ANIMATION_TRACK_KEYFRAME, calcKeyFrameSize(key)); 00205 00206 // Real time : The time position (seconds) 00207 Real time = key->getTime(); 00208 writeReals(&time, 1); 00209 // Quaternion rotate : Rotation to apply at this keyframe 00210 writeObject(key->getRotation()); 00211 // Vector3 translate : Translation to apply at this keyframe 00212 writeObject(key->getTranslate()); 00213 } 00214 //--------------------------------------------------------------------- 00215 unsigned long SkeletonSerializer::calcBoneSize(const Bone* pBone) 00216 { 00217 unsigned long size = CHUNK_OVERHEAD_SIZE; 00218 00219 // handle 00220 size += sizeof(unsigned short); 00221 00222 // position 00223 size += sizeof(Real) * 3; 00224 00225 // orientation 00226 size += sizeof(Real) * 4; 00227 00228 return size; 00229 00230 } 00231 //--------------------------------------------------------------------- 00232 unsigned long SkeletonSerializer::calcBoneParentSize(void) 00233 { 00234 unsigned long size = CHUNK_OVERHEAD_SIZE; 00235 00236 // handle 00237 size += sizeof(unsigned short); 00238 00239 // parent handle 00240 size += sizeof(unsigned short); 00241 00242 return size; 00243 00244 } 00245 //--------------------------------------------------------------------- 00246 unsigned long SkeletonSerializer::calcAnimationSize(const Animation* pAnim) 00247 { 00248 unsigned long size = CHUNK_OVERHEAD_SIZE; 00249 00250 // Name, including terminator 00251 size += (unsigned long)pAnim->getName().length() + 1; 00252 // length 00253 size += sizeof(Real); 00254 00255 // Nested animation tracks 00256 for (unsigned short i = 0; i < pAnim->getNumTracks(); ++i) 00257 { 00258 size += calcAnimationTrackSize(pAnim->getTrack(i)); 00259 } 00260 00261 00262 return size; 00263 00264 } 00265 //--------------------------------------------------------------------- 00266 unsigned long SkeletonSerializer::calcAnimationTrackSize(const AnimationTrack* pTrack) 00267 { 00268 unsigned long size = CHUNK_OVERHEAD_SIZE; 00269 00270 // unsigned short boneIndex : Index of bone to apply to 00271 size += sizeof(unsigned short); 00272 00273 // Nested keyframes 00274 for (unsigned short i = 0; i < pTrack->getNumKeyFrames(); ++i) 00275 { 00276 size += calcKeyFrameSize(pTrack->getKeyFrame(i)); 00277 } 00278 00279 00280 return size; 00281 } 00282 //--------------------------------------------------------------------- 00283 unsigned long SkeletonSerializer::calcKeyFrameSize(const KeyFrame* pKey) 00284 { 00285 unsigned long size = CHUNK_OVERHEAD_SIZE; 00286 00287 // Real time : The time position (seconds) 00288 size += sizeof(Real); 00289 // Quaternion rotate : Rotation to apply at this keyframe 00290 size += sizeof(Real) * 4; 00291 // Vector3 translate : Translation to apply at this keyframe 00292 size += sizeof(Real) * 3; 00293 00294 return size; 00295 } 00296 //--------------------------------------------------------------------- 00297 void SkeletonSerializer::readBone(DataChunk &chunk) 00298 { 00299 // char* name 00300 String name = readString(chunk); 00301 // unsigned short handle : handle of the bone, should be contiguous & start at 0 00302 unsigned short handle; 00303 readShorts(chunk, &handle, 1); 00304 00305 // Create new bone 00306 Bone* pBone = mpSkeleton->createBone(name, handle); 00307 00308 // Vector3 position : position of this bone relative to parent 00309 Vector3 pos; 00310 readObject(chunk, &pos); 00311 pBone->setPosition(pos); 00312 // Quaternion orientation : orientation of this bone relative to parent 00313 Quaternion q; 00314 readObject(chunk, &q); 00315 pBone->setOrientation(q); 00316 } 00317 //--------------------------------------------------------------------- 00318 void SkeletonSerializer::readBoneParent(DataChunk &chunk) 00319 { 00320 // All bones have been created by this point 00321 Bone *child, *parent; 00322 unsigned short childHandle, parentHandle; 00323 00324 // unsigned short handle : child bone 00325 readShorts(chunk, &childHandle, 1); 00326 // unsigned short parentHandle : parent bone 00327 readShorts(chunk, &parentHandle, 1); 00328 00329 // Find bones 00330 parent = mpSkeleton->getBone(parentHandle); 00331 child = mpSkeleton->getBone(childHandle); 00332 00333 // attach 00334 parent->addChild(child); 00335 00336 } 00337 //--------------------------------------------------------------------- 00338 void SkeletonSerializer::readAnimation(DataChunk &chunk) 00339 { 00340 // char* name : Name of the animation 00341 String name; 00342 name = readString(chunk); 00343 // Real length : Length of the animation in seconds 00344 Real len; 00345 readReals(chunk, &len, 1); 00346 00347 Animation *pAnim = mpSkeleton->createAnimation(name, len); 00348 00349 // Read all tracks 00350 if (!chunk.isEOF()) 00351 { 00352 unsigned short chunkID = readChunk(chunk); 00353 while(chunkID == SKELETON_ANIMATION_TRACK && !chunk.isEOF()) 00354 { 00355 readAnimationTrack(chunk, pAnim); 00356 00357 if (!chunk.isEOF()) 00358 { 00359 // Get next chunk 00360 chunkID = readChunk(chunk); 00361 } 00362 } 00363 if (!chunk.isEOF()) 00364 { 00365 // Backpedal back to start of this chunk if we've found a non-track 00366 chunk.skip(-(long)CHUNK_OVERHEAD_SIZE); 00367 } 00368 00369 } 00370 00371 00372 00373 } 00374 //--------------------------------------------------------------------- 00375 void SkeletonSerializer::readAnimationTrack(DataChunk &chunk, Animation* anim) 00376 { 00377 // unsigned short boneIndex : Index of bone to apply to 00378 unsigned short boneHandle; 00379 readShorts(chunk, &boneHandle, 1); 00380 00381 // Find bone 00382 Bone *targetBone = mpSkeleton->getBone(boneHandle); 00383 00384 // Create track 00385 AnimationTrack* pTrack = anim->createTrack(boneHandle, targetBone); 00386 00387 // Keep looking for nested keyframes 00388 if (!chunk.isEOF()) 00389 { 00390 unsigned short chunkID = readChunk(chunk); 00391 while(chunkID == SKELETON_ANIMATION_TRACK_KEYFRAME && !chunk.isEOF()) 00392 { 00393 readKeyFrame(chunk, pTrack); 00394 00395 if (!chunk.isEOF()) 00396 { 00397 // Get next chunk 00398 chunkID = readChunk(chunk); 00399 } 00400 } 00401 if (!chunk.isEOF()) 00402 { 00403 // Backpedal back to start of this chunk if we've found a non-keyframe 00404 chunk.skip(-(long)CHUNK_OVERHEAD_SIZE); 00405 } 00406 00407 } 00408 00409 00410 } 00411 //--------------------------------------------------------------------- 00412 void SkeletonSerializer::readKeyFrame(DataChunk &chunk, AnimationTrack* track) 00413 { 00414 // Real time : The time position (seconds) 00415 Real time; 00416 readReals(chunk, &time, 1); 00417 00418 KeyFrame *kf = track->createKeyFrame(time); 00419 00420 // Quaternion rotate : Rotation to apply at this keyframe 00421 Quaternion rot; 00422 readObject(chunk, &rot); 00423 kf->setRotation(rot); 00424 // Vector3 translate : Translation to apply at this keyframe 00425 Vector3 trans; 00426 readObject(chunk, &trans); 00427 kf->setTranslate(trans); 00428 } 00429 //--------------------------------------------------------------------- 00430 00431 00432 00433 } 00434 00435
Copyright © 2002-2003 by The OGRE Team
Last modified Wed Jan 21 00:10:28 2004