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