From 9e4a4f8c77fb80dd9704b5da657ec0c98018ce67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbj=C3=B6rn=20Andersson?= Date: Thu, 17 Oct 2024 18:34:32 +0200 Subject: [PATCH] GRAPHICS: Cleaned up and renamed unpackBitsRgn() This is actually used for images without Rgn as well. The new code should be easier to understand, and it handles all of the black and white images from the Mac versions of Loom, Indy 3, Indy 4, MI1, and MI2. It's still unfortunate - and perhaps unnecessary - that we had two different decoders for Rect/Rgn, but I'm not comfortable modifying the old one. Maybe later. --- image/pict.cpp | 131 +++++++++++++++++++++++++------------------------ image/pict.h | 4 +- 2 files changed, 69 insertions(+), 66 deletions(-) diff --git a/image/pict.cpp b/image/pict.cpp index feb7493e612..defeb3c09ef 100644 --- a/image/pict.cpp +++ b/image/pict.cpp @@ -22,8 +22,10 @@ #include "image/pict.h" #include "image/codecs/codec.h" +#include "common/bitstream.h" #include "common/debug.h" #include "common/endian.h" +#include "common/memstream.h" #include "common/stream.h" #include "common/substream.h" #include "common/textconsole.h" @@ -217,11 +219,11 @@ void PICTDecoder::o_longText(Common::SeekableReadStream &stream) { void PICTDecoder::o_bitsRgn(Common::SeekableReadStream &stream) { // Copy unpacked data with clipped region (8bpp or lower) - unpackBitsRectOrRgn(stream, false); + unpackBitsRectOrRgn(stream, false, true); } void PICTDecoder::o_packBitsRgn(Common::SeekableReadStream &stream) { - unpackBitsRectOrRgn(stream, true); + unpackBitsRectOrRgn(stream, true, true); } void PICTDecoder::o_shortComment(Common::SeekableReadStream &stream) { @@ -256,12 +258,12 @@ void PICTDecoder::o_headerOp(Common::SeekableReadStream &stream) { void PICTDecoder::on_bitsRect(Common::SeekableReadStream &stream) { // Copy unpacked data with clipped rectangle (8bpp or lower) - unpackBitsRectOrRgn(stream, false); + unpackBitsRectOrRgn(stream, false, false); } void PICTDecoder::on_packBitsRect(Common::SeekableReadStream &stream) { // Unpack data (8bpp or lower) - unpackBitsRectOrRgn(stream, true); + unpackBitsRectOrRgn(stream, true, false); } void PICTDecoder::on_directBitsRect(Common::SeekableReadStream &stream) { @@ -271,7 +273,7 @@ void PICTDecoder::on_directBitsRect(Common::SeekableReadStream &stream) { unpackBitsRect(stream, false, pixMap); } -void PICTDecoder::unpackBitsRectOrRgn(Common::SeekableReadStream &stream, bool hasPackBits) { +void PICTDecoder::unpackBitsRectOrRgn(Common::SeekableReadStream &stream, bool compressed, bool hasRegion) { PixMap pixMap = readRowBytes(stream, false); bool hasPixMap = (pixMap.rowBytes & 0x8000); pixMap.rowBytes = pixMap.rowBytes & 0x7fff; @@ -279,7 +281,7 @@ void PICTDecoder::unpackBitsRectOrRgn(Common::SeekableReadStream &stream, bool h if (hasPixMap) unpackBitsRect(stream, true, pixMap); else - unpackBitsRgn(stream, hasPackBits); + unpackBits(stream, compressed, hasRegion); } void PICTDecoder::on_compressedQuickTime(Common::SeekableReadStream &stream) { @@ -549,83 +551,84 @@ void PICTDecoder::unpackBitsRect(Common::SeekableReadStream &stream, bool withPa delete[] buffer; } -void PICTDecoder::unpackBitsRgn(Common::SeekableReadStream &stream, bool compressed) { - int x1, x2, y1, y2; - int size = 0; +// TODO: It should be possible to merge this with unpackBitsRect, but that's +// a story for another day because this works for now. +void PICTDecoder::unpackBits(Common::SeekableReadStream &stream, bool compressed, bool hasRegion) { if (!_outputSurface) { _outputSurface = new Graphics::Surface(); _outputSurface->create(_imageRect.width(), _imageRect.height(), Graphics::PixelFormat::createFormatCLUT8()); } - y1 = stream.readSint16BE(); - x1 = stream.readSint16BE(); - y2 = stream.readSint16BE(); - x2 = stream.readSint16BE(); + int y1 = stream.readSint16BE(); + int x1 = stream.readSint16BE(); + int y2 = stream.readSint16BE(); + int x2 = stream.readSint16BE(); - stream.skip(8); // Skip srcRect - stream.skip(8); // Skip dstRect - stream.skip(2); // Skip mode - stream.skip(stream.readUint16BE() - 2); + stream.skip(8); // srcRect + stream.skip(8); // dstRect + stream.skip(2); // mode - int x = 0; - int y = 0; - byte value; + if (hasRegion) + stream.skip(stream.readUint16BE() - 2); + + Common::Rect outputRect(_outputSurface->w, _outputSurface->h); if (!compressed) { - for (y = y1; y < y2 && y < _imageRect.height(); y++) { - byte b = stream.readByte(); - byte bit = 0x80; + Common::BitStream8MSB bs(stream); - for (x = x1; x < x2 && x < _imageRect.width(); x++) { - if (b & bit) - _outputSurface->setPixel(x, y, 0x0F); - else - _outputSurface->setPixel(x, y, 0x00); + for (int y = y1; y < y2; y++) { + int yPos = y - _imageRect.top; - bit >>= 1; + for (int x = x1; x < x2; x++) { + int xPos = x - _imageRect.left; - if (bit == 0) { - b = stream.readByte(); - bit = 0x80; - } + uint bit = bs.getBit(); + + if (outputRect.contains(xPos, yPos)) + _outputSurface->setPixel(xPos, yPos, bit); } } - } else { - for (y = y1; y < y2 && y < _imageRect.height(); y++) { - x = x1; - size = stream.readByte(); - while (size > 0) { - byte count = stream.readByte(); - size--; + return; + } - bool repeat; + for (int y = y1; y < y2; y++) { + int yPos = y - _imageRect.top; + int x = x1; - if (count >= 128) { - // Repeat value - count = 256 - count; - repeat = true; - value = stream.readByte(); - size--; - } else { - // Copy values - repeat = false; - value = 0; - } + byte rowBytes = stream.readByte(); + byte readBytes = 0; - for (int j = 0; j <= count; j++) { - if (!repeat) { - value = stream.readByte(); - size--; - } - for (int k = 7; k >= 0 && x < x2 && x < _imageRect.width(); k--, x++) { - if (value & (1 << k)) - _outputSurface->setPixel(x, y, 0x0F); - else - _outputSurface->setPixel(x, y, 0x00); - } - } + while (readBytes < rowBytes) { + byte rowBuf[128]; + byte bufLen; + + byte value = stream.readByte(); + readBytes++; + + if (value >= 128) { + bufLen = (256 - value) + 1; + byte repeatValue = stream.readByte(); + memset(rowBuf, repeatValue, bufLen); + readBytes++; + } else { + bufLen = value + 1; + stream.read(rowBuf, bufLen); + readBytes += bufLen; + } + + Common::MemoryReadStream ms(rowBuf, bufLen); + Common::BitStream8MSB bs(ms); + + for (int i = 0; i < 8 * bufLen; i++) { + int xPos = x - _imageRect.left; + uint bit = bs.getBit(); + + if (outputRect.contains(xPos, yPos)) + _outputSurface->setPixel(xPos, yPos, bit); + + x++; } } } diff --git a/image/pict.h b/image/pict.h index 29b8cb9c8cd..ec301e7e885 100644 --- a/image/pict.h +++ b/image/pict.h @@ -98,8 +98,8 @@ private: int _version; // Utility Functions - void unpackBitsRectOrRgn(Common::SeekableReadStream &stream, bool hasPackBits); - void unpackBitsRgn(Common::SeekableReadStream &stream, bool compressed); + void unpackBitsRectOrRgn(Common::SeekableReadStream &stream, bool compressed, bool hasRegion); + void unpackBits(Common::SeekableReadStream &stream, bool compressed, bool hasRegion); void unpackBitsRect(Common::SeekableReadStream &stream, bool withPalette, PixMap pixMap); void unpackBitsLine(byte *out, uint32 length, Common::SeekableReadStream *stream, byte bitsPerPixel, byte bytesPerPixel); void skipBitsRect(Common::SeekableReadStream &stream, bool withPalette);