[Scummvm-git-logs] scummvm master -> f94e15d65385eb3e696cb1df00a53dfccea00a63

elasota noreply at scummvm.org
Mon Jul 4 23:25:30 UTC 2022


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:
f94e15d653 MTROPOLIS: Improve movie range handling accuracy


Commit: f94e15d65385eb3e696cb1df00a53dfccea00a63
    https://github.com/scummvm/scummvm/commit/f94e15d65385eb3e696cb1df00a53dfccea00a63
Author: elasota (ejlasota at gmail.com)
Date: 2022-07-04T19:24:48-04:00

Commit Message:
MTROPOLIS: Improve movie range handling accuracy

Changed paths:
    engines/mtropolis/elements.cpp
    engines/mtropolis/elements.h


diff --git a/engines/mtropolis/elements.cpp b/engines/mtropolis/elements.cpp
index 5eaae0ecfdf..ad5d50e2811 100644
--- a/engines/mtropolis/elements.cpp
+++ b/engines/mtropolis/elements.cpp
@@ -545,7 +545,7 @@ void GraphicElement::render(Window *window) {
 MovieElement::MovieElement()
 	: _cacheBitmap(false), _reversed(false), _haveFiredAtFirstCel(false), _haveFiredAtLastCel(false)
 	, _alternate(false), _playEveryFrame(false), _assetID(0), _runtime(nullptr), _displayFrame(nullptr)
-	, _shouldPlayIfNotPaused(true), _needsReset(true), _currentPlayState(kMediaStateStopped) {
+	, _shouldPlayIfNotPaused(true), _needsReset(true), _currentPlayState(kMediaStateStopped), _playRange(IntRange::create(0, 0)) {
 }
 
 MovieElement::~MovieElement() {
@@ -697,7 +697,7 @@ void MovieElement::activate() {
 	_playMediaSignaller = project->notifyOnPlayMedia(this);
 
 	_maxTimestamp = qtDecoder->getDuration().convertToFramerate(qtDecoder->getTimeScale()).totalNumberOfFrames();
-	_playRange = IntRange::create(0, _maxTimestamp);
+	_playRange = IntRange::create(0, 0);
 	_currentTimestamp = 0;
 
 	if (_name.empty())
@@ -733,10 +733,12 @@ void MovieElement::queueAutoPlayEvents(Runtime *runtime, bool isAutoPlaying) {
 }
 
 void MovieElement::render(Window *window) {
+	const IntRange realRange = computeRealRange();
+
 	if (_needsReset) {
 		_videoDecoder->setReverse(_reversed);
 		_videoDecoder->seek(Audio::Timestamp(0, _timeScale).addFrames(_currentTimestamp));
-		_videoDecoder->setEndTime(Audio::Timestamp(0, _timeScale).addFrames(_reversed ? _playRange.min : _playRange.max));
+		_videoDecoder->setEndTime(Audio::Timestamp(0, _timeScale).addFrames(_reversed ? realRange.min : realRange.max));
 		const Graphics::Surface *decodedFrame = _videoDecoder->decodeNextFrame();
 		if (decodedFrame)
 			_displayFrame = decodedFrame;
@@ -785,8 +787,10 @@ void MovieElement::playMedia(Runtime *runtime, Project *project) {
 			_currentPlayState = kMediaStateStopped;
 		}
 
-		uint32 minTS = _playRange.min;
-		uint32 maxTS = _playRange.max;
+		const IntRange realRange = computeRealRange();
+
+		uint32 minTS = realRange.min;
+		uint32 maxTS = realRange.max;
 		uint32 targetTS = _currentTimestamp;
 
 		int framesDecodedThisFrame = 0;
@@ -825,7 +829,7 @@ void MovieElement::playMedia(Runtime *runtime, Project *project) {
 			}
 
 			if (_videoDecoder->endOfVideo())
-				targetTS = _reversed ? _playRange.min : _playRange.max;
+				targetTS = _reversed ? realRange.min : realRange.max;
 			else
 				targetTS = (_videoDecoder->getTime() * _timeScale + 500) / 1000;
 		}
@@ -884,7 +888,7 @@ void MovieElement::playMedia(Runtime *runtime, Project *project) {
 
 			if (_loop) {
 				_needsReset = true;
-				_currentTimestamp = _reversed ? _playRange.max : _playRange.min;
+				_currentTimestamp = _reversed ? realRange.max : realRange.min;
 				_contentsDirty = true;
 			}
 		}
@@ -895,6 +899,13 @@ void MovieElement::onSegmentUnloaded(int segmentIndex) {
 	_videoDecoder.reset();
 }
 
+IntRange MovieElement::computeRealRange() const {
+	// The default range for movies is 0..0, which is interpreted as unset
+	if (_playRange.min == 0 && _playRange.max == 0)
+		return IntRange::create(0, _maxTimestamp);
+	return _playRange;
+}
+
 MiniscriptInstructionOutcome MovieElement::scriptSetRange(MiniscriptThread *thread, const DynamicValue &value) {
 	if (value.getType() != DynamicValueTypes::kIntegerRange) {
 		thread->error("Wrong type for movie element range");
@@ -953,7 +964,11 @@ MiniscriptInstructionOutcome MovieElement::scriptSetRangeStart(MiniscriptThread
 		return kMiniscriptInstructionOutcomeFailed;
 	}
 
-	return scriptSetRangeTyped(thread, IntRange::create(asInteger, _playRange.max));
+	int32 rangeMax = _playRange.max;
+	if (rangeMax < asInteger)
+		rangeMax = asInteger;
+
+	return scriptSetRangeTyped(thread, IntRange::create(asInteger, rangeMax));
 }
 
 MiniscriptInstructionOutcome MovieElement::scriptSetRangeEnd(MiniscriptThread *thread, const DynamicValue &value) {
@@ -963,7 +978,11 @@ MiniscriptInstructionOutcome MovieElement::scriptSetRangeEnd(MiniscriptThread *t
 		return kMiniscriptInstructionOutcomeFailed;
 	}
 
-	return scriptSetRangeTyped(thread, IntRange::create(_playRange.min, asInteger));
+	int32 rangeMin = _playRange.min;
+	if (rangeMin > asInteger)
+		rangeMin = asInteger;
+
+	return scriptSetRangeTyped(thread, IntRange::create(rangeMin, asInteger));
 }
 
 MiniscriptInstructionOutcome MovieElement::scriptRangeWriteRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &result, const Common::String &attrib) {
@@ -984,23 +1003,22 @@ MiniscriptInstructionOutcome MovieElement::scriptSetRangeTyped(MiniscriptThread
 
 	if (_playRange.min < 0)
 		_playRange.min = 0;
-	else if (_playRange.min > (int32)_maxTimestamp)
-		_playRange.min = _maxTimestamp;
 
 	if (_playRange.max > (int32)_maxTimestamp)
 		_playRange.max = _maxTimestamp;
 
+	// Tested that this is the correct logic for inverted ranges
 	if (_playRange.max < _playRange.min)
-		_playRange.max = _playRange.min;
+		_playRange.min = _playRange.max;
 
 	uint32 minTS = _playRange.min;
 	uint32 maxTS = _playRange.max;
 	uint32 targetTS = _currentTimestamp;
 
-	if (targetTS < minTS)
-		targetTS = minTS;
-	if (targetTS > maxTS)
-		targetTS = maxTS;
+	// If the current timestamp is out of range then it goes to the start of the range
+	// Obsidian needs this for the cube maze security booth
+	if (targetTS < minTS || targetTS > maxTS)
+		targetTS = _reversed ? maxTS : minTS;
 
 	if (targetTS != _currentTimestamp) {
 		SeekToTimeTaskData *taskData = thread->getRuntime()->getVThread().pushTask("MovieElement::seekToTimeTask", this, &MovieElement::seekToTimeTask);
diff --git a/engines/mtropolis/elements.h b/engines/mtropolis/elements.h
index b2a37f0c333..ce8664e05d1 100644
--- a/engines/mtropolis/elements.h
+++ b/engines/mtropolis/elements.h
@@ -103,6 +103,8 @@ public:
 private:
 	void onSegmentUnloaded(int segmentIndex) override;
 
+	IntRange computeRealRange() const;
+
 	MiniscriptInstructionOutcome scriptSetRange(MiniscriptThread *thread, const DynamicValue &value);
 	MiniscriptInstructionOutcome scriptSetRangeStart(MiniscriptThread *thread, const DynamicValue &value);
 	MiniscriptInstructionOutcome scriptSetRangeEnd(MiniscriptThread *thread, const DynamicValue &value);




More information about the Scummvm-git-logs mailing list