[Scummvm-git-logs] scummvm master -> 6857eb56babdb9389f76bab75a1ef2cb2d7b03cd

athrxx noreply at scummvm.org
Wed Mar 20 22:26:48 UTC 2024


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:
6857eb56ba SCUMM: (LOOM/EGA/AMIGA) - add missing shadow mode


Commit: 6857eb56babdb9389f76bab75a1ef2cb2d7b03cd
    https://github.com/scummvm/scummvm/commit/6857eb56babdb9389f76bab75a1ef2cb2d7b03cd
Author: athrxx (athrxx at scummvm.org)
Date: 2024-03-20T23:26:09+01:00

Commit Message:
SCUMM: (LOOM/EGA/AMIGA) - add missing shadow mode

(bug no. 15030)

I have verified that neither the FM-Towns versions nor
INDY3 VGA have that mode. I don't know about Indy 3 EGA
(I presume not, but it would be worth checking).

I have verified (as can be seen in the ticket) that the original
seems to glitch on that new shadow mode in varying ways.
I haven't found the cause of it yet (current state of guessing:
glitchy text mask). And I am not sure if we need to replicate
the glitch, anyway...

Changed paths:
    engines/scumm/charset.cpp
    engines/scumm/charset.h
    engines/scumm/string.cpp


diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index 0764f8e3392..a56b79a5f01 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -336,8 +336,7 @@ CharsetRenderer::~CharsetRenderer() {
 }
 
 CharsetRendererCommon::CharsetRendererCommon(ScummEngine *vm)
-	: CharsetRenderer(vm), _fontPtr(nullptr), _bitsPerPixel(0), _fontHeight(0), _numChars(0) {
-	_enableShadow = false;
+	: CharsetRenderer(vm), _fontPtr(nullptr), _bitsPerPixel(0), _fontHeight(0), _numChars(0), _shadowType(kNoShadowType) {
 	_shadowColor = 0;
 }
 
@@ -723,10 +722,9 @@ int CharsetRendererV3::getCharWidth(uint16 chr) const {
 	return spacing;
 }
 
-void CharsetRendererPC::enableShadow(bool enable) {
+void CharsetRendererPC::setShadowMode(ShadowType mode) {
 	_shadowColor = 0;
-	_enableShadow = enable;
-	_shadowType = kNormalShadowType;
+	_shadowType = mode;
 }
 
 void CharsetRendererPC::drawBits1(Graphics::Surface &dest, int x, int y, const byte *src, int drawTop, int width, int height) {
@@ -735,37 +733,47 @@ void CharsetRendererPC::drawBits1(Graphics::Surface &dest, int x, int y, const b
 		return;
 	}
 
+	if (_shadowType == kOutlineShadowType) {
+		x++;
+		y++;
+	}
+
 	byte *dst = (byte *)dest.getBasePtr(x, y);
 	byte bits = 0;
 	uint8 col = _color;
 	int pitch = dest.pitch - width * dest.format.bytesPerPixel;
 	byte *dst2 = dst + dest.pitch;
-
-	if (_vm->_isIndy4Jap) {
-		// Characters allow shadows only if this is the main virtual screen, and we are not drawing
-		// a message on a GUI banner. The main menu is fine though, and allows shadows as well.
-		VirtScreen *vs = _vm->findVirtScreen(_top);
-		bool canDrawShadow = vs != nullptr && vs->number == kMainVirtScreen && !_vm->isMessageBannerActive();
-		enableShadow(canDrawShadow);
-	}
+	byte *dst3 = dst - 1;
+	byte *dst4 = dst - dest.pitch;
+	byte prevBits = 0;
+	bool leftShadePixel = false;
 
 	for (y = 0; y < height && y + drawTop < dest.h; y++) {
 		for (x = 0; x < width; x++) {
-			if ((x % 8) == 0)
+			if ((x % 8) == 0) {
+				prevBits = ~bits;
 				bits = *src++;
+				leftShadePixel = true;
+			}
 			if ((bits & revBitMask(x % 8)) && y + drawTop >= 0) {
-				if (_enableShadow) {
-					if (_shadowType == kNormalShadowType) {
-						dst[1] = dst2[1] = _shadowColor;
-
-						// Mac and DOS/V versions of Japanese INDY4 don't
-						// draw a shadow pixel below the first pixel.
-						// Verified from disasm.
-						if (!_vm->_isIndy4Jap)
-							dst2[0] = _shadowColor;
-					} else if (_shadowType == kHorizontalShadowType) {
-						dst[1] = _shadowColor;
+				if (_shadowType == kNormalShadowType) {
+					dst[1] = dst2[1] = _shadowColor;
+
+					// Mac and DOS/V versions of Japanese INDY4 don't
+					// draw a shadow pixel below the first pixel.
+					// Verified from disasm.
+					if (!_vm->_isIndy4Jap)
+						dst2[0] = _shadowColor;
+				} else if (_shadowType == kHorizontalShadowType) {
+					dst[1] = _shadowColor;
+				} else if (_shadowType == kOutlineShadowType) {
+					dst[1] = dst2[0] = dst2[1] = _shadowColor;
+					if (leftShadePixel) {
+						dst3[0] = _shadowColor;
+						leftShadePixel = false;
 					}
+					if (prevBits & revBitMask(x % 8))
+						dst4[0] = _shadowColor;
 				}
 				dst[0] = col;
 			} else if (!(bits & revBitMask(x % 8)) && (y < height - 1) &&
@@ -775,10 +783,14 @@ void CharsetRendererPC::drawBits1(Graphics::Surface &dest, int x, int y, const b
 
 			dst += dest.format.bytesPerPixel;
 			dst2 += dest.format.bytesPerPixel;
+			dst3 += dest.format.bytesPerPixel;
+			dst4 += dest.format.bytesPerPixel;
 		}
 
 		dst += pitch;
 		dst2 += pitch;
+		dst3 += pitch;
+		dst4 += pitch;
 	}
 }
 
@@ -843,39 +855,40 @@ int CharsetRendererV3::getDrawHeightIntern(uint16) {
 	return 8;
 }
 
-void CharsetRendererV3::setColor(byte color) {
-	bool useShadow = false;
+void CharsetRendererV3::setColor(byte color, bool shadowModeSpecialFlag) {
+	ShadowType mode = kNoShadowType;
 	_color = color;
 
-	// FM-TOWNS version of Loom uses old color method as well
-	if ((_vm->_game.version >= 2) && ((_vm->_game.features & GF_16COLOR) || (_vm->_game.id == GID_LOOM && _vm->_game.version == 3))) {
-		useShadow = ((_color & 0xF0) != 0);
-		_color &= 0x0f;
-	} else if (_vm->_game.features & GF_OLD256) {
-		useShadow = ((_color & 0x80) != 0);
-		_color &= 0x7f;
-	} else
-		useShadow = false;
-
+	if (_vm->_game.features & GF_OLD256) {
+		if (_color & 0x80)
+			mode = kNormalShadowType;
 #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
-	if (_vm->_game.platform == Common::kPlatformFMTowns) {
-		_color = (_color & 0x0f) | ((_color & 0x0f) << 4);
-		if (_color == 0)
-			_color = 0x88;
-	}
+		if (_vm->_game.platform == Common::kPlatformFMTowns) {
+			_color = (_color & 0x0f) | ((_color & 0x0f) << 4);
+			if (_color == 0)
+				_color = 0x88;
+		} else
 #endif
+		_color = (_vm->_game.id == GID_LOOM) ? _color & 0x0f : _color & 0x7f;
+	} else if (_vm->_game.id == GID_LOOM && _vm->_game.version == 3) {
+		mode = (_color & 0x40) ? (shadowModeSpecialFlag ? kNoShadowType : kOutlineShadowType) : ((_color & 0x80) ? kNormalShadowType : kNoShadowType);
+		_color &= 0x0f;
+	} else if (_vm->_game.version >= 2 && (_vm->_game.features & GF_16COLOR)) {
+		if ((_color & 0xF0) != 0)
+			mode = kNormalShadowType;
+	}
 
-	enableShadow(useShadow);
+	setShadowMode(mode);
 
 	translateColor();
 }
 
 #ifdef USE_RGB_COLOR
-void CharsetRendererPCE::setColor(byte color) {
+void CharsetRendererPCE::setColor(byte color, bool) {
 	_vm->setPCETextPalette(color);
 	_color = 15;
 
-	enableShadow(true);
+	setShadowMode(kNormalShadowType);
 }
 #endif
 
@@ -926,9 +939,12 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) {
 	if (_left + origWidth > _right + 1)
 		return;
 
-	if (_enableShadow) {
+	if (_shadowType == kNormalShadowType) {
 		width++;
 		height++;
+	} else if (_shadowType == kOutlineShadowType) {
+		width += 2;
+		height += 2;
 	}
 
 	if (_firstChar) {
@@ -969,7 +985,7 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) {
 
 	if (_str.right < _left) {
 		_str.right = _left;
-		if (_enableShadow)
+		if (_shadowType != kNoShadowType)
 			_str.right++;
 	}
 
@@ -1064,7 +1080,7 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
 
 	_vm->_charsetColorMap[1] = _color;
 	if (_vm->isScummvmKorTarget() && is2byte) {
-		enableShadow(true);
+		setShadowMode(kNormalShadowType);
 		_charPtr = _vm->get2byteCharPtr(chr);
 		_width = _vm->_2byteWidth;
 		_height = _vm->_2byteHeight;
@@ -1125,7 +1141,6 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
 		_vm->markRectAsDirty(vs->number, _left, _left + _width, drawTop, drawTop + _height);
 	}
 
-
 	// This check for kPlatformFMTowns and kMainVirtScreen is at least required for the chat with
 	// the navigator's head in front of the ghost ship in Monkey Island 1
 	if (!ignoreCharsetMask || (_vm->_game.platform == Common::kPlatformFMTowns && vs->number == kMainVirtScreen)) {
@@ -1171,7 +1186,7 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
 
 	if (_str.right < _left) {
 		_str.right = _left;
-		if (_vm->_game.platform != Common::kPlatformFMTowns && _enableShadow)
+		if (_vm->_game.platform != Common::kPlatformFMTowns && _shadowType != kNoShadowType)
 			_str.right++;
 	}
 
@@ -1285,14 +1300,22 @@ bool CharsetRendererClassic::prepareDraw(uint16 chr) {
 		_height = _origHeight = _vm->_2byteHeight;
 		_offsX = _offsY = 0;
 
-		if (_enableShadow) {
+		if (_vm->_isIndy4Jap) {
+			// Characters allow shadows only if this is the main virtual screen, and we are not drawing
+			// a message on a GUI banner. The main menu is fine though, and allows shadows as well.
+			VirtScreen *vs = _vm->findVirtScreen(_top);
+			bool canDrawShadow = vs != nullptr && vs->number == kMainVirtScreen && !_vm->isMessageBannerActive();
+			setShadowMode(canDrawShadow ? kNormalShadowType : kNoShadowType);
+		}
+
+		if (_shadowType != kNoShadowType) {
 			_width++;
 			_height++;
 		}
 
 		return true;
 	} else {
-		enableShadow(false);
+		setShadowMode(kNoShadowType);
 	}
 
 	uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
@@ -1405,20 +1428,20 @@ int CharsetRendererTownsV3::getFontHeight() const {
 	return _vm->_useCJKMode ? 8 : _fontHeight;
 }
 
-void CharsetRendererTownsV3::enableShadow(bool enable) {
+void CharsetRendererTownsV3::setShadowMode(ShadowType mode) {
 	if (_vm->isScummvmKorTarget()) {
-		CharsetRendererV3::enableShadow(enable);
+		CharsetRendererV3::setShadowMode(mode);
 		return;
 	}
 
 	_shadowColor = 8;
-	_enableShadow = enable;
+	_shadowType = mode;
 
 #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
 	_shadowColor = 0x88;
 #ifdef USE_RGB_COLOR
 	if (_vm->_cjkFont)
-		_vm->_cjkFont->setDrawingMode(enable ? Graphics::FontSJIS::kFMTownsShadowMode : Graphics::FontSJIS::kDefaultMode);
+		_vm->_cjkFont->setDrawingMode(mode != kNoShadowType ? Graphics::FontSJIS::kFMTownsShadowMode : Graphics::FontSJIS::kDefaultMode);
 #endif
 #endif
 }
@@ -1465,13 +1488,13 @@ void CharsetRendererTownsV3::drawBits1(Graphics::Surface &dest, int x, int y, co
 				bits = *src++;
 			if ((bits & revBitMask(x % 8)) && y + drawTop >= 0) {
 				if (dest.format.bytesPerPixel == 2) {
-					if (_enableShadow) {
+					if (_shadowType != kNoShadowType) {
 						WRITE_UINT16(dst + 2, _vm->_16BitPalette[_shadowColor]);
 						WRITE_UINT16(dst + dest.pitch, _vm->_16BitPalette[_shadowColor]);
 					}
 					WRITE_UINT16(dst, _vm->_16BitPalette[_color]);
 				} else {
-					if (_enableShadow) {
+					if (_shadowType != kNoShadowType) {
 #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
 						if (scale2x) {
 							dst[2] = dst[3] = dst2[2] = dst2[3] = _shadowColor;
@@ -1570,11 +1593,11 @@ void CharsetRendererPCE::drawBits1(Graphics::Surface &dest, int x, int y, const
 				bits = *src++;
 			if ((bits & revBitMask(bitCount % 8)) && y + drawTop >= 0) {
 				if (dest.format.bytesPerPixel == 2) {
-					if (_enableShadow)
+					if (_shadowType != kNoShadowType)
 						WRITE_UINT16(dst + dest.pitch + 2, _vm->_16BitPalette[_shadowColor]);
 					WRITE_UINT16(dst, _vm->_16BitPalette[_color]);
 				} else {
-					if (_enableShadow)
+					if (_shadowType != kNoShadowType)
 						*(dst + dest.pitch + 1) = _shadowColor;
 					*dst = _color;
 				}
@@ -1605,7 +1628,7 @@ void CharsetRendererPCE::setDrawCharIntern(uint16 chr) {
 #endif
 
 CharsetRendererMac::CharsetRendererMac(ScummEngine *vm, const Common::Path &fontFile)
-	 : CharsetRendererCommon(vm), _lastTop(0) {
+	: CharsetRendererCommon(vm), _lastTop(0) {
 
 	// The original Macintosh interpreter didn't use the correct spacing
 	// between characters for some of the text, e.g. the Grail Diary. This
@@ -1718,7 +1741,7 @@ void CharsetRendererMac::printChar(int chr, bool ignoreCharsetMask) {
 		_pad = false;
 	}
 
-	bool enableShadow = _enableShadow;
+	bool enableShadow = (_shadowType != kNoShadowType);
 	int color = _color;
 
 	// HACK: Notes and their names should always be drawn with a shadow.
@@ -1913,12 +1936,11 @@ void CharsetRendererMac::printCharInternal(int chr, int color, bool shadow, int
 	}
 }
 
-void CharsetRendererMac::setColor(byte color) {
+void CharsetRendererMac::setColor(byte color, bool) {
 	_color = color;
-	_enableShadow = false;
 	_shadowColor = 0;
 
-	_enableShadow = ((color & 0xF0) != 0);
+	_shadowType = ((color & 0xF0) != 0) ? kNormalShadowType : kNoShadowType;
 	// Anything outside the ordinary palette should be fine.
 	_shadowColor = 255;
 	_color &= 0x0F;
@@ -2124,7 +2146,7 @@ void CharsetRendererNES::printChar(int chr, bool ignoreCharsetMask) {
 
 	if (_str.right < _left) {
 		_str.right = _left;
-		if (_enableShadow)
+		if (_shadowType != kNoShadowType)
 			_str.right++;
 	}
 
@@ -2279,7 +2301,7 @@ bool CharsetRendererTownsClassic::prepareDraw(uint16 chr) {
 		_origHeight = _height = _vm->_2byteHeight;
 		_charPtr = _vm->get2byteCharPtr(chr);
 		_offsX = _offsY = 0;
-		if (_enableShadow) {
+		if (_shadowType != kNoShadowType) {
 			_width++;
 			_height++;
 		}
@@ -2291,7 +2313,7 @@ bool CharsetRendererTownsClassic::prepareDraw(uint16 chr) {
 }
 
 void CharsetRendererTownsClassic::setupShadowMode() {
-	_enableShadow = true;
+	_shadowType = kNormalShadowType;
 	_shadowColor = _vm->_townsCharsetColorMap[0];
 	assert(_vm->_cjkFont);
 
diff --git a/engines/scumm/charset.h b/engines/scumm/charset.h
index 9cb11a3df14..16c97dc1434 100644
--- a/engines/scumm/charset.h
+++ b/engines/scumm/charset.h
@@ -111,13 +111,27 @@ public:
 	virtual int getCharHeight(uint16 chr) const { return getFontHeight(); }
 	virtual int getCharWidth(uint16 chr) const = 0;
 
-	virtual void setColor(byte color) { _color = color; translateColor(); }
+	virtual void setColor(byte color, bool shadowModeSpecialFlag = false) { _color = color; translateColor(); }
 	virtual byte getColor() { return _color; }
 
 	void saveLoadWithSerializer(Common::Serializer &ser);
 };
 
 class CharsetRendererCommon : public CharsetRenderer {
+public:
+	enum ShadowType {
+		kNoShadowType,
+		kNormalShadowType,
+		kHorizontalShadowType,
+		kOutlineShadowType
+	};
+
+	CharsetRendererCommon(ScummEngine *vm);
+
+	void setCurID(int32 id) override;
+
+	int getFontHeight() const override;
+
 protected:
 	const byte *_fontPtr;
 	int _bitsPerPixel;
@@ -125,32 +139,17 @@ protected:
 	int _numChars;
 
 	byte _shadowColor;
-	bool _enableShadow;
-
-public:
-	CharsetRendererCommon(ScummEngine *vm);
-
-	void setCurID(int32 id) override;
-
-	int getFontHeight() const override;
+	ShadowType _shadowType;
 };
 
 class CharsetRendererPC : public CharsetRendererCommon {
-	enum ShadowType {
-		kNoShadowType,
-		kNormalShadowType,
-		kHorizontalShadowType
-	};
-
-	ShadowType _shadowType;
+public:
+	CharsetRendererPC(ScummEngine *vm) : CharsetRendererCommon(vm) { }
 
 protected:
-	virtual void enableShadow(bool enable);
+	virtual void setShadowMode(ShadowType mode);
 	virtual void drawBits1(Graphics::Surface &dest, int x, int y, const byte *src, int drawTop, int width, int height);
 	void drawBits1Kor(Graphics::Surface &dest, int x1, int y1, const byte *src, int drawTop, int width, int height);
-
-public:
-	CharsetRendererPC(ScummEngine *vm) : CharsetRendererCommon(vm), _shadowType(kNoShadowType) { }
 };
 
 class CharsetRendererClassic : public CharsetRendererPC {
@@ -232,7 +231,7 @@ public:
 	void printChar(int chr, bool ignoreCharsetMask) override;
 	void drawChar(int chr, Graphics::Surface &s, int x, int y) override;
 	void setCurID(int32 id) override;
-	void setColor(byte color) override;
+	void setColor(byte color, bool shadowModeSpecialFlag) override;
 	int getCharWidth(uint16 chr) const override;
 };
 
@@ -244,7 +243,7 @@ public:
 	int getFontHeight() const override;
 
 private:
-	void enableShadow(bool enable) override;
+	void setShadowMode(ShadowType mode) override;
 	void drawBits1(Graphics::Surface &dest, int x, int y, const byte *src, int drawTop, int width, int height) override;
 #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
 	int getDrawWidthIntern(uint16 chr) override;
@@ -268,7 +267,7 @@ private:
 public:
 	CharsetRendererPCE(ScummEngine *vm) : CharsetRendererV3(vm), _sjisCurChar(0) {}
 
-	void setColor(byte color) override;
+	void setColor(byte color, bool) override;
 };
 #endif
 
@@ -309,7 +308,7 @@ public:
 	int getFontHeight() const override;
 	int getCharWidth(uint16 chr) const override;
 	void printChar(int chr, bool ignoreCharsetMask) override;
-	void setColor(byte color) override;
+	void setColor(byte color, bool) override;
 };
 
 #ifdef ENABLE_SCUMM_7_8
diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp
index 667962c9748..eb50085cb1f 100644
--- a/engines/scumm/string.cpp
+++ b/engines/scumm/string.cpp
@@ -1228,6 +1228,9 @@ void ScummEngine::drawString(int a, const byte *msg) {
 	_charset->_disableOffsX = _charset->_firstChar = true;
 	_charset->setCurID(_string[a].charset);
 
+	VirtScreen *vs = findVirtScreen(_charset->_top);
+	bool shadowModeFlag = (vs && vs->number == kMainVirtScreen);
+
 	if (_game.version >= 5)
 		memcpy(_charsetColorMap, _charsetData[_charset->getCurID()], 4);
 
@@ -1318,9 +1321,9 @@ void ScummEngine::drawString(int a, const byte *msg) {
 				color = buf[i] + (buf[i + 1] << 8);
 				i += 2;
 				if (color == 0xFF)
-					_charset->setColor(_string[a].color);
+					_charset->setColor(_string[a].color, shadowModeFlag);
 				else
-					_charset->setColor(color);
+					_charset->setColor(color, shadowModeFlag);
 				break;
 			default:
 				break;




More information about the Scummvm-git-logs mailing list