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

Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:47 2004