[Scummvm-cvs-logs] SF.net SVN: scummvm:[41458] scummvm/trunk/engines/parallaction

peres001 at users.sourceforge.net peres001 at users.sourceforge.net
Fri Jun 12 07:03:18 CEST 2009


Revision: 41458
          http://scummvm.svn.sourceforge.net/scummvm/?rev=41458&view=rev
Author:   peres001
Date:     2009-06-12 05:03:18 +0000 (Fri, 12 Jun 2009)

Log Message:
-----------
* Final version of the IFF parsing code.
* Refactored ILBMDecoder usage from disk code.

Modified Paths:
--------------
    scummvm/trunk/engines/parallaction/disk.h
    scummvm/trunk/engines/parallaction/disk_br.cpp
    scummvm/trunk/engines/parallaction/disk_ns.cpp
    scummvm/trunk/engines/parallaction/gfxbase.cpp
    scummvm/trunk/engines/parallaction/iff.cpp
    scummvm/trunk/engines/parallaction/iff.h
    scummvm/trunk/engines/parallaction/module.mk

Added Paths:
-----------
    scummvm/trunk/engines/parallaction/disk.cpp

Added: scummvm/trunk/engines/parallaction/disk.cpp
===================================================================
--- scummvm/trunk/engines/parallaction/disk.cpp	                        (rev 0)
+++ scummvm/trunk/engines/parallaction/disk.cpp	2009-06-12 05:03:18 UTC (rev 41458)
@@ -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;
+}
+
+
+
+}


Property changes on: scummvm/trunk/engines/parallaction/disk.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Modified: scummvm/trunk/engines/parallaction/disk.h
===================================================================
--- scummvm/trunk/engines/parallaction/disk.h	2009-06-12 00:19:43 UTC (rev 41457)
+++ scummvm/trunk/engines/parallaction/disk.h	2009-06-12 05:03:18 UTC (rev 41458)
@@ -33,6 +33,7 @@
 #include "common/file.h"
 
 #include "graphics/surface.h"
+#include "parallaction/iff.h"
 
 
 
@@ -77,11 +78,40 @@
 	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);
+};
+
+
 class Disk_ns : public Disk {
 
 protected:
@@ -235,8 +265,8 @@
 	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 @@
 	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

Modified: scummvm/trunk/engines/parallaction/disk_br.cpp
===================================================================
--- scummvm/trunk/engines/parallaction/disk_br.cpp	2009-06-12 00:19:43 UTC (rev 41457)
+++ scummvm/trunk/engines/parallaction/disk_br.cpp	2009-06-12 05:03:18 UTC (rev 41458)
@@ -331,32 +331,40 @@
 	}
 }
 
-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 @@
 	}
 
 	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::loadBackground(BackgroundInfo& info, const char *filename) {
 	byte r,g,b;
-	byte *pal, *p;
+	byte *p;
 	Common::SeekableReadStream *stream;
 	uint i;
 
@@ -488,20 +490,14 @@
 	}
 
 	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 @@
 	// 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 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 @@
 		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,21 +581,14 @@
 	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;
+	ILBMLoader loader(ILBMLoader::BODYMODE_SURFACE);
+	loader.load(stream, true);
+
+	Graphics::Surface* surf = loader._surf;
 	assert(surf);
 
-	// 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);
-
 	// 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
 	// will have zero as a color.
@@ -741,15 +719,16 @@
 	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 @@
 			dst += 51;
 		}
 	}
-	free(srcPtr);
+	delete loader._surf;
 
 	return new GfxObj(0, new Cnv(max, 51, 51, data, true));
 }

Modified: scummvm/trunk/engines/parallaction/disk_ns.cpp
===================================================================
--- scummvm/trunk/engines/parallaction/disk_ns.cpp	2009-06-12 00:19:43 UTC (rev 41457)
+++ scummvm/trunk/engines/parallaction/disk_ns.cpp	2009-06-12 05:03:18 UTC (rev 41458)
@@ -900,56 +900,18 @@
 	}
 }
 
-// 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) {
+	PaletteFxRange ranges[6];
+	byte pal[768];
 
 	Common::SeekableReadStream *s = openFile(name);
-	BackgroundDecoder decoder(s, true);
+	ILBMLoader loader(&info.bg, pal, ranges);
+	loader.load(s, true);
 
-	PaletteFxRange ranges[6];
-	memset(ranges, 0, 6*sizeof(PaletteFxRange));
-	decoder.getCRNG(ranges, 6);
-
-	// 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();
-
 	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 @@
 		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 @@
 		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 @@
 		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 @@
 		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) {

Modified: scummvm/trunk/engines/parallaction/gfxbase.cpp
===================================================================
--- scummvm/trunk/engines/parallaction/gfxbase.cpp	2009-06-12 00:19:43 UTC (rev 41457)
+++ scummvm/trunk/engines/parallaction/gfxbase.cpp	2009-06-12 05:03:18 UTC (rev 41458)
@@ -162,9 +162,7 @@
 	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 @@
 	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;

Modified: scummvm/trunk/engines/parallaction/iff.cpp
===================================================================
--- scummvm/trunk/engines/parallaction/iff.cpp	2009-06-12 00:19:43 UTC (rev 41457)
+++ scummvm/trunk/engines/parallaction/iff.cpp	2009-06-12 05:03:18 UTC (rev 41458)
@@ -32,36 +32,19 @@
 namespace Parallaction {
 
 
-void IFFParser::setInputStream(Common::SeekableReadStream *stream) {
-	destroy();
-
+void IFFParser::setInputStream(Common::ReadStream *stream) {
 	assert(stream);
-	_stream = stream;
-	_startOffset = 0;
-	_endOffset = _stream->size();
+	_formChunk.setInputStream(stream);
+	_chunk.setInputStream(stream);
 
-	_formType = 0;
-	_formSize = (uint32)-1;
-
-	if (_stream->size() < 12) {
-		// this file is too small to be a valid IFF container
-		return;
+	_formChunk.readHeader();
+	if (_formChunk.id != ID_FORM) {
+		error("IFFParser input is not a FORM type IFF file");
 	}
-
-	if (_stream->readUint32BE() != ID_FORM) {
-		// no FORM header was found
-		return;
-	}
-
-	_formSize = _stream->readUint32BE();
-	_formType = _stream->readUint32BE();
+	_formSize = _formChunk.size;
+	_formType = _formChunk.readUint32BE();
 }
 
-void IFFParser::destroy() {
-	_stream = 0;
-	_startOffset = _endOffset = 0;
-}
-
 uint32 IFFParser::getFORMSize() const {
 	return _formSize;
 }
@@ -70,171 +53,99 @@
 	return _formType;
 }
 
-uint32 IFFParser::moveToIFFBlock(Common::IFF_ID chunkName) {
-	uint32 size = (uint32)-1;
+void IFFParser::parse(IFFCallback &callback) {
+	bool stop;
+	do {
+		_chunk.feed();
+		_formChunk.incBytesRead(_chunk.size);
 
-	_stream->seek(_startOffset + 0x0C);
-
-	while ((uint)_stream->pos() < _endOffset) {
-		uint32 chunk = _stream->readUint32BE();
-		uint32 size_temp = _stream->readUint32BE();
-
-		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;
-}
+		_formChunk.incBytesRead(8);
+		_chunk.readHeader();
 
-uint32 IFFParser::getIFFBlockSize(Common::IFF_ID chunkName) {
-	uint32 size = moveToIFFBlock(chunkName);
-	return size;
-}
+		// invoke the callback
+		Common::SubReadStream stream(&_chunk, _chunk.size);
+		IFFChunk chunk(_chunk.id, _chunk.size, &stream);
+		stop = callback(chunk);
 
-bool IFFParser::loadIFFBlock(Common::IFF_ID chunkName, void *loadTo, uint32 ptrSize) {
-	uint32 chunkSize = moveToIFFBlock(chunkName);
+		// eats up all the remaining data in the chunk
+		while (!stream.eos()) {
+			printf("attemping to eat data in chunk\n");
+			stream.readByte();
+		}
 
-	if (chunkSize == (uint32)-1) {
-		return false;
-	}
 
-	uint32 loadSize = 0;
-	loadSize = MIN(ptrSize, chunkSize);
-	_stream->read(loadTo, loadSize);
-	return true;
+	} while (!stop);
 }
 
-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);
+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);
 }
 
-
-// ILBM decoder implementation
-
-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);
-}
-
-
-ILBMDecoder::~ILBMDecoder() {
-	if (_disposeStream) {
-		delete _in;
-	}
-}
-
-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;
-}
-
-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);
 	}
+	byte *out = buffer;
 
-	Common::SeekableReadStream *bodyStream = _parser.getIFFBlockStream(ID_BODY);
-	assert(bodyStream);
-
-	byte *bitmap = (byte*)calloc(bitmapSize, 1);
-	assert(bitmap);
-
 	switch (_header.pack) {
 	case 1: {	// PackBits compressed bitmap
-		Graphics::PackBitsReadStream stream(*bodyStream);
+		Graphics::PackBitsReadStream packStream(*stream);
 
-		byte *out = bitmap;
-
 		// 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 @@
 			if (s[ofs] & bit) {
 				pix |= (1 << plane);
 			}
-			s += planeWidth;
+			s += inWidth;
 		}
 
 

Modified: scummvm/trunk/engines/parallaction/iff.h
===================================================================
--- scummvm/trunk/engines/parallaction/iff.h	2009-06-12 00:19:43 UTC (rev 41457)
+++ scummvm/trunk/engines/parallaction/iff.h	2009-06-12 05:03:18 UTC (rev 41458)
@@ -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(); }
+	~IFFParser() {
+		if (_disposeStream) {
+			delete _stream;
+		}
+		_stream = 0;
+	}
 
-	void setInputStream(Common::SeekableReadStream *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;
 
-	operator bool() const { return (_startOffset != _endOffset) && _stream; }
-
+	/**
+	 * 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 @@
 
 
 
-class ILBMDecoder {
-	Common::SeekableReadStream *_in;
-	bool _disposeStream;
+struct ILBMDecoder {
+	/**
+	 * ILBM header data, necessary for loadBitmap()
+	 */
+	Graphics::BMHD	_header;
 
-	void planarToChunky(byte *out, uint32 width, byte *in, uint32 planeWidth, uint32 nPlanes, bool packPlanes);
+	/**
+	 * 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.
 
-protected:
-	IFFParser 	_parser;
-	Graphics::BMHD 	_header;
-	bool	_hasHeader;
-	uint32	_bodySize;
-	uint32	_paletteSize;
+		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);
 
-public:
-	ILBMDecoder(Common::SeekableReadStream *input, bool disposeStream = false);
+	/**
+	 * 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);
 
-	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);
-	}
+	/**
+	 * 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);
 };
 
 

Modified: scummvm/trunk/engines/parallaction/module.mk
===================================================================
--- scummvm/trunk/engines/parallaction/module.mk	2009-06-12 00:19:43 UTC (rev 41457)
+++ scummvm/trunk/engines/parallaction/module.mk	2009-06-12 05:03:18 UTC (rev 41458)
@@ -7,6 +7,7 @@
 	debug.o \
 	detection.o \
 	dialogue.o \
+	disk.o \
 	disk_br.o \
 	disk_ns.o \
 	exec.o \


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list