aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/sword2/animation.cpp714
-rw-r--r--engines/sword2/animation.h162
-rw-r--r--engines/sword2/function.cpp11
-rw-r--r--engines/sword2/logic.h2
-rw-r--r--engines/sword2/sound.cpp9
-rw-r--r--engines/sword2/sound.h1
6 files changed, 249 insertions, 650 deletions
diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp
index a6925e9ade..c35be49865 100644
--- a/engines/sword2/animation.cpp
+++ b/engines/sword2/animation.cpp
@@ -25,20 +25,14 @@
* $Id$
*/
-
-#include "common/config-manager.h"
#include "common/file.h"
-#include "common/events.h"
#include "common/system.h"
#include "sword2/sword2.h"
#include "sword2/defs.h"
#include "sword2/header.h"
-#include "sword2/logic.h"
#include "sword2/maketext.h"
-#include "sword2/mouse.h"
#include "sword2/resman.h"
-#include "sword2/screen.h"
#include "sword2/sound.h"
#include "sword2/animation.h"
@@ -50,7 +44,7 @@ namespace Sword2 {
// Basic movie player
///////////////////////////////////////////////////////////////////////////////
-const MovieInfo MoviePlayer::_movies[19] = {
+static const MovieInfo sequenceList[19] = {
{ "carib", 222, false },
{ "escape", 187, false },
{ "eye", 248, false },
@@ -72,645 +66,299 @@ const MovieInfo MoviePlayer::_movies[19] = {
{ "enddemo", 110, false }
};
-MoviePlayer::MoviePlayer(Sword2Engine *vm, const char *name) {
- _vm = vm;
- _name = strdup(name);
- _mixer = _vm->_mixer;
- _system = _vm->_system;
- _pauseTicks = 0;
- _textSurface = NULL;
+MoviePlayer::MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Graphics::VideoDecoder *decoder, DecoderType decoderType)
+ : _vm(vm), _snd(snd), _bgSoundHandle(bgSoundHandle), _system(system), VideoPlayer(decoder) {
_bgSoundStream = NULL;
- _ticks = 0;
- _currentFrame = 0;
- _frameBuffer = NULL;
- _frameWidth = 0;
- _frameHeight = 0;
- _frameX = 0;
- _frameY = 0;
- _black = 1;
- _white = 255;
- _numFrames = 0;
- _leadOutFrame = (uint)-1;
- _seamless = false;
- _framesSkipped = 0;
- _currentText = 0;
-}
-
-MoviePlayer::~MoviePlayer() {
- free(_name);
+ _decoderType = decoderType;
}
-uint32 MoviePlayer::getTick() {
- return _system->getMillis() - _pauseTicks;
+MoviePlayer:: ~MoviePlayer(void) {
+ delete _bgSoundHandle;
+ delete _decoder;
}
-void MoviePlayer::savePalette() {
- memcpy(_originalPalette, _vm->_screen->getPalette(), sizeof(_originalPalette));
-}
+/**
+ * Plays an animated cutscene.
+ * @param id the id of the file
+ */
+bool MoviePlayer::load(const char *name) {
+ _id = -1;
-void MoviePlayer::restorePalette() {
- _vm->_screen->setPalette(0, 256, _originalPalette, RDPAL_INSTANT);
-}
+ for (int i = 0; i < ARRAYSIZE(sequenceList); i++) {
+ if (scumm_stricmp(name, sequenceList[i].name) == 0) {
+ _id = i;
+ break;
+ }
+ }
-void MoviePlayer::clearFrame() {
- memset(_frameBuffer, 0, _vm->_screen->getScreenWide() * _vm->_screen->getScreenDeep());
-}
+ if (_decoderType == kVideoDecoderDXA) {
+ _bgSoundStream = Audio::AudioStream::openStreamFile(name);
+ } else {
+ _bgSoundStream = NULL;
+ }
-void MoviePlayer::updateScreen() {
- _system->updateScreen();
-}
+ _textSurface = NULL;
-bool MoviePlayer::checkSkipFrame() {
- if (_framesSkipped > 10) {
- warning("Forced frame %d to be displayed", _currentFrame);
- _framesSkipped = 0;
- return false;
+ char filename[20];
+ switch (_decoderType) {
+ case kVideoDecoderDXA:
+ snprintf(filename, sizeof(filename), "%s.dxa", name);
+ break;
+ case kVideoDecoderSMK:
+ snprintf(filename, sizeof(filename), "%s.smk", name);
+ break;
}
- if (_bgSoundStream) {
- if ((_mixer->getSoundElapsedTime(_bgSoundHandle) * 12) / 1000 < _currentFrame + 1)
+ if (_decoder->loadFile(filename)) {
+ // The DXA animations in the Broken Sword games always use external audio tracks,
+ // if they have any sound at all.
+ if (_decoderType == kVideoDecoderDXA && _decoder->readSoundHeader() != MKID_BE('NULL'))
return false;
} else {
- if (getTick() <= _ticks)
- return false;
+ return false;
}
- _framesSkipped++;
return true;
}
-bool MoviePlayer::syncFrame() {
- _ticks += 83;
+void MoviePlayer::play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadIn, uint32 leadOut) {
+ // This happens when quitting during the "eye" cutscene.
+ if (_vm->shouldQuit())
+ return;
+
+ bool seamless = false;
- if (checkSkipFrame()) {
- warning("Skipped frame %d", _currentFrame);
- return false;
+ if (_id >= 0) {
+ seamless = sequenceList[_id].seamless;
+ _numFrames = sequenceList[_id].frames;
+ if (_numFrames > 60)
+ _leadOutFrame = _numFrames - 60;
}
- if (_bgSoundStream) {
- while (_mixer->isSoundHandleActive(_bgSoundHandle) && (_mixer->getSoundElapsedTime(_bgSoundHandle) * 12) / 1000 < _currentFrame) {
- _system->delayMillis(10);
- }
+ _movieTexts = movieTexts;
+ _numMovieTexts = numMovieTexts;
+ _currentMovieText = 0;
+ _leadOut = leadOut;
- // 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.
+ if (leadIn) {
+ _vm->_sound->playMovieSound(leadIn, kLeadInSound);
+ }
- _ticks = getTick();
- } else {
- while (getTick() < _ticks) {
- _system->delayMillis(10);
- }
+ if (_bgSoundStream) {
+ _snd->playInputStream(Audio::Mixer::kSFXSoundType, _bgSoundHandle, _bgSoundStream);
}
- return true;
-}
+ bool terminated = false;
+
+ Common::List<Common::Event> stopEvents;
+ Common::Event stopEvent;
+ stopEvents.clear();
+ stopEvent.type = Common::EVENT_KEYDOWN;
+ stopEvent.kbd = Common::KEYCODE_ESCAPE;
+ stopEvents.push_back(stopEvent);
+
+ terminated = !playVideo(&stopEvents);
-void MoviePlayer::drawFrame() {
- int screenWidth = _vm->_screen->getScreenWide();
+ closeTextObject(_currentMovieText);
- _system->copyRectToScreen(_frameBuffer + _frameY * screenWidth + _frameX, screenWidth, _frameX, _frameY, _frameWidth, _frameHeight);
+ if (terminated) {
+ _snd->stopHandle(*_bgSoundHandle);
+ _vm->_sound->stopMovieSounds();
+ _vm->_sound->stopSpeech();
+ }
+
+ while (_snd->isSoundHandleActive(*_bgSoundHandle))
+ _system->delayMillis(100);
}
-void MoviePlayer::openTextObject(SequenceTextInfo *t) {
+void MoviePlayer::openTextObject(uint32 index) {
+ MovieText *text = &_movieTexts[index];
+
// Pull out the text line to get the official text number (for WAV id)
- uint32 res = t->textNumber / SIZE;
- uint32 localText = t->textNumber & 0xffff;
+ uint32 res = text->_textNumber / SIZE;
+ uint32 localText = text->_textNumber & 0xffff;
// Open text resource and get the line
- byte *text = _vm->fetchTextLine(_vm->_resman->openResource(res), localText);
+ byte *textData = _vm->fetchTextLine(_vm->_resman->openResource(res), localText);
- _textObject.speechId = READ_LE_UINT16(text);
+ text->_speechId = READ_LE_UINT16(textData);
// Is it speech or subtitles, or both?
// If we want subtitles, or there was no sound
- if (_vm->getSubtitles() || !_textObject.speechId) {
- _textObject.textMem = _vm->_fontRenderer->makeTextSprite(text + 2, 600, 255, _vm->_speechFontId, 1);
+ if (_vm->getSubtitles() || !text->_speechId) {
+ text->_textMem = _vm->_fontRenderer->makeTextSprite(textData + 2, 600, 255, _vm->_speechFontId, 1);
}
_vm->_resman->closeResource(res);
- if (_textObject.textMem) {
+ if (text->_textMem) {
FrameHeader frame;
- frame.read(_textObject.textMem);
+ frame.read(text->_textMem);
- _textObject.textSprite.x = 320 - frame.width / 2;
- _textObject.textSprite.y = 440 - frame.height;
- _textObject.textSprite.w = frame.width;
- _textObject.textSprite.h = frame.height;
- _textObject.textSprite.type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION;
- _textObject.textSprite.data = _textObject.textMem + FrameHeader::size();
- _vm->_screen->createSurface(&_textObject.textSprite, &_textSurface);
+ text->_textSprite.x = 320 - frame.width / 2;
+ text->_textSprite.y = 440 - frame.height;
+ text->_textSprite.w = frame.width;
+ text->_textSprite.h = frame.height;
+ text->_textSprite.type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION;
+ text->_textSprite.data = text->_textMem + FrameHeader::size();
+ _vm->_screen->createSurface(&text->_textSprite, &_textSurface);
+
+ _textX = 320 - text->_textSprite.w / 2;
+ _textY = 420 - text->_textSprite.h;
}
}
-void MoviePlayer::closeTextObject() {
- free(_textObject.textMem);
- _textObject.textMem = NULL;
+void MoviePlayer::closeTextObject(uint32 index) {
+ if (index < _numMovieTexts) {
+ MovieText *text = &_movieTexts[index];
- _textObject.speechId = 0;
+ free(text->_textMem);
+ text->_textMem = NULL;
- if (_textSurface) {
- _vm->_screen->deleteSurface(_textSurface);
- _textSurface = NULL;
+ if (_textSurface) {
+ _vm->_screen->deleteSurface(_textSurface);
+ _textSurface = NULL;
+ }
}
}
-void MoviePlayer::calcTextPosition(int &xPos, int &yPos) {
- xPos = 320 - _textObject.textSprite.w / 2;
- yPos = 420 - _textObject.textSprite.h;
-}
+void MoviePlayer::drawTextObject(uint32 index, byte *screen) {
+ MovieText *text = &_movieTexts[index];
-void MoviePlayer::drawTextObject() {
- if (_textObject.textMem && _textSurface) {
- int screenWidth = _vm->_screen->getScreenWide();
- byte *src = _textObject.textSprite.data;
- uint16 width = _textObject.textSprite.w;
- uint16 height = _textObject.textSprite.h;
- int xPos, yPos;
+ byte white = _decoder->getWhite();
+ byte black = _decoder->getBlack();
- calcTextPosition(xPos, yPos);
+ if (text->_textMem && _textSurface) {
+ byte *src = text->_textSprite.data;
+ uint16 width = text->_textSprite.w;
+ uint16 height = text->_textSprite.h;
- byte *dst = _frameBuffer + yPos * screenWidth + xPos;
+ byte *dst = screen + _textY * _decoder->getWidth() + _textX;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if (src[x] == 1)
- dst[x] = _black;
+ dst[x] = black;
else if (src[x] == 255)
- dst[x] = _white;
+ dst[x] = white;
}
src += width;
- dst += screenWidth;
- }
-
- if (yPos + height > _frameY + _frameHeight || width > _frameWidth) {
- _system->copyRectToScreen(_frameBuffer + yPos * screenWidth + xPos, screenWidth, xPos, yPos, width, height);
- }
- }
-}
-
-void MoviePlayer::undrawTextObject() {
- if (_textObject.textMem) {
- int xPos, yPos;
-
- calcTextPosition(xPos, yPos);
- uint16 width = _textObject.textSprite.w;
- uint16 height = _textObject.textSprite.h;
-
- // We only need to undraw the text if it's outside the frame.
- // Otherwise the next frame will cover the old text anyway.
-
- if (yPos + height > _frameY + _frameHeight || width > _frameWidth) {
- int screenWidth = _vm->_screen->getScreenWide();
- byte *dst = _frameBuffer + yPos * screenWidth + xPos;
-
- for (int y = 0; y < height; y++) {
- memset(dst, 0, width);
- dst += screenWidth;
- }
-
- _system->copyRectToScreen(_frameBuffer + yPos * screenWidth + xPos, screenWidth, xPos, yPos, width, height);
- }
- }
-}
-
-bool MoviePlayer::load() {
- _bgSoundStream = NULL;
- _currentText = 0;
- _currentFrame = 0;
-
- for (int i = 0; i < ARRAYSIZE(_movies); i++) {
- if (scumm_stricmp(_name, _movies[i].name) == 0) {
- _seamless = _movies[i].seamless;
- _numFrames = _movies[i].frames;
- if (_numFrames > 60)
- _leadOutFrame = _numFrames - 60;
-
- // Not all cutscenes cover the entire screen, so clear
- // it. We will always clear the game screen, no matter
- // how the cutscene is to be displayed. (We have to do
- // this before showing the overlay.)
-
- _vm->_mouse->closeMenuImmediately();
-
- if (!_seamless) {
- _vm->_screen->clearScene();
- }
-
- _vm->_screen->updateDisplay();
- return true;
+ dst += _decoder->getWidth();
}
}
-
- return false;
}
-bool MoviePlayer::userInterrupt() {
- Common::Event event;
- bool terminate = false;
-
- Common::EventManager *eventMan = _system->getEventManager();
- while (eventMan->pollEvent(event)) {
- switch (event.type) {
- case Common::EVENT_SCREEN_CHANGED:
- handleScreenChanged();
- break;
- case Common::EVENT_RTL:
- case Common::EVENT_QUIT:
- terminate = true;
- break;
- case Common::EVENT_KEYDOWN:
- if (event.kbd.keycode == Common::KEYCODE_ESCAPE)
- terminate = true;
- break;
- default:
- break;
- }
- }
-
- return terminate;
-}
-
-void MoviePlayer::play(SequenceTextInfo *textList, uint32 numLines, int32 leadIn, int32 leadOut) {
- bool terminate = false;
- bool textVisible = false;
- bool startNextText = false;
-
- // This happens if the user quits during the "eye" cutscene.
- if (_vm->shouldQuit())
- return;
-
- _numSpeechLines = numLines;
- _firstSpeechFrame = (numLines > 0) ? textList[0].startFrame : 0;
-
- if (leadIn) {
- _vm->_sound->playMovieSound(leadIn, kLeadInSound);
- }
-
- savePalette();
+// FIXME: This assumes that the subtitles always fit within the frame of the
+// movie. In Broken Sword 2, that's a fairly safe assumption, but not
+// necessarily in all other games.
- _framesSkipped = 0;
- _ticks = getTick();
- _bgSoundStream = Audio::AudioStream::openStreamFile(_name);
+void MoviePlayer::performPostProcessing(byte *screen) {
+ MovieText *text;
+ int frame = _decoder->getCurFrame();
- if (_bgSoundStream) {
- _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_bgSoundHandle, _bgSoundStream);
- }
-
- while (!terminate && _currentFrame < _numFrames && decodeFrame()) {
- _currentFrame++;
-
- // The frame has been decoded. Now draw the subtitles, if any,
- // before drawing it to the screen.
-
- if (_currentText < numLines) {
- SequenceTextInfo *t = &textList[_currentText];
-
- if (_currentFrame == t->startFrame) {
- openTextObject(t);
- textVisible = true;
-
- if (_textObject.speechId) {
- startNextText = true;
- }
- }
-
- if (startNextText && _vm->_sound->amISpeaking() == RDSE_QUIET) {
- _vm->_sound->playCompSpeech(_textObject.speechId, 16, 0);
- startNextText = false;
- }
-
- if (_currentFrame == t->endFrame) {
- undrawTextObject();
- closeTextObject();
- _currentText++;
- textVisible = false;
- }
-
- if (textVisible)
- drawTextObject();
- }
-
- if (leadOut && _currentFrame == _leadOutFrame) {
- _vm->_sound->playMovieSound(leadOut, kLeadOutSound);
- }
-
- if (syncFrame()) {
- drawFrame();
- updateScreen();
- }
-
- if (userInterrupt()) {
- terminate = true;
- }
+ if (_currentMovieText < _numMovieTexts) {
+ text = &_movieTexts[_currentMovieText];
+ } else {
+ text = NULL;
}
- if (!_seamless) {
- // Most cutscenes fade to black on their own, but not all of
- // them. I think it looks better if they do.
-
- clearFrame();
-
- // If the sound is still playing, draw the subtitles one final
- // time. This happens in the "carib" cutscene.
-
- if (textVisible && _vm->_sound->amISpeaking() == RDSE_SPEAKING) {
- drawTextObject();
+ if (text && frame == text->_startFrame) {
+ if ((_vm->getSubtitles() || !text->_speechId) && _currentMovieText < _numMovieTexts) {
+ openTextObject(_currentMovieText);
}
-
- drawFrame();
- updateScreen();
}
- if (!terminate) {
- // Wait for the voice and sound track to stop playing. This is
- // to make sure that we don't cut off the speech in
- // mid-sentence, and - even more importantly - that we don't
- // free the sound buffer while it's still in use.
-
- while (_vm->_sound->amISpeaking() == RDSE_SPEAKING || _mixer->isSoundHandleActive(_bgSoundHandle)) {
- if (userInterrupt()) {
- terminate = true;
- _vm->_sound->stopSpeech();
- _mixer->stopHandle(_bgSoundHandle);
- }
- _system->delayMillis(100);
+ if (text && frame >= text->_startFrame) {
+ if (text->_speechId && !text->_played && _vm->_sound->amISpeaking() == RDSE_QUIET) {
+ text->_played = true;
+ _vm->_sound->playCompSpeech(text->_speechId, 16, 0);
}
- } else {
- _vm->_sound->stopSpeech();
- _mixer->stopHandle(_bgSoundHandle);
- }
-
- // The current text object may still be open
- undrawTextObject();
- closeTextObject();
-
- if (!_seamless) {
- clearFrame();
- drawFrame();
- updateScreen();
- }
-
- // Setting the palette implies a full redraw.
- restorePalette();
-}
-
-void MoviePlayer::pauseMovie(bool pause) {
- _mixer->pauseHandle(_bgSoundHandle, pause);
-
- if (pause) {
- _pauseStartTick = _system->getMillis();
- } else {
- _pauseTicks += (_system->getMillis() - _pauseStartTick);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Movie player for the original SMK movies
-///////////////////////////////////////////////////////////////////////////////
-
-MoviePlayerSMK::MoviePlayerSMK(Sword2Engine *vm, const char *name)
- : MoviePlayer(vm, name), SMKPlayer(vm->_mixer) {
- debug(0, "Creating SMK cutscene player");
-}
-
-MoviePlayerSMK::~MoviePlayerSMK() {
- closeFile();
-}
-
-bool MoviePlayerSMK::decodeFrame() {
- decodeNextFrame();
- copyFrameToBuffer(_frameBuffer, _frameX, _frameY, _vm->_screen->getScreenWide());
- return true;
-}
-
-bool MoviePlayerSMK::load() {
- if (!MoviePlayer::load())
- return false;
-
- char filename[20];
-
- snprintf(filename, sizeof(filename), "%s.smk", _name);
-
- if (loadFile(filename)) {
- _frameBuffer = _vm->_screen->getScreen();
-
- _frameWidth = getWidth();
- _frameHeight = getHeight();
-
- _frameX = (_vm->_screen->getScreenWide() - _frameWidth) / 2;
- _frameY = (_vm->_screen->getScreenDeep() - _frameHeight) / 2;
-
- return true;
- }
-
- return false;
-}
-
-#ifdef USE_ZLIB
-
-///////////////////////////////////////////////////////////////////////////////
-// Movie player for the new DXA movies
-///////////////////////////////////////////////////////////////////////////////
-
-MoviePlayerDXA::MoviePlayerDXA(Sword2Engine *vm, const char *name)
- : MoviePlayer(vm, name) {
- debug(0, "Creating DXA cutscene player");
-}
-
-MoviePlayerDXA::~MoviePlayerDXA() {
- closeFile();
-}
-
-bool MoviePlayerDXA::decodeFrame() {
- decodeNextFrame();
- copyFrameToBuffer(_frameBuffer, _frameX, _frameY, _vm->_screen->getScreenWide());
- return true;
-}
-
-bool MoviePlayerDXA::load() {
- if (!MoviePlayer::load())
- return false;
-
- char filename[20];
-
- snprintf(filename, sizeof(filename), "%s.dxa", _name);
-
- if (loadFile(filename)) {
- // The Broken Sword games always use external audio tracks.
- if (_fileStream->readUint32BE() != MKID_BE('NULL'))
- return false;
-
- _frameBuffer = _vm->_screen->getScreen();
-
- _frameWidth = getWidth();
- _frameHeight = getHeight();
-
- _frameX = (_vm->_screen->getScreenWide() - _frameWidth) / 2;
- _frameY = (_vm->_screen->getScreenDeep() - _frameHeight) / 2;
-
- return true;
- }
-
- return false;
-}
-
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-// Dummy player for subtitled speech only
-///////////////////////////////////////////////////////////////////////////////
-
-MoviePlayerDummy::MoviePlayerDummy(Sword2Engine *vm, const char *name)
- : MoviePlayer(vm, name) {
- debug(0, "Creating Dummy cutscene player");
-}
-
-MoviePlayerDummy::~MoviePlayerDummy() {
-}
-
-bool MoviePlayerDummy::load() {
- if (!MoviePlayer::load())
- return false;
-
- _frameBuffer = _vm->_screen->getScreen();
-
- _frameWidth = 640;
- _frameHeight = 400;
- _frameX = 0;
- _frameY = 40;
-
- return true;
-}
-
-bool MoviePlayerDummy::decodeFrame() {
- if ((_currentFrame == 0 && _numSpeechLines > 0) || _mixer->isSoundHandleActive(_bgSoundHandle)) {
- byte dummyPalette[] = {
- 0, 0, 0, 0,
- 255, 255, 255, 0,
- };
-
- // 0 is always black
- // 1 is the border colour - black
- // 255 is the pen colour - white
-
- _system->setPalette(dummyPalette, 0, 1);
- _system->setPalette(dummyPalette, 1, 1);
- _system->setPalette(dummyPalette + 4, 255, 1);
-
- byte msgNoCutscenesRU[] = "Po\344uk - to\344\345ko pev\345: hagmute k\344abuwy Ucke\343n, u\344u nocetute ca\343t npoekta u ckava\343te budeo po\344uku";
-
-#if defined(USE_ZLIB)
- byte msgNoCutscenes[] = "Cutscene - Narration Only: Press ESC to exit, or visit www.scummvm.org to download cutscene videos";
-#else
- byte msgNoCutscenes[] = "Cutscene - Narration Only: Press ESC to exit, or recompile ScummVM with ZLib support";
-#endif
-
- byte *msg;
-
- // Russian version substituted latin characters with Cyrillic.
- if (Common::parseLanguage(ConfMan.get("language")) == Common::RU_RUS) {
- msg = msgNoCutscenesRU;
+ if (frame <= text->_endFrame) {
+ drawTextObject(_currentMovieText, screen);
} else {
- msg = msgNoCutscenes;
+ _currentMovieText++;
}
-
- byte *data = _vm->_fontRenderer->makeTextSprite(msg, RENDERWIDE, 255, _vm->_speechFontId);
-
- FrameHeader frame_head;
- SpriteInfo msgSprite;
- byte *msgSurface;
-
- frame_head.read(data);
-
- msgSprite.x = _vm->_screen->getScreenWide() / 2 - frame_head.width / 2;
- msgSprite.y = (480 - frame_head.height) / 2;
- msgSprite.w = frame_head.width;
- msgSprite.h = frame_head.height;
- msgSprite.type = RDSPR_NOCOMPRESSION;
- msgSprite.data = data + FrameHeader::size();
-
- _vm->_screen->createSurface(&msgSprite, &msgSurface);
- _vm->_screen->drawSurface(&msgSprite, msgSurface);
- _vm->_screen->deleteSurface(msgSurface);
-
- free(data);
- updateScreen();
}
- // If we have played the final voice-over, skip ahead to the lead out
-
- if (!_mixer->isSoundHandleActive(_bgSoundHandle) &&
- _currentText >= _numSpeechLines &&
- _vm->_sound->amISpeaking() == RDSE_QUIET &&
- _leadOutFrame != (uint)-1 &&
- _currentFrame < _leadOutFrame) {
- _currentFrame = _leadOutFrame - 1;
+ if (_leadOut && _decoder->getCurFrame() == _leadOutFrame) {
+ _vm->_sound->playMovieSound(_leadOut, kLeadOutSound);
}
+}
- return true;
+DXAPlayerWithSound::DXAPlayerWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
+ : _mixer(mixer), _bgSoundHandle(bgSoundHandle) {
}
-bool MoviePlayerDummy::syncFrame() {
- if ((_numSpeechLines == 0 || _currentFrame < _firstSpeechFrame) && !_mixer->isSoundHandleActive(_bgSoundHandle)) {
- _ticks = getTick();
- return false;
- }
+int32 DXAPlayerWithSound::getAudioLag() {
+ if (!_fileStream)
+ return 0;
- return MoviePlayer::syncFrame();
-}
+ if (!_mixer->isSoundHandleActive(*_bgSoundHandle))
+ return 0;
-void MoviePlayerDummy::drawFrame() {
-}
+ int32 frameDelay = getFrameDelay();
+ int32 videoTime = _videoInfo.currentFrame * frameDelay;
+ int32 audioTime;
-void MoviePlayerDummy::drawTextObject() {
- if (_textObject.textMem && _textSurface) {
- _vm->_screen->drawSurface(&_textObject.textSprite, _textSurface);
- }
-}
+ audioTime = (((int32) _mixer->getSoundElapsedTime(*_bgSoundHandle)) * 100);
-void MoviePlayerDummy::undrawTextObject() {
- if (_textObject.textMem && _textSurface) {
- memset(_textSurface, 1, _textObject.textSprite.w * _textObject.textSprite.h);
- drawTextObject();
- }
+ return videoTime - audioTime;
}
///////////////////////////////////////////////////////////////////////////////
// Factory function for creating the appropriate cutscene player
///////////////////////////////////////////////////////////////////////////////
-MoviePlayer *makeMoviePlayer(Sword2Engine *vm, const char *name) {
- static char filename[20];
+MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *snd, OSystem *system) {
+ char filename[20];
+ char buf[60];
+ Audio::SoundHandle *bgSoundHandle = new Audio::SoundHandle;
snprintf(filename, sizeof(filename), "%s.smk", name);
if (Common::File::exists(filename)) {
- return new MoviePlayerSMK(vm, name);
+ Graphics::SMKPlayer *smkDecoder = new Graphics::SMKPlayer(snd);
+ return new MoviePlayer(vm, snd, system, bgSoundHandle, smkDecoder, kVideoDecoderSMK);
}
-#ifdef USE_ZLIB
snprintf(filename, sizeof(filename), "%s.dxa", name);
if (Common::File::exists(filename)) {
- return new MoviePlayerDXA(vm, name);
- }
+#ifdef USE_ZLIB
+ DXAPlayerWithSound *dxaDecoder = new DXAPlayerWithSound(snd, bgSoundHandle);
+ return new MoviePlayer(vm, snd, system, bgSoundHandle, dxaDecoder, kVideoDecoderDXA);
+#else
+ GUI::MessageDialog dialog("DXA cutscenes found but ScummVM has been built without zlib support", "OK");
+ dialog.runModal();
+ return NULL;
#endif
+ }
+ // Old MPEG2 cutscenes
snprintf(filename, sizeof(filename), "%s.mp2", name);
if (Common::File::exists(filename)) {
GUI::MessageDialog dialog("MPEG2 cutscenes are no longer supported", "OK");
dialog.runModal();
+ return NULL;
}
- return new MoviePlayerDummy(vm, name);
+ sprintf(buf, "Cutscene '%s' not found", name);
+ GUI::MessageDialog dialog(buf, "OK");
+ dialog.runModal();
+
+ return NULL;
+}
+
+void MoviePlayer::pauseMovie(bool pause) {
+ if (_bgSoundHandle) {
+ _snd->pauseHandle(*_bgSoundHandle, pause);
+ }
}
} // End of namespace Sword2
diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h
index 8b6a015037..dde1b75a8c 100644
--- a/engines/sword2/animation.h
+++ b/engines/sword2/animation.h
@@ -30,147 +30,87 @@
#include "graphics/video/dxa_player.h"
#include "graphics/video/smk_player.h"
+#include "graphics/video/video_player.h"
#include "sound/mixer.h"
#include "sword2/screen.h"
namespace Sword2 {
-struct SequenceTextInfo {
- uint32 textNumber;
- uint16 startFrame;
- uint16 endFrame;
+enum DecoderType {
+ kVideoDecoderDXA = 0,
+ kVideoDecoderSMK = 1
};
-struct MovieTextObject {
- byte *textMem;
- SpriteInfo textSprite;
- uint16 speechId;
-
- MovieTextObject() {
- textMem = NULL;
- speechId = 0;
+struct MovieText {
+ uint16 _startFrame;
+ uint16 _endFrame;
+ uint32 _textNumber;
+ byte *_textMem;
+ SpriteInfo _textSprite;
+ uint16 _speechId;
+ bool _played;
+
+ void reset() {
+ _textMem = NULL;
+ _speechId = 0;
+ _played = false;
}
};
struct MovieInfo {
const char *name;
- uint frames;
+ int frames;
bool seamless;
};
-class MoviePlayer {
-private:
- bool checkSkipFrame();
-
-protected:
- Sword2Engine *_vm;
- Audio::Mixer *_mixer;
- OSystem *_system;
-
- char *_name;
-
- byte _originalPalette[4 * 256];
-
- uint32 _numSpeechLines;
- uint32 _firstSpeechFrame;
- MovieTextObject _textObject;
- byte *_textSurface;
-
- Audio::SoundHandle _bgSoundHandle;
- Audio::AudioStream *_bgSoundStream;
-
- uint32 _ticks;
-
- uint32 _pauseStartTick;
- uint32 _pauseTicks;
-
- uint _currentFrame;
- byte *_frameBuffer;
- int _frameWidth, _frameHeight;
- int _frameX, _frameY;
-
- byte _black, _white;
-
- uint _numFrames;
- uint _leadOutFrame;
- bool _seamless;
-
- int _framesSkipped;
-
- static const MovieInfo _movies[];
-
- uint32 _currentText;
-
- uint32 getTick();
-
- void savePalette();
- void restorePalette();
-
- void openTextObject(SequenceTextInfo *t);
- void closeTextObject();
- void calcTextPosition(int &xPos, int &yPos);
-
- virtual void handleScreenChanged() {}
-
- virtual void clearFrame();
- virtual void updateScreen();
- virtual bool decodeFrame() = 0;
- virtual bool syncFrame();
- virtual void drawFrame();
- virtual void drawTextObject();
- virtual void undrawTextObject();
-
+class DXAPlayerWithSound : public Graphics::DXAPlayer {
public:
- MoviePlayer(Sword2Engine *vm, const char *name);
- virtual ~MoviePlayer();
+ DXAPlayerWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle);
+ ~DXAPlayerWithSound() {}
- virtual bool load();
- bool userInterrupt();
- void play(SequenceTextInfo *textList, uint32 numLines, int32 leadIn, int32 leadOut);
- void pauseMovie(bool pause);
+ int32 getAudioLag();
+private:
+ Audio::Mixer *_mixer;
+ Audio::SoundHandle *_bgSoundHandle;
};
-class MoviePlayerDummy : public MoviePlayer {
-protected:
- bool decodeFrame();
- bool syncFrame();
- void drawFrame();
- void drawTextObject();
- void undrawTextObject();
-
+class MoviePlayer : public Graphics::VideoPlayer {
public:
- MoviePlayerDummy(Sword2Engine *vm, const char *name);
- virtual ~MoviePlayerDummy();
+ MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Graphics::VideoDecoder *decoder, DecoderType decoderType);
+ virtual ~MoviePlayer(void);
- bool load();
-};
+ bool load(const char *name);
+ void play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadIn, uint32 leadOut);
+ void pauseMovie(bool pause);
-class MoviePlayerSMK : public MoviePlayer, ::Graphics::SMKPlayer {
protected:
- bool decodeFrame();
-
-public:
- MoviePlayerSMK(Sword2Engine *vm, const char *name);
- ~MoviePlayerSMK();
+ Sword2Engine *_vm;
+ Audio::Mixer *_snd;
+ OSystem *_system;
+ MovieText *_movieTexts;
+ uint32 _numMovieTexts;
+ uint32 _currentMovieText;
+ byte *_textSurface;
+ int _textX, _textY;
+ DecoderType _decoderType;
- bool load();
-};
+ Audio::SoundHandle *_bgSoundHandle;
+ Audio::AudioStream *_bgSoundStream;
-#ifdef USE_ZLIB
-class MoviePlayerDXA : public MoviePlayer, ::Graphics::DXAPlayer {
-protected:
- bool decodeFrame();
+ int _id;
+ uint32 _leadOut;
+ int _numFrames;
+ int _leadOutFrame;
-public:
- MoviePlayerDXA(Sword2Engine *vm, const char *name);
- ~MoviePlayerDXA();
+ void performPostProcessing(byte *screen);
- bool load();
+ void openTextObject(uint32 index);
+ void closeTextObject(uint32 index);
+ void drawTextObject(uint32 index, byte *screen);
};
-#endif
-MoviePlayer *makeMoviePlayer(Sword2Engine *vm, const char *name);
+MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *snd, OSystem *system);
} // End of namespace Sword2
diff --git a/engines/sword2/function.cpp b/engines/sword2/function.cpp
index 4c08614575..87fde864a6 100644
--- a/engines/sword2/function.cpp
+++ b/engines/sword2/function.cpp
@@ -2139,9 +2139,9 @@ int32 Logic::fnPlaySequence(int32 *params) {
// pause sfx during sequence
_vm->_sound->pauseFx();
- _moviePlayer = makeMoviePlayer(_vm, filename);
+ _moviePlayer = makeMoviePlayer(filename, _vm, _vm->_mixer, _vm->_system);
- if (_moviePlayer->load()) {
+ if (_moviePlayer->load(filename)) {
_moviePlayer->play(_sequenceTextList, _sequenceTextLines, _smackerLeadIn, _smackerLeadOut);
}
@@ -2230,9 +2230,10 @@ int32 Logic::fnAddSequenceText(int32 *params) {
if (!readVar(DEMO)) {
assert(_sequenceTextLines < MAX_SEQUENCE_TEXT_LINES);
- _sequenceTextList[_sequenceTextLines].textNumber = params[0];
- _sequenceTextList[_sequenceTextLines].startFrame = params[1];
- _sequenceTextList[_sequenceTextLines].endFrame = params[2];
+ _sequenceTextList[_sequenceTextLines].reset();
+ _sequenceTextList[_sequenceTextLines]._textNumber = params[0];
+ _sequenceTextList[_sequenceTextLines]._startFrame = params[1];
+ _sequenceTextList[_sequenceTextLines]._endFrame = params[2];
_sequenceTextLines++;
}
diff --git a/engines/sword2/logic.h b/engines/sword2/logic.h
index b98b369982..bd89e50e46 100644
--- a/engines/sword2/logic.h
+++ b/engines/sword2/logic.h
@@ -86,7 +86,7 @@ private:
// keeps count of number of text lines to disaply during the sequence
uint32 _sequenceTextLines;
- SequenceTextInfo _sequenceTextList[MAX_SEQUENCE_TEXT_LINES];
+ MovieText _sequenceTextList[MAX_SEQUENCE_TEXT_LINES];
// when not playing a wav we calculate the speech time based upon
// length of ascii
diff --git a/engines/sword2/sound.cpp b/engines/sword2/sound.cpp
index 6af94c9cb6..ee9fa1debf 100644
--- a/engines/sword2/sound.cpp
+++ b/engines/sword2/sound.cpp
@@ -217,6 +217,15 @@ void Sound::playMovieSound(int32 res, int type) {
_vm->_sound->playFx(handle, data, len, Audio::Mixer::kMaxChannelVolume, 0, false, Audio::Mixer::kMusicSoundType);
}
+void Sound::stopMovieSounds() {
+ if (_vm->_mixer->isSoundHandleActive(_leadInHandle)) {
+ _vm->_mixer->stopHandle(_leadInHandle);
+ }
+ if (_vm->_mixer->isSoundHandleActive(_leadOutHandle)) {
+ _vm->_mixer->stopHandle(_leadOutHandle);
+ }
+}
+
/**
* Queue a sound effect for playing later.
* @param res the sound resource number
diff --git a/engines/sword2/sound.h b/engines/sword2/sound.h
index 684be3dacd..9ba7976ba4 100644
--- a/engines/sword2/sound.h
+++ b/engines/sword2/sound.h
@@ -266,6 +266,7 @@ public:
void unpauseAllSound();
void playMovieSound(int32 res, int type);
+ void stopMovieSounds();
void queueFx(int32 res, int32 type, int32 delay, int32 volume, int32 pan);
int32 playFx(FxQueueEntry *fx);