2002-08-24 15:31:37 +00:00
|
|
|
/* ScummVM - Scumm Interpreter
|
2006-01-18 17:39:49 +00:00
|
|
|
* Copyright (C) 2002-2006 The ScummVM project
|
2002-08-24 15:31:37 +00:00
|
|
|
*
|
|
|
|
* 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
|
2005-10-18 01:30:26 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2002-08-24 15:31:37 +00:00
|
|
|
*
|
2006-02-11 09:55:41 +00:00
|
|
|
* $URL$
|
|
|
|
* $Id$
|
2002-08-24 15:31:37 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2005-06-24 15:23:51 +00:00
|
|
|
#include "common/stdafx.h"
|
2002-08-24 15:31:37 +00:00
|
|
|
|
2006-09-23 00:42:35 +00:00
|
|
|
#include "engines/engine.h"
|
2003-10-03 18:33:57 +00:00
|
|
|
|
2003-12-27 15:22:59 +00:00
|
|
|
#include "common/config-manager.h"
|
2003-06-15 01:42:19 +00:00
|
|
|
#include "common/file.h"
|
2005-01-10 22:06:49 +00:00
|
|
|
#include "common/system.h"
|
2003-06-15 01:42:19 +00:00
|
|
|
#include "common/timer.h"
|
2005-01-10 22:06:49 +00:00
|
|
|
#include "common/util.h"
|
2003-06-15 01:42:19 +00:00
|
|
|
|
2006-05-25 22:51:42 +00:00
|
|
|
#include "graphics/cursorman.h"
|
|
|
|
|
2003-10-03 18:33:57 +00:00
|
|
|
#include "scumm/bomp.h"
|
2006-03-03 15:16:02 +00:00
|
|
|
#include "scumm/file.h"
|
2004-01-06 17:28:29 +00:00
|
|
|
#include "scumm/imuse_digi/dimuse.h"
|
2006-02-20 20:57:26 +00:00
|
|
|
#include "scumm/imuse/imuse.h"
|
2003-10-03 18:33:57 +00:00
|
|
|
#include "scumm/scumm.h"
|
|
|
|
#include "scumm/sound.h"
|
|
|
|
#include "scumm/smush/channel.h"
|
|
|
|
#include "scumm/smush/chunk_type.h"
|
|
|
|
#include "scumm/smush/chunk.h"
|
|
|
|
#include "scumm/smush/smush_font.h"
|
|
|
|
#include "scumm/smush/smush_mixer.h"
|
|
|
|
#include "scumm/smush/smush_player.h"
|
2004-01-16 22:18:54 +00:00
|
|
|
|
|
|
|
#include "scumm/insane/insane.h"
|
2003-10-03 18:33:57 +00:00
|
|
|
|
|
|
|
#include "sound/mixer.h"
|
2004-11-27 15:58:18 +00:00
|
|
|
#include "sound/vorbis.h"
|
2005-01-28 11:59:08 +00:00
|
|
|
#include "sound/mp3.h"
|
2003-10-03 18:33:57 +00:00
|
|
|
|
2003-08-18 06:11:37 +00:00
|
|
|
#ifdef DUMP_SMUSH_FRAMES
|
|
|
|
#include <png.h>
|
|
|
|
#endif
|
|
|
|
|
2004-04-13 19:20:16 +00:00
|
|
|
#ifdef USE_ZLIB
|
|
|
|
#include <zlib.h>
|
|
|
|
#endif
|
|
|
|
|
2003-10-03 18:33:57 +00:00
|
|
|
namespace Scumm {
|
|
|
|
|
2003-03-17 12:28:50 +00:00
|
|
|
const int MAX_STRINGS = 200;
|
2002-08-24 15:31:37 +00:00
|
|
|
|
|
|
|
class StringResource {
|
|
|
|
private:
|
2003-03-17 12:28:50 +00:00
|
|
|
|
2002-08-24 15:31:37 +00:00
|
|
|
struct {
|
2003-03-17 12:28:50 +00:00
|
|
|
int id;
|
2003-06-04 20:20:50 +00:00
|
|
|
char *string;
|
2002-08-24 15:31:37 +00:00
|
|
|
} _strings[MAX_STRINGS];
|
2003-03-17 12:28:50 +00:00
|
|
|
|
|
|
|
int _nbStrings;
|
|
|
|
int _lastId;
|
2003-06-04 15:04:00 +00:00
|
|
|
const char *_lastString;
|
2003-03-17 12:28:50 +00:00
|
|
|
|
2002-08-24 15:31:37 +00:00
|
|
|
public:
|
2003-03-17 12:28:50 +00:00
|
|
|
|
|
|
|
StringResource() :
|
|
|
|
_nbStrings(0),
|
|
|
|
_lastId(-1) {
|
|
|
|
};
|
2002-08-24 15:31:37 +00:00
|
|
|
~StringResource() {
|
2003-06-07 00:45:32 +00:00
|
|
|
for (int32 i = 0; i < _nbStrings; i++) {
|
2002-08-24 15:31:37 +00:00
|
|
|
delete []_strings[i].string;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-19 10:34:18 +00:00
|
|
|
bool init(char *buffer, int32 length) {
|
2003-03-06 08:36:56 +00:00
|
|
|
char *def_start = strchr(buffer, '#');
|
2003-06-07 00:45:32 +00:00
|
|
|
while (def_start != NULL) {
|
2003-03-06 08:36:56 +00:00
|
|
|
char *def_end = strchr(def_start, '\n');
|
2003-01-19 10:34:18 +00:00
|
|
|
assert(def_end != NULL);
|
2003-03-17 12:28:50 +00:00
|
|
|
|
2003-03-06 08:36:56 +00:00
|
|
|
char *id_end = def_end;
|
2005-07-30 21:11:48 +00:00
|
|
|
while (id_end >= def_start && !isdigit(*(id_end-1))) {
|
2003-01-19 10:34:18 +00:00
|
|
|
id_end--;
|
|
|
|
}
|
2003-03-17 12:28:50 +00:00
|
|
|
|
2002-08-24 15:31:37 +00:00
|
|
|
assert(id_end > def_start);
|
2003-03-06 08:36:56 +00:00
|
|
|
char *id_start = id_end;
|
2003-06-07 00:45:32 +00:00
|
|
|
while (isdigit(*(id_start - 1))) {
|
2003-01-19 10:34:18 +00:00
|
|
|
id_start--;
|
|
|
|
}
|
2003-03-17 12:28:50 +00:00
|
|
|
|
2002-08-24 15:31:37 +00:00
|
|
|
char idstring[32];
|
|
|
|
memcpy(idstring, id_start, id_end - id_start);
|
|
|
|
idstring[id_end - id_start] = 0;
|
2002-08-30 07:24:45 +00:00
|
|
|
int32 id = atoi(idstring);
|
2003-03-06 08:36:56 +00:00
|
|
|
char *data_start = def_end;
|
2002-08-30 15:24:16 +00:00
|
|
|
|
2003-06-07 00:45:32 +00:00
|
|
|
while (*data_start == '\n' || *data_start == '\r') {
|
2002-08-30 07:24:45 +00:00
|
|
|
data_start++;
|
2003-01-19 10:34:18 +00:00
|
|
|
}
|
2003-03-06 08:36:56 +00:00
|
|
|
char *data_end = data_start;
|
2002-08-30 07:24:45 +00:00
|
|
|
|
2003-06-07 00:45:32 +00:00
|
|
|
while (1) {
|
2003-10-17 19:20:00 +00:00
|
|
|
if (data_end[-2] == '\r' && data_end[-1] == '\n' && data_end[0] == '\r' && data_end[1] == '\n') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// In Russian Full Throttle strings are finished with
|
|
|
|
// just one pair of CR-LF
|
|
|
|
if (data_end[-2] == '\r' && data_end[-1] == '\n' && data_end[0] == '#') {
|
2002-08-24 15:31:37 +00:00
|
|
|
break;
|
2003-01-19 10:34:18 +00:00
|
|
|
}
|
2002-08-24 15:31:37 +00:00
|
|
|
data_end++;
|
2003-06-07 00:45:32 +00:00
|
|
|
if (data_end >= buffer + length) {
|
2002-08-24 15:31:37 +00:00
|
|
|
data_end = buffer + length;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2002-08-30 15:24:16 +00:00
|
|
|
|
2002-08-24 15:31:37 +00:00
|
|
|
data_end -= 2;
|
|
|
|
assert(data_end > data_start);
|
2003-03-06 08:36:56 +00:00
|
|
|
char *value = new char[data_end - data_start + 1];
|
2002-08-24 15:31:37 +00:00
|
|
|
assert(value);
|
|
|
|
memcpy(value, data_start, data_end - data_start);
|
|
|
|
value[data_end - data_start] = 0;
|
2003-03-06 08:36:56 +00:00
|
|
|
char *line_start = value;
|
|
|
|
char *line_end;
|
2002-08-30 07:24:45 +00:00
|
|
|
|
2002-08-25 22:54:43 +00:00
|
|
|
while ((line_end = strchr(line_start, '\n'))) {
|
2002-08-25 22:25:18 +00:00
|
|
|
line_start = line_end+1;
|
|
|
|
if (line_start[0] == '/' && line_start[1] == '/') {
|
|
|
|
line_start += 2;
|
|
|
|
if (line_end[-1] == '\r')
|
|
|
|
line_end[-1] = ' ';
|
|
|
|
else
|
|
|
|
*line_end++ = ' ';
|
|
|
|
memmove(line_end, line_start, strlen(line_start)+1);
|
|
|
|
}
|
|
|
|
}
|
2002-08-24 15:31:37 +00:00
|
|
|
_strings[_nbStrings].id = id;
|
|
|
|
_strings[_nbStrings].string = value;
|
|
|
|
_nbStrings ++;
|
|
|
|
def_start = strchr(data_end + 2, '#');
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2003-06-04 15:04:00 +00:00
|
|
|
const char *get(int id) {
|
2003-06-07 00:45:32 +00:00
|
|
|
if (id == _lastId) {
|
2003-01-19 10:34:18 +00:00
|
|
|
return _lastString;
|
|
|
|
}
|
2004-08-22 09:14:19 +00:00
|
|
|
debugC(DEBUG_SMUSH, "StringResource::get(%d)", id);
|
2003-06-07 00:45:32 +00:00
|
|
|
for (int i = 0; i < _nbStrings; i++) {
|
|
|
|
if (_strings[i].id == id) {
|
2002-08-24 15:31:37 +00:00
|
|
|
_lastId = id;
|
|
|
|
_lastString = _strings[i].string;
|
|
|
|
return _strings[i].string;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
warning("invalid string id : %d", id);
|
|
|
|
_lastId = -1;
|
|
|
|
_lastString = "unknown string";
|
|
|
|
return _lastString;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2005-01-06 18:38:11 +00:00
|
|
|
static StringResource *getStrings(ScummEngine *vm, const char *file, bool is_encoded) {
|
2006-03-15 15:46:25 +00:00
|
|
|
debugC(DEBUG_SMUSH, "trying to read text resources from %s", file);
|
2005-01-06 18:38:11 +00:00
|
|
|
ScummFile theFile;
|
2003-03-17 12:28:50 +00:00
|
|
|
|
2005-01-06 18:38:11 +00:00
|
|
|
vm->openFile(theFile, file);
|
2003-03-17 12:28:50 +00:00
|
|
|
if (!theFile.isOpen()) {
|
|
|
|
return 0;
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
2003-03-17 12:28:50 +00:00
|
|
|
int32 length = theFile.size();
|
|
|
|
char *filebuffer = new char [length + 1];
|
|
|
|
assert(filebuffer);
|
|
|
|
theFile.read(filebuffer, length);
|
|
|
|
filebuffer[length] = 0;
|
2002-08-24 15:31:37 +00:00
|
|
|
|
2003-06-07 00:45:32 +00:00
|
|
|
if (is_encoded) {
|
2004-09-26 18:08:51 +00:00
|
|
|
enum {
|
|
|
|
ETRS_HEADER_LENGTH = 16
|
|
|
|
};
|
2003-03-17 12:28:50 +00:00
|
|
|
assert(length > ETRS_HEADER_LENGTH);
|
|
|
|
Chunk::type type = READ_BE_UINT32(filebuffer);
|
|
|
|
|
2003-06-07 00:45:32 +00:00
|
|
|
if (type != TYPE_ETRS) {
|
2003-03-17 12:28:50 +00:00
|
|
|
delete [] filebuffer;
|
2005-01-06 18:38:11 +00:00
|
|
|
return getStrings(vm, file, false);
|
2003-01-19 10:34:18 +00:00
|
|
|
}
|
2003-03-17 12:28:50 +00:00
|
|
|
|
|
|
|
char *old = filebuffer;
|
|
|
|
filebuffer = new char[length - ETRS_HEADER_LENGTH + 1];
|
2003-06-07 00:45:32 +00:00
|
|
|
for (int32 i = ETRS_HEADER_LENGTH; i < length; i++) {
|
2003-03-17 12:28:50 +00:00
|
|
|
filebuffer[i - ETRS_HEADER_LENGTH] = old[i] ^ 0xCC;
|
|
|
|
}
|
|
|
|
filebuffer[length - ETRS_HEADER_LENGTH] = '\0';
|
|
|
|
delete []old;
|
|
|
|
length -= ETRS_HEADER_LENGTH;
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
2003-03-17 12:28:50 +00:00
|
|
|
StringResource *sr = new StringResource;
|
|
|
|
assert(sr);
|
|
|
|
sr->init(filebuffer, length);
|
|
|
|
delete []filebuffer;
|
|
|
|
return sr;
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
|
|
|
|
2006-02-05 14:57:48 +00:00
|
|
|
void SmushPlayer::timerCallback(void *refCon) {
|
|
|
|
((SmushPlayer *)refCon)->parseNextFrame();
|
|
|
|
#ifdef _WIN32_WCE
|
|
|
|
((SmushPlayer *)refCon)->_inTimer = true;
|
|
|
|
((SmushPlayer *)refCon)->_inTimerCount++;
|
|
|
|
#endif
|
2006-03-01 21:37:00 +00:00
|
|
|
#ifdef __SYMBIAN32__
|
2006-07-14 13:33:58 +00:00
|
|
|
if (((SmushPlayer *)refCon)->_closeOnTextTick) {
|
2006-03-01 21:37:00 +00:00
|
|
|
delete ((SmushPlayer *)refCon)->_base;
|
|
|
|
((SmushPlayer *)refCon)->_base = NULL;
|
|
|
|
((SmushPlayer *)refCon)->_closeOnTextTick = false;
|
|
|
|
}
|
|
|
|
#endif
|
2006-02-05 14:57:48 +00:00
|
|
|
}
|
|
|
|
|
2006-10-10 12:16:21 +00:00
|
|
|
SmushPlayer::SmushPlayer(ScummEngine_v7 *scumm) {
|
2004-01-08 20:37:26 +00:00
|
|
|
_vm = scumm;
|
2003-03-17 12:28:50 +00:00
|
|
|
_version = -1;
|
|
|
|
_nbframes = 0;
|
2006-10-10 12:16:21 +00:00
|
|
|
_smixer = NULL;
|
2003-03-17 12:28:50 +00:00
|
|
|
_strings = NULL;
|
|
|
|
_sf[0] = NULL;
|
|
|
|
_sf[1] = NULL;
|
|
|
|
_sf[2] = NULL;
|
|
|
|
_sf[3] = NULL;
|
|
|
|
_sf[4] = NULL;
|
2003-06-20 11:21:53 +00:00
|
|
|
_base = NULL;
|
|
|
|
_frameBuffer = NULL;
|
2004-04-10 09:17:36 +00:00
|
|
|
_specialBuffer = NULL;
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2005-06-25 15:17:14 +00:00
|
|
|
_seekPos = -1;
|
2004-04-10 09:17:36 +00:00
|
|
|
|
2003-06-20 11:21:53 +00:00
|
|
|
_skipNext = false;
|
|
|
|
_dst = NULL;
|
|
|
|
_storeFrame = false;
|
2004-09-18 18:09:35 +00:00
|
|
|
_compressedFileMode = false;
|
2003-06-20 11:21:53 +00:00
|
|
|
_width = 0;
|
|
|
|
_height = 0;
|
2003-03-17 12:28:50 +00:00
|
|
|
_IACTpos = 0;
|
|
|
|
_soundFrequency = 22050;
|
2004-10-08 18:30:14 +00:00
|
|
|
_initDone = false;
|
2006-10-10 12:16:21 +00:00
|
|
|
_speed = -1;
|
2003-12-06 05:47:24 +00:00
|
|
|
_insanity = false;
|
2003-12-25 08:48:51 +00:00
|
|
|
_middleAudio = false;
|
2005-05-28 02:26:14 +00:00
|
|
|
_skipPalette = false;
|
2005-04-05 06:27:34 +00:00
|
|
|
_IACTstream = NULL;
|
2006-03-05 12:15:39 +00:00
|
|
|
_smixer = _vm->_smixer;
|
2006-02-05 14:57:48 +00:00
|
|
|
#ifdef _WIN32_WCE
|
|
|
|
_inTimer = false;
|
|
|
|
_inTimerCount = 0;
|
|
|
|
_inTimerCountRedraw = ConfMan.getInt("Smush_force_redraw");
|
|
|
|
#endif
|
2006-06-17 07:53:55 +00:00
|
|
|
#ifdef __SYMBIAN32__
|
2006-03-01 21:37:00 +00:00
|
|
|
_closeOnTextTick = false;
|
|
|
|
#endif
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SmushPlayer::~SmushPlayer() {
|
|
|
|
}
|
|
|
|
|
2006-10-10 12:16:21 +00:00
|
|
|
void SmushPlayer::init(int32 speed) {
|
2003-03-17 12:28:50 +00:00
|
|
|
_frame = 0;
|
2006-10-10 12:16:21 +00:00
|
|
|
_speed = speed;
|
2004-06-01 20:28:20 +00:00
|
|
|
_alreadyInit = false;
|
2006-10-10 12:16:21 +00:00
|
|
|
_endOfFile = false;
|
2006-10-07 17:42:32 +00:00
|
|
|
|
2004-06-27 21:06:04 +00:00
|
|
|
_vm->_smushVideoShouldFinish = false;
|
2006-10-07 17:42:32 +00:00
|
|
|
_vm->_smushActive = true;
|
|
|
|
|
2004-01-08 20:37:26 +00:00
|
|
|
_vm->setDirtyColors(0, 255);
|
2004-08-14 19:42:00 +00:00
|
|
|
_dst = _vm->virtscr[0].getPixels(0, 0);
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2004-09-29 17:50:17 +00:00
|
|
|
// HACK HACK HACK: This is an *evil* trick, beware!
|
|
|
|
// We do this to fix bug #1037052. A proper solution would change all the
|
|
|
|
// drawing code to use the pitch value specified by the virtual screen.
|
|
|
|
// However, since a lot of the SMUSH code currently assumes the screen
|
|
|
|
// width and pitch to be equal, this will require lots of changes. So
|
|
|
|
// we resort to this hackish solution for now.
|
|
|
|
_origPitch = _vm->virtscr[0].pitch;
|
2006-09-17 20:22:47 +00:00
|
|
|
_origNumStrips = _vm->_gdi->_numStrips;
|
2004-09-29 17:50:17 +00:00
|
|
|
_vm->virtscr[0].pitch = _vm->virtscr[0].w;
|
2006-09-17 20:22:47 +00:00
|
|
|
_vm->_gdi->_numStrips = _vm->virtscr[0].w / 8;
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2006-10-10 12:16:21 +00:00
|
|
|
_vm->_mixer->stopHandle(_compressedFileSoundHandle);
|
|
|
|
_vm->_mixer->stopHandle(_IACTchannel);
|
2006-03-05 12:15:39 +00:00
|
|
|
_vm->_smixer->stop();
|
|
|
|
|
2006-02-05 14:57:48 +00:00
|
|
|
Common::g_timer->installTimerProc(&timerCallback, 1000000 / _speed, this);
|
2004-10-08 18:30:14 +00:00
|
|
|
|
|
|
|
_initDone = true;
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
|
|
|
|
2004-04-26 09:04:08 +00:00
|
|
|
void SmushPlayer::release() {
|
2005-01-16 13:32:48 +00:00
|
|
|
if (!_initDone)
|
|
|
|
return;
|
2006-03-01 21:37:00 +00:00
|
|
|
#ifdef __SYMBIAN32__
|
|
|
|
_closeOnTextTick = true;
|
|
|
|
// Wait for _closeOnTextTick to be set to false to indicate file closure
|
2006-07-14 13:33:58 +00:00
|
|
|
while (_closeOnTextTick) {
|
2006-03-01 21:37:00 +00:00
|
|
|
User::After(15624);
|
|
|
|
}
|
|
|
|
#endif
|
2006-02-05 14:57:48 +00:00
|
|
|
_vm->_timer->removeTimerProc(&timerCallback);
|
|
|
|
|
2004-06-27 21:06:04 +00:00
|
|
|
_vm->_smushVideoShouldFinish = true;
|
2004-04-26 09:04:08 +00:00
|
|
|
|
2003-06-07 00:45:32 +00:00
|
|
|
for (int i = 0; i < 5; i++) {
|
2005-07-19 17:04:16 +00:00
|
|
|
delete _sf[i];
|
|
|
|
_sf[i] = NULL;
|
2003-03-17 12:28:50 +00:00
|
|
|
}
|
|
|
|
|
2005-07-19 17:04:16 +00:00
|
|
|
delete _strings;
|
|
|
|
_strings = NULL;
|
2003-01-19 20:28:16 +00:00
|
|
|
|
2005-07-19 17:04:16 +00:00
|
|
|
delete _base;
|
|
|
|
_base = NULL;
|
|
|
|
|
|
|
|
free(_specialBuffer);
|
|
|
|
_specialBuffer = NULL;
|
|
|
|
|
|
|
|
free(_frameBuffer);
|
|
|
|
_frameBuffer = NULL;
|
2004-09-18 18:09:35 +00:00
|
|
|
|
2006-03-05 12:15:39 +00:00
|
|
|
_IACTstream = NULL;
|
2003-06-15 00:07:24 +00:00
|
|
|
|
2006-10-07 17:42:32 +00:00
|
|
|
_vm->_smushActive = false;
|
2004-01-08 20:37:26 +00:00
|
|
|
_vm->_fullRedraw = true;
|
2004-09-29 17:50:17 +00:00
|
|
|
|
|
|
|
// HACK HACK HACK: This is an *evil* trick, beware! See above for
|
|
|
|
// some explanation.
|
|
|
|
_vm->virtscr[0].pitch = _origPitch;
|
2006-09-17 20:22:47 +00:00
|
|
|
_vm->_gdi->_numStrips = _origNumStrips;
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2005-01-16 13:32:48 +00:00
|
|
|
_initDone = false;
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
|
|
|
|
2003-03-06 08:36:56 +00:00
|
|
|
void SmushPlayer::checkBlock(const Chunk &b, Chunk::type type_expected, uint32 min_size) {
|
2003-06-07 00:45:32 +00:00
|
|
|
if (type_expected != b.getType()) {
|
2004-01-25 05:25:50 +00:00
|
|
|
error("Chunk type is different from expected : %x != %x", b.getType(), type_expected);
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
2003-06-07 00:45:32 +00:00
|
|
|
if (min_size > b.getSize()) {
|
2003-03-17 12:28:50 +00:00
|
|
|
error("Chunk size is inferior than minimum required size : %d < %d", b.getSize(), min_size);
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-01-09 23:33:46 +00:00
|
|
|
void SmushPlayer::handleSoundBuffer(int32 track_id, int32 index, int32 max_frames, int32 flags, int32 vol, int32 pan, Chunk &b, int32 size) {
|
2004-08-22 09:14:19 +00:00
|
|
|
debugC(DEBUG_SMUSH, "SmushPlayer::handleSoundBuffer(%d, %d)", track_id, index);
|
2003-06-07 00:45:32 +00:00
|
|
|
// if ((flags & 128) == 128) {
|
2003-03-17 12:28:50 +00:00
|
|
|
// return;
|
|
|
|
// }
|
2003-06-07 00:45:32 +00:00
|
|
|
// if ((flags & 64) == 64) {
|
2003-03-17 12:28:50 +00:00
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
SmushChannel *c = _smixer->findChannel(track_id);
|
2003-06-07 00:45:32 +00:00
|
|
|
if (c == NULL) {
|
2002-08-30 07:24:45 +00:00
|
|
|
c = new SaudChannel(track_id, _soundFrequency);
|
2003-03-17 12:28:50 +00:00
|
|
|
_smixer->addChannel(c);
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
2003-12-25 08:25:04 +00:00
|
|
|
|
2005-06-25 15:17:14 +00:00
|
|
|
if (_middleAudio || (index == 0)) {
|
2004-01-09 23:33:46 +00:00
|
|
|
c->setParameters(max_frames, flags, vol, pan, index);
|
2003-12-25 08:25:04 +00:00
|
|
|
} else {
|
2004-01-09 23:33:46 +00:00
|
|
|
c->checkParameters(index, max_frames, flags, vol, pan);
|
2003-01-19 10:34:18 +00:00
|
|
|
}
|
2003-12-25 08:48:51 +00:00
|
|
|
_middleAudio = false;
|
2002-08-24 15:31:37 +00:00
|
|
|
c->appendData(b, size);
|
|
|
|
}
|
|
|
|
|
2003-03-06 08:36:56 +00:00
|
|
|
void SmushPlayer::handleSoundFrame(Chunk &b) {
|
2002-08-24 15:31:37 +00:00
|
|
|
checkBlock(b, TYPE_PSAD);
|
2004-08-22 09:14:19 +00:00
|
|
|
debugC(DEBUG_SMUSH, "SmushPlayer::handleSoundFrame()");
|
2003-03-17 12:28:50 +00:00
|
|
|
|
2002-08-30 07:24:45 +00:00
|
|
|
int32 track_id = b.getWord();
|
|
|
|
int32 index = b.getWord();
|
|
|
|
int32 max_frames = b.getWord();
|
|
|
|
int32 flags = b.getWord();
|
|
|
|
int32 vol = b.getByte();
|
2004-01-09 23:33:46 +00:00
|
|
|
int32 pan = b.getChar();
|
2003-06-07 00:45:32 +00:00
|
|
|
if (index == 0) {
|
2004-08-22 09:14:19 +00:00
|
|
|
debugC(DEBUG_SMUSH, "track_id:%d, max_frames:%d, flags:%d, vol:%d, pan:%d", track_id, max_frames, flags, vol, pan);
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
2002-08-30 07:24:45 +00:00
|
|
|
int32 size = b.getSize() - 10;
|
2004-01-09 23:33:46 +00:00
|
|
|
handleSoundBuffer(track_id, index, max_frames, flags, vol, pan, b, size);
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
|
|
|
|
2003-03-06 08:36:56 +00:00
|
|
|
void SmushPlayer::handleStore(Chunk &b) {
|
2004-08-22 09:14:19 +00:00
|
|
|
debugC(DEBUG_SMUSH, "SmushPlayer::handleStore()");
|
2002-08-24 15:31:37 +00:00
|
|
|
checkBlock(b, TYPE_STOR, 4);
|
2003-01-19 20:28:16 +00:00
|
|
|
_storeFrame = true;
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
|
|
|
|
2003-03-06 08:36:56 +00:00
|
|
|
void SmushPlayer::handleFetch(Chunk &b) {
|
2004-08-22 09:14:19 +00:00
|
|
|
debugC(DEBUG_SMUSH, "SmushPlayer::handleFetch()");
|
2003-03-17 12:28:50 +00:00
|
|
|
checkBlock(b, TYPE_FTCH, 6);
|
2003-01-19 20:28:16 +00:00
|
|
|
|
|
|
|
if (_frameBuffer != NULL) {
|
2003-06-18 13:14:17 +00:00
|
|
|
memcpy(_dst, _frameBuffer, _width * _height);
|
2003-01-19 20:28:16 +00:00
|
|
|
}
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
|
|
|
|
2003-12-22 00:10:43 +00:00
|
|
|
void SmushPlayer::handleIACT(Chunk &b) {
|
2003-03-17 12:28:50 +00:00
|
|
|
checkBlock(b, TYPE_IACT, 8);
|
2006-10-08 18:22:51 +00:00
|
|
|
debugC(DEBUG_SMUSH, "SmushPlayer::IACT()");
|
2003-03-17 12:28:50 +00:00
|
|
|
|
2006-10-08 18:22:51 +00:00
|
|
|
int code = b.getWord();
|
2003-03-17 12:28:50 +00:00
|
|
|
int flags = b.getWord();
|
|
|
|
int unknown = b.getShort();
|
|
|
|
int track_flags = b.getWord();
|
2003-04-30 11:26:36 +00:00
|
|
|
|
2006-10-08 18:22:51 +00:00
|
|
|
if ((code != 8) && (flags != 46)) {
|
|
|
|
_vm->_insane->procIACT(_dst, 0, 0, 0, b, 0, 0, code, flags, unknown, track_flags);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_compressedFileMode) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-08-24 15:31:37 +00:00
|
|
|
assert(flags == 46 && unknown == 0);
|
2003-03-17 12:28:50 +00:00
|
|
|
int track_id = b.getWord();
|
|
|
|
int index = b.getWord();
|
|
|
|
int nbframes = b.getWord();
|
2002-08-30 07:24:45 +00:00
|
|
|
int32 size = b.getDword();
|
|
|
|
int32 bsize = b.getSize() - 18;
|
2003-03-17 12:28:50 +00:00
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_vm->_game.id != GID_CMI) {
|
2003-12-22 00:10:43 +00:00
|
|
|
int32 track = track_id;
|
|
|
|
if (track_flags == 1) {
|
|
|
|
track = track_id + 100;
|
|
|
|
} else if (track_flags == 2) {
|
|
|
|
track = track_id + 200;
|
|
|
|
} else if (track_flags == 3) {
|
|
|
|
track = track_id + 300;
|
|
|
|
} else if ((track_flags >= 100) && (track_flags <= 163)) {
|
|
|
|
track = track_id + 400;
|
|
|
|
} else if ((track_flags >= 200) && (track_flags <= 263)) {
|
|
|
|
track = track_id + 500;
|
|
|
|
} else if ((track_flags >= 300) && (track_flags <= 363)) {
|
|
|
|
track = track_id + 600;
|
|
|
|
} else {
|
|
|
|
error("ImuseChannel::handleIACT(): bad track_flags: %d", track_flags);
|
|
|
|
}
|
2004-08-22 09:14:19 +00:00
|
|
|
debugC(DEBUG_SMUSH, "SmushPlayer::handleIACT(): %d, %d, %d", track, index, track_flags);
|
2003-12-22 00:10:43 +00:00
|
|
|
|
|
|
|
SmushChannel *c = _smixer->findChannel(track);
|
|
|
|
if (c == 0) {
|
|
|
|
c = new ImuseChannel(track, _soundFrequency);
|
|
|
|
_smixer->addChannel(c);
|
|
|
|
}
|
|
|
|
if (index == 0)
|
2003-12-25 08:25:04 +00:00
|
|
|
c->setParameters(nbframes, size, track_flags, unknown, 0);
|
2003-12-22 00:10:43 +00:00
|
|
|
else
|
|
|
|
c->checkParameters(index, nbframes, size, track_flags, unknown);
|
|
|
|
c->appendData(b, bsize);
|
2003-01-18 13:54:26 +00:00
|
|
|
} else {
|
|
|
|
byte output_data[4096];
|
2003-03-06 08:36:56 +00:00
|
|
|
byte *src = (byte *)malloc(bsize);
|
2003-01-18 13:54:26 +00:00
|
|
|
b.read(src, bsize);
|
2003-03-06 08:36:56 +00:00
|
|
|
byte *d_src = src;
|
2003-01-18 13:54:26 +00:00
|
|
|
byte value;
|
|
|
|
|
2003-12-25 02:46:04 +00:00
|
|
|
while (bsize > 0) {
|
2003-01-19 10:34:18 +00:00
|
|
|
if (_IACTpos >= 2) {
|
2003-01-18 13:54:26 +00:00
|
|
|
int32 len = READ_BE_UINT16(_IACToutput) + 2;
|
2003-01-19 10:34:18 +00:00
|
|
|
len -= _IACTpos;
|
2003-01-18 13:54:26 +00:00
|
|
|
if (len > bsize) {
|
2003-01-19 10:34:18 +00:00
|
|
|
memcpy(_IACToutput + _IACTpos, d_src, bsize);
|
|
|
|
_IACTpos += bsize;
|
2003-01-18 13:54:26 +00:00
|
|
|
bsize = 0;
|
|
|
|
} else {
|
2003-01-19 10:34:18 +00:00
|
|
|
memcpy(_IACToutput + _IACTpos, d_src, len);
|
2003-03-06 08:36:56 +00:00
|
|
|
byte *dst = output_data;
|
|
|
|
byte *d_src2 = _IACToutput;
|
2003-01-18 13:54:26 +00:00
|
|
|
d_src2 += 2;
|
|
|
|
int32 count = 1024;
|
2003-01-19 10:34:18 +00:00
|
|
|
byte variable1 = *d_src2++;
|
2003-11-16 20:52:57 +00:00
|
|
|
byte variable2 = variable1 / 16;
|
2003-01-18 13:54:26 +00:00
|
|
|
variable1 &= 0x0f;
|
|
|
|
do {
|
|
|
|
value = *(d_src2++);
|
|
|
|
if (value == 0x80) {
|
2003-01-19 10:34:18 +00:00
|
|
|
*dst++ = *d_src2++;
|
|
|
|
*dst++ = *d_src2++;
|
2003-01-18 13:54:26 +00:00
|
|
|
} else {
|
|
|
|
int16 val = (int8)value << variable2;
|
2003-06-21 19:58:38 +00:00
|
|
|
*dst++ = val >> 8;
|
2003-01-19 10:34:18 +00:00
|
|
|
*dst++ = (byte)(val);
|
2003-01-18 13:54:26 +00:00
|
|
|
}
|
|
|
|
value = *(d_src2++);
|
|
|
|
if (value == 0x80) {
|
2003-01-19 10:34:18 +00:00
|
|
|
*dst++ = *d_src2++;
|
|
|
|
*dst++ = *d_src2++;
|
2003-01-18 13:54:26 +00:00
|
|
|
} else {
|
|
|
|
int16 val = (int8)value << variable1;
|
2003-11-16 20:52:57 +00:00
|
|
|
*dst++ = val >> 8;
|
2003-01-19 10:34:18 +00:00
|
|
|
*dst++ = (byte)(val);
|
2003-01-18 13:54:26 +00:00
|
|
|
}
|
|
|
|
} while (--count);
|
|
|
|
|
2005-04-04 18:42:35 +00:00
|
|
|
if (!_IACTstream) {
|
2006-05-28 06:04:46 +00:00
|
|
|
_IACTstream = Audio::makeAppendableAudioStream(22050, Audio::Mixer::FLAG_STEREO | Audio::Mixer::FLAG_16BITS, 900000);
|
2005-05-10 23:48:48 +00:00
|
|
|
_vm->_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_IACTchannel, _IACTstream);
|
2004-11-27 17:09:05 +00:00
|
|
|
}
|
|
|
|
_IACTstream->append(output_data, 0x1000);
|
2003-01-18 13:54:26 +00:00
|
|
|
|
|
|
|
bsize -= len;
|
|
|
|
d_src += len;
|
2003-01-19 10:34:18 +00:00
|
|
|
_IACTpos = 0;
|
2003-01-18 13:54:26 +00:00
|
|
|
}
|
|
|
|
} else {
|
2003-12-25 02:46:04 +00:00
|
|
|
if (bsize > 1 && _IACTpos == 0) {
|
2003-01-19 10:34:18 +00:00
|
|
|
*(_IACToutput + 0) = *d_src++;
|
2003-12-25 02:46:04 +00:00
|
|
|
_IACTpos = 1;
|
2003-01-18 13:54:26 +00:00
|
|
|
bsize--;
|
|
|
|
}
|
2003-12-25 02:46:04 +00:00
|
|
|
*(_IACToutput + _IACTpos) = *d_src++;
|
|
|
|
_IACTpos++;
|
2003-01-18 14:58:37 +00:00
|
|
|
bsize--;
|
2005-07-30 21:11:48 +00:00
|
|
|
}
|
2003-12-25 02:46:04 +00:00
|
|
|
}
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2003-01-18 13:54:26 +00:00
|
|
|
free(src);
|
|
|
|
}
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
|
|
|
|
2003-03-06 08:36:56 +00:00
|
|
|
void SmushPlayer::handleTextResource(Chunk &b) {
|
2003-03-17 12:28:50 +00:00
|
|
|
int pos_x = b.getShort();
|
|
|
|
int pos_y = b.getShort();
|
|
|
|
int flags = b.getShort();
|
|
|
|
int left = b.getShort();
|
|
|
|
int top = b.getShort();
|
2003-06-08 00:39:08 +00:00
|
|
|
int right = b.getShort();
|
2002-09-22 00:20:23 +00:00
|
|
|
/*int32 height =*/ b.getShort();
|
|
|
|
/*int32 unk2 =*/ b.getWord();
|
2003-01-18 21:51:00 +00:00
|
|
|
|
2003-06-04 15:04:00 +00:00
|
|
|
const char *str;
|
|
|
|
char *string = NULL, *string2 = NULL;
|
2003-01-19 10:34:18 +00:00
|
|
|
if (b.getType() == TYPE_TEXT) {
|
2003-03-17 12:28:50 +00:00
|
|
|
string = (char *)malloc(b.getSize() - 16);
|
2003-01-18 21:51:00 +00:00
|
|
|
str = string;
|
|
|
|
b.read(string, b.getSize() - 16);
|
|
|
|
} else {
|
2003-03-17 12:28:50 +00:00
|
|
|
int string_id = b.getWord();
|
2003-06-07 00:45:32 +00:00
|
|
|
if (!_strings)
|
2003-01-18 21:51:00 +00:00
|
|
|
return;
|
|
|
|
str = _strings->get(string_id);
|
|
|
|
}
|
2002-08-24 15:31:37 +00:00
|
|
|
|
|
|
|
// if subtitles disabled and bit 3 is set, then do not draw
|
2006-09-21 17:46:19 +00:00
|
|
|
//
|
|
|
|
// Query ConfMan here. However it may be slower, but
|
|
|
|
// player may want to switch the subtitles on or off during the
|
|
|
|
// playback. This fixes bug #1550974
|
|
|
|
if ((!ConfMan.getBool("subtitles")) && ((flags & 8) == 8))
|
2002-08-30 07:24:45 +00:00
|
|
|
return;
|
2002-08-24 15:31:37 +00:00
|
|
|
|
2003-03-17 12:28:50 +00:00
|
|
|
SmushFont *sf = _sf[0];
|
|
|
|
int color = 15;
|
2003-06-07 00:45:32 +00:00
|
|
|
while (*str == '/') {
|
2003-01-19 10:34:18 +00:00
|
|
|
str++; // For Full Throttle text resources
|
|
|
|
}
|
|
|
|
|
2004-04-02 21:56:27 +00:00
|
|
|
byte transBuf[512];
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_vm->_game.id == GID_CMI) {
|
2004-04-02 22:01:25 +00:00
|
|
|
_vm->translateText((const byte *)str - 1, transBuf);
|
2003-06-07 00:45:32 +00:00
|
|
|
while (*str++ != '/')
|
2003-06-04 15:04:00 +00:00
|
|
|
;
|
2004-04-02 21:56:27 +00:00
|
|
|
string2 = (char *)transBuf;
|
2003-02-14 16:01:55 +00:00
|
|
|
|
|
|
|
// If string2 contains formatting information there probably
|
|
|
|
// wasn't any translation for it in the language.tab file. In
|
|
|
|
// that case, pretend there is no string2.
|
|
|
|
if (string2[0] == '^')
|
|
|
|
string2[0] = 0;
|
2003-01-19 10:34:18 +00:00
|
|
|
}
|
|
|
|
|
2003-06-07 00:45:32 +00:00
|
|
|
while (str[0] == '^') {
|
2003-09-24 06:33:59 +00:00
|
|
|
switch (str[1]) {
|
2002-08-24 15:31:37 +00:00
|
|
|
case 'f':
|
|
|
|
{
|
|
|
|
int id = str[3] - '0';
|
|
|
|
str += 4;
|
2005-07-30 21:11:48 +00:00
|
|
|
sf = _sf[id];
|
2003-01-19 10:34:18 +00:00
|
|
|
}
|
|
|
|
break;
|
2002-08-24 15:31:37 +00:00
|
|
|
case 'c':
|
|
|
|
{
|
|
|
|
color = str[4] - '0' + 10 *(str[3] - '0');
|
|
|
|
str += 5;
|
2003-01-19 10:34:18 +00:00
|
|
|
}
|
|
|
|
break;
|
2002-08-24 15:31:37 +00:00
|
|
|
default:
|
|
|
|
error("invalid escape code in text string");
|
|
|
|
}
|
|
|
|
}
|
2002-09-20 05:46:03 +00:00
|
|
|
|
2005-10-13 23:27:11 +00:00
|
|
|
// HACK. This is to prevent bug #1310846. In updated Win95 dig
|
|
|
|
// there is such line:
|
|
|
|
//
|
|
|
|
// ^f01^c001LEAD TESTER
|
|
|
|
// Chris Purvis
|
|
|
|
// ^f01
|
|
|
|
// ^f01^c001WINDOWS COMPATIBILITY
|
|
|
|
// Chip Hinnenberg
|
|
|
|
// ^f01^c001WINDOWS TESTING
|
|
|
|
// Jim Davison
|
|
|
|
// Lynn Selk
|
|
|
|
//
|
|
|
|
// i.e. formatting exists not in the first line only
|
|
|
|
// We just strip that off and assume that neither font
|
|
|
|
// nor font color was altered. Proper fix would be to feed
|
|
|
|
// drawString() with each line sequentally
|
|
|
|
char *string3 = NULL, *sptr2;
|
|
|
|
const char *sptr;
|
|
|
|
|
|
|
|
if (strchr(str, '^')) {
|
|
|
|
string3 = (char *)malloc(strlen(str) + 1);
|
|
|
|
|
|
|
|
for (sptr = str, sptr2 = string3; *sptr;) {
|
|
|
|
if (*sptr == '^') {
|
|
|
|
switch (sptr[1]) {
|
|
|
|
case 'f':
|
|
|
|
sptr += 4;
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
sptr += 5;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error("invalid escape code in text string");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
*sptr2++ = *sptr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*sptr2++ = *sptr++; // copy zero character
|
|
|
|
str = string3;
|
|
|
|
}
|
|
|
|
|
2003-03-17 12:28:50 +00:00
|
|
|
assert(sf != NULL);
|
|
|
|
sf->setColor(color);
|
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_vm->_game.id == GID_CMI && string2[0] != 0) {
|
2003-06-04 15:04:00 +00:00
|
|
|
str = string2;
|
2003-01-30 08:10:16 +00:00
|
|
|
}
|
|
|
|
|
2002-09-20 05:46:03 +00:00
|
|
|
// flags:
|
2003-06-04 15:04:00 +00:00
|
|
|
// bit 0 - center 1
|
|
|
|
// bit 1 - not used 2
|
|
|
|
// bit 2 - ??? 4
|
|
|
|
// bit 3 - wrap around 8
|
2003-06-07 22:57:27 +00:00
|
|
|
switch (flags & 9) {
|
2005-07-30 21:11:48 +00:00
|
|
|
case 0:
|
2004-04-16 20:49:14 +00:00
|
|
|
sf->drawString(str, _dst, _width, _height, pos_x, pos_y, false);
|
2003-09-24 06:33:59 +00:00
|
|
|
break;
|
|
|
|
case 1:
|
2004-04-16 20:49:14 +00:00
|
|
|
sf->drawString(str, _dst, _width, _height, pos_x, MAX(pos_y, top), true);
|
2003-09-24 06:33:59 +00:00
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
// FIXME: Is 'right' the maximum line width here, just
|
|
|
|
// as it is in the next case? It's used several times
|
|
|
|
// in The Dig's intro, where 'left' and 'right' are
|
|
|
|
// always 0 and 321 respectively, and apparently we
|
|
|
|
// handle that correctly.
|
2004-04-16 20:49:14 +00:00
|
|
|
sf->drawStringWrap(str, _dst, _width, _height, pos_x, MAX(pos_y, top), left, right, false);
|
2003-09-24 06:33:59 +00:00
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
// In this case, the 'right' parameter is actually the
|
|
|
|
// maximum line width. This explains why it's sometimes
|
|
|
|
// smaller than 'left'.
|
|
|
|
//
|
|
|
|
// Note that in The Dig's "Spacetime Six" movie it's
|
|
|
|
// 621. I have no idea what that means.
|
2004-04-16 20:49:14 +00:00
|
|
|
sf->drawStringWrap(str, _dst, _width, _height, pos_x, MAX(pos_y, top), left, MIN(left + right, _width), true);
|
2003-09-24 06:33:59 +00:00
|
|
|
break;
|
|
|
|
default:
|
2005-08-14 02:04:26 +00:00
|
|
|
error("SmushPlayer::handleTextResource. Not handled flags: %d", flags);
|
2002-09-20 05:46:03 +00:00
|
|
|
}
|
2003-01-18 21:51:00 +00:00
|
|
|
|
2003-01-19 10:34:18 +00:00
|
|
|
if (string != NULL) {
|
2003-01-18 21:51:00 +00:00
|
|
|
free (string);
|
|
|
|
}
|
2005-10-13 23:27:11 +00:00
|
|
|
if (string3 != NULL) {
|
|
|
|
free (string3);
|
|
|
|
}
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
|
|
|
|
2004-01-26 22:44:47 +00:00
|
|
|
const char *SmushPlayer::getString(int id) {
|
|
|
|
return _strings->get(id);
|
|
|
|
}
|
|
|
|
|
2004-06-27 21:52:25 +00:00
|
|
|
bool SmushPlayer::readString(const char *file) {
|
2003-03-17 12:28:50 +00:00
|
|
|
const char *i = strrchr(file, '.');
|
2003-06-07 00:45:32 +00:00
|
|
|
if (i == NULL) {
|
2003-03-17 12:28:50 +00:00
|
|
|
error("invalid filename : %s", file);
|
|
|
|
}
|
|
|
|
char fname[260];
|
|
|
|
memcpy(fname, file, i - file);
|
|
|
|
strcpy(fname + (i - file), ".trs");
|
2005-01-06 18:38:11 +00:00
|
|
|
if ((_strings = getStrings(_vm, fname, false)) != 0) {
|
2003-03-17 12:28:50 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-01-06 18:38:11 +00:00
|
|
|
if ((_strings = getStrings(_vm, "digtxt.trs", true)) != 0) {
|
2003-03-17 12:28:50 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SmushPlayer::readPalette(byte *out, Chunk &in) {
|
|
|
|
in.read(out, 0x300);
|
|
|
|
}
|
|
|
|
|
|
|
|
static byte delta_color(byte org_color, int16 delta_color) {
|
2003-11-16 20:52:57 +00:00
|
|
|
int t = (org_color * 129 + delta_color) / 128;
|
2003-03-17 12:28:50 +00:00
|
|
|
if (t > 255)
|
|
|
|
t = 255;
|
|
|
|
if (t < 0)
|
|
|
|
t = 0;
|
|
|
|
return (byte)t;
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
|
|
|
|
2003-03-06 08:36:56 +00:00
|
|
|
void SmushPlayer::handleDeltaPalette(Chunk &b) {
|
2002-08-24 15:31:37 +00:00
|
|
|
checkBlock(b, TYPE_XPAL);
|
2004-08-22 09:14:19 +00:00
|
|
|
debugC(DEBUG_SMUSH, "SmushPlayer::handleDeltaPalette()");
|
2003-03-17 12:28:50 +00:00
|
|
|
|
2003-06-07 00:45:32 +00:00
|
|
|
if (b.getSize() == 0x300 * 3 + 4) {
|
2003-03-17 12:28:50 +00:00
|
|
|
|
|
|
|
b.getWord();
|
|
|
|
b.getWord();
|
|
|
|
|
2003-06-07 00:45:32 +00:00
|
|
|
for (int i = 0; i < 0x300; i++) {
|
2002-08-24 15:31:37 +00:00
|
|
|
_deltaPal[i] = b.getWord();
|
|
|
|
}
|
|
|
|
readPalette(_pal, b);
|
2005-05-07 01:52:17 +00:00
|
|
|
setDirtyColors(0, 255);
|
2003-06-07 00:45:32 +00:00
|
|
|
} else if (b.getSize() == 6) {
|
2003-03-17 12:28:50 +00:00
|
|
|
|
|
|
|
b.getWord();
|
|
|
|
b.getWord();
|
|
|
|
b.getWord();
|
|
|
|
|
2003-06-07 00:45:32 +00:00
|
|
|
for (int i = 0; i < 0x300; i++) {
|
2003-03-17 12:28:50 +00:00
|
|
|
_pal[i] = delta_color(_pal[i], _deltaPal[i]);
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
2005-05-07 01:52:17 +00:00
|
|
|
setDirtyColors(0, 255);
|
2002-08-24 15:31:37 +00:00
|
|
|
} else {
|
2003-03-17 12:28:50 +00:00
|
|
|
error("SmushPlayer::handleDeltaPalette() Wrong size for DeltaPalette");
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-03-06 08:36:56 +00:00
|
|
|
void SmushPlayer::handleNewPalette(Chunk &b) {
|
2003-03-17 12:28:50 +00:00
|
|
|
checkBlock(b, TYPE_NPAL, 0x300);
|
2004-08-22 09:14:19 +00:00
|
|
|
debugC(DEBUG_SMUSH, "SmushPlayer::handleNewPalette()");
|
2003-03-17 12:28:50 +00:00
|
|
|
|
2005-05-28 02:26:14 +00:00
|
|
|
if (_skipPalette)
|
|
|
|
return;
|
|
|
|
|
2002-08-24 15:31:37 +00:00
|
|
|
readPalette(_pal, b);
|
2005-05-07 01:52:17 +00:00
|
|
|
setDirtyColors(0, 255);
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
|
|
|
|
2005-06-17 18:10:51 +00:00
|
|
|
void smush_decode_codec1(byte *dst, const byte *src, int left, int top, int width, int height, int pitch);
|
2003-11-16 21:53:22 +00:00
|
|
|
|
2004-04-13 19:20:16 +00:00
|
|
|
#ifdef USE_ZLIB
|
|
|
|
void SmushPlayer::handleZlibFrameObject(Chunk &b) {
|
|
|
|
if (_skipNext) {
|
|
|
|
_skipNext = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32 chunkSize = b.getSize();
|
|
|
|
byte *chunkBuffer = (byte *)malloc(chunkSize);
|
|
|
|
assert(chunkBuffer);
|
|
|
|
b.read(chunkBuffer, chunkSize);
|
|
|
|
|
|
|
|
unsigned long decompressedSize = READ_BE_UINT32(chunkBuffer);
|
|
|
|
byte *fobjBuffer = (byte *)malloc(decompressedSize);
|
|
|
|
int result = uncompress(fobjBuffer, &decompressedSize, chunkBuffer + 4, chunkSize - 4);
|
|
|
|
if (result != Z_OK)
|
|
|
|
error("SmushPlayer::handleZlibFrameObject() Zlib uncompress error");
|
|
|
|
free(chunkBuffer);
|
|
|
|
|
|
|
|
byte *ptr = fobjBuffer;
|
|
|
|
int codec = READ_LE_UINT16(ptr); ptr += 2;
|
|
|
|
int left = READ_LE_UINT16(ptr); ptr += 2;
|
|
|
|
int top = READ_LE_UINT16(ptr); ptr += 2;
|
|
|
|
int width = READ_LE_UINT16(ptr); ptr += 2;
|
|
|
|
int height = READ_LE_UINT16(ptr); ptr += 2;
|
|
|
|
|
|
|
|
if ((height == 242) && (width == 384)) {
|
2005-01-16 13:34:43 +00:00
|
|
|
if (_specialBuffer == 0)
|
|
|
|
_specialBuffer = (byte *)malloc(242 * 384);
|
|
|
|
_dst = _specialBuffer;
|
2004-04-13 19:20:16 +00:00
|
|
|
} else if ((height > _vm->_screenHeight) || (width > _vm->_screenWidth))
|
|
|
|
return;
|
|
|
|
// FT Insane uses smaller frames to draw overlays with moving objects
|
|
|
|
// Other .san files do have them as well but their purpose in unknown
|
|
|
|
// and often it causes memory overdraw. So just skip those frames
|
|
|
|
else if (!_insanity && ((height != _vm->_screenHeight) || (width != _vm->_screenWidth)))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!_alreadyInit) {
|
|
|
|
_codec37.init(width, height);
|
|
|
|
_codec47.init(width, height);
|
|
|
|
_alreadyInit = true;
|
|
|
|
}
|
|
|
|
|
2004-05-04 14:56:47 +00:00
|
|
|
if ((height == 242) && (width == 384)) {
|
|
|
|
_width = width;
|
|
|
|
_height = height;
|
|
|
|
} else {
|
|
|
|
_width = _vm->_screenWidth;
|
|
|
|
_height = _vm->_screenHeight;
|
|
|
|
}
|
2004-04-13 19:20:16 +00:00
|
|
|
|
|
|
|
switch (codec) {
|
|
|
|
case 1:
|
|
|
|
case 3:
|
2005-06-17 18:10:51 +00:00
|
|
|
smush_decode_codec1(_dst, fobjBuffer + 14, left, top, width, height, _vm->_screenWidth);
|
2004-04-13 19:20:16 +00:00
|
|
|
break;
|
|
|
|
case 37:
|
|
|
|
_codec37.decode(_dst, fobjBuffer + 14);
|
|
|
|
break;
|
|
|
|
case 47:
|
|
|
|
_codec47.decode(_dst, fobjBuffer + 14);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error("Invalid codec for frame object : %d", (int)codec);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_storeFrame) {
|
|
|
|
if (_frameBuffer == NULL) {
|
|
|
|
_frameBuffer = (byte *)malloc(_width * _height);
|
|
|
|
}
|
|
|
|
memcpy(_frameBuffer, _dst, _width * _height);
|
|
|
|
_storeFrame = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(fobjBuffer);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-03-13 00:37:03 +00:00
|
|
|
void SmushPlayer::handleFrameObject(Chunk &b) {
|
2002-08-24 15:31:37 +00:00
|
|
|
checkBlock(b, TYPE_FOBJ, 14);
|
2003-06-07 00:45:32 +00:00
|
|
|
if (_skipNext) {
|
2002-08-24 15:31:37 +00:00
|
|
|
_skipNext = false;
|
|
|
|
return;
|
|
|
|
}
|
2003-03-17 12:28:50 +00:00
|
|
|
|
2002-08-24 15:31:37 +00:00
|
|
|
int codec = b.getWord();
|
2004-04-10 09:17:36 +00:00
|
|
|
int left = b.getWord();
|
|
|
|
int top = b.getWord();
|
2003-03-17 12:28:50 +00:00
|
|
|
int width = b.getWord();
|
|
|
|
int height = b.getWord();
|
|
|
|
|
2004-04-10 09:17:36 +00:00
|
|
|
if ((height == 242) && (width == 384)) {
|
2005-01-16 13:34:43 +00:00
|
|
|
if (_specialBuffer == 0)
|
|
|
|
_specialBuffer = (byte *)malloc(242 * 384);
|
|
|
|
_dst = _specialBuffer;
|
2004-04-10 09:17:36 +00:00
|
|
|
} else if ((height > _vm->_screenHeight) || (width > _vm->_screenWidth))
|
2003-03-17 12:28:50 +00:00
|
|
|
return;
|
2004-01-31 12:28:38 +00:00
|
|
|
// FT Insane uses smaller frames to draw overlays with moving objects
|
|
|
|
// Other .san files do have them as well but their purpose in unknown
|
|
|
|
// and often it causes memory overdraw. So just skip those frames
|
2004-04-10 09:17:36 +00:00
|
|
|
else if (!_insanity && ((height != _vm->_screenHeight) || (width != _vm->_screenWidth)))
|
2004-01-30 02:37:18 +00:00
|
|
|
return;
|
|
|
|
|
2003-06-07 00:45:32 +00:00
|
|
|
if (!_alreadyInit) {
|
2003-03-17 12:28:50 +00:00
|
|
|
_codec37.init(width, height);
|
|
|
|
_codec47.init(width, height);
|
|
|
|
_alreadyInit = true;
|
|
|
|
}
|
|
|
|
|
2004-05-04 14:56:47 +00:00
|
|
|
if ((height == 242) && (width == 384)) {
|
|
|
|
_width = width;
|
|
|
|
_height = height;
|
|
|
|
} else {
|
|
|
|
_width = _vm->_screenWidth;
|
|
|
|
_height = _vm->_screenHeight;
|
|
|
|
}
|
|
|
|
|
2003-03-17 12:28:50 +00:00
|
|
|
b.getWord();
|
|
|
|
b.getWord();
|
|
|
|
|
|
|
|
int32 chunk_size = b.getSize() - 14;
|
|
|
|
byte *chunk_buffer = (byte *)malloc(chunk_size);
|
|
|
|
assert(chunk_buffer);
|
|
|
|
b.read(chunk_buffer, chunk_size);
|
|
|
|
|
2002-08-24 15:31:37 +00:00
|
|
|
switch (codec) {
|
|
|
|
case 1:
|
2003-03-17 12:28:50 +00:00
|
|
|
case 3:
|
2005-06-17 18:10:51 +00:00
|
|
|
smush_decode_codec1(_dst, chunk_buffer, left, top, width, height, _vm->_screenWidth);
|
2002-08-24 15:31:37 +00:00
|
|
|
break;
|
|
|
|
case 37:
|
2003-06-18 13:14:17 +00:00
|
|
|
_codec37.decode(_dst, chunk_buffer);
|
2002-08-24 15:31:37 +00:00
|
|
|
break;
|
|
|
|
case 47:
|
2003-06-18 13:14:17 +00:00
|
|
|
_codec47.decode(_dst, chunk_buffer);
|
2002-08-24 15:31:37 +00:00
|
|
|
break;
|
|
|
|
default:
|
2003-03-17 12:28:50 +00:00
|
|
|
error("Invalid codec for frame object : %d", (int)codec);
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
2003-03-17 12:28:50 +00:00
|
|
|
|
2003-06-07 00:45:32 +00:00
|
|
|
if (_storeFrame) {
|
2003-03-17 12:28:50 +00:00
|
|
|
if (_frameBuffer == NULL) {
|
|
|
|
_frameBuffer = (byte *)malloc(_width * _height);
|
|
|
|
}
|
2003-06-18 13:14:17 +00:00
|
|
|
memcpy(_frameBuffer, _dst, _width * _height);
|
2003-03-17 12:28:50 +00:00
|
|
|
_storeFrame = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(chunk_buffer);
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
|
|
|
|
2003-03-06 08:36:56 +00:00
|
|
|
void SmushPlayer::handleFrame(Chunk &b) {
|
2002-08-24 15:31:37 +00:00
|
|
|
checkBlock(b, TYPE_FRME);
|
2004-08-22 09:14:19 +00:00
|
|
|
debugC(DEBUG_SMUSH, "SmushPlayer::handleFrame(%d)", _frame);
|
2002-08-24 15:31:37 +00:00
|
|
|
_skipNext = false;
|
|
|
|
|
2003-12-06 05:47:24 +00:00
|
|
|
if (_insanity) {
|
2004-01-08 20:37:26 +00:00
|
|
|
_vm->_insane->procPreRendering();
|
2003-12-06 05:47:24 +00:00
|
|
|
}
|
|
|
|
|
2003-06-07 00:45:32 +00:00
|
|
|
while (!b.eof()) {
|
2003-03-06 08:36:56 +00:00
|
|
|
Chunk *sub = b.subBlock();
|
2003-09-24 06:33:59 +00:00
|
|
|
switch (sub->getType()) {
|
|
|
|
case TYPE_NPAL:
|
|
|
|
handleNewPalette(*sub);
|
|
|
|
break;
|
|
|
|
case TYPE_FOBJ:
|
|
|
|
handleFrameObject(*sub);
|
|
|
|
break;
|
2004-04-13 19:20:16 +00:00
|
|
|
#ifdef USE_ZLIB
|
|
|
|
case TYPE_ZFOB:
|
|
|
|
handleZlibFrameObject(*sub);
|
|
|
|
break;
|
|
|
|
#endif
|
2003-09-24 06:33:59 +00:00
|
|
|
case TYPE_PSAD:
|
2004-09-18 18:09:35 +00:00
|
|
|
if (!_compressedFileMode)
|
|
|
|
handleSoundFrame(*sub);
|
2003-09-24 06:33:59 +00:00
|
|
|
break;
|
|
|
|
case TYPE_TRES:
|
|
|
|
handleTextResource(*sub);
|
|
|
|
break;
|
|
|
|
case TYPE_XPAL:
|
|
|
|
handleDeltaPalette(*sub);
|
|
|
|
break;
|
|
|
|
case TYPE_IACT:
|
2006-10-08 18:22:51 +00:00
|
|
|
handleIACT(*sub);
|
2003-09-24 06:33:59 +00:00
|
|
|
break;
|
|
|
|
case TYPE_STOR:
|
|
|
|
handleStore(*sub);
|
|
|
|
break;
|
|
|
|
case TYPE_FTCH:
|
|
|
|
handleFetch(*sub);
|
|
|
|
break;
|
|
|
|
case TYPE_SKIP:
|
2006-10-08 19:23:08 +00:00
|
|
|
_vm->_insane->procSKIP(*sub);
|
2006-10-08 19:35:13 +00:00
|
|
|
break;
|
2003-09-24 06:33:59 +00:00
|
|
|
case TYPE_TEXT:
|
|
|
|
handleTextResource(*sub);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error("Unknown frame subChunk found : %s, %d", Chunk::ChunkString(sub->getType()), sub->getSize());
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
2005-06-26 23:37:59 +00:00
|
|
|
|
|
|
|
b.reseek();
|
|
|
|
if (sub->getSize() & 1)
|
|
|
|
b.seek(1);
|
|
|
|
|
2002-08-24 15:31:37 +00:00
|
|
|
delete sub;
|
|
|
|
}
|
2003-03-17 12:28:50 +00:00
|
|
|
|
2003-12-06 05:47:24 +00:00
|
|
|
if (_insanity) {
|
2004-01-08 20:37:26 +00:00
|
|
|
_vm->_insane->procPostRendering(_dst, 0, 0, 0, _frame, _nbframes-1);
|
2003-12-06 05:47:24 +00:00
|
|
|
}
|
|
|
|
|
2006-02-05 14:57:48 +00:00
|
|
|
if (_width != 0 && _height != 0) {
|
|
|
|
#ifdef _WIN32_WCE
|
|
|
|
if (!_inTimer || _inTimerCount == _inTimerCountRedraw) {
|
|
|
|
updateScreen();
|
|
|
|
_inTimerCount = 0;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
updateScreen();
|
|
|
|
#endif
|
|
|
|
}
|
2003-03-17 12:28:50 +00:00
|
|
|
_smixer->handleFrame();
|
|
|
|
|
2002-08-24 15:31:37 +00:00
|
|
|
_frame++;
|
|
|
|
}
|
|
|
|
|
2003-03-06 08:36:56 +00:00
|
|
|
void SmushPlayer::handleAnimHeader(Chunk &b) {
|
2003-03-17 12:28:50 +00:00
|
|
|
checkBlock(b, TYPE_AHDR, 0x300 + 6);
|
2004-08-22 09:14:19 +00:00
|
|
|
debugC(DEBUG_SMUSH, "SmushPlayer::handleAnimHeader()");
|
2003-03-17 12:28:50 +00:00
|
|
|
|
2002-08-24 15:31:37 +00:00
|
|
|
_version = b.getWord();
|
|
|
|
_nbframes = b.getWord();
|
2003-01-19 11:11:07 +00:00
|
|
|
b.getWord();
|
2005-05-28 02:26:14 +00:00
|
|
|
|
|
|
|
if (_skipPalette)
|
|
|
|
return;
|
|
|
|
|
2005-04-03 06:27:44 +00:00
|
|
|
readPalette(_pal, b);
|
2005-05-07 01:52:17 +00:00
|
|
|
setDirtyColors(0, 255);
|
2003-03-17 12:28:50 +00:00
|
|
|
}
|
|
|
|
|
2004-06-27 21:52:25 +00:00
|
|
|
void SmushPlayer::setupAnim(const char *file) {
|
2003-06-18 13:14:17 +00:00
|
|
|
int i;
|
|
|
|
char file_font[11];
|
|
|
|
|
2003-12-22 19:05:49 +00:00
|
|
|
if (_insanity) {
|
2006-02-20 16:51:30 +00:00
|
|
|
if (!((_vm->_game.features & GF_DEMO) && (_vm->_game.platform == Common::kPlatformPC)))
|
2004-06-27 21:52:25 +00:00
|
|
|
readString("mineroad.trs");
|
2003-12-22 19:05:49 +00:00
|
|
|
} else
|
2004-06-27 21:52:25 +00:00
|
|
|
readString(file);
|
2003-03-17 12:28:50 +00:00
|
|
|
|
2006-02-20 16:51:30 +00:00
|
|
|
if (_vm->_game.id == GID_FT) {
|
|
|
|
if (!((_vm->_game.features & GF_DEMO) && (_vm->_game.platform == Common::kPlatformPC))) {
|
2005-04-20 19:59:18 +00:00
|
|
|
_sf[0] = new SmushFont(_vm, true, false);
|
|
|
|
_sf[1] = new SmushFont(_vm, true, false);
|
|
|
|
_sf[2] = new SmushFont(_vm, true, false);
|
|
|
|
_sf[3] = new SmushFont(_vm, true, false);
|
2004-06-27 21:52:25 +00:00
|
|
|
_sf[0]->loadFont("scummfnt.nut");
|
|
|
|
_sf[1]->loadFont("techfnt.nut");
|
|
|
|
_sf[2]->loadFont("titlfnt.nut");
|
|
|
|
_sf[3]->loadFont("specfnt.nut");
|
2003-11-17 21:16:43 +00:00
|
|
|
}
|
2006-02-20 16:51:30 +00:00
|
|
|
} else if (_vm->_game.id == GID_DIG) {
|
|
|
|
if (!(_vm->_game.features & GF_DEMO)) {
|
2003-11-17 21:16:43 +00:00
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
sprintf(file_font, "font%d.nut", i);
|
2005-04-20 19:59:18 +00:00
|
|
|
_sf[i] = new SmushFont(_vm, i != 0, false);
|
2004-06-27 21:52:25 +00:00
|
|
|
_sf[i]->loadFont(file_font);
|
2003-11-17 21:16:43 +00:00
|
|
|
}
|
2003-01-19 10:34:18 +00:00
|
|
|
}
|
2006-02-20 16:51:30 +00:00
|
|
|
} else if (_vm->_game.id == GID_CMI) {
|
2003-06-18 13:14:17 +00:00
|
|
|
for (i = 0; i < 5; i++) {
|
2006-02-20 16:51:30 +00:00
|
|
|
if ((_vm->_game.features & GF_DEMO) && (i == 4))
|
2003-11-17 21:33:25 +00:00
|
|
|
break;
|
|
|
|
sprintf(file_font, "font%d.nut", i);
|
2005-04-20 19:59:18 +00:00
|
|
|
_sf[i] = new SmushFont(_vm, false, true);
|
2004-06-27 21:52:25 +00:00
|
|
|
_sf[i]->loadFont(file_font);
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
2003-03-17 12:28:50 +00:00
|
|
|
} else {
|
2003-06-22 23:09:56 +00:00
|
|
|
error("SmushPlayer::setupAnim() Unknown font setup for game");
|
2005-07-30 21:11:48 +00:00
|
|
|
}
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
|
|
|
|
2003-03-17 12:28:50 +00:00
|
|
|
void SmushPlayer::parseNextFrame() {
|
2005-03-09 16:37:44 +00:00
|
|
|
Common::StackLock lock(_mutex);
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2005-06-25 15:17:14 +00:00
|
|
|
Chunk *sub;
|
2005-03-09 16:37:44 +00:00
|
|
|
|
2004-01-08 20:37:26 +00:00
|
|
|
if (_vm->_smushPaused)
|
2003-12-25 02:55:00 +00:00
|
|
|
return;
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2005-06-25 15:17:14 +00:00
|
|
|
if (_seekPos >= 0) {
|
|
|
|
if (_smixer)
|
|
|
|
_smixer->stop();
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2005-06-25 15:17:14 +00:00
|
|
|
if (_seekFile.size() > 0) {
|
2005-06-25 15:43:59 +00:00
|
|
|
delete _base;
|
2005-06-25 15:17:14 +00:00
|
|
|
_base = new FileChunk(_seekFile);
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2005-06-25 15:17:14 +00:00
|
|
|
if (_seekPos > 0) {
|
|
|
|
assert(_seekPos > 8);
|
|
|
|
// In this case we need to get palette and number of frames
|
|
|
|
sub = _base->subBlock();
|
|
|
|
checkBlock(*sub, TYPE_AHDR);
|
|
|
|
handleAnimHeader(*sub);
|
|
|
|
delete sub;
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2005-06-25 15:17:14 +00:00
|
|
|
_middleAudio = true;
|
|
|
|
_seekPos -= 8;
|
|
|
|
} else {
|
|
|
|
// We need this in Full Throttle when entering/leaving
|
|
|
|
// the old mine road.
|
|
|
|
tryCmpFile(_seekFile.c_str());
|
|
|
|
}
|
|
|
|
_skipPalette = false;
|
|
|
|
} else {
|
|
|
|
_skipPalette = true;
|
|
|
|
}
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2005-06-25 15:17:14 +00:00
|
|
|
_base->seek(_seekPos, FileChunk::seek_start);
|
|
|
|
_frame = _seekFrame;
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2005-06-25 15:17:14 +00:00
|
|
|
_seekPos = -1;
|
|
|
|
}
|
2003-12-25 02:55:00 +00:00
|
|
|
|
2005-06-25 15:17:14 +00:00
|
|
|
assert(_base);
|
2003-03-17 12:28:50 +00:00
|
|
|
if (_base->eof()) {
|
2004-06-27 21:06:04 +00:00
|
|
|
_vm->_smushVideoShouldFinish = true;
|
2006-10-10 12:16:21 +00:00
|
|
|
_endOfFile = true;
|
2003-03-17 12:28:50 +00:00
|
|
|
return;
|
2003-01-19 10:34:18 +00:00
|
|
|
}
|
2003-12-18 23:00:10 +00:00
|
|
|
|
2005-06-25 15:17:14 +00:00
|
|
|
sub = _base->subBlock();
|
2003-01-19 10:34:18 +00:00
|
|
|
|
2003-09-24 06:33:59 +00:00
|
|
|
switch (sub->getType()) {
|
2005-04-03 06:40:44 +00:00
|
|
|
case TYPE_AHDR: // FT INSANE may seek file to the beginning
|
|
|
|
handleAnimHeader(*sub);
|
|
|
|
break;
|
2003-09-24 06:33:59 +00:00
|
|
|
case TYPE_FRME:
|
|
|
|
handleFrame(*sub);
|
|
|
|
break;
|
|
|
|
default:
|
2004-01-25 05:25:50 +00:00
|
|
|
error("Unknown Chunk found at %x: %x, %d", _base->tell(), sub->getType(), sub->getSize());
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
2003-03-17 12:28:50 +00:00
|
|
|
delete sub;
|
2004-06-20 16:38:28 +00:00
|
|
|
|
2005-06-26 23:37:59 +00:00
|
|
|
_base->reseek();
|
|
|
|
|
2004-06-20 16:38:28 +00:00
|
|
|
if (_insanity)
|
2005-06-04 06:30:35 +00:00
|
|
|
_vm->_sound->processSound();
|
2006-02-05 14:57:48 +00:00
|
|
|
|
|
|
|
_vm->_imuseDigital->flushTracks();
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
|
|
|
|
2003-06-18 13:14:17 +00:00
|
|
|
void SmushPlayer::setPalette(const byte *palette) {
|
2005-05-07 01:52:17 +00:00
|
|
|
memcpy(_pal, palette, 0x300);
|
|
|
|
setDirtyColors(0, 255);
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
|
|
|
|
2004-01-26 22:44:47 +00:00
|
|
|
void SmushPlayer::setPaletteValue(int n, byte r, byte g, byte b) {
|
|
|
|
_pal[n * 3 + 0] = r;
|
|
|
|
_pal[n * 3 + 1] = g;
|
|
|
|
_pal[n * 3 + 2] = b;
|
2005-05-07 01:52:17 +00:00
|
|
|
setDirtyColors(n, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SmushPlayer::setDirtyColors(int min, int max) {
|
|
|
|
if (_palDirtyMin > min)
|
|
|
|
_palDirtyMin = min;
|
|
|
|
if (_palDirtyMax < max)
|
|
|
|
_palDirtyMax = max;
|
|
|
|
}
|
2004-01-26 22:44:47 +00:00
|
|
|
|
2005-05-07 01:52:17 +00:00
|
|
|
void SmushPlayer::warpMouse(int x, int y, int buttons) {
|
|
|
|
_warpNeeded = true;
|
|
|
|
_warpX = x;
|
|
|
|
_warpY = y;
|
|
|
|
_warpButtons = buttons;
|
2004-01-26 22:44:47 +00:00
|
|
|
}
|
|
|
|
|
2003-03-17 12:28:50 +00:00
|
|
|
void SmushPlayer::updateScreen() {
|
2003-08-18 06:11:37 +00:00
|
|
|
#ifdef DUMP_SMUSH_FRAMES
|
|
|
|
char fileName[100];
|
|
|
|
// change path below for dump png files
|
2006-02-05 14:57:48 +00:00
|
|
|
sprintf(fileName, "/path/to/somethere/%s%04d.png", _vm->getBaseName(), _frame);
|
2003-08-18 06:11:37 +00:00
|
|
|
FILE *file = fopen(fileName, "wb");
|
2005-07-30 21:11:48 +00:00
|
|
|
if (file == NULL)
|
2003-08-18 06:11:37 +00:00
|
|
|
error("can't open file for writing png");
|
2003-08-18 06:29:39 +00:00
|
|
|
|
|
|
|
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
|
2003-08-18 06:11:37 +00:00
|
|
|
if (png_ptr == NULL) {
|
2003-08-18 06:29:39 +00:00
|
|
|
fclose(file);
|
|
|
|
error("can't write png header");
|
|
|
|
}
|
|
|
|
png_infop info_ptr = png_create_info_struct(png_ptr);
|
2003-08-18 06:11:37 +00:00
|
|
|
if (info_ptr == NULL) {
|
2003-08-18 06:29:39 +00:00
|
|
|
fclose(file);
|
|
|
|
error("can't create png info struct");
|
|
|
|
}
|
|
|
|
if (setjmp(png_ptr->jmpbuf)) {
|
|
|
|
fclose(file);
|
|
|
|
error("png jmpbuf error");
|
|
|
|
}
|
|
|
|
|
|
|
|
png_init_io(png_ptr, file);
|
|
|
|
|
2005-07-30 21:11:48 +00:00
|
|
|
png_set_IHDR(png_ptr, info_ptr, _width, _height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
|
2003-08-18 06:29:39 +00:00
|
|
|
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
2003-08-18 06:11:37 +00:00
|
|
|
|
|
|
|
png_colorp palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof (png_color));
|
|
|
|
for (int i = 0; i != 256; ++i) {
|
2003-08-18 06:29:39 +00:00
|
|
|
(palette + i)->red = _pal[i * 3 + 0];
|
|
|
|
(palette + i)->green = _pal[i * 3 + 1];
|
|
|
|
(palette + i)->blue = _pal[i * 3 + 2];
|
2003-08-18 06:11:37 +00:00
|
|
|
}
|
2003-08-18 06:29:39 +00:00
|
|
|
|
2003-08-18 06:11:37 +00:00
|
|
|
png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH);
|
2003-08-18 06:29:39 +00:00
|
|
|
|
|
|
|
png_write_info(png_ptr, info_ptr);
|
|
|
|
png_set_flush(png_ptr, 10);
|
|
|
|
|
|
|
|
png_bytep row_pointers[480];
|
|
|
|
for (int y = 0 ; y < _height ; y++)
|
|
|
|
row_pointers[y] = (png_byte *) (_dst + y * _width);
|
|
|
|
png_write_image(png_ptr, row_pointers);
|
|
|
|
png_write_end(png_ptr, info_ptr);
|
|
|
|
png_free(png_ptr, palette);
|
|
|
|
|
|
|
|
fclose(file);
|
|
|
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
2003-08-18 06:11:37 +00:00
|
|
|
#endif
|
|
|
|
|
2006-02-05 14:57:48 +00:00
|
|
|
uint32 end_time, start_time = _vm->_system->getMillis();
|
2003-03-19 19:09:51 +00:00
|
|
|
_updateNeeded = true;
|
2006-02-05 14:57:48 +00:00
|
|
|
end_time = _vm->_system->getMillis();
|
|
|
|
debugC(DEBUG_SMUSH, "Smush stats: updateScreen( %03d )", end_time - start_time);
|
2003-03-17 12:28:50 +00:00
|
|
|
}
|
2002-08-24 15:31:37 +00:00
|
|
|
|
2003-12-06 05:47:24 +00:00
|
|
|
void SmushPlayer::insanity(bool flag) {
|
|
|
|
_insanity = flag;
|
|
|
|
}
|
|
|
|
|
2004-06-27 21:52:25 +00:00
|
|
|
void SmushPlayer::seekSan(const char *file, int32 pos, int32 contFrame) {
|
2005-03-09 16:37:44 +00:00
|
|
|
Common::StackLock lock(_mutex);
|
|
|
|
|
2005-06-25 15:17:14 +00:00
|
|
|
_seekFile = file ? file : "";
|
|
|
|
_seekPos = pos;
|
|
|
|
_seekFrame = contFrame;
|
2003-12-08 04:16:41 +00:00
|
|
|
}
|
|
|
|
|
2005-01-28 11:59:08 +00:00
|
|
|
void SmushPlayer::tryCmpFile(const char *filename) {
|
2005-06-11 15:46:00 +00:00
|
|
|
if (_compressedFile.isOpen()) {
|
|
|
|
_vm->_mixer->stopHandle(_compressedFileSoundHandle);
|
|
|
|
_compressedFile.close();
|
|
|
|
}
|
2004-09-18 18:09:35 +00:00
|
|
|
_compressedFileMode = false;
|
|
|
|
const char *i = strrchr(filename, '.');
|
|
|
|
if (i == NULL) {
|
|
|
|
error("invalid filename : %s", filename);
|
|
|
|
}
|
2005-08-10 12:42:56 +00:00
|
|
|
#if defined(USE_MAD) || defined(USE_VORBIS)
|
2005-06-21 22:08:21 +00:00
|
|
|
char fname[260];
|
2005-06-25 15:17:14 +00:00
|
|
|
#endif
|
|
|
|
#ifdef USE_MAD
|
2004-09-18 18:09:35 +00:00
|
|
|
memcpy(fname, filename, i - filename);
|
2005-01-28 11:59:08 +00:00
|
|
|
strcpy(fname + (i - filename), ".mp3");
|
|
|
|
_compressedFile.open(fname);
|
|
|
|
if (_compressedFile.isOpen()) {
|
|
|
|
int size = _compressedFile.size();
|
|
|
|
_compressedFileMode = true;
|
2006-04-29 22:33:31 +00:00
|
|
|
_vm->_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_compressedFileSoundHandle, Audio::makeMP3Stream(&_compressedFile, size));
|
2005-01-28 11:59:08 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
2005-08-10 12:42:56 +00:00
|
|
|
#ifdef USE_VORBIS
|
2005-01-28 11:59:08 +00:00
|
|
|
memcpy(fname, filename, i - filename);
|
|
|
|
strcpy(fname + (i - filename), ".ogg");
|
2004-09-18 18:09:35 +00:00
|
|
|
_compressedFile.open(fname);
|
|
|
|
if (_compressedFile.isOpen()) {
|
|
|
|
int size = _compressedFile.size();
|
|
|
|
_compressedFileMode = true;
|
2006-04-29 22:33:31 +00:00
|
|
|
_vm->_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_compressedFileSoundHandle, Audio::makeVorbisStream(&_compressedFile, size));
|
2005-01-28 11:59:08 +00:00
|
|
|
return;
|
2004-09-18 18:09:35 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2006-10-10 12:16:21 +00:00
|
|
|
void SmushPlayer::play(const char *filename, int32 speed, int32 offset, int32 startFrame) {
|
2006-02-05 14:57:48 +00:00
|
|
|
|
2003-06-18 13:14:17 +00:00
|
|
|
// Verify the specified file exists
|
2004-07-26 23:15:01 +00:00
|
|
|
ScummFile f;
|
|
|
|
_vm->openFile(f, filename);
|
2003-06-07 00:45:32 +00:00
|
|
|
if (!f.isOpen()) {
|
2003-06-15 00:54:14 +00:00
|
|
|
warning("SmushPlayer::play() File not found %s", filename);
|
2003-03-17 19:10:12 +00:00
|
|
|
return;
|
|
|
|
}
|
2003-06-18 13:14:17 +00:00
|
|
|
f.close();
|
2003-03-17 19:10:12 +00:00
|
|
|
|
2003-03-17 15:22:36 +00:00
|
|
|
_updateNeeded = false;
|
2005-05-07 01:52:17 +00:00
|
|
|
_warpNeeded = false;
|
|
|
|
_palDirtyMin = 256;
|
|
|
|
_palDirtyMax = -1;
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2003-09-10 23:29:33 +00:00
|
|
|
// Hide mouse
|
2006-05-25 22:51:42 +00:00
|
|
|
bool oldMouseState = CursorMan.showMouse(false);
|
2003-03-17 19:10:12 +00:00
|
|
|
|
2003-06-18 13:14:17 +00:00
|
|
|
// Load the video
|
2005-06-25 15:17:14 +00:00
|
|
|
_seekFile = filename;
|
|
|
|
_seekPos = offset;
|
|
|
|
_seekFrame = startFrame;
|
2006-02-05 14:57:48 +00:00
|
|
|
_base = 0;
|
2005-06-25 15:17:14 +00:00
|
|
|
|
2004-06-27 21:52:25 +00:00
|
|
|
setupAnim(filename);
|
2006-10-10 12:16:21 +00:00
|
|
|
init(speed);
|
2002-08-24 15:31:37 +00:00
|
|
|
|
2004-06-20 15:28:11 +00:00
|
|
|
for (;;) {
|
2006-02-05 14:57:48 +00:00
|
|
|
if (_warpNeeded) {
|
|
|
|
_vm->_system->warpMouse(_warpX, _warpY);
|
|
|
|
_warpNeeded = false;
|
|
|
|
}
|
|
|
|
_vm->parseEvents();
|
2006-10-07 17:42:32 +00:00
|
|
|
_vm->processInput();
|
2006-02-05 14:57:48 +00:00
|
|
|
if (_palDirtyMax >= _palDirtyMin) {
|
|
|
|
byte palette_colors[1024];
|
|
|
|
byte *p = palette_colors;
|
|
|
|
|
|
|
|
for (int i = _palDirtyMin; i <= _palDirtyMax; i++) {
|
|
|
|
byte *data = _pal + i * 3;
|
|
|
|
|
|
|
|
*p++ = data[0];
|
|
|
|
*p++ = data[1];
|
|
|
|
*p++ = data[2];
|
|
|
|
*p++ = 0;
|
2005-05-07 01:52:17 +00:00
|
|
|
}
|
2006-01-28 16:30:39 +00:00
|
|
|
|
2006-02-05 14:57:48 +00:00
|
|
|
_vm->_system->setPalette(palette_colors, _palDirtyMin, _palDirtyMax - _palDirtyMin + 1);
|
2006-01-27 18:04:42 +00:00
|
|
|
|
2006-02-05 14:57:48 +00:00
|
|
|
_palDirtyMax = -1;
|
|
|
|
_palDirtyMin = 256;
|
2005-05-07 01:52:17 +00:00
|
|
|
}
|
2006-01-27 18:04:42 +00:00
|
|
|
if (_updateNeeded) {
|
2006-02-22 13:26:13 +00:00
|
|
|
int w = _width, h = _height;
|
2006-02-05 14:57:48 +00:00
|
|
|
|
2006-02-22 13:26:13 +00:00
|
|
|
// Workaround for bug #1386333: "FT DEMO: assertion triggered
|
|
|
|
// when playing movie". Some frames there are 384 x 224
|
|
|
|
if (w > _vm->_screenWidth)
|
|
|
|
w = _vm->_screenWidth;
|
|
|
|
|
|
|
|
if (h > _vm->_screenHeight)
|
|
|
|
h = _vm->_screenHeight;
|
|
|
|
|
|
|
|
_vm->_system->copyRectToScreen(_dst, _width, 0, 0, w, h);
|
2004-02-28 12:58:13 +00:00
|
|
|
_vm->_system->updateScreen();
|
2003-03-19 19:09:51 +00:00
|
|
|
_updateNeeded = false;
|
2006-02-05 14:57:48 +00:00
|
|
|
#ifdef _WIN32_WCE
|
|
|
|
_inTimer = false;
|
|
|
|
_inTimerCount = 0;
|
|
|
|
#endif
|
|
|
|
}
|
2006-10-10 12:16:21 +00:00
|
|
|
if (_endOfFile)
|
|
|
|
break;
|
|
|
|
if (_vm->_quit || _vm->_saveLoadFlag || _vm->_smushVideoShouldFinish) {
|
2006-03-05 12:15:39 +00:00
|
|
|
_smixer->stop();
|
2006-10-10 12:16:21 +00:00
|
|
|
_vm->_mixer->stopHandle(_compressedFileSoundHandle);
|
|
|
|
_vm->_mixer->stopHandle(_IACTchannel);
|
2006-02-05 14:57:48 +00:00
|
|
|
break;
|
2006-03-05 12:15:39 +00:00
|
|
|
}
|
2004-09-28 20:19:37 +00:00
|
|
|
_vm->_system->delayMillis(10);
|
2005-04-12 08:51:06 +00:00
|
|
|
}
|
2003-03-17 12:28:50 +00:00
|
|
|
|
2004-04-26 09:04:08 +00:00
|
|
|
release();
|
|
|
|
|
2003-09-10 23:29:33 +00:00
|
|
|
// Reset mouse state
|
2006-05-25 22:51:42 +00:00
|
|
|
CursorMan.showMouse(oldMouseState);
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
2003-10-03 18:33:57 +00:00
|
|
|
|
|
|
|
} // End of namespace Scumm
|
2006-02-05 14:57:48 +00:00
|
|
|
|