Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OgreSkeletonSerializer.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 
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 Fri May 14 23:22:48 2004