aboutsummaryrefslogtreecommitdiff
path: root/engines/glk/frotz
diff options
context:
space:
mode:
authorPaul Gilbert2019-01-05 16:12:58 -0800
committerPaul Gilbert2019-01-05 16:12:58 -0800
commitbde504281311953bd99db087471b798da39ed143 (patch)
tree490b0191f9886ac614c41b1e29dbcde1bf604094 /engines/glk/frotz
parentb28ac82fcba4ff9aed2690428311166df4915d7e (diff)
downloadscummvm-rg350-bde504281311953bd99db087471b798da39ed143.tar.gz
scummvm-rg350-bde504281311953bd99db087471b798da39ed143.tar.bz2
scummvm-rg350-bde504281311953bd99db087471b798da39ed143.zip
GLK: FROTZ: Fix decoding of MG1 graphics
The prior code was based on the Frotz decoder, which was partially written in PC assembly, so was hard to represent. This new version uses code from the ztools pix2gif code
Diffstat (limited to 'engines/glk/frotz')
-rw-r--r--engines/glk/frotz/pics_decoder.cpp299
1 files changed, 105 insertions, 194 deletions
diff --git a/engines/glk/frotz/pics_decoder.cpp b/engines/glk/frotz/pics_decoder.cpp
index dba1335295..73032df0d8 100644
--- a/engines/glk/frotz/pics_decoder.cpp
+++ b/engines/glk/frotz/pics_decoder.cpp
@@ -27,6 +27,71 @@
namespace Glk {
namespace Frotz {
+#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);
@@ -38,219 +103,65 @@ PictureDecoder::~PictureDecoder() {
Common::SeekableReadStream *PictureDecoder::decode(Common::ReadStream &src, uint flags,
const Common::Array<byte> &palette, uint display, size_t width, size_t height) {
- static const int raise_bits[4] = { 0x0100, 0x0300, 0x0700, 0x0000 };
Common::MemoryWriteStreamDynamic out(DisposeAfterUse::NO);
- byte buf[512];
- byte transparent;
- int colour_shift = 0;
- int first_colour = 0;
- int code, prev_code = 0;
- int next_entry;
- int bits_per_code;
- int bits_shift;
- int bits;
- int bufpos = 0;
+ short code_table[CODE_TABLE_SIZE][2];
+ byte buffer[CODE_TABLE_SIZE];
- /*
- * Write out dimensions of image
- */
+ // Write out dimensions
out.writeUint16LE(width);
out.writeUint16LE(height);
- /* Set up the color mapping. This is only used for MCGA pictures; the colour
- * map affects every picture on the screen. The first colour to be defined is
- * colour 2. Every map defines up to 14 colours (colour 2 to 15). These colours
- * are not related to the standard Z-machine colour scheme which remains unchanged.
- * (This is based on the Amiga interpreter which had to work with 16 colours.
- * Colours 0 and 1 were used for text; changing the text colours actually changed
- * palette entries 0 and 1. This interface uses the same trick in Amiga mode.)
- */
-
- switch (display) {
- case kCGA:
- colour_shift = -2;
- break;
- case kEGA:
- colour_shift = 0;
- break;
- case kMCGA:
- colour_shift = 32;
- first_colour = 34;
- break;
- case kAmiga:
- colour_shift = -1;
- first_colour = 65;
- break;
- default:
- error("Unsupported mode");
- break;
- }
-
- // Note: we don't actually use paletted indexes, so adjust colour_shift
- // relative to first_colour
- colour_shift -= first_colour;
-
- out.writeUint16LE(palette.size() / 3);
+ // Write out palette
+ out.writeUint16LE(palette.size() / 3 + 2);
+ for (int idx = 0; idx < 6; ++idx)
+ out.writeByte(0);
if (!palette.empty())
out.write(&palette[0], palette.size());
- /* Bit 0 of "flags" indicates that the picture uses a transparent colour,
- * the top four bits tell us which colour it is. For CGA and MCGA pictures
- * this is always 0; for EGA pictures it can be any colour between 0 and 15.
- */
- transparent = 0xff;
+ byte transparent = 0xff;
if (flags & 1)
transparent = flags >> 12;
out.writeByte(transparent);
- /* The uncompressed picture is a long sequence of bytes. Every byte holds
- * the colour of a pixel, starting at the top left, stopping at the bottom right.
- * We keep track of our position in the current line. (There is a special case:
- * CGA pictures with no transparent colour are stored as bit patterns, i.e.
- * every byte holds the pattern for eight pixels. A pixel must be white if the
- * corresponding bit is set, otherwise it must be black.)
- */
-// current_x = 1 + width;
-// current_y = 1 - 1;
-
- /* The compressed picture is a stream of bits. We read the file byte-wise,
- * storing the current byte in the variable "bits". Several bits make one code;
- * the variable "bits_shift" helps us to build the next code.
- */
- bits_shift = 0;
- bits = 0;
-
-reset_table:
- /* Clear the table. We use a table of 3840 entries. Each entry consists of both
- * a value and a reference to another table entry. Following these references
- * we get a sequence of values. At the start of decompression all table entries
- * are undefined. Later we see how entries are set and used.
- */
- next_entry = 1;
-
- /* At the start of decompression 9 bits make one code; during the process this can
- * rise to 12 bits per code. 9 bits are sufficient to address both 256 literal values
- * and 256 table entries; 12 bits are sufficient to address both 256 literal values
- * and all 3840 table entries. The number of bits per code rises with the number of
- * table entries. When the table is cleared, the number of bits per code drops back to 9.
- */
- bits_per_code = 9;
-
-next_code:
-
- /* Read the next code from the graphics file. This requires some confusing bit operations.
- * Note that low bits always come first. Usually there are a few bits left over from
- * the previous code; these bits must be used before further bits are read from the
- * graphics file.
- */
- code = bits >> (8 - bits_shift);
-
- do {
- bits = src.readByte();
- code |= bits << bits_shift;
-
- bits_shift += 8;
- } while (bits_shift < bits_per_code);
-
- bits_shift -= bits_per_code;
-
- code &= 0xfff >> (12 - bits_per_code);
-
- /* There are two codes with a special meaning. The first one is 256 which clears
- * the table and sets the number of bits per code to 9. (This is necessary when
- * the table is full.) The second one is 257 which marks the end of the picture.
- * For the sake of efficiency, we drecement the code by 256.
- */
- code -= 256;
-
- if (code == 0)
- goto reset_table;
- if (code == 1) {
- bool t[256];
- // *******DEBUG*******
- Common::fill(&t[0], &t[256], false);
- for (uint idx = 0; idx < out.size(); ++idx)
- t[*((byte *)out.getData() + idx)] = true;
-
- return new Common::MemoryReadStream(out.getData(), out.size(), DisposeAfterUse::YES);
- }
-
- /* Codes from 0 to 255 are literals, i.e. they represent a plain byte value.
- * Codes from 258 onwards are references to table entries, i.e. they represent
- * a sequence of byte values (see the remarks on the table above). This means
- * that for each code one or several byte values are added to the decompressed
- * picture. But there is yet more work to do: Every time we read a code one
- * table entry is set. As we said above, a table entry consist of both a value
- * and a reference to another table entry. If the current code is a literal,
- * then the value has to be set to this literal; but if the code refers to a
- * sequence of byte values, then the value has to be set to the last byte of
- * this sequence. In any case, the reference is set to the previous code.
- * Finally, one should be aware that a code may legally refer to the table entry
- * which is currently being set. This requires some extra care.
- */
- _tableRef[next_entry] = prev_code;
+ int i;
+ short code, old = 0, first, clear_code;
+ Compress comp;
- prev_code = code;
+ clear_code = 1 << CODE_SIZE;
+ comp._nextCode = clear_code + 2;
+ comp._tLen = CODE_SIZE + 1;
+ comp._tPtr = 0;
- while (code >= 0) {
- buf[bufpos++] = _tableVal[code];
- code = (short) _tableRef[code];
+ for (i = 0; i < CODE_TABLE_SIZE; i++) {
+ code_table[i][PREFIX] = CODE_TABLE_SIZE;
+ code_table[i][PIXEL] = i;
}
- if (next_entry == prev_code)
- buf[0] = code;
-
- _tableVal[next_entry] = code;
-
- /* The number of bits per code is incremented when the current number of bits
- * no longer suffices to address all defined table entries; but in any case
- * the number of bits may never be greater than 12.
- */
- next_entry++;
-
- if (next_entry == raise_bits[bits_per_code - 9])
- bits_per_code++;
-
-reverse_buffer:
- /* Output the sequence of byte values (pixels). The order of the sequence
- * must be reversed. (This is why we have stored the sequence in a buffer;
- * experiments show that a buffer of 512 bytes suffices.)
- *
- * Either add a single pixel or a pattern of eight bits (b/w CGA pictures without
- * a transparent colour) to the current line. Increment our position by 1 or 8
- * respectively. The pixel may have to be painted several times if the scaling
- * factor is greater than one.
- */
- if (display == kCGA && transparent == 0xff) {
- // TODO
- } else {
- byte v = code;
-
- if (v != transparent) {
- v += colour_shift;
-
- if (display != kMCGA) {
- // TODO
- } else {
- // position shift
- }
-
- out.writeByte(v);
-
- if (display == kAmiga) {
- // TODO
- }
+ 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);
}
- /* If there are no more values in the buffer then read the next code from the file.
- * Otherwise fetch the next byte value from the buffer and continue outputing the picture.
- */
- if (bufpos == 0)
- goto next_code;
-
- code = (code & ~0xff) | buf[--bufpos];
- goto reverse_buffer;
+ return new Common::MemoryReadStream(out.getData(), out.size(), DisposeAfterUse::YES);
}
} // End of namespace Frotz