aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorNicola Mettifogo2009-06-12 05:03:18 +0000
committerNicola Mettifogo2009-06-12 05:03:18 +0000
commit5fccc0f98dda5cbcec208b17c2e6d36a36fadf1e (patch)
tree4077bb476edd1bd959eca925a6f5d80bceff230f /engines
parentf5b2e69522153c47438895ea80129ad5e3c9b952 (diff)
downloadscummvm-rg350-5fccc0f98dda5cbcec208b17c2e6d36a36fadf1e.tar.gz
scummvm-rg350-5fccc0f98dda5cbcec208b17c2e6d36a36fadf1e.tar.bz2
scummvm-rg350-5fccc0f98dda5cbcec208b17c2e6d36a36fadf1e.zip
* Final version of the IFF parsing code.
* Refactored ILBMDecoder usage from disk code. svn-id: r41458
Diffstat (limited to 'engines')
-rw-r--r--engines/parallaction/disk.cpp121
-rw-r--r--engines/parallaction/disk.h40
-rw-r--r--engines/parallaction/disk_br.cpp113
-rw-r--r--engines/parallaction/disk_ns.cpp72
-rw-r--r--engines/parallaction/gfxbase.cpp8
-rw-r--r--engines/parallaction/iff.cpp209
-rw-r--r--engines/parallaction/iff.h191
-rw-r--r--engines/parallaction/module.mk1
8 files changed, 422 insertions, 333 deletions
diff --git a/engines/parallaction/disk.cpp b/engines/parallaction/disk.cpp
new file mode 100644
index 0000000000..a58fa35655
--- /dev/null
+++ b/engines/parallaction/disk.cpp
@@ -0,0 +1,121 @@
+#include "parallaction/disk.h"
+#include "parallaction/graphics.h"
+#include "parallaction/iff.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, 1);
+ _mode = ILBMDecoder::ILBM_UNPACK_PLANES;
+ _intBuffer = (byte*)_surf->pixels;
+ break;
+
+ case BODYMODE_MASKBUFFER:
+ if (!_maskBuffer) {
+ _maskBuffer = new MaskBuffer;
+ assert(_maskBuffer);
+ }
+ _maskBuffer->create(w, h);
+ _mode = ILBMDecoder::ILBM_2_PACK_PLANES;
+ _intBuffer = _maskBuffer->data;
+ break;
+
+ case BODYMODE_PATHBUFFER:
+ if (!_pathBuffer) {
+ _pathBuffer = new PathBuffer;
+ assert(_pathBuffer);
+ }
+ _pathBuffer->create(w, h);
+ _mode = ILBMDecoder::ILBM_1_PACK_PLANES;
+ _intBuffer = _pathBuffer->data;
+ break;
+
+ default:
+ error("Invalid bodyMode '%i' for ILBMLoader", _bodyMode);
+ break;
+ }
+}
+
+bool ILBMLoader::callback(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) {
+ IFFParser parser(in, disposeStream);
+ Common::Functor1Mem< 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 4cc2711e96..936be1e140 100644
--- a/engines/parallaction/disk.h
+++ b/engines/parallaction/disk.h
@@ -33,6 +33,7 @@
#include "common/file.h"
#include "graphics/surface.h"
+#include "parallaction/iff.h"
@@ -77,8 +78,37 @@ public:
virtual Table* loadTable(const char* name) = 0;
virtual Common::SeekableReadStream* loadMusic(const char* name) = 0;
virtual Common::SeekableReadStream* loadSound(const char* name) = 0;
- virtual void loadMask(const char *name, MaskBuffer &buffer) { }
- virtual void loadPath(const char *name, PathBuffer &buffer) { }
+ virtual MaskBuffer *loadMask(const char *name, uint32 w, uint32 h) { return 0; }
+ 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;
+ 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(IFFChunk &chunk);
+ void setupBuffer(uint32 w, uint32 h);
+ void load(Common::ReadStream *in, bool disposeStream = false);
};
@@ -235,8 +265,8 @@ public:
Table* loadTable(const char* name);
Common::SeekableReadStream* loadMusic(const char* name);
Common::SeekableReadStream* loadSound(const char* name);
- void loadMask(const char *name, MaskBuffer &buffer);
- void loadPath(const char *name, PathBuffer &buffer);
+ MaskBuffer *loadMask(const char *name, uint32 w, uint32 h);
+ PathBuffer *loadPath(const char *name, uint32 w, uint32 h);
};
class DosDemoDisk_br : public DosDisk_br {
@@ -272,7 +302,7 @@ public:
GfxObj* loadObjects(const char *name, uint8 part = 0);
Common::SeekableReadStream* loadMusic(const char* name);
Common::SeekableReadStream* loadSound(const char* name);
- void loadMask(const char *name, MaskBuffer &buffer);
+ MaskBuffer *loadMask(const char *name, uint32 w, uint32 h);
};
} // namespace Parallaction
diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp
index ec4fc32cc1..3572129dc0 100644
--- a/engines/parallaction/disk_br.cpp
+++ b/engines/parallaction/disk_br.cpp
@@ -331,32 +331,40 @@ void DosDisk_br::loadSlide(BackgroundInfo& info, const char *name) {
}
}
-void DosDisk_br::loadMask(const char *name, MaskBuffer &buffer) {
+MaskBuffer *DosDisk_br::loadMask(const char *name, uint32 w, uint32 h) {
if (!name) {
- return;
+ return 0;
}
Common::SeekableReadStream *stream = openFile("msk/" + Common::String(name), ".msk");
- // NOTE: info.width and info.height are only valid if the background graphics
- // have already been loaded
- buffer.bigEndian = false;
- stream->read(buffer.data, buffer.size);
+ MaskBuffer *buffer = new MaskBuffer;
+ assert(buffer);
+ buffer->create(w, h);
+ buffer->bigEndian = false;
+
+ stream->read(buffer->data, buffer->size);
delete stream;
+
+ return buffer;
}
-void DosDisk_br::loadPath(const char *name, PathBuffer &buffer) {
+PathBuffer *DosDisk_br::loadPath(const char *name, uint32 w, uint32 h) {
if (!name) {
- return;
+ return 0;
}
Common::SeekableReadStream *stream = openFile("pth/" + Common::String(name), ".pth");
- // NOTE: info.width and info.height are only valid if the background graphics
- // have already been loaded
- buffer.bigEndian = false;
- stream->read(buffer.data, buffer.size);
+ PathBuffer *buffer = new PathBuffer;
+ assert(buffer);
+ buffer->create(w, h);
+ buffer->bigEndian = false;
+
+ stream->read(buffer->data, buffer->size);
delete stream;
+
+ return buffer;
}
void DosDisk_br::loadScenery(BackgroundInfo& info, const char *name, const char *mask, const char* path) {
@@ -380,18 +388,12 @@ void DosDisk_br::loadScenery(BackgroundInfo& info, const char *name, const char
}
if (mask) {
- info._mask = new MaskBuffer;
- info._mask->create(info.width, info.height);
- loadMask(mask, *info._mask);
+ info._mask = loadMask(mask, info.width, info.height);
}
if (path) {
- info._path = new PathBuffer;
- info._path->create(info.width, info.height);
- loadPath(path, *info._path);
+ info._path = loadPath(path, info.width, info.height);
}
-
- return;
}
Table* DosDisk_br::loadTable(const char* name) {
@@ -459,7 +461,7 @@ void AmigaDisk_br::adjustForPalette(Graphics::Surface &surf, int transparentColo
void AmigaDisk_br::loadBackground(BackgroundInfo& info, const char *filename) {
byte r,g,b;
- byte *pal, *p;
+ byte *p;
Common::SeekableReadStream *stream;
uint i;
@@ -488,20 +490,14 @@ void AmigaDisk_br::loadBackground(BackgroundInfo& info, const char *filename) {
}
stream = openFile("backs/" + Common::String(filename), ".bkg");
- ILBMDecoder decoder(stream, true);
- // TODO: encapsulate surface creation
- info.bg.w = decoder.getWidth();
- info.bg.h = decoder.getHeight();
- info.bg.pitch = info.bg.w;
- info.bg.bytesPerPixel = 1;
- info.bg.pixels = decoder.getBitmap();
- assert(info.bg.pixels);
+ byte pal[768];
+ ILBMLoader loader(&info.bg, pal);
+ loader.load(stream, true);
info.width = info.bg.w;
info.height = info.bg.h;
- pal = decoder.getPalette();
p = pal;
for (i = 16; i < 32; i++) {
r = *p >> 2;
@@ -516,8 +512,6 @@ void AmigaDisk_br::loadBackground(BackgroundInfo& info, const char *filename) {
// Overwrite the first color (transparent key) in the palette
info.palette.setEntry(0, pal[0] >> 2, pal[1] >> 2, pal[2] >> 0);
- delete []pal;
-
// background data is drawn used the upper portion of the palette
adjustForPalette(info.bg);
}
@@ -543,27 +537,24 @@ void finalpass(byte *buffer, uint32 size) {
}
}
-void AmigaDisk_br::loadMask(const char *name, MaskBuffer &buffer) {
+MaskBuffer *AmigaDisk_br::loadMask(const char *name, uint32 w, uint32 h) {
if (!name) {
- return;
+ return 0;
}
debugC(1, kDebugDisk, "AmigaDisk_br::loadMask '%s'", name);
Common::SeekableReadStream *stream = tryOpenFile("msk/" + Common::String(name), ".msk");
if (!stream) {
- return;
+ return 0;
}
- ILBMDecoder decoder(stream, true);
+ ILBMLoader loader(ILBMLoader::BODYMODE_MASKBUFFER);
+ loader.load(stream, true);
- // TODO: the buffer is allocated by the caller, so a copy here is
- // unavoidable... a better solution would be inform the function
- // of the size of the mask (the size in the mask file is not valid!)
- byte *bitmap = decoder.getBitmap(2, true);
- memcpy(buffer.data, bitmap, buffer.size);
- finalpass(buffer.data, buffer.size);
-
- buffer.bigEndian = true;
+ MaskBuffer *buffer = loader._maskBuffer;
+ buffer->bigEndian = true;
+ finalpass(buffer->data, buffer->size);
+ return buffer;
}
void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path) {
@@ -573,18 +564,12 @@ void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const cha
loadBackground(info, name);
}
if (mask) {
- info._mask = new MaskBuffer;
- info._mask->create(info.width, info.height);
- loadMask(mask, *info._mask);
+ info._mask = loadMask(mask, info.width, info.height);
}
if (path) {
- info._path = new PathBuffer;
- info._path->create(info.width, info.height);
- loadPath(path, *info._path);
+ info._path = loadPath(path, info.width, info.height);
}
-
- return;
}
void AmigaDisk_br::loadSlide(BackgroundInfo& info, const char *name) {
@@ -596,20 +581,13 @@ GfxObj* AmigaDisk_br::loadStatic(const char* name) {
debugC(1, kDebugDisk, "AmigaDisk_br::loadStatic '%s'", name);
Common::String sName = name;
-
Common::SeekableReadStream *stream = openFile("ras/" + sName, ".ras");
- ILBMDecoder decoder(stream, true);
- Graphics::Surface* surf = new Graphics::Surface;
- assert(surf);
+ ILBMLoader loader(ILBMLoader::BODYMODE_SURFACE);
+ loader.load(stream, true);
- // TODO: encapsulate surface creation
- surf->w = decoder.getWidth();
- surf->h = decoder.getHeight();
- surf->pitch = surf->w;
- surf->bytesPerPixel = 1;
- surf->pixels = decoder.getBitmap();
- assert(surf->pixels);
+ Graphics::Surface* surf = loader._surf;
+ assert(surf);
// 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
@@ -741,15 +719,16 @@ GfxObj* AmigaDisk_br::loadObjects(const char *name, uint8 part) {
debugC(5, kDebugDisk, "AmigaDisk_br::loadObjects");
Common::SeekableReadStream *stream = openFile(name);
- ILBMDecoder decoder(stream, true);
+ ILBMLoader loader(ILBMLoader::BODYMODE_SURFACE);
+ loader.load(stream, true);
uint16 max = objectsMax[part];
if (_vm->getFeatures() & GF_DEMO)
max = 72;
byte *data = new byte[max * 2601];
- byte *srcPtr = decoder.getBitmap();
- int w = decoder.getWidth();
+ byte *srcPtr = (byte*)loader._surf->getBasePtr(0,0);
+ int w = loader._surf->w;
// Convert to the expected display format
for (int i = 0; i < max; i++) {
@@ -764,7 +743,7 @@ GfxObj* AmigaDisk_br::loadObjects(const char *name, uint8 part) {
dst += 51;
}
}
- free(srcPtr);
+ 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 8aa2a9f543..a75decdf88 100644
--- a/engines/parallaction/disk_ns.cpp
+++ b/engines/parallaction/disk_ns.cpp
@@ -900,56 +900,18 @@ void AmigaDisk_ns::buildMask(byte* buf) {
}
}
-// TODO: extend the ILBMDecoder to return CRNG chunks and get rid of this BackgroundDecoder crap
-class BackgroundDecoder : public ILBMDecoder {
-
-public:
- BackgroundDecoder(Common::SeekableReadStream *input, bool disposeStream = false) : ILBMDecoder(input, disposeStream) {
- }
-
- uint32 getCRNG(PaletteFxRange *ranges, uint32 num) {
- assert(ranges);
-
- uint32 size = _parser.getIFFBlockSize(ID_CRNG);
- if (size == (uint32)-1) {
- return 0;
- }
-
- uint32 count = MIN((uint32)(size / sizeof(PaletteFxRange)), num);
- _parser.loadIFFBlock(ID_CRNG, ranges, count * sizeof(PaletteFxRange));
-
- for (uint32 i = 0; i < count; ++i) {
- ranges[i]._timer = FROM_BE_16(ranges[i]._timer);
- ranges[i]._step = FROM_BE_16(ranges[i]._step);
- ranges[i]._flags = FROM_BE_16(ranges[i]._flags);
- }
-
- return count;
- }
-};
-
void AmigaDisk_ns::loadBackground(BackgroundInfo& info, const char *name) {
-
- Common::SeekableReadStream *s = openFile(name);
- BackgroundDecoder decoder(s, true);
-
PaletteFxRange ranges[6];
- memset(ranges, 0, 6*sizeof(PaletteFxRange));
- decoder.getCRNG(ranges, 6);
+ byte pal[768];
- // TODO: encapsulate surface creation
- info.bg.w = decoder.getWidth();
- info.bg.h = decoder.getHeight();
- info.bg.pitch = info.bg.w;
- info.bg.bytesPerPixel = 1;
- info.bg.pixels = decoder.getBitmap();
+ Common::SeekableReadStream *s = openFile(name);
+ ILBMLoader loader(&info.bg, pal, ranges);
+ loader.load(s, true);
info.width = info.bg.w;
info.height = info.bg.h;
- byte *pal = decoder.getPalette();
- assert(pal);
byte *p = pal;
for (uint i = 0; i < 32; i++) {
byte r = *p >> 2;
@@ -960,7 +922,6 @@ void AmigaDisk_ns::loadBackground(BackgroundInfo& info, const char *name) {
p++;
info.palette.setEntry(i, r, g, b);
}
- delete []pal;
for (uint j = 0; j < 6; j++) {
info.setPaletteRange(j, ranges[j]);
@@ -979,9 +940,9 @@ void AmigaDisk_ns::loadMask(BackgroundInfo& info, const char *name) {
return; // no errors if missing mask files: not every location has one
}
- ILBMDecoder decoder(s, true);
- byte *pal = decoder.getPalette();
- assert(pal);
+ byte pal[768];
+ ILBMLoader loader(ILBMLoader::BODYMODE_MASKBUFFER, pal);
+ loader.load(s, true);
byte r, g, b;
for (uint i = 0; i < 4; i++) {
@@ -990,14 +951,8 @@ void AmigaDisk_ns::loadMask(BackgroundInfo& info, const char *name) {
b = pal[i*3+2];
info.layers[i] = (((r << 4) & 0xF00) | (g & 0xF0) | (b >> 4)) & 0xFF;
}
- delete []pal;
- info._mask = new MaskBuffer;
- info._mask->w = info.width;
- info._mask->h = info.height;
- info._mask->internalWidth = info.width >> 2;
- info._mask->size = info._mask->internalWidth * info._mask->h;
- info._mask->data = decoder.getBitmap(2, true);
+ info._mask = loader._maskBuffer;
}
void AmigaDisk_ns::loadPath(BackgroundInfo& info, const char *name) {
@@ -1010,15 +965,10 @@ void AmigaDisk_ns::loadPath(BackgroundInfo& info, const char *name) {
return; // no errors if missing path files: not every location has one
}
- ILBMDecoder decoder(s, true);
- info._path = new PathBuffer;
- info._path->create(info.width, info.height);
+ ILBMLoader loader(ILBMLoader::BODYMODE_PATHBUFFER);
+ loader.load(s, true);
+ info._path = loader._pathBuffer;
info._path->bigEndian = true;
-
- byte *bitmap = decoder.getBitmap(1, true);
- assert(bitmap);
- memcpy(info._path->data, bitmap, info._path->size);
- delete bitmap;
}
void AmigaDisk_ns::loadScenery(BackgroundInfo& info, const char* background, const char* mask, const char* path) {
diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp
index ec72b14c15..fc6cb28d9e 100644
--- a/engines/parallaction/gfxbase.cpp
+++ b/engines/parallaction/gfxbase.cpp
@@ -162,9 +162,7 @@ void BackgroundInfo::loadGfxObjMask(const char *name, GfxObj *obj) {
Common::Rect rect;
obj->getRect(0, rect);
- MaskBuffer *buf = new MaskBuffer;
- buf->create(rect.width(), rect.height());
- _vm->_disk->loadMask(name, *buf);
+ MaskBuffer *buf = _vm->_disk->loadMask(name, rect.width(), rect.height());
obj->_maskId = addMaskPatch(buf);
obj->_hasMask = true;
@@ -174,9 +172,7 @@ void BackgroundInfo::loadGfxObjPath(const char *name, GfxObj *obj) {
Common::Rect rect;
obj->getRect(0, rect);
- PathBuffer *buf = new PathBuffer;
- buf->create(rect.width(), rect.height());
- _vm->_disk->loadPath(name, *buf);
+ PathBuffer *buf = _vm->_disk->loadPath(name, rect.width(), rect.height());
obj->_pathId = addPathPatch(buf);
obj->_hasPath = true;
diff --git a/engines/parallaction/iff.cpp b/engines/parallaction/iff.cpp
index 43dcac3697..51e1e1d186 100644
--- a/engines/parallaction/iff.cpp
+++ b/engines/parallaction/iff.cpp
@@ -32,34 +32,17 @@
namespace Parallaction {
-void IFFParser::setInputStream(Common::SeekableReadStream *stream) {
- destroy();
-
+void IFFParser::setInputStream(Common::ReadStream *stream) {
assert(stream);
- _stream = stream;
- _startOffset = 0;
- _endOffset = _stream->size();
-
- _formType = 0;
- _formSize = (uint32)-1;
-
- if (_stream->size() < 12) {
- // this file is too small to be a valid IFF container
- return;
- }
+ _formChunk.setInputStream(stream);
+ _chunk.setInputStream(stream);
- if (_stream->readUint32BE() != ID_FORM) {
- // no FORM header was found
- return;
+ _formChunk.readHeader();
+ if (_formChunk.id != ID_FORM) {
+ error("IFFParser input is not a FORM type IFF file");
}
-
- _formSize = _stream->readUint32BE();
- _formType = _stream->readUint32BE();
-}
-
-void IFFParser::destroy() {
- _stream = 0;
- _startOffset = _endOffset = 0;
+ _formSize = _formChunk.size;
+ _formType = _formChunk.readUint32BE();
}
uint32 IFFParser::getFORMSize() const {
@@ -70,171 +53,99 @@ Common::IFF_ID IFFParser::getFORMType() const {
return _formType;
}
-uint32 IFFParser::moveToIFFBlock(Common::IFF_ID chunkName) {
- uint32 size = (uint32)-1;
-
- _stream->seek(_startOffset + 0x0C);
-
- while ((uint)_stream->pos() < _endOffset) {
- uint32 chunk = _stream->readUint32BE();
- uint32 size_temp = _stream->readUint32BE();
+void IFFParser::parse(IFFCallback &callback) {
+ bool stop;
+ do {
+ _chunk.feed();
+ _formChunk.incBytesRead(_chunk.size);
- if (chunk != chunkName) {
- _stream->seek((size_temp + 1) & (~1), SEEK_CUR);
- assert((uint)_stream->pos() <= _endOffset);
- } else {
- size = size_temp;
+ if (_formChunk.hasReadAll()) {
break;
}
- }
-
- return size;
-}
-
-uint32 IFFParser::getIFFBlockSize(Common::IFF_ID chunkName) {
- uint32 size = moveToIFFBlock(chunkName);
- return size;
-}
-
-bool IFFParser::loadIFFBlock(Common::IFF_ID chunkName, void *loadTo, uint32 ptrSize) {
- uint32 chunkSize = moveToIFFBlock(chunkName);
-
- if (chunkSize == (uint32)-1) {
- return false;
- }
-
- uint32 loadSize = 0;
- loadSize = MIN(ptrSize, chunkSize);
- _stream->read(loadTo, loadSize);
- return true;
-}
-
-Common::SeekableReadStream *IFFParser::getIFFBlockStream(Common::IFF_ID chunkName) {
- uint32 chunkSize = moveToIFFBlock(chunkName);
-
- if (chunkSize == (uint32)-1) {
- return 0;
- }
-
- uint32 pos = _stream->pos();
- return new Common::SeekableSubReadStream(_stream, pos, pos + chunkSize, false);
-}
+ _formChunk.incBytesRead(8);
+ _chunk.readHeader();
-// ILBM decoder implementation
+ // invoke the callback
+ Common::SubReadStream stream(&_chunk, _chunk.size);
+ IFFChunk chunk(_chunk.id, _chunk.size, &stream);
+ stop = callback(chunk);
-ILBMDecoder::ILBMDecoder(Common::SeekableReadStream *in, bool disposeStream) : _in(in), _disposeStream(disposeStream), _hasHeader(false), _bodySize((uint32)-1), _paletteSize((uint32)-1) {
- assert(in);
- _parser.setInputStream(in);
-
- if (_parser.getFORMType() != ID_ILBM) {
- return;
- }
-
- _hasHeader = _parser.loadIFFBlock(ID_BMHD, &_header, sizeof(_header));
- if (!_hasHeader) {
- return;
- }
-
- _header.width = TO_BE_16(_header.width);
- _header.height = TO_BE_16(_header.height);
-
- _paletteSize = _parser.getIFFBlockSize(ID_CMAP);
- _bodySize = _parser.getIFFBlockSize(ID_BODY);
-}
+ // eats up all the remaining data in the chunk
+ while (!stream.eos()) {
+ printf("attemping to eat data in chunk\n");
+ stream.readByte();
+ }
-ILBMDecoder::~ILBMDecoder() {
- if (_disposeStream) {
- delete _in;
- }
+ } while (!stop);
}
-uint32 ILBMDecoder::getWidth() {
- assert(_hasHeader);
- return _header.width;
-}
-uint32 ILBMDecoder::getHeight() {
- assert(_hasHeader);
- return _header.height;
-}
-uint32 ILBMDecoder::getNumColors() {
- assert(_hasHeader);
- return (1 << _header.depth);
-}
-
-byte *ILBMDecoder::getPalette() {
- assert(_paletteSize != (uint32)-1);
- byte *palette = new byte[_paletteSize];
- assert(palette);
- _parser.loadIFFBlock(ID_CMAP, palette, _paletteSize);
- return palette;
+void ILBMDecoder::loadHeader(Common::ReadStream *stream) {
+ assert(stream);
+ stream->read(&_header, sizeof(_header));
+ _header.width = FROM_BE_16(_header.width);
+ _header.height = FROM_BE_16(_header.height);
+ _header.x = FROM_BE_16(_header.x);
+ _header.y = FROM_BE_16(_header.y);
+ _header.transparentColor = FROM_BE_16(_header.transparentColor);
+ _header.pageWidth = FROM_BE_16(_header.pageWidth);
+ _header.pageHeight = FROM_BE_16(_header.pageHeight);
}
-byte *ILBMDecoder::getBitmap(uint32 numPlanes, bool packPlanes) {
- assert(_bodySize != (uint32)-1);
+void ILBMDecoder::loadBitmap(uint32 mode, byte *buffer, Common::ReadStream *stream) {
+ assert(stream);
+ uint32 numPlanes = MIN(mode & ILBM_UNPACK_PLANES, (uint32)_header.depth);
assert(numPlanes == 1 || numPlanes == 2 || numPlanes == 3 || numPlanes == 4 || numPlanes == 5 || numPlanes == 8);
- numPlanes = MIN(numPlanes, (uint32)_header.depth);
- if (numPlanes > 4) {
- packPlanes = false;
+ bool packPixels = (mode & ILBM_PACK_PLANES) != 0;
+ if (numPlanes != 1 && numPlanes != 2 && numPlanes != 4) {
+ packPixels = false;
}
- uint32 bitmapSize = _header.width * _header.height;
- uint32 bitmapWidth = _header.width;
- if (packPlanes) {
- bitmapSize /= (8 / numPlanes);
- bitmapWidth /= (8 / numPlanes);
+ uint32 outPitch = _header.width;
+ if (packPixels) {
+ outPitch /= (8 / numPlanes);
}
-
- Common::SeekableReadStream *bodyStream = _parser.getIFFBlockStream(ID_BODY);
- assert(bodyStream);
-
- byte *bitmap = (byte*)calloc(bitmapSize, 1);
- assert(bitmap);
+ byte *out = buffer;
switch (_header.pack) {
case 1: { // PackBits compressed bitmap
- Graphics::PackBitsReadStream stream(*bodyStream);
-
- byte *out = bitmap;
+ Graphics::PackBitsReadStream packStream(*stream);
// setup a buffer to hold enough data to build a line in the output
- uint32 scanWidth = ((_header.width + 15)/16) << 1;
- byte *scanBuffer = (byte*)malloc(scanWidth * _header.depth);
+ uint32 scanlineWidth = ((_header.width + 15)/16) << 1;
+ byte *scanline = new byte[scanlineWidth * _header.depth];
for (uint i = 0; i < _header.height; ++i) {
- byte *s = scanBuffer;
+ byte *s = scanline;
for (uint32 j = 0; j < _header.depth; ++j) {
- stream.read(s, scanWidth);
- s += scanWidth;
+ packStream.read(s, scanlineWidth);
+ s += scanlineWidth;
}
- planarToChunky(out, bitmapWidth, scanBuffer, scanWidth, numPlanes, packPlanes);
- out += bitmapWidth;
+ planarToChunky(out, outPitch, scanline, scanlineWidth, numPlanes, packPixels);
+ out += outPitch;
}
- free(scanBuffer);
+ delete []scanline;
break;
}
+
default:
+ // implement other compression types here!
error("only RLE compressed ILBM files are supported");
break;
}
-
- delete bodyStream;
-
- return bitmap;
}
-
-void ILBMDecoder::planarToChunky(byte *out, uint32 width, byte *in, uint32 planeWidth, uint32 nPlanes, bool packPlanes) {
+void ILBMDecoder::planarToChunky(byte *out, uint32 outPitch, byte *in, uint32 inWidth, uint32 nPlanes, bool packPlanes) {
byte pix, ofs, bit;
byte *s;
- uint32 pixels = width;
+ uint32 pixels = outPitch;
if (packPlanes) {
pixels *= (8 / nPlanes);
}
@@ -251,7 +162,7 @@ void ILBMDecoder::planarToChunky(byte *out, uint32 width, byte *in, uint32 plane
if (s[ofs] & bit) {
pix |= (1 << plane);
}
- s += planeWidth;
+ s += inWidth;
}
diff --git a/engines/parallaction/iff.h b/engines/parallaction/iff.h
index 43f78bf001..98e36e1b00 100644
--- a/engines/parallaction/iff.h
+++ b/engines/parallaction/iff.h
@@ -27,39 +27,126 @@
#define PARALLACTION_IFF_H
#include "common/stream.h"
+#include "common/func.h"
#include "common/iff_container.h" // for IFF chunk names
#include "graphics/iff.h" // for BMHD
-// this IFF parser code is courtesy of the Kyra engine team ;)
namespace Parallaction {
+/**
+ * Represents a IFF chunk available to client code.
+ *
+ * Client code must *not* deallocate _stream when done.
+ */
+struct IFFChunk {
+ Common::IFF_ID _type;
+ uint32 _size;
+ Common::ReadStream *_stream;
+
+ IFFChunk(Common::IFF_ID type, uint32 size, Common::ReadStream *stream) : _type(type), _size(size), _stream(stream) {
+ assert(_stream);
+ }
+};
+
+/**
+ * Parser for IFF containers.
+ */
class IFFParser {
+
+ /**
+ * This private class implements IFF chunk navigation.
+ */
+ class IFFChunkNav : public Common::ReadStream {
+ protected:
+ Common::ReadStream *_input;
+ uint32 _bytesRead;
+ public:
+ Common::IFF_ID id;
+ uint32 size;
+
+ IFFChunkNav() : _input(0) {
+ }
+ void setInputStream(Common::ReadStream *input) {
+ _input = input;
+ size = _bytesRead = 0;
+ }
+ void incBytesRead(uint32 inc) {
+ _bytesRead += inc;
+ if (_bytesRead > size) {
+ error("Chunk overread");
+ }
+ }
+ void readHeader() {
+ id = _input->readUint32BE();
+ size = _input->readUint32BE();
+ _bytesRead = 0;
+ }
+ bool hasReadAll() const {
+ return (size - _bytesRead) == 0;
+ }
+ void feed() {
+ if (size % 2) {
+ size++;
+ }
+ while (!hasReadAll()) {
+ readByte();
+ }
+ }
+ // Common::ReadStream implementation
+ bool eos() const { return _input->eos(); }
+ bool err() const { return _input->err(); }
+ void clearErr() { _input->clearErr(); }
+
+ uint32 read(void *dataPtr, uint32 dataSize) {
+ incBytesRead(dataSize);
+ return _input->read(dataPtr, dataSize);
+ }
+ };
+
+ IFFChunkNav _formChunk; //!< The root chunk of the file.
+ IFFChunkNav _chunk; //!< The current chunk.
+
+ Common::ReadStream *_stream;
+ bool _disposeStream;
+
+ void setInputStream(Common::ReadStream *stream);
+
public:
- IFFParser() : _stream(0), _startOffset(0), _endOffset(0) {}
- IFFParser(Common::SeekableReadStream *stream) : _stream(0), _startOffset(0), _endOffset(0) {
+ IFFParser(Common::ReadStream *stream, bool disposeStream = false) : _stream(stream), _disposeStream(stream) {
setInputStream(stream);
}
- ~IFFParser() { destroy(); }
-
- void setInputStream(Common::SeekableReadStream *stream);
+ ~IFFParser() {
+ if (_disposeStream) {
+ delete _stream;
+ }
+ _stream = 0;
+ }
- operator bool() const { return (_startOffset != _endOffset) && _stream; }
+ /**
+ * Returns the IFF FORM type.
+ * @return the IFF FORM type of the stream, or 0 if FORM header is not found.
+ */
+ Common::IFF_ID getFORMType() const;
+ /**
+ * Returns the size of the data.
+ * @return the size of the data in file, or -1 if FORM header is not found.
+ */
uint32 getFORMSize() const;
- Common::IFF_ID getFORMType() const;
- uint32 getIFFBlockSize(Common::IFF_ID chunk);
- bool loadIFFBlock(Common::IFF_ID chunk, void *loadTo, uint32 ptrSize);
- Common::SeekableReadStream *getIFFBlockStream(Common::IFF_ID chunkName);
-private:
- void destroy();
- uint32 moveToIFFBlock(Common::IFF_ID chunkName);
+ /**
+ * Callback type for the parser.
+ */
+ typedef Common::Functor1< IFFChunk&, bool > IFFCallback;
- Common::SeekableReadStream *_stream;
- uint32 _startOffset;
- uint32 _endOffset;
+ /**
+ * Parse the IFF container, invoking the callback on each chunk encountered.
+ * The callback can interrupt the parsing by returning 'true'.
+ */
+ void parse(IFFCallback &callback);
+private:
uint32 _formSize;
Common::IFF_ID _formType;
};
@@ -67,35 +154,49 @@ private:
-class ILBMDecoder {
- Common::SeekableReadStream *_in;
- bool _disposeStream;
-
+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);
+
+ /**
+ * 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);
-
-protected:
- IFFParser _parser;
- Graphics::BMHD _header;
- bool _hasHeader;
- uint32 _bodySize;
- uint32 _paletteSize;
-
-
-public:
- ILBMDecoder(Common::SeekableReadStream *input, bool disposeStream = false);
-
- virtual ~ILBMDecoder();
-
- uint32 getWidth();
- uint32 getHeight();
- uint32 getNumColors();
- byte *getPalette();
-
- byte *getBitmap(uint32 numPlanes, bool packPlanes);
- byte *getBitmap() {
- assert(_hasHeader);
- return getBitmap(_header.depth, false);
- }
};
diff --git a/engines/parallaction/module.mk b/engines/parallaction/module.mk
index 16b79c3d5a..bd45598d17 100644
--- a/engines/parallaction/module.mk
+++ b/engines/parallaction/module.mk
@@ -7,6 +7,7 @@ MODULE_OBJS := \
debug.o \
detection.o \
dialogue.o \
+ disk.o \
disk_br.o \
disk_ns.o \
exec.o \