[Scummvm-cvs-logs] scummvm master -> 7da359755d31b6a5a98fc791f795139441c82b56

csnover csnover at users.noreply.github.com
Fri Aug 19 21:04:13 CEST 2016


This automated email contains information about 13 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
9bfeb3c297 SCI32: Remove GfxScreen from GfxFrameout
80d9182554 SCI32: Implement SCI32 cursor support
03177721b8 SCI32: Allow pixel doubling of some cursors to improve usability
c8a2b9af22 SCI32: Fix comment
ff00e93c67 SCI32: Remove GfxScreen from SCI32
89a82f5b55 SCI32: Fix signature of kSetNowSeen
d5bcef1e66 SCI32: Hide cursors in 24bpp video playback mode
b74532fc1e SCI32: Clean up Cursor32 includes
6e2e862d8e SCI32: Implement kShakeScreen for SCI32
79d9e0af68 SCI32: Address TODO in seg_manager.h
fdb2290415 SCI32: Add some bounds checking, const-correctness, and errors to CelObj
b1d53ca25d SCI32: Add kSetNowSeen variant for older SCI32 games
7da359755d SCI32: Split kPlatform for SCI32


Commit: 9bfeb3c297a7868c53d4c37775148067d72f44c0
    https://github.com/scummvm/scummvm/commit/9bfeb3c297a7868c53d4c37775148067d72f44c0
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-19T13:57:40-05:00

Commit Message:
SCI32: Remove GfxScreen from GfxFrameout

Only cursor remains to be updated to go through GfxFrameout, and
then we can let GfxScreen go back to being SCI16-only.

Changed paths:
    engines/sci/graphics/frameout.cpp
    engines/sci/graphics/frameout.h
    engines/sci/graphics/screen.cpp
    engines/sci/sci.cpp



diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index 21ffb5f..7661fe5 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -29,6 +29,7 @@
 #include "common/system.h"
 #include "common/textconsole.h"
 #include "engines/engine.h"
+#include "engines/util.h"
 #include "graphics/palette.h"
 #include "graphics/surface.h"
 
@@ -55,31 +56,36 @@
 
 namespace Sci {
 
-GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxScreen *screen, GfxPalette32 *palette, GfxTransitions32 *transitions) :
+GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxPalette32 *palette, GfxTransitions32 *transitions) :
 	_isHiRes(ConfMan.getBool("enable_high_resolution_graphics")),
 	_palette(palette),
 	_resMan(resMan),
-	_screen(screen),
 	_segMan(segMan),
 	_transitions(transitions),
 	_benchmarkingFinished(false),
 	_throttleFrameOut(true),
 	_throttleState(0),
-	// TODO: Stop using _gfxScreen
-	_currentBuffer(screen->getDisplayWidth(), screen->getDisplayHeight(), nullptr),
 	_remapOccurred(false),
 	_frameNowVisible(false),
-	_screenRect(screen->getDisplayWidth(), screen->getDisplayHeight()),
 	_overdrawThreshold(0),
 	_palMorphIsOn(false) {
 
-	_currentBuffer.setPixels(calloc(1, screen->getDisplayWidth() * screen->getDisplayHeight()));
-
 	// QFG4 is the only SCI32 game that doesn't have a high-resolution toggle
 	if (g_sci->getGameId() == GID_QFG4) {
 		_isHiRes = false;
 	}
 
+	if (g_sci->getGameId() == GID_PHANTASMAGORIA) {
+		_currentBuffer = Buffer(630, 450, nullptr);
+	} else if (_isHiRes) {
+		_currentBuffer = Buffer(640, 480, nullptr);
+	} else {
+		_currentBuffer = Buffer(320, 200, nullptr);
+	}
+	_currentBuffer.setPixels(calloc(1, _currentBuffer.screenWidth * _currentBuffer.screenHeight));
+	_screenRect = Common::Rect(_currentBuffer.screenWidth, _currentBuffer.screenHeight);
+	initGraphics(_currentBuffer.screenWidth, _currentBuffer.screenHeight, _isHiRes);
+
 	switch (g_sci->getGameId()) {
 	case GID_HOYLE5:
 	case GID_GK2:
@@ -559,7 +565,7 @@ void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, PlaneShowStyle *show
 
 	int16 prevRoom = g_sci->getEngineState()->variables[VAR_GLOBAL][12].toSint16();
 
-	Common::Rect rect(_screen->getDisplayWidth(), _screen->getDisplayHeight());
+	Common::Rect rect(_currentBuffer.screenWidth, _currentBuffer.screenHeight);
 	_showList.add(rect);
 	showBits();
 
diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h
index 012ecf9..8107316 100644
--- a/engines/sci/graphics/frameout.h
+++ b/engines/sci/graphics/frameout.h
@@ -31,7 +31,6 @@ typedef Common::Array<DrawList> ScreenItemListList;
 typedef Common::Array<RectList> EraseListList;
 
 class GfxCoordAdjuster32;
-class GfxScreen;
 class GfxTransitions32;
 struct PlaneShowStyle;
 
@@ -44,13 +43,14 @@ private:
 	GfxCoordAdjuster32 *_coordAdjuster;
 	GfxPalette32 *_palette;
 	ResourceManager *_resMan;
-	GfxScreen *_screen;
 	SegManager *_segMan;
 
 public:
-	GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxScreen *screen, GfxPalette32 *palette, GfxTransitions32 *transitions);
+	GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxPalette32 *palette, GfxTransitions32 *transitions);
 	~GfxFrameout();
 
+	bool _isHiRes;
+
 	void clear();
 	void syncWithScripts(bool addElements); // this is what Game::restore does, only needed when our ScummVM dialogs are patched in
 	void run();
@@ -308,8 +308,6 @@ private:
 	}
 
 public:
-	bool _isHiRes;
-
 	/**
 	 * Whether palMorphFrameOut should be used instead of
 	 * frameOut for rendering. Used by kMorphOn to
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp
index c977a93..8e638b9 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -30,6 +30,9 @@
 #include "sci/engine/state.h"
 #include "sci/graphics/screen.h"
 #include "sci/graphics/view.h"
+#ifdef ENABLE_SCI32
+#include "sci/graphics/frameout.h"
+#endif
 
 namespace Sci {
 
@@ -53,12 +56,6 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) {
 	if ((g_sci->getPlatform() == Common::kPlatformWindows) || (g_sci->forceHiresGraphics())) {
 		if (g_sci->getGameId() == GID_KQ6)
 			_upscaledHires = GFX_SCREEN_UPSCALED_640x440;
-#ifdef ENABLE_SCI32
-		if (g_sci->getGameId() == GID_GK1)
-			_upscaledHires = GFX_SCREEN_UPSCALED_640x480;
-		if (g_sci->getGameId() == GID_PQ4)
-			_upscaledHires = GFX_SCREEN_UPSCALED_640x480;
-#endif
 	}
 
 	// Japanese versions of games use hi-res font on upscaled version of the game.
@@ -90,28 +87,11 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) {
 		}
 	}
 
-#ifdef ENABLE_SCI32
-	// GK1 Mac uses a 640x480 resolution too
-	if (g_sci->getPlatform() == Common::kPlatformMacintosh) {
-		if (g_sci->getGameId() == GID_GK1)
-			_upscaledHires = GFX_SCREEN_UPSCALED_640x480;
-	}
-#endif
-
 	if (_resMan->detectHires()) {
 		_scriptWidth = 640;
 		_scriptHeight = 480;
 	}
 
-#ifdef ENABLE_SCI32
-	// Phantasmagoria 1 effectively outputs 630x450
-	//  Coordinate translation has to use this resolution as well
-	if (g_sci->getGameId() == GID_PHANTASMAGORIA) {
-		_width = 630;
-		_height = 450;
-	}
-#endif
-
 	// if not yet set, set those to script-width/height
 	if (!_width)
 		_width = _scriptWidth;
@@ -212,7 +192,7 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) {
 			initGraphics(_displayWidth, _displayHeight + 28 + 2, _displayWidth > 320);
 		else
 			error("Unknown SCI1.1 Mac game");
-	} else
+	} else if (getSciVersion() < SCI_VERSION_2)
 		initGraphics(_displayWidth, _displayHeight, _displayWidth > 320);
 }
 
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index 2a098ad..61317ec 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -262,6 +262,7 @@ Common::Error SciEngine::run() {
 		_forceHiresGraphics = ConfMan.getBool("enable_high_resolution_graphics");
 	}
 
+	// TODO: Get rid of GfxScreen when running SCI32 games
 	// Initialize the game screen
 	_gfxScreen = new GfxScreen(_resMan);
 	_gfxScreen->enableUndithering(ConfMan.getBool("disable_dithering"));
@@ -737,7 +738,7 @@ void SciEngine::initGraphics() {
 		_gfxPaint32 = new GfxPaint32(_gamestate->_segMan);
 		_robotDecoder = new RobotDecoder(getPlatform() == Common::kPlatformMacintosh);
 		_gfxTransitions32 = new GfxTransitions32(_gamestate->_segMan);
-		_gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxScreen, _gfxPalette32, _gfxTransitions32);
+		_gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxPalette32, _gfxTransitions32);
 		_gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache);
 		_gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxText32);
 		_gfxFrameout->run();


Commit: 80d9182554bcc6b24b493510cf599baf7577dacc
    https://github.com/scummvm/scummvm/commit/80d9182554bcc6b24b493510cf599baf7577dacc
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-19T13:57:40-05:00

Commit Message:
SCI32: Implement SCI32 cursor support

Changed paths:
  A engines/sci/graphics/cursor32.cpp
  A engines/sci/graphics/cursor32.h
    engines/sci/engine/kernel.h
    engines/sci/engine/kernel_tables.h
    engines/sci/engine/kevent.cpp
    engines/sci/engine/kgraphics32.cpp
    engines/sci/engine/savegame.cpp
    engines/sci/engine/savegame.h
    engines/sci/engine/workarounds.cpp
    engines/sci/event.cpp
    engines/sci/graphics/frameout.cpp
    engines/sci/graphics/frameout.h
    engines/sci/graphics/video32.cpp
    engines/sci/module.mk
    engines/sci/sci.cpp
    engines/sci/sci.h



diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index b02a7e5..77927ba 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 76c24b0..097eb8b 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 d7a716a..56ee2f5 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 e458109..2286a66 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 7804b78..eeddda8 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 1bf6686..51dbbed 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 9b3b329..15f229f 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 4ad2a0c..b267d2e 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 0000000..a5491ee
--- /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 0000000..fe621e9
--- /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 7661fe5..aad3215 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 8107316..6cd0416 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 51be08d..f4aa766 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 18d97ea..eb2c6a1 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 61317ec..842384e 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 0425d21..881df3d 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;


Commit: 03177721b864439afb9b245d0f9be6528b458b12
    https://github.com/scummvm/scummvm/commit/03177721b864439afb9b245d0f9be6528b458b12
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-19T13:57:40-05:00

Commit Message:
SCI32: Allow pixel doubling of some cursors to improve usability

Changed paths:
    engines/sci/graphics/cursor32.cpp



diff --git a/engines/sci/graphics/cursor32.cpp b/engines/sci/graphics/cursor32.cpp
index a5491ee..5b63859 100644
--- a/engines/sci/graphics/cursor32.cpp
+++ b/engines/sci/graphics/cursor32.cpp
@@ -182,13 +182,39 @@ void GfxCursor32::setView(const GuiResourceId viewId, const int16 loopNo, const
 		_width = view._width;
 		_height = view._height;
 
+		// SSCI never increased the size of cursors, but some of the cursors
+		// in early SSCI games were designed for low-resolution screens and so
+		// are kind of hard to pick out when running in high-resolution mode.
+		// To address this, we make some slight adjustments to cursor display
+		// in a couple of games.
+		// GK1: All the cursors are increased in size since they all appear to
+		//      be designed for low-res display.
+		// PQ4: We only make the cursors bigger if they are above a set
+		//      threshold size because inventory items usually have a
+		//      high-resolution cursor representation.
+		bool pixelDouble = false;
+		if (g_sci->_gfxFrameout->_isHiRes &&
+			(g_sci->getGameId() == GID_GK1 ||
+			(g_sci->getGameId() == GID_PQ4 && _width <= 22 && _height <= 22))) {
+
+			_width *= 2;
+			_height *= 2;
+			_hotSpot.x *= 2;
+			_hotSpot.y *= 2;
+			pixelDouble = true;
+		}
+
 		_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);
+		if (pixelDouble) {
+			view.draw(target, _cursor.rect, Common::Point(0, 0), false, 2, 2);
+		} else {
+			view.draw(target, _cursor.rect, Common::Point(0, 0), false);
+		}
 	} else {
 		_hotSpot = Common::Point(0, 0);
 		_width = _height = 1;


Commit: c8a2b9af225e0ebca7d98f7b1063793a290953cd
    https://github.com/scummvm/scummvm/commit/c8a2b9af225e0ebca7d98f7b1063793a290953cd
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-19T13:57:40-05:00

Commit Message:
SCI32: Fix comment

Changed paths:
    engines/sci/graphics/cursor32.cpp
    engines/sci/graphics/frameout.cpp



diff --git a/engines/sci/graphics/cursor32.cpp b/engines/sci/graphics/cursor32.cpp
index 5b63859..a05c66e 100644
--- a/engines/sci/graphics/cursor32.cpp
+++ b/engines/sci/graphics/cursor32.cpp
@@ -183,10 +183,11 @@ void GfxCursor32::setView(const GuiResourceId viewId, const int16 loopNo, const
 		_height = view._height;
 
 		// SSCI never increased the size of cursors, but some of the cursors
-		// in early SSCI games were designed for low-resolution screens and so
-		// are kind of hard to pick out when running in high-resolution mode.
+		// in early SCI32 games were designed for low-resolution display mode
+		// and so are kind of hard to pick out when running in high-resolution
+		// mode.
 		// To address this, we make some slight adjustments to cursor display
-		// in a couple of games.
+		// in these early games:
 		// GK1: All the cursors are increased in size since they all appear to
 		//      be designed for low-res display.
 		// PQ4: We only make the cursors bigger if they are above a set
@@ -342,20 +343,21 @@ void GfxCursor32::move() {
 		return;
 	}
 
-	// If it was off the screen, just show it and return
+	// Cursor moved onto the screen after being offscreen
 	_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
+	// Cursor moved offscreen
 	if (!_cursor.rect.intersects(_vmapRegion.rect)) {
 		drawToHardware(_cursorBack);
 		return;
 	}
 
 	if (!_cursor.rect.intersects(_cursorBack.rect)) {
+		// Cursor moved to a completely different part of the screen
 		_drawBuff1.rect = _cursor.rect;
 		_drawBuff1.rect.clip(_vmapRegion.rect);
 		readVideo(_drawBuff1);
@@ -366,13 +368,13 @@ void GfxCursor32::move() {
 		paint(_drawBuff1, _cursor);
 		drawToHardware(_drawBuff1);
 
-		// erase
 		drawToHardware(_cursorBack);
 
 		_cursorBack.rect = _cursor.rect;
 		_cursorBack.rect.clip(_vmapRegion.rect);
 		copy(_cursorBack, _drawBuff2);
 	} else {
+		// Cursor moved, but still overlaps the previous cursor location
 		Common::Rect mergedRect(_cursorBack.rect);
 		mergedRect.extend(_cursor.rect);
 		mergedRect.clip(_vmapRegion.rect);
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index aad3215..e9234d9 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -72,7 +72,7 @@ GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAd
 	_overdrawThreshold(0),
 	_palMorphIsOn(false) {
 
-	// QFG4 is the only SCI32 game that doesn't have a high-resolution toggle
+	// QFG4 is the only SCI32 game that doesn't have a high-resolution version
 	if (g_sci->getGameId() == GID_QFG4) {
 		_isHiRes = false;
 	}


Commit: ff00e93c677e9437aee256b3ff9f1bce7e9b5032
    https://github.com/scummvm/scummvm/commit/ff00e93c677e9437aee256b3ff9f1bce7e9b5032
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-19T13:57:40-05:00

Commit Message:
SCI32: Remove GfxScreen from SCI32

Changed paths:
    engines/sci/engine/kernel.h
    engines/sci/engine/kernel_tables.h
    engines/sci/engine/kgraphics.cpp
    engines/sci/engine/kgraphics32.cpp
    engines/sci/graphics/cache.cpp
    engines/sci/graphics/celobj32.cpp
    engines/sci/graphics/celobj32.h
    engines/sci/graphics/screen.cpp
    engines/sci/sci.cpp



diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index 77927ba..892f0fe 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -422,6 +422,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 kSetNowSeen32(EngineState *s, int argc, reg_t *argv);
+reg_t kBaseSetter32(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);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 097eb8b..058e483 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -569,7 +569,10 @@ static SciKernelMapEntry s_kernelMap[] = {
 	{ MAP_CALL(Animate),           SIG_EVERYWHERE,           "(l0)(i)",               NULL,            NULL },
 	{ MAP_CALL(AssertPalette),     SIG_EVERYWHERE,           "i",                     NULL,            NULL },
 	{ MAP_CALL(AvoidPath),         SIG_EVERYWHERE,           "ii(.*)",                NULL,            NULL },
-	{ MAP_CALL(BaseSetter),        SIG_EVERYWHERE,           "o",                     NULL,            NULL },
+	{ MAP_CALL(BaseSetter),        SIG_SCI16, SIGFOR_ALL,    "o",                     NULL,            NULL },
+#ifdef ENABLE_SCI32
+	{ "BaseSetter", kBaseSetter32, SIG_SCI32, SIGFOR_ALL,    "o",                     NULL,            NULL },
+#endif
 	{ MAP_CALL(CanBeHere),         SIG_EVERYWHERE,           "o(l)",                  NULL,            NULL },
 	{ MAP_CALL(CantBeHere),        SIG_SCI16, SIGFOR_ALL,    "o(l)",                  NULL,            NULL },
 #ifdef ENABLE_SCI32
@@ -703,7 +706,7 @@ static SciKernelMapEntry s_kernelMap[] = {
 	{ MAP_CALL(SetMenu),           SIG_EVERYWHERE,           "i(.*)",                 NULL,            NULL },
 	{ MAP_CALL(SetNowSeen),        SIG_SCI16, SIGFOR_ALL,    "o(i)",                  NULL,            NULL },
 #ifdef ENABLE_SCI32
-	{ MAP_CALL(SetNowSeen),        SIG_SCI32, SIGFOR_ALL,    "o",                     NULL,            NULL },
+	{ "SetNowSeen", kSetNowSeen32, SIG_SCI32, SIGFOR_ALL,    "o",                     NULL,            NULL },
 #endif
 	{ MAP_CALL(SetPort),           SIG_EVERYWHERE,           "i(iiiii)(i)",           NULL,            kSetPort_workarounds },
 	{ MAP_CALL(SetQuitStr),        SIG_EVERYWHERE,           "r",                     NULL,            NULL },
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index cae5a09..d375a27 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -579,17 +579,8 @@ reg_t kBaseSetter(EngineState *s, int argc, reg_t *argv) {
 }
 
 reg_t kSetNowSeen(EngineState *s, int argc, reg_t *argv) {
-#ifdef ENABLE_SCI32
-	if (getSciVersion() >= SCI_VERSION_2) {
-		g_sci->_gfxFrameout->kernelSetNowSeen(argv[0]);
-		return NULL_REG;
-	} else {
-#endif
-		g_sci->_gfxCompare->kernelSetNowSeen(argv[0]);
-		return s->r_acc;
-#ifdef ENABLE_SCI32
-	}
-#endif
+	g_sci->_gfxCompare->kernelSetNowSeen(argv[0]);
+	return s->r_acc;
 }
 
 reg_t kPalette(EngineState *s, int argc, reg_t *argv) {
diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp
index 2286a66..41dc9a2 100644
--- a/engines/sci/engine/kgraphics32.cpp
+++ b/engines/sci/engine/kgraphics32.cpp
@@ -64,6 +64,45 @@ namespace Sci {
 
 extern void showScummVMDialog(const Common::String &message);
 
+reg_t kBaseSetter32(EngineState *s, int argc, reg_t *argv) {
+	reg_t object = argv[0];
+
+	const GuiResourceId viewId = readSelectorValue(s->_segMan, object, SELECTOR(view));
+	const int16 loopNo = readSelectorValue(s->_segMan, object, SELECTOR(loop));
+	const int16 celNo = readSelectorValue(s->_segMan, object, SELECTOR(cel));
+	const int16 x = readSelectorValue(s->_segMan, object, SELECTOR(x));
+	const int16 y = readSelectorValue(s->_segMan, object, SELECTOR(y));
+
+	CelObjView celObj(viewId, loopNo, celNo);
+
+	const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+	const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+
+	const Ratio scaleX(scriptWidth, celObj._scaledWidth);
+	const Ratio scaleY(scriptHeight, celObj._scaledHeight);
+
+	int16 brLeft;
+
+	if (celObj._mirrorX) {
+		brLeft = x - ((celObj._width - celObj._displace.x) * scaleX).toInt();
+	} else {
+		brLeft = x - (celObj._displace.x * scaleX).toInt();
+	}
+
+	const int16 brRight = brLeft + (celObj._width * scaleX).toInt() - 1;
+
+	writeSelectorValue(s->_segMan, object, SELECTOR(brLeft), brLeft);
+	writeSelectorValue(s->_segMan, object, SELECTOR(brRight), brRight);
+	writeSelectorValue(s->_segMan, object, SELECTOR(brBottom), y + 1);
+	writeSelectorValue(s->_segMan, object, SELECTOR(brTop), y + 1 - readSelectorValue(s->_segMan, object, SELECTOR(yStep)));
+
+	return s->r_acc;
+}
+
+reg_t kSetNowSeen32(EngineState *s, int argc, reg_t *argv) {
+	return make_reg(0, g_sci->_gfxFrameout->kernelSetNowSeen(argv[0]));
+}
+
 reg_t kSetCursor32(EngineState *s, int argc, reg_t *argv) {
 	switch (argc) {
 	case 1: {
diff --git a/engines/sci/graphics/cache.cpp b/engines/sci/graphics/cache.cpp
index fb1f557..9c77f31 100644
--- a/engines/sci/graphics/cache.cpp
+++ b/engines/sci/graphics/cache.cpp
@@ -95,10 +95,20 @@ int16 GfxCache::kernelViewGetCelHeight(GuiResourceId viewId, int16 loopNo, int16
 }
 
 int16 GfxCache::kernelViewGetLoopCount(GuiResourceId viewId) {
+#ifdef ENABLE_SCI32
+	if (getSciVersion() >= SCI_VERSION_2) {
+		return CelObjView::getNumLoops(viewId);
+	}
+#endif
 	return getView(viewId)->getLoopCount();
 }
 
 int16 GfxCache::kernelViewGetCelCount(GuiResourceId viewId, int16 loopNo) {
+#ifdef ENABLE_SCI32
+	if (getSciVersion() >= SCI_VERSION_2) {
+		return CelObjView::getNumCels(viewId, loopNo);
+	}
+#endif
 	return getView(viewId)->getCelCount(loopNo);
 }
 
diff --git a/engines/sci/graphics/celobj32.cpp b/engines/sci/graphics/celobj32.cpp
index 311684d..ebe845b 100644
--- a/engines/sci/graphics/celobj32.cpp
+++ b/engines/sci/graphics/celobj32.cpp
@@ -791,6 +791,43 @@ void CelObj::scaleDrawUncompNoMD(Buffer &target, const Ratio &scaleX, const Rati
 #pragma mark -
 #pragma mark CelObjView
 
+int16 CelObjView::getNumLoops(const GuiResourceId viewId) {
+	Resource *resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, viewId), false);
+
+	if (!resource) {
+		return 0;
+	}
+
+	return resource->data[2];
+}
+
+int16 CelObjView::getNumCels(const GuiResourceId viewId, const int16 loopNo) {
+	Resource *resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, viewId), false);
+
+	if (!resource) {
+		return 0;
+	}
+
+	byte *data = resource->data;
+
+	uint16 loopCount = data[2];
+	if (loopNo >= loopCount) {
+		return 0;
+	}
+
+	const uint16 viewHeaderSize = READ_SCI11ENDIAN_UINT16(data);
+	const uint8 loopHeaderSize = data[12];
+	const uint8 viewHeaderFieldSize = 2;
+
+	byte *loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * loopNo);
+
+	if ((int8)loopHeader[0] != -1) {
+		loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * (int8)loopHeader[0]);
+	}
+
+	return loopHeader[2];
+}
+
 CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int16 celNo) {
 	_info.type = kCelTypeView;
 	_info.resourceId = viewId;
diff --git a/engines/sci/graphics/celobj32.h b/engines/sci/graphics/celobj32.h
index eb6ce3a..e1751de 100644
--- a/engines/sci/graphics/celobj32.h
+++ b/engines/sci/graphics/celobj32.h
@@ -505,6 +505,9 @@ public:
 
 	using CelObj::draw;
 
+	static int16 getNumLoops(const GuiResourceId viewId);
+	static int16 getNumCels(const GuiResourceId viewId, const int16 loopNo);
+
 	/**
 	 * Draws the cel to the target buffer using the
 	 * positioning, mirroring, and scaling information from
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp
index 8e638b9..394a433 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -192,7 +192,7 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) {
 			initGraphics(_displayWidth, _displayHeight + 28 + 2, _displayWidth > 320);
 		else
 			error("Unknown SCI1.1 Mac game");
-	} else if (getSciVersion() < SCI_VERSION_2)
+	} else
 		initGraphics(_displayWidth, _displayHeight, _displayWidth > 320);
 }
 
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index 842384e..2c8683a 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -265,10 +265,13 @@ Common::Error SciEngine::run() {
 		_forceHiresGraphics = ConfMan.getBool("enable_high_resolution_graphics");
 	}
 
-	// TODO: Get rid of GfxScreen when running SCI32 games
-	// Initialize the game screen
-	_gfxScreen = new GfxScreen(_resMan);
-	_gfxScreen->enableUndithering(ConfMan.getBool("disable_dithering"));
+	if (getSciVersion() < SCI_VERSION_2) {
+		// Initialize the game screen
+		_gfxScreen = new GfxScreen(_resMan);
+		_gfxScreen->enableUndithering(ConfMan.getBool("disable_dithering"));
+	} else {
+		_gfxScreen = nullptr;
+	}
 
 	_kernel = new Kernel(_resMan, segMan);
 	_kernel->init();
@@ -737,7 +740,7 @@ void SciEngine::initGraphics() {
 		// SCI32 graphic objects creation
 		_gfxCoordAdjuster = new GfxCoordAdjuster32(_gamestate->_segMan);
 		_gfxCursor32 = new GfxCursor32();
-		_gfxCompare = new GfxCompare(_gamestate->_segMan, _gfxCache, _gfxScreen, _gfxCoordAdjuster);
+		_gfxCompare = new GfxCompare(_gamestate->_segMan, _gfxCache, nullptr, _gfxCoordAdjuster);
 		_gfxPaint32 = new GfxPaint32(_gamestate->_segMan);
 		_robotDecoder = new RobotDecoder(getPlatform() == Common::kPlatformMacintosh);
 		_gfxTransitions32 = new GfxTransitions32(_gamestate->_segMan);
@@ -748,9 +751,8 @@ void SciEngine::initGraphics() {
 		_gfxFrameout->run();
 	} else {
 #endif
-		_gfxCursor = new GfxCursor(_resMan, _gfxPalette16, _gfxScreen);
-
 		// SCI0-SCI1.1 graphic objects creation
+		_gfxCursor = new GfxCursor(_resMan, _gfxPalette16, _gfxScreen);
 		_gfxPorts = new GfxPorts(_gamestate->_segMan, _gfxScreen);
 		_gfxCoordAdjuster = new GfxCoordAdjuster16(_gfxPorts);
 		_gfxCursor->init(_gfxCoordAdjuster, _eventMan);


Commit: 89a82f5b55f95cd1b68374b670299ddc005fe1fb
    https://github.com/scummvm/scummvm/commit/89a82f5b55f95cd1b68374b670299ddc005fe1fb
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-19T13:57:40-05:00

Commit Message:
SCI32: Fix signature of kSetNowSeen

Changed paths:
    engines/sci/graphics/frameout.cpp
    engines/sci/graphics/frameout.h



diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index e9234d9..4bd7b46 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -1332,7 +1332,7 @@ bool GfxFrameout::isOnMe(const ScreenItem &screenItem, const Plane &plane, const
 	return true;
 }
 
-void GfxFrameout::kernelSetNowSeen(const reg_t screenItemObject) const {
+bool GfxFrameout::kernelSetNowSeen(const reg_t screenItemObject) const {
 	const reg_t planeObject = readSelector(_segMan, screenItemObject, SELECTOR(plane));
 
 	Plane *plane = _planes.findByObject(planeObject);
@@ -1342,7 +1342,7 @@ void GfxFrameout::kernelSetNowSeen(const reg_t screenItemObject) const {
 
 	ScreenItem *screenItem = plane->_screenItemList.findByObject(screenItemObject);
 	if (screenItem == nullptr) {
-		error("kSetNowSeen: Screen item %04x:%04x not found in plane %04x:%04x", PRINT_REG(screenItemObject), PRINT_REG(planeObject));
+		return false;
 	}
 
 	Common::Rect result = screenItem->getNowSeenRect(*plane);
@@ -1350,6 +1350,7 @@ void GfxFrameout::kernelSetNowSeen(const reg_t screenItemObject) const {
 	writeSelectorValue(_segMan, screenItemObject, SELECTOR(nsTop), result.top);
 	writeSelectorValue(_segMan, screenItemObject, SELECTOR(nsRight), result.right - 1);
 	writeSelectorValue(_segMan, screenItemObject, SELECTOR(nsBottom), result.bottom - 1);
+	return true;
 }
 
 void GfxFrameout::remapMarkRedraw() {
diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h
index 6cd0416..de90fc7 100644
--- a/engines/sci/graphics/frameout.h
+++ b/engines/sci/graphics/frameout.h
@@ -113,7 +113,7 @@ public:
 	void kernelAddScreenItem(const reg_t object);
 	void kernelUpdateScreenItem(const reg_t object);
 	void kernelDeleteScreenItem(const reg_t object);
-	void kernelSetNowSeen(const reg_t screenItemObject) const;
+	bool kernelSetNowSeen(const reg_t screenItemObject) const;
 
 #pragma mark -
 #pragma mark Planes


Commit: d5bcef1e662e969d558414ef110aebd4c8e87720
    https://github.com/scummvm/scummvm/commit/d5bcef1e662e969d558414ef110aebd4c8e87720
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-19T13:57:40-05:00

Commit Message:
SCI32: Hide cursors in 24bpp video playback mode

Drawing the cursor in this mode will result in a read overflow as
it is 8bpp.

Changed paths:
    engines/sci/graphics/video32.cpp



diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index f4aa766..b9fc706 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -269,6 +269,11 @@ void AVIPlayer::init() {
 		g_sci->_gfxFrameout->addScreenItem(*_screenItem);
 		g_sci->_gfxFrameout->frameOut(true);
 	} else {
+		// Attempting to draw a palettized cursor into a 24bpp surface will
+		// cause memory corruption, so hide the cursor in this mode (SCI did not
+		// have a 24bpp mode but just directed VFW to display videos instead)
+		g_sci->_gfxCursor32->hide();
+
 		const Buffer &currentBuffer = g_sci->_gfxFrameout->getCurrentBuffer();
 		const Graphics::PixelFormat format = _decoder->getPixelFormat();
 		initGraphics(currentBuffer.screenWidth, currentBuffer.screenHeight, g_sci->_gfxFrameout->_isHiRes, &format);
@@ -326,6 +331,7 @@ AVIPlayer::IOStatus AVIPlayer::close() {
 		const Buffer &currentBuffer = g_sci->_gfxFrameout->getCurrentBuffer();
 		const Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8();
 		initGraphics(currentBuffer.screenWidth, currentBuffer.screenHeight, isHiRes, &format);
+		g_sci->_gfxCursor32->unhide();
 	}
 
 	_decoder->close();


Commit: b74532fc1e3dfe034eff5df7f284feac7502b354
    https://github.com/scummvm/scummvm/commit/b74532fc1e3dfe034eff5df7f284feac7502b354
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-19T13:57:40-05:00

Commit Message:
SCI32: Clean up Cursor32 includes

Changed paths:
    engines/sci/graphics/cursor32.cpp
    engines/sci/graphics/cursor32.h



diff --git a/engines/sci/graphics/cursor32.cpp b/engines/sci/graphics/cursor32.cpp
index a05c66e..014b617 100644
--- a/engines/sci/graphics/cursor32.cpp
+++ b/engines/sci/graphics/cursor32.cpp
@@ -20,11 +20,12 @@
  *
  */
 
-#include "common/system.h"
-#include "graphics/cursorman.h"
-#include "sci/graphics/celobj32.h"
+#include "common/rational.h"        // for Rational, operator*
+#include "common/system.h"          // for OSystem, g_system
+#include "graphics/cursorman.h"     // for CursorMan
+#include "sci/graphics/celobj32.h"  // for CelObjView, CelInfo32, Ratio
 #include "sci/graphics/cursor32.h"
-#include "sci/graphics/frameout.h"
+#include "sci/graphics/frameout.h"  // for GfxFrameout
 
 namespace Sci {
 
diff --git a/engines/sci/graphics/cursor32.h b/engines/sci/graphics/cursor32.h
index fe621e9..d474553 100644
--- a/engines/sci/graphics/cursor32.h
+++ b/engines/sci/graphics/cursor32.h
@@ -23,9 +23,11 @@
 #ifndef SCI_GRAPHICS_CURSOR32_H
 #define SCI_GRAPHICS_CURSOR32_H
 
-#include "common/rect.h"
-#include "common/serializer.h"
-#include "sci/graphics/helpers.h"
+#include "common/rect.h"            // for Point, Rect
+#include "common/scummsys.h"        // for int16, byte, uint8
+#include "common/serializer.h"      // for Serializable, Serializer (ptr only)
+#include "sci/graphics/celobj32.h"  // for CelInfo32
+#include "sci/graphics/helpers.h"   // for GuiResourceId
 
 namespace Sci {
 


Commit: 6e2e862d8e5db0c8e786525fff2e2ae1f878f919
    https://github.com/scummvm/scummvm/commit/6e2e862d8e5db0c8e786525fff2e2ae1f878f919
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-19T13:57:40-05:00

Commit Message:
SCI32: Implement kShakeScreen for SCI32

Changed paths:
    engines/sci/engine/kernel.h
    engines/sci/engine/kernel_tables.h
    engines/sci/engine/kgraphics32.cpp
    engines/sci/graphics/frameout.cpp
    engines/sci/graphics/frameout.h
    engines/sci/graphics/helpers.h
    engines/sci/graphics/screen.cpp



diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index 892f0fe..3342e0a 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -424,6 +424,7 @@ reg_t kStubNull(EngineState *s, int argc, reg_t *argv);
 reg_t kSetCursor32(EngineState *s, int argc, reg_t *argv);
 reg_t kSetNowSeen32(EngineState *s, int argc, reg_t *argv);
 reg_t kBaseSetter32(EngineState *s, int argc, reg_t *argv);
+reg_t kShakeScreen32(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);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 058e483..bd114c6 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -712,7 +712,10 @@ static SciKernelMapEntry s_kernelMap[] = {
 	{ MAP_CALL(SetQuitStr),        SIG_EVERYWHERE,           "r",                     NULL,            NULL },
 	{ MAP_CALL(SetSynonyms),       SIG_EVERYWHERE,           "o",                     NULL,            NULL },
 	{ MAP_CALL(SetVideoMode),      SIG_EVERYWHERE,           "i",                     NULL,            NULL },
-	{ MAP_CALL(ShakeScreen),       SIG_EVERYWHERE,           "(i)(i)",                NULL,            NULL },
+	{ MAP_CALL(ShakeScreen),       SIG_SCI16, SIGFOR_ALL,    "(i)(i)",                NULL,            NULL },
+#ifdef ENABLE_SCI32
+	{ "ShakeScreen", kShakeScreen32, SIG_SCI32, SIGFOR_ALL,  "i(i)",                  NULL,            NULL },
+#endif
 	{ MAP_CALL(ShowMovie),         SIG_SCI16, SIGFOR_ALL,    "(.*)",                  NULL,            NULL },
 #ifdef ENABLE_SCI32
 	{ "ShowMovie", kShowMovie32,   SIG_SCI32, SIGFOR_DOS,    "ri(i)(i)",              NULL,            NULL },
diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp
index 41dc9a2..c56aec8 100644
--- a/engines/sci/engine/kgraphics32.cpp
+++ b/engines/sci/engine/kgraphics32.cpp
@@ -141,6 +141,11 @@ reg_t kSetCursor32(EngineState *s, int argc, reg_t *argv) {
 	return s->r_acc;
 }
 
+reg_t kShakeScreen32(EngineState *s, int argc, reg_t *argv) {
+	g_sci->_gfxFrameout->shakeScreen(argv[0].toSint16(), (ShakeDirection)argv[1].toSint16());
+	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/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index 4bd7b46..c0d8f15 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -1274,6 +1274,30 @@ void GfxFrameout::showRect(const Common::Rect &rect) {
 	}
 }
 
+void GfxFrameout::shakeScreen(int16 numShakes, const ShakeDirection direction) {
+	if (direction & kShakeHorizontal) {
+		// Used by QFG4 room 750
+		warning("TODO: Horizontal shake not implemented");
+		return;
+	}
+
+	while (numShakes--) {
+		if (direction & kShakeVertical) {
+			g_system->setShakePos(_isHiRes ? 8 : 4);
+		}
+
+		g_system->updateScreen();
+		g_sci->getEngineState()->wait(3);
+
+		if (direction & kShakeVertical) {
+			g_system->setShakePos(0);
+		}
+
+		g_system->updateScreen();
+		g_sci->getEngineState()->wait(3);
+	}
+}
+
 #pragma mark -
 #pragma mark Mouse cursor
 
diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h
index de90fc7..92e38fa 100644
--- a/engines/sci/graphics/frameout.h
+++ b/engines/sci/graphics/frameout.h
@@ -366,6 +366,11 @@ public:
 	 */
 	void showRect(const Common::Rect &rect);
 
+	/**
+	 * Shakes the screen.
+	 */
+	void shakeScreen(const int16 numShakes, const ShakeDirection direction);
+
 #pragma mark -
 #pragma mark Mouse cursor
 private:
diff --git a/engines/sci/graphics/helpers.h b/engines/sci/graphics/helpers.h
index 3fcc83c..1da3749 100644
--- a/engines/sci/graphics/helpers.h
+++ b/engines/sci/graphics/helpers.h
@@ -40,8 +40,10 @@ namespace Sci {
 #define MAX_CACHED_FONTS 20
 #define MAX_CACHED_VIEWS 50
 
-#define SCI_SHAKE_DIRECTION_VERTICAL 1
-#define SCI_SHAKE_DIRECTION_HORIZONTAL 2
+enum ShakeDirection {
+	kShakeVertical   = 1,
+	kShakeHorizontal = 2
+};
 
 typedef int GuiResourceId; // is a resource-number and -1 means no parameter given
 
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp
index 394a433..601ab9f 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -30,9 +30,6 @@
 #include "sci/engine/state.h"
 #include "sci/graphics/screen.h"
 #include "sci/graphics/view.h"
-#ifdef ENABLE_SCI32
-#include "sci/graphics/frameout.h"
-#endif
 
 namespace Sci {
 
@@ -612,13 +609,13 @@ void GfxScreen::setVerticalShakePos(uint16 shakePos) {
 
 void GfxScreen::kernelShakeScreen(uint16 shakeCount, uint16 directions) {
 	while (shakeCount--) {
-		if (directions & SCI_SHAKE_DIRECTION_VERTICAL)
+		if (directions & kShakeVertical)
 			setVerticalShakePos(10);
 		// TODO: horizontal shakes
 		g_system->updateScreen();
 		g_sci->getEngineState()->wait(3);
 
-		if (directions & SCI_SHAKE_DIRECTION_VERTICAL)
+		if (directions & kShakeVertical)
 			setVerticalShakePos(0);
 
 		g_system->updateScreen();


Commit: 79d9e0af68ccad31e6ef9faed176c5b0d4a6c47f
    https://github.com/scummvm/scummvm/commit/79d9e0af68ccad31e6ef9faed176c5b0d4a6c47f
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-19T13:57:40-05:00

Commit Message:
SCI32: Address TODO in seg_manager.h

Changed paths:
    engines/sci/engine/seg_manager.h



diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h
index acebece..8ed1c3a 100644
--- a/engines/sci/engine/seg_manager.h
+++ b/engines/sci/engine/seg_manager.h
@@ -30,8 +30,7 @@
 #include "sci/engine/vm_types.h"
 #include "sci/engine/segment.h"
 #ifdef ENABLE_SCI32
-// TODO: Baaaad?
-#include "sci/graphics/celobj32.h"
+#include "sci/graphics/celobj32.h" // kLowResX, kLowResY
 #endif
 
 namespace Sci {


Commit: fdb22904150caf50e6076904e65a29a833173bdd
    https://github.com/scummvm/scummvm/commit/fdb22904150caf50e6076904e65a29a833173bdd
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-19T13:57:40-05:00

Commit Message:
SCI32: Add some bounds checking, const-correctness, and errors to CelObj

Changed paths:
    engines/sci/graphics/celobj32.cpp
    engines/sci/graphics/celobj32.h



diff --git a/engines/sci/graphics/celobj32.cpp b/engines/sci/graphics/celobj32.cpp
index ebe845b..c5b1133 100644
--- a/engines/sci/graphics/celobj32.cpp
+++ b/engines/sci/graphics/celobj32.cpp
@@ -45,7 +45,7 @@ void CelScaler::activateScaleTables(const Ratio &scaleX, const Ratio &scaleY) {
 		}
 	}
 
-	int i = 1 - _activeIndex;
+	const int i = 1 - _activeIndex;
 	_activeIndex = i;
 	CelScalerTable &table = _scaleTables[i];
 
@@ -65,7 +65,7 @@ void CelScaler::activateScaleTables(const Ratio &scaleX, const Ratio &scaleY) {
 void CelScaler::buildLookupTable(int *table, const Ratio &ratio, const int size) {
 	int value = 0;
 	int remainder = 0;
-	int num = ratio.getNumerator();
+	const int num = ratio.getNumerator();
 	for (int i = 0; i < size; ++i) {
 		*table++ = value;
 		remainder += ratio.getDenominator();
@@ -204,7 +204,7 @@ struct SCALER_Scale {
 		if (g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth == kLowResX) {
 			const int16 unscaledX = (scaledPosition.x / scaleX).toInt();
 			if (FLIP) {
-				int lastIndex = celObj._width - 1;
+				const int lastIndex = celObj._width - 1;
 				for (int16 x = targetRect.left; x < targetRect.right; ++x) {
 					_valuesX[x] = lastIndex - (table->valuesX[x] - unscaledX);
 				}
@@ -220,7 +220,7 @@ struct SCALER_Scale {
 			}
 		} else {
 			if (FLIP) {
-				int lastIndex = celObj._width - 1;
+				const int lastIndex = celObj._width - 1;
 				for (int16 x = 0; x < targetRect.width(); ++x) {
 					_valuesX[targetRect.left + x] = lastIndex - table->valuesX[x];
 				}
@@ -261,7 +261,7 @@ private:
 #ifndef NDEBUG
 	const int16 _sourceHeight;
 #endif
-	byte *_pixels;
+	const byte *_pixels;
 	const int16 _sourceWidth;
 
 public:
@@ -270,7 +270,7 @@ public:
 	_sourceHeight(celObj._height),
 #endif
 	_sourceWidth(celObj._width) {
-		byte *resource = celObj.getResPointer();
+		const byte *resource = celObj.getResPointer();
 		_pixels = resource + READ_SCI11ENDIAN_UINT32(resource + celObj._celHeaderOffset + 24);
 	}
 
@@ -282,7 +282,7 @@ public:
 
 struct READER_Compressed {
 private:
-	byte *_resource;
+	const byte *const _resource;
 	byte _buffer[1024];
 	uint32 _controlOffset;
 	uint32 _dataOffset;
@@ -301,7 +301,7 @@ public:
 	_maxWidth(maxWidth) {
 		assert(maxWidth <= celObj._width);
 
-		byte *celHeader = _resource + celObj._celHeaderOffset;
+		const byte *const celHeader = _resource + celObj._celHeaderOffset;
 		_dataOffset = READ_SCI11ENDIAN_UINT32(celHeader + 24);
 		_uncompressedDataOffset = READ_SCI11ENDIAN_UINT32(celHeader + 28);
 		_controlOffset = READ_SCI11ENDIAN_UINT32(celHeader + 32);
@@ -311,14 +311,14 @@ public:
 		assert(y >= 0 && y < _sourceHeight);
 		if (y != _y) {
 			// compressed data segment for row
-			byte *row = _resource + _dataOffset + READ_SCI11ENDIAN_UINT32(_resource + _controlOffset + y * 4);
+			const byte *row = _resource + _dataOffset + READ_SCI11ENDIAN_UINT32(_resource + _controlOffset + y * 4);
 
 			// uncompressed data segment for row
-			byte *literal = _resource + _uncompressedDataOffset + READ_SCI11ENDIAN_UINT32(_resource + _controlOffset + _sourceHeight * 4 + y * 4);
+			const byte *literal = _resource + _uncompressedDataOffset + READ_SCI11ENDIAN_UINT32(_resource + _controlOffset + _sourceHeight * 4 + y * 4);
 
 			uint8 length;
 			for (int16 i = 0; i < _maxWidth; i += length) {
-				byte controlByte = *row++;
+				const byte controlByte = *row++;
 				length = controlByte;
 
 				// Run-length encoded
@@ -581,7 +581,7 @@ void CelObj::submitPalette() const {
 int CelObj::_nextCacheId = 1;
 CelCache *CelObj::_cache = nullptr;
 
-int CelObj::searchCache(const CelInfo32 &celInfo, int *nextInsertIndex) const {
+int CelObj::searchCache(const CelInfo32 &celInfo, int *const nextInsertIndex) const {
 	*nextInsertIndex = -1;
 	int oldestId = _nextCacheId + 1;
 	int oldestIndex = 0;
@@ -792,26 +792,27 @@ void CelObj::scaleDrawUncompNoMD(Buffer &target, const Ratio &scaleX, const Rati
 #pragma mark CelObjView
 
 int16 CelObjView::getNumLoops(const GuiResourceId viewId) {
-	Resource *resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, viewId), false);
+	const Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, viewId), false);
 
 	if (!resource) {
 		return 0;
 	}
 
+	assert(resource->size >= 3);
 	return resource->data[2];
 }
 
 int16 CelObjView::getNumCels(const GuiResourceId viewId, const int16 loopNo) {
-	Resource *resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, viewId), false);
+	const Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, viewId), false);
 
 	if (!resource) {
 		return 0;
 	}
 
-	byte *data = resource->data;
+	const byte *const data = resource->data;
 
-	uint16 loopCount = data[2];
-	if (loopNo >= loopCount) {
+	const uint16 loopCount = data[2];
+	if (loopNo >= loopCount || loopNo < 0) {
 		return 0;
 	}
 
@@ -819,10 +820,15 @@ int16 CelObjView::getNumCels(const GuiResourceId viewId, const int16 loopNo) {
 	const uint8 loopHeaderSize = data[12];
 	const uint8 viewHeaderFieldSize = 2;
 
-	byte *loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * loopNo);
+#ifndef NDEBUG
+	const byte *const dataMax = data + resource->size;
+#endif
+	const byte *loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * loopNo);
+	assert(loopHeader + 3 <= dataMax);
 
 	if ((int8)loopHeader[0] != -1) {
 		loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * (int8)loopHeader[0]);
+		assert(loopHeader >= data && loopHeader + 3 <= dataMax);
 	}
 
 	return loopHeader[2];
@@ -838,7 +844,7 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
 	_transparent = true;
 
 	int cacheInsertIndex;
-	int cacheIndex = searchCache(_info, &cacheInsertIndex);
+	const int cacheIndex = searchCache(_info, &cacheInsertIndex);
 	if (cacheIndex != -1) {
 		CelCacheEntry &entry = (*_cache)[cacheIndex];
 		const CelObjView *const cachedCelObj = dynamic_cast<CelObjView *>(entry.celObj);
@@ -854,15 +860,14 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
 	// generates view resource metadata for both SCI16 and SCI32
 	// implementations
 
-	Resource *resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, viewId), false);
+	const Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, viewId), false);
 
 	// NOTE: SCI2.1/SQ6 just silently returns here.
 	if (!resource) {
-		warning("View resource %d not loaded", viewId);
-		return;
+		error("View resource %d not found", viewId);
 	}
 
-	byte *data = resource->data;
+	const byte *const data = resource->data;
 
 	_scaledWidth = READ_SCI11ENDIAN_UINT16(data + 14);
 	_scaledHeight = READ_SCI11ENDIAN_UINT16(data + 16);
@@ -881,7 +886,7 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
 		}
 	}
 
-	uint16 loopCount = data[2];
+	const uint16 loopCount = data[2];
 	if (_info.loopNo >= loopCount) {
 		_info.loopNo = loopCount - 1;
 	}
@@ -896,7 +901,7 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
 	const uint8 loopHeaderSize = data[12];
 	const uint8 viewHeaderFieldSize = 2;
 
-	byte *loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * _info.loopNo);
+	const byte *loopHeader = data + viewHeaderFieldSize + viewHeaderSize + (loopHeaderSize * _info.loopNo);
 
 	if ((int8)loopHeader[0] != -1) {
 		if (loopHeader[1] == 1) {
@@ -911,10 +916,14 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
 		_info.celNo = celCount - 1;
 	}
 
+	if (_info.celNo < 0) {
+		error("Cel is less than 0!");
+	}
+
 	_hunkPaletteOffset = READ_SCI11ENDIAN_UINT32(data + 8);
 	_celHeaderOffset = READ_SCI11ENDIAN_UINT32(loopHeader + 12) + (data[13] * _info.celNo);
 
-	byte *celHeader = data + _celHeaderOffset;
+	const byte *const celHeader = data + _celHeaderOffset;
 
 	_width = READ_SCI11ENDIAN_UINT16(celHeader);
 	_height = READ_SCI11ENDIAN_UINT16(celHeader + 2);
@@ -943,7 +952,7 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
 }
 
 bool CelObjView::analyzeUncompressedForRemap() const {
-	byte *pixels = getResPointer() + READ_SCI11ENDIAN_UINT32(getResPointer() + _celHeaderOffset + 24);
+	const byte *pixels = getResPointer() + READ_SCI11ENDIAN_UINT32(getResPointer() + _celHeaderOffset + 24);
 	for (int i = 0; i < _width * _height; ++i) {
 		const byte pixel = pixels[i];
 		if (
@@ -960,7 +969,7 @@ bool CelObjView::analyzeUncompressedForRemap() const {
 bool CelObjView::analyzeForRemap() const {
 	READER_Compressed reader(*this, _width);
 	for (int y = 0; y < _height; y++) {
-		const byte *curRow = reader.getRow(y);
+		const byte *const curRow = reader.getRow(y);
 		for (int x = 0; x < _width; x++) {
 			const byte pixel = curRow[x];
 			if (
@@ -985,7 +994,7 @@ CelObjView *CelObjView::duplicate() const {
 }
 
 byte *CelObjView::getResPointer() const {
-	const Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, _info.resourceId), false);
+	Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, _info.resourceId), false);
 	if (resource == nullptr) {
 		error("Failed to load view %d from resource manager", _info.resourceId);
 	}
@@ -1006,7 +1015,7 @@ CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) {
 	_remap = false;
 
 	int cacheInsertIndex;
-	int cacheIndex = searchCache(_info, &cacheInsertIndex);
+	const int cacheIndex = searchCache(_info, &cacheInsertIndex);
 	if (cacheIndex != -1) {
 		CelCacheEntry &entry = (*_cache)[cacheIndex];
 		const CelObjPic *const cachedCelObj = dynamic_cast<CelObjPic *>(entry.celObj);
@@ -1018,15 +1027,14 @@ CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) {
 		return;
 	}
 
-	Resource *resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypePic, picId), false);
+	const Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypePic, picId), false);
 
 	// NOTE: SCI2.1/SQ6 just silently returns here.
 	if (!resource) {
-		warning("Pic resource %d not loaded", picId);
-		return;
+		error("Pic resource %d not found", picId);
 	}
 
-	byte *data = resource->data;
+	const byte *const data = resource->data;
 
 	_celCount = data[2];
 
@@ -1037,7 +1045,7 @@ CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) {
 	_celHeaderOffset = READ_SCI11ENDIAN_UINT16(data) + (READ_SCI11ENDIAN_UINT16(data + 4) * _info.celNo);
 	_hunkPaletteOffset = READ_SCI11ENDIAN_UINT32(data + 6);
 
-	byte *celHeader = data + _celHeaderOffset;
+	const byte *const celHeader = data + _celHeaderOffset;
 
 	_width = READ_SCI11ENDIAN_UINT16(celHeader);
 	_height = READ_SCI11ENDIAN_UINT16(celHeader + 2);
@@ -1049,8 +1057,8 @@ CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) {
 	_relativePosition.x = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 38);
 	_relativePosition.y = (int16)READ_SCI11ENDIAN_UINT16(celHeader + 40);
 
-	uint16 sizeFlag1 = READ_SCI11ENDIAN_UINT16(data + 10);
-	uint16 sizeFlag2 = READ_SCI11ENDIAN_UINT16(data + 12);
+	const uint16 sizeFlag1 = READ_SCI11ENDIAN_UINT16(data + 10);
+	const uint16 sizeFlag2 = READ_SCI11ENDIAN_UINT16(data + 12);
 
 	if (sizeFlag2) {
 		_scaledWidth = sizeFlag1;
@@ -1069,7 +1077,7 @@ CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) {
 	if (celHeader[10] & 128) {
 		// NOTE: This is correct according to SCI2.1/SQ6/DOS;
 		// the engine re-reads the byte value as a word value
-		uint16 flags = READ_SCI11ENDIAN_UINT16(celHeader + 10);
+		const uint16 flags = READ_SCI11ENDIAN_UINT16(celHeader + 10);
 		_transparent = flags & 1 ? true : false;
 		_remap = flags & 2 ? true : false;
 	} else {
@@ -1084,8 +1092,8 @@ CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) {
 }
 
 bool CelObjPic::analyzeUncompressedForSkip() const {
-	byte *resource = getResPointer();
-	byte *pixels = resource + READ_SCI11ENDIAN_UINT32(resource + _celHeaderOffset + 24);
+	const byte *const resource = getResPointer();
+	const byte *const pixels = resource + READ_SCI11ENDIAN_UINT32(resource + _celHeaderOffset + 24);
 	for (int i = 0; i < _width * _height; ++i) {
 		uint8 pixel = pixels[i];
 		if (pixel == _transparentColor) {
@@ -1097,7 +1105,7 @@ bool CelObjPic::analyzeUncompressedForSkip() const {
 }
 
 void CelObjPic::draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX) {
-	Ratio square;
+	const Ratio square;
 	_drawMirrored = mirrorX;
 	drawTo(target, targetRect, scaledPosition, square, square);
 }
@@ -1125,15 +1133,21 @@ CelObjMem::CelObjMem(const reg_t bitmapObject) {
 	_celHeaderOffset = 0;
 	_transparent = true;
 
-	SciBitmap &bitmap = *g_sci->getEngineState()->_segMan->lookupBitmap(bitmapObject);
-	_width = bitmap.getWidth();
-	_height = bitmap.getHeight();
-	_displace = bitmap.getDisplace();
-	_transparentColor = bitmap.getSkipColor();
-	_scaledWidth = bitmap.getScaledWidth();
-	_scaledHeight = bitmap.getScaledHeight();
-	_hunkPaletteOffset = bitmap.getHunkPaletteOffset();
-	_remap = bitmap.getRemap();
+	SciBitmap *bitmap = g_sci->getEngineState()->_segMan->lookupBitmap(bitmapObject);
+
+	// NOTE: SSCI did no error checking here at all.
+	if (!bitmap) {
+		error("Bitmap %04x:%04x not found", PRINT_REG(bitmapObject));
+	}
+
+	_width = bitmap->getWidth();
+	_height = bitmap->getHeight();
+	_displace = bitmap->getDisplace();
+	_transparentColor = bitmap->getSkipColor();
+	_scaledWidth = bitmap->getScaledWidth();
+	_scaledHeight = bitmap->getScaledHeight();
+	_hunkPaletteOffset = bitmap->getHunkPaletteOffset();
+	_remap = bitmap->getRemap();
 }
 
 CelObjMem *CelObjMem::duplicate() const {
diff --git a/engines/sci/graphics/celobj32.h b/engines/sci/graphics/celobj32.h
index e1751de..e58fb50 100644
--- a/engines/sci/graphics/celobj32.h
+++ b/engines/sci/graphics/celobj32.h
@@ -400,7 +400,7 @@ public:
 	 * Reads the pixel at the given coordinates. This method
 	 * is valid only for CelObjView and CelObjPic.
 	 */
-	virtual uint8 readPixel(uint16 x, uint16 y, bool mirrorX) const;
+	virtual uint8 readPixel(const uint16 x, const uint16 y, const bool mirrorX) const;
 
 	/**
 	 * Submits the palette from this cel to the palette


Commit: b1d53ca25d8b29dfc7fd42b3684e8548ef315da4
    https://github.com/scummvm/scummvm/commit/b1d53ca25d8b29dfc7fd42b3684e8548ef315da4
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-19T13:57:40-05:00

Commit Message:
SCI32: Add kSetNowSeen variant for older SCI32 games

KQ7 2.00b, PQ:SWAT, Phant1, GK2, and Torin are all verified as
using the 'ignore' variant; SQ6 and QFG4CD are verified as using
the 'fail' variant. MGDX and Shivers could not be checked as they
have only Phar Lap Win16 executables, so took a guess based on
their release dates.

Changed paths:
    engines/sci/engine/kgraphics32.cpp



diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp
index c56aec8..182f2cb 100644
--- a/engines/sci/engine/kgraphics32.cpp
+++ b/engines/sci/engine/kgraphics32.cpp
@@ -100,7 +100,26 @@ reg_t kBaseSetter32(EngineState *s, int argc, reg_t *argv) {
 }
 
 reg_t kSetNowSeen32(EngineState *s, int argc, reg_t *argv) {
-	return make_reg(0, g_sci->_gfxFrameout->kernelSetNowSeen(argv[0]));
+	const bool found = g_sci->_gfxFrameout->kernelSetNowSeen(argv[0]);
+
+	// NOTE: MGDX is assumed to use the older kSetNowSeen since it was
+	// released before SQ6, but this has not been verified since it cannot be
+	// disassembled at the moment (Phar Lap Windows-only release)
+	if (getSciVersion() <= SCI_VERSION_2_1_EARLY ||
+		g_sci->getGameId() == GID_SQ6 ||
+		g_sci->getGameId() == GID_MOTHERGOOSEHIRES) {
+
+		if (!found) {
+			error("kSetNowSeen: Unable to find screen item %04x:%04x", PRINT_REG(argv[0]));
+		}
+		return s->r_acc;
+	}
+
+	if (!found) {
+		warning("kSetNowSeen: Unable to find screen item %04x:%04x", PRINT_REG(argv[0]));
+	}
+
+	return make_reg(0, found);
 }
 
 reg_t kSetCursor32(EngineState *s, int argc, reg_t *argv) {


Commit: 7da359755d31b6a5a98fc791f795139441c82b56
    https://github.com/scummvm/scummvm/commit/7da359755d31b6a5a98fc791f795139441c82b56
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-19T13:57:40-05:00

Commit Message:
SCI32: Split kPlatform for SCI32

Changed paths:
    engines/sci/engine/kernel.h
    engines/sci/engine/kernel_tables.h
    engines/sci/engine/kmisc.cpp



diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index 3342e0a..2b488cb 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -425,6 +425,7 @@ reg_t kSetCursor32(EngineState *s, int argc, reg_t *argv);
 reg_t kSetNowSeen32(EngineState *s, int argc, reg_t *argv);
 reg_t kBaseSetter32(EngineState *s, int argc, reg_t *argv);
 reg_t kShakeScreen32(EngineState *s, int argc, reg_t *argv);
+reg_t kPlatform32(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);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index bd114c6..77fe6e2 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -679,7 +679,10 @@ static SciKernelMapEntry s_kernelMap[] = {
 	{ MAP_CALL(Palette),           SIG_EVERYWHERE,           "i(.*)",                 kPalette_subops, NULL },
 	{ MAP_CALL(Parse),             SIG_EVERYWHERE,           "ro",                    NULL,            NULL },
 	{ MAP_CALL(PicNotValid),       SIG_EVERYWHERE,           "(i)",                   NULL,            NULL },
-	{ MAP_CALL(Platform),          SIG_EVERYWHERE,           "(.*)",                  NULL,            NULL },
+	{ MAP_CALL(Platform),          SIG_SCI16, SIGFOR_ALL,    "(.*)",                  NULL,            NULL },
+#ifdef ENABLE_SCI32
+	{ "Platform", kPlatform32,     SIG_SCI32, SIGFOR_ALL,    "(i)",                   NULL,            NULL },
+#endif
 	{ MAP_CALL(Portrait),          SIG_EVERYWHERE,           "i(.*)",                 NULL,            NULL }, // subop
 	{ MAP_CALL(PrevNode),          SIG_EVERYWHERE,           "n",                     NULL,            NULL },
 	{ MAP_CALL(PriCoord),          SIG_EVERYWHERE,           "i",                     NULL,            NULL },
diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index c995409..448d7bb 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -540,57 +540,46 @@ enum kSciPlatforms {
 	kSciPlatformWindows = 2
 };
 
-enum kPlatformOps {
-	kPlatformUnk0 = 0,
-	kPlatformCDSpeed = 1,
-	kPlatformColorDepth = 2,
-	kPlatformCDCheck = 3,
-	kPlatformGetPlatform = 4,
-	kPlatformUnk5 = 5,
-	kPlatformIsHiRes = 6,
-	kPlatformIsItWindows = 7
-};
-
 reg_t kPlatform(EngineState *s, int argc, reg_t *argv) {
+	enum Operation {
+		kPlatformUnknown        = 0,
+		kPlatformGetPlatform    = 4,
+		kPlatformUnknown5       = 5,
+		kPlatformIsHiRes        = 6,
+		kPlatformWin311OrHigher = 7
+	};
+
 	bool isWindows = g_sci->getPlatform() == Common::kPlatformWindows;
 
-	if (argc == 0 && getSciVersion() < SCI_VERSION_2) {
+	if (argc == 0) {
 		// This is called in KQ5CD with no parameters, where it seems to do some
 		// graphics driver check. This kernel function didn't have subfunctions
 		// then. If 0 is returned, the game functions normally, otherwise all
 		// the animations show up like a slideshow (e.g. in the intro). So we
-		// return 0. However, the behavior changed for kPlatform with no
-		// parameters in SCI32.
+		// return 0.
 		return NULL_REG;
 	}
 
+	if (g_sci->forceHiresGraphics()) {
+		// force Windows platform, so that hires-graphics are enabled
+		isWindows = true;
+	}
+
 	uint16 operation = (argc == 0) ? 0 : argv[0].toUint16();
 
 	switch (operation) {
-	case kPlatformCDSpeed:
-		// TODO: Returns CD Speed?
-		warning("STUB: kPlatform(CDSpeed)");
-		break;
-	case kPlatformColorDepth:
-		// Always returns 2
-		return make_reg(0, /* 256-color */ 2);
-	case kPlatformCDCheck:
-		// TODO: Some sort of CD check?
-		warning("STUB: kPlatform(CDCheck)");
-		break;
-	case kPlatformUnk0:
+	case kPlatformUnknown:
 		// For Mac versions, kPlatform(0) with other args has more functionality
 		if (g_sci->getPlatform() == Common::kPlatformMacintosh && argc > 1)
 			return kMacPlatform(s, argc - 1, argv + 1);
 		// Otherwise, fall through
 	case kPlatformGetPlatform:
 		return make_reg(0, (isWindows) ? kSciPlatformWindows : kSciPlatformDOS);
-	case kPlatformUnk5:
+	case kPlatformUnknown5:
 		// This case needs to return the opposite of case 6 to get hires graphics
-		return make_reg(0, !ConfMan.getBool("enable_high_resolution_graphics"));
+		return make_reg(0, !isWindows);
 	case kPlatformIsHiRes:
-		return make_reg(0, ConfMan.getBool("enable_high_resolution_graphics"));
-	case kPlatformIsItWindows:
+	case kPlatformWin311OrHigher:
 		return make_reg(0, isWindows);
 	default:
 		error("Unsupported kPlatform operation %d", operation);
@@ -599,6 +588,37 @@ reg_t kPlatform(EngineState *s, int argc, reg_t *argv) {
 	return NULL_REG;
 }
 
+#ifdef ENABLE_SCI32
+reg_t kPlatform32(EngineState *s, int argc, reg_t *argv) {
+	enum Operation {
+		kGetPlatform   = 0,
+		kGetCDSpeed    = 1,
+		kGetColorDepth = 2,
+		kGetCDDrive    = 3
+	};
+
+	const Operation operation = argc > 0 ? (Operation)argv[0].toSint16() : kGetPlatform;
+
+	switch (operation) {
+	case kGetPlatform:
+		switch (g_sci->getPlatform()) {
+		case Common::kPlatformDOS:
+			return make_reg(0, kSciPlatformDOS);
+		case Common::kPlatformWindows:
+			return make_reg(0, kSciPlatformWindows);
+		default:
+			error("Unknown platform %d", g_sci->getPlatform());
+		}
+	case kGetColorDepth:
+		return make_reg(0, /* 256 color */ 2);
+	case kGetCDSpeed:
+	case kGetCDDrive:
+	default:
+		return make_reg(0, 0);
+	}
+}
+#endif
+
 reg_t kEmpty(EngineState *s, int argc, reg_t *argv) {
 	// Placeholder for empty kernel functions which are still called from the
 	// engine scripts (like the empty kSetSynonyms function in SCI1.1). This






More information about the Scummvm-git-logs mailing list