From 357d9989d4c6ae73e02a044b388f36069e093ce0 Mon Sep 17 00:00:00 2001 From: Robert Špalek Date: Sat, 7 Nov 2009 01:28:27 +0000 Subject: 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 --- engines/draci/animation.cpp | 49 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 9 deletions(-) (limited to 'engines/draci/animation.cpp') 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(frame)->getPixel(x, y, anim->getDisplacement()) != transparent) { + reinterpret_cast(frame)->getPixel(x, y, anim->getCurrentFrameDisplacement()) != transparent) { retval = anim->getID(); } -- cgit v1.2.3