diff options
Diffstat (limited to 'graphics/decoders')
| -rw-r--r-- | graphics/decoders/iff.cpp | 241 | ||||
| -rw-r--r-- | graphics/decoders/iff.h | 119 | 
2 files changed, 360 insertions, 0 deletions
| diff --git a/graphics/decoders/iff.cpp b/graphics/decoders/iff.cpp new file mode 100644 index 0000000000..50c7b4f7de --- /dev/null +++ b/graphics/decoders/iff.cpp @@ -0,0 +1,241 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "common/iff_container.h" +#include "common/stream.h" +#include "common/util.h" + +#include "graphics/decoders/iff.h" + +namespace Graphics { + +IFFDecoder::IFFDecoder() { +	_surface = 0; +	_palette = 0; + +	destroy(); +} + +IFFDecoder::~IFFDecoder() { +	destroy(); +} + +void IFFDecoder::destroy() { +	if (_surface) { +		_surface->free(); +		delete _surface; +		_surface = 0; +	} + +	if (_palette) { +		delete[] _palette; +		_palette = 0; +	} + +	memset(&_header, 0, sizeof(Header)); +	_paletteRanges.clear(); +	_type = TYPE_UNKNOWN; +	_paletteColorCount = 0; +	_numRelevantPlanes = 8; +	_pixelPacking = false; +} + +bool IFFDecoder::loadStream(Common::SeekableReadStream &stream) { +	destroy(); + +	const uint32 form = stream.readUint32BE(); + +	if (form != ID_FORM) { +		warning("Failed reading IFF-file"); +		return false; +	} + +	stream.skip(4); + +	const uint32 type = stream.readUint32BE(); + +	switch (type) { +		case ID_ILBM: +			_type = TYPE_ILBM; +			break; +		case ID_PBM: +			_type = TYPE_PBM; +			break; +	} + +	if (type == TYPE_UNKNOWN) { +		warning("Failed reading IFF-file"); +		return false; +	} + +	while (1) { +		const uint32 chunkType = stream.readUint32BE(); +		const uint32 chunkSize = stream.readUint32BE(); + +		if (stream.eos()) +			break; + +		switch (chunkType) { +		case ID_BMHD: +			loadHeader(stream); +			break; +		case ID_CMAP: +			loadPalette(stream, chunkSize); +			break; +		case ID_CRNG: +			loadPaletteRange(stream, chunkSize); +			break; +		case ID_BODY: +			loadBitmap(stream); +			break; +		default: +			stream.skip(chunkSize); +		} +	} + +	return true; +} + +void IFFDecoder::loadHeader(Common::SeekableReadStream &stream) { +	_header.width = stream.readUint16BE(); +	_header.height = stream.readUint16BE(); +	_header.x = stream.readUint16BE(); +	_header.y = stream.readUint16BE(); +	_header.numPlanes = stream.readByte(); +	_header.masking = stream.readByte(); +	_header.compression = stream.readByte(); +	_header.flags = stream.readByte(); +	_header.transparentColor = stream.readUint16BE(); +	_header.xAspect = stream.readByte(); +	_header.yAspect = stream.readByte(); +	_header.pageWidth = stream.readUint16BE(); +	_header.pageHeight = stream.readUint16BE(); + +	assert(_header.width >= 1); +	assert(_header.height >= 1); +	assert(_header.numPlanes >= 1 && _header.numPlanes <= 8 && _header.numPlanes != 7); +} + +void IFFDecoder::loadPalette(Common::SeekableReadStream &stream, const uint32 size) { +	_palette = new byte[size]; +	stream.read(_palette, size); +	_paletteColorCount = size / 3; +} + +void IFFDecoder::loadPaletteRange(Common::SeekableReadStream &stream, const uint32 size) { +	PaletteRange range; + +	range.timer = stream.readSint16BE(); +	range.step = stream.readSint16BE(); +	range.flags = stream.readSint16BE(); +	range.first = stream.readByte(); +	range.last = stream.readByte(); + +	_paletteRanges.push_back(range); +} + +void IFFDecoder::loadBitmap(Common::SeekableReadStream &stream) { +	_numRelevantPlanes = MIN(_numRelevantPlanes, _header.numPlanes); + +	if (_numRelevantPlanes != 1 && _numRelevantPlanes != 2 && _numRelevantPlanes != 4) +		_pixelPacking = false; + +	uint16 outPitch = _header.width; + +	if (_pixelPacking) +		outPitch /= (8 / _numRelevantPlanes); + +	// FIXME: CLUT8 is not a proper format for packed bitmaps but there is no way to tell it to use 1, 2 or 4 bits per pixel +	_surface = new Graphics::Surface(); +	_surface->create(outPitch, _header.height, Graphics::PixelFormat::createFormatCLUT8()); + +	if (_type == TYPE_ILBM) { +		uint32 scanlinePitch = ((_header.width + 15) >> 4) << 1; +		byte *scanlines = new byte[scanlinePitch * _header.numPlanes]; +		byte *data = (byte *)_surface->pixels; + +		for (uint16 i = 0; i < _header.height; ++i) { +			byte *scanline = scanlines; + +			for (uint16 j = 0; j < _header.numPlanes; ++j) { +				uint16 outSize = scanlinePitch; + +				if (_header.compression) { +					Common::PackBitsReadStream packStream(stream); +					packStream.read(scanline, outSize); +				} else { +					stream.read(scanline, outSize); +				} + +				scanline += outSize; +			} + +			packPixels(scanlines, data, scanlinePitch, outPitch); +			data += outPitch; +		} + +		delete[] scanlines; +	} else if (_type == TYPE_PBM) { +		byte *data = (byte *)_surface->pixels; +		uint32 outSize = _header.width * _header.height; + +		if (_header.compression) { +			Common::PackBitsReadStream packStream(stream); +			packStream.read(data, outSize); +		} else { +			stream.read(data, outSize); +		} +	} +} + +void IFFDecoder::packPixels(byte *scanlines, byte *data, const uint16 scanlinePitch, const uint16 outPitch) { +	uint32 numPixels = _header.width; + +	if (_pixelPacking) +		numPixels = outPitch * (8 / _numRelevantPlanes); + +	for (uint32 x = 0; x < numPixels; ++x) { +		byte *scanline = scanlines; +		byte pixel = 0; +		byte offset = x >> 3; +		byte bit = 0x80 >> (x & 7); + +		// first build a pixel by scanning all the usable planes in the input +		for (uint32 plane = 0; plane < _numRelevantPlanes; ++plane) { +			if (scanline[offset] & bit) +				pixel |= (1 << plane); + +			scanline += scanlinePitch; +		} + +		// then output the pixel according to the requested packing +		if (!_pixelPacking) +			data[x] = pixel; +		else if (_numRelevantPlanes == 1) +			data[x / 8] |= (pixel << (x & 7)); +		else if (_numRelevantPlanes == 2) +			data[x / 4] |= (pixel << ((x & 3) << 1)); +		else if (_numRelevantPlanes == 4) +			data[x / 2] |= (pixel << ((x & 1) << 2)); +	} +} + +} // End of namespace Graphics diff --git a/graphics/decoders/iff.h b/graphics/decoders/iff.h new file mode 100644 index 0000000000..beac62e519 --- /dev/null +++ b/graphics/decoders/iff.h @@ -0,0 +1,119 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** + * @file + * Image decoder used in engines: + *  - gob + *  - parallaction + *  - queen + *  - saga + */ + +#ifndef GRAPHICS_DECODERS_IFF_H +#define GRAPHICS_DECODERS_IFF_H + +#include "common/array.h" +#include "common/endian.h" + +#include "graphics/surface.h" +#include "graphics/decoders/image_decoder.h" + +namespace Common { +class SeekableReadStream; +} + +namespace Graphics { + +struct Surface; + +class IFFDecoder : public ImageDecoder { +public: +	struct Header { +		uint16 width, height; +		uint16 x, y; +		byte numPlanes; +		byte masking; +		byte compression; +		byte flags; +		uint16 transparentColor; +		byte xAspect, yAspect; +		uint16 pageWidth, pageHeight; +	}; + +	struct PaletteRange { +		int16  timer, step, flags; +		byte first, last; +	}; + +	enum Type { +		TYPE_UNKNOWN = 0, +		TYPE_ILBM, +		TYPE_PBM +	}; + +	IFFDecoder(); +	virtual ~IFFDecoder(); + +	// ImageDecoder API +	void destroy(); +	bool loadStream(Common::SeekableReadStream &stream); +	const Header *getHeader() const { return &_header; } +	const Surface *getSurface() const { return _surface; } +	const byte *getPalette() const { return _palette; } +	const Common::Array<PaletteRange> &getPaletteRanges() const { return _paletteRanges; } +	uint16 getPaletteColorCount() const { return _paletteColorCount; } + +	/** +	* The number of planes to decode, also determines the pixel packing if _packPixels is true. +	* 8 == decode all planes, map 1 pixel in 1 byte. (default, no packing even if _packPixels is true) +	*/ +	void setNumRelevantPlanes(const uint8 numRelevantPlanes) { _numRelevantPlanes = numRelevantPlanes; } + +	/** +	* Enables pixel packing, the amount of packing is determined by _numRelevantPlanes +	* 1 == decode first plane, pack 8 pixels in 1 byte. This makes _surface->w 1/8th of _header.width +	* 2 == decode first 2 planes, pack 4 pixels in 1 byte. This makes _surface->w 1/4th of _header.width +	* 4 == decode first 4 planes, pack 2 pixels in 1 byte. This makes _surface->w half of _header.width +	* Packed bitmaps won't have a proper surface format since there is no way to tell it to use 1, 2 or 4 bits per pixel +	*/ +	void setPixelPacking(const bool pixelPacking) { _pixelPacking = pixelPacking; } +private: + +	Header _header; +	Surface *_surface; +	byte *_palette; +	Common::Array<PaletteRange> _paletteRanges; +	Type _type; +	uint16 _paletteColorCount; +	uint8 _numRelevantPlanes; +	bool _pixelPacking; + +	void loadHeader(Common::SeekableReadStream &stream); +	void loadPalette(Common::SeekableReadStream &stream, const uint32 size); +	void loadPaletteRange(Common::SeekableReadStream &stream, const uint32 size); +	void loadBitmap(Common::SeekableReadStream &stream); +	void packPixels(byte *scanlines, byte *data, const uint16 scanlinePitch, const uint16 outPitch); +}; + +} // End of namespace Graphics + +#endif // GRAPHICS_DECODERS_IFF_H | 
