scummvm/graphics/ilbm.cpp

326 lines
8.2 KiB
C++

/* ScummVM - Scumm Interpreter
* Copyright (C) 2005-2006 The ScummVM project
*
* 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.
*
* $URL$
* $Id$
*/
#include "common/stdafx.h"
#include "common/endian.h"
#include "common/stream.h"
#include "graphics/surface.h"
namespace Graphics {
typedef uint32 IFF_ID;
struct Chunk {
IFF_ID id;
uint32 size;
uint32 bytesRead;
Common::ReadStream *_input;
Chunk(Common::ReadStream *input): _input(input) {
size = bytesRead = 0;
}
void incBytesRead(uint32 inc) {
bytesRead += inc;
if (bytesRead > size) {
error("Chunk overead");
}
}
void readHeader() {
id = _input->readUint32BE();
size = _input->readUint32BE();
bytesRead = 0;
}
bool eos() {
return (size - bytesRead) == 0;
}
void feed() {
if (size % 2) {
size++;
}
while(!_input->eos() && !eos()) {
readByte();
}
}
byte readByte() {
incBytesRead(1);
return _input->readByte();
}
int8 readSByte() {
incBytesRead(1);
return _input->readSByte();
}
uint16 readUint16() {
incBytesRead(2);
return _input->readUint16BE();
}
uint32 readUint32() {
incBytesRead(4);
return _input->readUint32BE();
}
int16 readSint16() {
return (int16)readUint16();
}
int32 readSint32() {
return (int32)readUint32();
}
};
static char * ID2string(IFF_ID id) {
static char str[] = "abcd";
str[0] = (char)(id >> 24 & 0xff);
str[1] = (char)(id >> 16 & 0xff);
str[2] = (char)(id >> 8 & 0xff);
str[3] = (char)(id >> 0 & 0xff);
return str;
}
struct BMHD {
uint16 width, height;
uint16 x, y;
byte depth;
byte masking;
byte pack;
byte flags;
uint16 transparentColor;
byte xAspect, yAspect;
uint16 pageWidth, pageHeight;
BMHD() {
memset(this, 0, sizeof(*this));
}
};
#define ID_FORM MKID_BE('FORM')
/* EA IFF 85 group identifier */
#define ID_CAT MKID_BE('CAT ')
/* EA IFF 85 group identifier */
#define ID_LIST MKID_BE('LIST')
/* EA IFF 85 group identifier */
#define ID_PROP MKID_BE('PROP')
/* EA IFF 85 group identifier */
#define ID_END MKID_BE('END ')
/* unofficial END-of-FORM identifier (see Amiga RKM Devices Ed.3
page 376) */
#define ID_ILBM MKID_BE('ILBM')
/* EA IFF 85 raster bitmap form */
#define ID_DEEP MKID_BE('DEEP')
/* Chunky pixel image files (Used in TV Paint) */
#define ID_RGB8 MKID_BE('RGB8')
/* RGB image forms, Turbo Silver (Impulse) */
#define ID_RGBN MKID_BE('RGBN')
/* RGB image forms, Turbo Silver (Impulse) */
#define ID_PBM MKID_BE('PBM ')
/* 256-color chunky format (DPaint 2 ?) */
#define ID_ACBM MKID_BE('ACBM')
/* Amiga Contiguous Bitmap (AmigaBasic) */
/* generic */
#define ID_FVER MKID_BE('FVER')
/* AmigaOS version string */
#define ID_JUNK MKID_BE('JUNK')
/* always ignore this chunk */
#define ID_ANNO MKID_BE('ANNO')
/* EA IFF 85 Generic Annotation chunk */
#define ID_AUTH MKID_BE('AUTH')
/* EA IFF 85 Generic Author chunk */
#define ID_CHRS MKID_BE('CHRS')
/* EA IFF 85 Generic character string chunk */
#define ID_NAME MKID_BE('NAME')
/* EA IFF 85 Generic Name of art, music, etc. chunk */
#define ID_TEXT MKID_BE('TEXT'))
/* EA IFF 85 Generic unformatted ASCII text chunk */
#define ID_copy MKID_BE('(c) ')
/* EA IFF 85 Generic Copyright text chunk */
/* ILBM chunks */
#define ID_BMHD MKID_BE('BMHD')
/* ILBM BitmapHeader */
#define ID_CMAP MKID_BE('CMAP')
/* ILBM 8bit RGB colormap */
#define ID_GRAB MKID_BE('GRAB')
/* ILBM "hotspot" coordiantes */
#define ID_DEST MKID_BE('DEST')
/* ILBM destination image info */
#define ID_SPRT MKID_BE('SPRT')
/* ILBM sprite identifier */
#define ID_CAMG MKID_BE('CAMG')
/* Amiga viewportmodes */
#define ID_BODY MKID_BE('BODY')
/* ILBM image data */
#define ID_CRNG MKID_BE('CRNG')
/* color cycling */
#define ID_CCRT MKID_BE('CCRT')
/* color cycling */
#define ID_CLUT MKID_BE('CLUT')
/* Color Lookup Table chunk */
#define ID_DPI MKID_BE('DPI ')
/* Dots per inch chunk */
#define ID_DPPV MKID_BE('DPPV')
/* DPaint perspective chunk (EA) */
#define ID_DRNG MKID_BE('DRNG')
/* DPaint IV enhanced color cycle chunk (EA) */
#define ID_EPSF MKID_BE('EPSF')
/* Encapsulated Postscript chunk */
#define ID_CMYK MKID_BE('CMYK')
/* Cyan, Magenta, Yellow, & Black color map (Soft-Logik) */
#define ID_CNAM MKID_BE('CNAM')
/* Color naming chunk (Soft-Logik) */
#define ID_PCHG MKID_BE('PCHG')
/* Line by line palette control information (Sebastiano Vigna) */
#define ID_PRVW MKID_BE('PRVW')
/* A mini duplicate ILBM used for preview (Gary Bonham) */
#define ID_XBMI MKID_BE('XBMI')
/* eXtended BitMap Information (Soft-Logik) */
#define ID_CTBL MKID_BE('CTBL')
/* Newtek Dynamic Ham color chunk */
#define ID_DYCP MKID_BE('DYCP')
/* Newtek Dynamic Ham chunk */
#define ID_SHAM MKID_BE('SHAM')
/* Sliced HAM color chunk */
#define ID_ABIT MKID_BE('ABIT')
/* ACBM body chunk */
#define ID_DCOL MKID_BE('DCOL')
/* unofficial direct color */
#define ID_DPPS MKID_BE('DPPS')
/* ? */
#define ID_TINY MKID_BE('TINY')
/* ? */
void decodeILBM(Common::ReadStream &input, Surface &surface, byte *&colors) {
IFF_ID typeId;
BMHD bitmapHeader;
Chunk formChunk(&input);
Chunk chunk(&input);
uint32 colorCount = 0, i, j, si;
byte byteRun;
byte idx;
colors = NULL;
si = 0;
formChunk.readHeader();
if (formChunk.id != ID_FORM) {
error("decodeILBM() input is not a FORM type IFF file");
}
typeId = formChunk.readUint32();
if (typeId != ID_PBM) {
error( "decodeILBM() input is not an PBM ");
}
while (!formChunk.eos()) {
formChunk.incBytesRead(8);
chunk.readHeader();
switch(chunk.id) {
case ID_BMHD:
bitmapHeader.width = chunk.readUint16();
bitmapHeader.height = chunk.readUint16();
bitmapHeader.x = chunk.readUint16();
bitmapHeader.y = chunk.readUint16();
bitmapHeader.depth = chunk.readByte();
if (bitmapHeader.depth > 8) {
error("decodeILBM() depth > 8");
}
bitmapHeader.masking = chunk.readByte();
bitmapHeader.pack = chunk.readByte();
if ((bitmapHeader.pack != 0) && (bitmapHeader.pack != 1)) {
error("decodeILBM() unsupported pack");
}
bitmapHeader.flags = chunk.readByte();
bitmapHeader.transparentColor = chunk.readUint16();
bitmapHeader.xAspect = chunk.readByte();
bitmapHeader.yAspect = chunk.readByte();
bitmapHeader.pageWidth = chunk.readUint16();
bitmapHeader.pageHeight = chunk.readUint16();
colorCount = 1 << bitmapHeader.depth;
colors = (byte*)malloc(sizeof(*colors) * colorCount * 3);
surface.create(bitmapHeader.width, bitmapHeader.height, 1);
break;
case ID_CMAP:
if (colors == NULL) {
error("wrong input chunk sequence");
}
for (i = 0; i < colorCount; i++) {
colors[i * 3 + 0] = chunk.readByte();
colors[i * 3 + 1] = chunk.readByte();
colors[i * 3 + 2] = chunk.readByte();
}
break;
case ID_BODY:
switch (bitmapHeader.pack) {
case 0:
while (!chunk.eos()) {
idx = chunk.readByte();
((byte*)surface.pixels)[si++] = idx;
}
break;
case 1:
while (!chunk.eos()) {
byteRun = chunk.readByte();
if (byteRun <= 127) {
i = byteRun + 1;
for (j = 0; j < i; j++){
idx = chunk.readByte();
((byte*)surface.pixels)[si++] = idx;
}
} else if (byteRun != 128) {
i = (256 - byteRun) + 1;
idx = chunk.readByte();
for (j = 0; j < i; j++) {
((byte*)surface.pixels)[si++] = idx;
}
}
}
break;
}
break;
case ID_GRAB: case ID_CRNG: case ID_TINY: case ID_DPPS:
break;
default:
error("unknown chunk : %s\n", ID2string(chunk.id));
}
chunk.feed();
formChunk.incBytesRead(chunk.size);
}
}
} // End of namespace Graphics