[Scummvm-git-logs] scummvm master -> 05b21ace680d65336219a74cd87696eb157f7e84

sluicebox 22204938+sluicebox at users.noreply.github.com
Wed Dec 4 17:18:32 UTC 2019


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

Summary:
da9c7d3d5b SCI32: Fix VMDPlayer yielding when frames skipped
05b21ace68 SCI32: Implement VMD Censorship Blobs


Commit: da9c7d3d5bb5b64f026d20eabfa8f3cb4297867b
    https://github.com/scummvm/scummvm/commit/da9c7d3d5bb5b64f026d20eabfa8f3cb4297867b
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2019-12-04T09:11:21-08:00

Commit Message:
SCI32: Fix VMDPlayer yielding when frames skipped

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


diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index e6e594b..7133be5 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -731,7 +731,7 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags, const ui
 VMDPlayer::EventFlags VMDPlayer::checkForEvent(const EventFlags flags) {
 	const int currentFrameNo = _decoder->getCurFrame();
 
-	if (currentFrameNo == _yieldFrame) {
+	if (currentFrameNo >= _yieldFrame) {
 		return kEventFlagEnd;
 	}
 


Commit: 05b21ace680d65336219a74cd87696eb157f7e84
    https://github.com/scummvm/scummvm/commit/05b21ace680d65336219a74cd87696eb157f7e84
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2019-12-04T09:11:21-08:00

Commit Message:
SCI32: Implement VMD Censorship Blobs

Phantasmagoria 1's censorship mode is now supported

Trac #11229

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 f88afcc..cbbfaef 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -463,6 +463,10 @@ reg_t kPlayVMDIgnorePalettes(EngineState *s, int argc, reg_t *argv);
 reg_t kPlayVMDGetStatus(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 kPlayVMDAddBlob(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDDeleteBlob(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 kPlayVMDSetPlane(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 77b442e..3d8c256 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -468,11 +468,10 @@ static const SciKernelMapSubEntry kPlayVMD_subops[] = {
 	{ SIG_SINCE_SCI21,    10, MAP_CALL(PlayVMDGetStatus),          "",                     NULL },
 	{ SIG_SINCE_SCI21,    14, MAP_CALL(PlayVMDPlayUntilEvent),     "i(i)(i)",              NULL },
 	{ SIG_SINCE_SCI21,    16, MAP_CALL(PlayVMDShowCursor),         "i",                    NULL },
-	// TODO: implement blob subops to pixelate Phant1 videos when censored mode is enabled
-	{ SIG_SINCE_SCI21,    17, MAP_EMPTY(PlayVMDStartBlob),         "",                     NULL },
-	{ SIG_SINCE_SCI21,    18, MAP_EMPTY(PlayVMDStopBlobs),         "",                     NULL },
-	{ SIG_SINCE_SCI21,    19, MAP_EMPTY(PlayVMDAddBlob),           "iiiii",                NULL },
-	{ SIG_SINCE_SCI21,    20, MAP_EMPTY(PlayVMDDeleteBlob),        "i",                    NULL },
+	{ SIG_SINCE_SCI21,    17, MAP_CALL(PlayVMDStartBlob),          "",                     NULL },
+	{ SIG_SINCE_SCI21,    18, MAP_CALL(PlayVMDStopBlobs),          "",                     NULL },
+	{ SIG_SINCE_SCI21,    19, MAP_CALL(PlayVMDAddBlob),            "iiiii",                NULL },
+	{ SIG_SINCE_SCI21,    20, MAP_CALL(PlayVMDDeleteBlob),         "i",                    NULL },
 	{ SIG_SINCE_SCI21,    21, MAP_CALL(PlayVMDSetBlackoutArea),    "iiii",                 NULL },
 	{ SIG_SINCE_SCI21,    23, MAP_CALL(PlayVMDRestrictPalette),    "ii",                   NULL },
 	{ SIG_SCI3,           27, MAP_CALL(PlayVMDSetPlane),           "i(i)",                 NULL },
diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp
index 03ed698..72762a6 100644
--- a/engines/sci/engine/kvideo.cpp
+++ b/engines/sci/engine/kvideo.cpp
@@ -435,6 +435,32 @@ reg_t kPlayVMDShowCursor(EngineState *s, int argc, reg_t *argv) {
 	return s->r_acc;
 }
 
+reg_t kPlayVMDStartBlob(EngineState *s, int argc, reg_t *argv) {
+	g_sci->_video32->getVMDPlayer().deleteBlobs();
+	return NULL_REG;
+}
+
+reg_t kPlayVMDStopBlobs(EngineState *s, int argc, reg_t *argv) {
+	g_sci->_video32->getVMDPlayer().deleteBlobs();
+	return NULL_REG;
+}
+
+reg_t kPlayVMDAddBlob(EngineState *s, int argc, reg_t *argv) {
+	int16 squareSize = argv[0].toSint16();
+	int16 top = argv[1].toSint16();
+	int16 left = argv[2].toSint16();
+	int16 bottom = argv[3].toSint16();
+	int16 right = argv[4].toSint16();
+	int16 blobNumber = g_sci->_video32->getVMDPlayer().addBlob(squareSize, top, left, bottom, right);
+	return make_reg(0, blobNumber);
+}
+
+reg_t kPlayVMDDeleteBlob(EngineState *s, int argc, reg_t *argv) {
+	int16 blobNumber = argv[0].toSint16();
+	g_sci->_video32->getVMDPlayer().deleteBlob(blobNumber);
+	return SIGNAL_REG;
+}
+
 reg_t kPlayVMDSetBlackoutArea(EngineState *s, int argc, reg_t *argv) {
 	const int16 scriptWidth = g_sci->_gfxFrameout->getScriptWidth();
 	const int16 scriptHeight = g_sci->_gfxFrameout->getScriptHeight();
diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index 7133be5..567660d9 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -126,7 +126,9 @@ VideoPlayer::EventFlags VideoPlayer::playUntilEvent(const EventFlags flags, cons
 
 	EventFlags stopFlag = kEventFlagNone;
 	for (;;) {
-		g_sci->sleep(MIN(_decoder->getTimeToNextFrame(), maxSleepMs));
+		if (!_needsUpdate) {
+			g_sci->sleep(MIN(_decoder->getTimeToNextFrame(), maxSleepMs));
+		}
 
 		const Graphics::Surface *nextFrame = nullptr;
 		// If a decoder needs more than one update per loop, this means we are
@@ -140,9 +142,20 @@ VideoPlayer::EventFlags VideoPlayer::playUntilEvent(const EventFlags flags, cons
 		}
 
 		// Some frames may contain only audio and/or palette data; this occurs
-		// with Duck videos and is not an error
+		// with Duck videos and is not an error.
+		// If _needsUpdate has been set but it's not time to render the next frame
+		// then the current frame is rendered again. This reduces the delay between
+		// a script adding or removing censorship blobs and the screen reflecting
+		// this upon resuming playback.
 		if (nextFrame) {
 			renderFrame(*nextFrame);
+			_currentFrame = nextFrame;
+			_needsUpdate = false;
+		} else if (_needsUpdate) {
+			if (_currentFrame) {
+				renderFrame(*_currentFrame);
+			}
+			_needsUpdate = false;
 		}
 
 		// Event checks must only happen *after* the decoder is updated (1) and
@@ -647,6 +660,9 @@ VMDPlayer::IOStatus VMDPlayer::close() {
 	_planeIsOwned = true;
 	_priority = 0;
 	_drawRect = Common::Rect();
+	_blobs.clear();
+	_needsUpdate = false;
+	_currentFrame = nullptr;
 	return kIOSuccess;
 }
 
@@ -756,6 +772,43 @@ VMDPlayer::EventFlags VMDPlayer::checkForEvent(const EventFlags flags) {
 	return kEventFlagNone;
 }
 
+int16 VMDPlayer::addBlob(int16 blockSize, int16 top, int16 left, int16 bottom, int16 right) {
+	if (_blobs.size() >= kMaxBlobs) {
+		return -1;
+	}
+	
+	int16 blobNumber = 0;
+	Common::List<Blob>::iterator prevBlobIterator = _blobs.begin();
+	for (; prevBlobIterator != _blobs.end(); ++prevBlobIterator, ++blobNumber) {
+		if (blobNumber < prevBlobIterator->blobNumber) {
+			break;
+		}
+	}
+
+	Blob blob = { blobNumber, blockSize, top, left, bottom, right };
+	_blobs.insert(prevBlobIterator, blob);
+
+	_needsUpdate = true;
+	return blobNumber;
+}
+
+void VMDPlayer::deleteBlobs() {
+	if (!_blobs.empty()) {
+		_blobs.clear();
+		_needsUpdate = true;
+	}
+}
+
+void VMDPlayer::deleteBlob(int16 blobNumber) {
+	for (Common::List<Blob>::iterator b = _blobs.begin(); b != _blobs.end(); ++b) {
+		if (b->blobNumber == blobNumber) {
+			_blobs.erase(b);
+			_needsUpdate = true;
+			break;
+		}
+	}
+}
+
 void VMDPlayer::initOverlay() {
 	// Composited videos forced through the overlay renderer (due to HQ video
 	// mode) still need to occlude whatever is behind them in the renderer (as
@@ -977,7 +1030,28 @@ void VMDPlayer::renderFrame(const Graphics::Surface &nextFrame) const {
 	if (_isComposited) {
 		renderComposited();
 	} else {
-		renderOverlay(nextFrame);
+		if (_blobs.empty()) {
+			renderOverlay(nextFrame);
+		} else {
+			Graphics::Surface censoredFrame;
+			censoredFrame.create(nextFrame.w, nextFrame.h, nextFrame.format);
+			censoredFrame.copyFrom(nextFrame);
+			drawBlobs(censoredFrame);
+			renderOverlay(censoredFrame);
+			censoredFrame.free();
+		}
+	}
+}
+
+void VMDPlayer::drawBlobs(Graphics::Surface& frame) const {
+	for (Common::List<Blob>::const_iterator blob = _blobs.begin(); blob != _blobs.end(); ++blob) {
+		for (int16 blockLeft = blob->left; blockLeft < blob->right; blockLeft += blob->blockSize) {
+			for (int16 blockTop = blob->top; blockTop < blob->bottom; blockTop += blob->blockSize) {
+				byte color = *(byte *)frame.getBasePtr(blockLeft, blockTop);
+				Common::Rect block(blockLeft, blockTop, blockLeft + blob->blockSize, blockTop + blob->blockSize);
+				frame.fillRect(block, color);
+			}
+		}
 	}
 }
 
diff --git a/engines/sci/graphics/video32.h b/engines/sci/graphics/video32.h
index cbfbe7d..1fad807 100644
--- a/engines/sci/graphics/video32.h
+++ b/engines/sci/graphics/video32.h
@@ -69,7 +69,9 @@ public:
 
 	VideoPlayer(EventManager *eventMan, Video::VideoDecoder *decoder = nullptr) :
 		_eventMan(eventMan),
-		_decoder(decoder)
+		_decoder(decoder),
+		_needsUpdate(false),
+		_currentFrame(nullptr)
 #ifdef USE_RGB_COLOR
 		,
 		_hqVideoMode(false)
@@ -171,6 +173,18 @@ protected:
 	 */
 	Common::Rect _drawRect;
 
+	/**
+	 * If true, playUntilEvent() will immediately render a frame.
+	 * Used by VMDPlayer when censorship blobs are added or removed in Phant1
+	 * in order to immediately update the screen upon resuming playback.
+	 */
+	bool _needsUpdate;
+
+	/**
+	 * Current frame rendered by playUntilEvent() 
+	 */
+	const Graphics::Surface* _currentFrame;
+
 #ifdef USE_RGB_COLOR
 	/**
 	 * Whether or not the player is currently in high-quality video rendering
@@ -614,6 +628,37 @@ private:
 	 * Whether or not the mouse cursor should be shown during playback.
 	 */
 	bool _showCursor;
+
+#pragma mark -
+#pragma mark VMDPlayer - Censorship blobs
+public:
+	/**
+	 * Censorship blobs are pixelated rectangles which are added and removed by
+	 * game scripts. Phant1 is the only game known to use this and always sets a
+	 * blockSize of 10. Each block's color comes from the pixel in the upper left
+	 * corner of the block's location.
+	 */
+	int16 addBlob(int16 blockSize, int16 top, int16 left, int16 bottom, int16 right);
+	void deleteBlobs();
+	void deleteBlob(int16 blobNumber);
+
+private:
+	enum {
+		kMaxBlobs = 10
+	};
+
+	struct Blob {
+		int16 blobNumber;
+		int16 blockSize;
+		int16 top;
+		int16 left;
+		int16 bottom;
+		int16 right;
+	};
+
+	Common::List<Blob> _blobs;
+
+	void drawBlobs(Graphics::Surface& frame) const;
 };
 
 #pragma mark -




More information about the Scummvm-git-logs mailing list