diff options
-rw-r--r-- | engines/mohawk/graphics.cpp | 75 | ||||
-rw-r--r-- | engines/mohawk/graphics.h | 11 | ||||
-rw-r--r-- | engines/mohawk/riven_external.cpp | 22 |
3 files changed, 104 insertions, 4 deletions
diff --git a/engines/mohawk/graphics.cpp b/engines/mohawk/graphics.cpp index 897ca79d0e..19882c4f1c 100644 --- a/engines/mohawk/graphics.cpp +++ b/engines/mohawk/graphics.cpp @@ -246,6 +246,13 @@ void GraphicsManager::copyAnimImageSectionToScreen(MohawkSurface *image, Common: getVM()->_system->unlockScreen(); } +void GraphicsManager::addImageToCache(uint16 id, MohawkSurface *surface) { + if (_cache.contains(id)) + error("Image %d already in cache", id); + + _cache[id] = surface; +} + MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) { _bmpDecoder = new MystBitmap(); @@ -630,6 +637,9 @@ RivenGraphics::RivenGraphics(MohawkEngine_Riven* vm) : GraphicsManager(), _vm(vm _scheduledTransition = -1; // no transition _dirtyScreen = false; _inventoryDrawn = false; + + _creditsImage = 302; + _creditsPos = 0; } RivenGraphics::~RivenGraphics() { @@ -840,6 +850,17 @@ void RivenGraphics::runScheduledTransition() { _scheduledTransition = -1; // Clear scheduled transition } +void RivenGraphics::clearMainScreen() { + _mainScreen->fillRect(Common::Rect(0, 0, 608, 392), _pixelFormat.RGBToColor(0, 0, 0)); +} + +void RivenGraphics::fadeToBlack() { + // Self-explanatory + scheduleTransition(16); + clearMainScreen(); + runScheduledTransition(); +} + void RivenGraphics::showInventory() { // Don't redraw the inventory if (_inventoryDrawn) @@ -955,6 +976,60 @@ void RivenGraphics::drawExtrasImage(uint16 id, Common::Rect dstRect) { _dirtyScreen = true; } +void RivenGraphics::beginCredits() { + // Clear the old cache + clearCache(); + + // Now cache all the credits images + for (uint16 i = 302; i <= 320; i++) { + MohawkSurface *surface = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, i)); + surface->convertToTrueColor(); + addImageToCache(i, surface); + } + + // And clear our screen too + clearMainScreen(); +} + +void RivenGraphics::updateCredits() { + if ((_creditsImage == 303 || _creditsImage == 304) && _creditsPos == 0) + fadeToBlack(); + + if (_creditsImage < 304) { + // For the first two credit images, they are faded from black to the image and then out again + scheduleTransition(16); + + Graphics::Surface *frame = findImage(_creditsImage++)->getSurface(); + + for (int y = 0; y < frame->h; y++) + memcpy(_mainScreen->getBasePtr(124, y), frame->getBasePtr(0, y), frame->pitch); + + runScheduledTransition(); + } else { + // Otheriwse, we're scrolling + // Move the screen up one row + memmove(_mainScreen->pixels, _mainScreen->getBasePtr(0, 1), _mainScreen->pitch * (_mainScreen->h - 1)); + + // Only update as long as we're not before the last frame + // Otherwise, we're just moving up a row (which we already did) + if (_creditsImage <= 320) { + // Copy the next row to the bottom of the screen + Graphics::Surface *frame = findImage(_creditsImage)->getSurface(); + memcpy(_mainScreen->getBasePtr(124, _mainScreen->h - 1), frame->getBasePtr(0, _creditsPos), frame->pitch); + _creditsPos++; + + if (_creditsPos == _mainScreen->h) { + _creditsImage++; + _creditsPos = 0; + } + } + + // Now flush the new screen + _vm->_system->copyRectToScreen((byte *)_mainScreen->pixels, _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h); + _vm->_system->updateScreen(); + } +} + LBGraphics::LBGraphics(MohawkEngine_LivingBooks *vm, uint16 width, uint16 height) : GraphicsManager(), _vm(vm) { _bmpDecoder = _vm->isPreMohawk() ? new OldMohawkBitmap() : new MohawkBitmap(); diff --git a/engines/mohawk/graphics.h b/engines/mohawk/graphics.h index 89189d442a..fbac2f2ea1 100644 --- a/engines/mohawk/graphics.h +++ b/engines/mohawk/graphics.h @@ -110,6 +110,7 @@ protected: virtual Common::Array<MohawkSurface *> decodeImages(uint16 id); virtual MohawkEngine *getVM() = 0; + void addImageToCache(uint16 id, MohawkSurface *surface); private: // An image cache that stores images until clearCache() is called @@ -195,11 +196,17 @@ public: // Transitions void scheduleTransition(uint16 id, Common::Rect rect = Common::Rect(0, 0, 608, 392)); void runScheduledTransition(); + void fadeToBlack(); // Inventory void showInventory(); void hideInventory(); + // Credits + void beginCredits(); + void updateCredits(); + uint getCurCreditsImage() { return _creditsImage; } + protected: MohawkSurface *decodeImage(uint16 id); MohawkEngine *getVM() { return (MohawkEngine *)_vm; } @@ -224,6 +231,10 @@ private: Graphics::Surface *_mainScreen; bool _dirtyScreen; Graphics::PixelFormat _pixelFormat; + void clearMainScreen(); + + // Credits + uint _creditsImage, _creditsPos; }; class LBGraphics : public GraphicsManager { diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp index e6ea25c9a6..dbc1bd9121 100644 --- a/engines/mohawk/riven_external.cpp +++ b/engines/mohawk/riven_external.cpp @@ -223,13 +223,27 @@ void RivenExternal::runEndGame(uint16 video) { } void RivenExternal::runCredits(uint16 video) { - // TODO: Play until the last frame and then run the credits + // Initialize our credits state + _vm->_cursor->hideCursor(); + _vm->_gfx->beginCredits(); + uint nextCreditsFrameStart = 0; VideoHandle videoHandle = _vm->_video->findVideoHandleRiven(video); - while (!_vm->_video->endOfVideo(videoHandle) && !_vm->shouldQuit()) { - if (_vm->_video->updateMovies()) - _vm->_system->updateScreen(); + while (!_vm->shouldQuit() && _vm->_gfx->getCurCreditsImage() <= 320) { + if (_vm->_video->getCurFrame(videoHandle) >= (int32)_vm->_video->getFrameCount(videoHandle) - 1) { + if (_vm->_system->getMillis() >= nextCreditsFrameStart) { + // the first two frames stay on for 5 seconds + // the rest of the scroll updates happen at 30Hz + if (_vm->_gfx->getCurCreditsImage() < 304) + nextCreditsFrameStart = _vm->_system->getMillis() + 5000; + else + nextCreditsFrameStart = _vm->_system->getMillis() + 1000 / 30; + + _vm->_gfx->updateCredits(); + } + } else if (_vm->_video->updateMovies()) + _vm->_system->updateScreen(); Common::Event event; while (_vm->_system->getEventManager()->pollEvent(event)) |