Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreSkeletonSerializer.cpp @ 3

Last change on this file since 3 was 3, checked in by anonymous, 17 years ago

=update

File size: 19.0 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29#include "OgreStableHeaders.h"
30
31#include "OgreSkeletonFileFormat.h"
32#include "OgreSkeletonSerializer.h"
33#include "OgreSkeleton.h"
34#include "OgreAnimation.h"
35#include "OgreAnimationTrack.h"
36#include "OgreKeyFrame.h"
37#include "OgreBone.h"
38#include "OgreString.h"
39#include "OgreDataStream.h"
40#include "OgreLogManager.h"
41
42
43
44
45namespace Ogre {
46    /// stream overhead = ID + size
47    const long STREAM_OVERHEAD_SIZE = sizeof(uint16) + sizeof(uint32);
48    //---------------------------------------------------------------------
49    SkeletonSerializer::SkeletonSerializer()
50    {
51        // Version number
52        // NB changed to include bone names in 1.1
53        mVersion = "[Serializer_v1.10]";
54    }
55    //---------------------------------------------------------------------
56    SkeletonSerializer::~SkeletonSerializer()
57    {
58    }
59    //---------------------------------------------------------------------
60    void SkeletonSerializer::exportSkeleton(const Skeleton* pSkeleton, 
61                const String& filename, Endian endianMode)
62    {
63                // Decide on endian mode
64                determineEndianness(endianMode);
65
66        String msg;
67        mpfFile = fopen(filename.c_str(), "wb");
68                if (!mpfFile)
69                {
70                        OGRE_EXCEPT(Exception::ERR_CANNOT_WRITE_TO_FILE,
71                                "Unable to open file " + filename + " for writing",
72                                "SkeletonSerializer::exportSkeleton");
73                }
74
75        writeFileHeader();
76
77        // Write main skeleton data
78        LogManager::getSingleton().logMessage("Exporting bones..");
79        writeSkeleton(pSkeleton);
80        LogManager::getSingleton().logMessage("Bones exported.");
81
82        // Write all animations
83        unsigned short numAnims = pSkeleton->getNumAnimations();
84        msg = "Exporting animations, count=";
85                StringUtil::StrStreamType num;
86                num << numAnims;
87        msg += num.str();
88        LogManager::getSingleton().logMessage(msg);
89        for (unsigned short i = 0; i < numAnims; ++i)
90        {
91            Animation* pAnim = pSkeleton->getAnimation(i);
92            msg = "Exporting animation: " + pAnim->getName();
93            LogManager::getSingleton().logMessage(msg);
94            writeAnimation(pSkeleton, pAnim);
95            LogManager::getSingleton().logMessage("Animation exported.");
96
97        }
98
99                // Write links
100                Skeleton::LinkedSkeletonAnimSourceIterator linkIt = 
101                        pSkeleton->getLinkedSkeletonAnimationSourceIterator();
102                while(linkIt.hasMoreElements())
103                {
104                        const LinkedSkeletonAnimationSource& link = linkIt.getNext();
105                        writeSkeletonAnimationLink(pSkeleton, link);
106                }
107
108        fclose(mpfFile);
109
110    }
111    //---------------------------------------------------------------------
112    void SkeletonSerializer::importSkeleton(DataStreamPtr& stream, Skeleton* pSkel)
113    {
114                // Determine endianness (must be the first thing we do!)
115                determineEndianness(stream);
116
117                // Check header
118        readFileHeader(stream);
119
120        unsigned short streamID;
121        while(!stream->eof())
122        {
123            streamID = readChunk(stream);
124            switch (streamID)
125            {
126            case SKELETON_BONE:
127                readBone(stream, pSkel);
128                break;
129            case SKELETON_BONE_PARENT:
130                readBoneParent(stream, pSkel);
131                break;
132            case SKELETON_ANIMATION:
133                readAnimation(stream, pSkel);
134                                break;
135                        case SKELETON_ANIMATION_LINK:
136                                readSkeletonAnimationLink(stream, pSkel);
137                                break;
138            }
139        }
140
141        // Assume bones are stored in the binding pose
142        pSkel->setBindingPose();
143
144
145    }
146    //---------------------------------------------------------------------
147    void SkeletonSerializer::writeSkeleton(const Skeleton* pSkel)
148    {
149        // Write each bone
150        unsigned short numBones = pSkel->getNumBones();
151        unsigned short i;
152        for (i = 0; i < numBones; ++i)
153        {
154            Bone* pBone = pSkel->getBone(i);
155            writeBone(pSkel, pBone);
156        }
157        // Write parents
158        for (i = 0; i < numBones; ++i)
159        {
160            Bone* pBone = pSkel->getBone(i);
161            unsigned short handle = pBone->getHandle();
162            Bone* pParent = (Bone*)pBone->getParent(); 
163            if (pParent != NULL) 
164            {
165                writeBoneParent(pSkel, handle, pParent->getHandle());             
166            }
167        }
168    }
169    //---------------------------------------------------------------------
170    void SkeletonSerializer::writeBone(const Skeleton* pSkel, const Bone* pBone)
171    {
172        writeChunkHeader(SKELETON_BONE, calcBoneSize(pSkel, pBone));
173
174        unsigned short handle = pBone->getHandle();
175        // char* name
176        writeString(pBone->getName());
177        // unsigned short handle            : handle of the bone, should be contiguous & start at 0
178        writeShorts(&handle, 1);
179        // Vector3 position                 : position of this bone relative to parent
180        writeObject(pBone->getPosition());
181        // Quaternion orientation           : orientation of this bone relative to parent
182        writeObject(pBone->getOrientation());
183        // Vector3 scale                    : scale of this bone relative to parent
184        if (pBone->getScale() != Vector3::UNIT_SCALE)
185        {
186            writeObject(pBone->getScale());
187        }
188    }
189    //---------------------------------------------------------------------
190    void SkeletonSerializer::writeBoneParent(const Skeleton* pSkel, 
191        unsigned short boneId, unsigned short parentId)
192    {
193        writeChunkHeader(SKELETON_BONE_PARENT, calcBoneParentSize(pSkel));
194
195        // unsigned short handle             : child bone
196        writeShorts(&boneId, 1);
197        // unsigned short parentHandle   : parent bone
198        writeShorts(&parentId, 1);
199
200    }
201    //---------------------------------------------------------------------
202    void SkeletonSerializer::writeAnimation(const Skeleton* pSkel, 
203        const Animation* anim)
204    {
205        writeChunkHeader(SKELETON_ANIMATION, calcAnimationSize(pSkel, anim));
206
207        // char* name                       : Name of the animation
208        writeString(anim->getName());
209        // float length                      : Length of the animation in seconds
210        float len = anim->getLength();
211        writeFloats(&len, 1);
212
213        // Write all tracks
214        Animation::NodeTrackIterator trackIt = anim->getNodeTrackIterator();
215        while(trackIt.hasMoreElements())
216        {
217            writeAnimationTrack(pSkel, trackIt.getNext());
218        }
219
220    }
221    //---------------------------------------------------------------------
222    void SkeletonSerializer::writeAnimationTrack(const Skeleton* pSkel, 
223        const NodeAnimationTrack* track)
224    {
225        writeChunkHeader(SKELETON_ANIMATION_TRACK, calcAnimationTrackSize(pSkel, track));
226
227        // unsigned short boneIndex     : Index of bone to apply to
228        Bone* bone = (Bone*)track->getAssociatedNode();
229        unsigned short boneid = bone->getHandle();
230        writeShorts(&boneid, 1);
231
232        // Write all keyframes
233        for (unsigned short i = 0; i < track->getNumKeyFrames(); ++i)
234        {
235            writeKeyFrame(pSkel, track->getNodeKeyFrame(i));
236        }
237
238    }
239    //---------------------------------------------------------------------
240    void SkeletonSerializer::writeKeyFrame(const Skeleton* pSkel, 
241        const TransformKeyFrame* key)
242    {
243
244        writeChunkHeader(SKELETON_ANIMATION_TRACK_KEYFRAME, 
245            calcKeyFrameSize(pSkel, key));
246
247        // float time                    : The time position (seconds)
248        float time = key->getTime();
249        writeFloats(&time, 1);
250        // Quaternion rotate            : Rotation to apply at this keyframe
251        writeObject(key->getRotation());
252        // Vector3 translate            : Translation to apply at this keyframe
253        writeObject(key->getTranslate());
254        // Vector3 scale                : Scale to apply at this keyframe
255        if (key->getScale() != Vector3::UNIT_SCALE)
256        {
257            writeObject(key->getScale());
258        }
259    }
260    //---------------------------------------------------------------------
261    size_t SkeletonSerializer::calcBoneSize(const Skeleton* pSkel, 
262        const Bone* pBone)
263    {
264        size_t size = STREAM_OVERHEAD_SIZE;
265
266        // handle
267        size += sizeof(unsigned short);
268
269        // position
270        size += sizeof(float) * 3;
271
272        // orientation
273        size += sizeof(float) * 4;
274
275        // scale
276        if (pBone->getScale() != Vector3::UNIT_SCALE)
277        {
278            size += sizeof(float) * 3;
279        }
280
281        return size;
282    }
283    //---------------------------------------------------------------------
284    size_t SkeletonSerializer::calcBoneSizeWithoutScale(const Skeleton* pSkel, 
285        const Bone* pBone)
286    {
287        size_t size = STREAM_OVERHEAD_SIZE;
288
289        // handle
290        size += sizeof(unsigned short);
291
292        // position
293        size += sizeof(float) * 3;
294
295        // orientation
296        size += sizeof(float) * 4;
297
298        return size;
299    }
300    //---------------------------------------------------------------------
301    size_t SkeletonSerializer::calcBoneParentSize(const Skeleton* pSkel)
302    {
303        size_t size = STREAM_OVERHEAD_SIZE;
304
305        // handle
306        size += sizeof(unsigned short);
307
308        // parent handle
309        size += sizeof(unsigned short);
310
311        return size;
312    }
313    //---------------------------------------------------------------------
314    size_t SkeletonSerializer::calcAnimationSize(const Skeleton* pSkel, 
315        const Animation* pAnim)
316    {
317        size_t size = STREAM_OVERHEAD_SIZE;
318
319        // Name, including terminator
320        size += pAnim->getName().length() + 1;
321        // length
322        size += sizeof(float);
323
324        // Nested animation tracks
325                Animation::NodeTrackIterator trackIt = pAnim->getNodeTrackIterator();
326                while(trackIt.hasMoreElements())
327                {
328            size += calcAnimationTrackSize(pSkel, trackIt.getNext());
329        }
330
331        return size;
332    }
333    //---------------------------------------------------------------------
334    size_t SkeletonSerializer::calcAnimationTrackSize(const Skeleton* pSkel, 
335        const NodeAnimationTrack* pTrack)
336    {
337        size_t size = STREAM_OVERHEAD_SIZE;
338
339        // unsigned short boneIndex     : Index of bone to apply to
340        size += sizeof(unsigned short);
341
342        // Nested keyframes
343        for (unsigned short i = 0; i < pTrack->getNumKeyFrames(); ++i)
344        {
345            size += calcKeyFrameSize(pSkel, pTrack->getNodeKeyFrame(i));
346        }
347
348        return size;
349    }
350    //---------------------------------------------------------------------
351    size_t SkeletonSerializer::calcKeyFrameSize(const Skeleton* pSkel, 
352        const TransformKeyFrame* pKey)
353    {
354        size_t size = STREAM_OVERHEAD_SIZE;
355
356        // float time                    : The time position (seconds)
357        size += sizeof(float);
358        // Quaternion rotate            : Rotation to apply at this keyframe
359        size += sizeof(float) * 4;
360        // Vector3 translate            : Translation to apply at this keyframe
361        size += sizeof(float) * 3;
362        // Vector3 scale                : Scale to apply at this keyframe
363        if (pKey->getScale() != Vector3::UNIT_SCALE)
364        {
365            size += sizeof(float) * 3;
366        }
367
368        return size;
369    }
370    //---------------------------------------------------------------------
371    size_t SkeletonSerializer::calcKeyFrameSizeWithoutScale(const Skeleton* pSkel, 
372        const TransformKeyFrame* pKey)
373    {
374        size_t size = STREAM_OVERHEAD_SIZE;
375
376        // float time                    : The time position (seconds)
377        size += sizeof(float);
378        // Quaternion rotate            : Rotation to apply at this keyframe
379        size += sizeof(float) * 4;
380        // Vector3 translate            : Translation to apply at this keyframe
381        size += sizeof(float) * 3;
382
383        return size;
384    }
385    //---------------------------------------------------------------------
386    void SkeletonSerializer::readBone(DataStreamPtr& stream, Skeleton* pSkel)
387    {
388        // char* name
389        String name = readString(stream);
390        // unsigned short handle            : handle of the bone, should be contiguous & start at 0
391        unsigned short handle;
392        readShorts(stream, &handle, 1);
393
394        // Create new bone
395        Bone* pBone = pSkel->createBone(name, handle);
396
397        // Vector3 position                 : position of this bone relative to parent
398        Vector3 pos;
399        readObject(stream, pos);
400        pBone->setPosition(pos);
401        // Quaternion orientation           : orientation of this bone relative to parent
402        Quaternion q;
403        readObject(stream, q);
404        pBone->setOrientation(q);
405        // Do we have scale?
406        if (mCurrentstreamLen > calcBoneSizeWithoutScale(pSkel, pBone))
407        {
408            Vector3 scale;
409            readObject(stream, scale);
410            pBone->setScale(scale);
411        }
412    }
413    //---------------------------------------------------------------------
414    void SkeletonSerializer::readBoneParent(DataStreamPtr& stream, Skeleton* pSkel)
415    {
416        // All bones have been created by this point
417        Bone *child, *parent;
418        unsigned short childHandle, parentHandle;
419
420        // unsigned short handle             : child bone
421        readShorts(stream, &childHandle, 1);
422        // unsigned short parentHandle   : parent bone
423        readShorts(stream, &parentHandle, 1);
424
425        // Find bones
426        parent = pSkel->getBone(parentHandle);
427        child = pSkel->getBone(childHandle);
428
429        // attach
430        parent->addChild(child);
431
432    }
433    //---------------------------------------------------------------------
434    void SkeletonSerializer::readAnimation(DataStreamPtr& stream, Skeleton* pSkel)
435    {
436        // char* name                       : Name of the animation
437        String name;
438        name = readString(stream);
439        // float length                      : Length of the animation in seconds
440        float len;
441        readFloats(stream, &len, 1);
442
443        Animation *pAnim = pSkel->createAnimation(name, len);
444
445        // Read all tracks
446        if (!stream->eof())
447        {
448            unsigned short streamID = readChunk(stream);
449            while(streamID == SKELETON_ANIMATION_TRACK && !stream->eof())
450            {
451                readAnimationTrack(stream, pAnim, pSkel);
452
453                if (!stream->eof())
454                {
455                    // Get next stream
456                    streamID = readChunk(stream);
457                }
458            }
459            if (!stream->eof())
460            {
461                // Backpedal back to start of this stream if we've found a non-track
462                stream->skip(-STREAM_OVERHEAD_SIZE);
463            }
464
465        }
466
467
468
469    }
470    //---------------------------------------------------------------------
471    void SkeletonSerializer::readAnimationTrack(DataStreamPtr& stream, Animation* anim, 
472        Skeleton* pSkel)
473    {
474        // unsigned short boneIndex     : Index of bone to apply to
475        unsigned short boneHandle;
476        readShorts(stream, &boneHandle, 1);
477
478        // Find bone
479        Bone *targetBone = pSkel->getBone(boneHandle);
480
481        // Create track
482        NodeAnimationTrack* pTrack = anim->createNodeTrack(boneHandle, targetBone);
483
484        // Keep looking for nested keyframes
485        if (!stream->eof())
486        {
487            unsigned short streamID = readChunk(stream);
488            while(streamID == SKELETON_ANIMATION_TRACK_KEYFRAME && !stream->eof())
489            {
490                readKeyFrame(stream, pTrack, pSkel);
491
492                if (!stream->eof())
493                {
494                    // Get next stream
495                    streamID = readChunk(stream);
496                }
497            }
498            if (!stream->eof())
499            {
500                // Backpedal back to start of this stream if we've found a non-keyframe
501                stream->skip(-STREAM_OVERHEAD_SIZE);
502            }
503
504        }
505
506
507    }
508    //---------------------------------------------------------------------
509    void SkeletonSerializer::readKeyFrame(DataStreamPtr& stream, NodeAnimationTrack* track, 
510        Skeleton* pSkel)
511    {
512        // float time                    : The time position (seconds)
513        float time;
514        readFloats(stream, &time, 1);
515
516        TransformKeyFrame *kf = track->createNodeKeyFrame(time);
517
518        // Quaternion rotate            : Rotation to apply at this keyframe
519        Quaternion rot;
520        readObject(stream, rot);
521        kf->setRotation(rot);
522        // Vector3 translate            : Translation to apply at this keyframe
523        Vector3 trans;
524        readObject(stream, trans);
525        kf->setTranslate(trans);
526        // Do we have scale?
527        if (mCurrentstreamLen > calcKeyFrameSizeWithoutScale(pSkel, kf))
528        {
529            Vector3 scale;
530            readObject(stream, scale);
531            kf->setScale(scale);
532        }
533    }
534        //---------------------------------------------------------------------
535        void SkeletonSerializer::writeSkeletonAnimationLink(const Skeleton* pSkel, 
536                const LinkedSkeletonAnimationSource& link)
537        {
538                writeChunkHeader(SKELETON_ANIMATION_LINK, 
539                        calcSkeletonAnimationLinkSize(pSkel, link));
540
541                // char* skeletonName
542                writeString(link.skeletonName);
543                // float scale
544                writeFloats(&(link.scale), 1);
545
546        }
547    //---------------------------------------------------------------------
548        size_t SkeletonSerializer::calcSkeletonAnimationLinkSize(const Skeleton* pSkel, 
549                const LinkedSkeletonAnimationSource& link)
550        {
551                size_t size = STREAM_OVERHEAD_SIZE;
552
553                // char* skeletonName
554                size += link.skeletonName.length() + 1;
555                // float scale
556                size += sizeof(float);
557
558                return size;
559
560        }
561        //---------------------------------------------------------------------
562        void SkeletonSerializer::readSkeletonAnimationLink(DataStreamPtr& stream, 
563                Skeleton* pSkel)
564        {
565                // char* skeletonName
566                String skelName = readString(stream);
567                // float scale
568                float scale;
569                readFloats(stream, &scale, 1);
570
571                pSkel->addLinkedSkeletonAnimationSource(skelName, scale);
572
573        }
574
575
576
577}
578
579
Note: See TracBrowser for help on using the repository browser.