aboutsummaryrefslogtreecommitdiff
path: root/scumm/insane.cpp
diff options
context:
space:
mode:
authorMax Horn2002-08-21 16:07:07 +0000
committerMax Horn2002-08-21 16:07:07 +0000
commitce46866403fdcc479cf9d67e4d430409b15dadc3 (patch)
tree75ebfaa1ed13f549959d76d3ce101c3e66f5451b /scumm/insane.cpp
parent662256f25dbe43abf67077a804e225738765f009 (diff)
downloadscummvm-rg350-ce46866403fdcc479cf9d67e4d430409b15dadc3.tar.gz
scummvm-rg350-ce46866403fdcc479cf9d67e4d430409b15dadc3.tar.bz2
scummvm-rg350-ce46866403fdcc479cf9d67e4d430409b15dadc3.zip
Initial revision
svn-id: r4785
Diffstat (limited to 'scumm/insane.cpp')
-rw-r--r--scumm/insane.cpp1510
1 files changed, 1510 insertions, 0 deletions
diff --git a/scumm/insane.cpp b/scumm/insane.cpp
new file mode 100644
index 0000000000..ef9dd779eb
--- /dev/null
+++ b/scumm/insane.cpp
@@ -0,0 +1,1510 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001/2002 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#if !defined(macintosh) && !defined(__MORPHOS__)
+#define NEED_SDL_HEADERS
+#endif
+
+#ifdef _WIN32_WCE
+#define PICKY_ALIGN
+#endif
+
+#include "stdafx.h"
+#include "scumm.h"
+#include "smush.h"
+
+static SmushPlayer * h_sp;
+
+SmushPlayer::SmushPlayer(Scumm * parent) {
+ _scumm = parent;
+ h_sp = this;
+}
+
+SmushPlayer::~SmushPlayer() {
+}
+
+static void smush_handler (Scumm * scumm) {
+ h_sp->update();
+}
+
+byte * SmushPlayer::loadTres() {
+ byte buf[100];
+ FILE * f_tres;
+ uint32 tmp, l;
+
+ sprintf((char *)buf, "%sVIDEO/DIGTXT.TRS", (byte *)_scumm->getGameDataPath());
+ f_tres = (FILE*)_scumm->fileOpen((char *)&buf, 1);
+
+ if (f_tres == NULL) {
+ sprintf((char *)buf, "%svideo/digtxt.trs", (byte *)_scumm->getGameDataPath());
+ f_tres = (FILE*)_scumm->fileOpen((char *)&buf, 1);
+ if (f_tres == NULL)
+ return NULL;
+ }
+
+ _scumm->fileRead(f_tres, &tmp, 4); // read tag
+ if (_scumm->_fileReadFailed)
+ error("SP: error while reading TRES");
+
+ tmp = READ_BE_UINT32(&tmp);
+ if (tmp == 'ETRS')
+ {
+ _scumm->fileRead(f_tres, &tmp, 4); // read length
+ tmp = READ_BE_UINT32(&tmp);
+ tmp -= 8;
+ _bufferTres = (byte*)malloc (tmp + 1);
+ _scumm->fileRead(f_tres, _bufferTres, 8); // skip 8 bytes
+ _scumm->fileRead(f_tres, _bufferTres, tmp);
+ for (l = 0; l < tmp; l++)
+ *(_bufferTres + l) ^= 0xcc;
+ _bufferTres[tmp] = 0;
+ }
+ else
+ {
+ _scumm->fileSeek(f_tres, 0, SEEK_END); // assume file is unencrypted
+ tmp = ftell(f_tres);
+ _scumm->fileSeek(f_tres, 0, SEEK_SET);
+ _bufferTres = (byte*)malloc (tmp + 1);
+ fread(_bufferTres, tmp, 1, f_tres);
+ _bufferTres[tmp] = 0;
+ }
+ _scumm->fileClose(f_tres);
+
+ return _bufferTres;
+}
+
+void SmushPlayer::loadFonts() {
+ byte buf[100];
+ FILE * f_tres;
+ uint32 tmp;
+ int l;
+ byte * buffer = NULL;
+
+ for (l = 0; l < SP_MAX_FONTS; l++)
+ {
+ _fonts [l] = NULL;
+ sprintf((char *)buf, "%sVIDEO/FONT%d.NUT", (char *)_scumm->getGameDataPath(), l);
+ f_tres = (FILE*)_scumm->fileOpen((char *)buf, 1);
+
+ if (f_tres == NULL) {
+ sprintf((char *)buf, "%svideo/font%d.nut", (char *)_scumm->getGameDataPath(), l);
+ f_tres = (FILE*)_scumm->fileOpen((char *)buf, 1);
+ if (f_tres == NULL)
+ continue;
+ }
+
+ _scumm->fileRead(f_tres, &tmp, 4); // read tag
+ tmp = READ_BE_UINT32(&tmp);
+ if (tmp == 'ANIM') {
+ _scumm->fileRead(f_tres, &tmp, 4); // read length
+ tmp = READ_BE_UINT32(&tmp);
+ buffer = (byte *)malloc(tmp);
+ _scumm->fileRead(f_tres, buffer, tmp);
+ _fonts[l] = buffer;
+ }
+ _scumm->fileClose(f_tres);
+ }
+}
+
+byte * SmushPlayer::getStringTRES(int32 number) {
+ byte * txt = NULL;
+ uint32 l, i, j;
+
+ for (l = 0;; l++) {
+ char t = *(_bufferTres + l);
+ if (t == 0)
+ break;
+ if (t == '#') {
+ byte buf[10];
+ strncpy ((char*)buf, (char*)_bufferTres + l + 1, 9);
+ buf[9] = 0;
+ if (strcmp ((char*)buf, "define a ") == 0) {
+ l += 10;
+ for (i = 0; i < 5; i++) {
+ buf[i] = *(_bufferTres + l + i);
+ if (buf[i] == 0x0d)
+ {
+ buf[i] = 0;
+ l += 2;
+ break;
+ }
+ }
+ if (atol((char*)buf) == number) {
+ for (j = 0; j < 200; j++) {
+ t = *(_bufferTres + l + j + i);
+ if ((t == 0) || (t == '#'))
+ break;
+ }
+ txt = (byte *)malloc(j + 1);
+ strncpy((char*)txt, (char*)_bufferTres + l + i, j);
+ txt[j] = 0;
+ return txt;
+ }
+ }
+ }
+ }
+
+ return txt;
+}
+
+uint32 SmushPlayer::getFontHeight(uint8 c_font) {
+ byte * font = _fonts[c_font];
+ uint32 offset = 0, t_offset = 0;
+
+ if (font == NULL)
+ return 0;
+
+ if (READ_BE_UINT32(font) != 'AHDR')
+ return 0;
+
+ offset = READ_BE_UINT32(font + 4) + 8;
+ if (READ_BE_UINT32(font + offset) == 'FRME') {
+ offset += 8;
+ if (READ_BE_UINT32(font + offset) == 'FOBJ') {
+ t_offset = offset + 8;
+ }
+ else
+ return 0;
+ }
+ return READ_LE_UINT16(font + t_offset + 8);
+}
+
+uint32 SmushPlayer::getCharWidth(uint8 c_font, byte txt) {
+ byte * font = _fonts[c_font];
+ uint32 offset = 0, t_offset = 0, l;
+
+ if (font == NULL)
+ return 0;
+
+ if (READ_BE_UINT32(font) != 'AHDR')
+ return 0;
+
+ offset = READ_BE_UINT32(font + 4) + 8;
+ for (l = 0; l <= txt; l++) {
+ if (READ_BE_UINT32(font + offset) == 'FRME') {
+ offset += 8;
+ if (READ_BE_UINT32(font + offset) == 'FOBJ') {
+ t_offset = offset + 8;
+ offset += READ_BE_UINT32(font + offset + 4) + 8;
+ }
+ else
+ return 0;
+ }
+ else
+ return 0;
+ }
+ return READ_LE_UINT16(font + t_offset + 6);
+}
+
+void SmushPlayer::drawStringTRES(uint32 x, uint32 y, byte * txt) {
+ char buf[4];
+ uint32 c_line = 0, l = 0, i, tmp_x, x_pos, last_l, t_width, t_height;
+ uint8 c_font = 0, c_color = 0, last_j;
+ int j;
+
+ if ((txt[l] == '^') && (txt[l + 1] == 'f')) {
+ buf[0] = txt[l + 2];
+ buf[1] = txt[l + 3];
+ buf[2] = 0;
+ l += 4;
+ c_font = atoi(buf);
+ if (c_font >= SP_MAX_FONTS)
+ error ("SP: number font out of range");
+ }
+ if ((txt[l] == '^') && (txt[l + 1] == 'c')) {
+ buf[0] = txt[l + 2];
+ buf[1] = txt[l + 3];
+ buf[2] = txt[l + 4];
+ buf[3] = 0;
+ l += 5;
+ c_color = atoi(buf);
+ }
+
+ t_height = getFontHeight(c_font);
+ x_pos = x;
+ last_j = 0;
+ last_l = l;
+
+ for (j = 0;; j++) {
+ if (txt[l + j] == 0) {
+ break;
+ }
+ if (txt[l + j] == 0x0d) {
+ if (txt[l + j + 2] == 0x0d) break;
+ l += j + 2;
+ j = -1;
+ last_j = 0;
+ c_line++;
+ x_pos = x;
+ if (c_line * t_height + y >= 200) {
+ if (y > t_height) {
+ y -= t_height;
+ }
+ else
+ {
+ y = 0;
+ }
+ continue;
+ }
+ }
+ t_width = getCharWidth (c_font, txt[l + j]);
+ if (x_pos + t_width >= 320) {
+ if ((x > t_width) && (c_line == 0)) {
+ x -= t_width;
+ x_pos += t_width;
+ if (txt[l + j] == ' ') {
+ last_j = j;
+ }
+ continue;
+ }
+ j = last_j;
+ txt[l + j] = 0x0d;
+ x_pos = x;
+ c_line++;
+ l++;
+ j = -1;
+ last_j = 0;
+ if (c_line * t_height + y >= 200) {
+ if (y > t_height) {
+ y -= t_height;
+ }
+ else {
+ y = 0;
+ }
+ }
+ }
+ else {
+ x_pos += t_width;
+ if (txt[l + j] == ' ') {
+ last_j = j;
+ }
+ }
+ }
+
+ l = last_l;
+ c_line = 0;
+
+ for (;;) {
+ tmp_x = x;
+ for (i = 0;; i++) {
+ if (txt[l + i] == 0)
+ goto exit_loop;
+ if (txt[l + i] == 0x0d) {
+ if (txt[l + i + 1] == 0x0a) {
+ l += i + 2;
+ break;
+ }
+ else {
+ l += i + 1;
+ break;
+ }
+ }
+ drawCharTRES (&tmp_x, y, c_line, c_font, c_color, txt[l + i]);
+ }
+ c_line++;
+ }
+exit_loop: ;
+
+}
+
+void SmushPlayer::codec44Depack(byte *dst, byte *src, uint32 len) {
+ byte val;
+ uint16 size_line;
+ uint16 num;
+
+ do {
+ size_line = READ_LE_UINT16(src);
+ src += 2;
+ len -= 2;
+
+ for (; size_line != 0;) {
+ num = *src++;
+ val = *src++;
+ memset(dst, val, num);
+ dst += num;
+ len -= 2;
+ size_line -= 2;
+ if (size_line == 0) break;
+
+ num = READ_LE_UINT16(src) + 1;
+ src += 2;
+ memcpy(dst, src, num);
+ dst += num;
+ src += num;
+ len -= num + 2;
+ size_line -= num + 2;
+
+ }
+ dst--;
+
+ } while (len > 1);
+}
+
+void SmushPlayer::drawCharTRES(uint32 * x, uint32 y, uint32 c_line, uint8 c_font, uint8 color, uint8 txt) {
+ byte * font = _fonts[c_font];
+ uint32 offset = 0, t_offset = 0, l, width, height, length = 0;
+
+ if (font == NULL)
+ return;
+
+ if (READ_BE_UINT32(font) != 'AHDR')
+ return;
+
+ offset = READ_BE_UINT32(font + 4) + 8;
+ for (l = 0; l <= txt; l++) {
+ if (READ_BE_UINT32(font + offset) == 'FRME') {
+ offset += 8;
+ if (READ_BE_UINT32(font + offset) == 'FOBJ') {
+ t_offset = offset + 8;
+ length = READ_BE_UINT32(font + offset + 4) - 0xe;
+ offset += READ_BE_UINT32(font + offset + 4) + 8;
+ }
+ else
+ return;
+ }
+ else
+ return;
+ }
+
+ byte * dst = (byte*)malloc (1000);
+ byte * src = (byte*)(font + t_offset + 0x0e);
+
+ codec44Depack (dst, src, length);
+
+ width = READ_LE_UINT16(font + t_offset + 6);
+ height = READ_LE_UINT16(font + t_offset + 8);
+
+ y += c_line * height;
+ for (uint32 ty = 0; ty < height; ty++) {
+ for (uint32 tx = 0; tx < width; tx++) {
+ byte pixel = *(dst + ty * width + tx);
+ if (pixel != 0) {
+ if (color == 0) {
+ if (pixel == 0x01)
+ pixel = 0xf;
+ }
+ else {
+ if (pixel == 0x01)
+ pixel = color;
+ }
+ if (pixel == 0xff)
+ pixel = 0x0;
+ *(_renderBitmap + ((ty + y) * 320 + *x + tx)) = pixel;
+ }
+ }
+ }
+ *x += width;
+ free (dst);
+}
+
+uint32 SmushPlayer::nextBE32() {
+ uint32 a = READ_BE_UINT32(_cur);
+ _cur += sizeof(uint32);
+
+ return a;
+}
+
+void SmushPlayer::openFile(byte *fileName) {
+ byte buf[100];
+
+ sprintf((char *)buf, "%sVIDEO/%s", (char *)_scumm->getGameDataPath(), (char *)fileName);
+ _in = (FILE*)_scumm->fileOpen((char *)buf, 1);
+
+ if (_in == NULL) {
+ sprintf((char *)buf, "%svideo/%s", (char *)_scumm->getGameDataPath(), (char *)fileName);
+ _in = (FILE*)_scumm->fileOpen((char *)buf, 1);
+ }
+}
+
+void SmushPlayer::nextBlock() {
+ _blockTag = _scumm->fileReadDwordBE(_in);
+ _blockSize = _scumm->fileReadDwordBE(_in);
+
+ if (_block != NULL)
+ free(_block);
+
+ _block = (byte *)malloc(_blockSize);
+
+ if (_block == NULL)
+ error("SP: cannot allocate memory");
+
+ _scumm->fileRead(_in, _block, _blockSize);
+}
+
+bool SmushPlayer::parseTag() {
+ switch (nextBlock(), _blockTag) {
+
+ case 'AHDR':
+ parseAHDR();
+ break;
+
+ case 'FRME':
+ parseFRME();
+ break;
+
+ default:
+ error("SP: Encountered invalid block %c%c%c%c", _blockTag >> 24, _blockTag >> 16, _blockTag >> 8, _blockTag);
+ }
+
+ return true;
+}
+
+void SmushPlayer::parseAHDR() {
+ memcpy(_fluPalette, _block + 6, 0x300);
+ _paletteChanged = true;
+}
+
+void SmushPlayer::parseIACT() {
+ uint32 pos, bpos, tag, sublen, subpos, trk, idx;
+ byte flags;
+ bool new_mixer = false;
+ byte *buf;
+
+ flags = SoundMixer::FLAG_AUTOFREE;
+
+ pos = 0;
+ pos += 6;
+
+ trk = READ_LE_UINT32(_cur + pos); /* FIXME: is this correct ? */
+ pos += 4;
+
+ for (idx = 0; idx < MAX_STREAMER; idx++) {
+ if (_imusTrk[idx] == trk)
+ break;
+ }
+
+ if (idx == MAX_STREAMER) {
+ for (idx = 0; idx < MAX_STREAMER; idx++) {
+ if (_imusTrk[idx] == 0 && _scumm->_mixer->_channels[idx] == NULL) {
+ _imusTrk[idx] = trk;
+ _imusSize[idx] = 0;
+ new_mixer = true;
+ break;
+ }
+ }
+ }
+
+ if (idx == MAX_STREAMER) {
+ warning("iMUS table full");
+ return;
+ }
+
+ pos += 8; /* FIXME: what are these ? */
+
+ while (pos < _frmeSize) {
+
+ if (_imusSize[idx] == 0) {
+ tag = READ_BE_UINT32(_cur + pos);
+ pos += 4;
+ if (tag != 'iMUS')
+ error("trk %d: iMUS tag not found", trk);
+ _imusSize[idx] = READ_BE_UINT32(_cur + pos);
+ pos += 4;
+ }
+ if (_imusSubSize[idx] == 0) {
+ _imusSubTag[idx] = READ_BE_UINT32(_cur + pos);
+ pos += 4;
+ _imusSubSize[idx] = READ_BE_UINT32(_cur + pos);
+ pos += 4;
+ _imusSize[idx] -= 8;
+ debug(3, "trk %d: tag '%4s' size %x", trk, _cur + pos - 8, _imusSubSize[idx]);
+ }
+
+ sublen = _imusSubSize[idx] < (_frmeSize - pos) ? _imusSubSize[idx] : (_frmeSize - pos);
+
+ switch (_imusSubTag[idx]) {
+ case 'MAP ':
+ tag = READ_BE_UINT32(_cur + pos);
+ if (tag != 'FRMT')
+ error("trk %d: no FRMT section");
+ _imusCodec[idx] = READ_BE_UINT32(_cur + pos + 16);
+ _imusRate[idx] = READ_BE_UINT32(_cur + pos + 20);
+ _imusChan[idx] = READ_BE_UINT32(_cur + pos + 24);
+ _imusPos[idx] = 0;
+ break;
+ case 'DATA':
+ switch (_imusCodec[idx]) {
+ case 8:
+ if (_imusChan[idx] == 2)
+ flags |= SoundMixer::FLAG_STEREO;
+ flags |= SoundMixer::FLAG_UNSIGNED;
+ buf = (byte *)malloc(sublen);
+ memcpy(buf, _cur + pos, sublen);
+ bpos = sublen;
+ break;
+ case 12:
+ if (_imusChan[idx] == 2)
+ flags |= SoundMixer::FLAG_STEREO;
+ flags |= SoundMixer::FLAG_16BITS;
+ buf = (byte *)malloc(2 * sublen);
+
+ bpos = 0;
+ subpos = 0;
+
+ while (subpos < sublen) {
+
+ while (_imusPos[idx] < 3 && subpos < sublen) {
+ _imusData[idx][_imusPos[idx]] = _cur[pos + subpos];
+ _imusPos[idx]++;
+ subpos++;
+ }
+
+ if (_imusPos[idx] == 3) {
+ uint32 temp;
+
+ temp = (_imusData[idx][1] & 0x0f) << 8;
+ temp = (temp | _imusData[idx][0]) << 4;
+ temp -= 0x8000;
+
+ buf[bpos++] = (byte)((temp >> 8) & 0xff);
+ buf[bpos++] = (byte)(temp & 0xff);
+
+ temp = (_imusData[idx][1] & 0xf0) << 4;
+ temp = (temp | _imusData[idx][2]) << 4;
+ temp -= 0x8000;
+
+ buf[bpos++] = (byte)((temp >> 8) & 0xff);
+ buf[bpos++] = (byte)(temp & 0xff);
+ _imusPos[idx] = 0;
+ }
+ }
+ break;
+ default:
+ error("trk %d: unknown iMUS codec %d", trk, _imusCodec[idx]);
+ }
+
+ debug(3, "trk %d: iMUSE play part, len 0x%x rate %d remain 0x%x",
+ trk, bpos, _imusRate[idx], _imusSubSize[idx]);
+
+ _imusBuf[idx] = buf;
+ _imusFinalSize[idx] = bpos;
+ _imusFlags[idx] = flags;
+ _imusNewMixer[idx] = new_mixer;
+
+ break;
+ default:
+ error("trk %d: unknown tag inside iMUS %08x [%c%c%c%c]",
+ trk, _imusSubTag[idx], _imusSubTag[idx] >> 24,
+ _imusSubTag[idx] >> 16, _imusSubTag[idx] >> 8, _imusSubTag[idx]);
+ }
+
+ _imusSubSize[idx] -= sublen;
+ _imusSize[idx] -= sublen;
+ pos += sublen;
+
+ if (_imusSubSize[idx] == 0 && _imusSubTag[idx] == 'DATA') {
+ _imusTrk[idx] = 0;
+ return;
+ }
+ }
+}
+
+void SmushPlayer::parseNPAL() {
+ memcpy(_fluPalette, _cur, 0x300);
+ _paletteChanged = true;
+}
+
+void SmushPlayer::codec1(CodecData * cd) {
+ uint y = cd->y;
+ byte *src = cd->src;
+ byte *dest = cd->out;
+ uint h = cd->h;
+
+ if (!h || !cd->w)
+ return;
+
+ dest += cd->y * cd->pitch;
+
+ do {
+ byte color;
+ uint len, num;
+ uint x;
+
+ if ((uint) y >= (uint) cd->outheight) {
+ src += READ_LE_UINT16(src)+2;
+ continue;
+ }
+
+ len = cd->w;
+ x = cd->x;
+ src += 2;
+
+ do {
+ byte code = *src++;
+
+ num = (code >> 1) + 1;
+ if (num > len)
+ num = len;
+ len -= num;
+
+ if (code & 1) {
+ color = *src++;
+// if ((color = *src++)!=0) {
+ do {
+ if ((uint) x < (uint) cd->outwidth)
+ dest[x] = color;
+ } while (++x, --num);
+// } else {
+// x += num;
+// }
+ } else {
+ do {
+ color = *src++;
+ if ( /*(color=*src++) != 0 && */ (uint) x < (uint) cd->outwidth)
+ dest[x] = color;
+ } while (++x, --num);
+ }
+ } while (len);
+ } while (dest += cd->pitch, y++, --h);
+}
+
+void SmushPlayer::codec37BompDepack(byte *dst, byte *src, int32 len) {
+ byte code;
+ byte color;
+ int32 num;
+
+ do {
+ code = *src++;
+ if (code & 1) {
+ num = (code >> 1) + 1;
+ color = *src++;
+ memset(dst, color, num);
+ dst += num;
+ } else {
+ num = (code >> 1) + 1;
+ memcpy(dst, src, num);
+ dst += num;
+ src += num;
+ }
+ } while (len -= num);
+}
+
+void SmushPlayer::codec37Proc4(byte *dst, byte *src, int32 next_offs, int32 bw, int32 bh, int32 pitch, int16 *table) {
+ byte code, *tmp;
+ int32 i;
+ uint32 t;
+
+ if (pitch != 320) {
+ warning("SP: invalid pitch");
+ return;
+ }
+
+ do {
+ i = bw;
+ do {
+ code = *src++;
+ if (code == 0xFD) {
+ t = src[0];
+ t += (t << 8) + (t << 16) + (t << 24);
+#ifdef PICKY_ALIGN
+ memcpy(dst, &t, sizeof uint32);
+ memcpy(dst + 320, &t, sizeof uint32);
+ memcpy(dst + 320 * 2, &t, sizeof uint32);
+ memcpy(dst + 320 * 3, &t, sizeof uint32);
+#else
+ *(uint32 *)(dst + 0) = t;
+ *(uint32 *)(dst + 320) = t;
+ *(uint32 *)(dst + 320 * 2) = t;
+ *(uint32 *)(dst + 320 * 3) = t;
+#endif
+ src += 1;
+ dst += 4;
+ } else if (code == 0xFE) {
+ t = src[0];
+ t += (t << 8) + (t << 16) + (t << 24);
+#ifdef PICKY_ALIGN
+ memcpy(dst, &t, sizeof uint32);
+#else
+ *(uint32 *)(dst + 0) = t;
+#endif
+ t = src[1];
+ t += (t << 8) + (t << 16) + (t << 24);
+#ifdef PICKY_ALIGN
+ memcpy(dst + 320, &t, sizeof uint32);
+#else
+ *(uint32 *)(dst + 320) = t;
+#endif
+ t = src[2];
+ t += (t << 8) + (t << 16) + (t << 24);
+#ifdef PICKY_ALIGN
+ memcpy(dst + 320 * 2, &t, sizeof uint32);
+#else
+ *(uint32 *)(dst + 320 * 2) = t;
+#endif
+ t = src[3];
+ t += (t << 8) + (t << 16) + (t << 24);
+#ifdef PICKY_ALIGN
+ memcpy(dst + 320 * 3, &t, sizeof uint32);
+#else
+ *(uint32 *)(dst + 320 * 3) = t;
+#endif
+ src += 4;
+ dst += 4;
+ } else if (code == 0xFF) {
+#ifdef PICKY_ALIGN
+ memcpy(dst, src, sizeof uint32);
+ memcpy(dst + 320, src + sizeof uint32, sizeof uint32);
+ memcpy(dst + 320 * 2, src + 2 * sizeof uint32, sizeof uint32);
+ memcpy(dst + 320 * 3, src + 3 * sizeof uint32, sizeof uint32);
+#else
+ *(uint32 *)(dst + 0) = ((uint32 *)src)[0];
+ *(uint32 *)(dst + 320) = ((uint32 *)src)[1];
+ *(uint32 *)(dst + 320 * 2) = ((uint32 *)src)[2];
+ *(uint32 *)(dst + 320 * 3) = ((uint32 *)src)[3];
+#endif
+ src += 16;
+ dst += 4;
+ } else if (code == 0x00) {
+ uint16 count = src[0] + 1;
+ src += 1;
+ for (uint16 l = 0; l < count; l++) {
+ tmp = dst + next_offs;
+#ifdef PICKY_ALIGN
+ memcpy(dst, tmp, sizeof uint32);
+ memcpy(dst + 320, tmp + 320, sizeof uint32);
+ memcpy(dst + 320 * 2, tmp + 320 * 2, sizeof uint32);
+ memcpy(dst + 320 * 3, tmp + 320 * 3, sizeof uint32);
+#else
+ *(uint32 *)(dst + 0) = *(uint32 *)(tmp);
+ *(uint32 *)(dst + 320) = *(uint32 *)(tmp + 320);
+ *(uint32 *)(dst + 320 * 2) = *(uint32 *)(tmp + 320 * 2);
+ *(uint32 *)(dst + 320 * 3) = *(uint32 *)(tmp + 320 * 3);
+#endif
+ dst += 4;
+ i--;
+ if (i == 0) {
+ i = bw;
+ dst += 320 * 4 - 320;
+ bh--;
+ }
+ }
+ i++;
+ } else {
+ tmp = dst + table[code] + next_offs;
+#ifdef PICKY_ALIGN
+ memcpy(dst, tmp, sizeof uint32);
+ memcpy(dst + 320, tmp + 320, sizeof uint32);
+ memcpy(dst + 320 * 2, tmp + 320 * 2, sizeof uint32);
+ memcpy(dst + 320 * 3, tmp + 320 * 3, sizeof uint32);
+#else
+ *(uint32 *)(dst + 0) = *(uint32 *)(tmp);
+ *(uint32 *)(dst + 320) = *(uint32 *)(tmp + 320);
+ *(uint32 *)(dst + 320 * 2) = *(uint32 *)(tmp + 320 * 2);
+ *(uint32 *)(dst + 320 * 3) = *(uint32 *)(tmp + 320 * 3);
+#endif
+ dst += 4;
+ }
+ if (i <= 0)
+ break;
+ if (bh <= 0)
+ break;
+ } while (--i);
+ dst += 320 * 4 - 320;
+ if (bh <= 0)
+ break;
+ } while (--bh);
+}
+
+
+void SmushPlayer::codec37Proc5(int32 game, byte *dst, byte *src, int32 next_offs, int32 bw, int32 bh,
+
+ int32 pitch, int16 *table) {
+ byte code, *tmp;
+ int32 i;
+ uint32 t;
+
+ if (pitch != 320) {
+ warning("SP: invalid pitch");
+ return;
+ }
+
+ do {
+ i = bw;
+ do {
+ code = *src++;
+
+ // FIXME: Full Throttle has different FD and FEs?
+ if ((game == GID_DIG) && (code == 0xFD)) {
+ t = src[0];
+ t += (t << 8) + (t << 16) + (t << 24);
+#ifdef PICKY_ALIGN
+ memcpy(dst, &t, sizeof uint32);
+ memcpy(dst + 320, &t, sizeof uint32);
+ memcpy(dst + 320 * 2, &t, sizeof uint32);
+ memcpy(dst + 320 * 3, &t, sizeof uint32);
+#else
+ *(uint32 *)(dst + 0) = t;
+ *(uint32 *)(dst + 320) = t;
+ *(uint32 *)(dst + 320 * 2) = t;
+ *(uint32 *)(dst + 320 * 3) = t;
+#endif
+ src += 1;
+ dst += 4;
+ } else if ((game == GID_DIG) && (code == 0xFE)) {
+ t = src[0];
+ t += (t << 8) + (t << 16) + (t << 24);
+#ifdef PICKY_ALIGN
+ memcpy(dst, &t, sizeof uint32);
+#else
+ *(uint32 *)(dst + 0) = t;
+#endif
+ t = src[1];
+ t += (t << 8) + (t << 16) + (t << 24);
+#ifdef PICKY_ALIGN
+ memcpy(dst + 320, &t, sizeof uint32);
+#else
+ *(uint32 *)(dst + 320) = t;
+#endif
+ t = src[2];
+ t += (t << 8) + (t << 16) + (t << 24);
+#ifdef PICKY_ALIGN
+ memcpy(dst + 320 * 2, &t, sizeof uint32);
+#else
+ *(uint32 *)(dst + 320 * 2) = t;
+#endif
+ t = src[3];
+ t += (t << 8) + (t << 16) + (t << 24);
+#ifdef PICKY_ALIGN
+ memcpy(dst + 320 * 3, &t, sizeof uint32);
+#else
+ *(uint32 *)(dst + 320 * 3) = t;
+#endif
+ src += 4;
+ dst += 4;
+ } else if (code == 0xFF) {
+#ifdef PICKY_ALIGN
+ memcpy(dst, src, sizeof uint32);
+ memcpy(dst + 320, src + sizeof uint32, sizeof uint32);
+ memcpy(dst + 320 * 2, src + 2 * sizeof uint32, sizeof uint32);
+ memcpy(dst + 320 * 3, src + 3 * sizeof uint32, sizeof uint32);
+#else
+ *(uint32 *)(dst + 0) = ((uint32 *)src)[0];
+ *(uint32 *)(dst + 320) = ((uint32 *)src)[1];
+ *(uint32 *)(dst + 320 * 2) = ((uint32 *)src)[2];
+ *(uint32 *)(dst + 320 * 3) = ((uint32 *)src)[3];
+#endif
+ src += 16;
+ dst += 4;
+ } else {
+ tmp = dst + table[code] + next_offs;
+#ifdef PICKY_ALIGN
+ memcpy(dst, tmp, sizeof uint32);
+ memcpy(dst + 320, tmp + 320, sizeof uint32);
+ memcpy(dst + 320 * 2, tmp + 320 * 2, sizeof uint32);
+ memcpy(dst + 320 * 3, tmp + 320 * 3, sizeof uint32);
+#else
+ *(uint32 *)(dst + 0) = *(uint32 *)(tmp);
+ *(uint32 *)(dst + 320) = *(uint32 *)(tmp + 320);
+ *(uint32 *)(dst + 320 * 2) = *(uint32 *)(tmp + 320 * 2);
+ *(uint32 *)(dst + 320 * 3) = *(uint32 *)(tmp + 320 * 3);
+#endif
+ dst += 4;
+ }
+ } while (--i);
+ dst += 320 * 4 - 320;
+ } while (--bh);
+}
+
+// this table is the same in FT and Dig
+static const int8 maketable_bytes[] = {
+ 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, 0, 0,
+ -8, -29, 8, -29, -18, -25, 17, -25, 0, -23, -6, -22, 6, -22, -13, -19,
+ 12, -19, 0, -18, 25, -18, -25, -17, -5, -17, 5, -17, -10, -15, 10, -15,
+ 0, -14, -4, -13, 4, -13, 19, -13, -19, -12, -8, -11, -2, -11, 0, -11,
+ 2, -11, 8, -11, -15, -10, -4, -10, 4, -10, 15, -10, -6, -9, -1, -9,
+ 1, -9, 6, -9, -29, -8, -11, -8, -8, -8, -3, -8, 3, -8, 8, -8,
+ 11, -8, 29, -8, -5, -7, -2, -7, 0, -7, 2, -7, 5, -7, -22, -6,
+ -9, -6, -6, -6, -3, -6, -1, -6, 1, -6, 3, -6, 6, -6, 9, -6,
+ 22, -6, -17, -5, -7, -5, -4, -5, -2, -5, 0, -5, 2, -5, 4, -5,
+ 7, -5, 17, -5, -13, -4, -10, -4, -5, -4, -3, -4, -1, -4, 0, -4,
+ 1, -4, 3, -4, 5, -4, 10, -4, 13, -4, -8, -3, -6, -3, -4, -3,
+ -3, -3, -2, -3, -1, -3, 0, -3, 1, -3, 2, -3, 4, -3, 6, -3,
+ 8, -3, -11, -2, -7, -2, -5, -2, -3, -2, -2, -2, -1, -2, 0, -2,
+ 1, -2, 2, -2, 3, -2, 5, -2, 7, -2, 11, -2, -9, -1, -6, -1,
+ -4, -1, -3, -1, -2, -1, -1, -1, 0, -1, 1, -1, 2, -1, 3, -1,
+ 4, -1, 6, -1, 9, -1, -31, 0, -23, 0, -18, 0, -14, 0, -11, 0,
+ -7, 0, -5, 0, -4, 0, -3, 0, -2, 0, -1, 0, 0, -31, 1, 0,
+ 2, 0, 3, 0, 4, 0, 5, 0, 7, 0, 11, 0, 14, 0, 18, 0,
+ 23, 0, 31, 0, -9, 1, -6, 1, -4, 1, -3, 1, -2, 1, -1, 1,
+ 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 6, 1, 9, 1, -11, 2,
+ -7, 2, -5, 2, -3, 2, -2, 2, -1, 2, 0, 2, 1, 2, 2, 2,
+ 3, 2, 5, 2, 7, 2, 11, 2, -8, 3, -6, 3, -4, 3, -2, 3,
+ -1, 3, 0, 3, 1, 3, 2, 3, 3, 3, 4, 3, 6, 3, 8, 3,
+ -13, 4, -10, 4, -5, 4, -3, 4, -1, 4, 0, 4, 1, 4, 3, 4,
+ 5, 4, 10, 4, 13, 4, -17, 5, -7, 5, -4, 5, -2, 5, 0, 5,
+ 2, 5, 4, 5, 7, 5, 17, 5, -22, 6, -9, 6, -6, 6, -3, 6,
+ -1, 6, 1, 6, 3, 6, 6, 6, 9, 6, 22, 6, -5, 7, -2, 7,
+ 0, 7, 2, 7, 5, 7, -29, 8, -11, 8, -8, 8, -3, 8, 3, 8,
+ 8, 8, 11, 8, 29, 8, -6, 9, -1, 9, 1, 9, 6, 9, -15, 10,
+ -4, 10, 4, 10, 15, 10, -8, 11, -2, 11, 0, 11, 2, 11, 8, 11,
+ 19, 12, -19, 13, -4, 13, 4, 13, 0, 14, -10, 15, 10, 15, -5, 17,
+ 5, 17, 25, 17, -25, 18, 0, 18, -12, 19, 13, 19, -6, 22, 6, 22,
+ 0, 23, -17, 25, 18, 25, -8, 29, 8, 29, 0, 31, 0, 0, -6, -22,
+ 6, -22, -13, -19, 12, -19, 0, -18, -5, -17, 5, -17, -10, -15, 10, -15,
+ 0, -14, -4, -13, 4, -13, 19, -13, -19, -12, -8, -11, -2, -11, 0, -11,
+ 2, -11, 8, -11, -15, -10, -4, -10, 4, -10, 15, -10, -6, -9, -1, -9,
+ 1, -9, 6, -9, -11, -8, -8, -8, -3, -8, 0, -8, 3, -8, 8, -8,
+ 11, -8, -5, -7, -2, -7, 0, -7, 2, -7, 5, -7, -22, -6, -9, -6,
+ -6, -6, -3, -6, -1, -6, 1, -6, 3, -6, 6, -6, 9, -6, 22, -6,
+ -17, -5, -7, -5, -4, -5, -2, -5, -1, -5, 0, -5, 1, -5, 2, -5,
+ 4, -5, 7, -5, 17, -5, -13, -4, -10, -4, -5, -4, -3, -4, -2, -4,
+ -1, -4, 0, -4, 1, -4, 2, -4, 3, -4, 5, -4, 10, -4, 13, -4,
+ -8, -3, -6, -3, -4, -3, -3, -3, -2, -3, -1, -3, 0, -3, 1, -3,
+ 2, -3, 3, -3, 4, -3, 6, -3, 8, -3, -11, -2, -7, -2, -5, -2,
+ -4, -2, -3, -2, -2, -2, -1, -2, 0, -2, 1, -2, 2, -2, 3, -2,
+ 4, -2, 5, -2, 7, -2, 11, -2, -9, -1, -6, -1, -5, -1, -4, -1,
+ -3, -1, -2, -1, -1, -1, 0, -1, 1, -1, 2, -1, 3, -1, 4, -1,
+ 5, -1, 6, -1, 9, -1, -23, 0, -18, 0, -14, 0, -11, 0, -7, 0,
+ -5, 0, -4, 0, -3, 0, -2, 0, -1, 0, 0, -23, 1, 0, 2, 0,
+ 3, 0, 4, 0, 5, 0, 7, 0, 11, 0, 14, 0, 18, 0, 23, 0,
+ -9, 1, -6, 1, -5, 1, -4, 1, -3, 1, -2, 1, -1, 1, 0, 1,
+ 1, 1, 2, 1, 3, 1, 4, 1, 5, 1, 6, 1, 9, 1, -11, 2,
+ -7, 2, -5, 2, -4, 2, -3, 2, -2, 2, -1, 2, 0, 2, 1, 2,
+ 2, 2, 3, 2, 4, 2, 5, 2, 7, 2, 11, 2, -8, 3, -6, 3,
+ -4, 3, -3, 3, -2, 3, -1, 3, 0, 3, 1, 3, 2, 3, 3, 3,
+ 4, 3, 6, 3, 8, 3, -13, 4, -10, 4, -5, 4, -3, 4, -2, 4,
+ -1, 4, 0, 4, 1, 4, 2, 4, 3, 4, 5, 4, 10, 4, 13, 4,
+ -17, 5, -7, 5, -4, 5, -2, 5, -1, 5, 0, 5, 1, 5, 2, 5,
+ 4, 5, 7, 5, 17, 5, -22, 6, -9, 6, -6, 6, -3, 6, -1, 6,
+ 1, 6, 3, 6, 6, 6, 9, 6, 22, 6, -5, 7, -2, 7, 0, 7,
+ 2, 7, 5, 7, -11, 8, -8, 8, -3, 8, 0, 8, 3, 8, 8, 8,
+ 11, 8, -6, 9, -1, 9, 1, 9, 6, 9, -15, 10, -4, 10, 4, 10,
+ 15, 10, -8, 11, -2, 11, 0, 11, 2, 11, 8, 11, 19, 12, -19, 13,
+ -4, 13, 4, 13, 0, 14, -10, 15, 10, 15, -5, 17, 5, 17, 0, 18,
+ -12, 19, 13, 19, -6, 22, 6, 22, 0, 23,
+};
+
+void SmushPlayer::codec37Maketable(PersistentCodecData37 * pcd, int32 pitch, byte idx) {
+ int32 i, j;
+
+ if (pcd->table_last_pitch == pitch && pcd->table_last_flags == idx)
+ return;
+
+ pcd->table_last_pitch = pitch;
+ pcd->table_last_flags = idx;
+
+ assert(idx * 255 + 254 < (int32)(sizeof(maketable_bytes) / 2));
+
+ for (i = 0; i < 255; i++) {
+ j = i + idx * 255;
+ pcd->table1[i] = maketable_bytes[j * 2 + 1] * pitch + maketable_bytes[j * 2];
+ }
+}
+
+bool SmushPlayer::codec37(int32 game, CodecData * cd, PersistentCodecData37 * pcd) {
+ int32 width_in_blocks, height_in_blocks;
+ int32 src_pitch;
+ byte *curbuf;
+ int32 size;
+ bool result = false;
+
+ _frameChanged = 1;
+
+ width_in_blocks = (cd->w + 3) >> 2;
+ height_in_blocks = (cd->h + 3) >> 2;
+ src_pitch = width_in_blocks * 4;
+
+ codec37Maketable(pcd, src_pitch, cd->src[1]);
+
+ switch (cd->src[0]) {
+ case 0:{
+ curbuf = pcd->deltaBufs[pcd->curtable];
+ memset(pcd->deltaBuf, 0, curbuf - pcd->deltaBuf);
+ size = READ_LE_UINT32(cd->src + 4);
+ memset(curbuf + size, 0, pcd->deltaBuf + pcd->deltaSize - curbuf - size);
+ memcpy(curbuf, cd->src + 16, size);
+ break;
+ }
+
+ case 2:{
+ size = READ_LE_UINT32(cd->src + 4);
+ curbuf = pcd->deltaBufs[pcd->curtable];
+ if (size == 64000)
+ codec37BompDepack(curbuf, cd->src + 16, size);
+ else
+ return (1);
+
+ memset(pcd->deltaBuf, 0, curbuf - pcd->deltaBuf);
+ memset(curbuf + size, 0, pcd->deltaBuf + pcd->deltaSize - curbuf - size);
+ break;
+ }
+
+ case 3:{
+ uint16 number = READ_LE_UINT16(cd->src + 2);
+
+ if (number && pcd->flags + 1 != number)
+ break;
+
+ if (number & 1 && cd->src[12] & 1 && cd->flags & 0x10) {
+ _frameChanged = 0;
+ result = true;
+ break;
+ }
+
+ if ((number & 1) || !(cd->src[12] & 1)) {
+ pcd->curtable ^= 1;
+ }
+
+ codec37Proc5(game, pcd->deltaBufs[pcd->curtable], cd->src + 16,
+ pcd->deltaBufs[pcd->curtable ^ 1] -
+ pcd->deltaBufs[pcd->curtable], width_in_blocks,
+ height_in_blocks, src_pitch, pcd->table1);
+ break;
+
+ }
+ case 4:{
+ uint16 number = READ_LE_UINT16(cd->src + 2);
+
+ if (number && pcd->flags + 1 != number)
+ break;
+
+ if (number & 1 && cd->src[12] & 1 && cd->flags & 0x10) {
+ _frameChanged = 0;
+ result = true;
+ break;
+ }
+
+ if ((number & 1) || !(cd->src[12] & 1)) {
+ pcd->curtable ^= 1;
+ }
+
+ codec37Proc4(pcd->deltaBufs[pcd->curtable], cd->src + 16,
+ pcd->deltaBufs[pcd->curtable ^ 1] -
+ pcd->deltaBufs[pcd->curtable], width_in_blocks,
+ height_in_blocks, src_pitch, pcd->table1);
+ break;
+ }
+
+ case 1:
+ warning("SP: code %d", cd->src[0]);
+ return (1);
+
+ default:
+ error("SP: codec37 default case");
+ }
+
+ pcd->flags = READ_LE_UINT16(cd->src + 2);
+
+ if (result) {
+ pcd->curtable ^= 1;
+ } else {
+ memcpy(cd->out, pcd->deltaBufs[pcd->curtable], 320 * 200);
+ }
+
+ return (_frameChanged);
+}
+
+void SmushPlayer::codec37Init(PersistentCodecData37 * pcd, int32 width, int32 height) {
+ pcd->width = width;
+ pcd->height = height;
+ pcd->deltaSize = width * height * 2 + 0x3E00 + 0xBA00;
+ pcd->deltaBuf = (byte *)calloc(pcd->deltaSize, 1);
+ pcd->deltaBufs[0] = pcd->deltaBuf + 0x3E00;
+ pcd->deltaBufs[1] = pcd->deltaBuf + width * height + 0xBA00;
+ pcd->curtable = 0;
+ pcd->table1 = (int16 *)calloc(255, sizeof(uint16));
+}
+
+void SmushPlayer::parseFOBJ() {
+ byte codec;
+ CodecData cd;
+
+ cd.out = _renderBitmap;
+ cd.pitch = cd.outwidth = 320;
+ cd.outheight = 200;
+ cd.y = 0;
+ cd.x = 0;
+ cd.src = _cur + 0xE;
+ cd.w = READ_LE_UINT16(_cur + 6);
+ cd.h = READ_LE_UINT16(_cur + 8);
+ cd.flags = 0;
+
+ codec = _cur[0];
+
+ switch (codec) {
+ case 1:
+ codec1(&cd);
+ break;
+ case 37:
+ _frameChanged = codec37(_scumm->_gameId, &cd, &pcd37);
+ break;
+ default:
+ error("SP: invalid codec %d", codec);
+ }
+}
+
+void SmushPlayer::parsePSAD() { // FIXME: Needs to append to a sound buffer
+ uint32 pos, sublen, tag, idx, trk;
+ bool new_mixer = false;
+ byte *buf;
+ pos = 0;
+
+ trk = READ_LE_UINT16(_cur + pos); /* FIXME: is this correct ? */
+ pos += 2;
+
+ for (idx = 0; idx < MAX_STREAMER; idx++) {
+ if (_psadTrk[idx] == trk)
+ break;
+ }
+
+ if (idx == MAX_STREAMER) {
+ for (idx = 0; idx < MAX_STREAMER; idx++) {
+ if (_psadTrk[idx] == 0 && _scumm->_mixer->_channels[idx] == NULL) {
+ _psadTrk[idx] = trk;
+ _saudSize[idx] = 0;
+ new_mixer = true;
+ break;
+ }
+ }
+ }
+
+ if (idx == MAX_STREAMER) {
+ warning("PSAD table full\n");
+ return;
+ }
+
+ pos += 8; /* FIXME: what are these ? */
+
+ while (pos < _frmeSize) {
+
+ if (_saudSize[idx] == 0) {
+ tag = READ_BE_UINT32(_cur + pos);
+ pos += 4;
+ if (tag != 'SAUD') // FIXME: DIG specific?
+ warning("trk %d: SAUD tag not found", trk);
+ _saudSize[idx] = READ_BE_UINT32(_cur + pos);
+ pos += 4;
+ }
+
+ if (_saudSubSize[idx] == 0) {
+ _saudSubTag[idx] = READ_BE_UINT32(_cur + pos);
+ pos += 4;
+ _saudSubSize[idx] = READ_BE_UINT32(_cur + pos);
+ pos += 4;
+ _saudSize[idx] -= 8;
+ debug(3, "trk %d: tag '%4s' size %x", trk, _cur + pos - 8, _saudSubSize[idx]);
+ }
+
+ sublen = _saudSubSize[idx] < (_frmeSize - pos) ? _saudSubSize[idx] : (_frmeSize - pos);
+
+ switch (_saudSubTag[idx]) {
+ case 'STRK':
+ /* FIXME: what is this stuff ? */
+ _strkRate[idx] = 22050;
+ break;
+ case 'SDAT':
+ buf = (byte *)malloc(sublen);
+
+ memcpy(buf, _cur + pos, sublen);
+
+ debug(3, "trk %d: SDAT part len 0x%x rate %d", trk, sublen, _strkRate[idx]);
+
+ _strkBuf[idx] = buf;
+ _strkFinalSize[idx] = sublen;
+ _strkNewMixer[idx] = new_mixer;
+ break;
+ case 'SMRK':
+ _psadTrk[idx] = 0;
+ break;
+ case 'SHDR':
+ /* FIXME: what is this stuff ? */
+ break;
+ default: // FIXME: Add FT tags
+ warning("trk %d: unknown tag inside PSAD", trk);
+ }
+ _saudSubSize[idx] -= sublen;
+ _saudSize[idx] -= sublen;
+ pos += sublen;
+ }
+}
+
+void SmushPlayer::parseTRES() {
+ if (_scumm->_gameId == GID_DIG) {
+ if ((_scumm->_noSubtitles) && (READ_LE_UINT16(_cur + 4) != 0))
+ return;
+
+ byte * txt = getStringTRES (READ_LE_UINT16(_cur + 16));
+ drawStringTRES (READ_LE_UINT16(_cur), READ_LE_UINT16(_cur + 2), txt);
+ if (txt != NULL)
+ free (txt);
+ }
+}
+
+void SmushPlayer::parseXPAL() {
+ int32 num;
+ int32 i;
+
+ num = READ_LE_UINT16(_cur + 2);
+ if (num == 0 || num == 0x200) {
+ if (num == 0x200)
+ memcpy(_fluPalette, _cur + 0x604, 0x300);
+
+ for (i = 0; i < 0x300; i++) {
+ _fluPalMul129[i] = _fluPalette[i] * 129;
+ _fluPalWords[i] = READ_LE_UINT16(_cur + 4 + i * 2);
+ }
+ return;
+ }
+
+ parseNPAL();
+
+ for (i = 0; i < 0x300; i++) {
+ _fluPalMul129[i] += _fluPalWords[i];
+ _fluPalette[i] = _fluPalMul129[i] >> 7;
+ }
+
+ _paletteChanged = true;
+}
+
+void SmushPlayer::parseFRME() {
+ _cur = _block;
+
+ do {
+ _frmeTag = nextBE32();
+ _frmeSize = nextBE32();
+
+ switch (_frmeTag) {
+ case 'NPAL':
+ parseNPAL();
+ break;
+ case 'FOBJ':
+ parseFOBJ();
+ break;
+ case 'PSAD':
+ parsePSAD();
+ break;
+ case 'TRES':
+ parseTRES();
+ break;
+ case 'XPAL':
+ parseXPAL();
+ break;
+ case 'IACT':
+ parseIACT();
+ break;
+ case 'STOR':
+ case 'FTCH':
+ break;
+
+ default:
+ error("SP: Encountered invalid block %c%c%c%c", _frmeTag >> 24, _frmeTag >> 16, _frmeTag >> 8, _frmeTag);
+ }
+
+ _cur += (_frmeSize + 1) & ~1;
+ } while (_cur + 4 < _block + _blockSize);
+}
+
+void SmushPlayer::init() {
+ _renderBitmap = _scumm->_videoBuffer;
+ codec37Init(&pcd37, 320, 200);
+
+ memset(_saudSize, 0, sizeof(_saudSize));
+ memset(_saudSubSize, 0, sizeof(_saudSubSize));
+ memset(_psadTrk, 0, sizeof(_psadTrk));
+
+ memset(_imusSize, 0, sizeof(_imusSize));
+ memset(_imusSubSize, 0, sizeof(_imusSubSize));
+ memset(_imusTrk, 0, sizeof(_imusTrk));
+ memset(_imusData, 0, sizeof(_imusData));
+ memset(_imusPos, 0, sizeof(_imusPos));
+ memset(_imusChan, 0, sizeof(_imusChan));
+
+ if (_scumm->_gameId == GID_DIG)
+ {
+ for (uint8 l = 0; l < SP_MAX_FONTS; l++) {
+ _fonts[l] = NULL;
+ }
+ _bufferTres = NULL;
+ loadTres();
+ loadFonts();
+ }
+ _scumm->_timer->installProcedure(&smush_handler, 75);
+}
+
+void SmushPlayer::deinit() {
+ if (_scumm->_gameId == GID_DIG)
+ {
+ if (_bufferTres != NULL)
+ free (_bufferTres);
+
+ for (int l = 0; l < SP_MAX_FONTS; l++) {
+ if (_fonts[l] != NULL) {
+ free (_fonts[l]);
+ _fonts[l] = NULL;
+ }
+ }
+ }
+ _scumm->_timer->releaseProcedure(&smush_handler);
+}
+
+void SmushPlayer::go() {
+ while (parseTag()) {
+ }
+}
+
+void SmushPlayer::setPalette() {
+ int32 i;
+ byte palette_colors[1024];
+ byte *p = palette_colors;
+ byte *data = _fluPalette;
+
+ for (i = 0; i != 256; i++, data += 3, p += 4) {
+ p[0] = data[0];
+ p[1] = data[1];
+ p[2] = data[2];
+ p[3] = 0;
+ }
+
+ _scumm->_system->set_palette(palette_colors, 0, 256);
+}
+
+void SmushPlayer::update() {
+ _lock = false;
+}
+
+void SmushPlayer::startVideo(short int arg, byte *videoFile) {
+ int32 frameIndex = 0;
+ int32 idx;
+
+ _in = NULL;
+ _paletteChanged = false;
+ _block = NULL;
+ _blockTag = 0;
+ _blockSize = 0;
+ _cur = NULL;
+ _renderBitmap = NULL;
+ _frameSize = 0;
+ _frmeTag = 0;
+ _frmeSize = 0;
+ _deltaBuf = NULL;
+ _deltaBufSize = 0;
+ _lock = true;
+
+ memset (&pcd37, 0, sizeof (PersistentCodecData37));
+
+ _scumm->_sound->pauseBundleMusic(true);
+ init();
+ openFile(videoFile);
+
+ if (_in == NULL)
+ return;
+
+ if (_scumm->fileReadDwordBE(_in) != 'ANIM')
+ error("SP: file is not an anim");
+
+ fileSize = _scumm->fileReadDwordBE(_in);
+
+ _scumm->videoFinished = 0;
+ _scumm->_insaneState = 1;
+
+ do {
+ _frameChanged = true;
+
+ if (ftell(_in) >= fileSize)
+ break;
+#ifdef INSANE_DEBUG
+ warning("Playing frame %d", frameIndex);
+#endif
+
+ parseTag();
+ frameIndex++;
+
+ do {
+ _scumm->waitForTimer(1);
+ } while (_lock);
+ _lock = true;
+
+ if (_scumm->_gameId == GID_DIG) {
+ for (idx = 0; idx < MAX_STREAMER; idx++) {
+ if (_imusTrk[idx] != 0) {
+ if (_imusNewMixer[idx]) {
+ _scumm->_mixer->play_stream(NULL, idx, _imusBuf[idx], _imusFinalSize[idx], _imusRate[idx], _imusFlags[idx]);
+ } else {
+ _scumm->_mixer->append(idx, _imusBuf[idx], _imusFinalSize[idx], _imusRate[idx], _imusFlags[idx]);
+ }
+ }
+ }
+ }
+
+ if (_scumm->_gameId == GID_FT) {
+ for (idx = 0; idx < MAX_STREAMER; idx++) {
+ if (_psadTrk[idx] != 0) {
+ if (_strkNewMixer[idx]) {
+ _scumm->_mixer->play_stream(NULL, idx, _strkBuf[idx], _strkFinalSize[idx], _strkRate[idx], SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
+ } else {
+ _scumm->_mixer->append(idx, _strkBuf[idx], _strkFinalSize[idx], _strkRate[idx], SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
+ }
+ }
+ }
+ }
+
+ if (_paletteChanged) {
+ _paletteChanged = false;
+ setPalette();
+ _scumm->setDirtyColors(0, 255);
+ }
+
+ if (_frameChanged) {
+ _scumm->_system->copy_rect(_scumm->_videoBuffer, 320, 0, 0, 320, 200);
+ _scumm->_system->update_screen();
+ }
+
+ _scumm->processKbd();
+
+ } while (!_scumm->videoFinished);
+
+ deinit();
+
+ _scumm->_insaneState = 0;
+ _scumm->exitCutscene();
+ _scumm->_sound->pauseBundleMusic(false);
+}