Initial commit
This commit is contained in:
845
engines/grim/movie/codecs/blocky16.cpp
Normal file
845
engines/grim/movie/codecs/blocky16.cpp
Normal file
@@ -0,0 +1,845 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "common/util.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "engines/grim/movie/codecs/blocky16.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
#if defined(SCUMM_NEED_ALIGNMENT)
|
||||
|
||||
#define COPY_4X1_LINE(dst, src) \
|
||||
do { \
|
||||
(dst)[0] = (src)[0]; \
|
||||
(dst)[1] = (src)[1]; \
|
||||
(dst)[2] = (src)[2]; \
|
||||
(dst)[3] = (src)[3]; \
|
||||
} while (0)
|
||||
|
||||
#if defined(SCUMM_BIG_ENDIAN)
|
||||
|
||||
#define WRITE_2X1_LINE(dst, v) \
|
||||
do { \
|
||||
(dst)[0] = (byte)((v >> 8) & 0xFF); \
|
||||
(dst)[1] = (byte)((v >> 0) & 0xFF); \
|
||||
} while (0)
|
||||
|
||||
#define WRITE_4X1_LINE(dst, v) \
|
||||
do { \
|
||||
(dst)[0] = (byte)((v >> 24) & 0xFF); \
|
||||
(dst)[1] = (byte)((v >> 16) & 0XFF); \
|
||||
(dst)[2] = (byte)((v >> 8) & 0xFF); \
|
||||
(dst)[3] = (byte)((v >> 0) & 0xFF); \
|
||||
} while (0)
|
||||
|
||||
#else /* SCUMM_BIG_ENDIAN */
|
||||
|
||||
#define WRITE_2X1_LINE(dst, v) \
|
||||
do { \
|
||||
(dst)[0] = (byte)((v >> 0) & 0xFF); \
|
||||
(dst)[1] = (byte)((v >> 8) & 0xFF); \
|
||||
} while (0)
|
||||
|
||||
#define WRITE_4X1_LINE(dst, v) \
|
||||
do { \
|
||||
(dst)[0] = (byte)((v >> 0) & 0xFF); \
|
||||
(dst)[1] = (byte)((v >> 8) & 0XFF); \
|
||||
(dst)[2] = (byte)((v >> 16) & 0xFF); \
|
||||
(dst)[3] = (byte)((v >> 24) & 0xFF); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
#else /* SCUMM_NEED_ALIGNMENT */
|
||||
|
||||
#define COPY_4X1_LINE(dst, src) \
|
||||
*(uint32 *)(dst) = *(const uint32 *)(src);
|
||||
|
||||
#define WRITE_2X1_LINE(dst, v) \
|
||||
*(uint16 *)(dst) = v;
|
||||
|
||||
#define WRITE_4X1_LINE(dst, v) \
|
||||
*(uint32 *)(dst) = v;
|
||||
|
||||
#endif
|
||||
|
||||
static int8 blocky16_table_small1[] = {
|
||||
0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1,
|
||||
};
|
||||
|
||||
static int8 blocky16_table_small2[] = {
|
||||
0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2,
|
||||
};
|
||||
|
||||
static int8 blocky16_table_big1[] = {
|
||||
0, 2, 5, 7, 7, 7, 7, 7, 7, 5, 2, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static int8 blocky16_table_big2[] = {
|
||||
0, 0, 0, 0, 1, 3, 4, 6, 7, 7, 7, 7, 6, 4, 3, 1,
|
||||
};
|
||||
|
||||
static int8 blocky16_table[] = {
|
||||
0, 0, -1, -43, 6, -43, -9, -42, 13, -41,
|
||||
-16, -40, 19, -39, -23, -36, 26, -34, -2, -33,
|
||||
4, -33, -29, -32, -9, -32, 11, -31, -16, -29,
|
||||
32, -29, 18, -28, -34, -26, -22, -25, -1, -25,
|
||||
3, -25, -7, -24, 8, -24, 24, -23, 36, -23,
|
||||
-12, -22, 13, -21, -38, -20, 0, -20, -27, -19,
|
||||
-4, -19, 4, -19, -17, -18, -8, -17, 8, -17,
|
||||
18, -17, 28, -17, 39, -17, -12, -15, 12, -15,
|
||||
-21, -14, -1, -14, 1, -14, -41, -13, -5, -13,
|
||||
5, -13, 21, -13, -31, -12, -15, -11, -8, -11,
|
||||
8, -11, 15, -11, -2, -10, 1, -10, 31, -10,
|
||||
-23, -9, -11, -9, -5, -9, 4, -9, 11, -9,
|
||||
42, -9, 6, -8, 24, -8, -18, -7, -7, -7,
|
||||
-3, -7, -1, -7, 2, -7, 18, -7, -43, -6,
|
||||
-13, -6, -4, -6, 4, -6, 8, -6, -33, -5,
|
||||
-9, -5, -2, -5, 0, -5, 2, -5, 5, -5,
|
||||
13, -5, -25, -4, -6, -4, -3, -4, 3, -4,
|
||||
9, -4, -19, -3, -7, -3, -4, -3, -2, -3,
|
||||
-1, -3, 0, -3, 1, -3, 2, -3, 4, -3,
|
||||
6, -3, 33, -3, -14, -2, -10, -2, -5, -2,
|
||||
-3, -2, -2, -2, -1, -2, 0, -2, 1, -2,
|
||||
2, -2, 3, -2, 5, -2, 7, -2, 14, -2,
|
||||
19, -2, 25, -2, 43, -2, -7, -1, -3, -1,
|
||||
-2, -1, -1, -1, 0, -1, 1, -1, 2, -1,
|
||||
3, -1, 10, -1, -5, 0, -3, 0, -2, 0,
|
||||
-1, 0, 1, 0, 2, 0, 3, 0, 5, 0,
|
||||
7, 0, -10, 1, -7, 1, -3, 1, -2, 1,
|
||||
-1, 1, 0, 1, 1, 1, 2, 1, 3, 1,
|
||||
-43, 2, -25, 2, -19, 2, -14, 2, -5, 2,
|
||||
-3, 2, -2, 2, -1, 2, 0, 2, 1, 2,
|
||||
2, 2, 3, 2, 5, 2, 7, 2, 10, 2,
|
||||
14, 2, -33, 3, -6, 3, -4, 3, -2, 3,
|
||||
-1, 3, 0, 3, 1, 3, 2, 3, 4, 3,
|
||||
19, 3, -9, 4, -3, 4, 3, 4, 7, 4,
|
||||
25, 4, -13, 5, -5, 5, -2, 5, 0, 5,
|
||||
2, 5, 5, 5, 9, 5, 33, 5, -8, 6,
|
||||
-4, 6, 4, 6, 13, 6, 43, 6, -18, 7,
|
||||
-2, 7, 0, 7, 2, 7, 7, 7, 18, 7,
|
||||
-24, 8, -6, 8, -42, 9, -11, 9, -4, 9,
|
||||
5, 9, 11, 9, 23, 9, -31, 10, -1, 10,
|
||||
2, 10, -15, 11, -8, 11, 8, 11, 15, 11,
|
||||
31, 12, -21, 13, -5, 13, 5, 13, 41, 13,
|
||||
-1, 14, 1, 14, 21, 14, -12, 15, 12, 15,
|
||||
-39, 17, -28, 17, -18, 17, -8, 17, 8, 17,
|
||||
17, 18, -4, 19, 0, 19, 4, 19, 27, 19,
|
||||
38, 20, -13, 21, 12, 22, -36, 23, -24, 23,
|
||||
-8, 24, 7, 24, -3, 25, 1, 25, 22, 25,
|
||||
34, 26, -18, 28, -32, 29, 16, 29, -11, 31,
|
||||
9, 32, 29, 32, -4, 33, 2, 33, -26, 34,
|
||||
23, 36, -19, 39, 16, 40, -13, 41, 9, 42,
|
||||
-6, 43, 1, 43, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0
|
||||
};
|
||||
|
||||
void Blocky16::makeTablesInterpolation(int param) {
|
||||
int32 variable1, variable2;
|
||||
int32 b1, b2;
|
||||
int32 value_table47_1_2, value_table47_1_1, value_table47_2_2, value_table47_2_1;
|
||||
int32 tableSmallBig[64], tmp, s;
|
||||
int8 *table47_1 = nullptr, *table47_2 = nullptr;
|
||||
int32 *ptr_small_big;
|
||||
byte *ptr;
|
||||
int i, x, y;
|
||||
|
||||
if (param == 8) {
|
||||
table47_1 = blocky16_table_big1;
|
||||
table47_2 = blocky16_table_big2;
|
||||
ptr = _tableBig + 384;
|
||||
for (i = 0; i < 256; i++) {
|
||||
*ptr = 0;
|
||||
ptr += 388;
|
||||
}
|
||||
ptr = _tableBig + 385;
|
||||
for (i = 0; i < 256; i++) {
|
||||
*ptr = 0;
|
||||
ptr += 388;
|
||||
}
|
||||
} else if (param == 4) {
|
||||
table47_1 = blocky16_table_small1;
|
||||
table47_2 = blocky16_table_small2;
|
||||
ptr = _tableSmall + 96;
|
||||
for (i = 0; i < 256; i++) {
|
||||
*ptr = 0;
|
||||
ptr += 128;
|
||||
}
|
||||
ptr = _tableSmall + 97;
|
||||
for (i = 0; i < 256; i++) {
|
||||
*ptr = 0;
|
||||
ptr += 128;
|
||||
}
|
||||
} else {
|
||||
error("Blocky16::makeTablesInterpolation: unknown param %d", param);
|
||||
}
|
||||
|
||||
s = 0;
|
||||
for (x = 0; x < 16; x++) {
|
||||
value_table47_1_1 = table47_1[x];
|
||||
value_table47_2_1 = table47_2[x];
|
||||
for (y = 0; y < 16; y++) {
|
||||
value_table47_1_2 = table47_1[y];
|
||||
value_table47_2_2 = table47_2[y];
|
||||
|
||||
if (value_table47_2_1 == 0) {
|
||||
b1 = 0;
|
||||
} else if (value_table47_2_1 == param - 1) {
|
||||
b1 = 1;
|
||||
} else if (value_table47_1_1 == 0) {
|
||||
b1 = 2;
|
||||
} else if (value_table47_1_1 == param - 1) {
|
||||
b1 = 3;
|
||||
} else {
|
||||
b1 = 4;
|
||||
}
|
||||
|
||||
if (value_table47_2_2 == 0) {
|
||||
b2 = 0;
|
||||
} else if (value_table47_2_2 == param - 1) {
|
||||
b2 = 1;
|
||||
} else if (value_table47_1_2 == 0) {
|
||||
b2 = 2;
|
||||
} else if (value_table47_1_2 == param - 1) {
|
||||
b2 = 3;
|
||||
} else {
|
||||
b2 = 4;
|
||||
}
|
||||
|
||||
memset(tableSmallBig, 0, param * param * 4);
|
||||
|
||||
variable2 = abs(value_table47_2_2 - value_table47_2_1);
|
||||
tmp = abs(value_table47_1_2 - value_table47_1_1);
|
||||
if (variable2 <= tmp) {
|
||||
variable2 = tmp;
|
||||
}
|
||||
|
||||
for (variable1 = 0; variable1 <= variable2; variable1++) {
|
||||
int32 variable3, variable4;
|
||||
|
||||
if (variable2 > 0) {
|
||||
// Linearly interpolate between value_table47_1_1 and value_table47_1_2
|
||||
// respectively value_table47_2_1 and value_table47_2_2.
|
||||
variable4 = (value_table47_1_1 * variable1 + value_table47_1_2 * (variable2 - variable1) + variable2 / 2) / variable2;
|
||||
variable3 = (value_table47_2_1 * variable1 + value_table47_2_2 * (variable2 - variable1) + variable2 / 2) / variable2;
|
||||
} else {
|
||||
variable4 = value_table47_1_1;
|
||||
variable3 = value_table47_2_1;
|
||||
}
|
||||
ptr_small_big = &tableSmallBig[param * variable3 + variable4];
|
||||
*ptr_small_big = 1;
|
||||
|
||||
if ((b1 == 2 && b2 == 3) || (b2 == 2 && b1 == 3) ||
|
||||
(b1 == 0 && b2 != 1) || (b2 == 0 && b1 != 1)) {
|
||||
if (variable3 >= 0) {
|
||||
i = variable3 + 1;
|
||||
while (i--) {
|
||||
*ptr_small_big = 1;
|
||||
ptr_small_big -= param;
|
||||
}
|
||||
}
|
||||
} else if ((b2 != 0 && b1 == 1) || (b1 != 0 && b2 == 1)) {
|
||||
if (param > variable3) {
|
||||
i = param - variable3;
|
||||
while (i--) {
|
||||
*ptr_small_big = 1;
|
||||
ptr_small_big += param;
|
||||
}
|
||||
}
|
||||
} else if ((b1 == 2 && b2 != 3) || (b2 == 2 && b1 != 3)) {
|
||||
if (variable4 >= 0) {
|
||||
i = variable4 + 1;
|
||||
while (i--) {
|
||||
*(ptr_small_big--) = 1;
|
||||
}
|
||||
}
|
||||
} else if ((b1 == 0 && b2 == 1) || (b2 == 0 && b1 == 1) ||
|
||||
(b1 == 3 && b2 != 2) || (b2 == 3 && b1 != 2)) {
|
||||
if (param > variable4) {
|
||||
i = param - variable4;
|
||||
while (i--) {
|
||||
*(ptr_small_big++) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (param == 8) {
|
||||
for (i = 64 - 1; i >= 0; i--) {
|
||||
if (tableSmallBig[i] != 0) {
|
||||
_tableBig[256 + s + _tableBig[384 + s]] = (byte)i;
|
||||
_tableBig[384 + s]++;
|
||||
} else {
|
||||
_tableBig[320 + s + _tableBig[385 + s]] = (byte)i;
|
||||
_tableBig[385 + s]++;
|
||||
}
|
||||
}
|
||||
s += 388;
|
||||
}
|
||||
if (param == 4) {
|
||||
for (i = 16 - 1; i >= 0; i--) {
|
||||
if (tableSmallBig[i] != 0) {
|
||||
_tableSmall[64 + s + _tableSmall[96 + s]] = (byte)i;
|
||||
_tableSmall[96 + s]++;
|
||||
} else {
|
||||
_tableSmall[80 + s + _tableSmall[97 + s]] = (byte)i;
|
||||
_tableSmall[97 + s]++;
|
||||
}
|
||||
}
|
||||
s += 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Blocky16::makeTables47(int width) {
|
||||
if (_lastTableWidth == width)
|
||||
return;
|
||||
|
||||
_lastTableWidth = width;
|
||||
|
||||
int32 a, c, d;
|
||||
int16 tmp;
|
||||
|
||||
for (int l = 0; l < 512; l += 2) {
|
||||
_table[l / 2] = (int16)(blocky16_table[l + 1] * width + blocky16_table[l]);
|
||||
}
|
||||
|
||||
a = 0;
|
||||
c = 0;
|
||||
do {
|
||||
for (d = 0; d < _tableSmall[96 + c]; d++) {
|
||||
tmp = _tableSmall[64 + c + d];
|
||||
tmp = (int16)((byte)(tmp >> 2) * width + (tmp & 3));
|
||||
_tableSmall[c + d * 2] = (byte)tmp;
|
||||
_tableSmall[c + d * 2 + 1] = tmp >> 8;
|
||||
}
|
||||
for (d = 0; d < _tableSmall[97 + c]; d++) {
|
||||
tmp = _tableSmall[80 + c + d];
|
||||
tmp = (int16)((byte)(tmp >> 2) * width + (tmp & 3));
|
||||
_tableSmall[32 + c + d * 2] = (byte)tmp;
|
||||
_tableSmall[32 + c + d * 2 + 1] = tmp >> 8;
|
||||
}
|
||||
for (d = 0; d < _tableBig[384 + a]; d++) {
|
||||
tmp = _tableBig[256 + a + d];
|
||||
tmp = (int16)((byte)(tmp >> 3) * width + (tmp & 7));
|
||||
_tableBig[a + d * 2] = (byte)tmp;
|
||||
_tableBig[a + d * 2 + 1] = tmp >> 8;
|
||||
}
|
||||
for (d = 0; d < _tableBig[385 + a]; d++) {
|
||||
tmp = _tableBig[320 + a + d];
|
||||
tmp = (int16)((byte)(tmp >> 3) * width + (tmp & 7));
|
||||
_tableBig[128 + a + d * 2] = (byte)tmp;
|
||||
_tableBig[128 + a + d * 2 + 1] = tmp >> 8;
|
||||
}
|
||||
|
||||
a += 388;
|
||||
c += 128;
|
||||
} while (c < 32768);
|
||||
}
|
||||
|
||||
void Blocky16::level3(byte *d_dst) {
|
||||
int32 tmp2;
|
||||
uint32 t;
|
||||
byte code = *_d_src++;
|
||||
int i;
|
||||
|
||||
if (code <= 0xF5) {
|
||||
if (code == 0xF5) {
|
||||
int16 tmp = READ_LE_UINT16(_d_src);
|
||||
tmp2 = tmp * 2;
|
||||
_d_src += 2;
|
||||
} else {
|
||||
tmp2 = _table[code] * 2;
|
||||
}
|
||||
tmp2 += _offset1;
|
||||
for (i = 0; i < 2; i++) {
|
||||
COPY_4X1_LINE(d_dst + 0, d_dst + tmp2 + 0);
|
||||
d_dst += _d_pitch;
|
||||
}
|
||||
} else if ((code == 0xFF) || (code == 0xF8)) {
|
||||
WRITE_2X1_LINE(d_dst + 0, READ_LE_UINT16(_d_src + 0));
|
||||
WRITE_2X1_LINE(d_dst + 2, READ_LE_UINT16(_d_src + 2));
|
||||
d_dst += _d_pitch;
|
||||
WRITE_2X1_LINE(d_dst + 0, READ_LE_UINT16(_d_src + 4));
|
||||
WRITE_2X1_LINE(d_dst + 2, READ_LE_UINT16(_d_src + 6));
|
||||
_d_src += 8;
|
||||
} else if (code == 0xFD) {
|
||||
t = *_d_src++;
|
||||
t = READ_LE_UINT16(_param6_7Ptr + t * 2);
|
||||
t = (t << 16) | t;
|
||||
for (i = 0; i < 2; i++) {
|
||||
WRITE_4X1_LINE(d_dst + 0, t);
|
||||
d_dst += _d_pitch;
|
||||
}
|
||||
} else if (code == 0xFE) {
|
||||
t = READ_LE_UINT16(_d_src);
|
||||
_d_src += 2;
|
||||
t = (t << 16) | t;
|
||||
for (i = 0; i < 2; i++) {
|
||||
WRITE_4X1_LINE(d_dst + 0, t);
|
||||
d_dst += _d_pitch;
|
||||
}
|
||||
} else if (code == 0xF6) {
|
||||
tmp2 = _offset2;
|
||||
for (i = 0; i < 2; i++) {
|
||||
COPY_4X1_LINE(d_dst + 0, d_dst + tmp2 + 0);
|
||||
d_dst += _d_pitch;
|
||||
}
|
||||
} else if (code == 0xF7) {
|
||||
tmp2 = READ_LE_UINT32(_d_src);
|
||||
_d_src += 4;
|
||||
WRITE_2X1_LINE(d_dst + 0, READ_LE_UINT16(_param6_7Ptr + (byte)tmp2 * 2));
|
||||
WRITE_2X1_LINE(d_dst + 2, READ_LE_UINT16(_param6_7Ptr + (byte)(tmp2 >> 8) * 2));
|
||||
tmp2 >>= 16;
|
||||
d_dst += _d_pitch;
|
||||
WRITE_2X1_LINE(d_dst + 0, READ_LE_UINT16(_param6_7Ptr + (byte)tmp2 * 2));
|
||||
WRITE_2X1_LINE(d_dst + 2, READ_LE_UINT16(_param6_7Ptr + (byte)(tmp2 >> 8) * 2));
|
||||
} else if ((code >= 0xF9) && (code <= 0xFC)) {
|
||||
t = READ_LE_UINT16(_paramPtr + code * 2);
|
||||
t = (t << 16) | t;
|
||||
for (i = 0; i < 2; i++) {
|
||||
WRITE_4X1_LINE(d_dst + 0, t);
|
||||
d_dst += _d_pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Blocky16::level2(byte *d_dst) {
|
||||
int32 tmp2;
|
||||
uint32 t = 0, val;
|
||||
byte code = *_d_src++;
|
||||
int i;
|
||||
|
||||
if (code <= 0xF5) {
|
||||
if (code == 0xF5) {
|
||||
int16 tmp = READ_LE_UINT16(_d_src);
|
||||
tmp2 = tmp * 2;
|
||||
_d_src += 2;
|
||||
} else {
|
||||
tmp2 = _table[code] * 2;
|
||||
}
|
||||
tmp2 += _offset1;
|
||||
for (i = 0; i < 4; i++) {
|
||||
COPY_4X1_LINE(d_dst + 0, d_dst + tmp2 + 0);
|
||||
COPY_4X1_LINE(d_dst + 4, d_dst + tmp2 + 4);
|
||||
d_dst += _d_pitch;
|
||||
}
|
||||
} else if (code == 0xFF) {
|
||||
level3(d_dst);
|
||||
d_dst += 4;
|
||||
level3(d_dst);
|
||||
d_dst += _d_pitch * 2 - 4;
|
||||
level3(d_dst);
|
||||
d_dst += 4;
|
||||
level3(d_dst);
|
||||
} else if (code == 0xF6) {
|
||||
tmp2 = _offset2;
|
||||
for (i = 0; i < 4; i++) {
|
||||
COPY_4X1_LINE(d_dst + 0, d_dst + tmp2 + 0);
|
||||
COPY_4X1_LINE(d_dst + 4, d_dst + tmp2 + 4);
|
||||
d_dst += _d_pitch;
|
||||
}
|
||||
} else if ((code == 0xF7) || (code == 0xF8)) {
|
||||
byte tmp = *_d_src++;
|
||||
if (code == 0xF8) {
|
||||
val = READ_LE_UINT32(_d_src);
|
||||
_d_src += 4;
|
||||
} else {
|
||||
tmp2 = READ_LE_UINT16(_d_src);
|
||||
val = READ_LE_UINT16(_param6_7Ptr + (byte)(tmp2 >> 8) * 2) << 16;
|
||||
val |= READ_LE_UINT16(_param6_7Ptr + (byte)tmp2 * 2);
|
||||
_d_src += 2;
|
||||
}
|
||||
byte *tmp_ptr = _tableSmall + (tmp * 128);
|
||||
byte l = tmp_ptr[96];
|
||||
int16 *tmp_ptr2 = (int16 *)tmp_ptr;
|
||||
while (l--) {
|
||||
WRITE_2X1_LINE(d_dst + READ_LE_UINT16(tmp_ptr2) * 2, val);
|
||||
tmp_ptr2++;
|
||||
}
|
||||
l = tmp_ptr[97];
|
||||
val >>= 16;
|
||||
tmp_ptr2 = (int16 *)(tmp_ptr + 32);
|
||||
while (l--) {
|
||||
WRITE_2X1_LINE(d_dst + READ_LE_UINT16(tmp_ptr2) * 2, val);
|
||||
tmp_ptr2++;
|
||||
}
|
||||
} else if (code >= 0xF9) {
|
||||
if (code == 0xFD) {
|
||||
t = *_d_src++;
|
||||
t = READ_LE_UINT16(_param6_7Ptr + t * 2);
|
||||
t = (t << 16) | t;
|
||||
} else if (code == 0xFE) {
|
||||
t = READ_LE_UINT16(_d_src);
|
||||
t = (t << 16) | t;
|
||||
_d_src += 2;
|
||||
} else if ((code >= 0xF9) && (code <= 0xFC)) {
|
||||
t = READ_LE_UINT16(_paramPtr + code * 2);
|
||||
t = (t << 16) | t;
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
WRITE_4X1_LINE(d_dst + 0, t);
|
||||
WRITE_4X1_LINE(d_dst + 4, t);
|
||||
d_dst += _d_pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Blocky16::level1(byte *d_dst) {
|
||||
int32 tmp2;
|
||||
uint32 t = 0, val;
|
||||
byte code = *_d_src++;
|
||||
int i;
|
||||
|
||||
if (code <= 0xF5) {
|
||||
if (code == 0xF5) {
|
||||
int16 tmp = READ_LE_UINT16(_d_src);
|
||||
tmp2 = tmp * 2;
|
||||
_d_src += 2;
|
||||
} else {
|
||||
tmp2 = _table[code] * 2;
|
||||
}
|
||||
tmp2 += _offset1;
|
||||
for (i = 0; i < 8; i++) {
|
||||
COPY_4X1_LINE(d_dst + 0, d_dst + tmp2 + 0);
|
||||
COPY_4X1_LINE(d_dst + 4, d_dst + tmp2 + 4);
|
||||
COPY_4X1_LINE(d_dst + 8, d_dst + tmp2 + 8);
|
||||
COPY_4X1_LINE(d_dst + 12, d_dst + tmp2 + 12);
|
||||
d_dst += _d_pitch;
|
||||
}
|
||||
} else if (code == 0xFF) {
|
||||
level2(d_dst);
|
||||
d_dst += 8;
|
||||
level2(d_dst);
|
||||
d_dst += _d_pitch * 4 - 8;
|
||||
level2(d_dst);
|
||||
d_dst += 8;
|
||||
level2(d_dst);
|
||||
} else if (code == 0xF6) {
|
||||
tmp2 = _offset2;
|
||||
for (i = 0; i < 8; i++) {
|
||||
COPY_4X1_LINE(d_dst + 0, d_dst + tmp2 + 0);
|
||||
COPY_4X1_LINE(d_dst + 4, d_dst + tmp2 + 4);
|
||||
COPY_4X1_LINE(d_dst + 8, d_dst + tmp2 + 8);
|
||||
COPY_4X1_LINE(d_dst + 12, d_dst + tmp2 + 12);
|
||||
d_dst += _d_pitch;
|
||||
}
|
||||
} else if ((code == 0xF7) || (code == 0xF8)) {
|
||||
byte tmp = *_d_src++;
|
||||
if (code == 0xF8) {
|
||||
val = READ_LE_UINT32(_d_src);
|
||||
_d_src += 4;
|
||||
} else {
|
||||
tmp2 = READ_LE_UINT16(_d_src);
|
||||
val = READ_LE_UINT16(_param6_7Ptr + (byte)(tmp2 >> 8) * 2) << 16;
|
||||
val |= READ_LE_UINT16(_param6_7Ptr + (byte)tmp2 * 2);
|
||||
_d_src += 2;
|
||||
}
|
||||
byte *tmp_ptr = _tableBig + (tmp * 388);
|
||||
byte l = tmp_ptr[384];
|
||||
int16 *tmp_ptr2 = (int16 *)tmp_ptr;
|
||||
while (l--) {
|
||||
WRITE_2X1_LINE(d_dst + READ_LE_UINT16(tmp_ptr2) * 2, val);
|
||||
tmp_ptr2++;
|
||||
}
|
||||
l = tmp_ptr[385];
|
||||
val >>= 16;
|
||||
tmp_ptr2 = (int16 *)(tmp_ptr + 128);
|
||||
while (l--) {
|
||||
WRITE_2X1_LINE(d_dst + READ_LE_UINT16(tmp_ptr2) * 2, val);
|
||||
tmp_ptr2++;
|
||||
}
|
||||
} else if (code >= 0xF9) {
|
||||
if (code == 0xFD) {
|
||||
t = *_d_src++;
|
||||
t = READ_LE_UINT16(_param6_7Ptr + t * 2);
|
||||
t = (t << 16) | t;
|
||||
} else if (code == 0xFE) {
|
||||
t = READ_LE_UINT16(_d_src);
|
||||
t = (t << 16) | t;
|
||||
_d_src += 2;
|
||||
} else if ((code >= 0xF9) && (code <= 0xFC)) {
|
||||
t = READ_LE_UINT16(_paramPtr + code * 2);
|
||||
t = (t << 16) | t;
|
||||
}
|
||||
for (i = 0; i < 8; i++) {
|
||||
WRITE_4X1_LINE(d_dst + 0, t);
|
||||
WRITE_4X1_LINE(d_dst + 4, t);
|
||||
WRITE_4X1_LINE(d_dst + 8, t);
|
||||
WRITE_4X1_LINE(d_dst + 12, t);
|
||||
d_dst += _d_pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Blocky16::decode2(byte *dst, const byte *src, int width, int height, const byte *param_ptr, const byte *param6_7_ptr) {
|
||||
_d_src = src;
|
||||
_paramPtr = param_ptr - 0xf9 - 0xf9;
|
||||
_param6_7Ptr = param6_7_ptr;
|
||||
int bh = _blocksHeight;
|
||||
int next_line = width * 2 * 7;
|
||||
_d_pitch = width * 2;
|
||||
|
||||
do {
|
||||
int tmp_bw = _blocksWidth;
|
||||
do {
|
||||
level1(dst);
|
||||
dst += 16;
|
||||
} while (--tmp_bw);
|
||||
dst += next_line;
|
||||
} while (--bh);
|
||||
}
|
||||
|
||||
void Blocky16::init(int width, int height) {
|
||||
deinit();
|
||||
_width = width;
|
||||
_height = height;
|
||||
makeTablesInterpolation(4);
|
||||
makeTablesInterpolation(8);
|
||||
|
||||
_blocksWidth = (width + 7) / 8;
|
||||
_blocksHeight = (height + 7) / 8;
|
||||
|
||||
_frameSize = _width * _height * 2;
|
||||
|
||||
// some animations, like tb_kitty.snm don't have a multiple of 8 width or height,
|
||||
// so set the size of the buffer in _blocksWidth * 8 * _blocksHeight * 8, instead
|
||||
// of using _frameSize.
|
||||
int size = _blocksWidth * 8 * _blocksHeight * 8 * 2;
|
||||
_offset = size - _frameSize;
|
||||
// workaround for read over buffer by increasing buffer
|
||||
// 200 bytes is enough for smush anims:
|
||||
// lol, byeruba, crushed, eldepot, heltrain, hostage
|
||||
uint32 deltaSize = size * 3 + 200;
|
||||
_deltaBuf = new byte[deltaSize]();
|
||||
_deltaBufs[0] = _deltaBuf;
|
||||
_deltaBufs[1] = _deltaBuf + _frameSize;
|
||||
_curBuf = _deltaBuf + _frameSize * 2;
|
||||
}
|
||||
|
||||
Blocky16::Blocky16() {
|
||||
_tableBig = new byte[99328]();
|
||||
_tableSmall = new byte[32768]();
|
||||
_deltaBuf = nullptr;
|
||||
_deltaBufs[0] = nullptr;
|
||||
_deltaBufs[1] = nullptr;
|
||||
_curBuf = nullptr;
|
||||
_prevSeqNb = 0;
|
||||
_lastTableWidth = 0;
|
||||
_d_src = nullptr;
|
||||
_paramPtr = nullptr;
|
||||
_param6_7Ptr = nullptr;
|
||||
_blocksHeight = _blocksWidth = 0;
|
||||
_height = _width = 0;
|
||||
_offset = _offset1 = _offset2 = 0;
|
||||
_frameSize = 0;
|
||||
_d_pitch = 0;
|
||||
}
|
||||
|
||||
void Blocky16::deinit() {
|
||||
_lastTableWidth = -1;
|
||||
if (_deltaBuf) {
|
||||
delete[] _deltaBuf;
|
||||
_deltaBuf = nullptr;
|
||||
_deltaBufs[0] = nullptr;
|
||||
_deltaBufs[1] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Blocky16::~Blocky16() {
|
||||
deinit();
|
||||
if (_tableBig) {
|
||||
delete[] _tableBig;
|
||||
_tableBig = nullptr;
|
||||
}
|
||||
if (_tableSmall) {
|
||||
delete[] _tableSmall;
|
||||
_tableSmall = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static int bomp_left;
|
||||
static int bomp_num;
|
||||
static int bomp_color;
|
||||
static const byte *bomp_src;
|
||||
|
||||
static byte bompDecode() {
|
||||
byte code, result;
|
||||
const byte *src;
|
||||
|
||||
if (bomp_left == 2) {
|
||||
src = bomp_src;
|
||||
bomp_num = (*src >> 1) + 1;
|
||||
code = *(src++) & 1;
|
||||
bomp_src = src;
|
||||
if (code != 0) {
|
||||
bomp_left = 1;
|
||||
bomp_color = *src++;
|
||||
bomp_src = src;
|
||||
} else {
|
||||
bomp_left = 0;
|
||||
}
|
||||
} else {
|
||||
src = bomp_src;
|
||||
}
|
||||
if (bomp_left != 0) {
|
||||
if (bomp_left - 1 == 0) {
|
||||
result = bomp_color;
|
||||
} else {
|
||||
result = 255;
|
||||
}
|
||||
} else {
|
||||
result = *(src++);
|
||||
bomp_src = src;
|
||||
}
|
||||
|
||||
bomp_num--;
|
||||
if (bomp_num == 0) {
|
||||
bomp_left = 2;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void bompInit(const byte *src) {
|
||||
bomp_left = 2;
|
||||
bomp_src = src;
|
||||
}
|
||||
|
||||
static void bompDecodeMain(byte *dst, const byte *src, int size) {
|
||||
size /= 2;
|
||||
bompInit(src);
|
||||
while (size--) {
|
||||
#ifdef SCUMM_BIG_ENDIAN
|
||||
*(dst + 1) = bompDecode();
|
||||
*(dst + 0) = bompDecode();
|
||||
#else
|
||||
*(dst + 0) = bompDecode();
|
||||
*(dst + 1) = bompDecode();
|
||||
#endif
|
||||
dst += 2;
|
||||
}
|
||||
}
|
||||
|
||||
void Blocky16::decode(byte *dst, const byte *src) {
|
||||
_offset1 = ((_deltaBufs[1] - _curBuf) / 2) * 2;
|
||||
_offset2 = ((_deltaBufs[0] - _curBuf) / 2) * 2;
|
||||
|
||||
int32 seq_nb = READ_LE_UINT16(src + 16);
|
||||
|
||||
const byte *gfx_data = src + 560;
|
||||
|
||||
if (seq_nb == 0) {
|
||||
makeTables47(_width);
|
||||
if (src[32] == src[33]) {
|
||||
memset(_deltaBufs[0], src[32], _frameSize);
|
||||
memset(_deltaBufs[1], src[32], _frameSize);
|
||||
} else {
|
||||
int count = _frameSize / 2;
|
||||
uint16 *ptr1 = (uint16 *)_deltaBufs[0];
|
||||
uint16 *ptr2 = (uint16 *)_deltaBufs[1];
|
||||
uint16 val = READ_LE_UINT16(src + 32);
|
||||
while (count--) {
|
||||
*(uint16 *)(ptr1++) = val;
|
||||
*(uint16 *)(ptr2++) = val;
|
||||
};
|
||||
|
||||
}
|
||||
_prevSeqNb = -1;
|
||||
}
|
||||
|
||||
switch (src[18]) {
|
||||
case 0:
|
||||
#if defined(SCUMM_BIG_ENDIAN)
|
||||
for (int i = 0; i < _width * _height; i++) {
|
||||
((uint16 *)_curBuf)[i] = READ_LE_UINT16(gfx_data + i * 2);
|
||||
}
|
||||
#else
|
||||
memcpy(_curBuf, gfx_data, _frameSize);
|
||||
#endif
|
||||
break;
|
||||
case 1:
|
||||
error("blocky16: not implemented decode1 proc");
|
||||
break;
|
||||
case 2:
|
||||
if (seq_nb == _prevSeqNb + 1) {
|
||||
decode2(_curBuf, gfx_data, _width, _height, src + 24, src + 40);
|
||||
}
|
||||
|
||||
break;
|
||||
case 3:
|
||||
memcpy(_curBuf, _deltaBufs[1], _frameSize);
|
||||
break;
|
||||
case 4:
|
||||
memcpy(_curBuf, _deltaBufs[0], _frameSize);
|
||||
break;
|
||||
case 5:
|
||||
bompDecodeMain(_curBuf, gfx_data, READ_LE_UINT32(src + 36));
|
||||
break;
|
||||
case 6:
|
||||
{
|
||||
int count = _frameSize / 2;
|
||||
uint16 *ptr = (uint16 *)_curBuf;
|
||||
while (count--) {
|
||||
int offset = *gfx_data++ * 2;
|
||||
*(uint16 *)ptr++ = READ_LE_UINT16(src + 40 + offset);
|
||||
};
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
error("blocky16: not implemented decode7 proc");
|
||||
break;
|
||||
case 8:
|
||||
{
|
||||
bompInit(gfx_data);
|
||||
int count = _frameSize / 2;
|
||||
uint16 *ptr = (uint16 *)_curBuf;
|
||||
while (count--) {
|
||||
int offset = bompDecode() * 2;
|
||||
*(uint16 *)ptr++ = READ_LE_UINT16(src + 40 + offset);
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(dst, _curBuf, _frameSize);
|
||||
|
||||
if (seq_nb == _prevSeqNb + 1) {
|
||||
byte *tmp_ptr = nullptr;
|
||||
if (src[19] == 1) {
|
||||
tmp_ptr = _curBuf;
|
||||
_curBuf = _deltaBufs[1];
|
||||
_deltaBufs[1] = tmp_ptr;
|
||||
} else if (src[19] == 2) {
|
||||
tmp_ptr = _deltaBufs[0];
|
||||
_deltaBufs[0] = _deltaBufs[1];
|
||||
_deltaBufs[1] = _curBuf - _offset; // subtract the offset here or else a black bar will appear
|
||||
_curBuf = tmp_ptr; // on top of tb_kitty.snm.
|
||||
}
|
||||
}
|
||||
_prevSeqNb = seq_nb;
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
65
engines/grim/movie/codecs/blocky16.h
Normal file
65
engines/grim/movie/codecs/blocky16.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRIM_BLOCKY16_H
|
||||
#define GRIM_BLOCKY16_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class Blocky16 {
|
||||
private:
|
||||
|
||||
byte *_deltaBufs[2];
|
||||
byte *_deltaBuf;
|
||||
byte *_curBuf;
|
||||
int32 _prevSeqNb;
|
||||
int _lastTableWidth;
|
||||
const byte *_d_src, *_paramPtr, *_param6_7Ptr;
|
||||
int _d_pitch;
|
||||
int32 _offset1, _offset2;
|
||||
byte *_tableBig;
|
||||
byte *_tableSmall;
|
||||
int16 _table[256];
|
||||
int32 _frameSize;
|
||||
int _offset;
|
||||
int _width, _height;
|
||||
int _blocksWidth, _blocksHeight;
|
||||
|
||||
void makeTablesInterpolation(int param);
|
||||
void makeTables47(int width);
|
||||
void level1(byte *d_dst);
|
||||
void level2(byte *d_dst);
|
||||
void level3(byte *d_dst);
|
||||
void decode2(byte *dst, const byte *src, int width, int height, const byte *param_ptr, const byte *param6_7_ptr);
|
||||
|
||||
public:
|
||||
Blocky16();
|
||||
~Blocky16();
|
||||
void init(int width, int height);
|
||||
void deinit();
|
||||
void decode(byte *dst, const byte *src);
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
659
engines/grim/movie/codecs/blocky8.cpp
Normal file
659
engines/grim/movie/codecs/blocky8.cpp
Normal file
@@ -0,0 +1,659 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "common/util.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "engines/grim/movie/codecs/blocky8.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
#if defined(SCUMM_NEED_ALIGNMENT)
|
||||
|
||||
#define COPY_4X1_LINE(dst, src) \
|
||||
do { \
|
||||
(dst)[0] = (src)[0]; \
|
||||
(dst)[1] = (src)[1]; \
|
||||
(dst)[2] = (src)[2]; \
|
||||
(dst)[3] = (src)[3]; \
|
||||
} while (0)
|
||||
|
||||
#define COPY_2X1_LINE(dst, src) \
|
||||
do { \
|
||||
(dst)[0] = (src)[0]; \
|
||||
(dst)[1] = (src)[1]; \
|
||||
} while (0)
|
||||
|
||||
|
||||
#else /* SCUMM_NEED_ALIGNMENT */
|
||||
|
||||
#define COPY_4X1_LINE(dst, src) \
|
||||
*(uint32 *)(dst) = *(const uint32 *)(src)
|
||||
|
||||
#define COPY_2X1_LINE(dst, src) \
|
||||
*(uint16 *)(dst) = *(const uint16 *)(src)
|
||||
|
||||
#endif
|
||||
|
||||
#define FILL_4X1_LINE(dst, val) \
|
||||
do { \
|
||||
(dst)[0] = val; \
|
||||
(dst)[1] = val; \
|
||||
(dst)[2] = val; \
|
||||
(dst)[3] = val; \
|
||||
} while (0)
|
||||
|
||||
#define FILL_2X1_LINE(dst, val) \
|
||||
do { \
|
||||
(dst)[0] = val; \
|
||||
(dst)[1] = val; \
|
||||
} while (0)
|
||||
|
||||
static const int8 blocky8_table_small1[] = {
|
||||
0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1,
|
||||
};
|
||||
|
||||
static const int8 blocky8_table_small2[] = {
|
||||
0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2,
|
||||
};
|
||||
|
||||
static const int8 blocky8_table_big1[] = {
|
||||
0, 2, 5, 7, 7, 7, 7, 7, 7, 5, 2, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static const int8 blocky8_table_big2[] = {
|
||||
0, 0, 0, 0, 1, 3, 4, 6, 7, 7, 7, 7, 6, 4, 3, 1,
|
||||
};
|
||||
|
||||
static const int8 blocky8_table[] = {
|
||||
0, 0, -1, -43, 6, -43, -9, -42, 13, -41,
|
||||
-16, -40, 19, -39, -23, -36, 26, -34, -2, -33,
|
||||
4, -33, -29, -32, -9, -32, 11, -31, -16, -29,
|
||||
32, -29, 18, -28, -34, -26, -22, -25, -1, -25,
|
||||
3, -25, -7, -24, 8, -24, 24, -23, 36, -23,
|
||||
-12, -22, 13, -21, -38, -20, 0, -20, -27, -19,
|
||||
-4, -19, 4, -19, -17, -18, -8, -17, 8, -17,
|
||||
18, -17, 28, -17, 39, -17, -12, -15, 12, -15,
|
||||
-21, -14, -1, -14, 1, -14, -41, -13, -5, -13,
|
||||
5, -13, 21, -13, -31, -12, -15, -11, -8, -11,
|
||||
8, -11, 15, -11, -2, -10, 1, -10, 31, -10,
|
||||
-23, -9, -11, -9, -5, -9, 4, -9, 11, -9,
|
||||
42, -9, 6, -8, 24, -8, -18, -7, -7, -7,
|
||||
-3, -7, -1, -7, 2, -7, 18, -7, -43, -6,
|
||||
-13, -6, -4, -6, 4, -6, 8, -6, -33, -5,
|
||||
-9, -5, -2, -5, 0, -5, 2, -5, 5, -5,
|
||||
13, -5, -25, -4, -6, -4, -3, -4, 3, -4,
|
||||
9, -4, -19, -3, -7, -3, -4, -3, -2, -3,
|
||||
-1, -3, 0, -3, 1, -3, 2, -3, 4, -3,
|
||||
6, -3, 33, -3, -14, -2, -10, -2, -5, -2,
|
||||
-3, -2, -2, -2, -1, -2, 0, -2, 1, -2,
|
||||
2, -2, 3, -2, 5, -2, 7, -2, 14, -2,
|
||||
19, -2, 25, -2, 43, -2, -7, -1, -3, -1,
|
||||
-2, -1, -1, -1, 0, -1, 1, -1, 2, -1,
|
||||
3, -1, 10, -1, -5, 0, -3, 0, -2, 0,
|
||||
-1, 0, 1, 0, 2, 0, 3, 0, 5, 0,
|
||||
7, 0, -10, 1, -7, 1, -3, 1, -2, 1,
|
||||
-1, 1, 0, 1, 1, 1, 2, 1, 3, 1,
|
||||
-43, 2, -25, 2, -19, 2, -14, 2, -5, 2,
|
||||
-3, 2, -2, 2, -1, 2, 0, 2, 1, 2,
|
||||
2, 2, 3, 2, 5, 2, 7, 2, 10, 2,
|
||||
14, 2, -33, 3, -6, 3, -4, 3, -2, 3,
|
||||
-1, 3, 0, 3, 1, 3, 2, 3, 4, 3,
|
||||
19, 3, -9, 4, -3, 4, 3, 4, 7, 4,
|
||||
25, 4, -13, 5, -5, 5, -2, 5, 0, 5,
|
||||
2, 5, 5, 5, 9, 5, 33, 5, -8, 6,
|
||||
-4, 6, 4, 6, 13, 6, 43, 6, -18, 7,
|
||||
-2, 7, 0, 7, 2, 7, 7, 7, 18, 7,
|
||||
-24, 8, -6, 8, -42, 9, -11, 9, -4, 9,
|
||||
5, 9, 11, 9, 23, 9, -31, 10, -1, 10,
|
||||
2, 10, -15, 11, -8, 11, 8, 11, 15, 11,
|
||||
31, 12, -21, 13, -5, 13, 5, 13, 41, 13,
|
||||
-1, 14, 1, 14, 21, 14, -12, 15, 12, 15,
|
||||
-39, 17, -28, 17, -18, 17, -8, 17, 8, 17,
|
||||
17, 18, -4, 19, 0, 19, 4, 19, 27, 19,
|
||||
38, 20, -13, 21, 12, 22, -36, 23, -24, 23,
|
||||
-8, 24, 7, 24, -3, 25, 1, 25, 22, 25,
|
||||
34, 26, -18, 28, -32, 29, 16, 29, -11, 31,
|
||||
9, 32, 29, 32, -4, 33, 2, 33, -26, 34,
|
||||
23, 36, -19, 39, 16, 40, -13, 41, 9, 42,
|
||||
-6, 43, 1, 43, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0
|
||||
};
|
||||
|
||||
void Blocky8::makeTablesInterpolation(int param) {
|
||||
int32 variable1, variable2;
|
||||
int32 b1, b2;
|
||||
int32 value_table47_1_2, value_table47_1_1, value_table47_2_2, value_table47_2_1;
|
||||
int32 tableSmallBig[64], tmp, s;
|
||||
const int8 *table47_1 = nullptr, *table47_2 = nullptr;
|
||||
int32 *ptr_small_big;
|
||||
byte *ptr;
|
||||
int i, x, y;
|
||||
|
||||
if (param == 8) {
|
||||
table47_1 = blocky8_table_big1;
|
||||
table47_2 = blocky8_table_big2;
|
||||
ptr = _tableBig;
|
||||
for (i = 0; i < 256; i++) {
|
||||
ptr[384] = 0;
|
||||
ptr[385] = 0;
|
||||
ptr += 388;
|
||||
}
|
||||
} else if (param == 4) {
|
||||
table47_1 = blocky8_table_small1;
|
||||
table47_2 = blocky8_table_small2;
|
||||
ptr = _tableSmall;
|
||||
for (i = 0; i < 256; i++) {
|
||||
ptr[96] = 0;
|
||||
ptr[97] = 0;
|
||||
ptr += 128;
|
||||
}
|
||||
} else {
|
||||
error("Blocky8::makeTablesInterpolation: unknown param %d", param);
|
||||
}
|
||||
|
||||
s = 0;
|
||||
for (x = 0; x < 16; x++) {
|
||||
value_table47_1_1 = table47_1[x];
|
||||
value_table47_2_1 = table47_2[x];
|
||||
for (y = 0; y < 16; y++) {
|
||||
value_table47_1_2 = table47_1[y];
|
||||
value_table47_2_2 = table47_2[y];
|
||||
|
||||
if (value_table47_2_1 == 0) {
|
||||
b1 = 0;
|
||||
} else if (value_table47_2_1 == param - 1) {
|
||||
b1 = 1;
|
||||
} else if (value_table47_1_1 == 0) {
|
||||
b1 = 2;
|
||||
} else if (value_table47_1_1 == param - 1) {
|
||||
b1 = 3;
|
||||
} else {
|
||||
b1 = 4;
|
||||
}
|
||||
|
||||
if (value_table47_2_2 == 0) {
|
||||
b2 = 0;
|
||||
} else if (value_table47_2_2 == param - 1) {
|
||||
b2 = 1;
|
||||
} else if (value_table47_1_2 == 0) {
|
||||
b2 = 2;
|
||||
} else if (value_table47_1_2 == param - 1) {
|
||||
b2 = 3;
|
||||
} else {
|
||||
b2 = 4;
|
||||
}
|
||||
|
||||
memset(tableSmallBig, 0, param * param * 4);
|
||||
|
||||
variable2 = ABS(value_table47_2_2 - value_table47_2_1);
|
||||
tmp = ABS(value_table47_1_2 - value_table47_1_1);
|
||||
if (variable2 <= tmp) {
|
||||
variable2 = tmp;
|
||||
}
|
||||
|
||||
for (variable1 = 0; variable1 <= variable2; variable1++) {
|
||||
int32 variable3, variable4;
|
||||
|
||||
if (variable2 > 0) {
|
||||
// Linearly interpolate between value_table47_1_1 and value_table47_1_2
|
||||
// respectively value_table47_2_1 and value_table47_2_2.
|
||||
variable4 = (value_table47_1_1 * variable1 + value_table47_1_2 * (variable2 - variable1) + variable2 / 2) / variable2;
|
||||
variable3 = (value_table47_2_1 * variable1 + value_table47_2_2 * (variable2 - variable1) + variable2 / 2) / variable2;
|
||||
} else {
|
||||
variable4 = value_table47_1_1;
|
||||
variable3 = value_table47_2_1;
|
||||
}
|
||||
ptr_small_big = &tableSmallBig[param * variable3 + variable4];
|
||||
*ptr_small_big = 1;
|
||||
|
||||
if ((b1 == 2 && b2 == 3) || (b2 == 2 && b1 == 3) ||
|
||||
(b1 == 0 && b2 != 1) || (b2 == 0 && b1 != 1)) {
|
||||
if (variable3 >= 0) {
|
||||
i = variable3 + 1;
|
||||
while (i--) {
|
||||
*ptr_small_big = 1;
|
||||
ptr_small_big -= param;
|
||||
}
|
||||
}
|
||||
} else if ((b2 != 0 && b1 == 1) || (b1 != 0 && b2 == 1)) {
|
||||
if (param > variable3) {
|
||||
i = param - variable3;
|
||||
while (i--) {
|
||||
*ptr_small_big = 1;
|
||||
ptr_small_big += param;
|
||||
}
|
||||
}
|
||||
} else if ((b1 == 2 && b2 != 3) || (b2 == 2 && b1 != 3)) {
|
||||
if (variable4 >= 0) {
|
||||
i = variable4 + 1;
|
||||
while (i--) {
|
||||
*(ptr_small_big--) = 1;
|
||||
}
|
||||
}
|
||||
} else if ((b1 == 0 && b2 == 1) || (b2 == 0 && b1 == 1) ||
|
||||
(b1 == 3 && b2 != 2) || (b2 == 3 && b1 != 2)) {
|
||||
if (param > variable4) {
|
||||
i = param - variable4;
|
||||
while (i--) {
|
||||
*(ptr_small_big++) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (param == 8) {
|
||||
for (i = 64 - 1; i >= 0; i--) {
|
||||
if (tableSmallBig[i] != 0) {
|
||||
_tableBig[256 + s + _tableBig[384 + s]] = (byte)i;
|
||||
_tableBig[384 + s]++;
|
||||
} else {
|
||||
_tableBig[320 + s + _tableBig[385 + s]] = (byte)i;
|
||||
_tableBig[385 + s]++;
|
||||
}
|
||||
}
|
||||
s += 388;
|
||||
}
|
||||
if (param == 4) {
|
||||
for (i = 16 - 1; i >= 0; i--) {
|
||||
if (tableSmallBig[i] != 0) {
|
||||
_tableSmall[64 + s + _tableSmall[96 + s]] = (byte)i;
|
||||
_tableSmall[96 + s]++;
|
||||
} else {
|
||||
_tableSmall[80 + s + _tableSmall[97 + s]] = (byte)i;
|
||||
_tableSmall[97 + s]++;
|
||||
}
|
||||
}
|
||||
s += 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Blocky8::makeTables47(int width) {
|
||||
if (_lastTableWidth == width)
|
||||
return;
|
||||
|
||||
_lastTableWidth = width;
|
||||
|
||||
int32 a, c, d;
|
||||
int16 tmp;
|
||||
|
||||
for (int l = 0; l < 512; l += 2) {
|
||||
_table[l / 2] = (int16)(blocky8_table[l + 1] * width + blocky8_table[l]);
|
||||
}
|
||||
|
||||
a = 0;
|
||||
c = 0;
|
||||
do {
|
||||
for (d = 0; d < _tableSmall[96 + c]; d++) {
|
||||
tmp = _tableSmall[64 + c + d];
|
||||
tmp = (int16)((byte)(tmp >> 2) * width + (tmp & 3));
|
||||
_tableSmall[c + d * 2] = (byte)tmp;
|
||||
_tableSmall[c + d * 2 + 1] = tmp >> 8;
|
||||
}
|
||||
for (d = 0; d < _tableSmall[97 + c]; d++) {
|
||||
tmp = _tableSmall[80 + c + d];
|
||||
tmp = (int16)((byte)(tmp >> 2) * width + (tmp & 3));
|
||||
_tableSmall[32 + c + d * 2] = (byte)tmp;
|
||||
_tableSmall[32 + c + d * 2 + 1] = tmp >> 8;
|
||||
}
|
||||
for (d = 0; d < _tableBig[384 + a]; d++) {
|
||||
tmp = _tableBig[256 + a + d];
|
||||
tmp = (int16)((byte)(tmp >> 3) * width + (tmp & 7));
|
||||
_tableBig[a + d * 2] = (byte)tmp;
|
||||
_tableBig[a + d * 2 + 1] = tmp >> 8;
|
||||
}
|
||||
for (d = 0; d < _tableBig[385 + a]; d++) {
|
||||
tmp = _tableBig[320 + a + d];
|
||||
tmp = (int16)((byte)(tmp >> 3) * width + (tmp & 7));
|
||||
_tableBig[128 + a + d * 2] = (byte)tmp;
|
||||
_tableBig[128 + a + d * 2 + 1] = tmp >> 8;
|
||||
}
|
||||
|
||||
a += 388;
|
||||
c += 128;
|
||||
} while (c < 32768);
|
||||
}
|
||||
|
||||
#ifdef USE_ARM_SMUSH_ASM
|
||||
|
||||
extern "C" {
|
||||
#ifndef IPHONE
|
||||
#define ARM_Blocky8_decode2 _ARM_Blocky8_decode2
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" void ARM_Blocky8_decode2(byte *dst, const byte *src, int width, int height, const byte *param_ptr,
|
||||
int16 *_table, byte *_tableBig, int32 offset1, int32 offset2, byte *_tableSmall);
|
||||
|
||||
#define decode2(SRC,DST,WIDTH,HEIGHT,PARAM) \
|
||||
ARM_Blocky8_decode2(SRC,DST,WIDTH,HEIGHT,PARAM,_table,_tableBig, \
|
||||
_offset1,_offset2,_tableSmall)
|
||||
|
||||
#else
|
||||
void Blocky8::level3(byte *d_dst) {
|
||||
int32 tmp;
|
||||
byte code = *_d_src++;
|
||||
|
||||
if (code < 0xF8) {
|
||||
tmp = _table[code] + _offset1;
|
||||
COPY_2X1_LINE(d_dst, d_dst + tmp);
|
||||
COPY_2X1_LINE(d_dst + _d_pitch, d_dst + _d_pitch + tmp);
|
||||
} else if (code == 0xFF) {
|
||||
COPY_2X1_LINE(d_dst, _d_src + 0);
|
||||
COPY_2X1_LINE(d_dst + _d_pitch, _d_src + 2);
|
||||
_d_src += 4;
|
||||
} else if (code == 0xFE) {
|
||||
byte t = *_d_src++;
|
||||
FILL_2X1_LINE(d_dst, t);
|
||||
FILL_2X1_LINE(d_dst + _d_pitch, t);
|
||||
} else if (code == 0xFC) {
|
||||
tmp = _offset2;
|
||||
COPY_2X1_LINE(d_dst, d_dst + tmp);
|
||||
COPY_2X1_LINE(d_dst + _d_pitch, d_dst + _d_pitch + tmp);
|
||||
} else {
|
||||
byte t = _paramPtr[code];
|
||||
FILL_2X1_LINE(d_dst, t);
|
||||
FILL_2X1_LINE(d_dst + _d_pitch, t);
|
||||
}
|
||||
}
|
||||
|
||||
void Blocky8::level2(byte *d_dst) {
|
||||
int32 tmp;
|
||||
byte code = *_d_src++;
|
||||
int i;
|
||||
|
||||
if (code < 0xF8) {
|
||||
tmp = _table[code] + _offset1;
|
||||
for (i = 0; i < 4; i++) {
|
||||
COPY_4X1_LINE(d_dst, d_dst + tmp);
|
||||
d_dst += _d_pitch;
|
||||
}
|
||||
} else if (code == 0xFF) {
|
||||
level3(d_dst);
|
||||
d_dst += 2;
|
||||
level3(d_dst);
|
||||
d_dst += _d_pitch * 2 - 2;
|
||||
level3(d_dst);
|
||||
d_dst += 2;
|
||||
level3(d_dst);
|
||||
} else if (code == 0xFE) {
|
||||
byte t = *_d_src++;
|
||||
for (i = 0; i < 4; i++) {
|
||||
FILL_4X1_LINE(d_dst, t);
|
||||
d_dst += _d_pitch;
|
||||
}
|
||||
} else if (code == 0xFD) {
|
||||
byte *tmp_ptr = _tableSmall + *_d_src++ * 128;
|
||||
int32 l = tmp_ptr[96];
|
||||
byte val = *_d_src++;
|
||||
int16 *tmp_ptr2 = (int16 *)tmp_ptr;
|
||||
while (l--) {
|
||||
*(d_dst + READ_LE_UINT16(tmp_ptr2)) = val;
|
||||
tmp_ptr2++;
|
||||
}
|
||||
l = tmp_ptr[97];
|
||||
val = *_d_src++;
|
||||
tmp_ptr2 = (int16 *)(tmp_ptr + 32);
|
||||
while (l--) {
|
||||
*(d_dst + READ_LE_UINT16(tmp_ptr2)) = val;
|
||||
tmp_ptr2++;
|
||||
}
|
||||
} else if (code == 0xFC) {
|
||||
tmp = _offset2;
|
||||
for (i = 0; i < 4; i++) {
|
||||
COPY_4X1_LINE(d_dst, d_dst + tmp);
|
||||
d_dst += _d_pitch;
|
||||
}
|
||||
} else {
|
||||
byte t = _paramPtr[code];
|
||||
for (i = 0; i < 4; i++) {
|
||||
FILL_4X1_LINE(d_dst, t);
|
||||
d_dst += _d_pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Blocky8::level1(byte *d_dst) {
|
||||
int32 tmp, tmp2;
|
||||
byte code = *_d_src++;
|
||||
int i;
|
||||
|
||||
if (code < 0xF8) {
|
||||
tmp2 = _table[code] + _offset1;
|
||||
for (i = 0; i < 8; i++) {
|
||||
COPY_4X1_LINE(d_dst + 0, d_dst + tmp2);
|
||||
COPY_4X1_LINE(d_dst + 4, d_dst + tmp2 + 4);
|
||||
d_dst += _d_pitch;
|
||||
}
|
||||
} else if (code == 0xFF) {
|
||||
level2(d_dst);
|
||||
d_dst += 4;
|
||||
level2(d_dst);
|
||||
d_dst += _d_pitch * 4 - 4;
|
||||
level2(d_dst);
|
||||
d_dst += 4;
|
||||
level2(d_dst);
|
||||
} else if (code == 0xFE) {
|
||||
byte t = *_d_src++;
|
||||
for (i = 0; i < 8; i++) {
|
||||
FILL_4X1_LINE(d_dst, t);
|
||||
FILL_4X1_LINE(d_dst + 4, t);
|
||||
d_dst += _d_pitch;
|
||||
}
|
||||
} else if (code == 0xFD) {
|
||||
tmp = *_d_src++;
|
||||
byte *tmp_ptr = _tableBig + tmp * 388;
|
||||
byte l = tmp_ptr[384];
|
||||
byte val = *_d_src++;
|
||||
int16 *tmp_ptr2 = (int16 *)tmp_ptr;
|
||||
while (l--) {
|
||||
*(d_dst + READ_LE_UINT16(tmp_ptr2)) = val;
|
||||
tmp_ptr2++;
|
||||
}
|
||||
l = tmp_ptr[385];
|
||||
val = *_d_src++;
|
||||
tmp_ptr2 = (int16 *)(tmp_ptr + 128);
|
||||
while (l--) {
|
||||
*(d_dst + READ_LE_UINT16(tmp_ptr2)) = val;
|
||||
tmp_ptr2++;
|
||||
}
|
||||
} else if (code == 0xFC) {
|
||||
tmp2 = _offset2;
|
||||
for (i = 0; i < 8; i++) {
|
||||
COPY_4X1_LINE(d_dst + 0, d_dst + tmp2);
|
||||
COPY_4X1_LINE(d_dst + 4, d_dst + tmp2 + 4);
|
||||
d_dst += _d_pitch;
|
||||
}
|
||||
} else {
|
||||
byte t = _paramPtr[code];
|
||||
for (i = 0; i < 8; i++) {
|
||||
FILL_4X1_LINE(d_dst, t);
|
||||
FILL_4X1_LINE(d_dst + 4, t);
|
||||
d_dst += _d_pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Blocky8::decode2(byte *dst, const byte *src, int width, int height, const byte *param_ptr) {
|
||||
_d_src = src;
|
||||
_paramPtr = param_ptr - 0xf8;
|
||||
int bw = (width + 7) / 8;
|
||||
int bh = (height + 7) / 8;
|
||||
int next_line = width * 7;
|
||||
_d_pitch = width;
|
||||
|
||||
do {
|
||||
int tmp_bw = bw;
|
||||
do {
|
||||
level1(dst);
|
||||
dst += 8;
|
||||
} while (--tmp_bw);
|
||||
dst += next_line;
|
||||
} while (--bh);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void bompDecodeLine(byte *dst, const byte *src, int len) {
|
||||
assert(len > 0);
|
||||
|
||||
int num;
|
||||
byte code, color;
|
||||
|
||||
while (len > 0) {
|
||||
code = *src++;
|
||||
num = (code >> 1) + 1;
|
||||
if (num > len)
|
||||
num = len;
|
||||
len -= num;
|
||||
if (code & 1) {
|
||||
color = *src++;
|
||||
memset(dst, color, num);
|
||||
} else {
|
||||
memcpy(dst, src, num);
|
||||
src += num;
|
||||
}
|
||||
dst += num;
|
||||
}
|
||||
}
|
||||
|
||||
Blocky8::Blocky8() {
|
||||
_tableBig = new byte[99328]();
|
||||
_tableSmall = new byte[32768]();
|
||||
_deltaBuf = nullptr;
|
||||
_width = -1;
|
||||
_height = -1;
|
||||
_frameSize = 0;
|
||||
_offset1 = 0;
|
||||
_offset2 = 0;
|
||||
_prevSeqNb = 0;
|
||||
_lastTableWidth = 0;
|
||||
_deltaBufs[0] = nullptr;
|
||||
_deltaBufs[1] = nullptr;
|
||||
_curBuf = nullptr;
|
||||
_d_pitch = 0;
|
||||
_d_src = nullptr;
|
||||
_paramPtr = nullptr;
|
||||
}
|
||||
|
||||
void Blocky8::init(int width, int height) {
|
||||
if (_width == width && _height == height)
|
||||
return;
|
||||
deinit();
|
||||
_width = width;
|
||||
_height = height;
|
||||
makeTablesInterpolation(4);
|
||||
makeTablesInterpolation(8);
|
||||
|
||||
_frameSize = _width * _height;
|
||||
uint32 deltaSize = _frameSize * 3;
|
||||
_deltaBuf = new byte[deltaSize]();
|
||||
_deltaBufs[0] = _deltaBuf;
|
||||
_deltaBufs[1] = _deltaBuf + _frameSize;
|
||||
_curBuf = _deltaBuf + _frameSize * 2;
|
||||
}
|
||||
|
||||
void Blocky8::deinit() {
|
||||
_lastTableWidth = -1;
|
||||
if (_deltaBuf) {
|
||||
delete[] _deltaBuf;
|
||||
_deltaBuf = nullptr;
|
||||
_deltaBufs[0] = nullptr;
|
||||
_deltaBufs[1] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Blocky8::~Blocky8() {
|
||||
deinit();
|
||||
if (_tableBig) {
|
||||
delete[] _tableBig;
|
||||
_tableBig = nullptr;
|
||||
}
|
||||
if (_tableSmall) {
|
||||
delete[] _tableSmall;
|
||||
_tableSmall = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Blocky8::decode(byte *dst, const byte *src) {
|
||||
if ((_tableBig == nullptr) || (_tableSmall == nullptr) || (_deltaBuf == nullptr))
|
||||
return false;
|
||||
|
||||
_offset1 = _deltaBufs[1] - _curBuf;
|
||||
_offset2 = _deltaBufs[0] - _curBuf;
|
||||
|
||||
int32 seq_nb = READ_LE_UINT16(src + 0);
|
||||
|
||||
const byte *gfx_data = src + 26;
|
||||
|
||||
if (seq_nb == 0) {
|
||||
makeTables47(_width);
|
||||
memset(_deltaBufs[0], src[12], _frameSize);
|
||||
memset(_deltaBufs[1], src[13], _frameSize);
|
||||
_prevSeqNb = -1;
|
||||
}
|
||||
|
||||
if ((src[4] & 1) != 0) {
|
||||
gfx_data += 32896;
|
||||
}
|
||||
|
||||
switch (src[2]) {
|
||||
case 0:
|
||||
memcpy(_curBuf, gfx_data, _frameSize);
|
||||
break;
|
||||
case 1:
|
||||
// Used by Outlaws, but not by any SCUMM game.
|
||||
error("blocky8: not implemented decode1 proc");
|
||||
break;
|
||||
case 2:
|
||||
if (seq_nb == _prevSeqNb + 1) {
|
||||
decode2(_curBuf, gfx_data, _width, _height, src + 8);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
memcpy(_curBuf, _deltaBufs[1], _frameSize);
|
||||
break;
|
||||
case 4:
|
||||
memcpy(_curBuf, _deltaBufs[0], _frameSize);
|
||||
break;
|
||||
case 5:
|
||||
bompDecodeLine(_curBuf, gfx_data, READ_LE_UINT32(src + 14));
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(dst, _curBuf, _frameSize);
|
||||
|
||||
if (seq_nb == _prevSeqNb + 1) {
|
||||
if (src[3] == 1) {
|
||||
SWAP(_curBuf, _deltaBufs[1]);
|
||||
} else if (src[3] == 2) {
|
||||
SWAP(_deltaBufs[0], _deltaBufs[1]);
|
||||
SWAP(_deltaBufs[1], _curBuf);
|
||||
}
|
||||
}
|
||||
_prevSeqNb = seq_nb;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Grim
|
||||
63
engines/grim/movie/codecs/blocky8.h
Normal file
63
engines/grim/movie/codecs/blocky8.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SMUSH_BLOCKY8_H
|
||||
#define SMUSH_BLOCKY8_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class Blocky8 {
|
||||
private:
|
||||
|
||||
byte *_deltaBufs[2];
|
||||
byte *_deltaBuf;
|
||||
byte *_curBuf;
|
||||
int32 _prevSeqNb;
|
||||
int _lastTableWidth;
|
||||
const byte *_d_src, *_paramPtr;
|
||||
int _d_pitch;
|
||||
int32 _offset1, _offset2;
|
||||
byte *_tableBig;
|
||||
byte *_tableSmall;
|
||||
int16 _table[256];
|
||||
int32 _frameSize;
|
||||
int _width, _height;
|
||||
|
||||
void makeTablesInterpolation(int param);
|
||||
void makeTables47(int width);
|
||||
void level1(byte *d_dst);
|
||||
void level2(byte *d_dst);
|
||||
void level3(byte *d_dst);
|
||||
void decode2(byte *dst, const byte *src, int width, int height, const byte *param_ptr);
|
||||
|
||||
public:
|
||||
Blocky8();
|
||||
~Blocky8();
|
||||
void init(int width, int height);
|
||||
void deinit();
|
||||
bool decode(byte *dst, const byte *src);
|
||||
};
|
||||
|
||||
} // End of namespace Grim
|
||||
|
||||
#endif
|
||||
368
engines/grim/movie/codecs/blocky8ARM.s
Normal file
368
engines/grim/movie/codecs/blocky8ARM.s
Normal file
@@ -0,0 +1,368 @@
|
||||
@ 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/>.
|
||||
@
|
||||
@ @author Robin Watts (robin@wss.co.uk)
|
||||
@
|
||||
@ This file, provides an ARM optimised version of sections of blocky8.cpp.
|
||||
@ The algorithm is essentially the same as that within blocky8.cpp
|
||||
@ so to understand this file you should understand blocky8.cpp first.
|
||||
|
||||
.text
|
||||
|
||||
.global _ARM_Blocky8_decode2
|
||||
|
||||
_ARM_Blocky8_decode2:
|
||||
@ r0 = dst
|
||||
@ r1 = src
|
||||
@ r2 = width
|
||||
@ r3 = height
|
||||
@ r4 = param
|
||||
@ <> = _table
|
||||
@ <> = _tableBig
|
||||
@ <> = _offset1
|
||||
@ <> = _offset2
|
||||
@ <> = _tableSmall
|
||||
STMFD r13!,{r2,r4-r11,R14}
|
||||
|
||||
LDR r4,[r13,#40] @ r4 = param (40 = (9+1)*4)
|
||||
@ stall
|
||||
@ stall
|
||||
SUB r4,r4,#0xF8
|
||||
|
||||
@ r0 = dst
|
||||
@ r1 = _d_src
|
||||
@ r2 = _d_pitch
|
||||
@ r3 = height
|
||||
@ r4 = param
|
||||
ADD r7,r2,#7 @ r14 = bw
|
||||
MOV r7,r7,LSR #3
|
||||
y_loop:
|
||||
x_loop:
|
||||
@ LEVEL 1
|
||||
LDRB r6,[r1],#1 @ r6 = *_d_src++
|
||||
@ stall
|
||||
@ stall
|
||||
CMP r6,#0xF8
|
||||
BLT level1codeSMALL
|
||||
CMP r6,#0xFC
|
||||
BLT level1codeMID
|
||||
BEQ level1codeFC
|
||||
CMP r6,#0xFE
|
||||
BGT level1codeFF
|
||||
BEQ level1codeFE
|
||||
level1codeFD:
|
||||
LDRB r6,[r1],#1 @ r6 = tmp = *_d_src++
|
||||
LDR r8,[r13,#48] @ r8 = _tableBig (48 = (9+1+2)*4)
|
||||
@ stall
|
||||
ADD r12,r6,r6,LSL #1 @ r12= tmp*3
|
||||
ADD r6,r6,r12,LSL #5 @ r6 = tmp*97
|
||||
ADD r8,r8,r6,LSL #2 @ r8 = _tableBig + tmp*388
|
||||
LDRB r9,[r8,#384] @ r9 = l = tmp_ptr[384]
|
||||
LDRB r6,[r1],#1 @ r6 = val = *_d_src++
|
||||
ADD r12,r8,#384 @ r12= &tmp_ptr[384]
|
||||
@ I don''t really believe the next 2 lines are necessary, but...
|
||||
CMP r9,#0
|
||||
BEQ level1codeFD_over1
|
||||
level1codeFD_loop1:
|
||||
LDRB r10,[r8],#1
|
||||
LDRB r11,[r8],#1
|
||||
SUBS r9,r9,#1
|
||||
ADD r10,r10,r0
|
||||
STRB r6,[r10,r11,LSL #8] @ *(_d_dst + (*tmp_ptr2++)) = val
|
||||
BGT level1codeFD_loop1
|
||||
level1codeFD_over1:
|
||||
LDRB r9,[r12,#1] @ r9 = l = tmp_ptr[385]
|
||||
LDRB r6,[r1],#1 @ r6 = val = *_d_src++
|
||||
SUB r12,r12,#256 @ r12= &tmp_ptr[128] (256 = 384-128)
|
||||
@ I don''t really believe the next 2 lines are necessary, but...
|
||||
CMP r9,#0
|
||||
BEQ level1codeFD_over2
|
||||
level1codeFD_loop2:
|
||||
LDRB r10,[r12],#1
|
||||
LDRB r11,[r12],#1
|
||||
SUBS r9,r9,#1
|
||||
ADD r10,r10,r0
|
||||
STRB r6,[r10,r11,LSL #8] @ *(_d_dst + (*tmp_ptr2++)) = val
|
||||
BGT level1codeFD_loop2
|
||||
level1codeFD_over2:
|
||||
level1_end:
|
||||
|
||||
ADD r0,r0,#8
|
||||
SUBS r7,r7,#1
|
||||
BGT x_loop
|
||||
|
||||
ADD r7,r2,#7
|
||||
MOV r7,r7,LSR #3
|
||||
ADD r0,r0,r2,LSL #3
|
||||
SUB r0,r0,r7,LSL #3 @ r0 = dst += next_line
|
||||
SUBS r3,r3,#8 @ if (--bh > 0)
|
||||
BGT y_loop @ loop back
|
||||
|
||||
LDMFD r13!,{r2,r4-r11,PC}
|
||||
|
||||
level1codeSMALL:
|
||||
LDR r8,[r13,#44] @ r8 = _table (44 = (9+1+1)*4)
|
||||
LDR r9,[r13,#52] @ r9 = _offset1 (52 = (9+1+3)*4)
|
||||
MOV r6,r6,LSL #1 @ r6 = code<<1
|
||||
LDRSH r8,[r8,r6] @ tmp2 = _table[code]
|
||||
level1codeFC:
|
||||
@ EQ => FC
|
||||
LDREQ r9,[r13,#56] @ r9 = _offset2 (56 = (9+1+4)*4)
|
||||
MOVEQ r8,#0
|
||||
SUB r11,r2,#7 @ r11 = _d_pitch-7
|
||||
ADD r9,r9,r0 @ tmp2 = _d_dst+_offset
|
||||
ADD r8,r8,r9 @ tmp2 = _d_dst+_table[code]+_offset
|
||||
@ r8 = &_dst[tmp2]
|
||||
MOV r12,#8
|
||||
level1codeSMALL_loop:
|
||||
LDRB r5, [r8],#1 @ r5 = d_dst[tmp2]
|
||||
LDRB r6, [r8],#1 @ r10 = d_dst[tmp2]
|
||||
LDRB r9, [r8],#1 @ r10 = d_dst[tmp2]
|
||||
LDRB r10,[r8],#1 @ r10 = d_dst[tmp2]
|
||||
STRB r5, [r0],#1 @ d_dst[0] = r5
|
||||
STRB r6, [r0],#1 @ d_dst[1] = r6
|
||||
STRB r9, [r0],#1 @ d_dst[2] = r9
|
||||
STRB r10,[r0],#1 @ d_dst[3] = r10
|
||||
LDRB r5, [r8],#1 @ r5 = d_dst[tmp2]
|
||||
LDRB r6, [r8],#1 @ r10 = d_dst[tmp2]
|
||||
LDRB r9, [r8],#1 @ r10 = d_dst[tmp2]
|
||||
LDRB r10,[r8],r11 @ r10 = d_dst[tmp2]
|
||||
STRB r5, [r0],#1 @ d_dst[4] = r5
|
||||
STRB r6, [r0],#1 @ d_dst[5] = r6
|
||||
STRB r9, [r0],#1 @ d_dst[6] = r9
|
||||
STRB r10,[r0],r11 @ d_dst[7] = r10 d_dst += d_pitch
|
||||
SUBS r12,r12,#1
|
||||
BGT level1codeSMALL_loop
|
||||
SUB r0,r0,r2,LSL #3 @ revert d_dst
|
||||
B level1_end
|
||||
|
||||
level1codeMID:
|
||||
@ LT => F8<=code<FC case
|
||||
@ EQ => FE case
|
||||
LDRB r6,[r4,r6] @ r6 = t = _paramPtr[code]
|
||||
level1codeFE:
|
||||
LDREQB r6,[r1],#1 @ r6 = t = *_d_src++
|
||||
MOV r12,#8
|
||||
SUB r11,r2,#7 @ r11 = _d_pitch-7
|
||||
level1codeMID_loop:
|
||||
STRB r6,[r0],#1
|
||||
STRB r6,[r0],#1
|
||||
STRB r6,[r0],#1
|
||||
STRB r6,[r0],#1
|
||||
STRB r6,[r0],#1
|
||||
STRB r6,[r0],#1
|
||||
STRB r6,[r0],#1
|
||||
STRB r6,[r0],r11
|
||||
SUBS r12,r12,#1
|
||||
BGT level1codeMID_loop
|
||||
SUB r0,r0,r2,LSL #3 @ revert d_dst
|
||||
B level1_end
|
||||
|
||||
level1codeFF:
|
||||
BL level2
|
||||
ADD r0,r0,#4
|
||||
BL level2
|
||||
ADD r0,r0,r2,LSL #2
|
||||
SUB r0,r0,#4
|
||||
BL level2
|
||||
ADD r0,r0,#4
|
||||
BL level2
|
||||
SUB r0,r0,#4
|
||||
SUB r0,r0,r2,LSL #2
|
||||
B level1_end
|
||||
|
||||
level2:
|
||||
@ r0 = _d_dst
|
||||
@ r1 = _d_src
|
||||
@ r2 = _d_pitch
|
||||
@ r3 = PRESERVE
|
||||
@ r4 = param
|
||||
@ r7 = PRESERVE
|
||||
@ r14= return address
|
||||
LDRB r6,[r1],#1 @ r6 = *_d_src++
|
||||
@ stall
|
||||
@ stall
|
||||
CMP r6,#0xF8
|
||||
BLT level2codeSMALL
|
||||
CMP r6,#0xFC
|
||||
BLT level2codeMID
|
||||
BEQ level2codeFC
|
||||
CMP r6,#0xFE
|
||||
BGT level2codeFF
|
||||
BEQ level2codeFE
|
||||
level2codeFD:
|
||||
LDRB r6,[r1],#1 @ r6 = tmp = *_d_src++
|
||||
LDR r8,[r13,#60] @ r8 = _tableSmall (60 = (9+1+5)*4)
|
||||
@ stall
|
||||
@ stall
|
||||
ADD r8,r8,r6,LSL #7 @ r8 = _tableSmall + tmp*128
|
||||
LDRB r9,[r8,#96] @ r9 = l = tmp_ptr[96]
|
||||
LDRB r6,[r1],#1 @ r6 = val = *_d_src++
|
||||
ADD r12,r8,#32 @ r12 = tmp_ptr + 32
|
||||
@ I don''t really believe the next 2 lines are necessary, but...
|
||||
CMP r9,#0
|
||||
BEQ level2codeFD_over1
|
||||
level2codeFD_loop1:
|
||||
LDRB r10,[r8],#1
|
||||
LDRB r11,[r8],#1
|
||||
SUBS r9,r9,#1
|
||||
ADD r10,r10,r0
|
||||
STRB r6,[r10,r11,LSL #8] @ *(_d_dst + (*tmp_ptr2++)) = val
|
||||
BGT level2codeFD_loop1
|
||||
level2codeFD_over1:
|
||||
LDRB r9,[r12,#65] @ r9 = l = tmp_ptr[97] (65 = 97-32)
|
||||
LDRB r6,[r1],#1 @ r6 = val = *_d_src++
|
||||
@ I don''t really believe the next 2 lines are necessary, but...
|
||||
CMP r9,#0
|
||||
MOVEQ PC,R14
|
||||
level2codeFD_loop2:
|
||||
LDRB r10,[r12],#1
|
||||
LDRB r11,[r12],#1
|
||||
SUBS r9,r9,#1
|
||||
ADD r10,r10,r0
|
||||
STRB r6,[r10,r11,LSL #8] @ *(_d_dst + (*tmp_ptr2++)) = val
|
||||
BGT level2codeFD_loop2
|
||||
|
||||
MOV PC,R14
|
||||
|
||||
level2codeSMALL:
|
||||
LDR r8,[r13,#44] @ r8 = _table (44 = (9+1+1)*4)
|
||||
LDR r9,[r13,#52] @ r9 = _offset1 (52 = (9+1+3)*4)
|
||||
MOV r6,r6,LSL #1 @ r6 = code<<1
|
||||
LDRSH r8,[r8,r6] @ tmp2 = _table[code]
|
||||
level2codeFC:
|
||||
@ EQ => FC
|
||||
LDREQ r9,[r13,#56] @ r9 = _offset2 (56 = (9+1+4)*4)
|
||||
MOVEQ r8,#0
|
||||
SUB r11,r2,#3 @ r11 = _d_pitch-3
|
||||
ADD r9,r9,r0 @ tmp2 = _d_dst + _table[code]
|
||||
ADD r8,r8,r9 @ tmp2 = _d_dst+_table[code]+_offset1
|
||||
@ r8 = &_dst[tmp2]
|
||||
MOV r12,#4
|
||||
level2codeSMALL_loop:
|
||||
LDRB r5, [r8],#1 @ r5 = d_dst[tmp2]
|
||||
LDRB r6, [r8],#1 @ r10 = d_dst[tmp2]
|
||||
LDRB r9, [r8],#1 @ r10 = d_dst[tmp2]
|
||||
LDRB r10,[r8],r11 @ r10 = d_dst[tmp2]
|
||||
STRB r5, [r0],#1 @ d_dst[4] = r5
|
||||
STRB r6, [r0],#1 @ d_dst[5] = r6
|
||||
STRB r9, [r0],#1 @ d_dst[6] = r9
|
||||
STRB r10,[r0],r11 @ d_dst[7] = r10 d_dst += d_pitch
|
||||
SUBS r12,r12,#1
|
||||
BGT level2codeSMALL_loop
|
||||
SUB r0,r0,r2,LSL #2 @ revert d_dst
|
||||
MOV PC,R14
|
||||
|
||||
level2codeMID:
|
||||
@ LT => F8<=code<FC case
|
||||
@ EQ => FE case
|
||||
LDRB r6,[r4,r6] @ r6 = t = _paramPtr[code]
|
||||
level2codeFE:
|
||||
LDREQB r6,[r1],#1 @ r6 = t = *_d_src++
|
||||
MOV r12,#4
|
||||
SUB r11,r2,#3 @ r11 = _d_pitch-7
|
||||
level2codeMID_loop:
|
||||
STRB r6,[r0],#1
|
||||
STRB r6,[r0],#1
|
||||
STRB r6,[r0],#1
|
||||
STRB r6,[r0],r11
|
||||
SUBS r12,r12,#1
|
||||
BGT level2codeMID_loop
|
||||
SUB r0,r0,r2,LSL #2 @ revert d_dst
|
||||
MOV PC,R14
|
||||
|
||||
level2codeFF:
|
||||
MOV r5,r14
|
||||
BL level3
|
||||
ADD r0,r0,#2
|
||||
BL level3
|
||||
ADD r0,r0,r2,LSL #1
|
||||
SUB r0,r0,#2
|
||||
BL level3
|
||||
ADD r0,r0,#2
|
||||
BL level3
|
||||
SUB r0,r0,#2
|
||||
SUB r0,r0,r2,LSL #1
|
||||
MOV PC,R5
|
||||
|
||||
level3:
|
||||
@ r0 = _d_dst
|
||||
@ r1 = _d_src
|
||||
@ r2 = _d_pitch
|
||||
@ r3 = PRESERVE
|
||||
@ r4 = param
|
||||
@ r5 = preserve
|
||||
@ r7 = PRESERVE
|
||||
@ r14= return address
|
||||
LDRB r6,[r1],#1 @ r6 = code = *_d_src++
|
||||
@ stall
|
||||
@ stall
|
||||
CMP r6,#0xF8
|
||||
BLT level3codeSMALL
|
||||
CMP r6,#0xFC
|
||||
BLT level3codeMID
|
||||
BEQ level3codeFC
|
||||
CMP r6,#0xFE
|
||||
BGT level3codeFF
|
||||
level3codeFE:
|
||||
LDRB r6,[r1],#1 @ r6 = t = *_d_src++
|
||||
level3codeMID:
|
||||
@ LT => F8<=code<FC case
|
||||
@ EQ => FE case
|
||||
LDRLTB r6,[r4,r6] @ r6 = t = _paramPtr[code]
|
||||
@ stall
|
||||
@ stall
|
||||
STRB r6,[r0,#1]
|
||||
STRB r6,[r0],r2
|
||||
STRB r6,[r0,#1]
|
||||
STRB r6,[r0],-r2
|
||||
MOV PC,R14
|
||||
|
||||
level3codeFF:
|
||||
LDRB r6,[r1],#1
|
||||
LDRB r9,[r1],#1
|
||||
LDRB r10,[r1],#1
|
||||
LDRB r11,[r1],#1
|
||||
STRB r9, [r0,#1]
|
||||
STRB r6, [r0],r2
|
||||
STRB r11,[r0,#1]
|
||||
STRB r10,[r0],-r2
|
||||
MOV PC,R14
|
||||
|
||||
level3codeSMALL:
|
||||
LDR r8,[r13,#44] @ r8 = _table (44 = (9+1+1)*4)
|
||||
LDR r9,[r13,#52] @ r9 = _offset1 (52 = (9+1+3)*4)
|
||||
MOV r6,r6,LSL #1 @ r6 = code<<1
|
||||
LDRSH r8,[r8,r6] @ tmp2 = _table[code]
|
||||
level3codeFC:
|
||||
@ EQ => FC
|
||||
LDREQ r9,[r13,#56] @ r9 = _offset2 (56 = (9+1+4)*4)
|
||||
MOVEQ r8,#0
|
||||
ADD r9,r9,r0 @ tmp2 = _d_dst+offset
|
||||
ADD r8,r8,r9 @ tmp2 = _d_dst+_table[code]+_offset
|
||||
@ r8 = &_dst[tmp2]
|
||||
LDRB r6, [r8,#1] @ r6 = d_dst[tmp2+1]
|
||||
LDRB r9, [r8],r2 @ r9 = d_dst[tmp2+0]
|
||||
LDRB r10,[r8,#1] @ r10= d_dst[tmp2+dst+1]
|
||||
LDRB r11,[r8],-r2 @ r11= d_dst[tmp2+dst]
|
||||
STRB r6, [r0,#1] @ d_dst[1 ] = r6
|
||||
STRB r9, [r0],r2 @ d_dst[0 ] = r9
|
||||
STRB r10,[r0,#1] @ d_dst[dst+1] = r10
|
||||
STRB r11,[r0],-r2 @ d_dst[dst ] = r11
|
||||
MOV PC,R14
|
||||
570
engines/grim/movie/codecs/codec48.cpp
Normal file
570
engines/grim/movie/codecs/codec48.cpp
Normal file
@@ -0,0 +1,570 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "common/util.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "engines/grim/movie/codecs/codec48.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
Codec48Decoder::Codec48Decoder() {
|
||||
_frameSize = 640 * 480; // Yes, this is correct. Looks like the buffers are always this size
|
||||
|
||||
_curBuf = 0;
|
||||
_deltaBuf[0] = new byte[_frameSize * 2];
|
||||
_deltaBuf[1] = _deltaBuf[0] + _frameSize;
|
||||
|
||||
_offsetTable = new int16[255];
|
||||
_tableLastPitch = -1;
|
||||
_tableLastIndex = -1;
|
||||
|
||||
_interTable = nullptr;
|
||||
}
|
||||
|
||||
void Codec48Decoder::init(int width, int height) {
|
||||
if (_width == width && _height == height)
|
||||
return;
|
||||
deinit();
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
_blockX = (_width + 7) / 8;
|
||||
_blockY = (_height + 7) / 8;
|
||||
_pitch = _blockX * 8;
|
||||
|
||||
// don't support when this is not equal yet
|
||||
assert(_width == _pitch);
|
||||
}
|
||||
|
||||
void Codec48Decoder::deinit() {
|
||||
}
|
||||
|
||||
Codec48Decoder::~Codec48Decoder() {
|
||||
delete[] _deltaBuf[0];
|
||||
delete[] _offsetTable;
|
||||
delete[] _interTable;
|
||||
}
|
||||
|
||||
bool Codec48Decoder::decode(byte *dst, const byte *src) {
|
||||
// The header is identical to codec 37, except the flags field is somewhat different
|
||||
|
||||
const byte *gfxData = src + 0x10;
|
||||
|
||||
makeTable(_pitch, src[1]);
|
||||
|
||||
int16 seqNb = READ_LE_UINT16(src + 2);
|
||||
|
||||
if (seqNb == 0)
|
||||
memset(_deltaBuf[0], 0, _frameSize * 2);
|
||||
|
||||
if (src[12] & (1 << 3)) {
|
||||
// Interpolation table present
|
||||
if (!_interTable)
|
||||
_interTable = new byte[65536];
|
||||
|
||||
byte *ptr = _interTable;
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
byte *ptr1 = ptr + i;
|
||||
byte *ptr2 = ptr + i;
|
||||
|
||||
for (int j = 256 - i; j > 0; j--) {
|
||||
byte pixel = *gfxData++;
|
||||
*ptr2 = pixel;
|
||||
*ptr1++ = pixel;
|
||||
ptr2 += 256;
|
||||
}
|
||||
|
||||
ptr += 256;
|
||||
}
|
||||
}
|
||||
|
||||
switch (src[0]) {
|
||||
case 0:
|
||||
// Raw frame
|
||||
memcpy(_deltaBuf[_curBuf], gfxData, READ_LE_UINT32(src + 4));
|
||||
break;
|
||||
case 2:
|
||||
// Blast object
|
||||
bompDecodeLine(_deltaBuf[_curBuf], gfxData, _width * _height);
|
||||
break;
|
||||
case 3:
|
||||
// 8x8 block encoding
|
||||
if (!(seqNb && seqNb != _prevSeqNb + 1)) {
|
||||
if (seqNb & 1 || !(src[12] & 1) || src[12] & 0x10)
|
||||
_curBuf ^= 1;
|
||||
|
||||
decode3(_deltaBuf[_curBuf], gfxData, _deltaBuf[_curBuf ^ 1] - _deltaBuf[_curBuf]);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
// Some other encoding, but it's unused. (Good)
|
||||
warning("SmushDecoder::decode() codec 48 frame type 5 encountered! Please report!");
|
||||
break;
|
||||
default:
|
||||
warning("SmushDecoder::decode() Unknown codec 48 frame type %d", src[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
_prevSeqNb = seqNb;
|
||||
memcpy(dst, _deltaBuf[_curBuf], _pitch * _height);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Codec48Decoder::bompDecodeLine(byte *dst, const byte *src, int len) {
|
||||
while (len > 0) {
|
||||
byte code = *src++;
|
||||
byte num = (code >> 1) + 1;
|
||||
|
||||
if (num > len)
|
||||
num = len;
|
||||
|
||||
len -= num;
|
||||
|
||||
if (code & 1) {
|
||||
byte color = *src++;
|
||||
memset(dst, color, num);
|
||||
} else {
|
||||
memcpy(dst, src, num);
|
||||
src += num;
|
||||
}
|
||||
|
||||
dst += num;
|
||||
}
|
||||
}
|
||||
|
||||
void Codec48Decoder::makeTable(int pitch, int index) {
|
||||
// codec48's table is codec47's table appended by the first
|
||||
// part of codec37's table
|
||||
|
||||
// This is essentially Codec37Decoder::makeTable() with a different table
|
||||
|
||||
static const int8 table[] = {
|
||||
0, 0, -1, -43, 6, -43, -9, -42, 13, -41,
|
||||
-16, -40, 19, -39, -23, -36, 26, -34, -2, -33,
|
||||
4, -33, -29, -32, -9, -32, 11, -31, -16, -29,
|
||||
32, -29, 18, -28, -34, -26, -22, -25, -1, -25,
|
||||
3, -25, -7, -24, 8, -24, 24, -23, 36, -23,
|
||||
-12, -22, 13, -21, -38, -20, 0, -20, -27, -19,
|
||||
-4, -19, 4, -19, -17, -18, -8, -17, 8, -17,
|
||||
18, -17, 28, -17, 39, -17, -12, -15, 12, -15,
|
||||
-21, -14, -1, -14, 1, -14, -41, -13, -5, -13,
|
||||
5, -13, 21, -13, -31, -12, -15, -11, -8, -11,
|
||||
8, -11, 15, -11, -2, -10, 1, -10, 31, -10,
|
||||
-23, -9, -11, -9, -5, -9, 4, -9, 11, -9,
|
||||
42, -9, 6, -8, 24, -8, -18, -7, -7, -7,
|
||||
-3, -7, -1, -7, 2, -7, 18, -7, -43, -6,
|
||||
-13, -6, -4, -6, 4, -6, 8, -6, -33, -5,
|
||||
-9, -5, -2, -5, 0, -5, 2, -5, 5, -5,
|
||||
13, -5, -25, -4, -6, -4, -3, -4, 3, -4,
|
||||
9, -4, -19, -3, -7, -3, -4, -3, -2, -3,
|
||||
-1, -3, 0, -3, 1, -3, 2, -3, 4, -3,
|
||||
6, -3, 33, -3, -14, -2, -10, -2, -5, -2,
|
||||
-3, -2, -2, -2, -1, -2, 0, -2, 1, -2,
|
||||
2, -2, 3, -2, 5, -2, 7, -2, 14, -2,
|
||||
19, -2, 25, -2, 43, -2, -7, -1, -3, -1,
|
||||
-2, -1, -1, -1, 0, -1, 1, -1, 2, -1,
|
||||
3, -1, 10, -1, -5, 0, -3, 0, -2, 0,
|
||||
-1, 0, 1, 0, 2, 0, 3, 0, 5, 0,
|
||||
7, 0, -10, 1, -7, 1, -3, 1, -2, 1,
|
||||
-1, 1, 0, 1, 1, 1, 2, 1, 3, 1,
|
||||
-43, 2, -25, 2, -19, 2, -14, 2, -5, 2,
|
||||
-3, 2, -2, 2, -1, 2, 0, 2, 1, 2,
|
||||
2, 2, 3, 2, 5, 2, 7, 2, 10, 2,
|
||||
14, 2, -33, 3, -6, 3, -4, 3, -2, 3,
|
||||
-1, 3, 0, 3, 1, 3, 2, 3, 4, 3,
|
||||
19, 3, -9, 4, -3, 4, 3, 4, 7, 4,
|
||||
25, 4, -13, 5, -5, 5, -2, 5, 0, 5,
|
||||
2, 5, 5, 5, 9, 5, 33, 5, -8, 6,
|
||||
-4, 6, 4, 6, 13, 6, 43, 6, -18, 7,
|
||||
-2, 7, 0, 7, 2, 7, 7, 7, 18, 7,
|
||||
-24, 8, -6, 8, -42, 9, -11, 9, -4, 9,
|
||||
5, 9, 11, 9, 23, 9, -31, 10, -1, 10,
|
||||
2, 10, -15, 11, -8, 11, 8, 11, 15, 11,
|
||||
31, 12, -21, 13, -5, 13, 5, 13, 41, 13,
|
||||
-1, 14, 1, 14, 21, 14, -12, 15, 12, 15,
|
||||
-39, 17, -28, 17, -18, 17, -8, 17, 8, 17,
|
||||
17, 18, -4, 19, 0, 19, 4, 19, 27, 19,
|
||||
38, 20, -13, 21, 12, 22, -36, 23, -24, 23,
|
||||
-8, 24, 7, 24, -3, 25, 1, 25, 22, 25,
|
||||
34, 26, -18, 28, -32, 29, 16, 29, -11, 31,
|
||||
9, 32, 29, 32, -4, 33, 2, 33, -26, 34,
|
||||
23, 36, -19, 39, 16, 40, -13, 41, 9, 42,
|
||||
-6, 43, 1, 43, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 2, 0, 3, 0, 5, 0,
|
||||
8, 0, 13, 0, 21, 0, -1, 0, -2, 0,
|
||||
-3, 0, -5, 0, -8, 0, -13, 0, -17, 0,
|
||||
-21, 0, 0, 1, 1, 1, 2, 1, 3, 1,
|
||||
5, 1, 8, 1, 13, 1, 21, 1, -1, 1,
|
||||
-2, 1, -3, 1, -5, 1, -8, 1, -13, 1,
|
||||
-17, 1, -21, 1, 0, 2, 1, 2, 2, 2,
|
||||
3, 2, 5, 2, 8, 2, 13, 2, 21, 2,
|
||||
-1, 2, -2, 2, -3, 2, -5, 2, -8, 2,
|
||||
-13, 2, -17, 2, -21, 2, 0, 3, 1, 3,
|
||||
2, 3, 3, 3, 5, 3, 8, 3, 13, 3,
|
||||
21, 3, -1, 3, -2, 3, -3, 3, -5, 3,
|
||||
-8, 3, -13, 3, -17, 3, -21, 3, 0, 5,
|
||||
1, 5, 2, 5, 3, 5, 5, 5, 8, 5,
|
||||
13, 5, 21, 5, -1, 5, -2, 5, -3, 5,
|
||||
-5, 5, -8, 5, -13, 5, -17, 5, -21, 5,
|
||||
0, 8, 1, 8, 2, 8, 3, 8, 5, 8,
|
||||
8, 8, 13, 8, 21, 8, -1, 8, -2, 8,
|
||||
-3, 8, -5, 8, -8, 8, -13, 8, -17, 8,
|
||||
-21, 8, 0, 13, 1, 13, 2, 13, 3, 13,
|
||||
5, 13, 8, 13, 13, 13, 21, 13, -1, 13,
|
||||
-2, 13, -3, 13, -5, 13, -8, 13, -13, 13,
|
||||
-17, 13, -21, 13, 0, 21, 1, 21, 2, 21,
|
||||
3, 21, 5, 21, 8, 21, 13, 21, 21, 21,
|
||||
-1, 21, -2, 21, -3, 21, -5, 21, -8, 21,
|
||||
-13, 21, -17, 21, -21, 21, 0, -1, 1, -1,
|
||||
2, -1, 3, -1, 5, -1, 8, -1, 13, -1,
|
||||
21, -1, -1, -1, -2, -1, -3, -1, -5, -1,
|
||||
-8, -1, -13, -1, -17, -1, -21, -1, 0, -2,
|
||||
1, -2, 2, -2, 3, -2, 5, -2, 8, -2,
|
||||
13, -2, 21, -2, -1, -2, -2, -2, -3, -2,
|
||||
-5, -2, -8, -2, -13, -2, -17, -2, -21, -2,
|
||||
0, -3, 1, -3, 2, -3, 3, -3, 5, -3,
|
||||
8, -3, 13, -3, 21, -3, -1, -3, -2, -3,
|
||||
-3, -3, -5, -3, -8, -3, -13, -3, -17, -3,
|
||||
-21, -3, 0, -5, 1, -5, 2, -5, 3, -5,
|
||||
5, -5, 8, -5, 13, -5, 21, -5, -1, -5,
|
||||
-2, -5, -3, -5, -5, -5, -8, -5, -13, -5,
|
||||
-17, -5, -21, -5, 0, -8, 1, -8, 2, -8,
|
||||
3, -8, 5, -8, 8, -8, 13, -8, 21, -8,
|
||||
-1, -8, -2, -8, -3, -8, -5, -8, -8, -8,
|
||||
-13, -8, -17, -8, -21, -8, 0, -13, 1, -13,
|
||||
2, -13, 3, -13, 5, -13, 8, -13, 13, -13,
|
||||
21, -13, -1, -13, -2, -13, -3, -13, -5, -13,
|
||||
-8, -13, -13, -13, -17, -13, -21, -13, 0, -17,
|
||||
1, -17, 2, -17, 3, -17, 5, -17, 8, -17,
|
||||
13, -17, 21, -17, -1, -17, -2, -17, -3, -17,
|
||||
-5, -17, -8, -17, -13, -17, -17, -17, -21, -17,
|
||||
0, -21, 1, -21, 2, -21, 3, -21, 5, -21,
|
||||
8, -21, 13, -21, 21, -21, -1, -21, -2, -21,
|
||||
-3, -21, -5, -21, -8, -21, -13, -21, -17, -21
|
||||
};
|
||||
|
||||
if (_tableLastPitch == pitch && _tableLastIndex == index)
|
||||
return;
|
||||
|
||||
_tableLastPitch = pitch;
|
||||
_tableLastIndex = index;
|
||||
index *= 255;
|
||||
assert(index + 254 < (int32)(sizeof(table) / 2));
|
||||
|
||||
for (int32 i = 0; i < 255; i++) {
|
||||
int32 j = (i + index) * 2;
|
||||
_offsetTable[i] = table[j + 1] * pitch + table[j];
|
||||
}
|
||||
}
|
||||
|
||||
void Codec48Decoder::decode3(byte *dst, const byte *src, int bufOffset) {
|
||||
for (int i = 0; i < _blockY; i++) {
|
||||
for (int j = 0; j < _blockX; j++) {
|
||||
byte opcode = *src++;
|
||||
|
||||
switch (opcode) {
|
||||
case 0xFF: {
|
||||
// Interpolate a 4x4 block based on 1 pixel, then scale to 8x8
|
||||
byte scaleBuffer[16];
|
||||
scaleBuffer[15] = *src++;
|
||||
scaleBuffer[7] = _interTable[(dst[-_pitch + 7] << 8) | scaleBuffer[15]];
|
||||
scaleBuffer[3] = _interTable[(dst[-_pitch + 7] << 8) | scaleBuffer[7]];
|
||||
scaleBuffer[11] = _interTable[(scaleBuffer[15] << 8) | scaleBuffer[7]];
|
||||
|
||||
scaleBuffer[1] = _interTable[(dst[-1] << 8) | scaleBuffer[3]];
|
||||
scaleBuffer[0] = _interTable[(dst[-1] << 8) | scaleBuffer[1]];
|
||||
scaleBuffer[2] = _interTable[(scaleBuffer[3] << 8) | scaleBuffer[1]];
|
||||
|
||||
scaleBuffer[5] = _interTable[(dst[_pitch * 2 - 1] << 8) | scaleBuffer[7]];
|
||||
scaleBuffer[4] = _interTable[(dst[_pitch * 2 - 1] << 8) | scaleBuffer[5]];
|
||||
scaleBuffer[6] = _interTable[(scaleBuffer[7] << 8) | scaleBuffer[5]];
|
||||
|
||||
scaleBuffer[9] = _interTable[(dst[_pitch * 3 - 1] << 8) | scaleBuffer[11]];
|
||||
scaleBuffer[8] = _interTable[(dst[_pitch * 3 - 1] << 8) | scaleBuffer[9]];
|
||||
scaleBuffer[10] = _interTable[(scaleBuffer[11] << 8) | scaleBuffer[9]];
|
||||
|
||||
scaleBuffer[13] = _interTable[(dst[_pitch * 4 - 1] << 8) | scaleBuffer[15]];
|
||||
scaleBuffer[12] = _interTable[(dst[_pitch * 4 - 1] << 8) | scaleBuffer[13]];
|
||||
scaleBuffer[14] = _interTable[(scaleBuffer[15] << 8) | scaleBuffer[13]];
|
||||
|
||||
scaleBlock(dst, scaleBuffer);
|
||||
break;
|
||||
}
|
||||
case 0xFE:
|
||||
// Copy a block using an absolute offset
|
||||
copyBlock(dst, bufOffset, (int16)READ_LE_UINT16(src));
|
||||
src += 2;
|
||||
break;
|
||||
case 0xFD: {
|
||||
// Interpolate a 4x4 block based on 4 pixels, then scale to 8x8
|
||||
byte scaleBuffer[16];
|
||||
scaleBuffer[5] = src[0];
|
||||
scaleBuffer[7] = src[1];
|
||||
scaleBuffer[13] = src[2];
|
||||
scaleBuffer[15] = src[3];
|
||||
|
||||
scaleBuffer[1] = _interTable[(dst[-_pitch + 3] << 8) | scaleBuffer[5]];
|
||||
scaleBuffer[3] = _interTable[(dst[-_pitch + 7] << 8) | scaleBuffer[7]];
|
||||
scaleBuffer[11] = _interTable[(scaleBuffer[15] << 8) | scaleBuffer[7]];
|
||||
scaleBuffer[9] = _interTable[(scaleBuffer[13] << 8) | scaleBuffer[5]];
|
||||
|
||||
scaleBuffer[0] = _interTable[(dst[-1] << 8) | scaleBuffer[1]];
|
||||
scaleBuffer[2] = _interTable[(scaleBuffer[3] << 8) | scaleBuffer[1]];
|
||||
scaleBuffer[4] = _interTable[(dst[_pitch * 2 - 1] << 8) | scaleBuffer[5]];
|
||||
scaleBuffer[6] = _interTable[(scaleBuffer[7] << 8) | scaleBuffer[5]];
|
||||
|
||||
scaleBuffer[8] = _interTable[(dst[_pitch * 3 - 1] << 8) | scaleBuffer[9]];
|
||||
scaleBuffer[10] = _interTable[(scaleBuffer[11] << 8) | scaleBuffer[9]];
|
||||
scaleBuffer[12] = _interTable[(dst[_pitch * 4 - 1] << 8) | scaleBuffer[13]];
|
||||
scaleBuffer[14] = _interTable[(scaleBuffer[15] << 8) | scaleBuffer[13]];
|
||||
|
||||
scaleBlock(dst, scaleBuffer);
|
||||
|
||||
src += 4;
|
||||
break;
|
||||
}
|
||||
case 0xFC:
|
||||
// Copy 4 4x4 blocks using the offset table
|
||||
*((uint32 *)dst) = *((uint32 *)(dst + bufOffset + _offsetTable[src[0]]));
|
||||
*((uint32 *)(dst + _pitch)) = *((uint32 *)(dst + bufOffset + _offsetTable[src[0]] + _pitch));
|
||||
*((uint32 *)(dst + _pitch * 2)) = *((uint32 *)(dst + bufOffset + _offsetTable[src[0]] + _pitch * 2));
|
||||
*((uint32 *)(dst + _pitch * 3)) = *((uint32 *)(dst + bufOffset + _offsetTable[src[0]] + _pitch * 3));
|
||||
|
||||
*((uint32 *)(dst + 4)) = *((uint32 *)(dst + bufOffset + _offsetTable[src[1]] + 4));
|
||||
*((uint32 *)(dst + _pitch + 4)) = *((uint32 *)(dst + bufOffset + _offsetTable[src[1]] + _pitch + 4));
|
||||
*((uint32 *)(dst + _pitch * 2 + 4)) = *((uint32 *)(dst + bufOffset + _offsetTable[src[1]] + _pitch * 2 + 4));
|
||||
*((uint32 *)(dst + _pitch * 3 + 4)) = *((uint32 *)(dst + bufOffset + _offsetTable[src[1]] + _pitch * 3 + 4));
|
||||
|
||||
*((uint32 *)(dst + _pitch * 4)) = *((uint32 *)(dst + bufOffset + _offsetTable[src[2]] + _pitch * 4));
|
||||
*((uint32 *)(dst + _pitch * 5)) = *((uint32 *)(dst + bufOffset + _offsetTable[src[2]] + _pitch * 5));
|
||||
*((uint32 *)(dst + _pitch * 6)) = *((uint32 *)(dst + bufOffset + _offsetTable[src[2]] + _pitch * 6));
|
||||
*((uint32 *)(dst + _pitch * 7)) = *((uint32 *)(dst + bufOffset + _offsetTable[src[2]] + _pitch * 7));
|
||||
|
||||
*((uint32 *)(dst + _pitch * 4 + 4)) = *((uint32 *)(dst + bufOffset + _offsetTable[src[3]] + _pitch * 4 + 4));
|
||||
*((uint32 *)(dst + _pitch * 5 + 4)) = *((uint32 *)(dst + bufOffset + _offsetTable[src[3]] + _pitch * 5 + 4));
|
||||
*((uint32 *)(dst + _pitch * 6 + 4)) = *((uint32 *)(dst + bufOffset + _offsetTable[src[3]] + _pitch * 6 + 4));
|
||||
*((uint32 *)(dst + _pitch * 7 + 4)) = *((uint32 *)(dst + bufOffset + _offsetTable[src[3]] + _pitch * 7 + 4));
|
||||
|
||||
src += 4;
|
||||
break;
|
||||
case 0xFB:
|
||||
// Copy 4 4x4 blocks using absolute offsets
|
||||
*((uint32 *)dst) = *((uint32 *)(dst + bufOffset + (int16)READ_LE_UINT16(src)));
|
||||
*((uint32 *)(dst + _pitch)) = *((uint32 *)(dst + bufOffset + (int16)READ_LE_UINT16(src) + _pitch));
|
||||
*((uint32 *)(dst + _pitch * 2)) = *((uint32 *)(dst + bufOffset + (int16)READ_LE_UINT16(src) + _pitch * 2));
|
||||
*((uint32 *)(dst + _pitch * 3)) = *((uint32 *)(dst + bufOffset + (int16)READ_LE_UINT16(src) + _pitch * 3));
|
||||
|
||||
*((uint32 *)(dst + 4)) = *((uint32 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 2) + 4));
|
||||
*((uint32 *)(dst + _pitch + 4)) = *((uint32 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 2) + _pitch + 4));
|
||||
*((uint32 *)(dst + _pitch * 2 + 4)) = *((uint32 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 2) + _pitch * 2 + 4));
|
||||
*((uint32 *)(dst + _pitch * 3 + 4)) = *((uint32 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 2) + _pitch * 3 + 4));
|
||||
|
||||
*((uint32 *)(dst + _pitch * 4)) = *((uint32 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 4) + _pitch * 4));
|
||||
*((uint32 *)(dst + _pitch * 5)) = *((uint32 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 4) + _pitch * 5));
|
||||
*((uint32 *)(dst + _pitch * 6)) = *((uint32 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 4) + _pitch * 6));
|
||||
*((uint32 *)(dst + _pitch * 7)) = *((uint32 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 4) + _pitch * 7));
|
||||
|
||||
*((uint32 *)(dst + _pitch * 4 + 4)) = *((uint32 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 6) + _pitch * 4 + 4));
|
||||
*((uint32 *)(dst + _pitch * 5 + 4)) = *((uint32 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 6) + _pitch * 5 + 4));
|
||||
*((uint32 *)(dst + _pitch * 6 + 4)) = *((uint32 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 6) + _pitch * 6 + 4));
|
||||
*((uint32 *)(dst + _pitch * 7 + 4)) = *((uint32 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 6) + _pitch * 7 + 4));
|
||||
src += 8;
|
||||
break;
|
||||
case 0xFA:
|
||||
// Scale a 4x4 block to an 8x8 block
|
||||
scaleBlock(dst, src);
|
||||
src += 16;
|
||||
break;
|
||||
case 0xF9:
|
||||
// Copy 16 2x2 blocks using the offset table
|
||||
*((uint16 *)dst) = *((uint16 *)(dst + bufOffset + _offsetTable[src[0]]));
|
||||
*((uint16 *)(dst + _pitch)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[0]] + _pitch));
|
||||
|
||||
*((uint16 *)(dst + 2)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[1]] + 2));
|
||||
*((uint16 *)(dst + _pitch + 2)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[1]] + _pitch + 2));
|
||||
|
||||
*((uint16 *)(dst + 4)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[2]] + 4));
|
||||
*((uint16 *)(dst + _pitch + 4)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[2]] + _pitch + 4));
|
||||
|
||||
*((uint16 *)(dst + 6)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[3]] + 6));
|
||||
*((uint16 *)(dst + _pitch + 6)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[3]] + _pitch + 6));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 2)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[4]] + _pitch * 2));
|
||||
*((uint16 *)(dst + _pitch * 3)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[4]] + _pitch * 3));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 2 + 2)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[5]] + _pitch * 2 + 2));
|
||||
*((uint16 *)(dst + _pitch * 3 + 2)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[5]] + _pitch * 3 + 2));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 2 + 4)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[6]] + _pitch * 2 + 4));
|
||||
*((uint16 *)(dst + _pitch * 3 + 4)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[6]] + _pitch * 3 + 4));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 2 + 6)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[7]] + _pitch * 2 + 6));
|
||||
*((uint16 *)(dst + _pitch * 3 + 6)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[7]] + _pitch * 3 + 6));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 4)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[8]] + _pitch * 4));
|
||||
*((uint16 *)(dst + _pitch * 5)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[8]] + _pitch * 5));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 4 + 2)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[9]] + _pitch * 4 + 2));
|
||||
*((uint16 *)(dst + _pitch * 5 + 2)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[9]] + _pitch * 5 + 2));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 4 + 4)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[10]] + _pitch * 4 + 4));
|
||||
*((uint16 *)(dst + _pitch * 5 + 4)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[10]] + _pitch * 5 + 4));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 4 + 6)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[11]] + _pitch * 4 + 6));
|
||||
*((uint16 *)(dst + _pitch * 5 + 6)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[11]] + _pitch * 5 + 6));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 6)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[12]] + _pitch * 6));
|
||||
*((uint16 *)(dst + _pitch * 7)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[12]] + _pitch * 7));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 6 + 2)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[13]] + _pitch * 6 + 2));
|
||||
*((uint16 *)(dst + _pitch * 7 + 2)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[13]] + _pitch * 7 + 2));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 6 + 4)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[14]] + _pitch * 6 + 4));
|
||||
*((uint16 *)(dst + _pitch * 7 + 4)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[14]] + _pitch * 7 + 4));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 6 + 6)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[15]] + _pitch * 6 + 6));
|
||||
*((uint16 *)(dst + _pitch * 7 + 6)) = *((uint16 *)(dst + bufOffset + _offsetTable[src[15]] + _pitch * 7 + 6));
|
||||
src += 16;
|
||||
break;
|
||||
case 0xF8:
|
||||
// Copy 16 2x2 blocks using absolute offsets
|
||||
*((uint16 *)dst) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src)));
|
||||
*((uint16 *)(dst + _pitch)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src) + _pitch));
|
||||
|
||||
*((uint16 *)(dst + 2)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 2) + 2));
|
||||
*((uint16 *)(dst + _pitch + 2)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 2) + _pitch + 2));
|
||||
|
||||
*((uint16 *)(dst + 4)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 4) + 4));
|
||||
*((uint16 *)(dst + _pitch + 4)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 4) + _pitch + 4));
|
||||
|
||||
*((uint16 *)(dst + 6)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 6) + 6));
|
||||
*((uint16 *)(dst + _pitch + 6)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 6) + _pitch + 6));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 2)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 8) + _pitch * 2));
|
||||
*((uint16 *)(dst + _pitch * 3)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 8) + _pitch * 3));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 2 + 2)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 10) + _pitch * 2 + 2));
|
||||
*((uint16 *)(dst + _pitch * 3 + 2)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 10) + _pitch * 3 + 2));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 2 + 4)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 12) + _pitch * 2 + 4));
|
||||
*((uint16 *)(dst + _pitch * 3 + 4)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 12) + _pitch * 3 + 4));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 2 + 6)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 14) + _pitch * 2 + 6));
|
||||
*((uint16 *)(dst + _pitch * 3 + 6)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 14) + _pitch * 3 + 6));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 4)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 16) + _pitch * 4));
|
||||
*((uint16 *)(dst + _pitch * 5)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 16) + _pitch * 5));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 4 + 2)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 18) + _pitch * 4 + 2));
|
||||
*((uint16 *)(dst + _pitch * 5 + 2)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 18) + _pitch * 5 + 2));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 4 + 4)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 20) + _pitch * 4 + 4));
|
||||
*((uint16 *)(dst + _pitch * 5 + 4)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 20) + _pitch * 5 + 4));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 4 + 6)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 22) + _pitch * 4 + 6));
|
||||
*((uint16 *)(dst + _pitch * 5 + 6)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 22) + _pitch * 5 + 6));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 6)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 24) + _pitch * 6));
|
||||
*((uint16 *)(dst + _pitch * 7)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 24) + _pitch * 7));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 6 + 2)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 26) + _pitch * 6 + 2));
|
||||
*((uint16 *)(dst + _pitch * 7 + 2)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 26) + _pitch * 7 + 2));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 6 + 4)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 28) + _pitch * 6 + 4));
|
||||
*((uint16 *)(dst + _pitch * 7 + 4)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 28) + _pitch * 7 + 4));
|
||||
|
||||
*((uint16 *)(dst + _pitch * 6 + 6)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 30) + _pitch * 6 + 6));
|
||||
*((uint16 *)(dst + _pitch * 7 + 6)) = *((uint16 *)(dst + bufOffset + (int16)READ_LE_UINT16(src + 30) + _pitch * 7 + 6));
|
||||
|
||||
src += 32;
|
||||
break;
|
||||
case 0xF7:
|
||||
// Raw 8x8 block
|
||||
*((uint32 *)dst) = *((const uint32 *)src);
|
||||
*((uint32 *)(dst + 4)) = *((const uint32 *)(src + 4));
|
||||
*((uint32 *)(dst + _pitch)) = *((const uint32 *)(src + 8));
|
||||
*((uint32 *)(dst + _pitch + 4)) = *((const uint32 *)(src + 12));
|
||||
*((uint32 *)(dst + _pitch * 2)) = *((const uint32 *)(src + 16));
|
||||
*((uint32 *)(dst + _pitch * 2 + 4)) = *((const uint32 *)(src + 20));
|
||||
*((uint32 *)(dst + _pitch * 3)) = *((const uint32 *)(src + 24));
|
||||
*((uint32 *)(dst + _pitch * 3 + 4)) = *((const uint32 *)(src + 28));
|
||||
*((uint32 *)(dst + _pitch * 4)) = *((const uint32 *)(src + 32));
|
||||
*((uint32 *)(dst + _pitch * 4 + 4)) = *((const uint32 *)(src + 36));
|
||||
*((uint32 *)(dst + _pitch * 5)) = *((const uint32 *)(src + 40));
|
||||
*((uint32 *)(dst + _pitch * 5 + 4)) = *((const uint32 *)(src + 44));
|
||||
*((uint32 *)(dst + _pitch * 6)) = *((const uint32 *)(src + 48));
|
||||
*((uint32 *)(dst + _pitch * 6 + 4)) = *((const uint32 *)(src + 52));
|
||||
*((uint32 *)(dst + _pitch * 7)) = *((const uint32 *)(src + 56));
|
||||
*((uint32 *)(dst + _pitch * 7 + 4)) = *((const uint32 *)(src + 60));
|
||||
|
||||
src += 64;
|
||||
break;
|
||||
default:
|
||||
// Copy a block using the offset table
|
||||
copyBlock(dst, bufOffset, _offsetTable[opcode]);
|
||||
break;
|
||||
}
|
||||
|
||||
dst += 8;
|
||||
}
|
||||
|
||||
dst += _pitch * 7;
|
||||
}
|
||||
}
|
||||
|
||||
void Codec48Decoder::copyBlock(byte *dst, int deltaBufOffset, int offset) {
|
||||
const byte *src = dst + deltaBufOffset + offset;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
*((uint32 *)(dst + _pitch * i)) = *((const uint32 *)(src + _pitch * i));
|
||||
*((uint32 *)(dst + _pitch * i + 4)) = *((const uint32 *)(src + _pitch * i + 4));
|
||||
}
|
||||
}
|
||||
|
||||
void Codec48Decoder::scaleBlock(byte *dst, const byte *src) {
|
||||
// This is doing a 2x scale of data
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
uint16 pixels = src[0];
|
||||
pixels = (pixels << 8) | pixels;
|
||||
*((uint16 *)dst) = pixels;
|
||||
*((uint16 *)(dst + _pitch)) = pixels;
|
||||
pixels = src[1];
|
||||
pixels = (pixels << 8) | pixels;
|
||||
*((uint16 *)(dst + 2)) = pixels;
|
||||
*((uint16 *)(dst + _pitch + 2)) = pixels;
|
||||
pixels = src[2];
|
||||
pixels = (pixels << 8) | pixels;
|
||||
*((uint16 *)(dst + 4)) = pixels;
|
||||
*((uint16 *)(dst + _pitch + 4)) = pixels;
|
||||
pixels = src[3];
|
||||
pixels = (pixels << 8) | pixels;
|
||||
*((uint16 *)(dst + 6)) = pixels;
|
||||
*((uint16 *)(dst + _pitch + 6)) = pixels;
|
||||
src += 4;
|
||||
dst += _pitch * 2;
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
60
engines/grim/movie/codecs/codec48.h
Normal file
60
engines/grim/movie/codecs/codec48.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CODEC48_H
|
||||
#define CODEC48_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class Codec48Decoder {
|
||||
public:
|
||||
Codec48Decoder();
|
||||
~Codec48Decoder();
|
||||
void init(int width, int height);
|
||||
void deinit();
|
||||
bool decode(byte *dst, const byte *src);
|
||||
|
||||
private:
|
||||
void makeTable(int pitch, int index);
|
||||
|
||||
void bompDecodeLine(byte *dst, const byte *src, int len);
|
||||
|
||||
void decode3(byte *dst, const byte *src, int bufOffset);
|
||||
void scaleBlock(byte *dst, const byte *src);
|
||||
void copyBlock(byte *dst, int deltaBufOffset, int offset);
|
||||
|
||||
int _curBuf;
|
||||
byte *_deltaBuf[2];
|
||||
int _blockX, _blockY;
|
||||
int _pitch;
|
||||
int16 *_offsetTable;
|
||||
int _tableLastPitch, _tableLastIndex;
|
||||
int16 _prevSeqNb;
|
||||
int32 _frameSize;
|
||||
int _width, _height;
|
||||
byte *_interTable;
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
738
engines/grim/movie/codecs/smush_decoder.cpp
Normal file
738
engines/grim/movie/codecs/smush_decoder.cpp
Normal file
@@ -0,0 +1,738 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "common/events.h"
|
||||
#include "common/file.h"
|
||||
#include "common/rational.h"
|
||||
#include "common/system.h"
|
||||
#include "common/timer.h"
|
||||
#include "common/memstream.h"
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/mixer.h"
|
||||
#include "audio/decoders/raw.h"
|
||||
|
||||
#include "engines/grim/debug.h"
|
||||
#include "engines/grim/movie/codecs/codec48.h"
|
||||
#include "engines/grim/movie/codecs/blocky8.h"
|
||||
#include "engines/grim/movie/codecs/blocky16.h"
|
||||
#include "engines/grim/movie/codecs/smush_decoder.h"
|
||||
#include "engines/grim/movie/codecs/vima.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
#define ANNO_HEADER "MakeAnim animation type 'Bl16' parameters: "
|
||||
#define BUFFER_SIZE 16385
|
||||
#define SMUSH_SPEED 66667
|
||||
|
||||
bool SmushDecoder::_demo = false;
|
||||
|
||||
static uint16 smushDestTable[5786];
|
||||
|
||||
SmushDecoder::SmushDecoder() {
|
||||
_file = nullptr;
|
||||
|
||||
_videoLooping = false;
|
||||
_startPos = 0;
|
||||
_frames = nullptr;
|
||||
|
||||
_videoTrack = nullptr;
|
||||
_audioTrack = nullptr;
|
||||
_videoPause = false;
|
||||
}
|
||||
|
||||
SmushDecoder::~SmushDecoder() {
|
||||
delete _videoTrack;
|
||||
delete _audioTrack;
|
||||
delete[] _frames;
|
||||
}
|
||||
|
||||
void SmushDecoder::init() {
|
||||
_videoTrack->init();
|
||||
_audioTrack->init();
|
||||
}
|
||||
|
||||
void SmushDecoder::initFrames() {
|
||||
delete[] _frames;
|
||||
_frames = new Frame[_videoTrack->getFrameCount()];
|
||||
|
||||
int seekPos = _file->pos();
|
||||
int curFrame = -1;
|
||||
_file->seek(_startPos, SEEK_SET);
|
||||
while (curFrame < _videoTrack->getFrameCount() - 1) {
|
||||
Frame &frame = _frames[++curFrame];
|
||||
frame.frame = curFrame;
|
||||
frame.pos = _file->pos();
|
||||
frame.keyframe = false;
|
||||
|
||||
uint32 tag = _file->readUint32BE();
|
||||
uint32 size;
|
||||
if (tag == MKTAG('A', 'N', 'N', 'O')) {
|
||||
size = _file->readUint32BE();
|
||||
_file->seek(size, SEEK_CUR);
|
||||
tag = _file->readUint32BE();
|
||||
}
|
||||
assert(tag == MKTAG('F', 'R', 'M', 'E'));
|
||||
size = _file->readUint32BE();
|
||||
|
||||
while (size > 0) {
|
||||
uint32 subType = _file->readUint32BE();
|
||||
uint32 subSize = _file->readUint32BE();
|
||||
int32 subPos = _file->pos();
|
||||
|
||||
if (subType == MKTAG('B', 'l', '1', '6')) {
|
||||
_file->seek(18, SEEK_CUR);
|
||||
if (_file->readByte() == 0) {
|
||||
frame.keyframe = true;
|
||||
}
|
||||
}
|
||||
|
||||
size -= subSize + 8 + (subSize & 1);
|
||||
_file->seek(subPos + subSize + (subSize & 1), SEEK_SET);
|
||||
}
|
||||
|
||||
_file->seek(size, SEEK_CUR);
|
||||
}
|
||||
|
||||
_file->seek(seekPos, SEEK_SET);
|
||||
}
|
||||
|
||||
void SmushDecoder::close() {
|
||||
VideoDecoder::close();
|
||||
_audioTrack = nullptr;
|
||||
_videoTrack = nullptr;
|
||||
_videoLooping = false;
|
||||
_startPos = 0;
|
||||
delete[] _frames;
|
||||
_frames = nullptr;
|
||||
if (_file) {
|
||||
delete _file;
|
||||
_file = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SmushDecoder::readHeader() {
|
||||
if (!_file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 mainTag = _file->readUint32BE();
|
||||
uint32 pos = _file->pos();
|
||||
uint32 expectedTag = 0;
|
||||
uint32 size = _file->readUint32BE(); // file-size
|
||||
|
||||
// Verify that we have the correct combination of headers.
|
||||
if (mainTag == MKTAG('A', 'N', 'I', 'M')) { // Demo
|
||||
expectedTag = MKTAG('A', 'H', 'D', 'R');
|
||||
} else if (mainTag == MKTAG('S', 'A', 'N', 'M')) { // Retail
|
||||
expectedTag = MKTAG('S', 'H', 'D', 'R');
|
||||
} else {
|
||||
error("Invalid SMUSH-header");
|
||||
}
|
||||
|
||||
uint32 tag = _file->readUint32BE();
|
||||
size = _file->readUint32BE();
|
||||
pos = _file->pos();
|
||||
|
||||
assert(tag == expectedTag);
|
||||
(void)expectedTag;
|
||||
|
||||
if (tag == MKTAG('A', 'H', 'D', 'R')) { // Demo
|
||||
uint32 version = _file->readUint16LE();
|
||||
uint16 nbFrames = _file->readUint16LE();
|
||||
_file->readUint16BE(); // unknown
|
||||
|
||||
int width = -1;
|
||||
int height = -1;
|
||||
_videoLooping = false;
|
||||
_startPos = 0;
|
||||
|
||||
_videoTrack = new SmushVideoTrack(width, height, SMUSH_SPEED, nbFrames, false);
|
||||
_videoTrack->_x = -1;
|
||||
_videoTrack->_y = -1;
|
||||
addTrack(_videoTrack);
|
||||
_file->read(_videoTrack->getPal(), 0x300);
|
||||
|
||||
int audioRate = 11025;
|
||||
if (version == 2) {
|
||||
|
||||
_file->readUint32LE(); // framerate
|
||||
_file->readUint32LE();
|
||||
audioRate = _file->readUint32LE();
|
||||
}
|
||||
|
||||
_file->readUint32BE();
|
||||
_file->readUint32BE();
|
||||
_audioTrack = new SmushAudioTrack(getSoundType(), false, audioRate, 2);
|
||||
addTrack(_audioTrack);
|
||||
return true;
|
||||
|
||||
} else if (tag == MKTAG('S', 'H', 'D', 'R')) { // Retail
|
||||
_file->readUint16LE();
|
||||
uint16 nbFrames = _file->readUint32LE();
|
||||
_file->readUint16LE();
|
||||
int width = _file->readUint16LE();
|
||||
int height = _file->readUint16LE();
|
||||
_file->readUint16LE();
|
||||
int frameRate = _file->readUint32LE();
|
||||
|
||||
int16 flags = _file->readUint16LE();
|
||||
// Output information for checking out the flags
|
||||
if (Debug::isChannelEnabled(Debug::Movie | Debug::Info)) {
|
||||
warning("SMUSH Flags:");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
warning(" %d", (flags & (1 << i)) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
_file->seek(pos + size + (size & 1), SEEK_SET);
|
||||
|
||||
_videoLooping = true;
|
||||
// If the video is NOT looping, setLooping will set the speed to the proper value
|
||||
_videoTrack = new SmushVideoTrack(width, height, frameRate, nbFrames, true);
|
||||
addTrack(_videoTrack);
|
||||
return handleFramesHeader();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SmushDecoder::handleFramesHeader() {
|
||||
uint32 tag;
|
||||
int32 size;
|
||||
int pos = 0;
|
||||
int freq = 0;
|
||||
int channels = 0;
|
||||
|
||||
tag = _file->readUint32BE();
|
||||
if (tag != MKTAG('F', 'L', 'H', 'D')) {
|
||||
return false;
|
||||
}
|
||||
size = _file->readUint32BE();
|
||||
byte *f_header = new byte[size];
|
||||
_file->read(f_header, size);
|
||||
|
||||
do {
|
||||
if (READ_BE_UINT32(f_header + pos) == MKTAG('B', 'l', '1', '6')) {
|
||||
pos += READ_BE_UINT32(f_header + pos + 4) + 8;
|
||||
} else if (READ_BE_UINT32(f_header + pos) == MKTAG('W', 'a', 'v', 'e')) {
|
||||
freq = READ_LE_UINT32(f_header + pos + 8);
|
||||
channels = READ_LE_UINT32(f_header + pos + 12);
|
||||
pos += 20;
|
||||
} else {
|
||||
error("SmushDecoder::handleFramesHeader() unknown tag");
|
||||
}
|
||||
} while (pos < size);
|
||||
delete[] f_header;
|
||||
|
||||
_audioTrack = new SmushAudioTrack(getSoundType(), true, freq, channels);
|
||||
addTrack(_audioTrack);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SmushDecoder::loadStream(Common::SeekableReadStream *stream) {
|
||||
close();
|
||||
|
||||
_file = stream;
|
||||
|
||||
// Load the video
|
||||
if (!readHeader()) {
|
||||
warning("Failure loading SMUSH-file");
|
||||
return false;
|
||||
}
|
||||
|
||||
_startPos = _file->pos();
|
||||
|
||||
init();
|
||||
return true;
|
||||
}
|
||||
|
||||
const Graphics::Surface *SmushDecoder::decodeNextFrame() {
|
||||
handleFrame();
|
||||
|
||||
// We might be interested in getting the last frame even after the video ends:
|
||||
if (endOfVideo()) {
|
||||
return _videoTrack->decodeNextFrame();
|
||||
}
|
||||
return VideoDecoder::decodeNextFrame();
|
||||
}
|
||||
|
||||
void SmushDecoder::setLooping(bool l) {
|
||||
_videoLooping = l;
|
||||
|
||||
if (!_videoLooping) {
|
||||
_videoTrack->setMsPerFrame(SMUSH_SPEED);
|
||||
}
|
||||
}
|
||||
|
||||
void SmushDecoder::handleFrame() {
|
||||
uint32 tag;
|
||||
int32 size;
|
||||
|
||||
if (isPaused()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_videoTrack->endOfTrack()) { // Looping is handled outside, by rewinding the video.
|
||||
_audioTrack->stop(); // HACK: Avoids the movie playing past the last frame
|
||||
// pauseVideo(true);
|
||||
return;
|
||||
}
|
||||
|
||||
tag = _file->readUint32BE();
|
||||
size = _file->readUint32BE();
|
||||
if (tag == MKTAG('A', 'N', 'N', 'O')) {
|
||||
char *anno;
|
||||
byte *data;
|
||||
|
||||
data = new byte[size];
|
||||
_file->read(data, size);
|
||||
anno = (char *)data;
|
||||
if (strncmp(anno, ANNO_HEADER, sizeof(ANNO_HEADER) - 1) == 0) {
|
||||
//char *annoData = anno + sizeof(ANNO_HEADER);
|
||||
|
||||
// Examples:
|
||||
// Water streaming around boat from Manny's balcony
|
||||
// MakeAnim animation type 'Bl16' parameters: 10000;12000;100;1;0;0;0;0;25;0;
|
||||
// Water in front of the Blue Casket
|
||||
// MakeAnim animation type 'Bl16' parameters: 20000;25000;100;1;0;0;0;0;25;0;
|
||||
// Scrimshaw exterior:
|
||||
// MakeAnim animation type 'Bl16' parameters: 6000;8000;100;0;0;0;0;0;2;0;
|
||||
// Lola engine room (loops a limited number of times?):
|
||||
// MakeAnim animation type 'Bl16' parameters: 6000;8000;90;1;0;0;0;0;2;0;
|
||||
Debug::debug(Debug::Movie, "Announcement data: %s\n", anno);
|
||||
// It looks like the announcement data is actually for setting some of the
|
||||
// header parameters, not for any looping purpose
|
||||
} else {
|
||||
Debug::debug(Debug::Movie, "Announcement header not understood: %s\n", anno);
|
||||
}
|
||||
delete[] anno;
|
||||
tag = _file->readUint32BE();
|
||||
size = _file->readUint32BE();
|
||||
}
|
||||
|
||||
assert(tag == MKTAG('F', 'R', 'M', 'E'));
|
||||
handleFRME(_file, size);
|
||||
|
||||
_videoTrack->finishFrame();
|
||||
}
|
||||
|
||||
void SmushDecoder::handleFRME(Common::SeekableReadStream *stream, uint32 size) {
|
||||
int blockSize = size;
|
||||
|
||||
byte *block = new byte[size];
|
||||
stream->read(block, size);
|
||||
|
||||
Common::MemoryReadStream *memStream = new Common::MemoryReadStream(block, size, DisposeAfterUse::NO);
|
||||
while (size > 0) {
|
||||
uint32 subType = memStream->readUint32BE();
|
||||
uint32 subSize = memStream->readUint32BE();
|
||||
uint32 subPos = memStream->pos();
|
||||
|
||||
switch (subType) {
|
||||
// Retail only:
|
||||
case MKTAG('B', 'l', '1', '6'):
|
||||
_videoTrack->handleBlocky16(memStream, subSize);
|
||||
break;
|
||||
case MKTAG('W', 'a', 'v', 'e'):
|
||||
_audioTrack->handleVIMA(memStream, blockSize);
|
||||
break;
|
||||
// Demo only:
|
||||
case MKTAG('F', 'O', 'B', 'J'):
|
||||
_videoTrack->handleFrameObject(memStream, subSize);
|
||||
break;
|
||||
case MKTAG('I', 'A', 'C', 'T'):
|
||||
_audioTrack->handleIACT(memStream, subSize);
|
||||
break;
|
||||
case MKTAG('X', 'P', 'A', 'L'):
|
||||
_videoTrack->handleDeltaPalette(memStream, subSize);
|
||||
break;
|
||||
default:
|
||||
Debug::error(Debug::Movie, "SmushDecoder::handleFrame() unknown tag");
|
||||
}
|
||||
size -= subSize + 8 + (subSize & 1);
|
||||
memStream->seek(subPos + subSize + (subSize & 1), SEEK_SET);
|
||||
}
|
||||
delete memStream;
|
||||
delete[] block;
|
||||
}
|
||||
|
||||
bool SmushDecoder::rewind() {
|
||||
return seekToFrame(0);
|
||||
}
|
||||
|
||||
bool SmushDecoder::seekIntern(const Audio::Timestamp &time) {
|
||||
int32 wantedFrame = (uint32)((time.msecs() / 1000.0f) * _videoTrack->getFrameRate().toDouble());
|
||||
if (wantedFrame != 0) {
|
||||
Debug::debug(Debug::Movie, "Seek to time: %d, frame: %d", time.msecs(), wantedFrame);
|
||||
Debug::debug(Debug::Movie, "Current frame: %d", _videoTrack->getCurFrame());
|
||||
}
|
||||
|
||||
if (wantedFrame > _videoTrack->getFrameCount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_frames) {
|
||||
initFrames();
|
||||
}
|
||||
|
||||
// Track down the keyframe
|
||||
int keyframe = 0;
|
||||
for (int i = wantedFrame; i >= 0; --i) {
|
||||
if (_frames[i].keyframe) {
|
||||
keyframe = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_videoTrack->setFrameStart(keyframe);
|
||||
|
||||
// VIMA frames are 50 frames ahead of time, so we have to make sure we have 50 frames
|
||||
// of audio before the wantedFrame. Here we use 51 to have a bit of safe margin
|
||||
if (wantedFrame - keyframe < 51) {
|
||||
keyframe = wantedFrame - 51;
|
||||
}
|
||||
if (keyframe < 0) {
|
||||
keyframe = 0;
|
||||
}
|
||||
|
||||
_file->seek(_frames[keyframe].pos, SEEK_SET);
|
||||
_videoTrack->setCurFrame(keyframe - 1);
|
||||
|
||||
while (_videoTrack->getCurFrame() < wantedFrame - 1) {
|
||||
decodeNextFrame();
|
||||
}
|
||||
|
||||
// As said, VIMA is 50 frames ahead of time. Every frame it pushes 1470 samples, and 50 * 1470 = 73500.
|
||||
// The first frame, instead of 1470, it pushes 73500 samples to have this 50-frames-time.
|
||||
// So if we have used frame 0 as keyframe we can remove safely time * rate samples, and we will
|
||||
// still have the 50 frames margin. If we have used a later frame as keyframe we don't have the 73500
|
||||
// samples pushed the first frame, so we have to be careful not to remove too much data,
|
||||
// otherwise the audio will start at a later point. (72030 == 73500 - 1470)
|
||||
int offset = (keyframe == 0 ? 0 : 72030);
|
||||
|
||||
// Skip decoded audio between the keyframe and the target frame
|
||||
Audio::Timestamp delay = 0;
|
||||
if (_videoTrack->getCurFrame() > 0) {
|
||||
delay = _videoTrack->getFrameTime(_videoTrack->getCurFrame());
|
||||
}
|
||||
if (keyframe > 0) {
|
||||
delay = delay - _videoTrack->getFrameTime(keyframe);
|
||||
}
|
||||
|
||||
int32 sampleCount = (delay.msecs() / 1000.f) * _audioTrack->getRate() - offset;
|
||||
_audioTrack->skipSamples(sampleCount);
|
||||
|
||||
VideoDecoder::seekIntern(time);
|
||||
return true;
|
||||
}
|
||||
|
||||
SmushDecoder::SmushVideoTrack::SmushVideoTrack(int width, int height, int fps, int numFrames, bool is16Bit) {
|
||||
if (!is16Bit) { // Demo
|
||||
_format = Graphics::PixelFormat::createFormatCLUT8();
|
||||
_codec48 = new Codec48Decoder();
|
||||
_blocky8 = new Blocky8();
|
||||
_blocky16 = nullptr;
|
||||
} else {
|
||||
_format = Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
|
||||
_codec48 = nullptr;
|
||||
_blocky8 = nullptr;
|
||||
_blocky16 = new Blocky16();
|
||||
_blocky16->init(width, height);
|
||||
}
|
||||
_width = width;
|
||||
_height = height;
|
||||
_nbframes = numFrames;
|
||||
_is16Bit = is16Bit;
|
||||
_x = 0;
|
||||
_y = 0;
|
||||
setMsPerFrame(fps);
|
||||
_curFrame = 0;
|
||||
for (int i = 0; i < 0x300; i++) {
|
||||
_palette[i] = 0;
|
||||
_deltaPal[i] = 0;
|
||||
_dirtyPalette = false;
|
||||
}
|
||||
_frameStart = 0;
|
||||
}
|
||||
|
||||
SmushDecoder::SmushVideoTrack::~SmushVideoTrack() {
|
||||
delete _codec48;
|
||||
delete _blocky8;
|
||||
delete _blocky16;
|
||||
_surface.free();
|
||||
}
|
||||
|
||||
void SmushDecoder::SmushVideoTrack::init() {
|
||||
_curFrame = -1;
|
||||
_frameStart = -1;
|
||||
if (_is16Bit) { // Retail only
|
||||
_surface.create(_width, _height, _format);
|
||||
}
|
||||
}
|
||||
|
||||
void SmushDecoder::SmushVideoTrack::finishFrame() {
|
||||
_curFrame++;
|
||||
}
|
||||
|
||||
void SmushDecoder::SmushVideoTrack::setFrameStart(int frame) {
|
||||
_frameStart = frame - 1;
|
||||
}
|
||||
|
||||
void SmushDecoder::SmushVideoTrack::handleBlocky16(Common::SeekableReadStream *stream, uint32 size) {
|
||||
if (_curFrame < _frameStart) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(_is16Bit);
|
||||
byte *ptr = new byte[size];
|
||||
stream->read(ptr, size);
|
||||
|
||||
_blocky16->decode((byte *)_surface.getPixels(), ptr);
|
||||
delete[] ptr;
|
||||
}
|
||||
|
||||
void SmushDecoder::SmushVideoTrack::handleFrameObject(Common::SeekableReadStream *stream, uint32 size) {
|
||||
if (_curFrame < _frameStart) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(!_is16Bit);
|
||||
assert(size >= 14);
|
||||
byte codec = stream->readByte();
|
||||
assert(codec == 47 || codec == 48);
|
||||
/* byte codecParam = */ stream->readByte();
|
||||
_x = stream->readSint16LE();
|
||||
_y = stream->readSint16LE();
|
||||
uint16 width = stream->readUint16LE();
|
||||
uint16 height = stream->readUint16LE();
|
||||
if (width != _width || height != _height) {
|
||||
_width = width;
|
||||
_height = height;
|
||||
_surface.create(_width, _height, _format);
|
||||
_codec48->init(_width, _height);
|
||||
_blocky8->init(_width, _height);
|
||||
}
|
||||
stream->readUint16LE();
|
||||
stream->readUint16LE();
|
||||
|
||||
size -= 14;
|
||||
byte *ptr = new byte[size];
|
||||
stream->read(ptr, size);
|
||||
|
||||
if (codec == 47) {
|
||||
_blocky8->decode((byte *)_surface.getPixels(), ptr);
|
||||
} else if (codec == 48) {
|
||||
_codec48->decode((byte *)_surface.getPixels(), ptr);
|
||||
}
|
||||
delete[] ptr;
|
||||
}
|
||||
|
||||
static byte delta_color(byte org_color, int16 delta_color) {
|
||||
int t = (org_color * 129 + delta_color) / 128;
|
||||
return CLIP(t, 0, 255);
|
||||
}
|
||||
|
||||
void SmushDecoder::SmushVideoTrack::handleDeltaPalette(Common::SeekableReadStream *stream, int32 size) {
|
||||
if (size == 0x300 * 3 + 4) {
|
||||
stream->seek(4, SEEK_CUR);
|
||||
for (int i = 0; i < 0x300; i++) {
|
||||
_deltaPal[i] = stream->readUint16LE();
|
||||
}
|
||||
stream->read(_palette, 0x300);
|
||||
_dirtyPalette = true;
|
||||
} else if (size == 6) {
|
||||
for (int i = 0; i < 0x300; i++) {
|
||||
_palette[i] = delta_color(_palette[i], _deltaPal[i]);
|
||||
}
|
||||
_dirtyPalette = true;
|
||||
} else {
|
||||
error("SmushDecoder::handleDeltaPalette() Wrong size for DeltaPalette");
|
||||
}
|
||||
}
|
||||
|
||||
Graphics::Surface *SmushDecoder::SmushVideoTrack::decodeNextFrame() {
|
||||
return &_surface;
|
||||
}
|
||||
|
||||
void SmushDecoder::SmushVideoTrack::setMsPerFrame(int ms) {
|
||||
_frameRate = Common::Rational(1000000, ms);
|
||||
}
|
||||
SmushDecoder::SmushAudioTrack::SmushAudioTrack(Audio::Mixer::SoundType soundType, bool isVima, int freq, int channels) :
|
||||
AudioTrack(soundType) {
|
||||
_isVima = isVima;
|
||||
_channels = channels;
|
||||
_freq = freq;
|
||||
_queueStream = Audio::makeQueuingAudioStream(_freq, (_channels == 2));
|
||||
_IACTpos = 0;
|
||||
}
|
||||
|
||||
SmushDecoder::SmushAudioTrack::~SmushAudioTrack() {
|
||||
delete _queueStream;
|
||||
}
|
||||
|
||||
void SmushDecoder::SmushAudioTrack::init() {
|
||||
_IACTpos = 0;
|
||||
|
||||
if (_isVima) {
|
||||
vimaInit(smushDestTable);
|
||||
}
|
||||
}
|
||||
|
||||
void SmushDecoder::SmushAudioTrack::handleVIMA(Common::SeekableReadStream *stream, uint32 size) {
|
||||
if (size < 8)
|
||||
return;
|
||||
int decompressedSize = stream->readUint32BE();
|
||||
if (decompressedSize == MKTAG('P', 'S', 'A', 'D')) {
|
||||
decompressedSize = stream->readUint32BE();
|
||||
if (decompressedSize > (int)size - 8)
|
||||
decompressedSize = size - 8;
|
||||
if (decompressedSize < 10)
|
||||
return;
|
||||
stream->skip(10);
|
||||
decompressedSize -= 10;
|
||||
byte *src = (byte *)malloc(decompressedSize);
|
||||
stream->read(src, decompressedSize);
|
||||
|
||||
int flags = Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN;
|
||||
if (_channels == 2) {
|
||||
flags |= Audio::FLAG_STEREO;
|
||||
}
|
||||
|
||||
if (!_queueStream) {
|
||||
_queueStream = Audio::makeQueuingAudioStream(_freq, (_channels == 2));
|
||||
}
|
||||
_queueStream->queueBuffer(src, decompressedSize, DisposeAfterUse::YES, flags);
|
||||
|
||||
return;
|
||||
}
|
||||
if (decompressedSize < 0) {
|
||||
stream->readUint32BE();
|
||||
decompressedSize = stream->readUint32BE();
|
||||
}
|
||||
|
||||
byte *src = new byte[size];
|
||||
stream->read(src, size);
|
||||
|
||||
// this will be deleted using free() by the stream, so allocate it using malloc().
|
||||
int16 *dst = (int16 *)malloc(decompressedSize * _channels * 2);
|
||||
decompressVima(src, dst, decompressedSize * _channels * 2, smushDestTable, true);
|
||||
|
||||
int flags = Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN;
|
||||
if (_channels == 2) {
|
||||
flags |= Audio::FLAG_STEREO;
|
||||
}
|
||||
|
||||
if (!_queueStream) {
|
||||
_queueStream = Audio::makeQueuingAudioStream(_freq, (_channels == 2));
|
||||
}
|
||||
_queueStream->queueBuffer((byte *)dst, decompressedSize * _channels * 2, DisposeAfterUse::YES, flags);
|
||||
delete[] src;
|
||||
}
|
||||
|
||||
void SmushDecoder::SmushAudioTrack::handleIACT(Common::SeekableReadStream *stream, int32 size) {
|
||||
byte *src = new byte[size];
|
||||
stream->read(src, size);
|
||||
|
||||
int32 bsize = size - 18;
|
||||
const byte *d_src = src + 18;
|
||||
|
||||
while (bsize > 0) {
|
||||
if (_IACTpos >= 2) {
|
||||
int32 len = READ_BE_UINT16(_IACToutput) + 2;
|
||||
len -= _IACTpos;
|
||||
if (len > bsize) {
|
||||
memcpy(_IACToutput + _IACTpos, d_src, bsize);
|
||||
_IACTpos += bsize;
|
||||
bsize = 0;
|
||||
} else {
|
||||
// this will be deleted using free() by the stream, so allocate it using malloc().
|
||||
byte *output_data = (byte *)malloc(4096);
|
||||
memcpy(_IACToutput + _IACTpos, d_src, len);
|
||||
byte *dst = output_data;
|
||||
byte *d_src2 = _IACToutput;
|
||||
d_src2 += 2;
|
||||
int32 count = 1024;
|
||||
byte variable1 = *d_src2++;
|
||||
byte variable2 = variable1 / 16;
|
||||
variable1 &= 0x0f;
|
||||
do {
|
||||
byte value;
|
||||
value = *(d_src2++);
|
||||
if (value == 0x80) {
|
||||
*dst++ = *d_src2++;
|
||||
*dst++ = *d_src2++;
|
||||
} else {
|
||||
int16 val = (int8)value << variable2;
|
||||
*dst++ = val >> 8;
|
||||
*dst++ = (byte)(val);
|
||||
}
|
||||
value = *(d_src2++);
|
||||
if (value == 0x80) {
|
||||
*dst++ = *d_src2++;
|
||||
*dst++ = *d_src2++;
|
||||
} else {
|
||||
int16 val = (int8)value << variable1;
|
||||
*dst++ = val >> 8;
|
||||
*dst++ = (byte)(val);
|
||||
}
|
||||
} while (--count);
|
||||
|
||||
if (!_queueStream) {
|
||||
_queueStream = Audio::makeQueuingAudioStream(22050, true);
|
||||
}
|
||||
_queueStream->queueBuffer(output_data, 0x1000, DisposeAfterUse::YES, Audio::FLAG_STEREO | Audio::FLAG_16BITS);
|
||||
|
||||
bsize -= len;
|
||||
d_src += len;
|
||||
_IACTpos = 0;
|
||||
}
|
||||
} else {
|
||||
if (bsize > 1 && _IACTpos == 0) {
|
||||
*(_IACToutput + 0) = *d_src++;
|
||||
_IACTpos = 1;
|
||||
bsize--;
|
||||
}
|
||||
*(_IACToutput + _IACTpos) = *d_src++;
|
||||
_IACTpos++;
|
||||
bsize--;
|
||||
}
|
||||
}
|
||||
delete[] src;
|
||||
}
|
||||
|
||||
bool SmushDecoder::SmushAudioTrack::seek(const Audio::Timestamp &time) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void SmushDecoder::SmushAudioTrack::skipSamples(int sampleCount) {
|
||||
if (sampleCount <= 0)
|
||||
return;
|
||||
|
||||
if (_queueStream->isStereo())
|
||||
sampleCount *= 2;
|
||||
|
||||
int16 *tempBuffer = new int16[sampleCount];
|
||||
_queueStream->readBuffer(tempBuffer, sampleCount);
|
||||
delete[] tempBuffer;
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
156
engines/grim/movie/codecs/smush_decoder.h
Normal file
156
engines/grim/movie/codecs/smush_decoder.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRIM_SMUSH_DECODER_H
|
||||
#define GRIM_SMUSH_DECODER_H
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
|
||||
#include "video/video_decoder.h"
|
||||
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace Audio {
|
||||
class QueuingAudioStream;
|
||||
}
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class Codec48Decoder;
|
||||
class Blocky8;
|
||||
class Blocky16;
|
||||
|
||||
class SmushDecoder : public Video::VideoDecoder {
|
||||
public:
|
||||
SmushDecoder();
|
||||
~SmushDecoder();
|
||||
|
||||
int getX() const { return _videoTrack->_x; }
|
||||
int getY() const { return _videoTrack->_y; }
|
||||
void setLooping(bool l);
|
||||
bool isRewindable() const override { return true; }
|
||||
bool isSeekable() const override { return true; }
|
||||
bool rewind() override;
|
||||
bool seekIntern(const Audio::Timestamp &time) override;
|
||||
bool loadStream(Common::SeekableReadStream *stream) override;
|
||||
|
||||
protected:
|
||||
bool readHeader();
|
||||
void handleFrameDemo();
|
||||
void handleFrame();
|
||||
bool handleFramesHeader();
|
||||
void handleFRME(Common::SeekableReadStream *stream, uint32 size);
|
||||
void init();
|
||||
void close() override;
|
||||
const Graphics::Surface *decodeNextFrame() override;
|
||||
class SmushVideoTrack : public FixedRateVideoTrack {
|
||||
public:
|
||||
SmushVideoTrack(int width, int height, int fps, int numFrames, bool is16Bit);
|
||||
~SmushVideoTrack();
|
||||
|
||||
uint16 getWidth() const override { return _width; }
|
||||
uint16 getHeight() const override { return _height; }
|
||||
Graphics::PixelFormat getPixelFormat() const override { return _format; }
|
||||
int getCurFrame() const override { return _curFrame; }
|
||||
void setCurFrame(int frame) { _curFrame = frame; }
|
||||
int getFrameCount() const override { return _nbframes; }
|
||||
Common::Rational getFrameRate() const override { return _frameRate; }
|
||||
void setMsPerFrame(int ms);
|
||||
|
||||
void finishFrame();
|
||||
bool isSeekable() const override { return true; }
|
||||
bool seek(const Audio::Timestamp &time) override { return true; }
|
||||
void setFrameStart(int frame);
|
||||
|
||||
void handleBlocky16(Common::SeekableReadStream *stream, uint32 size);
|
||||
void handleFrameObject(Common::SeekableReadStream *stream, uint32 size);
|
||||
void handleDeltaPalette(Common::SeekableReadStream *stream, int32 size);
|
||||
void init();
|
||||
Graphics::Surface *decodeNextFrame() override;
|
||||
const byte *getPalette() const override { _dirtyPalette = false; return _palette; }
|
||||
bool hasDirtyPalette() const override { return _dirtyPalette; }
|
||||
|
||||
byte *getPal() { _dirtyPalette = true; return _palette; }
|
||||
int _x, _y;
|
||||
private:
|
||||
void convertDemoFrame();
|
||||
bool _is16Bit;
|
||||
int32 _curFrame;
|
||||
byte _palette[0x300];
|
||||
int16 _deltaPal[0x300];
|
||||
mutable bool _dirtyPalette;
|
||||
int _width, _height;
|
||||
Graphics::Surface _surface;
|
||||
Graphics::PixelFormat _format;
|
||||
Common::Rational _frameRate;
|
||||
Blocky8 *_blocky8;
|
||||
Blocky16 *_blocky16;
|
||||
Codec48Decoder *_codec48;
|
||||
int32 _nbframes;
|
||||
int _frameStart;
|
||||
};
|
||||
|
||||
class SmushAudioTrack : public AudioTrack {
|
||||
public:
|
||||
SmushAudioTrack(Audio::Mixer::SoundType soundType, bool isVima, int freq = 22050, int channels = -1);
|
||||
~SmushAudioTrack();
|
||||
|
||||
Audio::AudioStream *getAudioStream() const override { return _queueStream; }
|
||||
bool isSeekable() const override { return true; }
|
||||
bool seek(const Audio::Timestamp &time) override;
|
||||
void skipSamples(int samples);
|
||||
inline int getRate() const { return _queueStream->getRate(); }
|
||||
|
||||
void handleVIMA(Common::SeekableReadStream *stream, uint32 size);
|
||||
void handleIACT(Common::SeekableReadStream *stream, int32 size);
|
||||
void init();
|
||||
private:
|
||||
bool _isVima;
|
||||
byte _IACToutput[4096];
|
||||
int32 _IACTpos;
|
||||
int _channels;
|
||||
int _freq;
|
||||
Audio::QueuingAudioStream *_queueStream;
|
||||
};
|
||||
private:
|
||||
void initFrames();
|
||||
|
||||
SmushAudioTrack *_audioTrack;
|
||||
SmushVideoTrack *_videoTrack;
|
||||
|
||||
Common::SeekableReadStream *_file;
|
||||
|
||||
uint32 _startPos;
|
||||
|
||||
bool _videoPause;
|
||||
bool _videoLooping;
|
||||
struct Frame {
|
||||
int frame;
|
||||
int pos;
|
||||
bool keyframe;
|
||||
};
|
||||
Frame *_frames;
|
||||
static bool _demo;
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
254
engines/grim/movie/codecs/vima.cpp
Normal file
254
engines/grim/movie/codecs/vima.cpp
Normal file
@@ -0,0 +1,254 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "common/util.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
static int16 imcTable1[] = {
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
|
||||
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
|
||||
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
|
||||
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
|
||||
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
|
||||
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
|
||||
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
|
||||
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
||||
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
|
||||
};
|
||||
|
||||
static int8 imcTable2[] = {
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
|
||||
};
|
||||
|
||||
static int8 imcOtherTable1[] = {
|
||||
-1, 4, -1, 4
|
||||
};
|
||||
|
||||
static int8 imcOtherTable2[] = {
|
||||
-1, -1, 2, 6, -1, -1, 2, 6
|
||||
};
|
||||
|
||||
static int8 imcOtherTable3[] = {
|
||||
-1, -1, -1, -1, 1, 2, 4, 6,
|
||||
-1, -1, -1, -1, 1, 2, 4, 6
|
||||
};
|
||||
|
||||
static int8 imcOtherTable4[] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
1, 1, 1, 2, 2, 4, 5, 6,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
1, 1, 1, 2, 2, 4, 5, 6
|
||||
};
|
||||
|
||||
static int8 imcOtherTable5[] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
1, 1, 1, 1, 1, 2, 2, 2,
|
||||
2, 4, 4, 4, 5, 5, 6, 6,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
1, 1, 1, 1, 1, 2, 2, 2,
|
||||
2, 4, 4, 4, 5, 5, 6, 6
|
||||
};
|
||||
|
||||
static int8 imcOtherTable6[] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 4, 4, 4, 4, 4, 4,
|
||||
5, 5, 5, 5, 6, 6, 6, 6,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 4, 4, 4, 4, 4, 4,
|
||||
5, 5, 5, 5, 6, 6, 6, 6
|
||||
};
|
||||
|
||||
static int8 *offsets[] = {
|
||||
imcOtherTable1, imcOtherTable2, imcOtherTable3,
|
||||
imcOtherTable4, imcOtherTable5, imcOtherTable6
|
||||
};
|
||||
|
||||
void vimaInit(uint16 *destTable) {
|
||||
int destTableStartPos, incer;
|
||||
|
||||
for (destTableStartPos = 0, incer = 0; destTableStartPos < 64; destTableStartPos++, incer++) {
|
||||
unsigned int destTablePos, imcTable1Pos;
|
||||
for (imcTable1Pos = 0, destTablePos = destTableStartPos;
|
||||
imcTable1Pos < sizeof(imcTable1) / sizeof(imcTable1[0]); imcTable1Pos++, destTablePos += 64) {
|
||||
int put = 0, count, tableValue;
|
||||
for (count = 32, tableValue = imcTable1[imcTable1Pos]; count != 0; count >>= 1, tableValue >>= 1) {
|
||||
if (incer & count) {
|
||||
put += tableValue;
|
||||
}
|
||||
}
|
||||
destTable[destTablePos] = put;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void decompressVima(const byte *src, int16 *dest, int destLen, uint16 *destTable, bool isSmush) {
|
||||
int numChannels = 1;
|
||||
byte sBytes[2];
|
||||
int16 sWords[2];
|
||||
|
||||
sBytes[0] = *src++;
|
||||
if (sBytes[0] & 0x80) {
|
||||
sBytes[0] = ~sBytes[0];
|
||||
numChannels = 2;
|
||||
}
|
||||
sWords[0] = READ_BE_UINT16(src);
|
||||
src += 2;
|
||||
if (numChannels > 1) {
|
||||
sBytes[1] = *src++;
|
||||
sWords[1] = READ_BE_UINT16(src);
|
||||
src += 2;
|
||||
}
|
||||
|
||||
int numSamples = destLen / (numChannels * 2);
|
||||
|
||||
if (READ_BE_UINT32(src) == MKTAG('I', 'M', 'A', '4')) {
|
||||
int outputWord = 0;
|
||||
int currTablePos = 0;
|
||||
static const int tableDeltas[16] = {
|
||||
-1, -1, -1, -1,
|
||||
2, 4, 6, 8,
|
||||
-1, -1, -1, -1,
|
||||
2, 4, 6, 8
|
||||
};
|
||||
int16 *destPos = dest;
|
||||
int curai = 7;
|
||||
byte inputByte = 0;
|
||||
bool nibbleSwitch = false;
|
||||
|
||||
src += 4;
|
||||
if (isSmush) {
|
||||
outputWord = READ_LE_INT16(src);
|
||||
currTablePos = src[2];
|
||||
src += 3;
|
||||
}
|
||||
|
||||
for (int sample = 0; sample < numSamples; sample++) {
|
||||
byte nibble;
|
||||
if (!nibbleSwitch) {
|
||||
inputByte = *src++;
|
||||
nibble = inputByte >> 4;
|
||||
} else
|
||||
nibble = inputByte & 0xf;
|
||||
nibbleSwitch = !nibbleSwitch;
|
||||
currTablePos = CLIP(currTablePos + tableDeltas[nibble & 0xf], 0, 88);
|
||||
int delta = curai >> 3;
|
||||
if (nibble & 4) {
|
||||
delta = delta + curai;
|
||||
}
|
||||
if (nibble & 2) {
|
||||
delta = delta + (curai >> 1);
|
||||
}
|
||||
if (nibble & 1) {
|
||||
delta = delta + (curai >> 2);
|
||||
}
|
||||
if (nibble & 8) {
|
||||
delta = -delta;
|
||||
}
|
||||
outputWord = CLIP(outputWord + delta, -0x8000, 0x7fff);
|
||||
if (currTablePos > 0)
|
||||
curai = imcTable1[currTablePos];
|
||||
for (int channel = 0; channel < numChannels; channel++)
|
||||
WRITE_LE_UINT16(destPos + channel, outputWord);
|
||||
destPos += numChannels;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int bits = READ_BE_UINT16(src);
|
||||
int bitPtr = 0;
|
||||
src += 2;
|
||||
|
||||
for (int channel = 0; channel < numChannels; channel++) {
|
||||
int16 *destPos = dest + channel;
|
||||
int currTablePos = sBytes[channel];
|
||||
int outputWord = sWords[channel];
|
||||
|
||||
for (int sample = 0; sample < numSamples; sample++) {
|
||||
int numBits = imcTable2[currTablePos];
|
||||
bitPtr += numBits;
|
||||
int highBit = 1 << (numBits - 1);
|
||||
int lowBits = highBit - 1;
|
||||
int val = (bits >> (16 - bitPtr)) & (highBit | lowBits);
|
||||
|
||||
if (bitPtr > 7) {
|
||||
bits = ((bits & 0xff) << 8) | *src++;
|
||||
bitPtr -= 8;
|
||||
}
|
||||
|
||||
if (val & highBit)
|
||||
val ^= highBit;
|
||||
else
|
||||
highBit = 0;
|
||||
|
||||
if (val == lowBits) {
|
||||
outputWord = ((int16)(bits << bitPtr) & 0xffffff00);
|
||||
bits = ((bits & 0xff) << 8) | *src++;
|
||||
outputWord |= ((bits >> (8 - bitPtr)) & 0xff);
|
||||
bits = ((bits & 0xff) << 8) | *src++;
|
||||
} else {
|
||||
int index = (val << (7 - numBits)) | (currTablePos << 6);
|
||||
int delta = destTable[index];
|
||||
|
||||
if (val)
|
||||
delta += (imcTable1[currTablePos] >> (numBits - 1));
|
||||
if (highBit)
|
||||
delta = -delta;
|
||||
|
||||
outputWord += delta;
|
||||
if (outputWord < -0x8000)
|
||||
outputWord = -0x8000;
|
||||
else if (outputWord > 0x7fff)
|
||||
outputWord = 0x7fff;
|
||||
}
|
||||
|
||||
WRITE_LE_UINT16(destPos, outputWord);
|
||||
destPos += numChannels;
|
||||
|
||||
currTablePos += offsets[numBits - 2][val];
|
||||
|
||||
if (currTablePos < 0)
|
||||
currTablePos = 0;
|
||||
else if (currTablePos > 88)
|
||||
currTablePos = 88;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
32
engines/grim/movie/codecs/vima.h
Normal file
32
engines/grim/movie/codecs/vima.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRIM_VIMA_H
|
||||
#define GRIM_VIMA_H
|
||||
|
||||
namespace Grim {
|
||||
|
||||
void vimaInit(uint16 *destTable);
|
||||
void decompressVima(const byte *src, int16 *dest, int destLen, uint16 *destTable, bool isSmush);
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user