aboutsummaryrefslogtreecommitdiff
path: root/engines/sword2
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sword2')
-rw-r--r--engines/sword2/animation.cpp958
-rw-r--r--engines/sword2/animation.h143
-rw-r--r--engines/sword2/function.cpp14
-rw-r--r--engines/sword2/render.cpp31
-rw-r--r--engines/sword2/screen.h4
5 files changed, 731 insertions, 419 deletions
diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp
index 50adeef69b..cd0baaa980 100644
--- a/engines/sword2/animation.cpp
+++ b/engines/sword2/animation.cpp
@@ -20,9 +20,10 @@
*/
#include "common/stdafx.h"
-#include "common/file.h"
#include "common/config-manager.h"
+#include "common/file.h"
#include "common/system.h"
+
#include "sound/vorbis.h"
#include "sound/mp3.h"
@@ -30,6 +31,7 @@
#include "sword2/defs.h"
#include "sword2/header.h"
#include "sword2/maketext.h"
+#include "sword2/mouse.h"
#include "sword2/resman.h"
#include "sword2/screen.h"
#include "sword2/sound.h"
@@ -37,94 +39,15 @@
namespace Sword2 {
-AnimationState::AnimationState(Sword2Engine *vm)
- : BaseAnimationState(vm->_mixer, vm->_system, 640, 480), _vm(vm) {
-}
-
-AnimationState::~AnimationState() {
-}
-
-#ifdef BACKEND_8BIT
-
-void AnimationState::setPalette(byte *pal) {
- _vm->_screen->setPalette(0, 256, pal, RDPAL_INSTANT);
-}
-
-#else
-
-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;
-
- OverlayColor pen = _sys->RGBToColor(255, 255, 255);
- OverlayColor border = _sys->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));
- }
+// TODO: The interaction between the basic cutscene player class and the
+// specific plyers is sometimes a bit awkward, since our classes for
+// DXA and MPEG decoding are so fundamentally different. The DXA decoder
+// is just a decoder, while the MPEG decoder has delusions of being a
+// player. This could probably be simplified quite a bit.
- dst += _movieScale * moviePitch;
- src += s->w;
- }
-}
-
-#endif
-
-void AnimationState::clearScreen() {
-#ifdef BACKEND_8BIT
- memset(_vm->_screen->getScreen(), 0, _movieWidth * _movieHeight);
-#else
- OverlayColor black = _sys->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
- _vm->_screen->plotYUV(_lut, width, height, dat);
-#else
- plotYUV(width, height, dat);
-#endif
-}
+///////////////////////////////////////////////////////////////////////////////
+// Basic movie player
+///////////////////////////////////////////////////////////////////////////////
MovieInfo MoviePlayer::_movies[] = {
{ "carib", 222, false },
@@ -141,208 +64,318 @@ MovieInfo MoviePlayer::_movies[] = {
{ "river", 656, false },
{ "sailing", 138, false },
{ "shaman", 788, true },
- { "stone1", 34, false },
+ { "stone1", 34, true },
{ "stone2", 282, false },
- { "stone3", 65, false },
+ { "stone3", 65, true },
{ "demo", 60, false },
{ "enddemo", 110, false }
};
-MoviePlayer::MoviePlayer(Sword2Engine *vm)
- : _vm(vm), _snd(_vm->_mixer), _sys(_vm->_system), _textSurface(NULL) {
+MoviePlayer::MoviePlayer(Sword2Engine *vm) {
+ _vm = vm;
+ _mixer = _vm->_mixer;
+ _system = _vm->_system;
+ _textSurface = NULL;
+ _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;
+ _forceFrame = false;
+ _textList = NULL;
+ _currentText = 0;
}
-void MoviePlayer::openTextObject(MovieTextObject *obj) {
- if (obj->textSprite)
- _vm->_screen->createSurface(obj->textSprite, &_textSurface);
+MoviePlayer::~MoviePlayer() {
}
-void MoviePlayer::closeTextObject(MovieTextObject *obj) {
- if (_textSurface) {
- _vm->_screen->deleteSurface(_textSurface);
- _textSurface = NULL;
- }
-}
+void MoviePlayer::updatePalette(byte *pal, bool packed) {
+ byte palette[4 * 256];
+ byte *p = palette;
-void MoviePlayer::drawTextObject(AnimationState *anim, MovieTextObject *obj) {
- if (obj->textSprite && _textSurface) {
-#ifdef BACKEND_8BIT
- _vm->_screen->drawSurface(obj->textSprite, _textSurface);
-#else
- if (anim)
- anim->drawTextObject(obj->textSprite, _textSurface);
- else
- _vm->_screen->drawSurface(obj->textSprite, _textSurface);
-#endif
+ 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) {
+ _black = i;
+ maxWeight = weight;
+ }
+
+ if (weight <= minWeight) {
+ _white = i;
+ minWeight = i;
+ }
+
+ *p++ = r;
+ *p++ = g;
+ *p++ = b;
+ *p++ = 0;
}
+
+ _vm->_screen->setPalette(0, 256, palette, RDPAL_INSTANT);
+ _forceFrame = true;
}
-/**
- * Plays an animated cutscene.
- * @param filename the file name of the cutscene file
- * @param text the subtitles and voiceovers for the cutscene
- * @param leadInRes lead-in music resource id
- * @param leadOutRes lead-out music resource id
- */
+void MoviePlayer::savePalette() {
+ memcpy(_originalPalette, _vm->_screen->getPalette(), sizeof(_originalPalette));
+}
-int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], int32 leadInRes, int32 leadOutRes) {
- Audio::SoundHandle leadInHandle;
+void MoviePlayer::restorePalette() {
+ _vm->_screen->setPalette(0, 256, _originalPalette, RDPAL_INSTANT);
+}
- // This happens if the user quits during the "eye" smacker
- if (_vm->_quit)
- return RD_OK;
+void MoviePlayer::clearScreen() {
+ _vm->_screen->clearScene();
+ _system->copyRectToScreen(_vm->_screen->getScreen(), _vm->_screen->getScreenWide(), 0, 0, _vm->_screen->getScreenWide(), _vm->_screen->getScreenDeep());
+}
- if (leadInRes) {
- byte *leadIn = _vm->_resman->openResource(leadInRes);
- uint32 leadInLen = _vm->_resman->fetchLen(leadInRes) - ResHeader::size();
+void MoviePlayer::updateScreen() {
+ _system->updateScreen();
+}
- assert(_vm->_resman->fetchType(leadIn) == WAV_FILE);
+bool MoviePlayer::checkSkipFrame() {
+ if (_forceFrame) {
+ _forceFrame = false;
+ return false;
+ }
- leadIn += ResHeader::size();
+ if (_framesSkipped > 10) {
+ warning("Forced frame %d to be displayed", _currentFrame);
+ _framesSkipped = 0;
+ return false;
+ }
- _vm->_sound->playFx(&leadInHandle, leadIn, leadInLen, Audio::Mixer::kMaxChannelVolume, 0, false, Audio::Mixer::kMusicSoundType);
+ if (_bgSoundStream) {
+ if ((_mixer->getSoundElapsedTime(_bgSoundHandle) * 12) / 1000 < _currentFrame + 1)
+ return false;
+ } else {
+ if (_system->getMillis() <= _ticks)
+ return false;
}
- byte *leadOut = NULL;
- uint32 leadOutLen = 0;
+ _framesSkipped++;
+ return true;
+}
- if (leadOutRes) {
- leadOut = _vm->_resman->openResource(leadOutRes);
- leadOutLen = _vm->_resman->fetchLen(leadOutRes) - ResHeader::size();
+void MoviePlayer::waitForFrame() {
+ if (_bgSoundStream) {
+ while (_mixer->isSoundHandleActive(_bgSoundHandle) && (_mixer->getSoundElapsedTime(_bgSoundHandle) * 12) / 1000 < _currentFrame) {
+ _system->delayMillis(10);
+ }
- assert(_vm->_resman->fetchType(leadOut) == WAV_FILE);
+ // 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.
- leadOut += ResHeader::size();
+ _ticks = _system->getMillis();
+ } else {
+ while (_system->getMillis() < _ticks) {
+ _system->delayMillis(10);
+ }
}
+}
- _leadOutFrame = (uint)-1;
-
- int i;
+void MoviePlayer::drawFrame() {
+ _ticks += 83;
- for (i = 0; i < ARRAYSIZE(_movies); i++) {
- if (scumm_stricmp(filename, _movies[i].name) == 0) {
- _seamless = _movies[i].seamless;
- if (_movies[i].frames > 60)
- _leadOutFrame = _movies[i].frames - 60;
- break;
- }
+ if (checkSkipFrame()) {
+ warning("Skipped frame %d", _currentFrame);
+ return;
}
- if (i == ARRAYSIZE(_movies))
- warning("Unknown movie, '%s'", filename);
+ waitForFrame();
-#ifdef USE_MPEG2
- playMPEG(filename, text, leadOut, leadOutLen);
-#else
- // No MPEG2? Use the old 'Narration Only' hack
- playDummy(filename, text, leadOut, leadOutLen);
-#endif
+ int screenWidth = _vm->_screen->getScreenWide();
- _snd->stopHandle(leadInHandle);
+ _system->copyRectToScreen(_frameBuffer + _frameY * screenWidth + _frameX, screenWidth, _frameX, _frameY, _frameWidth, _frameHeight);
+ _vm->_screen->setNeedFullRedraw();
+}
- // Wait for the lead-out to stop, if there is any. Though don't do it
- // for seamless movies, since they are meant to blend into the rest of
- // the game.
+void MoviePlayer::openTextObject(MovieTextObject *t) {
+ if (t->textSprite) {
+ _vm->_screen->createSurface(t->textSprite, &_textSurface);
+ }
+}
- if (!_seamless) {
- while (_vm->_mixer->isSoundHandleActive(_leadOutHandle)) {
- _vm->_screen->updateDisplay();
- _vm->_system->delayMillis(30);
+void MoviePlayer::closeTextObject(MovieTextObject *t) {
+ if (_textSurface) {
+ _vm->_screen->deleteSurface(_textSurface);
+ _textSurface = NULL;
+ }
+}
+
+void MoviePlayer::drawTextObject(MovieTextObject *t) {
+ if (t->textSprite && _textSurface) {
+ int screenWidth = _vm->_screen->getScreenWide();
+ byte *src = t->textSprite->data;
+ byte *dst = _frameBuffer + (_frameY + _frameHeight - t->textSprite->h - 20) * screenWidth + _frameX + (_frameWidth - t->textSprite->w) / 2;
+
+ for (int y = 0; y < t->textSprite->h; y++) {
+ for (int x = 0; x < t->textSprite->w; x++) {
+ if (src[x] == 1)
+ dst[x] = _white;
+ else if (src[x] == 255)
+ dst[x] = _black;
+ }
+ src += t->textSprite->w;
+ dst += screenWidth;
}
}
+}
- if (leadInRes)
- _vm->_resman->closeResource(leadInRes);
+void MoviePlayer::undrawTextObject(MovieTextObject *t) {
+}
- if (leadOutRes)
- _vm->_resman->closeResource(leadOutRes);
+bool MoviePlayer::load(const char *name, MovieTextObject *text[]) {
+ _bgSoundStream = NULL;
+ _textList = text;
+ _currentText = 0;
+ _currentFrame = 0;
- return RD_OK;
+ 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;
+ return true;
+ }
+ }
+
+ return false;
}
-void MoviePlayer::playMPEG(const char *filename, MovieTextObject *text[], byte *leadOut, uint32 leadOutLen) {
- uint frameCounter = 0, textCounter = 0;
- Audio::SoundHandle handle;
- bool skipCutscene = false, textVisible = false;
- uint32 flags = Audio::Mixer::FLAG_16BITS;
+void MoviePlayer::play(int32 leadIn, int32 leadOut) {
+ bool terminate = false;
+ bool textVisible = false;
bool startNextText = false;
+ byte *data;
+ uint32 len;
+ Audio::SoundHandle leadInHandle, leadOutHandle;
+ uint32 flags = Audio::Mixer::FLAG_16BITS;
+
+ // This happens if the user quits during the "eye" cutscene.
+ if (_vm->_quit)
+ return;
- byte oldPal[256 * 4];
- memcpy(oldPal, _vm->_screen->getPalette(), sizeof(oldPal));
+ if (leadIn) {
+ data = _vm->_resman->openResource(leadIn);
+ len = _vm->_resman->fetchLen(leadIn) - ResHeader::size();
- AnimationState *anim = new AnimationState(_vm);
+ assert(_vm->_resman->fetchType(data) == WAV_FILE);
- if (!anim->init(filename)) {
- delete anim;
- anim = NULL;
- // Missing Files? Use the old 'Narration Only' hack
- playDummy(filename, text, leadOut, leadOutLen);
- return;
+ data += ResHeader::size();
+
+ _vm->_sound->playFx(&leadInHandle, data, len, Audio::Mixer::kMaxChannelVolume, 0, false, Audio::Mixer::kMusicSoundType);
+ }
+
+ savePalette();
+
+ // 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.
+
+ _vm->_mouse->closeMenuImmediately();
+
+ if (!_seamless) {
+ _vm->_screen->clearScene();
}
- // Clear the screen, because whatever is on it will be visible when the
- // overlay is removed. And if there isn't an overlay, we don't want it
- // to be visible during the cutscene. (Not all cutscenes cover the
- // entire screen.)
- _vm->_screen->clearScene();
_vm->_screen->updateDisplay();
#ifndef SCUMM_BIG_ENDIAN
flags |= Audio::Mixer::FLAG_LITTLE_ENDIAN;
#endif
- while (!skipCutscene && anim->decodeFrame()) {
- // The frame has been drawn. Now draw the subtitles, if any,
- // before updating the screen.
+ _framesSkipped = 0;
+
+ _ticks = _system->getMillis();
+
+ if (_bgSoundStream) {
+ _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_bgSoundHandle, _bgSoundStream);
+ }
- if (text && text[textCounter]) {
- if (frameCounter == text[textCounter]->startFrame) {
- openTextObject(text[textCounter]);
+ while (!terminate && _currentFrame < _numFrames && decodeFrame()) {
+ _currentFrame++;
+
+ // The frame has been decoded. Now draw the subtitles, if any,
+ // before drawing it to the screen.
+
+ if (_textList && _textList[_currentText]) {
+ MovieTextObject *t = _textList[_currentText];
+
+ if (_currentFrame == t->startFrame) {
+ openTextObject(t);
textVisible = true;
- if (text[textCounter]->speech) {
+ if (t->speech) {
startNextText = true;
}
}
- if (startNextText && !_snd->isSoundHandleActive(handle)) {
- _snd->playRaw(&handle, text[textCounter]->speech, text[textCounter]->speechBufferSize, 22050, flags);
+ if (startNextText && !_mixer->isSoundHandleActive(_speechHandle)) {
+ _mixer->playRaw(&_speechHandle, t->speech, t->speechBufferSize, 22050, flags);
startNextText = false;
}
- if (frameCounter == text[textCounter]->endFrame) {
- closeTextObject(text[textCounter]);
- textCounter++;
+ if (_currentFrame == t->endFrame) {
+ undrawTextObject(t);
+ closeTextObject(t);
+ _currentText++;
textVisible = false;
}
if (textVisible)
- drawTextObject(anim, text[textCounter]);
+ drawTextObject(t);
}
-#ifdef BACKEND_8BIT
- _sys->copyRectToScreen(_vm->_screen->getScreen(), 640, 0, 0, 640, 480);
-#endif
+ if (leadOut && _currentFrame == _leadOutFrame) {
+ data = _vm->_resman->openResource(leadOut);
+ len = _vm->_resman->fetchLen(leadOut) - ResHeader::size();
- anim->updateScreen();
- frameCounter++;
+ assert(_vm->_resman->fetchType(data) == WAV_FILE);
- if (frameCounter == _leadOutFrame && leadOut)
- _vm->_sound->playFx(&_leadOutHandle, leadOut, leadOutLen, Audio::Mixer::kMaxChannelVolume, 0, false, Audio::Mixer::kMusicSoundType);
+ data += ResHeader::size();
+
+ _vm->_sound->playFx(&leadOutHandle, data, len, Audio::Mixer::kMaxChannelVolume, 0, false, Audio::Mixer::kMusicSoundType);
+ }
+
+ drawFrame();
+ updateScreen();
OSystem::Event event;
- while (_sys->pollEvent(event)) {
+
+ while (_system->pollEvent(event)) {
switch (event.type) {
case OSystem::EVENT_SCREEN_CHANGED:
- anim->handleScreenChanged();
- break;
- case OSystem::EVENT_KEYDOWN:
- if (event.kbd.keycode == 27)
- skipCutscene = true;
+ handleScreenChanged();
break;
case OSystem::EVENT_QUIT:
_vm->closeGame();
- skipCutscene = true;
+ terminate = true;
+ break;
+ case OSystem::EVENT_KEYDOWN:
+ if (event.kbd.keycode == 27)
+ terminate = true;
break;
default:
break;
@@ -350,208 +383,433 @@ void MoviePlayer::playMPEG(const char *filename, MovieTextObject *text[], byte *
}
}
- if (!skipCutscene) {
- // Sleep for one frame so that the last frame is displayed.
- _sys->delayMillis(1000 / 12);
- }
-
if (!_seamless) {
- // 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->clearScreen();
- }
+ // Most cutscenes fade to black on their own, but not all of
+ // them. I think it looks better if they do.
- // If the speech is still playing, redraw the subtitles. At least in
- // the English version this is most noticeable in the "carib" cutscene.
+ clearScreen();
- if (textVisible && _snd->isSoundHandleActive(handle))
- drawTextObject(anim, text[textCounter]);
+ // If the sound is still playing, draw the subtitles one final
+ // time. This happens in the "carib" cutscene.
- if (text)
- closeTextObject(text[textCounter]);
+ if (textVisible && _mixer->isSoundHandleActive(_speechHandle)) {
+ drawTextObject(_textList[_currentText]);
+ }
- anim->updateScreen();
+ updateScreen();
+ }
- // 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.
+ if (!terminate) {
+ // 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 still in use.
- if (skipCutscene)
- _snd->stopHandle(handle);
+ while (_mixer->isSoundHandleActive(_speechHandle)) {
+ _system->delayMillis(100);
+ }
- while (_snd->isSoundHandleActive(handle)) {
- _vm->_screen->updateDisplay(false);
- _sys->delayMillis(100);
+ while (_mixer->isSoundHandleActive(_bgSoundHandle)) {
+ _system->delayMillis(100);
+ }
+ } else {
+ _mixer->stopHandle(_speechHandle);
+ _mixer->stopHandle(_bgSoundHandle);
}
if (!_seamless) {
- // Clear the screen again
- anim->clearScreen();
- anim->updateScreen();
+ clearScreen();
+ updateScreen();
}
- _vm->_screen->setPalette(0, 256, oldPal, RDPAL_INSTANT);
+ // Setting the palette implies a full redraw.
+ restorePalette();
+}
+
+#ifdef USE_ZLIB
+
+///////////////////////////////////////////////////////////////////////////////
+// Movie player for the new DXA movies
+///////////////////////////////////////////////////////////////////////////////
- delete anim;
- anim = NULL;
+MoviePlayerDXA::MoviePlayerDXA(Sword2Engine *vm) : MoviePlayer(vm) {
+ debug(0, "Creating DXA cutscene player");
}
-/**
- * This just plays the cutscene with voiceovers / subtitles, in case the files
- * are missing.
- */
+MoviePlayerDXA::~MoviePlayerDXA() {
+ closeFile();
+}
-void MoviePlayer::playDummy(const char *filename, MovieTextObject *text[], byte *leadOut, uint32 leadOutLen) {
- if (!text)
- return;
+void MoviePlayerDXA::setPalette(byte *pal) {
+ updatePalette(pal);
+}
- int frameCounter = 0, textCounter = 0;
+bool MoviePlayerDXA::decodeFrame() {
+ decodeNextFrame();
+ copyFrameToBuffer(_frameBuffer, _frameX, _frameY, _vm->_screen->getScreenWide());
+ return true;
+}
- byte oldPal[256 * 4];
- byte tmpPal[256 * 4];
+bool MoviePlayerDXA::load(const char *name, MovieTextObject *text[]) {
+ if (!MoviePlayer::load(name, text))
+ return false;
- _vm->_screen->clearScene();
+ char filename[20];
- // HACK: Draw instructions
- //
- // I'm using the the menu area, because that's unlikely to be touched
- // by anything else during the cutscene.
+ snprintf(filename, sizeof(filename), "%s.dxa", name);
- memset(_vm->_screen->getScreen(), 0, _vm->_screen->getScreenWide() * MENUDEEP);
+ if (loadFile(filename)) {
+ // The Broken Sword games always use external audio tracks.
+ if (_fd.readUint32BE() != MKID_BE('NULL'))
+ return false;
- byte *data;
+ _frameBuffer = _vm->_screen->getScreen();
- // Russian version substituted latin characters with cyrillic. That's
- // why it renders completely unreadable with default message
- if (Common::parseLanguage(ConfMan.get("language")) == Common::RU_RUS) {
- byte msg[] = "Po\344uk - to\344\345ko pev\345: hagmute k\344abuwy Ucke\343n, u\344u nocetute ca\343t npoekta u ckava\343te budeo po\344uku";
- data = _vm->_fontRenderer->makeTextSprite(msg, RENDERWIDE, 255, _vm->_speechFontId);
- } else {
- // TODO: Translate message to other languages?
-#ifdef USE_MPEG2
- byte msg[] = "Cutscene - Narration Only: Press ESC to exit, or visit www.scummvm.org to download cutscene videos";
+ _frameWidth = getWidth();
+ _frameHeight = getHeight();
+
+ _frameX = (_vm->_screen->getScreenWide() - _frameWidth) / 2;
+ _frameY = (_vm->_screen->getScreenDeep() - _frameHeight) / 2;
+
+ _bgSoundStream = Audio::AudioStream::openStreamFile(name);
+
+ return true;
+ }
+
+ return false;
+}
+
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Movie player for the old MPEG movies
+///////////////////////////////////////////////////////////////////////////////
+
+MoviePlayerMPEG::MoviePlayerMPEG(Sword2Engine *vm) : MoviePlayer(vm) {
+#ifdef BACKEND_8BIT
+ debug(0, "Creating MPEG cutscene player (8-bit)");
#else
- byte msg[] = "Cutscene - Narration Only: Press ESC to exit, or recompile ScummVM with MPEG2 support";
+ debug(0, "Creating MPEG cutscene player (16-bit)");
#endif
+}
+
+MoviePlayerMPEG::~MoviePlayerMPEG() {
+ delete _anim;
+ _anim = NULL;
+}
- data = _vm->_fontRenderer->makeTextSprite(msg, RENDERWIDE, 255, _vm->_speechFontId);
+bool MoviePlayerMPEG::load(const char *name, MovieTextObject *text[]) {
+ if (!MoviePlayer::load(name, text))
+ return false;
+
+ _anim = new AnimationState(_vm, this);
+
+ if (!_anim->init(name)) {
+ delete _anim;
+ _anim = NULL;
+ return false;
}
- FrameHeader frame_head;
- SpriteInfo msgSprite;
- byte *msgSurface;
+#ifdef BACKEND_8BIT
+ _frameBuffer = _vm->_screen->getScreen();
+#endif
- frame_head.read(data);
+ return true;
+}
- msgSprite.x = _vm->_screen->getScreenWide() / 2 - frame_head.width / 2;
- msgSprite.y = MENUDEEP / 2 - frame_head.height / 2;
- msgSprite.w = frame_head.width;
- msgSprite.h = frame_head.height;
- msgSprite.type = RDSPR_NOCOMPRESSION;
- msgSprite.data = data + FrameHeader::size();
+bool MoviePlayerMPEG::checkSkipFrame() {
+ return false;
+}
- _vm->_screen->createSurface(&msgSprite, &msgSurface);
- _vm->_screen->drawSurface(&msgSprite, msgSurface);
- _vm->_screen->deleteSurface(msgSurface);
+void MoviePlayerMPEG::waitForFrame() {
+}
- free(data);
+bool MoviePlayerMPEG::decodeFrame() {
+ bool result = _anim->decodeFrame();
- // In case the cutscene has a long lead-in, start just before the first
- // line of text.
+#ifdef BACKEND_8BIT
+ _frameWidth = _anim->getFrameWidth();
+ _frameHeight = _anim->getFrameHeight();
- frameCounter = text[0]->startFrame - 12;
+ _frameX = (_vm->_screen->getScreenWide() - _frameWidth) / 2;
+ _frameY = (_vm->_screen->getScreenDeep() - _frameHeight) / 2;
+#endif
- // Fake a palette that will hopefully make the text visible. In the
- // opening cutscene it seems to use colours 1 (black) and 255 (white).
+ return result;
+}
- memcpy(oldPal, _vm->_screen->getPalette(), sizeof(oldPal));
- memset(tmpPal, 0, sizeof(tmpPal));
- tmpPal[255 * 4 + 0] = 255;
- tmpPal[255 * 4 + 1] = 255;
- tmpPal[255 * 4 + 2] = 255;
- _vm->_screen->setPalette(0, 256, tmpPal, RDPAL_INSTANT);
+#ifndef BACKEND_8BIT
+void MoviePlayerMPEG::handleScreenChanged() {
+ _anim->handleScreenChanged();
+}
- Audio::SoundHandle handle;
+void MoviePlayerMPEG::clearScreen() {
+ _anim->clearScreen();
+}
- bool skipCutscene = false;
+void MoviePlayerMPEG::drawFrame() {
+}
- uint32 flags = Audio::Mixer::FLAG_16BITS;
+void MoviePlayerMPEG::updateScreen() {
+ _anim->updateScreen();
+}
-#ifndef SCUMM_BIG_ENDIAN
- flags |= Audio::Mixer::FLAG_LITTLE_ENDIAN;
+void MoviePlayerMPEG::drawTextObject(MovieTextObject *t) {
+ if (t->textSprite && _textSurface) {
+ _anim->drawTextObject(t->textSprite, _textSurface);
+ }
+}
#endif
- while (1) {
- if (!text[textCounter])
- break;
+AnimationState::AnimationState(Sword2Engine *vm, MoviePlayer *player)
+ : BaseAnimationState(vm->_mixer, vm->_system, 640, 480) {
+ _vm = vm;
+ _player = player;
+}
+
+AnimationState::~AnimationState() {
+}
+
+#ifdef BACKEND_8BIT
+void AnimationState::setPalette(byte *pal) {
+ _player->updatePalette(pal, false);
+}
+#else
+
+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;
+
+ OverlayColor pen = _sys->RGBToColor(255, 255, 255);
+ OverlayColor border = _sys->RGBToColor(0, 0, 0);
- if (frameCounter == text[textCounter]->startFrame) {
- _vm->_screen->clearScene();
- openTextObject(text[textCounter]);
- drawTextObject(NULL, text[textCounter]);
- if (text[textCounter]->speech) {
- _snd->playRaw(&handle, text[textCounter]->speech, text[textCounter]->speechBufferSize, 22050, flags);
+ // 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 (frameCounter == text[textCounter]->endFrame) {
- closeTextObject(text[textCounter]);
- _vm->_screen->clearScene();
- _vm->_screen->setNeedFullRedraw();
- textCounter++;
+ 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));
}
- frameCounter++;
- _vm->_screen->updateDisplay();
+ dst += _movieScale * moviePitch;
+ src += s->w;
+ }
+}
- KeyboardEvent *ke = _vm->keyboardEvent();
+#endif
- if ((ke && ke->keycode == 27) || _vm->_quit) {
- _snd->stopHandle(handle);
- skipCutscene = true;
- break;
+void AnimationState::clearScreen() {
+#ifdef BACKEND_8BIT
+ memset(_vm->_screen->getScreen(), 0, _movieWidth * _movieHeight);
+#else
+ OverlayColor black = _sys->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
+}
- // 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.
+///////////////////////////////////////////////////////////////////////////////
+// Dummy player for subtitled speech only
+///////////////////////////////////////////////////////////////////////////////
+
+MoviePlayerDummy::MoviePlayerDummy(Sword2Engine *vm) : MoviePlayer(vm) {
+ debug(0, "Creating Dummy cutscene player");
+}
- _sys->delayMillis(90);
+MoviePlayerDummy::~MoviePlayerDummy() {
+}
+
+bool MoviePlayerDummy::load(const char *name, MovieTextObject *text[]) {
+ if (!MoviePlayer::load(name, text))
+ return false;
+
+ _frameBuffer = _vm->_screen->getScreen();
+
+ _frameWidth = 640;
+ _frameHeight = 400;
+ _frameX = 0;
+ _frameY = 40;
+
+ return true;
+}
+
+bool MoviePlayerDummy::decodeFrame() {
+ if (_currentFrame == 0 && _textList) {
+ 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_MPEG2) || 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");
+#endif
+
+ byte *msg;
+
+ // Russian version substituted latin characters with Cyrillic.
+ if (Common::parseLanguage(ConfMan.get("language")) == Common::RU_RUS) {
+ msg = msgNoCutscenesRU;
+ } else {
+ msg = msgNoCutscenes;
+ }
+
+ 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();
}
- // 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.
+ // If we have played the final voice-over, skip ahead to the lead out
- while (_snd->isSoundHandleActive(handle)) {
- _vm->_screen->updateDisplay(false);
- _sys->delayMillis(100);
+ if (_textList && !_textList[_currentText] && !_mixer->isSoundHandleActive(_speechHandle) && _leadOutFrame != (uint)-1 && _currentFrame < _leadOutFrame) {
+ _currentFrame = _leadOutFrame - 1;
}
- closeTextObject(text[textCounter]);
+ return true;
+}
- _vm->_screen->clearScene();
- _vm->_screen->setNeedFullRedraw();
+bool MoviePlayerDummy::checkSkipFrame() {
+ return false;
+}
+
+void MoviePlayerDummy::waitForFrame() {
+ if (!_textList || _currentFrame < _textList[0]->startFrame) {
+ _ticks = _system->getMillis();
+ return;
+ }
+
+ MoviePlayer::waitForFrame();
+}
+
+void MoviePlayerDummy::drawFrame() {
+ _ticks += 83;
+ waitForFrame();
+}
- // HACK: Remove the instructions created above
- Common::Rect r;
+void MoviePlayerDummy::drawTextObject(MovieTextObject *t) {
+ _vm->_screen->drawSurface(t->textSprite, _textSurface);
+}
+
+void MoviePlayerDummy::undrawTextObject(MovieTextObject *t) {
+ memset(_textSurface, 1, t->textSprite->w * t->textSprite->h);
+ drawTextObject(t);
+}
- memset(_vm->_screen->getScreen(), 0, _vm->_screen->getScreenWide() * MENUDEEP);
- r.left = r.top = 0;
- r.right = _vm->_screen->getScreenWide();
- r.bottom = MENUDEEP;
- _vm->_screen->updateRect(&r);
+///////////////////////////////////////////////////////////////////////////////
+// Factory function for creating the appropriate cutscene player
+///////////////////////////////////////////////////////////////////////////////
- // FIXME: For now, only play the lead-out music for cutscenes that have
- // subtitles.
+MoviePlayer *makeMoviePlayer(Sword2Engine *vm, const char *name) {
+ char filename[20];
- if (!skipCutscene && leadOut)
- _vm->_sound->playFx(&_leadOutHandle, leadOut, leadOutLen, Audio::Mixer::kMaxChannelVolume, 0, false, Audio::Mixer::kMusicSoundType);
+#ifdef USE_ZLIB
+ snprintf(filename, sizeof(filename), "%s.dxa", name);
+
+ if (Common::File::exists(filename)) {
+ return new MoviePlayerDXA(vm);
+ }
+#endif
+
+#ifdef USE_MPEG2
+ snprintf(filename, sizeof(filename), "%s.mp2", name);
+
+ if (Common::File::exists(filename)) {
+ return new MoviePlayerMPEG(vm);
+ }
+#endif
- _vm->_screen->setPalette(0, 256, oldPal, RDPAL_INSTANT);
+ return new MoviePlayerDummy(vm);
}
} // End of namespace Sword2
diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h
index 32598c013d..09ece3b8e8 100644
--- a/engines/sword2/animation.h
+++ b/engines/sword2/animation.h
@@ -23,6 +23,7 @@
#define SWORD2_ANIMATION_H
#include "graphics/animation.h"
+#include "graphics/dxa_player.h"
#include "sound/mixer.h"
namespace Sword2 {
@@ -41,12 +42,97 @@ struct MovieTextObject {
uint16 *speech;
};
+struct MovieInfo {
+ const char *name;
+ const uint frames;
+ const bool seamless;
+};
+
+class MoviePlayer {
+protected:
+ Sword2Engine *_vm;
+ Audio::Mixer *_mixer;
+ OSystem *_system;
+
+ byte _originalPalette[4 * 256];
+
+ byte *_textSurface;
+
+ Audio::SoundHandle _speechHandle;
+ Audio::SoundHandle _bgSoundHandle;
+ Audio::AudioStream *_bgSoundStream;
+
+ uint32 _ticks;
+
+ uint _currentFrame;
+ byte *_frameBuffer;
+ int _frameWidth, _frameHeight;
+ int _frameX, _frameY;
+
+ byte _black, _white;
+
+ uint _numFrames;
+ uint _leadOutFrame;
+ bool _seamless;
+
+ int _framesSkipped;
+ bool _forceFrame;
+
+ static struct MovieInfo _movies[];
+
+ MovieTextObject **_textList;
+ int _currentText;
+
+ void savePalette();
+ void restorePalette();
+
+ void openTextObject(MovieTextObject *t);
+ void closeTextObject(MovieTextObject *t);
+
+ virtual void handleScreenChanged() {}
+
+ virtual void clearScreen();
+ virtual void updateScreen();
+ virtual bool decodeFrame() = 0;
+ virtual bool checkSkipFrame();
+ virtual void waitForFrame();
+ virtual void drawFrame();
+ virtual void drawTextObject(MovieTextObject *t);
+ virtual void undrawTextObject(MovieTextObject *t);
+
+public:
+ MoviePlayer(Sword2Engine *vm);
+ virtual ~MoviePlayer();
+
+ void updatePalette(byte *pal, bool packed = true);
+ virtual bool load(const char *name, MovieTextObject *text[]);
+ void play(int32 leadIn, int32 leadOut);
+};
+
+class MoviePlayerDummy : public MoviePlayer {
+protected:
+ virtual bool decodeFrame();
+ virtual bool checkSkipFrame();
+ virtual void waitForFrame();
+ virtual void drawFrame();
+ virtual void drawTextObject(MovieTextObject *t);
+ virtual void undrawTextObject(MovieTextObject *t);
+
+public:
+ MoviePlayerDummy(Sword2Engine *vm);
+ virtual ~MoviePlayerDummy();
+
+ virtual bool load(const char *name, MovieTextObject *text[]);
+};
+
+#ifdef USE_MPEG2
class AnimationState : public ::Graphics::BaseAnimationState {
private:
Sword2Engine *_vm;
+ MoviePlayer *_player;
public:
- AnimationState(Sword2Engine *vm);
+ AnimationState(Sword2Engine *vm, MoviePlayer *player);
~AnimationState();
#ifndef BACKEND_8BIT
@@ -63,38 +149,45 @@ private:
#endif
};
-struct MovieInfo {
- char name[9];
- uint frames;
- bool seamless;
-};
+class MoviePlayerMPEG : public MoviePlayer {
+protected:
+ AnimationState *_anim;
-class MoviePlayer {
-private:
- Sword2Engine *_vm;
- Audio::Mixer *_snd;
- OSystem *_sys;
-
- byte *_textSurface;
+ virtual bool checkSkipFrame();
+ virtual void waitForFrame();
+ virtual bool decodeFrame();
- Audio::SoundHandle _leadOutHandle;
-
- uint _leadOutFrame;
- bool _seamless;
+#ifndef BACKEND_8BIT
+ virtual void handleScreenChanged();
+ virtual void clearScreen();
+ virtual void drawFrame();
+ virtual void updateScreen();
+ virtual void drawTextObject(MovieTextObject *t);
+#endif
- static struct MovieInfo _movies[];
+public:
+ MoviePlayerMPEG(Sword2Engine *vm);
+ virtual ~MoviePlayerMPEG();
- void openTextObject(MovieTextObject *obj);
- void closeTextObject(MovieTextObject *obj);
- void drawTextObject(AnimationState *anim, MovieTextObject *obj);
+ virtual bool load(const char *name, MovieTextObject *text[]);
+};
+#endif
- void playMPEG(const char *filename, MovieTextObject *text[], byte *leadOut, uint32 leadOutLen);
- void playDummy(const char *filename, MovieTextObject *text[], byte *leadOut, uint32 leadOutLen);
+#ifdef USE_ZLIB
+class MoviePlayerDXA : public MoviePlayer, ::Graphics::DXAPlayer {
+protected:
+ virtual void setPalette(byte *pal);
+ virtual bool decodeFrame();
public:
- MoviePlayer(Sword2Engine *vm);
- int32 play(const char *filename, MovieTextObject *text[], int32 leadInRes, int32 leadOutRes);
+ MoviePlayerDXA(Sword2Engine *vm);
+ virtual ~MoviePlayerDXA();
+
+ virtual bool load(const char *name, MovieTextObject *text[]);
};
+#endif
+
+MoviePlayer *makeMoviePlayer(Sword2Engine *vm, const char *name);
} // End of namespace Sword2
diff --git a/engines/sword2/function.cpp b/engines/sword2/function.cpp
index b35325f9f9..a186fb9266 100644
--- a/engines/sword2/function.cpp
+++ b/engines/sword2/function.cpp
@@ -2131,17 +2131,13 @@ int32 Logic::fnPlaySequence(int32 *params) {
// pause sfx during sequence
_vm->_sound->pauseFx();
- MoviePlayer player(_vm);
- uint32 rv;
+ MoviePlayer *player = makeMoviePlayer(_vm, filename);
- if (_sequenceTextLines && !readVar(DEMO))
- rv = player.play(filename, sequenceSpeechArray, _smackerLeadIn, _smackerLeadOut);
- else
- rv = player.play(filename, NULL, _smackerLeadIn, _smackerLeadOut);
+ if (player->load(filename, (_sequenceTextLines && !readVar(DEMO)) ? sequenceSpeechArray : NULL)) {
+ player->play(_smackerLeadIn, _smackerLeadOut);
+ }
- // check the error return-value
- if (rv)
- debug(5, "MoviePlayer.play(\"%s\") returned 0x%.8x", filename, rv);
+ delete player;
// unpause sound fx again, in case we're staying in same location
_vm->_sound->unpauseFx();
diff --git a/engines/sword2/render.cpp b/engines/sword2/render.cpp
index 4231c49025..24130af5c6 100644
--- a/engines/sword2/render.cpp
+++ b/engines/sword2/render.cpp
@@ -29,10 +29,6 @@
#include "sword2/defs.h"
#include "sword2/screen.h"
-#ifdef BACKEND_8BIT
-#include "sword2/animation.h"
-#endif
-
namespace Sword2 {
#define MILLISECSPERCYCLE 83
@@ -555,31 +551,4 @@ void Screen::closeBackgroundLayer() {
_layer = 0;
}
-#ifdef BACKEND_8BIT
-void Screen::plotYUV(byte *lut, int width, int height, byte *const *dat) {
- byte *buf = _buffer + ((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;
- }
-}
-#endif
-
-
} // End of namespace Sword2
diff --git a/engines/sword2/screen.h b/engines/sword2/screen.h
index 1a393e53a4..d5a01485fa 100644
--- a/engines/sword2/screen.h
+++ b/engines/sword2/screen.h
@@ -428,10 +428,6 @@ public:
void plotPoint(int x, int y, uint8 colour);
void drawLine(int x0, int y0, int x1, int y1, uint8 colour);
-#ifdef BACKEND_8BIT
- void plotYUV(byte *lut, int width, int height, byte *const *dat);
-#endif
-
void rollCredits();
void splashScreen();
};