aboutsummaryrefslogtreecommitdiff
path: root/graphics/iff.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'graphics/iff.cpp')
-rw-r--r--graphics/iff.cpp258
1 files changed, 119 insertions, 139 deletions
diff --git a/graphics/iff.cpp b/graphics/iff.cpp
index ea6447ac01..902f97499a 100644
--- a/graphics/iff.cpp
+++ b/graphics/iff.cpp
@@ -48,194 +48,179 @@ char *ID2string(Common::IFF_ID id) {
namespace Graphics {
-
-void fillBMHD(BMHD &bitmapHeader, Common::ReadStream &stream) {
-
- bitmapHeader.width = stream.readUint16BE();
- bitmapHeader.height = stream.readUint16BE();
- bitmapHeader.x = stream.readUint16BE();
- bitmapHeader.y = stream.readUint16BE();
- bitmapHeader.depth = stream.readByte();
- bitmapHeader.masking = stream.readByte();
- bitmapHeader.pack = stream.readByte();
- bitmapHeader.flags = stream.readByte();
- bitmapHeader.transparentColor = stream.readUint16BE();
- bitmapHeader.xAspect = stream.readByte();
- bitmapHeader.yAspect = stream.readByte();
- bitmapHeader.pageWidth = stream.readUint16BE();
- bitmapHeader.pageHeight = stream.readUint16BE();
-
+void BMHD::load(Common::ReadStream *stream) {
+ assert(stream);
+ stream->read(this, sizeof(BMHD));
+ width = FROM_BE_16(width);
+ height = FROM_BE_16(height);
+ x = FROM_BE_16(x);
+ y = FROM_BE_16(y);
+ transparentColor = FROM_BE_16(transparentColor);
+ pageWidth = FROM_BE_16(pageWidth);
+ pageHeight = FROM_BE_16(pageHeight);
}
-ILBMDecoder::ILBMDecoder(Common::ReadStream &input, Surface &surface, byte *&colors) : IFFParser(input), _surface(&surface), _colors(&colors) {
- if (_typeId != ID_ILBM)
- error("unsupported IFF subtype '%s'", Common::ID2string(_typeId));
+void ILBMDecoder::loadHeader(Common::ReadStream *stream) {
+ _header.load(stream);
}
-void ILBMDecoder::decode() {
-
- Common::IFFChunk *chunk;
- while ((chunk = nextChunk()) != 0) {
- switch (chunk->id) {
- case ID_BMHD:
- readBMHD(*chunk);
- break;
+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);
- case ID_CMAP:
- readCMAP(*chunk);
- break;
-
- case ID_BODY:
- readBODY(*chunk);
- break;
- }
+ bool packPixels = (mode & ILBM_PACK_PLANES) != 0;
+ if (numPlanes != 1 && numPlanes != 2 && numPlanes != 4) {
+ packPixels = false;
}
- return;
-}
+ uint32 outPitch = _header.width;
+ if (packPixels) {
+ outPitch /= (8 / numPlanes);
+ }
+ byte *out = buffer;
-void ILBMDecoder::readBMHD(Common::IFFChunk &chunk) {
+ switch (_header.pack) {
+ case 1: { // PackBits compressed bitmap
+ Graphics::PackBitsReadStream packStream(*stream);
- fillBMHD(_bitmapHeader, chunk);
+ // setup a buffer to hold enough data to build a line in the output
+ uint32 scanlineWidth = ((_header.width + 15)/16) << 1;
+ byte *scanline = new byte[scanlineWidth * _header.depth];
- _colorCount = 1 << _bitmapHeader.depth;
- *_colors = (byte*)malloc(sizeof(**_colors) * _colorCount * 3);
- _surface->create(_bitmapHeader.width, _bitmapHeader.height, 1);
+ for (uint i = 0; i < _header.height; ++i) {
+ byte *s = scanline;
+ for (uint32 j = 0; j < _header.depth; ++j) {
+ packStream.read(s, scanlineWidth);
+ s += scanlineWidth;
+ }
-}
+ planarToChunky(out, outPitch, scanline, scanlineWidth, numPlanes, packPixels);
+ out += outPitch;
+ }
-void ILBMDecoder::readCMAP(Common::IFFChunk &chunk) {
- if (*_colors == NULL) {
- error("wrong input chunk sequence");
+ delete []scanline;
+ break;
}
- for (uint32 i = 0; i < _colorCount; i++) {
- (*_colors)[i * 3 + 0] = chunk.readByte();
- (*_colors)[i * 3 + 1] = chunk.readByte();
- (*_colors)[i * 3 + 2] = chunk.readByte();
+
+ default:
+ // implement other compression types here!
+ error("only RLE compressed ILBM files are supported");
+ break;
}
}
-void ILBMDecoder::readBODY(Common::IFFChunk& chunk) {
+void ILBMDecoder::planarToChunky(byte *out, uint32 outPitch, byte *in, uint32 inWidth, uint32 nPlanes, bool packPlanes) {
+ byte pix, ofs, bit;
+ byte *s;
- switch (_bitmapHeader.pack) {
- case 0:
- error("unpacked ILBM files are not supported");
- break;
+ uint32 pixels = outPitch;
+ if (packPlanes) {
+ pixels *= (8 / nPlanes);
+ }
- case 1: {
- uint32 scanWidth = (_bitmapHeader.width + 7) >> 3;
- byte *scan = (byte*)malloc(scanWidth);
- byte *out = (byte*)_surface->pixels;
+ for (uint32 x = 0; x < pixels; ++x) {
- PackBitsReadStream stream(chunk);
+ pix = 0;
+ ofs = x >> 3;
+ bit = 0x80 >> (x & 7);
- for (uint32 i = 0; i < _bitmapHeader.height; i++) {
- for (uint32 j = 0; j < _bitmapHeader.depth; j++) {
- stream.read(scan, scanWidth);
- fillPlane(out, scan, scanWidth, j);
+ // first build a pixel by scanning all the usable planes in the input
+ s = in;
+ for (uint32 plane = 0; plane < nPlanes; ++plane) {
+ if (s[ofs] & bit) {
+ pix |= (1 << plane);
}
-
- out += _bitmapHeader.width;
+ s += inWidth;
}
- free(scan);
- break;
- }
-
- }
-}
-void ILBMDecoder::fillPlane(byte *out, byte* buf, uint32 width, uint32 plane) {
- byte src, idx, set;
- byte mask = 1 << plane;
-
- for (uint32 j = 0; j < _bitmapHeader.width; j++) {
- src = buf[j >> 3];
- idx = 7 - (j & 7);
- set = src & (1 << idx);
-
- if (set)
- out[j] |= mask;
+ // then output the pixel according to the requested packing
+ if (!packPlanes) {
+ out[x] = pix;
+ } else
+ if (nPlanes == 1) {
+ out[x/8] |= (pix << (x & 7));
+ } else
+ if (nPlanes == 2) {
+ out[x/4] |= (pix << ((x & 3) << 1));
+ } else
+ if (nPlanes == 4) {
+ out[x/2] |= (pix << ((x & 1) << 2));
+ }
}
}
-
-
-PBMDecoder::PBMDecoder(Common::ReadStream &input, Surface &surface, byte *&colors) : IFFParser(input), _surface(&surface), _colors(&colors) {
- if (_typeId != ID_PBM)
- error("unsupported IFF subtype '%s'", Common::ID2string(_typeId));
+void PBMDecoder::loadHeader(Common::ReadStream *stream) {
+ _header.load(stream);
}
-void PBMDecoder::decode() {
- Common::IFFChunk *chunk;
- while ((chunk = nextChunk()) != 0) {
- switch (chunk->id) {
- case ID_BMHD:
- readBMHD(*chunk);
- break;
+void PBMDecoder::loadBitmap(byte *buffer, Common::ReadStream *stream) {
+ uint32 outSize = _header.width * _header.height;
- case ID_CMAP:
- readCMAP(*chunk);
- break;
+ switch (_header.pack) {
+ case 0:
+ stream->read(buffer, outSize);
+ break;
- case ID_BODY:
- readBODY(*chunk);
- break;
+ case 1: {
+ PackBitsReadStream packStream(*stream);
+ packStream.read(buffer, outSize);
+ break;
}
}
-
- return;
}
-void PBMDecoder::readBMHD(Common::IFFChunk &chunk) {
- fillBMHD(_bitmapHeader, chunk);
+struct PBMLoader {
+ PBMDecoder _decoder;
+ Surface *_surface;
+ byte *_colors;
- _colorCount = 1 << _bitmapHeader.depth;
- *_colors = (byte*)malloc(sizeof(**_colors) * _colorCount * 3);
- _surface->create(_bitmapHeader.width, _bitmapHeader.height, 1);
-
-}
-
-void PBMDecoder::readCMAP(Common::IFFChunk &chunk) {
- if (*_colors == NULL) {
- error("wrong input chunk sequence");
- }
- for (uint32 i = 0; i < _colorCount; i++) {
- (*_colors)[i * 3 + 0] = chunk.readByte();
- (*_colors)[i * 3 + 1] = chunk.readByte();
- (*_colors)[i * 3 + 2] = chunk.readByte();
+ void load(Common::ReadStream &input, Surface &surface, byte *&colors) {
+ _surface = &surface;
+ _colors = colors;
+ Common::IFFParser parser(&input);
+ Common::Functor1Mem< Common::IFFChunk&, bool, PBMLoader > c(this, &PBMLoader::callback);
+ parser.parse(c);
}
-}
-void PBMDecoder::readBODY(Common::IFFChunk& chunk) {
+ bool callback(Common::IFFChunk &chunk) {
+ switch (chunk._type) {
+ case ID_BMHD:
+ _decoder.loadHeader(chunk._stream);
+ break;
- uint si = 0;
+ case ID_CMAP:
+ if (_colors) {
+ chunk._stream->read(_colors, chunk._size);
+ }
+ break;
- switch (_bitmapHeader.pack) {
- case 0:
- while (!chunk.hasReadAll()) {
- ((byte*)_surface->pixels)[si++] = chunk.readByte();
+ case ID_BODY:
+ if (_surface) {
+ _surface->create(_decoder._header.width, _decoder._header.height, 1);
+ _decoder.loadBitmap((byte*)_surface->pixels, chunk._stream);
+ }
+ return true; // stop the parser
}
- break;
- case 1: {
- PackBitsReadStream stream(chunk);
- stream.read((byte*)_surface->pixels, _surface->w * _surface->h);
- break;
+ return false;
}
+};
- }
+void decodePBM(Common::ReadStream &input, Surface &surface, byte *colors) {
+ PBMLoader loader;
+ loader.load(input, surface, colors);
}
-
PackBitsReadStream::PackBitsReadStream(Common::ReadStream &input) : _input(&input) {
}
@@ -282,9 +267,4 @@ uint32 PackBitsReadStream::read(void *dataPtr, uint32 dataSize) {
}
-void decodePBM(Common::ReadStream &input, Surface &surface, byte *&colors) {
- PBMDecoder decoder(input, surface, colors);
- decoder.decode();
-}
-
}