[Scummvm-cvs-logs] scummvm master -> 19f90177b72f4b18311cc4cff488c6567434a5fe

csnover csnover at users.noreply.github.com
Sun Jul 10 17:27:45 CEST 2016


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

Summary:
28d4f5b0e4 VIDEO: Expose API for providing a memory location to draw VMDs
4d91b458e5 SCI32: Implement kPlayVMD
b6dbc79021 SCI32: Add support for blacklined video
19f90177b7 SCI32: Clean up Video32/VMDPlayer


Commit: 28d4f5b0e48780dbbee3343d3d41fdd79340a3f4
    https://github.com/scummvm/scummvm/commit/28d4f5b0e48780dbbee3343d3d41fdd79340a3f4
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-07-10T09:35:24-05:00

Commit Message:
VIDEO: Expose API for providing a memory location to draw VMDs

In SSCI, VMD is drawn by a standard CelObjMem wrapped by a
ScreenItem, giving the location of the bitmap memory to the
decoder. The decoder already supports this, but the API was
previously hidden behind the AdvancedVMDDecoder wrapper
(which is more convenient to use than the VMDDecoder class).

Changed paths:
    video/coktel_decoder.cpp
    video/coktel_decoder.h



diff --git a/video/coktel_decoder.cpp b/video/coktel_decoder.cpp
index 21dda15..278dc2d 100644
--- a/video/coktel_decoder.cpp
+++ b/video/coktel_decoder.cpp
@@ -2810,6 +2810,10 @@ void AdvancedVMDDecoder::close() {
 	_decoder->close();
 }
 
+void AdvancedVMDDecoder::setSurfaceMemory(void *mem, uint16 width, uint16 height, uint8 bpp) {
+	_decoder->setSurfaceMemory(mem, width, height, bpp);
+}
+
 AdvancedVMDDecoder::VMDVideoTrack::VMDVideoTrack(VMDDecoder *decoder) : _decoder(decoder) {
 }
 
diff --git a/video/coktel_decoder.h b/video/coktel_decoder.h
index a72f76e..44de1c7 100644
--- a/video/coktel_decoder.h
+++ b/video/coktel_decoder.h
@@ -568,6 +568,8 @@ public:
 	bool loadStream(Common::SeekableReadStream *stream);
 	void close();
 
+	void setSurfaceMemory(void *mem, uint16 width, uint16 height, uint8 bpp);
+
 private:
 	class VMDVideoTrack : public FixedRateVideoTrack {
 	public:


Commit: 4d91b458e53ebda8726055d338da12c05a7879ea
    https://github.com/scummvm/scummvm/commit/4d91b458e53ebda8726055d338da12c05a7879ea
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-07-10T09:35:24-05:00

Commit Message:
SCI32: Implement kPlayVMD

Changed paths:
  A engines/sci/graphics/video32.cpp
  A engines/sci/graphics/video32.h
    engines/sci/engine/kernel.h
    engines/sci/engine/kernel_tables.h
    engines/sci/engine/kvideo.cpp
    engines/sci/engine/state.h
    engines/sci/graphics/controls32.cpp
    engines/sci/graphics/cursor.h
    engines/sci/graphics/frameout.cpp
    engines/sci/graphics/frameout.h
    engines/sci/graphics/paint32.cpp
    engines/sci/graphics/screen_item32.h
    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 d95e228..d49f064 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -441,6 +441,17 @@ reg_t kDoAudioFade(EngineState *s, int argc, reg_t *argv);
 reg_t kDoAudioHasSignal(EngineState *s, int argc, reg_t *argv);
 reg_t kDoAudioSetLoop(EngineState *s, int argc, reg_t *argv);
 
+reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDOpen(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDInit(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDClose(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDPlayUntilEvent(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDShowCursor(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDStartBlob(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDStopBlobs(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDBlack(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDRestrictPalette(EngineState *s, int argc, reg_t *argv);
+
 reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv);
 reg_t kArray(EngineState *s, int argc, reg_t *argv);
 reg_t kListAt(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index dacaafe..6e5add1 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -412,6 +412,22 @@ static const SciKernelMapSubEntry kList_subops[] = {
 	SCI_SUBOPENTRY_TERMINATOR
 };
 
+// There are a lot of subops to PlayVMD, but only a few of them are ever
+// actually used by games
+//    version,         subId, function-mapping,                    signature,              workarounds
+static const SciKernelMapSubEntry kPlayVMD_subops[] = {
+	{ SIG_SINCE_SCI21,     0, MAP_CALL(PlayVMDOpen),               "r(i)(i)",              NULL },
+	{ SIG_SINCE_SCI21,     1, MAP_CALL(PlayVMDInit),               "ii(i)(i)(ii)",         NULL },
+	{ SIG_SINCE_SCI21,     6, MAP_CALL(PlayVMDClose),              "",                     NULL },
+	{ SIG_SINCE_SCI21,    14, MAP_CALL(PlayVMDPlayUntilEvent),     "i(i)(i)",              NULL },
+	{ SIG_SINCE_SCI21,    16, MAP_CALL(PlayVMDShowCursor),         "i",                    NULL },
+	{ SIG_SINCE_SCI21,    17, MAP_DUMMY(PlayVMDStartBlob),         "",                     NULL },
+	{ SIG_SINCE_SCI21,    18, MAP_DUMMY(PlayVMDStopBlobs),         "",                     NULL },
+	{ SIG_SINCE_SCI21,    21, MAP_CALL(PlayVMDBlack),              "iiii",                 NULL },
+	{ SIG_SINCE_SCI21,    23, MAP_CALL(PlayVMDRestrictPalette),    "ii",                   NULL },
+	SCI_SUBOPENTRY_TERMINATOR
+};
+
 //    version,         subId, function-mapping,                    signature,              workarounds
 static const SciKernelMapSubEntry kRemapColors_subops[] = {
 	{ SIG_SCI32,           0, MAP_CALL(RemapColorsOff),            "(i)",                  NULL },
@@ -792,7 +808,7 @@ static SciKernelMapEntry s_kernelMap[] = {
 	{ MAP_CALL(IsOnMe),            SIG_EVERYWHERE,           "iioi",                  NULL,            NULL },
 	{ MAP_CALL(List),              SIG_SINCE_SCI21, SIGFOR_ALL, "(.*)",               kList_subops,    NULL },
 	{ MAP_CALL(MulDiv),            SIG_EVERYWHERE,           "iii",                   NULL,            NULL },
-	{ MAP_CALL(PlayVMD),           SIG_EVERYWHERE,           "(.*)",                  NULL,            NULL },
+	{ MAP_CALL(PlayVMD),           SIG_EVERYWHERE,           "(.*)",                  kPlayVMD_subops, NULL },
 	{ MAP_CALL(Robot),             SIG_EVERYWHERE,           "(.*)",                  NULL,            NULL },
 	{ MAP_CALL(Save),              SIG_EVERYWHERE,           "i(.*)",                 kSave_subops,    NULL },
 	{ MAP_CALL(Text),              SIG_SINCE_SCI21MID, SIGFOR_ALL, "i(.*)",           kText_subops,    NULL },
diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp
index 8db0c54..aa37da6 100644
--- a/engines/sci/engine/kvideo.cpp
+++ b/engines/sci/engine/kvideo.cpp
@@ -40,7 +40,8 @@
 #include "video/qt_decoder.h"
 #include "sci/video/seq_decoder.h"
 #ifdef ENABLE_SCI32
-#include "video/coktel_decoder.h"
+#include "sci/graphics/frameout.h"
+#include "sci/graphics/video32.h"
 #include "sci/video/robot_decoder.h"
 #endif
 
@@ -289,113 +290,83 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) {
 }
 
 reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) {
-	uint16 operation = argv[0].toUint16();
-	Video::VideoDecoder *videoDecoder = 0;
-	bool reshowCursor = g_sci->_gfxCursor->isVisible();
-	Common::String warningMsg;
-
-	switch (operation) {
-	case 0:	// init
-		s->_videoState.reset();
-		s->_videoState.fileName = s->_segMan->derefString(argv[1]);
+	if (!s)
+		return make_reg(0, getSciVersion());
+	error("not supposed to call this");
+}
 
-		if (argc > 2 && argv[2] != NULL_REG)
-			warning("kPlayVMD: third parameter isn't 0 (it's %04x:%04x - %s)", PRINT_REG(argv[2]), s->_segMan->getObjectName(argv[2]));
-		break;
-	case 1:
-	{
-		// Set VMD parameters. Called with a maximum of 6 parameters:
-		//
-		// x, y, flags, gammaBoost, gammaFirst, gammaLast
-		//
-		// gammaBoost boosts palette colors in the range gammaFirst to
-		// gammaLast, but only if bit 4 in flags is set. Percent value such that
-		// 0% = no amplification These three parameters are optional if bit 4 is
-		// clear. Also note that the x, y parameters play subtle games if used
-		// with subfx 21. The subtleness has to do with creation of temporary
-		// planes and positioning relative to such planes.
-
-		uint16 flags = argv[3].getOffset();
-		Common::String flagspec;
-
-		if (argc > 3) {
-			if (flags & kDoubled)
-				flagspec += "doubled ";
-			if (flags & kDropFrames)
-				flagspec += "dropframes ";
-			if (flags & kBlackLines)
-				flagspec += "blacklines ";
-			if (flags & kUnkBit3)
-				flagspec += "bit3 ";
-			if (flags & kGammaBoost)
-				flagspec += "gammaboost ";
-			if (flags & kHoldBlackFrame)
-				flagspec += "holdblack ";
-			if (flags & kHoldLastFrame)
-				flagspec += "holdlast ";
-			if (flags & kUnkBit7)
-				flagspec += "bit7 ";
-			if (flags & kStretch)
-				flagspec += "stretch";
-
-			warning("VMDFlags: %s", flagspec.c_str());
-
-			s->_videoState.flags = flags;
-		}
+reg_t kPlayVMDOpen(EngineState *s, int argc, reg_t *argv) {
+	const Common::String fileName = s->_segMan->getString(argv[0]);
+	// argv[1] is an optional cache size argument which we do not use
+	// const uint16 cacheSize = argc > 1 ? CLIP<int16>(argv[1].toSint16(), 16, 1024) : 0;
+	const VMDPlayer::OpenFlags flags = argc > 2 ? (VMDPlayer::OpenFlags)argv[2].toUint16() : VMDPlayer::kOpenFlagNone;
 
-		warning("x, y: %d, %d", argv[1].getOffset(), argv[2].getOffset());
-		s->_videoState.x = argv[1].getOffset();
-		s->_videoState.y = argv[2].getOffset();
+	return make_reg(0, g_sci->_video32->getVMDPlayer().open(fileName, flags));
+}
 
-		if (argc > 4 && flags & 16)
-			warning("gammaBoost: %d%% between palette entries %d and %d", argv[4].getOffset(), argv[5].getOffset(), argv[6].getOffset());
-		break;
+reg_t kPlayVMDInit(EngineState *s, int argc, reg_t *argv) {
+	const int16 x = argv[0].toSint16();
+	const int16 y = argv[1].toSint16();
+	const VMDPlayer::PlayFlags flags = argc > 2 ? (VMDPlayer::PlayFlags)argv[2].toUint16() : VMDPlayer::kPlayFlagNone;
+	int16 boostPercent;
+	int16 boostStartColor;
+	int16 boostEndColor;
+	if (argc > 5 && (flags & VMDPlayer::kPlayFlagBoost)) {
+		boostPercent = argv[3].toSint16();
+		boostStartColor = argv[4].toSint16();
+		boostEndColor = argv[5].toSint16();
+	} else {
+		boostPercent = 0;
+		boostStartColor = -1;
+		boostEndColor = -1;
 	}
-	case 6:	// Play
-		videoDecoder = new Video::AdvancedVMDDecoder();
 
-		if (s->_videoState.fileName.empty()) {
-			// Happens in Lighthouse
-			warning("kPlayVMD: Empty filename passed");
-			return s->r_acc;
-		}
+	g_sci->_video32->getVMDPlayer().init(x, y, flags, boostPercent, boostStartColor, boostEndColor);
 
-		if (!videoDecoder->loadFile(s->_videoState.fileName)) {
-			warning("Could not open VMD %s", s->_videoState.fileName.c_str());
-			break;
-		}
+	return make_reg(0, 0);
+}
 
-		if (reshowCursor)
-			g_sci->_gfxCursor->kernelHide();
+reg_t kPlayVMDClose(EngineState *s, int argc, reg_t *argv) {
+	return make_reg(0, g_sci->_video32->getVMDPlayer().close());
+}
 
-		playVideo(videoDecoder, s->_videoState);
+reg_t kPlayVMDPlayUntilEvent(EngineState *s, int argc, reg_t *argv) {
+	const VMDPlayer::EventFlags flags = (VMDPlayer::EventFlags)argv[0].toUint16();
+	const int16 lastFrameNo = argc > 1 ? argv[1].toSint16() : -1;
+	const int16 yieldInterval = argc > 2 ? argv[2].toSint16() : -1;
+	return make_reg(0, g_sci->_video32->getVMDPlayer().kernelPlayUntilEvent(flags, lastFrameNo, yieldInterval));
+}
 
-		if (reshowCursor)
-			g_sci->_gfxCursor->kernelShow();
-		break;
-	case 23:	// set video palette range
-		s->_vmdPalStart = argv[1].toUint16();
-		s->_vmdPalEnd = argv[2].toUint16();
-		break;
-	case 14:
-		// Takes an additional integer parameter (e.g. 3)
-	case 16:
-		// Takes an additional parameter, usually 0
-	case 21:
-		// Looks to be setting the video size and position. Called with 4 extra integer
-		// parameters (e.g. 86, 41, 235, 106)
-	default:
-		warningMsg = Common::String::format("PlayVMD - unsupported subop %d. Params: %d (", operation, argc);
+reg_t kPlayVMDShowCursor(EngineState *s, int argc, reg_t *argv) {
+	g_sci->_video32->getVMDPlayer().setShowCursor((bool)argv[0].toUint16());
+	return s->r_acc;
+}
 
-		for (int i = 0; i < argc; i++) {
-			warningMsg +=  Common::String::format("%04x:%04x", PRINT_REG(argv[i]));
-			warningMsg += (i == argc - 1 ? ")" : ", ");
-		}
+reg_t kPlayVMDStartBlob(EngineState *s, int argc, reg_t *argv) {
+	debug("kPlayVMDStartBlob");
+	return s->r_acc;
+}
 
-		warning("%s", warningMsg.c_str());
-		break;
-	}
+reg_t kPlayVMDStopBlobs(EngineState *s, int argc, reg_t *argv) {
+	debug("kPlayVMDStopBlobs");
+	return s->r_acc;
+}
+
+reg_t kPlayVMDBlack(EngineState *s, int argc, reg_t *argv) {
+	const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+	const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+
+	Common::Rect blackoutArea;
+	blackoutArea.left = MAX((int16)0, argv[0].toSint16());
+	blackoutArea.top = MAX((int16)0, argv[1].toSint16());
+	blackoutArea.right = MIN(scriptWidth, (int16)(argv[2].toSint16() + 1));
+	blackoutArea.bottom = MIN(scriptHeight, (int16)(argv[3].toSint16() + 1));
+	g_sci->_video32->getVMDPlayer().setBlackoutArea(blackoutArea);
+	return s->r_acc;
+}
 
+reg_t kPlayVMDRestrictPalette(EngineState *s, int argc, reg_t *argv) {
+	g_sci->_video32->getVMDPlayer().restrictPalette(argv[0].toUint16(), argv[1].toUint16());
 	return s->r_acc;
 }
 
diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h
index baca4a5..dd8d76f 100644
--- a/engines/sci/engine/state.h
+++ b/engines/sci/engine/state.h
@@ -201,6 +201,7 @@ public:
 	uint16 _memorySegmentSize;
 	byte _memorySegment[kMemorySegmentMax];
 
+	// TODO: Excise video code from the state manager
 	VideoState _videoState;
 	uint16 _vmdPalStart, _vmdPalEnd;
 	bool _syncedAudioOptions;
diff --git a/engines/sci/graphics/controls32.cpp b/engines/sci/graphics/controls32.cpp
index 4cbb454..6b91bb4 100644
--- a/engines/sci/graphics/controls32.cpp
+++ b/engines/sci/graphics/controls32.cpp
@@ -459,7 +459,7 @@ void ScrollWindow::hide() {
 		return;
 	}
 
-	g_sci->_gfxFrameout->deleteScreenItem(_screenItem, _plane);
+	g_sci->_gfxFrameout->deleteScreenItem(*_screenItem, _plane);
 	_screenItem = nullptr;
 	g_sci->_gfxFrameout->frameOut(true);
 
diff --git a/engines/sci/graphics/cursor.h b/engines/sci/graphics/cursor.h
index 8d125c4..5125469 100644
--- a/engines/sci/graphics/cursor.h
+++ b/engines/sci/graphics/cursor.h
@@ -25,6 +25,8 @@
 
 #include "common/array.h"
 #include "common/hashmap.h"
+#include "sci/sci.h"
+#include "sci/graphics/helpers.h"
 
 namespace Sci {
 
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index c0feea8..ceab949 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -278,20 +278,52 @@ bool GfxFrameout::checkForFred(const reg_t object) {
 #pragma mark -
 #pragma mark Screen items
 
-void GfxFrameout::deleteScreenItem(ScreenItem *screenItem, Plane *plane) {
-	if (screenItem->_created == 0) {
-		screenItem->_created = 0;
-		screenItem->_updated = 0;
-		screenItem->_deleted = getScreenCount();
+void GfxFrameout::addScreenItem(ScreenItem &screenItem) const {
+	Plane *plane = _planes.findByObject(screenItem._plane);
+	if (plane == nullptr) {
+		error("GfxFrameout::addScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x", PRINT_REG(screenItem._plane), PRINT_REG(screenItem._object));
+	}
+	plane->_screenItemList.add(&screenItem);
+}
+
+void GfxFrameout::updateScreenItem(ScreenItem &screenItem) const {
+	// TODO: In SCI3+ this will need to go through Plane
+//	Plane *plane = _planes.findByObject(screenItem._plane);
+//	if (plane == nullptr) {
+//		error("GfxFrameout::updateScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x", PRINT_REG(screenItem._plane), PRINT_REG(screenItem._object));
+//	}
+
+	screenItem.update();
+}
+
+void GfxFrameout::deleteScreenItem(ScreenItem &screenItem) {
+	Plane *plane = _planes.findByObject(screenItem._plane);
+	if (plane == nullptr) {
+		error("GfxFrameout::deleteScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x", PRINT_REG(screenItem._plane), PRINT_REG(screenItem._object));
+	}
+	if (plane->_screenItemList.findByObject(screenItem._object) == nullptr) {
+		error("GfxFrameout::deleteScreenItem: Screen item %04x:%04x not found in plane %04x:%04x", PRINT_REG(screenItem._object), PRINT_REG(screenItem._plane));
+	}
+	deleteScreenItem(screenItem, *plane);
+}
+
+void GfxFrameout::deleteScreenItem(ScreenItem &screenItem, Plane &plane) {
+	if (screenItem._created == 0) {
+		screenItem._created = 0;
+		screenItem._updated = 0;
+		screenItem._deleted = getScreenCount();
 	} else {
-		plane->_screenItemList.erase(screenItem);
-		plane->_screenItemList.pack();
+		plane._screenItemList.erase(&screenItem);
+		plane._screenItemList.pack();
 	}
 }
 
-void GfxFrameout::deleteScreenItem(ScreenItem *screenItem, const reg_t planeObject) {
+void GfxFrameout::deleteScreenItem(ScreenItem &screenItem, const reg_t planeObject) {
 	Plane *plane = _planes.findByObject(planeObject);
-	deleteScreenItem(screenItem, plane);
+	if (plane == nullptr) {
+		error("GfxFrameout::deleteScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x", PRINT_REG(planeObject), PRINT_REG(screenItem._object));
+	}
+	deleteScreenItem(screenItem, *plane);
 }
 
 void GfxFrameout::kernelAddScreenItem(const reg_t object) {
@@ -364,7 +396,7 @@ void GfxFrameout::kernelDeleteScreenItem(const reg_t object) {
 		return;
 	}
 
-	deleteScreenItem(screenItem, plane);
+	deleteScreenItem(*screenItem, *plane);
 }
 
 #pragma mark -
diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h
index cc62c61..99658ed 100644
--- a/engines/sci/graphics/frameout.h
+++ b/engines/sci/graphics/frameout.h
@@ -202,14 +202,29 @@ private:
 
 public:
 	/**
+	 * Adds a screen item.
+	 */
+	void addScreenItem(ScreenItem &screenItem) const;
+
+	/**
+	 * Updates a screen item.
+	 */
+	void updateScreenItem(ScreenItem &screenItem) const;
+
+	/**
+	 * Deletes a screen item.
+	 */
+	void deleteScreenItem(ScreenItem &screenItem);
+
+	/**
 	 * Deletes a screen item from the given plane.
 	 */
-	void deleteScreenItem(ScreenItem *screenItem, Plane *plane);
+	void deleteScreenItem(ScreenItem &screenItem, Plane &plane);
 
 	/**
 	 * Deletes a screen item from the given plane.
 	 */
-	void deleteScreenItem(ScreenItem *screenItem, const reg_t plane);
+	void deleteScreenItem(ScreenItem &screenItem, const reg_t plane);
 
 	void kernelAddScreenItem(const reg_t object);
 	void kernelUpdateScreenItem(const reg_t object);
diff --git a/engines/sci/graphics/paint32.cpp b/engines/sci/graphics/paint32.cpp
index bfd4648..74eb162 100644
--- a/engines/sci/graphics/paint32.cpp
+++ b/engines/sci/graphics/paint32.cpp
@@ -81,7 +81,7 @@ void GfxPaint32::kernelDeleteLine(const reg_t screenItemObject, const reg_t plan
 	}
 
 	_segMan->freeHunkEntry(screenItem->_celInfo.bitmap);
-	g_sci->_gfxFrameout->deleteScreenItem(screenItem, plane);
+	g_sci->_gfxFrameout->deleteScreenItem(*screenItem, *plane);
 }
 
 void GfxPaint32::plotter(int x, int y, int color, void *data) {
diff --git a/engines/sci/graphics/screen_item32.h b/engines/sci/graphics/screen_item32.h
index caa7a9d..56f858d 100644
--- a/engines/sci/graphics/screen_item32.h
+++ b/engines/sci/graphics/screen_item32.h
@@ -64,12 +64,12 @@ private:
 	 */
 	static uint16 _nextObjectId;
 
+public:
 	/**
 	 * The parent plane of this screen item.
 	 */
 	reg_t _plane;
 
-public:
 	/**
 	 * Scaling data used to calculate the final screen
 	 * dimensions of the screen item as well as the scaling
diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
new file mode 100644
index 0000000..0f0116e
--- /dev/null
+++ b/engines/sci/graphics/video32.cpp
@@ -0,0 +1,365 @@
+/* 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 "audio/mixer.h"
+#include "sci/console.h"
+#include "sci/event.h"
+#include "sci/graphics/cursor.h"
+#include "sci/graphics/frameout.h"
+#include "sci/graphics/palette32.h"
+#include "sci/graphics/text32.h"
+#include "sci/graphics/video32.h"
+#include "sci/sci.h"
+#include "video/coktel_decoder.h"
+
+namespace Sci {
+VMDPlayer::VMDPlayer(SegManager *segMan, EventManager *eventMan) :
+	_segMan(segMan),
+	_eventMan(eventMan),
+	_decoder(new Video::AdvancedVMDDecoder(Audio::Mixer::kSFXSoundType)),
+	_isOpen(false),
+	_isInitialized(false),
+	_startColor(0),
+	_planeSet(false),
+	_endColor(255),
+	_blackLines(false),
+	_doublePixels(false),
+	_lastYieldedFrameNo(0),
+	_blackoutRect(),
+	_blackPalette(false),
+	_boostPercent(100),
+	_boostStartColor(0),
+	_boostEndColor(255),
+	_leaveLastFrame(false),
+	_leaveScreenBlack(false),
+	_plane(nullptr),
+	_screenItem(nullptr),
+	_stretchVertical(false),
+	_priority(0),
+	_blackoutPlane(nullptr),
+	_yieldInterval(0) {}
+
+VMDPlayer::~VMDPlayer() {
+	close();
+	delete _decoder;
+}
+
+VMDPlayer::IOStatus VMDPlayer::open(const Common::String &fileName, const OpenFlags flags) {
+	if (_isOpen) {
+		error("Attempted to play %s, but another VMD was loaded", fileName.c_str());
+	}
+
+	if (_decoder->loadFile(fileName)) {
+		if (flags & kOpenFlagMute) {
+			_decoder->setVolume(0);
+		}
+		_isOpen = true;
+		return kIOSuccess;
+	} else {
+		return kIOError;
+	}
+}
+
+void VMDPlayer::init(const int16 x, const int16 y, const PlayFlags flags, const int16 boostPercent, const int16 boostStartColor, const int16 boostEndColor) {
+	_x = getSciVersion() >= SCI_VERSION_3 ? x : (x & ~1);
+	_y = y;
+	_leaveScreenBlack = flags & kPlayFlagLeaveScreenBlack;
+	_leaveLastFrame = flags & kPlayFlagLeaveLastFrame;
+	_doublePixels = flags & kPlayFlagDoublePixels;
+	_blackLines = flags & kPlayFlagBlackLines;
+	_boostPercent = 100 + (flags & kPlayFlagBoost ? boostPercent : 0);
+	_blackPalette = flags & kPlayFlagBlackPalette;
+	_stretchVertical = flags & kPlayFlagStretchVertical;
+	_boostStartColor = CLIP<int16>(boostStartColor, 0, 255);
+	_boostEndColor = CLIP<int16>(boostEndColor, 0, 255);
+}
+
+void VMDPlayer::restrictPalette(const uint8 startColor, const uint8 endColor) {
+	_startColor = startColor;
+	_endColor = endColor;
+}
+
+VMDPlayer::EventFlags VMDPlayer::kernelPlayUntilEvent(const EventFlags flags, const int16 lastFrameNo, const int16 yieldInterval) {
+	assert(lastFrameNo >= -1);
+
+	const int32 maxFrameNo = (int32)(_decoder->getFrameCount() - 1);
+
+	if ((flags & kEventFlagToFrame) && lastFrameNo > 0) {
+		_decoder->setEndFrame(MIN((int32)lastFrameNo, maxFrameNo));
+	} else {
+		_decoder->setEndFrame(maxFrameNo);
+	}
+
+	if (flags & kEventFlagYieldToVM) {
+		_yieldInterval = 3;
+		if (yieldInterval == -1 && !(flags & kEventFlagToFrame)) {
+			_yieldInterval = lastFrameNo;
+		} else if (yieldInterval != -1) {
+			_yieldInterval = MIN((int32)yieldInterval, maxFrameNo);
+		}
+	} else {
+		_yieldInterval = maxFrameNo;
+	}
+
+	return playUntilEvent(flags);
+}
+
+VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
+	// Flushing all the keyboard and mouse events out of the event manager to
+	// avoid letting any events queued from before the video started from
+	// accidentally activating an event callback
+	for (;;) {
+		const SciEvent event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_MOUSE_PRESS | SCI_EVENT_MOUSE_RELEASE | SCI_EVENT_QUIT);
+		if (event.type == SCI_EVENT_NONE) {
+			break;
+		} else if (event.type == SCI_EVENT_QUIT) {
+			return kEventFlagEnd;
+		}
+	}
+
+	_decoder->pauseVideo(false);
+
+	if (flags & kEventFlagReverse) {
+		// NOTE: This flag may not work properly since SSCI does not care
+		// if a video has audio, but the VMD decoder does.
+		const bool success = _decoder->setReverse(true);
+		assert(success);
+		_decoder->setVolume(0);
+	}
+
+	if (!_isInitialized) {
+		_isInitialized = true;
+
+		if (!_showCursor) {
+			g_sci->_gfxCursor->kernelHide();
+		}
+
+		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;
+
+		Common::Rect vmdRect(
+			_x,
+			_y,
+			_x + _decoder->getWidth(),
+			_y + _decoder->getHeight()
+		);
+		ScaleInfo vmdScaleInfo;
+
+		if (!_blackoutRect.isEmpty() && !_planeSet) {
+			_blackoutPlane = new Plane(_blackoutRect);
+			g_sci->_gfxFrameout->addPlane(*_blackoutPlane);
+		}
+
+		if (_doublePixels) {
+			vmdScaleInfo.x = 256;
+			vmdScaleInfo.y = 256;
+			vmdScaleInfo.signal = kScaleSignalDoScaling32;
+			vmdRect.right += vmdRect.width();
+			vmdRect.bottom += vmdRect.height();
+		} else if (_stretchVertical) {
+			vmdScaleInfo.y = 256;
+			vmdScaleInfo.signal = kScaleSignalDoScaling32;
+			vmdRect.bottom += vmdRect.height();
+		}
+
+		BitmapResource vmdBitmap(_segMan, vmdRect.width(), vmdRect.height(), 255, 0, 0, screenWidth, screenHeight, 0, false);
+
+		if (screenWidth != scriptWidth || screenHeight != scriptHeight) {
+			mulru(vmdRect, Ratio(scriptWidth, screenWidth), Ratio(scriptHeight, screenHeight), 1);
+		}
+
+		CelInfo32 vmdCelInfo;
+		vmdCelInfo.bitmap = vmdBitmap.getObject();
+		_decoder->setSurfaceMemory(vmdBitmap.getPixels(), vmdBitmap.getWidth(), vmdBitmap.getHeight(), 1);
+
+		if (!_planeSet) {
+			_x = 0;
+			_y = 0;
+			_plane = new Plane(vmdRect, kPlanePicColored);
+			if (_priority) {
+				_plane->_priority = _priority;
+			}
+			g_sci->_gfxFrameout->addPlane(*_plane);
+			_screenItem = new ScreenItem(_plane->_object, vmdCelInfo, Common::Point(), vmdScaleInfo);
+		} else {
+			_screenItem = new ScreenItem(_plane->_object, vmdCelInfo, Common::Point(_x, _y), vmdScaleInfo);
+			if (_priority) {
+				_screenItem->_priority = _priority;
+			}
+		}
+
+		// NOTE: There was code for positioning the screen item using insetRect
+		// here, but none of the game scripts seem to use this functionality.
+
+		g_sci->_gfxFrameout->addScreenItem(*_screenItem);
+
+		_decoder->start();
+	}
+
+	EventFlags stopFlag = kEventFlagNone;
+	while (!g_engine->shouldQuit()) {
+		if (_decoder->endOfVideo()) {
+			stopFlag = kEventFlagEnd;
+			break;
+		}
+
+		g_sci->getEngineState()->speedThrottler(_decoder->getTimeToNextFrame());
+		g_sci->getEngineState()->_throttleTrigger = true;
+		if (_decoder->needsUpdate()) {
+			renderFrame();
+		}
+
+		const int currentFrameNo = _decoder->getCurFrame();
+
+		if (
+			_yieldInterval > 0 &&
+			currentFrameNo != _lastYieldedFrameNo &&
+			(currentFrameNo % _yieldInterval) == 0
+		) {
+			_lastYieldedFrameNo = currentFrameNo;
+			stopFlag = kEventFlagYieldToVM;
+			break;
+		}
+
+		if (flags & kEventFlagMouseDown && _eventMan->getSciEvent(SCI_EVENT_MOUSE_PRESS | SCI_EVENT_PEEK).type != SCI_EVENT_NONE) {
+			stopFlag = kEventFlagMouseDown;
+			break;
+		}
+
+		if (flags & kEventFlagEscapeKey) {
+			const SciEvent event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_PEEK);
+			if (event.type != SCI_EVENT_NONE && event.character == SCI_KEY_ESC) {
+				stopFlag = kEventFlagEscapeKey;
+				break;
+			}
+		}
+
+		if (flags & kEventFlagHotRectangle) {
+			// TODO: Hot rectangles
+			warning("Hot rectangles not implemented in VMD player");
+			stopFlag = kEventFlagHotRectangle;
+			break;
+		}
+	}
+
+	_decoder->pauseVideo(true);
+	return stopFlag;
+}
+
+void VMDPlayer::renderFrame() {
+	// TODO: This is kind of different from the original implementation
+	// which has access to dirty rects from the decoder; we probably do
+	// not need to care to limit output this way
+
+	_decoder->decodeNextFrame();
+
+	// NOTE: Normally this would write a hunk palette at the end of the
+	// video bitmap that CelObjMem would read out and submit, but instead
+	// we are just submitting it directly here because the decoder exposes
+	// this information a little bit differently than the one in SSCI
+	const bool dirtyPalette = _decoder->hasDirtyPalette();
+	if (dirtyPalette) {
+		Palette palette;
+		if (_blackPalette) {
+			for (uint16 i = _startColor; i <= _endColor; ++i) {
+				palette.colors[i].r = palette.colors[i].g = palette.colors[i].b = 0;
+				palette.colors[i].used = true;
+			}
+		} else {
+			const byte *vmdPalette = _decoder->getPalette() + _startColor * 3;
+			for (uint16 i = _startColor; i <= _endColor; ++i) {
+				palette.colors[i].r = *vmdPalette++;
+				palette.colors[i].g = *vmdPalette++;
+				palette.colors[i].b = *vmdPalette++;
+				palette.colors[i].used = true;
+			}
+		}
+
+		g_sci->_gfxPalette32->submit(palette);
+		g_sci->_gfxFrameout->updateScreenItem(*_screenItem);
+		g_sci->_gfxFrameout->frameOut(true);
+
+		if (_blackPalette) {
+			const byte *vmdPalette = _decoder->getPalette() + _startColor * 3;
+			for (uint16 i = _startColor; i <= _endColor; ++i) {
+				palette.colors[i].r = *vmdPalette++;
+				palette.colors[i].g = *vmdPalette++;
+				palette.colors[i].b = *vmdPalette++;
+				palette.colors[i].used = true;
+			}
+
+			g_sci->_gfxPalette32->submit(palette);
+			g_sci->_gfxPalette32->updateForFrame();
+			g_sci->_gfxPalette32->updateHardware();
+		}
+	} else {
+		g_sci->_gfxFrameout->updateScreenItem(*_screenItem);
+		g_sci->getSciDebugger()->onFrame();
+		g_sci->_gfxFrameout->frameOut(true);
+		g_sci->_gfxFrameout->throttle();
+	}
+}
+
+VMDPlayer::IOStatus VMDPlayer::close() {
+	if (!_isOpen) {
+		return kIOSuccess;
+	}
+
+	_decoder->close();
+	_isOpen = false;
+	_isInitialized = false;
+
+	if (_planeSet && _screenItem != nullptr) {
+		g_sci->_gfxFrameout->deleteScreenItem(*_screenItem);
+		_screenItem = nullptr;
+	} else if (_plane != nullptr) {
+		g_sci->_gfxFrameout->deletePlane(*_plane);
+		_plane = nullptr;
+	}
+
+	if (!_leaveLastFrame && _leaveScreenBlack) {
+		// This call *actually* deletes the plane/screen item
+		g_sci->_gfxFrameout->frameOut(true);
+	}
+
+	if (_blackoutPlane != nullptr) {
+		g_sci->_gfxFrameout->deletePlane(*_blackoutPlane);
+		_blackoutPlane = nullptr;
+	}
+
+	if (!_leaveLastFrame && !_leaveScreenBlack) {
+		// This call *actually* deletes the blackout plane
+		g_sci->_gfxFrameout->frameOut(true);
+	}
+
+	if (!_showCursor) {
+		g_sci->_gfxCursor->kernelShow();
+	}
+
+	_planeSet = false;
+	_priority = 0;
+	return kIOSuccess;
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/graphics/video32.h b/engines/sci/graphics/video32.h
new file mode 100644
index 0000000..481b222
--- /dev/null
+++ b/engines/sci/graphics/video32.h
@@ -0,0 +1,275 @@
+/* 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_VIDEO32_H
+#define SCI_GRAPHICS_VIDEO32_H
+
+namespace Video { class AdvancedVMDDecoder; }
+namespace Sci {
+class Plane;
+class ScreenItem;
+class SegManager;
+
+class VMDPlayer {
+public:
+	enum OpenFlags {
+		kOpenFlagNone = 0,
+		kOpenFlagMute = 1
+	};
+
+	enum IOStatus {
+		kIOSuccess = 0,
+		kIOError   = 0xFFFF
+	};
+
+	enum PlayFlags {
+		kPlayFlagNone             = 0,
+		kPlayFlagDoublePixels     = 1,
+		kPlayFlagNoFrameskip      = 2, // NOTE: the current VMD decoder does not allow this
+		kPlayFlagBlackLines       = 4,
+		kPlayFlagBoost            = 0x10,
+		kPlayFlagLeaveScreenBlack = 0x20,
+		kPlayFlagLeaveLastFrame   = 0x40,
+		kPlayFlagBlackPalette     = 0x80,
+		kPlayFlagStretchVertical  = 0x100
+	};
+
+	enum EventFlags {
+		kEventFlagNone         = 0,
+		kEventFlagEnd          = 1,
+		kEventFlagEscapeKey    = 2,
+		kEventFlagMouseDown    = 4,
+		kEventFlagHotRectangle = 8,
+		kEventFlagToFrame      = 0x10,
+		kEventFlagYieldToVM    = 0x20,
+		kEventFlagReverse      = 0x80
+	};
+
+	VMDPlayer(SegManager *segMan, EventManager *eventMan);
+	~VMDPlayer();
+
+	/**
+	 * Opens a stream to a VMD resource.
+	 */
+	IOStatus open(const Common::String &fileName, const OpenFlags flags);
+
+	/**
+	 * Initializes the VMD rendering parameters for the
+	 * current VMD. This must be called after `open`.
+	 */
+	void init(const int16 x, const int16 y, const PlayFlags flags, const int16 boostPercent, const int16 boostStartColor, const int16 boostEndColor);
+
+	/**
+	 * Stops playback and closes the currently open VMD stream.
+	 */
+	IOStatus close();
+
+	/**
+	 * Restricts use of the system palette by VMD playback to
+	 * the given range of palette indexes.
+	 */
+	void restrictPalette(const uint8 startColor, const uint8 endColor);
+
+	// NOTE: Was WaitForEvent in SSCI
+	EventFlags kernelPlayUntilEvent(const EventFlags flags, const int16 lastFrameNo, const int16 yieldInterval);
+
+	/**
+	 * Sets the area of the screen that should be blacked out
+	 * during VMD playback.
+	 */
+	void setBlackoutArea(const Common::Rect &rect) { _blackoutRect = rect; }
+
+	/**
+	 * Sets whether or not the mouse cursor should be drawn.
+	 * This does not have any effect during playback, but can
+	 * be used to prevent the mouse cursor from being shown
+	 * after the video has finished.
+	 */
+	void setShowCursor(const bool shouldShow) { _showCursor = shouldShow; }
+
+private:
+	SegManager *_segMan;
+	EventManager *_eventMan;
+	Video::AdvancedVMDDecoder *_decoder;
+
+	/**
+	 * Plays the VMD until an event occurs (e.g. user
+	 * presses escape, clicks, etc.).
+	 */
+	EventFlags playUntilEvent(const EventFlags flags);
+
+	/**
+	 * Renders a frame of video to the output bitmap.
+	 */
+	void renderFrame();
+
+	/**
+	 * Whether or not a VMD stream has been opened with
+	 * `open`.
+	 */
+	bool _isOpen;
+
+	/**
+	 * Whether or not a VMD player has been initialised
+	 * with `init`.
+	 */
+	bool _isInitialized;
+
+	/**
+	 * Whether or not the playback area of the VMD
+	 * should be left black at the end of playback.
+	 */
+	bool _leaveScreenBlack;
+
+	/**
+	 * Whether or not the area of the VMD should be left
+	 * displaying the final frame of the video.
+	 */
+	bool _leaveLastFrame;
+
+	/**
+	 * Whether or not the video should be pixel doubled.
+	 */
+	bool _doublePixels;
+
+	/**
+	 * Whether or not the video should be pixel doubled
+	 * vertically only.
+	 */
+	bool _stretchVertical;
+
+	/**
+	 * Whether or not black lines should be rendered
+	 * across the video.
+	 */
+	bool _blackLines;
+
+	/**
+	 * The amount of brightness boost for the video.
+	 * Values above 100 increase brightness; values below
+	 * 100 reduce it.
+	 */
+	int16 _boostPercent;
+
+	/**
+	 * The first color in the palette that should be
+	 * brightness boosted.
+	 */
+	uint8 _boostStartColor;
+
+	/**
+	 * The last color in the palette that should be
+	 * brightness boosted.
+	 */
+	uint8 _boostEndColor;
+
+	/**
+	 * The first color in the system palette that the VMD
+	 * can write to.
+	 */
+	uint8 _startColor;
+
+	/**
+	 * The last color in the system palette that the VMD
+	 * can write to.
+	 */
+	uint8 _endColor;
+
+	/**
+	 * If true, video frames are rendered after a blank
+	 * palette is submitted to the palette manager,
+	 * which is then restored after the video pixels
+	 * have already been rendered.
+	 */
+	bool _blackPalette;
+
+	// TODO: planeSet and priority are used in SCI3+ only
+	bool _planeSet;
+
+	/**
+	 * The screen priority of the video.
+	 * @see ScreenItem::_priority
+	 */
+	int _priority;
+
+	/**
+	 * The plane where the VMD will be drawn.
+	 */
+	Plane *_plane;
+
+	/**
+	 * The screen item representing the VMD surface.
+	 */
+	ScreenItem *_screenItem;
+
+	/**
+	 * An optional plane that will be used to black out
+	 * areas of the screen outside the area of the VMD
+	 * surface.
+	 */
+	Plane *_blackoutPlane;
+
+	/**
+	 * The dimensions of the blackout plane.
+	 */
+	Common::Rect _blackoutRect;
+
+	/**
+	 * Whether or not the mouse cursor should be shown
+	 * during playback.
+	 */
+	bool _showCursor;
+
+	/**
+	 * The location of the VMD plane, in game script
+	 * coordinates.
+	 */
+	int16 _x, _y;
+
+	/**
+	 * For VMDs played with the `kEventFlagYieldToVM` flag,
+	 * the number of frames that should be drawn until
+	 * yielding back to the SCI VM.
+	 */
+	int32 _yieldInterval;
+
+	/**
+	 * For VMDs played with the `kEventFlagYieldToVM` flag,
+	 * the last frame when control of the main thread was
+	 * yielded back to the SCI VM.
+	 */
+	int _lastYieldedFrameNo;
+};
+
+class Video32 {
+public:
+	Video32(SegManager *segMan, EventManager *eventMan) :
+	_VMDPlayer(segMan, eventMan) {}
+
+	VMDPlayer &getVMDPlayer() { return _VMDPlayer; }
+
+private:
+	VMDPlayer _VMDPlayer;
+};
+} // End of namespace Sci
+
+#endif
diff --git a/engines/sci/module.mk b/engines/sci/module.mk
index 5d54e2a..1511356 100644
--- a/engines/sci/module.mk
+++ b/engines/sci/module.mk
@@ -91,6 +91,7 @@ MODULE_OBJS += \
 	graphics/remap32.o \
 	graphics/screen_item32.o \
 	graphics/text32.o \
+	graphics/video32.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 41fa144..0e63918 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -69,7 +69,9 @@
 #include "sci/graphics/palette32.h"
 #include "sci/graphics/remap32.h"
 #include "sci/graphics/text32.h"
+#include "sci/graphics/video32.h"
 #include "sci/sound/audio32.h"
+// TODO: Move this to video32
 #include "sci/video/robot_decoder.h"
 #endif
 
@@ -92,6 +94,7 @@ SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc, SciGameId gam
 	_sync = nullptr;
 #ifdef ENABLE_SCI32
 	_audio32 = nullptr;
+	_video32 = nullptr;
 #endif
 	_features = 0;
 	_resMan = 0;
@@ -277,15 +280,20 @@ Common::Error SciEngine::run() {
 	if (getGameId() == GID_CHRISTMAS1990)
 		_vocabulary = new Vocabulary(_resMan, false);
 
+	_gamestate = new EngineState(segMan);
+	_eventMan = new EventManager(_resMan->detectFontExtended());
 #ifdef ENABLE_SCI32
 	if (getSciVersion() >= SCI_VERSION_2_1_EARLY) {
 		_audio32 = new Audio32(_resMan);
 	} else
 #endif
 		_audio = new AudioPlayer(_resMan);
+#ifdef ENABLE_SCI32
+	if (getSciVersion() >= SCI_VERSION_2) {
+		_video32 = new Video32(segMan, _eventMan);
+	}
+#endif
 	_sync = new Sync(_resMan, segMan);
-	_gamestate = new EngineState(segMan);
-	_eventMan = new EventManager(_resMan->detectFontExtended());
 
 	// Create debugger console. It requires GFX and _gamestate to be initialized
 	_console = new Console(this);
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index 3216fa1..6481365 100644
--- a/engines/sci/sci.h
+++ b/engines/sci/sci.h
@@ -80,9 +80,11 @@ class GfxText32;
 class GfxTransitions;
 
 #ifdef ENABLE_SCI32
+// TODO: Move RobotDecoder to Video32
 class RobotDecoder;
 class GfxFrameout;
 class Audio32;
+class Video32;
 #endif
 
 // our engine debug levels
@@ -371,6 +373,7 @@ public:
 
 #ifdef ENABLE_SCI32
 	Audio32 *_audio32;
+	Video32 *_video32;
 	RobotDecoder *_robotDecoder;
 	GfxFrameout *_gfxFrameout; // kFrameout and the like for 32-bit gfx
 #endif


Commit: b6dbc79021be137367372faa3b53081e7a332efd
    https://github.com/scummvm/scummvm/commit/b6dbc79021be137367372faa3b53081e7a332efd
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-07-10T09:36:10-05:00

Commit Message:
SCI32: Add support for blacklined video

Ow. My eyeballs.

Changed paths:
    common/gui_options.cpp
    common/gui_options.h
    engines/sci/detection.cpp
    engines/sci/detection_tables.h
    engines/sci/graphics/celobj32.cpp
    engines/sci/graphics/celobj32.h
    engines/sci/graphics/screen_item32.cpp
    engines/sci/graphics/screen_item32.h
    engines/sci/graphics/video32.cpp
    engines/sci/graphics/video32.h



diff --git a/common/gui_options.cpp b/common/gui_options.cpp
index 473f78c..df880f4 100644
--- a/common/gui_options.cpp
+++ b/common/gui_options.cpp
@@ -74,6 +74,7 @@ const struct GameOpt {
 	{ GUIO_GAMEOPTIONS6, "gameOption6" },
 	{ GUIO_GAMEOPTIONS7, "gameOption7" },
 	{ GUIO_GAMEOPTIONS8, "gameOption8" },
+	{ GUIO_GAMEOPTIONS9, "gameOption9" },
 
 	{ GUIO_NONE, 0 }
 };
diff --git a/common/gui_options.h b/common/gui_options.h
index aa15d90..ec3eccd 100644
--- a/common/gui_options.h
+++ b/common/gui_options.h
@@ -68,6 +68,7 @@
 #define GUIO_GAMEOPTIONS6    "\055"
 #define GUIO_GAMEOPTIONS7    "\056"
 #define GUIO_GAMEOPTIONS8    "\057"
+#define GUIO_GAMEOPTIONS9    "\058"
 
 #define GUIO0() (GUIO_NONE)
 #define GUIO1(a) (a)
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index 6b945d6..8d5c923 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -397,6 +397,16 @@ static const ADExtraGuiOptionsMap optionsList[] = {
 	},
 
 	{
+		GAMEOPTION_ENABLE_BLACK_LINED_VIDEO,
+		{
+			_s("Enable black-lined video"),
+			_s("Draw black lines over videos to increase their apparent sharpness"),
+			"enable_black_lined_video",
+			false
+		}
+	},
+
+	{
 		GAMEOPTION_PREFER_DIGITAL_SFX,
 		{
 			_s("Prefer digital sound effects"),
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index 54e8abe..4e90682 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -30,6 +30,7 @@ namespace Sci {
 #define GAMEOPTION_SQ4_SILVER_CURSORS       GUIO_GAMEOPTIONS6
 #define GAMEOPTION_EGA_UNDITHER             GUIO_GAMEOPTIONS7
 #define GAMEOPTION_HIGH_RESOLUTION_GRAPHICS GUIO_GAMEOPTIONS8
+#define GAMEOPTION_ENABLE_BLACK_LINED_VIDEO GUIO_GAMEOPTIONS9
 
 // SCI3 games have a different script format (in CSC files) and are currently unsupported
 #define ENABLE_SCI3_GAMES
@@ -848,7 +849,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.000", 0, "b996fa1e57389a1e179a00a0049de1f4", 8110},
 		{"ressci.000", 0, "a19fc3604c6e5407abcf03d59ee87217", 168522221},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Gabriel Knight 2 - English DOS (from jvprat)
 	// Executable scanning reports "2.100.002", VERSION file reports "1.1"
@@ -866,7 +867,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.006", 0, "ce9359037277b7d7976da185c2fa0aad", 2977},
 		{"ressci.006", 0, "8e44e03890205a7be12f45aaba9644b4", 60659424},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Gabriel Knight 2 - French DOS (6-CDs Sierra Originals reedition)
 	// Executable scanning reports "2.100.002", VERSION file reports "1.0"
@@ -884,7 +885,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.006", 0, "11b2e722170b8c93fdaa5428e2c7676f", 3001},
 		{"ressci.006", 0, "4037d941aec39d2e654e20960429aefc", 60568486},
 		AD_LISTEND},
-		Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Gabriel Knight 2 - English Macintosh
 	// NOTE: This only contains disc 1 files (as well as the persistent file:
@@ -896,7 +897,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"Data4", 0, "8b843c62eb53136a855d6e0087e3cb0d", 5889553},
 		{"Data5", 0, "f9fcf9ab2eb13b2125c33a1cda03a093", 14349984},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+		Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
 
 #endif // ENABLE_SCI32
 
@@ -2512,7 +2513,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.000", 0, "eae93e1b1d1ccc58b4691c371281c95d", 8188},
 		{"ressci.000", 0, "89353723488219e25589165d73ed663e", 66965678},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Larry 7 - German DOS (from Tobis87)
 	// SCI interpreter version 3.000.000
@@ -2520,7 +2521,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.000", 0, "c11e6bfcfc2f2d05da47e5a7df3e9b1a", 8188},
 		{"ressci.000", 0, "a8c6817bb94f332ff498a71c8b47f893", 66971724},
 		AD_LISTEND},
-		Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Larry 7 - French DOS (provided by richiefs in bug report #2670691)
 	// SCI interpreter version 3.000.000
@@ -2528,7 +2529,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.000", 0, "4407849fd52fe3efb0c30fba60cd5cd4", 8206},
 		{"ressci.000", 0, "dc37c3055fffbefb494ff22b145d377b", 66964472},
 		AD_LISTEND},
-		Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Larry 7 - Italian DOS CD (from glorifindel)
 	// SCI interpreter version 3.000.000
@@ -2536,7 +2537,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.000", 0, "9852a97141f789413f29bf956052acdb", 8212},
 		{"ressci.000", 0, "440b9fed89590abb4e4386ed6f948ee2", 67140181},
 		AD_LISTEND},
-		Common::IT_ITA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::IT_ITA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Larry 7 - Spanish DOS (from the Leisure Suit Larry Collection)
 	// Executable scanning reports "3.000.000", VERSION file reports "1.0s"
@@ -2544,7 +2545,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.000", 0, "8f3d603e1acc834a5d598b30cdfc93f3", 8188},
 		{"ressci.000", 0, "32792f9bc1bf3633a88b382bb3f6e40d", 67071418},
 		AD_LISTEND},
-		Common::ES_ESP, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::ES_ESP, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 #endif
 
 	// Lighthouse - English Windows Demo (from jvprat)
@@ -2553,7 +2554,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resource.map", 0, "543124606352bfa5e07696ddf2a669be", 64},
 		{"resource.000", 0, "5d7714416b612463d750fb9c5690c859", 28952},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 #ifdef ENABLE_SCI3_GAMES
 	// Lighthouse - English Windows Demo
@@ -2572,7 +2573,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.002", 0, "c68db5333f152fea6ca2dfc75cad8b34", 7573},
 		{"ressci.002", 0, "175468431a979b9f317c294ce3bc1430", 94628315},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Lighthouse - Japanese DOS (from m_kiewitz)
 	// Executable scanning reports "3.000.000", VERSION file reports "1.0C"
@@ -2582,7 +2583,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.002", 0, "723fc742c623d8933e5753a264324cb0", 7657},
 		{"ressci.002", 0, "175468431a979b9f317c294ce3bc1430", 94627469},
 		AD_LISTEND},
-		Common::JA_JPN, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::JA_JPN, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Lighthouse - Spanish DOS (from jvprat)
 	// Executable scanning reports "3.000.000", VERSION file reports "1.1"
@@ -2592,7 +2593,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.002", 0, "e7dc85884a2417e2eff9de0c63dd65fa", 7630},
 		{"ressci.002", 0, "3c8d627c555b0e3e4f1d9955bc0f0df4", 94631127},
 		AD_LISTEND},
-		Common::ES_ESP, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::ES_ESP, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 #endif	// ENABLE_SCI3_GAMES
 
 #endif // ENABLE_SCI32
@@ -2760,7 +2761,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.007", 0, "aa8175cfc93242af6f5e65bdceaafc0d", 7972},
 		//{"ressci.007", 0, "3aae6559aa1df273bc542d5ac6330d75", 25859038},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Phantasmagoria - English DOS (from jvprat)
 	// Executable scanning reports "2.100.002", VERSION file reports "1.100.000UK"
@@ -2780,7 +2781,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.007", 0, "afbd16ea77869a720afa1c5371de107d", 7972},
 		//{"ressci.007", 0, "3aae6559aa1df273bc542d5ac6330d75", 25859038},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Phantasmagoria - German DOS/Windows
 	// Windows executable scanning reports "unknown" - "Sep 19 1995 09:39:48"
@@ -2803,7 +2804,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.007", 0, "06309b8043aecb85bd507b15d16cb544", 7984},
 		//{"ressci.007", 0, "3aae6559aa1df273bc542d5ac6330d75", 26898681},
 		AD_LISTEND},
-		Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+		Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
 
 	// Phantasmagoria - French DOS
 	// Supplied by Kervala in bug #6574
@@ -2822,7 +2823,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"ressci.006", 0, "3aae6559aa1df273bc542d5ac6330d75", 85415107},
 		{"resmap.007", 0, "5633960bc106c39ca91d2d8fce18fd2d", 7984},
 		AD_LISTEND},
-		Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Phantasmagoria - English DOS Demo
 	// Executable scanning reports "2.100.002"
@@ -2830,7 +2831,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.001", 0, "416138651ea828219ca454cae18341a3", 11518},
 		{"ressci.001", 0, "3aae6559aa1df273bc542d5ac6330d75", 65844612},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Phantasmagoria - English DOS/Windows (GOG version) - ressci.* merged in ressci.000
 	// Windows executable scanning reports "2.100.002" - "Sep 19 1995 15:09:43"
@@ -2841,7 +2842,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"ressci.000", 0, "cd5967f9b9586e3380645961c0765be3", 116822037},
 		{"resmap.000", 0, "3cafc1c6a53945c1f3babbfd6380c64c", 16468},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Phantasmagoria - English Macintosh
 	// NOTE: This only contains disc 1 files (as well as the two persistent files:
@@ -2857,7 +2858,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		// Data8-12 are empty
 		{"Data13", 0, "6d2c450fca19a69b5af74ed5b03c0a17", 14923328},
 		AD_LISTEND},
-	 Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+	 Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
 
 #ifdef ENABLE_SCI3_GAMES
 	// Some versions of Phantasmagoria 2 were heavily censored.
@@ -2879,7 +2880,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.005", 0, "8bd5ceeedcbe16dfe55d1b90dcd4be84", 1942},
 		{"ressci.005", 0, "05f9fe2bee749659acb3cd2c90252fc5", 67905112},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Phantasmagoria 2 - English DOS (GOG version) (supplied by littleboy in patch #1360)
 	// Note: Fully uncensored, basically the US release, but ressci.* merged into ressci.000
@@ -2890,7 +2891,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"ressci.000", 0, "c54f26d9f43f908151263254b6d97053", 108134481},
 		{"resmap.000", 0, "de154a223a9ef4ea7358b76adc38ef5b", 2956},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Phantasmagoria 2 - German DOS/Windows (supplied by AReim1982)
 	// Note: Fully uncensored, but one scene is missing probably because of a mastering error (Curtis + Therese meeting near water cooler)
@@ -2910,7 +2911,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.005", 0, "2fc48a4a5a73b726994f189da51a8b2a", 1954},
 		{"ressci.005", 0, "e94005890d22dd3b7f605a2a7c025803", 68232146},
 		AD_LISTEND},
-		Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+		Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
 #endif	// ENABLE_SCI3_GAMES
 
 #endif // ENABLE_SCI32
@@ -3196,7 +3197,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.000", 0, "1c2563fee189885e29d9348f37306d94", 12175},
 		{"ressci.000", 0, "b2e1826ca81ce2e7e764587f5a14eee9", 127149181},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Police Quest: SWAT - English Windows (from the Police Quest Collection)
 	// Executable scanning reports "2.100.002", VERSION file reports "1.0c"
@@ -3211,7 +3212,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.004", 0, "4228038906f041623e65789500b22285", 6835},
 		{"ressci.004", 0, "b7e619e6ecf62fe65d5116a3a422e5f0", 46223872},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 #endif // ENABLE_SCI32
 
 	// Quest for Glory 1 / Hero's Quest - English DOS 3.5" Floppy (supplied by merkur in bug report #2718784)
@@ -3607,7 +3608,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.001", 0, "775304e9b2a545156be4d94209550094", 1393},
 		{"ressci.001", 0, "259437fd75fdf51e8207fda8c01fa4fd", 2334384},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 #ifdef ENABLE_SCI3_GAMES
 	// RAMA - English Windows (from jvprat)
@@ -3620,7 +3621,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.003", 0, "31ef4c0621711585d031f0ae81707251", 1636},
 		{"ressci.003", 0, "2a68edd064e5e4937b5e9c74b38f2082", 6860492},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// RAMA - English Windows (from Quietust, in bug report #2850645)
 	{"rama", "", {
@@ -3631,7 +3632,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.003", 0, "48841e4b84ef1b98b48d43566fda9e13", 1636},
 		{"ressci.003", 0, "2a68edd064e5e4937b5e9c74b38f2082", 6870356},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// RAMA - German Windows CD (from farmboy0, in pull request 397)
 	{"rama", "", {
@@ -3642,7 +3643,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.003", 0, "222096000bd83a1d56577114a452cccf", 1636},
 		{"ressci.003", 0, "2a68edd064e5e4937b5e9c74b38f2082", 6954219},
 		AD_LISTEND},
-		Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// RAMA - Italian Windows CD (from glorifindel)
 	// SCI interpreter version 3.000.000 (a guess?)
@@ -3650,7 +3651,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"ressci.001", 0, "2a68edd064e5e4937b5e9c74b38f2082", 70611091},
 		{"resmap.001", 0, "70ba2ff04a2b7fb2c52420ba7fbd47c2", 8338},
 		AD_LISTEND},
-		Common::IT_ITA, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::IT_ITA, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 #endif	// ENABLE_SCI3_GAMES
 
 	// Shivers - English Windows (from jvprat)
@@ -3659,14 +3660,14 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.000", 0, "f2ead37749ed8f6535a2445a7d05a0cc", 46525},
 		{"ressci.000", 0, "4294c6d7510935f2e0a52e302073c951", 262654836},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Shivers - German Windows (from Tobis87)
 	{"shivers", "", {
 		{"resmap.000", 0, "f483d0a1f78334c18052e92785c3086e", 46537},
 		{"ressci.000", 0, "6751b144671e2deed919eb9d284b07eb", 262390692},
 		AD_LISTEND},
-		Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Shivers - English Windows Demo
 	// Executable scanning reports "2.100.002"
@@ -3692,7 +3693,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.000", 0, "d8659188b84beaef076bd869837cd530", 634},
 		{"ressci.000", 0, "7fbac0807a044c9543e8ac376d200e59", 4925003},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Shivers 2 - English Windows (from abevi)
 	// VERSION.TXT Version 1.0 (3/25/97)
@@ -3700,7 +3701,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"ressci.001", 0, "a79d03d6eb75be0a79324f14e3d2ace4", 95346793},
 		{"resmap.001", 0, "a4804d436d90c4ec2e46b537f5e954db", 6268},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 #endif
 
@@ -4238,7 +4239,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resource.map", 0, "6dddfa3a8f3a3a513ec9dfdfae955005", 10528},
 		{"resource.000", 0, "c4259ab7355aead07773397b1052827d", 41150806},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Space Quest 6 - English DOS/Win3.11 CD ver 1.11 (from FRG)
 	// SCI interpreter version 2.100.002 (just a guess)
@@ -4246,7 +4247,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resource.map", 0, "e0615d6e4e10e37ae42e6a2a95aaf145", 10528},
 		{"resource.000", 0, "c4259ab7355aead07773397b1052827d", 41150806},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Space Quest 6 - French DOS/Win3.11 CD (from French magazine Joystick - September 1997)
 	// Executable scanning reports "2.100.002", VERSION file reports "1.0"
@@ -4254,7 +4255,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resource.map", 0, "3c831625931d5079b73ae8c275f52c95", 10534},
 		{"resource.000", 0, "4195ca940f759424f62b90e262cc1737", 40932397},
 		AD_LISTEND},
-		Common::FR_FRA, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::FR_FRA, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Space Quest 6 - German DOS (from Tobis87, updated info from markcoolio in bug report #2723884)
 	// SCI interpreter version 2.100.002 (just a guess)
@@ -4262,7 +4263,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resource.map", 0, "664d797415484f85c90b1b45aedc7686", 10534},
 		{"resource.000", 0, "ba87ba91e5bdabb4169dd0df75777722", 40933685},
 		AD_LISTEND},
-		Common::DE_DEU, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::DE_DEU, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Space Quest 6 - English DOS/Win3.11 Interactive Demo (from FRG)
 	// SCI interpreter version 2.100.002 (just a guess)
@@ -4321,7 +4322,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
 		// TODO: depend on one of the patches?
 		AD_LISTEND},
-		Common::ES_ESP, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::ES_ESP, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Torin's Passage (Multilingual) - French Windows CD
 	// SCI interpreter version 2.100.002
@@ -4329,7 +4330,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799},
 		{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
 		AD_LISTEND},
-		Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Torin's Passage - German Windows CD (from m_kiewitz)
 	// SCI interpreter version 2.100.002
@@ -4338,7 +4339,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.000", 0, "e55c3097329b3c53752301e01c6af2fb", 9787},
 		{"ressci.000", 0, "118f9bec04bfe17c4f87bbb5ddb43c18", 56127540},
 		AD_LISTEND},
-		Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Torin's Passage (Multilingual) - German Windows CD
 	// SCI interpreter version 2.100.002
@@ -4346,7 +4347,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799},
 		{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
 		AD_LISTEND},
-		Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Torin's Passage (Multilingual) - Italian Windows CD (from glorifindel)
 	// SCI interpreter version 2.100.002
@@ -4354,7 +4355,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799},
 		{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
 		AD_LISTEND},
-		Common::IT_ITA, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::IT_ITA, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Torin's Passage - French Windows (from LePhilousophe)
 	// SCI interpreter version 2.100.002
@@ -4362,7 +4363,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"resmap.000", 0, "66ed46e3e56f487e688d52f05b33d0ba", 9787},
 		{"ressci.000", 0, "118f9bec04bfe17c4f87bbb5ddb43c18", 56126981},
 		AD_LISTEND},
-		Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
+		Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	},
 
 	// Torin's Passage - Russian Windows CD (SoftClub official translate)
 	// SCI interpreter version 2.100.002
@@ -4372,7 +4373,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{ "ressci.000", 0, "e672da099fb1663b87c78abc6c8ba2a4", 130622695 },
 		{ "resmap.000", 0, "643859f8f2be8e7701611e29b3b65208", 9799 },
 	AD_LISTEND },
-	Common::RU_RUS, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+	Common::RU_RUS, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
 
 	// Torin's Passage - English Macintosh
 	{"torin", "", {
@@ -4384,7 +4385,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 		{"Data6", 0, "b639487c83d1dae0e001e700f3631566", 7594881},
 		{"Data7", 0, "2afd9b5434102b89610916b904c3f73a", 7627374},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+		Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE | ADGF_CD, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
 #endif // ENABLE_SCI32
 
 	// SCI Fanmade Games
diff --git a/engines/sci/graphics/celobj32.cpp b/engines/sci/graphics/celobj32.cpp
index f8cd5fd..da41879 100644
--- a/engines/sci/graphics/celobj32.cpp
+++ b/engines/sci/graphics/celobj32.cpp
@@ -83,9 +83,11 @@ const CelScalerTable *CelScaler::getScalerTable(const Ratio &scaleX, const Ratio
 
 #pragma mark -
 #pragma mark CelObj
+bool CelObj::_drawBlackLines = false;
 
 void CelObj::init() {
 	CelObj::deinit();
+	_drawBlackLines = false;
 	_nextCacheId = 1;
 	_scaler = new CelScaler();
 	_cache = new CelCache;
@@ -407,6 +409,7 @@ void CelObj::draw(Buffer &target, const ScreenItem &screenItem, const Common::Re
 	const Common::Point &scaledPosition = screenItem._scaledPosition;
 	const Ratio &scaleX = screenItem._ratioX;
 	const Ratio &scaleY = screenItem._ratioY;
+	_drawBlackLines = screenItem._drawBlackLines;
 
 	if (_remap) {
 		// NOTE: In the original code this check was `g_Remap_numActiveRemaps && _remap`,
@@ -488,6 +491,8 @@ void CelObj::draw(Buffer &target, const ScreenItem &screenItem, const Common::Re
 			}
 		}
 	}
+
+	_drawBlackLines = false;
 }
 
 void CelObj::draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect, bool mirrorX) {
@@ -627,7 +632,7 @@ void CelObj::putCopyInCache(const int cacheIndex) const {
 #pragma mark -
 #pragma mark CelObj - Drawing
 
-template<typename MAPPER, typename SCALER>
+template<typename MAPPER, typename SCALER, bool DRAW_BLACK_LINES>
 struct RENDERER {
 	MAPPER &_mapper;
 	SCALER &_scaler;
@@ -645,6 +650,12 @@ struct RENDERER {
 		const int16 targetWidth = targetRect.width();
 		const int16 targetHeight = targetRect.height();
 		for (int16 y = 0; y < targetHeight; ++y) {
+			if (DRAW_BLACK_LINES && (y % 2) == 0) {
+				memset(targetPixel, 0, targetWidth);
+				targetPixel += targetWidth + skipStride;
+				continue;
+			}
+
 			_scaler.setTarget(targetRect.left, targetRect.top + y);
 
 			for (int16 x = 0; x < targetWidth; ++x) {
@@ -661,7 +672,7 @@ void CelObj::render(Buffer &target, const Common::Rect &targetRect, const Common
 
 	MAPPER mapper;
 	SCALER scaler(*this, targetRect.left - scaledPosition.x + targetRect.width(), scaledPosition);
-	RENDERER<MAPPER, SCALER> renderer(mapper, scaler, _transparentColor);
+	RENDERER<MAPPER, SCALER, false> renderer(mapper, scaler, _transparentColor);
 	renderer.draw(target, targetRect, scaledPosition);
 }
 
@@ -670,8 +681,13 @@ void CelObj::render(Buffer &target, const Common::Rect &targetRect, const Common
 
 	MAPPER mapper;
 	SCALER scaler(*this, targetRect, scaledPosition, scaleX, scaleY);
-	RENDERER<MAPPER, SCALER> renderer(mapper, scaler, _transparentColor);
-	renderer.draw(target, targetRect, scaledPosition);
+	if (_drawBlackLines) {
+		RENDERER<MAPPER, SCALER, true> renderer(mapper, scaler, _transparentColor);
+		renderer.draw(target, targetRect, scaledPosition);
+	} else {
+		RENDERER<MAPPER, SCALER, false> renderer(mapper, scaler, _transparentColor);
+		renderer.draw(target, targetRect, scaledPosition);
+	}
 }
 
 void dummyFill(Buffer &target, const Common::Rect &targetRect) {
diff --git a/engines/sci/graphics/celobj32.h b/engines/sci/graphics/celobj32.h
index e405592..eb6ce3a 100644
--- a/engines/sci/graphics/celobj32.h
+++ b/engines/sci/graphics/celobj32.h
@@ -228,6 +228,18 @@ class ScreenItem;
 class CelObj {
 protected:
 	/**
+	 * When true, every second line of the cel will be
+	 * rendered as a black line.
+	 *
+	 * @see ScreenItem::_drawBlackLines
+	 * @note Using a static member because otherwise this
+	 * would otherwise need to be copied down through
+	 * several calls. (SSCI did similar, using a global
+	 * variable.)
+	 */
+	static bool _drawBlackLines;
+
+	/**
 	 * When true, this cel will be horizontally mirrored
 	 * when it is drawn. This is an internal flag that is
 	 * set by draw methods based on the combination of the
diff --git a/engines/sci/graphics/screen_item32.cpp b/engines/sci/graphics/screen_item32.cpp
index ebaf132..7383dc2 100644
--- a/engines/sci/graphics/screen_item32.cpp
+++ b/engines/sci/graphics/screen_item32.cpp
@@ -42,7 +42,8 @@ _pictureId(-1),
 _created(g_sci->_gfxFrameout->getScreenCount()),
 _updated(0),
 _deleted(0),
-_mirrorX(false) {
+_mirrorX(false),
+_drawBlackLines(false) {
 	SegManager *segMan = g_sci->getEngineState()->_segMan;
 
 	setFromObject(segMan, object, true, true);
@@ -62,7 +63,8 @@ _pictureId(-1),
 _created(g_sci->_gfxFrameout->getScreenCount()),
 _updated(0),
 _deleted(0),
-_mirrorX(false) {}
+_mirrorX(false),
+_drawBlackLines(false) {}
 
 ScreenItem::ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Rect &rect) :
 _plane(plane),
@@ -77,7 +79,8 @@ _pictureId(-1),
 _created(g_sci->_gfxFrameout->getScreenCount()),
 _updated(0),
 _deleted(0),
-_mirrorX(false) {
+_mirrorX(false),
+_drawBlackLines(false) {
 	if (celInfo.type == kCelTypeColor) {
 		_insetRect = rect;
 	}
@@ -97,7 +100,8 @@ _pictureId(-1),
 _created(g_sci->_gfxFrameout->getScreenCount()),
 _updated(0),
 _deleted(0),
-_mirrorX(false) {}
+_mirrorX(false),
+_drawBlackLines(false) {}
 
 ScreenItem::ScreenItem(const ScreenItem &other) :
 _plane(other._plane),
@@ -108,7 +112,8 @@ _celObj(nullptr),
 _object(other._object),
 _mirrorX(other._mirrorX),
 _scaledPosition(other._scaledPosition),
-_screenRect(other._screenRect) {
+_screenRect(other._screenRect),
+_drawBlackLines(other._drawBlackLines) {
 	if (other._useInsetRect) {
 		_insetRect = other._insetRect;
 	}
@@ -134,6 +139,7 @@ void ScreenItem::operator=(const ScreenItem &other) {
 	}
 	_scale = other._scale;
 	_scaledPosition = other._scaledPosition;
+	_drawBlackLines = other._drawBlackLines;
 }
 
 ScreenItem::~ScreenItem() {
diff --git a/engines/sci/graphics/screen_item32.h b/engines/sci/graphics/screen_item32.h
index 56f858d..3d9d5ef 100644
--- a/engines/sci/graphics/screen_item32.h
+++ b/engines/sci/graphics/screen_item32.h
@@ -180,7 +180,7 @@ public:
 	 *   plane is a pic type and its picture resource ID has
 	 *   changed
 	 */
-	int _created, _updated, _deleted; // ?
+	int _created, _updated, _deleted;
 
 	/**
 	 * For screen items that represent picture cels, this
@@ -214,6 +214,14 @@ public:
 	Common::Rect _screenRect;
 
 	/**
+	 * Whether or not the screen item should be drawn
+	 * with black lines drawn every second line. This is
+	 * used when pixel doubling videos to improve apparent
+	 * sharpness at the cost of your eyesight.
+	 */
+	bool _drawBlackLines;
+
+	/**
 	 * Initialises static Plane members.
 	 */
 	static void init();
diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index 0f0116e..86ff82a 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "audio/mixer.h"
+#include "common/config-manager.h"
 #include "sci/console.h"
 #include "sci/event.h"
 #include "sci/graphics/cursor.h"
@@ -85,7 +86,7 @@ void VMDPlayer::init(const int16 x, const int16 y, const PlayFlags flags, const
 	_leaveScreenBlack = flags & kPlayFlagLeaveScreenBlack;
 	_leaveLastFrame = flags & kPlayFlagLeaveLastFrame;
 	_doublePixels = flags & kPlayFlagDoublePixels;
-	_blackLines = flags & kPlayFlagBlackLines;
+	_blackLines = ConfMan.getBool("enable_black_lined_video") && (flags & kPlayFlagBlackLines);
 	_boostPercent = 100 + (flags & kPlayFlagBoost ? boostPercent : 0);
 	_blackPalette = flags & kPlayFlagBlackPalette;
 	_stretchVertical = flags & kPlayFlagStretchVertical;
@@ -209,6 +210,10 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
 			}
 		}
 
+		if (_blackLines) {
+			_screenItem->_drawBlackLines = true;
+		}
+
 		// NOTE: There was code for positioning the screen item using insetRect
 		// here, but none of the game scripts seem to use this functionality.
 
@@ -267,11 +272,29 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
 	return stopFlag;
 }
 
-void VMDPlayer::renderFrame() {
-	// TODO: This is kind of different from the original implementation
-	// which has access to dirty rects from the decoder; we probably do
-	// not need to care to limit output this way
+void VMDPlayer::fillPalette(Palette &palette) const {
+	const byte *vmdPalette = _decoder->getPalette() + _startColor * 3;
+	for (uint16 i = _startColor; i <= _endColor; ++i) {
+		int16 r = *vmdPalette++;
+		int16 g = *vmdPalette++;
+		int16 b = *vmdPalette++;
+
+		if (_boostPercent != 100 && i >= _boostStartColor && i <= _boostEndColor) {
+			r = CLIP<int16>(r * _boostPercent / 100, 0, 255);
+			g = CLIP<int16>(g * _boostPercent / 100, 0, 255);
+			b = CLIP<int16>(b * _boostPercent / 100, 0, 255);
+		}
 
+		palette.colors[i].r = r;
+		palette.colors[i].g = g;
+		palette.colors[i].b = b;
+		palette.colors[i].used = true;
+	}
+}
+
+void VMDPlayer::renderFrame() const {
+	// This writes directly to the CelObjMem we already created,
+	// so no need to take its return value
 	_decoder->decodeNextFrame();
 
 	// NOTE: Normally this would write a hunk palette at the end of the
@@ -287,13 +310,7 @@ void VMDPlayer::renderFrame() {
 				palette.colors[i].used = true;
 			}
 		} else {
-			const byte *vmdPalette = _decoder->getPalette() + _startColor * 3;
-			for (uint16 i = _startColor; i <= _endColor; ++i) {
-				palette.colors[i].r = *vmdPalette++;
-				palette.colors[i].g = *vmdPalette++;
-				palette.colors[i].b = *vmdPalette++;
-				palette.colors[i].used = true;
-			}
+			fillPalette(palette);
 		}
 
 		g_sci->_gfxPalette32->submit(palette);
@@ -301,14 +318,7 @@ void VMDPlayer::renderFrame() {
 		g_sci->_gfxFrameout->frameOut(true);
 
 		if (_blackPalette) {
-			const byte *vmdPalette = _decoder->getPalette() + _startColor * 3;
-			for (uint16 i = _startColor; i <= _endColor; ++i) {
-				palette.colors[i].r = *vmdPalette++;
-				palette.colors[i].g = *vmdPalette++;
-				palette.colors[i].b = *vmdPalette++;
-				palette.colors[i].used = true;
-			}
-
+			fillPalette(palette);
 			g_sci->_gfxPalette32->submit(palette);
 			g_sci->_gfxPalette32->updateForFrame();
 			g_sci->_gfxPalette32->updateHardware();
diff --git a/engines/sci/graphics/video32.h b/engines/sci/graphics/video32.h
index 481b222..d51316b 100644
--- a/engines/sci/graphics/video32.h
+++ b/engines/sci/graphics/video32.h
@@ -120,7 +120,14 @@ private:
 	/**
 	 * Renders a frame of video to the output bitmap.
 	 */
-	void renderFrame();
+	void renderFrame() const;
+
+	/**
+	 * Fills the given palette with RGB values from
+	 * the VMD palette, applying brightness boost if
+	 * it is enabled.
+	 */
+	void fillPalette(Palette &palette) const;
 
 	/**
 	 * Whether or not a VMD stream has been opened with


Commit: 19f90177b72f4b18311cc4cff488c6567434a5fe
    https://github.com/scummvm/scummvm/commit/19f90177b72f4b18311cc4cff488c6567434a5fe
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-07-10T10:18:30-05:00

Commit Message:
SCI32: Clean up Video32/VMDPlayer

Changed paths:
    engines/sci/engine/kernel.h
    engines/sci/engine/kernel_tables.h
    engines/sci/engine/kvideo.cpp
    engines/sci/graphics/video32.cpp
    engines/sci/graphics/video32.h



diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index d49f064..845e63a 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -447,9 +447,7 @@ reg_t kPlayVMDInit(EngineState *s, int argc, reg_t *argv);
 reg_t kPlayVMDClose(EngineState *s, int argc, reg_t *argv);
 reg_t kPlayVMDPlayUntilEvent(EngineState *s, int argc, reg_t *argv);
 reg_t kPlayVMDShowCursor(EngineState *s, int argc, reg_t *argv);
-reg_t kPlayVMDStartBlob(EngineState *s, int argc, reg_t *argv);
-reg_t kPlayVMDStopBlobs(EngineState *s, int argc, reg_t *argv);
-reg_t kPlayVMDBlack(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDSetBlackoutArea(EngineState *s, int argc, reg_t *argv);
 reg_t kPlayVMDRestrictPalette(EngineState *s, int argc, reg_t *argv);
 
 reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 6e5add1..31a9938 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -423,7 +423,7 @@ static const SciKernelMapSubEntry kPlayVMD_subops[] = {
 	{ SIG_SINCE_SCI21,    16, MAP_CALL(PlayVMDShowCursor),         "i",                    NULL },
 	{ SIG_SINCE_SCI21,    17, MAP_DUMMY(PlayVMDStartBlob),         "",                     NULL },
 	{ SIG_SINCE_SCI21,    18, MAP_DUMMY(PlayVMDStopBlobs),         "",                     NULL },
-	{ SIG_SINCE_SCI21,    21, MAP_CALL(PlayVMDBlack),              "iiii",                 NULL },
+	{ SIG_SINCE_SCI21,    21, MAP_CALL(PlayVMDSetBlackoutArea),    "iiii",                 NULL },
 	{ SIG_SINCE_SCI21,    23, MAP_CALL(PlayVMDRestrictPalette),    "ii",                   NULL },
 	SCI_SUBOPENTRY_TERMINATOR
 };
diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp
index aa37da6..1096e78 100644
--- a/engines/sci/engine/kvideo.cpp
+++ b/engines/sci/engine/kvideo.cpp
@@ -342,17 +342,7 @@ reg_t kPlayVMDShowCursor(EngineState *s, int argc, reg_t *argv) {
 	return s->r_acc;
 }
 
-reg_t kPlayVMDStartBlob(EngineState *s, int argc, reg_t *argv) {
-	debug("kPlayVMDStartBlob");
-	return s->r_acc;
-}
-
-reg_t kPlayVMDStopBlobs(EngineState *s, int argc, reg_t *argv) {
-	debug("kPlayVMDStopBlobs");
-	return s->r_acc;
-}
-
-reg_t kPlayVMDBlack(EngineState *s, int argc, reg_t *argv) {
+reg_t kPlayVMDSetBlackoutArea(EngineState *s, int argc, reg_t *argv) {
 	const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
 	const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
 
diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index 86ff82a..dfddac1 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -33,37 +33,49 @@
 #include "video/coktel_decoder.h"
 
 namespace Sci {
+
+#pragma mark VMDPlayer
+
 VMDPlayer::VMDPlayer(SegManager *segMan, EventManager *eventMan) :
 	_segMan(segMan),
 	_eventMan(eventMan),
 	_decoder(new Video::AdvancedVMDDecoder(Audio::Mixer::kSFXSoundType)),
+
 	_isOpen(false),
 	_isInitialized(false),
+	_yieldInterval(0),
+	_lastYieldedFrameNo(0),
+
+	_plane(nullptr),
+	_screenItem(nullptr),
+	_planeIsOwned(true),
+	_priority(0),
+	_doublePixels(false),
+	_stretchVertical(false),
+	_blackLines(false),
+	_leaveScreenBlack(false),
+	_leaveLastFrame(false),
+
+	_blackoutPlane(nullptr),
+
 	_startColor(0),
-	_planeSet(false),
 	_endColor(255),
-	_blackLines(false),
-	_doublePixels(false),
-	_lastYieldedFrameNo(0),
-	_blackoutRect(),
 	_blackPalette(false),
+
 	_boostPercent(100),
 	_boostStartColor(0),
 	_boostEndColor(255),
-	_leaveLastFrame(false),
-	_leaveScreenBlack(false),
-	_plane(nullptr),
-	_screenItem(nullptr),
-	_stretchVertical(false),
-	_priority(0),
-	_blackoutPlane(nullptr),
-	_yieldInterval(0) {}
+
+	_showCursor(false) {}
 
 VMDPlayer::~VMDPlayer() {
 	close();
 	delete _decoder;
 }
 
+#pragma mark -
+#pragma mark VMDPlayer - Playback
+
 VMDPlayer::IOStatus VMDPlayer::open(const Common::String &fileName, const OpenFlags flags) {
 	if (_isOpen) {
 		error("Attempted to play %s, but another VMD was loaded", fileName.c_str());
@@ -83,20 +95,57 @@ VMDPlayer::IOStatus VMDPlayer::open(const Common::String &fileName, const OpenFl
 void VMDPlayer::init(const int16 x, const int16 y, const PlayFlags flags, const int16 boostPercent, const int16 boostStartColor, const int16 boostEndColor) {
 	_x = getSciVersion() >= SCI_VERSION_3 ? x : (x & ~1);
 	_y = y;
-	_leaveScreenBlack = flags & kPlayFlagLeaveScreenBlack;
-	_leaveLastFrame = flags & kPlayFlagLeaveLastFrame;
 	_doublePixels = flags & kPlayFlagDoublePixels;
 	_blackLines = ConfMan.getBool("enable_black_lined_video") && (flags & kPlayFlagBlackLines);
 	_boostPercent = 100 + (flags & kPlayFlagBoost ? boostPercent : 0);
-	_blackPalette = flags & kPlayFlagBlackPalette;
-	_stretchVertical = flags & kPlayFlagStretchVertical;
 	_boostStartColor = CLIP<int16>(boostStartColor, 0, 255);
 	_boostEndColor = CLIP<int16>(boostEndColor, 0, 255);
+	_leaveScreenBlack = flags & kPlayFlagLeaveScreenBlack;
+	_leaveLastFrame = flags & kPlayFlagLeaveLastFrame;
+	_blackPalette = flags & kPlayFlagBlackPalette;
+	_stretchVertical = flags & kPlayFlagStretchVertical;
 }
 
-void VMDPlayer::restrictPalette(const uint8 startColor, const uint8 endColor) {
-	_startColor = startColor;
-	_endColor = endColor;
+VMDPlayer::IOStatus VMDPlayer::close() {
+	if (!_isOpen) {
+		return kIOSuccess;
+	}
+
+	_decoder->close();
+	_isOpen = false;
+	_isInitialized = false;
+
+	if (!_planeIsOwned && _screenItem != nullptr) {
+		g_sci->_gfxFrameout->deleteScreenItem(*_screenItem);
+		_screenItem = nullptr;
+	} else if (_plane != nullptr) {
+		g_sci->_gfxFrameout->deletePlane(*_plane);
+		_plane = nullptr;
+	}
+
+	if (!_leaveLastFrame && _leaveScreenBlack) {
+		// This call *actually* deletes the plane/screen item
+		g_sci->_gfxFrameout->frameOut(true);
+	}
+
+	if (_blackoutPlane != nullptr) {
+		g_sci->_gfxFrameout->deletePlane(*_blackoutPlane);
+		_blackoutPlane = nullptr;
+	}
+
+	if (!_leaveLastFrame && !_leaveScreenBlack) {
+		// This call *actually* deletes the blackout plane
+		g_sci->_gfxFrameout->frameOut(true);
+	}
+
+	if (!_showCursor) {
+		g_sci->_gfxCursor->kernelShow();
+	}
+
+	_lastYieldedFrameNo = 0;
+	_planeIsOwned = true;
+	_priority = 0;
+	return kIOSuccess;
 }
 
 VMDPlayer::EventFlags VMDPlayer::kernelPlayUntilEvent(const EventFlags flags, const int16 lastFrameNo, const int16 yieldInterval) {
@@ -154,20 +203,13 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
 			g_sci->_gfxCursor->kernelHide();
 		}
 
-		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;
-
-		Common::Rect vmdRect(
-			_x,
-			_y,
-			_x + _decoder->getWidth(),
-			_y + _decoder->getHeight()
-		);
+		Common::Rect vmdRect(_x,
+							 _y,
+							 _x + _decoder->getWidth(),
+							 _y + _decoder->getHeight());
 		ScaleInfo vmdScaleInfo;
 
-		if (!_blackoutRect.isEmpty() && !_planeSet) {
+		if (!_blackoutRect.isEmpty() && _planeIsOwned) {
 			_blackoutPlane = new Plane(_blackoutRect);
 			g_sci->_gfxFrameout->addPlane(*_blackoutPlane);
 		}
@@ -184,6 +226,11 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
 			vmdRect.bottom += vmdRect.height();
 		}
 
+		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;
+
 		BitmapResource vmdBitmap(_segMan, vmdRect.width(), vmdRect.height(), 255, 0, 0, screenWidth, screenHeight, 0, false);
 
 		if (screenWidth != scriptWidth || screenHeight != scriptHeight) {
@@ -194,7 +241,7 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
 		vmdCelInfo.bitmap = vmdBitmap.getObject();
 		_decoder->setSurfaceMemory(vmdBitmap.getPixels(), vmdBitmap.getWidth(), vmdBitmap.getHeight(), 1);
 
-		if (!_planeSet) {
+		if (_planeIsOwned) {
 			_x = 0;
 			_y = 0;
 			_plane = new Plane(vmdRect, kPlanePicColored);
@@ -237,8 +284,7 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
 
 		const int currentFrameNo = _decoder->getCurFrame();
 
-		if (
-			_yieldInterval > 0 &&
+		if (_yieldInterval > 0 &&
 			currentFrameNo != _lastYieldedFrameNo &&
 			(currentFrameNo % _yieldInterval) == 0
 		) {
@@ -247,21 +293,35 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
 			break;
 		}
 
-		if (flags & kEventFlagMouseDown && _eventMan->getSciEvent(SCI_EVENT_MOUSE_PRESS | SCI_EVENT_PEEK).type != SCI_EVENT_NONE) {
+		SciEvent event = _eventMan->getSciEvent(SCI_EVENT_MOUSE_PRESS | SCI_EVENT_PEEK);
+		if ((flags & kEventFlagMouseDown) && event.type == SCI_EVENT_MOUSE_PRESS) {
 			stopFlag = kEventFlagMouseDown;
 			break;
 		}
 
-		if (flags & kEventFlagEscapeKey) {
-			const SciEvent event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_PEEK);
-			if (event.type != SCI_EVENT_NONE && event.character == SCI_KEY_ESC) {
+		event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_PEEK);
+		if ((flags & kEventFlagEscapeKey) && event.type == SCI_EVENT_KEYBOARD) {
+			bool stop = false;
+			if (getSciVersion() < SCI_VERSION_3) {
+				while ((event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD)),
+					   event.type != SCI_EVENT_NONE) {
+					if (event.character == SCI_KEY_ESC) {
+						stop = true;
+						break;
+					}
+				}
+			} else {
+				stop = (event.character == SCI_KEY_ESC);
+			}
+
+			if (stop) {
 				stopFlag = kEventFlagEscapeKey;
 				break;
 			}
 		}
 
-		if (flags & kEventFlagHotRectangle) {
-			// TODO: Hot rectangles
+		// TODO: Hot rectangles
+		if ((flags & kEventFlagHotRectangle) /* && event.type == SCI_EVENT_HOT_RECTANGLE */) {
 			warning("Hot rectangles not implemented in VMD player");
 			stopFlag = kEventFlagHotRectangle;
 			break;
@@ -272,25 +332,8 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
 	return stopFlag;
 }
 
-void VMDPlayer::fillPalette(Palette &palette) const {
-	const byte *vmdPalette = _decoder->getPalette() + _startColor * 3;
-	for (uint16 i = _startColor; i <= _endColor; ++i) {
-		int16 r = *vmdPalette++;
-		int16 g = *vmdPalette++;
-		int16 b = *vmdPalette++;
-
-		if (_boostPercent != 100 && i >= _boostStartColor && i <= _boostEndColor) {
-			r = CLIP<int16>(r * _boostPercent / 100, 0, 255);
-			g = CLIP<int16>(g * _boostPercent / 100, 0, 255);
-			b = CLIP<int16>(b * _boostPercent / 100, 0, 255);
-		}
-
-		palette.colors[i].r = r;
-		palette.colors[i].g = g;
-		palette.colors[i].b = b;
-		palette.colors[i].used = true;
-	}
-}
+#pragma mark -
+#pragma mark VMDPlayer - Rendering
 
 void VMDPlayer::renderFrame() const {
 	// This writes directly to the CelObjMem we already created,
@@ -304,6 +347,7 @@ void VMDPlayer::renderFrame() const {
 	const bool dirtyPalette = _decoder->hasDirtyPalette();
 	if (dirtyPalette) {
 		Palette palette;
+		palette.timestamp = g_sci->getTickCount();
 		if (_blackPalette) {
 			for (uint16 i = _startColor; i <= _endColor; ++i) {
 				palette.colors[i].r = palette.colors[i].g = palette.colors[i].b = 0;
@@ -331,45 +375,32 @@ void VMDPlayer::renderFrame() const {
 	}
 }
 
-VMDPlayer::IOStatus VMDPlayer::close() {
-	if (!_isOpen) {
-		return kIOSuccess;
-	}
-
-	_decoder->close();
-	_isOpen = false;
-	_isInitialized = false;
-
-	if (_planeSet && _screenItem != nullptr) {
-		g_sci->_gfxFrameout->deleteScreenItem(*_screenItem);
-		_screenItem = nullptr;
-	} else if (_plane != nullptr) {
-		g_sci->_gfxFrameout->deletePlane(*_plane);
-		_plane = nullptr;
-	}
-
-	if (!_leaveLastFrame && _leaveScreenBlack) {
-		// This call *actually* deletes the plane/screen item
-		g_sci->_gfxFrameout->frameOut(true);
-	}
+void VMDPlayer::fillPalette(Palette &palette) const {
+	const byte *vmdPalette = _decoder->getPalette() + _startColor * 3;
+	for (uint16 i = _startColor; i <= _endColor; ++i) {
+		int16 r = *vmdPalette++;
+		int16 g = *vmdPalette++;
+		int16 b = *vmdPalette++;
 
-	if (_blackoutPlane != nullptr) {
-		g_sci->_gfxFrameout->deletePlane(*_blackoutPlane);
-		_blackoutPlane = nullptr;
-	}
+		if (_boostPercent != 100 && i >= _boostStartColor && i <= _boostEndColor) {
+			r = CLIP<int16>(r * _boostPercent / 100, 0, 255);
+			g = CLIP<int16>(g * _boostPercent / 100, 0, 255);
+			b = CLIP<int16>(b * _boostPercent / 100, 0, 255);
+		}
 
-	if (!_leaveLastFrame && !_leaveScreenBlack) {
-		// This call *actually* deletes the blackout plane
-		g_sci->_gfxFrameout->frameOut(true);
+		palette.colors[i].r = r;
+		palette.colors[i].g = g;
+		palette.colors[i].b = b;
+		palette.colors[i].used = true;
 	}
+}
 
-	if (!_showCursor) {
-		g_sci->_gfxCursor->kernelShow();
-	}
+#pragma mark -
+#pragma mark VMDPlayer - Palette
 
-	_planeSet = false;
-	_priority = 0;
-	return kIOSuccess;
+void VMDPlayer::restrictPalette(const uint8 startColor, const uint8 endColor) {
+	_startColor = startColor;
+	_endColor = endColor;
 }
 
 } // End of namespace Sci
diff --git a/engines/sci/graphics/video32.h b/engines/sci/graphics/video32.h
index d51316b..cf863ba 100644
--- a/engines/sci/graphics/video32.h
+++ b/engines/sci/graphics/video32.h
@@ -29,6 +29,11 @@ class Plane;
 class ScreenItem;
 class SegManager;
 
+#pragma mark VMDPlayer
+
+/**
+ * VMDPlayer is used to play VMD videos.
+ */
 class VMDPlayer {
 public:
 	enum OpenFlags {
@@ -44,7 +49,6 @@ public:
 	enum PlayFlags {
 		kPlayFlagNone             = 0,
 		kPlayFlagDoublePixels     = 1,
-		kPlayFlagNoFrameskip      = 2, // NOTE: the current VMD decoder does not allow this
 		kPlayFlagBlackLines       = 4,
 		kPlayFlagBoost            = 0x10,
 		kPlayFlagLeaveScreenBlack = 0x20,
@@ -67,6 +71,14 @@ public:
 	VMDPlayer(SegManager *segMan, EventManager *eventMan);
 	~VMDPlayer();
 
+private:
+	SegManager *_segMan;
+	EventManager *_eventMan;
+	Video::AdvancedVMDDecoder *_decoder;
+
+#pragma mark -
+#pragma mark VMDPlayer - Playback
+public:
 	/**
 	 * Opens a stream to a VMD resource.
 	 */
@@ -83,33 +95,35 @@ public:
 	 */
 	IOStatus close();
 
-	/**
-	 * Restricts use of the system palette by VMD playback to
-	 * the given range of palette indexes.
-	 */
-	void restrictPalette(const uint8 startColor, const uint8 endColor);
-
 	// NOTE: Was WaitForEvent in SSCI
 	EventFlags kernelPlayUntilEvent(const EventFlags flags, const int16 lastFrameNo, const int16 yieldInterval);
 
+private:
 	/**
-	 * Sets the area of the screen that should be blacked out
-	 * during VMD playback.
+	 * Whether or not a VMD stream has been opened with
+	 * `open`.
 	 */
-	void setBlackoutArea(const Common::Rect &rect) { _blackoutRect = rect; }
+	bool _isOpen;
 
 	/**
-	 * Sets whether or not the mouse cursor should be drawn.
-	 * This does not have any effect during playback, but can
-	 * be used to prevent the mouse cursor from being shown
-	 * after the video has finished.
+	 * Whether or not a VMD player has been initialised
+	 * with `init`.
 	 */
-	void setShowCursor(const bool shouldShow) { _showCursor = shouldShow; }
+	bool _isInitialized;
 
-private:
-	SegManager *_segMan;
-	EventManager *_eventMan;
-	Video::AdvancedVMDDecoder *_decoder;
+	/**
+	 * For VMDs played with the `kEventFlagYieldToVM` flag,
+	 * the number of frames that should be rendered until
+	 * yielding back to the SCI VM.
+	 */
+	int32 _yieldInterval;
+
+	/**
+	 * For VMDs played with the `kEventFlagYieldToVM` flag,
+	 * the last frame when control of the main thread was
+	 * yielded back to the SCI VM.
+	 */
+	int _lastYieldedFrameNo;
 
 	/**
 	 * Plays the VMD until an event occurs (e.g. user
@@ -117,41 +131,38 @@ private:
 	 */
 	EventFlags playUntilEvent(const EventFlags flags);
 
+#pragma mark -
+#pragma mark VMDPlayer - Rendering
+private:
 	/**
-	 * Renders a frame of video to the output bitmap.
+	 * The location of the VMD plane, in game script
+	 * coordinates.
 	 */
-	void renderFrame() const;
+	int16 _x, _y;
 
 	/**
-	 * Fills the given palette with RGB values from
-	 * the VMD palette, applying brightness boost if
-	 * it is enabled.
+	 * The plane where the VMD will be drawn.
 	 */
-	void fillPalette(Palette &palette) const;
+	Plane *_plane;
 
 	/**
-	 * Whether or not a VMD stream has been opened with
-	 * `open`.
+	 * The screen item representing the VMD surface.
 	 */
-	bool _isOpen;
+	ScreenItem *_screenItem;
 
-	/**
-	 * Whether or not a VMD player has been initialised
-	 * with `init`.
-	 */
-	bool _isInitialized;
+	// TODO: planeIsOwned and priority are used in SCI3+ only
 
 	/**
-	 * Whether or not the playback area of the VMD
-	 * should be left black at the end of playback.
+	 * If true, the plane for this VMD was set
+	 * externally and is not owned by this VMDPlayer.
 	 */
-	bool _leaveScreenBlack;
+	bool _planeIsOwned;
 
 	/**
-	 * Whether or not the area of the VMD should be left
-	 * displaying the final frame of the video.
+	 * The screen priority of the video.
+	 * @see ScreenItem::_priority
 	 */
-	bool _leaveLastFrame;
+	int _priority;
 
 	/**
 	 * Whether or not the video should be pixel doubled.
@@ -171,24 +182,60 @@ private:
 	bool _blackLines;
 
 	/**
-	 * The amount of brightness boost for the video.
-	 * Values above 100 increase brightness; values below
-	 * 100 reduce it.
+	 * Whether or not the playback area of the VMD
+	 * should be left black at the end of playback.
 	 */
-	int16 _boostPercent;
+	bool _leaveScreenBlack;
 
 	/**
-	 * The first color in the palette that should be
-	 * brightness boosted.
+	 * Whether or not the area of the VMD should be left
+	 * displaying the final frame of the video.
 	 */
-	uint8 _boostStartColor;
+	bool _leaveLastFrame;
 
 	/**
-	 * The last color in the palette that should be
-	 * brightness boosted.
+	 * Renders a frame of video to the output bitmap.
 	 */
-	uint8 _boostEndColor;
+	void renderFrame() const;
+
+	/**
+	 * Fills the given palette with RGB values from
+	 * the VMD palette, applying brightness boost if
+	 * it is enabled.
+	 */
+	void fillPalette(Palette &palette) const;
+
+#pragma mark -
+#pragma mark VMDPlayer - Blackout
+public:
+	/**
+	 * Sets the area of the screen that should be blacked out
+	 * during VMD playback.
+	 */
+	void setBlackoutArea(const Common::Rect &rect) { _blackoutRect = rect; }
+
+private:
+	/**
+	 * The dimensions of the blackout plane.
+	 */
+	Common::Rect _blackoutRect;
+
+	/**
+	 * An optional plane that will be used to black out
+	 * areas of the screen outside of the VMD surface.
+	 */
+	Plane *_blackoutPlane;
+
+#pragma mark -
+#pragma mark VMDPlayer - Palette
+public:
+	/**
+	 * Restricts use of the system palette by VMD playback to
+	 * the given range of palette indexes.
+	 */
+	void restrictPalette(const uint8 startColor, const uint8 endColor);
 
+private:
 	/**
 	 * The first color in the system palette that the VMD
 	 * can write to.
@@ -209,62 +256,45 @@ private:
 	 */
 	bool _blackPalette;
 
-	// TODO: planeSet and priority are used in SCI3+ only
-	bool _planeSet;
-
-	/**
-	 * The screen priority of the video.
-	 * @see ScreenItem::_priority
-	 */
-	int _priority;
-
+#pragma mark -
+#pragma mark VMDPlayer - Brightness boost
+private:
 	/**
-	 * The plane where the VMD will be drawn.
+	 * The amount of brightness boost for the video.
+	 * Values above 100 increase brightness; values below
+	 * 100 reduce it.
 	 */
-	Plane *_plane;
+	int16 _boostPercent;
 
 	/**
-	 * The screen item representing the VMD surface.
+	 * The first color in the palette that should be
+	 * brightness boosted.
 	 */
-	ScreenItem *_screenItem;
+	uint8 _boostStartColor;
 
 	/**
-	 * An optional plane that will be used to black out
-	 * areas of the screen outside the area of the VMD
-	 * surface.
+	 * The last color in the palette that should be
+	 * brightness boosted.
 	 */
-	Plane *_blackoutPlane;
+	uint8 _boostEndColor;
 
+#pragma mark -
+#pragma mark VMDPlayer - Mouse cursor
+public:
 	/**
-	 * The dimensions of the blackout plane.
+	 * Sets whether or not the mouse cursor should be drawn.
+	 * This does not have any effect during playback, but can
+	 * be used to prevent the mouse cursor from being shown
+	 * again after the video has finished.
 	 */
-	Common::Rect _blackoutRect;
+	void setShowCursor(const bool shouldShow) { _showCursor = shouldShow; }
 
+private:
 	/**
 	 * Whether or not the mouse cursor should be shown
 	 * during playback.
 	 */
 	bool _showCursor;
-
-	/**
-	 * The location of the VMD plane, in game script
-	 * coordinates.
-	 */
-	int16 _x, _y;
-
-	/**
-	 * For VMDs played with the `kEventFlagYieldToVM` flag,
-	 * the number of frames that should be drawn until
-	 * yielding back to the SCI VM.
-	 */
-	int32 _yieldInterval;
-
-	/**
-	 * For VMDs played with the `kEventFlagYieldToVM` flag,
-	 * the last frame when control of the main thread was
-	 * yielded back to the SCI VM.
-	 */
-	int _lastYieldedFrameNo;
 };
 
 class Video32 {






More information about the Scummvm-git-logs mailing list