diff options
author | richiesams | 2013-08-04 23:10:27 -0500 |
---|---|---|
committer | richiesams | 2013-08-04 23:52:31 -0500 |
commit | 7b9858d6b45ad4c02729445975518a48292c3658 (patch) | |
tree | bf16bfbb81d4614ff10d4fd6ec2ce5a4e0211d69 | |
parent | a86a0832e08c777ef23f2ce97004963b301dd598 (diff) | |
download | scummvm-rg350-7b9858d6b45ad4c02729445975518a48292c3658.tar.gz scummvm-rg350-7b9858d6b45ad4c02729445975518a48292c3658.tar.bz2 scummvm-rg350-7b9858d6b45ad4c02729445975518a48292c3658.zip |
ZVISION: Make video code blocking.
The script system requires that all ResultAction::execute() block until they finish. The video system *was* 'asyncronous'
in that you would just start a video and then run() would finish processing it. This code forces the video to complely finish
before playVideo returns. The Clock object is used to keep track of deltaTime while the video is playing.
-rw-r--r-- | engines/zvision/console.cpp | 6 | ||||
-rw-r--r-- | engines/zvision/events.cpp | 5 | ||||
-rw-r--r-- | engines/zvision/render_manager.cpp | 13 | ||||
-rw-r--r-- | engines/zvision/render_manager.h | 24 | ||||
-rw-r--r-- | engines/zvision/video.cpp | 87 | ||||
-rw-r--r-- | engines/zvision/zvision.cpp | 31 | ||||
-rw-r--r-- | engines/zvision/zvision.h | 22 |
7 files changed, 93 insertions, 95 deletions
diff --git a/engines/zvision/console.cpp b/engines/zvision/console.cpp index 9c7d79a8f1..6634e0bef4 100644 --- a/engines/zvision/console.cpp +++ b/engines/zvision/console.cpp @@ -69,9 +69,9 @@ bool Console::cmdLoadVideo(int argc, const char **argv) { return true; } - Video::VideoDecoder *videoDecoder = new ZorkAVIDecoder(); - if (videoDecoder && videoDecoder->loadFile(argv[1])) { - _engine->getRenderManager()->startVideo(videoDecoder); + ZorkAVIDecoder videoDecoder; + if (videoDecoder.loadFile(argv[1])) { + _engine->playVideo(videoDecoder); } return true; diff --git a/engines/zvision/events.cpp b/engines/zvision/events.cpp index e392d3c78a..508d2610aa 100644 --- a/engines/zvision/events.cpp +++ b/engines/zvision/events.cpp @@ -61,11 +61,6 @@ void ZVision::processEvents() { if (_event.kbd.hasFlags(Common::KBD_CTRL)) quitGame(); break; - case Common::KEYCODE_ESCAPE: - if (_renderManager->isVideoPlaying()) - _renderManager->cancelVideo(); - - break; default: break; } diff --git a/engines/zvision/render_manager.cpp b/engines/zvision/render_manager.cpp index b6163c83c1..604c310689 100644 --- a/engines/zvision/render_manager.cpp +++ b/engines/zvision/render_manager.cpp @@ -38,25 +38,12 @@ RenderManager::RenderManager(OSystem *system, const int width, const int height) : _system(system), _width(width), _height(height), - _pixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0), // RGB555 - _currentVideo(0), _currentBackground(0), - _scaledVideoFrameBuffer(0), _needsScreenUpdate(false), _renderTable(width, height) { } -/** - * Initialize graphics - */ -void RenderManager::initialize() { - initGraphics(_width, _height, true, &_pixelFormat); -} - void RenderManager::updateScreen(bool isConsoleActive) { - if (_currentVideo != 0) - continueVideo(); - if (_needsScreenUpdate || isConsoleActive) { _system->updateScreen(); _needsScreenUpdate = false; diff --git a/engines/zvision/render_manager.h b/engines/zvision/render_manager.h index fc2598ecf9..9554e888d9 100644 --- a/engines/zvision/render_manager.h +++ b/engines/zvision/render_manager.h @@ -26,8 +26,6 @@ #include "common/types.h" #include "common/rect.h" -#include "graphics/pixelformat.h" - #include "zvision/render_table.h" class OSystem; @@ -51,7 +49,6 @@ private: OSystem *_system; const int _width; const int _height; - const Graphics::PixelFormat _pixelFormat; RenderTable _renderTable; Common::SeekableReadStream *_currentBackground; @@ -66,22 +63,6 @@ public: void updateScreen(bool isConsoleActive); /** - * Start a video playing. It will also load the first frame of the video. - * - * @param videoDecoder The video to play - */ - void startVideo(Video::VideoDecoder *videoDecoder); - /** - * @return Is a video currently being played - */ - bool isVideoPlaying() { return _currentVideo == 0; } - /** - * Cancels a video prematurely. Any sound remaining in the queue will continue to play. - * The last frame of the video will remain on the screen until something else overwrites it - */ - void cancelVideo(); - - /** * Blits the image or a portion of the image to the screen. Actual screen updates won't happen until the end of the frame. * The image will be clipped to fit inside the window. * @@ -116,11 +97,6 @@ public: bool needsScreenUpdate() { return _needsScreenUpdate; }; private: - /** - * Checks the time since the last video frame, and blits the next frame to the screen - */ - void continueVideo(); - void renderSubRectToScreen(uint16 *buffer, uint32 imageWidth, uint32 imageHeight, uint32 horizontalPitch, uint32 destinationX, uint32 destinationY, Common::Rect subRectangle); }; diff --git a/engines/zvision/video.cpp b/engines/zvision/video.cpp index 1ccf736970..8550a6cfca 100644 --- a/engines/zvision/video.cpp +++ b/engines/zvision/video.cpp @@ -27,7 +27,9 @@ #include "engines/util.h" #include "graphics/surface.h" +#include "zvision/clock.h" #include "zvision/render_manager.h" +#include "zvision/zvision.h" namespace ZVision { @@ -71,62 +73,77 @@ void scale2x(const byte *src, byte *dst, uint32 srcWidth, uint32 srcHeight, byte } } -void RenderManager::startVideo(Video::VideoDecoder *videoDecoder) { - if (!videoDecoder) - return; - - _currentVideo = videoDecoder; - +void ZVision::playVideo(Video::VideoDecoder &videoDecoder) { + // Videos use a different pixel format Common::List<Graphics::PixelFormat> formats; - formats.push_back(videoDecoder->getPixelFormat()); + formats.push_back(videoDecoder.getPixelFormat()); initGraphics(_width, _height, true, formats); - - _scaledVideoFrameBuffer = new byte[_currentVideo->getWidth() * _currentVideo->getHeight() * _currentVideo->getPixelFormat().bytesPerPixel * 4]; - - _currentVideo->start(); - // Load the first frame - continueVideo(); -} - -void RenderManager::continueVideo() { - byte bytesPerPixel = _currentVideo->getPixelFormat().bytesPerPixel; - uint16 origWidth = _currentVideo->getWidth(); - uint16 origHeight = _currentVideo->getHeight(); + byte bytesPerPixel = videoDecoder.getPixelFormat().bytesPerPixel; + uint16 origWidth = videoDecoder.getWidth(); + uint16 origHeight = videoDecoder.getHeight(); uint16 pitch = origWidth * bytesPerPixel; + + // Most videos are very small. Therefore we do a simple 2x scale bool shouldBeScaled = (origWidth * 2 <= 640 && origHeight * 2 <= 480); uint16 finalWidth = shouldBeScaled ? origWidth * 2 : origWidth; uint16 finalHeight = shouldBeScaled ? origHeight * 2 : origHeight; - uint16 x = (_system->getWidth() - finalWidth) / 2; - uint16 y = (_system->getHeight() - finalHeight) / 2; + byte *scaledVideoFrameBuffer = new byte[origHeight * pitch * 4]; + + uint16 x = (_width - finalWidth) / 2; + uint16 y = (_height - finalHeight) / 2; + + _clock->stop(); + videoDecoder.start(); + + // Only continue while the video is still playing + while (videoDecoder.isPlaying()) { + _clock->update(); + uint32 currentTime = _clock->getLastMeasuredTime(); + + // Check for engine quit and video stop key presses + while (_eventMan->pollEvent(_event)) { + switch (_event.type) { + case Common::EVENT_KEYDOWN: + switch (_event.kbd.keycode) { + case Common::KEYCODE_q: + if (_event.kbd.hasFlags(Common::KBD_CTRL)) + quitGame(); + break; + case Common::KEYCODE_SPACE: + videoDecoder.stop(); + break; + } + } + } - if (!_currentVideo->endOfVideo()) { - if (_currentVideo->needsUpdate()) { - const Graphics::Surface *frame = _currentVideo->decodeNextFrame(); + if (videoDecoder.needsUpdate()) { + const Graphics::Surface *frame = videoDecoder.decodeNextFrame(); if (frame) { if (shouldBeScaled) { - scale2x((byte *)frame->pixels, _scaledVideoFrameBuffer, origWidth, origHeight, bytesPerPixel); - _system->copyRectToScreen(_scaledVideoFrameBuffer, pitch * 2, x, y, finalWidth, finalHeight); + scale2x((byte *)frame->pixels, scaledVideoFrameBuffer, origWidth, origHeight, bytesPerPixel); + _system->copyRectToScreen(scaledVideoFrameBuffer, pitch * 2, x, y, finalWidth, finalHeight); } else { _system->copyRectToScreen((byte *)frame->pixels, pitch, x, y, finalWidth, finalHeight); } - _needsScreenUpdate = true; + _system->updateScreen(); } } - } else { - cancelVideo(); + + // Calculate the frame delay based off a desired frame time + int delay = _desiredFrameTime - (currentTime - _system->getMillis()); + // Ensure non-negative + delay = delay < 0 ? 0 : delay; + _system->delayMillis(delay); } -} -void RenderManager::cancelVideo() { + _clock->stop(); + + // Reset the pixel format to the original state initGraphics(_width, _height, true, &_pixelFormat); - delete _currentVideo; - _currentVideo = 0; - delete[] _scaledVideoFrameBuffer; - _scaledVideoFrameBuffer = 0; } } // End of namespace ZVision diff --git a/engines/zvision/zvision.cpp b/engines/zvision/zvision.cpp index ca43549f50..0015c41499 100644 --- a/engines/zvision/zvision.cpp +++ b/engines/zvision/zvision.cpp @@ -31,11 +31,14 @@ #include "common/file.h" #include "engines/util.h" + +#include "audio/mixer.h" #include "zvision/zvision.h" #include "zvision/console.h" #include "zvision/script_manager.h" #include "zvision/render_manager.h" +#include "zvision/clock.h" #include "zvision/zfs_archive.h" #include "zvision/detection.h" @@ -47,7 +50,9 @@ ZVision::ZVision(OSystem *syst, const ZVisionGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc), _width(640), - _height(480) { + _height(480), + _pixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0), /*RGB 555*/ + _desiredFrameTime(33) /* ~30 fps */ { // Put your engine in a sane state, but do nothing big yet; // in particular, do not load data from files; rather, if you // need to do such things, do them from run(). @@ -75,14 +80,19 @@ ZVision::ZVision(OSystem *syst, const ZVisionGameDescription *gameDesc) _scriptManager = new ScriptManager(this); _renderManager = new RenderManager(_system, _width, _height); + // Create clock + _clock = new Clock(_system); + debug("ZVision::ZVision"); } - + ZVision::~ZVision() { debug("ZVision::~ZVision"); // Dispose of resources delete _console; + delete _clock; + delete _renderManager; delete _scriptManager; delete _rnd; @@ -103,7 +113,7 @@ void ZVision::initialize() { SearchMan.add(name, archive); } - _renderManager->initialize(); + initGraphics(_width, _height, true, &_pixelFormat); _scriptManager->initialize(); @@ -115,25 +125,20 @@ Common::Error ZVision::run() { initialize(); // Main loop - uint32 currentTime = _system->getMillis(); - uint32 lastTime = currentTime; - const uint desiredFrameTime = 33; // ~30 fps - while (!shouldQuit()) { - processEvents(); + _clock->update(); + uint32 currentTime = _clock->getLastMeasuredTime(); - currentTime = _system->getMillis(); - uint32 deltaTime = currentTime - lastTime; - lastTime = currentTime; + processEvents(); - _scriptManager->updateNodes(deltaTime); + _scriptManager->updateNodes(_clock->getDeltaTime()); _scriptManager->checkPuzzleCriteria(); // Render a frame _renderManager->updateScreen(_console->isActive()); // Calculate the frame delay based off a desired frame time - int delay = desiredFrameTime - (currentTime - _system->getMillis()); + int delay = _desiredFrameTime - (currentTime - _system->getMillis()); // Ensure non-negative delay = delay < 0 ? 0 : delay; _system->delayMillis(delay); diff --git a/engines/zvision/zvision.h b/engines/zvision/zvision.h index 9588623f56..459096a03b 100644 --- a/engines/zvision/zvision.h +++ b/engines/zvision/zvision.h @@ -29,16 +29,24 @@ #include "engines/engine.h" +#include "graphics/pixelformat.h" + #include "zvision/detection.h" #include "gui/debugger.h" - + + +namespace Video { +class VideoDecoder; +} + namespace ZVision { struct ZVisionGameDescription; class Console; class ScriptManager; class RenderManager; +class Clock; // our engine debug channels enum { @@ -58,25 +66,35 @@ private: const ZVisionGameDescription *_gameDescription; const int _width; const int _height; + const Graphics::PixelFormat _pixelFormat; + + const uint _desiredFrameTime; // We need random numbers Common::RandomSource *_rnd; + // Managers ScriptManager *_scriptManager; RenderManager *_renderManager; + // Clock + Clock *_clock; + // To prevent allocation every time we process events Common::Event _event; public: uint32 getFeatures() const; Common::Language getLanguage() const; - virtual Common::Error run(); + Common::Error run(); + ScriptManager *getScriptManager() const; RenderManager *getRenderManager() const; Common::RandomSource *getRandomSource() const; ZVisionGameId getGameId() const; + void playVideo(Video::VideoDecoder &videoDecoder); + private: void initialize(); |