aboutsummaryrefslogtreecommitdiff
path: root/engines/xeen
diff options
context:
space:
mode:
authorPaul Gilbert2015-01-18 19:12:10 -0500
committerPaul Gilbert2015-01-18 19:12:10 -0500
commit07a10855be2f60ae253623c26c8bb0ac38e58af4 (patch)
treeeb8601359c50ac740a6fa529872a8fdb85938ca6 /engines/xeen
parentf18a8c364b2b2f608081bb79cad54de3abacd111 (diff)
downloadscummvm-rg350-07a10855be2f60ae253623c26c8bb0ac38e58af4.tar.gz
scummvm-rg350-07a10855be2f60ae253623c26c8bb0ac38e58af4.tar.bz2
scummvm-rg350-07a10855be2f60ae253623c26c8bb0ac38e58af4.zip
XEEN: In progress work on sprite scaling
Diffstat (limited to 'engines/xeen')
-rw-r--r--engines/xeen/screen.cpp2
-rw-r--r--engines/xeen/sprites.cpp34
-rw-r--r--engines/xeen/sprites.h3
-rw-r--r--engines/xeen/xsurface.cpp121
-rw-r--r--engines/xeen/xsurface.h3
5 files changed, 156 insertions, 7 deletions
diff --git a/engines/xeen/screen.cpp b/engines/xeen/screen.cpp
index b1b42ac551..de591d396d 100644
--- a/engines/xeen/screen.cpp
+++ b/engines/xeen/screen.cpp
@@ -178,7 +178,7 @@ void Window::drawList(DrawStruct *items, int count) {
// TODO: There are two sprite calls in this method. Figure out why
items->_sprites->draw(screen, items->_frame,
- Common::Point(items->_x, items->_y), items->_flags);
+ Common::Point(items->_x, items->_y), items->_flags, items->_scale);
}
}
diff --git a/engines/xeen/sprites.cpp b/engines/xeen/sprites.cpp
index 8a14ec0178..8ddf4ed48d 100644
--- a/engines/xeen/sprites.cpp
+++ b/engines/xeen/sprites.cpp
@@ -228,11 +228,35 @@ void SpriteResource::drawOffset(XSurface &dest, uint16 offset, const Common::Poi
dest.addDirtyRect(r);
}
-void SpriteResource::draw(XSurface &dest, int frame, const Common::Point &destPos, int flags) const {
- // TODO: Support the different flags
- drawOffset(dest, _index[frame]._offset1, destPos, flags);
- if (_index[frame]._offset2)
- drawOffset(dest, _index[frame]._offset2, destPos, flags);
+void SpriteResource::draw(XSurface &dest, int frame, const Common::Point &destPos,
+ int flags, int scale) const {
+ if (scale == 0) {
+ drawOffset(dest, _index[frame]._offset1, destPos, flags);
+ if (_index[frame]._offset2)
+ drawOffset(dest, _index[frame]._offset2, destPos, flags);
+ } else {
+ // Get the bounds for the surface and create a temporary one
+ Common::MemoryReadStream f(_data, _filesize);
+ f.seek(_index[frame]._offset1);
+ int xOffset = f.readUint16LE();
+ int width = f.readUint16LE();
+ int yOffset = f.readUint16LE();
+ int height = f.readUint16LE();
+ XSurface tempSurface(xOffset + width, yOffset + height);
+
+ // Draw sprite into temporary surface
+ tempSurface.fillRect(Common::Rect(0, 0, width, height), 0);
+ drawOffset(tempSurface, _index[frame]._offset1, Common::Point(), flags);
+ if (_index[frame]._offset2)
+ drawOffset(tempSurface, _index[frame]._offset2, Common::Point(), flags);
+
+ // TODO: I don't currently know the algorithm the original used for scaling.
+ // This is a best fit estimate that every increment of the scale field
+ // reduces the size of a sprite by approximately 6.6%
+ int newScale = MAX(100.0 - 6.6 * scale, 0.0);
+ if (newScale > 0)
+ tempSurface.transBlitTo(dest, Common::Point(), newScale, 0);
+ }
}
void SpriteResource::draw(XSurface &dest, int frame) const {
diff --git a/engines/xeen/sprites.h b/engines/xeen/sprites.h
index 973875cfed..d1a801e6ca 100644
--- a/engines/xeen/sprites.h
+++ b/engines/xeen/sprites.h
@@ -62,7 +62,8 @@ public:
void clear();
- void draw(XSurface &dest, int frame, const Common::Point &destPos, int flags = 0) const;
+ void draw(XSurface &dest, int frame, const Common::Point &destPos,
+ int flags = 0, int scale = 0) const;
void draw(XSurface &dest, int frame) const;
diff --git a/engines/xeen/xsurface.cpp b/engines/xeen/xsurface.cpp
index 698e478aee..b01ade17df 100644
--- a/engines/xeen/xsurface.cpp
+++ b/engines/xeen/xsurface.cpp
@@ -24,6 +24,7 @@
#include "common/util.h"
#include "xeen/xsurface.h"
#include "xeen/resources.h"
+#include "xeen/screen.h"
namespace Xeen {
@@ -80,6 +81,126 @@ void XSurface::transBlitTo(XSurface &dest, const Common::Point &destPos) const {
dest.addDirtyRect(Common::Rect(destPos.x, destPos.y, destPos.x + w, destPos.y));
}
+void XSurface::transBlitTo(XSurface &dest, const Common::Point &destPos,
+ int scale, int transparentColor) {
+ int destX = destPos.x, destY = destPos.y;
+ int frameWidth = this->w;
+ int frameHeight = this->h;
+ int direction = 1;
+
+ int highestDim = MAX(frameWidth, frameHeight);
+ bool lineDist[SCREEN_WIDTH];
+ int distXCount = 0, distYCount = 0;
+
+ if (scale != 0) {
+ int distCtr = 0;
+ int distIndex = 0;
+ do {
+ distCtr += scale;
+ if (distCtr < 100) {
+ lineDist[distIndex] = false;
+ }
+ else {
+ lineDist[distIndex] = true;
+ distCtr -= 100;
+
+ if (distIndex < frameWidth)
+ ++distXCount;
+
+ if (distIndex < frameHeight)
+ ++distYCount;
+ }
+ } while (++distIndex < highestDim);
+
+ destX -= distXCount / 2;
+ destY -= distYCount - 1;
+ }
+
+ // Start of draw logic for scaled sprites
+ const byte *srcPixelsP = (const byte *)getPixels();
+
+ int destRight = dest.w - 1;
+ int destBottom = dest.h - 1;
+
+ // Check x bounding area
+ int spriteLeft = 0;
+ int spriteWidth = distXCount;
+ int widthAmount = destX + distXCount - 1;
+
+ if (destX < 0) {
+ spriteWidth += destX;
+ spriteLeft -= destX;
+ }
+ widthAmount -= destRight;
+ if (widthAmount > 0)
+ spriteWidth -= widthAmount;
+
+ if (spriteWidth <= 0)
+ return;
+
+ // Check y bounding area
+ int spriteTop = 0;
+ int spriteHeight = distYCount;
+ int heightAmount = destY + distYCount - 1;
+
+ if (destY < 0) {
+ spriteHeight += destY;
+ spriteTop -= destY;
+ }
+ heightAmount -= destBottom;
+ if (heightAmount > 0)
+ spriteHeight -= heightAmount;
+ int spriteBottom = spriteTop + spriteHeight;
+
+ if (spriteHeight <= 0)
+ return;
+
+ byte *destPixelsP = (byte *)dest.getBasePtr(destX + spriteLeft, destY + spriteTop);
+ int destWidth = 0, destHeight = 0;
+
+ spriteLeft = spriteLeft * direction;
+
+ // Loop through the lines of the sprite
+ for (int yp = 0, sprY = -1; yp < frameHeight; ++yp, srcPixelsP += this->pitch) {
+ if (!lineDist[yp])
+ // Not a display line, so skip it
+ continue;
+ // Check whether the sprite line is in the display range
+ ++sprY;
+ if ((sprY >= spriteBottom) || (sprY < spriteTop))
+ continue;
+
+ // Found a line to display. Loop through the pixels
+ const byte *srcP = srcPixelsP;
+ byte *destP = destPixelsP;
+ ++destHeight;
+
+ for (int xp = 0, sprX = 0; xp < frameWidth; ++xp, ++srcP) {
+ if (xp < spriteLeft)
+ // Not yet reached start of display area
+ continue;
+ if (!lineDist[sprX++])
+ // Not a display pixel
+ continue;
+
+ if (*srcP != transparentColor)
+ *destP = *srcP;
+
+ destP += direction;
+ }
+
+ // Keep track of widest line drawn
+ destWidth = MAX(destP - destPixelsP, destWidth);
+
+ // Move to the next destination line
+ destPixelsP += dest.pitch;
+ }
+
+ // Add a dirty rect for the affected area
+ dest.addDirtyRect(Common::Rect(destX + spriteLeft, destY + spriteTop,
+ destX + spriteLeft + destWidth, destY + spriteTop + destHeight));
+}
+
void XSurface::blitTo(XSurface &dest, const Common::Point &destPos) const {
if (dest.getPixels() == nullptr)
dest.create(w, h);
diff --git a/engines/xeen/xsurface.h b/engines/xeen/xsurface.h
index 263ea5336f..61f4f96cb1 100644
--- a/engines/xeen/xsurface.h
+++ b/engines/xeen/xsurface.h
@@ -48,6 +48,9 @@ public:
void transBlitTo(XSurface &dest, const Common::Point &destPos) const;
+ void transBlitTo(XSurface &dest, const Common::Point &destPos,
+ int scale, int transparentColor);
+
void blitTo(XSurface &dest, const Common::Point &destPos) const;
void blitTo(XSurface &dest) const;