History: AnimationSerializer-cpp
Source of version: 1 (current)
Copy to clipboard
{CODE(wrap="1", colors="c++")}/*
-----------------------------------------------------------------------------
Copyright (c) 2010 Jacob 'jacmoe' Moen
You may use this sample code for anything you like, it is public domain.
-----------------------------------------------------------------------------
*/
/*
-----------------------------------------------------------------------------
Filename: AnimationSerializer.cpp
Description: A serializer for keyframe animations
-----------------------------------------------------------------------------
*/
#include "AnimationSerializer.h"
#include "OgrePrerequisites.h"
#include "OgreException.h"
#include "OgreAnimation.h"
#include "OgreAnimationTrack.h"
#include "OgreKeyFrame.h"
#include "OgreString.h"
#include "OgreDataStream.h"
#include "OgreLogManager.h"
#include "OgreResourceGroupManager.h"
#include "OgreStringConverter.h"
/// stream overhead = ID + size
const long STREAM_OVERHEAD_SIZE = sizeof(Ogre::uint16) + sizeof(Ogre::uint32);
AnimationSerializer::AnimationSerializer()
{
mVersion = "[AnimationSerializer.10]";
}
AnimationSerializer::~AnimationSerializer()
{
}
void AnimationSerializer::exportAnimation(const Ogre::Animation* pAnimation, const Ogre::String& filename,
Endian endianMode)
{
// Decide on endian mode
determineEndianness(endianMode);
Ogre::String msg;
mpfFile = fopen(filename.c_str(), "wb");
if (!mpfFile)
{
OGRE_EXCEPT(Ogre::Exception::ERR_CANNOT_WRITE_TO_FILE,
"Unable to open file " + filename + " for writing",
"AnimationSerializer::exportAnimation");
}
writeFileHeader();
Ogre::LogManager::getSingleton().stream()
<< "Exporting animation: " << pAnimation->getName();
writeAnimation(pAnimation);
Ogre::LogManager::getSingleton().logMessage("Animation exported.");
fclose(mpfFile);
}
Ogre::Animation* AnimationSerializer::importAnimation(const Ogre::String& filename)
{
Ogre::DataStreamPtr stream = Ogre::ResourceGroupManager::getSingleton().openResource(filename);
return importAnimation(stream);
}
Ogre::Animation* AnimationSerializer::importAnimation(Ogre::DataStreamPtr& stream)
{
// Determine endianness (must be the first thing we do!)
determineEndianness(stream);
// Check header
readFileHeader(stream);
Ogre::Animation* anim;
unsigned short streamID;
while(!stream->eof())
{
streamID = readChunk(stream);
switch (streamID)
{
case AC_ANIMATION:
anim = readAnimation(stream);
break;
}
}
return anim;
}
void AnimationSerializer::writeAnimation(const Ogre::Animation* anim)
{
writeChunkHeader(AC_ANIMATION, calcAnimationSize(anim));
// char* name : Name of the animation
writeString(anim->getName());
// float length : Length of the animation in seconds
float len = anim->getLength();
writeFloats(&len, 1);
// Write all tracks
Ogre::Animation::NodeTrackIterator trackIt = anim->getNodeTrackIterator();
while(trackIt.hasMoreElements())
{
writeAnimationTrack(trackIt.getNext());
}
}
void AnimationSerializer::writeAnimationTrack(const Ogre::NodeAnimationTrack* track)
{
static unsigned short trackId = 0;
writeChunkHeader(AC_ANIMATION_TRACK, calcAnimationTrackSize(track));
writeShorts(&trackId, 1);
// Write all keyframes
for (unsigned short i = 0; i < track->getNumKeyFrames(); ++i)
{
writeKeyFrame(track->getNodeKeyFrame(i));
}
trackId++;
}
void AnimationSerializer::writeKeyFrame(const Ogre::TransformKeyFrame* key)
{
writeChunkHeader(AC_ANIMATION_TRACK_KEYFRAME,
calcKeyFrameSize(key));
// float time : The time position (seconds)
float time = key->getTime();
writeFloats(&time, 1);
// Quaternion rotate : Rotation to apply at this keyframe
writeObject(key->getRotation());
// Vector3 translate : Translation to apply at this keyframe
writeObject(key->getTranslate());
}
Ogre::Animation* AnimationSerializer::readAnimation(Ogre::DataStreamPtr& stream)
{
Ogre::String name;
name = readString(stream);
// float length : Length of the animation in seconds
float len;
readFloats(stream, &len, 1);
Ogre::Animation* anim = new Ogre::Animation(name, len);
// Read all tracks
if (!stream->eof())
{
unsigned short streamID = readChunk(stream);
while(streamID == AC_ANIMATION_TRACK && !stream->eof())
{
readAnimationTrack(stream, anim);
if (!stream->eof())
{
// Get next stream
streamID = readChunk(stream);
}
}
if (!stream->eof())
{
// Backpedal back to start of this stream if we've found a non-track
stream->skip(-STREAM_OVERHEAD_SIZE);
}
}
return anim;
}
void AnimationSerializer::readAnimationTrack(Ogre::DataStreamPtr& stream, Ogre::Animation* anim)
{
unsigned short trackId;
readShorts(stream, &trackId, 1);
// Create track
Ogre::NodeAnimationTrack* pTrack = anim->createNodeTrack(trackId);
// Keep looking for nested keyframes
if (!stream->eof())
{
unsigned short streamID = readChunk(stream);
while(streamID == AC_ANIMATION_TRACK_KEYFRAME && !stream->eof())
{
readKeyFrame(stream, pTrack);
if (!stream->eof())
{
// Get next stream
streamID = readChunk(stream);
}
}
if (!stream->eof())
{
// Backpedal back to start of this stream if we've found a non-keyframe
stream->skip(-STREAM_OVERHEAD_SIZE);
}
}
}
void AnimationSerializer::readKeyFrame(Ogre::DataStreamPtr& stream, Ogre::NodeAnimationTrack* track)
{
// float time : The time position (seconds)
float time;
readFloats(stream, &time, 1);
Ogre::TransformKeyFrame *kf = track->createNodeKeyFrame(time);
// Quaternion rotate : Rotation to apply at this keyframe
Ogre::Quaternion rot;
readObject(stream, rot);
kf->setRotation(rot);
// Vector3 translate : Translation to apply at this keyframe
Ogre::Vector3 trans;
readObject(stream, trans);
kf->setTranslate(trans);
}
size_t AnimationSerializer::calcAnimationSize(const Ogre::Animation* pAnim)
{
size_t size = STREAM_OVERHEAD_SIZE;
// Name, including terminator
size += pAnim->getName().length() + 1;
// length
size += sizeof(float);
// Nested animation tracks
Ogre::Animation::NodeTrackIterator trackIt = pAnim->getNodeTrackIterator();
while(trackIt.hasMoreElements())
{
size += calcAnimationTrackSize(trackIt.getNext());
}
return size;
}
size_t AnimationSerializer::calcAnimationTrackSize(const Ogre::NodeAnimationTrack* pTrack)
{
size_t size = STREAM_OVERHEAD_SIZE;
// unsigned short boneIndex : Index of bone to apply to
size += sizeof(unsigned short);
// Nested keyframes
for (unsigned short i = 0; i < pTrack->getNumKeyFrames(); ++i)
{
size += calcKeyFrameSize(pTrack->getNodeKeyFrame(i));
}
return size;
}
size_t AnimationSerializer::calcKeyFrameSize(const Ogre::TransformKeyFrame* pKey)
{
size_t size = STREAM_OVERHEAD_SIZE;
// float time : The time position (seconds)
size += sizeof(float);
// Quaternion rotate : Rotation to apply at this keyframe
size += sizeof(float) * 4;
// Vector3 translate : Translation to apply at this keyframe
size += sizeof(float) * 3;
return size;
}
{CODE}