diff options
-rw-r--r-- | engines/xeen/sprites.cpp | 215 | ||||
-rw-r--r-- | engines/xeen/sprites.h | 118 |
2 files changed, 269 insertions, 64 deletions
diff --git a/engines/xeen/sprites.cpp b/engines/xeen/sprites.cpp index 7b484b53e3..fed8b6a410 100644 --- a/engines/xeen/sprites.cpp +++ b/engines/xeen/sprites.cpp @@ -109,7 +109,85 @@ void SpriteResource::clear() { _index.clear(); } -void SpriteResource::drawOffset(XSurface &dest, uint16 offset, const Common::Point &pt, +void SpriteResource::draw(XSurface &dest, int frame, const Common::Point &destPos, + uint flags, int scale) { + draw(dest, frame, destPos, Common::Rect(0, 0, dest.w, dest.h), flags, scale); +} + +void SpriteResource::draw(Window &dest, int frame, const Common::Point &destPos, + uint flags, int scale) { + draw(dest, frame, destPos, dest.getBounds(), flags, scale); +} + +void SpriteResource::draw(int windowIndex, int frame, const Common::Point &destPos, + uint flags, int scale) { + Window &win = (*g_vm->_windows)[windowIndex]; + draw(win, frame, destPos, flags, scale); +} + +void SpriteResource::draw(XSurface &dest, int frame, const Common::Point &destPos, + const Common::Rect &bounds, uint flags, int scale) { + Common::Rect r = bounds; + if (flags & SPRFLAG_BOTTOM_CLIPPED) + r.clip(SCREEN_WIDTH, _clippedBottom); + + // Create drawer to handle the rendering + SpriteDrawer *draw; + switch (flags & SPRFLAG_MODE_MASK) { + case SPRFLAG_DRAWER1: + draw = new SpriteDrawer1(_data, _filesize, flags & 0x1F); + break; + case SPRFLAG_DRAWER3: + draw = new SpriteDrawer3(_data, _filesize, flags & 0x1F); + break; + case SPRFLAG_DRAWER5: + draw = new SpriteDrawer5(_data, _filesize, flags & 0x1F); + break; + case SPRFLAG_DRAWER6: + draw = new SpriteDrawer6(_data, _filesize, flags & 0x1F); + break; + default: + draw = new SpriteDrawer(_data, _filesize); + break; + } + + // Sprites can consist of separate background & foreground + draw->draw(dest, _index[frame]._offset1, destPos, r, flags, scale); + if (_index[frame]._offset2) + draw->draw(dest, _index[frame]._offset2, destPos, r, flags, scale); + + delete draw; +} + +void SpriteResource::draw(XSurface &dest, int frame) { + draw(dest, frame, Common::Point()); +} + +void SpriteResource::draw(int windowIndex, int frame) { + draw((*g_vm->_windows)[windowIndex], frame, Common::Point()); +} + +Common::Point SpriteResource::getFrameSize(int frame) const { + Common::MemoryReadStream f(_data, _filesize); + Common::Point frameSize; + + for (int idx = 0; idx < (_index[frame]._offset2 ? 2 : 1); ++idx) { + f.seek((idx == 0) ? _index[frame]._offset1 : _index[frame]._offset2); + int xOffset = f.readUint16LE(); + int width = f.readUint16LE(); + int yOffset = f.readUint16LE(); + int height = f.readUint16LE(); + + frameSize.x = MAX((int)frameSize.x, xOffset + width); + frameSize.y = MAX((int)frameSize.y, yOffset + height); + } + + return frameSize; +} + +/*------------------------------------------------------------------------*/ + +void SpriteDrawer::draw(XSurface &dest, uint16 offset, const Common::Point &pt, const Common::Rect &clipRect, uint flags, int scale) { static const uint SCALE_TABLE[] = { 0xFFFF, 0xFFEF, 0xEFEF, 0xEFEE, 0xEEEE, 0xEEAE, 0xAEAE, 0xAEAA, @@ -287,11 +365,11 @@ void SpriteResource::drawOffset(XSurface &dest, uint16 offset, const Common::Poi if (*lineP != -1 && xp >= bounds.left && xp < bounds.right) { drawBounds.left = MIN(drawBounds.left, xp); drawBounds.right = MAX((int)drawBounds.right, xp + 1); - *destP = (byte)*lineP; + drawPixel(destP, (byte)*lineP); if (enlarge) { - *(destP + SCREEN_WIDTH) = (byte)*lineP; - *(destP + 1) = (byte)*lineP; - *(destP + 1 + SCREEN_WIDTH) = (byte)*lineP; + drawPixel(destP + SCREEN_WIDTH, (byte)*lineP); + drawPixel(destP + 1, (byte)*lineP); + drawPixel(destP + 1 + SCREEN_WIDTH, (byte)*lineP); } } @@ -317,72 +395,107 @@ void SpriteResource::drawOffset(XSurface &dest, uint16 offset, const Common::Poi } } -void SpriteResource::draw(XSurface &dest, int frame, const Common::Point &destPos, - uint flags, int scale) { - draw(dest, frame, destPos, Common::Rect(0, 0, dest.w, dest.h), flags, scale); +uint SpriteDrawer::getScaledVal(int xy, uint16 &scaleMask) { + if (!xy) + return 0; + + uint result = 0; + for (int idx = 0; idx < xy; ++idx) { + uint bit = (scaleMask >> 15) & 1; + scaleMask = ((scaleMask & 0x7fff) << 1) + bit; + result += bit; + } + + return result; } -void SpriteResource::draw(Window &dest, int frame, const Common::Point &destPos, - uint flags, int scale) { - draw(dest, frame, destPos, dest.getBounds(), flags, scale); +void SpriteDrawer::drawPixel(byte *dest, byte pixel) { + *dest = pixel; } -void SpriteResource::draw(int windowIndex, int frame, const Common::Point &destPos, - uint flags, int scale) { - Window &win = (*g_vm->_windows)[windowIndex]; - draw(win, frame, destPos, flags, scale); +/*------------------------------------------------------------------------*/ + +const byte DRAWER1_OFFSET[24] = { + 0x30, 0xC0, 0xB0, 0x10, 0x41, 0x20, 0x40, 0x21, 0x48, 0x46, 0x43, 0x40, + 0xD0, 0xD3, 0xD6, 0xD8, 0x01, 0x04, 0x07, 0x0A, 0xEA, 0xEE, 0xF2, 0xF6 +}; + +const byte DRAWER1_MASK[24] = { + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x0F, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x07, 0x07 +}; + +SpriteDrawer1::SpriteDrawer1(byte *data, size_t filesize, int index) : SpriteDrawer(data, filesize) { + _offset = DRAWER1_OFFSET[index]; + _mask = DRAWER1_MASK[index]; } -void SpriteResource::draw(XSurface &dest, int frame, const Common::Point &destPos, - const Common::Rect &bounds, uint flags, int scale) { - Common::Rect r = bounds; - if (flags & SPRFLAG_BOTTOM_CLIPPED) - r.clip(SCREEN_WIDTH, _clippedBottom); +void SpriteDrawer1::drawPixel(byte *dest, byte pixel) { + *dest = (pixel & _mask) + _offset; +} - // Sprites can consist of separate background & foreground - drawOffset(dest, _index[frame]._offset1, destPos, r, flags, scale); - if (_index[frame]._offset2) - drawOffset(dest, _index[frame]._offset2, destPos, r, flags, scale); +/*------------------------------------------------------------------------*/ + +const uint16 DRAWER3_MASK[4] = { 0xF01, 0xF03, 0xF07, 0xF0F }; +const uint16 DRAWER3_OFFSET[4] = { 1, 2, 4, 8 }; + +SpriteDrawer3::SpriteDrawer3(byte *data, size_t filesize, int index) : SpriteDrawer(data, filesize) { + _offset = DRAWER3_OFFSET[index]; + _mask = DRAWER3_MASK[index]; } -void SpriteResource::draw(XSurface &dest, int frame) { - draw(dest, frame, Common::Point()); +void SpriteDrawer3::drawPixel(byte *dest, byte pixel) { + uint16 val = (int)*dest << 8 | pixel; + val = (val & _mask) - _offset; + + byte level = (val & 0xff) + (val >> 8); + if (level >= 0x80) { + *dest &= 0xf0; + } else if (level <= 0xf) { + *dest = (*dest & 0xf0) | level; + } else { + *dest |= 0xf; + } } -void SpriteResource::draw(int windowIndex, int frame) { - draw((*g_vm->_windows)[windowIndex], frame, Common::Point()); +/*------------------------------------------------------------------------*/ + +const uint16 DRAWER5_MASK[4] = { 0x3333, 0x6666, 0x999A, 0xCCCD }; + +SpriteDrawer5::SpriteDrawer5(byte *data, size_t filesize, int index) : SpriteDrawer(data, filesize) { + _mask = DRAWER5_MASK[index]; + _random1 = g_vm->getRandomNumber(0xffff); + _random2 = g_vm->getRandomNumber(0xffff); } -uint SpriteResource::getScaledVal(int xy, uint16 &scaleMask) { - if (!xy) - return 0; +void SpriteDrawer5::drawPixel(byte *dest, byte pixel) { + bool flag = (_random1 & 0x8000) != 0; + _random1 = (int)((uint16)_random1 << 1) - _random2 - (flag ? 1 : 0); - uint result = 0; - for (int idx = 0; idx < xy; ++idx) { - uint bit = (scaleMask >> 15) & 1; - scaleMask = ((scaleMask & 0x7fff) << 1) + bit; - result += bit; - } + rcr(_random2, flag); + rcr(_random2, flag); + _random2 ^= _random1; - return result; + if (_random2 > _mask) + *dest = pixel; } -Common::Point SpriteResource::getFrameSize(int frame) const { - Common::MemoryReadStream f(_data, _filesize); - Common::Point frameSize; +void SpriteDrawer5::rcr(uint16 &val, bool &cf) { + bool newCf = (val & 1); + val = (val >> 1) | (cf ? 0x8000 : 0); + cf = newCf; +} - for (int idx = 0; idx < (_index[frame]._offset2 ? 2 : 1); ++idx) { - f.seek((idx == 0) ? _index[frame]._offset1 : _index[frame]._offset2); - int xOffset = f.readUint16LE(); - int width = f.readUint16LE(); - int yOffset = f.readUint16LE(); - int height = f.readUint16LE(); +/*------------------------------------------------------------------------*/ - frameSize.x = MAX((int)frameSize.x, xOffset + width); - frameSize.y = MAX((int)frameSize.y, yOffset + height); - } +const byte DRAWER6_COLOR[16] = { 1, 2, 4, 8, 1, 3, 7, 15, 8, 12, 14, 15, 1, 2, 1, 2 }; - return frameSize; +SpriteDrawer6::SpriteDrawer6(byte *data, size_t filesize, int index) : SpriteDrawer(data, filesize) { + _color = DRAWER6_COLOR[index]; +} + +void SpriteDrawer6::drawPixel(byte *dest, byte pixel) { + *dest = _color; } } // End of namespace Xeen diff --git a/engines/xeen/sprites.h b/engines/xeen/sprites.h index fe4c45c63a..beb310e193 100644 --- a/engines/xeen/sprites.h +++ b/engines/xeen/sprites.h @@ -40,7 +40,9 @@ enum { }; enum SpriteFlags { - SPRFLAG_800 = 0x800, SPRFLAG_SCENE_CLIPPED = 0x2000, SPRFLAG_BOTTOM_CLIPPED = 0x4000, + SPRFLAG_MODE_MASK = 0xF00, SPRFLAG_DRAWER1 = 0x100, SPRFLAG_DRAWER3 = 0X300, + SPRFLAG_DRAWER5 = 0x500, SPRFLAG_DRAWER6 = 0x600, SPRFLAG_800 = 0x800, + SPRFLAG_SCENE_CLIPPED = 0x2000, SPRFLAG_BOTTOM_CLIPPED = 0x4000, SPRFLAG_HORIZ_FLIPPED = 0x8000, SPRFLAG_RESIZE = 0x10000 }; @@ -50,7 +52,7 @@ private: uint16 _offset1, _offset2; }; Common::Array<IndexEntry> _index; - int32 _filesize; + size_t _filesize; byte *_data; int _scaledWidth, _scaledHeight; Common::String _filename; @@ -72,17 +74,6 @@ private: */ void draw(int windowNum, int frame, const Common::Point &destPos, const Common::Rect &bounds, uint flags = 0, int scale = 0); - - /** - * Draw a sprite frame based on a passed offset into the data stream - */ - void drawOffset(XSurface &dest, uint16 offset, const Common::Point &pt, - const Common::Rect &clipRect, uint flags, int scale); - - /** - * Scale a co-ordinate value based on the passed scaling mask - */ - static uint getScaledVal(int xy, uint16 &scaleMask); public: SpriteResource(); SpriteResource(const Common::String &filename); @@ -182,6 +173,107 @@ public: static void setClippedBottom(int y) { _clippedBottom = y; } }; +/** + * Basic sprite drawer + */ +class SpriteDrawer { +private: + byte *_data; + size_t _filesize; +private: + /** + * Scale a co-ordinate value based on the passed scaling mask + */ + static uint getScaledVal(int xy, uint16 &scaleMask); +protected: + /** + * Output a pixel + */ + virtual void drawPixel(byte *dest, byte pixel); +public: + /** + * Constructor + */ + SpriteDrawer(byte *data, size_t filesize) : _data(data), _filesize(filesize) {} + + /** + * Draw a sprite frame based on a passed offset into the data stream + */ + void draw(XSurface &dest, uint16 offset, const Common::Point &pt, + const Common::Rect &clipRect, uint flags, int scale); +}; + +/** + * Handles drawing a sprite as masked/offset + */ +class SpriteDrawer1 : public SpriteDrawer { +private: + byte _offset, _mask; +protected: + /** + * Output a pixel + */ + virtual void drawPixel(byte *dest, byte pixel) override; +public: + /** + * Constructor + */ + SpriteDrawer1(byte *data, size_t filesize, int index); +}; + +class SpriteDrawer3 : public SpriteDrawer { +private: + uint16 _offset, _mask; +private: + /** + * Output a pixel + */ + virtual void drawPixel(byte *dest, byte pixel) override; +public: + /** + * Constructor + */ + SpriteDrawer3(byte *data, size_t filesize, int index); +}; + +class SpriteDrawer5 : public SpriteDrawer { +private: + uint16 _mask, _random1, _random2; +private: + /** + * Roll carry right opcode emulation + */ + void rcr(uint16 &val, bool &cf); +protected: + /** + * Output a pixel + */ + virtual void drawPixel(byte *dest, byte pixel) override; +public: + /** + * Constructor + */ + SpriteDrawer5(byte *data, size_t filesize, int index); +}; + +/** + * Handles drawing a sprite as a solid color + */ +class SpriteDrawer6 : public SpriteDrawer { +private: + byte _color; +protected: + /** + * Output a pixel + */ + virtual void drawPixel(byte *dest, byte pixel) override; +public: + /** + * Constructor + */ + SpriteDrawer6(byte *data, size_t filesize, int index); +}; + } // End of namespace Xeen #endif /* MADS_SPRITES_H */ |