aboutsummaryrefslogtreecommitdiff
path: root/engines/mohawk/riven_video.cpp
diff options
context:
space:
mode:
authorBastien Bouclet2017-02-20 18:02:57 +0100
committerEugene Sandulenko2017-07-03 08:50:10 +0200
commitf977b5712328133b638c33992d4e111624d1881d (patch)
treec8480f6b0f9f3f2471f44fa09c894015fdc49ba1 /engines/mohawk/riven_video.cpp
parent9153393219b398ce5a7a8122d9af38e32e128059 (diff)
downloadscummvm-rg350-f977b5712328133b638c33992d4e111624d1881d.tar.gz
scummvm-rg350-f977b5712328133b638c33992d4e111624d1881d.tar.bz2
scummvm-rg350-f977b5712328133b638c33992d4e111624d1881d.zip
MOHAWK: Rewrite the Riven movie manager
Diffstat (limited to 'engines/mohawk/riven_video.cpp')
-rw-r--r--engines/mohawk/riven_video.cpp341
1 files changed, 341 insertions, 0 deletions
diff --git a/engines/mohawk/riven_video.cpp b/engines/mohawk/riven_video.cpp
new file mode 100644
index 0000000000..375af47ffe
--- /dev/null
+++ b/engines/mohawk/riven_video.cpp
@@ -0,0 +1,341 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "mohawk/riven_video.h"
+
+#include "mohawk/cursors.h"
+#include "mohawk/resource.h"
+#include "mohawk/riven.h"
+#include "mohawk/riven_graphics.h"
+#include "mohawk/riven_scripts.h"
+#include "mohawk/riven_stack.h"
+
+#include "common/system.h"
+
+#include "graphics/surface.h"
+
+#include "video/qt_decoder.h"
+
+namespace Mohawk {
+
+RivenVideo::RivenVideo(MohawkEngine_Riven *vm, uint16 code) :
+ _vm(vm),
+ _id(0),
+ _slot(code),
+ _x(0),
+ _y(0),
+ _loop(false),
+ _enabled(false),
+ _video(nullptr),
+ _playing(false) {
+}
+
+RivenVideo::~RivenVideo() {
+ delete _video;
+}
+
+void RivenVideo::load(uint16 id) {
+ if (id == _id && _video) {
+ return;
+ }
+
+ close();
+
+ _id = id;
+ _video = new Video::QuickTimeDecoder();
+ _video->setChunkBeginOffset(_vm->getResourceOffset(ID_TMOV, id));
+ _video->loadStream(_vm->getResource(ID_TMOV, id));
+}
+
+void RivenVideo::close() {
+ stop();
+
+ delete _video;
+ _video = nullptr;
+}
+
+bool RivenVideo::endOfVideo() const {
+ return !_video || _video->endOfVideo();
+}
+
+int RivenVideo::getCurFrame() const {
+ assert(_video);
+ return _video->getCurFrame();
+}
+
+uint32 RivenVideo::getFrameCount() const {
+ assert(_video);
+ return _video->getFrameCount();
+}
+
+uint32 RivenVideo::getTime() const {
+ assert(_video);
+ return _video->getTime();
+}
+
+uint32 RivenVideo::getDuration() const {
+ assert(_video);
+ return _video->getDuration().msecs();
+}
+
+void RivenVideo::setBounds(uint32 startTime, uint32 endTime) {
+ assert(_video);
+ _video->setEndTime(Audio::Timestamp(0, endTime, 600));
+ _video->seek(Audio::Timestamp(0, startTime, 600));
+}
+
+void RivenVideo::seek(uint32 time) {
+ assert(_video);
+
+ if (time == 0) {
+ // Fast path
+ _video->rewind();
+ } else {
+ _video->seek(Audio::Timestamp(0, time, 600));
+ }
+}
+
+void RivenVideo::pause(bool isPaused) {
+ if (_video) {
+ _video->pauseVideo(isPaused);
+ }
+}
+
+void RivenVideo::stop() {
+ if (_video) {
+ _video->stop();
+ }
+ _playing = false;
+}
+
+bool RivenVideo::isPlaying() const {
+ return _playing;
+}
+
+int RivenVideo::getVolume() const {
+ assert(_video);
+ return _video->getVolume();
+}
+
+void RivenVideo::setVolume(int volume) {
+ assert(_video);
+ _video->setVolume(CLIP(volume, 0, 255));
+}
+
+RivenVideoManager::RivenVideoManager(MohawkEngine_Riven *vm) : _vm(vm) {
+}
+
+RivenVideoManager::~RivenVideoManager() {
+ removeVideos();
+}
+
+void RivenVideoManager::pauseVideos() {
+ for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++)
+ (*it)->pause(true);
+}
+
+void RivenVideoManager::resumeVideos() {
+ for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++)
+ (*it)->pause(false);
+}
+
+void RivenVideoManager::closeVideos() {
+ for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++) {
+ (*it)->close();
+ }
+}
+
+void RivenVideoManager::removeVideos() {
+ for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++) {
+ delete *it;
+ }
+
+ _videos.clear();
+}
+
+void RivenVideoManager::updateMovies() {
+ for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++) {
+ RivenVideo *video = *it;
+ // Check of the video has reached the end
+ if (video->endOfVideo()) {
+ if (video->isPlaying() && video->isLooping()) {
+ // Seek back if looping
+ video->seek(0);
+ } else {
+ continue;
+ }
+ }
+
+ // Check if we need to draw a frame
+ if (video->needsUpdate()) {
+ video->drawNextFrame();
+ }
+ }
+}
+
+void RivenVideo::drawNextFrame() {
+ const Graphics::Surface *frame = _video->decodeNextFrame();
+
+ if (!frame || !isEnabled()) {
+ return;
+ }
+
+ Graphics::Surface *convertedFrame = nullptr;
+ Graphics::PixelFormat pixelFormat = g_system->getScreenFormat();
+
+ if (frame->format != pixelFormat) {
+ // Convert to the current screen format
+ convertedFrame = frame->convertTo(pixelFormat, _video->getPalette());
+ frame = convertedFrame;
+ }
+
+ g_system->copyRectToScreen(frame->getPixels(), frame->pitch,
+ _x, _y, _video->getWidth(), _video->getHeight());
+
+ // Delete 8bpp conversion surface
+ if (convertedFrame) {
+ convertedFrame->free();
+ delete convertedFrame;
+ }
+}
+
+bool RivenVideo::needsUpdate() const {
+ return _video && _video->isPlaying() && !_video->isPaused() && _video->needsUpdate();
+}
+
+void RivenVideo::playBlocking(int32 endTime) {
+ _vm->_cursor->hideCursor();
+
+ if (!_playing) {
+ play();
+ }
+
+ // Sanity check
+ if (isLooping())
+ error("Called playBlocking() on a looping video");
+
+ bool playTillEnd;
+ if (endTime == -1) {
+ playTillEnd = true;
+ } else {
+ playTillEnd = false;
+ _video->setEndTime(Audio::Timestamp(0, endTime, 600));
+ }
+
+ if (playTillEnd) {
+ enable();
+ }
+
+ bool continuePlaying = true;
+ while (!endOfVideo() && !_vm->shouldQuit() && continuePlaying) {
+ // Draw a frame
+ _vm->doFrame();
+
+ // Handle skipping
+ if (playTillEnd && _vm->getStack()->keyGetPressed() == Common::KEYCODE_ESCAPE) {
+ continuePlaying = false;
+
+ // Seek to the last frame
+ _video->seek(_video->getDuration().addMsecs(-1));
+
+ _vm->getStack()->mouseForceUp();
+ _vm->getStack()->keyForceUp();
+ }
+ }
+
+ if (playTillEnd) {
+ disable();
+ stop();
+ }
+
+ // Execute the stored opcode
+ uint16 storedOpcodeId = _vm->_scriptMan->getStoredMovieOpcodeID();
+ uint32 storedOpcodeTime = _vm->_scriptMan->getStoredMovieOpcodeTime();
+ if (_id == storedOpcodeId && getTime() >= storedOpcodeTime) { // CHECKME: Suspicious use of time units
+ _vm->_scriptMan->runStoredMovieOpcode();
+ }
+
+ _vm->_cursor->showCursor();
+}
+
+void RivenVideo::play() {
+ if (!_video) {
+ load(_id);
+ }
+
+ if (_video->endOfVideo()) {
+ _video->rewind();
+ }
+
+ _video->start();
+ _playing = true;
+}
+
+void RivenVideo::enable() {
+ _enabled = true;
+}
+
+void RivenVideo::disable() {
+ if (needsUpdate()) {
+ drawNextFrame();
+ }
+
+ if (_video) {
+ Common::Rect targetRect = Common::Rect(_video->getWidth(), _video->getHeight());
+ targetRect.translate(_x, _y);
+
+ _vm->_gfx->copySystemRectToScreen(targetRect);
+ }
+
+ _enabled = false;
+}
+
+void RivenVideoManager::disableAllMovies() {
+ debug(2, "Disabling all movies");
+ for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++)
+ (*it)->disable();
+}
+
+RivenVideo *RivenVideoManager::openSlot(uint16 slot) {
+ // If this video is already playing, return that handle
+ RivenVideo *oldHandle = getSlot(slot);
+ if (oldHandle)
+ return oldHandle;
+
+ // Create the video
+ RivenVideo *video = new RivenVideo(_vm, slot);
+
+ // Add it to the video list
+ _videos.push_back(video);
+
+ return video;
+}
+
+RivenVideo *RivenVideoManager::getSlot(uint16 slot) {
+ for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++)
+ if ((*it)->getSlot() == slot)
+ return *it;
+
+ return nullptr;
+}
+
+} // End of namespace Mohawk