mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-04 18:06:26 +00:00
168 lines
4.2 KiB
C++
168 lines
4.2 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "glk/zcode/pics_decoder.h"
|
|
#include "glk/zcode/pics.h"
|
|
#include "common/memstream.h"
|
|
|
|
namespace Glk {
|
|
namespace ZCode {
|
|
|
|
#define MAX_BIT 512 /* Must be less than or equal to CODE_TABLE_SIZE */
|
|
#define CODE_SIZE 8
|
|
#define CODE_TABLE_SIZE 4096
|
|
#define PREFIX 0
|
|
#define PIXEL 1
|
|
|
|
/**
|
|
* Support class used for picture decompression
|
|
*/
|
|
class Compress {
|
|
private:
|
|
byte _codeBuffer[CODE_TABLE_SIZE];
|
|
public:
|
|
short _nextCode;
|
|
short _sLen;
|
|
short _sPtr;
|
|
short _tLen;
|
|
short _tPtr;
|
|
|
|
Compress() : _nextCode(0), _sLen(0), _sPtr(0), _tLen(0), _tPtr(0) {}
|
|
|
|
/**
|
|
* Read a code
|
|
*/
|
|
short readCode(Common::ReadStream &src);
|
|
};
|
|
|
|
static short MASK[16] = {
|
|
0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f,
|
|
0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff
|
|
};
|
|
|
|
short Compress::readCode(Common::ReadStream &src) {
|
|
short code, bsize, tlen, tptr;
|
|
|
|
code = 0;
|
|
tlen = _tLen;
|
|
tptr = 0;
|
|
|
|
while (tlen) {
|
|
if (_sLen == 0) {
|
|
if ((_sLen = src.read(_codeBuffer, MAX_BIT)) == 0) {
|
|
error("fread");
|
|
}
|
|
_sLen *= 8;
|
|
_sPtr = 0;
|
|
}
|
|
bsize = ((_sPtr + 8) & ~7) - _sPtr;
|
|
bsize = (tlen > bsize) ? bsize : tlen;
|
|
code |= (((uint)_codeBuffer[_sPtr >> 3] >> (_sPtr & 7)) & MASK[bsize]) << tptr;
|
|
|
|
tlen -= bsize;
|
|
tptr += bsize;
|
|
_sLen -= bsize;
|
|
_sPtr += bsize;
|
|
}
|
|
|
|
if ((_nextCode == MASK[_tLen]) && (_tLen < 12))
|
|
_tLen++;
|
|
|
|
return code;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
PictureDecoder::PictureDecoder() {
|
|
_tableVal = new byte[3 * 3840];
|
|
_tableRef = (uint16 *)(_tableVal + 3840);
|
|
}
|
|
|
|
PictureDecoder::~PictureDecoder() {
|
|
delete[] _tableVal;
|
|
}
|
|
|
|
Common::SeekableReadStream *PictureDecoder::decode(Common::ReadStream &src, uint flags,
|
|
const Common::Array<byte> &palette, uint display, size_t width, size_t height) {
|
|
Common::MemoryWriteStreamDynamic out(DisposeAfterUse::NO);
|
|
short code_table[CODE_TABLE_SIZE][2];
|
|
byte buffer[CODE_TABLE_SIZE];
|
|
|
|
// Write out dimensions
|
|
out.writeUint16LE(width);
|
|
out.writeUint16LE(height);
|
|
|
|
// Write out palette
|
|
out.writeUint16LE(palette.size() / 3 + 2);
|
|
for (int idx = 0; idx < 6; ++idx)
|
|
out.writeByte((idx < 3) ? 0x77 : 0);
|
|
if (!palette.empty())
|
|
out.write(&palette[0], palette.size());
|
|
|
|
byte transparent = 0xff;
|
|
if (flags & 1)
|
|
transparent = flags >> 12;
|
|
out.writeByte(transparent);
|
|
|
|
int i;
|
|
short code, old = 0, first, clear_code;
|
|
Compress comp;
|
|
|
|
clear_code = 1 << CODE_SIZE;
|
|
comp._nextCode = clear_code + 2;
|
|
comp._tLen = CODE_SIZE + 1;
|
|
comp._tPtr = 0;
|
|
|
|
for (i = 0; i < CODE_TABLE_SIZE; i++) {
|
|
code_table[i][PREFIX] = CODE_TABLE_SIZE;
|
|
code_table[i][PIXEL] = i;
|
|
}
|
|
|
|
for (;;) {
|
|
if ((code = comp.readCode(src)) == (clear_code + 1))
|
|
break;
|
|
if (code == clear_code) {
|
|
comp._tLen = CODE_SIZE + 1;
|
|
comp._nextCode = clear_code + 2;
|
|
code = comp.readCode(src);
|
|
} else {
|
|
first = (code == comp._nextCode) ? old : code;
|
|
while (code_table[first][PREFIX] != CODE_TABLE_SIZE)
|
|
first = code_table[first][PREFIX];
|
|
code_table[comp._nextCode][PREFIX] = old;
|
|
code_table[comp._nextCode++][PIXEL] = code_table[first][PIXEL];
|
|
}
|
|
old = code;
|
|
i = 0;
|
|
do
|
|
buffer[i++] = (unsigned char)code_table[code][PIXEL];
|
|
while ((code = code_table[code][PREFIX]) != CODE_TABLE_SIZE);
|
|
do
|
|
out.writeByte(buffer[--i]);
|
|
while (i > 0);
|
|
}
|
|
|
|
return new Common::MemoryReadStream(out.getData(), out.size(), DisposeAfterUse::YES);
|
|
}
|
|
|
|
} // End of namespace ZCode
|
|
} // End of namespace Glk
|