source: OGRE/trunk/ogrenew/OgreMain/src/OgreSkeletonSerializer.cpp @ 657

Revision 657, 17.2 KB checked in by mattausch, 18 years ago (diff)

added ogre dependencies and patched ogre sources

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-2005 The OGRE Team
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-----------------------------------------------------------------------------
24*/
25#include "OgreStableHeaders.h"
26
27#include "OgreSkeletonFileFormat.h"
28#include "OgreSkeletonSerializer.h"
29#include "OgreSkeleton.h"
30#include "OgreAnimation.h"
31#include "OgreAnimationTrack.h"
32#include "OgreKeyFrame.h"
33#include "OgreBone.h"
34#include "OgreString.h"
35#include "OgreDataStream.h"
36#include "OgreLogManager.h"
37
38
39
40
41namespace Ogre {
42    /// stream overhead = ID + size
43    const long STREAM_OVERHEAD_SIZE = sizeof(uint16) + sizeof(uint32);
44    //---------------------------------------------------------------------
45    SkeletonSerializer::SkeletonSerializer()
46    {
47        // Version number
48        // NB changed to include bone names in 1.1
49        mVersion = "[Serializer_v1.10]";
50    }
51    //---------------------------------------------------------------------
52    SkeletonSerializer::~SkeletonSerializer()
53    {
54    }
55    //---------------------------------------------------------------------
56    void SkeletonSerializer::exportSkeleton(const Skeleton* pSkeleton, const String& filename)
57    {
58        String msg;
59        mpfFile = fopen(filename.c_str(), "wb");
60
61        writeFileHeader();
62
63        // Write main skeleton data
64        LogManager::getSingleton().logMessage("Exporting bones..");
65        writeSkeleton(pSkeleton);
66        LogManager::getSingleton().logMessage("Bones exported.");
67
68        // Write all animations
69        unsigned short numAnims = pSkeleton->getNumAnimations();
70        msg = "Exporting animations, count=";
71                StringUtil::StrStreamType num;
72                num << numAnims;
73        msg += num.str();
74        LogManager::getSingleton().logMessage(msg);
75        for (unsigned short i = 0; i < numAnims; ++i)
76        {
77            Animation* pAnim = pSkeleton->getAnimation(i);
78            msg = "Exporting animation: " + pAnim->getName();
79            LogManager::getSingleton().logMessage(msg);
80            writeAnimation(pSkeleton, pAnim);
81            LogManager::getSingleton().logMessage("Animation exported.");
82
83        }
84
85                // Write links
86                Skeleton::LinkedSkeletonAnimSourceIterator linkIt =
87                        pSkeleton->getLinkedSkeletonAnimationSourceIterator();
88                while(linkIt.hasMoreElements())
89                {
90                        const LinkedSkeletonAnimationSource& link = linkIt.getNext();
91                        writeSkeletonAnimationLink(pSkeleton, link);
92                }
93
94        fclose(mpfFile);
95
96    }
97    //---------------------------------------------------------------------
98    void SkeletonSerializer::importSkeleton(DataStreamPtr& stream, Skeleton* pSkel)
99    {
100
101        // Check header
102        readFileHeader(stream);
103
104        unsigned short streamID;
105        while(!stream->eof())
106        {
107            streamID = readChunk(stream);
108            switch (streamID)
109            {
110            case SKELETON_BONE:
111                readBone(stream, pSkel);
112                break;
113            case SKELETON_BONE_PARENT:
114                readBoneParent(stream, pSkel);
115                break;
116            case SKELETON_ANIMATION:
117                readAnimation(stream, pSkel);
118                                break;
119                        case SKELETON_ANIMATION_LINK:
120                                readSkeletonAnimationLink(stream, pSkel);
121                                break;
122            }
123        }
124
125        // Assume bones are stored in the binding pose
126        pSkel->setBindingPose();
127
128
129    }
130    //---------------------------------------------------------------------
131    void SkeletonSerializer::writeSkeleton(const Skeleton* pSkel)
132    {
133        // Write each bone
134        unsigned short numBones = pSkel->getNumBones();
135        unsigned short i;
136        for (i = 0; i < numBones; ++i)
137        {
138            Bone* pBone = pSkel->getBone(i);
139            writeBone(pSkel, pBone);
140        }
141        // Write parents
142        for (i = 0; i < numBones; ++i)
143        {
144            Bone* pBone = pSkel->getBone(i);
145            unsigned short handle = pBone->getHandle();
146            Bone* pParent = (Bone*)pBone->getParent();
147            if (pParent != NULL)
148            {
149                writeBoneParent(pSkel, handle, pParent->getHandle());             
150            }
151        }
152    }
153    //---------------------------------------------------------------------
154    void SkeletonSerializer::writeBone(const Skeleton* pSkel, const Bone* pBone)
155    {
156        writeChunkHeader(SKELETON_BONE, calcBoneSize(pSkel, pBone));
157
158        unsigned short handle = pBone->getHandle();
159        // char* name
160        writeString(pBone->getName());
161        // unsigned short handle            : handle of the bone, should be contiguous & start at 0
162        writeShorts(&handle, 1);
163        // Vector3 position                 : position of this bone relative to parent
164        writeObject(pBone->getPosition());
165        // Quaternion orientation           : orientation of this bone relative to parent
166        writeObject(pBone->getOrientation());
167    }
168    //---------------------------------------------------------------------
169    void SkeletonSerializer::writeBoneParent(const Skeleton* pSkel,
170        unsigned short boneId, unsigned short parentId)
171    {
172        writeChunkHeader(SKELETON_BONE_PARENT, calcBoneParentSize(pSkel));
173
174        // unsigned short handle             : child bone
175        writeShorts(&boneId, 1);
176        // unsigned short parentHandle   : parent bone
177        writeShorts(&parentId, 1);
178
179    }
180    //---------------------------------------------------------------------
181    void SkeletonSerializer::writeAnimation(const Skeleton* pSkel,
182        const Animation* anim)
183    {
184        writeChunkHeader(SKELETON_ANIMATION, calcAnimationSize(pSkel, anim));
185
186        // char* name                       : Name of the animation
187        writeString(anim->getName());
188        // float length                      : Length of the animation in seconds
189        float len = anim->getLength();
190        writeFloats(&len, 1);
191
192        // Write all tracks
193        Animation::TrackIterator trackIt = anim->getTrackIterator();
194        while(trackIt.hasMoreElements())
195        {
196            writeAnimationTrack(pSkel, trackIt.getNext());
197        }
198
199    }
200    //---------------------------------------------------------------------
201    void SkeletonSerializer::writeAnimationTrack(const Skeleton* pSkel,
202        const AnimationTrack* track)
203    {
204        writeChunkHeader(SKELETON_ANIMATION_TRACK, calcAnimationTrackSize(pSkel, track));
205
206        // unsigned short boneIndex     : Index of bone to apply to
207        Bone* bone = (Bone*)track->getAssociatedNode();
208        unsigned short boneid = bone->getHandle();
209        writeShorts(&boneid, 1);
210
211        // Write all keyframes
212        for (unsigned short i = 0; i < track->getNumKeyFrames(); ++i)
213        {
214            writeKeyFrame(pSkel, track->getKeyFrame(i));
215        }
216
217    }
218    //---------------------------------------------------------------------
219    void SkeletonSerializer::writeKeyFrame(const Skeleton* pSkel,
220        const KeyFrame* key)
221    {
222
223        writeChunkHeader(SKELETON_ANIMATION_TRACK_KEYFRAME,
224            calcKeyFrameSize(pSkel, key));
225
226        // float time                    : The time position (seconds)
227        float time = key->getTime();
228        writeFloats(&time, 1);
229        // Quaternion rotate            : Rotation to apply at this keyframe
230        writeObject(key->getRotation());
231        // Vector3 translate            : Translation to apply at this keyframe
232        writeObject(key->getTranslate());
233        // Vector3 scale                : Scale to apply at this keyframe
234        writeObject(key->getScale());
235    }
236    //---------------------------------------------------------------------
237    size_t SkeletonSerializer::calcBoneSize(const Skeleton* pSkel,
238        const Bone* pBone)
239    {
240        size_t size = STREAM_OVERHEAD_SIZE;
241
242        // handle
243        size += sizeof(unsigned short);
244
245        // position
246        size += sizeof(float) * 3;
247
248        // orientation
249        size += sizeof(float) * 4;
250
251        return size;
252    }
253    //---------------------------------------------------------------------
254    size_t SkeletonSerializer::calcBoneParentSize(const Skeleton* pSkel)
255    {
256        size_t size = STREAM_OVERHEAD_SIZE;
257
258        // handle
259        size += sizeof(unsigned short);
260
261        // parent handle
262        size += sizeof(unsigned short);
263
264        return size;
265    }
266    //---------------------------------------------------------------------
267    size_t SkeletonSerializer::calcAnimationSize(const Skeleton* pSkel,
268        const Animation* pAnim)
269    {
270        size_t size = STREAM_OVERHEAD_SIZE;
271
272        // Name, including terminator
273        size += pAnim->getName().length() + 1;
274        // length
275        size += sizeof(float);
276
277        // Nested animation tracks
278                Animation::TrackIterator trackIt = pAnim->getTrackIterator();
279                while(trackIt.hasMoreElements())
280                {
281            size += calcAnimationTrackSize(pSkel, trackIt.getNext());
282        }
283
284        return size;
285    }
286    //---------------------------------------------------------------------
287    size_t SkeletonSerializer::calcAnimationTrackSize(const Skeleton* pSkel,
288        const AnimationTrack* pTrack)
289    {
290        size_t size = STREAM_OVERHEAD_SIZE;
291
292        // unsigned short boneIndex     : Index of bone to apply to
293        size += sizeof(unsigned short);
294
295        // Nested keyframes
296        for (unsigned short i = 0; i < pTrack->getNumKeyFrames(); ++i)
297        {
298            size += calcKeyFrameSize(pSkel, pTrack->getKeyFrame(i));
299        }
300
301        return size;
302    }
303    //---------------------------------------------------------------------
304    size_t SkeletonSerializer::calcKeyFrameSize(const Skeleton* pSkel,
305        const KeyFrame* pKey)
306    {
307        size_t size = STREAM_OVERHEAD_SIZE;
308
309        // float time                    : The time position (seconds)
310        size += sizeof(float);
311        // Quaternion rotate            : Rotation to apply at this keyframe
312        size += sizeof(float) * 4;
313        // Vector3 translate            : Translation to apply at this keyframe
314        size += sizeof(float) * 3;
315        // Vector3 scale                : Scale to apply at this keyframe
316        size += sizeof(float) * 3;
317
318        return size;
319    }
320    //---------------------------------------------------------------------
321    void SkeletonSerializer::readBone(DataStreamPtr& stream, Skeleton* pSkel)
322    {
323        // char* name
324        String name = readString(stream);
325        // unsigned short handle            : handle of the bone, should be contiguous & start at 0
326        unsigned short handle;
327        readShorts(stream, &handle, 1);
328
329        // Create new bone
330        Bone* pBone = pSkel->createBone(name, handle);
331
332        // Vector3 position                 : position of this bone relative to parent
333        Vector3 pos;
334        readObject(stream, pos);
335        pBone->setPosition(pos);
336        // Quaternion orientation           : orientation of this bone relative to parent
337        Quaternion q;
338        readObject(stream, q);
339        pBone->setOrientation(q);
340    }
341    //---------------------------------------------------------------------
342    void SkeletonSerializer::readBoneParent(DataStreamPtr& stream, Skeleton* pSkel)
343    {
344        // All bones have been created by this point
345        Bone *child, *parent;
346        unsigned short childHandle, parentHandle;
347
348        // unsigned short handle             : child bone
349        readShorts(stream, &childHandle, 1);
350        // unsigned short parentHandle   : parent bone
351        readShorts(stream, &parentHandle, 1);
352
353        // Find bones
354        parent = pSkel->getBone(parentHandle);
355        child = pSkel->getBone(childHandle);
356
357        // attach
358        parent->addChild(child);
359
360    }
361    //---------------------------------------------------------------------
362    void SkeletonSerializer::readAnimation(DataStreamPtr& stream, Skeleton* pSkel)
363    {
364        // char* name                       : Name of the animation
365        String name;
366        name = readString(stream);
367        // float length                      : Length of the animation in seconds
368        float len;
369        readFloats(stream, &len, 1);
370
371        Animation *pAnim = pSkel->createAnimation(name, len);
372
373        // Read all tracks
374        if (!stream->eof())
375        {
376            unsigned short streamID = readChunk(stream);
377            while(streamID == SKELETON_ANIMATION_TRACK && !stream->eof())
378            {
379                readAnimationTrack(stream, pAnim, pSkel);
380
381                if (!stream->eof())
382                {
383                    // Get next stream
384                    streamID = readChunk(stream);
385                }
386            }
387            if (!stream->eof())
388            {
389                // Backpedal back to start of this stream if we've found a non-track
390                stream->skip(-STREAM_OVERHEAD_SIZE);
391            }
392
393        }
394
395
396
397    }
398    //---------------------------------------------------------------------
399    void SkeletonSerializer::readAnimationTrack(DataStreamPtr& stream, Animation* anim,
400        Skeleton* pSkel)
401    {
402        // unsigned short boneIndex     : Index of bone to apply to
403        unsigned short boneHandle;
404        readShorts(stream, &boneHandle, 1);
405
406        // Find bone
407        Bone *targetBone = pSkel->getBone(boneHandle);
408
409        // Create track
410        AnimationTrack* pTrack = anim->createTrack(boneHandle, targetBone);
411
412        // Keep looking for nested keyframes
413        if (!stream->eof())
414        {
415            unsigned short streamID = readChunk(stream);
416            while(streamID == SKELETON_ANIMATION_TRACK_KEYFRAME && !stream->eof())
417            {
418                readKeyFrame(stream, pTrack, pSkel);
419
420                if (!stream->eof())
421                {
422                    // Get next stream
423                    streamID = readChunk(stream);
424                }
425            }
426            if (!stream->eof())
427            {
428                // Backpedal back to start of this stream if we've found a non-keyframe
429                stream->skip(-STREAM_OVERHEAD_SIZE);
430            }
431
432        }
433
434
435    }
436    //---------------------------------------------------------------------
437    void SkeletonSerializer::readKeyFrame(DataStreamPtr& stream, AnimationTrack* track,
438        Skeleton* pSkel)
439    {
440        // float time                    : The time position (seconds)
441        float time;
442        readFloats(stream, &time, 1);
443
444        KeyFrame *kf = track->createKeyFrame(time);
445
446        // Quaternion rotate            : Rotation to apply at this keyframe
447        Quaternion rot;
448        readObject(stream, rot);
449        kf->setRotation(rot);
450        // Vector3 translate            : Translation to apply at this keyframe
451        Vector3 trans;
452        readObject(stream, trans);
453        kf->setTranslate(trans);
454        // Do we have scale?
455        if (mCurrentstreamLen == calcKeyFrameSize(pSkel, kf))
456        {
457            Vector3 scale;
458            readObject(stream, scale);
459            kf->setScale(scale);
460        }
461    }
462        //---------------------------------------------------------------------
463        void SkeletonSerializer::writeSkeletonAnimationLink(const Skeleton* pSkel,
464                const LinkedSkeletonAnimationSource& link)
465        {
466                writeChunkHeader(SKELETON_ANIMATION_LINK,
467                        calcSkeletonAnimationLinkSize(pSkel, link));
468
469                // char* skeletonName
470                writeString(link.skeletonName);
471                // float scale
472                writeFloats(&(link.scale), 1);
473
474        }
475    //---------------------------------------------------------------------
476        size_t SkeletonSerializer::calcSkeletonAnimationLinkSize(const Skeleton* pSkel,
477                const LinkedSkeletonAnimationSource& link)
478        {
479                size_t size = STREAM_OVERHEAD_SIZE;
480
481                // char* skeletonName
482                size += link.skeletonName.length() + 1;
483                // float scale
484                size += sizeof(float);
485
486                return size;
487
488        }
489        //---------------------------------------------------------------------
490        void SkeletonSerializer::readSkeletonAnimationLink(DataStreamPtr& stream,
491                Skeleton* pSkel)
492        {
493                // char* skeletonName
494                String skelName = readString(stream);
495                // float scale
496                float scale;
497                readFloats(stream, &scale, 1);
498
499                pSkel->addLinkedSkeletonAnimationSource(skelName, scale);
500
501        }
502
503
504
505}
506
507
Note: See TracBrowser for help on using the repository browser.