From 6c3e9f5151fac4906c2fabc2e26ee39bc7043664 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Sun, 5 Jul 2009 03:24:46 +0000 Subject: [PATCH] * API change for Animation and AnimObj; AnimObj is now a proper class and each instance handles its own animation. Animation handles adding, fetching and deleting of AnimObjs (probably needs a namechange). * Implemented actual animation (previously only the first frame was display) * Implemented animation starting, stoping, looping * Loaded looping dragon animation as a test svn-id: r42114 --- engines/draci/animation.cpp | 231 +++++++++++++++++++++++++++--------- engines/draci/animation.h | 61 ++++++++-- engines/draci/game.cpp | 10 +- 3 files changed, 227 insertions(+), 75 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 5e6578de575..a29281d510e 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -28,111 +28,224 @@ namespace Draci { -void Animation::addAnimation(uint id, uint z, bool playing) { +AnimObj::AnimObj(DraciEngine *vm) : _vm(vm) { + _id = kUnused; + _z = 0; + _playing = false; + _looping = false; + _delay = 0; + _tick = _vm->_system->getMillis(); + _currentFrame = 0; +} + +AnimObj::~AnimObj() { + deleteFrames(); +} + +bool AnimObj::isLooping() { + return _looping; +} + +void AnimObj::setLooping(bool looping) { + _looping = looping; +} + +void AnimObj::setDelay(uint delay) { + _delay = delay; +} + +void AnimObj::nextFrame(bool force) { + + // If there's only one or no frames, return + if (getFramesNum() < 2) + return; + + Common::Rect frameRect = _frames[_currentFrame]->getRect(); + + // If we are at the last frame and not looping, stop the animation + // The animation is also restarted to frame zero + if ((_currentFrame == nextFrameNum() - 1) && !_looping) { + _currentFrame = 0; + _playing = false; + return; + } + + if (force || (_tick + _delay <= _vm->_system->getMillis())) { + _vm->_screen->getSurface()->markDirtyRect(frameRect); + _currentFrame = nextFrameNum(); + _tick = _vm->_system->getMillis(); + } + + debugC(6, kDraciAnimationDebugLevel, + "tick=%d delay=%d tick+delay=%d currenttime=%d frame=%d framenum=%d", + _tick, _delay, _tick + _delay, _vm->_system->getMillis(), _currentFrame, _frames.size()); +} + +uint AnimObj::nextFrameNum() { + + if ((_currentFrame == getFramesNum() - 1) && _looping) + return 0; + else + return _currentFrame + 1; +} + +void AnimObj::drawFrame(Surface *surface) { - AnimObj *obj = new AnimObj(); - obj->_id = id; - obj->_z = z; - obj->_currentFrame = 0; - obj->_playing = playing; + if (_frames.size() == 0) + return; - insertAnimation(*obj); + if (_id == kOverlayImage) { + _frames[_currentFrame]->draw(surface, false); + } + else { + _frames[_currentFrame]->draw(surface, true); + } } -void Animation::play(uint id) { - - AnimObj &obj = *getAnimation(id); - - obj._playing = true; -} - -void Animation::stop(uint id) { - - AnimObj &obj = *getAnimation(id); - - obj._playing = false; -} - -Common::List::iterator Animation::getAnimation(uint id) { +void AnimObj::setID(int id) { - Common::List::iterator it; + _id = id; +} + +int AnimObj::getID() { + + return _id; +} + +void AnimObj::setZ(uint z) { + + _z = z; +} + +uint AnimObj::getZ() { + + return _z; +} + +bool AnimObj::isPlaying() { + + return _playing; +} + +void AnimObj::setPlaying(bool playing) { + + _playing = playing; +} + +void AnimObj::addFrame(Drawable *frame) { + + _frames.push_back(frame); +} + +uint AnimObj::getFramesNum() { + + return _frames.size(); +} + +void AnimObj::deleteFrames() { + + for (uint i = 0; i < getFramesNum(); ++i) { + delete _frames[i]; + _frames.pop_back(); + } +} + +AnimObj *Animation::addAnimation(int id, uint z, bool playing) { + + AnimObj *obj = new AnimObj(_vm); + obj->setID(id); + obj->setZ(z); + obj->setPlaying(playing); + obj->setLooping(false); + + insertAnimation(obj); + + return obj; +} + +void Animation::play(int id) { + + AnimObj *obj = getAnimation(id); + + obj->setPlaying(true); +} + +void Animation::stop(int id) { + + AnimObj *obj = getAnimation(id); + + obj->setPlaying(false); +} + +AnimObj *Animation::getAnimation(int id) { + + Common::List::iterator it; for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { - if (it->_id == id) { - return it; + if ((*it)->getID() == id) { + return *it; } } - return _animObjects.end(); + return *_animObjects.end(); } -void Animation::insertAnimation(AnimObj &animObj) { +void Animation::insertAnimation(AnimObj *animObj) { - Common::List::iterator it; + Common::List::iterator it; for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { - if (animObj._z < it->_z) + if (animObj->getZ() < (*it)->getZ()) break; } _animObjects.insert(it, animObj); } -void Animation::addFrame(uint id, Drawable *frame) { - - Common::List::iterator it = getAnimation(id); - - it->_frames.push_back(frame); -} - void Animation::addOverlay(Drawable *overlay, uint z) { - AnimObj *obj = new AnimObj(); - obj->_id = kOverlayImage; - obj->_z = z; - obj->_currentFrame = 0; - obj->_playing = true; - obj->_frames.push_back(overlay); + AnimObj *obj = new AnimObj(_vm); + obj->setID(kOverlayImage); + obj->setZ(z); + obj->setPlaying(true); + obj->addFrame(overlay); - insertAnimation(*obj); + insertAnimation(obj); } void Animation::drawScene(Surface *surf) { - Common::List::iterator it; + Common::List::iterator it; for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { - if (!it->_playing) { + if (! ((*it)->isPlaying()) ) { continue; } - if (it->_id == kOverlayImage) { - it->_frames[it->_currentFrame]->draw(surf, false); - } - else { - it->_frames[it->_currentFrame]->draw(surf, true); - } + (*it)->nextFrame(); + (*it)->drawFrame(surf); } } -void Animation::deleteAnimation(uint id) { +void Animation::deleteAnimation(int id) { - Common::List::iterator it = getAnimation(id); + Common::List::iterator it; - for (uint i = 0; i < it->_frames.size(); ++i) { - delete it->_frames[i]; + for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { + if ((*it)->getID() == id) + break; } + + (*it)->deleteFrames(); _animObjects.erase(it); } void Animation::deleteAll() { - Common::List::iterator it; + Common::List::iterator it; for (it = _animObjects.begin(); it != _animObjects.end(); ++it) { - for (uint i = 0; i < it->_frames.size(); ++i) { - delete it->_frames[i]; - } + (*it)->deleteFrames(); } _animObjects.clear(); diff --git a/engines/draci/animation.h b/engines/draci/animation.h index c69947ea281..d4be8b5ba38 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -30,44 +30,81 @@ namespace Draci { -enum { kOverlayImage = -1 }; +enum { kOverlayImage = -1, kUnused = -2 }; class DraciEngine; -struct AnimObj { - uint _id; +class AnimObj { +public: + AnimObj(DraciEngine *vm); + ~AnimObj(); + + uint getZ(); + void setZ(uint z); + + void setID(int id); + int getID(); + + void setDelay(uint delay); + + void nextFrame(bool force = false); + void drawFrame(Surface *surface); + + void addFrame(Drawable *frame); + uint getFramesNum(); + void deleteFrames(); + + bool isPlaying(); + void setPlaying(bool playing); + + bool isLooping(); + void setLooping(bool looping); + + +private: + + uint nextFrameNum(); + + int _id; uint _currentFrame; uint _z; - bool _playing; + uint _delay; + uint _tick; + bool _playing; + bool _looping; Common::Array _frames; + + DraciEngine *_vm; }; +// TODO: Probably needs a namechange to AnimationManager or similar since AnimObj now +// acts as an animation object + class Animation { public: Animation(DraciEngine *vm) : _vm(vm) {}; ~Animation() { deleteAll(); } - void addAnimation(uint id, uint z, bool playing = false); - void addFrame(uint id, Drawable *frame); + AnimObj *addAnimation(int id, uint z, bool playing = false); void addOverlay(Drawable *overlay, uint z); - void play(uint id); - void stop(uint id); + void play(int id); + void stop(int id); - void deleteAnimation(uint id); + void deleteAnimation(int id); void deleteAll(); void drawScene(Surface *surf); - Common::List::iterator getAnimation(uint id); + AnimObj *getAnimation(int id); private: - void insertAnimation(AnimObj &animObj); + void insertAnimation(AnimObj *animObj); DraciEngine *_vm; - Common::List _animObjects; + Common::List _animObjects; }; } diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index b24d62d36d1..a843a8267ee 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -189,7 +189,7 @@ int Game::loadAnimation(uint animNum) { animationReader.readByte(); // Cyclic field, not used animationReader.readByte(); // Relative field, not used - _vm->_anims->addAnimation(animNum, 254, false); + AnimObj *obj = _vm->_anims->addAnimation(animNum, 254, false); for (uint i = 0; i < numFrames; ++i) { uint spriteNum = animationReader.readUint16LE() - 1; @@ -202,8 +202,7 @@ int Game::loadAnimation(uint animNum) { uint freq = animationReader.readUint16LE(); uint delay = animationReader.readUint16LE(); - // TODO: implement Animation::setDelay() - //_vm->_anims->setDelay(animNum, delay*10); + obj->setDelay(delay * 10); BAFile *spriteFile = _vm->_spritesArchive->getFile(spriteNum); @@ -212,7 +211,10 @@ int Game::loadAnimation(uint animNum) { if (mirror) sp->setMirrorOn(); - _vm->_anims->addFrame(animNum, sp); + // HACK: This is only for testing + obj->setLooping(true); + + obj->addFrame(sp); } return animNum;