[Scummvm-git-logs] scummvm master -> 68518fc8a9b04ccfff5822d99b28615d30762a22

moralrecordings code at moral.net.au
Mon Oct 11 17:11:14 UTC 2021


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

Summary:
d61a03d120 DIRECTOR: LINGO: Fix memory leak
0ecdd9b26f DIRECTOR: Add preliminary loader for film loops
0efc7139a9 DIRECTOR: Refactor FilmLoopCastMember to use Sprite
6f60e8c54e DIRECTOR: Add stub for FilmLoopCastMember::createWidget
e4f767c916 DIRECTOR: Move methods from Channel to Sprite
8963cf211a DIRECTOR: Move methods from Window to DirectorPlotData
257fd958e7 DIRECTOR: Add blitting code to FilmLoopCastMember
0e0254a5f7 DIRECTOR: Fix currentFrameRate loading for v4
8b240f69b8 DIRECTOR: Fix inkBlitShape to use destRect for drawing
47c5b37067 DIRECTOR: Fix use-after-free in Sprite
68518fc8a9 DIRECTOR: Fix default palette index


Commit: d61a03d12081012ae2f068f061e10794a790012a
    https://github.com/scummvm/scummvm/commit/d61a03d12081012ae2f068f061e10794a790012a
Author: Scott Percival (code at moral.net.au)
Date: 2021-10-12T01:08:34+08:00

Commit Message:
DIRECTOR: LINGO: Fix memory leak

Changed paths:
    engines/director/lingo/lingo.cpp


diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index dabbcb772b..6d25d24e1a 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -721,7 +721,7 @@ Datum Datum::eval() const {
 		return g_lingo->varFetch(*this);
 	}
 
-	return *this;
+	return Datum(*this);
 }
 
 int Datum::asInt() const {
@@ -1368,8 +1368,8 @@ Datum Lingo::varFetch(const Datum &var, bool silent) {
 	case CASTREF:
 	case CHUNKREF:
 		{
-			result.type = STRING;
-			result.u.s = new Common::String(evalChunkRef(var), Common::kUtf8);
+			Common::String chunk(evalChunkRef(var), Common::kUtf8);
+			result = Datum(chunk);
 		}
 		break;
 	default:


Commit: 0ecdd9b26f64d7ed3d86fad6eecd9ea9e5245e2d
    https://github.com/scummvm/scummvm/commit/0ecdd9b26f64d7ed3d86fad6eecd9ea9e5245e2d
Author: Scott Percival (code at moral.net.au)
Date: 2021-10-12T01:08:34+08:00

Commit Message:
DIRECTOR: Add preliminary loader for film loops

Changed paths:
    engines/director/cast.cpp
    engines/director/cast.h
    engines/director/castmember.cpp
    engines/director/castmember.h


diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index 1b9273f866..17ec4c5442 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -417,11 +417,6 @@ void Cast::loadCast() {
 		debug("STUB: Unhandled 'PICT' resource");
 	}
 
-	// Film Loop resources
-	if (_castArchive->hasResource(MKTAG('S', 'C', 'V', 'W'), -1)) {
-		debug("STUB: Unhandled 'SCVW' resource");
-	}
-
 	// External Cast Reference resources
 	if (_castArchive->hasResource(MKTAG('S', 'C', 'R', 'F'), -1)) {
 		debug("STUB: Unhandled 'SCRF' resource");
@@ -505,7 +500,31 @@ void Cast::loadCastChildren() {
 				// for D2, we shall use the castId to get the palette
 				member->_palette = g_director->getPalette(member->getID());
 			} else {
-				warning("Cast::loadSpriteChildren(): Expected 1 child for palette cast, got %d", member->_children.size());
+				warning("Cast::loadCastChildren(): Expected 1 child for palette cast, got %d", member->_children.size());
+			}
+			continue;
+		}
+
+		// Then load film loops
+		if (c->_value->_type == kCastFilmLoop) {
+			FilmLoopCastMember *member = ((FilmLoopCastMember *)c->_value);
+
+			if (_version >= kFileVer400 && _version < kFileVer500) {
+				if (member->_children.size() == 1) {
+					uint16 filmLoopId = member->_children[0].index;
+					uint32 tag = member->_children[0].tag;
+					if (_castArchive->hasResource(tag, filmLoopId)) {
+						Common::SeekableReadStreamEndian *loop = _castArchive->getResource(tag, filmLoopId);
+						debugC(2, kDebugLoading, "****** Loading '%s' id: %d, %d bytes", tag2str(tag), filmLoopId, (int)loop->size());
+						member->loadFilmLoopData(*loop);
+					} else {
+						warning("Cast::loadCastChildren(): Film loop not found");
+					}
+				} else {
+					warning("Cast::loadCastChildren(): Expected 1 child for film loop cast, got %d", member->_children.size());
+				}
+			} else {
+				warning("STUB: Cast::loadCastChildren(): Film loops not supported for version %d", _version);
 			}
 			continue;
 		}
@@ -925,8 +944,8 @@ void Cast::loadCastData(Common::SeekableReadStreamEndian &stream, uint16 id, Res
 		_loadedCast->setVal(id, new DigitalVideoCastMember(this, id, castStream, _version));
 		break;
 	case kCastFilmLoop:
-		warning("STUB: Cast::loadCastData(): kCastFilmLoop (id=%d, %d children)! This will be missing from the movie and may cause problems", id, res->children.size());
-		castInfoSize = 0;
+		debugC(3, kDebugLoading, "Cast::loadCastData(): loading kCastFilmLoop (%d children)", res->children.size());
+		_loadedCast->setVal(id, new FilmLoopCastMember(this, id, castStream, _version));
 		break;
 	case kCastPalette:
 		debugC(3, kDebugLoading, "Cast::loadCastData(): loading kCastPalette (%d children)", res->children.size());
@@ -1206,6 +1225,14 @@ void Cast::loadCastInfo(Common::SeekableReadStreamEndian &stream, uint16 id) {
 		((SoundCastMember *)member)->_looping = castInfo.flags & 16 ? 0 : 1;
 	}
 
+	// For FilmLoopCastMember, read the flags in the CastInfo
+	if (_version >= kFileVer400 && _version < kFileVer500 && member->_type == kCastFilmLoop) {
+		((FilmLoopCastMember *)member)->_looping = castInfo.flags & 64 ? 0 : 1;
+		((FilmLoopCastMember *)member)->_enableSound = castInfo.flags & 8 ? 1 : 0;
+		((FilmLoopCastMember *)member)->_crop = castInfo.flags & 2 ? 0 : 1;
+		((FilmLoopCastMember *)member)->_center = castInfo.flags & 1 ? 1 : 0;
+	}
+
 	ci->autoHilite = castInfo.flags & 2;
 	ci->scriptId = castInfo.scriptId;
 	if (ci->scriptId != 0)
diff --git a/engines/director/cast.h b/engines/director/cast.h
index 8b55496342..c5d1baf971 100644
--- a/engines/director/cast.h
+++ b/engines/director/cast.h
@@ -42,6 +42,7 @@ struct LingoArchive;
 struct Resource;
 class Stxt;
 class BitmapCastMember;
+class FilmLoopCastMember;
 class ScriptCastMember;
 class ShapeCastMember;
 class TextCastMember;
diff --git a/engines/director/castmember.cpp b/engines/director/castmember.cpp
index 3a78185174..7a8fc344ce 100644
--- a/engines/director/castmember.cpp
+++ b/engines/director/castmember.cpp
@@ -548,6 +548,128 @@ void DigitalVideoCastMember::setFrameRate(int rate) {
 	warning("STUB: DigitalVideoCastMember::setFrameRate(%d)", rate);
 }
 
+/////////////////////////////////////
+// Film loops
+/////////////////////////////////////
+
+FilmLoopCastMember::FilmLoopCastMember(Cast *cast, uint16 castId, Common::SeekableReadStreamEndian &stream, uint16 version)
+		: CastMember(cast, castId, stream) {
+	_type = kCastFilmLoop;
+	_looping = true;
+	_enableSound = true;
+	_crop = false;
+	_center = false;
+}
+
+FilmLoopCastMember::~FilmLoopCastMember() {
+
+}
+
+void FilmLoopCastMember::loadFilmLoopData(Common::SeekableReadStreamEndian &stream) {
+	_bbox = Common::Rect();
+	_frames.clear();
+
+	uint32 size = stream.readUint32BE();
+	if (debugChannelSet(5, kDebugLoading)) {
+		debugC(5, kDebugLoading, "SCVW body:");
+		uint32 pos = stream.pos();
+		stream.seek(0);
+		stream.hexdump(size);
+		stream.seek(pos);
+	}
+	uint32 framesOffset = stream.readUint32BE();
+	if (debugChannelSet(5, kDebugLoading)) {
+		debugC(5, kDebugLoading, "SCVW header:");
+		stream.hexdump(framesOffset - 8);
+	}
+	stream.skip(6);
+	uint16 channelSize = stream.readUint16BE(); // should be 20!
+	stream.skip(framesOffset - 16);
+
+	FilmLoopFrame newFrame;
+
+	while (stream.pos() < size) {
+		uint16 frameSize = stream.readUint16BE() - 2;
+		if (debugChannelSet(5, kDebugLoading)) {
+			debugC(5, kDebugLoading, "Frame entry:");
+			stream.hexdump(frameSize);
+		}
+
+		while (frameSize > 0) {
+			uint16 msgWidth = stream.readUint16BE();
+			uint16 order = stream.readUint16BE();
+			frameSize -= 4;
+
+			int channel = (order / channelSize) - 1;
+			int channelOffset = order % channelSize;
+
+			uint16 spriteCastId = 0;
+			int16 x = 0;
+			int16 y = 0;
+			uint16 width = 0;
+			uint16 height = 0;
+			if (newFrame.sprites.contains(channel)) {
+				FilmLoopSprite s = newFrame.sprites.getVal(channel);
+				spriteCastId = s.castId;
+				x = s.bbox.left;
+				y = s.bbox.top;
+				width = s.bbox.width();
+				height = s.bbox.height();
+			}
+			debugC(8, kDebugLoading, "Message: msgWidth %d, channel %d, channelOffset %d", msgWidth, channel, channelOffset);
+			if (debugChannelSet(8, kDebugLoading)) {
+				stream.hexdump(msgWidth);
+			}
+
+			for (int i = channelOffset; i < channelOffset + msgWidth; i += 2) {
+				switch (i) {
+				case 6:
+					spriteCastId = stream.readUint16BE();
+					break;
+				case 8:
+					y = stream.readSint16BE();
+					break;
+				case 10:
+					x = stream.readSint16BE();
+					break;
+				case 12:
+					height = stream.readUint16BE();
+					break;
+				case 14:
+					width = stream.readUint16BE();
+					break;
+				default:
+					stream.readUint16BE();
+					break;
+				}
+			}
+
+			frameSize -= msgWidth;
+
+			Common::Rect spriteBbox(x, y, x + width, y + height);
+			newFrame.sprites.setVal(channel, FilmLoopSprite(spriteCastId, spriteBbox));
+			if (!_bbox.isValidRect()) {
+				_bbox = spriteBbox;
+			} else {
+				_bbox.extend(spriteBbox);
+			}
+		}
+
+		if (debugChannelSet(5, kDebugLoading)) {
+			for (Common::HashMap<int, FilmLoopSprite>::iterator s = newFrame.sprites.begin(); s != newFrame.sprites.end(); ++s) {
+				debugC(5, kDebugLoading, "FilmLoopSprite: channel %d, castId %d, bbox %d %d %d %d", s->_key,
+						s->_value.castId, s->_value.bbox.left, s->_value.bbox.top,
+						s->_value.bbox.width(), s->_value.bbox.height());
+
+			}
+		}
+
+		_frames.push_back(newFrame);
+
+	}
+
+}
+
 
 /////////////////////////////////////
 // Sound
diff --git a/engines/director/castmember.h b/engines/director/castmember.h
index d76960ef6b..b2cc36be17 100644
--- a/engines/director/castmember.h
+++ b/engines/director/castmember.h
@@ -189,6 +189,35 @@ public:
 	Channel *_channel;
 };
 
+
+
+struct FilmLoopSprite {
+	uint16 castId;
+	Common::Rect bbox;
+	FilmLoopSprite() { castId = 0; }
+	FilmLoopSprite(uint16 castId1, Common::Rect &bbox1) { castId = castId1; bbox = bbox1; }
+};
+
+struct FilmLoopFrame {
+	Common::HashMap<int, FilmLoopSprite> sprites;
+};
+
+class FilmLoopCastMember : public CastMember {
+public:
+	FilmLoopCastMember(Cast *cast, uint16 castId, Common::SeekableReadStreamEndian &stream, uint16 version);
+	~FilmLoopCastMember();
+
+	void loadFilmLoopData(Common::SeekableReadStreamEndian &stream);
+
+	bool _enableSound;
+	bool _looping;
+	bool _crop;
+	bool _center;
+
+	Common::Rect _bbox;
+	Common::Array<FilmLoopFrame> _frames;
+};
+
 class SoundCastMember : public CastMember {
 public:
 	SoundCastMember(Cast *cast, uint16 castId, Common::SeekableReadStreamEndian &stream, uint16 version);


Commit: 0efc7139a9100617c8ea079edc234dbca74cc1af
    https://github.com/scummvm/scummvm/commit/0efc7139a9100617c8ea079edc234dbca74cc1af
Author: Scott Percival (code at moral.net.au)
Date: 2021-10-12T01:08:34+08:00

Commit Message:
DIRECTOR: Refactor FilmLoopCastMember to use Sprite

Changed paths:
    engines/director/castmember.cpp
    engines/director/castmember.h
    engines/director/sprite.cpp
    engines/director/sprite.h


diff --git a/engines/director/castmember.cpp b/engines/director/castmember.cpp
index 7a8fc344ce..89d3bc678c 100644
--- a/engines/director/castmember.cpp
+++ b/engines/director/castmember.cpp
@@ -30,6 +30,7 @@
 #include "director/cursor.h"
 #include "director/channel.h"
 #include "director/movie.h"
+#include "director/sprite.h"
 #include "director/sound.h"
 #include "director/window.h"
 #include "director/stxt.h"
@@ -603,63 +604,93 @@ void FilmLoopCastMember::loadFilmLoopData(Common::SeekableReadStreamEndian &stre
 			int channel = (order / channelSize) - 1;
 			int channelOffset = order % channelSize;
 
-			uint16 spriteCastId = 0;
-			int16 x = 0;
-			int16 y = 0;
-			uint16 width = 0;
-			uint16 height = 0;
+			Sprite sprite(nullptr);
 			if (newFrame.sprites.contains(channel)) {
-				FilmLoopSprite s = newFrame.sprites.getVal(channel);
-				spriteCastId = s.castId;
-				x = s.bbox.left;
-				y = s.bbox.top;
-				width = s.bbox.width();
-				height = s.bbox.height();
+				sprite = newFrame.sprites.getVal(channel);
 			}
 			debugC(8, kDebugLoading, "Message: msgWidth %d, channel %d, channelOffset %d", msgWidth, channel, channelOffset);
 			if (debugChannelSet(8, kDebugLoading)) {
 				stream.hexdump(msgWidth);
 			}
 
-			for (int i = channelOffset; i < channelOffset + msgWidth; i += 2) {
-				switch (i) {
-				case 6:
-					spriteCastId = stream.readUint16BE();
+			int fieldPosition = channelOffset;
+			int finishPosition = channelOffset + msgWidth;
+			while (fieldPosition < finishPosition) {
+				switch (fieldPosition) {
+				case kSpritePositionUnk1:
+					stream.readByte();
+					fieldPosition++;
+					break;
+				case kSpritePositionEnabled:
+					sprite._enabled = stream.readByte() != 0;
+					fieldPosition++;
+					break;
+				case kSpritePositionUnk2:
+					stream.readUint16BE();
+					fieldPosition += 2;
+					break;
+				case kSpritePositionFlags:
+					sprite._thickness = stream.readByte();
+					sprite._inkData = stream.readByte();
+					sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
+
+					if (sprite._inkData & 0x40)
+						sprite._trails = 1;
+					else
+						sprite._trails = 0;
+
+					fieldPosition += 2;
+					break;
+				case kSpritePositionCastId:
+					sprite._castId = CastMemberID(stream.readUint16(), 0);
+					fieldPosition += 2;
 					break;
-				case 8:
-					y = stream.readSint16BE();
+				case kSpritePositionY:
+					sprite._startPoint.y = stream.readUint16();
+					fieldPosition += 2;
 					break;
-				case 10:
-					x = stream.readSint16BE();
+				case kSpritePositionX:
+					sprite._startPoint.x = stream.readUint16();
+					fieldPosition += 2;
 					break;
-				case 12:
-					height = stream.readUint16BE();
+				case kSpritePositionWidth:
+					sprite._width = stream.readUint16();
+					fieldPosition += 2;
 					break;
-				case 14:
-					width = stream.readUint16BE();
+				case kSpritePositionHeight:
+					sprite._height = stream.readUint16();
+					fieldPosition += 2;
 					break;
 				default:
 					stream.readUint16BE();
+					fieldPosition += 2;
 					break;
 				}
 			}
 
 			frameSize -= msgWidth;
 
-			Common::Rect spriteBbox(x, y, x + width, y + height);
-			newFrame.sprites.setVal(channel, FilmLoopSprite(spriteCastId, spriteBbox));
-			if (!_bbox.isValidRect()) {
-				_bbox = spriteBbox;
-			} else {
-				_bbox.extend(spriteBbox);
+			Common::Rect spriteBbox(
+				sprite._startPoint.x,
+				sprite._startPoint.y,
+				sprite._startPoint.x + sprite._width,
+				sprite._startPoint.y + sprite._height
+			);
+			newFrame.sprites.setVal(channel, sprite);
+			if (!((spriteBbox.width() == 0) && (spriteBbox.height() == 0))) {
+				if ((_bbox.width() == 0) && (_bbox.height() == 0)) {
+					_bbox = spriteBbox;
+				} else {
+					_bbox.extend(spriteBbox);
+				}
 			}
 		}
 
 		if (debugChannelSet(5, kDebugLoading)) {
-			for (Common::HashMap<int, FilmLoopSprite>::iterator s = newFrame.sprites.begin(); s != newFrame.sprites.end(); ++s) {
-				debugC(5, kDebugLoading, "FilmLoopSprite: channel %d, castId %d, bbox %d %d %d %d", s->_key,
-						s->_value.castId, s->_value.bbox.left, s->_value.bbox.top,
-						s->_value.bbox.width(), s->_value.bbox.height());
+			for (Common::HashMap<int, Sprite>::iterator s = newFrame.sprites.begin(); s != newFrame.sprites.end(); ++s) {
+				debugC(5, kDebugLoading, "Sprite: channel %d, castId %s, bbox %d %d %d %d", s->_key,
+						s->_value._castId.asString().c_str(), s->_value._startPoint.x, s->_value._startPoint.y,
+						s->_value._width, s->_value._height);
 
 			}
 		}
@@ -667,6 +698,7 @@ void FilmLoopCastMember::loadFilmLoopData(Common::SeekableReadStreamEndian &stre
 		_frames.push_back(newFrame);
 
 	}
+	debugC(5, kDebugLoading, "Full bounding box: %d %d %d %d", _bbox.left, _bbox.top, _bbox.width(), _bbox.height());
 
 }
 
diff --git a/engines/director/castmember.h b/engines/director/castmember.h
index b2cc36be17..7d7cc5ac27 100644
--- a/engines/director/castmember.h
+++ b/engines/director/castmember.h
@@ -26,6 +26,7 @@
 #include "graphics/font.h"
 
 #include "director/archive.h"
+#include "director/sprite.h"
 #include "director/stxt.h"
 
 #include "director/lingo/lingo-object.h"
@@ -58,6 +59,7 @@ class AudioDecoder;
 struct CastMemberInfo;
 class Channel;
 struct Resource;
+class Sprite;
 class Stxt;
 
 class CastMember : public Object<CastMember> {
@@ -190,16 +192,8 @@ public:
 };
 
 
-
-struct FilmLoopSprite {
-	uint16 castId;
-	Common::Rect bbox;
-	FilmLoopSprite() { castId = 0; }
-	FilmLoopSprite(uint16 castId1, Common::Rect &bbox1) { castId = castId1; bbox = bbox1; }
-};
-
 struct FilmLoopFrame {
-	Common::HashMap<int, FilmLoopSprite> sprites;
+	Common::HashMap<int, Sprite> sprites;
 };
 
 class FilmLoopCastMember : public CastMember {
diff --git a/engines/director/sprite.cpp b/engines/director/sprite.cpp
index 7e5899143a..27d9275887 100644
--- a/engines/director/sprite.cpp
+++ b/engines/director/sprite.cpp
@@ -35,8 +35,8 @@ namespace Director {
 
 Sprite::Sprite(Frame *frame) {
 	_frame = frame;
-	_score = _frame->getScore();
-	_movie = _score->getMovie();
+	_score = _frame ? _frame->getScore() : nullptr;
+	_movie = _score ? _score->getMovie() : nullptr;
 
 	_scriptId = CastMemberID(0, 0);
 	_colorcode = 0;
@@ -71,6 +71,45 @@ Sprite::Sprite(Frame *frame) {
 	_stretch = 0;
 }
 
+Sprite::Sprite(const Sprite &sprite) {
+	_frame = sprite._frame;
+	_score = sprite._score;
+	_movie = sprite._movie;
+
+	_scriptId = sprite._scriptId;
+	_colorcode = sprite._colorcode;
+	_blendAmount = sprite._blendAmount;
+	_unk3 = sprite._unk3;
+
+	_enabled = sprite._enabled;
+	_castId = sprite._castId;
+	_pattern = sprite._pattern;
+
+	_spriteType = sprite._spriteType;
+	_inkData = sprite._inkData;
+	_ink = sprite._ink;
+	_trails = sprite._trails;
+
+	_matte = sprite._matte;
+	_cast = sprite._cast;
+
+	_thickness = sprite._thickness;
+	_startPoint = sprite._startPoint;
+	_width = sprite._width;
+	_height = sprite._height;
+	_moveable = sprite._moveable;
+	_editable = sprite._editable;
+	_puppet = sprite._puppet;
+	_immediate = sprite._immediate;
+	_backColor = sprite._backColor;
+	_foreColor = sprite._foreColor;
+
+	_blend = sprite._blend;
+
+	_volume = sprite._volume;
+	_stretch = sprite._stretch;
+}
+
 Sprite::~Sprite() {
 	delete _matte;
 }
diff --git a/engines/director/sprite.h b/engines/director/sprite.h
index 26ea5a14a1..04734a2dd1 100644
--- a/engines/director/sprite.h
+++ b/engines/director/sprite.h
@@ -32,8 +32,8 @@ class TextCastMember;
 
 enum SpritePosition {
 	kSpritePositionUnk1 = 0,
-	kSpritePositionEnabled,
-	kSpritePositionUnk2,
+	kSpritePositionEnabled = 1,
+	kSpritePositionUnk2 = 2,
 	kSpritePositionFlags = 4,
 	kSpritePositionCastId = 6,
 	kSpritePositionY = 8,
@@ -59,7 +59,8 @@ enum MainChannelsPosition {
 
 class Sprite {
 public:
-	Sprite(Frame *frame);
+	Sprite(Frame *frame = nullptr);
+	Sprite(const Sprite &sprite);
 	~Sprite();
 
 	Frame *getFrame() const { return _frame; }


Commit: 6f60e8c54e4ca6e7cad108e7f57e3f106241a5b3
    https://github.com/scummvm/scummvm/commit/6f60e8c54e4ca6e7cad108e7f57e3f106241a5b3
Author: Scott Percival (code at moral.net.au)
Date: 2021-10-12T01:08:34+08:00

Commit Message:
DIRECTOR: Add stub for FilmLoopCastMember::createWidget

Changed paths:
    engines/director/castmember.cpp
    engines/director/castmember.h


diff --git a/engines/director/castmember.cpp b/engines/director/castmember.cpp
index 89d3bc678c..683bea1876 100644
--- a/engines/director/castmember.cpp
+++ b/engines/director/castmember.cpp
@@ -566,6 +566,50 @@ FilmLoopCastMember::~FilmLoopCastMember() {
 
 }
 
+bool FilmLoopCastMember::isModified() {
+	if (_frames.size())
+		return true;
+
+	if (_bbox.width() && _bbox.height())
+		return true;
+
+	return false;
+}
+
+Graphics::MacWidget *FilmLoopCastMember::createWidget(Common::Rect &bbox, Channel *channel, SpriteType spriteType) {
+	Graphics::MacWidget *widget = new Graphics::MacWidget(g_director->getCurrentWindow(), bbox.left, bbox.top, bbox.width(), bbox.height(), g_director->_wm, false);
+
+	if (channel->_filmLoopFrame >= _frames.size()) {
+		warning("Film loop frame %d requested, only %d available", channel->_filmLoopFrame, _frames.size());
+		return widget;
+	}
+
+	// get the list of sprite IDs for this frame
+	Common::Array<int> spriteIds;
+	for (Common::HashMap<int, Director::Sprite>::iterator iter = _frames[channel->_filmLoopFrame].sprites.begin(); iter != _frames[channel->_filmLoopFrame].sprites.end(); ++iter) {
+		spriteIds.push_back(iter->_key);
+	}
+	Common::sort(spriteIds.begin(), spriteIds.end());
+
+	// render the sprites in order onto the widget surface
+	for (Common::Array<int>::iterator iter = spriteIds.begin(); iter != spriteIds.end(); ++iter) {
+		Sprite src = _frames[channel->_filmLoopFrame].sprites[*iter];
+		if (src._castId.member == 0)
+			continue;
+		// translate sprite relative to the global bounding box
+		int16 x = (src._startPoint.x - _bbox.left) * bbox.width() / _bbox.width() + bbox.left;
+		int16 y = (src._startPoint.y - _bbox.top) * bbox.height() / _bbox.height() + bbox.top;
+		int16 width = src._width * bbox.width() / _bbox.width();
+		int16 height = src._height * bbox.height() / _bbox.height();
+		Common::Rect srcBbox(x, y, x + width, y + height);
+		//Graphics::MacWidget *srcWidget = src._cast->createWidget(srcBbox, channel, spriteType);
+		//widget->getSurface()->blitFrom(*srcWidget->getSurface(), Common::Point(x, y));
+		//delete srcWidget;
+	}
+
+	return widget;
+}
+
 void FilmLoopCastMember::loadFilmLoopData(Common::SeekableReadStreamEndian &stream) {
 	_bbox = Common::Rect();
 	_frames.clear();
@@ -605,6 +649,7 @@ void FilmLoopCastMember::loadFilmLoopData(Common::SeekableReadStreamEndian &stre
 			int channelOffset = order % channelSize;
 
 			Sprite sprite(nullptr);
+			sprite._movie = g_director->getCurrentMovie();
 			if (newFrame.sprites.contains(channel)) {
 				sprite = newFrame.sprites.getVal(channel);
 			}
@@ -642,7 +687,7 @@ void FilmLoopCastMember::loadFilmLoopData(Common::SeekableReadStreamEndian &stre
 					fieldPosition += 2;
 					break;
 				case kSpritePositionCastId:
-					sprite._castId = CastMemberID(stream.readUint16(), 0);
+					sprite.setCast(CastMemberID(stream.readUint16(), 0));
 					fieldPosition += 2;
 					break;
 				case kSpritePositionY:
diff --git a/engines/director/castmember.h b/engines/director/castmember.h
index 7d7cc5ac27..84067b7411 100644
--- a/engines/director/castmember.h
+++ b/engines/director/castmember.h
@@ -201,6 +201,9 @@ public:
 	FilmLoopCastMember(Cast *cast, uint16 castId, Common::SeekableReadStreamEndian &stream, uint16 version);
 	~FilmLoopCastMember();
 
+	virtual bool isModified() override;
+	virtual Graphics::MacWidget *createWidget(Common::Rect &bbox, Channel *channel, SpriteType spriteType) override;
+
 	void loadFilmLoopData(Common::SeekableReadStreamEndian &stream);
 
 	bool _enableSound;


Commit: e4f767c91621f35aa0243be8675807291ef19f5b
    https://github.com/scummvm/scummvm/commit/e4f767c91621f35aa0243be8675807291ef19f5b
Author: Scott Percival (code at moral.net.au)
Date: 2021-10-12T01:08:34+08:00

Commit Message:
DIRECTOR: Move methods from Channel to Sprite

Changed paths:
    engines/director/channel.cpp
    engines/director/channel.h
    engines/director/sprite.cpp
    engines/director/sprite.h


diff --git a/engines/director/channel.cpp b/engines/director/channel.cpp
index e545afbf87..079e9abdf2 100644
--- a/engines/director/channel.cpp
+++ b/engines/director/channel.cpp
@@ -28,6 +28,7 @@
 #include "director/channel.h"
 #include "director/sprite.h"
 #include "director/castmember.h"
+#include "director/types.h"
 #include "director/window.h"
 
 #include "graphics/macgui/mactext.h"
@@ -56,6 +57,8 @@ Channel::Channel(Sprite *sp, int priority) {
 	_startTime = 0;
 	_stopTime = 0;
 
+	_filmLoopFrame = 0;
+
 	_visible = true;
 	_dirty = true;
 
@@ -69,7 +72,7 @@ Channel::~Channel() {
 }
 
 DirectorPlotData Channel::getPlotData() {
-	DirectorPlotData pd(g_director->_wm, _sprite->_spriteType, _sprite->_ink, _sprite->_blend, getBackColor(), getForeColor());
+	DirectorPlotData pd(g_director->_wm, _sprite->_spriteType, _sprite->_ink, _sprite->_blend, _sprite->getBackColor(), _sprite->getForeColor());
 	pd.colorWhite = pd._wm->_colorWhite;
 	pd.colorBlack = pd._wm->_colorBlack;
 	pd.dst = nullptr;
@@ -77,7 +80,7 @@ DirectorPlotData Channel::getPlotData() {
 	pd.srf = getSurface();
 	if (!pd.srf && _sprite->_spriteType != kBitmapSprite) {
 		// Shapes come colourized from macDrawPixel
-		pd.ms = getShape();
+		pd.ms = _sprite->getShape();
 		pd.applyColor = false;
 	} else {
 		pd.setApplyColor();
@@ -338,6 +341,18 @@ void Channel::setClean(Sprite *nextSprite, int spriteId, bool partial) {
 					((DigitalVideoCastMember *)nextSprite->_cast)->loadVideo(pathMakeRelative(path, true, false));
 					((DigitalVideoCastMember *)nextSprite->_cast)->startVideo(this);
 				}
+			} else if (nextSprite->_cast->_type == kCastFilmLoop) {
+				// brand new film loop, reset the frame counter
+				_filmLoopFrame = 0;
+			}
+		}
+
+		// if the next sprite in the channel shares the cast member
+		if (nextSprite->_cast && _sprite->_castId == nextSprite->_castId) {
+			if (nextSprite->_cast->_type == kCastFilmLoop) {
+				// increment the film loop counter
+				_filmLoopFrame += 1;
+				_filmLoopFrame %= ((FilmLoopCastMember *)nextSprite->_cast)->_frames.size();
 			}
 		}
 
@@ -694,86 +709,4 @@ Common::Point Channel::getPosition() {
 	return res;
 }
 
-MacShape *Channel::getShape() {
-	if (!_sprite->isQDShape() && (_sprite->_cast && _sprite->_cast->_type != kCastShape))
-		return nullptr;
-
-	MacShape *shape = new MacShape();
-
-	shape->ink = _sprite->_ink;
-	shape->spriteType = _sprite->_spriteType;
-	shape->foreColor = _sprite->_foreColor;
-	shape->backColor = _sprite->_backColor;
-	shape->lineSize = _sprite->_thickness & 0x3;
-	shape->pattern = _sprite->getPattern();
-
-	if (g_director->getVersion() >= 300 && shape->spriteType == kCastMemberSprite) {
-		if (!_sprite->_cast) {
-			warning("Channel::getShape(): kCastMemberSprite has no cast defined");
-			delete shape;
-			return nullptr;
-		}
-
-		ShapeCastMember *sc = (ShapeCastMember *)_sprite->_cast;
-		switch (sc->_shapeType) {
-		case kShapeRectangle:
-			shape->spriteType = sc->_fillType ? kRectangleSprite : kOutlinedRectangleSprite;
-			break;
-		case kShapeRoundRect:
-			shape->spriteType = sc->_fillType ? kRoundedRectangleSprite : kOutlinedRoundedRectangleSprite;
-			break;
-		case kShapeOval:
-			shape->spriteType = sc->_fillType ? kOvalSprite : kOutlinedOvalSprite;
-			break;
-		case kShapeLine:
-			shape->spriteType = sc->_lineDirection == 6 ? kLineBottomTopSprite : kLineTopBottomSprite;
-			break;
-		default:
-			break;
-		}
-
-		if (g_director->getVersion() >= 400) {
-			shape->foreColor = sc->getForeColor();
-			shape->backColor = sc->getBackColor();
-			shape->lineSize = sc->_lineThickness;
-			shape->ink = sc->_ink;
-		}
-	}
-
-	// for outlined shapes, line thickness of 1 means invisible.
-	shape->lineSize -= 1;
-
-	return shape;
-}
-
-uint32 Channel::getBackColor() {
-	if (!_sprite->_cast)
-		return _sprite->_backColor;
-
-	switch (_sprite->_cast->_type) {
-	case kCastText:
-	case kCastButton:
-	case kCastShape: {
-		return _sprite->_cast->getBackColor();
-	}
-	default:
-		return _sprite->_backColor;
-	}
-}
-
-uint32 Channel::getForeColor() {
-	if (!_sprite->_cast)
-		return _sprite->_foreColor;
-
-	switch (_sprite->_cast->_type) {
-	case kCastText:
-	case kCastButton:
-	case kCastShape: {
-		return _sprite->_cast->getForeColor();
-	}
-	default:
-		return _sprite->_foreColor;
-	}
-}
-
 } // End of namespace Director
diff --git a/engines/director/channel.h b/engines/director/channel.h
index cd81175b50..2167ec3480 100644
--- a/engines/director/channel.h
+++ b/engines/director/channel.h
@@ -97,18 +97,18 @@ public:
 	int _width;
 	int _height;
 
-	// Using in digital movie sprites
+	// Used in digital movie sprites
 	double _movieRate;
 	int _movieTime;
 	int _startTime;
 	int _stopTime;
 
+	// Used in film loops
+	uint _filmLoopFrame;
+
 private:
 	Graphics::ManagedSurface *getSurface();
-	MacShape *getShape();
 	Common::Point getPosition();
-	uint32 getForeColor();
-	uint32 getBackColor();
 
 	void addRegistrationOffset(Common::Point &pos, bool subtract = false);
 };
diff --git a/engines/director/sprite.cpp b/engines/director/sprite.cpp
index 27d9275887..4dda654a18 100644
--- a/engines/director/sprite.cpp
+++ b/engines/director/sprite.cpp
@@ -187,6 +187,88 @@ Graphics::Surface *Sprite::getQDMatte() {
 	return _matte ? _matte->getMask() : nullptr;
 }
 
+MacShape *Sprite::getShape() {
+	if (!isQDShape() && (_cast && _cast->_type != kCastShape))
+		return nullptr;
+
+	MacShape *shape = new MacShape();
+
+	shape->ink = _ink;
+	shape->spriteType = _spriteType;
+	shape->foreColor = _foreColor;
+	shape->backColor = _backColor;
+	shape->lineSize = _thickness & 0x3;
+	shape->pattern = getPattern();
+
+	if (g_director->getVersion() >= 300 && shape->spriteType == kCastMemberSprite) {
+		if (!_cast) {
+			warning("Sprite::getShape(): kCastMemberSprite has no cast defined");
+			delete shape;
+			return nullptr;
+		}
+
+		ShapeCastMember *sc = (ShapeCastMember *)_cast;
+		switch (sc->_shapeType) {
+		case kShapeRectangle:
+			shape->spriteType = sc->_fillType ? kRectangleSprite : kOutlinedRectangleSprite;
+			break;
+		case kShapeRoundRect:
+			shape->spriteType = sc->_fillType ? kRoundedRectangleSprite : kOutlinedRoundedRectangleSprite;
+			break;
+		case kShapeOval:
+			shape->spriteType = sc->_fillType ? kOvalSprite : kOutlinedOvalSprite;
+			break;
+		case kShapeLine:
+			shape->spriteType = sc->_lineDirection == 6 ? kLineBottomTopSprite : kLineTopBottomSprite;
+			break;
+		default:
+			break;
+		}
+
+		if (g_director->getVersion() >= 400) {
+			shape->foreColor = sc->getForeColor();
+			shape->backColor = sc->getBackColor();
+			shape->lineSize = sc->_lineThickness;
+			shape->ink = sc->_ink;
+		}
+	}
+
+	// for outlined shapes, line thickness of 1 means invisible.
+	shape->lineSize -= 1;
+
+	return shape;
+}
+
+uint32 Sprite::getBackColor() {
+	if (!_cast)
+		return _backColor;
+
+	switch (_cast->_type) {
+	case kCastText:
+	case kCastButton:
+	case kCastShape: {
+		return _cast->getBackColor();
+	}
+	default:
+		return _backColor;
+	}
+}
+
+uint32 Sprite::getForeColor() {
+	if (!_cast)
+		return _foreColor;
+
+	switch (_cast->_type) {
+	case kCastText:
+	case kCastButton:
+	case kCastShape: {
+		return _cast->getForeColor();
+	}
+	default:
+		return _foreColor;
+	}
+}
+
 void Sprite::updateEditable() {
 	if (!_cast)
 		return;
diff --git a/engines/director/sprite.h b/engines/director/sprite.h
index 04734a2dd1..86b2e15dde 100644
--- a/engines/director/sprite.h
+++ b/engines/director/sprite.h
@@ -80,6 +80,9 @@ public:
 	bool isQDShape();
 	Graphics::Surface *getQDMatte();
 	void createQDMatte();
+	MacShape *getShape();
+	uint32 getForeColor();
+	uint32 getBackColor();
 
 	Frame *_frame;
 	Score *_score;


Commit: 8963cf211ac8d6cb2558899a2a4c48e168f4a1d1
    https://github.com/scummvm/scummvm/commit/8963cf211ac8d6cb2558899a2a4c48e168f4a1d1
Author: Scott Percival (code at moral.net.au)
Date: 2021-10-12T01:08:34+08:00

Commit Message:
DIRECTOR: Move methods from Window to DirectorPlotData

Changed paths:
    engines/director/director.h
    engines/director/graphics.cpp
    engines/director/window.cpp
    engines/director/window.h


diff --git a/engines/director/director.h b/engines/director/director.h
index ee79766255..4f6a989a8e 100644
--- a/engines/director/director.h
+++ b/engines/director/director.h
@@ -126,6 +126,8 @@ struct MacShape {
 	Graphics::MacPlotData *pd;
 };
 
+const int SCALE_THRESHOLD = 0x100;
+
 // An extension of MacPlotData for interfacing with inks and patterns without
 // needing extra surfaces.
 struct DirectorPlotData {
@@ -148,7 +150,12 @@ struct DirectorPlotData {
 	uint32 foreColor;
 	bool applyColor;
 
-	void setApplyColor(); // graphics.cpp
+	// graphics.cpp
+	void setApplyColor();
+	uint32 preprocessColor(uint32 src);
+	void inkBlitShape(Common::Rect &srcRect);
+	void inkBlitSurface(Common::Rect &srcRect, const Graphics::Surface *mask);
+	void inkBlitStretchSurface(Common::Rect &srcRect, const Graphics::Surface *mask);
 
 	DirectorPlotData(Graphics::MacWindowManager *w, SpriteType s, InkType i, int a, uint32 b, uint32 f) : _wm(w), sprite(s), ink(i), alpha(a), backColor(b), foreColor(f) {
 		srf = nullptr;
diff --git a/engines/director/graphics.cpp b/engines/director/graphics.cpp
index 099873c6dc..9b0df3f0c9 100644
--- a/engines/director/graphics.cpp
+++ b/engines/director/graphics.cpp
@@ -300,4 +300,184 @@ void DirectorPlotData::setApplyColor() {
 	}
 }
 
+uint32 DirectorPlotData::preprocessColor(uint32 src) {
+	// HACK: Right now this method is just used for adjusting the colourization on text
+	// sprites, as it would be costly to colourize the chunks on the fly each
+	// time a section needs drawing. It's ugly but mostly works.
+	if (sprite == kTextSprite) {
+		switch(ink) {
+		case kInkTypeMask:
+			src = (src == backColor ? foreColor : 0xff);
+			break;
+		case kInkTypeReverse:
+			src = (src == foreColor ? 0 : colorWhite);
+			break;
+		case kInkTypeNotReverse:
+			src = (src == backColor ? colorWhite : 0);
+			break;
+			// looks like this part is wrong, maybe it's very same as reverse?
+			// check warlock/DATA/WARLOCKSHIP/ENG/ABOUT to see more detail.
+//		case kInkTypeGhost:
+//			src = (src == foreColor ? backColor : colorWhite);
+//			break;
+		case kInkTypeNotGhost:
+			src = (src == backColor ? colorWhite : backColor);
+			break;
+		case kInkTypeNotCopy:
+			src = (src == foreColor ? backColor : foreColor);
+			break;
+		case kInkTypeNotTrans:
+			src = (src == foreColor ? backColor : colorWhite);
+			break;
+		default:
+			break;
+		}
+	}
+
+	return src;
+}
+
+void DirectorPlotData::inkBlitShape(Common::Rect &srcRect) {
+	if (!ms)
+		return;
+
+	// Preprocess shape colours
+	switch (ink) {
+	case kInkTypeNotTrans:
+	case kInkTypeNotReverse:
+	case kInkTypeNotGhost:
+		return;
+	case kInkTypeReverse:
+		ms->foreColor = 0;
+		ms->backColor = 0;
+		break;
+	default:
+		break;
+	}
+
+	Common::Rect fillAreaRect((int)srcRect.width(), (int)srcRect.height());
+	fillAreaRect.moveTo(srcRect.left, srcRect.top);
+	Graphics::MacPlotData plotFill(dst, nullptr, &g_director->getPatterns(), ms->pattern, srcRect.left, srcRect.top, 1, ms->backColor);
+
+	Common::Rect strokeRect(MAX((int)srcRect.width() - ms->lineSize, 0), MAX((int)srcRect.height() - ms->lineSize, 0));
+	strokeRect.moveTo(srcRect.left, srcRect.top);
+	Graphics::MacPlotData plotStroke(dst, nullptr, &g_director->getPatterns(), 1, strokeRect.left, strokeRect.top, ms->lineSize, ms->backColor);
+
+	switch (ms->spriteType) {
+	case kRectangleSprite:
+		ms->pd = &plotFill;
+		Graphics::drawFilledRect(fillAreaRect, ms->foreColor, g_director->getInkDrawPixel(), this);
+		// fall through
+	case kOutlinedRectangleSprite:
+		// if we have lineSize <= 0, means we are not drawing anything. so we may return directly.
+		if (ms->lineSize <= 0)
+			break;
+		ms->pd = &plotStroke;
+		Graphics::drawRect(strokeRect, ms->foreColor, g_director->getInkDrawPixel(), this);
+		break;
+	case kRoundedRectangleSprite:
+		ms->pd = &plotFill;
+		Graphics::drawRoundRect(fillAreaRect, 12, ms->foreColor, true, g_director->getInkDrawPixel(), this);
+		// fall through
+	case kOutlinedRoundedRectangleSprite:
+		if (ms->lineSize <= 0)
+			break;
+		ms->pd = &plotStroke;
+		Graphics::drawRoundRect(strokeRect, 12, ms->foreColor, false, g_director->getInkDrawPixel(), this);
+		break;
+	case kOvalSprite:
+		ms->pd = &plotFill;
+		Graphics::drawEllipse(fillAreaRect.left, fillAreaRect.top, fillAreaRect.right, fillAreaRect.bottom, ms->foreColor, true, g_director->getInkDrawPixel(), this);
+		// fall through
+	case kOutlinedOvalSprite:
+		if (ms->lineSize <= 0)
+			break;
+		ms->pd = &plotStroke;
+		Graphics::drawEllipse(strokeRect.left, strokeRect.top, strokeRect.right, strokeRect.bottom, ms->foreColor, false, g_director->getInkDrawPixel(), this);
+		break;
+	case kLineTopBottomSprite:
+		ms->pd = &plotStroke;
+		Graphics::drawLine(strokeRect.left, strokeRect.top, strokeRect.right, strokeRect.bottom, ms->foreColor, g_director->getInkDrawPixel(), this);
+		break;
+	case kLineBottomTopSprite:
+		ms->pd = &plotStroke;
+		Graphics::drawLine(strokeRect.left, strokeRect.bottom, strokeRect.right, strokeRect.top, ms->foreColor, g_director->getInkDrawPixel(), this);
+		break;
+	default:
+		warning("DirectorPlotData::inkBlitShape: Expected shape type but got type %d", ms->spriteType);
+	}
+}
+
+void DirectorPlotData::inkBlitSurface(Common::Rect &srcRect, const Graphics::Surface *mask) {
+	if (!srf)
+		return;
+
+	// TODO: Determine why colourization causes problems in Warlock
+	if (sprite == kTextSprite)
+		applyColor = false;
+
+	srcPoint.y = abs(srcRect.top - destRect.top);
+	for (int i = 0; i < destRect.height(); i++, srcPoint.y++) {
+		if (_wm->_pixelformat.bytesPerPixel == 1) {
+			srcPoint.x = abs(srcRect.left - destRect.left);
+			const byte *msk = mask ? (const byte *)mask->getBasePtr(srcPoint.x, srcPoint.y) : nullptr;
+
+			for (int j = 0; j < destRect.width(); j++, srcPoint.x++) {
+				if (!mask || (msk && !(*msk++))) {
+					(g_director->getInkDrawPixel())(destRect.left + j, destRect.top + i,
+											preprocessColor(*((byte *)srf->getBasePtr(srcPoint.x, srcPoint.y))), this);
+				}
+			}
+		} else {
+			srcPoint.x = abs(srcRect.left - destRect.left);
+			const uint32 *msk = mask ? (const uint32 *)mask->getBasePtr(srcPoint.x, srcPoint.y) : nullptr;
+
+			for (int j = 0; j < destRect.width(); j++, srcPoint.x++) {
+				if (!mask || (msk && !(*msk++))) {
+					(g_director->getInkDrawPixel())(destRect.left + j, destRect.top + i,
+											preprocessColor(*((int *)srf->getBasePtr(srcPoint.x, srcPoint.y))), this);
+				}
+			}
+		}
+	}
+}
+
+void DirectorPlotData::inkBlitStretchSurface(Common::Rect &srcRect, const Graphics::Surface *mask) {
+	if (!srf)
+		return;
+
+	// TODO: Determine why colourization causes problems in Warlock
+	if (sprite == kTextSprite)
+		applyColor = false;
+
+	int scaleX = SCALE_THRESHOLD * srcRect.width() / destRect.width();
+	int scaleY = SCALE_THRESHOLD * srcRect.height() / destRect.height();
+
+	srcPoint.y = abs(srcRect.top - destRect.top);
+
+	for (int i = 0, scaleYCtr = 0; i < destRect.height(); i++, scaleYCtr += scaleY, srcPoint.y++) {
+		if (_wm->_pixelformat.bytesPerPixel == 1) {
+			srcPoint.x = abs(srcRect.left - destRect.left);
+			const byte *msk = mask ? (const byte *)mask->getBasePtr(srcPoint.x, srcPoint.y) : nullptr;
+
+			for (int xCtr = 0, scaleXCtr = 0; xCtr < destRect.width(); xCtr++, scaleXCtr += scaleX, srcPoint.x++) {
+				if (!mask || !(*msk++)) {
+				(g_director->getInkDrawPixel())(destRect.left + xCtr, destRect.top + i,
+										preprocessColor(*((byte *)srf->getBasePtr(scaleXCtr / SCALE_THRESHOLD, scaleYCtr / SCALE_THRESHOLD))), this);
+				}
+			}
+		} else {
+			srcPoint.x = abs(srcRect.left - destRect.left);
+			const uint32 *msk = mask ? (const uint32 *)mask->getBasePtr(srcPoint.x, srcPoint.y) : nullptr;
+
+			for (int xCtr = 0, scaleXCtr = 0; xCtr < destRect.width(); xCtr++, scaleXCtr += scaleX, srcPoint.x++) {
+				if (!mask || !(*msk++)) {
+				(g_director->getInkDrawPixel())(destRect.left + xCtr, destRect.top + i,
+										preprocessColor(*((int *)srf->getBasePtr(scaleXCtr / SCALE_THRESHOLD, scaleYCtr / SCALE_THRESHOLD))), this);
+				}
+			}
+		}
+	}
+}
+
 } // End of namespace Director
diff --git a/engines/director/window.cpp b/engines/director/window.cpp
index 0bdcc0784f..3e50e30ada 100644
--- a/engines/director/window.cpp
+++ b/engines/director/window.cpp
@@ -198,13 +198,13 @@ void Window::inkBlitFrom(Channel *channel, Common::Rect destRect, Graphics::Mana
 	pd.dst = blitTo;
 
 	if (pd.ms) {
-		inkBlitShape(&pd, srcRect);
+		pd.inkBlitShape(srcRect);
 	} else if (pd.srf) {
 		if (channel->isStretched()) {
 			srcRect = channel->getBbox(true);
-			inkBlitStretchSurface(&pd, srcRect, channel->getMask());
+			pd.inkBlitStretchSurface(srcRect, channel->getMask());
 		} else {
-			inkBlitSurface(&pd, srcRect, channel->getMask());
+			pd.inkBlitSurface(srcRect, channel->getMask());
 		}
 	} else {
 		if (debugChannelSet(kDebugImages, 2))
@@ -212,186 +212,6 @@ void Window::inkBlitFrom(Channel *channel, Common::Rect destRect, Graphics::Mana
 	}
 }
 
-void Window::inkBlitShape(DirectorPlotData *pd, Common::Rect &srcRect) {
-	if (!pd->ms)
-		return;
-
-	// Preprocess shape colours
-	switch (pd->ink) {
-	case kInkTypeNotTrans:
-	case kInkTypeNotReverse:
-	case kInkTypeNotGhost:
-		return;
-	case kInkTypeReverse:
-		pd->ms->foreColor = 0;
-		pd->ms->backColor = 0;
-		break;
-	default:
-		break;
-	}
-
-	Common::Rect fillAreaRect((int)srcRect.width(), (int)srcRect.height());
-	fillAreaRect.moveTo(srcRect.left, srcRect.top);
-	Graphics::MacPlotData plotFill(pd->dst, nullptr, &g_director->getPatterns(), pd->ms->pattern, srcRect.left, srcRect.top, 1, pd->ms->backColor);
-
-	Common::Rect strokeRect(MAX((int)srcRect.width() - pd->ms->lineSize, 0), MAX((int)srcRect.height() - pd->ms->lineSize, 0));
-	strokeRect.moveTo(srcRect.left, srcRect.top);
-	Graphics::MacPlotData plotStroke(pd->dst, nullptr, &g_director->getPatterns(), 1, strokeRect.left, strokeRect.top, pd->ms->lineSize, pd->ms->backColor);
-
-	switch (pd->ms->spriteType) {
-	case kRectangleSprite:
-		pd->ms->pd = &plotFill;
-		Graphics::drawFilledRect(fillAreaRect, pd->ms->foreColor, g_director->getInkDrawPixel(), pd);
-		// fall through
-	case kOutlinedRectangleSprite:
-		// if we have lineSize <= 0, means we are not drawing anything. so we may return directly.
-		if (pd->ms->lineSize <= 0)
-			break;
-		pd->ms->pd = &plotStroke;
-		Graphics::drawRect(strokeRect, pd->ms->foreColor, g_director->getInkDrawPixel(), pd);
-		break;
-	case kRoundedRectangleSprite:
-		pd->ms->pd = &plotFill;
-		Graphics::drawRoundRect(fillAreaRect, 12, pd->ms->foreColor, true, g_director->getInkDrawPixel(), pd);
-		// fall through
-	case kOutlinedRoundedRectangleSprite:
-		if (pd->ms->lineSize <= 0)
-			break;
-		pd->ms->pd = &plotStroke;
-		Graphics::drawRoundRect(strokeRect, 12, pd->ms->foreColor, false, g_director->getInkDrawPixel(), pd);
-		break;
-	case kOvalSprite:
-		pd->ms->pd = &plotFill;
-		Graphics::drawEllipse(fillAreaRect.left, fillAreaRect.top, fillAreaRect.right, fillAreaRect.bottom, pd->ms->foreColor, true, g_director->getInkDrawPixel(), pd);
-		// fall through
-	case kOutlinedOvalSprite:
-		if (pd->ms->lineSize <= 0)
-			break;
-		pd->ms->pd = &plotStroke;
-		Graphics::drawEllipse(strokeRect.left, strokeRect.top, strokeRect.right, strokeRect.bottom, pd->ms->foreColor, false, g_director->getInkDrawPixel(), pd);
-		break;
-	case kLineTopBottomSprite:
-		pd->ms->pd = &plotStroke;
-		Graphics::drawLine(strokeRect.left, strokeRect.top, strokeRect.right, strokeRect.bottom, pd->ms->foreColor, g_director->getInkDrawPixel(), pd);
-		break;
-	case kLineBottomTopSprite:
-		pd->ms->pd = &plotStroke;
-		Graphics::drawLine(strokeRect.left, strokeRect.bottom, strokeRect.right, strokeRect.top, pd->ms->foreColor, g_director->getInkDrawPixel(), pd);
-		break;
-	default:
-		warning("Window::inkBlitFrom: Expected shape type but got type %d", pd->ms->spriteType);
-	}
-}
-
-void Window::inkBlitSurface(DirectorPlotData *pd, Common::Rect &srcRect, const Graphics::Surface *mask) {
-	if (!pd->srf)
-		return;
-
-	// TODO: Determine why colourization causes problems in Warlock
-	if (pd->sprite == kTextSprite)
-		pd->applyColor = false;
-
-	pd->srcPoint.y = abs(srcRect.top - pd->destRect.top);
-	for (int i = 0; i < pd->destRect.height(); i++, pd->srcPoint.y++) {
-		if (_wm->_pixelformat.bytesPerPixel == 1) {
-			pd->srcPoint.x = abs(srcRect.left - pd->destRect.left);
-			const byte *msk = mask ? (const byte *)mask->getBasePtr(pd->srcPoint.x, pd->srcPoint.y) : nullptr;
-
-			for (int j = 0; j < pd->destRect.width(); j++, pd->srcPoint.x++) {
-				if (!mask || (msk && !(*msk++))) {
-					(g_director->getInkDrawPixel())(pd->destRect.left + j, pd->destRect.top + i,
-											preprocessColor(pd, *((byte *)pd->srf->getBasePtr(pd->srcPoint.x, pd->srcPoint.y))), pd);
-				}
-			}
-		} else {
-			pd->srcPoint.x = abs(srcRect.left - pd->destRect.left);
-			const uint32 *msk = mask ? (const uint32 *)mask->getBasePtr(pd->srcPoint.x, pd->srcPoint.y) : nullptr;
-
-			for (int j = 0; j < pd->destRect.width(); j++, pd->srcPoint.x++) {
-				if (!mask || (msk && !(*msk++))) {
-					(g_director->getInkDrawPixel())(pd->destRect.left + j, pd->destRect.top + i,
-											preprocessColor(pd, *((int *)pd->srf->getBasePtr(pd->srcPoint.x, pd->srcPoint.y))), pd);
-				}
-			}
-		}
-	}
-}
-
-void Window::inkBlitStretchSurface(DirectorPlotData *pd, Common::Rect &srcRect, const Graphics::Surface *mask) {
-	if (!pd->srf)
-		return;
-
-	// TODO: Determine why colourization causes problems in Warlock
-	if (pd->sprite == kTextSprite)
-		pd->applyColor = false;
-
-	int scaleX = SCALE_THRESHOLD * srcRect.width() / pd->destRect.width();
-	int scaleY = SCALE_THRESHOLD * srcRect.height() / pd->destRect.height();
-
-	pd->srcPoint.y = abs(srcRect.top - pd->destRect.top);
-
-	for (int i = 0, scaleYCtr = 0; i < pd->destRect.height(); i++, scaleYCtr += scaleY, pd->srcPoint.y++) {
-		if (_wm->_pixelformat.bytesPerPixel == 1) {
-			pd->srcPoint.x = abs(srcRect.left - pd->destRect.left);
-			const byte *msk = mask ? (const byte *)mask->getBasePtr(pd->srcPoint.x, pd->srcPoint.y) : nullptr;
-
-			for (int xCtr = 0, scaleXCtr = 0; xCtr < pd->destRect.width(); xCtr++, scaleXCtr += scaleX, pd->srcPoint.x++) {
-				if (!mask || !(*msk++)) {
-				(g_director->getInkDrawPixel())(pd->destRect.left + xCtr, pd->destRect.top + i,
-										preprocessColor(pd, *((byte *)pd->srf->getBasePtr(scaleXCtr / SCALE_THRESHOLD, scaleYCtr / SCALE_THRESHOLD))), pd);
-				}
-			}
-		} else {
-			pd->srcPoint.x = abs(srcRect.left - pd->destRect.left);
-			const uint32 *msk = mask ? (const uint32 *)mask->getBasePtr(pd->srcPoint.x, pd->srcPoint.y) : nullptr;
-
-			for (int xCtr = 0, scaleXCtr = 0; xCtr < pd->destRect.width(); xCtr++, scaleXCtr += scaleX, pd->srcPoint.x++) {
-				if (!mask || !(*msk++)) {
-				(g_director->getInkDrawPixel())(pd->destRect.left + xCtr, pd->destRect.top + i,
-										preprocessColor(pd, *((int *)pd->srf->getBasePtr(scaleXCtr / SCALE_THRESHOLD, scaleYCtr / SCALE_THRESHOLD))), pd);
-				}
-			}
-		}
-	}
-}
-
-int Window::preprocessColor(DirectorPlotData *p, uint32 src) {
-	// HACK: Right now this method is just used for adjusting the colourization on text
-	// sprites, as it would be costly to colourize the chunks on the fly each
-	// time a section needs drawing. It's ugly but mostly works.
-	if (p->sprite == kTextSprite) {
-		switch(p->ink) {
-		case kInkTypeMask:
-			src = (src == p->backColor ? p->foreColor : 0xff);
-			break;
-		case kInkTypeReverse:
-			src = (src == p->foreColor ? 0 : p->colorWhite);
-			break;
-		case kInkTypeNotReverse:
-			src = (src == p->backColor ? p->colorWhite : 0);
-			break;
-			// looks like this part is wrong, maybe it's very same as reverse?
-			// check warlock/DATA/WARLOCKSHIP/ENG/ABOUT to see more detail.
-//		case kInkTypeGhost:
-//			src = (src == p->foreColor ? p->backColor : p->colorWhite);
-//			break;
-		case kInkTypeNotGhost:
-			src = (src == p->backColor ? p->colorWhite : p->backColor);
-			break;
-		case kInkTypeNotCopy:
-			src = (src == p->foreColor ? p->backColor : p->foreColor);
-			break;
-		case kInkTypeNotTrans:
-			src = (src == p->foreColor ? p->backColor : p->colorWhite);
-			break;
-		default:
-			break;
-		}
-	}
-
-	return src;
-}
-
 Common::Point Window::getMousePos() {
 	return g_system->getEventManager()->getMousePos() - Common::Point(_innerDims.left, _innerDims.top);
 }
diff --git a/engines/director/window.h b/engines/director/window.h
index 4baaba0092..dc4003949b 100644
--- a/engines/director/window.h
+++ b/engines/director/window.h
@@ -38,8 +38,6 @@ class MacWindowManager;
 
 namespace Director {
 
-const int SCALE_THRESHOLD = 0x100;
-
 class Channel;
 class MacArchive;
 struct MacShape;
@@ -201,13 +199,9 @@ private:
 	bool _titleVisible;
 
 private:
-	int preprocessColor(DirectorPlotData *p, uint32 src);
 
 	void inkBlitFrom(Channel *channel, Common::Rect destRect, Graphics::ManagedSurface *blitTo = nullptr);
-	void inkBlitShape(DirectorPlotData *pd, Common::Rect &srcRect);
 
-	void inkBlitSurface(DirectorPlotData *pd, Common::Rect &srcRect, const Graphics::Surface *mask);
-	void inkBlitStretchSurface(DirectorPlotData *pd, Common::Rect &srcRect, const Graphics::Surface *mask);
 };
 
 } // End of namespace Director


Commit: 257fd958e724fddcc72bc9904477f8f092fee3c4
    https://github.com/scummvm/scummvm/commit/257fd958e724fddcc72bc9904477f8f092fee3c4
Author: Scott Percival (code at moral.net.au)
Date: 2021-10-12T01:08:34+08:00

Commit Message:
DIRECTOR: Add blitting code to FilmLoopCastMember

Changed paths:
    engines/director/castmember.cpp
    engines/director/graphics.cpp


diff --git a/engines/director/castmember.cpp b/engines/director/castmember.cpp
index 683bea1876..1daf876b4e 100644
--- a/engines/director/castmember.cpp
+++ b/engines/director/castmember.cpp
@@ -577,7 +577,10 @@ bool FilmLoopCastMember::isModified() {
 }
 
 Graphics::MacWidget *FilmLoopCastMember::createWidget(Common::Rect &bbox, Channel *channel, SpriteType spriteType) {
-	Graphics::MacWidget *widget = new Graphics::MacWidget(g_director->getCurrentWindow(), bbox.left, bbox.top, bbox.width(), bbox.height(), g_director->_wm, false);
+	Common::Rect widgetRect(bbox.width() ? bbox.width() : _bbox.width(), bbox.height() ? bbox.height() : _bbox.height());
+	channel->_width = widgetRect.width();
+	channel->_height = widgetRect.height();
+	Graphics::MacWidget *widget = new Graphics::MacWidget(g_director->getCurrentWindow(), bbox.left, bbox.top, widgetRect.width(), widgetRect.height(), g_director->_wm, false);
 
 	if (channel->_filmLoopFrame >= _frames.size()) {
 		warning("Film loop frame %d requested, only %d available", channel->_filmLoopFrame, _frames.size());
@@ -594,17 +597,38 @@ Graphics::MacWidget *FilmLoopCastMember::createWidget(Common::Rect &bbox, Channe
 	// render the sprites in order onto the widget surface
 	for (Common::Array<int>::iterator iter = spriteIds.begin(); iter != spriteIds.end(); ++iter) {
 		Sprite src = _frames[channel->_filmLoopFrame].sprites[*iter];
-		if (src._castId.member == 0)
+		if (!src._cast)
 			continue;
 		// translate sprite relative to the global bounding box
-		int16 x = (src._startPoint.x - _bbox.left) * bbox.width() / _bbox.width() + bbox.left;
-		int16 y = (src._startPoint.y - _bbox.top) * bbox.height() / _bbox.height() + bbox.top;
-		int16 width = src._width * bbox.width() / _bbox.width();
-		int16 height = src._height * bbox.height() / _bbox.height();
-		Common::Rect srcBbox(x, y, x + width, y + height);
-		//Graphics::MacWidget *srcWidget = src._cast->createWidget(srcBbox, channel, spriteType);
-		//widget->getSurface()->blitFrom(*srcWidget->getSurface(), Common::Point(x, y));
-		//delete srcWidget;
+		int16 relX = (src._startPoint.x - _bbox.left) * widgetRect.width() / _bbox.width();
+		int16 absX = relX + bbox.left;
+		int16 relY = (src._startPoint.y - _bbox.top) * widgetRect.height() / _bbox.height();
+		int16 absY = relY + bbox.top;
+		int16 width = src._width * widgetRect.width() / _bbox.width();
+		int16 height = src._height * widgetRect.height() / _bbox.height();
+		Common::Rect absBbox(absX, absY, absX + width, absY + height);
+		Common::Rect relBbox(relX, relY, relX + width, relY + height);
+
+		Graphics::MacWidget *srcWidget = src._cast->createWidget(absBbox, channel, spriteType);
+		DirectorPlotData pd(g_director->_wm, src._spriteType, src._ink, src._blend, src.getBackColor(), src.getForeColor());
+		pd.colorWhite = pd._wm->_colorWhite;
+		pd.colorBlack = pd._wm->_colorBlack;
+		pd.dst = widget->getSurface();
+		pd.destRect = widgetRect;
+
+		pd.srf = srcWidget ? srcWidget->getSurface() : nullptr;
+		if (!pd.srf && src._spriteType != kBitmapSprite) {
+			// Shapes come colourized from macDrawPixel
+			pd.ms = src.getShape();
+			pd.applyColor = false;
+			pd.inkBlitShape(relBbox);
+		} else {
+			pd.setApplyColor();
+			// TODO: Support masks
+			pd.inkBlitSurface(relBbox, nullptr);
+		}
+		if (srcWidget)
+			delete srcWidget;
 	}
 
 	return widget;
diff --git a/engines/director/graphics.cpp b/engines/director/graphics.cpp
index 9b0df3f0c9..f62062fdbe 100644
--- a/engines/director/graphics.cpp
+++ b/engines/director/graphics.cpp
@@ -435,7 +435,7 @@ void DirectorPlotData::inkBlitSurface(Common::Rect &srcRect, const Graphics::Sur
 			for (int j = 0; j < destRect.width(); j++, srcPoint.x++) {
 				if (!mask || (msk && !(*msk++))) {
 					(g_director->getInkDrawPixel())(destRect.left + j, destRect.top + i,
-											preprocessColor(*((int *)srf->getBasePtr(srcPoint.x, srcPoint.y))), this);
+											preprocessColor(*((uint32 *)srf->getBasePtr(srcPoint.x, srcPoint.y))), this);
 				}
 			}
 		}


Commit: 0e0254a5f78475beea0fc89e54ea921ad224080e
    https://github.com/scummvm/scummvm/commit/0e0254a5f78475beea0fc89e54ea921ad224080e
Author: Scott Percival (code at moral.net.au)
Date: 2021-10-12T01:08:34+08:00

Commit Message:
DIRECTOR: Fix currentFrameRate loading for v4

Changed paths:
    engines/director/cast.cpp


diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index 17ec4c5442..1117976b7a 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -223,12 +223,9 @@ bool Cast::loadConfig() {
 
 	_castArrayStart = stream->readUint16();
 	_castArrayEnd = stream->readUint16();
+
+	// v3 and below use this, override for v4 and over
 	byte currentFrameRate = stream->readByte();
-	if (!_isShared) {
-		_movie->getScore()->_currentFrameRate = currentFrameRate;
-		if (_movie->getScore()->_currentFrameRate == 0)
-			_movie->getScore()->_currentFrameRate = 20;
-	}
 
 	byte lightswitch = stream->readByte();
 	uint16 unk1 = stream->readUint16();
@@ -246,8 +243,8 @@ bool Cast::loadConfig() {
 	// uint16 stageColorG = stream.readUint16();
 	// uint16 stageColorB = stream.readUint16();
 
-	debugC(1, kDebugLoading, "Cast::loadConfig(): len: %d, fileVersion: %d, framerate: %d, light: %d, unk: %d, font: %d, size: %d"
-			", style: %d", len, fileVersion, currentFrameRate, lightswitch, unk1, commentFont, commentSize, commentStyle);
+	debugC(1, kDebugLoading, "Cast::loadConfig(): len: %d, fileVersion: %d, light: %d, unk: %d, font: %d, size: %d"
+			", style: %d", len, fileVersion, lightswitch, unk1, commentFont, commentSize, commentStyle);
 	debugC(1, kDebugLoading, "Cast::loadConfig(): stagecolor: %d, depth: %d",
 			_stageColor, bitdepth);
 	if (debugChannelSet(1, kDebugLoading))
@@ -269,9 +266,10 @@ bool Cast::loadConfig() {
 	}
 
 	if (_version >= kFileVer400) {
-		for (int i = 0; i < 0x08; i++) {
+		for (int i = 0; i < 0x07; i++) {
 			stream->readByte();
 		}
+		currentFrameRate = stream->readByte();
 		_platform = platformFromID(stream->readUint16());
 		for (int i = 0; i < 0x0c; i++) {
 			stream->readByte();
@@ -283,6 +281,13 @@ bool Cast::loadConfig() {
 		debugC(1, kDebugLoading, "Cast::loadConfig(): platform: %s, defaultPalette: %d", getPlatformAbbrev(_platform), _defaultPalette);
 	}
 
+	if (!_isShared) {
+		debugC(1, kDebugLoading, "Cast::loadConfig(): currentFrameRate: %d", currentFrameRate);
+		_movie->getScore()->_currentFrameRate = currentFrameRate;
+		if (_movie->getScore()->_currentFrameRate == 0)
+			_movie->getScore()->_currentFrameRate = 20;
+	}
+
 	uint16 humanVer = humanVersion(_version);
 	if (humanVer > _vm->getVersion()) {
 		if (_vm->getVersion() > 0)


Commit: 8b240f69b8aa6605e67fca5a9e4bb93a5e73c0f0
    https://github.com/scummvm/scummvm/commit/8b240f69b8aa6605e67fca5a9e4bb93a5e73c0f0
Author: Scott Percival (code at moral.net.au)
Date: 2021-10-12T01:08:34+08:00

Commit Message:
DIRECTOR: Fix inkBlitShape to use destRect for drawing

Changed paths:
    engines/director/castmember.cpp
    engines/director/director.h
    engines/director/graphics.cpp
    engines/director/window.cpp


diff --git a/engines/director/castmember.cpp b/engines/director/castmember.cpp
index 1daf876b4e..cc9211bca7 100644
--- a/engines/director/castmember.cpp
+++ b/engines/director/castmember.cpp
@@ -601,31 +601,29 @@ Graphics::MacWidget *FilmLoopCastMember::createWidget(Common::Rect &bbox, Channe
 			continue;
 		// translate sprite relative to the global bounding box
 		int16 relX = (src._startPoint.x - _bbox.left) * widgetRect.width() / _bbox.width();
-		int16 absX = relX + bbox.left;
 		int16 relY = (src._startPoint.y - _bbox.top) * widgetRect.height() / _bbox.height();
-		int16 absY = relY + bbox.top;
 		int16 width = src._width * widgetRect.width() / _bbox.width();
 		int16 height = src._height * widgetRect.height() / _bbox.height();
-		Common::Rect absBbox(absX, absY, absX + width, absY + height);
 		Common::Rect relBbox(relX, relY, relX + width, relY + height);
 
-		Graphics::MacWidget *srcWidget = src._cast->createWidget(absBbox, channel, spriteType);
+		Graphics::MacWidget *srcWidget = src._cast->createWidget(relBbox, channel, spriteType);
 		DirectorPlotData pd(g_director->_wm, src._spriteType, src._ink, src._blend, src.getBackColor(), src.getForeColor());
 		pd.colorWhite = pd._wm->_colorWhite;
 		pd.colorBlack = pd._wm->_colorBlack;
 		pd.dst = widget->getSurface();
-		pd.destRect = widgetRect;
+		pd.destRect = relBbox;
 
 		pd.srf = srcWidget ? srcWidget->getSurface() : nullptr;
+		Common::Rect srcWidgetBbox(width, height);
 		if (!pd.srf && src._spriteType != kBitmapSprite) {
 			// Shapes come colourized from macDrawPixel
 			pd.ms = src.getShape();
 			pd.applyColor = false;
-			pd.inkBlitShape(relBbox);
+			pd.inkBlitShape();
 		} else {
 			pd.setApplyColor();
 			// TODO: Support masks
-			pd.inkBlitSurface(relBbox, nullptr);
+			pd.inkBlitStretchSurface(srcWidgetBbox, nullptr);
 		}
 		if (srcWidget)
 			delete srcWidget;
diff --git a/engines/director/director.h b/engines/director/director.h
index 4f6a989a8e..f28281de08 100644
--- a/engines/director/director.h
+++ b/engines/director/director.h
@@ -153,7 +153,7 @@ struct DirectorPlotData {
 	// graphics.cpp
 	void setApplyColor();
 	uint32 preprocessColor(uint32 src);
-	void inkBlitShape(Common::Rect &srcRect);
+	void inkBlitShape();
 	void inkBlitSurface(Common::Rect &srcRect, const Graphics::Surface *mask);
 	void inkBlitStretchSurface(Common::Rect &srcRect, const Graphics::Surface *mask);
 
diff --git a/engines/director/graphics.cpp b/engines/director/graphics.cpp
index f62062fdbe..36fdb1f59f 100644
--- a/engines/director/graphics.cpp
+++ b/engines/director/graphics.cpp
@@ -337,7 +337,7 @@ uint32 DirectorPlotData::preprocessColor(uint32 src) {
 	return src;
 }
 
-void DirectorPlotData::inkBlitShape(Common::Rect &srcRect) {
+void DirectorPlotData::inkBlitShape() {
 	if (!ms)
 		return;
 
@@ -355,12 +355,12 @@ void DirectorPlotData::inkBlitShape(Common::Rect &srcRect) {
 		break;
 	}
 
-	Common::Rect fillAreaRect((int)srcRect.width(), (int)srcRect.height());
-	fillAreaRect.moveTo(srcRect.left, srcRect.top);
-	Graphics::MacPlotData plotFill(dst, nullptr, &g_director->getPatterns(), ms->pattern, srcRect.left, srcRect.top, 1, ms->backColor);
+	Common::Rect fillAreaRect((int)destRect.width(), (int)destRect.height());
+	fillAreaRect.moveTo(destRect.left, destRect.top);
+	Graphics::MacPlotData plotFill(dst, nullptr, &g_director->getPatterns(), ms->pattern, destRect.left, destRect.top, 1, ms->backColor);
 
-	Common::Rect strokeRect(MAX((int)srcRect.width() - ms->lineSize, 0), MAX((int)srcRect.height() - ms->lineSize, 0));
-	strokeRect.moveTo(srcRect.left, srcRect.top);
+	Common::Rect strokeRect(MAX((int)destRect.width() - ms->lineSize, 0), MAX((int)destRect.height() - ms->lineSize, 0));
+	strokeRect.moveTo(destRect.left, destRect.top);
 	Graphics::MacPlotData plotStroke(dst, nullptr, &g_director->getPatterns(), 1, strokeRect.left, strokeRect.top, ms->lineSize, ms->backColor);
 
 	switch (ms->spriteType) {
diff --git a/engines/director/window.cpp b/engines/director/window.cpp
index 3e50e30ada..3c147fffd8 100644
--- a/engines/director/window.cpp
+++ b/engines/director/window.cpp
@@ -198,7 +198,7 @@ void Window::inkBlitFrom(Channel *channel, Common::Rect destRect, Graphics::Mana
 	pd.dst = blitTo;
 
 	if (pd.ms) {
-		pd.inkBlitShape(srcRect);
+		pd.inkBlitShape();
 	} else if (pd.srf) {
 		if (channel->isStretched()) {
 			srcRect = channel->getBbox(true);


Commit: 47c5b37067ebd53ccda509e077774afd893f649e
    https://github.com/scummvm/scummvm/commit/47c5b37067ebd53ccda509e077774afd893f649e
Author: Scott Percival (code at moral.net.au)
Date: 2021-10-12T01:08:34+08:00

Commit Message:
DIRECTOR: Fix use-after-free in Sprite

Changed paths:
    engines/director/sprite.cpp
    engines/director/sprite.h


diff --git a/engines/director/sprite.cpp b/engines/director/sprite.cpp
index 4dda654a18..f388d0cfda 100644
--- a/engines/director/sprite.cpp
+++ b/engines/director/sprite.cpp
@@ -90,8 +90,8 @@ Sprite::Sprite(const Sprite &sprite) {
 	_ink = sprite._ink;
 	_trails = sprite._trails;
 
-	_matte = sprite._matte;
 	_cast = sprite._cast;
+	_matte = nullptr;
 
 	_thickness = sprite._thickness;
 	_startPoint = sprite._startPoint;
@@ -111,7 +111,8 @@ Sprite::Sprite(const Sprite &sprite) {
 }
 
 Sprite::~Sprite() {
-	delete _matte;
+	if (_matte)
+		delete _matte;
 }
 
 bool Sprite::isQDShape() {
diff --git a/engines/director/sprite.h b/engines/director/sprite.h
index 86b2e15dde..dc3754f854 100644
--- a/engines/director/sprite.h
+++ b/engines/director/sprite.h
@@ -61,6 +61,7 @@ class Sprite {
 public:
 	Sprite(Frame *frame = nullptr);
 	Sprite(const Sprite &sprite);
+	Sprite& operator=(const Sprite &sprite) = default;
 	~Sprite();
 
 	Frame *getFrame() const { return _frame; }


Commit: 68518fc8a9b04ccfff5822d99b28615d30762a22
    https://github.com/scummvm/scummvm/commit/68518fc8a9b04ccfff5822d99b28615d30762a22
Author: Scott Percival (code at moral.net.au)
Date: 2021-10-12T01:08:34+08:00

Commit Message:
DIRECTOR: Fix default palette index

Changed paths:
    engines/director/cast.cpp


diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index 1117976b7a..87ccc10b52 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -274,7 +274,13 @@ bool Cast::loadConfig() {
 		for (int i = 0; i < 0x0c; i++) {
 			stream->readByte();
 		}
-		_defaultPalette = (int16)stream->readUint16();
+		_defaultPalette = stream->readSint16();
+		// In this header value, the first builtin palette starts at 0 and
+		// continues down into negative numbers.
+		// For frames, 0 is used to represent an absence of a palette change,
+		// with the builtin palettes starting from -1.
+		if (_defaultPalette <= 0)
+			_defaultPalette -= 1;
 		for (int i = 0; i < 0x08; i++) {
 			stream->readByte();
 		}




More information about the Scummvm-git-logs mailing list