aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/sci/engine/kernel.h2
-rw-r--r--engines/sci/engine/kernel_tables.h7
-rw-r--r--engines/sci/engine/kevent.cpp9
-rw-r--r--engines/sci/engine/kgraphics32.cpp40
-rw-r--r--engines/sci/engine/savegame.cpp24
-rw-r--r--engines/sci/engine/savegame.h2
-rw-r--r--engines/sci/engine/workarounds.cpp1
-rw-r--r--engines/sci/event.cpp9
-rw-r--r--engines/sci/graphics/cursor32.cpp367
-rw-r--r--engines/sci/graphics/cursor32.h248
-rw-r--r--engines/sci/graphics/frameout.cpp18
-rw-r--r--engines/sci/graphics/frameout.h18
-rw-r--r--engines/sci/graphics/video32.cpp6
-rw-r--r--engines/sci/module.mk1
-rw-r--r--engines/sci/sci.cpp12
-rw-r--r--engines/sci/sci.h2
16 files changed, 736 insertions, 30 deletions
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index b02a7e545a..77927ba7d5 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -421,6 +421,8 @@ reg_t kStubNull(EngineState *s, int argc, reg_t *argv);
#ifdef ENABLE_SCI32
// SCI2 Kernel Functions
+reg_t kSetCursor32(EngineState *s, int argc, reg_t *argv);
+
reg_t kDoAudio32(EngineState *s, int argc, reg_t *argv);
reg_t kDoAudioInit(EngineState *s, int argc, reg_t *argv);
reg_t kDoAudioWaitForPlay(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 76c24b09e3..097eb8b405 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -693,10 +693,11 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(Said), SIG_EVERYWHERE, "[r0]", NULL, NULL },
{ MAP_CALL(SaveGame), SIG_EVERYWHERE, "[r0]i[r0](r0)", NULL, NULL },
{ MAP_CALL(ScriptID), SIG_EVERYWHERE, "[io](i)", NULL, NULL },
- { MAP_CALL(SetCursor), SIG_SINCE_SCI21, SIGFOR_ALL, "i(i)([io])(i*)", NULL, NULL },
- // TODO: SCI2.1 may supply an object optionally (mother goose sci21 right on startup) - find out why
{ MAP_CALL(SetCursor), SIG_SCI11, SIGFOR_ALL, "i(i)(i)(i)(iiiiii)", NULL, NULL },
- { MAP_CALL(SetCursor), SIG_EVERYWHERE, "i(i)(i)(i)(i)", NULL, kSetCursor_workarounds },
+ { MAP_CALL(SetCursor), SIG_SCI16, SIGFOR_ALL, "i(i)(i)(i)(i)", NULL, kSetCursor_workarounds },
+#ifdef ENABLE_SCI32
+ { "SetCursor", kSetCursor32, SIG_SCI32, SIGFOR_ALL, "i(i)(i)(i)", NULL, kSetCursor_workarounds },
+#endif
{ MAP_CALL(SetDebug), SIG_EVERYWHERE, "(i*)", NULL, NULL },
{ MAP_CALL(SetJump), SIG_EVERYWHERE, "oiii", NULL, NULL },
{ MAP_CALL(SetMenu), SIG_EVERYWHERE, "i(.*)", NULL, NULL },
diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp
index d7a716a504..56ee2f594c 100644
--- a/engines/sci/engine/kevent.cpp
+++ b/engines/sci/engine/kevent.cpp
@@ -86,11 +86,14 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
#ifdef ENABLE_SCI32
if (getSciVersion() >= SCI_VERSION_2)
mousePos = curEvent.mousePosSci;
- else
+ else {
#endif
mousePos = curEvent.mousePos;
- // Limit the mouse cursor position, if necessary
- g_sci->_gfxCursor->refreshPosition();
+ // Limit the mouse cursor position, if necessary
+ g_sci->_gfxCursor->refreshPosition();
+#ifdef ENABLE_SCI32
+ }
+#endif
if (g_sci->getVocabulary())
g_sci->getVocabulary()->parser_event = NULL_REG; // Invalidate parser event
diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp
index e458109cc2..2286a66de1 100644
--- a/engines/sci/engine/kgraphics32.cpp
+++ b/engines/sci/engine/kgraphics32.cpp
@@ -38,7 +38,6 @@
#include "sci/graphics/compare.h"
#include "sci/graphics/controls16.h"
#include "sci/graphics/coordadjuster.h"
-#include "sci/graphics/cursor.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/paint16.h"
#include "sci/graphics/picture.h"
@@ -48,6 +47,7 @@
#include "sci/graphics/text16.h"
#include "sci/graphics/view.h"
#ifdef ENABLE_SCI32
+#include "sci/graphics/cursor32.h"
#include "sci/graphics/celobj32.h"
#include "sci/graphics/controls32.h"
#include "sci/graphics/font.h" // TODO: remove once kBitmap is moved in a separate class
@@ -64,6 +64,44 @@ namespace Sci {
extern void showScummVMDialog(const Common::String &message);
+reg_t kSetCursor32(EngineState *s, int argc, reg_t *argv) {
+ switch (argc) {
+ case 1: {
+ if (argv[0].toSint16() == -2) {
+ g_sci->_gfxCursor32->clearRestrictedArea();
+ } else {
+ if (argv[0].isNull()) {
+ g_sci->_gfxCursor32->hide();
+ } else {
+ g_sci->_gfxCursor32->show();
+ }
+ }
+ break;
+ }
+ case 2: {
+ const Common::Point position(argv[0].toSint16(), argv[1].toSint16());
+ g_sci->_gfxCursor32->setPosition(position);
+ break;
+ }
+ case 3: {
+ g_sci->_gfxCursor32->setView(argv[0].toUint16(), argv[1].toSint16(), argv[2].toSint16());
+ break;
+ }
+ case 4: {
+ const Common::Rect restrictRect(argv[0].toSint16(),
+ argv[1].toSint16(),
+ argv[2].toSint16() + 1,
+ argv[3].toSint16() + 1);
+ g_sci->_gfxCursor32->setRestrictedArea(restrictRect);
+ break;
+ }
+ default:
+ error("kSetCursor: Invalid number of arguments (%d)", argc);
+ }
+
+ return s->r_acc;
+}
+
reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv) {
const Buffer &buffer = g_sci->_gfxFrameout->getCurrentBuffer();
if (buffer.screenWidth < 640 || buffer.screenHeight < 400)
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index 7804b7892d..eeddda8390 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -48,6 +48,7 @@
#include "sci/sound/music.h"
#ifdef ENABLE_SCI32
+#include "sci/graphics/cursor32.h"
#include "sci/graphics/frameout.h"
#include "sci/graphics/palette32.h"
#include "sci/graphics/remap32.h"
@@ -889,6 +890,29 @@ void GfxRemap32::saveLoadWithSerializer(Common::Serializer &s) {
_needsUpdate = true;
}
}
+
+void GfxCursor32::saveLoadWithSerializer(Common::Serializer &s) {
+ if (s.getVersion() < 37) {
+ return;
+ }
+
+ s.syncAsSint32LE(_hideCount);
+ s.syncAsSint16LE(_restrictedArea.left);
+ s.syncAsSint16LE(_restrictedArea.top);
+ s.syncAsSint16LE(_restrictedArea.right);
+ s.syncAsSint16LE(_restrictedArea.bottom);
+ s.syncAsUint16LE(_cursorInfo.resourceId);
+ s.syncAsUint16LE(_cursorInfo.loopNo);
+ s.syncAsUint16LE(_cursorInfo.celNo);
+
+ if (s.isLoading()) {
+ hide();
+ setView(_cursorInfo.resourceId, _cursorInfo.loopNo, _cursorInfo.celNo);
+ if (!_hideCount) {
+ show();
+ }
+ }
+}
#endif
void GfxPorts::saveLoadWithSerializer(Common::Serializer &s) {
diff --git a/engines/sci/engine/savegame.h b/engines/sci/engine/savegame.h
index 1bf66864e8..51dbbedd87 100644
--- a/engines/sci/engine/savegame.h
+++ b/engines/sci/engine/savegame.h
@@ -37,7 +37,7 @@ struct EngineState;
*
* Version - new/changed feature
* =============================
- * 37 - Segment entry data changed to pointers
+ * 37 - Segment entry data changed to pointers, SCI32 cursor
* 36 - SCI32 bitmap segment
* 35 - SCI32 remap
* 34 - SCI32 palettes, and store play time in ticks
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index 9b3b329418..15f229f2d8 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -688,6 +688,7 @@ const SciWorkaroundEntry kPaletteUnsetFlag_workarounds[] = {
// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
const SciWorkaroundEntry kSetCursor_workarounds[] = {
{ GID_KQ5, -1, 768, 0, "KQCursor", "init", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // CD: gets called with 4 additional "900d" parameters
+ { GID_MOTHERGOOSEHIRES,0, 0, -1, "MG", "setCursor", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // At the start of the game, an object is passed as the cel number
SCI_WORKAROUNDENTRY_TERMINATOR
};
diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp
index 4ad2a0cfa3..b267d2ebc2 100644
--- a/engines/sci/event.cpp
+++ b/engines/sci/event.cpp
@@ -30,6 +30,7 @@
#include "sci/engine/state.h"
#include "sci/engine/kernel.h"
#ifdef ENABLE_SCI32
+#include "sci/graphics/cursor32.h"
#include "sci/graphics/frameout.h"
#endif
#include "sci/graphics/screen.h"
@@ -168,9 +169,17 @@ SciEvent EventManager::getScummVMEvent() {
if (getSciVersion() >= SCI_VERSION_2) {
const Buffer &screen = g_sci->_gfxFrameout->getCurrentBuffer();
+ 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);
+ }
+
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);
diff --git a/engines/sci/graphics/cursor32.cpp b/engines/sci/graphics/cursor32.cpp
new file mode 100644
index 0000000000..a5491eec2a
--- /dev/null
+++ b/engines/sci/graphics/cursor32.cpp
@@ -0,0 +1,367 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/system.h"
+#include "graphics/cursorman.h"
+#include "sci/graphics/celobj32.h"
+#include "sci/graphics/cursor32.h"
+#include "sci/graphics/frameout.h"
+
+namespace Sci {
+
+GfxCursor32::GfxCursor32() :
+ _hideCount(0),
+ _position(0, 0),
+ _writeToVMAP(false) {
+ CursorMan.showMouse(false);
+}
+
+void GfxCursor32::init(const Buffer &vmap) {
+ _vmap = vmap;
+ _vmapRegion.rect = Common::Rect(_vmap.screenWidth, _vmap.screenHeight);
+ _vmapRegion.data = (byte *)_vmap.getPixels();
+ _restrictedArea = _vmapRegion.rect;
+}
+
+GfxCursor32::~GfxCursor32() {
+ CursorMan.showMouse(true);
+ free(_cursor.data);
+ free(_cursorBack.data);
+ free(_drawBuff1.data);
+ free(_drawBuff2.data);
+ free(_savedVmapRegion.data);
+}
+
+void GfxCursor32::hide() {
+ if (_hideCount++) {
+ return;
+ }
+
+ if (!_cursorBack.rect.isEmpty()) {
+ drawToHardware(_cursorBack);
+ }
+}
+
+void GfxCursor32::revealCursor() {
+ _cursorBack.rect = _cursor.rect;
+ _cursorBack.rect.clip(_vmapRegion.rect);
+ if (_cursorBack.rect.isEmpty()) {
+ return;
+ }
+
+ readVideo(_cursorBack);
+ _drawBuff1.rect = _cursor.rect;
+ copy(_drawBuff1, _cursorBack);
+ paint(_drawBuff1, _cursor);
+ drawToHardware(_drawBuff1);
+}
+
+void GfxCursor32::paint(DrawRegion &target, const DrawRegion &source) {
+ if (source.rect.isEmpty()) {
+ return;
+ }
+
+ Common::Rect drawRect(source.rect);
+ drawRect.clip(target.rect);
+ if (drawRect.isEmpty()) {
+ return;
+ }
+
+ const int16 sourceXOffset = drawRect.left - source.rect.left;
+ const int16 sourceYOffset = drawRect.top - source.rect.top;
+ const int16 drawRectWidth = drawRect.width();
+ const int16 drawRectHeight = drawRect.height();
+
+ byte *targetPixel = target.data + ((drawRect.top - target.rect.top) * target.rect.width()) + (drawRect.left - target.rect.left);
+ const byte *sourcePixel = source.data + (sourceYOffset * source.rect.width()) + sourceXOffset;
+ const uint8 skipColor = source.skipColor;
+
+ const int16 sourceStride = source.rect.width() - drawRectWidth;
+ const int16 targetStride = target.rect.width() - drawRectWidth;
+
+ for (int16 y = 0; y < drawRectHeight; ++y) {
+ for (int16 x = 0; x < drawRectWidth; ++x) {
+ if (*sourcePixel != skipColor) {
+ *targetPixel = *sourcePixel;
+ }
+ ++targetPixel;
+ ++sourcePixel;
+ }
+ sourcePixel += sourceStride;
+ targetPixel += targetStride;
+ }
+}
+
+void GfxCursor32::drawToHardware(const DrawRegion &source) {
+ Common::Rect drawRect(source.rect);
+ drawRect.clip(_vmapRegion.rect);
+ const int16 sourceXOffset = drawRect.left - source.rect.left;
+ const int16 sourceYOffset = drawRect.top - source.rect.top;
+ byte *sourcePixel = source.data + (sourceYOffset * source.rect.width()) + sourceXOffset;
+
+ g_system->copyRectToScreen(sourcePixel, source.rect.width(), drawRect.left, drawRect.top, drawRect.width(), drawRect.height());
+}
+
+void GfxCursor32::unhide() {
+ if (_hideCount == 0 || --_hideCount) {
+ return;
+ }
+
+ _cursor.rect.moveTo(_position.x - _hotSpot.x, _position.y - _hotSpot.y);
+ revealCursor();
+}
+
+void GfxCursor32::show() {
+ if (_hideCount) {
+ _hideCount = 0;
+ _cursor.rect.moveTo(_position.x - _hotSpot.x, _position.y - _hotSpot.y);
+ revealCursor();
+ }
+}
+
+void GfxCursor32::setRestrictedArea(const Common::Rect &rect) {
+ _restrictedArea = rect;
+
+ const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
+ const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
+ const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+
+ mulru(_restrictedArea, Ratio(screenWidth, scriptWidth), Ratio(screenHeight, scriptHeight), 0);
+
+ if (_position.x < rect.left) {
+ _position.x = rect.left;
+ }
+ if (_position.x >= rect.right) {
+ _position.x = rect.right - 1;
+ }
+ if (_position.y < rect.top) {
+ _position.y = rect.top;
+ }
+ if (_position.y >= rect.bottom) {
+ _position.y = rect.bottom - 1;
+ }
+
+ g_system->warpMouse(_position.x, _position.y);
+}
+
+void GfxCursor32::clearRestrictedArea() {
+ _restrictedArea = _vmapRegion.rect;
+}
+
+void GfxCursor32::setView(const GuiResourceId viewId, const int16 loopNo, const int16 celNo) {
+ hide();
+
+ _cursorInfo.resourceId = viewId;
+ _cursorInfo.loopNo = loopNo;
+ _cursorInfo.celNo = celNo;
+
+ if (viewId != -1) {
+ CelObjView view(viewId, loopNo, celNo);
+
+ _hotSpot = view._displace;
+ _width = view._width;
+ _height = view._height;
+
+ _cursor.data = (byte *)realloc(_cursor.data, _width * _height);
+ _cursor.rect = Common::Rect(_width, _height);
+ memset(_cursor.data, 255, _width * _height);
+ _cursor.skipColor = 255;
+
+ Buffer target(_width, _height, _cursor.data);
+ view.draw(target, _cursor.rect, Common::Point(0, 0), false);
+ } else {
+ _hotSpot = Common::Point(0, 0);
+ _width = _height = 1;
+ _cursor.data = (byte *)realloc(_cursor.data, _width * _height);
+ _cursor.rect = Common::Rect(_width, _height);
+ *_cursor.data = _cursor.skipColor;
+ _cursorBack.rect = _cursor.rect;
+ _cursorBack.rect.clip(_vmapRegion.rect);
+ if (!_cursorBack.rect.isEmpty()) {
+ readVideo(_cursorBack);
+ }
+ }
+
+ _cursorBack.data = (byte *)realloc(_cursorBack.data, _width * _height);
+ _drawBuff1.data = (byte *)realloc(_drawBuff1.data, _width * _height);
+ _drawBuff2.data = (byte *)realloc(_drawBuff2.data, _width * _height * 4);
+ _savedVmapRegion.data = (byte *)realloc(_savedVmapRegion.data, _width * _height);
+
+ unhide();
+}
+
+void GfxCursor32::readVideo(DrawRegion &target) {
+ if (g_sci->_gfxFrameout->_frameNowVisible) {
+ copy(target, _vmapRegion);
+ } else {
+ // NOTE: SSCI would read the background for the cursor directly out of
+ // video memory here, but as far as can be determined, this does not
+ // seem to actually be necessary for proper cursor rendering
+ }
+}
+
+void GfxCursor32::copy(DrawRegion &target, const DrawRegion &source) {
+ if (source.rect.isEmpty()) {
+ return;
+ }
+
+ Common::Rect drawRect(source.rect);
+ drawRect.clip(target.rect);
+ if (drawRect.isEmpty()) {
+ return;
+ }
+
+ const int16 sourceXOffset = drawRect.left - source.rect.left;
+ const int16 sourceYOffset = drawRect.top - source.rect.top;
+ const int16 drawWidth = drawRect.width();
+ const int16 drawHeight = drawRect.height();
+
+ byte *targetPixel = target.data + ((drawRect.top - target.rect.top) * target.rect.width()) + (drawRect.left - target.rect.left);
+ const byte *sourcePixel = source.data + (sourceYOffset * source.rect.width()) + sourceXOffset;
+
+ const int16 sourceStride = source.rect.width();
+ const int16 targetStride = target.rect.width();
+
+ for (int y = 0; y < drawHeight; ++y) {
+ memcpy(targetPixel, sourcePixel, drawWidth);
+ targetPixel += targetStride;
+ sourcePixel += sourceStride;
+ }
+}
+
+void GfxCursor32::setPosition(const Common::Point &position) {
+ const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+ const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
+ const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
+
+ _position.x = (position.x * Ratio(screenWidth, scriptWidth)).toInt();
+ _position.y = (position.y * Ratio(screenHeight, scriptHeight)).toInt();
+
+ g_system->warpMouse(_position.x, _position.y);
+}
+
+void GfxCursor32::gonnaPaint(Common::Rect paintRect) {
+ if (!_hideCount && !_writeToVMAP && !_cursorBack.rect.isEmpty()) {
+ paintRect.left &= ~3;
+ paintRect.right |= 3;
+ if (_cursorBack.rect.intersects(paintRect)) {
+ _writeToVMAP = true;
+ }
+ }
+}
+
+void GfxCursor32::paintStarting() {
+ if (_writeToVMAP) {
+ _savedVmapRegion.rect = _cursor.rect;
+ copy(_savedVmapRegion, _vmapRegion);
+ paint(_vmapRegion, _cursor);
+ }
+}
+
+void GfxCursor32::donePainting() {
+ if (_writeToVMAP) {
+ copy(_vmapRegion, _savedVmapRegion);
+ _savedVmapRegion.rect = Common::Rect();
+ _writeToVMAP = false;
+ }
+
+ if (!_hideCount && !_cursorBack.rect.isEmpty()) {
+ copy(_cursorBack, _vmapRegion);
+ }
+}
+
+void GfxCursor32::deviceMoved(Common::Point &position) {
+ if (position.x < _restrictedArea.left) {
+ position.x = _restrictedArea.left;
+ }
+ if (position.x >= _restrictedArea.right) {
+ position.x = _restrictedArea.right - 1;
+ }
+ if (position.y < _restrictedArea.top) {
+ position.y = _restrictedArea.top;
+ }
+ if (position.y >= _restrictedArea.bottom) {
+ position.y = _restrictedArea.bottom - 1;
+ }
+
+ _position = position;
+
+ g_system->warpMouse(position.x, position.y);
+ move();
+}
+
+void GfxCursor32::move() {
+ if (_hideCount) {
+ return;
+ }
+
+ // If it was off the screen, just show it and return
+ _cursor.rect.moveTo(_position.x - _hotSpot.x, _position.y - _hotSpot.y);
+ if (_cursorBack.rect.isEmpty()) {
+ revealCursor();
+ return;
+ }
+
+ // If we just moved entirely off screen, remove background & return
+ if (!_cursor.rect.intersects(_vmapRegion.rect)) {
+ drawToHardware(_cursorBack);
+ return;
+ }
+
+ if (!_cursor.rect.intersects(_cursorBack.rect)) {
+ _drawBuff1.rect = _cursor.rect;
+ _drawBuff1.rect.clip(_vmapRegion.rect);
+ readVideo(_drawBuff1);
+
+ _drawBuff2.rect = _drawBuff1.rect;
+ copy(_drawBuff2, _drawBuff1);
+
+ paint(_drawBuff1, _cursor);
+ drawToHardware(_drawBuff1);
+
+ // erase
+ drawToHardware(_cursorBack);
+
+ _cursorBack.rect = _cursor.rect;
+ _cursorBack.rect.clip(_vmapRegion.rect);
+ copy(_cursorBack, _drawBuff2);
+ } else {
+ Common::Rect mergedRect(_cursorBack.rect);
+ mergedRect.extend(_cursor.rect);
+ mergedRect.clip(_vmapRegion.rect);
+
+ _drawBuff2.rect = mergedRect;
+ readVideo(_drawBuff2);
+
+ copy(_drawBuff2, _cursorBack);
+
+ _cursorBack.rect = _cursor.rect;
+ _cursorBack.rect.clip(_vmapRegion.rect);
+ copy(_cursorBack, _drawBuff2);
+
+ paint(_drawBuff2, _cursor);
+ drawToHardware(_drawBuff2);
+ }
+}
+} // End of namespace Sci
diff --git a/engines/sci/graphics/cursor32.h b/engines/sci/graphics/cursor32.h
new file mode 100644
index 0000000000..fe621e9d55
--- /dev/null
+++ b/engines/sci/graphics/cursor32.h
@@ -0,0 +1,248 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SCI_GRAPHICS_CURSOR32_H
+#define SCI_GRAPHICS_CURSOR32_H
+
+#include "common/rect.h"
+#include "common/serializer.h"
+#include "sci/graphics/helpers.h"
+
+namespace Sci {
+
+class GfxCursor32 : Common::Serializable {
+public:
+ GfxCursor32();
+ ~GfxCursor32();
+
+ /**
+ * Initialises the cursor system with the given
+ * buffer to use as the output buffer for
+ * rendering the cursor.
+ */
+ void init(const Buffer &vmap);
+
+ /**
+ * Called when the hardware mouse moves.
+ */
+ void deviceMoved(Common::Point &position);
+
+ /**
+ * Called by GfxFrameout once for each show
+ * rectangle that is going to be drawn to
+ * hardware.
+ */
+ void gonnaPaint(Common::Rect paintRect);
+
+ /**
+ * Called by GfxFrameout when the rendering to
+ * hardware begins.
+ */
+ void paintStarting();
+
+ /**
+ * Called by GfxFrameout when the output buffer
+ * has finished rendering to hardware.
+ */
+ void donePainting();
+
+ /**
+ * Hides the cursor. Each call to `hide` will
+ * increment a hide counter, which must be
+ * returned to 0 before the cursor will be
+ * shown again.
+ */
+ void hide();
+
+ /**
+ * Shows the cursor, if the hide counter is
+ * returned to 0.
+ */
+ void unhide();
+
+ /**
+ * Shows the cursor regardless of the state of
+ * the hide counter.
+ */
+ void show();
+
+ /**
+ * Sets the view used to render the cursor.
+ */
+ void setView(const GuiResourceId viewId, const int16 loopNo, const int16 celNo);
+
+ /**
+ * Explicitly sets the position of the cursor,
+ * in game script coordinates.
+ */
+ void setPosition(const Common::Point &position);
+
+ /**
+ * Sets the region that the mouse is allowed
+ * to move within.
+ */
+ void setRestrictedArea(const Common::Rect &rect);
+
+ /**
+ * Removes restrictions on mouse movement.
+ */
+ void clearRestrictedArea();
+
+ virtual void saveLoadWithSerializer(Common::Serializer &ser);
+
+private:
+ struct DrawRegion {
+ Common::Rect rect;
+ byte *data;
+ uint8 skipColor;
+
+ DrawRegion() : rect(), data(nullptr) {}
+ };
+
+ /**
+ * Information about the current cursor.
+ * Used to restore cursor when loading a
+ * savegame.
+ */
+ CelInfo32 _cursorInfo;
+
+ /**
+ * Content behind the cursor? TODO
+ */
+ DrawRegion _cursorBack;
+
+ /**
+ * Scratch buffer.
+ */
+ DrawRegion _drawBuff1;
+
+ /**
+ * Scratch buffer 2.
+ */
+ DrawRegion _drawBuff2;
+
+ /**
+ * A draw region representing the current
+ * output buffer.
+ */
+ DrawRegion _vmapRegion;
+
+ /**
+ * The content behind the cursor in the
+ * output buffer.
+ */
+ DrawRegion _savedVmapRegion;
+
+ /**
+ * The cursor bitmap.
+ */
+ DrawRegion _cursor;
+
+ /**
+ * The width and height of the cursor,
+ * in screen coordinates.
+ */
+ int16 _width, _height;
+
+ /**
+ * The output buffer where the cursor is
+ * rendered.
+ */
+ Buffer _vmap;
+
+ /**
+ * The number of times the cursor has been
+ * hidden.
+ */
+ int _hideCount;
+
+ /**
+ * The rendered position of the cursor, in
+ * screen coordinates.
+ */
+ Common::Point _position;
+
+ /**
+ * The position of the cursor hot spot, relative
+ * to the cursor origin, in screen pixels.
+ */
+ Common::Point _hotSpot;
+
+ /**
+ * The area within which the cursor is allowed
+ * to move, in screen pixels.
+ */
+ Common::Rect _restrictedArea;
+
+ /**
+ * Indicates whether or not the cursor needs to
+ * be repainted on the output buffer due to a
+ * change of graphics in the area underneath the
+ * cursor.
+ */
+ bool _writeToVMAP;
+
+ /**
+ * Reads data from the output buffer or hardware
+ * to the given draw region.
+ */
+ void readVideo(DrawRegion &target);
+
+ /**
+ * Reads data from the output buffer to the
+ * given draw region.
+ */
+ void readVideoFromVmap(DrawRegion &target);
+
+ /**
+ * Copies pixel data from the given source to
+ * the given target.
+ */
+ void copy(DrawRegion &target, const DrawRegion &source);
+
+ /**
+ * Draws from the given source onto the given
+ * target, skipping pixels in the source that
+ * match the `skipColor` property.
+ */
+ void paint(DrawRegion &target, const DrawRegion &source);
+
+ /**
+ * Draws the cursor to the position it was
+ * drawn to prior to moving offscreen or being
+ * hidden by a call to `hide`.
+ */
+ void revealCursor();
+
+ /**
+ * Draws the given source to the output buffer.
+ */
+ void drawToHardware(const DrawRegion &source);
+
+ /**
+ * Renders the cursor at its new location.
+ */
+ void move();
+};
+
+} // End of namespace Sci
+#endif
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index 7661fe5be2..aad321521e 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -42,6 +42,7 @@
#include "sci/graphics/cache.h"
#include "sci/graphics/coordadjuster.h"
#include "sci/graphics/compare.h"
+#include "sci/graphics/cursor32.h"
#include "sci/graphics/font.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/paint32.h"
@@ -56,9 +57,10 @@
namespace Sci {
-GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxPalette32 *palette, GfxTransitions32 *transitions) :
+GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxPalette32 *palette, GfxTransitions32 *transitions, GfxCursor32 *cursor) :
_isHiRes(ConfMan.getBool("enable_high_resolution_graphics")),
_palette(palette),
+ _cursor(cursor),
_resMan(resMan),
_segMan(segMan),
_transitions(transitions),
@@ -1120,6 +1122,10 @@ void GfxFrameout::mergeToShowList(const Common::Rect &drawRect, RectList &showLi
}
void GfxFrameout::showBits() {
+ if (!_showList.size()) {
+ return;
+ }
+
for (RectList::const_iterator rect = _showList.begin(); rect != _showList.end(); ++rect) {
Common::Rect rounded(**rect);
// NOTE: SCI engine used BR-inclusive rects so used slightly
@@ -1127,13 +1133,10 @@ void GfxFrameout::showBits() {
// was always even.
rounded.left &= ~1;
rounded.right = (rounded.right + 1) & ~1;
-
- // TODO:
- // _cursor->GonnaPaint(rounded);
+ _cursor->gonnaPaint(rounded);
}
- // TODO:
- // _cursor->PaintStarting();
+ _cursor->paintStarting();
for (RectList::const_iterator rect = _showList.begin(); rect != _showList.end(); ++rect) {
Common::Rect rounded(**rect);
@@ -1155,8 +1158,7 @@ void GfxFrameout::showBits() {
g_system->copyRectToScreen(sourceBuffer, _currentBuffer.screenWidth, rounded.left, rounded.top, rounded.width(), rounded.height());
}
- // TODO:
- // _cursor->DonePainting();
+ _cursor->donePainting();
_showList.clear();
}
diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h
index 8107316371..6cd0416a7a 100644
--- a/engines/sci/graphics/frameout.h
+++ b/engines/sci/graphics/frameout.h
@@ -30,6 +30,7 @@ namespace Sci {
typedef Common::Array<DrawList> ScreenItemListList;
typedef Common::Array<RectList> EraseListList;
+class GfxCursor32;
class GfxCoordAdjuster32;
class GfxTransitions32;
struct PlaneShowStyle;
@@ -40,13 +41,14 @@ struct PlaneShowStyle;
*/
class GfxFrameout {
private:
+ GfxCursor32 *_cursor;
GfxCoordAdjuster32 *_coordAdjuster;
GfxPalette32 *_palette;
ResourceManager *_resMan;
SegManager *_segMan;
public:
- GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxPalette32 *palette, GfxTransitions32 *transitions);
+ GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxPalette32 *palette, GfxTransitions32 *transitions, GfxCursor32 *cursor);
~GfxFrameout();
bool _isHiRes;
@@ -196,13 +198,6 @@ private:
bool _remapOccurred;
/**
- * Whether or not the data in the current buffer is what
- * is visible to the user. During rendering updates,
- * this flag is set to false.
- */
- bool _frameNowVisible;
-
- /**
* TODO: Document
* TODO: Depending upon if the engine ever modifies this
* rect, it may be stupid to store it separately instead
@@ -309,6 +304,13 @@ private:
public:
/**
+ * Whether or not the data in the current buffer is what
+ * is visible to the user. During rendering updates,
+ * this flag is set to false.
+ */
+ bool _frameNowVisible;
+
+ /**
* Whether palMorphFrameOut should be used instead of
* frameOut for rendering. Used by kMorphOn to
* explicitly enable palMorphFrameOut for one frame.
diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index 51be08dac9..f4aa7664d3 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -31,7 +31,7 @@
#include "sci/engine/vm_types.h" // for reg_t
#include "sci/event.h" // for SciEvent, EventManager, SCI_...
#include "sci/graphics/celobj32.h" // for CelInfo32, ::kLowResX, ::kLo...
-#include "sci/graphics/cursor.h" // for GfxCursor
+#include "sci/graphics/cursor32.h" // for GfxCursor32
#include "sci/graphics/frameout.h" // for GfxFrameout
#include "sci/graphics/helpers.h" // for Color, Palette
#include "sci/graphics/palette32.h" // for GfxPalette32
@@ -597,7 +597,7 @@ VMDPlayer::IOStatus VMDPlayer::close() {
}
if (!_showCursor) {
- g_sci->_gfxCursor->kernelShow();
+ g_sci->_gfxCursor32->unhide();
}
_lastYieldedFrameNo = 0;
@@ -658,7 +658,7 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
_isInitialized = true;
if (!_showCursor) {
- g_sci->_gfxCursor->kernelHide();
+ g_sci->_gfxCursor32->hide();
}
Common::Rect vmdRect(_x,
diff --git a/engines/sci/module.mk b/engines/sci/module.mk
index 18d97ea57e..eb2c6a148b 100644
--- a/engines/sci/module.mk
+++ b/engines/sci/module.mk
@@ -93,6 +93,7 @@ MODULE_OBJS += \
graphics/text32.o \
graphics/transitions32.o \
graphics/video32.o \
+ graphics/cursor32.o \
sound/audio32.o \
sound/decoders/sol.o \
video/robot_decoder.o
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index 61317ecb97..842384ed1a 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -65,6 +65,7 @@
#ifdef ENABLE_SCI32
#include "sci/graphics/controls32.h"
+#include "sci/graphics/cursor32.h"
#include "sci/graphics/frameout.h"
#include "sci/graphics/palette32.h"
#include "sci/graphics/remap32.h"
@@ -96,6 +97,7 @@ SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc, SciGameId gam
#ifdef ENABLE_SCI32
_audio32 = nullptr;
_video32 = nullptr;
+ _gfxCursor32 = nullptr;
#endif
_features = 0;
_resMan = 0;
@@ -176,6 +178,7 @@ SciEngine::~SciEngine() {
// destruction of screen items in the Video32 destructor relies on these
// components
delete _video32;
+ delete _gfxCursor32;
delete _gfxPalette32;
delete _gfxTransitions32;
delete _gfxFrameout;
@@ -708,6 +711,7 @@ void SciEngine::initGraphics() {
_gfxPalette32 = 0;
_gfxRemap32 = 0;
_gfxTransitions32 = 0;
+ _gfxCursor32 = 0;
#endif
if (hasMacIconBar())
@@ -727,23 +731,25 @@ void SciEngine::initGraphics() {
#endif
_gfxCache = new GfxCache(_resMan, _gfxScreen, _gfxPalette16);
- _gfxCursor = new GfxCursor(_resMan, _gfxPalette16, _gfxScreen);
#ifdef ENABLE_SCI32
if (getSciVersion() >= SCI_VERSION_2) {
// SCI32 graphic objects creation
_gfxCoordAdjuster = new GfxCoordAdjuster32(_gamestate->_segMan);
- _gfxCursor->init(_gfxCoordAdjuster, _eventMan);
+ _gfxCursor32 = new GfxCursor32();
_gfxCompare = new GfxCompare(_gamestate->_segMan, _gfxCache, _gfxScreen, _gfxCoordAdjuster);
_gfxPaint32 = new GfxPaint32(_gamestate->_segMan);
_robotDecoder = new RobotDecoder(getPlatform() == Common::kPlatformMacintosh);
_gfxTransitions32 = new GfxTransitions32(_gamestate->_segMan);
- _gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxPalette32, _gfxTransitions32);
+ _gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxPalette32, _gfxTransitions32, _gfxCursor32);
+ _gfxCursor32->init(_gfxFrameout->getCurrentBuffer());
_gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache);
_gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxText32);
_gfxFrameout->run();
} else {
#endif
+ _gfxCursor = new GfxCursor(_resMan, _gfxPalette16, _gfxScreen);
+
// SCI0-SCI1.1 graphic objects creation
_gfxPorts = new GfxPorts(_gamestate->_segMan, _gfxScreen);
_gfxCoordAdjuster = new GfxCoordAdjuster16(_gfxPorts);
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index 0425d21564..881df3d87a 100644
--- a/engines/sci/sci.h
+++ b/engines/sci/sci.h
@@ -98,6 +98,7 @@ class GfxFrameout;
class Audio32;
class Video32;
class GfxTransitions32;
+class GfxCursor32;
#endif
// our engine debug levels
@@ -391,6 +392,7 @@ public:
RobotDecoder *_robotDecoder;
GfxFrameout *_gfxFrameout; // kFrameout and the like for 32-bit gfx
GfxTransitions32 *_gfxTransitions32;
+ GfxCursor32 *_gfxCursor32;
#endif
AudioPlayer *_audio;