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

athrxx noreply at scummvm.org
Sat Jul 23 21:18:11 UTC 2022


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

Summary:
660512ac4d SCUMM: (V3/4 - CGA) - fix CGA mode for MI1EGA + cleanup
af2ce28786 SCUMM: (V4 - Hercules) - fix Hercules mode for MI1EGA
4230a882b0 SCUMM: (V4/EGA/CGA) - improve post-load fixes
e993bbc389 SCUMM: (V4 - Hercules) - fix typo


Commit: 660512ac4d88dd21f8f8e4c9c563929475066e7e
    https://github.com/scummvm/scummvm/commit/660512ac4d88dd21f8f8e4c9c563929475066e7e
Author: athrxx (athrxx at scummvm.org)
Date: 2022-07-23T23:17:45+02:00

Commit Message:
SCUMM: (V3/4 - CGA) - fix CGA mode for MI1EGA + cleanup

In the end, once fully understood, the CGA rendering is very similar for all versions. So I did manage to clean out some code. Hercules mode for MI1EGA is broken here, I will have another commit for that, once I understand how it works.

Changed paths:
    engines/scumm/actor.cpp
    engines/scumm/gfx.cpp
    engines/scumm/scumm.h


diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp
index ec37dc69144..a798221e079 100644
--- a/engines/scumm/actor.cpp
+++ b/engines/scumm/actor.cpp
@@ -3159,16 +3159,16 @@ void Actor::setActorCostume(int c) {
 	} else if (_vm->_game.features & GF_OLD_BUNDLE) {
 		for (i = 0; i < 16; i++)
 			_palette[i] = i;
-
-		// Make stuff more visible on CGA. Based on disassembly
-		if (_vm->_renderMode == Common::kRenderCGA && _vm->_game.version > 2) {
-			_palette[6] = 5;
-			_palette[7] = 15;
-		}
 	} else {
 		for (i = 0; i < 32; i++)
 			_palette[i] = 0xFF;
 	}
+
+	// Make stuff more visible on CGA. Based on disassembly. It is exactly the same in INDY3, LOOM and MI1 EGA.
+	if (_vm->_renderMode == Common::kRenderCGA && _vm->_game.version > 2 && _vm->_game.version < 5) {
+		_palette[6] = 5;
+		_palette[7] = 15;
+	}
 }
 
 static const char *const v0ActorNames_English[25] = {
@@ -3827,6 +3827,24 @@ void Actor::saveLoadWithSerializer(Common::Serializer &s) {
 				_cost.frame[i] = (_cost.frame[i] << 2) | newDirToOldDir(_facing);
 		}
 	}
+
+	// Post-load actor palette fixes for games that were saved with a different video mode (concerns INDY3, LOOM and MI1EGA).
+	if (s.isLoading() && (_vm->_game.version == 3 || _vm->_game.version == 4) && _vm->_game.platform == Common::kPlatformDOS) {
+		// Loom is not really much of a problem here, since it has extensive scripted post-load
+		// treatment in ScummEngine_v3::scummLoop_handleSaveLoad(). But there are situations
+		// where it won't be triggered (basically savegames from places where the original does
+		// not allow saving).  Indy3 is more dependant on this than Loom, since it does have much
+		// less scripted post-load magic of its own. Monkey Island always needs this, since V4+
+		// games don't do scripted loading of savegames (scripted post-load things) at all.
+		bool cga = (_vm->_renderMode == Common::kRenderCGA);
+		if ((cga && _palette[6] == 6 && _palette[7] == 7) || (!cga && _palette[6] == 5 && _palette[7] == 15)) {
+			_palette[6] ^= 3;
+			_palette[7] ^= 8;
+		}
+		// Extra fix for Bobbin in his normal costume.
+		if (_vm->_game.id == GID_LOOM && _number == 1 && ((cga && _palette[8] == 8) || (!cga && _palette[8] == 0)))
+			_palette[8] ^= 8;
+	}
 }
 
 void Actor_v3::saveLoadWithSerializer(Common::Serializer &s) {
@@ -3861,23 +3879,6 @@ void Actor_v3::saveLoadWithSerializer(Common::Serializer &s) {
 		s.syncAsUint16LE(_stepX, VER(rev));
 		s.syncAsUint16LE(_stepThreshold, VER(rev));
 	}
-
-	// Post-load actor palette fixes for games that were saved with a different video mode.
-	if (s.isLoading() && _vm->_game.version == 3 && _vm->_game.platform == Common::kPlatformDOS) {
-		// Loom is not really much of a problem here, since it has extensive scripted post-load
-		// treatment in ScummEngine_v3::scummLoop_handleSaveLoad(). But there are situations
-		// where it won't be triggered (basically savegames from places where the original does
-		// not allow saving).  Indy3 is more dependant on this than Loom, since it does have much
-		// less scripted post-load magic of its own.
-		bool cga = (_vm->_renderMode == Common::kRenderCGA);
-		if ((cga && _palette[6] == 6 && _palette[7] == 7) || (!cga && _palette[6] == 5 && _palette[7] == 15)) {
-			_palette[6] ^= 3;
-			_palette[7] ^= 8;
-		}
-		// Extra fix for Bobbin in his normal costume.
-		if (_vm->_game.id == GID_LOOM && _number == 1 && ((cga && _palette[8] == 8) || (!cga && _palette[8] == 0)))
-			_palette[8] ^= 8;
-	}
 }
 
 } // End of namespace Scumm
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index 19e1980b913..2343a8527b5 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -54,8 +54,6 @@ static void copy8Col(byte *dst, int dstPitch, const byte *src, int height, uint8
 #endif
 static void clear8Col(byte *dst, int dstPitch, int height, uint8 bitDepth);
 
-static void ditherHerc(byte *src, byte *hercbuf, int srcPitch, int *x, int *y, int *width, int *height);
-
 struct StripTable {
 	int offsets[160];
 	int run[160];
@@ -767,27 +765,15 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i
 					_system->copyRectToScreen(blackbuf, 16, 0, 0, 16, 240); // Fix left strip
 				}
 			}
-		} else if (_game.version == 1 || _game.version == 2) {
-			// MM/ZAK v1/v2
-			src = postProcessV2Graphics(vs, pitch, x, y, width, height);
-		} else if (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG) {
-			// MI1
-			ditherHerc(_compositeBuf, _hercCGAScaleBuf, width, &x, &y, &width, &height);
-
-			src = _hercCGAScaleBuf + x + y * kHercWidth;
-			pitch = kHercWidth;
-
-			// center image on the screen
-			x += (kHercWidth - _screenWidth * 2) / 2;	// (720 - 320*2)/2 = 40
 		} else if (_useCJKMode && m == 2) {
 			pitch *= m;
 			x *= m;
 			y *= m;
 			width *= m;
 			height *= m;
-		} else if (_renderMode == Common::kRenderCGA) {
-			// LOOM, MI1
-			ditherCGA(_compositeBuf, width, x, y, width, height);
+		} else if (_game.platform == Common::kPlatformDOS && _game.version < 5) {
+			// CGA and Hercules modes for MM/ZAK v1/v2, INDY3, LOOM, MI1EGA
+			src = postProcessDOSGraphics(vs, pitch, x, y, width, height);
 		}
 	}
 
@@ -795,11 +781,24 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i
 	_system->copyRectToScreen(src, pitch, x, y, width, height);
 }
 
-const byte *ScummEngine::postProcessV2Graphics(VirtScreen *vs, int &pitch, int &x, int &y, int &width, int &height) const {
-	static const byte v2VrbColMap[] =	{ 0x0, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF, 0xF, 0x5, 0x5, 0x5, 0xA, 0xA, 0xF, 0xF };
-	static const byte v2TxtColMap[] =	{ 0x0, 0xF, 0xA, 0x5, 0xA, 0x5, 0x5, 0xF, 0xA, 0xA, 0xA, 0xA, 0xA, 0x5, 0x5, 0xF };
-	static const byte mmv1VrbColMap[] =	{ 0x0, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF, 0xA, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF };
-	static const byte v2MainColMap[] =	{ 0x0, 0x4, 0x1, 0x5, 0x8, 0xA, 0x2, 0xF, 0xC, 0x7, 0xD, 0x5, 0xE, 0xB, 0xD, 0xF };
+const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int &x, int &y, int &width, int &height) const {
+	static const byte v2VrbColMap[] =	{	0x0, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF, 0xF, 0x5, 0x5, 0x5, 0xA, 0xA, 0xF, 0xF };
+	static const byte v2TxtColMap[] =	{	0x0, 0xF, 0xA, 0x5, 0xA, 0x5, 0x5, 0xF, 0xA, 0xA, 0xA, 0xA, 0xA, 0x5, 0x5, 0xF };
+	static const byte mmv1VrbColMap[] =	{	0x0, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF, 0xA, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF };
+	static const byte v2MainColMap[] =	{	0x0, 0x4, 0x1, 0x5, 0x8, 0xA, 0x2, 0xF, 0xC, 0x7, 0xD, 0x5, 0xE, 0xB, 0xD, 0xF };
+	static const byte v3MainColMap[] =	{	0x0, 0x4, 0x1, 0x5, 0x8, 0xA, 0x2, 0x3, 0xC, 0x7, 0xD, 0x5, 0xF, 0xB, 0x5, 0xF,
+											0x0, 0x1, 0x4, 0x5, 0x2, 0xA, 0x8, 0xC, 0x3, 0xD, 0x5, 0x5, 0xF, 0xE, 0x5, 0xF };
+	static const byte v4MainColMap[] =	{	0x0, 0x4, 0x1, 0x5, 0x2, 0xA, 0x2, 0x3, 0x0, 0x5, 0x5, 0x7, 0xF, 0xE, 0x5, 0xF,
+											0x0, 0x1, 0x4, 0x5, 0x8, 0xA, 0x8, 0xC, 0x0, 0x7, 0x5, 0xD, 0xF, 0xB, 0x5, 0xF,
+											0x0, 0x4, 0x1, 0x5, 0x2, 0xA, 0x2, 0x3, 0x0, 0x5, 0x5, 0x7, 0xF, 0xE, 0x5, 0xF,
+											0x0, 0x1, 0x4, 0x5, 0x8, 0xA, 0x8, 0xC, 0x0, 0xD, 0x5, 0xD, 0xF, 0xB, 0x5, 0xF };
+
+	static const byte hrcTableV4[32] = {	0x00, 0x00, 0x08, 0x80,	0xaa, 0xaa, 0xbb, 0xdd,	0x55, 0x00, 0x66, 0x99,	0x99, 0x66, 0x7f, 0xf7,
+											0x11, 0x44, 0x55, 0xaa,	0x77, 0xdd, 0xee, 0x77,	0xaa, 0xff, 0xee, 0xbb,	0xff, 0xbb, 0xff, 0xff };
+
+	static const byte *mainColMap[] = { nullptr, nullptr, v2MainColMap, v3MainColMap, v4MainColMap };
+
+	assert(_game.version < 5);
 
 	byte tmpTxtColMap[16];
 	for (uint8 i = 0; i < ARRAYSIZE(tmpTxtColMap); ++i)
@@ -809,17 +808,26 @@ const byte *ScummEngine::postProcessV2Graphics(VirtScreen *vs, int &pitch, int &
 	byte *dst = _compositeBuf;
 	const byte *src = res;
 	bool renderHerc = (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG);
+	bool renderV1 = (_game.version == 1);
+	bool renderV3 = _game.version > 2;
 	const byte *colMap = (_game.id == GID_ZAK || _game.version == 2) ? ((vs->number == kVerbVirtScreen || renderHerc) ? v2VrbColMap : v2TxtColMap) : (vs->number == kVerbVirtScreen ? mmv1VrbColMap : tmpTxtColMap);
+	const byte *colMap2 = mainColMap[_game.version];
+
+	// For v3 CGA is dithered as 4x4 squares, for v4 as 4x8 squares. Odd lines have the colors swapped, so there will be checkered patterns.
+	uint8 lnMod = (_game.version > 3) ? 0x40 : 0x20;
+	uint8 lnIdx = (y & ((lnMod >> 4) - 1)) << 4;
 
 	if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderCGAComp) {
-		if (vs->number == kMainVirtScreen) {
+		if (renderV3 || vs->number == kMainVirtScreen) {
 			for (int h = height; h; --h) {
 				for (int w = width >> 1; w; --w) {
-					byte c = (_game.version == 1) ? *src : (v2MainColMap[src[0]] & 0x0C) | (v2MainColMap[src[1]] & 0x03);
+					byte c = renderV1 ? *src : (colMap2[src[0] + lnIdx] & 0x0C) | (colMap2[src[1] + lnIdx] & 0x03);
 					*dst++ = (c >> 2) & 3;
 					*dst++ = c & 3;
 					src += 2;
 				}
+				if (renderV3)
+					lnIdx = (lnIdx + 0x10) % lnMod;
 			}
 		} else {
 			for (int h = height; h; --h) {
@@ -856,7 +864,7 @@ const byte *ScummEngine::postProcessV2Graphics(VirtScreen *vs, int &pitch, int &
 			for (int h = height2; h; --h) {
 				for (int w = width >> 1; w; --w) {
 					const uint32 *s = (const uint32*)dst;
-					byte c = (_game.version == 1) ? *src : (v2MainColMap[src[0]] & 0x0C) | (v2MainColMap[src[1]] & 0x03);
+					byte c = renderV1 ? *src : (v2MainColMap[src[0]] & 0x0C) | (v2MainColMap[src[1]] & 0x03);
 					*dst++ = (c >> 3) & 1;
 					*dst++ = (c >> 2) & 1;
 					*dst++ = (c >> 1) & 1;
@@ -905,7 +913,7 @@ const byte *ScummEngine::postProcessV2Graphics(VirtScreen *vs, int &pitch, int &
 			height <<= 1;
 		}
 
-	} else if (_game.version == 1 && vs->number == kTextVirtScreen) {
+	} else if (renderV1 && vs->number == kTextVirtScreen) {
 		// For EGA, the only colors that need remapping are for the kTextVirtScreen.
 		for (uint8 i = 0; i < ARRAYSIZE(tmpTxtColMap); ++i)
 			tmpTxtColMap[i] = _gdi->remapColorToRenderMode(i);
@@ -918,39 +926,6 @@ const byte *ScummEngine::postProcessV2Graphics(VirtScreen *vs, int &pitch, int &
 	return res;
 }
 
-// CGA
-// indy3 loom maniac monkey1 zak
-//
-// Herc (720x350)
-// maniac monkey1 zak
-//
-// EGA
-// monkey2 loom maniac monkey1 atlantis indy3 zak loomcd
-
-static const byte cgaDither[2][2][16] = {
-	{{0, 1, 0, 1, 2, 2, 0, 0, 3, 1, 3, 1, 3, 2, 1, 3},
-	 {0, 0, 1, 1, 0, 2, 2, 3, 0, 3, 1, 1, 3, 3, 1, 3}},
-	{{0, 0, 1, 1, 0, 2, 2, 3, 0, 3, 1, 1, 3, 3, 1, 3},
-	 {0, 1, 0, 1, 2, 2, 0, 0, 3, 1, 1, 1, 3, 2, 1, 3}}};
-
-void ScummEngine::ditherCGA(byte *dst, int dstPitch, int x, int y, int width, int height) const {
-	byte *ptr;
-	int idx1, idx2;
-	// CGA dithers 4x4 square with direct substitutes
-	// Odd lines have colors swapped, so there will be checkered patterns.
-	// But apparently there is a mistake for 10th color.
-	for (int y1 = 0; y1 < height; y1++) {
-		ptr = dst + y1 * dstPitch;
-		idx1 = (y + y1) % 2;
-
-		for (int x1 = 0; x1 < width; x1++) {
-			idx2 = (x + x1) % 2;
-			*ptr = cgaDither[idx1][idx2][*ptr & 0xF];
-			ptr++;
-		}
-	}
-}
-
 // Hercules dithering. It uses same dithering tables but output is 1bpp and
 // it stretches in this way:
 //         aaaa0
@@ -960,8 +935,8 @@ void ScummEngine::ditherCGA(byte *dst, int dstPitch, int x, int y, int width, in
 // dd      cccc0
 //         cccc1
 //         dddd0
-void ditherHerc(byte *src, byte *hercbuf, int srcPitch, int *x, int *y, int *width, int *height) {
-	byte *srcptr, *dstptr;
+//void ScummEngine::ditherV4herc(byte *src, byte *hercbuf, int srcPitch, int *x, int *y, int *width, int *height) const {
+	/*byte *srcptr, *dstptr;
 	const int xo = *x, yo = *y, widtho = *width, heighto = *height;
 	int dsty = yo*2 - yo/4;
 
@@ -974,21 +949,21 @@ void ditherHerc(byte *src, byte *hercbuf, int srcPitch, int *x, int *y, int *wid
 		const int idx1 = (dsty % 7) % 2;
 		for (int x1 = 0; x1 < widtho; x1++) {
 			const int idx2 = (xo + x1) % 2;
-			const byte tmp = cgaDither[idx1][idx2][*srcptr & 0xF];
-			*dstptr++ = tmp >> 1;
-			*dstptr++ = tmp & 0x1;
+			//const byte tmp = _ditheringTable[idx1][idx2][*srcptr & 0xF];
+			//*dstptr++ = tmp >> 1;
+			//*dstptr++ = tmp & 0x1;
 			srcptr++;
 		}
 		if (idx1 || dsty % 7 == 6)
 			y1++;
 		dsty++;
-	}
+	}*/
 
-	*x *= 2;
-	*y = yo*2 - yo/4;
-	*width *= 2;
-	*height = dsty - *y;
-}
+	//*x *= 2;
+	//*y = yo*2 - yo/4;
+	//*width *= 2;
+	//*height = dsty - *y;
+//}
 
 #pragma mark -
 #pragma mark --- Background buffers & charset mask ---
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 16f36a5932b..5db3ea79d45 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -1072,8 +1072,7 @@ protected:
 	void mac_undrawIndy3TextBox();
 	void mac_undrawIndy3CreditsText();
 
-	const byte *postProcessV2Graphics(VirtScreen *vs, int &pitch, int &x, int &y, int &width, int &height) const;
-	void ditherCGA(byte *dst, int dstPitch, int x, int y, int width, int height) const;
+	const byte *postProcessDOSGraphics(VirtScreen *vs, int &pitch, int &x, int &y, int &width, int &height) const;
 
 public:
 	VirtScreen *findVirtScreen(int y);
@@ -1082,7 +1081,6 @@ public:
 protected:
 	void fadeIn(int effect);
 	void fadeOut(int effect);
-	void setScrollBuffer();
 
 	void dissolveEffectSelector();
 	void transitionEffect(int a);


Commit: af2ce287863efd343a9d1baa8f76cc2d84afc938
    https://github.com/scummvm/scummvm/commit/af2ce287863efd343a9d1baa8f76cc2d84afc938
Author: athrxx (athrxx at scummvm.org)
Date: 2022-07-23T23:17:45+02:00

Commit Message:
SCUMM: (V4 - Hercules) - fix Hercules mode for MI1EGA

Changed paths:
    engines/scumm/cursor.cpp
    engines/scumm/gfx.cpp


diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp
index ff8f6531ffc..c3d31560fc3 100644
--- a/engines/scumm/cursor.cpp
+++ b/engines/scumm/cursor.cpp
@@ -692,32 +692,36 @@ void ScummEngine_v5::setBuiltinCursor(int idx) {
 				252, 252, 253, 254
 			};
 			color = indy4AmigaColors[idx];
+		} else if (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG) {
+			color = idx & 1;
 		} else {
 			color = default_cursor_colors[idx];
 		}
 		memset(_grabbedCursor, 0xFF, sizeof(_grabbedCursor));
 	}
 
-	_cursor.hotspotX = _cursorHotspots[2 * _currentCursor] * _textSurfaceMultiplier;
-	_cursor.hotspotY = _cursorHotspots[2 * _currentCursor + 1] * _textSurfaceMultiplier;
-	_cursor.width = 16 * _textSurfaceMultiplier;
-	_cursor.height = 16 * _textSurfaceMultiplier;
-
-	int scl = _outputPixelFormat.bytesPerPixel * _textSurfaceMultiplier;
+	int sclW = (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG) ? 2 : _textSurfaceMultiplier;
+	int sclH = (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG) ? 1 : _textSurfaceMultiplier;
+	int sclW2 = _outputPixelFormat.bytesPerPixel * sclW;
 
+	_cursor.hotspotX = _cursorHotspots[2 * _currentCursor] * sclW;
+	_cursor.hotspotY = _cursorHotspots[2 * _currentCursor + 1] * sclH;
+	_cursor.width = 16 * sclW;
+	_cursor.height = 16 * sclH;
+	
 	for (i = 0; i < 16; i++) {
 		for (j = 0; j < 16; j++) {
 			if (src[i] & (1 << j)) {
-				byte *dst1 = _grabbedCursor + 16 * scl * i * _textSurfaceMultiplier + (15 - j) * scl;
-				byte *dst2 = (_textSurfaceMultiplier == 2) ? dst1 + 16 * scl : dst1;
+				byte *dst1 = _grabbedCursor + 16 * sclW2 * i * sclH + (15 - j) * sclW2;
+				byte *dst2 = (sclH == 2) ? dst1 + 16 * sclW2 : dst1;
 				if (_outputPixelFormat.bytesPerPixel == 2) {
-					for (int b = 0; b < scl; b += 2) {
+					for (int b = 0; b < sclW; b++) {
 						*((uint16 *)dst1) = *((uint16 *)dst2) = color;
 						dst1 += 2;
 						dst2 += 2;
 					}
 				} else {
-					for (int b = 0; b < scl; b++)
+					for (int b = 0; b < sclW; b++)
 						*dst1++ = *dst2++ = color;
 				}
 			}
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index 2343a8527b5..d0580d78d32 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -628,6 +628,15 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i
 	assert(x >= 0 && width <= vs->pitch);
 	assert(_textSurface.getPixels());
 
+	// Some extra clipping/alignment for certain render modes. This is from the MI1EGA interpreter where it actually matters.
+	// The dithering patterns require the alignment, otherwise there will be visible glitches. For V3, the original interpreter
+	// actually does this for all graphics modes... 
+	if (_game.version > 2 && (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderHercG || _renderMode == Common::kRenderHercA)) {
+		top &= ~3;
+		if (bottom & 3)
+			bottom = (bottom + 4) & ~3;
+	}
+
 	// Perform some clipping
 	if (width > vs->w - x)
 		width = vs->w - x;
@@ -782,23 +791,26 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i
 }
 
 const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int &x, int &y, int &width, int &height) const {
-	static const byte v2VrbColMap[] =	{	0x0, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF, 0xF, 0x5, 0x5, 0x5, 0xA, 0xA, 0xF, 0xF };
-	static const byte v2TxtColMap[] =	{	0x0, 0xF, 0xA, 0x5, 0xA, 0x5, 0x5, 0xF, 0xA, 0xA, 0xA, 0xA, 0xA, 0x5, 0x5, 0xF };
-	static const byte mmv1VrbColMap[] =	{	0x0, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF, 0xA, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF };
-	static const byte v2MainColMap[] =	{	0x0, 0x4, 0x1, 0x5, 0x8, 0xA, 0x2, 0xF, 0xC, 0x7, 0xD, 0x5, 0xE, 0xB, 0xD, 0xF };
-	static const byte v3MainColMap[] =	{	0x0, 0x4, 0x1, 0x5, 0x8, 0xA, 0x2, 0x3, 0xC, 0x7, 0xD, 0x5, 0xF, 0xB, 0x5, 0xF,
-											0x0, 0x1, 0x4, 0x5, 0x2, 0xA, 0x8, 0xC, 0x3, 0xD, 0x5, 0x5, 0xF, 0xE, 0x5, 0xF };
-	static const byte v4MainColMap[] =	{	0x0, 0x4, 0x1, 0x5, 0x2, 0xA, 0x2, 0x3, 0x0, 0x5, 0x5, 0x7, 0xF, 0xE, 0x5, 0xF,
-											0x0, 0x1, 0x4, 0x5, 0x8, 0xA, 0x8, 0xC, 0x0, 0x7, 0x5, 0xD, 0xF, 0xB, 0x5, 0xF,
-											0x0, 0x4, 0x1, 0x5, 0x2, 0xA, 0x2, 0x3, 0x0, 0x5, 0x5, 0x7, 0xF, 0xE, 0x5, 0xF,
-											0x0, 0x1, 0x4, 0x5, 0x8, 0xA, 0x8, 0xC, 0x0, 0xD, 0x5, 0xD, 0xF, 0xB, 0x5, 0xF };
-
-	static const byte hrcTableV4[32] = {	0x00, 0x00, 0x08, 0x80,	0xaa, 0xaa, 0xbb, 0xdd,	0x55, 0x00, 0x66, 0x99,	0x99, 0x66, 0x7f, 0xf7,
-											0x11, 0x44, 0x55, 0xaa,	0x77, 0xdd, 0xee, 0x77,	0xaa, 0xff, 0xee, 0xbb,	0xff, 0xbb, 0xff, 0xff };
+	static const byte v2VrbColMap[] =	{ 0x0, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF, 0xF, 0x5, 0x5, 0x5, 0xA, 0xA, 0xF, 0xF };
+	static const byte v2TxtColMap[] =	{ 0x0, 0xF, 0xA, 0x5, 0xA, 0x5, 0x5, 0xF, 0xA, 0xA, 0xA, 0xA, 0xA, 0x5, 0x5, 0xF };
+	static const byte mmv1VrbColMap[] =	{ 0x0, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF, 0xA, 0x5, 0x5, 0x5, 0xA, 0xA, 0xA, 0xF };
+	static const byte v2MainColMap[] =	{ 0x0, 0x4, 0x1, 0x5, 0x8, 0xA, 0x2, 0xF, 0xC, 0x7, 0xD, 0x5, 0xE, 0xB, 0xD, 0xF };
 
-	static const byte *mainColMap[] = { nullptr, nullptr, v2MainColMap, v3MainColMap, v4MainColMap };
+	static const byte v3MainColMap[] =	{
+		0x0, 0x4, 0x1, 0x5, 0x8, 0xA, 0x2, 0x3, 0xC, 0x7, 0xD, 0x5, 0xF, 0xB, 0x5, 0xF, 0x0, 0x1, 0x4, 0x5, 0x2, 0xA, 0x8, 0xC, 0x3, 0xD, 0x5, 0x5, 0xF, 0xE, 0x5, 0xF
+	};
+
+	static const byte v4MainColMap[] =	{
+		0x0, 0x4, 0x1, 0x5, 0x2, 0xA, 0x2, 0x3, 0x0, 0x5, 0x5, 0x7, 0xF, 0xE, 0x5, 0xF, 0x0, 0x1, 0x4, 0x5, 0x8, 0xA, 0x8, 0xC, 0x0, 0x7, 0x5, 0xD, 0xF, 0xB, 0x5, 0xF,
+		0x0, 0x4, 0x1, 0x5, 0x2, 0xA, 0x2, 0x3, 0x0, 0x5, 0x5, 0x7, 0xF, 0xE, 0x5, 0xF, 0x0, 0x1, 0x4, 0x5, 0x8, 0xA, 0x8, 0xC, 0x0, 0xD, 0x5, 0xD, 0xF, 0xB, 0x5, 0xF
+	};
 
-	assert(_game.version < 5);
+	static const byte hrcTableV4[32] = {
+		0x00, 0x08, 0xAA, 0xBB, 0x55, 0x66, 0x99, 0x77, 0x11, 0x55, 0x77, 0xEE, 0xAA, 0xEE, 0xFF, 0xFF,
+		0x00, 0x80, 0xAA, 0xDD, 0x00, 0x99, 0x66, 0xF7, 0x44, 0xAA, 0xDD, 0x77, 0xFF, 0xBB, 0xBB, 0xFF
+	};
+
+	static const byte *mainColMap[] = { nullptr, nullptr, v2MainColMap, v3MainColMap, v4MainColMap };
 
 	byte tmpTxtColMap[16];
 	for (uint8 i = 0; i < ARRAYSIZE(tmpTxtColMap); ++i)
@@ -810,11 +822,15 @@ const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int
 	bool renderHerc = (_renderMode == Common::kRenderHercA || _renderMode == Common::kRenderHercG);
 	bool renderV1 = (_game.version == 1);
 	bool renderV3 = _game.version > 2;
+
+	if (!renderV1 && !renderHerc && _renderMode != Common::kRenderCGA)
+		return res;
+
 	const byte *colMap = (_game.id == GID_ZAK || _game.version == 2) ? ((vs->number == kVerbVirtScreen || renderHerc) ? v2VrbColMap : v2TxtColMap) : (vs->number == kVerbVirtScreen ? mmv1VrbColMap : tmpTxtColMap);
 	const byte *colMap2 = mainColMap[_game.version];
 
-	// For v3 CGA is dithered as 4x4 squares, for v4 as 4x8 squares. Odd lines have the colors swapped, so there will be checkered patterns.
-	uint8 lnMod = (_game.version > 3) ? 0x40 : 0x20;
+	// For LOOM and INDY3, CGA gets dithered as 4x4 squares, for MI1EGA as 4x8 squares. Odd lines have the colors swapped, so there will be checkered patterns.
+	uint8 lnMod = (_game.version > 3 && !renderHerc) ? 0x40 : 0x20;
 	uint8 lnIdx = (y & ((lnMod >> 4) - 1)) << 4;
 
 	if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderCGAComp) {
@@ -839,18 +855,37 @@ const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int
 		}
 
 	} else if (renderHerc || _renderMode == Common::kRenderCGA_BW) {
-		// The monochrome rendering is very similiar for Hercules and CGA b/w.
-		// For Hercules we have to do some corrections to fit into the 350 pixels
-		// height. The text and verb vs are rendered in normal height, only the
-		// main vs gets scaled by leaving out every other line. And we center the
-		// image horizontally within the 720 pixels width.
-		// For CGA b/w the origial resolution is 640x200, so we just scale that
-		// to our 640x400 by repeating each line.
+		// The monochrome rendering is very similiar for Hercules and CGA b/w. For Hercules we have to do some corrections to fit into the 350 pixels height.
+		// For Hercules V1/2, the text and verb vs are rendered in normal height, only the main vs gets scaled by leaving out every other line. Hercules V4
+		// instead scales everything in a 4-to-7 lines ratio. And for all versions, we center the image horizontally within the 720 pixels width.
+		// For CGA b/w the origial resolution is 640x200, so we just scale that to our 640x400 by repeating each line.
 		pitch = renderHerc ? kHercWidth : (_screenWidth << 1);
 		dst = res = _hercCGAScaleBuf;
 		int pitch1 = (pitch - width) << 1;
 
-		if (vs->number == kMainVirtScreen) {
+		if (renderV3) {
+			pitch1 = pitch - (width << 1);
+			int height2 = height >> 2;
+			height = height2 * 7;
+			y = (y << 1) - (y >> 2);
+
+			for (int h1 = height2; h1; --h1) {
+				lnIdx = 0; // The 7-lines pattern always starts from the beginning. Which works fine, since the strips get vertically aligned for Hercules and CGA.
+				for (int h2 = 7; h2; --h2) {
+					for (int w = width >> 2; w; --w) {
+						byte c = (hrcTableV4[src[0] + lnIdx] & 0xC0) | (hrcTableV4[src[1] + lnIdx] & 0x30) | (hrcTableV4[src[2] + lnIdx] & 0x0C) | (hrcTableV4[src[3] + lnIdx] & 0x03);
+						for (int i = 7; i >= 0; --i)
+							*dst++ = (c >> i) & 1;
+						src += 4;
+					}
+					dst += pitch1;
+					if (lnIdx ^= 0x10)
+						src -= width;
+				}
+				src += width;
+			}
+
+		} else if (vs->number == kMainVirtScreen) {
 			uint32 *dst2 = (uint32*)(dst + pitch);
 			int pitch2 = pitch1 >> 2;
 			int height2 = height;
@@ -864,7 +899,7 @@ const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int
 			for (int h = height2; h; --h) {
 				for (int w = width >> 1; w; --w) {
 					const uint32 *s = (const uint32*)dst;
-					byte c = renderV1 ? *src : (v2MainColMap[src[0]] & 0x0C) | (v2MainColMap[src[1]] & 0x03);
+					byte c = renderV1 ? *src : (colMap2[src[0]] & 0x0C) | (colMap2[src[1]] & 0x03);
 					*dst++ = (c >> 3) & 1;
 					*dst++ = (c >> 2) & 1;
 					*dst++ = (c >> 1) & 1;
@@ -926,45 +961,6 @@ const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int
 	return res;
 }
 
-// Hercules dithering. It uses same dithering tables but output is 1bpp and
-// it stretches in this way:
-//         aaaa0
-// aa      aaaa1
-// bb      bbbb0      Here 0 and 1 mean dithering table row number
-// cc -->  bbbb1
-// dd      cccc0
-//         cccc1
-//         dddd0
-//void ScummEngine::ditherV4herc(byte *src, byte *hercbuf, int srcPitch, int *x, int *y, int *width, int *height) const {
-	/*byte *srcptr, *dstptr;
-	const int xo = *x, yo = *y, widtho = *width, heighto = *height;
-	int dsty = yo*2 - yo/4;
-
-	for (int y1 = 0; y1 < heighto;) {
-		assert(dsty < kHercHeight);
-
-		srcptr = src + y1 * srcPitch;
-		dstptr = hercbuf + dsty * kHercWidth + xo * 2;
-
-		const int idx1 = (dsty % 7) % 2;
-		for (int x1 = 0; x1 < widtho; x1++) {
-			const int idx2 = (xo + x1) % 2;
-			//const byte tmp = _ditheringTable[idx1][idx2][*srcptr & 0xF];
-			//*dstptr++ = tmp >> 1;
-			//*dstptr++ = tmp & 0x1;
-			srcptr++;
-		}
-		if (idx1 || dsty % 7 == 6)
-			y1++;
-		dsty++;
-	}*/
-
-	//*x *= 2;
-	//*y = yo*2 - yo/4;
-	//*width *= 2;
-	//*height = dsty - *y;
-//}
-
 #pragma mark -
 #pragma mark --- Background buffers & charset mask ---
 #pragma mark -


Commit: 4230a882b06d64b53081192faf868baeb8fedc0a
    https://github.com/scummvm/scummvm/commit/4230a882b06d64b53081192faf868baeb8fedc0a
Author: athrxx (athrxx at scummvm.org)
Date: 2022-07-23T23:17:46+02:00

Commit Message:
SCUMM: (V4/EGA/CGA) - improve post-load fixes

Also include room palette fixes for games that were saved with a different video mode. Unfortunately the scripts make changes to the room palette based on VAR_VIDEOMODE. The original interpreter does not fix that.

Changed paths:
    engines/scumm/actor.cpp
    engines/scumm/saveload.cpp
    engines/scumm/script_v5.cpp
    engines/scumm/scumm.cpp
    engines/scumm/scumm.h


diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp
index a798221e079..eae8e2ae26f 100644
--- a/engines/scumm/actor.cpp
+++ b/engines/scumm/actor.cpp
@@ -3828,8 +3828,10 @@ void Actor::saveLoadWithSerializer(Common::Serializer &s) {
 		}
 	}
 
-	// Post-load actor palette fixes for games that were saved with a different video mode (concerns INDY3, LOOM and MI1EGA).
-	if (s.isLoading() && (_vm->_game.version == 3 || _vm->_game.version == 4) && _vm->_game.platform == Common::kPlatformDOS) {
+	// WORKAROUND: Post-load actor palette fixes for games that were saved with a different render mode
+	// (concerns INDY3, LOOM and MI1EGA). The original interpreter does not fix this, savegames from
+	// different videomodes will cause glitches there.
+	if (s.isLoading() && (_vm->_game.version == 3 || _vm->_game.id == GID_MONKEY_EGA) && _vm->_game.platform == Common::kPlatformDOS) {
 		// Loom is not really much of a problem here, since it has extensive scripted post-load
 		// treatment in ScummEngine_v3::scummLoop_handleSaveLoad(). But there are situations
 		// where it won't be triggered (basically savegames from places where the original does
@@ -3837,7 +3839,10 @@ void Actor::saveLoadWithSerializer(Common::Serializer &s) {
 		// less scripted post-load magic of its own. Monkey Island always needs this, since V4+
 		// games don't do scripted loading of savegames (scripted post-load things) at all.
 		bool cga = (_vm->_renderMode == Common::kRenderCGA);
-		if ((cga && _palette[6] == 6 && _palette[7] == 7) || (!cga && _palette[6] == 5 && _palette[7] == 15)) {
+		if (cga && _vm->_game.id == GID_MONKEY_EGA && _palette[6] == 0xFF && _palette[7] == 0xFF) {
+			_palette[6] = 5;
+			_palette[7] = 15;
+		} else if ((cga && _palette[6] == 6 && _palette[7] == 7) || (!cga && _palette[6] == 5 && _palette[7] == 15)) {
 			_palette[6] ^= 3;
 			_palette[7] ^= 8;
 		}
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index 6dd2dbeddcd..bce0c2ff4a8 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -1446,7 +1446,13 @@ void ScummEngine::saveLoadWithSerializer(Common::Serializer &s) {
 	// Set video mode var to the current actual mode, not the one that was enabled when the game was saved.
 	// At least for Loom this fixes glitches, since the game actually reads the var and makes actor palette
 	// adjustments based on that. This is a bug that happens in the original interpreter, too.
-	setVideoModeVarToCurrentConfig();
+	if (s.isLoading() && VAR_VIDEOMODE != 0xFF) {
+		int videoModeSaved = VAR(VAR_VIDEOMODE);
+		setVideoModeVarToCurrentConfig();
+		// For MI1EGA we need to know if the savegame is from a different render mode, so we can apply some
+		// post-load fixes if necessary.
+		_videoModeChanged = (videoModeSaved != VAR(VAR_VIDEOMODE));
+	}
 
 	// WORKAROUND: FM-TOWNS Zak used the extra 40 pixels at the bottom to increase the inventory to 10 items
 	// if we trim to 200 pixels, we can show only 6 items
@@ -1466,7 +1472,6 @@ void ScummEngine::saveLoadWithSerializer(Common::Serializer &s) {
 		runInventoryScript(0);
 	}
 
-
 	//
 	// Save/load a list of the locked objects
 	//
diff --git a/engines/scumm/script_v5.cpp b/engines/scumm/script_v5.cpp
index 9031d456317..68260ee988b 100644
--- a/engines/scumm/script_v5.cpp
+++ b/engines/scumm/script_v5.cpp
@@ -540,7 +540,7 @@ void ScummEngine_v5::o5_actorOps() {
 
 			// WORKAROUND for original bug. The original interpreter has a color fix for CGA mode which can be seen
 			// in Actor::setActorCostume(). Sometimes (e. g. when Bobbin walks out of the darkened tent) the actor
-			// colors are changed via script without taking into the account the need to repeat the color fix.
+			// colors are changed via script without taking into account the need to repeat the color fix.
 			if (_game.id == GID_LOOM && _renderMode == Common::kRenderCGA && act == 1) {
 				if (i == 6 && j == 6)
 					j = 5;
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 0cd105a6454..f632b919862 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -2681,6 +2681,27 @@ void ScummEngine_v5::scummLoop_handleSaveLoad() {
 
 	ScummEngine::scummLoop_handleSaveLoad();
 
+	// WORKAROUND: MI1 post-load room palette fixes for games that were saved with a different
+	// render mode. The entry scripts apply custom fixes here, based on the VAR_VIDEOMODE
+	// var. Saving this state and then loading the savegame with a different render mode setting,
+	// will mess up the room palette. The original interpreter does not fix this, savegames
+	// from different videomodes are basically incompatible, at least until a scene comes up
+	// where the script might again apply the necessary fixes. Unfortunately, this workaround
+	// will also only work if the current room has a script with the correct fixes...
+	if (_game.id == GID_MONKEY_EGA && _videoModeChanged) {
+		_videoModeChanged = false;
+		// Reset everything that the former entry script might have
+		// done (based on the former VAR_VIDEOMODE).
+		for (int i = 0; i < ARRAYSIZE(_roomPalette); ++i)
+			_roomPalette[i] = i;
+		// We want just the ENCD script...
+		int entryScript = VAR_ENTRY_SCRIPT;
+		VAR_ENTRY_SCRIPT = 0xFF;
+		runEntryScript();
+		VAR_ENTRY_SCRIPT = entryScript;
+		warning("Loading savegame with a different render mode setting. Glitches might occur");
+	}
+
 	// update IQ points after loading
 	if (processIQPoints)
 		runScript(145, 0, 0, nullptr);
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 5db3ea79d45..848bdd3a8b8 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -606,6 +606,7 @@ protected:
 	uint32 _lastSaveTime = 0;
 	bool _saveTemporaryState = false;
 	bool _loadFromLauncher = false;
+	bool _videoModeChanged = false;
 	Common::String _saveLoadFileName;
 	Common::String _saveLoadDescription;
 


Commit: e993bbc389de3edf540c6fa8a8ff46bdad7e7608
    https://github.com/scummvm/scummvm/commit/e993bbc389de3edf540c6fa8a8ff46bdad7e7608
Author: athrxx (athrxx at scummvm.org)
Date: 2022-07-23T23:17:46+02:00

Commit Message:
SCUMM: (V4 - Hercules) - fix typo

Changed paths:
    engines/scumm/gfx.cpp


diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index d0580d78d32..742ab8e4878 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -806,7 +806,7 @@ const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int
 	};
 
 	static const byte hrcTableV4[32] = {
-		0x00, 0x08, 0xAA, 0xBB, 0x55, 0x66, 0x99, 0x77, 0x11, 0x55, 0x77, 0xEE, 0xAA, 0xEE, 0xFF, 0xFF,
+		0x00, 0x08, 0xAA, 0xBB, 0x55, 0x66, 0x99, 0x7F, 0x11, 0x55, 0x77, 0xEE, 0xAA, 0xEE, 0xFF, 0xFF,
 		0x00, 0x80, 0xAA, 0xDD, 0x00, 0x99, 0x66, 0xF7, 0x44, 0xAA, 0xDD, 0x77, 0xFF, 0xBB, 0xBB, 0xFF
 	};
 
@@ -829,7 +829,7 @@ const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int
 	const byte *colMap = (_game.id == GID_ZAK || _game.version == 2) ? ((vs->number == kVerbVirtScreen || renderHerc) ? v2VrbColMap : v2TxtColMap) : (vs->number == kVerbVirtScreen ? mmv1VrbColMap : tmpTxtColMap);
 	const byte *colMap2 = mainColMap[_game.version];
 
-	// For LOOM and INDY3, CGA gets dithered as 4x4 squares, for MI1EGA as 4x8 squares. Odd lines have the colors swapped, so there will be checkered patterns.
+	// For LOOM and INDY3, CGA gets dithered as 2x2 squares, for MI1EGA as 2x4 squares. Odd lines have the colors swapped, so there will be checkered patterns.
 	uint8 lnMod = (_game.version > 3 && !renderHerc) ? 0x40 : 0x20;
 	uint8 lnIdx = (y & ((lnMod >> 4) - 1)) << 4;
 
@@ -864,6 +864,7 @@ const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int
 		int pitch1 = (pitch - width) << 1;
 
 		if (renderV3) {
+			// This is for MI1EGA Hercules only
 			pitch1 = pitch - (width << 1);
 			int height2 = height >> 2;
 			height = height2 * 7;
@@ -886,6 +887,7 @@ const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int
 			}
 
 		} else if (vs->number == kMainVirtScreen) {
+			// V1/2 Hercules and CGA b/w mode
 			uint32 *dst2 = (uint32*)(dst + pitch);
 			int pitch2 = pitch1 >> 2;
 			int height2 = height;
@@ -912,6 +914,7 @@ const byte *ScummEngine::postProcessDOSGraphics(VirtScreen *vs, int &pitch, int
 			}
 
 		} else {
+			// V1/2 Hercules and CGA b/w mode
 			if (renderHerc) {
 				pitch1 = kHercWidth - (width << 1);
 				y -= vs->topline;




More information about the Scummvm-git-logs mailing list