diff options
-rw-r--r-- | sword1/animation.cpp | 8 | ||||
-rw-r--r-- | sword2/driver/animation.cpp | 101 | ||||
-rw-r--r-- | sword2/driver/animation.h | 8 | ||||
-rw-r--r-- | sword2/driver/d_sound.cpp | 38 | ||||
-rw-r--r-- | sword2/driver/d_sound.h | 2 |
5 files changed, 122 insertions, 35 deletions
diff --git a/sword1/animation.cpp b/sword1/animation.cpp index 46d8c59006..73b88221a7 100644 --- a/sword1/animation.cpp +++ b/sword1/animation.cpp @@ -74,8 +74,14 @@ bool AnimationState::init(const char *basename) { p = 0; while (!feof(f)) { - if (fscanf(f, "%i %i", &palettes[p].end, &palettes[p].cnt) != 2) + int end, cnt; + + if (fscanf(f, "%i %i", &end, &cnt) != 2) break; + + palettes[p].end = (uint) end; + palettes[p].cnt = (uint) cnt; + for (i = 0; i < palettes[p].cnt; i++) { int r, g, b; fscanf(f, "%i", &r); diff --git a/sword2/driver/animation.cpp b/sword2/driver/animation.cpp index c20fb8498d..e54b76f0de 100644 --- a/sword2/driver/animation.cpp +++ b/sword2/driver/animation.cpp @@ -80,8 +80,14 @@ bool AnimationState::init(const char *name) { p = 0; while (!feof(f)) { - if (fscanf(f, "%i %i", &palettes[p].end, &palettes[p].cnt) != 2) + int end, cnt; + + if (fscanf(f, "%i %i", &end, &cnt) != 2) break; + + palettes[p].end = (uint) end; + palettes[p].cnt = (uint) cnt; + for (i = 0; i < palettes[p].cnt; i++) { int r, g, b; fscanf(f, "%i", &r); @@ -410,6 +416,26 @@ bool AnimationState::decodeFrame() { return false; } +MovieInfo MoviePlayer::_movies[] = { + { "carib", 222 }, + { "escape", 187 }, + { "eye", 248 }, + { "finale", 1485 }, + { "guard", 75 }, + { "intro", 1800 }, + { "jungle", 186 }, + { "museum", 167 }, + { "pablo", 75 }, + { "pyramid", 60 }, + { "quaram", 184 }, + { "river", 656 }, + { "sailing", 138 }, + { "shaman", 788 }, + { "stone1", 34 }, + { "stone2", 282 }, + { "stone3", 65 } +}; + void MoviePlayer::openTextObject(MovieTextObject *obj) { if (obj->textSprite) _vm->_graphics->createSurface(obj->textSprite, &_textSurface); @@ -444,7 +470,7 @@ void MoviePlayer::drawTextObject(AnimationState *anim, MovieTextObject *obj) { int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *musicOut) { #ifdef USE_MPEG2 - int frameCounter = 0, textCounter = 0; + uint frameCounter = 0, textCounter = 0; PlayingSoundHandle handle; bool skipCutscene = false, textVisible = false; uint32 flags = SoundMixer::FLAG_16BITS; @@ -454,7 +480,7 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *mu memcpy(oldPal, _vm->_graphics->_palCopy, 1024); AnimationState *anim = new AnimationState(_vm); - + if (!anim->init(filename)) { delete anim; // Missing Files? Use the old 'Narration Only' hack @@ -468,6 +494,22 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *mu flags |= SoundMixer::FLAG_LITTLE_ENDIAN; #endif + int i; + uint leadOutFrame = (uint) -1; + + for (i = 0; i < ARRAYSIZE(_movies); i++) { + if (scumm_stricmp(filename, _movies[i].name) == 0) { + if (_movies[i].frames >= 60) + leadOutFrame = _movies[i].frames - 60; + else + leadOutFrame = 0; + break; + } + } + + if (i == ARRAYSIZE(_movies)) + warning("Unknown movie, '%s'", filename); + while (anim->decodeFrame()) { if (text && text[textCounter]) { if (frameCounter == text[textCounter]->startFrame) { @@ -495,6 +537,9 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *mu frameCounter++; + if (frameCounter == leadOutFrame && musicOut) + _vm->_sound->playFx(0, musicOut, 0, 0, RDSE_FXLEADOUT); + #ifdef BACKEND_8BIT _vm->_graphics->updateDisplay(true); #else @@ -512,6 +557,37 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *mu } + if (!skipCutscene) { + // Sleep for one frame so that the last frame is displayed. + _vm->_system->delay_msecs(1000 / 12); + } + +#ifndef BACKEND_8BIT + // Most movies fade to black on their own, but not all of them. Since + // we may be hanging around in the cutscene player for a while longer, + // waiting for the lead-out sound to finish, paint the overlay black. + + anim->clearDisplay(); +#else + _vm->_graphics->clearScene(); + _vm->_graphics->setNeedFullRedraw(); +#endif + + // If the speech is still playing, redraw the subtitles. At least in + // the English version this is most noticeable in the "carib" cutscene. + + if (textVisible && handle.isActive()) + drawTextObject(anim, text[textCounter]); + + if (text) + closeTextObject(text[textCounter]); + +#ifndef BACKEND_8BIT + anim->updateDisplay(); +#else + _vm->_graphics->updateDisplay(true); +#endif + // Wait for the voice 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 @@ -522,14 +598,9 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *mu _vm->_system->delay_msecs(100); } - if (text) - closeTextObject(text[textCounter]); + // Clear the screen again #ifndef BACKEND_8BIT - // Most movies fade to black on their own, but not all of them. Since - // we may be hanging around in the cutscene player for a while longer, - // waiting for the lead-out sound to finish, paint the overlay black. - anim->clearDisplay(); anim->updateDisplay(); #endif @@ -537,13 +608,13 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *mu _vm->_graphics->clearScene(); _vm->_graphics->setNeedFullRedraw(); - if (!skipCutscene) - _vm->_sound->playLeadOut(musicOut); - _vm->_graphics->setPalette(0, 256, oldPal, RDPAL_INSTANT); delete anim; + // Wait for the lead-out to stop, if there is any. + _vm->_sound->waitForLeadOut(); + // Lead-in and lead-out music are, as far as I can tell, only used for // the animated cut-scenes, so this seems like a good place to close // both of them. @@ -688,8 +759,10 @@ int32 MoviePlayer::playDummy(const char *filename, MovieTextObject *text[], uint // FIXME: For now, only play the lead-out music for cutscenes // that have subtitles. - if (!skipCutscene) - _vm->_sound->playLeadOut(musicOut); + if (!skipCutscene && musicOut) { + _vm->_sound->playFx(0, musicOut, 0, 0, RDSE_FXLEADOUT); + _vm->_sound->waitForLeadOut(); + } _vm->_graphics->setPalette(0, 256, oldPal, RDPAL_INSTANT); } diff --git a/sword2/driver/animation.h b/sword2/driver/animation.h index f87e074c7e..25c4284f4c 100644 --- a/sword2/driver/animation.h +++ b/sword2/driver/animation.h @@ -54,7 +54,6 @@ typedef sequence_t mpeg2_sequence_t; namespace Sword2 { - #ifdef BACKEND_8BIT #define SQR(x) ((x) * (x)) #define SHIFT 3 @@ -135,11 +134,18 @@ private: #endif }; +struct MovieInfo { + char name[9]; + uint frames; +}; + class MoviePlayer { private: Sword2Engine *_vm; uint8 *_textSurface; + static struct MovieInfo _movies[]; + void openTextObject(MovieTextObject *obj); void closeTextObject(MovieTextObject *obj); void drawTextObject(AnimationState *anim, MovieTextObject *obj); diff --git a/sword2/driver/d_sound.cpp b/sword2/driver/d_sound.cpp index 4277e525da..0d16c72969 100644 --- a/sword2/driver/d_sound.cpp +++ b/sword2/driver/d_sound.cpp @@ -252,11 +252,16 @@ bool MusicHandle::endOfData(void) const { */ bool Sound::getWavInfo(uint8 *data, WavInfo *wavInfo) { + uint32 wavLength; + uint32 offset; + if (READ_UINT32(data) != MKID('RIFF')) { warning("getWavInfo: No 'RIFF' header"); return false; } + wavLength = READ_LE_UINT32(data + 4) + 8; + if (READ_UINT32(data + 8) != MKID('WAVE')) { warning("getWavInfo: No 'WAVE' header"); return false; @@ -270,15 +275,21 @@ bool Sound::getWavInfo(uint8 *data, WavInfo *wavInfo) { wavInfo->channels = READ_LE_UINT16(data + 22); wavInfo->rate = READ_LE_UINT16(data + 24); - data += READ_LE_UINT32(data + 16) + 20; + offset = READ_LE_UINT32(data + 16) + 20; - if (READ_UINT32(data) != MKID('data')) { - warning("getWavInfo: No 'data' header"); - return false; + // It's almost certainly a WAV file, but we still need to find its + // 'data' chunk. + + while (READ_UINT32(data + offset) != MKID('data')) { + if (offset >= wavLength) { + warning("getWavInfo: Can't find 'data' chunk"); + return false; + } + offset += (READ_LE_UINT32(data + offset + 4) + 8); } - wavInfo->samples = READ_LE_UINT32(data + 4); - wavInfo->data = data + 8; + wavInfo->samples = READ_LE_UINT32(data + offset + 4); + wavInfo->data = data + offset + 8; return true; } @@ -429,20 +440,11 @@ void Sound::restoreMusicState(void) { } } -void Sound::playLeadOut(uint8 *leadOut) { - int i; +void Sound::waitForLeadOut(void) { + int i = getFxIndex(-1); - if (!leadOut) - return; - - playFx(0, leadOut, 0, 0, RDSE_FXLEADOUT); - - i = getFxIndex(-1); - - if (i == MAXFX) { - warning("playLeadOut: Can't find lead-out sound handle"); + if (i == MAXFX) return; - } while (_fx[i]._handle.isActive()) { _vm->_graphics->updateDisplay(); diff --git a/sword2/driver/d_sound.h b/sword2/driver/d_sound.h index 8612bbefb0..19a3458510 100644 --- a/sword2/driver/d_sound.h +++ b/sword2/driver/d_sound.h @@ -131,7 +131,7 @@ public: void stopMusic(void); void saveMusicState(void); void restoreMusicState(void); - void playLeadOut(uint8 *leadOut); + void waitForLeadOut(void); int32 streamCompMusic(const char *filename, uint32 musicId, bool looping); int32 musicTimeRemaining(void); |