[Scummvm-cvs-logs] scummvm master -> c8affb54cca259f37522216bad739be085bf9caa

csnover csnover at users.noreply.github.com
Fri Aug 12 03:50:43 CEST 2016


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

Summary:
c28a5733e0 SCI32: Fix GfxFrameout::_isHiRes flag to be accurate for all games
13297c1929 SCI32: Implement kShowMovie
4ff0924e57 SCI32: Additional Video32 documentation
cdab24aa07 SCI32: Fix KQ7 1.51 basic video playback
93b06f4a9e SCI32: Fix crash when kShowMovie is called but the video cannot be found
c8affb54cc SCI32: Fix KQ7 1.51 video background


Commit: c28a5733e0911f071f02f3d14aec0dfe53f1aa05
    https://github.com/scummvm/scummvm/commit/c28a5733e0911f071f02f3d14aec0dfe53f1aa05
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-11T20:50:33-05:00

Commit Message:
SCI32: Fix GfxFrameout::_isHiRes flag to be accurate for all games

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



diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index 1decfa0..21ffb5f 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -56,7 +56,7 @@
 namespace Sci {
 
 GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxScreen *screen, GfxPalette32 *palette, GfxTransitions32 *transitions) :
-	_isHiRes(false),
+	_isHiRes(ConfMan.getBool("enable_high_resolution_graphics")),
 	_palette(palette),
 	_resMan(resMan),
 	_screen(screen),
@@ -75,13 +75,9 @@ GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAd
 
 	_currentBuffer.setPixels(calloc(1, screen->getDisplayWidth() * screen->getDisplayHeight()));
 
-	// TODO: Make hires detection work uniformly across all SCI engine
-	// versions (this flag is normally passed by SCI::MakeGraphicsMgr
-	// to the GraphicsMgr constructor depending upon video configuration,
-	// so should be handled upstream based on game configuration instead
-	// of here)
-	if (getSciVersion() >= SCI_VERSION_2_1_EARLY && _resMan->detectHires()) {
-		_isHiRes = true;
+	// QFG4 is the only SCI32 game that doesn't have a high-resolution toggle
+	if (g_sci->getGameId() == GID_QFG4) {
+		_isHiRes = false;
 	}
 
 	switch (g_sci->getGameId()) {
diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h
index 42f1d80..012ecf9 100644
--- a/engines/sci/graphics/frameout.h
+++ b/engines/sci/graphics/frameout.h
@@ -41,7 +41,6 @@ struct PlaneShowStyle;
  */
 class GfxFrameout {
 private:
-	bool _isHiRes;
 	GfxCoordAdjuster32 *_coordAdjuster;
 	GfxPalette32 *_palette;
 	ResourceManager *_resMan;
@@ -309,6 +308,8 @@ private:
 	}
 
 public:
+	bool _isHiRes;
+
 	/**
 	 * Whether palMorphFrameOut should be used instead of
 	 * frameOut for rendering. Used by kMorphOn to


Commit: 13297c19298c5ad73c9e996c5c31ca91de124911
    https://github.com/scummvm/scummvm/commit/13297c19298c5ad73c9e996c5c31ca91de124911
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-11T20:50:33-05:00

Commit Message:
SCI32: Implement kShowMovie

Changed paths:
    engines/sci/engine/kernel.h
    engines/sci/engine/kernel_tables.h
    engines/sci/engine/kmisc.cpp
    engines/sci/engine/kvideo.cpp
    engines/sci/engine/vm.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 5ff4f93..b02a7e5 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -450,6 +450,17 @@ reg_t kPlayVMDShowCursor(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 kShowMovie32(EngineState *s, int argc, reg_t *argv);
+reg_t kShowMovieWin(EngineState *s, int argc, reg_t *argv);
+reg_t kShowMovieWinOpen(EngineState *s, int argc, reg_t *argv);
+reg_t kShowMovieWinInit(EngineState *s, int argc, reg_t *argv);
+reg_t kShowMovieWinPlay(EngineState *s, int argc, reg_t *argv);
+reg_t kShowMovieWinClose(EngineState *s, int argc, reg_t *argv);
+reg_t kShowMovieWinCue(EngineState *s, int argc, reg_t *argv);
+reg_t kShowMovieWinGetDuration(EngineState *s, int argc, reg_t *argv);
+reg_t kShowMovieWinPlayUntilEvent(EngineState *s, int argc, reg_t *argv);
+reg_t kShowMovieWinInitDouble(EngineState *s, int argc, reg_t *argv);
+
 reg_t 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 e0e4dcc..76c24b0 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -423,6 +423,27 @@ static const SciKernelMapSubEntry kList_subops[] = {
 	SCI_SUBOPENTRY_TERMINATOR
 };
 
+//    version,         subId, function-mapping,                    signature,              workarounds
+static const SciKernelMapSubEntry kShowMovieWin_subops[] = {
+	{ SIG_SCI2,            0, MAP_CALL(ShowMovieWinOpen),          "r",                    NULL },
+	{ SIG_SCI2,            1, MAP_CALL(ShowMovieWinInit),          "ii(ii)",               NULL },
+	{ SIG_SCI2,            2, MAP_CALL(ShowMovieWinPlay),          "i",                    NULL },
+	{ SIG_SCI2,            6, MAP_CALL(ShowMovieWinClose),         "",                     NULL },
+	{ SIG_SINCE_SCI21,     0, MAP_CALL(ShowMovieWinOpen),          "ir",                   NULL },
+	{ SIG_SINCE_SCI21,     1, MAP_CALL(ShowMovieWinInit),          "iii(ii)",              NULL },
+	{ SIG_SINCE_SCI21,     2, MAP_CALL(ShowMovieWinPlay),          "i(ii)(i)(i)",          NULL },
+	{ SIG_SINCE_SCI21,     6, MAP_CALL(ShowMovieWinClose),         "i",                    NULL },
+	// Since movies are rendered within the graphics engine in ScummVM,
+	// it is not necessary to copy the palette from SCI to MCI, so this
+	// can be a no-op
+	{ SIG_SINCE_SCI21,     7, MAP_EMPTY(ShowMovieWinSetPalette),   "i",                    NULL },
+	{ SIG_SINCE_SCI21,     8, MAP_CALL(ShowMovieWinGetDuration),   "i",                    NULL },
+	{ SIG_SINCE_SCI21,    11, MAP_CALL(ShowMovieWinCue),           "ii",                   NULL },
+	{ SIG_SINCE_SCI21,    14, MAP_CALL(ShowMovieWinPlayUntilEvent), "i(i)",                NULL },
+	{ SIG_SINCE_SCI21,    15, MAP_CALL(ShowMovieWinInitDouble),    "iii",                  NULL },
+	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
@@ -688,7 +709,11 @@ static SciKernelMapEntry s_kernelMap[] = {
 	{ MAP_CALL(SetSynonyms),       SIG_EVERYWHERE,           "o",                     NULL,            NULL },
 	{ MAP_CALL(SetVideoMode),      SIG_EVERYWHERE,           "i",                     NULL,            NULL },
 	{ MAP_CALL(ShakeScreen),       SIG_EVERYWHERE,           "(i)(i)",                NULL,            NULL },
-	{ MAP_CALL(ShowMovie),         SIG_EVERYWHERE,           "(.*)",                  NULL,            NULL },
+	{ MAP_CALL(ShowMovie),         SIG_SCI16, SIGFOR_ALL,    "(.*)",                  NULL,            NULL },
+#ifdef ENABLE_SCI32
+	{ "ShowMovie", kShowMovie32,   SIG_SCI32, SIGFOR_DOS,    "ri(i)(i)",              NULL,            NULL },
+	{ "ShowMovie", kShowMovieWin,  SIG_SCI32, SIGFOR_WIN,    "(.*)",                  kShowMovieWin_subops, NULL },
+#endif
 	{ MAP_CALL(Show),              SIG_EVERYWHERE,           "i",                     NULL,            NULL },
 	{ MAP_CALL(SinDiv),            SIG_EVERYWHERE,           "ii",                    NULL,            NULL },
 	{ MAP_CALL(Sort),              SIG_EVERYWHERE,           "ooo",                   NULL,            NULL },
@@ -820,7 +845,7 @@ static SciKernelMapEntry s_kernelMap[] = {
 	{ MAP_CALL(List),              SIG_SINCE_SCI21, SIGFOR_ALL, "(.*)",               kList_subops,    NULL },
 	{ MAP_CALL(MulDiv),            SIG_EVERYWHERE,           "iii",                   NULL,            NULL },
 	{ MAP_CALL(PlayVMD),           SIG_EVERYWHERE,           "(.*)",                  kPlayVMD_subops, NULL },
-	{ MAP_CALL(Robot),             SIG_EVERYWHERE,           "(.*)",                  NULL,            NULL },
+	{ MAP_EMPTY(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 },
 	{ MAP_CALL(AddPicAt),          SIG_EVERYWHERE,           "oiii(i)(i)",            NULL,            NULL },
diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index 1924848..c995409 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -20,6 +20,7 @@
  *
  */
 
+#include "common/config-manager.h"
 #include "common/system.h"
 
 #include "sci/sci.h"
@@ -542,7 +543,7 @@ enum kSciPlatforms {
 enum kPlatformOps {
 	kPlatformUnk0 = 0,
 	kPlatformCDSpeed = 1,
-	kPlatformUnk2 = 2,
+	kPlatformColorDepth = 2,
 	kPlatformCDCheck = 3,
 	kPlatformGetPlatform = 4,
 	kPlatformUnk5 = 5,
@@ -563,11 +564,6 @@ reg_t kPlatform(EngineState *s, int argc, reg_t *argv) {
 		return NULL_REG;
 	}
 
-	if (g_sci->forceHiresGraphics()) {
-		// force Windows platform, so that hires-graphics are enabled
-		isWindows = true;
-	}
-
 	uint16 operation = (argc == 0) ? 0 : argv[0].toUint16();
 
 	switch (operation) {
@@ -575,9 +571,9 @@ reg_t kPlatform(EngineState *s, int argc, reg_t *argv) {
 		// TODO: Returns CD Speed?
 		warning("STUB: kPlatform(CDSpeed)");
 		break;
-	case kPlatformUnk2:
+	case kPlatformColorDepth:
 		// Always returns 2
-		return make_reg(0, 2);
+		return make_reg(0, /* 256-color */ 2);
 	case kPlatformCDCheck:
 		// TODO: Some sort of CD check?
 		warning("STUB: kPlatform(CDCheck)");
@@ -591,9 +587,9 @@ reg_t kPlatform(EngineState *s, int argc, reg_t *argv) {
 		return make_reg(0, (isWindows) ? kSciPlatformWindows : kSciPlatformDOS);
 	case kPlatformUnk5:
 		// This case needs to return the opposite of case 6 to get hires graphics
-		return make_reg(0, !isWindows);
+		return make_reg(0, !ConfMan.getBool("enable_high_resolution_graphics"));
 	case kPlatformIsHiRes:
-		return make_reg(0, isWindows);
+		return make_reg(0, ConfMan.getBool("enable_high_resolution_graphics"));
 	case kPlatformIsItWindows:
 		return make_reg(0, isWindows);
 	default:
diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp
index de4d4a2..86d8a4b 100644
--- a/engines/sci/engine/kvideo.cpp
+++ b/engines/sci/engine/kvideo.cpp
@@ -61,33 +61,15 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) {
 	uint16 screenWidth = g_sci->_gfxScreen->getDisplayWidth();
 	uint16 screenHeight = g_sci->_gfxScreen->getDisplayHeight();
 
-	videoState.fileName.toLowercase();
-	bool isVMD = videoState.fileName.hasSuffix(".vmd");
-
-	if (screenWidth == 640 && width <= 320 && height <= 240 && ((videoState.flags & kDoubled) || !isVMD)) {
+	if (screenWidth == 640 && width <= 320 && height <= 240) {
 		width *= 2;
 		height *= 2;
 		pitch *= 2;
 		scaleBuffer = new byte[width * height * bytesPerPixel];
 	}
 
-	uint16 x, y;
-
-	// Sanity check...
-	if (videoState.x > 0 && videoState.y > 0 && isVMD) {
-		x = videoState.x;
-		y = videoState.y;
-
-		if (x + width > screenWidth || y + height > screenHeight) {
-			// Happens in the Lighthouse demo
-			warning("VMD video won't fit on screen, centering it instead");
-			x = (screenWidth - width) / 2;
-			y = (screenHeight - height) / 2;
-		}
-	} else {
-		x = (screenWidth - width) / 2;
-		y = (screenHeight - height) / 2;
-	}
+	uint16 x = (screenWidth - width) / 2;
+	uint16 y = (screenHeight - height) / 2;
 
 	bool skipVideo = false;
 	EngineState *s = g_sci->getEngineState();
@@ -181,16 +163,6 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
 		// TODO: This appears to be some sort of subop. case 0 contains the string
 		// for the video, so we'll just play it from there for now.
 
-#ifdef ENABLE_SCI32
-		if (getSciVersion() >= SCI_VERSION_2_1_EARLY) {
-			// SCI2.1 always has argv[0] as 1, the rest of the arguments seem to
-			// follow SCI1.1/2.
-			if (argv[0].toUint16() != 1)
-				error("SCI2.1 kShowMovie argv[0] not 1");
-			argv++;
-			argc--;
-		}
-#endif
 		switch (argv[0].toUint16()) {
 		case 0: {
 			Common::String filename = s->_segMan->getString(argv[1]);
@@ -243,52 +215,102 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
 }
 
 #ifdef ENABLE_SCI32
+reg_t kShowMovie32(EngineState *s, int argc, reg_t *argv) {
+	Common::String fileName = s->_segMan->getString(argv[0]);
+	const int16 numTicks = argv[1].toSint16();
+	const int16 x = argc > 3 ? argv[2].toSint16() : 0;
+	const int16 y = argc > 3 ? argv[3].toSint16() : 0;
 
-reg_t kRobot(EngineState *s, int argc, reg_t *argv) {
-	int16 subop = argv[0].toUint16();
-
-	switch (subop) {
-	case 0: { // init
-		int id = argv[1].toUint16();
-		reg_t obj = argv[2];
-		int16 flag = argv[3].toSint16();
-		int16 x = argv[4].toUint16();
-		int16 y = argv[5].toUint16();
-		warning("kRobot(init), id %d, obj %04x:%04x, flag %d, x=%d, y=%d", id, PRINT_REG(obj), flag, x, y);
-		g_sci->_robotDecoder->load(id);
-		g_sci->_robotDecoder->start();
-		g_sci->_robotDecoder->setPos(x, y);
-		}
-		break;
-	case 1:	// LSL6 hires (startup)
-		// TODO
-		return NULL_REG;	// an integer is expected
-	case 4: {	// start - we don't really have a use for this one
-			//int id = argv[1].toUint16();
-			//warning("kRobot(start), id %d", id);
-		}
-		break;
-	case 7:	// unknown, called e.g. by Phantasmagoria
-		warning("kRobot(%d)", subop);
-		break;
-	case 8: // sync
-		//if (true) {	// debug: automatically skip all robot videos
-		if (g_sci->_robotDecoder->endOfVideo()) {
-			g_sci->_robotDecoder->close();
-			// Signal the engine scripts that the video is done
-			writeSelector(s->_segMan, argv[1], SELECTOR(signal), SIGNAL_REG);
-		} else {
-			writeSelector(s->_segMan, argv[1], SELECTOR(signal), NULL_REG);
-		}
-		break;
-	default:
-		warning("kRobot(%d)", subop);
-		break;
-	}
+	g_sci->_video32->getSEQPlayer().play(fileName, numTicks, x, y);
 
 	return s->r_acc;
 }
 
+reg_t kShowMovieWin(EngineState *s, int argc, reg_t *argv) {
+	if (!s)
+		return make_reg(0, getSciVersion());
+	error("not supposed to call this");
+}
+
+reg_t kShowMovieWinOpen(EngineState *s, int argc, reg_t *argv) {
+	// SCI2.1 adds a movie ID to the call, but the movie ID is broken,
+	// so just ignore it
+	if (getSciVersion() > SCI_VERSION_2) {
+		++argv;
+		--argc;
+	}
+
+	const Common::String fileName = s->_segMan->getString(argv[0]);
+	return make_reg(0, g_sci->_video32->getAVIPlayer().open(fileName));
+}
+
+reg_t kShowMovieWinInit(EngineState *s, int argc, reg_t *argv) {
+	// SCI2.1 adds a movie ID to the call, but the movie ID is broken,
+	// so just ignore it
+	if (getSciVersion() > SCI_VERSION_2) {
+		++argv;
+		--argc;
+	}
+
+	const int16 x = argv[0].toSint16();
+	const int16 y = argv[1].toSint16();
+	const int16 width = argc > 3 ? argv[2].toSint16() : 0;
+	const int16 height = argc > 3 ? argv[3].toSint16() : 0;
+	return make_reg(0, g_sci->_video32->getAVIPlayer().init1x(x, y, width, height));
+}
+
+reg_t kShowMovieWinPlay(EngineState *s, int argc, reg_t *argv) {
+	if (getSciVersion() == SCI_VERSION_2) {
+		AVIPlayer::EventFlags flags = (AVIPlayer::EventFlags)argv[0].toUint16();
+		return make_reg(0, g_sci->_video32->getAVIPlayer().playUntilEvent(flags));
+	} else {
+		// argv[0] is a broken movie ID
+		const int16 from = argc > 2 ? argv[1].toSint16() : 0;
+		const int16 to = argc > 2 ? argv[2].toSint16() : 0;
+		const int16 showStyle = argc > 3 ? argv[3].toSint16() : 0;
+		const bool cue = argc > 4 ? (bool)argv[4].toSint16() : false;
+		return make_reg(0, g_sci->_video32->getAVIPlayer().play(from, to, showStyle, cue));
+	}
+}
+
+reg_t kShowMovieWinClose(EngineState *s, int argc, reg_t *argv) {
+	return make_reg(0, g_sci->_video32->getAVIPlayer().close());
+}
+
+reg_t kShowMovieWinGetDuration(EngineState *s, int argc, reg_t *argv) {
+	return make_reg(0, g_sci->_video32->getAVIPlayer().getDuration());
+}
+
+reg_t kShowMovieWinCue(EngineState *s, int argc, reg_t *argv) {
+	// SCI2.1 adds a movie ID to the call, but the movie ID is broken,
+	// so just ignore it
+	if (getSciVersion() > SCI_VERSION_2) {
+		++argv;
+		--argc;
+	}
+
+	const uint16 frameNo = argv[0].toUint16();
+	return make_reg(0, g_sci->_video32->getAVIPlayer().cue(frameNo));
+}
+
+reg_t kShowMovieWinPlayUntilEvent(EngineState *s, int argc, reg_t *argv) {
+	const int defaultFlags =
+		AVIPlayer::kEventFlagEnd |
+		AVIPlayer::kEventFlagEscapeKey;
+
+	// argv[0] is the movie number, which is not used by this method
+	const AVIPlayer::EventFlags flags = (AVIPlayer::EventFlags)(argc > 1 ? argv[1].toUint16() : defaultFlags);
+
+	return make_reg(0, g_sci->_video32->getAVIPlayer().playUntilEvent(flags));
+}
+
+reg_t kShowMovieWinInitDouble(EngineState *s, int argc, reg_t *argv) {
+	// argv[0] is a broken movie ID
+	const int16 x = argv[1].toSint16();
+	const int16 y = argv[2].toSint16();
+	return make_reg(0, g_sci->_video32->getAVIPlayer().init2x(x, y));
+}
+
 reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) {
 	if (!s)
 		return make_reg(0, getSciVersion());
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index 3e12084..548fd47 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -405,6 +405,21 @@ static void callKernelFunc(EngineState *s, int kernelCallNr, int argc) {
 			error("[VM] k%s[%x]: no subfunction ID parameter given", kernelCall.name, kernelCallNr);
 		if (argv[0].isPointer())
 			error("[VM] k%s[%x]: given subfunction ID is actually a pointer", kernelCall.name, kernelCallNr);
+
+#ifdef ENABLE_SCI32
+		// The Windows version of kShowMovie has subops, but the subop number
+		// is put in the second parameter in SCI2.1+, even though every other
+		// kcall with subops puts the subop in the first parameter. To allow use
+		// of the normal subops system, we swap the arguments so the subop
+		// number is in the usual place.
+		if (getSciVersion() > SCI_VERSION_2 &&
+			g_sci->getPlatform() == Common::kPlatformWindows &&
+			strcmp(kernelCall.name, "ShowMovie") == 0) {
+			assert(argc > 1);
+			SWAP(argv[0], argv[1]);
+		}
+#endif
+
 		const uint16 subId = argv[0].toUint16();
 		// Skip over subfunction-id
 		argc--;
diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index dc2641c..ac4522c 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -29,11 +29,397 @@
 #include "sci/graphics/palette32.h"
 #include "sci/graphics/text32.h"
 #include "sci/graphics/video32.h"
-#include "sci/sci.h"
+#include "audio/mixer.h"                 // for Audio::Mixer::kSFXSoundType
+#include "common/config-manager.h"       // for ConfMan
+#include "common/textconsole.h"          // for error, warning
+#include "common/system.h"
+#include "engine.h"                      // for Engine, g_engine
+#include "engines/util.h"
+#include "graphics/scaler/scalebit.h"
+#include "sci/console.h"                 // for Console
+#include "sci/engine/state.h"            // for EngineState
+#include "sci/engine/vm_types.h"         // for reg_t
+#include "sci/event.h"                   // for SciEvent, EventManager, SCI_...
+#include "sci/graphics/celobj32.h"       // for CelInfo32
+#include "sci/graphics/cursor.h"         // for GfxCursor
+#include "sci/graphics/helpers.h"        // for Color, Palette
+#include "sci/graphics/palette32.h"      // for GfxPalette32
+#include "sci/graphics/plane32.h"        // for Plane, PlanePictureCodes::kP...
+#include "sci/graphics/screen_item32.h"  // for ScaleInfo, ScreenItem, Scale...
+#include "sci/graphics/text32.h"         // for BitmapResource
+#include "sci/video/seq_decoder.h"
+#include "sci/sci.h"                     // for SciEngine, g_sci, getSciVersion
+#include "video/avi_decoder.h"
 #include "video/coktel_decoder.h"
 
 namespace Sci {
 
+#pragma mark SEQPlayer
+
+SEQPlayer::SEQPlayer(SegManager *segMan) :
+	_segMan(segMan),
+	_decoder(nullptr),
+	_plane(nullptr),
+	_screenItem(nullptr) {}
+
+void SEQPlayer::play(const Common::String &fileName, const int16 numTicks, const int16 x, const int16 y) {
+	delete _decoder;
+	_decoder = new SEQDecoder(numTicks);
+	_decoder->loadFile(fileName);
+
+	// NOTE: In the original engine, video was output directly to the hardware,
+	// bypassing the game's rendering engine. Instead of doing this, we use a
+	// mechanism that is very similar to that used by the VMD player, which
+	// allows the SEQ to be drawn into a bitmap ScreenItem and displayed using
+	// the normal graphics system.
+	_segMan->allocateBitmap(&_bitmap, _decoder->getWidth(), _decoder->getHeight(), kDefaultSkipColor, 0, 0, kLowResX, kLowResY, 0, false, false);
+
+	CelInfo32 celInfo;
+	celInfo.type = kCelTypeMem;
+	celInfo.bitmap = _bitmap;
+
+	_plane = new Plane(Common::Rect(kLowResX, kLowResY), kPlanePicColored);
+	g_sci->_gfxFrameout->addPlane(*_plane);
+
+	// Normally we would use the x, y coordinates passed into the play function
+	// to position the screen item, but because the video frame bitmap is
+	// drawn in low-resolution coordinates, it gets automatically scaled up by
+	// the engine (pixel doubling with aspect ratio correction). As a result,
+	// the animation does not need the extra offsets from the game in order to
+	// be correctly positioned in the middle of the window, so we ignore them.
+	_screenItem = new ScreenItem(_plane->_object, celInfo, Common::Point(0, 0), ScaleInfo());
+	g_sci->_gfxFrameout->addScreenItem(*_screenItem);
+	g_sci->_gfxFrameout->frameOut(true);
+	_decoder->start();
+
+	while (!g_engine->shouldQuit() && !_decoder->endOfVideo()) {
+		renderFrame();
+		g_sci->getEngineState()->speedThrottler(_decoder->getTimeToNextFrame());
+		g_sci->getEngineState()->_throttleTrigger = true;
+	}
+
+	_segMan->freeBitmap(_screenItem->_celInfo.bitmap);
+	g_sci->_gfxFrameout->deletePlane(*_plane);
+	g_sci->_gfxFrameout->frameOut(true);
+	_screenItem = nullptr;
+	_plane = nullptr;
+}
+
+void SEQPlayer::renderFrame() const {
+	const Graphics::Surface *surface = _decoder->decodeNextFrame();
+
+	SciBitmap &bitmap = *_segMan->lookupBitmap(_bitmap);
+	bitmap.getBuffer().copyRectToSurface(*surface, 0, 0, Common::Rect(surface->w, surface->h));
+
+	const bool dirtyPalette = _decoder->hasDirtyPalette();
+	if (dirtyPalette) {
+		Palette palette;
+		const byte *rawPalette = _decoder->getPalette();
+		for (int i = 0; i < ARRAYSIZE(palette.colors); ++i) {
+			palette.colors[i].r = *rawPalette++;
+			palette.colors[i].g = *rawPalette++;
+			palette.colors[i].b = *rawPalette++;
+			palette.colors[i].used = true;
+		}
+
+		g_sci->_gfxPalette32->submit(palette);
+	}
+
+	g_sci->_gfxFrameout->updateScreenItem(*_screenItem);
+	g_sci->getSciDebugger()->onFrame();
+	g_sci->_gfxFrameout->frameOut(true);
+}
+
+#pragma mark -
+#pragma mark AVIPlayer
+
+AVIPlayer::AVIPlayer(SegManager *segMan, EventManager *eventMan) :
+	_segMan(segMan),
+	_eventMan(eventMan),
+	_decoder(new Video::AVIDecoder(Audio::Mixer::kSFXSoundType)),
+	_scaleBuffer(nullptr),
+	_plane(nullptr),
+	_screenItem(nullptr),
+	_status(kAVINotOpen) {}
+
+AVIPlayer::~AVIPlayer() {
+	close();
+	delete _decoder;
+}
+
+AVIPlayer::IOStatus AVIPlayer::open(const Common::String &fileName) {
+	if (_status != kAVINotOpen) {
+		close();
+	}
+
+	if (!_decoder->loadFile(fileName)) {
+		return kIOFileNotFound;
+	}
+
+	_status = kAVIOpen;
+	return kIOSuccess;
+}
+
+AVIPlayer::IOStatus AVIPlayer::init1x(const int16 x, const int16 y, int16 width, int16 height) {
+	if (!width || !height) {
+		width = _decoder->getWidth();
+		height = _decoder->getHeight();
+	}
+
+	// QFG4CD gives non-multiple-of-2 values for width and height,
+	// which would normally be OK except the source video is a pixel bigger
+	// in each dimension
+	width = (width + 1) & ~1;
+	height = (height + 1) & ~1;
+
+	_drawRect.left = x;
+	_drawRect.top = y;
+	_drawRect.right = x + width;
+	_drawRect.bottom = y + height;
+
+	// SCI2.1 uses init2x to draw a pixel-doubled AVI, but SCI2 has only the
+	// one play routine which automatically pixel-doubles in hi-res mode
+	if (getSciVersion() == SCI_VERSION_2) {
+		// NOTE: This is somewhat of a hack; credits.avi from GK1 is not
+		// rendered correctly in SSCI because it is a 640x480 video, but the
+		// game script gives the wrong dimensions. Since this is the only
+		// high-resolution AVI ever used, just set the draw rectangle to draw
+		// the entire screen
+		if (_decoder->getWidth() > 320) {
+			_drawRect.left = 0;
+			_drawRect.top = 0;
+			_drawRect.right = 320;
+			_drawRect.bottom = 200;
+		}
+
+		// In hi-res mode, video will be pixel doubled, so the origin (which
+		// corresponds to the correct position without pixel doubling) needs to
+		// be corrected
+		if (g_sci->_gfxFrameout->_isHiRes && _decoder->getWidth() <= 320) {
+			_drawRect.left /= 2;
+			_drawRect.top /= 2;
+		}
+	}
+
+	_pixelDouble = false;
+	init();
+
+	return kIOSuccess;
+}
+
+AVIPlayer::IOStatus AVIPlayer::init2x(const int16 x, const int16 y) {
+	_drawRect.left = x;
+	_drawRect.top = y;
+	_drawRect.right = x + _decoder->getWidth() * 2;
+	_drawRect.bottom = y + _decoder->getHeight() * 2;
+
+	_pixelDouble = true;
+	init();
+
+	return kIOSuccess;
+}
+
+void AVIPlayer::init() {
+	int16 xRes;
+	int16 yRes;
+
+	if (g_sci->_gfxFrameout->_isHiRes && _decoder->getWidth() > 320) {
+		xRes = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
+		yRes = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
+	} else {
+		xRes = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+		yRes = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+	}
+
+	_plane = new Plane(_drawRect);
+	g_sci->_gfxFrameout->addPlane(*_plane);
+
+	if (_decoder->getPixelFormat().bytesPerPixel == 1) {
+		_segMan->allocateBitmap(&_bitmap, _decoder->getWidth(), _decoder->getHeight(), kDefaultSkipColor, 0, 0, xRes, yRes, 0, false, false);
+
+		CelInfo32 celInfo;
+		celInfo.type = kCelTypeMem;
+		celInfo.bitmap = _bitmap;
+
+		_screenItem = new ScreenItem(_plane->_object, celInfo, Common::Point(_drawRect.left, _drawRect.top), ScaleInfo());
+		g_sci->_gfxFrameout->addScreenItem(*_screenItem);
+		g_sci->_gfxFrameout->frameOut(true);
+	} else {
+		const Buffer &currentBuffer = g_sci->_gfxFrameout->getCurrentBuffer();
+		const Graphics::PixelFormat format = _decoder->getPixelFormat();
+		initGraphics(currentBuffer.screenWidth, currentBuffer.screenHeight, g_sci->_gfxFrameout->_isHiRes, &format);
+
+		if (_pixelDouble) {
+			const int16 width = _drawRect.width();
+			const int16 height = _drawRect.height();
+			_scaleBuffer = calloc(1, width * height * format.bytesPerPixel);
+		}
+	}
+}
+
+AVIPlayer::IOStatus AVIPlayer::play(const int16 from, const int16 to, const int16, const bool async) {
+	if (from >= 0 && to > 0 && from <= to) {
+		_decoder->seekToFrame(from);
+		_decoder->setEndFrame(to);
+	}
+
+	if (!async) {
+		renderVideo();
+	}
+
+	_status = kAVIPlaying;
+	return kIOSuccess;
+}
+
+void AVIPlayer::renderVideo() const {
+	_decoder->start();
+	while (!g_engine->shouldQuit() && !_decoder->endOfVideo()) {
+		g_sci->getEngineState()->speedThrottler(_decoder->getTimeToNextFrame());
+		g_sci->getEngineState()->_throttleTrigger = true;
+		if (_decoder->needsUpdate()) {
+			renderFrame();
+		}
+	}
+}
+
+AVIPlayer::IOStatus AVIPlayer::close() {
+	if (_status == kAVINotOpen) {
+		return kIOSuccess;
+	}
+
+	free(_scaleBuffer);
+	_scaleBuffer = nullptr;
+
+	if (_decoder->getPixelFormat().bytesPerPixel != 1) {
+		const bool isHiRes = g_sci->_gfxFrameout->_isHiRes;
+		const Buffer &currentBuffer = g_sci->_gfxFrameout->getCurrentBuffer();
+		const Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8();
+		initGraphics(currentBuffer.screenWidth, currentBuffer.screenHeight, isHiRes, &format);
+	}
+
+	_decoder->close();
+	_status = kAVINotOpen;
+	g_sci->_gfxFrameout->deletePlane(*_plane);
+	_plane = nullptr;
+	_screenItem = nullptr;
+	return kIOSuccess;
+}
+
+AVIPlayer::IOStatus AVIPlayer::cue(const uint16 frameNo) {
+	if (!_decoder->seekToFrame(frameNo)) {
+		return kIOSeekFailed;
+	}
+
+	_status = kAVIPaused;
+	return kIOSuccess;
+}
+
+uint16 AVIPlayer::getDuration() const {
+	if (_status == kAVINotOpen) {
+		return 0;
+	}
+
+	return _decoder->getFrameCount();
+}
+
+void AVIPlayer::renderFrame() const {
+	const Graphics::Surface *surface = _decoder->decodeNextFrame();
+
+	if (surface->format.bytesPerPixel == 1) {
+		SciBitmap &bitmap = *_segMan->lookupBitmap(_bitmap);
+		if (surface->w > bitmap.getWidth() || surface->h > bitmap.getHeight()) {
+			warning("Attempted to draw a video frame larger than the destination bitmap");
+			return;
+		}
+
+		bitmap.getBuffer().copyRectToSurface(*surface, 0, 0, Common::Rect(surface->w, surface->h));
+
+		const bool dirtyPalette = _decoder->hasDirtyPalette();
+		if (dirtyPalette) {
+			Palette palette;
+			const byte *rawPalette = _decoder->getPalette();
+			for (int i = 0; i < ARRAYSIZE(palette.colors); ++i) {
+				palette.colors[i].r = *rawPalette++;
+				palette.colors[i].g = *rawPalette++;
+				palette.colors[i].b = *rawPalette++;
+				palette.colors[i].used = true;
+			}
+
+			g_sci->_gfxPalette32->submit(palette);
+		}
+
+		g_sci->_gfxFrameout->updateScreenItem(*_screenItem);
+		g_sci->getSciDebugger()->onFrame();
+		g_sci->_gfxFrameout->frameOut(true);
+	} else {
+		Common::Rect drawRect(_drawRect);
+		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;
+
+		if (_pixelDouble) {
+			scale(2, _scaleBuffer, surface->pitch * 2, surface->getPixels(), surface->pitch, surface->format.bytesPerPixel, surface->w, surface->h);
+			g_system->copyRectToScreen(_scaleBuffer, surface->pitch * 2, _drawRect.left, _drawRect.top, _drawRect.width(), _drawRect.height());
+		} else {
+			mulinc(drawRect, Ratio(screenWidth, scriptWidth), Ratio(screenHeight, scriptHeight));
+
+			g_system->copyRectToScreen(surface->getPixels(), surface->pitch, drawRect.left, drawRect.top, surface->w, surface->h);
+		}
+	}
+}
+
+AVIPlayer::EventFlags AVIPlayer::playUntilEvent(EventFlags flags) {
+	_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();
+		}
+
+		SciEvent event = _eventMan->getSciEvent(SCI_EVENT_MOUSE_PRESS | SCI_EVENT_PEEK);
+		if ((flags & kEventFlagMouseDown) && event.type == SCI_EVENT_MOUSE_PRESS) {
+			stopFlag = kEventFlagMouseDown;
+			break;
+		}
+
+		event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_PEEK);
+		if ((flags & kEventFlagEscapeKey) && event.type == SCI_EVENT_KEYBOARD) {
+			bool stop = false;
+			while ((event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD)),
+				   event.type != SCI_EVENT_NONE) {
+				if (event.character == SCI_KEY_ESC) {
+					stop = true;
+					break;
+				}
+			}
+
+			if (stop) {
+				stopFlag = kEventFlagEscapeKey;
+				break;
+			}
+		}
+
+		// TODO: Hot rectangles
+		if ((flags & kEventFlagHotRectangle) /* && event.type == SCI_EVENT_HOT_RECTANGLE */) {
+			warning("Hot rectangles not implemented in VMD player");
+			stopFlag = kEventFlagHotRectangle;
+			break;
+		}
+	}
+
+	return stopFlag;
+}
+
+#pragma mark -
 #pragma mark VMDPlayer
 
 VMDPlayer::VMDPlayer(SegManager *segMan, EventManager *eventMan) :
@@ -117,7 +503,7 @@ VMDPlayer::IOStatus VMDPlayer::close() {
 
 	if (!_planeIsOwned && _screenItem != nullptr) {
 		g_sci->_gfxFrameout->deleteScreenItem(*_screenItem);
-		g_sci->getEngineState()->_segMan->freeBitmap(_screenItem->_celInfo.bitmap);
+		_segMan->freeBitmap(_screenItem->_celInfo.bitmap);
 		_screenItem = nullptr;
 	} else if (_plane != nullptr) {
 		g_sci->_gfxFrameout->deletePlane(*_plane);
diff --git a/engines/sci/graphics/video32.h b/engines/sci/graphics/video32.h
index 7033f7c..b0deba1 100644
--- a/engines/sci/graphics/video32.h
+++ b/engines/sci/graphics/video32.h
@@ -23,12 +23,208 @@
 #ifndef SCI_GRAPHICS_VIDEO32_H
 #define SCI_GRAPHICS_VIDEO32_H
 
-namespace Video { class AdvancedVMDDecoder; }
+#include "common/rect.h"              // for Rect
+#include "common/scummsys.h"          // for int16, uint8, int32
+#include "common/str.h"               // for String
+#include "sci/video/robot_decoder.h"  // for RobotDecoder
+
+namespace Video {
+class AdvancedVMDDecoder;
+class AVIDecoder;
+}
 namespace Sci {
 class Plane;
 class ScreenItem;
 class SegManager;
+class SEQDecoder;
+struct Palette;
 
+#pragma mark SEQPlayer
+
+/**
+ * SEQPlayer is used to play SEQ animations.
+ * Used by DOS versions of GK1 and QFG4CD.
+ */
+class SEQPlayer {
+public:
+	SEQPlayer(SegManager *segMan);
+
+	/**
+	 * Plays a SEQ animation with the given
+	 * file name, with each frame being displayed
+	 * for `numTicks` ticks.
+	 */
+	void play(const Common::String &fileName, const int16 numTicks, const int16 x, const int16 y);
+
+private:
+	SegManager *_segMan;
+	SEQDecoder *_decoder;
+
+	/**
+	 * The plane where the SEQ will be drawn.
+	 */
+	Plane *_plane;
+
+	/**
+	 * The screen item representing the SEQ surface.
+	 */
+	ScreenItem *_screenItem;
+
+	/**
+	 * The bitmap used to render video output.
+	 */
+	reg_t _bitmap;
+
+	/**
+	 * Renders a single frame of video.
+	 */
+	void renderFrame() const;
+};
+
+#pragma mark -
+#pragma mark AVIPlayer
+
+/**
+ * AVIPlayer is used to play AVI videos. Used by
+ * Windows versions of GK1CD, KQ7, and QFG4CD.
+ */
+class AVIPlayer {
+public:
+	enum IOStatus {
+		kIOSuccess      = 0,
+		kIOFileNotFound = 2,
+		kIOSeekFailed   = 12
+	};
+
+	enum AVIStatus {
+		kAVINotOpen  = 0,
+		kAVIOpen     = 1,
+		kAVIPlaying  = 2,
+		kAVIPaused   = 3
+	};
+
+	enum EventFlags {
+		kEventFlagNone         = 0,
+		kEventFlagEnd          = 1,
+		kEventFlagEscapeKey    = 2,
+		kEventFlagMouseDown    = 4,
+		kEventFlagHotRectangle = 8
+	};
+
+	AVIPlayer(SegManager *segMan, EventManager *eventMan);
+	~AVIPlayer();
+
+	/**
+	 * Opens a stream to an AVI resource.
+	 */
+	IOStatus open(const Common::String &fileName);
+
+	/**
+	 * Initializes the AVI rendering parameters for the
+	 * current AVI. This must be called after `open`.
+	 */
+	IOStatus init1x(const int16 x, const int16 y, const int16 width, const int16 height);
+
+	/**
+	 * Initializes the AVI rendering parameters for the
+	 * current AVI, in pixel-doubling mode. This must
+	 * be called after `open`.
+	 */
+	IOStatus init2x(const int16 x, const int16 y);
+
+	/**
+	 * Begins playback of the current AVI.
+	 */
+	IOStatus play(const int16 from, const int16 to, const int16 showStyle, const bool cue);
+
+	/**
+	 * Stops playback and closes the currently open AVI stream.
+	 */
+	IOStatus close();
+
+	/**
+	 * Seeks the currently open AVI stream to the given frame.
+	 */
+	IOStatus cue(const uint16 frameNo);
+
+	/**
+	 * Returns the duration of the current video.
+	 */
+	uint16 getDuration() const;
+
+	/**
+	 * Plays the AVI until an event occurs (e.g. user
+	 * presses escape, clicks, etc.).
+	 */
+	EventFlags playUntilEvent(const EventFlags flags);
+
+private:
+	typedef Common::HashMap<uint16, AVIStatus> StatusMap;
+
+	SegManager *_segMan;
+	EventManager *_eventMan;
+	Video::AVIDecoder *_decoder;
+
+	/**
+	 * Playback status of the player.
+	 */
+	AVIStatus _status;
+
+	/**
+	 * The plane where the AVI will be drawn.
+	 */
+	Plane *_plane;
+
+	/**
+	 * The screen item representing the AVI surface,
+	 * in 8bpp mode. In 24bpp mode, video is drawn
+	 * directly to the screen.
+	 */
+	ScreenItem *_screenItem;
+
+	/**
+	 * The bitmap used to render video output in
+	 * 8bpp mode.
+	 */
+	reg_t _bitmap;
+
+	/**
+	 * The rectangle where the video will be drawn,
+	 * in game script coordinates.
+	 */
+	Common::Rect _drawRect;
+
+	/**
+	 * The scale buffer for pixel-doubled videos
+	 * drawn in 24bpp mode.
+	 */
+	void *_scaleBuffer;
+
+	/**
+	 * In SCI2.1, whether or not the video should
+	 * be pixel doubled for playback.
+	 */
+	bool _pixelDouble;
+
+	/**
+	 * Performs common initialisation for both
+	 * scaled and unscaled videos.
+	 */
+	void init();
+
+	/**
+	 * Renders video without event input until the
+	 * video is complete.
+	 */
+	void renderVideo() const;
+
+	/**
+	 * Renders a single frame of video.
+	 */
+	void renderFrame() const;
+};
+
+#pragma mark -
 #pragma mark VMDPlayer
 
 /**
@@ -300,11 +496,17 @@ private:
 class Video32 {
 public:
 	Video32(SegManager *segMan, EventManager *eventMan) :
+	_SEQPlayer(segMan),
+	_AVIPlayer(segMan, eventMan),
 	_VMDPlayer(segMan, eventMan) {}
 
+	SEQPlayer &getSEQPlayer() { return _SEQPlayer; }
+	AVIPlayer &getAVIPlayer() { return _AVIPlayer; }
 	VMDPlayer &getVMDPlayer() { return _VMDPlayer; }
 
 private:
+	SEQPlayer _SEQPlayer;
+	AVIPlayer _AVIPlayer;
 	VMDPlayer _VMDPlayer;
 };
 } // End of namespace Sci


Commit: 4ff0924e57a9bc9101ee0799a967fe3373dd2574
    https://github.com/scummvm/scummvm/commit/4ff0924e57a9bc9101ee0799a967fe3373dd2574
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-11T20:50:33-05:00

Commit Message:
SCI32: Additional Video32 documentation

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



diff --git a/engines/sci/graphics/video32.h b/engines/sci/graphics/video32.h
index b0deba1..7320ede 100644
--- a/engines/sci/graphics/video32.h
+++ b/engines/sci/graphics/video32.h
@@ -229,6 +229,8 @@ private:
 
 /**
  * VMDPlayer is used to play VMD videos.
+ * Used by Phant1, GK2, PQ:SWAT, Shivers, SQ6,
+ * Torin, and Lighthouse.
  */
 class VMDPlayer {
 public:
@@ -493,6 +495,10 @@ private:
 	bool _showCursor;
 };
 
+/**
+ * Video32 provides facilities for playing back
+ * video in SCI engine.
+ */
 class Video32 {
 public:
 	Video32(SegManager *segMan, EventManager *eventMan) :


Commit: cdab24aa07c18ad4a25a1659f7fca15cca5e358e
    https://github.com/scummvm/scummvm/commit/cdab24aa07c18ad4a25a1659f7fca15cca5e358e
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-11T20:50:33-05:00

Commit Message:
SCI32: Fix KQ7 1.51 basic video playback

There is still a problem where the background is white instead
of black; this is caused by the palette of the video using entry
0 as white. This seems to have worked out OK in SSCI because the
video was not actually played back inside the engine itself, so
didn't interfere with the palette of the engine. ScummVM has no
such separation, so the palette of the video interferes with the
palette of the blank background pic, turning it white.

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



diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index ac4522c..e8baed2 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -161,9 +161,18 @@ AVIPlayer::IOStatus AVIPlayer::open(const Common::String &fileName) {
 }
 
 AVIPlayer::IOStatus AVIPlayer::init1x(const int16 x, const int16 y, int16 width, int16 height) {
+
+	_pixelDouble = false;
+
 	if (!width || !height) {
 		width = _decoder->getWidth();
 		height = _decoder->getHeight();
+	} else if (getSciVersion() == SCI_VERSION_2_1_EARLY && g_sci->getGameId() == GID_KQ7) {
+		// KQ7 1.51 provides an explicit width and height when it wants scaling,
+		// though the width and height it provides are not scaled
+		_pixelDouble = true;
+		width *= 2;
+		height *= 2;
 	}
 
 	// QFG4CD gives non-multiple-of-2 values for width and height,
@@ -177,7 +186,7 @@ AVIPlayer::IOStatus AVIPlayer::init1x(const int16 x, const int16 y, int16 width,
 	_drawRect.right = x + width;
 	_drawRect.bottom = y + height;
 
-	// SCI2.1 uses init2x to draw a pixel-doubled AVI, but SCI2 has only the
+	// SCI2.1mid uses init2x to draw a pixel-doubled AVI, but SCI2 has only the
 	// one play routine which automatically pixel-doubles in hi-res mode
 	if (getSciVersion() == SCI_VERSION_2) {
 		// NOTE: This is somewhat of a hack; credits.avi from GK1 is not
@@ -201,7 +210,6 @@ AVIPlayer::IOStatus AVIPlayer::init1x(const int16 x, const int16 y, int16 width,
 		}
 	}
 
-	_pixelDouble = false;
 	init();
 
 	return kIOSuccess;
@@ -223,7 +231,24 @@ void AVIPlayer::init() {
 	int16 xRes;
 	int16 yRes;
 
+	bool useScreenDimensions = false;
 	if (g_sci->_gfxFrameout->_isHiRes && _decoder->getWidth() > 320) {
+		useScreenDimensions = true;
+	}
+
+	// KQ7 1.51 gives video position in screen coordinates, not game
+	// coordinates, because in SSCI they are passed to Video for Windows, which
+	// renders as an overlay on the game video. Because we put the video into a
+	// ScreenItem instead of rendering directly to the hardware surface, the
+	// coordinates need to be converted to game script coordinates
+	if (g_sci->getGameId() == GID_KQ7 && getSciVersion() == SCI_VERSION_2_1_EARLY) {
+		useScreenDimensions = !_pixelDouble;
+		// This y-translation is arbitrary, based on what roughly centers the
+		// videos in the game window
+		_drawRect.translate(-_drawRect.left / 2, -_drawRect.top * 2 / 3);
+	}
+
+	if (useScreenDimensions) {
 		xRes = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
 		yRes = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
 	} else {
@@ -265,9 +290,12 @@ AVIPlayer::IOStatus AVIPlayer::play(const int16 from, const int16 to, const int1
 
 	if (!async) {
 		renderVideo();
+	} else if (getSciVersion() == SCI_VERSION_2_1_EARLY) {
+		playUntilEvent((EventFlags)(kEventFlagEnd | kEventFlagEscapeKey));
+	} else {
+		_status = kAVIPlaying;
 	}
 
-	_status = kAVIPlaying;
 	return kIOSuccess;
 }
 


Commit: 93b06f4a9e08de281ee7eb9c780ceac147c3fb23
    https://github.com/scummvm/scummvm/commit/93b06f4a9e08de281ee7eb9c780ceac147c3fb23
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-11T20:50:33-05:00

Commit Message:
SCI32: Fix crash when kShowMovie is called but the video cannot be found

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



diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index e8baed2..0dde86a 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -161,6 +161,9 @@ AVIPlayer::IOStatus AVIPlayer::open(const Common::String &fileName) {
 }
 
 AVIPlayer::IOStatus AVIPlayer::init1x(const int16 x, const int16 y, int16 width, int16 height) {
+	if (_status == kAVINotOpen) {
+		return kIOFileNotFound;
+	}
 
 	_pixelDouble = false;
 
@@ -189,7 +192,7 @@ AVIPlayer::IOStatus AVIPlayer::init1x(const int16 x, const int16 y, int16 width,
 	// SCI2.1mid uses init2x to draw a pixel-doubled AVI, but SCI2 has only the
 	// one play routine which automatically pixel-doubles in hi-res mode
 	if (getSciVersion() == SCI_VERSION_2) {
-		// NOTE: This is somewhat of a hack; credits.avi from GK1 is not
+		// This is somewhat of a hack; credits.avi from GK1 is not
 		// rendered correctly in SSCI because it is a 640x480 video, but the
 		// game script gives the wrong dimensions. Since this is the only
 		// high-resolution AVI ever used, just set the draw rectangle to draw
@@ -216,6 +219,10 @@ AVIPlayer::IOStatus AVIPlayer::init1x(const int16 x, const int16 y, int16 width,
 }
 
 AVIPlayer::IOStatus AVIPlayer::init2x(const int16 x, const int16 y) {
+	if (_status == kAVINotOpen) {
+		return kIOFileNotFound;
+	}
+
 	_drawRect.left = x;
 	_drawRect.top = y;
 	_drawRect.right = x + _decoder->getWidth() * 2;
@@ -283,6 +290,10 @@ void AVIPlayer::init() {
 }
 
 AVIPlayer::IOStatus AVIPlayer::play(const int16 from, const int16 to, const int16, const bool async) {
+	if (_status == kAVINotOpen) {
+		return kIOFileNotFound;
+	}
+
 	if (from >= 0 && to > 0 && from <= to) {
 		_decoder->seekToFrame(from);
 		_decoder->setEndFrame(to);


Commit: c8affb54cca259f37522216bad739be085bf9caa
    https://github.com/scummvm/scummvm/commit/c8affb54cca259f37522216bad739be085bf9caa
Author: Colin Snover (github.com at zetafleet.com)
Date: 2016-08-11T20:50:33-05:00

Commit Message:
SCI32: Fix KQ7 1.51 video background

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



diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index 0dde86a..380ab80 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -371,7 +371,25 @@ void AVIPlayer::renderFrame() const {
 			return;
 		}
 
-		bitmap.getBuffer().copyRectToSurface(*surface, 0, 0, Common::Rect(surface->w, surface->h));
+		// KQ7 1.51 encodes videos with palette entry 0 as white, which makes
+		// the area around the video turn white too, since it is coded to use
+		// palette entry 0. This happens to work in the original game because
+		// the video is rendered by VfW, not in the engine itself. To fix this,
+		// we just modify the incoming pixel data from the video so if a pixel
+		// is using entry 0, we change it to use entry 255, which is guaranteed
+		// to always be white
+		if (getSciVersion() == SCI_VERSION_2_1_EARLY && g_sci->getGameId() == GID_KQ7) {
+			uint8 *target = bitmap.getPixels();
+			uint8 *source = (uint8 *)surface->getPixels();
+			uint8 *end = (uint8 *)surface->getPixels() + surface->w * surface->h;
+
+			while (source != end) {
+				uint8 value = *source++;
+				*target++ = value == 0 ? 255 : value;
+			}
+		} else {
+			bitmap.getBuffer().copyRectToSurface(*surface, 0, 0, Common::Rect(surface->w, surface->h));
+		}
 
 		const bool dirtyPalette = _decoder->hasDirtyPalette();
 		if (dirtyPalette) {
@@ -384,6 +402,9 @@ void AVIPlayer::renderFrame() const {
 				palette.colors[i].used = true;
 			}
 
+			// Prevent KQ7 1.51 from setting entry 0 to white
+			palette.colors[0].used = false;
+
 			g_sci->_gfxPalette32->submit(palette);
 		}
 






More information about the Scummvm-git-logs mailing list