[Scummvm-git-logs] scummvm master -> 295a8b7295efaaa87960903077bfd10d4b457947
elasota
noreply at scummvm.org
Mon Jun 19 18:07:35 UTC 2023
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
295a8b7295 MTROPOLIS: Attempt to implement MPEG movies in MTI DVD
Commit: 295a8b7295efaaa87960903077bfd10d4b457947
https://github.com/scummvm/scummvm/commit/295a8b7295efaaa87960903077bfd10d4b457947
Author: elasota (ejlasota at gmail.com)
Date: 2023-06-19T14:06:28-04:00
Commit Message:
MTROPOLIS: Attempt to implement MPEG movies in MTI DVD
Changed paths:
engines/mtropolis/plugin/mti.cpp
engines/mtropolis/plugin/mti.h
engines/mtropolis/runtime.cpp
engines/mtropolis/runtime.h
diff --git a/engines/mtropolis/plugin/mti.cpp b/engines/mtropolis/plugin/mti.cpp
index b5ef3dbe15d..f186e14ed8a 100644
--- a/engines/mtropolis/plugin/mti.cpp
+++ b/engines/mtropolis/plugin/mti.cpp
@@ -19,13 +19,16 @@
*
*/
-#include "graphics/managed_surface.h"
-
#include "mtropolis/plugin/mti.h"
#include "mtropolis/plugins.h"
#include "mtropolis/miniscript.h"
+#include "video/mpegps_decoder.h"
+
+#include "graphics/managed_surface.h"
+
+#include "common/file.h"
#include "common/random.h"
namespace MTropolis {
@@ -446,10 +449,102 @@ const char *PrintModifier::getDefaultName() const {
return "Print Modifier";
}
-SampleModifier::SampleModifier() : _videoNumber(0) {
+class MPEGVideoPlayer : public IPostEffect, public IPlayMediaSignalReceiver {
+public:
+ explicit MPEGVideoPlayer(Runtime *runtime, const Common::SharedPtr<Video::VideoDecoder> &videoDecoder, IMPEGVideoCompletionNotifier *completionNotifier);
+ ~MPEGVideoPlayer();
+
+ static Common::SharedPtr<MPEGVideoPlayer> createForVideoID(Runtime *runtime, int videoID, IMPEGVideoCompletionNotifier *completionNotifier);
+
+ void playMedia(Runtime *runtime, Project *project) override;
+ void renderPostEffect(Graphics::ManagedSurface &surface) const override;
+
+private:
+ Runtime *_runtime;
+ Project *_project;
+ IMPEGVideoCompletionNotifier *_completionNotifier;
+
+ const Graphics::Surface *_displayingSurface;
+ Common::SharedPtr<Video::VideoDecoder> _decoder;
+ Common::SharedPtr<PlayMediaSignaller> _playMediaReceiver;
+ bool _finished;
+};
+
+
+MPEGVideoPlayer::MPEGVideoPlayer(Runtime *runtime, const Common::SharedPtr<Video::VideoDecoder> &videoDecoder, IMPEGVideoCompletionNotifier *completionNotifier)
+ : _runtime(runtime), _project(nullptr), _decoder(videoDecoder), _finished(false), _displayingSurface(nullptr), _completionNotifier(completionNotifier) {
+ _project = runtime->getProject();
+
+ runtime->addPostEffect(this);
+ _playMediaReceiver = _project->notifyOnPlayMedia(this);
+}
+
+MPEGVideoPlayer::~MPEGVideoPlayer() {
+ _playMediaReceiver->removeReceiver(this);
+ _runtime->removePostEffect(this);
+}
+
+Common::SharedPtr<MPEGVideoPlayer> MPEGVideoPlayer::createForVideoID(Runtime *runtime, int videoID, IMPEGVideoCompletionNotifier *completionNotifier) {
+#ifdef USE_MPEG2
+ Common::String videoPath = Common::String::format("video/%i.vob", videoID);
+
+ Common::SharedPtr<Video::VideoDecoder> decoder(new Video::MPEGPSDecoder());
+ if (!decoder->loadFile(Common::Path(videoPath)))
+ return nullptr;
+
+ decoder->start();
+
+ return Common::SharedPtr<MPEGVideoPlayer>(new MPEGVideoPlayer(runtime, decoder, completionNotifier));
+#else
+ return nullptr;
+#endif
+}
+
+void MPEGVideoPlayer::playMedia(Runtime *runtime, Project *project) {
+ if (_finished)
+ return;
+
+ while (_decoder->getTimeToNextFrame() == 0) {
+ const Graphics::Surface *newFrame = _decoder->decodeNextFrame();
+ if (newFrame) {
+ _displayingSurface = newFrame;
+ _runtime->setSceneGraphDirty();
+ } else {
+ _finished = true;
+ _displayingSurface = nullptr;
+ _completionNotifier->onVideoCompleted();
+ break;
+ }
+ }
+}
+
+void MPEGVideoPlayer::renderPostEffect(Graphics::ManagedSurface &surface) const {
+ if (_displayingSurface) {
+ const Graphics::Surface *surf = _displayingSurface;
+
+ Graphics::ManagedSurface *mainWindowSurf = _runtime->getMainWindow().lock()->getSurface().get();
+
+ int32 topLeftX = (mainWindowSurf->w - surf->w) / 2;
+ int32 topLeftY = (mainWindowSurf->h - surf->h) / 2;
+
+ Common::Rect fullVideoRect(topLeftX, topLeftY, topLeftX + surf->w, topLeftY + surf->h);
+ Common::Rect clippedVideoRect = fullVideoRect;
+ clippedVideoRect.clip(Common::Rect(0, 0, mainWindowSurf->w, mainWindowSurf->h));
+
+ Common::Rect videoSrcRect(0, 0, surf->w, surf->h);
+ videoSrcRect.left += clippedVideoRect.left - fullVideoRect.left;
+ videoSrcRect.right += clippedVideoRect.right - fullVideoRect.right;
+ videoSrcRect.top += clippedVideoRect.top - fullVideoRect.top;
+ videoSrcRect.bottom += clippedVideoRect.bottom - fullVideoRect.bottom;
+
+ mainWindowSurf->blitFrom(*surf, videoSrcRect, clippedVideoRect);
+ }
+}
+SampleModifier::SampleModifier() : _videoNumber(0), _runtime(nullptr), _isPlaying(false) {
}
SampleModifier::~SampleModifier() {
+ stopPlaying();
}
bool SampleModifier::respondsToEvent(const Event &evt) const {
@@ -458,13 +553,30 @@ bool SampleModifier::respondsToEvent(const Event &evt) const {
VThreadState SampleModifier::consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) {
if (_executeWhen.respondsTo(msg->getEvent())) {
- warning("Sample modifier (MPEG video playback) is not implemented. This would normally play video %i.", static_cast<int>(_videoNumber));
+ _runtime = runtime;
+
+ stopPlaying();
+ _vidPlayer.reset();
+
+ _vidPlayer = MPEGVideoPlayer::createForVideoID(runtime, _videoNumber, this);
+ if (_vidPlayer) {
+ runtime->addMouseBlocker();
+ runtime->getMainWindow().lock()->setMouseVisible(false);
+ runtime->setSceneGraphDirty();
+ _keySignaller = _runtime->getProject()->notifyOnKeyboardEvent(this);
+ _isPlaying = true;
+ } else {
+ warning("Attempted to play MPEG video %i but player setup failed", static_cast<int>(_videoNumber));
+ }
+
return kVThreadReturn;
}
return kVThreadReturn;
}
void SampleModifier::disable(Runtime *runtime) {
+ stopPlaying();
+ _vidPlayer.reset();
}
bool SampleModifier::load(const PlugInModifierLoaderContext &context, const Data::MTI::SampleModifier &data) {
@@ -482,6 +594,17 @@ bool SampleModifier::load(const PlugInModifierLoaderContext &context, const Data
return true;
}
+void SampleModifier::onVideoCompleted() {
+ stopPlaying();
+}
+
+void SampleModifier::onKeyboardEvent(Runtime *runtime, const KeyboardInputEvent &keyEvt) {
+ if (keyEvt.getKeyEventType() == Common::EVENT_KEYDOWN && keyEvt.getKeyState().keycode == Common::KEYCODE_SPACE) {
+ _vidPlayer.reset();
+ stopPlaying();
+ }
+}
+
#ifdef MTROPOLIS_DEBUG_ENABLE
void SampleModifier::debugInspect(IDebugInspectionReport *report) const {
}
@@ -495,6 +618,15 @@ const char *SampleModifier::getDefaultName() const {
return "Sample Modifier";
}
+void SampleModifier::stopPlaying() {
+ if (_isPlaying) {
+ _runtime->removeMouseBlocker();
+ _runtime->getMainWindow().lock()->setMouseVisible(true);
+ _keySignaller->removeReceiver(this);
+ _isPlaying = false;
+ }
+}
+
MTIPlugIn::MTIPlugIn()
: _shanghaiModifierFactory(this), _printModifierFactory(this), _sampleModifierFactory(this) {
}
diff --git a/engines/mtropolis/plugin/mti.h b/engines/mtropolis/plugin/mti.h
index aa27da12d56..637c5484f32 100644
--- a/engines/mtropolis/plugin/mti.h
+++ b/engines/mtropolis/plugin/mti.h
@@ -118,7 +118,14 @@ private:
Common::String _filePath;
};
-class SampleModifier : public Modifier {
+class MPEGVideoPlayer;
+
+class IMPEGVideoCompletionNotifier : IInterfaceBase {
+public:
+ virtual void onVideoCompleted() = 0;
+};
+
+class SampleModifier : public Modifier, public IMPEGVideoCompletionNotifier, public IKeyboardEventReceiver {
public:
SampleModifier();
~SampleModifier();
@@ -129,6 +136,9 @@ public:
bool load(const PlugInModifierLoaderContext &context, const Data::MTI::SampleModifier &data);
+ void onVideoCompleted() override;
+ void onKeyboardEvent(Runtime *runtime, const KeyboardInputEvent &keyEvt) override;
+
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "Sample Modifier"; }
void debugInspect(IDebugInspectionReport *report) const override;
@@ -138,8 +148,15 @@ private:
Common::SharedPtr<Modifier> shallowClone() const override;
const char *getDefaultName() const override;
+ void stopPlaying();
+
Event _executeWhen;
int32 _videoNumber;
+
+ Common::SharedPtr<MPEGVideoPlayer> _vidPlayer;
+ Common::SharedPtr<KeyboardEventSignaller> _keySignaller;
+ Runtime *_runtime;
+ bool _isPlaying;
};
diff --git a/engines/mtropolis/runtime.cpp b/engines/mtropolis/runtime.cpp
index d3dd4a4c1e5..c9c7db7715a 100644
--- a/engines/mtropolis/runtime.cpp
+++ b/engines/mtropolis/runtime.cpp
@@ -4258,7 +4258,7 @@ Runtime::Runtime(OSystem *system, Audio::Mixer *mixer, ISaveUIProvider *saveProv
_cachedMousePosition(Common::Point(0, 0)), _realMousePosition(Common::Point(0, 0)), _trackedMouseOutside(false),
_forceCursorRefreshOnce(true), _autoResetCursor(false), _haveModifierOverrideCursor(false), _haveCursorElement(false), _sceneGraphChanged(false), _isQuitting(false),
_collisionCheckTime(0), /*_elementCursorUpdateTime(0), */_defaultVolumeState(true), _activeSceneTransitionEffect(nullptr), _sceneTransitionStartTime(0), _sceneTransitionEndTime(0),
- _sharedSceneWasSetExplicitly(false), _modifierOverrideCursorID(0), _subtitleRenderer(subRenderer), _multiClickStartTime(0), _multiClickInterval(500), _multiClickCount(0)
+ _sharedSceneWasSetExplicitly(false), _modifierOverrideCursorID(0), _subtitleRenderer(subRenderer), _multiClickStartTime(0), _multiClickInterval(500), _multiClickCount(0), _numMouseBlockers(0)
{
_random.reset(new Common::RandomSource("mtropolis"));
@@ -4356,6 +4356,8 @@ bool Runtime::runFrame() {
DispatchKeyTaskData *taskData = _vthread->pushTask("Runtime::dispatchKeyTask", this, &Runtime::dispatchKeyTask);
taskData->dispatch = dispatch;
}
+
+ _project->onKeyboardEvent(this, *static_cast<KeyboardInputEvent *>(evt.get()));
}
break;
case kOSEventTypeMouseDown:
@@ -5697,9 +5699,11 @@ VThreadState Runtime::updateMousePositionTask(const UpdateMousePositionTaskData
int32 bestLayer = INT32_MIN;
bool bestDirect = false;
- for (size_t ri = 0; ri < _sceneStack.size(); ri++) {
- const SceneStackEntry &sceneStackEntry = _sceneStack[_sceneStack.size() - 1 - ri];
- recursiveFindMouseCollision(collisionItem, bestSceneStack, bestLayer, bestDirect, sceneStackEntry.scene.get(), _sceneStack.size() - 1 - ri, data.x, data.y, kMouseInteractivityTestAnything);
+ if (_numMouseBlockers == 0) {
+ for (size_t ri = 0; ri < _sceneStack.size(); ri++) {
+ const SceneStackEntry &sceneStackEntry = _sceneStack[_sceneStack.size() - 1 - ri];
+ recursiveFindMouseCollision(collisionItem, bestSceneStack, bestLayer, bestDirect, sceneStackEntry.scene.get(), _sceneStack.size() - 1 - ri, data.x, data.y, kMouseInteractivityTestAnything);
+ }
}
Common::SharedPtr<Structural> newMouseOver;
@@ -6311,6 +6315,15 @@ void Runtime::setGlobalPalette(const Palette &palette) {
_globalPalette = palette;
}
+void Runtime::addMouseBlocker() {
+ _numMouseBlockers++;
+}
+
+void Runtime::removeMouseBlocker() {
+ assert(_numMouseBlockers > 0);
+ _numMouseBlockers--;
+}
+
void Runtime::checkBoundaries() {
// Boundary Detection Messenger behavior is very quirky in mTropolis 1.1. Basically, if an object moves in the direction of
// the boundary, then it may trigger collision checks with the boundary. If it moves but does not move in the direction of
@@ -6839,10 +6852,10 @@ KeyboardEventSignaller::KeyboardEventSignaller() {
KeyboardEventSignaller::~KeyboardEventSignaller() {
}
-void KeyboardEventSignaller::onKeyboardEvent(Runtime *runtime, Common::EventType evtType, bool repeat, const Common::KeyState &keyEvt) {
+void KeyboardEventSignaller::onKeyboardEvent(Runtime *runtime, const KeyboardInputEvent &keyEvt) {
const size_t numReceivers = _receivers.size();
for (size_t i = 0; i < numReceivers; i++) {
- _receivers[i]->onKeyboardEvent(runtime, evtType, repeat, keyEvt);
+ _receivers[i]->onKeyboardEvent(runtime, keyEvt);
}
}
@@ -7305,8 +7318,8 @@ Common::SharedPtr<PlayMediaSignaller> Project::notifyOnPlayMedia(IPlayMediaSigna
return _playMediaSignaller;
}
-void Project::onKeyboardEvent(Runtime *runtime, const Common::EventType evtType, bool repeat, const Common::KeyState &keyEvt) {
- _keyboardEventSignaller->onKeyboardEvent(runtime, evtType, repeat, keyEvt);
+void Project::onKeyboardEvent(Runtime *runtime, const KeyboardInputEvent &keyEvt) {
+ _keyboardEventSignaller->onKeyboardEvent(runtime, keyEvt);
}
Common::SharedPtr<KeyboardEventSignaller> Project::notifyOnKeyboardEvent(IKeyboardEventReceiver *receiver) {
diff --git a/engines/mtropolis/runtime.h b/engines/mtropolis/runtime.h
index c29a7929755..166b30e1b03 100644
--- a/engines/mtropolis/runtime.h
+++ b/engines/mtropolis/runtime.h
@@ -1704,6 +1704,9 @@ public:
const Palette &getGlobalPalette() const;
void setGlobalPalette(const Palette &palette);
+ void addMouseBlocker();
+ void removeMouseBlocker();
+
const Common::String *resolveAttributeIDName(uint32 attribID) const;
const Common::WeakPtr<Window> &getMainWindow() const;
@@ -1961,6 +1964,8 @@ private:
uint32 _multiClickInterval;
uint _multiClickCount;
+ uint _numMouseBlockers;
+
bool _defaultVolumeState;
// True if any elements were added to the scene, removed from the scene, or reparented since last draw
@@ -2325,7 +2330,7 @@ private:
};
struct IKeyboardEventReceiver : public IInterfaceBase {
- virtual void onKeyboardEvent(Runtime *runtime, Common::EventType evtType, bool repeat, const Common::KeyState &keyEvt) = 0;
+ virtual void onKeyboardEvent(Runtime *runtime, const KeyboardInputEvent &keyEvt) = 0;
};
class KeyboardEventSignaller {
@@ -2333,7 +2338,7 @@ public:
KeyboardEventSignaller();
~KeyboardEventSignaller();
- void onKeyboardEvent(Runtime *runtime, Common::EventType evtType, bool repeat, const Common::KeyState &keyEvt);
+ void onKeyboardEvent(Runtime *runtime, const KeyboardInputEvent &keyEvt);
void addReceiver(IKeyboardEventReceiver *receiver);
void removeReceiver(IKeyboardEventReceiver *receiver);
@@ -2420,7 +2425,7 @@ public:
const Common::String *findNameOfLabel(const Label &label) const;
void onPostRender();
- void onKeyboardEvent(Runtime *runtime, const Common::EventType evtType, bool repeat, const Common::KeyState &keyEvt);
+ void onKeyboardEvent(Runtime *runtime, const KeyboardInputEvent &keyEvt);
Common::SharedPtr<SegmentUnloadSignaller> notifyOnSegmentUnload(int segmentIndex, ISegmentUnloadSignalReceiver *receiver);
Common::SharedPtr<KeyboardEventSignaller> notifyOnKeyboardEvent(IKeyboardEventReceiver *receiver);
More information about the Scummvm-git-logs
mailing list