scummvm/engines/agos/animation.cpp
2009-01-20 05:43:57 +00:00

533 lines
12 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
*
*/
#include "common/endian.h"
#include "common/events.h"
#include "common/system.h"
#include "graphics/cursorman.h"
#include "graphics/surface.h"
#include "agos/animation.h"
#include "agos/intern.h"
#include "agos/agos.h"
#include "sound/audiostream.h"
#include "sound/wave.h"
#include "gui/message.h"
namespace AGOS {
MoviePlayer::MoviePlayer(AGOSEngine *vm)
: _vm(vm) {
_mixer = _vm->_mixer;
_leftButtonDown = false;
_rightButtonDown = false;
_skipMovie = false;
memset(baseName, 0, sizeof(baseName));
_ticks = 0;
}
MoviePlayer::~MoviePlayer() {
}
void MoviePlayer::play() {
if (_vm->getBitFlag(40)) {
_vm->setBitFlag(42, false);
startSound();
return;
}
_leftButtonDown = false;
_rightButtonDown = false;
_skipMovie = false;
_vm->_mixer->stopAll();
_ticks = _vm->_system->getMillis();
startSound();
playVideo();
stopVideo();
_vm->o_killAnimate();
if (_vm->getBitFlag(41)) {
_vm->fillBackFromFront();
} else {
uint8 palette[1024];
memset(palette, 0, sizeof(palette));
_vm->clearSurfaces();
_vm->_system->setPalette(palette, 0, 256);
}
_vm->fillBackGroundFromBack();
_vm->_fastFadeOutFlag = true;
}
void MoviePlayer::handleNextFrame() {
Common::Event event;
Common::EventManager *eventMan = _vm->_system->getEventManager();
while (eventMan->pollEvent(event)) {
switch (event.type) {
case Common::EVENT_KEYDOWN:
if (event.kbd.ascii == 27) {
_leftButtonDown = true;
_rightButtonDown = true;
}
break;
case Common::EVENT_LBUTTONDOWN:
_leftButtonDown = true;
break;
case Common::EVENT_RBUTTONDOWN:
_rightButtonDown = true;
break;
case Common::EVENT_LBUTTONUP:
_leftButtonDown = false;
break;
case Common::EVENT_RBUTTONUP:
_rightButtonDown = false;
break;
default:
break;
}
}
if (_leftButtonDown && _rightButtonDown && !_vm->getBitFlag(41)) {
_skipMovie = true;
_mixer->stopHandle(_bgSound);
}
}
///////////////////////////////////////////////////////////////////////////////
// Movie player for DXA movies
///////////////////////////////////////////////////////////////////////////////
const char * MoviePlayerDXA::_sequenceList[90] = {
"agent32",
"Airlock",
"Badluck",
"bentalk1",
"bentalk2",
"bentalk3",
"BigFight",
"BLOWLAB",
"breakdown",
"bridge",
"button2",
"cargo",
"COACH",
"Colatalk",
"cygnus2",
"dream",
"escape2",
"FASALL",
"fbikewurb",
"feebdel",
"Feebohno",
"feebpump",
"feefone1",
"feefone2",
"founder2",
"founder3",
"founder4",
"fxmadsam",
"fxwakeup",
"gate",
"Get Car",
"getaxe",
"getlift",
"icetrench",
"intomb1",
"intomb2",
"Jackpot",
"knockout",
"labocto",
"longfeeb",
"Mainmin",
"maznat",
"meetsquid",
"mflirt",
"mfxHappy",
"Mix_Feeb1",
"Mix_Feeb2",
"Mix_Feeb3",
"Mix_Guardscn",
"Mlights1",
"MLights2",
"MProtest",
"mudman",
"munlock",
"MUS5P2",
"MUSOSP1",
"Omenter",
"Omnicofe",
"OUTMIN~1",
"Readbook",
"Rebelhq",
"RebelHQ2",
"Reedin",
"rescue1",
"rescue2",
"samcar",
"Samdead",
"scanner",
"Sleepy",
"spitbrai",
"statue1",
"statue2",
"sva1",
"sva2",
"Teeter",
"Temple2",
"Temple3",
"Temple4",
"Temple5",
"Temple6",
"Temple7",
"Temple8",
"Tic-tac2",
"torture",
"transmit",
"Typey",
"ventfall",
"ventoff",
"wasting",
"wurbatak"
};
MoviePlayerDXA::MoviePlayerDXA(AGOSEngine *vm, const char *name)
: MoviePlayer(vm) {
debug(0, "Creating DXA cutscene player");
memset(baseName, 0, sizeof(baseName));
memcpy(baseName, name, strlen(name));
_sequenceNum = 0;
}
bool MoviePlayerDXA::load() {
char videoName[20];
uint i;
if ((_vm->getPlatform() == Common::kPlatformAmiga || _vm->getPlatform() == Common::kPlatformMacintosh) &&
_vm->_language != Common::EN_ANY) {
_sequenceNum = 0;
for (i = 0; i < 90; i++) {
if (!scumm_stricmp(baseName, _sequenceList[i]))
_sequenceNum = i;
}
}
sprintf(videoName, "%s.dxa", baseName);
if (!loadFile(videoName))
error("Failed to load video file %s", videoName);
debug(0, "Playing video %s", videoName);
CursorMan.showMouse(false);
return true;
}
void MoviePlayerDXA::playVideo() {
while (getCurFrame() < getFrameCount() && !_skipMovie && !_vm->shouldQuit())
handleNextFrame();
}
void MoviePlayerDXA::stopVideo() {
closeFile();
_mixer->stopHandle(_bgSound);
}
void MoviePlayerDXA::startSound() {
byte *buffer;
uint32 offset, size, tag;
tag = _fileStream->readUint32BE();
if (tag == MKID_BE('WAVE')) {
size = _fileStream->readUint32BE();
if (_sequenceNum) {
Common::File in;
_fileStream->seek(size, SEEK_CUR);
in.open((const char *)"audio.wav");
if (!in.isOpen()) {
error("Can't read offset file 'audio.wav'");
}
in.seek(_sequenceNum * 8, SEEK_SET);
offset = in.readUint32LE();
size = in.readUint32LE();
buffer = (byte *)malloc(size);
in.seek(offset, SEEK_SET);
in.read(buffer, size);
in.close();
} else {
buffer = (byte *)malloc(size);
_fileStream->read(buffer, size);
}
Common::MemoryReadStream stream(buffer, size);
_bgSoundStream = Audio::makeWAVStream(stream);
free(buffer);
} else {
_bgSoundStream = Audio::AudioStream::openStreamFile(baseName);
}
if (_bgSoundStream != NULL) {
_vm->_mixer->stopHandle(_bgSound);
_vm->_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_bgSound, _bgSoundStream);
}
}
void MoviePlayerDXA::nextFrame() {
if (_vm->_mixer->isSoundHandleActive(_bgSound) && (_vm->_mixer->getSoundElapsedTime(_bgSound) * getFrameRate()) / 1000 < (uint32)getCurFrame()) {
copyFrameToBuffer(_vm->getBackBuf(), 465, 222, _vm->_screenWidth);
return;
}
if (getCurFrame() < getFrameCount()) {
decodeNextFrame();
copyFrameToBuffer(_vm->getBackBuf(), 465, 222, _vm->_screenWidth);
} else {
closeFile();
_vm->_variableArray[254] = 6747;
}
}
void MoviePlayerDXA::handleNextFrame() {
decodeNextFrame();
if (processFrame())
_vm->_system->updateScreen();
MoviePlayer::handleNextFrame();
}
void MoviePlayerDXA::setPalette(byte *pal) {
byte palette[1024];
byte *p = palette;
for (int i = 0; i < 256; i++) {
*p++ = *pal++;
*p++ = *pal++;
*p++ = *pal++;
*p++ = 0;
}
_vm->_system->setPalette(palette, 0, 256);
}
bool MoviePlayerDXA::processFrame() {
Graphics::Surface *screen = _vm->_system->lockScreen();
copyFrameToBuffer((byte *)screen->pixels, (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, _vm->_screenWidth);
_vm->_system->unlockScreen();
if ((_bgSoundStream == NULL) || ((int)(_mixer->getSoundElapsedTime(_bgSound) * getFrameRate()) / 1000 < getCurFrame() + 1) ||
_frameSkipped > getFrameRate()) {
if (_frameSkipped > getFrameRate()) {
warning("force frame %i redraw", getCurFrame());
_frameSkipped = 0;
}
if (_bgSoundStream && _mixer->isSoundHandleActive(_bgSound)) {
while (_mixer->isSoundHandleActive(_bgSound) && (_mixer->getSoundElapsedTime(_bgSound) * getFrameRate()) / 1000 < (uint32)getCurFrame()) {
_vm->_system->delayMillis(10);
}
// In case the background sound ends prematurely, update
// _ticks so that we can still fall back on the no-sound
// sync case for the subsequent frames.
_ticks = _vm->_system->getMillis();
} else {
_ticks += getFrameDelay();
while (_vm->_system->getMillis() < _ticks)
_vm->_system->delayMillis(10);
}
return true;
}
warning("dropped frame %i", getCurFrame());
_frameSkipped++;
return false;
}
///////////////////////////////////////////////////////////////////////////////
// Movie player for Smacker movies
///////////////////////////////////////////////////////////////////////////////
MoviePlayerSMK::MoviePlayerSMK(AGOSEngine *vm, const char *name)
: MoviePlayer(vm), SMKPlayer(vm->_mixer) {
debug(0, "Creating SMK cutscene player");
memset(baseName, 0, sizeof(baseName));
memcpy(baseName, name, strlen(name));
}
bool MoviePlayerSMK::load() {
char videoName[20];
sprintf(videoName, "%s.smk", baseName);
if (!loadFile(videoName))
error("Failed to load video file %s", videoName);
debug(0, "Playing video %s", videoName);
CursorMan.showMouse(false);
return true;
}
void MoviePlayerSMK::playVideo() {
while (getCurFrame() < getFrameCount() && !_skipMovie && !_vm->shouldQuit())
handleNextFrame();
}
void MoviePlayerSMK::stopVideo() {
closeFile();
}
void MoviePlayerSMK::startSound() {
}
void MoviePlayerSMK::handleNextFrame() {
decodeNextFrame();
processFrame();
MoviePlayer::handleNextFrame();
}
void MoviePlayerSMK::nextFrame() {
if (_vm->getBitFlag(42)) {
closeFile();
return;
}
if (getCurFrame() < getFrameCount()) {
decodeNextFrame();
copyFrameToBuffer(_vm->getBackBuf(), 465, 222, _vm->_screenWidth);
} else {
closeFile();
_vm->_variableArray[254] = 6747;
}
}
void MoviePlayerSMK::setPalette(byte *pal) {
byte palette[1024];
byte *p = palette;
for (int i = 0; i < 256; i++) {
*p++ = *pal++;
*p++ = *pal++;
*p++ = *pal++;
*p++ = 0;
}
_vm->_system->setPalette(palette, 0, 256);
}
bool MoviePlayerSMK::processFrame() {
Graphics::Surface *screen = _vm->_system->lockScreen();
copyFrameToBuffer((byte *)screen->pixels, (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, _vm->_screenWidth);
_vm->_system->unlockScreen();
uint32 waitTime = getFrameWaitTime();
if (!waitTime) {
warning("dropped frame %i", getCurFrame());
return false;
}
_vm->_system->updateScreen();
// Wait before showing the next frame
_vm->_system->delayMillis(waitTime);
return true;
}
///////////////////////////////////////////////////////////////////////////////
// Factory function for creating the appropriate cutscene player
///////////////////////////////////////////////////////////////////////////////
MoviePlayer *makeMoviePlayer(AGOSEngine *vm, const char *name) {
char baseName[40];
char filename[20];
int baseLen = strlen(name) - 4;
memset(baseName, 0, sizeof(baseName));
memcpy(baseName, name, baseLen);
if (vm->getLanguage() == Common::DE_DEU && baseLen >= 8) {
// Check short filename to work around
// bug in a German Windows 2CD version.
char shortName[20];
memset(shortName, 0, sizeof(shortName));
memcpy(shortName, baseName, 6);
sprintf(filename, "%s~1.dxa", shortName);
if (Common::File::exists(filename)) {
memset(baseName, 0, sizeof(baseName));
memcpy(baseName, filename, 8);
}
sprintf(filename, "%s~1.smk", shortName);
if (Common::File::exists(filename)) {
memset(baseName, 0, sizeof(baseName));
memcpy(baseName, filename, 8);
}
}
sprintf(filename, "%s.dxa", baseName);
if (Common::File::exists(filename)) {
return new MoviePlayerDXA(vm, baseName);
}
sprintf(filename, "%s.smk", baseName);
if (Common::File::exists(filename)) {
return new MoviePlayerSMK(vm, baseName);
}
char buf[60];
sprintf(buf, "Cutscene file '%s' not found!", baseName);
GUI::MessageDialog dialog(buf, "OK");
dialog.runModal();
return NULL;
}
} // End of namespace AGOS