diff options
author | Robert Špalek | 2009-11-07 01:28:27 +0000 |
---|---|---|
committer | Robert Špalek | 2009-11-07 01:28:27 +0000 |
commit | 357d9989d4c6ae73e02a044b388f36069e093ce0 (patch) | |
tree | 06d8453b5babaa0c5a844ff0f31e56652276c665 | |
parent | fdad4e7b543af2debcc35492e46c979ab1dd8fec (diff) | |
download | scummvm-rg350-357d9989d4c6ae73e02a044b388f36069e093ce0.tar.gz scummvm-rg350-357d9989d4c6ae73e02a044b388f36069e093ce0.tar.bz2 scummvm-rg350-357d9989d4c6ae73e02a044b388f36069e093ce0.zip |
Implemented relative animations.
In these animations, each sprite can specify a relative shift with respect
to the previous sprite. Moving animations (such as walking of the dragon)
are easily described in this framework. I have sort of hacked their support
and it seems to work.
The current walking code does not interact with the new code yet, but it will
be easy to do.
svn-id: r45712
-rw-r--r-- | engines/draci/animation.cpp | 49 | ||||
-rw-r--r-- | engines/draci/animation.h | 9 | ||||
-rw-r--r-- | engines/draci/game.cpp | 10 | ||||
-rw-r--r-- | engines/draci/walking.cpp | 3 |
4 files changed, 56 insertions, 15 deletions
diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 674e2473df..9d56c89674 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -33,6 +33,7 @@ Animation::Animation(DraciEngine *vm, int index) : _vm(vm) { _id = kUnused; _index = index; _z = 0; + clearShift(); _displacement = kNoDisplacement; _playing = false; _looping = false; @@ -56,6 +57,13 @@ void Animation::setRelative(int relx, int rely) { _displacement.relY = rely; } +Displacement Animation::getCurrentFrameDisplacement() const { + Displacement dis = _displacement; + dis.relX += (int) (dis.extraScaleX * _shift.x); + dis.relY += (int) (dis.extraScaleY * _shift.y); + return dis; +} + void Animation::setLooping(bool looping) { _looping = looping; debugC(7, kDraciAnimationDebugLevel, "Setting looping to %d on animation %d", @@ -67,8 +75,8 @@ void Animation::markDirtyRect(Surface *surface) const { return; // Fetch the current frame's rectangle - Drawable *frame = _frames[_currentFrame]; - Common::Rect frameRect = frame->getRect(_displacement); + const Drawable *frame = getConstCurrentFrame(); + Common::Rect frameRect = frame->getRect(getCurrentFrameDisplacement()); // Mark the rectangle dirty on the surface surface->markDirtyRect(frameRect); @@ -79,7 +87,7 @@ void Animation::nextFrame(bool force) { if (getFrameCount() == 0 || !_playing) return; - Drawable *frame = _frames[_currentFrame]; + const Drawable *frame = getConstCurrentFrame(); Surface *surface = _vm->_screen->getSurface(); if (force || (_tick + frame->getDelay() <= _vm->_system->getMillis())) { @@ -92,7 +100,12 @@ void Animation::nextFrame(bool force) { // Mark old frame dirty so it gets deleted markDirtyRect(surface); + _shift.x += _relativeShifts[_currentFrame].x; + _shift.y += _relativeShifts[_currentFrame].y; _currentFrame = nextFrameNum(); + if (!_currentFrame) { + clearShift(); // TODO: don't do that, but rather let the animation fly away when needed. + } _tick = _vm->_system->getMillis(); // Fetch new frame and mark it dirty @@ -123,13 +136,15 @@ void Animation::drawFrame(Surface *surface) { if (_frames.size() == 0 || !_playing) return; - const Drawable *frame = _frames[_currentFrame]; + const Drawable *frame = getConstCurrentFrame(); if (_id == kOverlayImage) { + // No displacement or relative animations is supported. frame->draw(surface, false, 0, 0); } else { - // Draw frame - frame->drawReScaled(surface, false, _displacement); + // Draw frame: first shifted by the relative shift and then + // scaled/shifted by the given displacement. + frame->drawReScaled(surface, false, getCurrentFrameDisplacement()); } const SoundSample *sample = _samples[_currentFrame]; @@ -164,6 +179,15 @@ void Animation::setScaleFactors(double scaleX, double scaleY) { void Animation::addFrame(Drawable *frame, const SoundSample *sample) { _frames.push_back(frame); _samples.push_back(sample); + _relativeShifts.push_back(Common::Point(0, 0)); +} + +void Animation::makeLastFrameRelative(int x, int y) { + _relativeShifts.back() = Common::Point(x, y); +} + +void Animation::clearShift() { + _shift = Common::Point(0, 0); } void Animation::replaceFrame(int i, Drawable *frame, const SoundSample *sample) { @@ -171,6 +195,11 @@ void Animation::replaceFrame(int i, Drawable *frame, const SoundSample *sample) _samples[i] = sample; } +const Drawable *Animation::getConstCurrentFrame() const { + // If there are no frames stored, return NULL + return _frames.size() > 0 ? _frames[_currentFrame] : NULL; +} + Drawable *Animation::getCurrentFrame() { // If there are no frames stored, return NULL return _frames.size() > 0 ? _frames[_currentFrame] : NULL; @@ -202,6 +231,7 @@ void Animation::deleteFrames() { delete _frames[i]; _frames.pop_back(); } + _relativeShifts.clear(); _samples.clear(); } @@ -280,6 +310,7 @@ void AnimationManager::stop(int id) { // Reset the animation to the beginning anim->setCurrentFrame(0); + anim->clearShift(); debugC(3, kDraciAnimationDebugLevel, "Stopping animation %d...", id); } @@ -499,19 +530,19 @@ int AnimationManager::getTopAnimationID(int x, int y) const { continue; } - const Drawable *frame = anim->getCurrentFrame(); + const Drawable *frame = anim->getConstCurrentFrame(); if (frame == NULL) { continue; } - if (frame->getRect(anim->getDisplacement()).contains(x, y)) { + if (frame->getRect(anim->getCurrentFrameDisplacement()).contains(x, y)) { if (frame->getType() == kDrawableText) { retval = anim->getID(); } else if (frame->getType() == kDrawableSprite && - reinterpret_cast<const Sprite *>(frame)->getPixel(x, y, anim->getDisplacement()) != transparent) { + reinterpret_cast<const Sprite *>(frame)->getPixel(x, y, anim->getCurrentFrameDisplacement()) != transparent) { retval = anim->getID(); } diff --git a/engines/draci/animation.h b/engines/draci/animation.h index 473e875941..9fd5a87f97 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -28,6 +28,7 @@ #include "draci/sprite.h" #include "draci/sound.h" +#include "common/rect.h" namespace Draci { @@ -75,11 +76,14 @@ public: void addFrame(Drawable *frame, const SoundSample *sample); void replaceFrame(int i, Drawable *frame, const SoundSample *sample); + const Drawable *getConstCurrentFrame() const; Drawable *getCurrentFrame(); Drawable *getFrame(int frameNum); void setCurrentFrame(uint frame); uint currentFrameNum() const { return _currentFrame; } uint getFrameCount() const { return _frames.size(); } + void makeLastFrameRelative(int x, int y); + void clearShift(); bool isPlaying() const { return _playing; } void setPlaying(bool playing); @@ -93,7 +97,8 @@ public: void setRelative(int relx, int rely); int getRelativeX() const { return _displacement.relX; } int getRelativeY() const { return _displacement.relY; } - const Displacement &getDisplacement() const { return _displacement; } + const Displacement &getDisplacement() const { return _displacement; } // displacement of the whole animation + Displacement getCurrentFrameDisplacement() const; // displacement of the current frame (includes _shift) int getIndex() const { return _index; } void setIndex(int index) { _index = index; } @@ -132,6 +137,7 @@ private: uint _currentFrame; uint _z; + Common::Point _shift; // partial sum of _relativeShifts from the beginning of the animation until the current frame bool _hasChangedFrame; Displacement _displacement; @@ -144,6 +150,7 @@ private: /** Array of frames of the animation. The animation object owns these pointers. */ Common::Array<Drawable *> _frames; + Common::Array<Common::Point> _relativeShifts; /** Array of samples played during the animation. The animation * object doesn't own these pointers, but they are stored in the * cache. diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 15ec8028f4..ed5768fd42 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -1194,9 +1194,7 @@ int Game::loadAnimation(uint animNum, uint z) { // into details. animationReader.readByte(); const bool cyclic = animationReader.readByte(); - - // FIXME: handle this properly - animationReader.readByte(); // Relative field, not used + const bool relative = animationReader.readByte(); Animation *anim = _vm->_anims->addAnimation(animNum, z, false); @@ -1216,7 +1214,8 @@ int Game::loadAnimation(uint animNum, uint z) { // _spritesArchive is flushed when entering a room. All // scripts in a room are responsible for loading their animations. const BAFile *spriteFile = _vm->_spritesArchive->getFile(spriteNum); - Sprite *sp = new Sprite(spriteFile->_data, spriteFile->_length, x, y, true); + Sprite *sp = new Sprite(spriteFile->_data, spriteFile->_length, + relative ? 0 : x, relative ? 0 : y, true); // Some frames set the scaled dimensions to 0 even though other frames // from the same animations have them set to normal values @@ -1239,6 +1238,9 @@ int Game::loadAnimation(uint animNum, uint z) { const SoundSample *sam = _vm->_soundsArchive->getSample(sample, freq); anim->addFrame(sp, sam); + if (relative) { + anim->makeLastFrameRelative(x, y); + } } return animNum; diff --git a/engines/draci/walking.cpp b/engines/draci/walking.cpp index 4a0e65c9b3..9edffc6996 100644 --- a/engines/draci/walking.cpp +++ b/engines/draci/walking.cpp @@ -522,8 +522,9 @@ bool WalkingState::continueWalking() { // We are walking in the middle of an edge. The animation phase has // just changed. Update the position of the hero. + _position += 4; // TODO: compute shifts properly from the animation Common::Point newPos = WalkingMap::interpolate( - _path[_segment], _path[_segment+1], ++_position, _length); + _path[_segment], _path[_segment+1], _position, _length); _vm->_game->setHeroPosition(newPos); _vm->_game->positionAnimAsHero(anim); |