diff options
| -rw-r--r-- | engines/parallaction/disk.cpp | 121 | ||||
| -rw-r--r-- | engines/parallaction/disk.h | 40 | ||||
| -rw-r--r-- | engines/parallaction/disk_br.cpp | 113 | ||||
| -rw-r--r-- | engines/parallaction/disk_ns.cpp | 72 | ||||
| -rw-r--r-- | engines/parallaction/gfxbase.cpp | 8 | ||||
| -rw-r--r-- | engines/parallaction/iff.cpp | 209 | ||||
| -rw-r--r-- | engines/parallaction/iff.h | 191 | ||||
| -rw-r--r-- | engines/parallaction/module.mk | 1 | 
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 \ | 
