[Scummvm-git-logs] scummvm master -> a8b779ee0e67c96c4efc951cf34accadc794e583

npjg nathanael.gentrydb8 at gmail.com
Fri Jul 3 17:19:30 UTC 2020


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

Summary:
a8b779ee0e DIRECTOR: Lazily load ink masks


Commit: a8b779ee0e67c96c4efc951cf34accadc794e583
    https://github.com/scummvm/scummvm/commit/a8b779ee0e67c96c4efc951cf34accadc794e583
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-07-03T13:19:06-04:00

Commit Message:
DIRECTOR: Lazily load ink masks

This is for mask and matte inks. Now, rather than a bitmap sprite requiring a
flood fill every time (for mask ink) the matte is created and cached when matte
ink is first requested on that cast. Mask ink does not require a new surface to
be created, but it uses the same new channel interface.

Changed paths:
    engines/director/castmember.cpp
    engines/director/castmember.h
    engines/director/graphics.cpp
    engines/director/score.cpp
    engines/director/score.h
    engines/director/stage.cpp


diff --git a/engines/director/castmember.cpp b/engines/director/castmember.cpp
index 45bd4831fb..ad48a36c80 100644
--- a/engines/director/castmember.cpp
+++ b/engines/director/castmember.cpp
@@ -45,6 +45,7 @@ BitmapCastMember::BitmapCastMember(Cast *cast, uint16 castId, Common::ReadStream
 		: CastMember(cast, castId) {
 	_type = kCastBitmap;
 	_img = nullptr;
+	_matte = nullptr;
 	_bytes = 0;
 	_pitch = 0;
 	_flags = 0;
@@ -121,6 +122,9 @@ BitmapCastMember::BitmapCastMember(Cast *cast, uint16 castId, Common::ReadStream
 BitmapCastMember::~BitmapCastMember() {
 	if (_img)
 		delete _img;
+
+	if (_matte)
+		delete _matte;
 }
 
 void BitmapCastMember::createWidget() {
@@ -135,6 +139,61 @@ void BitmapCastMember::createWidget() {
 	_widget->getSurface()->blitFrom(*_img->getSurface());
 }
 
+void BitmapCastMember::createMatte() {
+	// Like background trans, but all white pixels NOT ENCLOSED by coloured pixels
+	// are transparent
+	Graphics::Surface tmp;
+	tmp.create(_initialRect.width(), _initialRect.height(), Graphics::PixelFormat::createFormatCLUT8());
+	tmp.copyFrom(*_img->getSurface());
+
+	// Searching white color in the corners
+	int whiteColor = -1;
+
+	for (int y = 0; y < tmp.h; y++) {
+		for (int x = 0; x < tmp.w; x++) {
+			byte color = *(byte *)tmp.getBasePtr(x, y);
+
+			if (g_director->getPalette()[color * 3 + 0] == 0xff &&
+					g_director->getPalette()[color * 3 + 1] == 0xff &&
+					g_director->getPalette()[color * 3 + 2] == 0xff) {
+				whiteColor = color;
+				break;
+			}
+		}
+	}
+
+	if (whiteColor == -1) {
+		debugC(1, kDebugImages, "BitmapCastMember::createMatte(): No white color for matte image");
+	} else {
+		delete _matte;
+
+		_matte = new Graphics::FloodFill(&tmp, whiteColor, 0, true);
+
+		for (int yy = 0; yy < tmp.h; yy++) {
+			_matte->addSeed(0, yy);
+			_matte->addSeed(tmp.w - 1, yy);
+		}
+
+		for (int xx = 0; xx < tmp.w; xx++) {
+			_matte->addSeed(xx, 0);
+			_matte->addSeed(xx, tmp.h - 1);
+		}
+
+		_matte->fillMask();
+	}
+
+	tmp.free();
+}
+
+Graphics::Surface *BitmapCastMember::getMatte() {
+	// Lazy loading of mattes
+	if (!_matte) {
+		createMatte();
+	}
+
+	return _matte ? _matte->getMask() : nullptr;
+}
+
 DigitalVideoCastMember::DigitalVideoCastMember(Cast *cast, uint16 castId, Common::ReadStreamEndian &stream, uint16 version)
 		: CastMember(cast, castId) {
 	_type = kCastDigitalVideo;
diff --git a/engines/director/castmember.h b/engines/director/castmember.h
index 88b9c04d3a..59b8fa015e 100644
--- a/engines/director/castmember.h
+++ b/engines/director/castmember.h
@@ -29,6 +29,7 @@
 
 namespace Graphics {
 struct Surface;
+struct FloodFill;
 class MacText;
 class MacWindowManager;
 class MacButton;
@@ -86,9 +87,13 @@ public:
 	BitmapCastMember(Cast *cast, uint16 castId, Common::ReadStreamEndian &stream, uint32 castTag, uint16 version);
 	~BitmapCastMember();
 	virtual void createWidget() override;
+
+	void createMatte();
+	Graphics::Surface *getMatte();
 	// virtual void setColors(int *fgcolor, int *bgcolor) override;
 
 	Image::ImageDecoder *_img;
+	Graphics::FloodFill *_matte;
 
 	uint16 _pitch;
 	uint16 _regX;
diff --git a/engines/director/graphics.cpp b/engines/director/graphics.cpp
index 14313e8ef4..d924af6f79 100644
--- a/engines/director/graphics.cpp
+++ b/engines/director/graphics.cpp
@@ -836,10 +836,11 @@ void inkDrawPixel(int x, int y, int color, void *data) {
 		if (*src == p->backColor)
 			break;
 		// fall through
+	case kInkTypeMatte:
+	case kInkTypeMask:
+		// Only unmasked pixels make it here, so copy them straight
 	case kInkTypeCopy:
 		*dst = *src;
-	case kInkTypeMask:
-		// TODO: Migrate from Stage to here
 		break;
 	case kInkTypeTransparent:
 		// FIXME: Is colour to ignore always white (last entry in pallette)?
@@ -870,9 +871,6 @@ void inkDrawPixel(int x, int y, int color, void *data) {
 		if (*src != p->numColors - 1)
 			*dst = *dst | *src;
 		break;
-	case kInkTypeMatte:
-		// TODO: Migrate from Stage to here.
-		break;
 		// Arithmetic ink types
 	case kInkTypeBlend:
 		if (*src != p->numColors - 1)
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 4e831542d0..846f774db2 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -68,6 +68,37 @@ Graphics::ManagedSurface *Channel::getSurface() {
 	}
 }
 
+const Graphics::Surface *Channel::getMask() {
+	switch (_sprite->_ink) {
+	case kInkTypeMatte:
+		// Mattes are only supported in bitmaps for now. Shapes don't need mattes,
+		// as they already have all non-enclosed white pixels transparent.
+		// Matte on text has a trivial enough effect to not worry about implementing.
+		if (_sprite->_cast && _sprite->_cast->_type == kCastBitmap) {
+			return ((BitmapCastMember *)_sprite->_cast)->getMatte();
+		} else {
+			return nullptr;
+		}
+
+	case kInkTypeMask: {
+		CastMember *member = g_director->getCurrentMovie()->getCastMember(_sprite->_castId + 1);
+
+		if (_sprite->_cast && member->_initialRect == _sprite->_cast->_initialRect) {
+			return &member->_widget->getSurface()->rawSurface();
+		} else {
+			warning("Channel::getMask(): Requested cast mask, but no matching mask was found");
+			return nullptr;
+		}
+
+		// Silence warning
+		break;
+	}
+
+	default:
+		return nullptr;
+	}
+}
+
 bool Channel::isDirty(Sprite *nextSprite) {
 	// When a sprite is puppeted setTheSprite ensures that the dirty flag here is
 	// set. Otherwise, we need to rerender when the position, bounding box, or
diff --git a/engines/director/score.h b/engines/director/score.h
index 7493e80a8e..804a2a8187 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -26,6 +26,7 @@
 //#include "graphics/macgui/macwindowmanager.h"
 
 namespace Graphics {
+	struct Surface;
 	class ManagedSurface;
 	class Font;
 	class MacWindow;
@@ -112,10 +113,12 @@ struct Channel {
 
 	Channel(Sprite *sp);
 	bool isDirty(Sprite *nextSprite = nullptr);
+
 	Common::Rect getBbox();
 	Common::Point getPosition();
 	MacShape *getShape();
 	Graphics::ManagedSurface *getSurface();
+	const Graphics::Surface *getMask();
 
 	void setClean(Sprite *nextSprite, int spriteId);
 	void addDelta(Common::Point pos);
diff --git a/engines/director/stage.cpp b/engines/director/stage.cpp
index 76a0c05a2c..44d1fc024f 100644
--- a/engines/director/stage.cpp
+++ b/engines/director/stage.cpp
@@ -185,86 +185,20 @@ void Stage::inkBlitFrom(Channel *channel, Common::Rect destRect, Graphics::Manag
 		return;
 	}
 
-	// Otherwise, we are drawing a cast type that does have a built-in surface, so
-	// blit from that.
-	// TODO: Work this ink type into inkDrawPixel.
-	if (sprite->_ink == kInkTypeMatte) {
-		drawMatteSprite(channel, srcRect, destRect, blitTo);
-		return;
-	}
+	// First, get any masks that might be needed.
+	const Graphics::Surface *mask = channel->getMask();
 
 	pd.srcPoint.y = MAX(abs(srcRect.top - destRect.top), 0);
 	for (int i = 0; i < destRect.height(); i++, pd.srcPoint.y++) {
 		pd.srcPoint.x = MAX(abs(srcRect.left - destRect.left), 0);
+		const byte *msk = mask ? (const byte *)mask->getBasePtr(pd.srcPoint.x, pd.srcPoint.y) : nullptr;
 
 		for (int j = 0; j < destRect.width(); j++, pd.srcPoint.x++)
-			inkDrawPixel(destRect.left + j, destRect.top + i, 0, &pd);
+			if (!mask || (msk && (sprite->_ink == kInkTypeMatte ? !(*msk++) : *msk++)))
+				inkDrawPixel(destRect.left + j, destRect.top + i, 0, &pd);
 	}
 }
 
-void Stage::drawMatteSprite(Channel *channel, Common::Rect &srcRect, Common::Rect &destRect, Graphics::ManagedSurface *blitTo) {
-	// Like background trans, but all white pixels NOT ENCLOSED by coloured pixels are transparent
-	Graphics::Surface tmp;
-	tmp.create(destRect.width(), destRect.height(), Graphics::PixelFormat::createFormatCLUT8());
-	tmp.copyFrom(channel->getSurface()->rawSurface());
-
-	if (!blitTo->clip(srcRect, destRect))
-		return; // Out of screen
-
-	// Searching white color in the corners
-	int whiteColor = -1;
-
-	for (int y = 0; y < tmp.h; y++) {
-		for (int x = 0; x < tmp.w; x++) {
-			byte color = *(byte *)tmp.getBasePtr(x, y);
-
-			if (g_director->getPalette()[color * 3 + 0] == 0xff &&
-				g_director->getPalette()[color * 3 + 1] == 0xff &&
-				g_director->getPalette()[color * 3 + 2] == 0xff) {
-				whiteColor = color;
-				break;
-			}
-		}
-	}
-
-	if (whiteColor == -1) {
-		debugC(1, kDebugImages, "Score::drawMatteSprite(): No white color for Matte image");
-
-		for (int yy = 0; yy < destRect.height(); yy++) {
-		const byte *src = (const byte *)channel->getSurface()->getBasePtr(MAX(abs(srcRect.left - destRect.left), 0), MAX(abs(srcRect.top - destRect.top + yy), 0));
-		byte *dst = (byte *)blitTo->getBasePtr(destRect.left, destRect.top + yy);
-
-			for (int xx = 0; xx < destRect.width(); xx++, src++, dst++)
-				*dst = *src;
-		}
-	} else {
-		Graphics::FloodFill ff(&tmp, whiteColor, 0, true);
-
-		for (int yy = 0; yy < tmp.h; yy++) {
-			ff.addSeed(0, yy);
-			ff.addSeed(tmp.w - 1, yy);
-		}
-
-		for (int xx = 0; xx < tmp.w; xx++) {
-			ff.addSeed(xx, 0);
-			ff.addSeed(xx, tmp.h - 1);
-		}
-		ff.fillMask();
-
-		for (int yy = 0; yy < destRect.height(); yy++) {
-			const byte *mask = (const byte *)ff.getMask()->getBasePtr(MAX(abs(srcRect.left - destRect.left), 0), MAX(abs(srcRect.top - destRect.top - yy), 0));
-			const byte *src = (const byte *)channel->getSurface()->getBasePtr(MAX(abs(srcRect.left - destRect.left), 0), MAX(abs(srcRect.top - destRect.top - yy), 0));
-			byte *dst = (byte *)blitTo->getBasePtr(destRect.left, destRect.top + yy);
-
-			for (int xx = 0; xx < destRect.width(); xx++, src++, dst++, mask++)
-				if (*mask == 0)
-					*dst = *src;
-		}
-	}
-
-	tmp.free();
-}
-
 Common::Point Stage::getMousePos() {
 	return g_system->getEventManager()->getMousePos() - Common::Point(_dims.left, _dims.top);
 }




More information about the Scummvm-git-logs mailing list