aboutsummaryrefslogtreecommitdiff
path: root/engines/mohawk/bitmap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/mohawk/bitmap.cpp')
-rw-r--r--engines/mohawk/bitmap.cpp218
1 files changed, 137 insertions, 81 deletions
diff --git a/engines/mohawk/bitmap.cpp b/engines/mohawk/bitmap.cpp
index b622b3efbf..73b21d14ec 100644
--- a/engines/mohawk/bitmap.cpp
+++ b/engines/mohawk/bitmap.cpp
@@ -28,6 +28,7 @@
#include "common/debug.h"
#include "common/util.h"
#include "common/endian.h"
+#include "common/memstream.h"
#include "common/system.h"
namespace Mohawk {
@@ -36,12 +37,28 @@ namespace Mohawk {
#define DRAW_COMPRESSION (_header.format & kDrawMASK)
MohawkBitmap::MohawkBitmap() {
+ static const PackFunction packTable[] = {
+ { kPackNone, "Raw", &MohawkBitmap::unpackRaw },
+ { kPackLZ, "LZ", &MohawkBitmap::unpackLZ },
+ { kPackRiven, "Riven", &MohawkBitmap::unpackRiven }
+ };
+
+ _packTable = packTable;
+ _packTableSize = ARRAYSIZE(packTable);
+
+ static const DrawFunction drawTable[] = {
+ { kDrawRaw, "Raw", &MohawkBitmap::drawRaw },
+ { kDrawRLE8, "RLE8", &MohawkBitmap::drawRLE8 }
+ };
+
+ _drawTable = drawTable;
+ _drawTableSize = ARRAYSIZE(drawTable);
}
MohawkBitmap::~MohawkBitmap() {
}
-ImageData *MohawkBitmap::decodeImage(Common::SeekableReadStream *stream) {
+MohawkSurface *MohawkBitmap::decodeImage(Common::SeekableReadStream *stream) {
_data = stream;
_header.colorTable.palette = NULL;
@@ -54,7 +71,7 @@ ImageData *MohawkBitmap::decodeImage(Common::SeekableReadStream *stream) {
debug (2, "Decoding Mohawk Bitmap (%dx%d, %dbpp, %s Packing + %s Drawing)", _header.width, _header.height, getBitsPerPixel(), getPackName(), getDrawName());
- if (getBitsPerPixel() != 8)
+ if (getBitsPerPixel() != 8 && getBitsPerPixel() != 24)
error ("Unhandled bpp %d", getBitsPerPixel());
// Read in the palette if it's here.
@@ -72,14 +89,20 @@ ImageData *MohawkBitmap::decodeImage(Common::SeekableReadStream *stream) {
}
}
- _surface = new Graphics::Surface();
- _surface->create(_header.width, _header.height, getBitsPerPixel() >> 3);
+ Graphics::Surface *surface = createSurface(_header.width, _header.height);
unpackImage();
- drawImage();
+ drawImage(surface);
delete _data;
- return new ImageData(_surface, _header.colorTable.palette);
+ return new MohawkSurface(surface, _header.colorTable.palette);
+}
+
+Graphics::Surface *MohawkBitmap::createSurface(uint16 width, uint16 height) {
+ Graphics::Surface *surface = new Graphics::Surface();
+ byte bytesPerPixel = (getBitsPerPixel() <= 8) ? 1 : g_system->getScreenFormat().bytesPerPixel;
+ surface->create(width, height, bytesPerPixel);
+ return surface;
}
byte MohawkBitmap::getBitsPerPixel() {
@@ -95,65 +118,46 @@ byte MohawkBitmap::getBitsPerPixel() {
case kBitsPerPixel24:
return 24;
default:
- error ("Unknown bits per pixel");
+ error("Unknown bits per pixel");
}
return 0;
}
-struct CompressionInfo {
- uint16 flag;
- const char *name;
- void (MohawkBitmap::*func)();
-};
-
-static const CompressionInfo packTable[] = {
- { kPackNone, "Raw", &MohawkBitmap::unpackRaw },
- { kPackLZ, "LZ", &MohawkBitmap::unpackLZ },
- { kPackLZ1, "LZ1", &MohawkBitmap::unpackLZ1 },
- { kPackRiven, "Riven", &MohawkBitmap::unpackRiven }
-};
-
const char *MohawkBitmap::getPackName() {
- for (uint32 i = 0; i < ARRAYSIZE(packTable); i++)
- if (PACK_COMPRESSION == packTable[i].flag)
- return packTable[i].name;
+ for (int i = 0; i < _packTableSize; i++)
+ if (PACK_COMPRESSION == _packTable[i].flag)
+ return _packTable[i].name;
return "Unknown";
}
void MohawkBitmap::unpackImage() {
- for (uint32 i = 0; i < ARRAYSIZE(packTable); i++)
- if (PACK_COMPRESSION == packTable[i].flag) {
- (this->*packTable[i].func)();
+ for (int i = 0; i < _packTableSize; i++)
+ if (PACK_COMPRESSION == _packTable[i].flag) {
+ (this->*_packTable[i].func)();
return;
}
- warning("Unknown Pack Compression");
+ error("Unknown Pack Compression");
}
-static const CompressionInfo drawTable[] = {
- { kDrawRaw, "Raw", &MohawkBitmap::drawRaw },
- { kDrawRLE8, "RLE8", &MohawkBitmap::drawRLE8 },
- { kDrawRLE, "RLE", &MohawkBitmap::drawRLE }
-};
-
const char *MohawkBitmap::getDrawName() {
- for (uint32 i = 0; i < ARRAYSIZE(drawTable); i++)
- if (DRAW_COMPRESSION == drawTable[i].flag)
- return drawTable[i].name;
+ for (int i = 0; i < _drawTableSize; i++)
+ if (DRAW_COMPRESSION == _drawTable[i].flag)
+ return _drawTable[i].name;
return "Unknown";
}
-void MohawkBitmap::drawImage() {
- for (uint32 i = 0; i < ARRAYSIZE(drawTable); i++)
- if (DRAW_COMPRESSION == drawTable[i].flag) {
- (this->*drawTable[i].func)();
+void MohawkBitmap::drawImage(Graphics::Surface *surface) {
+ for (int i = 0; i < _drawTableSize; i++)
+ if (DRAW_COMPRESSION == _drawTable[i].flag) {
+ (this->*_drawTable[i].func)(surface);
return;
}
- warning("Unknown Draw Compression");
+ error("Unknown Draw Compression");
}
//////////////////////////////////////////
@@ -266,14 +270,6 @@ void MohawkBitmap::unpackLZ() {
}
//////////////////////////////////////////
-// LZ Unpacker
-//////////////////////////////////////////
-
-void MohawkBitmap::unpackLZ1() {
- error("STUB: unpackLZ1()");
-}
-
-//////////////////////////////////////////
// Riven Unpacker
//////////////////////////////////////////
@@ -527,10 +523,28 @@ void MohawkBitmap::handleRivenSubcommandStream(byte count, byte *&dst) {
// Raw Drawer
//////////////////////////////////////////
-void MohawkBitmap::drawRaw() {
+void MohawkBitmap::drawRaw(Graphics::Surface *surface) {
+ assert(surface);
+
for (uint16 y = 0; y < _header.height; y++) {
- _data->read((byte *)_surface->pixels + y * _header.width, _header.width);
- _data->skip(_header.bytesPerRow - _header.width);
+ if (getBitsPerPixel() == 24) {
+ Graphics::PixelFormat pixelFormat = g_system->getScreenFormat();
+
+ for (uint16 x = 0; x < _header.width; x++) {
+ byte b = _data->readByte();
+ byte g = _data->readByte();
+ byte r = _data->readByte();
+ if (surface->bytesPerPixel == 2)
+ *((uint16 *)surface->getBasePtr(x, y)) = pixelFormat.RGBToColor(r, g, b);
+ else
+ *((uint32 *)surface->getBasePtr(x, y)) = pixelFormat.RGBToColor(r, g, b);
+ }
+
+ _data->skip(_header.bytesPerRow - _header.width * 3);
+ } else {
+ _data->read((byte *)surface->pixels + y * _header.width, _header.width);
+ _data->skip(_header.bytesPerRow - _header.width);
+ }
}
}
@@ -538,20 +552,18 @@ void MohawkBitmap::drawRaw() {
// RLE8 Drawer
//////////////////////////////////////////
-void MohawkBitmap::drawRLE8() {
+void MohawkBitmap::drawRLE8(Graphics::Surface *surface, bool isLE) {
// A very simple RLE8 scheme is used as a secondary compression on
// most images in non-Riven tBMP's.
+ assert(surface);
+
for (uint16 i = 0; i < _header.height; i++) {
- uint16 rowByteCount = _data->readUint16BE();
+ uint16 rowByteCount = isLE ? _data->readUint16LE() : _data->readUint16BE();
int32 startPos = _data->pos();
- byte *dst = (byte *)_surface->pixels + i * _header.width;
+ byte *dst = (byte *)surface->pixels + i * _header.width;
int16 remaining = _header.width;
- // HACK: It seems only the bottom 9 bits are valid for images
- // TODO: Verify if this is still needed after the buffer clearing fix.
- rowByteCount &= 0x1ff;
-
while (remaining > 0) {
byte code = _data->readByte();
uint16 runLen = (code & 0x7F) + 1;
@@ -576,18 +588,10 @@ void MohawkBitmap::drawRLE8() {
}
//////////////////////////////////////////
-// RLE Drawer
-//////////////////////////////////////////
-
-void MohawkBitmap::drawRLE() {
- warning("STUB: drawRLE()");
-}
-
-//////////////////////////////////////////
// Myst Bitmap Decoder
//////////////////////////////////////////
-ImageData* MystBitmap::decodeImage(Common::SeekableReadStream* stream) {
+MohawkSurface *MystBitmap::decodeImage(Common::SeekableReadStream* stream) {
uint32 uncompressedSize = stream->readUint32LE();
Common::SeekableReadStream* bmpStream = decompressLZ(stream, uncompressedSize);
delete stream;
@@ -642,12 +646,11 @@ ImageData* MystBitmap::decodeImage(Common::SeekableReadStream* stream) {
bmpStream->seek(_header.imageOffset);
- Graphics::Surface *surface = new Graphics::Surface();
+ Graphics::Surface *surface = createSurface(_info.width, _info.height);
int srcPitch = _info.width * (_info.bitsPerPixel >> 3);
const int extraDataLength = (srcPitch % 4) ? 4 - (srcPitch % 4) : 0;
if (_info.bitsPerPixel == 8) {
- surface->create(_info.width, _info.height, 1);
byte *dst = (byte *)surface->pixels;
for (uint32 i = 0; i < _info.height; i++) {
@@ -656,7 +659,6 @@ ImageData* MystBitmap::decodeImage(Common::SeekableReadStream* stream) {
}
} else {
Graphics::PixelFormat pixelFormat = g_system->getScreenFormat();
- surface->create(_info.width, _info.height, pixelFormat.bytesPerPixel);
byte *dst = (byte *)surface->pixels + (surface->h - 1) * surface->pitch;
@@ -681,25 +683,79 @@ ImageData* MystBitmap::decodeImage(Common::SeekableReadStream* stream) {
delete bmpStream;
- return new ImageData(surface, palData);
+ return new MohawkSurface(surface, palData);
}
-ImageData *OldMohawkBitmap::decodeImage(Common::SeekableReadStream *stream) {
+MohawkSurface *OldMohawkBitmap::decodeImage(Common::SeekableReadStream *stream) {
Common::SeekableSubReadStreamEndian *endianStream = (Common::SeekableSubReadStreamEndian *)stream;
- // The format part is just a guess at this point. Note that the width and height roles have been reversed!
-
- _header.height = endianStream->readUint16() & 0x3FF;
- _header.width = endianStream->readUint16() & 0x3FF;
- _header.bytesPerRow = endianStream->readUint16() & 0x3FE;
+ // 12 bytes header for the image
_header.format = endianStream->readUint16();
+ _header.bytesPerRow = endianStream->readUint16();
+ _header.width = endianStream->readUint16();
+ _header.height = endianStream->readUint16();
+ int offsetX = endianStream->readSint16();
+ int offsetY = endianStream->readSint16();
+
+ debug(7, "Decoding Old Mohawk Bitmap (%dx%d, %d bytesPerRow, %04x Format)", _header.width, _header.height, _header.bytesPerRow, _header.format);
+ debug(7, "Offset X = %d, Y = %d", offsetX, offsetY);
+
+ bool leRLE8 = false;
+
+ if ((_header.format & 0xf0) == kOldPackLZ) {
+ // 12 bytes header for the compressed data
+ uint32 uncompressedSize = endianStream->readUint32();
+ uint32 compressedSize = endianStream->readUint32();
+ uint16 posBits = endianStream->readUint16();
+ uint16 lengthBits = endianStream->readUint16();
- debug(2, "Decoding Old Mohawk Bitmap (%dx%d, %04x Format)", _header.width, _header.height, _header.format);
+ if (compressedSize != (uint32)endianStream->size() - 24)
+ error("More bytes (%d) remaining in stream than header says there should be (%d)", endianStream->size() - 24, compressedSize);
- warning("Unhandled old Mohawk Bitmap decoding");
+ // These two errors are really just sanity checks and should never go off
+ if (posBits != POS_BITS)
+ error("Position bits modified to %d", posBits);
+ if (lengthBits != LEN_BITS)
+ error("Length bits modified to %d", lengthBits);
+ _data = decompressLZ(stream, uncompressedSize);
+
+ if (endianStream->pos() != endianStream->size())
+ error("OldMohawkBitmap decompression failed");
+ } else {
+ if ((_header.format & 0xf0) != 0)
+ error("Tried to use unknown OldMohawkBitmap compression (format %02x)", _header.format & 0xf0);
+
+ // This is so nasty on so many levels. The original Windows LZ decompressor for the
+ // Living Books v1 games had knowledge of the underlying RLE8 data. While going
+ // through the LZ data, it would byte swap the RLE8 length fields to make them LE.
+ // This is an extremely vile thing and there's no way in hell that I'm doing
+ // anything similar. When no LZ compression is used, the underlying RLE8 fields
+ // are LE, so we need to set a swap in this condition for LE vs. BE in the RLE8
+ // decoder. *sigh*
+
+ if (!endianStream->isBE())
+ leRLE8 = true;
+
+ _data = stream;
+ stream = NULL;
+ }
+
+ Graphics::Surface *surface = createSurface(_header.width, _header.height);
+
+ if ((_header.format & 0xf00) == kOldDrawRLE8)
+ drawRLE8(surface, leRLE8);
+ else
+ drawRaw(surface);
+
+ delete _data;
delete stream;
- return new ImageData(NULL, NULL);
+
+ MohawkSurface *mhkSurface = new MohawkSurface(surface);
+ mhkSurface->setOffsetX(offsetX);
+ mhkSurface->setOffsetY(offsetY);
+
+ return mhkSurface;
}
} // End of namespace Mohawk