mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-25 13:42:37 +00:00
* 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
This commit is contained in:
parent
18301b6f78
commit
a2a71cb8fb
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user