1 /* ScummVM - Graphic Adventure Engine
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include "graphics/iff.h"
26 #include "graphics/surface.h"
28 #include "common/util.h"
33 // this really belongs to iff_container.cpp, but we don't want
34 // to put only this in a source file
35 char *ID2string(Common::IFF_ID id
) {
36 static char str
[] = "abcd";
38 str
[0] = (char)(id
>> 24 & 0xff);
39 str
[1] = (char)(id
>> 16 & 0xff);
40 str
[2] = (char)(id
>> 8 & 0xff);
41 str
[3] = (char)(id
>> 0 & 0xff);
51 void BMHD::load(Common::ReadStream
*stream
) {
53 stream
->read(this, sizeof(BMHD
));
54 width
= FROM_BE_16(width
);
55 height
= FROM_BE_16(height
);
58 transparentColor
= FROM_BE_16(transparentColor
);
59 pageWidth
= FROM_BE_16(pageWidth
);
60 pageHeight
= FROM_BE_16(pageHeight
);
64 void ILBMDecoder::loadHeader(Common::ReadStream
*stream
) {
68 void ILBMDecoder::loadBitmap(uint32 mode
, byte
*buffer
, Common::ReadStream
*stream
) {
70 uint32 numPlanes
= MIN(mode
& ILBM_UNPACK_PLANES
, (uint32
)_header
.depth
);
71 assert(numPlanes
== 1 || numPlanes
== 2 || numPlanes
== 3 || numPlanes
== 4 || numPlanes
== 5 || numPlanes
== 8);
73 bool packPixels
= (mode
& ILBM_PACK_PLANES
) != 0;
74 if (numPlanes
!= 1 && numPlanes
!= 2 && numPlanes
!= 4) {
78 uint32 outPitch
= _header
.width
;
80 outPitch
/= (8 / numPlanes
);
84 switch (_header
.pack
) {
85 case 1: { // PackBits compressed bitmap
86 Graphics::PackBitsReadStream
packStream(*stream
);
88 // setup a buffer to hold enough data to build a line in the output
89 uint32 scanlineWidth
= ((_header
.width
+ 15)/16) << 1;
90 byte
*scanline
= new byte
[scanlineWidth
* _header
.depth
];
92 for (uint i
= 0; i
< _header
.height
; ++i
) {
94 for (uint32 j
= 0; j
< _header
.depth
; ++j
) {
95 packStream
.read(s
, scanlineWidth
);
99 planarToChunky(out
, outPitch
, scanline
, scanlineWidth
, numPlanes
, packPixels
);
108 // implement other compression types here!
109 error("only RLE compressed ILBM files are supported");
114 void ILBMDecoder::planarToChunky(byte
*out
, uint32 outPitch
, byte
*in
, uint32 inWidth
, uint32 nPlanes
, bool packPlanes
) {
118 uint32 pixels
= outPitch
;
120 pixels
*= (8 / nPlanes
);
123 for (uint32 x
= 0; x
< pixels
; ++x
) {
127 bit
= 0x80 >> (x
& 7);
129 // first build a pixel by scanning all the usable planes in the input
131 for (uint32 plane
= 0; plane
< nPlanes
; ++plane
) {
139 // then output the pixel according to the requested packing
144 out
[x
/8] |= (pix
<< (x
& 7));
147 out
[x
/4] |= (pix
<< ((x
& 3) << 1));
150 out
[x
/2] |= (pix
<< ((x
& 1) << 2));
157 void PBMDecoder::loadHeader(Common::ReadStream
*stream
) {
158 _header
.load(stream
);
162 void PBMDecoder::loadBitmap(byte
*buffer
, Common::ReadStream
*stream
) {
163 uint32 outSize
= _header
.width
* _header
.height
;
165 switch (_header
.pack
) {
167 stream
->read(buffer
, outSize
);
171 PackBitsReadStream
packStream(*stream
);
172 packStream
.read(buffer
, outSize
);
184 void load(Common::ReadStream
&input
, Surface
&surface
, byte
*&colors
) {
187 Common::IFFParser
parser(&input
);
188 Common::Functor1Mem
< Common::IFFChunk
&, bool, PBMLoader
> c(this, &PBMLoader::callback
);
192 bool callback(Common::IFFChunk
&chunk
) {
193 switch (chunk
._type
) {
195 _decoder
.loadHeader(chunk
._stream
);
200 chunk
._stream
->read(_colors
, chunk
._size
);
206 _surface
->create(_decoder
._header
.width
, _decoder
._header
.height
, 1);
207 _decoder
.loadBitmap((byte
*)_surface
->pixels
, chunk
._stream
);
209 return true; // stop the parser
216 void decodePBM(Common::ReadStream
&input
, Surface
&surface
, byte
*colors
) {
218 loader
.load(input
, surface
, colors
);
224 PackBitsReadStream::PackBitsReadStream(Common::ReadStream
&input
) : _input(&input
) {
227 PackBitsReadStream::~PackBitsReadStream() {
230 bool PackBitsReadStream::eos() const {
231 return _input
->eos();
234 uint32
PackBitsReadStream::read(void *dataPtr
, uint32 dataSize
) {
235 byte
*out
= (byte
*)dataPtr
;
236 uint32 left
= dataSize
;
238 uint32 lenR
= 0, lenW
= 0;
239 while (left
> 0 && !_input
->eos()) {
240 lenR
= _input
->readByte();
245 } else if (lenR
<= 127) {
248 lenW
= MIN(lenR
, left
);
249 for (uint32 j
= 0; j
< lenW
; j
++) {
250 *out
++ = _input
->readByte();
252 for ( ; lenR
> lenW
; lenR
--) {
255 } else { // len > 128
257 lenW
= MIN((256 - lenR
) + 1, left
);
258 byte val
= _input
->readByte();
259 memset(out
, val
, lenW
);
266 return dataSize
- left
;