1 /* ResidualVM - A 3D game interpreter
2  *
3  * ResidualVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 
24 #include "common/endian.h"
25 #include "common/util.h"
26 #include "common/textconsole.h"
27 
28 #include "engines/grim/movie/codecs/blocky8.h"
29 
30 namespace Grim {
31 
32 #if defined(SYSTEM_NEED_ALIGNMENT)
33 
34 #define COPY_4X1_LINE(dst, src)			\
35 	do {					\
36 		(dst)[0] = (src)[0];	\
37 		(dst)[1] = (src)[1];	\
38 		(dst)[2] = (src)[2];	\
39 		(dst)[3] = (src)[3];	\
40 	} while (0)
41 
42 #define COPY_2X1_LINE(dst, src)			\
43 	do {					\
44 		(dst)[0] = (src)[0];	\
45 		(dst)[1] = (src)[1];	\
46 	} while (0)
47 
48 
49 #else /* SYSTEM_NEED_ALIGNMENT */
50 
51 #define COPY_4X1_LINE(dst, src)			\
52 	*(uint32 *)(dst) = *(const uint32 *)(src)
53 
54 #define COPY_2X1_LINE(dst, src)			\
55 	*(uint16 *)(dst) = *(const uint16 *)(src)
56 
57 #endif
58 
59 #define FILL_4X1_LINE(dst, val)			\
60 	do {					\
61 		(dst)[0] = val;	\
62 		(dst)[1] = val;	\
63 		(dst)[2] = val;	\
64 		(dst)[3] = val;	\
65 	} while (0)
66 
67 #define FILL_2X1_LINE(dst, val)			\
68 	do {					\
69 		(dst)[0] = val;	\
70 		(dst)[1] = val;	\
71 	} while (0)
72 
73 static const int8 blocky8_table_small1[] = {
74   0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1,
75 };
76 
77 static const int8 blocky8_table_small2[] = {
78   0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2,
79 };
80 
81 static const int8 blocky8_table_big1[] = {
82   0, 2, 5, 7, 7, 7, 7, 7, 7, 5, 2, 0, 0, 0, 0, 0,
83 };
84 
85 static const int8 blocky8_table_big2[] = {
86   0, 0, 0, 0, 1, 3, 4, 6, 7, 7, 7, 7, 6, 4, 3, 1,
87 };
88 
89 static const int8 blocky8_table[] = {
90 	  0,   0,  -1, -43,   6, -43,  -9, -42,  13, -41,
91 	-16, -40,  19, -39, -23, -36,  26, -34,  -2, -33,
92 	  4, -33, -29, -32,  -9, -32,  11, -31, -16, -29,
93 	 32, -29,  18, -28, -34, -26, -22, -25,  -1, -25,
94 	  3, -25,  -7, -24,   8, -24,  24, -23,  36, -23,
95 	-12, -22,  13, -21, -38, -20,   0, -20, -27, -19,
96 	 -4, -19,   4, -19, -17, -18,  -8, -17,   8, -17,
97 	 18, -17,  28, -17,  39, -17, -12, -15,  12, -15,
98 	-21, -14,  -1, -14,   1, -14, -41, -13,  -5, -13,
99 	  5, -13,  21, -13, -31, -12, -15, -11,  -8, -11,
100 	  8, -11,  15, -11,  -2, -10,   1, -10,  31, -10,
101 	-23,  -9, -11,  -9,  -5,  -9,   4,  -9,  11,  -9,
102 	 42,  -9,   6,  -8,  24,  -8, -18,  -7,  -7,  -7,
103 	 -3,  -7,  -1,  -7,   2,  -7,  18,  -7, -43,  -6,
104 	-13,  -6,  -4,  -6,   4,  -6,   8,  -6, -33,  -5,
105 	 -9,  -5,  -2,  -5,   0,  -5,   2,  -5,   5,  -5,
106 	 13,  -5, -25,  -4,  -6,  -4,  -3,  -4,   3,  -4,
107 	  9,  -4, -19,  -3,  -7,  -3,  -4,  -3,  -2,  -3,
108 	 -1,  -3,   0,  -3,   1,  -3,   2,  -3,   4,  -3,
109 	  6,  -3,  33,  -3, -14,  -2, -10,  -2,  -5,  -2,
110 	 -3,  -2,  -2,  -2,  -1,  -2,   0,  -2,   1,  -2,
111 	  2,  -2,   3,  -2,   5,  -2,   7,  -2,  14,  -2,
112 	 19,  -2,  25,  -2,  43,  -2,  -7,  -1,  -3,  -1,
113 	 -2,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,
114 	  3,  -1,  10,  -1,  -5,   0,  -3,   0,  -2,   0,
115 	 -1,   0,   1,   0,   2,   0,   3,   0,   5,   0,
116 	  7,   0, -10,   1,  -7,   1,  -3,   1,  -2,   1,
117 	 -1,   1,   0,   1,   1,   1,   2,   1,   3,   1,
118 	-43,   2, -25,   2, -19,   2, -14,   2,  -5,   2,
119 	 -3,   2,  -2,   2,  -1,   2,   0,   2,   1,   2,
120 	  2,   2,   3,   2,   5,   2,   7,   2,  10,   2,
121 	 14,   2, -33,   3,  -6,   3,  -4,   3,  -2,   3,
122 	 -1,   3,   0,   3,   1,   3,   2,   3,   4,   3,
123 	 19,   3,  -9,   4,  -3,   4,   3,   4,   7,   4,
124 	 25,   4, -13,   5,  -5,   5,  -2,   5,   0,   5,
125 	  2,   5,   5,   5,   9,   5,  33,   5,  -8,   6,
126 	 -4,   6,   4,   6,  13,   6,  43,   6, -18,   7,
127 	 -2,   7,   0,   7,   2,   7,   7,   7,  18,   7,
128 	-24,   8,  -6,   8, -42,   9, -11,   9,  -4,   9,
129 	  5,   9,  11,   9,  23,   9, -31,  10,  -1,  10,
130 	  2,  10, -15,  11,  -8,  11,   8,  11,  15,  11,
131 	 31,  12, -21,  13,  -5,  13,   5,  13,  41,  13,
132 	 -1,  14,   1,  14,  21,  14, -12,  15,  12,  15,
133 	-39,  17, -28,  17, -18,  17,  -8,  17,   8,  17,
134 	 17,  18,  -4,  19,   0,  19,   4,  19,  27,  19,
135 	 38,  20, -13,  21,  12,  22, -36,  23, -24,  23,
136 	 -8,  24,   7,  24,  -3,  25,   1,  25,  22,  25,
137 	 34,  26, -18,  28, -32,  29,  16,  29, -11,  31,
138 	  9,  32,  29,  32,  -4,  33,   2,  33, -26,  34,
139 	 23,  36, -19,  39,  16,  40, -13,  41,   9,  42,
140 	 -6,  43,   1,  43,   0,   0,   0,   0,   0,   0,
141 	  0,   0,   0
142 };
143 
makeTablesInterpolation(int param)144 void Blocky8::makeTablesInterpolation(int param) {
145 	int32 variable1, variable2;
146 	int32 b1, b2;
147 	int32 value_table47_1_2, value_table47_1_1, value_table47_2_2, value_table47_2_1;
148 	int32 tableSmallBig[64], tmp, s;
149 	const int8 *table47_1 = nullptr, *table47_2 = nullptr;
150 	int32 *ptr_small_big;
151 	byte *ptr;
152 	int i, x, y;
153 
154 	if (param == 8) {
155 		table47_1 = blocky8_table_big1;
156 		table47_2 = blocky8_table_big2;
157 		ptr = _tableBig;
158 		for (i = 0; i < 256; i++) {
159 			ptr[384] = 0;
160 			ptr[385] = 0;
161 			ptr += 388;
162 		}
163 	} else if (param == 4) {
164 		table47_1 = blocky8_table_small1;
165 		table47_2 = blocky8_table_small2;
166 		ptr = _tableSmall;
167 		for (i = 0; i < 256; i++) {
168 			ptr[96] = 0;
169 			ptr[97] = 0;
170 			ptr += 128;
171 		}
172 	} else {
173 		error("Blocky8::makeTablesInterpolation: unknown param %d", param);
174 	}
175 
176 	s = 0;
177 	for (x = 0; x < 16; x++) {
178 		value_table47_1_1 = table47_1[x];
179 		value_table47_2_1 = table47_2[x];
180 		for (y = 0; y < 16; y++) {
181 			value_table47_1_2 = table47_1[y];
182 			value_table47_2_2 = table47_2[y];
183 
184 			if (value_table47_2_1 == 0) {
185 				b1 = 0;
186 			} else if (value_table47_2_1 == param - 1) {
187 				b1 = 1;
188 			} else if (value_table47_1_1 == 0) {
189 				b1 = 2;
190 			} else if (value_table47_1_1 == param - 1) {
191 				b1 = 3;
192 			} else {
193 				b1 = 4;
194 			}
195 
196 			if (value_table47_2_2 == 0) {
197 				b2 = 0;
198 			} else if (value_table47_2_2 == param - 1) {
199 				b2 = 1;
200 			} else if (value_table47_1_2 == 0) {
201 				b2 = 2;
202 			} else if (value_table47_1_2 == param - 1) {
203 				b2 = 3;
204 			} else {
205 				b2 = 4;
206 			}
207 
208 			memset(tableSmallBig, 0, param * param * 4);
209 
210 			variable2 = ABS(value_table47_2_2 - value_table47_2_1);
211 			tmp = ABS(value_table47_1_2 - value_table47_1_1);
212 			if (variable2 <= tmp) {
213 				variable2 = tmp;
214 			}
215 
216 			for (variable1 = 0; variable1 <= variable2; variable1++) {
217 				int32 variable3, variable4;
218 
219 				if (variable2 > 0) {
220 					// Linearly interpolate between value_table47_1_1 and value_table47_1_2
221 					// respectively value_table47_2_1 and value_table47_2_2.
222 					variable4 = (value_table47_1_1 * variable1 + value_table47_1_2 * (variable2 - variable1) + variable2 / 2) / variable2;
223 					variable3 = (value_table47_2_1 * variable1 + value_table47_2_2 * (variable2 - variable1) + variable2 / 2) / variable2;
224 				} else {
225 					variable4 = value_table47_1_1;
226 					variable3 = value_table47_2_1;
227 				}
228 				ptr_small_big = &tableSmallBig[param * variable3 + variable4];
229 				*ptr_small_big = 1;
230 
231 				if ((b1 == 2 && b2 == 3) || (b2 == 2 && b1 == 3) ||
232 				    (b1 == 0 && b2 != 1) || (b2 == 0 && b1 != 1)) {
233 					if (variable3 >= 0) {
234 						i = variable3 + 1;
235 						while (i--) {
236 							*ptr_small_big = 1;
237 							ptr_small_big -= param;
238 						}
239 					}
240 				} else if ((b2 != 0 && b1 == 1) || (b1 != 0 && b2 == 1)) {
241 					if (param > variable3) {
242 						i = param - variable3;
243 						while (i--) {
244 							*ptr_small_big = 1;
245 							ptr_small_big += param;
246 						}
247 					}
248 				} else if ((b1 == 2 && b2 != 3) || (b2 == 2 && b1 != 3)) {
249 					if (variable4 >= 0) {
250 						i = variable4 + 1;
251 						while (i--) {
252 							*(ptr_small_big--) = 1;
253 						}
254 					}
255 				} else if ((b1 == 0 && b2 == 1) || (b2 == 0 && b1 == 1) ||
256 						   (b1 == 3 && b2 != 2) || (b2 == 3 && b1 != 2)) {
257 					if (param > variable4) {
258 						i = param - variable4;
259 						while (i--) {
260 							*(ptr_small_big++) = 1;
261 						}
262 					}
263 				}
264 			}
265 
266 			if (param == 8) {
267 				for (i = 64 - 1; i >= 0; i--) {
268 					if (tableSmallBig[i] != 0) {
269 						_tableBig[256 + s + _tableBig[384 + s]] = (byte)i;
270 						_tableBig[384 + s]++;
271 					} else {
272 						_tableBig[320 + s + _tableBig[385 + s]] = (byte)i;
273 						_tableBig[385 + s]++;
274 					}
275 				}
276 				s += 388;
277 			}
278 			if (param == 4) {
279 				for (i = 16 - 1; i >= 0; i--) {
280 					if (tableSmallBig[i] != 0) {
281 						_tableSmall[64 + s + _tableSmall[96 + s]] = (byte)i;
282 						_tableSmall[96 + s]++;
283 					} else {
284 						_tableSmall[80 + s + _tableSmall[97 + s]] = (byte)i;
285 						_tableSmall[97 + s]++;
286 					}
287 				}
288 				s += 128;
289 			}
290 		}
291 	}
292 }
293 
makeTables47(int width)294 void Blocky8::makeTables47(int width) {
295 	if (_lastTableWidth == width)
296 		return;
297 
298 	_lastTableWidth = width;
299 
300 	int32 a, c, d;
301 	int16 tmp;
302 
303 	for (int l = 0; l < 512; l += 2) {
304 		_table[l / 2] = (int16)(blocky8_table[l + 1] * width + blocky8_table[l]);
305 	}
306 
307 	a = 0;
308 	c = 0;
309 	do {
310 		for (d = 0; d < _tableSmall[96 + c]; d++) {
311 			tmp = _tableSmall[64 + c + d];
312 			tmp = (int16)((byte)(tmp >> 2) * width + (tmp & 3));
313 			_tableSmall[c + d * 2] = (byte)tmp;
314 			_tableSmall[c + d * 2 + 1] = tmp >> 8;
315 		}
316 		for (d = 0; d < _tableSmall[97 + c]; d++) {
317 			tmp = _tableSmall[80 + c + d];
318 			tmp = (int16)((byte)(tmp >> 2) * width + (tmp & 3));
319 			_tableSmall[32 + c + d * 2] = (byte)tmp;
320 			_tableSmall[32 + c + d * 2 + 1] = tmp >> 8;
321 		}
322 		for (d = 0; d < _tableBig[384 + a]; d++) {
323 			tmp = _tableBig[256 + a + d];
324 			tmp = (int16)((byte)(tmp >> 3) * width + (tmp & 7));
325 			_tableBig[a + d * 2] = (byte)tmp;
326 			_tableBig[a + d * 2 + 1] = tmp >> 8;
327 		}
328 		for (d = 0; d < _tableBig[385 + a]; d++) {
329 			tmp = _tableBig[320 + a + d];
330 			tmp = (int16)((byte)(tmp >> 3) * width + (tmp & 7));
331 			_tableBig[128 + a + d * 2] = (byte)tmp;
332 			_tableBig[128 + a + d * 2 + 1] = tmp >> 8;
333 		}
334 
335 		a += 388;
336 		c += 128;
337 	} while (c < 32768);
338 }
339 
340 #ifdef USE_ARM_SMUSH_ASM
341 
342 extern "C" {
343 #ifndef IPHONE
344 #define ARM_Blocky8_decode2 _ARM_Blocky8_decode2
345 #endif
346 }
347 
348 extern "C" void ARM_Blocky8_decode2(      byte  *dst,
349                                   const byte  *src,
350                                         int    width,
351                                         int    height,
352                                   const byte  *param_ptr,
353                                         int16 *_table,
354                                         byte  *_tableBig,
355                                         int32  offset1,
356                                         int32  offset2,
357                                         byte  *_tableSmall);
358 
359 #define decode2(SRC,DST,WIDTH,HEIGHT,PARAM) \
360  ARM_Blocky8_decode2(SRC,DST,WIDTH,HEIGHT,PARAM,_table,_tableBig, \
361                    _offset1,_offset2,_tableSmall)
362 
363 #else
level3(byte * d_dst)364 void Blocky8::level3(byte *d_dst) {
365 	int32 tmp;
366 	byte code = *_d_src++;
367 
368 	if (code < 0xF8) {
369 		tmp = _table[code] + _offset1;
370 		COPY_2X1_LINE(d_dst, d_dst + tmp);
371 		COPY_2X1_LINE(d_dst + _d_pitch, d_dst + _d_pitch + tmp);
372 	} else if (code == 0xFF) {
373 		COPY_2X1_LINE(d_dst, _d_src + 0);
374 		COPY_2X1_LINE(d_dst + _d_pitch, _d_src + 2);
375 		_d_src += 4;
376 	} else if (code == 0xFE) {
377 		byte t = *_d_src++;
378 		FILL_2X1_LINE(d_dst, t);
379 		FILL_2X1_LINE(d_dst + _d_pitch, t);
380 	} else if (code == 0xFC) {
381 		tmp = _offset2;
382 		COPY_2X1_LINE(d_dst, d_dst + tmp);
383 		COPY_2X1_LINE(d_dst + _d_pitch, d_dst + _d_pitch + tmp);
384 	} else {
385 		byte t = _paramPtr[code];
386 		FILL_2X1_LINE(d_dst, t);
387 		FILL_2X1_LINE(d_dst + _d_pitch, t);
388 	}
389 }
390 
level2(byte * d_dst)391 void Blocky8::level2(byte *d_dst) {
392 	int32 tmp;
393 	byte code = *_d_src++;
394 	int i;
395 
396 	if (code < 0xF8) {
397 		tmp = _table[code] + _offset1;
398 		for (i = 0; i < 4; i++) {
399 			COPY_4X1_LINE(d_dst, d_dst + tmp);
400 			d_dst += _d_pitch;
401 		}
402 	} else if (code == 0xFF) {
403 		level3(d_dst);
404 		d_dst += 2;
405 		level3(d_dst);
406 		d_dst += _d_pitch * 2 - 2;
407 		level3(d_dst);
408 		d_dst += 2;
409 		level3(d_dst);
410 	} else if (code == 0xFE) {
411 		byte t = *_d_src++;
412 		for (i = 0; i < 4; i++) {
413 			FILL_4X1_LINE(d_dst, t);
414 			d_dst += _d_pitch;
415 		}
416 	} else if (code == 0xFD) {
417 		byte *tmp_ptr = _tableSmall + *_d_src++ * 128;
418 		int32 l = tmp_ptr[96];
419 		byte val = *_d_src++;
420 		int16 *tmp_ptr2 = (int16 *)tmp_ptr;
421 		while (l--) {
422 			*(d_dst + READ_LE_UINT16(tmp_ptr2)) = val;
423 			tmp_ptr2++;
424 		}
425 		l = tmp_ptr[97];
426 		val = *_d_src++;
427 		tmp_ptr2 = (int16 *)(tmp_ptr + 32);
428 		while (l--) {
429 			*(d_dst + READ_LE_UINT16(tmp_ptr2)) = val;
430 			tmp_ptr2++;
431 		}
432 	} else if (code == 0xFC) {
433 		tmp = _offset2;
434 		for (i = 0; i < 4; i++) {
435 			COPY_4X1_LINE(d_dst, d_dst + tmp);
436 			d_dst += _d_pitch;
437 		}
438 	} else {
439 		byte t = _paramPtr[code];
440 		for (i = 0; i < 4; i++) {
441 			FILL_4X1_LINE(d_dst, t);
442 			d_dst += _d_pitch;
443 		}
444 	}
445 }
446 
level1(byte * d_dst)447 void Blocky8::level1(byte *d_dst) {
448 	int32 tmp, tmp2;
449 	byte code = *_d_src++;
450 	int i;
451 
452 	if (code < 0xF8) {
453 		tmp2 = _table[code] + _offset1;
454 		for (i = 0; i < 8; i++) {
455 			COPY_4X1_LINE(d_dst + 0, d_dst + tmp2);
456 			COPY_4X1_LINE(d_dst + 4, d_dst + tmp2 + 4);
457 			d_dst += _d_pitch;
458 		}
459 	} else if (code == 0xFF) {
460 		level2(d_dst);
461 		d_dst += 4;
462 		level2(d_dst);
463 		d_dst += _d_pitch * 4 - 4;
464 		level2(d_dst);
465 		d_dst += 4;
466 		level2(d_dst);
467 	} else if (code == 0xFE) {
468 		byte t = *_d_src++;
469 		for (i = 0; i < 8; i++) {
470 			FILL_4X1_LINE(d_dst, t);
471 			FILL_4X1_LINE(d_dst + 4, t);
472 			d_dst += _d_pitch;
473 		}
474 	} else if (code == 0xFD) {
475 		tmp = *_d_src++;
476 		byte *tmp_ptr = _tableBig + tmp * 388;
477 		byte l = tmp_ptr[384];
478 		byte val = *_d_src++;
479 		int16 *tmp_ptr2 = (int16 *)tmp_ptr;
480 		while (l--) {
481 			*(d_dst + READ_LE_UINT16(tmp_ptr2)) = val;
482 			tmp_ptr2++;
483 		}
484 		l = tmp_ptr[385];
485 		val = *_d_src++;
486 		tmp_ptr2 = (int16 *)(tmp_ptr + 128);
487 		while (l--) {
488 			*(d_dst + READ_LE_UINT16(tmp_ptr2)) = val;
489 			tmp_ptr2++;
490 		}
491 	} else if (code == 0xFC) {
492 		tmp2 = _offset2;
493 		for (i = 0; i < 8; i++) {
494 			COPY_4X1_LINE(d_dst + 0, d_dst + tmp2);
495 			COPY_4X1_LINE(d_dst + 4, d_dst + tmp2 + 4);
496 			d_dst += _d_pitch;
497 		}
498 	} else {
499 		byte t = _paramPtr[code];
500 		for (i = 0; i < 8; i++) {
501 			FILL_4X1_LINE(d_dst, t);
502 			FILL_4X1_LINE(d_dst + 4, t);
503 			d_dst += _d_pitch;
504 		}
505 	}
506 }
507 
decode2(byte * dst,const byte * src,int width,int height,const byte * param_ptr)508 void Blocky8::decode2(byte *dst, const byte *src, int width, int height, const byte *param_ptr) {
509 	_d_src = src;
510 	_paramPtr = param_ptr - 0xf8;
511 	int bw = (width + 7) / 8;
512 	int bh = (height + 7) / 8;
513 	int next_line = width * 7;
514 	_d_pitch = width;
515 
516 	do {
517 		int tmp_bw = bw;
518 		do {
519 			level1(dst);
520 			dst += 8;
521 		} while (--tmp_bw);
522 		dst += next_line;
523 	} while (--bh);
524 }
525 #endif
526 
bompDecodeLine(byte * dst,const byte * src,int len)527 static void bompDecodeLine(byte *dst, const byte *src, int len) {
528 	assert(len > 0);
529 
530 	int num;
531 	byte code, color;
532 
533 	while (len > 0) {
534 		code = *src++;
535 		num = (code >> 1) + 1;
536 		if (num > len)
537 			num = len;
538 		len -= num;
539 		if (code & 1) {
540 			color = *src++;
541 			memset(dst, color, num);
542 		} else {
543 			memcpy(dst, src, num);
544 			src += num;
545 		}
546 		dst += num;
547 	}
548 }
549 
Blocky8()550 Blocky8::Blocky8() {
551 	_tableBig = new byte[99328];
552 	_tableSmall = new byte[32768];
553 	memset(_tableBig, 0, 99328);
554 	memset(_tableSmall, 0, 32768);
555 	_deltaBuf = nullptr;
556 	_width = -1;
557 	_height = -1;
558 	_frameSize = 0;
559 	_offset1 = 0;
560 	_offset2 = 0;
561 	_prevSeqNb = 0;
562 	_lastTableWidth = 0;
563 	_deltaBufs[0] = nullptr;
564 	_deltaBufs[1] = nullptr;
565 	_curBuf = nullptr;
566 	_d_pitch = 0;
567 	_d_src = nullptr;
568 	_paramPtr = nullptr;
569 }
570 
init(int width,int height)571 void Blocky8::init(int width, int height) {
572 	if (_width == width && _height == height)
573 		return;
574 	deinit();
575 	_width = width;
576 	_height = height;
577 	makeTablesInterpolation(4);
578 	makeTablesInterpolation(8);
579 
580 	_frameSize = _width * _height;
581 	uint32 deltaSize = _frameSize * 3;
582 	_deltaBuf = new byte[deltaSize];
583 	memset(_deltaBuf, 0, deltaSize);
584 	_deltaBufs[0] = _deltaBuf;
585 	_deltaBufs[1] = _deltaBuf + _frameSize;
586 	_curBuf = _deltaBuf + _frameSize * 2;
587 }
588 
deinit()589 void Blocky8::deinit() {
590 	_lastTableWidth = -1;
591 	if (_deltaBuf) {
592 		delete[] _deltaBuf;
593 		_deltaBuf = nullptr;
594 		_deltaBufs[0] = nullptr;
595 		_deltaBufs[1] = nullptr;
596 	}
597 }
598 
~Blocky8()599 Blocky8::~Blocky8() {
600 	deinit();
601 	if (_tableBig) {
602 		delete[] _tableBig;
603 		_tableBig = nullptr;
604 	}
605 	if (_tableSmall) {
606 		delete[] _tableSmall;
607 		_tableSmall = nullptr;
608 	}
609 }
610 
decode(byte * dst,const byte * src)611 bool Blocky8::decode(byte *dst, const byte *src) {
612 	if ((_tableBig == nullptr) || (_tableSmall == nullptr) || (_deltaBuf == nullptr))
613 		return false;
614 
615 	_offset1 = _deltaBufs[1] - _curBuf;
616 	_offset2 = _deltaBufs[0] - _curBuf;
617 
618 	int32 seq_nb = READ_LE_UINT16(src + 0);
619 
620 	const byte *gfx_data = src + 26;
621 
622 	if (seq_nb == 0) {
623 		makeTables47(_width);
624 		memset(_deltaBufs[0], src[12], _frameSize);
625 		memset(_deltaBufs[1], src[13], _frameSize);
626 		_prevSeqNb = -1;
627 	}
628 
629 	if ((src[4] & 1) != 0) {
630 		gfx_data += 32896;
631 	}
632 
633 	switch (src[2]) {
634 	case 0:
635 		memcpy(_curBuf, gfx_data, _frameSize);
636 		break;
637 	case 1:
638 		// Used by Outlaws, but not by any SCUMM game.
639 		error("blocky8: not implemented decode1 proc");
640 		break;
641 	case 2:
642 		if (seq_nb == _prevSeqNb + 1) {
643 			decode2(_curBuf, gfx_data, _width, _height, src + 8);
644 		}
645 		break;
646 	case 3:
647 		memcpy(_curBuf, _deltaBufs[1], _frameSize);
648 		break;
649 	case 4:
650 		memcpy(_curBuf, _deltaBufs[0], _frameSize);
651 		break;
652 	case 5:
653 		bompDecodeLine(_curBuf, gfx_data, READ_LE_UINT32(src + 14));
654 		break;
655 	}
656 
657 	memcpy(dst, _curBuf, _frameSize);
658 
659 	if (seq_nb == _prevSeqNb + 1) {
660 		if (src[3] == 1) {
661 			SWAP(_curBuf, _deltaBufs[1]);
662 		} else if (src[3] == 2) {
663 			SWAP(_deltaBufs[0], _deltaBufs[1]);
664 			SWAP(_deltaBufs[1], _curBuf);
665 		}
666 	}
667 	_prevSeqNb = seq_nb;
668 
669 	return true;
670 }
671 
672 } // End of namespace Grim
673