scummvm/engines/parallaction/disk.cpp

1176 lines
25 KiB
C++
Raw Normal View History

2007-03-02 21:50:36 +00:00
/* ScummVM - Scumm Interpreter
* Copyright (C) 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"
2007-03-02 21:50:36 +00:00
#include "parallaction/defs.h"
#include "parallaction/graphics.h"
#include "parallaction/parallaction.h"
#include "parallaction/disk.h"
#include "parallaction/walk.h"
#include "graphics/ilbm.h"
2007-03-02 21:50:36 +00:00
namespace Parallaction {
class RLEStream : public Common::ReadStream {
Common::ReadStream *_input;
byte _rembuf[257];
int32 _wpos;
int32 _rpos;
int32 _toBeRead;
byte* _dst;
int32 _read;
void store(byte b) {
if (_toBeRead > 0) {
*_dst++ = b;
_read++;
_wpos = 0;
_rpos = 0;
} else {
assert(_wpos < 257);
_rembuf[_wpos++] = b;
_rpos = 0;
}
_toBeRead--;
}
void feed() {
int32 len = MIN(_wpos - _rpos, _toBeRead);
if (len == 0) return;
memcpy(_dst, _rembuf + _rpos, len);
_rpos += len;
_read += len;
_toBeRead -= len;
}
void unpack() {
byte byteRun;
byte idx;
uint32 i, j;
while (_toBeRead > 0 && !_input->eos()) {
byteRun = _input->readByte();
if (byteRun <= 127) {
i = byteRun + 1;
for (j = 0; j < i; j++) {
idx = _input->readByte();
store(idx);
}
} else if (byteRun != 128) {
i = (256 - byteRun) + 1;
idx = _input->readByte();
for (j = 0; j < i; j++) {
store(idx);
}
}
}
}
public:
RLEStream(Common::ReadStream *input) : _input(input), _wpos(0), _rpos(0) {
}
~RLEStream() {
}
bool eos() const {
return _input->eos() & (_rpos == _wpos);
}
uint32 read(void *dataPtr, uint32 dataSize) {
_toBeRead = (int32)dataSize;
_dst = (byte*)dataPtr;
_read = 0;
feed();
unpack();
return _read;
}
};
/*
This stream class is just a wrapper around Archive, so
deallocation is not a problem. In fact, this class doesn't
delete its input (Archive) stream.
*/
class DummyArchiveStream : public Common::SeekableReadStream {
Archive *_input;
public:
DummyArchiveStream(Archive &input) : _input(&input) {
}
~DummyArchiveStream() {
// this class exists to provide this empty destructor
}
bool eos() const {
return _input->eos();
}
uint32 read(void* data, uint32 dataSize) {
return _input->read(data, dataSize);
}
uint32 pos() const {
return _input->pos();
}
uint32 size() const {
return _input->size();
}
void seek(int32 offset, int whence) {
_input->seek(offset, whence);
}
};
Disk::Disk(Parallaction *vm) : _vm(vm) {
}
Disk::~Disk() {
}
void Disk::errorFileNotFound(const char *s) {
error("File '%s' not found", s);
}
void Disk::selectArchive(const char *name) {
_resArchive.open(name);
}
void Disk::setLanguage(uint16 language) {
switch (language) {
case 0:
strcpy(_languageDir, "it/");
break;
case 1:
strcpy(_languageDir, "fr/");
break;
case 2:
strcpy(_languageDir, "en/");
break;
case 3:
strcpy(_languageDir, "ge/");
break;
default:
error("unknown language");
}
_languageDir[2] = '\0';
_locArchive.open(_languageDir);
_languageDir[2] = '/';
return;
}
#pragma mark -
DosDisk::DosDisk(Parallaction* vm) : Disk(vm) {
}
DosDisk::~DosDisk() {
}
//
// loads a cnv from an external file
//
Cnv* DosDisk::loadExternalCnv(const char *filename) {
// printf("Gfx::loadExternalCnv(%s)...", filename);
char path[PATH_LEN];
sprintf(path, "%s.cnv", filename);
Common::File stream;
if (!stream.open(path))
errorFileNotFound(path);
uint16 numFrames = stream.readByte();
uint16 width = stream.readByte();
uint16 height = stream.readByte();
uint32 decsize = numFrames * width * height;
byte *data = (byte*)malloc(decsize);
stream.read(data, decsize);
return new Cnv(numFrames, width, height, data);
}
StaticCnv *DosDisk::loadExternalStaticCnv(const char *filename) {
char path[PATH_LEN];
sprintf(path, "%s.cnv", filename);
Common::File stream;
if (!stream.open(path))
errorFileNotFound(path);
StaticCnv *cnv = new StaticCnv;
stream.skip(1);
cnv->_width = stream.readByte();
cnv->_height = stream.readByte();
uint16 size = cnv->_width*cnv->_height;
cnv->_data0 = (byte*)malloc(size);
stream.read(cnv->_data0, size);
return cnv;
}
Cnv* DosDisk::loadCnv(const char *filename) {
// printf("Gfx::loadCnv(%s)\n", filename);
char path[PATH_LEN];
strcpy(path, filename);
if (!_resArchive.openArchivedFile(path)) {
sprintf(path, "%s.pp", filename);
if (!_resArchive.openArchivedFile(path))
errorFileNotFound(path);
}
uint16 numFrames = _resArchive.readByte();
uint16 width = _resArchive.readByte();
uint16 height = _resArchive.readByte();
uint32 decsize = numFrames * width * height;
byte *data = (byte*)malloc(decsize);
RLEStream decoder(&_resArchive);
decoder.read(data, decsize);
return new Cnv(numFrames, width, height, data);
}
Cnv* DosDisk::loadTalk(const char *name) {
2007-03-10 15:02:39 +00:00
const char *ext = strstr(name, ".talk");
2007-03-02 21:50:36 +00:00
if (ext != NULL) {
// npc talk
return loadCnv(name);
2007-03-02 21:50:36 +00:00
}
// character talk
char v20[PATH_LEN];
char *v24 = const_cast<char*>(name);
if (IS_MINI_CHARACTER(v24)) {
v24+=4;
}
2007-03-02 21:50:36 +00:00
if (_engineFlags & kEngineTransformedDonna) {
sprintf(v20, "%stta", v24);
} else {
sprintf(v20, "%stal", v24);
2007-03-02 21:50:36 +00:00
}
return loadExternalCnv(v20);
2007-03-02 21:50:36 +00:00
}
Script* DosDisk::loadLocation(const char *name) {
char archivefile[PATH_LEN];
if (IS_MINI_CHARACTER(_vm->_characterName)) {
sprintf(archivefile, "%s%s", _vm->_characterName+4, _languageDir);
} else {
if (IS_DUMMY_CHARACTER(_vm->_characterName)) strcpy(archivefile, _languageDir);
else {
sprintf(archivefile, "%s%s", _vm->_characterName, _languageDir);
}
}
strcat(archivefile, name);
strcat(archivefile, ".loc");
if (!_locArchive.openArchivedFile(archivefile)) {
sprintf(archivefile, "%s%s.loc", _languageDir, name);
if (!_locArchive.openArchivedFile(archivefile))
errorFileNotFound(name);
}
return new Script(new DummyArchiveStream(_locArchive), true);
}
Script* DosDisk::loadScript(const char* name) {
char vC8[PATH_LEN];
sprintf(vC8, "%s.script", name);
if (!_resArchive.openArchivedFile(vC8))
errorFileNotFound(vC8);
return new Script(new DummyArchiveStream(_resArchive), true);
}
StaticCnv* DosDisk::loadHead(const char* name) {
char path[PATH_LEN];
if (IS_MINI_CHARACTER(name)) {
name += 4;
}
snprintf(path, 8, "%shead", name);
path[8] = '\0';
return loadExternalStaticCnv(path);
}
StaticCnv* DosDisk::loadPointer() {
return loadExternalStaticCnv("pointer");
}
2007-03-02 21:50:36 +00:00
Font* DosDisk::loadFont(const char* name) {
char path[PATH_LEN];
sprintf(path, "%scnv", name);
return createFont(name, loadExternalCnv(path));
}
Cnv* DosDisk::loadObjects(const char *name) {
if (IS_MINI_CHARACTER(name)) {
name += 4;
}
char path[PATH_LEN];
sprintf(path, "%sobj", name);
return loadExternalCnv(path);
}
StaticCnv* DosDisk::loadStatic(const char* name) {
char path[PATH_LEN];
strcpy(path, name);
if (!_resArchive.openArchivedFile(path)) {
sprintf(path, "%s.pp", name);
if (!_resArchive.openArchivedFile(path))
errorFileNotFound(path);
}
StaticCnv* cnv = new StaticCnv;
_resArchive.skip(1);
cnv->_width = _resArchive.readByte();
cnv->_height = _resArchive.readByte();
uint16 size = cnv->_width*cnv->_height;
cnv->_data0 = (byte*)malloc(size);
RLEStream decoder(&_resArchive);
decoder.read(cnv->_data0, size);
return cnv;
}
Cnv* DosDisk::loadFrames(const char* name) {
return loadCnv(name);
}
//
// slides (background images) are stored compressed by scanline in a rle fashion
//
// the uncompressed data must then be unpacked to get:
// * color data [bits 0-5]
// * mask data [bits 6-7] (z buffer)
// * path data [bit 8] (walkable areas)
//
void DosDisk::unpackBackground(Common::ReadStream *stream, byte *screen, byte *mask, byte *path) {
byte b;
uint32 i = 0;
while (!stream->eos()) {
b = stream->readByte();
path[i/8] |= ((b & 0x80) >> 7) << (i & 7);
mask[i/4] |= ((b & 0x60) >> 5) << ((i & 3) << 1);
screen[i] = b & 0x1F;
i++;
}
return;
}
void DosDisk::parseDepths(Common::SeekableReadStream &stream) {
_vm->_gfx->_bgLayers[0] = stream.readByte();
_vm->_gfx->_bgLayers[1] = stream.readByte();
_vm->_gfx->_bgLayers[2] = stream.readByte();
_vm->_gfx->_bgLayers[3] = stream.readByte();
}
void DosDisk::parseBackground(Common::SeekableReadStream &stream) {
stream.read(_vm->_gfx->_palette, BASE_PALETTE_SIZE);
_vm->_gfx->setPalette(_vm->_gfx->_palette);
parseDepths(stream);
for (uint32 _si = 0; _si < 6; _si++) {
_vm->_gfx->_palettefx[_si]._timer = stream.readUint16BE();
_vm->_gfx->_palettefx[_si]._step = stream.readUint16BE();
_vm->_gfx->_palettefx[_si]._flags = stream.readUint16BE();
_vm->_gfx->_palettefx[_si]._first = stream.readByte();
_vm->_gfx->_palettefx[_si]._last = stream.readByte();
}
}
void DosDisk::loadBackground(const char *filename) {
if (!_resArchive.openArchivedFile(filename))
errorFileNotFound(filename);
parseBackground(_resArchive);
byte *bg = (byte*)calloc(1, SCREEN_WIDTH*SCREEN_HEIGHT);
byte *mask = (byte*)calloc(1, SCREENMASK_WIDTH*SCREEN_HEIGHT);
byte *path = (byte*)calloc(1, SCREENPATH_WIDTH*SCREEN_HEIGHT);
RLEStream stream(&_resArchive);
unpackBackground(&stream, bg, mask, path);
_vm->_gfx->setBackground(bg);
_vm->_gfx->setMask(mask);
setPath(path);
free(bg);
free(mask);
free(path);
return;
}
//
// read background path and mask from a file
//
// mask and path are normally combined (via OR) into the background picture itself
// read the comment on the top of this file for more
//
void DosDisk::loadMaskAndPath(const char *name) {
char path[PATH_LEN];
sprintf(path, "%s.msk", name);
if (!_resArchive.openArchivedFile(path))
errorFileNotFound(name);
byte *maskBuf = (byte*)calloc(1, SCREENMASK_WIDTH*SCREEN_HEIGHT);
byte *pathBuf = (byte*)calloc(1, SCREENPATH_WIDTH*SCREEN_HEIGHT);
parseDepths(_resArchive);
_resArchive.read(pathBuf, SCREENPATH_WIDTH*SCREEN_HEIGHT);
_resArchive.read(maskBuf, SCREENMASK_WIDTH*SCREEN_HEIGHT);
_vm->_gfx->setMask(maskBuf);
setPath(pathBuf);
return;
}
void DosDisk::loadSlide(const char *filename) {
char path[PATH_LEN];
sprintf(path, "%s.slide", filename);
loadBackground(path);
}
void DosDisk::loadScenery(const char *name, const char *mask) {
char path[PATH_LEN];
sprintf(path, "%s.dyn", name);
loadBackground(path);
if (mask != NULL) {
// load external masks and paths only for certain locations
loadMaskAndPath(mask);
}
}
Table* DosDisk::loadTable(const char* name) {
char path[PATH_LEN];
sprintf(path, "%s.tab", name);
Common::File stream;
if (!stream.open(path))
errorFileNotFound(path);
Table *t = new Table(100);
fillBuffers(stream);
while (scumm_stricmp(_tokens[0], "ENDTABLE")) {
t->addData(_tokens[0]);
fillBuffers(stream);
}
stream.close();
return t;
}
Common::ReadStream* DosDisk::loadMusic(const char* name) {
char path[PATH_LEN];
sprintf(path, "%s.mid", name);
Common::File *stream = new Common::File;
if (!stream->open(path))
errorFileNotFound(path);
return stream;
}
#pragma mark -
/* the decoder presented here is taken from pplib by Stuart Caie. The
* following statement comes from the original source.
*
* pplib 1.0: a simple PowerPacker decompression and decryption library
* placed in the Public Domain on 2003-09-18 by Stuart Caie.
*/
#define PP_READ_BITS(nbits, var) do { \
bit_cnt = (nbits); (var) = 0; \
while (bits_left < bit_cnt) { \
if (buf < src) return 0; \
bit_buffer |= *--buf << bits_left; \
bits_left += 8; \
} \
bits_left -= bit_cnt; \
while (bit_cnt--) { \
(var) = ((var) << 1) | (bit_buffer & 1); \
bit_buffer >>= 1; \
} \
} while (0)
#define PP_BYTE_OUT(byte) do { \
if (out <= dest) return 0; \
*--out = (byte); written++; \
} while (0)
class PowerPackerStream : public Common::SeekableReadStream {
SeekableReadStream *_stream;
bool _dispose;
private:
int ppDecrunchBuffer(byte *src, byte *dest, uint32 src_len, uint32 dest_len) {
byte *buf, *out, *dest_end, *off_lens, bits_left = 0, bit_cnt;
uint32 bit_buffer = 0, x, todo, offbits, offset, written = 0;
if (src == NULL || dest == NULL) return 0;
/* set up input and output pointers */
off_lens = src; src = &src[4];
buf = &src[src_len];
out = dest_end = &dest[dest_len];
/* skip the first few bits */
PP_READ_BITS(src[src_len + 3], x);
/* while there are input bits left */
while (written < dest_len) {
PP_READ_BITS(1, x);
if (x == 0) {
/* bit==0: literal, then match. bit==1: just match */
todo = 1; do { PP_READ_BITS(2, x); todo += x; } while (x == 3);
while (todo--) { PP_READ_BITS(8, x); PP_BYTE_OUT(x); }
/* should we end decoding on a literal, break out of the main loop */
if (written == dest_len) break;
}
/* match: read 2 bits for initial offset bitlength / match length */
PP_READ_BITS(2, x);
offbits = off_lens[x];
todo = x+2;
if (x == 3) {
PP_READ_BITS(1, x);
if (x == 0) offbits = 7;
PP_READ_BITS(offbits, offset);
do { PP_READ_BITS(3, x); todo += x; } while (x == 7);
}
else {
PP_READ_BITS(offbits, offset);
}
if (&out[offset] >= dest_end) return 0; /* match_overflow */
while (todo--) { x = out[offset]; PP_BYTE_OUT(x); }
}
/* all output bytes written without error */
return 1;
}
uint16 getCrunchType(uint32 signature) {
byte eff;
switch (signature) {
case 0x50503230: /* PP20 */
eff = 4;
break;
case 0x50504C53: /* PPLS */
error("PPLS crunched files are not supported");
eff = 8;
break;
case 0x50583230: /* PX20 */
error("PX20 crunched files are not supported");
eff = 6;
break;
default:
eff = 0;
}
return eff;
}
public:
PowerPackerStream(Common::SeekableReadStream &stream) {
_dispose = false;
uint32 signature = stream.readUint32BE();
if (getCrunchType(signature) == 0) {
stream.seek(0, SEEK_SET);
_stream = &stream;
return;
}
stream.seek(4, SEEK_END);
uint32 decrlen = stream.readUint32BE() >> 8;
byte *dest = (byte*)malloc(decrlen);
uint32 crlen = stream.size() - 4;
byte *src = (byte*)malloc(crlen);
stream.seek(4, SEEK_SET);
stream.read(src, crlen);
ppDecrunchBuffer(src, dest, crlen-8, decrlen);
free(src);
_stream = new Common::MemoryReadStream(dest, decrlen, true);
_dispose = true;
}
~PowerPackerStream() {
if (_dispose) delete _stream;
}
uint32 size() const {
return _stream->size();
}
uint32 pos() const {
return _stream->pos();
}
bool eos() const {
return _stream->eos();
}
void seek(int32 offs, int whence = SEEK_SET) {
_stream->seek(offs, whence);
}
uint32 read(void *dataPtr, uint32 dataSize) {
return _stream->read(dataPtr, dataSize);
}
};
AmigaDisk::AmigaDisk(Parallaction *vm) : Disk(vm) {
}
AmigaDisk::~AmigaDisk() {
}
#define NUM_PLANES 5
// FIXME: no mask is loaded
void AmigaDisk::unpackBitmap(byte *dst, byte *src, uint16 numFrames, uint16 planeSize) {
byte s0, s1, s2, s3, s4, mask, t0, t1, t2, t3, t4;
for (uint32 i = 0; i < numFrames; i++) {
for (uint32 j = 0; j < planeSize; j++) {
s0 = src[j];
s1 = src[j+planeSize];
s2 = src[j+planeSize*2];
s3 = src[j+planeSize*3];
s4 = src[j+planeSize*4];
for (uint32 k = 0; k < 8; k++) {
mask = 1 << (7 - k);
t0 = (s0 & mask ? 1 << 0 : 0);
t1 = (s1 & mask ? 1 << 1 : 0);
t2 = (s2 & mask ? 1 << 2 : 0);
t3 = (s3 & mask ? 1 << 3 : 0);
t4 = (s4 & mask ? 1 << 4 : 0);
*dst++ = t0 | t1 | t2 | t3 | t4;
}
}
src += planeSize * NUM_PLANES;
}
}
StaticCnv* AmigaDisk::makeStaticCnv(Common::SeekableReadStream &stream) {
stream.skip(1);
uint16 width = stream.readByte();
uint16 height = stream.readByte();
assert((width & 7) == 0);
byte bytesPerPlane = width / 8;
uint32 rawsize = bytesPerPlane * NUM_PLANES * height;
byte *buf = (byte*)malloc(rawsize);
stream.read(buf, rawsize);
uint32 decsize = width * height;
byte *data = (byte*)calloc(decsize, 1);
unpackBitmap(data, buf, 1, height * bytesPerPlane);
free(buf);
StaticCnv *cnv = new StaticCnv();
cnv->_width = width;
cnv->_height = height;
cnv->_data0 = data;
cnv->_data1 = NULL;
return cnv;
}
Cnv* AmigaDisk::makeCnv(Common::SeekableReadStream &stream) {
uint16 numFrames = stream.readByte();
uint16 width = stream.readByte();
uint16 height = stream.readByte();
assert((width & 7) == 0);
byte bytesPerPlane = width / 8;
uint32 rawsize = numFrames * bytesPerPlane * NUM_PLANES * height;
byte *buf = (byte*)malloc(rawsize);
stream.read(buf, rawsize);
uint32 decsize = numFrames * width * height;
byte *data = (byte*)calloc(decsize, 1);
unpackBitmap(data, buf, numFrames, height * bytesPerPlane);
free(buf);
return new Cnv(numFrames, width, height, data);
}
#undef NUM_PLANES
Script* AmigaDisk::loadLocation(const char *name) {
debugC(1, kDebugDisk, "AmigaDisk::loadLocation '%s'", name);
char path[PATH_LEN];
sprintf(path, "%s%s%s.loc.pp", _vm->_characterName, _languageDir, name);
if (!_locArchive.openArchivedFile(path)) {
sprintf(path, "%s%s.loc.pp", _languageDir, name);
if (!_locArchive.openArchivedFile(path)) {
errorFileNotFound(name);
}
}
return new Script(new PowerPackerStream(_locArchive), true);
}
Script* AmigaDisk::loadScript(const char* name) {
debugC(1, kDebugDisk, "AmigaDisk::loadScript '%s'", name);
char vC8[PATH_LEN];
sprintf(vC8, "%s.script", name);
if (!_resArchive.openArchivedFile(vC8))
errorFileNotFound(vC8);
return new Script(new DummyArchiveStream(_resArchive), true);
}
Cnv* AmigaDisk::loadTalk(const char *name) {
debugC(1, kDebugDisk, "AmigaDisk::loadTalk '%s'", name);
Common::SeekableReadStream *s;
char path[PATH_LEN];
sprintf(path, "%s.talk", name);
s = openArchivedFile(path, false);
if (s == NULL) {
s = openArchivedFile(name, true);
}
Cnv *cnv = makeCnv(*s);
delete s;
return cnv;
}
Cnv* AmigaDisk::loadObjects(const char *name) {
debugC(1, kDebugDisk, "AmigaDisk::loadObjects");
char path[PATH_LEN];
sprintf(path, "%s.objs", name);
Common::SeekableReadStream *s = openArchivedFile(path, true);
Cnv *cnv = makeCnv(*s);
delete s;
return cnv;
}
StaticCnv* AmigaDisk::loadPointer() {
debugC(1, kDebugDisk, "AmigaDisk::loadPointer");
Common::File stream;
if (!stream.open("pointer"))
errorFileNotFound("pointer");
return makeStaticCnv(stream);
}
StaticCnv* AmigaDisk::loadHead(const char* name) {
debugC(1, kDebugDisk, "AmigaDisk::loadHead '%s'", name);
char path[PATH_LEN];
sprintf(path, "%s.head", name);
Common::SeekableReadStream *s = openArchivedFile(path, true);
StaticCnv *cnv = makeStaticCnv(*s);
delete s;
return cnv;
}
Font* AmigaDisk::loadFont(const char* name) {
debugC(1, kDebugDisk, "AmigaDisk::loadFont '%s'", name);
char path[PATH_LEN];
sprintf(path, "%sfont", name);
if (!_resArchive.openArchivedFile(path))
errorFileNotFound(path);
return createFont(name, _resArchive);
}
StaticCnv* AmigaDisk::loadStatic(const char* name) {
debugC(1, kDebugDisk, "AmigaDisk::loadStatic '%s'", name);
Common::SeekableReadStream *s = openArchivedFile(name, true);
StaticCnv *cnv = makeStaticCnv(*s);
delete s;
return cnv;
}
Common::SeekableReadStream *AmigaDisk::openArchivedFile(const char* name, bool errorOnFileNotFound) {
if (_resArchive.openArchivedFile(name)) {
return new DummyArchiveStream(_resArchive);
}
char path[PATH_LEN];
sprintf(path, "%s.pp", name);
if (_resArchive.openArchivedFile(path)) {
return new PowerPackerStream(_resArchive);
}
sprintf(path, "%s.dd", name);
if (_resArchive.openArchivedFile(path)) {
return new PowerPackerStream(_resArchive);
}
if (errorOnFileNotFound)
errorFileNotFound(name);
return NULL;
}
Cnv* AmigaDisk::loadFrames(const char* name) {
debugC(1, kDebugDisk, "AmigaDisk::loadFrames '%s'", name);
if (IS_MINI_CHARACTER(name))
return NULL;
Common::SeekableReadStream *s = openArchivedFile(name, true);
Cnv *cnv = makeCnv(*s);
delete s;
return cnv;
}
void AmigaDisk::loadSlide(const char *name) {
debugC(1, kDebugDisk, "AmigaDisk::loadSlide '%s'", name);
loadBackground(name);
return;
}
// FIXME: mask values are not computed correctly for level 1 and 2
void buildMask(byte* buf) {
byte mask1[16] = { 0, 0x80, 0x20, 0xA0, 8, 0x88, 0x28, 0xA8, 2, 0x82, 0x22, 0xA2, 0xA, 0x8A, 0x2A, 0xAA };
byte mask0[16] = { 0, 0x40, 0x10, 0x50, 4, 0x44, 0x14, 0x54, 1, 0x41, 0x11, 0x51, 0x5, 0x45, 0x15, 0x55 };
byte plane0[40];
byte plane1[40];
for (uint32 i = 0; i < 200; i++) {
memcpy(plane0, buf, 40);
memcpy(plane1, buf+40, 40);
for (uint32 j = 0; j < 40; j++) {
*buf++ = mask0[(plane0[j] & 0xF0) >> 4] | mask1[(plane1[j] & 0xF0) >> 4];
*buf++ = mask0[plane0[j] & 0xF] | mask1[plane1[j] & 0xF];
}
}
}
class BackgroundDecoder : public Graphics::ILBMDecoder {
PaletteFxRange *_range;
uint32 _i;
protected:
void readCRNG() {
_range[_i]._timer = _chunk.readUint16();
_range[_i]._step = _chunk.readUint16();
_range[_i]._flags = _chunk.readUint16();
_range[_i]._first = _chunk.readByte();
_range[_i]._last = _chunk.readByte();
_i++;
}
public:
BackgroundDecoder(Common::ReadStream &input, PaletteFxRange *range) : ILBMDecoder(input), _range(range), _i(0) {
}
uint32 getNumRanges() {
return _i;
}
};
void AmigaDisk::loadBackground(const char *name) {
Common::SeekableReadStream *s = openArchivedFile(name, true);
BackgroundDecoder decoder(*s, _vm->_gfx->_palettefx);
Graphics::Surface surf;
byte *pal;
decoder.decode(surf, pal);
for (uint32 i = 0; i < BASE_PALETTE_COLORS * 3; i++)
_vm->_gfx->_palette[i] = pal[i] >> 2;
free(pal);
_vm->_gfx->setPalette(_vm->_gfx->_palette);
_vm->_gfx->setBackground(static_cast<byte*>(surf.pixels));
surf.free();
delete s;
return;
}
void AmigaDisk::loadMask(const char *name) {
char path[PATH_LEN];
sprintf(path, "%s.mask", name);
Common::SeekableReadStream *s = openArchivedFile(path, true);
s->seek(0x30, SEEK_SET);
byte r, g, b;
for (uint i = 0; i < 4; i++) {
r = s->readByte();
g = s->readByte();
b = s->readByte();
_vm->_gfx->_bgLayers[i] = (((r << 4) & 0xF00) | (g & 0xF0) | (b >> 4)) & 0xFF;
// printf("rgb = (%x, %x, %x) -> %x\n", r, g, b, _vm->_gfx->_bgLayers[i]);
}
s->seek(0x126, SEEK_SET); // HACK: skipping IFF/ILBM header should be done by analysis, not magic
RLEStream stream(s);
byte *buf = (byte*)malloc(SCREENMASK_WIDTH*SCREEN_HEIGHT);
stream.read(buf, SCREENMASK_WIDTH*SCREEN_HEIGHT);
buildMask(buf);
_vm->_gfx->setMask(buf);
free(buf);
delete s;
return;
}
void AmigaDisk::loadPath(const char *name) {
char path[PATH_LEN];
sprintf(path, "%s.path", name);
Common::SeekableReadStream *s = openArchivedFile(path, false);
if (s == NULL)
return; // no errors if missing path files: not every location has one
s->seek(0x120, SEEK_SET); // HACK: skipping IFF/ILBM header should be done by analysis, not magic
RLEStream stream(s);
byte *buf = (byte*)malloc(SCREENPATH_WIDTH*SCREEN_HEIGHT);
stream.read(buf, SCREENPATH_WIDTH*SCREEN_HEIGHT);
setPath(buf);
free(buf);
delete s;
return;
}
void AmigaDisk::loadScenery(const char* background, const char* mask) {
debugC(1, kDebugDisk, "AmigaDisk::loadScenery '%s', '%s'", background, mask);
char path[PATH_LEN];
sprintf(path, "%s.bkgnd", background);
loadBackground(path);
loadMask(background);
loadPath(background);
return;
}
Table* AmigaDisk::loadTable(const char* name) {
debugC(1, kDebugDisk, "AmigaDisk::loadTable '%s'", name);
char path[PATH_LEN];
sprintf(path, "%s.table", name);
bool dispose = false;
Common::SeekableReadStream *stream;
if (!scumm_stricmp(name, "global")) {
Common::File *s = new Common::File;
if (!s->open(path))
errorFileNotFound(path);
dispose = true;
stream = s;
} else {
if (!_resArchive.openArchivedFile(path))
errorFileNotFound(path);
stream = &_resArchive;
}
Table *t = new Table(100);
fillBuffers(*stream);
while (scumm_stricmp(_tokens[0], "ENDTABLE")) {
t->addData(_tokens[0]);
fillBuffers(*stream);
}
if (dispose)
delete stream;
return t;
}
Common::ReadStream* AmigaDisk::loadMusic(const char* name) {
return openArchivedFile(name);
}
2007-03-02 21:50:36 +00:00
} // namespace Parallaction