[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