[Scummvm-git-logs] scummvm master -> 69c6470c6a650fbe83b1c3c4dabd92508c08161f
elasota
noreply at scummvm.org
Fri Jul 15 05:39:25 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:
69c6470c6a MTROPOLIS: Add scene transition effect support
Commit: 69c6470c6a650fbe83b1c3c4dabd92508c08161f
https://github.com/scummvm/scummvm/commit/69c6470c6a650fbe83b1c3c4dabd92508c08161f
Author: elasota (ejlasota at gmail.com)
Date: 2022-07-15T01:38:31-04:00
Commit Message:
MTROPOLIS: Add scene transition effect support
Changed paths:
engines/mtropolis/detection.cpp
engines/mtropolis/detection_tables.h
engines/mtropolis/hacks.cpp
engines/mtropolis/hacks.h
engines/mtropolis/modifiers.cpp
engines/mtropolis/modifiers.h
engines/mtropolis/mtropolis.cpp
engines/mtropolis/plugin/obsidian.h
engines/mtropolis/plugin/standard.cpp
engines/mtropolis/plugin/standard.h
engines/mtropolis/render.cpp
engines/mtropolis/render.h
engines/mtropolis/runtime.cpp
engines/mtropolis/runtime.h
diff --git a/engines/mtropolis/detection.cpp b/engines/mtropolis/detection.cpp
index 8280f2867fa..3e3a808b83d 100644
--- a/engines/mtropolis/detection.cpp
+++ b/engines/mtropolis/detection.cpp
@@ -70,6 +70,17 @@ static const ADExtraGuiOptionsMap optionsList[] = {
0
}
},
+ {
+ GAMEOPTION_ENABLE_SHORT_TRANSITIONS,
+ {
+ _s("Enable short transitions"),
+ _s("Enables transitions that are set to maximum rate instead of skipping them"),
+ "mtropolis_mod_minimum_transition_duration",
+ false,
+ 0,
+ 0
+ }
+ },
{
GAMEOPTION_LAUNCH_DEBUG,
{
@@ -107,7 +118,7 @@ static const char *directoryGlobs[] = {
class MTropolisMetaEngineDetection : public AdvancedMetaEngineDetection {
public:
MTropolisMetaEngineDetection() : AdvancedMetaEngineDetection(MTropolis::gameDescriptions, sizeof(MTropolis::MTropolisGameDescription), mTropolisGames, MTropolis::optionsList) {
- _guiOptions = GUIO3(GAMEOPTION_DYNAMIC_MIDI, GAMEOPTION_LAUNCH_DEBUG, GAMEOPTION_LAUNCH_BREAK);
+ _guiOptions = GUIO4(GAMEOPTION_DYNAMIC_MIDI, GAMEOPTION_LAUNCH_DEBUG, GAMEOPTION_LAUNCH_BREAK, GAMEOPTION_ENABLE_SHORT_TRANSITIONS);
_maxScanDepth = 3;
_directoryGlobs = directoryGlobs;
}
diff --git a/engines/mtropolis/detection_tables.h b/engines/mtropolis/detection_tables.h
index 40a63564187..0cd0eeed3e0 100644
--- a/engines/mtropolis/detection_tables.h
+++ b/engines/mtropolis/detection_tables.h
@@ -26,11 +26,12 @@
#include "mtropolis/detection.h"
-#define GAMEOPTION_WIDESCREEN_MOD GUIO_GAMEOPTIONS1
-#define GAMEOPTION_DYNAMIC_MIDI GUIO_GAMEOPTIONS2
-#define GAMEOPTION_LAUNCH_DEBUG GUIO_GAMEOPTIONS3
-#define GAMEOPTION_LAUNCH_BREAK GUIO_GAMEOPTIONS4
-#define GAMEOPTION_AUTO_SAVE GUIO_GAMEOPTIONS5
+#define GAMEOPTION_WIDESCREEN_MOD GUIO_GAMEOPTIONS1
+#define GAMEOPTION_DYNAMIC_MIDI GUIO_GAMEOPTIONS2
+#define GAMEOPTION_LAUNCH_DEBUG GUIO_GAMEOPTIONS3
+#define GAMEOPTION_LAUNCH_BREAK GUIO_GAMEOPTIONS4
+#define GAMEOPTION_AUTO_SAVE GUIO_GAMEOPTIONS5
+#define GAMEOPTION_ENABLE_SHORT_TRANSITIONS GUIO_GAMEOPTIONS6
namespace MTropolis {
diff --git a/engines/mtropolis/hacks.cpp b/engines/mtropolis/hacks.cpp
index 31aa28bf538..5d57e6a55ff 100644
--- a/engines/mtropolis/hacks.cpp
+++ b/engines/mtropolis/hacks.cpp
@@ -34,6 +34,7 @@ namespace MTropolis {
Hacks::Hacks() {
ignoreMismatchedProjectNameInObjectLookups = false;
midiVolumeScale = 256;
+ minTransitionDuration = 0;
}
Hacks::~Hacks() {
diff --git a/engines/mtropolis/hacks.h b/engines/mtropolis/hacks.h
index 110a55913fe..804e204ce60 100644
--- a/engines/mtropolis/hacks.h
+++ b/engines/mtropolis/hacks.h
@@ -49,6 +49,8 @@ struct Hacks {
bool ignoreMismatchedProjectNameInObjectLookups;
uint midiVolumeScale; // 256 = 1.0
+ uint32 minTransitionDuration;
+
Common::Point reportDisplaySize; // If X or Y is non-zero, report this as the display size
Common::Point mainWindowOffset; // Coordinate offset of the main window
diff --git a/engines/mtropolis/modifiers.cpp b/engines/mtropolis/modifiers.cpp
index d3dfa5e83ed..c4391c1f554 100644
--- a/engines/mtropolis/modifiers.cpp
+++ b/engines/mtropolis/modifiers.cpp
@@ -846,6 +846,39 @@ bool SceneTransitionModifier::load(ModifierLoaderContext &context, const Data::S
return true;
}
+bool SceneTransitionModifier::respondsToEvent(const Event &evt) const {
+ return _enableWhen.respondsTo(evt) || _disableWhen.respondsTo(evt);
+}
+
+VThreadState SceneTransitionModifier::consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) {
+ if (_enableWhen.respondsTo(msg->getEvent())) {
+ SceneTransitionEffect effect;
+
+ // For some reason, these vary
+ uint32 timeDivisor = 100;
+ switch (effect._transitionType) {
+ case SceneTransitionTypes::kRandomDissolve:
+ timeDivisor = 50;
+ break;
+ case SceneTransitionTypes::kFade:
+ timeDivisor = 25;
+ break;
+ default:
+ break;
+ }
+
+ effect._duration = _duration / timeDivisor;
+ effect._steps = _steps;
+ effect._transitionDirection = _transitionDirection;
+ effect._transitionType = _transitionType;
+ runtime->setSceneTransitionEffect(true, &effect);
+ }
+ if (_disableWhen.respondsTo(msg->getEvent()))
+ runtime->setSceneTransitionEffect(true, nullptr);
+
+ return kVThreadReturn;
+}
+
Common::SharedPtr<Modifier> SceneTransitionModifier::shallowClone() const {
return Common::SharedPtr<Modifier>(new SceneTransitionModifier(*this));
}
diff --git a/engines/mtropolis/modifiers.h b/engines/mtropolis/modifiers.h
index 85101ba75fb..aebbd1ea091 100644
--- a/engines/mtropolis/modifiers.h
+++ b/engines/mtropolis/modifiers.h
@@ -320,6 +320,7 @@ public:
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "Vector Modifier"; }
+ SupportStatus debugGetSupportStatus() const override { return kSupportStatusDone; }
#endif
private:
@@ -348,6 +349,9 @@ class SceneTransitionModifier : public Modifier {
public:
bool load(ModifierLoaderContext &context, const Data::SceneTransitionModifier &data);
+ bool respondsToEvent(const Event &evt) const override;
+ VThreadState consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) override;
+
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "Scene Transition Modifier"; }
#endif
diff --git a/engines/mtropolis/mtropolis.cpp b/engines/mtropolis/mtropolis.cpp
index aca9a3b09e8..70d318f6b86 100644
--- a/engines/mtropolis/mtropolis.cpp
+++ b/engines/mtropolis/mtropolis.cpp
@@ -132,6 +132,9 @@ Common::Error MTropolisEngine::run() {
}
}
+ if (ConfMan.getBool("mtropolis_mod_minimum_transition_duration"))
+ _runtime->getHacks().minTransitionDuration = 75;
+
_runtime->queueProject(projectDesc);
// Figure out pixel formats
diff --git a/engines/mtropolis/plugin/obsidian.h b/engines/mtropolis/plugin/obsidian.h
index a74982e9ddb..3c539247b08 100644
--- a/engines/mtropolis/plugin/obsidian.h
+++ b/engines/mtropolis/plugin/obsidian.h
@@ -83,6 +83,7 @@ public:
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "TextWork Modifier"; }
+ SupportStatus debugGetSupportStatus() const override { return kSupportStatusDone; }
#endif
private:
@@ -111,6 +112,7 @@ public:
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "Dictionary Modifier"; }
+ SupportStatus debugGetSupportStatus() const override { return kSupportStatusDone; }
#endif
private:
@@ -139,6 +141,7 @@ public:
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "WordMixer Modifier"; }
+ SupportStatus debugGetSupportStatus() const override { return kSupportStatusDone; }
#endif
private:
@@ -167,6 +170,7 @@ public:
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "Xor Mod Modifier"; }
+ SupportStatus debugGetSupportStatus() const override { return kSupportStatusDone; }
#endif
private:
@@ -190,6 +194,7 @@ public:
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "Xor Check Modifier"; }
+ SupportStatus debugGetSupportStatus() const override { return kSupportStatusDone; }
#endif
private:
diff --git a/engines/mtropolis/plugin/standard.cpp b/engines/mtropolis/plugin/standard.cpp
index 137d4057748..b8fff035c0d 100644
--- a/engines/mtropolis/plugin/standard.cpp
+++ b/engines/mtropolis/plugin/standard.cpp
@@ -1605,6 +1605,34 @@ bool STransCtModifier::load(const PlugInModifierLoaderContext &context, const Da
return true;
}
+bool STransCtModifier::respondsToEvent(const Event &evt) const {
+ return _enableWhen.respondsTo(evt) || _disableWhen.respondsTo(evt);
+}
+
+VThreadState STransCtModifier::consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) {
+ if (_enableWhen.respondsTo(msg->getEvent())) {
+ SceneTransitionEffect effect;
+ effect._duration = _duration / 10;
+ effect._steps = _steps;
+
+ if (SceneTransitionTypes::loadFromData(effect._transitionType, _transitionType) && SceneTransitionDirections::loadFromData(effect._transitionDirection, _transitionDirection)) {
+ // Weird quirk: Duration doesn't seem to affect duration properly for wipe transitions.
+ // In Obsidian, this mostly effects 180-degree turns.
+ // Good place to test this is in the corners of the Bureau library.
+ if (effect._transitionType == SceneTransitionTypes::kWipe && effect._duration < 1000)
+ effect._duration = 1000;
+
+ runtime->setSceneTransitionEffect(false, &effect);
+ } else {
+ warning("Source-scene transition had invalid data");
+ }
+ }
+ if (_disableWhen.respondsTo(msg->getEvent()))
+ runtime->setSceneTransitionEffect(false, nullptr);
+
+ return kVThreadReturn;
+}
+
bool STransCtModifier::readAttribute(MiniscriptThread *thread, DynamicValue &result, const Common::String &attrib) {
if (attrib == "rate") {
if (_duration <= (kMaxDuration / 100))
diff --git a/engines/mtropolis/plugin/standard.h b/engines/mtropolis/plugin/standard.h
index 989541b4a3d..c5481eaae3e 100644
--- a/engines/mtropolis/plugin/standard.h
+++ b/engines/mtropolis/plugin/standard.h
@@ -73,11 +73,15 @@ public:
bool load(const PlugInModifierLoaderContext &context, const Data::Standard::STransCtModifier &data);
+ bool respondsToEvent(const Event &evt) const override;
+ VThreadState consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) override;
+
bool readAttribute(MiniscriptThread *thread, DynamicValue &result, const Common::String &attrib) override;
MiniscriptInstructionOutcome writeRefAttribute(MiniscriptThread *thread, DynamicValueWriteProxy &result, const Common::String &attrib) override;
#ifdef MTROPOLIS_DEBUG_ENABLE
const char *debugGetTypeName() const override { return "STransCt Scene Transition Modifier"; }
+ SupportStatus debugGetSupportStatus() const override { return kSupportStatusDone; }
#endif
private:
diff --git a/engines/mtropolis/render.cpp b/engines/mtropolis/render.cpp
index 175717b9d18..005185d8be9 100644
--- a/engines/mtropolis/render.cpp
+++ b/engines/mtropolis/render.cpp
@@ -303,6 +303,215 @@ void renderProject(Runtime *runtime, Window *mainWindow) {
runtime->clearSceneGraphDirty();
}
+class DissolveOrderedDitherPatternGenerator {
+public:
+ DissolveOrderedDitherPatternGenerator();
+
+ uint8 getNext();
+ void nextLine();
+
+private:
+ uint8 _ditherPattern[16][16];
+
+ uint16 _x;
+ uint16 _y;
+};
+
+DissolveOrderedDitherPatternGenerator::DissolveOrderedDitherPatternGenerator() {
+ OrderedDitherGenerator<uint8, 16>::generateOrderedDither(_ditherPattern);
+}
+
+inline uint8 DissolveOrderedDitherPatternGenerator::getNext() {
+ uint8 result = _ditherPattern[_y][_x];
+
+ uint16 newX = _x + 1;
+ if (newX == 16)
+ newX = 0;
+ _x = newX;
+
+ return result;
+}
+
+inline void DissolveOrderedDitherPatternGenerator::nextLine() {
+ _x = 0;
+ uint16 newY = _y + 1;
+ if (newY == 16)
+ newY = 0;
+ _y = newY;
+}
+
+class DissolveOrderedDitherRandomGenerator {
+public:
+ DissolveOrderedDitherRandomGenerator();
+
+ uint8 getNext();
+ void nextLine();
+
+private:
+ uint32 _lcgState;
+};
+
+
+DissolveOrderedDitherRandomGenerator::DissolveOrderedDitherRandomGenerator() : _lcgState(13) {
+}
+
+inline uint8 DissolveOrderedDitherRandomGenerator::getNext() {
+ _lcgState = ((_lcgState * 1103515245u) + 12345u) & 0x7fffffffu;
+ return (_lcgState >> 16) & 0xff;
+}
+
+inline void DissolveOrderedDitherRandomGenerator::nextLine() {
+}
+
+template<class TPixel, class TGenerator>
+static void runDissolveTransitionWithType(Graphics::ManagedSurface &surface, const Graphics::ManagedSurface &oldFrame, const Graphics::ManagedSurface &newFrame, uint8 breakpoint) {
+ TGenerator generator;
+
+ assert(surface.format.bytesPerPixel == oldFrame.format.bytesPerPixel);
+ assert(surface.format.bytesPerPixel == newFrame.format.bytesPerPixel);
+
+ uint16 w = surface.w;
+ uint16 h = surface.h;
+
+ for (uint y = 0; y < h; y++) {
+ TPixel *destRow = static_cast<TPixel *>(surface.getBasePtr(0, y));
+ const TPixel *oldRow = static_cast<const TPixel *>(oldFrame.getBasePtr(0, y));
+ const TPixel *newRow = static_cast<const TPixel *>(newFrame.getBasePtr(0, y));
+
+ for (uint x = 0; x < w; x++) {
+ if (generator.getNext() <= breakpoint)
+ destRow[x] = newRow[x];
+ else
+ destRow[x] = oldRow[x];
+ }
+
+ generator.nextLine();
+ }
+}
+
+template<class TGenerator>
+static void runDissolveTransition(Graphics::ManagedSurface &surface, const Graphics::ManagedSurface &oldFrame, const Graphics::ManagedSurface &newFrame, uint8 breakpoint) {
+ switch (surface.format.bytesPerPixel) {
+ case 1:
+ runDissolveTransitionWithType<uint8, TGenerator>(surface, oldFrame, newFrame, breakpoint);
+ break;
+ case 2:
+ runDissolveTransitionWithType<uint16, TGenerator>(surface, oldFrame, newFrame, breakpoint);
+ break;
+ case 4:
+ runDissolveTransitionWithType<uint32, TGenerator>(surface, oldFrame, newFrame, breakpoint);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
+
+static void safeCopyRectToSurface(Graphics::ManagedSurface &surface, const Graphics::Surface &srcSurface, int destX, int destY, const Common::Rect subRect) {
+ if (subRect.width() == 0 || subRect.height() == 0)
+ return;
+
+ surface.copyRectToSurface(srcSurface, destX, destY, subRect);
+}
+
+void renderSceneTransition(Runtime *runtime, Window *mainWindow, const SceneTransitionEffect &effect, uint32 startTime, uint32 endTime, uint32 currentTime, const Graphics::ManagedSurface &oldFrame, const Graphics::ManagedSurface &newFrame) {
+ Graphics::ManagedSurface &surface = *mainWindow->getSurface();
+
+ assert(endTime > startTime);
+
+ uint32 duration = endTime - startTime;
+
+ uint16 w = surface.w;
+ uint16 h = surface.h;
+
+ if (effect._transitionType == SceneTransitionTypes::kSlide || effect._transitionType == SceneTransitionTypes::kWipe)
+ safeCopyRectToSurface(surface, oldFrame, 0, 0, Common::Rect(0, 0, w, h));
+
+ switch (effect._transitionType) {
+ case SceneTransitionTypes::kPatternDissolve:
+ runDissolveTransition<DissolveOrderedDitherPatternGenerator>(surface, oldFrame, newFrame, (currentTime - startTime) * 255 / duration);
+ break;
+ case SceneTransitionTypes::kRandomDissolve:
+ runDissolveTransition<DissolveOrderedDitherRandomGenerator>(surface, oldFrame, newFrame, (currentTime - startTime) * 255 / duration);
+ break;
+ case SceneTransitionTypes::kFade:
+ // Fade transitions fade to black and then fade from black in the new scene
+ warning("Fade transitions are not implemented");
+ break;
+ case SceneTransitionTypes::kSlide:
+ case SceneTransitionTypes::kPush: {
+ uint32 directionalOffset = 0;
+ switch (effect._transitionDirection) {
+ case SceneTransitionDirections::kUp:
+ directionalOffset = static_cast<uint32>(currentTime - startTime) * static_cast<uint32>(h) / duration;
+
+ if (effect._transitionType == SceneTransitionTypes::kPush)
+ safeCopyRectToSurface(surface, oldFrame, 0, 0, Common::Rect(0, directionalOffset, w, h));
+
+ safeCopyRectToSurface(surface, newFrame, 0, h - directionalOffset, Common::Rect(0, 0, w, directionalOffset));
+ break;
+ case SceneTransitionDirections::kDown:
+ directionalOffset = static_cast<uint32>(currentTime - startTime) * static_cast<uint32>(h) / duration;
+
+ if (effect._transitionType == SceneTransitionTypes::kPush)
+ safeCopyRectToSurface(surface, oldFrame, 0, directionalOffset, Common::Rect(0, 0, w, h - directionalOffset));
+
+ safeCopyRectToSurface(surface, newFrame, 0, 0, Common::Rect(0, h - directionalOffset, w, h));
+ break;
+ case SceneTransitionDirections::kLeft:
+ directionalOffset = static_cast<uint32>(currentTime - startTime) * static_cast<uint32>(w) / duration;
+
+ if (effect._transitionType == SceneTransitionTypes::kPush)
+ safeCopyRectToSurface(surface, oldFrame, 0, 0, Common::Rect(directionalOffset, 0, w, h));
+
+ safeCopyRectToSurface(surface, newFrame, w - directionalOffset, 0, Common::Rect(0, 0, directionalOffset, h));
+ break;
+ case SceneTransitionDirections::kRight:
+ directionalOffset = static_cast<uint32>(currentTime - startTime) * static_cast<uint32>(w) / duration;
+
+ if (effect._transitionType == SceneTransitionTypes::kPush)
+ safeCopyRectToSurface(surface, oldFrame, directionalOffset, 0, Common::Rect(0, 0, w - directionalOffset, h));
+
+ safeCopyRectToSurface(surface, newFrame, 0, 0, Common::Rect(w - directionalOffset, 0, w, h));
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ } break;
+ case SceneTransitionTypes::kZoom:
+ warning("Zoom transitions are not implemented");
+ break;
+ case SceneTransitionTypes::kWipe:{
+ uint32 directionalOffset = 0;
+ switch (effect._transitionDirection) {
+ case SceneTransitionDirections::kUp:
+ directionalOffset = static_cast<uint32>(currentTime - startTime) * static_cast<uint32>(h) / duration;
+ safeCopyRectToSurface(surface, newFrame, 0, h - directionalOffset, Common::Rect(0, h - directionalOffset, w, h));
+ break;
+ case SceneTransitionDirections::kDown:
+ directionalOffset = static_cast<uint32>(currentTime - startTime) * static_cast<uint32>(h) / duration;
+ safeCopyRectToSurface(surface, newFrame, 0, 0, Common::Rect(0, 0, w, directionalOffset));
+ break;
+ case SceneTransitionDirections::kLeft:
+ directionalOffset = static_cast<uint32>(currentTime - startTime) * static_cast<uint32>(w) / duration;
+ safeCopyRectToSurface(surface, newFrame, w - directionalOffset, 0, Common::Rect(w - directionalOffset, 0, w, h));
+ break;
+ case SceneTransitionDirections::kRight:
+ directionalOffset = static_cast<uint32>(currentTime - startTime) * static_cast<uint32>(w) / duration;
+ safeCopyRectToSurface(surface, newFrame, 0, 0, Common::Rect(0, 0, directionalOffset, h));
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ } break;
+ default:
+ assert(false);
+ break;
+ }
+}
+
void convert32To16(Graphics::Surface &destSurface, const Graphics::Surface &srcSurface) {
const Graphics::PixelFormat srcFmt = srcSurface.format;
const Graphics::PixelFormat destFmt = destSurface.format;
diff --git a/engines/mtropolis/render.h b/engines/mtropolis/render.h
index 17e847a4466..953ab150562 100644
--- a/engines/mtropolis/render.h
+++ b/engines/mtropolis/render.h
@@ -40,6 +40,7 @@ namespace MTropolis {
class CursorGraphic;
class Runtime;
class Project;
+struct SceneTransitionEffect;
enum TextAlignment {
kTextAlignmentLeft,
@@ -133,6 +134,8 @@ namespace Render {
uint32 resolveRGB(uint8 r, uint8 g, uint8 b, const Graphics::PixelFormat &fmt);
void renderProject(Runtime *runtime, Window *mainWindow);
+void renderSceneTransition(Runtime *runtime, Window *mainWindow, const SceneTransitionEffect &effect, uint32 startTime, uint32 endTime, uint32 currentTime, const Graphics::ManagedSurface &oldFrame, const Graphics::ManagedSurface &newFrame);
+
void convert32To16(Graphics::Surface &destSurface, const Graphics::Surface &srcSurface);
void convert16To32(Graphics::Surface &destSurface, const Graphics::Surface &srcSurface);
diff --git a/engines/mtropolis/runtime.cpp b/engines/mtropolis/runtime.cpp
index c9688035372..32c11152edd 100644
--- a/engines/mtropolis/runtime.cpp
+++ b/engines/mtropolis/runtime.cpp
@@ -259,7 +259,7 @@ size_t caseInsensitiveFind(const Common::String &strToSearch, const Common::Stri
return Common::String::npos;
}
-bool SceneTransitionTypes::loadFromData(SceneTransitionType &transType, uint16 data) {
+bool SceneTransitionTypes::loadFromData(SceneTransitionType &transType, int32 data) {
switch (data) {
case Data::SceneTransitionTypes::kNone:
transType = kNone;
@@ -293,7 +293,7 @@ bool SceneTransitionTypes::loadFromData(SceneTransitionType &transType, uint16 d
}
-bool SceneTransitionDirections::loadFromData(SceneTransitionDirection &transDir, uint16 data) {
+bool SceneTransitionDirections::loadFromData(SceneTransitionDirection &transDir, int32 data) {
switch (data) {
case Data::SceneTransitionDirections::kUp:
transDir = kUp;
@@ -3298,6 +3298,10 @@ HighLevelSceneTransition::HighLevelSceneTransition(const Common::SharedPtr<Struc
: scene(hlst_scene), type(hlst_type), addToDestinationScene(hlst_addToDestinationScene), addToReturnList(hlst_addToReturnList) {
}
+SceneTransitionEffect::SceneTransitionEffect()
+ : _duration(100000), _steps(64), _transitionType(SceneTransitionTypes::kNone), _transitionDirection(SceneTransitionDirections::kUp) {
+}
+
MessageDispatch::MessageDispatch(const Common::SharedPtr<MessageProperties> &msgProps, Structural *root, bool cascade, bool relay, bool couldBeCommand)
: _cascade(cascade), _relay(relay), _terminated(false), _msg(msgProps), _isCommand(false) {
if (couldBeCommand && EventIDs::isCommand(msgProps->getEvent().eventType)) {
@@ -3730,7 +3734,7 @@ Runtime::Runtime(OSystem *system, Audio::Mixer *mixer, ISaveUIProvider *saveProv
_lastFrameCursor(nullptr), _defaultCursor(new DefaultCursorGraphic()), _platform(kProjectPlatformUnknown),
_cachedMousePosition(Common::Point(0, 0)), _realMousePosition(Common::Point(0, 0)), _trackedMouseOutside(false),
_forceCursorRefreshOnce(true), _autoResetCursor(false), _haveModifierOverrideCursor(false), _sceneGraphChanged(false), _isQuitting(false),
- _collisionCheckTime(0), _defaultVolumeState(true) {
+ _collisionCheckTime(0), _defaultVolumeState(true), _activeSceneTransitionEffect(nullptr), _sceneTransitionStartTime(0), _sceneTransitionEndTime(0) {
_random.reset(new Common::RandomSource("mtropolis"));
_vthread.reset(new VThread());
@@ -3800,7 +3804,7 @@ bool Runtime::runFrame() {
break;
}
- if (_osEventQueue.size() > 0) {
+ if (_sceneTransitionState != kSceneTransitionStateTransitioning && _osEventQueue.size() > 0) {
Common::SharedPtr<OSEvent> evt = _osEventQueue[0];
_osEventQueue.remove_at(0);
@@ -3953,19 +3957,57 @@ bool Runtime::runFrame() {
}
if (_sceneTransitionState == kSceneTransitionStateWaitingForDraw) {
- if (_sceneTransitionEffect.duration == 0) {
- // This needs to skip past the transition phase and hit the next condition
+ if (_sourceSceneTransitionEffect._transitionType != SceneTransitionTypes::kNone)
+ _activeSceneTransitionEffect = &_sourceSceneTransitionEffect;
+ else if (_destinationSceneTransitionEffect._transitionType != SceneTransitionTypes::kNone)
+ _activeSceneTransitionEffect = &_destinationSceneTransitionEffect;
+ else
+ _activeSceneTransitionEffect = nullptr;
+
+ _sceneTransitionState = kSceneTransitionStateTransitioning;
+ _sceneTransitionStartTime = _playTime;
+
+ uint32 transitionDuration = 0;
+
+ if (_activeSceneTransitionEffect) {
+ transitionDuration = _activeSceneTransitionEffect->_duration;
+
+ if (transitionDuration < _hacks.minTransitionDuration)
+ transitionDuration = _hacks.minTransitionDuration;
+ }
+
+ if (transitionDuration == 0) {
+ // No transition at all. This needs to skip past the transition phase and hit the next condition
_sceneTransitionEndTime = _playTime;
- _sceneTransitionState = kSceneTransitionStateTransitioning;
} else {
- _sceneTransitionState = kSceneTransitionStateDrawingTargetFrame;
- _sceneTransitionEndTime = _playTime + _sceneTransitionEffect.duration / 10;
+ _sceneTransitionEndTime = _playTime + transitionDuration;
+
+ if (!_mainWindow.expired()) {
+ Common::SharedPtr<Window> mainWindow = _mainWindow.lock();
+ _sceneTransitionOldFrame.reset(new Graphics::ManagedSurface());
+ _sceneTransitionNewFrame.reset(new Graphics::ManagedSurface());
+
+ _sceneTransitionOldFrame->copyFrom(*mainWindow->getSurface());
+
+ Render::renderProject(this, mainWindow.get());
+
+ _sceneTransitionNewFrame->copyFrom(*mainWindow->getSurface());
+ }
}
}
if (_sceneTransitionState == kSceneTransitionStateTransitioning && _playTime >= _sceneTransitionEndTime) {
_sceneTransitionState = kSceneTransitionStateNotTransitioning;
+ if (_sceneTransitionNewFrame && !_mainWindow.expired())
+ _mainWindow.lock()->getSurface()->copyFrom(*_sceneTransitionNewFrame);
+
+ _sceneTransitionOldFrame.reset();
+ _sceneTransitionNewFrame.reset();
+
+ _sourceSceneTransitionEffect = SceneTransitionEffect();
+ _destinationSceneTransitionEffect = SceneTransitionEffect();
+
for (const SceneStackEntry &sceneStackEntry : _sceneStack)
recursiveAutoPlayMedia(sceneStackEntry.scene.get());
@@ -3976,6 +4018,11 @@ bool Runtime::runFrame() {
continue;
}
+ if (_sceneTransitionState == kSceneTransitionStateTransitioning) {
+ // Keep looping transition and don't do anything else until it's done
+ break;
+ }
+
{
Common::SharedPtr<ScheduledEvent> firstScheduledEvent = _scheduler.getFirstEvent();
if (firstScheduledEvent && firstScheduledEvent->getScheduledTime() <= _playTime) {
@@ -4031,8 +4078,13 @@ void Runtime::drawFrame() {
{
Common::SharedPtr<Window> mainWindow = _mainWindow.lock();
- if (mainWindow)
- Render::renderProject(this, mainWindow.get());
+ if (mainWindow) {
+ if (_sceneTransitionState == kSceneTransitionStateTransitioning) {
+ assert(_activeSceneTransitionEffect != nullptr);
+ Render::renderSceneTransition(this, mainWindow.get(), *_activeSceneTransitionEffect, _sceneTransitionStartTime, _sceneTransitionEndTime, _playTime, *_sceneTransitionOldFrame, *_sceneTransitionNewFrame);
+ } else
+ Render::renderProject(this, mainWindow.get());
+ }
}
const size_t numWindows = _windows.size();
@@ -4254,8 +4306,7 @@ void Runtime::executeCompleteTransitionToScene(const Common::SharedPtr<Structura
// Scene transitions have to be set up by the destination scene
_sceneTransitionState = kSceneTransitionStateWaitingForDraw;
- _sceneTransitionEffect.transitionType = SceneTransitionTypes::kNone;
- _sceneTransitionEffect.duration = 0;
+ _activeSceneTransitionEffect = nullptr;
executeSharedScenePostSceneChangeActions();
}
@@ -5580,6 +5631,14 @@ void Runtime::addSceneStateTransition(const HighLevelSceneTransition &transition
_pendingSceneTransitions.push_back(transition);
}
+void Runtime::setSceneTransitionEffect(bool isInDestinationScene, SceneTransitionEffect *effect) {
+ SceneTransitionEffect *target = isInDestinationScene ? &_destinationSceneTransitionEffect : &_sourceSceneTransitionEffect;
+ if (!effect)
+ *target = SceneTransitionEffect();
+ else
+ *target = *effect;
+}
+
Project *Runtime::getProject() const {
return _project.get();
}
diff --git a/engines/mtropolis/runtime.h b/engines/mtropolis/runtime.h
index c736ce482ab..1c97601a944 100644
--- a/engines/mtropolis/runtime.h
+++ b/engines/mtropolis/runtime.h
@@ -147,7 +147,7 @@ enum SceneTransitionType {
kWipe, // Directional
};
-bool loadFromData(SceneTransitionType &transType, uint16 data);
+bool loadFromData(SceneTransitionType &transType, int32 data);
} // End of namespace SceneTransitionTypes
@@ -160,7 +160,7 @@ enum SceneTransitionDirection {
kRight,
};
-bool loadFromData(SceneTransitionDirection &transDir, uint16 data);
+bool loadFromData(SceneTransitionDirection &transDir, int32 data);
} // End of namespace SceneTransitionDirections
@@ -1287,10 +1287,12 @@ struct HighLevelSceneTransition {
};
struct SceneTransitionEffect {
- uint32 duration; // 6000000 is maximum
- uint16 steps;
- SceneTransitionTypes::SceneTransitionType transitionType;
- SceneTransitionDirections::SceneTransitionDirection transitionDirection;
+ SceneTransitionEffect();
+
+ uint32 _duration; // 6000000 is maximum
+ uint16 _steps;
+ SceneTransitionTypes::SceneTransitionType _transitionType;
+ SceneTransitionDirections::SceneTransitionDirection _transitionDirection;
};
class MessageDispatch {
@@ -1487,6 +1489,8 @@ public:
void addSceneStateTransition(const HighLevelSceneTransition &transition);
+ void setSceneTransitionEffect(bool isInDestinationScene, SceneTransitionEffect *effect);
+
Project *getProject() const;
void postConsumeMessageTask(IMessageConsumer *msgConsumer, const Common::SharedPtr<MessageProperties> &msg);
@@ -1593,7 +1597,6 @@ private:
enum SceneTransitionState {
kSceneTransitionStateNotTransitioning,
kSceneTransitionStateWaitingForDraw,
- kSceneTransitionStateDrawingTargetFrame,
kSceneTransitionStateTransitioning,
};
@@ -1705,7 +1708,12 @@ private:
Common::Array<SceneReturnListEntry> _sceneReturnList;
SceneTransitionState _sceneTransitionState;
- SceneTransitionEffect _sceneTransitionEffect;
+ SceneTransitionEffect _sourceSceneTransitionEffect;
+ SceneTransitionEffect _destinationSceneTransitionEffect;
+ SceneTransitionEffect *_activeSceneTransitionEffect;
+ Common::SharedPtr<Graphics::ManagedSurface> _sceneTransitionOldFrame;
+ Common::SharedPtr<Graphics::ManagedSurface> _sceneTransitionNewFrame;
+ uint32 _sceneTransitionStartTime;
uint32 _sceneTransitionEndTime;
Common::WeakPtr<Window> _mainWindow;
More information about the Scummvm-git-logs
mailing list