aboutsummaryrefslogtreecommitdiff
path: root/engines/glk/frotz/pics_decoder.cpp
blob: dba1335295208313d3bea2463c1876af77b84a1a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
/* 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 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.
 *
 */

#include "glk/frotz/pics_decoder.h"
#include "glk/frotz/pics.h"
#include "common/memstream.h"

namespace Glk {
namespace Frotz {

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) {
	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;

	/*
	 * Write out dimensions of image
	 */
	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);
	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;
	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;

	prev_code = code;

	while (code >= 0) {
		buf[bufpos++] = _tableVal[code];
		code = (short) _tableRef[code];
	}

	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
			}
		}
	}

	/* 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;
}

} // End of namespace Frotz
} // End of namespace Glk