diff options
author | Bastien Bouclet | 2017-02-20 18:02:57 +0100 |
---|---|---|
committer | Eugene Sandulenko | 2017-07-03 08:50:10 +0200 |
commit | f977b5712328133b638c33992d4e111624d1881d (patch) | |
tree | c8480f6b0f9f3f2471f44fa09c894015fdc49ba1 /engines/mohawk/riven_video.cpp | |
parent | 9153393219b398ce5a7a8122d9af38e32e128059 (diff) | |
download | scummvm-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.cpp | 341 |
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 |