diff options
Diffstat (limited to 'sword2')
-rw-r--r-- | sword2/driver/animation.cpp | 388 | ||||
-rw-r--r-- | sword2/driver/animation.h | 64 | ||||
-rw-r--r-- | sword2/driver/d_draw.cpp | 285 | ||||
-rw-r--r-- | sword2/driver/d_draw.h | 21 |
4 files changed, 383 insertions, 375 deletions
diff --git a/sword2/driver/animation.cpp b/sword2/driver/animation.cpp index 365457be25..74c681de8a 100644 --- a/sword2/driver/animation.cpp +++ b/sword2/driver/animation.cpp @@ -28,11 +28,13 @@ namespace Sword2 { -// Build 'Best-Match' RGB lookup table +/** + * Build 'Best-Match' RGB lookup table + */ + void AnimationState::buildLookup(int p, int lines) { int y, cb; int r, g, b, ii; - if (p != curpal) { curpal = p; @@ -44,17 +46,17 @@ void AnimationState::buildLookup(int p, int lines) { return; for (ii = 0; ii < lines; ii++) { - r = (-16*256 + (int)(256*1.596) * ((cr<<SHIFT)-128)) / 256; + r = (-16 * 256 + (int) (256 * 1.596) * ((cr << SHIFT) - 128)) / 256; for (cb = 0; cb < BITDEPTH; cb++) { - g = (-16*256 - (int)(0.813*256) * ((cr<<SHIFT)-128) - (int)(0.391*256) * ((cb<<SHIFT)-128)) / 256; - b = (-16*256 + (int)(2.018*256) * ((cb<<SHIFT)-128)) / 256; + g = (-16 * 256 - (int) (0.813 * 256) * ((cr << SHIFT) - 128) - (int) (0.391 * 256) * ((cb << SHIFT) - 128)) / 256; + b = (-16 * 256 + (int) (2.018 * 256) * ((cb << SHIFT) - 128)) / 256; for (y = 0; y < BITDEPTH; y++) { int idx, bst = 0; - int dis = 2*SQR(r-palettes[p].pal[0])+4*SQR(g-palettes[p].pal[1])+SQR(b-palettes[p].pal[2]); + int dis = 2 * SQR(r - palettes[p].pal[0]) + 4 * SQR(g - palettes[p].pal[1]) + SQR(b - palettes[p].pal[2]); for (idx = 1; idx < 256; idx++) { - long d2 = 2*SQR(r-palettes[p].pal[4*idx])+4*SQR(g-palettes[p].pal[4*idx+1])+SQR(b-palettes[p].pal[4*idx+2]); + long d2 = 2 * SQR(r - palettes[p].pal[4 * idx]) + 4 * SQR(g - palettes[p].pal[4 * idx + 1]) + SQR(b - palettes[p].pal[4 * idx + 2]); if (d2 < dis) { bst = idx; dis = d2; @@ -74,6 +76,294 @@ void AnimationState::buildLookup(int p, int lines) { } } +void MoviePlayer::openTextObject(MovieTextObject *obj) { + if (obj->textSprite) + _vm->_graphics->createSurface(obj->textSprite, &_textSurface); +} + +void MoviePlayer::closeTextObject(MovieTextObject *obj) { + if (_textSurface) { + _vm->_graphics->deleteSurface(_textSurface); + _textSurface = NULL; + } +} + +void MoviePlayer::drawTextObject(MovieTextObject *obj) { + if (obj->textSprite && _textSurface) + _vm->_graphics->drawSurface(obj->textSprite, _textSurface); +} + +/** + * Plays an animated cutscene. + * @param filename the file name of the cutscene file + * @param text the subtitles and voiceovers for the cutscene + * @param musicOut lead-out music + */ + +int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *musicOut) { +#ifdef USE_MPEG2 + int frameCounter = 0, textCounter = 0; + PlayingSoundHandle handle; + bool skipCutscene = false, textVisible = false; + uint32 flags = SoundMixer::FLAG_16BITS, ticks = _vm->_system->get_msecs() + 83; + + uint8 oldPal[1024]; + memcpy(oldPal, _vm->_graphics->_palCopy, 1024); + + AnimationState * anim = initAnimation(filename); + if (!anim) { + // Missing Files? Use the old 'Narration Only' hack + playDummy(filename, text, musicOut); + return RD_OK; + } + + _vm->_graphics->clearScene(); + memset(_vm->_graphics->_buffer, 0, _vm->_graphics->_screenWide * MENUDEEP); + +#ifndef SCUMM_BIG_ENDIAN + flags |= SoundMixer::FLAG_LITTLE_ENDIAN; +#endif + + while (1) { + if (!decodeFrame(anim)) break; + _vm->_graphics->setNeedFullRedraw(); + + if (text && text[textCounter]) { + if (frameCounter == text[textCounter]->startFrame) { + openTextObject(text[textCounter]); + textVisible = true; + if (text[textCounter]->speech) { + _vm->_mixer->playRaw(&handle, text[textCounter]->speech, text[textCounter]->speechBufferSize, 22050, flags); + } + } + + if (frameCounter == text[textCounter]->endFrame) { + closeTextObject(text[textCounter]); + textCounter++; + textVisible = false; + } + if (textVisible) + drawTextObject(text[textCounter]); + } + + frameCounter++; + + _vm->_graphics->updateDisplay(true); + + KeyboardEvent ke; + + if ((_vm->_input->readKey(&ke) == RD_OK && ke.keycode == 27) || _vm->_quit) { + _vm->_mixer->stopHandle(handle); + skipCutscene = true; + break; + } + + // Simulate ~12 frames per second. I don't know what + // frame rate the original movies had, or even if it + // was constant, but this seems to work reasonably. + + _vm->sleepUntil(ticks); + ticks += 82; + + } + + // 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 + // it's in use. + + while (handle.isActive()) { + _vm->_graphics->updateDisplay(false); + _vm->_system->delay_msecs(100); + } + + if (text) + closeTextObject(text[textCounter]); + + _vm->_graphics->clearScene(); + _vm->_graphics->setNeedFullRedraw(); + + // HACK: Remove the instructions created above + Common::Rect r; + + memset(_vm->_graphics->_buffer, 0, _vm->_graphics->_screenWide * MENUDEEP); + r.left = r.top = 0; + r.right = _vm->_graphics->_screenWide; + r.bottom = MENUDEEP; + _vm->_graphics->updateRect(&r); + + // FIXME: For now, only play the lead-out music for cutscenes + // that have subtitles. + if (!skipCutscene) + _vm->_sound->playLeadOut(musicOut); + + _vm->_graphics->setPalette(0, 256, oldPal, RDPAL_INSTANT); + + doneAnimation(anim); + + // 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. + + _vm->_sound->closeFx(-1); + _vm->_sound->closeFx(-2); + + return RD_OK; +#else + // No MPEG2? Use the old 'Narration Only' hack + playDummy(filename, text, musicOut); + return RD_OK; +#endif +} + +/** + * This just plays the cutscene with voiceovers / subtitles, in case the files + * are missing. + */ + +int32 MoviePlayer::playDummy(const char *filename, MovieTextObject *text[], uint8 *musicOut) { + int frameCounter = 0, textCounter = 0; + if (text) { + uint8 oldPal[1024]; + uint8 tmpPal[1024]; + + _vm->_graphics->clearScene(); + + // HACK: Draw instructions + // + // I'm using the the menu area, because that's unlikely to be + // touched by anything else during the cutscene. + + memset(_vm->_graphics->_buffer, 0, _vm->_graphics->_screenWide * MENUDEEP); + + uint8 msg[] = "Cutscene - Narration Only: Press ESC to exit, or visit www.scummvm.org to download cutscene videos"; + Memory *data = _vm->_fontRenderer->makeTextSprite(msg, 640, 255, _vm->_speechFontId); + FrameHeader *frame = (FrameHeader *) data->ad; + SpriteInfo msgSprite; + uint8 *msgSurface; + + msgSprite.x = _vm->_graphics->_screenWide / 2 - frame->width / 2; + msgSprite.y = RDMENU_MENUDEEP / 2 - frame->height / 2; + msgSprite.w = frame->width; + msgSprite.h = frame->height; + msgSprite.type = RDSPR_NOCOMPRESSION; + msgSprite.data = data->ad + sizeof(FrameHeader); + + _vm->_graphics->createSurface(&msgSprite, &msgSurface); + _vm->_graphics->drawSurface(&msgSprite, msgSurface); + _vm->_graphics->deleteSurface(msgSurface); + _vm->_memory->freeMemory(data); + + // In case the cutscene has a long lead-in, start just before + // the first line of text. + + frameCounter = text[0]->startFrame - 12; + + // Fake a palette that will hopefully make the text visible. + // In the opening cutscene it seems to use colours 1 (black?) + // and 255 (white?). + // + // The text should probably be colored the same as the rest of + // the in-game text. + + memcpy(oldPal, _vm->_graphics->_palCopy, 1024); + memset(tmpPal, 0, 1024); + tmpPal[255 * 4 + 0] = 255; + tmpPal[255 * 4 + 1] = 255; + tmpPal[255 * 4 + 2] = 255; + _vm->_graphics->setPalette(0, 256, tmpPal, RDPAL_INSTANT); + + PlayingSoundHandle handle; + + bool skipCutscene = false; + + uint32 flags = SoundMixer::FLAG_16BITS; + +#ifndef SCUMM_BIG_ENDIAN + flags |= SoundMixer::FLAG_LITTLE_ENDIAN; +#endif + + while (1) { + if (!text[textCounter]) + break; + + if (frameCounter == text[textCounter]->startFrame) { + _vm->_graphics->clearScene(); + openTextObject(text[textCounter]); + drawTextObject(text[textCounter]); + if (text[textCounter]->speech) { + _vm->_mixer->playRaw(&handle, text[textCounter]->speech, text[textCounter]->speechBufferSize, 22050, flags); + } + } + if (frameCounter == text[textCounter]->endFrame) { + closeTextObject(text[textCounter]); + _vm->_graphics->clearScene(); + _vm->_graphics->setNeedFullRedraw(); + textCounter++; + } + + frameCounter++; + + _vm->_graphics->updateDisplay(); + + KeyboardEvent ke; + + if ((_vm->_input->readKey(&ke) == RD_OK && ke.keycode == 27) || _vm->_quit) { + _vm->_mixer->stopHandle(handle); + skipCutscene = true; + break; + } + + // Simulate ~12 frames per second. I don't know what + // frame rate the original movies had, or even if it + // was constant, but this seems to work reasonably. + + _vm->_system->delay_msecs(90); + } + + // 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 + // it's in use. + + while (handle.isActive()) { + _vm->_graphics->updateDisplay(false); + _vm->_system->delay_msecs(100); + } + + closeTextObject(text[textCounter]); + + _vm->_graphics->clearScene(); + _vm->_graphics->setNeedFullRedraw(); + + // HACK: Remove the instructions created above + Common::Rect r; + + memset(_vm->_graphics->_buffer, 0, _vm->_graphics->_screenWide * MENUDEEP); + r.left = r.top = 0; + r.right = _vm->_graphics->_screenWide; + r.bottom = MENUDEEP; + _vm->_graphics->updateRect(&r); + + // FIXME: For now, only play the lead-out music for cutscenes + // that have subtitles. + + if (!skipCutscene) + _vm->_sound->playLeadOut(musicOut); + + _vm->_graphics->setPalette(0, 256, oldPal, RDPAL_INSTANT); + } + + // 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. + + _vm->_sound->closeFx(-1); + _vm->_sound->closeFx(-2); + + return RD_OK; +} + void MoviePlayer::checkPaletteSwitch(AnimationState * st) { // if we have reached the last image with this palette, switch to new one if (st->framenum == st->palettes[st->palnum].end) { @@ -86,52 +376,42 @@ void MoviePlayer::checkPaletteSwitch(AnimationState * st) { } } -#ifndef USE_MPEG2 -bool MoviePlayer::decodeFrame(AnimationState * st) { - // Dummy for MPEG2-less builds - return false; -} -#else +#ifdef USE_MPEG2 + bool MoviePlayer::decodeFrame(AnimationState * st) { mpeg2_state_t state; const mpeg2_sequence_t *sequence_i; - size_t size = (size_t)-1; + size_t size = (size_t) -1; do { - state = mpeg2_parse (st->decoder); + state = mpeg2_parse(st->decoder); sequence_i = st->info->sequence; switch (state) { - case STATE_BUFFER: - size = st->mpgfile->read(st->buffer, BUFFER_SIZE); - mpeg2_buffer (st->decoder, st->buffer, st->buffer + size); + case STATE_BUFFER: + size = st->mpgfile->read(st->buffer, BUFFER_SIZE); + mpeg2_buffer(st->decoder, st->buffer, st->buffer + size); break; - case STATE_SLICE: - case STATE_END: - if (st->info->display_fbuf) { - checkPaletteSwitch(st); - _vm->_graphics->plotYUV(st->lut, sequence_i->width, sequence_i->height, st->info->display_fbuf->buf); - st->framenum++; - st->buildLookup(st->palnum+1, st->lutcalcnum); - return true; - } + case STATE_SLICE: + case STATE_END: + if (st->info->display_fbuf) { + checkPaletteSwitch(st); + _vm->_graphics->plotYUV(st->lut, sequence_i->width, sequence_i->height, st->info->display_fbuf->buf); + st->framenum++; + st->buildLookup(st->palnum + 1, st->lutcalcnum); + return true; + } break; - default: - break; + default: + break; } } while (size); return false; } -#endif -#ifndef USE_MPEG2 -AnimationState *MoviePlayer::initAnimation(const char *name) { - return 0; -} -#else AnimationState *MoviePlayer::initAnimation(const char *name) { char basename[512], tempFile[512]; AnimationState *st = new AnimationState; @@ -158,9 +438,9 @@ AnimationState *MoviePlayer::initAnimation(const char *name) { fscanf(f, "%i", &r); fscanf(f, "%i", &g); fscanf(f, "%i", &b); - st->palettes[p].pal[4*i] = r; - st->palettes[p].pal[4*i+1] = g; - st->palettes[p].pal[4*i+2] = b; + st->palettes[p].pal[4 * i] = r; + st->palettes[p].pal[4 * i + 1] = g; + st->palettes[p].pal[4 * i + 2] = b; } p++; } @@ -184,7 +464,7 @@ AnimationState *MoviePlayer::initAnimation(const char *name) { } // Load and configure decoder - st->decoder = mpeg2_init (); + st->decoder = mpeg2_init(); if (st->decoder == NULL) { warning("Cutscene: Could not allocate an MPEG2 decoder"); delete st; @@ -195,34 +475,48 @@ AnimationState *MoviePlayer::initAnimation(const char *name) { st->framenum = 0; // Load in palette data - st->lutcalcnum = (BITDEPTH + st->palettes[st->palnum].end + 2) / (st->palettes[st->palnum].end + 2); - + st->lutcalcnum = (BITDEPTH + st->palettes[st->palnum].end + 2) / (st->palettes[st->palnum].end + 2); /* Play audio - TODO: Sync with video?*/ + +#ifdef USE_VORBIS // Another TODO: There is no reason that this only allows OGG, and not MP3, or any other format // the mixer might support one day... is there? File *sndFile = new File; sprintf(tempFile, "%s.ogg", basename); if (sndFile->open(tempFile)) _vm->_mixer->playVorbis(&st->bgSound, sndFile, 100000000); +#endif // FIXME: This leaks (sndFile will never be deleted) return st; } -#endif -#ifndef USE_MPEG2 -void MoviePlayer::doneAnimation(AnimationState *st) { -} -#else void MoviePlayer::doneAnimation(AnimationState *st) { - _vm->_mixer->stopHandle(st->bgSound); + if (st->bgSound.isActive()) + _vm->_mixer->stopHandle(st->bgSound); mpeg2_close (st->decoder); st->mpgfile->close(); delete st->mpgfile; delete st; } + +#else + +bool MoviePlayer::decodeFrame(AnimationState * st) { + // Dummy for MPEG2-less builds + return false; +} + +AnimationState *MoviePlayer::initAnimation(const char *name) { + return 0; +} + +void MoviePlayer::doneAnimation(AnimationState *st) { +} + #endif + } // End of namespace Sword2 diff --git a/sword2/driver/animation.h b/sword2/driver/animation.h index a6890df3c4..1d85d86e86 100644 --- a/sword2/driver/animation.h +++ b/sword2/driver/animation.h @@ -41,41 +41,61 @@ namespace Sword2 { #define BUFFER_SIZE 4096 - class AnimationState { public: - int palnum; + int palnum; - byte lookup[2][BITDEPTH * BITDEPTH * BITDEPTH]; - byte *lut; - byte *lut2; - int lutcalcnum; + byte lookup[2][BITDEPTH * BITDEPTH * BITDEPTH]; + byte *lut; + byte *lut2; + int lutcalcnum; - int framenum; + int framenum; - #ifdef USE_MPEG2 - mpeg2dec_t *decoder; - const mpeg2_info_t *info; - #endif - File *mpgfile; +#ifdef USE_MPEG2 + mpeg2dec_t *decoder; + const mpeg2_info_t *info; +#endif - int curpal; - int cr; - int pos; + File *mpgfile; - struct { - int cnt; - int end; - byte pal[4 * 256]; - } palettes[50]; + int curpal; + int cr; + int pos; - byte buffer[BUFFER_SIZE]; + struct { + int cnt; + int end; + byte pal[4 * 256]; + } palettes[50]; - PlayingSoundHandle bgSound; + byte buffer[BUFFER_SIZE]; + + PlayingSoundHandle bgSound; public: void buildLookup(int p, int lines); +}; +class MoviePlayer { +private: + Sword2Engine *_vm; + uint8 *_textSurface; + + void openTextObject(MovieTextObject *obj); + void closeTextObject(MovieTextObject *obj); + void drawTextObject(MovieTextObject *obj); + + void checkPaletteSwitch(AnimationState * st); + + AnimationState * initAnimation(const char *name); + void doneAnimation(AnimationState * st); + bool decodeFrame(AnimationState * st); + +public: + MoviePlayer(Sword2Engine *vm) : _vm(vm), _textSurface(NULL) {} + int32 play(const char *filename, MovieTextObject *text[], uint8 *musicOut); + int32 playDummy(const char *filename, MovieTextObject *text[], uint8 *musicOut); }; } // End of namespace Sword2 diff --git a/sword2/driver/d_draw.cpp b/sword2/driver/d_draw.cpp index a56b60af9e..b3e4814df9 100644 --- a/sword2/driver/d_draw.cpp +++ b/sword2/driver/d_draw.cpp @@ -116,289 +116,4 @@ void Graphics::clearScene(void) { memset(_buffer + MENUDEEP * _screenWide, 0, _screenWide * RENDERDEEP); } -void MoviePlayer::openTextObject(MovieTextObject *obj) { - if (obj->textSprite) - _vm->_graphics->createSurface(obj->textSprite, &_textSurface); -} - -void MoviePlayer::closeTextObject(MovieTextObject *obj) { - if (_textSurface) { - _vm->_graphics->deleteSurface(_textSurface); - _textSurface = NULL; - } -} - -void MoviePlayer::drawTextObject(MovieTextObject *obj) { - if (obj->textSprite && _textSurface) - _vm->_graphics->drawSurface(obj->textSprite, _textSurface); -} - -/** - * Plays an animated cutscene. - * @param filename the file name of the cutscene file - * @param text the subtitles and voiceovers for the cutscene - * @param musicOut lead-out music - */ - -int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *musicOut) { -#ifdef USE_MPEG2 - int frameCounter = 0, textCounter = 0; - PlayingSoundHandle handle; - bool skipCutscene = false, textVisible = false; - uint32 flags = SoundMixer::FLAG_16BITS, ticks = _vm->_system->get_msecs() + 83; - - uint8 oldPal[1024]; - memcpy(oldPal, _vm->_graphics->_palCopy, 1024); - - AnimationState * anim = initAnimation(filename); - if (!anim) { - // Missing Files? Use the old 'Narration Only' hack - playDummy(filename, text, musicOut); - return RD_OK; - } - - _vm->_graphics->clearScene(); - memset(_vm->_graphics->_buffer, 0, _vm->_graphics->_screenWide * MENUDEEP); - - -#ifndef SCUMM_BIG_ENDIAN - flags |= SoundMixer::FLAG_LITTLE_ENDIAN; -#endif - - while (1) { - if (!decodeFrame(anim)) break; - _vm->_graphics->setNeedFullRedraw(); - - if (text && text[textCounter]) { - if (frameCounter == text[textCounter]->startFrame) { - openTextObject(text[textCounter]); - textVisible = true; - if (text[textCounter]->speech) { - _vm->_mixer->playRaw(&handle, text[textCounter]->speech, text[textCounter]->speechBufferSize, 22050, flags); - } - } - - if (frameCounter == text[textCounter]->endFrame) { - closeTextObject(text[textCounter]); - textCounter++; - textVisible = false; - } - if (textVisible) - drawTextObject(text[textCounter]); - } - - frameCounter++; - - _vm->_graphics->updateDisplay(true); - - KeyboardEvent ke; - - if ((_vm->_input->readKey(&ke) == RD_OK && ke.keycode == 27) || _vm->_quit) { - _vm->_mixer->stopHandle(handle); - skipCutscene = true; - break; - } - - // Simulate ~12 frames per second. I don't know what - // frame rate the original movies had, or even if it - // was constant, but this seems to work reasonably. - - _vm->sleepUntil(ticks); - ticks += 82; - - } - - // 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 - // it's in use. - - while (handle.isActive()) { - _vm->_graphics->updateDisplay(false); - _vm->_system->delay_msecs(100); - } - - if (text) - closeTextObject(text[textCounter]); - - _vm->_graphics->clearScene(); - _vm->_graphics->setNeedFullRedraw(); - - // HACK: Remove the instructions created above - Common::Rect r; - - memset(_vm->_graphics->_buffer, 0, _vm->_graphics->_screenWide * MENUDEEP); - r.left = r.top = 0; - r.right = _vm->_graphics->_screenWide; - r.bottom = MENUDEEP; - _vm->_graphics->updateRect(&r); - - // FIXME: For now, only play the lead-out music for cutscenes - // that have subtitles. - if (!skipCutscene) - _vm->_sound->playLeadOut(musicOut); - - _vm->_graphics->setPalette(0, 256, oldPal, RDPAL_INSTANT); - - doneAnimation(anim); - - // 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. - - _vm->_sound->closeFx(-1); - _vm->_sound->closeFx(-2); - - return RD_OK; -#else - // No MPEG2? Use the old 'Narration Only' hack - playDummy(filename, text, musicOut); - return RD_OK; -#endif -} - -// This just plays the cutscene with voiceovers / subtitles, in case the files are missing -int32 MoviePlayer::playDummy(const char *filename, MovieTextObject *text[], uint8 *musicOut) { - int frameCounter = 0, textCounter = 0; - if (text) { - uint8 oldPal[1024]; - uint8 tmpPal[1024]; - - _vm->_graphics->clearScene(); - - // HACK: Draw instructions - // - // I'm using the the menu area, because that's unlikely to be - // touched by anything else during the cutscene. - - memset(_vm->_graphics->_buffer, 0, _vm->_graphics->_screenWide * MENUDEEP); - - uint8 msg[] = "Cutscene - Narration Only: Press ESC to exit, or visit www.scummvm.org to download cutscene videos"; - Memory *data = _vm->_fontRenderer->makeTextSprite(msg, 640, 255, _vm->_speechFontId); - FrameHeader *frame = (FrameHeader *) data->ad; - SpriteInfo msgSprite; - uint8 *msgSurface; - - msgSprite.x = _vm->_graphics->_screenWide / 2 - frame->width / 2; - msgSprite.y = RDMENU_MENUDEEP / 2 - frame->height / 2; - msgSprite.w = frame->width; - msgSprite.h = frame->height; - msgSprite.type = RDSPR_NOCOMPRESSION; - msgSprite.data = data->ad + sizeof(FrameHeader); - - _vm->_graphics->createSurface(&msgSprite, &msgSurface); - _vm->_graphics->drawSurface(&msgSprite, msgSurface); - _vm->_graphics->deleteSurface(msgSurface); - _vm->_memory->freeMemory(data); - - // In case the cutscene has a long lead-in, start just before - // the first line of text. - - frameCounter = text[0]->startFrame - 12; - - // Fake a palette that will hopefully make the text visible. - // In the opening cutscene it seems to use colours 1 (black?) - // and 255 (white?). - // - // The text should probably be colored the same as the rest of - // the in-game text. - - memcpy(oldPal, _vm->_graphics->_palCopy, 1024); - memset(tmpPal, 0, 1024); - tmpPal[255 * 4 + 0] = 255; - tmpPal[255 * 4 + 1] = 255; - tmpPal[255 * 4 + 2] = 255; - _vm->_graphics->setPalette(0, 256, tmpPal, RDPAL_INSTANT); - - PlayingSoundHandle handle; - - bool skipCutscene = false; - - uint32 flags = SoundMixer::FLAG_16BITS; - -#ifndef SCUMM_BIG_ENDIAN - flags |= SoundMixer::FLAG_LITTLE_ENDIAN; -#endif - - while (1) { - if (!text[textCounter]) - break; - - if (frameCounter == text[textCounter]->startFrame) { - _vm->_graphics->clearScene(); - openTextObject(text[textCounter]); - drawTextObject(text[textCounter]); - if (text[textCounter]->speech) { - _vm->_mixer->playRaw(&handle, text[textCounter]->speech, text[textCounter]->speechBufferSize, 22050, flags); - } - } - if (frameCounter == text[textCounter]->endFrame) { - closeTextObject(text[textCounter]); - _vm->_graphics->clearScene(); - _vm->_graphics->setNeedFullRedraw(); - textCounter++; - } - - frameCounter++; - - _vm->_graphics->updateDisplay(); - - KeyboardEvent ke; - - if ((_vm->_input->readKey(&ke) == RD_OK && ke.keycode == 27) || _vm->_quit) { - _vm->_mixer->stopHandle(handle); - skipCutscene = true; - break; - } - - // Simulate ~12 frames per second. I don't know what - // frame rate the original movies had, or even if it - // was constant, but this seems to work reasonably. - - _vm->_system->delay_msecs(90); - } - - // 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 - // it's in use. - - while (handle.isActive()) { - _vm->_graphics->updateDisplay(false); - _vm->_system->delay_msecs(100); - } - - closeTextObject(text[textCounter]); - - _vm->_graphics->clearScene(); - _vm->_graphics->setNeedFullRedraw(); - - // HACK: Remove the instructions created above - Common::Rect r; - - memset(_vm->_graphics->_buffer, 0, _vm->_graphics->_screenWide * MENUDEEP); - r.left = r.top = 0; - r.right = _vm->_graphics->_screenWide; - r.bottom = MENUDEEP; - _vm->_graphics->updateRect(&r); - - // FIXME: For now, only play the lead-out music for cutscenes - // that have subtitles. - - if (!skipCutscene) - _vm->_sound->playLeadOut(musicOut); - - _vm->_graphics->setPalette(0, 256, oldPal, RDPAL_INSTANT); - } - - // 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. - - _vm->_sound->closeFx(-1); - _vm->_sound->closeFx(-2); - - return RD_OK; -} - } // End of namespace Sword2 diff --git a/sword2/driver/d_draw.h b/sword2/driver/d_draw.h index f98e77999c..49cc544124 100644 --- a/sword2/driver/d_draw.h +++ b/sword2/driver/d_draw.h @@ -65,27 +65,6 @@ struct MouseAnim { #pragma END_PACK_STRUCTS #endif -class MoviePlayer { -private: - Sword2Engine *_vm; - uint8 *_textSurface; - - void openTextObject(MovieTextObject *obj); - void closeTextObject(MovieTextObject *obj); - void drawTextObject(MovieTextObject *obj); - - void checkPaletteSwitch(AnimationState * st); - - AnimationState * initAnimation(const char *name); - void doneAnimation(AnimationState * st); - bool decodeFrame(AnimationState * st); - -public: - MoviePlayer(Sword2Engine *vm) : _vm(vm), _textSurface(NULL) {} - int32 play(const char *filename, MovieTextObject *text[], uint8 *musicOut); - int32 playDummy(const char *filename, MovieTextObject *text[], uint8 *musicOut); -}; - struct BlockSurface { byte data[BLOCKWIDTH * BLOCKHEIGHT]; bool transparent; |