[Scummvm-git-logs] scummvm master -> 12289a93c8cc7736a2e8374d6b23ac37578e24b5

somaen noreply at scummvm.org
Sun Mar 26 17:11:51 UTC 2023


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:
c3b1baf906 DIRECTOR: Refactor BitmapCastMember to store a Picture instead of decoder
12289a93c8 DIRECTOR: Add support for "get/set picture of cast"


Commit: c3b1baf9060358bba5fc1c4e4a34144f0d339a84
    https://github.com/scummvm/scummvm/commit/c3b1baf9060358bba5fc1c4e4a34144f0d339a84
Author: Einar Johan Trøan Sømåen (somaen at scummvm.org)
Date: 2023-03-26T19:11:46+02:00

Commit Message:
DIRECTOR: Refactor BitmapCastMember to store a Picture instead of decoder

This is in preparation for allowing for Lingo to get/set the picture
of BitmapCastMember.

In particular, storing a Picture lets us easily replace the existing
image (instead of having to rely on ImageDecoder as source).

Also, having Picture instances that are easy to copy will make lifetime
management easier if pictures are copied into longer-living things such
as globals.

Changed paths:
  A engines/director/picture.cpp
  A engines/director/picture.h
    engines/director/cast.cpp
    engines/director/castmember.cpp
    engines/director/castmember.h
    engines/director/cursor.cpp
    engines/director/director.cpp
    engines/director/director.h
    engines/director/graphics.cpp
    engines/director/lingo/lingo.h
    engines/director/module.mk
    engines/director/tests.cpp


diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index cd40c822d9a..55abe885840 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -706,12 +706,11 @@ void Cast::loadBitmapData(int key, BitmapCastMember *bitmapCast) {
 				delete file;
 
 				if (res) {
-					bitmapCast->_img = decoder;
+					bitmapCast->setPicture(*decoder, decoder->hasPalette());
 					bitmapCast->_external = true;
 
 					const Graphics::Surface *surf = decoder->getSurface();
 					if (decoder->hasPalette()) {
-						bitmapCast->_size = surf->pitch * surf->h + decoder->getPaletteColorCount() * 3;
 						// For BMPs this sometimes gets set to 16 in the cast record,
 						// we should go with what the target image has.
 						bitmapCast->_bitsPerPixel = 8;
@@ -781,10 +780,9 @@ void Cast::loadBitmapData(int key, BitmapCastMember *bitmapCast) {
 		return;
 	}
 
-	bitmapCast->_img = img;
-	const Graphics::Surface *surf = img->getSurface();
-	bitmapCast->_size = surf->pitch * surf->h + img->getPaletteColorCount() * 3;
+	bitmapCast->setPicture(*img, true);
 
+	delete img;
 	delete pic;
 
 	debugC(5, kDebugImages, "Cast::loadBitmapData(): Bitmap: id: %d, w: %d, h: %d, flags1: %x, flags2: %x bytes: %x, bpp: %d clut: %x", imgId, w, h, bitmapCast->_flags1, bitmapCast->_flags2, bitmapCast->_bytes, bitmapCast->_bitsPerPixel, bitmapCast->_clut);
diff --git a/engines/director/castmember.cpp b/engines/director/castmember.cpp
index afb9846075d..e81838c6ca1 100644
--- a/engines/director/castmember.cpp
+++ b/engines/director/castmember.cpp
@@ -31,6 +31,7 @@
 #include "director/cursor.h"
 #include "director/channel.h"
 #include "director/movie.h"
+#include "director/picture.h"
 #include "director/score.h"
 #include "director/sprite.h"
 #include "director/sound.h"
@@ -94,7 +95,7 @@ void CastMember::setModified(bool modified) {
 BitmapCastMember::BitmapCastMember(Cast *cast, uint16 castId, Common::SeekableReadStreamEndian &stream, uint32 castTag, uint16 version, uint8 flags1)
 		: CastMember(cast, castId, stream) {
 	_type = kCastBitmap;
-	_img = nullptr;
+	_picture = nullptr;
 	_ditheredImg = nullptr;
 	_matte = nullptr;
 	_noMatte = false;
@@ -210,7 +211,9 @@ BitmapCastMember::BitmapCastMember(Cast *cast, uint16 castId, Image::ImageDecode
 	_matte = nullptr;
 	_noMatte = false;
 	_bytes = 0;
-	_img = img;
+	if (img != nullptr) {
+		_picture = new Picture(*img);
+	}
 	_ditheredImg = nullptr;
 	_clut = -1;
 	_ditheredTargetClut = 0;
@@ -226,8 +229,7 @@ BitmapCastMember::BitmapCastMember(Cast *cast, uint16 castId, Image::ImageDecode
 }
 
 BitmapCastMember::~BitmapCastMember() {
-	if (_img)
-		delete _img;
+	delete _picture;
 
 	if (_ditheredImg) {
 		_ditheredImg->free();
@@ -239,8 +241,8 @@ BitmapCastMember::~BitmapCastMember() {
 }
 
 Graphics::MacWidget *BitmapCastMember::createWidget(Common::Rect &bbox, Channel *channel, SpriteType spriteType) {
-	if (!_img) {
-		warning("BitmapCastMember::createWidget: No image decoder");
+	if (!_picture) {
+		warning("BitmapCastMember::createWidget: No picture");
 		return nullptr;
 	}
 
@@ -250,9 +252,9 @@ Graphics::MacWidget *BitmapCastMember::createWidget(Common::Rect &bbox, Channel
 
 	// Check if we need to dither the image
 	int dstBpp = g_director->_wm->_pixelformat.bytesPerPixel;
-	int srcBpp = _img->getSurface()->format.bytesPerPixel;
+	int srcBpp = _picture->_surface.format.bytesPerPixel;
 
-	const byte *pal = _img->getPalette();
+	const byte *pal = _picture->_palette;
 	bool previouslyDithered = _ditheredImg != nullptr;
 	if (_ditheredImg) {
 		_ditheredImg->free();
@@ -267,11 +269,11 @@ Graphics::MacWidget *BitmapCastMember::createWidget(Common::Rect &bbox, Channel
 		// needed, here is the code
 #if 0
 		|| (srcBpp == 1 &&
-			memcmp(g_director->_wm->getPalette(), _img->getPalette(), _img->getPaletteColorCount() * 3))
+			memcmp(g_director->_wm->getPalette(), _img->_palette, _img->_paletteSize))
 #endif
 			) {
 
-			_ditheredImg = _img->getSurface()->convertTo(g_director->_wm->_pixelformat, _img->getPalette(), _img->getPaletteColorCount(), g_director->_wm->getPalette(), g_director->_wm->getPaletteSize());
+			_ditheredImg = _picture->_surface.convertTo(g_director->_wm->_pixelformat, _picture->_palette, _picture->_paletteColors, g_director->_wm->getPalette(), g_director->_wm->getPaletteSize());
 
 			pal = g_director->_wm->getPalette();
 		} else {
@@ -306,7 +308,7 @@ Graphics::MacWidget *BitmapCastMember::createWidget(Common::Rect &bbox, Channel
 			case 2:
 				{
 					const PaletteV4 &srcPal = g_director->getLoaded4Palette();
-					_ditheredImg = _img->getSurface()->convertTo(g_director->_wm->_pixelformat, srcPal.palette, srcPal.length, currentPalette->palette, currentPalette->length, Graphics::kDitherNaive);
+					_ditheredImg = _picture->_surface.convertTo(g_director->_wm->_pixelformat, srcPal.palette, srcPal.length, currentPalette->palette, currentPalette->length, Graphics::kDitherNaive);
 				}
 				break;
 			// 4bpp - if using a builtin palette, use one of the corresponding 4-bit ones.
@@ -317,7 +319,7 @@ Graphics::MacWidget *BitmapCastMember::createWidget(Common::Rect &bbox, Channel
 					// I guess default to the mac palette?
 					int palIndex = pals.contains(castPaletteId) ? castPaletteId : kClutSystemMac;
 					const PaletteV4 &srcPal = pals.getVal(palIndex);
-					_ditheredImg = _img->getSurface()->convertTo(g_director->_wm->_pixelformat, srcPal.palette, srcPal.length, currentPalette->palette, currentPalette->length, Graphics::kDitherNaive);
+					_ditheredImg = _picture->_surface.convertTo(g_director->_wm->_pixelformat, srcPal.palette, srcPal.length, currentPalette->palette, currentPalette->length, Graphics::kDitherNaive);
 				}
 				break;
 			// 8bpp - if using a different palette, and we're not doing a color cycling operation, convert using nearest colour matching
@@ -334,8 +336,8 @@ Graphics::MacWidget *BitmapCastMember::createWidget(Common::Rect &bbox, Channel
 					// For BMP images especially, they'll often have the right colors
 					// but in the wrong palette order.
 					const byte *palPtr = _external ? pal : srcPal.palette;
-					int palLength = _external ? _img->getPaletteColorCount() * 3 : srcPal.length;
-					_ditheredImg = _img->getSurface()->convertTo(g_director->_wm->_pixelformat, palPtr, palLength, currentPalette->palette, currentPalette->length, Graphics::kDitherNaive);
+					int palLength = _external ? _picture->getPaletteSize() : srcPal.length;
+					_ditheredImg = _picture->_surface.convertTo(g_director->_wm->_pixelformat, palPtr, palLength, currentPalette->palette, currentPalette->length, Graphics::kDitherNaive);
 				}
 				break;
 			default:
@@ -350,7 +352,7 @@ Graphics::MacWidget *BitmapCastMember::createWidget(Common::Rect &bbox, Channel
 				if (!_external) {
 					// Finally, the first and last colours in the palette are special. No matter what the palette remap
 					// does, we need to scrub those to be the same.
-					const Graphics::Surface *src = _img->getSurface();
+					const Graphics::Surface *src = &_picture->_surface;
 					for (int y = 0; y < src->h; y++) {
 						for (int x = 0; x < src->w; x++) {
 							const int test = *(const byte *)src->getBasePtr(x, y);
@@ -381,7 +383,7 @@ void BitmapCastMember::copyStretchImg(Graphics::Surface *surface, const Common::
 	if (_ditheredImg)
 		srcSurf = _ditheredImg;
 	else
-		srcSurf = _img->getSurface();
+		srcSurf = &_picture->_surface;
 
 	if (bbox.width() != _initialRect.width() || bbox.height() != _initialRect.height()) {
 
@@ -430,6 +432,10 @@ void BitmapCastMember::copyStretchImg(Graphics::Surface *surface, const Common::
 }
 
 bool BitmapCastMember::isModified() {
+	if (CastMember::isModified()) {
+		// Let's us use "setChanged" when changing the picture through Lingo
+		return true;
+	}
 	// Check for palette changes.
 	// If a bitmap has a custom palette assigned to it, createWidget()
 	// will dither the image so that it fits within the current palette.
@@ -544,6 +550,17 @@ Common::String BitmapCastMember::formatInfo() {
 	);
 }
 
+void BitmapCastMember::setPicture(Image::ImageDecoder &image, bool adjustSize) {
+	delete _picture;
+	_picture = new Picture(image);
+	if (adjustSize) {
+		auto surf = image.getSurface();
+		_size = surf->pitch * surf->h + _picture->getPaletteSize();
+	}
+	// Make sure we get redrawn
+	setModified(true);
+}
+
 /////////////////////////////////////
 // DigitalVideo
 /////////////////////////////////////
diff --git a/engines/director/castmember.h b/engines/director/castmember.h
index 63f356adaf1..81f0fbfbbc1 100644
--- a/engines/director/castmember.h
+++ b/engines/director/castmember.h
@@ -57,6 +57,7 @@ namespace Director {
 class AudioDecoder;
 struct CastMemberInfo;
 class Channel;
+struct Picture;
 struct Resource;
 class Sprite;
 class Stxt;
@@ -136,7 +137,9 @@ public:
 
 	Common::String formatInfo() override;
 
-	Image::ImageDecoder *_img;
+	void setPicture(Image::ImageDecoder &image, bool adjustSize);
+
+	Picture *_picture = nullptr;
 	Graphics::Surface *_ditheredImg;
 	Graphics::FloodFill *_matte;
 
diff --git a/engines/director/cursor.cpp b/engines/director/cursor.cpp
index 18c14cc19be..f705ce3678e 100644
--- a/engines/director/cursor.cpp
+++ b/engines/director/cursor.cpp
@@ -27,6 +27,7 @@
 #include "director/cursor.h"
 #include "director/movie.h"
 #include "director/castmember.h"
+#include "director/picture.h"
 
 namespace Director {
 
@@ -92,15 +93,15 @@ void Cursor::readFromCast(Datum cursorCasts) {
 	for (int y = 0; y < 16; y++) {
 		const byte *cursor = nullptr, *mask = nullptr;
 
-		if (y < cursorBitmap->_img->getSurface()->h &&
-				y < maskBitmap->_img->getSurface()->h) {
-			cursor = (const byte *)cursorBitmap->_img->getSurface()->getBasePtr(0, y);
-			mask = (const byte *)maskBitmap->_img->getSurface()->getBasePtr(0, y);
+		if (y < cursorBitmap->_picture->_surface.h &&
+				y < maskBitmap->_picture->_surface.h) {
+			cursor = (const byte *)cursorBitmap->_picture->_surface.getBasePtr(0, y);
+			mask = (const byte *)maskBitmap->_picture->_surface.getBasePtr(0, y);
 		}
 
 		for (int x = 0; x < 16; x++) {
-			if (x >= cursorBitmap->_img->getSurface()->w ||
-					x >= maskBitmap->_img->getSurface()->w) {
+			if (x >= cursorBitmap->_picture->_surface.w ||
+					x >= maskBitmap->_picture->_surface.w) {
 				cursor = mask = nullptr;
 			}
 
diff --git a/engines/director/director.cpp b/engines/director/director.cpp
index 312c9088e1b..1ff68d22964 100644
--- a/engines/director/director.cpp
+++ b/engines/director/director.cpp
@@ -33,6 +33,7 @@
 #include "director/archive.h"
 #include "director/cast.h"
 #include "director/movie.h"
+#include "director/picture.h"
 #include "director/score.h"
 #include "director/sound.h"
 #include "director/window.h"
@@ -361,4 +362,8 @@ bool DirectorEngine::desktopEnabled() {
 	return !(_wmMode & Graphics::kWMModeNoDesktop);
 }
 
+PatternTile::~PatternTile() {
+	delete img;
+}
+
 } // End of namespace Director
diff --git a/engines/director/director.h b/engines/director/director.h
index a52fcf64199..327f2c06c33 100644
--- a/engines/director/director.h
+++ b/engines/director/director.h
@@ -128,20 +128,17 @@ struct MacShape {
 	int lineSize;
 	uint pattern;
 
-	Image::ImageDecoder *tile;
+	Picture *tile;
 	const Common::Rect *tileRect;
 
 	Graphics::MacPlotData *pd;
 };
 
 struct PatternTile {
-	Image::ImageDecoder *img = 0;
+	Picture *img = nullptr;
 	Common::Rect rect;
 
-	~PatternTile() {
-		if (img)
-			delete img;
-	}
+	~PatternTile();
 };
 
 const int SCALE_THRESHOLD = 0x100;
@@ -199,7 +196,7 @@ public:
 	uint16 getPaletteColorCount() const { return _currentPaletteLength; }
 
 	void loadPatterns();
-	Image::ImageDecoder *getTile(int num);
+	Picture *getTile(int num);
 	const Common::Rect &getTileRect(int num);
 	uint32 transformColor(uint32 color);
 	Graphics::MacPatterns &getPatterns();
diff --git a/engines/director/graphics.cpp b/engines/director/graphics.cpp
index 80288032129..cf5d065521d 100644
--- a/engines/director/graphics.cpp
+++ b/engines/director/graphics.cpp
@@ -28,6 +28,7 @@
 #include "director/castmember.h"
 #include "director/movie.h"
 #include "director/images.h"
+#include "director/picture.h"
 #include "director/window.h"
 
 namespace Director {
@@ -58,8 +59,10 @@ void DirectorEngine::loadPatterns() {
 	for (int i = 0; i < ARRAYSIZE(builtinTiles); i++) {
 		Common::MemoryReadStream stream(builtinTiles[i].ptr, builtinTiles[i].size);
 
-		_builtinTiles[i].img = new BITDDecoder(builtinTiles[i].w, builtinTiles[i].h, 8, builtinTiles[i].w, macPalette, kFileVer300);
-		_builtinTiles[i].img->loadStream(stream);
+		auto decoder = new BITDDecoder(builtinTiles[i].w, builtinTiles[i].h, 8, builtinTiles[i].w, macPalette, kFileVer300);
+		decoder->loadStream(stream);
+		_builtinTiles[i].img = new Picture(*decoder);
+		delete decoder;
 
 		_builtinTiles[i].rect = Common::Rect(0, 0, builtinTiles[i].w, builtinTiles[i].h);
 	}
@@ -70,7 +73,7 @@ Graphics::MacPatterns &DirectorEngine::getPatterns() {
 	return _director3QuickDrawPatterns;
 }
 
-Image::ImageDecoder *DirectorEngine::getTile(int num) {
+Picture *DirectorEngine::getTile(int num) {
 	TilePatternEntry *tile = &getCurrentMovie()->getCast()->_tiles[num];
 
 	if (tile->bitmapId.isNull())
@@ -92,7 +95,7 @@ Image::ImageDecoder *DirectorEngine::getTile(int num) {
 		return _builtinTiles[num].img;
 	}
 
-	return ((BitmapCastMember *)member)->_img;
+	return ((BitmapCastMember *)member)->_picture;
 }
 
 const Common::Rect &DirectorEngine::getTileRect(int num) {
@@ -265,7 +268,7 @@ void inkDrawPixel(int x, int y, int src, void *data) {
 			int x1 = p->ms->tileRect->left + (p->ms->pd->fillOriginX + x) % p->ms->tileRect->width();
 			int y1 = p->ms->tileRect->top  + (p->ms->pd->fillOriginY + y) % p->ms->tileRect->height();
 
-			src = p->ms->tile->getSurface()->getPixel(x1, y1);
+			src = p->ms->tile->_surface.getPixel(x1, y1);
 		} else {
 			// Get the pixel that macDrawPixel will give us, but store it to apply the
 			// ink later
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index 8f38387c791..f6dffd0fdd1 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -47,6 +47,7 @@ struct LingoArchive;
 struct LingoV4Bytecode;
 struct LingoV4TheEntity;
 struct Node;
+struct Picture;
 class AbstractObject;
 class Cast;
 class ScriptContext;
diff --git a/engines/director/module.mk b/engines/director/module.mk
index e7c4d7f67b9..b27ee30d89d 100644
--- a/engines/director/module.mk
+++ b/engines/director/module.mk
@@ -16,6 +16,7 @@ MODULE_OBJS = \
 	images.o \
 	metaengine.o \
 	movie.o \
+	picture.o \
 	resource.o \
 	score.o \
 	sound.o \
diff --git a/engines/director/picture.cpp b/engines/director/picture.cpp
new file mode 100644
index 00000000000..04d4db10139
--- /dev/null
+++ b/engines/director/picture.cpp
@@ -0,0 +1,49 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "image/image_decoder.h"
+#include "director/picture.h"
+
+namespace Director {
+
+Picture::Picture(Image::ImageDecoder &img) {
+	_surface.copyFrom(*img.getSurface());
+	copyPalette(img.getPalette(), img.getPaletteColorCount());
+}
+
+Picture::Picture(Picture &picture) {
+	_surface.copyFrom(picture._surface);
+	copyPalette(picture._palette, picture._paletteColors);
+}
+
+Picture::~Picture() {
+	_surface.free();
+	delete[] _palette;
+}
+
+void Picture::copyPalette(const byte *src, int numColors) {
+	delete[] _palette;
+	_paletteColors = numColors;
+	_palette = new byte[getPaletteSize()]();
+	memcpy(_palette, src, getPaletteSize());
+}
+
+} // End of namespace Director
diff --git a/engines/director/picture.h b/engines/director/picture.h
new file mode 100644
index 00000000000..cfaee61546c
--- /dev/null
+++ b/engines/director/picture.h
@@ -0,0 +1,51 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DIRECTOR_PICTURE_H
+#define DIRECTOR_PICTURE_H
+
+#include "graphics/surface.h"
+
+namespace Image {
+class ImageDecoder;
+}
+
+namespace Director {
+
+struct Picture {
+	Graphics::Surface _surface;
+	byte *_palette = nullptr;
+	int _paletteColors = 0;
+
+	int getPaletteSize() const {
+		return _paletteColors * 3;
+	}
+
+	Picture(Image::ImageDecoder &img);
+	Picture(Picture &picture);
+	~Picture();
+private:
+	void copyPalette(const byte *src, int numColors);
+};
+
+} // End of namespace Director
+
+#endif // DIRECTOR_PICTURE_H
diff --git a/engines/director/tests.cpp b/engines/director/tests.cpp
index d9c98f39b1c..127597ccb2f 100644
--- a/engines/director/tests.cpp
+++ b/engines/director/tests.cpp
@@ -35,6 +35,7 @@
 #include "director/director.h"
 #include "director/archive.h"
 #include "director/movie.h"
+#include "director/picture.h"
 #include "director/window.h"
 #include "director/lingo/lingo.h"
 
@@ -103,10 +104,10 @@ void Window::testFontScaling() {
 
 	x = 10;
 	for (int i = 0; i < kNumBuiltinTiles; i++) {
-		Image::ImageDecoder *tile = g_director->getTile(i);
-		surface.blitFrom(tile->getSurface(), Common::Point(x, 250));
+		Picture *tile = g_director->getTile(i);
+		surface.blitFrom(tile->_surface, Common::Point(x, 250));
 
-		x += tile->getSurface()->w + 10;
+		x += tile->_surface.w + 10;
 	}
 
 	Common::String path = pathMakeRelative("blend2.pic");


Commit: 12289a93c8cc7736a2e8374d6b23ac37578e24b5
    https://github.com/scummvm/scummvm/commit/12289a93c8cc7736a2e8374d6b23ac37578e24b5
Author: Einar Johan Trøan Sømåen (somaen at scummvm.org)
Date: 2023-03-26T19:11:46+02:00

Commit Message:
DIRECTOR: Add support for "get/set picture of cast"

Changed paths:
    engines/director/castmember.cpp
    engines/director/castmember.h
    engines/director/lingo/lingo-builtins.cpp
    engines/director/lingo/lingo-object.cpp
    engines/director/lingo/lingo.cpp
    engines/director/lingo/lingo.h
    engines/director/lingo/tests/equality.lingo
    engines/director/types.h


diff --git a/engines/director/castmember.cpp b/engines/director/castmember.cpp
index e81838c6ca1..a60a2bfd4f7 100644
--- a/engines/director/castmember.cpp
+++ b/engines/director/castmember.cpp
@@ -550,6 +550,30 @@ Common::String BitmapCastMember::formatInfo() {
 	);
 }
 
+PictureReference *BitmapCastMember::getPicture() const {
+	auto picture = new PictureReference;
+
+	// Not sure if we can make the assumption that the owning
+	// BitmapCastMember will live as long as any reference,
+	// so we'll make a copy of the Picture.
+	picture->_picture = new Picture(*_picture);
+
+	return picture;
+}
+
+void BitmapCastMember::setPicture(PictureReference &picture) {
+	delete _picture;
+	_picture = new Picture(*picture._picture);
+
+	// Force redither
+	delete _ditheredImg;
+	_ditheredImg = nullptr;
+
+	// Make sure we get redrawn
+	setModified(true);
+	// TODO: Should size be adjusted?
+}
+
 void BitmapCastMember::setPicture(Image::ImageDecoder &image, bool adjustSize) {
 	delete _picture;
 	_picture = new Picture(image);
diff --git a/engines/director/castmember.h b/engines/director/castmember.h
index 81f0fbfbbc1..1f38c9be2cf 100644
--- a/engines/director/castmember.h
+++ b/engines/director/castmember.h
@@ -137,6 +137,8 @@ public:
 
 	Common::String formatInfo() override;
 
+	PictureReference *getPicture() const;
+	void setPicture(PictureReference &picture);
 	void setPicture(Image::ImageDecoder &image, bool adjustSize);
 
 	Picture *_picture = nullptr;
diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index ce81990b56a..9314167a060 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -1767,9 +1767,9 @@ void LB::b_objectp(int nargs) {
 }
 
 void LB::b_pictureP(int nargs) {
-	g_lingo->pop();
-	warning("STUB: b_pictureP");
-	g_lingo->push(Datum(0));
+	Datum d = g_lingo->pop();
+	Datum res((d.type == PICTUREREF) ? 1 : 0);
+	g_lingo->push(res);
 }
 
 void LB::b_stringp(int nargs) {
diff --git a/engines/director/lingo/lingo-object.cpp b/engines/director/lingo/lingo-object.cpp
index 80e99b56f95..aba78187dda 100644
--- a/engines/director/lingo/lingo-object.cpp
+++ b/engines/director/lingo/lingo-object.cpp
@@ -963,7 +963,8 @@ Datum BitmapCastMember::getField(int field) {
 		d = _clut;
 		break;
 	case kThePicture:
-		warning("STUB: BitmapCastMember::getField(): Unprocessed getting field \"%s\" of cast %d", g_lingo->field2str(field), _castId);
+		d.type = PICTUREREF;
+		d.u.picture = getPicture();
 		break;
 	default:
 		d = CastMember::getField(field);
@@ -993,7 +994,12 @@ bool BitmapCastMember::setField(int field, const Datum &d) {
 		_clut = d.asInt();
 		return true;
 	case kThePicture:
-		warning("STUB: BitmapCastMember::setField(): Unprocessed setting field \"%s\" of cast %d", g_lingo->field2str(field), _castId);
+		if (d.type == PICTUREREF && d.u.picture != nullptr) {
+			setPicture(*d.u.picture);
+			return true;
+		} else {
+			warning("BitmapCastMember::setField(): Wrong Datum type %d for kThePicture (or nullptr)", d.type);
+		}
 		return false;
 	default:
 		break;
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index 0a22e1f49ca..244d71468dc 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -938,6 +938,9 @@ void Datum::reset() {
 		case MENUREF:
 			delete u.menu;
 			break;
+		case PICTUREREF:
+			delete u.picture;
+			break;
 		default:
 			warning("Datum::reset(): Unprocessed REF type %d", type);
 			break;
@@ -1163,6 +1166,9 @@ Common::String Datum::asString(bool printonly) const {
 	case MENUREF:
 		s = Common::String::format("menu(%d, %d)", u.menu->menuIdNum, u.menu->menuItemIdNum);
 		break;
+	case PICTUREREF:
+		s = Common::String::format("picture: %p", (void*)u.picture->_picture);
+		break;
 	default:
 		warning("Incorrect operation asString() for type: %s", type2str());
 	}
@@ -1228,6 +1234,8 @@ const char *Datum::type2str(bool ilk) const {
 		return ilk ? "object" : "OBJECT";
 	case PARRAY:
 		return ilk ? "proplist" : "PARRAY";
+	case PICTUREREF:
+		return ilk ? "picture" :  "PICTUREREF";
 	case POINT:
 		return ilk ? "point" : "POINT";
 	case PROPREF:
@@ -1267,6 +1275,8 @@ int Datum::equalTo(Datum &d, bool ignoreCase) const {
 		return u.obj == d.u.obj;
 	case CASTREF:
 		return *u.cast == *d.u.cast;
+	case PICTUREREF:
+		return 0; // Original always returns 0 on picture reference comparison
 	default:
 		break;
 	}
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index f6dffd0fdd1..1180a1d879e 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -41,6 +41,7 @@ namespace Director {
 
 struct ChunkReference;
 struct MenuReference;
+struct PictureReference;
 struct TheEntity;
 struct TheEntityField;
 struct LingoArchive;
@@ -144,6 +145,7 @@ struct Datum {	/* interpreter stack type */
 		ChunkReference *cref; /* CHUNKREF */
 		CastMemberID *cast;	/* CASTREF, FIELDREF */
 		MenuReference *menu; /* MENUREF	*/
+		PictureReference *picture; /* PICTUREREF */
 	} u;
 
 	int *refCount;
@@ -209,6 +211,13 @@ struct MenuReference {
 	MenuReference();
 };
 
+struct PictureReference {
+	Picture *_picture = nullptr;
+	~PictureReference() {
+		delete _picture;
+	}
+};
+
 struct PCell {
 	Datum p;
 	Datum v;
diff --git a/engines/director/lingo/tests/equality.lingo b/engines/director/lingo/tests/equality.lingo
index 7e8bf9c9a48..c84b9a44fc8 100644
--- a/engines/director/lingo/tests/equality.lingo
+++ b/engines/director/lingo/tests/equality.lingo
@@ -19,3 +19,8 @@ scummvmAssert("<Object:#FileIO" > 0)
 
 -- Invalid comparisons should return FALSE
 scummvmAssert(not (#test <= 0))
+
+-- Picture comparisons are always false, even between the exact same cast.
+set a to the picture of cast 1
+scummvmAssert(a <> a)
+scummvmAssert(a <> the picture of cast 1)   -- always false
diff --git a/engines/director/types.h b/engines/director/types.h
index 52d0319024c..5d9ddefc5aa 100644
--- a/engines/director/types.h
+++ b/engines/director/types.h
@@ -357,6 +357,7 @@ enum DatumType {
 	MENUREF,
 	OBJECT,
 	PARRAY,
+	PICTUREREF,
 	POINT,
 	PROPREF,
 	RECT,




More information about the Scummvm-git-logs mailing list