aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Schickel2013-01-06 11:20:52 -0800
committerJohannes Schickel2013-01-06 11:20:52 -0800
commit988596b347c7508b83f30e336add33047b49dd5f (patch)
tree604678b7d9476dc1755f5ef5ff4668b7aefd3a69
parent3e025a8c55fce06ab4dd5a615e46fa6a9b9a6fb3 (diff)
parentbefa207bfa3709c7292252654a5bb9384d950a02 (diff)
downloadscummvm-rg350-988596b347c7508b83f30e336add33047b49dd5f.tar.gz
scummvm-rg350-988596b347c7508b83f30e336add33047b49dd5f.tar.bz2
scummvm-rg350-988596b347c7508b83f30e336add33047b49dd5f.zip
Merge pull request #299 from tomaz82/IFFDecoder
New IFFDecoder
-rw-r--r--common/iff_container.cpp47
-rw-r--r--common/iff_container.h41
-rw-r--r--engines/gob/inter.h2
-rw-r--r--engines/gob/inter_v7.cpp27
-rw-r--r--engines/gob/surface.cpp124
-rw-r--r--engines/gob/surface.h32
-rw-r--r--engines/parallaction/disk.cpp145
-rw-r--r--engines/parallaction/disk.h33
-rw-r--r--engines/parallaction/disk_br.cpp48
-rw-r--r--engines/parallaction/disk_ns.cpp57
-rw-r--r--engines/parallaction/module.mk1
-rw-r--r--engines/queen/display.cpp88
-rw-r--r--engines/queen/display.h4
-rw-r--r--engines/saga/scene.cpp19
-rw-r--r--graphics/decoders/iff.cpp241
-rw-r--r--graphics/decoders/iff.h119
-rw-r--r--graphics/iff.cpp289
-rw-r--r--graphics/iff.h137
-rw-r--r--graphics/module.mk2
19 files changed, 564 insertions, 892 deletions
diff --git a/common/iff_container.cpp b/common/iff_container.cpp
index 7bcbf86e0f..ffaa5c6d06 100644
--- a/common/iff_container.cpp
+++ b/common/iff_container.cpp
@@ -22,6 +22,7 @@
#include "common/iff_container.h"
#include "common/substream.h"
+#include "common/util.h"
namespace Common {
@@ -75,4 +76,50 @@ void IFFParser::parse(IFFCallback &callback) {
} while (!stop);
}
+
+PackBitsReadStream::PackBitsReadStream(Common::ReadStream &input) : _input(&input) {
+}
+
+PackBitsReadStream::~PackBitsReadStream() {
+}
+
+bool PackBitsReadStream::eos() const {
+ return _input->eos();
+}
+
+uint32 PackBitsReadStream::read(void *dataPtr, uint32 dataSize) {
+ byte *out = (byte *)dataPtr;
+ uint32 left = dataSize;
+
+ uint32 lenR = 0, lenW = 0;
+ while (left > 0 && !_input->eos()) {
+ lenR = _input->readByte();
+
+ if (lenR == 128) {
+ // no-op
+ lenW = 0;
+ } else if (lenR <= 127) {
+ // literal run
+ lenR++;
+ lenW = MIN(lenR, left);
+ for (uint32 j = 0; j < lenW; j++) {
+ *out++ = _input->readByte();
+ }
+ for (; lenR > lenW; lenR--) {
+ _input->readByte();
+ }
+ } else { // len > 128
+ // expand run
+ lenW = MIN((256 - lenR) + 1, left);
+ byte val = _input->readByte();
+ memset(out, val, lenW);
+ out += lenW;
+ }
+
+ left -= lenW;
+ }
+
+ return dataSize - left;
+}
+
} // End of namespace Common
diff --git a/common/iff_container.h b/common/iff_container.h
index 104ecf0f36..a730930b2c 100644
--- a/common/iff_container.h
+++ b/common/iff_container.h
@@ -77,22 +77,22 @@ page 376) */
#define ID_copy MKTAG('(','c',')',' ')
/* EA IFF 85 Generic Copyright text chunk */
-/* ILBM chunks */
+/* IFF chunks */
#define ID_BMHD MKTAG('B','M','H','D')
-/* ILBM BitmapHeader */
+/* IFF BitmapHeader */
#define ID_CMAP MKTAG('C','M','A','P')
-/* ILBM 8bit RGB colormap */
+/* IFF 8bit RGB colormap */
#define ID_GRAB MKTAG('G','R','A','B')
-/* ILBM "hotspot" coordiantes */
+/* IFF "hotspot" coordiantes */
#define ID_DEST MKTAG('D','E','S','T')
-/* ILBM destination image info */
+/* IFF destination image info */
#define ID_SPRT MKTAG('S','P','R','T')
-/* ILBM sprite identifier */
+/* IFF sprite identifier */
#define ID_CAMG MKTAG('C','A','M','G')
/* Amiga viewportmodes */
#define ID_BODY MKTAG('B','O','D','Y')
-/* ILBM image data */
+/* IFF image data */
#define ID_CRNG MKTAG('C','R','N','G')
/* color cycling */
#define ID_CCRT MKTAG('C','C','R','T')
@@ -114,7 +114,7 @@ page 376) */
#define ID_PCHG MKTAG('P','C','H','G')
/* Line by line palette control information (Sebastiano Vigna) */
#define ID_PRVW MKTAG('P','R','V','W')
-/* A mini duplicate ILBM used for preview (Gary Bonham) */
+/* A mini duplicate IFF used for preview (Gary Bonham) */
#define ID_XBMI MKTAG('X','B','M','I')
/* eXtended BitMap Information (Soft-Logik) */
#define ID_CTBL MKTAG('C','T','B','L')
@@ -239,6 +239,31 @@ public:
};
+/**
+ * Decode a given PackBits encoded stream.
+ *
+ * PackBits is an RLE compression algorithm introduced by Apple. It is also
+ * used to encode ILBM and PBM subtypes of IFF files, and some flavors of
+ * TIFF.
+ *
+ * As there is no compression across row boundaries in the above formats,
+ * read() will extract a *new* line on each call, discarding any alignment
+ * or padding.
+ */
+class PackBitsReadStream : public Common::ReadStream {
+
+protected:
+ Common::ReadStream *_input;
+
+public:
+ PackBitsReadStream(Common::ReadStream &input);
+ ~PackBitsReadStream();
+
+ virtual bool eos() const;
+
+ uint32 read(void *dataPtr, uint32 dataSize);
+};
+
} // namespace Common
#endif
diff --git a/engines/gob/inter.h b/engines/gob/inter.h
index 63bf3eb1c6..2aa837e777 100644
--- a/engines/gob/inter.h
+++ b/engines/gob/inter.h
@@ -693,7 +693,7 @@ protected:
void o7_zeroVar();
void o7_getINIValue();
void o7_setINIValue();
- void o7_loadLBMPalette();
+ void o7_loadIFFPalette();
void o7_opendBase();
void o7_closedBase();
void o7_getDBString();
diff --git a/engines/gob/inter_v7.cpp b/engines/gob/inter_v7.cpp
index 6cf69ed9df..4d92386c94 100644
--- a/engines/gob/inter_v7.cpp
+++ b/engines/gob/inter_v7.cpp
@@ -27,6 +27,7 @@
#include "graphics/cursorman.h"
#include "graphics/wincursor.h"
+#include "graphics/decoders/iff.h"
#include "gob/gob.h"
#include "gob/global.h"
@@ -72,7 +73,7 @@ void Inter_v7::setupOpcodesDraw() {
OPCODEDRAW(0x95, o7_zeroVar);
OPCODEDRAW(0xA1, o7_getINIValue);
OPCODEDRAW(0xA2, o7_setINIValue);
- OPCODEDRAW(0xA4, o7_loadLBMPalette);
+ OPCODEDRAW(0xA4, o7_loadIFFPalette);
OPCODEDRAW(0xC4, o7_opendBase);
OPCODEDRAW(0xC5, o7_closedBase);
OPCODEDRAW(0xC6, o7_getDBString);
@@ -523,7 +524,7 @@ void Inter_v7::o7_setINIValue() {
_inis.setValue(file, section, key, value);
}
-void Inter_v7::o7_loadLBMPalette() {
+void Inter_v7::o7_loadIFFPalette() {
Common::String file = _vm->_game->_script->evalString();
if (!file.contains('.'))
file += ".LBM";
@@ -534,26 +535,26 @@ void Inter_v7::o7_loadLBMPalette() {
if (startIndex > stopIndex)
SWAP(startIndex, stopIndex);
- Common::SeekableReadStream *lbmFile = _vm->_dataIO->getFile(file);
- if (!lbmFile) {
- warning("o7_loadLBMPalette(): No such file \"%s\"", file.c_str());
+ Common::SeekableReadStream *iffFile = _vm->_dataIO->getFile(file);
+ if (!iffFile) {
+ warning("o7_loadIFFPalette(): No such file \"%s\"", file.c_str());
return;
}
- ImageType type = Surface::identifyImage(*lbmFile);
- if (type != kImageTypeLBM) {
- warning("o7_loadLBMPalette(): \"%s\" is no LBM", file.c_str());
+ ImageType type = Surface::identifyImage(*iffFile);
+ if (type != kImageTypeIFF) {
+ warning("o7_loadIFFPalette(): \"%s\" is no IFF", file.c_str());
return;
}
- byte palette[768];
-
- LBMLoader lbm(*lbmFile);
- if (!lbm.loadPalette(palette)) {
- warning("o7_loadLBMPalette(): Failed reading palette from LBM \"%s\"", file.c_str());
+ Graphics::IFFDecoder decoder;
+ decoder.loadStream(*iffFile);
+ if (!decoder.getPalette() || decoder.getPaletteColorCount() != 256) {
+ warning("o7_loadIFFPalette(): Failed reading palette from IFF \"%s\"", file.c_str());
return;
}
+ byte *palette = (byte *)decoder.getPalette();
memset(palette , 0x00, 3);
memset(palette + 765, 0xFF, 3);
for (int i = 0; i < 768; i++)
diff --git a/engines/gob/surface.cpp b/engines/gob/surface.cpp
index afbb7c3bae..6b65eb6ab9 100644
--- a/engines/gob/surface.cpp
+++ b/engines/gob/surface.cpp
@@ -26,112 +26,15 @@
#include "common/stream.h"
#include "common/util.h"
#include "common/frac.h"
+#include "common/textconsole.h"
#include "graphics/primitives.h"
#include "graphics/pixelformat.h"
#include "graphics/surface.h"
+#include "graphics/decoders/iff.h"
namespace Gob {
-LBMLoader::LBMLoader(Common::SeekableReadStream &stream) : _parser(&stream),
- _hasHeader(false), _palette(0), _image(0) {
-
-}
-
-bool LBMLoader::loadHeader(Graphics::BMHD &header) {
- if (!readHeader())
- return false;
-
- header = _decoder._header;
- return true;
-}
-
-bool LBMLoader::loadPalette(byte *palette) {
- assert(!_palette);
- assert(palette);
-
- _palette = palette;
-
- Common::Functor1Mem<Common::IFFChunk&, bool, LBMLoader> c(this, &LBMLoader::callbackPalette);
- _parser.parse(c);
-
- if (!_palette)
- return false;
-
- _palette = 0;
- return true;
-}
-
-bool LBMLoader::loadImage(byte *image) {
- assert(!_image);
- assert(image);
-
- if (!readHeader())
- return false;
-
- _image = image;
-
- Common::Functor1Mem<Common::IFFChunk&, bool, LBMLoader> c(this, &LBMLoader::callbackImage);
- _parser.parse(c);
-
- if (!_image)
- return false;
-
- _image = 0;
- return true;
-}
-
-bool LBMLoader::callbackHeader(Common::IFFChunk &chunk) {
- if (chunk._type == ID_BMHD) {
- if (chunk._size == sizeof(Graphics::BMHD)) {
- _decoder.loadHeader(chunk._stream);
- _hasHeader = true;
- }
-
- return true; // Stop the IFF parser
- }
-
- return false;
-}
-
-bool LBMLoader::callbackPalette(Common::IFFChunk &chunk) {
- assert(_palette);
-
- if (chunk._type == ID_CMAP) {
- if (chunk._size == 768) {
- if (chunk._stream->read(_palette, chunk._size) != chunk._size)
- _palette = 0;
- } else
- _palette = 0;
-
- return true; // Stop the IFF parser
- }
-
- return false;
-}
-
-bool LBMLoader::callbackImage(Common::IFFChunk &chunk) {
- assert(_image);
-
- if (chunk._type == ID_BODY) {
- _decoder.loadBitmap(Graphics::ILBMDecoder::ILBM_UNPACK_PLANES, _image, chunk._stream);
- return true;
- }
-
- return false;
-}
-
-bool LBMLoader::readHeader() {
- if (_hasHeader)
- return true;
-
- Common::Functor1Mem<Common::IFFChunk&, bool, LBMLoader> c(this, &LBMLoader::callbackHeader);
- _parser.parse(c);
-
- return _hasHeader;
-}
-
-
static void plotPixel(int x, int y, int color, void *data) {
Surface *dest = (Surface *)data;
@@ -841,8 +744,8 @@ bool Surface::loadImage(Common::SeekableReadStream &stream, ImageType type) {
switch (type) {
case kImageTypeTGA:
return loadTGA(stream);
- case kImageTypeLBM:
- return loadLBM(stream);
+ case kImageTypeIFF:
+ return loadIFF(stream);
case kImageTypeBRC:
return loadBRC(stream);
case kImageTypeBMP:
@@ -871,7 +774,7 @@ ImageType Surface::identifyImage(Common::SeekableReadStream &stream) {
stream.seek(startPos);
if (!strncmp(buffer , "FORM", 4))
- return kImageTypeLBM;
+ return kImageTypeIFF;
if (!strncmp(buffer + 6, "JFIF", 4))
return kImageTypeJPEG;
if (!strncmp(buffer , "BRC" , 3))
@@ -904,20 +807,17 @@ bool Surface::loadTGA(Common::SeekableReadStream &stream) {
return false;
}
-bool Surface::loadLBM(Common::SeekableReadStream &stream) {
+bool Surface::loadIFF(Common::SeekableReadStream &stream) {
+ Graphics::IFFDecoder decoder;
+ decoder.loadStream(stream);
- LBMLoader loader(stream);
-
- Graphics::BMHD header;
- loader.loadHeader(header);
-
- if (header.depth != 8)
- // Only 8bpp LBMs supported for now
+ if (!decoder.getSurface())
return false;
- resize(header.width, header.height);
+ resize(decoder.getSurface()->w, decoder.getSurface()->h);
+ memcpy(_vidMem, decoder.getSurface()->pixels, decoder.getSurface()->w * decoder.getSurface()->h);
- return loader.loadImage(_vidMem);
+ return true;
}
bool Surface::loadBRC(Common::SeekableReadStream &stream) {
diff --git a/engines/gob/surface.h b/engines/gob/surface.h
index 8f895a7910..8a1b502a95 100644
--- a/engines/gob/surface.h
+++ b/engines/gob/surface.h
@@ -26,9 +26,6 @@
#include "common/scummsys.h"
#include "common/ptr.h"
#include "common/rational.h"
-#include "common/iff_container.h"
-
-#include "graphics/iff.h"
namespace Common {
class SeekableReadStream;
@@ -39,37 +36,12 @@ namespace Gob {
enum ImageType {
kImageTypeNone = -1,
kImageTypeTGA = 0,
- kImageTypeLBM,
+ kImageTypeIFF,
kImageTypeBRC,
kImageTypeBMP,
kImageTypeJPEG
};
-class LBMLoader {
-public:
- LBMLoader(Common::SeekableReadStream &stream);
-
- bool loadHeader (Graphics::BMHD &header);
- bool loadPalette(byte *palette);
- bool loadImage (byte *image);
-
-private:
- Common::IFFParser _parser;
-
- bool _hasHeader;
-
- Graphics::ILBMDecoder _decoder;
-
- byte *_palette;
- byte *_image;
-
- bool callbackHeader (Common::IFFChunk &chunk);
- bool callbackPalette(Common::IFFChunk &chunk);
- bool callbackImage (Common::IFFChunk &chunk);
-
- bool readHeader();
-};
-
/** An iterator over a surface's image data, automatically handles different color depths. */
class Pixel {
public:
@@ -182,7 +154,7 @@ private:
uint16 dWidth, uint16 dHeight, uint16 sWidth, uint16 sHeight);
bool loadTGA (Common::SeekableReadStream &stream);
- bool loadLBM (Common::SeekableReadStream &stream);
+ bool loadIFF (Common::SeekableReadStream &stream);
bool loadBRC (Common::SeekableReadStream &stream);
bool loadBMP (Common::SeekableReadStream &stream);
bool loadJPEG(Common::SeekableReadStream &stream);
diff --git a/engines/parallaction/disk.cpp b/engines/parallaction/disk.cpp
deleted file mode 100644
index f20e05771a..0000000000
--- a/engines/parallaction/disk.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "common/iff_container.h"
-#include "common/textconsole.h"
-
-#include "parallaction/disk.h"
-#include "parallaction/graphics.h"
-
-namespace Parallaction {
-
-void ILBMLoader::setupBuffer(uint32 w, uint32 h) {
- _intBuffer = 0;
- switch (_bodyMode) {
- case BODYMODE_SURFACE:
- if (!_surf) {
- _surf = new Graphics::Surface;
- assert(_surf);
- }
- _surf->create(w, h, Graphics::PixelFormat::createFormatCLUT8());
- _mode = Graphics::ILBMDecoder::ILBM_UNPACK_PLANES;
- _intBuffer = (byte *)_surf->pixels;
- break;
-
- case BODYMODE_MASKBUFFER:
- if (!_maskBuffer) {
- _maskBuffer = new MaskBuffer;
- assert(_maskBuffer);
- }
- _maskBuffer->create(w, h);
- _mode = Graphics::ILBMDecoder::ILBM_2_PACK_PLANES;
- _intBuffer = _maskBuffer->data;
- break;
-
- case BODYMODE_PATHBUFFER:
- if (!_pathBuffer) {
- _pathBuffer = new PathBuffer;
- assert(_pathBuffer);
- }
- _pathBuffer->create(w, h);
- _mode = Graphics::ILBMDecoder::ILBM_1_PACK_PLANES;
- _intBuffer = _pathBuffer->data;
- break;
-
- default:
- error("Invalid bodyMode '%i' for ILBMLoader", _bodyMode);
- break;
- }
-}
-
-bool ILBMLoader::callback(Common::IFFChunk &chunk) {
- switch (chunk._type) {
- case ID_BMHD:
- _decoder.loadHeader(chunk._stream);
- break;
-
- case ID_CMAP:
- if (_palette) {
- chunk._stream->read(_palette, chunk._size);
- }
- break;
-
- case ID_CRNG:
- if (_crng) {
- PaletteFxRange *ptr = &_crng[_numCRNG];
- chunk._stream->read((byte *)ptr, chunk._size);
- ptr->_timer = FROM_BE_16(ptr->_timer);
- ptr->_step = FROM_BE_16(ptr->_step);
- ptr->_flags = FROM_BE_16(ptr->_flags);
- ++_numCRNG;
- }
- break;
-
- case ID_BODY:
- setupBuffer(_decoder._header.width, _decoder._header.height);
- assert(_intBuffer);
- _decoder.loadBitmap(_mode, _intBuffer, chunk._stream);
- return true; // stop the parser
- }
-
- return false;
-}
-
-void ILBMLoader::load(Common::ReadStream *in, bool disposeStream) {
- Common::IFFParser parser(in, disposeStream);
- Common::Functor1Mem< Common::IFFChunk&, bool, ILBMLoader > c(this, &ILBMLoader::callback);
- parser.parse(c);
-}
-
-ILBMLoader::ILBMLoader(uint32 bodyMode, byte *palette, PaletteFxRange *crng) {
- _bodyMode = bodyMode;
- _surf = 0;
- _maskBuffer = 0;
- _pathBuffer = 0;
- _palette = palette;
- _crng = crng;
- _numCRNG = 0;
-}
-
-ILBMLoader::ILBMLoader(Graphics::Surface *surf, byte *palette, PaletteFxRange *crng) {
- _bodyMode = ILBMLoader::BODYMODE_SURFACE;
- _surf = surf;
- _palette = palette;
- _crng = crng;
- _numCRNG = 0;
-}
-
-ILBMLoader::ILBMLoader(MaskBuffer *buffer) {
- _bodyMode = ILBMLoader::BODYMODE_MASKBUFFER;
- _maskBuffer = buffer;
- _palette = 0;
- _crng = 0;
- _numCRNG = 0;
-}
-
-ILBMLoader::ILBMLoader(PathBuffer *buffer) {
- _bodyMode = ILBMLoader::BODYMODE_PATHBUFFER;
- _pathBuffer = buffer;
- _palette = 0;
- _crng = 0;
- _numCRNG = 0;
-}
-
-
-
-}
diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h
index d1171c3179..63e33dcfbd 100644
--- a/engines/parallaction/disk.h
+++ b/engines/parallaction/disk.h
@@ -28,13 +28,10 @@
#include "common/archive.h"
#include "common/str.h"
-#include "graphics/iff.h"
-
namespace Common {
class FSDirectory;
class ReadStream;
class SeekableReadStream;
-struct IFFChunk;
}
namespace Graphics {
@@ -86,36 +83,6 @@ public:
virtual PathBuffer *loadPath(const char *name, uint32 w, uint32 h) { return 0; }
};
-struct PaletteFxRange;
-
-struct ILBMLoader {
- enum {
- BODYMODE_SURFACE,
- BODYMODE_MASKBUFFER,
- BODYMODE_PATHBUFFER
- };
- uint32 _bodyMode;
- Graphics::Surface *_surf;
- MaskBuffer *_maskBuffer;
- PathBuffer *_pathBuffer;
- byte *_palette;
- PaletteFxRange *_crng;
- uint32 _mode;
- byte* _intBuffer;
- uint32 _numCRNG;
- Graphics::ILBMDecoder _decoder;
-
- ILBMLoader(uint32 bodyMode, byte *palette = 0, PaletteFxRange *crng = 0);
- ILBMLoader(Graphics::Surface *surf, byte *palette = 0, PaletteFxRange *crng = 0);
- ILBMLoader(MaskBuffer *buffer);
- ILBMLoader(PathBuffer *buffer);
-
- bool callback(Common::IFFChunk &chunk);
- void setupBuffer(uint32 w, uint32 h);
- void load(Common::ReadStream *in, bool disposeStream = false);
-};
-
-
class Disk_ns : public Disk {
protected:
diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp
index 8988897456..efddfb9935 100644
--- a/engines/parallaction/disk_br.cpp
+++ b/engines/parallaction/disk_br.cpp
@@ -20,11 +20,10 @@
*
*/
-#include "graphics/iff.h"
-
#include "common/config-manager.h"
#include "common/fs.h"
#include "common/textconsole.h"
+#include "graphics/decoders/iff.h"
#include "parallaction/parallaction.h"
#include "parallaction/parser.h"
@@ -459,8 +458,9 @@ void AmigaDisk_br::adjustForPalette(Graphics::Surface &surf, int transparentColo
void AmigaDisk_br::loadBackground(BackgroundInfo& info, const char *filename) {
byte r,g,b;
- byte *p;
+ const byte *p;
Common::SeekableReadStream *stream;
+ Graphics::IFFDecoder decoder;
uint i;
stream = tryOpenFile("backs/" + Common::String(filename), ".ap");
@@ -488,15 +488,16 @@ void AmigaDisk_br::loadBackground(BackgroundInfo& info, const char *filename) {
}
stream = openFile("backs/" + Common::String(filename), ".bkg");
+ decoder.loadStream(*stream);
- byte pal[768];
- ILBMLoader loader(&info.bg, pal);
- loader.load(stream, true);
-
+ info.bg.copyFrom(*decoder.getSurface());
info.width = info.bg.w;
info.height = info.bg.h;
- p = pal;
+ // Overwrite the first color (transparent key) in the palette
+ p = decoder.getPalette();
+ info.palette.setEntry(0, p[0] >> 2, p[1] >> 2, p[2] >> 0);
+
for (i = 16; i < 32; i++) {
r = *p >> 2;
p++;
@@ -507,9 +508,6 @@ void AmigaDisk_br::loadBackground(BackgroundInfo& info, const char *filename) {
info.palette.setEntry(i, r, g, b);
}
- // Overwrite the first color (transparent key) in the palette
- info.palette.setEntry(0, pal[0] >> 2, pal[1] >> 2, pal[2] >> 0);
-
// background data is drawn used the upper portion of the palette
adjustForPalette(info.bg);
}
@@ -546,10 +544,15 @@ MaskBuffer *AmigaDisk_br::loadMask(const char *name, uint32 w, uint32 h) {
return 0;
}
- ILBMLoader loader(ILBMLoader::BODYMODE_MASKBUFFER);
- loader.load(stream, true);
+ Graphics::IFFDecoder decoder;
+ decoder.setNumRelevantPlanes(2); // use only 2 first bits from each pixels
+ decoder.setPixelPacking(true); // pack 4 2bit pixels into 1 byte
+ decoder.loadStream(*stream);
- MaskBuffer *buffer = loader._maskBuffer;
+ MaskBuffer *buffer = new MaskBuffer;
+ // surface width was shrunk to 1/4th of the bitmap width due to the pixel packing
+ buffer->create(decoder.getSurface()->w * 4, decoder.getSurface()->h);
+ memcpy(buffer->data, decoder.getSurface()->pixels, buffer->size);
buffer->bigEndian = true;
finalpass(buffer->data, buffer->size);
return buffer;
@@ -580,12 +583,12 @@ GfxObj* AmigaDisk_br::loadStatic(const char* name) {
Common::String sName = name;
Common::SeekableReadStream *stream = openFile("ras/" + sName, ".ras");
+ Graphics::IFFDecoder decoder;
+ decoder.loadStream(*stream);
- ILBMLoader loader(ILBMLoader::BODYMODE_SURFACE);
- loader.load(stream, true);
-
- Graphics::Surface* surf = loader._surf;
+ Graphics::Surface *surf = new Graphics::Surface;
assert(surf);
+ surf->copyFrom(*decoder.getSurface());
// Static pictures are drawn used the upper half of the palette: this must be
// done before shadow mask is applied. This way, only really transparent pixels
@@ -717,16 +720,16 @@ GfxObj* AmigaDisk_br::loadObjects(const char *name, uint8 part) {
debugC(5, kDebugDisk, "AmigaDisk_br::loadObjects");
Common::SeekableReadStream *stream = openFile(name);
- ILBMLoader loader(ILBMLoader::BODYMODE_SURFACE);
- loader.load(stream, true);
+ Graphics::IFFDecoder decoder;
+ decoder.loadStream(*stream);
uint16 max = objectsMax[part];
if (_vm->getFeatures() & GF_DEMO)
max = 72;
byte *data = new byte[max * 2601];
- byte *srcPtr = (byte *)loader._surf->getBasePtr(0,0);
- int w = loader._surf->w;
+ byte *srcPtr = (byte *)decoder.getSurface()->getBasePtr(0,0);
+ int w = decoder.getSurface()->w;
// Convert to the expected display format
for (int i = 0; i < max; i++) {
@@ -741,7 +744,6 @@ GfxObj* AmigaDisk_br::loadObjects(const char *name, uint8 part) {
dst += 51;
}
}
- delete loader._surf;
return new GfxObj(0, new Cnv(max, 51, 51, data, true));
}
diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp
index bad854525d..f03f16ca37 100644
--- a/engines/parallaction/disk_ns.cpp
+++ b/engines/parallaction/disk_ns.cpp
@@ -22,9 +22,11 @@
#include "common/config-manager.h"
#include "common/fs.h"
+#include "common/iff_container.h"
#include "common/memstream.h"
#include "common/substream.h"
#include "common/textconsole.h"
+#include "graphics/decoders/iff.h"
#include "parallaction/parser.h"
#include "parallaction/parallaction.h"
@@ -312,7 +314,7 @@ void DosDisk_ns::decodeCnv(byte *data, uint16 numFrames, uint16 width, uint16 he
int32 decsize = numFrames * width * height;
bool packed = (stream->size() - stream->pos()) != decsize;
if (packed) {
- Graphics::PackBitsReadStream decoder(*stream);
+ Common::PackBitsReadStream decoder(*stream);
decoder.read(data, decsize);
} else {
stream->read(data, decsize);
@@ -914,17 +916,15 @@ void AmigaDisk_ns::buildMask(byte* buf) {
void AmigaDisk_ns::loadBackground(BackgroundInfo& info, const char *name) {
- PaletteFxRange ranges[6];
- byte pal[768];
-
Common::SeekableReadStream *s = openFile(name);
- ILBMLoader loader(&info.bg, pal, ranges);
- loader.load(s, true);
+ Graphics::IFFDecoder decoder;
+ decoder.loadStream(*s);
+ info.bg.copyFrom(*decoder.getSurface());
info.width = info.bg.w;
info.height = info.bg.h;
- byte *p = pal;
+ const byte *p = decoder.getPalette();
for (uint i = 0; i < 32; i++) {
byte r = *p >> 2;
p++;
@@ -935,8 +935,15 @@ void AmigaDisk_ns::loadBackground(BackgroundInfo& info, const char *name) {
info.palette.setEntry(i, r, g, b);
}
- for (uint j = 0; j < 6; j++) {
- info.setPaletteRange(j, ranges[j]);
+ const Common::Array<Graphics::IFFDecoder::PaletteRange> &paletteRanges = decoder.getPaletteRanges();
+ for (uint j = 0; j < 6 && j < paletteRanges.size(); j++) {
+ PaletteFxRange range;
+ range._timer = paletteRanges[j].timer;
+ range._step = paletteRanges[j].step;
+ range._flags = paletteRanges[j].flags;
+ range._first = paletteRanges[j].first;
+ range._last = paletteRanges[j].last;
+ info.setPaletteRange(j, range);
}
}
@@ -952,19 +959,25 @@ void AmigaDisk_ns::loadMask_internal(BackgroundInfo& info, const char *name) {
return; // no errors if missing mask files: not every location has one
}
- byte pal[768];
- ILBMLoader loader(ILBMLoader::BODYMODE_MASKBUFFER, pal);
- loader.load(s, true);
+ Graphics::IFFDecoder decoder;
+ decoder.setNumRelevantPlanes(2); // use only 2 first bits from each pixel
+ decoder.setPixelPacking(true); // pack 4 2bit pixels into 1 byte
+ decoder.loadStream(*s);
+ const byte *p = decoder.getPalette();
byte r, g, b;
for (uint i = 0; i < 4; i++) {
- r = pal[i*3];
- g = pal[i*3+1];
- b = pal[i*3+2];
+ r = p[i*3];
+ g = p[i*3+1];
+ b = p[i*3+2];
info.layers[i] = (((r << 4) & 0xF00) | (g & 0xF0) | (b >> 4)) & 0xFF;
}
- info._mask = loader._maskBuffer;
+ info._mask = new MaskBuffer;
+ // surface width was shrunk to 1/4th of the bitmap width due to the pixel packing
+ info._mask->create(decoder.getSurface()->w * 4, decoder.getSurface()->h);
+ memcpy(info._mask->data, decoder.getSurface()->pixels, info._mask->size);
+ info._mask->bigEndian = true;
}
void AmigaDisk_ns::loadPath_internal(BackgroundInfo& info, const char *name) {
@@ -977,9 +990,15 @@ void AmigaDisk_ns::loadPath_internal(BackgroundInfo& info, const char *name) {
return; // no errors if missing path files: not every location has one
}
- ILBMLoader loader(ILBMLoader::BODYMODE_PATHBUFFER);
- loader.load(s, true);
- info._path = loader._pathBuffer;
+ Graphics::IFFDecoder decoder;
+ decoder.setNumRelevantPlanes(1); // use only first bit from each pixel
+ decoder.setPixelPacking(true); // pack 8 1bit pixels into 1 byte
+ decoder.loadStream(*s);
+
+ info._path = new PathBuffer;
+ // surface width was shrunk to 1/8th of the bitmap width due to the pixel packing
+ info._path->create(decoder.getSurface()->w * 8, decoder.getSurface()->h);
+ memcpy(info._path->data, decoder.getSurface()->pixels, info._path->size);
info._path->bigEndian = true;
}
diff --git a/engines/parallaction/module.mk b/engines/parallaction/module.mk
index 36572a51df..f8a4e0b9a3 100644
--- a/engines/parallaction/module.mk
+++ b/engines/parallaction/module.mk
@@ -8,7 +8,6 @@ MODULE_OBJS := \
debug.o \
detection.o \
dialogue.o \
- disk.o \
disk_br.o \
disk_ns.o \
exec.o \
diff --git a/engines/queen/display.cpp b/engines/queen/display.cpp
index cd9a1075fa..d7b20c203e 100644
--- a/engines/queen/display.cpp
+++ b/engines/queen/display.cpp
@@ -29,6 +29,7 @@
#include "graphics/cursorman.h"
#include "graphics/palette.h"
#include "graphics/surface.h"
+#include "graphics/decoders/iff.h"
#include "graphics/decoders/pcx.h"
#include "queen/display.h"
@@ -701,7 +702,7 @@ void Display::setupPanel() {
uint8 *data = _vm->resource()->loadFile(dataName, 0, &dataSize);
if (_vm->resource()->getPlatform() == Common::kPlatformAmiga) {
- decodeLBM(data, dataSize, _panelBuf, PANEL_W, &panelWidth, &panelHeight, _pal.panel, 0, 32, 144);
+ decodeIFF(data, dataSize, _panelBuf, PANEL_W, &panelWidth, &panelHeight, _pal.panel, 0, 32, 144);
} else {
WRITE_LE_UINT16(data + 14, PANEL_H - 10);
decodePCX(data, dataSize, _panelBuf + PANEL_W * 10, PANEL_W, &panelWidth, &panelHeight, _pal.panel, 144, 256);
@@ -720,7 +721,7 @@ void Display::setupNewRoom(const char *name, uint16 room) {
uint8 *data = _vm->resource()->loadFile(dataName, 0, &dataSize);
if (_vm->resource()->getPlatform() == Common::kPlatformAmiga) {
- decodeLBM(data, dataSize, _backdropBuf, BACKDROP_W, &_bdWidth, &_bdHeight, _pal.room, 0, 32);
+ decodeIFF(data, dataSize, _backdropBuf, BACKDROP_W, &_bdWidth, &_bdHeight, _pal.room, 0, 32);
if (_bdHeight < BACKDROP_H) {
memset(_backdropBuf + _bdHeight * BACKDROP_W, 0, (BACKDROP_H - _bdHeight) * BACKDROP_W);
}
@@ -828,73 +829,22 @@ void Display::decodePCX(const uint8 *src, uint32 srcSize, uint8 *dst, uint16 dst
memcpy(dst + y * dstPitch, pcxSurface->getBasePtr(0, y), pcxSurface->w);
}
-void Display::decodeLBM(const uint8 *src, uint32 srcSize, uint8 *dst, uint16 dstPitch, uint16 *w, uint16 *h, uint8 *pal, uint16 palStart, uint16 palEnd, uint8 colorBase) {
- int planeCount = 0, planePitch = 0;
- const uint8 *srcEnd = src + srcSize;
- src += 12;
- while (src < srcEnd) {
- uint32 type = READ_BE_UINT32(src);
- uint32 size = READ_BE_UINT32(src + 4);
- src += 8;
- switch (type) {
- case MKTAG('B','M','H','D'): {
- *w = READ_BE_UINT16(src + 0);
- *h = READ_BE_UINT16(src + 2);
- planeCount = src[8];
- planePitch = ((*w + 15) >> 4) * 2;
- }
- break;
- case MKTAG('C','M','A','P'): {
- assert(palStart <= palEnd && palEnd <= size / 3);
- memcpy(pal, src + palStart * 3, (palEnd - palStart) * 3);
- }
- break;
- case MKTAG('B','O','D','Y'): {
- uint32 planarSize = (*h) * planeCount * planePitch;
- uint8 *planarBuf = new uint8[planarSize];
- uint8 *dstPlanar = planarBuf;
- for (int y = 0; y < *h; ++y) {
- for (int p = 0; p < planeCount; ++p) {
- const uint8 *end = dstPlanar + planePitch;
- while (dstPlanar < end) {
- int code = (int8)*src++;
- if (code != -128) {
- if (code < 0) {
- code = -code + 1;
- memset(dstPlanar, *src++, code);
- } else {
- ++code;
- memcpy(dstPlanar, src, code);
- src += code;
- }
- dstPlanar += code;
- }
- }
- }
- }
- src = planarBuf;
- for (int y = 0; y < *h; ++y) {
- for (int x = 0; x < *w / 8; ++x) {
- for (int b = 0; b < 8; ++b) {
- const uint8 mask = (1 << (7 - b));
- uint8 color = 0;
- for (int p = 0; p < planeCount; ++p) {
- if (src[planePitch * p + x] & mask) {
- color |= 1 << p;
- }
- }
- dst[x * 8 + b] = colorBase + color;
- }
- }
- src += planeCount * planePitch;
- dst += dstPitch;
- }
- delete[] planarBuf;
- }
- return;
- }
- src += size;
- }
+void Display::decodeIFF(const uint8 *src, uint32 srcSize, uint8 *dst, uint16 dstPitch, uint16 *w, uint16 *h, uint8 *pal, uint16 palStart, uint16 palEnd, uint8 colorBase) {
+ Common::MemoryReadStream str(src, srcSize);
+
+ ::Graphics::IFFDecoder iff;
+ if (!iff.loadStream(str))
+ error("Error while reading IFF image");
+
+ const ::Graphics::Surface *iffSurface = iff.getSurface();
+ *w = iffSurface->w;
+ *h = iffSurface->h;
+
+ assert(palStart <= palEnd && palEnd <= 256);
+ memcpy(pal, iff.getPalette() + palStart * 3, (palEnd - palStart) * 3);
+ for (uint16 y = 0; y < iffSurface->h; y++)
+ for(uint16 x = 0; x < iffSurface->w; x++)
+ dst[(y * dstPitch) + x] = *(const byte *)iffSurface->getBasePtr(x, y) + colorBase;
}
void Display::horizontalScrollUpdate(int16 xCamera) {
diff --git a/engines/queen/display.h b/engines/queen/display.h
index 4256b19d72..8a8aaef5a6 100644
--- a/engines/queen/display.h
+++ b/engines/queen/display.h
@@ -116,8 +116,8 @@ public:
//! decode PCX picture data
void decodePCX(const uint8 *src, uint32 srcSize, uint8 *dst, uint16 dstPitch, uint16 *w, uint16 *h, uint8 *pal, uint16 palStart, uint16 palEnd);
- //! decode ILBM picture data
- void decodeLBM(const uint8 *src, uint32 srcSize, uint8 *dst, uint16 dstPitch, uint16 *w, uint16 *h, uint8 *pal, uint16 palStart, uint16 palEnd, uint8 colorBase = 0);
+ //! decode IFF picture data
+ void decodeIFF(const uint8 *src, uint32 srcSize, uint8 *dst, uint16 dstPitch, uint16 *w, uint16 *h, uint8 *pal, uint16 palStart, uint16 palEnd, uint8 colorBase = 0);
void horizontalScrollUpdate(int16 xCamera);
void horizontalScroll(int16 scroll);
diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp
index 35d923f821..75876b1c90 100644
--- a/engines/saga/scene.cpp
+++ b/engines/saga/scene.cpp
@@ -41,9 +41,10 @@
#include "saga/actor.h"
#include "saga/resource.h"
-#include "graphics/iff.h"
#include "common/util.h"
+#include "graphics/decoders/iff.h"
+
namespace Saga {
static int initSceneDoors[SCENE_DOORS_MAX] = {
@@ -450,11 +451,11 @@ void Scene::changeScene(int16 sceneNumber, int actorsEntrance, SceneTransitionTy
debug(5, "Scene::changeScene(%d, %d, %d, %d)", sceneNumber, actorsEntrance, transitionType, chapter);
// This is used for latter ITE demos where all places on world map except
- // Tent Faire are substituted with LBM picture and short description
+ // Tent Faire are substituted with IFF picture and short description
if (_vm->_hasITESceneSubstitutes) {
for (int i = 0; i < ARRAYSIZE(sceneSubstitutes); i++) {
if (sceneSubstitutes[i].sceneId == sceneNumber) {
- byte *pal, colors[768];
+ const byte *pal;
Common::File file;
Rect rect;
PalEntry cPal[PAL_ENTRIES];
@@ -462,12 +463,12 @@ void Scene::changeScene(int16 sceneNumber, int actorsEntrance, SceneTransitionTy
_vm->_interface->setMode(kPanelSceneSubstitute);
if (file.open(sceneSubstitutes[i].image)) {
- Graphics::Surface bbmBuffer;
- Graphics::decodePBM(file, bbmBuffer, colors);
- pal = colors;
- rect.setWidth(bbmBuffer.w);
- rect.setHeight(bbmBuffer.h);
- _vm->_gfx->drawRegion(rect, (const byte*)bbmBuffer.pixels);
+ Graphics::IFFDecoder decoder;
+ decoder.loadStream(file);
+ pal = decoder.getPalette();
+ rect.setWidth(decoder.getSurface()->w);
+ rect.setHeight(decoder.getSurface()->h);
+ _vm->_gfx->drawRegion(rect, (const byte *)decoder.getSurface()->pixels);
for (int j = 0; j < PAL_ENTRIES; j++) {
cPal[j].red = *pal++;
cPal[j].green = *pal++;
diff --git a/graphics/decoders/iff.cpp b/graphics/decoders/iff.cpp
new file mode 100644
index 0000000000..50c7b4f7de
--- /dev/null
+++ b/graphics/decoders/iff.cpp
@@ -0,0 +1,241 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "common/iff_container.h"
+#include "common/stream.h"
+#include "common/util.h"
+
+#include "graphics/decoders/iff.h"
+
+namespace Graphics {
+
+IFFDecoder::IFFDecoder() {
+ _surface = 0;
+ _palette = 0;
+
+ destroy();
+}
+
+IFFDecoder::~IFFDecoder() {
+ destroy();
+}
+
+void IFFDecoder::destroy() {
+ if (_surface) {
+ _surface->free();
+ delete _surface;
+ _surface = 0;
+ }
+
+ if (_palette) {
+ delete[] _palette;
+ _palette = 0;
+ }
+
+ memset(&_header, 0, sizeof(Header));
+ _paletteRanges.clear();
+ _type = TYPE_UNKNOWN;
+ _paletteColorCount = 0;
+ _numRelevantPlanes = 8;
+ _pixelPacking = false;
+}
+
+bool IFFDecoder::loadStream(Common::SeekableReadStream &stream) {
+ destroy();
+
+ const uint32 form = stream.readUint32BE();
+
+ if (form != ID_FORM) {
+ warning("Failed reading IFF-file");
+ return false;
+ }
+
+ stream.skip(4);
+
+ const uint32 type = stream.readUint32BE();
+
+ switch (type) {
+ case ID_ILBM:
+ _type = TYPE_ILBM;
+ break;
+ case ID_PBM:
+ _type = TYPE_PBM;
+ break;
+ }
+
+ if (type == TYPE_UNKNOWN) {
+ warning("Failed reading IFF-file");
+ return false;
+ }
+
+ while (1) {
+ const uint32 chunkType = stream.readUint32BE();
+ const uint32 chunkSize = stream.readUint32BE();
+
+ if (stream.eos())
+ break;
+
+ switch (chunkType) {
+ case ID_BMHD:
+ loadHeader(stream);
+ break;
+ case ID_CMAP:
+ loadPalette(stream, chunkSize);
+ break;
+ case ID_CRNG:
+ loadPaletteRange(stream, chunkSize);
+ break;
+ case ID_BODY:
+ loadBitmap(stream);
+ break;
+ default:
+ stream.skip(chunkSize);
+ }
+ }
+
+ return true;
+}
+
+void IFFDecoder::loadHeader(Common::SeekableReadStream &stream) {
+ _header.width = stream.readUint16BE();
+ _header.height = stream.readUint16BE();
+ _header.x = stream.readUint16BE();
+ _header.y = stream.readUint16BE();
+ _header.numPlanes = stream.readByte();
+ _header.masking = stream.readByte();
+ _header.compression = stream.readByte();
+ _header.flags = stream.readByte();
+ _header.transparentColor = stream.readUint16BE();
+ _header.xAspect = stream.readByte();
+ _header.yAspect = stream.readByte();
+ _header.pageWidth = stream.readUint16BE();
+ _header.pageHeight = stream.readUint16BE();
+
+ assert(_header.width >= 1);
+ assert(_header.height >= 1);
+ assert(_header.numPlanes >= 1 && _header.numPlanes <= 8 && _header.numPlanes != 7);
+}
+
+void IFFDecoder::loadPalette(Common::SeekableReadStream &stream, const uint32 size) {
+ _palette = new byte[size];
+ stream.read(_palette, size);
+ _paletteColorCount = size / 3;
+}
+
+void IFFDecoder::loadPaletteRange(Common::SeekableReadStream &stream, const uint32 size) {
+ PaletteRange range;
+
+ range.timer = stream.readSint16BE();
+ range.step = stream.readSint16BE();
+ range.flags = stream.readSint16BE();
+ range.first = stream.readByte();
+ range.last = stream.readByte();
+
+ _paletteRanges.push_back(range);
+}
+
+void IFFDecoder::loadBitmap(Common::SeekableReadStream &stream) {
+ _numRelevantPlanes = MIN(_numRelevantPlanes, _header.numPlanes);
+
+ if (_numRelevantPlanes != 1 && _numRelevantPlanes != 2 && _numRelevantPlanes != 4)
+ _pixelPacking = false;
+
+ uint16 outPitch = _header.width;
+
+ if (_pixelPacking)
+ outPitch /= (8 / _numRelevantPlanes);
+
+ // FIXME: CLUT8 is not a proper format for packed bitmaps but there is no way to tell it to use 1, 2 or 4 bits per pixel
+ _surface = new Graphics::Surface();
+ _surface->create(outPitch, _header.height, Graphics::PixelFormat::createFormatCLUT8());
+
+ if (_type == TYPE_ILBM) {
+ uint32 scanlinePitch = ((_header.width + 15) >> 4) << 1;
+ byte *scanlines = new byte[scanlinePitch * _header.numPlanes];
+ byte *data = (byte *)_surface->pixels;
+
+ for (uint16 i = 0; i < _header.height; ++i) {
+ byte *scanline = scanlines;
+
+ for (uint16 j = 0; j < _header.numPlanes; ++j) {
+ uint16 outSize = scanlinePitch;
+
+ if (_header.compression) {
+ Common::PackBitsReadStream packStream(stream);
+ packStream.read(scanline, outSize);
+ } else {
+ stream.read(scanline, outSize);
+ }
+
+ scanline += outSize;
+ }
+
+ packPixels(scanlines, data, scanlinePitch, outPitch);
+ data += outPitch;
+ }
+
+ delete[] scanlines;
+ } else if (_type == TYPE_PBM) {
+ byte *data = (byte *)_surface->pixels;
+ uint32 outSize = _header.width * _header.height;
+
+ if (_header.compression) {
+ Common::PackBitsReadStream packStream(stream);
+ packStream.read(data, outSize);
+ } else {
+ stream.read(data, outSize);
+ }
+ }
+}
+
+void IFFDecoder::packPixels(byte *scanlines, byte *data, const uint16 scanlinePitch, const uint16 outPitch) {
+ uint32 numPixels = _header.width;
+
+ if (_pixelPacking)
+ numPixels = outPitch * (8 / _numRelevantPlanes);
+
+ for (uint32 x = 0; x < numPixels; ++x) {
+ byte *scanline = scanlines;
+ byte pixel = 0;
+ byte offset = x >> 3;
+ byte bit = 0x80 >> (x & 7);
+
+ // first build a pixel by scanning all the usable planes in the input
+ for (uint32 plane = 0; plane < _numRelevantPlanes; ++plane) {
+ if (scanline[offset] & bit)
+ pixel |= (1 << plane);
+
+ scanline += scanlinePitch;
+ }
+
+ // then output the pixel according to the requested packing
+ if (!_pixelPacking)
+ data[x] = pixel;
+ else if (_numRelevantPlanes == 1)
+ data[x / 8] |= (pixel << (x & 7));
+ else if (_numRelevantPlanes == 2)
+ data[x / 4] |= (pixel << ((x & 3) << 1));
+ else if (_numRelevantPlanes == 4)
+ data[x / 2] |= (pixel << ((x & 1) << 2));
+ }
+}
+
+} // End of namespace Graphics
diff --git a/graphics/decoders/iff.h b/graphics/decoders/iff.h
new file mode 100644
index 0000000000..beac62e519
--- /dev/null
+++ b/graphics/decoders/iff.h
@@ -0,0 +1,119 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @file
+ * Image decoder used in engines:
+ * - gob
+ * - parallaction
+ * - queen
+ * - saga
+ */
+
+#ifndef GRAPHICS_DECODERS_IFF_H
+#define GRAPHICS_DECODERS_IFF_H
+
+#include "common/array.h"
+#include "common/endian.h"
+
+#include "graphics/surface.h"
+#include "graphics/decoders/image_decoder.h"
+
+namespace Common {
+class SeekableReadStream;
+}
+
+namespace Graphics {
+
+struct Surface;
+
+class IFFDecoder : public ImageDecoder {
+public:
+ struct Header {
+ uint16 width, height;
+ uint16 x, y;
+ byte numPlanes;
+ byte masking;
+ byte compression;
+ byte flags;
+ uint16 transparentColor;
+ byte xAspect, yAspect;
+ uint16 pageWidth, pageHeight;
+ };
+
+ struct PaletteRange {
+ int16 timer, step, flags;
+ byte first, last;
+ };
+
+ enum Type {
+ TYPE_UNKNOWN = 0,
+ TYPE_ILBM,
+ TYPE_PBM
+ };
+
+ IFFDecoder();
+ virtual ~IFFDecoder();
+
+ // ImageDecoder API
+ void destroy();
+ bool loadStream(Common::SeekableReadStream &stream);
+ const Header *getHeader() const { return &_header; }
+ const Surface *getSurface() const { return _surface; }
+ const byte *getPalette() const { return _palette; }
+ const Common::Array<PaletteRange> &getPaletteRanges() const { return _paletteRanges; }
+ uint16 getPaletteColorCount() const { return _paletteColorCount; }
+
+ /**
+ * The number of planes to decode, also determines the pixel packing if _packPixels is true.
+ * 8 == decode all planes, map 1 pixel in 1 byte. (default, no packing even if _packPixels is true)
+ */
+ void setNumRelevantPlanes(const uint8 numRelevantPlanes) { _numRelevantPlanes = numRelevantPlanes; }
+
+ /**
+ * Enables pixel packing, the amount of packing is determined by _numRelevantPlanes
+ * 1 == decode first plane, pack 8 pixels in 1 byte. This makes _surface->w 1/8th of _header.width
+ * 2 == decode first 2 planes, pack 4 pixels in 1 byte. This makes _surface->w 1/4th of _header.width
+ * 4 == decode first 4 planes, pack 2 pixels in 1 byte. This makes _surface->w half of _header.width
+ * Packed bitmaps won't have a proper surface format since there is no way to tell it to use 1, 2 or 4 bits per pixel
+ */
+ void setPixelPacking(const bool pixelPacking) { _pixelPacking = pixelPacking; }
+private:
+
+ Header _header;
+ Surface *_surface;
+ byte *_palette;
+ Common::Array<PaletteRange> _paletteRanges;
+ Type _type;
+ uint16 _paletteColorCount;
+ uint8 _numRelevantPlanes;
+ bool _pixelPacking;
+
+ void loadHeader(Common::SeekableReadStream &stream);
+ void loadPalette(Common::SeekableReadStream &stream, const uint32 size);
+ void loadPaletteRange(Common::SeekableReadStream &stream, const uint32 size);
+ void loadBitmap(Common::SeekableReadStream &stream);
+ void packPixels(byte *scanlines, byte *data, const uint16 scanlinePitch, const uint16 outPitch);
+};
+
+} // End of namespace Graphics
+
+#endif // GRAPHICS_DECODERS_IFF_H
diff --git a/graphics/iff.cpp b/graphics/iff.cpp
deleted file mode 100644
index 395d8d803b..0000000000
--- a/graphics/iff.cpp
+++ /dev/null
@@ -1,289 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "graphics/iff.h"
-#include "graphics/surface.h"
-
-#include "common/endian.h"
-#include "common/func.h"
-#include "common/iff_container.h"
-#include "common/textconsole.h"
-#include "common/util.h"
-
-namespace Graphics {
-
-void BMHD::load(Common::ReadStream *stream) {
- assert(stream);
- stream->read(this, sizeof(BMHD));
- width = FROM_BE_16(width);
- height = FROM_BE_16(height);
- x = FROM_BE_16(x);
- y = FROM_BE_16(y);
- transparentColor = FROM_BE_16(transparentColor);
- pageWidth = FROM_BE_16(pageWidth);
- pageHeight = FROM_BE_16(pageHeight);
-}
-
-
-void ILBMDecoder::loadHeader(Common::ReadStream *stream) {
- _header.load(stream);
-}
-
-void ILBMDecoder::loadBitmap(uint32 mode, byte *buffer, Common::ReadStream *stream, uint32 outPitch) {
- assert(stream);
- uint32 numPlanes = MIN(mode & ILBM_UNPACK_PLANES, (uint32)_header.depth);
- assert(numPlanes >= 1 && numPlanes <= 8 && numPlanes != 7);
-
- bool packPixels = (mode & ILBM_PACK_PLANES) != 0;
- if (numPlanes != 1 && numPlanes != 2 && numPlanes != 4) {
- packPixels = false;
- }
-
- if (outPitch == 0)
- outPitch = _header.width;
- if (packPixels) {
- outPitch /= (8 / numPlanes);
- }
- byte *out = buffer;
-
- switch (_header.pack) {
- case 0: { // non-compressed bitmap
- // setup a buffer to hold enough data to build a line in the output
- uint32 scanlineWidth = ((_header.width + 15) / 16) << 1;
- byte *scanline = new byte[scanlineWidth * _header.depth];
-
- for (uint i = 0; i < _header.height; ++i) {
- byte *s = scanline;
- for (uint32 j = 0; j < _header.depth; ++j) {
- stream->read(s, scanlineWidth);
- s += scanlineWidth;
- }
-
- planarToChunky(out, outPitch, scanline, scanlineWidth, numPlanes, packPixels);
- out += outPitch;
- }
-
- delete[] scanline;
- break;
- }
-
- case 1: { // PackBits compressed bitmap
- Graphics::PackBitsReadStream packStream(*stream);
-
- // setup a buffer to hold enough data to build a line in the output
- uint32 scanlineWidth = ((_header.width + 15) / 16) << 1;
- byte *scanline = new byte[scanlineWidth * _header.depth];
-
- for (uint i = 0; i < _header.height; ++i) {
- byte *s = scanline;
- for (uint32 j = 0; j < _header.depth; ++j) {
- packStream.read(s, scanlineWidth);
- s += scanlineWidth;
- }
-
- planarToChunky(out, outPitch, scanline, scanlineWidth, numPlanes, packPixels);
- out += outPitch;
- }
-
- delete[] scanline;
- break;
- }
-
- default:
- // implement other compression types here!
- error("only uncompressed and RLE compressed ILBM files are supported");
- break;
- }
-}
-
-void ILBMDecoder::planarToChunky(byte *out, uint32 outPitch, byte *in, uint32 inWidth, uint32 nPlanes, bool packPlanes) {
- byte pix, ofs, bit;
- byte *s;
-
- uint32 pixels = outPitch;
- if (packPlanes) {
- pixels *= (8 / nPlanes);
- }
-
- for (uint32 x = 0; x < pixels; ++x) {
-
- pix = 0;
- ofs = x >> 3;
- bit = 0x80 >> (x & 7);
-
- // first build a pixel by scanning all the usable planes in the input
- s = in;
- for (uint32 plane = 0; plane < nPlanes; ++plane) {
- if (s[ofs] & bit) {
- pix |= (1 << plane);
- }
- s += inWidth;
- }
-
-
- // then output the pixel according to the requested packing
- if (!packPlanes) {
- out[x] = pix;
- } else if (nPlanes == 1) {
- out[x / 8] |= (pix << (x & 7));
- } else if (nPlanes == 2) {
- out[x / 4] |= (pix << ((x & 3) << 1));
- } else if (nPlanes == 4) {
- out[x / 2] |= (pix << ((x & 1) << 2));
- }
- }
-
-}
-
-
-// handles PBM subtype of IFF FORM files
-//
-struct PBMDecoder {
- /**
- * PBM header data, necessary for loadBitmap()
- */
- Graphics::BMHD _header;
-
- /**
- * Fills the _header member from the given stream.
- */
- void loadHeader(Common::ReadStream *stream);
-
- /**
- * Loads and unpacks the PBM bitmap data from the stream into the buffer.
- * The functions assumes the buffer is large enough to contain all data.
- */
- void loadBitmap(byte *buffer, Common::ReadStream *stream);
-};
-
-void PBMDecoder::loadHeader(Common::ReadStream *stream) {
- _header.load(stream);
-}
-
-
-void PBMDecoder::loadBitmap(byte *buffer, Common::ReadStream *stream) {
- uint32 outSize = _header.width * _header.height;
-
- switch (_header.pack) {
- case 0:
- stream->read(buffer, outSize);
- break;
-
- case 1: {
- PackBitsReadStream packStream(*stream);
- packStream.read(buffer, outSize);
- break;
- }
- }
-}
-
-
-struct PBMLoader {
- PBMDecoder _decoder;
- Surface *_surface;
- byte *_colors;
-
- void load(Common::ReadStream &input, Surface &surface, byte *&colors) {
- _surface = &surface;
- _colors = colors;
- Common::IFFParser parser(&input);
- Common::Functor1Mem<Common::IFFChunk &, bool, PBMLoader> c(this, &PBMLoader::callback);
- parser.parse(c);
- }
-
- bool callback(Common::IFFChunk &chunk) {
- switch (chunk._type) {
- case ID_BMHD:
- _decoder.loadHeader(chunk._stream);
- break;
-
- case ID_CMAP:
- if (_colors) {
- chunk._stream->read(_colors, chunk._size);
- }
- break;
-
- case ID_BODY:
- if (_surface) {
- _surface->create(_decoder._header.width, _decoder._header.height, PixelFormat::createFormatCLUT8());
- _decoder.loadBitmap((byte *)_surface->pixels, chunk._stream);
- }
- return true; // stop the parser
- }
-
- return false;
- }
-};
-
-void decodePBM(Common::ReadStream &input, Surface &surface, byte *colors) {
- PBMLoader loader;
- loader.load(input, surface, colors);
-}
-
-
-
-
-PackBitsReadStream::PackBitsReadStream(Common::ReadStream &input) : _input(&input) {
-}
-
-PackBitsReadStream::~PackBitsReadStream() {
-}
-
-bool PackBitsReadStream::eos() const {
- return _input->eos();
-}
-
-uint32 PackBitsReadStream::read(void *dataPtr, uint32 dataSize) {
- byte *out = (byte *)dataPtr;
- uint32 left = dataSize;
-
- uint32 lenR = 0, lenW = 0;
- while (left > 0 && !_input->eos()) {
- lenR = _input->readByte();
-
- if (lenR == 128) {
- // no-op
- lenW = 0;
- } else if (lenR <= 127) {
- // literal run
- lenR++;
- lenW = MIN(lenR, left);
- for (uint32 j = 0; j < lenW; j++) {
- *out++ = _input->readByte();
- }
- for (; lenR > lenW; lenR--) {
- _input->readByte();
- }
- } else { // len > 128
- // expand run
- lenW = MIN((256 - lenR) + 1, left);
- byte val = _input->readByte();
- memset(out, val, lenW);
- out += lenW;
- }
-
- left -= lenW;
- }
-
- return dataSize - left;
-}
-
-} // End of namespace Graphics
diff --git a/graphics/iff.h b/graphics/iff.h
deleted file mode 100644
index 651867fa52..0000000000
--- a/graphics/iff.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/*
- * Bitmap decoder used in engines:
- * - parallaction
- * - saga
- */
-
-#ifndef GRAPHICS_IFF_H
-#define GRAPHICS_IFF_H
-
-#include "common/stream.h"
-
-namespace Graphics {
-
-struct Surface;
-
-
-struct BMHD {
- uint16 width, height;
- uint16 x, y;
- byte depth;
- byte masking;
- byte pack;
- byte flags;
- uint16 transparentColor;
- byte xAspect, yAspect;
- uint16 pageWidth, pageHeight;
-
- BMHD() {
- memset(this, 0, sizeof(*this));
- }
-
- void load(Common::ReadStream *stream);
-};
-
-
-struct ILBMDecoder {
- /**
- * ILBM header data, necessary for loadBitmap()
- */
- Graphics::BMHD _header;
-
- /**
- * Available decoding modes for loadBitmap().
- */
- enum {
- ILBM_UNPACK_PLANES = 0xFF, ///< Decode all bitplanes, and map 1 pixel to 1 byte.
- ILBM_PACK_PLANES = 0x100, ///< Request unpacking, used as a mask with below options.
-
- ILBM_1_PLANES = 1, ///< Decode only the first bitplane, don't pack.
- ILBM_1_PACK_PLANES = ILBM_1_PLANES | ILBM_PACK_PLANES, ///< Decode only the first bitplane, pack 8 pixels in 1 byte.
- ILBM_2_PLANES = 2, ///< Decode first 2 bitplanes, don't pack.
- ILBM_2_PACK_PLANES = ILBM_2_PLANES | ILBM_PACK_PLANES, ///< Decode first 2 bitplanes, pack 4 pixels in 1 byte.
- ILBM_3_PLANES = 3, ///< Decode first 3 bitplanes, don't pack.
- ILBM_4_PLANES = 4, ///< Decode first 4 bitplanes, don't pack.
- ILBM_4_PACK_PLANES = ILBM_4_PLANES | ILBM_PACK_PLANES, ///< Decode first 4 bitplanes, pack 2 pixels in 1 byte.
- ILBM_5_PLANES = 5, ///< Decode first 5 bitplanes, don't pack.
- ILBM_8_PLANES = 8 ///< Decode all 8 bitplanes.
- };
-
- /**
- * Fills the _header member from the given stream.
- */
- void loadHeader(Common::ReadStream *stream);
-
- /**
- * Loads and unpacks the ILBM bitmap data from the stream into the buffer.
- * The functions assumes the buffer is large enough to contain all data.
- * The caller controls how data should be packed by choosing mode from
- * the enum above.
- */
- void loadBitmap(uint32 mode, byte *buffer, Common::ReadStream *stream, uint32 outPitch = 0);
-
- /**
- * Converts from bitplanar to chunky representation. Intended for internal
- * usage, but you can be (ab)use it from client code if you know what you
- * are doing.
- */
- void planarToChunky(byte *out, uint32 width, byte *in, uint32 planeWidth, uint32 nPlanes, bool packPlanes);
-};
-
-
-
-/**
- * Handles PBM subtype of IFF FORM files
- */
-void decodePBM(Common::ReadStream &input, Surface &surface, byte *colors);
-
-
-/**
- * Decode a given PackBits encoded stream.
- *
- * PackBits is an RLE compression algorithm introduced by Apple. It is also
- * used to encode ILBM and PBM subtypes of IFF files, and some flavors of
- * TIFF.
- *
- * As there is no compression across row boundaries in the above formats,
- * read() will extract a *new* line on each call, discarding any alignment
- * or padding.
- */
-class PackBitsReadStream : public Common::ReadStream {
-
-protected:
- Common::ReadStream *_input;
-
-public:
- PackBitsReadStream(Common::ReadStream &input);
- ~PackBitsReadStream();
-
- virtual bool eos() const;
-
- uint32 read(void *dataPtr, uint32 dataSize);
-};
-
-} // End of namespace Graphics
-
-#endif
diff --git a/graphics/module.mk b/graphics/module.mk
index f560d9dc97..8b63435905 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -11,7 +11,6 @@ MODULE_OBJS := \
fonts/newfont.o \
fonts/ttf.o \
fonts/winfont.o \
- iff.o \
maccursor.o \
primitives.o \
scaler.o \
@@ -24,6 +23,7 @@ MODULE_OBJS := \
wincursor.o \
yuv_to_rgb.o \
decoders/bmp.o \
+ decoders/iff.o \
decoders/jpeg.o \
decoders/pcx.o \
decoders/pict.o \