aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
authorColin Snover2016-08-20 21:02:07 -0500
committerColin Snover2016-09-29 19:39:16 -0500
commit44dd029cb17160316b2015321a0a53f8854b6dd3 (patch)
treeb6975dd6bf0f1bc7723345273abdecf034a667a5 /engines/sci
parent2be2629a3b2b43a0c86cfb7ea26cf979b91251bd (diff)
downloadscummvm-rg350-44dd029cb17160316b2015321a0a53f8854b6dd3.tar.gz
scummvm-rg350-44dd029cb17160316b2015321a0a53f8854b6dd3.tar.bz2
scummvm-rg350-44dd029cb17160316b2015321a0a53f8854b6dd3.zip
SCI32: Implement kSetHotRectangles
Used only by chapter 7 of Phant1.
Diffstat (limited to 'engines/sci')
-rw-r--r--engines/sci/engine/kernel.h1
-rw-r--r--engines/sci/engine/kernel_tables.h1
-rw-r--r--engines/sci/engine/kevent.cpp24
-rw-r--r--engines/sci/event.cpp64
-rw-r--r--engines/sci/event.h16
-rw-r--r--engines/sci/graphics/video32.cpp40
6 files changed, 116 insertions, 30 deletions
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index bd9d1bb770..6cacb5f839 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -483,6 +483,7 @@ reg_t kShowMovieWinGetDuration(EngineState *s, int argc, reg_t *argv);
reg_t kShowMovieWinPlayUntilEvent(EngineState *s, int argc, reg_t *argv);
reg_t kShowMovieWinInitDouble(EngineState *s, int argc, reg_t *argv);
+reg_t kSetHotRectangles(EngineState *s, int argc, reg_t *argv);
reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv);
reg_t kListAt(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 201afb66e2..b8d8450bc1 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -969,6 +969,7 @@ static SciKernelMapEntry s_kernelMap[] = {
// SetHotRectangles - used by Phantasmagoria 1, script 64981 (used in the chase scene)
// <lskovlun> The idea, if I understand correctly, is that the engine generates events
// of a special HotRect type continuously when the mouse is on that rectangle
+ { MAP_CALL(SetHotRectangles), SIG_SINCE_SCI21MID, SIGFOR_ALL, "i(r)", NULL, NULL },
// Used by SQ6 to scroll through the inventory via the up/down buttons
{ MAP_CALL(MovePlaneItems), SIG_SINCE_SCI21, SIGFOR_ALL, "oii(i)", NULL, NULL },
diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp
index 600dce3014..8dcafe0f38 100644
--- a/engines/sci/engine/kevent.cpp
+++ b/engines/sci/engine/kevent.cpp
@@ -369,6 +369,30 @@ reg_t kLocalToGlobal32(EngineState *s, int argc, reg_t *argv) {
return make_reg(0, visible);
}
+
+reg_t kSetHotRectangles(EngineState *s, int argc, reg_t *argv) {
+ if (argc == 1) {
+ g_sci->getEventManager()->setHotRectanglesActive((bool)argv[0].toUint16());
+ return s->r_acc;
+ }
+
+ const int16 numRects = argv[0].toSint16();
+ SciArray &hotRects = *s->_segMan->lookupArray(argv[1]);
+
+ Common::Array<Common::Rect> rects;
+ rects.resize(numRects);
+
+ for (int16 i = 0; i < numRects; ++i) {
+ rects[i].left = hotRects.int16At(i * 4);
+ rects[i].top = hotRects.int16At(i * 4 + 1);
+ rects[i].right = hotRects.int16At(i * 4 + 2) + 1;
+ rects[i].bottom = hotRects.int16At(i * 4 + 3) + 1;
+ }
+
+ g_sci->getEventManager()->setHotRectanglesActive(true);
+ g_sci->getEventManager()->setHotRectangles(rects);
+ return s->r_acc;
+}
#endif
} // End of namespace Sci
diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp
index 43db00c566..345b380a48 100644
--- a/engines/sci/event.cpp
+++ b/engines/sci/event.cpp
@@ -109,8 +109,12 @@ static const MouseEventConversion mouseEventMappings[] = {
{ Common::EVENT_MBUTTONUP, SCI_EVENT_MOUSE_RELEASE }
};
-EventManager::EventManager(bool fontIsExtended) : _fontIsExtended(fontIsExtended) {
-}
+EventManager::EventManager(bool fontIsExtended) :
+ _fontIsExtended(fontIsExtended)
+#ifdef ENABLE_SCI32
+ , _hotRectanglesActive(false)
+#endif
+ {}
EventManager::~EventManager() {
}
@@ -138,8 +142,8 @@ static int altify(int ch) {
SciEvent EventManager::getScummVMEvent() {
#ifdef ENABLE_SCI32
- SciEvent input = { SCI_EVENT_NONE, 0, 0, Common::Point(), Common::Point() };
- SciEvent noEvent = { SCI_EVENT_NONE, 0, 0, Common::Point(), Common::Point() };
+ SciEvent input = { SCI_EVENT_NONE, 0, 0, Common::Point(), Common::Point(), -1 };
+ SciEvent noEvent = { SCI_EVENT_NONE, 0, 0, Common::Point(), Common::Point(), -1 };
#else
SciEvent input = { SCI_EVENT_NONE, 0, 0, Common::Point() };
SciEvent noEvent = { SCI_EVENT_NONE, 0, 0, Common::Point() };
@@ -169,17 +173,20 @@ SciEvent EventManager::getScummVMEvent() {
if (getSciVersion() >= SCI_VERSION_2) {
const Buffer &screen = g_sci->_gfxFrameout->getCurrentBuffer();
+ Common::Point mousePosSci = mousePos;
+ mulru(mousePosSci, Ratio(screen.scriptWidth, screen.screenWidth), Ratio(screen.scriptHeight, screen.screenHeight));
+ noEvent.mousePosSci = input.mousePosSci = mousePosSci;
+
if (ev.type == Common::EVENT_MOUSEMOVE) {
// This will clamp `mousePos` according to the restricted zone,
// so any cursor or screen item associated with the mouse position
// does not bounce when it hits the edge (or ignore the edge)
g_sci->_gfxCursor32->deviceMoved(mousePos);
+ if (_hotRectanglesActive) {
+ checkHotRectangles(mousePosSci);
+ }
}
- Common::Point mousePosSci = mousePos;
- mulru(mousePosSci, Ratio(screen.scriptWidth, screen.screenWidth), Ratio(screen.scriptHeight, screen.screenHeight));
- noEvent.mousePosSci = input.mousePosSci = mousePosSci;
-
} else {
#endif
g_sci->_gfxScreen->adjustBackUpscaledCoordinates(mousePos.y, mousePos.x);
@@ -365,7 +372,7 @@ void EventManager::updateScreen() {
SciEvent EventManager::getSciEvent(uint32 mask) {
#ifdef ENABLE_SCI32
- SciEvent event = { SCI_EVENT_NONE, 0, 0, Common::Point(), Common::Point() };
+ SciEvent event = { SCI_EVENT_NONE, 0, 0, Common::Point(), Common::Point(), -1 };
#else
SciEvent event = { SCI_EVENT_NONE, 0, 0, Common::Point() };
#endif
@@ -402,4 +409,43 @@ SciEvent EventManager::getSciEvent(uint32 mask) {
return event;
}
+
+#ifdef ENABLE_SCI32
+void EventManager::setHotRectanglesActive(const bool active) {
+ _hotRectanglesActive = active;
+}
+
+void EventManager::setHotRectangles(const Common::Array<Common::Rect> &rects) {
+ _hotRects = rects;
+}
+
+void EventManager::checkHotRectangles(const Common::Point &mousePosition) {
+ int lastActiveRectIndex = _activeRectIndex;
+ _activeRectIndex = -1;
+
+ for (int16 i = 0; i < (int16)_hotRects.size(); ++i) {
+ if (_hotRects[i].contains(mousePosition)) {
+ _activeRectIndex = i;
+ if (i != lastActiveRectIndex) {
+ SciEvent hotRectEvent;
+ hotRectEvent.type = SCI_EVENT_HOT_RECTANGLE;
+ hotRectEvent.hotRectangleIndex = i;
+ _events.push_front(hotRectEvent);
+ break;
+ }
+
+ lastActiveRectIndex = _activeRectIndex;
+ }
+ }
+
+ if (lastActiveRectIndex != _activeRectIndex && lastActiveRectIndex != -1) {
+ _activeRectIndex = -1;
+ SciEvent hotRectEvent;
+ hotRectEvent.type = SCI_EVENT_HOT_RECTANGLE;
+ hotRectEvent.hotRectangleIndex = -1;
+ _events.push_front(hotRectEvent);
+ }
+}
+#endif
+
} // End of namespace Sci
diff --git a/engines/sci/event.h b/engines/sci/event.h
index 15a94b3e73..23b59f964a 100644
--- a/engines/sci/event.h
+++ b/engines/sci/event.h
@@ -50,6 +50,8 @@ struct SciEvent {
* in script coordinates.
*/
Common::Point mousePosSci;
+
+ int16 hotRectangleIndex;
#endif
};
@@ -60,6 +62,9 @@ struct SciEvent {
#define SCI_EVENT_KEYBOARD (1 << 2)
#define SCI_EVENT_DIRECTION (1 << 6)
#define SCI_EVENT_SAID (1 << 7)
+#ifdef ENABLE_SCI32
+#define SCI_EVENT_HOT_RECTANGLE (1 << 8)
+#endif
/*Fake values for other events*/
#define SCI_EVENT_QUIT (1 << 11)
#define SCI_EVENT_PEEK (1 << 15)
@@ -138,6 +143,17 @@ private:
const bool _fontIsExtended;
Common::List<SciEvent> _events;
+#ifdef ENABLE_SCI32
+public:
+ void setHotRectanglesActive(const bool active);
+ void setHotRectangles(const Common::Array<Common::Rect> &rects);
+ void checkHotRectangles(const Common::Point &mousePosition);
+
+private:
+ bool _hotRectanglesActive;
+ Common::Array<Common::Rect> _hotRects;
+ int16 _activeRectIndex;
+#endif
};
} // End of namespace Sci
diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index 506cde7b17..84c07d32f5 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -485,13 +485,6 @@ AVIPlayer::EventFlags AVIPlayer::playUntilEvent(EventFlags flags) {
break;
}
}
-
- // TODO: Hot rectangles
- if ((flags & kEventFlagHotRectangle) /* && event.type == SCI_EVENT_HOT_RECTANGLE */) {
- warning("Hot rectangles not implemented in VMD player");
- stopFlag = kEventFlagHotRectangle;
- break;
- }
}
return stopFlag;
@@ -655,11 +648,11 @@ VMDPlayer::EventFlags VMDPlayer::kernelPlayUntilEvent(const EventFlags flags, co
}
VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
- // Flushing all the keyboard and mouse events out of the event manager to
- // avoid letting any events queued from before the video started from
- // accidentally activating an event callback
+ // Flushing all the keyboard and mouse events out of the event manager
+ // keeps events queued from before the start of playback from accidentally
+ // activating a video stop flag
for (;;) {
- const SciEvent event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_MOUSE_PRESS | SCI_EVENT_MOUSE_RELEASE | SCI_EVENT_QUIT);
+ const SciEvent event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_MOUSE_PRESS | SCI_EVENT_MOUSE_RELEASE | SCI_EVENT_HOT_RECTANGLE | SCI_EVENT_QUIT);
if (event.type == SCI_EVENT_NONE) {
break;
} else if (event.type == SCI_EVENT_QUIT) {
@@ -667,8 +660,6 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
}
}
- _decoder->pauseVideo(false);
-
if (flags & kEventFlagReverse) {
// NOTE: This flag may not work properly since SSCI does not care
// if a video has audio, but the VMD decoder does.
@@ -748,6 +739,14 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
g_sci->_gfxFrameout->addScreenItem(*_screenItem);
+ // HACK: When VMD playback is allowed to yield back to the VM, this
+ // causes the VMD decoder to freak out for some reason and video output
+ // starts jittering horribly. This problem does not happen if audio sync
+ // is disabled, but this causes some audible clicking between frames
+ // of audio (and, presumably, will cause some AV sync problems). Still,
+ // that's better than really bad jitter.
+ _decoder->setAudioSync(!(flags & kEventFlagYieldToVM));
+
_decoder->start();
}
@@ -758,9 +757,11 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
break;
}
- g_sci->getEngineState()->speedThrottler(_decoder->getTimeToNextFrame());
- g_sci->getEngineState()->_throttleTrigger = true;
- if (_decoder->needsUpdate()) {
+ // Sleeping any more than 1/60th of a second will make the mouse feel
+ // very sluggish during VMD action sequences because the frame rate of
+ // VMDs is usually only 15fps
+ g_sci->sleep(MIN<uint32>(10, _decoder->getTimeToNextFrame()));
+ while (_decoder->needsUpdate()) {
renderFrame();
}
@@ -802,15 +803,13 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
}
}
- // TODO: Hot rectangles
- if ((flags & kEventFlagHotRectangle) /* && event.type == SCI_EVENT_HOT_RECTANGLE */) {
- warning("Hot rectangles not implemented in VMD player");
+ event = _eventMan->getSciEvent(SCI_EVENT_HOT_RECTANGLE | SCI_EVENT_PEEK);
+ if ((flags & kEventFlagHotRectangle) && event.type == SCI_EVENT_HOT_RECTANGLE) {
stopFlag = kEventFlagHotRectangle;
break;
}
}
- _decoder->pauseVideo(true);
return stopFlag;
}
@@ -859,7 +858,6 @@ void VMDPlayer::renderFrame() const {
g_sci->_gfxFrameout->updateScreenItem(*_screenItem);
g_sci->getSciDebugger()->onFrame();
g_sci->_gfxFrameout->frameOut(true);
- g_sci->_gfxFrameout->throttle();
}
}