diff options
author | Denis Kasak | 2009-07-20 17:25:57 +0000 |
---|---|---|
committer | Denis Kasak | 2009-07-20 17:25:57 +0000 |
commit | a2a71cb8fbdbf1426d73c6f09f315abf04cfcbb9 (patch) | |
tree | 9775895526760b51efd16912422aacb122859368 | |
parent | 18301b6f78fd6d7eb77b5055129b71d2b8dce270 (diff) | |
download | scummvm-rg350-a2a71cb8fbdbf1426d73c6f09f315abf04cfcbb9.tar.gz scummvm-rg350-a2a71cb8fbdbf1426d73c6f09f315abf04cfcbb9.tar.bz2 scummvm-rg350-a2a71cb8fbdbf1426d73c6f09f315abf04cfcbb9.zip |
* Added scaling support
* Made the dragon scale when it is in different parts of the room
* Added getters for relative coordinates (Animation::getRelativeX() and Animation::getRelativeY())
* Commented Game::loop() and Sprite::draw*() methods in more detail
svn-id: r42627
-rw-r--r-- | engines/draci/animation.cpp | 70 | ||||
-rw-r--r-- | engines/draci/animation.h | 18 | ||||
-rw-r--r-- | engines/draci/game.cpp | 22 | ||||
-rw-r--r-- | engines/draci/game.h | 3 | ||||
-rw-r--r-- | engines/draci/sprite.cpp | 107 | ||||
-rw-r--r-- | engines/draci/sprite.h | 13 |
6 files changed, 217 insertions, 16 deletions
diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index b5f0d6b806..3faa85ac63 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -33,6 +33,8 @@ Animation::Animation(DraciEngine *vm) : _vm(vm) { _z = 0; _relX = 0; _relY = 0; + _scaleX = 1.0; + _scaleY = 1.0; setPlaying(false); _looping = false; _tick = _vm->_system->getMillis(); @@ -50,7 +52,14 @@ bool Animation::isLooping() { void Animation::setRelative(int relx, int rely) { // Delete the previous frame - Common::Rect frameRect = _frames[_currentFrame]->getRect(); + Common::Rect frameRect; + + if (isScaled()) { + frameRect = getFrame()->getScaledRect(_scaleX, _scaleY); + } else { + frameRect = getFrame()->getRect(); + } + frameRect.translate(_relX, _relY); _vm->_screen->getSurface()->markDirtyRect(frameRect); @@ -58,6 +67,24 @@ void Animation::setRelative(int relx, int rely) { _relY = rely; } +void Animation::setScaling(double scalex, double scaley) { + + _scaleX = scalex; + _scaleY = scaley; +} + +bool Animation::isScaled() const { + return !(_scaleX == 1.0 && _scaleY == 1.0); +} + +double Animation::getScaleX() const { + return _scaleX; +} + +double Animation::getScaleY() const { + return _scaleY; +} + void Animation::setLooping(bool looping) { _looping = looping; debugC(7, kDraciAnimationDebugLevel, "Setting looping to %d on animation %d", @@ -72,7 +99,13 @@ void Animation::nextFrame(bool force) { Drawable *frame = _frames[_currentFrame]; - Common::Rect frameRect = frame->getRect(); + Common::Rect frameRect; + + if (isScaled()) { + frameRect = frame->getScaledRect(_scaleX, _scaleY); + } else { + frameRect = frame->getRect(); + } // Translate rectangle to compensate for relative coordinates frameRect.translate(_relX, _relY); @@ -111,19 +144,29 @@ void Animation::drawFrame(Surface *surface) { return; if (_id == kOverlayImage) { - _frames[_currentFrame]->draw(surface, false); + _frames[_currentFrame]->drawScaled(surface, _scaleX, _scaleY, false); } else { Drawable *ptr = _frames[_currentFrame]; + int x = ptr->getX(); int y = ptr->getY(); + + // Take account relative coordinates int newX = x + _relX; int newY = y + _relY; + // Translate the frame to those relative coordinates ptr->setX(newX); ptr->setY(newY); - ptr->draw(surface, true); + // Draw frame + if (isScaled()) + ptr->drawScaled(surface, _scaleX, _scaleY, true); + else + ptr->drawScaled(surface, _scaleX, _scaleY, true); + + // Revert back to old coordinates ptr->setX(x); ptr->setY(y); } @@ -145,6 +188,14 @@ uint Animation::getZ() { return _z; } +int Animation::getRelativeX() { + return _relX; +} + +int Animation::getRelativeY() { + return _relY; +} + bool Animation::isPlaying() { return _playing; } @@ -208,8 +259,15 @@ void AnimationManager::stop(int id) { Animation *anim = getAnimation(id); // Clean up the last frame that was drawn before stopping - Common::Rect frameRect = anim->getFrame()->getRect(); - frameRect.translate(anim->_relX, anim->_relY); + Common::Rect frameRect; + + if (anim->isScaled()) { + frameRect = anim->getFrame()->getScaledRect(anim->getScaleX(), anim->getScaleY()); + } else { + frameRect = anim->getFrame()->getRect(); + } + + frameRect.translate(anim->getRelativeX(), anim->getRelativeY()); _vm->_screen->getSurface()->markDirtyRect(frameRect); if (anim) { diff --git a/engines/draci/animation.h b/engines/draci/animation.h index 66988482f0..0aab82f5e7 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -37,7 +37,7 @@ enum { kCurrentFrame = -1 }; class DraciEngine; class Animation { - + public: Animation(DraciEngine *vm); ~Animation(); @@ -62,10 +62,14 @@ public: bool isLooping(); void setLooping(bool looping); - void setRelative(int relx, int rely); + double getScaleX() const; + double getScaleY() const; + void setScaling(double scalex, double scaley); + bool isScaled() const; - int _relX; - int _relY; + void setRelative(int relx, int rely); + int getRelativeX(); + int getRelativeY(); private: @@ -75,6 +79,12 @@ private: uint _currentFrame; uint _z; + int _relX; + int _relY; + + double _scaleX; + double _scaleY; + uint _tick; bool _playing; bool _looping; diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index d913eb904f..46de4825fc 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -171,16 +171,33 @@ void Game::loop() { if (_vm->_mouse->lButtonPressed() && _currentRoom._walkingMap.isWalkable(x, y)) { + // Fetch dragon's animation ID + // FIXME: Need to add proper walking (this only warps the dragon to position) int animID = getObject(kDragonObject)->_anims[0]; Animation *anim = _vm->_anims->getAnimation(animID); Drawable *frame = anim->getFrame(); + // Calculate scaling factor + double scaleX = _currentRoom._pers0 + _currentRoom._persStep * y; + double scaleY = scaleX; + + // Calculate scaled height of sprite + int height = frame->getScaledHeight(scaleY); + + // Set the Z coordinate for the dragon's animation anim->setZ(y+1); - y -= frame->getHeight(); - anim->setRelative(x, y); + // We naturally want the dragon to position its feet to the location of the + // click but sprites are drawn from their top-left corner so we subtract + // the height of the dragon's sprite + y -= height; + anim->setRelative(x, y); + + // Set the scaling factor + anim->setScaling(scaleX, scaleY); + // Play the animation _vm->_anims->play(animID); debugC(4, kDraciLogicDebugLevel, "Walk to x: %d y: %d", x, y); @@ -221,6 +238,7 @@ void Game::loadRoom(int roomNum) { for (int i = 5; i >= 0; --i) { real[i] = roomReader.readByte(); + debug(2, "%d", real[i]); } _currentRoom._pers0 = real_to_double(real); diff --git a/engines/draci/game.h b/engines/draci/game.h index 0c3dddae20..511ce95e85 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -134,6 +134,9 @@ struct Room { class Game { + // HACK: Remove this before committing; if anyone sees this, remind me :D + friend class Animation; + public: Game(DraciEngine *vm); diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index dae7a289a2..9f1cb3371d 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -29,6 +29,8 @@ #include "draci/sprite.h" #include "draci/font.h" +#include <cmath> + namespace Draci { /** @@ -115,6 +117,87 @@ void Sprite::setMirrorOff() { _mirror = false; } +// TODO: Research what kind of sampling the original player uses +void Sprite::drawScaled(Surface *surface, double scaleX, double scaleY, bool markDirty) const { + + Common::Rect sourceRect(0, 0, _width, _height); + Common::Rect destRect(_x, _y, _x + getScaledWidth(scaleX), _y + getScaledHeight(scaleY)); + Common::Rect surfaceRect(0, 0, surface->w, surface->h); + Common::Rect clippedDestRect(destRect); + + clippedDestRect.clip(surfaceRect); + + // Calculate by how much we need to adjust the source rectangle to account for cropping + const int adjustLeft = clippedDestRect.left - destRect.left; + const int adjustRight = clippedDestRect.right - destRect.right; + const int adjustTop = clippedDestRect.top - destRect.top; + const int adjustBottom = clippedDestRect.bottom - destRect.bottom; + + // Resize source rectangle + sourceRect.left += adjustLeft; + sourceRect.right += adjustRight; + sourceRect.top += adjustTop; + sourceRect.bottom += adjustBottom; + + // Get pointers to source and destination buffers + byte *dst = (byte *)surface->getBasePtr(clippedDestRect.left, clippedDestRect.top); + byte *src = _data; + + const int transparent = surface->getTransparentColour(); + + // Calculate how many rows and columns we need to draw + const int rows = clippedDestRect.bottom - clippedDestRect.top; + const int columns = clippedDestRect.right - clippedDestRect.left; + + int *rowIndices = new int[rows]; + int *columnIndices = new int[columns]; + + // Precalculate pixel indexes + for (int i = 0; i < rows; ++i) { + rowIndices[i] = lround(i / scaleY); + } + + for (int j = 0; j < columns; ++j) { + columnIndices[j] = lround(j / scaleX); + } + + // Blit the sprite to the surface + for (int i = 0; i < rows; ++i) { + + // Fetch index of current row to be drawn + int row = rowIndices[i]; + + for (int j = 0, q = sourceRect.left; j < columns; ++j, ++q) { + + // Fetch index of current column to be drawn + int column = columnIndices[j]; + + // Don't blit if the pixel is transparent on the target surface + if (src[row * _width + column] != transparent) { + + // Draw the sprite mirrored if the _mirror flag is set + if (_mirror) { + dst[sourceRect.right - q - 1] = src[row * _width + column]; + } else { + dst[q] = src[row * _width + column]; + } + } + } + + // Advance to next row + dst += surface->pitch; + } + + // Mark the sprite's rectangle dirty + if (markDirty) { + surface->markDirtyRect(destRect); + } + + delete[] rowIndices; + delete[] columnIndices; +} + + /** * @brief Draws the sprite to a Draci::Surface * @param surface Pointer to a Draci::Surface @@ -131,16 +214,19 @@ void Sprite::draw(Surface *surface, bool markDirty) const { clippedDestRect.clip(surfaceRect); - int adjustLeft = clippedDestRect.left - destRect.left; - int adjustRight = clippedDestRect.right - destRect.right; - int adjustTop = clippedDestRect.top - destRect.top; - int adjustBottom = clippedDestRect.bottom - destRect.bottom; + // Calculate by how much we need to adjust the source rectangle to account for cropping + const int adjustLeft = clippedDestRect.left - destRect.left; + const int adjustRight = clippedDestRect.right - destRect.right; + const int adjustTop = clippedDestRect.top - destRect.top; + const int adjustBottom = clippedDestRect.bottom - destRect.bottom; + // Resize source rectangle sourceRect.left += adjustLeft; sourceRect.right += adjustRight; sourceRect.top += adjustTop; sourceRect.bottom += adjustBottom; + // Get pointers to source and destination buffers byte *dst = (byte *)surface->getBasePtr(clippedDestRect.left, clippedDestRect.top); byte *src = _data; @@ -162,6 +248,7 @@ void Sprite::draw(Surface *surface, bool markDirty) const { } } + // Advance to next row dst += surface->pitch; } @@ -175,6 +262,18 @@ Common::Rect Sprite::getRect() const { return Common::Rect(_x, _y, _x + _width, _y + _height); } +Common::Rect Sprite::getScaledRect(double scaleX, double scaleY) const { + return Common::Rect(_x, _y, _x + getScaledWidth(scaleX), _y + getScaledHeight(scaleY)); +} + +uint Sprite::getScaledHeight(double scaleY) const { + return lround(scaleY * _height); +} + +uint Sprite::getScaledWidth(double scaleX) const { + return lround(scaleX * _width); +} + Text::Text(const Common::String &str, Font *font, byte fontColour, int x, int y, uint spacing) { uint len = str.size(); diff --git a/engines/draci/sprite.h b/engines/draci/sprite.h index 38ee2736ea..88a2858671 100644 --- a/engines/draci/sprite.h +++ b/engines/draci/sprite.h @@ -38,11 +38,17 @@ friend class Text; public: virtual void draw(Surface *surface, bool markDirty = true) const = 0; + virtual void drawScaled(Surface *surface, double scaleX, double scaleY, + bool markDirty = true) const = 0; + virtual ~Drawable() {}; virtual uint16 getWidth() { return _width; } virtual uint16 getHeight() { return _height; } + virtual uint getScaledWidth(double scaleX) const = 0; + virtual uint getScaledHeight(double scaleY) const = 0; + virtual int getX() { return _x; } virtual int getY() { return _y; } @@ -53,6 +59,7 @@ public: int getDelay() { return _delay; } virtual Common::Rect getRect() const = 0; + virtual Common::Rect getScaledRect(double scaleX, double scaleY) const = 0; private: uint16 _width; //!< Width of the sprite @@ -89,11 +96,17 @@ public: ~Sprite(); void draw(Surface *surface, bool markDirty = true) const; + void drawScaled(Surface *surface, double scaleX, double scaleY, bool markDirty = true) const; void setMirrorOn(); void setMirrorOff(); virtual Common::Rect getRect() const; + Common::Rect getScaledRect(double scaleX, double scaleY) const; + + virtual uint getScaledWidth(double scaleX) const; + virtual uint getScaledHeight(double scaleY) const; + const byte *getBuffer() const { return _data; } private: |