aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorDenis Kasak2009-07-20 17:25:57 +0000
committerDenis Kasak2009-07-20 17:25:57 +0000
commita2a71cb8fbdbf1426d73c6f09f315abf04cfcbb9 (patch)
tree9775895526760b51efd16912422aacb122859368 /engines
parent18301b6f78fd6d7eb77b5055129b71d2b8dce270 (diff)
downloadscummvm-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
Diffstat (limited to 'engines')
-rw-r--r--engines/draci/animation.cpp70
-rw-r--r--engines/draci/animation.h18
-rw-r--r--engines/draci/game.cpp22
-rw-r--r--engines/draci/game.h3
-rw-r--r--engines/draci/sprite.cpp107
-rw-r--r--engines/draci/sprite.h13
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: