* Final version of the IFF parsing code.
* Refactored ILBMDecoder usage from disk code. svn-id: r41458
This commit is contained in:
parent
f5b2e69522
commit
5fccc0f98d
8 changed files with 423 additions and 334 deletions
121
engines/parallaction/disk.cpp
Normal file
121
engines/parallaction/disk.cpp
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -33,6 +33,7 @@
|
||||||
#include "common/file.h"
|
#include "common/file.h"
|
||||||
|
|
||||||
#include "graphics/surface.h"
|
#include "graphics/surface.h"
|
||||||
|
#include "parallaction/iff.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,8 +78,37 @@ public:
|
||||||
virtual Table* loadTable(const char* name) = 0;
|
virtual Table* loadTable(const char* name) = 0;
|
||||||
virtual Common::SeekableReadStream* loadMusic(const char* name) = 0;
|
virtual Common::SeekableReadStream* loadMusic(const char* name) = 0;
|
||||||
virtual Common::SeekableReadStream* loadSound(const char* name) = 0;
|
virtual Common::SeekableReadStream* loadSound(const char* name) = 0;
|
||||||
virtual void loadMask(const char *name, MaskBuffer &buffer) { }
|
virtual MaskBuffer *loadMask(const char *name, uint32 w, uint32 h) { return 0; }
|
||||||
virtual void loadPath(const char *name, PathBuffer &buffer) { }
|
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);
|
Table* loadTable(const char* name);
|
||||||
Common::SeekableReadStream* loadMusic(const char* name);
|
Common::SeekableReadStream* loadMusic(const char* name);
|
||||||
Common::SeekableReadStream* loadSound(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);
|
||||||
void loadPath(const char *name, PathBuffer &buffer);
|
PathBuffer *loadPath(const char *name, uint32 w, uint32 h);
|
||||||
};
|
};
|
||||||
|
|
||||||
class DosDemoDisk_br : public DosDisk_br {
|
class DosDemoDisk_br : public DosDisk_br {
|
||||||
|
@ -272,7 +302,7 @@ public:
|
||||||
GfxObj* loadObjects(const char *name, uint8 part = 0);
|
GfxObj* loadObjects(const char *name, uint8 part = 0);
|
||||||
Common::SeekableReadStream* loadMusic(const char* name);
|
Common::SeekableReadStream* loadMusic(const char* name);
|
||||||
Common::SeekableReadStream* loadSound(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
|
} // namespace Parallaction
|
||||||
|
|
|
@ -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) {
|
if (!name) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::SeekableReadStream *stream = openFile("msk/" + Common::String(name), ".msk");
|
Common::SeekableReadStream *stream = openFile("msk/" + Common::String(name), ".msk");
|
||||||
|
|
||||||
// NOTE: info.width and info.height are only valid if the background graphics
|
MaskBuffer *buffer = new MaskBuffer;
|
||||||
// have already been loaded
|
assert(buffer);
|
||||||
buffer.bigEndian = false;
|
buffer->create(w, h);
|
||||||
stream->read(buffer.data, buffer.size);
|
buffer->bigEndian = false;
|
||||||
|
|
||||||
|
stream->read(buffer->data, buffer->size);
|
||||||
delete stream;
|
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) {
|
if (!name) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::SeekableReadStream *stream = openFile("pth/" + Common::String(name), ".pth");
|
Common::SeekableReadStream *stream = openFile("pth/" + Common::String(name), ".pth");
|
||||||
|
|
||||||
// NOTE: info.width and info.height are only valid if the background graphics
|
PathBuffer *buffer = new PathBuffer;
|
||||||
// have already been loaded
|
assert(buffer);
|
||||||
buffer.bigEndian = false;
|
buffer->create(w, h);
|
||||||
stream->read(buffer.data, buffer.size);
|
buffer->bigEndian = false;
|
||||||
|
|
||||||
|
stream->read(buffer->data, buffer->size);
|
||||||
delete stream;
|
delete stream;
|
||||||
|
|
||||||
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DosDisk_br::loadScenery(BackgroundInfo& info, const char *name, const char *mask, const char* path) {
|
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) {
|
if (mask) {
|
||||||
info._mask = new MaskBuffer;
|
info._mask = loadMask(mask, info.width, info.height);
|
||||||
info._mask->create(info.width, info.height);
|
|
||||||
loadMask(mask, *info._mask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path) {
|
if (path) {
|
||||||
info._path = new PathBuffer;
|
info._path = loadPath(path, info.width, info.height);
|
||||||
info._path->create(info.width, info.height);
|
|
||||||
loadPath(path, *info._path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Table* DosDisk_br::loadTable(const char* name) {
|
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) {
|
void AmigaDisk_br::loadBackground(BackgroundInfo& info, const char *filename) {
|
||||||
byte r,g,b;
|
byte r,g,b;
|
||||||
byte *pal, *p;
|
byte *p;
|
||||||
Common::SeekableReadStream *stream;
|
Common::SeekableReadStream *stream;
|
||||||
uint i;
|
uint i;
|
||||||
|
|
||||||
|
@ -488,20 +490,14 @@ void AmigaDisk_br::loadBackground(BackgroundInfo& info, const char *filename) {
|
||||||
}
|
}
|
||||||
|
|
||||||
stream = openFile("backs/" + Common::String(filename), ".bkg");
|
stream = openFile("backs/" + Common::String(filename), ".bkg");
|
||||||
ILBMDecoder decoder(stream, true);
|
|
||||||
|
|
||||||
// TODO: encapsulate surface creation
|
byte pal[768];
|
||||||
info.bg.w = decoder.getWidth();
|
ILBMLoader loader(&info.bg, pal);
|
||||||
info.bg.h = decoder.getHeight();
|
loader.load(stream, true);
|
||||||
info.bg.pitch = info.bg.w;
|
|
||||||
info.bg.bytesPerPixel = 1;
|
|
||||||
info.bg.pixels = decoder.getBitmap();
|
|
||||||
assert(info.bg.pixels);
|
|
||||||
|
|
||||||
info.width = info.bg.w;
|
info.width = info.bg.w;
|
||||||
info.height = info.bg.h;
|
info.height = info.bg.h;
|
||||||
|
|
||||||
pal = decoder.getPalette();
|
|
||||||
p = pal;
|
p = pal;
|
||||||
for (i = 16; i < 32; i++) {
|
for (i = 16; i < 32; i++) {
|
||||||
r = *p >> 2;
|
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
|
// Overwrite the first color (transparent key) in the palette
|
||||||
info.palette.setEntry(0, pal[0] >> 2, pal[1] >> 2, pal[2] >> 0);
|
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
|
// background data is drawn used the upper portion of the palette
|
||||||
adjustForPalette(info.bg);
|
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) {
|
if (!name) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
debugC(1, kDebugDisk, "AmigaDisk_br::loadMask '%s'", name);
|
debugC(1, kDebugDisk, "AmigaDisk_br::loadMask '%s'", name);
|
||||||
|
|
||||||
Common::SeekableReadStream *stream = tryOpenFile("msk/" + Common::String(name), ".msk");
|
Common::SeekableReadStream *stream = tryOpenFile("msk/" + Common::String(name), ".msk");
|
||||||
if (!stream) {
|
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
|
MaskBuffer *buffer = loader._maskBuffer;
|
||||||
// unavoidable... a better solution would be inform the function
|
buffer->bigEndian = true;
|
||||||
// of the size of the mask (the size in the mask file is not valid!)
|
finalpass(buffer->data, buffer->size);
|
||||||
byte *bitmap = decoder.getBitmap(2, true);
|
return buffer;
|
||||||
memcpy(buffer.data, bitmap, buffer.size);
|
|
||||||
finalpass(buffer.data, buffer.size);
|
|
||||||
|
|
||||||
buffer.bigEndian = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path) {
|
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);
|
loadBackground(info, name);
|
||||||
}
|
}
|
||||||
if (mask) {
|
if (mask) {
|
||||||
info._mask = new MaskBuffer;
|
info._mask = loadMask(mask, info.width, info.height);
|
||||||
info._mask->create(info.width, info.height);
|
|
||||||
loadMask(mask, *info._mask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path) {
|
if (path) {
|
||||||
info._path = new PathBuffer;
|
info._path = loadPath(path, info.width, info.height);
|
||||||
info._path->create(info.width, info.height);
|
|
||||||
loadPath(path, *info._path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AmigaDisk_br::loadSlide(BackgroundInfo& info, const char *name) {
|
void AmigaDisk_br::loadSlide(BackgroundInfo& info, const char *name) {
|
||||||
|
@ -596,21 +581,14 @@ GfxObj* AmigaDisk_br::loadStatic(const char* name) {
|
||||||
debugC(1, kDebugDisk, "AmigaDisk_br::loadStatic '%s'", name);
|
debugC(1, kDebugDisk, "AmigaDisk_br::loadStatic '%s'", name);
|
||||||
|
|
||||||
Common::String sName = name;
|
Common::String sName = name;
|
||||||
|
|
||||||
Common::SeekableReadStream *stream = openFile("ras/" + sName, ".ras");
|
Common::SeekableReadStream *stream = openFile("ras/" + sName, ".ras");
|
||||||
ILBMDecoder decoder(stream, true);
|
|
||||||
|
|
||||||
Graphics::Surface* surf = new Graphics::Surface;
|
ILBMLoader loader(ILBMLoader::BODYMODE_SURFACE);
|
||||||
|
loader.load(stream, true);
|
||||||
|
|
||||||
|
Graphics::Surface* surf = loader._surf;
|
||||||
assert(surf);
|
assert(surf);
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Static pictures are drawn used the upper half of the palette: this must be
|
// 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
|
// done before shadow mask is applied. This way, only really transparent pixels
|
||||||
// will have zero as a color.
|
// will have zero as a color.
|
||||||
|
@ -741,15 +719,16 @@ GfxObj* AmigaDisk_br::loadObjects(const char *name, uint8 part) {
|
||||||
debugC(5, kDebugDisk, "AmigaDisk_br::loadObjects");
|
debugC(5, kDebugDisk, "AmigaDisk_br::loadObjects");
|
||||||
|
|
||||||
Common::SeekableReadStream *stream = openFile(name);
|
Common::SeekableReadStream *stream = openFile(name);
|
||||||
ILBMDecoder decoder(stream, true);
|
ILBMLoader loader(ILBMLoader::BODYMODE_SURFACE);
|
||||||
|
loader.load(stream, true);
|
||||||
|
|
||||||
uint16 max = objectsMax[part];
|
uint16 max = objectsMax[part];
|
||||||
if (_vm->getFeatures() & GF_DEMO)
|
if (_vm->getFeatures() & GF_DEMO)
|
||||||
max = 72;
|
max = 72;
|
||||||
|
|
||||||
byte *data = new byte[max * 2601];
|
byte *data = new byte[max * 2601];
|
||||||
byte *srcPtr = decoder.getBitmap();
|
byte *srcPtr = (byte*)loader._surf->getBasePtr(0,0);
|
||||||
int w = decoder.getWidth();
|
int w = loader._surf->w;
|
||||||
|
|
||||||
// Convert to the expected display format
|
// Convert to the expected display format
|
||||||
for (int i = 0; i < max; i++) {
|
for (int i = 0; i < max; i++) {
|
||||||
|
@ -764,7 +743,7 @@ GfxObj* AmigaDisk_br::loadObjects(const char *name, uint8 part) {
|
||||||
dst += 51;
|
dst += 51;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(srcPtr);
|
delete loader._surf;
|
||||||
|
|
||||||
return new GfxObj(0, new Cnv(max, 51, 51, data, true));
|
return new GfxObj(0, new Cnv(max, 51, 51, data, true));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
void AmigaDisk_ns::loadBackground(BackgroundInfo& info, const char *name) {
|
||||||
|
PaletteFxRange ranges[6];
|
||||||
|
byte pal[768];
|
||||||
|
|
||||||
Common::SeekableReadStream *s = openFile(name);
|
Common::SeekableReadStream *s = openFile(name);
|
||||||
BackgroundDecoder decoder(s, true);
|
ILBMLoader loader(&info.bg, pal, ranges);
|
||||||
|
loader.load(s, true);
|
||||||
PaletteFxRange ranges[6];
|
|
||||||
memset(ranges, 0, 6*sizeof(PaletteFxRange));
|
|
||||||
decoder.getCRNG(ranges, 6);
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
|
|
||||||
info.width = info.bg.w;
|
info.width = info.bg.w;
|
||||||
info.height = info.bg.h;
|
info.height = info.bg.h;
|
||||||
|
|
||||||
byte *pal = decoder.getPalette();
|
|
||||||
assert(pal);
|
|
||||||
byte *p = pal;
|
byte *p = pal;
|
||||||
for (uint i = 0; i < 32; i++) {
|
for (uint i = 0; i < 32; i++) {
|
||||||
byte r = *p >> 2;
|
byte r = *p >> 2;
|
||||||
|
@ -960,7 +922,6 @@ void AmigaDisk_ns::loadBackground(BackgroundInfo& info, const char *name) {
|
||||||
p++;
|
p++;
|
||||||
info.palette.setEntry(i, r, g, b);
|
info.palette.setEntry(i, r, g, b);
|
||||||
}
|
}
|
||||||
delete []pal;
|
|
||||||
|
|
||||||
for (uint j = 0; j < 6; j++) {
|
for (uint j = 0; j < 6; j++) {
|
||||||
info.setPaletteRange(j, ranges[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
|
return; // no errors if missing mask files: not every location has one
|
||||||
}
|
}
|
||||||
|
|
||||||
ILBMDecoder decoder(s, true);
|
byte pal[768];
|
||||||
byte *pal = decoder.getPalette();
|
ILBMLoader loader(ILBMLoader::BODYMODE_MASKBUFFER, pal);
|
||||||
assert(pal);
|
loader.load(s, true);
|
||||||
|
|
||||||
byte r, g, b;
|
byte r, g, b;
|
||||||
for (uint i = 0; i < 4; i++) {
|
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];
|
b = pal[i*3+2];
|
||||||
info.layers[i] = (((r << 4) & 0xF00) | (g & 0xF0) | (b >> 4)) & 0xFF;
|
info.layers[i] = (((r << 4) & 0xF00) | (g & 0xF0) | (b >> 4)) & 0xFF;
|
||||||
}
|
}
|
||||||
delete []pal;
|
|
||||||
|
|
||||||
info._mask = new MaskBuffer;
|
info._mask = loader._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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AmigaDisk_ns::loadPath(BackgroundInfo& info, const char *name) {
|
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
|
return; // no errors if missing path files: not every location has one
|
||||||
}
|
}
|
||||||
|
|
||||||
ILBMDecoder decoder(s, true);
|
ILBMLoader loader(ILBMLoader::BODYMODE_PATHBUFFER);
|
||||||
info._path = new PathBuffer;
|
loader.load(s, true);
|
||||||
info._path->create(info.width, info.height);
|
info._path = loader._pathBuffer;
|
||||||
info._path->bigEndian = true;
|
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) {
|
void AmigaDisk_ns::loadScenery(BackgroundInfo& info, const char* background, const char* mask, const char* path) {
|
||||||
|
|
|
@ -162,9 +162,7 @@ void BackgroundInfo::loadGfxObjMask(const char *name, GfxObj *obj) {
|
||||||
Common::Rect rect;
|
Common::Rect rect;
|
||||||
obj->getRect(0, rect);
|
obj->getRect(0, rect);
|
||||||
|
|
||||||
MaskBuffer *buf = new MaskBuffer;
|
MaskBuffer *buf = _vm->_disk->loadMask(name, rect.width(), rect.height());
|
||||||
buf->create(rect.width(), rect.height());
|
|
||||||
_vm->_disk->loadMask(name, *buf);
|
|
||||||
|
|
||||||
obj->_maskId = addMaskPatch(buf);
|
obj->_maskId = addMaskPatch(buf);
|
||||||
obj->_hasMask = true;
|
obj->_hasMask = true;
|
||||||
|
@ -174,9 +172,7 @@ void BackgroundInfo::loadGfxObjPath(const char *name, GfxObj *obj) {
|
||||||
Common::Rect rect;
|
Common::Rect rect;
|
||||||
obj->getRect(0, rect);
|
obj->getRect(0, rect);
|
||||||
|
|
||||||
PathBuffer *buf = new PathBuffer;
|
PathBuffer *buf = _vm->_disk->loadPath(name, rect.width(), rect.height());
|
||||||
buf->create(rect.width(), rect.height());
|
|
||||||
_vm->_disk->loadPath(name, *buf);
|
|
||||||
|
|
||||||
obj->_pathId = addPathPatch(buf);
|
obj->_pathId = addPathPatch(buf);
|
||||||
obj->_hasPath = true;
|
obj->_hasPath = true;
|
||||||
|
|
|
@ -32,34 +32,17 @@
|
||||||
namespace Parallaction {
|
namespace Parallaction {
|
||||||
|
|
||||||
|
|
||||||
void IFFParser::setInputStream(Common::SeekableReadStream *stream) {
|
void IFFParser::setInputStream(Common::ReadStream *stream) {
|
||||||
destroy();
|
|
||||||
|
|
||||||
assert(stream);
|
assert(stream);
|
||||||
_stream = stream;
|
_formChunk.setInputStream(stream);
|
||||||
_startOffset = 0;
|
_chunk.setInputStream(stream);
|
||||||
_endOffset = _stream->size();
|
|
||||||
|
|
||||||
_formType = 0;
|
_formChunk.readHeader();
|
||||||
_formSize = (uint32)-1;
|
if (_formChunk.id != ID_FORM) {
|
||||||
|
error("IFFParser input is not a FORM type IFF file");
|
||||||
if (_stream->size() < 12) {
|
|
||||||
// this file is too small to be a valid IFF container
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
_formSize = _formChunk.size;
|
||||||
if (_stream->readUint32BE() != ID_FORM) {
|
_formType = _formChunk.readUint32BE();
|
||||||
// no FORM header was found
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_formSize = _stream->readUint32BE();
|
|
||||||
_formType = _stream->readUint32BE();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IFFParser::destroy() {
|
|
||||||
_stream = 0;
|
|
||||||
_startOffset = _endOffset = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 IFFParser::getFORMSize() const {
|
uint32 IFFParser::getFORMSize() const {
|
||||||
|
@ -70,171 +53,99 @@ Common::IFF_ID IFFParser::getFORMType() const {
|
||||||
return _formType;
|
return _formType;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 IFFParser::moveToIFFBlock(Common::IFF_ID chunkName) {
|
void IFFParser::parse(IFFCallback &callback) {
|
||||||
uint32 size = (uint32)-1;
|
bool stop;
|
||||||
|
do {
|
||||||
|
_chunk.feed();
|
||||||
|
_formChunk.incBytesRead(_chunk.size);
|
||||||
|
|
||||||
_stream->seek(_startOffset + 0x0C);
|
if (_formChunk.hasReadAll()) {
|
||||||
|
|
||||||
while ((uint)_stream->pos() < _endOffset) {
|
|
||||||
uint32 chunk = _stream->readUint32BE();
|
|
||||||
uint32 size_temp = _stream->readUint32BE();
|
|
||||||
|
|
||||||
if (chunk != chunkName) {
|
|
||||||
_stream->seek((size_temp + 1) & (~1), SEEK_CUR);
|
|
||||||
assert((uint)_stream->pos() <= _endOffset);
|
|
||||||
} else {
|
|
||||||
size = size_temp;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return size;
|
_formChunk.incBytesRead(8);
|
||||||
}
|
_chunk.readHeader();
|
||||||
|
|
||||||
uint32 IFFParser::getIFFBlockSize(Common::IFF_ID chunkName) {
|
// invoke the callback
|
||||||
uint32 size = moveToIFFBlock(chunkName);
|
Common::SubReadStream stream(&_chunk, _chunk.size);
|
||||||
return size;
|
IFFChunk chunk(_chunk.id, _chunk.size, &stream);
|
||||||
}
|
stop = callback(chunk);
|
||||||
|
|
||||||
bool IFFParser::loadIFFBlock(Common::IFF_ID chunkName, void *loadTo, uint32 ptrSize) {
|
// eats up all the remaining data in the chunk
|
||||||
uint32 chunkSize = moveToIFFBlock(chunkName);
|
while (!stream.eos()) {
|
||||||
|
printf("attemping to eat data in chunk\n");
|
||||||
if (chunkSize == (uint32)-1) {
|
stream.readByte();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ILBM decoder implementation
|
} while (!stop);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ILBMDecoder::~ILBMDecoder() {
|
|
||||||
if (_disposeStream) {
|
void ILBMDecoder::loadHeader(Common::ReadStream *stream) {
|
||||||
delete _in;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 ILBMDecoder::getWidth() {
|
void ILBMDecoder::loadBitmap(uint32 mode, byte *buffer, Common::ReadStream *stream) {
|
||||||
assert(_hasHeader);
|
assert(stream);
|
||||||
return _header.width;
|
uint32 numPlanes = MIN(mode & ILBM_UNPACK_PLANES, (uint32)_header.depth);
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte *ILBMDecoder::getBitmap(uint32 numPlanes, bool packPlanes) {
|
|
||||||
assert(_bodySize != (uint32)-1);
|
|
||||||
assert(numPlanes == 1 || numPlanes == 2 || numPlanes == 3 || numPlanes == 4 || numPlanes == 5 || numPlanes == 8);
|
assert(numPlanes == 1 || numPlanes == 2 || numPlanes == 3 || numPlanes == 4 || numPlanes == 5 || numPlanes == 8);
|
||||||
|
|
||||||
numPlanes = MIN(numPlanes, (uint32)_header.depth);
|
bool packPixels = (mode & ILBM_PACK_PLANES) != 0;
|
||||||
if (numPlanes > 4) {
|
if (numPlanes != 1 && numPlanes != 2 && numPlanes != 4) {
|
||||||
packPlanes = false;
|
packPixels = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 bitmapSize = _header.width * _header.height;
|
uint32 outPitch = _header.width;
|
||||||
uint32 bitmapWidth = _header.width;
|
if (packPixels) {
|
||||||
if (packPlanes) {
|
outPitch /= (8 / numPlanes);
|
||||||
bitmapSize /= (8 / numPlanes);
|
|
||||||
bitmapWidth /= (8 / numPlanes);
|
|
||||||
}
|
}
|
||||||
|
byte *out = buffer;
|
||||||
Common::SeekableReadStream *bodyStream = _parser.getIFFBlockStream(ID_BODY);
|
|
||||||
assert(bodyStream);
|
|
||||||
|
|
||||||
byte *bitmap = (byte*)calloc(bitmapSize, 1);
|
|
||||||
assert(bitmap);
|
|
||||||
|
|
||||||
switch (_header.pack) {
|
switch (_header.pack) {
|
||||||
case 1: { // PackBits compressed bitmap
|
case 1: { // PackBits compressed bitmap
|
||||||
Graphics::PackBitsReadStream stream(*bodyStream);
|
Graphics::PackBitsReadStream packStream(*stream);
|
||||||
|
|
||||||
byte *out = bitmap;
|
|
||||||
|
|
||||||
// setup a buffer to hold enough data to build a line in the output
|
// setup a buffer to hold enough data to build a line in the output
|
||||||
uint32 scanWidth = ((_header.width + 15)/16) << 1;
|
uint32 scanlineWidth = ((_header.width + 15)/16) << 1;
|
||||||
byte *scanBuffer = (byte*)malloc(scanWidth * _header.depth);
|
byte *scanline = new byte[scanlineWidth * _header.depth];
|
||||||
|
|
||||||
for (uint i = 0; i < _header.height; ++i) {
|
for (uint i = 0; i < _header.height; ++i) {
|
||||||
byte *s = scanBuffer;
|
byte *s = scanline;
|
||||||
for (uint32 j = 0; j < _header.depth; ++j) {
|
for (uint32 j = 0; j < _header.depth; ++j) {
|
||||||
stream.read(s, scanWidth);
|
packStream.read(s, scanlineWidth);
|
||||||
s += scanWidth;
|
s += scanlineWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
planarToChunky(out, bitmapWidth, scanBuffer, scanWidth, numPlanes, packPlanes);
|
planarToChunky(out, outPitch, scanline, scanlineWidth, numPlanes, packPixels);
|
||||||
out += bitmapWidth;
|
out += outPitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(scanBuffer);
|
delete []scanline;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
// implement other compression types here!
|
||||||
error("only RLE compressed ILBM files are supported");
|
error("only RLE compressed ILBM files are supported");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete bodyStream;
|
|
||||||
|
|
||||||
return bitmap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ILBMDecoder::planarToChunky(byte *out, uint32 outPitch, byte *in, uint32 inWidth, uint32 nPlanes, bool packPlanes) {
|
||||||
void ILBMDecoder::planarToChunky(byte *out, uint32 width, byte *in, uint32 planeWidth, uint32 nPlanes, bool packPlanes) {
|
|
||||||
byte pix, ofs, bit;
|
byte pix, ofs, bit;
|
||||||
byte *s;
|
byte *s;
|
||||||
|
|
||||||
uint32 pixels = width;
|
uint32 pixels = outPitch;
|
||||||
if (packPlanes) {
|
if (packPlanes) {
|
||||||
pixels *= (8 / nPlanes);
|
pixels *= (8 / nPlanes);
|
||||||
}
|
}
|
||||||
|
@ -251,7 +162,7 @@ void ILBMDecoder::planarToChunky(byte *out, uint32 width, byte *in, uint32 plane
|
||||||
if (s[ofs] & bit) {
|
if (s[ofs] & bit) {
|
||||||
pix |= (1 << plane);
|
pix |= (1 << plane);
|
||||||
}
|
}
|
||||||
s += planeWidth;
|
s += inWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,39 +27,126 @@
|
||||||
#define PARALLACTION_IFF_H
|
#define PARALLACTION_IFF_H
|
||||||
|
|
||||||
#include "common/stream.h"
|
#include "common/stream.h"
|
||||||
|
#include "common/func.h"
|
||||||
#include "common/iff_container.h" // for IFF chunk names
|
#include "common/iff_container.h" // for IFF chunk names
|
||||||
#include "graphics/iff.h" // for BMHD
|
#include "graphics/iff.h" // for BMHD
|
||||||
|
|
||||||
// this IFF parser code is courtesy of the Kyra engine team ;)
|
|
||||||
|
|
||||||
namespace Parallaction {
|
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 {
|
class IFFParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This private class implements IFF chunk navigation.
|
||||||
|
*/
|
||||||
|
class IFFChunkNav : public Common::ReadStream {
|
||||||
|
protected:
|
||||||
|
Common::ReadStream *_input;
|
||||||
|
uint32 _bytesRead;
|
||||||
public:
|
public:
|
||||||
IFFParser() : _stream(0), _startOffset(0), _endOffset(0) {}
|
Common::IFF_ID id;
|
||||||
IFFParser(Common::SeekableReadStream *stream) : _stream(0), _startOffset(0), _endOffset(0) {
|
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(Common::ReadStream *stream, bool disposeStream = false) : _stream(stream), _disposeStream(stream) {
|
||||||
setInputStream(stream);
|
setInputStream(stream);
|
||||||
}
|
}
|
||||||
~IFFParser() { destroy(); }
|
~IFFParser() {
|
||||||
|
if (_disposeStream) {
|
||||||
|
delete _stream;
|
||||||
|
}
|
||||||
|
_stream = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void setInputStream(Common::SeekableReadStream *stream);
|
/**
|
||||||
|
* Returns the IFF FORM type.
|
||||||
operator bool() const { return (_startOffset != _endOffset) && _stream; }
|
* @return the IFF FORM type of the stream, or 0 if FORM header is not found.
|
||||||
|
*/
|
||||||
uint32 getFORMSize() const;
|
|
||||||
Common::IFF_ID getFORMType() const;
|
Common::IFF_ID getFORMType() const;
|
||||||
|
|
||||||
uint32 getIFFBlockSize(Common::IFF_ID chunk);
|
/**
|
||||||
bool loadIFFBlock(Common::IFF_ID chunk, void *loadTo, uint32 ptrSize);
|
* Returns the size of the data.
|
||||||
Common::SeekableReadStream *getIFFBlockStream(Common::IFF_ID chunkName);
|
* @return the size of the data in file, or -1 if FORM header is not found.
|
||||||
|
*/
|
||||||
|
uint32 getFORMSize() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback type for the parser.
|
||||||
|
*/
|
||||||
|
typedef Common::Functor1< IFFChunk&, bool > IFFCallback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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:
|
private:
|
||||||
void destroy();
|
|
||||||
uint32 moveToIFFBlock(Common::IFF_ID chunkName);
|
|
||||||
|
|
||||||
Common::SeekableReadStream *_stream;
|
|
||||||
uint32 _startOffset;
|
|
||||||
uint32 _endOffset;
|
|
||||||
|
|
||||||
uint32 _formSize;
|
uint32 _formSize;
|
||||||
Common::IFF_ID _formType;
|
Common::IFF_ID _formType;
|
||||||
};
|
};
|
||||||
|
@ -67,35 +154,49 @@ private:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ILBMDecoder {
|
struct ILBMDecoder {
|
||||||
Common::SeekableReadStream *_in;
|
/**
|
||||||
bool _disposeStream;
|
* ILBM header data, necessary for loadBitmap()
|
||||||
|
*/
|
||||||
void planarToChunky(byte *out, uint32 width, byte *in, uint32 planeWidth, uint32 nPlanes, bool packPlanes);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
IFFParser _parser;
|
|
||||||
Graphics::BMHD _header;
|
Graphics::BMHD _header;
|
||||||
bool _hasHeader;
|
|
||||||
uint32 _bodySize;
|
|
||||||
uint32 _paletteSize;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
|
||||||
public:
|
ILBM_1_PLANES = 1, //!< Decode only the first bitplane, don't pack.
|
||||||
ILBMDecoder(Common::SeekableReadStream *input, bool disposeStream = false);
|
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.
|
||||||
|
};
|
||||||
|
|
||||||
virtual ~ILBMDecoder();
|
/**
|
||||||
|
* Fills the _header member from the given stream.
|
||||||
|
*/
|
||||||
|
void loadHeader(Common::ReadStream *stream);
|
||||||
|
|
||||||
uint32 getWidth();
|
/**
|
||||||
uint32 getHeight();
|
* Loads and unpacks the ILBM bitmap data from the stream into the buffer.
|
||||||
uint32 getNumColors();
|
* The functions assumes the buffer is large enough to contain all data.
|
||||||
byte *getPalette();
|
* The caller controls how data should be packed by choosing mode from
|
||||||
|
* the enum above.
|
||||||
|
*/
|
||||||
|
void loadBitmap(uint32 mode, byte *buffer, Common::ReadStream *stream);
|
||||||
|
|
||||||
byte *getBitmap(uint32 numPlanes, bool packPlanes);
|
/**
|
||||||
byte *getBitmap() {
|
* Converts from bitplanar to chunky representation. Intended for internal
|
||||||
assert(_hasHeader);
|
* usage, but you can be (ab)use it from client code if you know what you
|
||||||
return getBitmap(_header.depth, false);
|
* are doing.
|
||||||
}
|
*/
|
||||||
|
void planarToChunky(byte *out, uint32 width, byte *in, uint32 planeWidth, uint32 nPlanes, bool packPlanes);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ MODULE_OBJS := \
|
||||||
debug.o \
|
debug.o \
|
||||||
detection.o \
|
detection.o \
|
||||||
dialogue.o \
|
dialogue.o \
|
||||||
|
disk.o \
|
||||||
disk_br.o \
|
disk_br.o \
|
||||||
disk_ns.o \
|
disk_ns.o \
|
||||||
exec.o \
|
exec.o \
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue