diff options
author | Paul Gilbert | 2015-01-18 19:12:10 -0500 |
---|---|---|
committer | Paul Gilbert | 2015-01-18 19:12:10 -0500 |
commit | 07a10855be2f60ae253623c26c8bb0ac38e58af4 (patch) | |
tree | eb8601359c50ac740a6fa529872a8fdb85938ca6 /engines/xeen | |
parent | f18a8c364b2b2f608081bb79cad54de3abacd111 (diff) | |
download | scummvm-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.cpp | 2 | ||||
-rw-r--r-- | engines/xeen/sprites.cpp | 34 | ||||
-rw-r--r-- | engines/xeen/sprites.h | 3 | ||||
-rw-r--r-- | engines/xeen/xsurface.cpp | 121 | ||||
-rw-r--r-- | engines/xeen/xsurface.h | 3 |
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; |