From 781d7da6b1f0ff9ad7dd4b28b51ed1e3064d222b Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 15 Feb 2009 13:29:48 +0000 Subject: [PATCH] Applied my patch for the BS1/2 video player - Support for the MPEG2 videos in BS1/2 has been dropped. The MPEG2 videos were lossy, and support for them complicated the code a lot. - Support for the non-existing enhanced MPEG cutscene packs for BS1 has been dropped. As a consequence, the credits player and the splitted audio stream players used for these packs has been removed - The original Smacker videos for both games are now supported, using our Smacker player (which is based off publically available specs and FFMPEG) - The animations now use the common video player code. Both the Smacker videos and our DXA video packs are supported svn-id: r38236 --- engines/sword1/animation.cpp | 548 ++++++---------------------------- engines/sword1/animation.h | 155 ++-------- engines/sword1/credits.cpp | 349 ---------------------- engines/sword1/credits.h | 75 ----- engines/sword1/logic.cpp | 17 +- engines/sword1/module.mk | 1 - engines/sword1/sword1.cpp | 8 +- engines/sword1/sword1.h | 2 - engines/sword2/animation.cpp | 299 ++++--------------- engines/sword2/animation.h | 49 +-- engines/sword2/sword2.cpp | 2 + graphics/video/video_player.h | 6 + 12 files changed, 196 insertions(+), 1315 deletions(-) delete mode 100644 engines/sword1/credits.cpp delete mode 100644 engines/sword1/credits.h diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp index 04344a9b3f1..f6e6e4d1dbe 100644 --- a/engines/sword1/animation.cpp +++ b/engines/sword1/animation.cpp @@ -27,7 +27,6 @@ #include "common/file.h" #include "sword1/sword1.h" #include "sword1/animation.h" -#include "sword1/credits.h" #include "sword1/text.h" #include "sound/vorbis.h" @@ -36,8 +35,11 @@ #include "common/str.h" #include "common/events.h" #include "common/system.h" +#include "common/list.h" #include "graphics/surface.h" +#include "gui/message.h" + namespace Sword1 { static const char *sequenceList[20] = { @@ -67,107 +69,14 @@ static const char *sequenceList[20] = { // Basic movie player /////////////////////////////////////////////////////////////////////////////// -MoviePlayer::MoviePlayer(SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system) - : _vm(vm), _screen(screen), _textMan(textMan), _snd(snd), _system(system) { +MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Graphics::VideoDecoder *decoder, DecoderType decoderType) + : _vm(vm), _textMan(textMan), _snd(snd), _bgSoundHandle(bgSoundHandle), _system(system), VideoPlayer(decoder) { _bgSoundStream = NULL; - _ticks = 0; - _black = 1; - _white = 255; - _currentFrame = 0; - _forceFrame = false; - _framesSkipped = 0; + _decoderType = decoderType; } MoviePlayer::~MoviePlayer(void) { -} - -void MoviePlayer::updatePalette(byte *pal, bool packed) { - byte palette[4 * 256]; - byte *p = palette; - - uint32 maxWeight = 0; - uint32 minWeight = 0xFFFFFFFF; - - for (int i = 0; i < 256; i++) { - int r = *pal++; - int g = *pal++; - int b = *pal++; - - if (!packed) - pal++; - - uint32 weight = 3 * r * r + 6 * g * g + 2 * b * b; - - if (weight >= maxWeight) { - _white = i; - maxWeight = weight; - } - - if (weight <= minWeight) { - _black = i; - minWeight = i; - } - - *p++ = r; - *p++ = g; - *p++ = b; - *p++ = 0; - } - - _system->setPalette(palette, 0, 256); - _forceFrame = true; -} - -void MoviePlayer::handleScreenChanged(void) { -} - -bool MoviePlayer::initOverlays(uint32 id) { - return true; -} - -bool MoviePlayer::checkSkipFrame(void) { - if (_forceFrame) { - _forceFrame = false; - return false; - } - if (_framesSkipped > 10) { - warning("Forced frame %d to be displayed", _currentFrame); - _framesSkipped = 0; - return false; - } - if (_bgSoundStream) { - if ((_snd->getSoundElapsedTime(_bgSoundHandle) * 12) / 1000 < _currentFrame + 1) - return false; - } else { - if (_system->getMillis() <= _ticks) - return false; - } - _framesSkipped++; - return true; -} - -bool MoviePlayer::syncFrame(void) { - _ticks += 83; - if (checkSkipFrame()) { - warning("Skipped frame %d", _currentFrame); - return false; - } - if (_bgSoundStream) { - while (_snd->isSoundHandleActive(_bgSoundHandle) && (_snd->getSoundElapsedTime(_bgSoundHandle) * 12) / 1000 < _currentFrame) { - _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 = _system->getMillis(); - } else { - while (_system->getMillis() < _ticks) { - _system->delayMillis(10); - } - } - return true; + delete(_decoder); } /** @@ -178,8 +87,11 @@ bool MoviePlayer::load(uint32 id) { Common::File f; char fileName[20]; - _id = id; - _bgSoundStream = NULL; + if (_decoderType == kVideoDecoderDXA) { + _bgSoundStream = Audio::AudioStream::openStreamFile(sequenceList[id]); + } else { + _bgSoundStream = NULL; + } if (SwordEngine::_systemVars.showText) { sprintf(fileName, "%s.txt", sequenceList[id]); @@ -221,98 +133,51 @@ bool MoviePlayer::load(uint32 id) { } } - if (SwordEngine::_systemVars.cutscenePackVersion == 1) { - if ((id == SEQ_INTRO) || (id == SEQ_FINALE) || (id == SEQ_HISTORY) || (id == SEQ_FERRARI)) { -#ifdef USE_VORBIS - // these sequences are language specific - sprintf(fileName, "%s.snd", sequenceList[id]); - Common::File *oggSource = new Common::File(); - if (oggSource->open(fileName)) { - SplittedAudioStream *sStream = new SplittedAudioStream(); - uint32 numSegs = oggSource->readUint32LE(); // number of audio segments, either 1 or 2. - // for each segment and each of the 7 languages, we've got fileoffset and size - uint32 *header = (uint32*)malloc(numSegs * 7 * 2 * 4); - for (uint32 cnt = 0; cnt < numSegs * 7 * 2; cnt++) - header[cnt] = oggSource->readUint32LE(); - for (uint32 segCnt = 0; segCnt < numSegs; segCnt++) { - oggSource->seek( header[SwordEngine::_systemVars.language * 2 + 0 + segCnt * 14]); - uint32 segSize = header[SwordEngine::_systemVars.language * 2 + 1 + segCnt * 14]; - Common::MemoryReadStream *stream = oggSource->readStream(segSize); - Audio::AudioStream *apStream = Audio::makeVorbisStream(stream, true); - if (!apStream) - error("Can't create Vorbis Stream from file %s", fileName); - sStream->appendStream(apStream); - } - free(header); - _bgSoundStream = sStream; - } else - warning("Sound file \"%s\" not found", fileName); - delete oggSource; -#endif - initOverlays(id); - } + char filename[20]; + switch (_decoderType) { + case kVideoDecoderDXA: + snprintf(filename, sizeof(filename), "%s.dxa", sequenceList[id]); + break; + case kVideoDecoderSMK: + snprintf(filename, sizeof(filename), "%s.smk", sequenceList[id]); + break; } + + if (_decoder->loadFile(filename)) { + // The Broken Sword games always use external audio tracks. + if (_decoder->readSoundHeader() != MKID_BE('NULL')) + return false; + } else { + return false; + } + return true; } void MoviePlayer::play(void) { - _screen->clearScreen(); - _framesSkipped = 0; - _ticks = _system->getMillis(); - _bgSoundStream = Audio::AudioStream::openStreamFile(sequenceList[_id]); if (_bgSoundStream) { - _snd->playInputStream(Audio::Mixer::kSFXSoundType, &_bgSoundHandle, _bgSoundStream); + _snd->playInputStream(Audio::Mixer::kSFXSoundType, _bgSoundHandle, _bgSoundStream); } - _currentFrame = 0; bool terminated = false; - Common::EventManager *eventMan = _system->getEventManager(); - while (!terminated && decodeFrame()) { - if (!_movieTexts.empty()) { - if (_currentFrame == _movieTexts[0]->_startFrame) { - _textMan->makeTextSprite(2, (uint8 *)_movieTexts[0]->_text, 600, LETTER_COL); - FrameHeader *frame = _textMan->giveSpriteData(2); - _textWidth = frame->width; - _textHeight = frame->height; - _textX = 320 - _textWidth / 2; - _textY = 420 - _textHeight; - } - if (_currentFrame == _movieTexts[0]->_endFrame) { - _textMan->releaseText(2, false); - delete _movieTexts.remove_at(0); - } - } - processFrame(); - if (syncFrame()) - updateScreen(); - _currentFrame++; - Common::Event event; - while (eventMan->pollEvent(event)) { - switch (event.type) { - case Common::EVENT_SCREEN_CHANGED: - handleScreenChanged(); - break; - case Common::EVENT_KEYDOWN: - if (event.kbd.keycode == Common::KEYCODE_ESCAPE) - terminated = true; - break; - default: - break; - } - } - if (_vm->shouldQuit()) - terminated = true; - } + Common::List stopEvents; + Common::Event stopEvent; + stopEvents.clear(); + stopEvent.type = Common::EVENT_KEYDOWN; + stopEvent.kbd = Common::KEYCODE_ESCAPE; + stopEvents.push_back(stopEvent); + + terminated = !playVideo(&stopEvents); if (terminated) - _snd->stopHandle(_bgSoundHandle); + _snd->stopHandle(*_bgSoundHandle); _textMan->releaseText(2, false); while (!_movieTexts.empty()) delete _movieTexts.remove_at(_movieTexts.size() - 1); - while (_snd->isSoundHandleActive(_bgSoundHandle)) + while (_snd->isSoundHandleActive(*_bgSoundHandle)) _system->delayMillis(100); // It's tempting to call _screen->fullRefresh() here to restore the old @@ -322,324 +187,105 @@ void MoviePlayer::play(void) { byte pal[3 * 256]; memset(pal, 0, sizeof(pal)); - updatePalette(pal, true); + _system->setPalette(pal, 0, 255); } -SplittedAudioStream::SplittedAudioStream(void) { - _queue = NULL; -} +void MoviePlayer::performPostProcessing(byte *screen) { + if (!_movieTexts.empty()) { + if (_decoder->getCurFrame() == _movieTexts[0]->_startFrame) { + _textMan->makeTextSprite(2, (uint8 *)_movieTexts[0]->_text, 600, LETTER_COL); -SplittedAudioStream::~SplittedAudioStream(void) { - while (_queue) { - delete _queue->stream; - FileQueue *que = _queue->next; - delete _queue; - _queue = que; - } -} - -int SplittedAudioStream::getRate(void) const { - if (_queue) - return _queue->stream->getRate(); - else - return 22050; -} - -void SplittedAudioStream::appendStream(Audio::AudioStream *stream) { - FileQueue **que = &_queue; - while (*que) - que = &((*que)->next); - *que = new FileQueue; - (*que)->stream = stream; - (*que)->next = NULL; -} - -bool SplittedAudioStream::endOfData(void) const { - if (_queue) - return _queue->stream->endOfData(); - else - return true; -} - -bool SplittedAudioStream::isStereo(void) const { - if (_queue) - return _queue->stream->isStereo(); - else - return false; // all the BS1 files are mono, anyways. -} - -int SplittedAudioStream::readBuffer(int16 *buffer, const int numSamples) { - int retVal = 0; - int needSamples = numSamples; - while (needSamples && _queue) { - int retSmp = _queue->stream->readBuffer(buffer, needSamples); - needSamples -= retSmp; - retVal += retSmp; - buffer += retSmp; - if (_queue->stream->endOfData()) { - delete _queue->stream; - FileQueue *que = _queue->next; - delete _queue; - _queue = que; + FrameHeader *frame = _textMan->giveSpriteData(2); + _textWidth = frame->width; + _textHeight = frame->height; + _textX = 320 - _textWidth / 2; + _textY = 420 - _textHeight; + } + if (_decoder->getCurFrame() == _movieTexts[0]->_endFrame) { + _textMan->releaseText(2, false); + delete _movieTexts.remove_at(0); } } - return retVal; -} - -#ifdef USE_ZLIB - -/////////////////////////////////////////////////////////////////////////////// -// Movie player for the new DXA movies -/////////////////////////////////////////////////////////////////////////////// - -MoviePlayerDXA::MoviePlayerDXA(SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system) - : MoviePlayer(vm, screen, textMan, snd, system) { - debug(0, "Creating DXA cutscene player"); -} - -MoviePlayerDXA::~MoviePlayerDXA(void) { - closeFile(); -} - -bool MoviePlayerDXA::load(uint32 id) { - if (!MoviePlayer::load(id)) - return false; - - char filename[20]; - snprintf(filename, sizeof(filename), "%s.dxa", sequenceList[id]); - if (loadFile(filename)) { - // The Broken Sword games always use external audio tracks. - if (_fileStream->readUint32BE() != MKID_BE('NULL')) - return false; - _frameWidth = getWidth(); - _frameHeight = getHeight(); - _frameX = (640 - _frameWidth) / 2; - _frameY = (480 - _frameHeight) / 2; - return true; - } - return false; -} - -bool MoviePlayerDXA::initOverlays(uint32 id) { - // TODO - return true; -} - -void MoviePlayerDXA::setPalette(byte *pal) { - updatePalette(pal, true); -} - -bool MoviePlayerDXA::decodeFrame(void) { - if ((uint32)_currentFrame < (uint32)getFrameCount()) { - decodeNextFrame(); - return true; - } - return false; -} - -void MoviePlayerDXA::processFrame(void) { -} - -void MoviePlayerDXA::updateScreen(void) { - Graphics::Surface *frameBuffer = _system->lockScreen(); - copyFrameToBuffer((byte *)frameBuffer->pixels, _frameX, _frameY, 640); - - // TODO: Handle the advanced cutscene packs. Do they really exist? - - // We cannot draw the text to _drawBuffer, since that's one of the - // decoder's internal buffers, and besides it may be much smaller than - // the screen, so it's possible that the subtitles don't fit on it. - // Instead, we get the frame buffer from the backend, after copying the - // frame to it, and draw on that. if (_textMan->giveSpriteData(2)) { byte *src = (byte *)_textMan->giveSpriteData(2) + sizeof(FrameHeader); - byte *dst = (byte *)frameBuffer->getBasePtr(_textX, _textY); + byte *dst = screen + _textY * _decoder->getWidth() + _textX * 1; for (int y = 0; y < _textHeight; y++) { for (int x = 0; x < _textWidth; x++) { switch (src[x]) { case BORDER_COL: - dst[x] = _black; + dst[x] = _decoder->getBlack(); break; case LETTER_COL: - dst[x] = _white; + dst[x] = _decoder->getWhite(); break; } } src += _textWidth; - dst += frameBuffer->pitch; - } - - } - - _system->unlockScreen(); - - _system->updateScreen(); -} - -#endif - -#ifdef USE_MPEG2 - -/////////////////////////////////////////////////////////////////////////////// -// Movie player for the old MPEG movies -/////////////////////////////////////////////////////////////////////////////// - -MoviePlayerMPEG::MoviePlayerMPEG(SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system) - : MoviePlayer(vm, screen, textMan, snd, system) { -#ifdef BACKEND_8BIT - debug(0, "Creating MPEG cutscene player (8-bit)"); -#else - debug(0, "Creating MPEG cutscene player (16-bit)"); -#endif - for (uint8 cnt = 0; cnt < INTRO_LOGO_OVLS; cnt++) - _logoOvls[cnt] = NULL; - _introPal = NULL; - _anim = NULL; -} - -MoviePlayerMPEG::~MoviePlayerMPEG(void) { - free(_introPal); - for (uint8 cnt = 0; cnt < INTRO_LOGO_OVLS; cnt++) - free(_logoOvls[cnt]); - delete _anim; -} - -void MoviePlayerMPEG::handleScreenChanged(void) { - _anim->handleScreenChanged(); -} - -void MoviePlayerMPEG::insertOverlay(OverlayColor *buf, uint8 *ovl, OverlayColor *pal) { - if (ovl != NULL) - for (uint32 cnt = 0; cnt < 640 * 400; cnt++) - if (ovl[cnt]) - buf[cnt] = pal[ovl[cnt]]; -} - -bool MoviePlayerMPEG::load(uint32 id) { - if (MoviePlayer::load(id)) { - _anim = new AnimationState(this, _screen, _system); - return _anim->init(sequenceList[id]); - } - return false; -} - -bool MoviePlayerMPEG::initOverlays(uint32 id) { - if (id == SEQ_INTRO) { - ArcFile ovlFile; - if (!ovlFile.open("intro.dat")) { - warning("\"intro.dat\" not found"); - return false; - } - ovlFile.enterPath(SwordEngine::_systemVars.language); - for (uint8 fcnt = 0; fcnt < 12; fcnt++) { - _logoOvls[fcnt] = ovlFile.decompressFile(fcnt); - if (fcnt > 0) - for (uint32 cnt = 0; cnt < 640 * 400; cnt++) - if (_logoOvls[fcnt - 1][cnt] && !_logoOvls[fcnt][cnt]) - _logoOvls[fcnt][cnt] = _logoOvls[fcnt - 1][cnt]; - } - uint8 *pal = ovlFile.fetchFile(12); - _introPal = (OverlayColor *)malloc(256 * sizeof(OverlayColor)); - Graphics::PixelFormat format = _system->getOverlayFormat(); - for (uint16 cnt = 0; cnt < 256; cnt++) - _introPal[cnt] = format.RGBToColor(pal[cnt * 3 + 0], pal[cnt * 3 + 1], pal[cnt * 3 + 2]); - } - - return true; -} - -bool MoviePlayerMPEG::decodeFrame(void) { - return _anim->decodeFrame(); -} - -void MoviePlayerMPEG::updateScreen(void) { - _anim->updateScreen(); -} - -void MoviePlayerMPEG::processFrame(void) { -#ifndef BACKEND_8BIT - if ((_id != 4) || (SwordEngine::_systemVars.cutscenePackVersion == 0)) - return; - OverlayColor *buf = _anim->giveRgbBuffer(); - if ((_currentFrame > 397) && (_currentFrame < 444)) { // Broken Sword Logo - if (_currentFrame <= 403) - insertOverlay(buf, _logoOvls[_currentFrame - 398], _introPal); // fade up - else if (_currentFrame <= 437) - insertOverlay(buf, _logoOvls[(_currentFrame - 404) % 6 + 6], _introPal); // animation - else { - insertOverlay(buf, _logoOvls[5 - (_currentFrame - 438)], _introPal); // fade down + dst += _decoder->getWidth(); } } -#endif } -AnimationState::AnimationState(MoviePlayer *player, Screen *screen, OSystem *system) - : BaseAnimationState(system, 640, 400), _player(player), _screen(screen) { +DXAPlayerWithSound::DXAPlayerWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle) + : _mixer(mixer), _bgSoundHandle(bgSoundHandle) { } -AnimationState::~AnimationState(void) { +int32 DXAPlayerWithSound::getAudioLag() { + if (!_fileStream) + return 0; + + int32 frameDelay = getFrameDelay(); + int32 videoTime = _videoInfo.currentFrame * frameDelay; + int32 audioTime; + + audioTime = (((int32) _mixer->getSoundElapsedTime(*_bgSoundHandle)) * 100); + + return videoTime - audioTime; } -#ifdef BACKEND_8BIT -void AnimationState::setPalette(byte *pal) { - _player->updatePalette(pal, false); -} -#endif - -void AnimationState::drawYUV(int width, int height, byte *const *dat) { - _frameWidth = width; - _frameHeight = height; - -#ifdef BACKEND_8BIT - _screen->plotYUV(_lut, width, height, dat); -#else - plotYUV(width, height, dat); -#endif -} - -OverlayColor *AnimationState::giveRgbBuffer(void) { -#ifdef BACKEND_8BIT - return NULL; -#else - return _overlay; -#endif -} - -Audio::AudioStream *AnimationState::createAudioStream(const char *name, void *arg) { - if (arg) - return (Audio::AudioStream*)arg; - else - return Audio::AudioStream::openStreamFile(name); -} - -#endif - /////////////////////////////////////////////////////////////////////////////// // Factory function for creating the appropriate cutscene player /////////////////////////////////////////////////////////////////////////////// -MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system) { -#if defined(USE_ZLIB) || defined(USE_MPEG2) +MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, Audio::Mixer *snd, OSystem *system) { char filename[20]; -#endif + char buf[60]; + Audio::SoundHandle bgSoundHandle; + + snprintf(filename, sizeof(filename), "%s.smk", sequenceList[id]); + + if (Common::File::exists(filename)) { + Graphics::SMKPlayer *smkDecoder = new Graphics::SMKPlayer(snd); + return new MoviePlayer(vm, textMan, snd, system, &bgSoundHandle, smkDecoder, kVideoDecoderSMK); + } -#ifdef USE_ZLIB snprintf(filename, sizeof(filename), "%s.dxa", sequenceList[id]); if (Common::File::exists(filename)) { - return new MoviePlayerDXA(vm, screen, textMan, snd, system); - } +#ifdef USE_ZLIB + DXAPlayerWithSound *dxaDecoder = new DXAPlayerWithSound(snd, &bgSoundHandle); + return new MoviePlayer(vm, textMan, 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 + } -#ifdef USE_MPEG2 + // Old MPEG2 cutscenes snprintf(filename, sizeof(filename), "%s.mp2", sequenceList[id]); if (Common::File::exists(filename)) { - return new MoviePlayerMPEG(vm, screen, textMan, snd, system); + GUI::MessageDialog dialog("MPEG2 cutscenes are no longer supported", "OK"); + dialog.runModal(); + return NULL; } -#endif + + sprintf(buf, "Cutscene '%s' not found", sequenceList[id]); + GUI::MessageDialog dialog(buf, "OK"); + dialog.runModal(); return NULL; } diff --git a/engines/sword1/animation.h b/engines/sword1/animation.h index 3c6bf0fc1a5..a2212215465 100644 --- a/engines/sword1/animation.h +++ b/engines/sword1/animation.h @@ -27,7 +27,8 @@ #define SWORD1_ANIMATION_H #include "graphics/video/dxa_player.h" -#include "graphics/video/mpeg_player.h" +#include "graphics/video/smk_player.h" +#include "graphics/video/video_player.h" #include "sword1/screen.h" #include "sword1/sound.h" @@ -35,32 +36,11 @@ namespace Sword1 { -enum { - SEQ_FERRARI = 0, - SEQ_LADDER, - SEQ_STEPS, - SEQ_SEWER, - SEQ_INTRO, - SEQ_RIVER, - SEQ_TRUCK, - SEQ_GRAVE, - SEQ_MONTFCON, - SEQ_TAPESTRY, - SEQ_IRELAND, - SEQ_FINALE, - SEQ_HISTORY, - SEQ_SPANISH, - SEQ_WELL, - SEQ_CANDLE, - SEQ_GEODROP, - SEQ_VULTURE, - SEQ_ENDDEMO, - SEQ_CREDITS +enum DecoderType { + kVideoDecoderDXA = 0, + kVideoDecoderSMK = 1 }; -#define INTRO_LOGO_OVLS 12 -#define INTRO_TEXT_OVLS 8 - class MovieText { public: uint16 _startFrame; @@ -76,126 +56,39 @@ public: } }; -class MoviePlayer { +class DXAPlayerWithSound : public Graphics::DXAPlayer { public: - MoviePlayer(SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system); - virtual ~MoviePlayer(void); - virtual bool load(uint32 id); - void play(void); - void updatePalette(byte *pal, bool packed = true); + DXAPlayerWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle); + ~DXAPlayerWithSound() {} + + int32 getAudioLag(); private: - bool checkSkipFrame(void); + Audio::Mixer *_mixer; + Audio::SoundHandle *_bgSoundHandle; +}; + +class MoviePlayer : public Graphics::VideoPlayer { +public: + MoviePlayer(SwordEngine *vm, Text *textMan, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Graphics::VideoDecoder *decoder, DecoderType decoderType); + virtual ~MoviePlayer(void); + bool load(uint32 id); + void play(void); protected: SwordEngine *_vm; - Screen *_screen; Text *_textMan; Audio::Mixer *_snd; OSystem *_system; Common::Array _movieTexts; int _textX, _textY, _textWidth, _textHeight; - byte _black, _white; + DecoderType _decoderType; - uint32 _id; - - uint _currentFrame; - int _framesSkipped; - bool _forceFrame; - - int _frameWidth, _frameHeight; - int _frameX, _frameY; - - Audio::SoundHandle _bgSoundHandle; + Audio::SoundHandle *_bgSoundHandle; Audio::AudioStream *_bgSoundStream; - uint32 _ticks; - virtual void handleScreenChanged(void); - virtual bool initOverlays(uint32 id); - virtual bool decodeFrame(void) = 0; - virtual void processFrame(void) = 0; - virtual bool syncFrame(void); - virtual void updateScreen(void) = 0; + void performPostProcessing(byte *screen); }; -#ifdef USE_ZLIB - -class MoviePlayerDXA : public MoviePlayer, ::Graphics::DXAPlayer { -protected: - virtual void setPalette(byte *pal); -public: - MoviePlayerDXA(SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system); - virtual ~MoviePlayerDXA(void); - bool load(uint32 id); -protected: - bool initOverlays(uint32 id); - bool decodeFrame(void); - void processFrame(void); - void updateScreen(void); -}; - -#endif - -#ifdef USE_MPEG2 - -class AnimationState : public Graphics::BaseAnimationState { -private: - MoviePlayer *_player; - Screen *_screen; - -public: - AnimationState(MoviePlayer *player, Screen *screen, OSystem *system); - ~AnimationState(void); - OverlayColor *giveRgbBuffer(void); - -private: - void drawYUV(int width, int height, byte *const *dat); - -#ifdef BACKEND_8BIT - void setPalette(byte *pal); -#endif - -protected: - virtual Audio::AudioStream *createAudioStream(const char *name, void *arg); -}; - -class MoviePlayerMPEG : public MoviePlayer { -public: - MoviePlayerMPEG(SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system); - virtual ~MoviePlayerMPEG(void); - bool load(uint32 id); -protected: - void insertOverlay(OverlayColor *buf, uint8 *ovl, OverlayColor *pal); - AnimationState *_anim; - OverlayColor *_introPal; - uint8 *_logoOvls[INTRO_LOGO_OVLS]; - - bool initOverlays(uint32 id); - bool decodeFrame(void); - void processFrame(void); - void updateScreen(void); - void handleScreenChanged(void); -}; - -#endif - -struct FileQueue { - Audio::AudioStream *stream; - FileQueue *next; -}; - -class SplittedAudioStream : public Audio::AudioStream { -public: - SplittedAudioStream(void); - ~SplittedAudioStream(void); - void appendStream(Audio::AudioStream *stream); - virtual int readBuffer(int16 *buffer, const int numSamples); - virtual bool isStereo(void) const; - virtual bool endOfData(void) const; - virtual int getRate(void) const; -private: - FileQueue *_queue; -}; - -MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system); +MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, Audio::Mixer *snd, OSystem *system); } // End of namespace Sword1 diff --git a/engines/sword1/credits.cpp b/engines/sword1/credits.cpp deleted file mode 100644 index 986f751f8ad..00000000000 --- a/engines/sword1/credits.cpp +++ /dev/null @@ -1,349 +0,0 @@ -/* 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 "sword1/credits.h" -#include "sword1/screen.h" -#include "sword1/sword1.h" - -#include "sound/audiostream.h" -#include "sound/mixer.h" - -#include "common/file.h" -#include "common/util.h" -#include "common/events.h" -#include "common/system.h" - - -#define CREDITS_X 480 -#define CREDITS_Y 300 -#define BUFSIZE_Y 640 - -#define START_X ((640 - CREDITS_X) / 2) -#define START_Y ((480 - CREDITS_Y) / 2) - -#define SCROLL_TIMING (2000 / 59) // 29.5 frames per second - -#define LOGO_FADEUP_TIME (133 * 1000) -#define LOGO_FADEDOWN_TIME (163 * 1000) - -namespace Sword1 { - -enum { - FONT_PAL = 0, - FONT, - TEXT, - REVO_PAL, - REVO_LOGO, - F_EOF -}; - -enum { - FNT_LFT = 0, // left column - FNT_RGT, // right column - FNT_CEN, // centered - FNT_BIG = 64, // big font - FNT_EOL = 128, // linebreak - FNT_EOB = 255 // end of textblock -}; - - -CreditsPlayer::CreditsPlayer(OSystem *pSystem, Audio::Mixer *pMixer) { - _system = pSystem; - _mixer = pMixer; - _smlFont = _bigFont = NULL; -} - -bool spaceInBuf(uint16 blitSta, uint16 blitEnd, uint16 renderDest) { - if (blitEnd > blitSta) { - if ((renderDest > blitEnd) || (renderDest + 15 < blitSta)) - return true; - } else { - if ((renderDest > blitEnd) && (renderDest + 15 < blitSta)) - return true; - } - return false; -} - -void CreditsPlayer::play(void) { - Audio::AudioStream *bgSoundStream = Audio::AudioStream::openStreamFile("credits"); - if (bgSoundStream == NULL) { - warning("\"credits.ogg\" not found, skipping credits sequence"); - return; - } - ArcFile credFile; - if (!credFile.open("credits.dat")) { - warning("\"credits.dat\" not found, skipping credits sequence"); - return; - } - - uint8 *palSrc = credFile.fetchFile(FONT_PAL, &_palLen); - for (uint32 cnt = 0; cnt < _palLen; cnt++) - _palette[(cnt / 3) * 4 + cnt % 3] = palSrc[cnt]; - _palLen /= 3; - - generateFonts(&credFile); - - uint8 *textData = credFile.fetchFile(TEXT); - textData += READ_LE_UINT32(textData + SwordEngine::_systemVars.language * 4); - - uint8 *screenBuf = (uint8*)malloc(CREDITS_X * BUFSIZE_Y); - memset(screenBuf, 0, CREDITS_X * BUFSIZE_Y); - _system->copyRectToScreen(screenBuf, 640, 0, 0, 640, 480); - _system->setPalette(_palette, 0, _palLen); - - // everything's initialized, time to render and show the credits. - Audio::SoundHandle bgSound; - _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &bgSound, bgSoundStream, 0); - - int relDelay = 0; - uint16 scrollY = 0; - uint16 renderY = BUFSIZE_Y / 2; - uint16 clearY = 0xFFFF; - bool clearLine = false; - while (((*textData != FNT_EOB) || (scrollY != renderY)) && !Engine::shouldQuit()) { - if ((int32)_mixer->getSoundElapsedTime(bgSound) - relDelay < (SCROLL_TIMING * 2)) { // sync to audio - if (scrollY < BUFSIZE_Y - CREDITS_Y) - _system->copyRectToScreen(screenBuf + scrollY * CREDITS_X, CREDITS_X, START_X, START_Y, CREDITS_X, CREDITS_Y); - else { - _system->copyRectToScreen(screenBuf + scrollY * CREDITS_X, CREDITS_X, START_X, START_Y, CREDITS_X, BUFSIZE_Y - scrollY); - _system->copyRectToScreen(screenBuf, CREDITS_X, START_X, START_Y + BUFSIZE_Y - scrollY, CREDITS_X, CREDITS_Y - (BUFSIZE_Y - scrollY)); - } - _system->updateScreen(); - } else - warning("frame skipped"); - - while (spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, renderY) && (*textData != FNT_EOB)) { - if (*textData & FNT_EOL) { - renderY = (renderY + 16) % BUFSIZE_Y; // linebreak - clearLine = true; - *textData &= ~FNT_EOL; - } - if (spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, renderY)) { - if (clearLine) - memset(screenBuf + renderY * CREDITS_X, 0, 16 * CREDITS_X); - clearLine = false; - renderLine(screenBuf, textData + 1, renderY, *textData); - if (*textData & FNT_BIG) - renderY += 16; - while (*++textData != 0) // search for the start of next string - ; - textData++; - } - if (*textData == FNT_EOB) - clearY = renderY; - } - if ((*textData == FNT_EOB) && spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, clearY)) { - memset(screenBuf + clearY * CREDITS_X, 0, 16 * CREDITS_X); - clearY = (clearY + 16) % BUFSIZE_Y; - } - - relDelay += SCROLL_TIMING; - delay(relDelay - (int32)_mixer->getSoundElapsedTime(bgSound)); - scrollY = (scrollY + 1) % BUFSIZE_Y; - } - free(_smlFont); - free(_bigFont); - _smlFont = _bigFont = NULL; - free(screenBuf); - - // credits done, now show the revolution logo - uint8 *revoBuf = credFile.decompressFile(REVO_LOGO); - uint8 *revoPal = credFile.fetchFile(REVO_PAL, &_palLen); - _palLen /= 3; - while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEUP_TIME) && !Engine::shouldQuit()) { - delay(100); - } - memset(_palette, 0, 256 * 4); - _system->setPalette(_palette, 0, 256); - _system->copyRectToScreen(revoBuf, 480, START_X, START_Y, CREDITS_X, CREDITS_Y); - _system->updateScreen(); - - fadePalette(revoPal, true, _palLen); - while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEDOWN_TIME) && !Engine::shouldQuit()) { - delay(100); - } - fadePalette(revoPal, false, _palLen); - delay(3000); - - if (Engine::shouldQuit()) - _mixer->stopAll(); - free(revoBuf); -} - -void CreditsPlayer::fadePalette(uint8 *srcPal, bool fadeup, uint16 len) { - int8 fadeDir = fadeup ? 1 : -1; - int fadeStart = fadeup ? 0 : 12; - - int relDelay = _system->getMillis(); - for (int fadeStep = fadeStart; (fadeStep >= 0) && (fadeStep <= 12) && !Engine::shouldQuit(); fadeStep += fadeDir) { - for (uint16 cnt = 0; cnt < len * 3; cnt++) - _palette[(cnt / 3) * 4 + (cnt % 3)] = (srcPal[cnt] * fadeStep) / 12; - _system->setPalette(_palette, 0, 256); - relDelay += 1000 / 12; - delay(relDelay - _system->getMillis()); - } -} - -void CreditsPlayer::renderLine(uint8 *screenBuf, uint8 *line, uint16 yBufPos, uint8 flags) { - uint8 *font; - uint16 fntSize = 16; - if (flags & FNT_BIG) { - font = _bigFont; - fntSize = 32; - flags &= ~FNT_BIG; - } else - font = _smlFont; - - uint16 width = getWidth(font, line); - uint16 xBufPos = (flags == FNT_CEN) ? (CREDITS_X - width) / 2 : ((flags == FNT_LFT) ? (234 - width) : 255); - uint8 *bufDest = screenBuf + yBufPos * CREDITS_X + xBufPos; - while (*line) { - uint8 *chrSrc = font + _numChars + (*line - 1) * fntSize * fntSize; - for (uint16 cnty = 0; cnty < fntSize; cnty++) { - for (uint16 cntx = 0; cntx < fntSize; cntx++) - bufDest[cnty * CREDITS_X + cntx] = chrSrc[cntx]; - chrSrc += fntSize; - } - bufDest += font[*line++ - 1]; - } -} - -uint16 CreditsPlayer::getWidth(uint8 *font, uint8 *line) { - uint16 width = 0; - while (*line) - width += font[*line++ - 1]; - return width; -} - -void CreditsPlayer::generateFonts(ArcFile *arcFile) { - _bigFont = arcFile->decompressFile(FONT); - _numChars = *_bigFont; - memmove(_bigFont, _bigFont + 1, _numChars * (32 * 32 + 1)); - _smlFont = (uint8*)malloc(_numChars * (32 * 32 + 1)); - uint8 *src = _bigFont + _numChars; - uint8 *dst = _smlFont + _numChars; - for (uint16 cnt = 0; cnt < _numChars; cnt++) { - _smlFont[cnt] = (_bigFont[cnt]++ + 1) / 2; // width table - for (uint16 cnty = 0; cnty < 16; cnty++) { - for (uint16 cntx = 0; cntx < 16; cntx++) { - uint8 resR = (uint8)((_palette[src[0] * 4 + 0] + _palette[src[1] * 4 + 0] + _palette[src[32] * 4 + 0] + _palette[src[33] * 4 + 0]) >> 2); - uint8 resG = (uint8)((_palette[src[0] * 4 + 1] + _palette[src[1] * 4 + 1] + _palette[src[32] * 4 + 1] + _palette[src[33] * 4 + 1]) >> 2); - uint8 resB = (uint8)((_palette[src[0] * 4 + 2] + _palette[src[1] * 4 + 2] + _palette[src[32] * 4 + 2] + _palette[src[33] * 4 + 2]) >> 2); - *dst++ = getPalIdx(resR, resG, resB); - src += 2; - } - src += 32; - } - } -} - -uint8 CreditsPlayer::getPalIdx(uint8 r, uint8 g, uint8 b) { - for (uint16 cnt = 0; cnt < _palLen; cnt++) - if ((_palette[cnt * 4 + 0] == r) && (_palette[cnt * 4 + 1] == g) && (_palette[cnt * 4 + 2] == b)) - return (uint8)cnt; - assert(_palLen < 256); - _palette[_palLen * 4 + 0] = r; - _palette[_palLen * 4 + 1] = g; - _palette[_palLen * 4 + 2] = b; - return (uint8)_palLen++; -} - -void CreditsPlayer::delay(int msecs) { - - Common::Event event; - uint32 start = _system->getMillis(); - do { - Common::EventManager *eventMan = _system->getEventManager(); - while (eventMan->pollEvent(event)) { -#if 0 - switch (event.type) { - default: - break; - } -#endif - } - - _system->updateScreen(); - - if (msecs > 0) - _system->delayMillis(10); - - } while ((_system->getMillis() < start + msecs) && !Engine::shouldQuit()); -} - -ArcFile::ArcFile(void) { - _buf = NULL; -} - -ArcFile::~ArcFile(void) { - if (_buf) - free(_buf); -} - -bool ArcFile::open(const char *name) { - Common::File arc; - if (!arc.open(name)) - return false; - _bufPos = _buf = (uint8*)malloc(arc.size()); - arc.read(_buf, arc.size()); - arc.close(); - return true; -} - -void ArcFile::enterPath(uint32 id) { - _bufPos += READ_LE_UINT32(_bufPos + id * 4); -} - -uint8 *ArcFile::fetchFile(uint32 fileId, uint32 *size) { - if (size) - *size = READ_LE_UINT32(_bufPos + (fileId + 1) * 4) - READ_LE_UINT32(_bufPos + fileId * 4); - return _bufPos + READ_LE_UINT32(_bufPos + fileId * 4); -} - -uint8 *ArcFile::decompressFile(uint32 fileId) { - uint32 size; - uint8 *srcBuf = fetchFile(fileId, &size); - uint8 *dstBuf = (uint8*)malloc(READ_LE_UINT32(srcBuf)); - uint8 *srcPos = srcBuf + 4; - uint8 *dstPos = dstBuf; - while (srcPos < srcBuf + size) { - uint16 len = READ_LE_UINT16(srcPos); - memset(dstPos, 0, len); - dstPos += len; - srcPos += 2; - if (srcPos < srcBuf + size) { - len = *srcPos++; - memcpy(dstPos, srcPos, len); - dstPos += len; - srcPos += len; - } - } - return dstBuf; -} - -} // end of namespace Sword1 diff --git a/engines/sword1/credits.h b/engines/sword1/credits.h deleted file mode 100644 index 1b4864709bb..00000000000 --- a/engines/sword1/credits.h +++ /dev/null @@ -1,75 +0,0 @@ -/* 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$ - * - */ - -#ifndef SWORD1_CREDITS_H -#define SWORD1_CREDITS_H - -#include "common/util.h" - -namespace Audio { - class Mixer; -} -class OSystem; - -namespace Sword1 { - -class ArcFile { -public: - ArcFile(void); - ~ArcFile(void); - bool open(const char *name); - uint8 *fetchFile(uint32 fileId, uint32 *size = NULL); - uint8 *decompressFile(uint32 fileId); - void enterPath(uint32 id); - void backToRoot(void) { _bufPos = _buf; } -private: - uint8 *_bufPos; - uint8 *_buf; -}; - -class CreditsPlayer { -public: - CreditsPlayer(OSystem *pSystem, Audio::Mixer *pMixer); - void play(void); -private: - void generateFonts(ArcFile *arcFile); - void renderLine(uint8 *screenBuf, uint8 *line, uint16 yBufPos, uint8 flags); - void fadePalette(uint8 *srcPal, bool fadeup, uint16 len); - void delay(int msecs); - uint16 getWidth(uint8 *font, uint8 *line); - uint8 getPalIdx(uint8 r, uint8 g, uint8 b); - uint8 _palette[256 * 4]; - uint32 _palLen; - uint8 _numChars; - - OSystem *_system; - Audio::Mixer *_mixer; - - uint8 *_smlFont, *_bigFont; -}; - -} // end of namespace Sword1 - -#endif // BS1CREDITS_H diff --git a/engines/sword1/logic.cpp b/engines/sword1/logic.cpp index 2b24e4ba544..bd35e774a0c 100644 --- a/engines/sword1/logic.cpp +++ b/engines/sword1/logic.cpp @@ -41,7 +41,6 @@ #include "sword1/music.h" #include "sword1/swordres.h" #include "sword1/animation.h" -#include "sword1/credits.h" #include "sword1/debug.h" @@ -960,16 +959,12 @@ int Logic::fnPlaySequence(Object *cpt, int32 id, int32 sequenceId, int32 d, int3 // meantime, we don't want any looping sound effects still playing. _sound->quitScreen(); - if ((SwordEngine::_systemVars.cutscenePackVersion == 1) && (sequenceId == SEQ_CREDITS)) { - CreditsPlayer player(_system, _mixer); - player.play(); - } else { - MoviePlayer *player = makeMoviePlayer(sequenceId, _vm, _screen, _textMan, _mixer, _system); - if (player) { - if (player->load(sequenceId)) - player->play(); - delete player; - } + MoviePlayer *player = makeMoviePlayer(sequenceId, _vm, _textMan, _mixer, _system); + if (player) { + _screen->clearScreen(); + if (player->load(sequenceId)) + player->play(); + delete player; } return SCRIPT_CONT; } diff --git a/engines/sword1/module.mk b/engines/sword1/module.mk index f101be6cef0..6e48069dd0d 100644 --- a/engines/sword1/module.mk +++ b/engines/sword1/module.mk @@ -3,7 +3,6 @@ MODULE := engines/sword1 MODULE_OBJS := \ animation.o \ control.o \ - credits.o \ debug.o \ detection.o \ eventman.o \ diff --git a/engines/sword1/sword1.cpp b/engines/sword1/sword1.cpp index 86c8bf16762..e0228b4c333 100644 --- a/engines/sword1/sword1.cpp +++ b/engines/sword1/sword1.cpp @@ -58,10 +58,12 @@ SwordEngine::SwordEngine(OSystem *syst) Common::File::addDefaultDirectory(_gameDataDir.getChild("MUSIC")); Common::File::addDefaultDirectory(_gameDataDir.getChild("SPEECH")); Common::File::addDefaultDirectory(_gameDataDir.getChild("VIDEO")); + Common::File::addDefaultDirectory(_gameDataDir.getChild("SMACKSHI")); Common::File::addDefaultDirectory(_gameDataDir.getChild("clusters")); Common::File::addDefaultDirectory(_gameDataDir.getChild("music")); Common::File::addDefaultDirectory(_gameDataDir.getChild("speech")); Common::File::addDefaultDirectory(_gameDataDir.getChild("video")); + Common::File::addDefaultDirectory(_gameDataDir.getChild("smackshi")); } SwordEngine::~SwordEngine() { @@ -475,12 +477,6 @@ void SwordEngine::checkCdFiles(void) { // check if we're running from cd, hdd or */ // make the demo flag depend on the Gamesettings for now, and not on what the datafiles look like _systemVars.isDemo = (_features & GF_DEMO) != 0; - _systemVars.cutscenePackVersion = 0; -#ifdef USE_MPEG2 - if (Common::File::exists("intro.snd")) { - _systemVars.cutscenePackVersion = 1; - } -#endif } Common::Error SwordEngine::go() { diff --git a/engines/sword1/sword1.h b/engines/sword1/sword1.h index 2cbf19d4369..ca5c958bf8d 100644 --- a/engines/sword1/sword1.h +++ b/engines/sword1/sword1.h @@ -67,8 +67,6 @@ struct SystemVars { uint8 language; bool isDemo; bool isMac; - - uint8 cutscenePackVersion; }; class SwordEngine : public Engine { diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp index 9375896f818..a6925e9adeb 100644 --- a/engines/sword2/animation.cpp +++ b/engines/sword2/animation.cpp @@ -42,6 +42,8 @@ #include "sword2/sound.h" #include "sword2/animation.h" +#include "gui/message.h" + namespace Sword2 { /////////////////////////////////////////////////////////////////////////////// @@ -91,7 +93,6 @@ MoviePlayer::MoviePlayer(Sword2Engine *vm, const char *name) { _leadOutFrame = (uint)-1; _seamless = false; _framesSkipped = 0; - _forceFrame = false; _currentText = 0; } @@ -103,43 +104,6 @@ uint32 MoviePlayer::getTick() { return _system->getMillis() - _pauseTicks; } -void MoviePlayer::updatePalette(byte *pal, bool packed) { - byte palette[4 * 256]; - byte *p = palette; - - uint32 maxWeight = 0; - uint32 minWeight = 0xFFFFFFFF; - - for (int i = 0; i < 256; i++) { - int r = *pal++; - int g = *pal++; - int b = *pal++; - - if (!packed) - pal++; - - uint32 weight = 3 * r * r + 6 * g * g + 2 * b * b; - - if (weight >= maxWeight) { - _white = i; - maxWeight = weight; - } - - if (weight <= minWeight) { - _black = i; - minWeight = i; - } - - *p++ = r; - *p++ = g; - *p++ = b; - *p++ = 0; - } - - _vm->_screen->setPalette(0, 256, palette, RDPAL_INSTANT); - _forceFrame = true; -} - void MoviePlayer::savePalette() { memcpy(_originalPalette, _vm->_screen->getPalette(), sizeof(_originalPalette)); } @@ -157,11 +121,6 @@ void MoviePlayer::updateScreen() { } bool MoviePlayer::checkSkipFrame() { - if (_forceFrame) { - _forceFrame = false; - return false; - } - if (_framesSkipped > 10) { warning("Forced frame %d to be displayed", _currentFrame); _framesSkipped = 0; @@ -512,6 +471,48 @@ void MoviePlayer::pauseMovie(bool pause) { } } +/////////////////////////////////////////////////////////////////////////////// +// 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 /////////////////////////////////////////////////////////////////////////////// @@ -527,10 +528,6 @@ MoviePlayerDXA::~MoviePlayerDXA() { closeFile(); } -void MoviePlayerDXA::setPalette(byte *pal) { - updatePalette(pal); -} - bool MoviePlayerDXA::decodeFrame() { decodeNextFrame(); copyFrameToBuffer(_frameBuffer, _frameX, _frameY, _vm->_screen->getScreenWide()); @@ -566,199 +563,6 @@ bool MoviePlayerDXA::load() { #endif -#ifdef USE_MPEG2 - -/////////////////////////////////////////////////////////////////////////////// -// Movie player for the old MPEG movies -/////////////////////////////////////////////////////////////////////////////// - -MoviePlayerMPEG::MoviePlayerMPEG(Sword2Engine *vm, const char *name) - : MoviePlayer(vm, name) { -#ifdef BACKEND_8BIT - debug(0, "Creating MPEG cutscene player (8-bit)"); -#else - debug(0, "Creating MPEG cutscene player (16-bit)"); -#endif -} - -MoviePlayerMPEG::~MoviePlayerMPEG() { - delete _anim; - _anim = NULL; -} - -bool MoviePlayerMPEG::load() { - if (!MoviePlayer::load()) - return false; - - _anim = new AnimationState(_vm, this); - - if (!_anim->init(_name)) { - delete _anim; - _anim = NULL; - return false; - } - -#ifdef BACKEND_8BIT - _frameBuffer = _vm->_screen->getScreen(); -#endif - - return true; -} - -bool MoviePlayerMPEG::decodeFrame() { - bool result = _anim->decodeFrame(); - -#ifdef BACKEND_8BIT - _frameWidth = _anim->getFrameWidth(); - _frameHeight = _anim->getFrameHeight(); - - _frameX = (_vm->_screen->getScreenWide() - _frameWidth) / 2; - _frameY = (_vm->_screen->getScreenDeep() - _frameHeight) / 2; -#endif - - return result; -} - -AnimationState::AnimationState(Sword2Engine *vm, MoviePlayer *player) - : BaseAnimationState(vm->_system, 640, 480) { - _vm = vm; - _player = player; -} - -AnimationState::~AnimationState() { -} - -#ifdef BACKEND_8BIT - -void AnimationState::setPalette(byte *pal) { - _player->updatePalette(pal, false); -} - -#else - -void MoviePlayerMPEG::handleScreenChanged() { - _anim->handleScreenChanged(); -} - -void MoviePlayerMPEG::clearFrame() { - _anim->clearFrame(); -} - -void MoviePlayerMPEG::drawFrame() { -} - -void MoviePlayerMPEG::updateScreen() { - _anim->updateScreen(); -} - -void MoviePlayerMPEG::drawTextObject() { - if (_textObject.textMem && _textSurface) { - _anim->drawTextObject(&_textObject.textSprite, _textSurface); - } -} - -void MoviePlayerMPEG::undrawTextObject() { - // As long as we only have subtitles for full-sized cutscenes, we don't - // really need to implement this function. -} - -void AnimationState::drawTextObject(SpriteInfo *s, byte *src) { - int moviePitch = _movieScale * _movieWidth; - int textX = _movieScale * s->x; - int textY = _movieScale * (_frameHeight - s->h - 12); - - OverlayColor *dst = _overlay + textY * moviePitch + textX; - - Graphics::PixelFormat format = _sys->getOverlayFormat(); - OverlayColor pen = format.RGBToColor(255, 255, 255); - OverlayColor border = format.RGBToColor(0, 0, 0); - - // TODO: Use the AdvMame scalers for the text? Pre-scale it? - - for (int y = 0; y < s->h; y++) { - OverlayColor *ptr = dst; - - for (int x = 0; x < s->w; x++) { - switch (src[x]) { - case 1: - *ptr++ = border; - if (_movieScale > 1) { - *ptr++ = border; - if (_movieScale > 2) - *ptr++ = border; - } - break; - case 255: - *ptr++ = pen; - if (_movieScale > 1) { - *ptr++ = pen; - if (_movieScale > 2) - *ptr++ = pen; - } - break; - default: - ptr += _movieScale; - break; - } - } - - if (_movieScale > 1) { - memcpy(dst + moviePitch, dst, _movieScale * s->w * sizeof(OverlayColor)); - if (_movieScale > 2) - memcpy(dst + 2 * moviePitch, dst, _movieScale * s->w * sizeof(OverlayColor)); - } - - dst += _movieScale * moviePitch; - src += s->w; - } -} -#endif - -void AnimationState::clearFrame() { -#ifdef BACKEND_8BIT - memset(_vm->_screen->getScreen(), 0, _movieWidth * _movieHeight); -#else - Graphics::PixelFormat format = _sys->getOverlayFormat(); - OverlayColor black = format.RGBToColor(0, 0, 0); - - for (int i = 0; i < _movieScale * _movieWidth * _movieScale * _movieHeight; i++) - _overlay[i] = black; -#endif -} - -void AnimationState::drawYUV(int width, int height, byte *const *dat) { - _frameWidth = width; - _frameHeight = height; - -#ifdef BACKEND_8BIT - byte *buf = _vm->_screen->getScreen() + ((480 - height) / 2) * RENDERWIDE + (640 - width) / 2; - - int x, y; - - int ypos = 0; - int cpos = 0; - int linepos = 0; - - for (y = 0; y < height; y += 2) { - for (x = 0; x < width; x += 2) { - int i = ((((dat[2][cpos] + ROUNDADD) >> SHIFT) * (BITDEPTH + 1)) + ((dat[1][cpos] + ROUNDADD) >> SHIFT)) * (BITDEPTH + 1); - cpos++; - - buf[linepos ] = _lut[i + ((dat[0][ ypos ] + ROUNDADD) >> SHIFT)]; - buf[RENDERWIDE + linepos++] = _lut[i + ((dat[0][width + ypos++] + ROUNDADD) >> SHIFT)]; - buf[linepos ] = _lut[i + ((dat[0][ ypos ] + ROUNDADD) >> SHIFT)]; - buf[RENDERWIDE + linepos++] = _lut[i + ((dat[0][width + ypos++] + ROUNDADD) >> SHIFT)]; - } - linepos += (2 * RENDERWIDE - width); - ypos += width; - } -#else - plotYUV(width, height, dat); -#endif -} - -#endif - /////////////////////////////////////////////////////////////////////////////// // Dummy player for subtitled speech only /////////////////////////////////////////////////////////////////////////////// @@ -802,10 +606,10 @@ bool MoviePlayerDummy::decodeFrame() { 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_MPEG2) || defined(USE_ZLIB) +#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 MPEG2 or ZLib support"; + byte msgNoCutscenes[] = "Cutscene - Narration Only: Press ESC to exit, or recompile ScummVM with ZLib support"; #endif byte *msg; @@ -885,6 +689,12 @@ void MoviePlayerDummy::undrawTextObject() { MoviePlayer *makeMoviePlayer(Sword2Engine *vm, const char *name) { static char filename[20]; + snprintf(filename, sizeof(filename), "%s.smk", name); + + if (Common::File::exists(filename)) { + return new MoviePlayerSMK(vm, name); + } + #ifdef USE_ZLIB snprintf(filename, sizeof(filename), "%s.dxa", name); @@ -893,13 +703,12 @@ MoviePlayer *makeMoviePlayer(Sword2Engine *vm, const char *name) { } #endif -#ifdef USE_MPEG2 snprintf(filename, sizeof(filename), "%s.mp2", name); if (Common::File::exists(filename)) { - return new MoviePlayerMPEG(vm, name); + GUI::MessageDialog dialog("MPEG2 cutscenes are no longer supported", "OK"); + dialog.runModal(); } -#endif return new MoviePlayerDummy(vm, name); } diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h index da59a4c509e..8b6a0150370 100644 --- a/engines/sword2/animation.h +++ b/engines/sword2/animation.h @@ -29,7 +29,7 @@ #define SWORD2_ANIMATION_H #include "graphics/video/dxa_player.h" -#include "graphics/video/mpeg_player.h" +#include "graphics/video/smk_player.h" #include "sound/mixer.h" #include "sword2/screen.h" @@ -97,7 +97,6 @@ protected: bool _seamless; int _framesSkipped; - bool _forceFrame; static const MovieInfo _movies[]; @@ -126,7 +125,6 @@ public: MoviePlayer(Sword2Engine *vm, const char *name); virtual ~MoviePlayer(); - void updatePalette(byte *pal, bool packed = true); virtual bool load(); bool userInterrupt(); void play(SequenceTextInfo *textList, uint32 numLines, int32 leadIn, int32 leadOut); @@ -148,57 +146,20 @@ public: bool load(); }; -#ifdef USE_MPEG2 -class AnimationState : public ::Graphics::BaseAnimationState { -private: - Sword2Engine *_vm; - MoviePlayer *_player; - -public: - AnimationState(Sword2Engine *vm, MoviePlayer *player); - ~AnimationState(); - -#ifndef BACKEND_8BIT - void drawTextObject(SpriteInfo *s, byte *src); -#endif - - void clearFrame(); - -private: - void drawYUV(int width, int height, byte *const *dat); - -#ifdef BACKEND_8BIT - void setPalette(byte *pal); -#endif -}; - -class MoviePlayerMPEG : public MoviePlayer { +class MoviePlayerSMK : public MoviePlayer, ::Graphics::SMKPlayer { protected: - AnimationState *_anim; - - virtual bool decodeFrame(); - -#ifndef BACKEND_8BIT - void handleScreenChanged(); - void clearFrame(); - void drawFrame(); - void updateScreen(); - void drawTextObject(); - void undrawTextObject(); -#endif + bool decodeFrame(); public: - MoviePlayerMPEG(Sword2Engine *vm, const char *name); - ~MoviePlayerMPEG(); + MoviePlayerSMK(Sword2Engine *vm, const char *name); + ~MoviePlayerSMK(); bool load(); }; -#endif #ifdef USE_ZLIB class MoviePlayerDXA : public MoviePlayer, ::Graphics::DXAPlayer { protected: - void setPalette(byte *pal); bool decodeFrame(); public: diff --git a/engines/sword2/sword2.cpp b/engines/sword2/sword2.cpp index 9fdc10123da..71a949fe884 100644 --- a/engines/sword2/sword2.cpp +++ b/engines/sword2/sword2.cpp @@ -252,9 +252,11 @@ Sword2Engine::Sword2Engine(OSystem *syst) : Engine(syst) { Common::File::addDefaultDirectory(_gameDataDir.getChild("CLUSTERS")); Common::File::addDefaultDirectory(_gameDataDir.getChild("SWORD2")); Common::File::addDefaultDirectory(_gameDataDir.getChild("VIDEO")); + Common::File::addDefaultDirectory(_gameDataDir.getChild("SMACKS")); Common::File::addDefaultDirectory(_gameDataDir.getChild("clusters")); Common::File::addDefaultDirectory(_gameDataDir.getChild("sword2")); Common::File::addDefaultDirectory(_gameDataDir.getChild("video")); + Common::File::addDefaultDirectory(_gameDataDir.getChild("smacks")); if (0 == scumm_stricmp(ConfMan.get("gameid").c_str(), "sword2demo")) _features = GF_DEMO; diff --git a/graphics/video/video_player.h b/graphics/video/video_player.h index 3073538cabe..2fe90210cd8 100644 --- a/graphics/video/video_player.h +++ b/graphics/video/video_player.h @@ -141,6 +141,12 @@ public: */ virtual bool decodeNextFrame() = 0; + /** + * Used to read the sound header from DXA files. It's not pretty, + * but it's slightly better than exposing _fileStream + */ + uint32 readSoundHeader() { return _fileStream->readUint32BE(); } + protected: struct { uint32 width;