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

bluegr noreply at scummvm.org
Wed Dec 18 22:38:52 UTC 2024


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

Summary:
407197e6af AGI: Move misplaced picture opcode handler
202f594198 AGI: Create separate PREAGI picture version and draw function
07716bd8a3 AGI: Implement PREAGI picture patterns
3bd221196a AGI: Add Pictures debug channel
99c022767a AGI: Implement PREAGI picture coordinate clipping
5bfae4a276 AGI: Fix PREAGI missing flood fills
e082448239 AGI: Fix PREAGI memory corruption when drawing pictures


Commit: 407197e6afcdb86c34e13723a91d3305f9bb9110
    https://github.com/scummvm/scummvm/commit/407197e6afcdb86c34e13723a91d3305f9bb9110
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2024-12-19T00:38:46+02:00

Commit Message:
AGI: Move misplaced picture opcode handler

This is a V1 opcode that was moved to the wrong function in 2016.
See: 8a595e7771aa89d06876e13d7ab6751e26da8982

Confirmed in the TrollVM source that this code originated in.

With this understood, I am reverting my change to fix SQ1 Apple II.
Its pictures contain FC bytes that had no effect in the original because
they were correctly ignored. SQ1's FC bytes crashed this opcode handler,
so I added validation, because I didn't realize that the handler itself
was the mistake. See: 91916981cf9ab2e9f1f7fc9116bdd8f9b9c7bdd7

Changed paths:
    engines/agi/picture.cpp


diff --git a/engines/agi/picture.cpp b/engines/agi/picture.cpp
index 9e0eb7d528d..c8b019eacc5 100644
--- a/engines/agi/picture.cpp
+++ b/engines/agi/picture.cpp
@@ -379,7 +379,6 @@ void PictureMgr::drawPictureC64() {
 			_scrOn = true;
 			break;
 		case 0xe6:  // plot brush
-			// TODO: should this be getNextParamByte()?
 			_patCode = getNextByte();
 			plotBrush();
 			break;
@@ -420,6 +419,11 @@ void PictureMgr::drawPictureV1() {
 		case 0xfb:
 			draw_LineShort();
 			break;
+		case 0xfc:
+			draw_SetColor();
+			draw_SetPriority();
+			draw_Fill();
+			break;
 		case 0xff: // end of data
 			return;
 		default:
@@ -525,7 +529,6 @@ void PictureMgr::drawPictureV2() {
 			draw_Fill();
 			break;
 		case 0xf9:
-			// TODO: should this be getNextParamByte()?
 			_patCode = getNextByte();
 
 			if (_vm->getGameType() == GType_PreAGI)
@@ -534,14 +537,6 @@ void PictureMgr::drawPictureV2() {
 		case 0xfa:
 			plotBrush();
 			break;
-		// FIXME: There is no opcode FC. A refactor in 2016 moved it to this
-		//        function and removed the comment that it was for V1 or V1.5.
-		//        Determine where this should go (if anywhere) before removing.
-		case 0xfc:
-			draw_SetColor();
-			draw_SetPriority();
-			draw_Fill();
-			break;
 		case 0xff: // end of data
 			return;
 		default:
@@ -597,8 +592,7 @@ void PictureMgr::drawPictureAGI256() {
 }
 
 void PictureMgr::draw_SetColor() {
-	if (!getNextParamByte(_scrColor))
-		return;
+	_scrColor = getNextByte();
 
 	// For CGA, replace the color with its mixture color
 	if (_vm->_renderMode == Common::kRenderCGA) {
@@ -607,7 +601,7 @@ void PictureMgr::draw_SetColor() {
 }
 
 void PictureMgr::draw_SetPriority() {
-	getNextParamByte(_priColor);
+	_priColor = getNextByte();
 }
 
 // this gets a nibble instead of a full byte


Commit: 202f5941985693bec572953766cc7a736e8a9dcd
    https://github.com/scummvm/scummvm/commit/202f5941985693bec572953766cc7a736e8a9dcd
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2024-12-19T00:38:46+02:00

Commit Message:
AGI: Create separate PREAGI picture version and draw function

Changed paths:
    engines/agi/picture.cpp
    engines/agi/picture.h
    engines/agi/preagi/mickey.cpp
    engines/agi/preagi/winnie.cpp


diff --git a/engines/agi/picture.cpp b/engines/agi/picture.cpp
index c8b019eacc5..39a07b7828f 100644
--- a/engines/agi/picture.cpp
+++ b/engines/agi/picture.cpp
@@ -337,6 +337,9 @@ void PictureMgr::drawPicture() {
 	case AGIPIC_V15:
 		drawPictureV15();
 		break;
+	case AGIPIC_PREAGI:
+		drawPicturePreAGI();
+		break;
 	case AGIPIC_V2:
 		drawPictureV2();
 		break;
@@ -480,13 +483,62 @@ void PictureMgr::drawPictureV15() {
 	}
 }
 
+void PictureMgr::drawPicturePreAGI() {
+	debugC(8, kDebugLevelMain, "Drawing PreAGI picture");
+
+	int step = 0;
+	while (_dataOffset < _dataSize) {
+		byte curByte = getNextByte();
+
+		switch (curByte) {
+		case 0xf0:
+			draw_SetColor();
+			_scrOn = true;
+			break;
+		case 0xf1:
+			_scrOn = false;
+			break;
+		case 0xf4:
+			yCorner();
+			break;
+		case 0xf5:
+			xCorner();
+			break;
+		case 0xf6:
+			draw_LineAbsolute();
+			break;
+		case 0xf7:
+			draw_LineShort();
+			break;
+		case 0xf8:
+			draw_Fill();
+			break;
+		case 0xf9:
+			_patCode = getNextByte();
+			plotBrush();
+			break;
+		case 0xff: // end of data
+			return;
+		default:
+			warning("Unknown picture opcode (%x) at (%x)", curByte, _dataOffset - 1);
+			break;
+		}
+
+		// Limit drawing to the optional maximum number of opcodes.
+		// Used by Mickey for crystal animation.
+		step++;
+		if (step == _maxStep) {
+			return;
+		}
+	}
+}
+
 void PictureMgr::drawPictureV2() {
 	debugC(8, kDebugLevelMain, "Drawing V2/V3 picture");
 
 	// AGIv3 nibble parameters are indicated by a flag in the picture's directory entry
 	bool nibbleMode = (_vm->_game.dirPic[_resourceNr].flags & RES_PICTURE_V3_NIBBLE_PARM) != 0;
 
-	int step = 0;
 	while (_dataOffset < _dataSize) {
 		byte curByte = getNextByte();
 
@@ -530,9 +582,6 @@ void PictureMgr::drawPictureV2() {
 			break;
 		case 0xf9:
 			_patCode = getNextByte();
-
-			if (_vm->getGameType() == GType_PreAGI)
-				plotBrush();
 			break;
 		case 0xfa:
 			plotBrush();
@@ -543,12 +592,6 @@ void PictureMgr::drawPictureV2() {
 			warning("Unknown picture opcode (%x) at (%x)", curByte, _dataOffset - 1);
 			break;
 		}
-
-		// Limit drawing to the optional maximum number of opcodes
-		step++;
-		if (step == _maxStep) {
-			return;
-		}
 	}
 }
 
diff --git a/engines/agi/picture.h b/engines/agi/picture.h
index 46f0b2f7226..b9bc3e85243 100644
--- a/engines/agi/picture.h
+++ b/engines/agi/picture.h
@@ -46,7 +46,8 @@ enum AgiPictureVersion {
 	AGIPIC_C64,     // Winnie (Apple II, C64, CoCo)
 	AGIPIC_V1,      // Currently unused
 	AGIPIC_V15,     // Troll (DOS)
-	AGIPIC_V2       // AGIv2, AGIv3, Winnie (DOS, Amiga), Mickey (DOS)
+	AGIPIC_PREAGI,  // Winnie (DOS, Amiga), Mickey (DOS)
+	AGIPIC_V2       // AGIv2, AGIv3
 };
 
 enum AgiPictureFlags {
@@ -88,6 +89,7 @@ private:
 	void drawPictureC64();
 	void drawPictureV1();
 	void drawPictureV15();
+	void drawPicturePreAGI();
 	void drawPictureV2();
 	void drawPictureAGI256();
 
diff --git a/engines/agi/preagi/mickey.cpp b/engines/agi/preagi/mickey.cpp
index 118a6847e91..7829adf43d6 100644
--- a/engines/agi/preagi/mickey.cpp
+++ b/engines/agi/preagi/mickey.cpp
@@ -2275,6 +2275,8 @@ void MickeyEngine::init() {
 #endif
 
 	setFlag(VM_FLAG_SOUND_ON, true); // enable sound
+
+	_picture->setPictureVersion(AGIPIC_PREAGI);
 }
 
 Common::Error MickeyEngine::go() {
diff --git a/engines/agi/preagi/winnie.cpp b/engines/agi/preagi/winnie.cpp
index 7c92bf58a47..515fed28c0f 100644
--- a/engines/agi/preagi/winnie.cpp
+++ b/engines/agi/preagi/winnie.cpp
@@ -1526,6 +1526,7 @@ void WinnieEngine::init() {
 		_picture->setPictureVersion(AGIPIC_C64);
 		break;
 	default:
+		_picture->setPictureVersion(AGIPIC_PREAGI);
 		break;
 	}
 


Commit: 07716bd8a3182fe4a869954493a8c8b20568e633
    https://github.com/scummvm/scummvm/commit/07716bd8a3182fe4a869954493a8c8b20568e633
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2024-12-19T00:38:46+02:00

Commit Message:
AGI: Implement PREAGI picture patterns

- Fixes Winnie items
- Fixes Mickey spaceship lights
- Fixes Mickey star map

Fixes bug #5730

Changed paths:
    engines/agi/picture.cpp
    engines/agi/picture.h
    engines/agi/preagi/mickey.cpp


diff --git a/engines/agi/picture.cpp b/engines/agi/picture.cpp
index 39a07b7828f..40014da5ee2 100644
--- a/engines/agi/picture.cpp
+++ b/engines/agi/picture.cpp
@@ -187,9 +187,9 @@ void PictureMgr::plotPattern(int x, int y) {
 		0, 1, 4, 9, 16, 25, 37, 50
 	};
 
-	static uint16 circle_data[] = {
+	static const uint16 circle_data[] = {
 		0x8000,
-		0xE000, 0xE000, 0xE000,
+		0x0000, 0xE000, 0x0000,
 		0x7000, 0xF800, 0x0F800, 0x0F800, 0x7000,
 		0x3800, 0x7C00, 0x0FE00, 0x0FE00, 0x0FE00, 0x7C00, 0x3800,
 		0x1C00, 0x7F00, 0x0FF80, 0x0FF80, 0x0FF80, 0x0FF80, 0x0FF80, 0x7F00, 0x1C00,
@@ -215,12 +215,6 @@ void PictureMgr::plotPattern(int x, int y) {
 
 	circle_ptr = &circle_data[circle_list[pen_size]];
 
-	// SGEORGE : Fix v3 picture data for drawing circles. Manifests in goldrush
-	if (_pictureVersion == AGIPIC_V2) {
-		circle_data[1] = 0;
-		circle_data[3] = 0;
-	}
-
 	// setup the X position
 	// = pen_x - pen.size/2
 
@@ -254,22 +248,9 @@ void PictureMgr::plotPattern(int x, int y) {
 	temp16 = temp16 << 1;
 	pen_width = temp16;                 // width of shape?
 
-	bool circleCond;
-	int counterStep;
-	int ditherCond;
-
-	if (_flags & kPicFCircle)
-		_patCode |= 0x10;
-
-	if (_vm->getGameType() == GType_PreAGI) {
-		circleCond = ((_patCode & 0x10) == 0);
-		counterStep = 3;
-		ditherCond = 0x03;
-	} else {
-		circleCond = ((_patCode & 0x10) != 0);
-		counterStep = 4;
-		ditherCond = 0x02;
-	}
+	bool circleCond = ((_patCode & 0x10) != 0);
+	int counterStep = 4;
+	int ditherCond = 0x02;
 
 	for (; pen_y < pen_final_y; pen_y++) {
 		circle_word = *circle_ptr++;
@@ -314,6 +295,62 @@ void PictureMgr::plotBrush() {
 	}
 }
 
+void PictureMgr::plotBrush_PreAGI() {
+	_patCode = getNextByte();
+	if (_patCode > 12) {
+		_patCode = 12;
+	}
+
+	for (;;) {
+		byte x, y;
+		if (!(getNextParamByte(x) && getNextParamByte(y)))
+			break;
+
+		plotPattern_PreAGI(x, y);
+	}
+}
+
+void PictureMgr::plotPattern_PreAGI(byte x, byte y) {
+	// PreAGI patterns are 13 solid circles
+	static const byte circleData[] = {
+		0x00,
+		0x01, 0x01,
+		0x01, 0x02, 0x02,
+		0x01, 0x02, 0x03, 0x03,
+		0x02, 0x03, 0x04, 0x04, 0x04,
+		0x02, 0x03, 0x04, 0x05, 0x05, 0x05,
+		0x02, 0x04, 0x05, 0x05, 0x06, 0x06, 0x06,
+		0x02, 0x04, 0x05, 0x06, 0x06, 0x07, 0x07, 0x07,
+		0x02, 0x04, 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x08,
+		0x03, 0x05, 0x06, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09,
+		0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a,
+		0x03, 0x05, 0x07, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b,
+		0x03, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0c
+	};
+
+	int circleDataIndex = (_patCode * (_patCode + 1)) / 2;
+
+	// draw the circle by drawing its vertical lines two at a time, starting at the
+	// left and right edges and working inwards. circles have odd widths, so the
+	// final iteration draws the middle line twice.
+	for (int i = _patCode; i >= 0; i--) {
+		const byte height = circleData[circleDataIndex++];
+		int16 x1, y1, x2, y2;
+
+		// left vertical line
+		x1 = x - i;
+		x2 = x1;
+		y1 = y - height;
+		y2 = y + height;
+		draw_Line(x1, y1, x2, y2);
+
+		// right vertical line
+		x1 = x + i;
+		x2 = x1;
+		draw_Line(x1, y1, x2, y2);
+	}
+}
+
 /**************************************************************************
 ** Draw AGI picture
 **************************************************************************/
@@ -382,8 +419,7 @@ void PictureMgr::drawPictureC64() {
 			_scrOn = true;
 			break;
 		case 0xe6:  // plot brush
-			_patCode = getNextByte();
-			plotBrush();
+			plotBrush_PreAGI();
 			break;
 		case 0xff: // end of data
 			return;
@@ -514,8 +550,7 @@ void PictureMgr::drawPicturePreAGI() {
 			draw_Fill();
 			break;
 		case 0xf9:
-			_patCode = getNextByte();
-			plotBrush();
+			plotBrush_PreAGI();
 			break;
 		case 0xff: // end of data
 			return;
diff --git a/engines/agi/picture.h b/engines/agi/picture.h
index b9bc3e85243..5cb92772cef 100644
--- a/engines/agi/picture.h
+++ b/engines/agi/picture.h
@@ -52,9 +52,8 @@ enum AgiPictureVersion {
 
 enum AgiPictureFlags {
 	kPicFNone      = (1 << 0),
-	kPicFCircle    = (1 << 1), // Mickey, spaceship lights (not drawn accurately)
-	kPicFf3Stop    = (1 << 2), // Troll, certain pictures
-	kPicFTrollMode = (1 << 3)  // Troll, drawing the Troll
+	kPicFf3Stop    = (1 << 1), // Troll, certain pictures
+	kPicFTrollMode = (1 << 2)  // Troll, drawing the Troll
 };
 
 class AgiBase;
@@ -75,6 +74,8 @@ private:
 	void yCorner(bool skipOtherCoords = false);
 	void plotPattern(int x, int y);
 	void plotBrush();
+	void plotPattern_PreAGI(byte x, byte y);
+	void plotBrush_PreAGI();
 
 	byte getNextByte();
 	bool getNextParamByte(byte &b);
diff --git a/engines/agi/preagi/mickey.cpp b/engines/agi/preagi/mickey.cpp
index 7829adf43d6..784554d0695 100644
--- a/engines/agi/preagi/mickey.cpp
+++ b/engines/agi/preagi/mickey.cpp
@@ -762,7 +762,7 @@ void MickeyEngine::drawRoomAnimation() {
 		// draw blinking ship lights
 		uint8 lightPicture[] = {
 			0xF0, 1,          // Set Color: 1
-			0xF9, 2, 43, 45,  // Set Pattern: 2, plot at 43,45
+			0xF9, 2, 44, 45,  // Set Pattern: 2, plot at 44,45
 			0xFF              // End
 		};
 
@@ -777,7 +777,6 @@ void MickeyEngine::drawRoomAnimation() {
 			lightPicture[1] = iColor; // change light color
 			lightPicture[4] += 7;     // increase x coordinate
 
-			_picture->setPictureFlags(kPicFCircle);
 			_picture->setMaxStep(0);
 			_picture->setOffset(IDI_MSA_PIC_X0, IDI_MSA_PIC_Y0);
 			_picture->decodePictureFromBuffer(lightPicture, sizeof(lightPicture), false, IDI_MSA_PIC_WIDTH, IDI_MSA_PIC_HEIGHT);


Commit: 3bd221196ad34b375607fb815fe9e86d9116c53e
    https://github.com/scummvm/scummvm/commit/3bd221196ad34b375607fb815fe9e86d9116c53e
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2024-12-19T00:38:46+02:00

Commit Message:
AGI: Add Pictures debug channel

Changed paths:
    engines/agi/agi.h
    engines/agi/detection.cpp
    engines/agi/picture.cpp


diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 42bb3d6bf25..5e4a7dc68a8 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -153,13 +153,14 @@ enum kDebugLevels {
 	kDebugLevelMain =      1 << 0,
 	kDebugLevelResources = 1 << 1,
 	kDebugLevelSprites =   1 << 2,
-	kDebugLevelInventory = 1 << 3,
-	kDebugLevelInput =     1 << 4,
-	kDebugLevelMenu =      1 << 5,
-	kDebugLevelScripts =   1 << 6,
-	kDebugLevelSound =     1 << 7,
-	kDebugLevelText =      1 << 8,
-	kDebugLevelSavegame =  1 << 9
+	kDebugLevelPictures =  1 << 3,
+	kDebugLevelInventory = 1 << 4,
+	kDebugLevelInput =     1 << 5,
+	kDebugLevelMenu =      1 << 6,
+	kDebugLevelScripts =   1 << 7,
+	kDebugLevelSound =     1 << 8,
+	kDebugLevelText =      1 << 9,
+	kDebugLevelSavegame =  1 << 10
 };
 
 /**
diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp
index 9d5c0ba9317..6999c0accc3 100644
--- a/engines/agi/detection.cpp
+++ b/engines/agi/detection.cpp
@@ -37,6 +37,7 @@
 static const DebugChannelDef debugFlagList[] = {
 	{Agi::kDebugLevelMain, "Main", "Generic debug level"},
 	{Agi::kDebugLevelResources, "Resources", "Resources debugging"},
+	{Agi::kDebugLevelPictures, "Pictures", "Pictures debugging"},
 	{Agi::kDebugLevelSprites, "Sprites", "Sprites debugging"},
 	{Agi::kDebugLevelInventory, "Inventory", "Inventory debugging"},
 	{Agi::kDebugLevelInput, "Input", "Input events debugging"},
diff --git a/engines/agi/picture.cpp b/engines/agi/picture.cpp
index 40014da5ee2..a4c33abbeb2 100644
--- a/engines/agi/picture.cpp
+++ b/engines/agi/picture.cpp
@@ -386,7 +386,7 @@ void PictureMgr::drawPicture() {
 }
 
 void PictureMgr::drawPictureC64() {
-	debugC(8, kDebugLevelMain, "Drawing Apple II / C64 / CoCo picture");
+	debugC(kDebugLevelPictures, "Drawing Apple II / C64 / CoCo picture");
 
 	_scrColor = 0;
 
@@ -431,7 +431,7 @@ void PictureMgr::drawPictureC64() {
 }
 
 void PictureMgr::drawPictureV1() {
-	debugC(8, kDebugLevelMain, "Drawing V1 picture");
+	debugC(kDebugLevelPictures, "Drawing V1 picture");
 
 	while (_dataOffset < _dataSize) {
 		byte curByte = getNextByte();
@@ -473,7 +473,7 @@ void PictureMgr::drawPictureV1() {
 }
 
 void PictureMgr::drawPictureV15() {
-	debugC(8, kDebugLevelMain, "Drawing V1.5 picture");
+	debugC(kDebugLevelPictures, "Drawing V1.5 picture");
 
 	while (_dataOffset < _dataSize) {
 		byte curByte = getNextByte();
@@ -520,7 +520,7 @@ void PictureMgr::drawPictureV15() {
 }
 
 void PictureMgr::drawPicturePreAGI() {
-	debugC(8, kDebugLevelMain, "Drawing PreAGI picture");
+	debugC(kDebugLevelPictures, "Drawing PreAGI picture");
 
 	int step = 0;
 	while (_dataOffset < _dataSize) {
@@ -569,7 +569,7 @@ void PictureMgr::drawPicturePreAGI() {
 }
 
 void PictureMgr::drawPictureV2() {
-	debugC(8, kDebugLevelMain, "Drawing V2/V3 picture");
+	debugC(kDebugLevelPictures, "Drawing V2/V3 picture");
 
 	// AGIv3 nibble parameters are indicated by a flag in the picture's directory entry
 	bool nibbleMode = (_vm->_game.dirPic[_resourceNr].flags & RES_PICTURE_V3_NIBBLE_PARM) != 0;
@@ -637,7 +637,7 @@ void PictureMgr::drawPictureAGI256() {
 	byte *dataPtr = _data;
 	byte *dataEndPtr = _data + _dataSize;
 
-	debugC(8, kDebugLevelMain, "Drawing AGI256 picture");
+	debugC(kDebugLevelPictures, "Drawing AGI256 picture");
 
 	while (dataPtr < dataEndPtr) {
 		byte color = *dataPtr++;
@@ -968,7 +968,7 @@ void PictureMgr::decodePictureFromBuffer(byte *data, uint32 length, bool clearSc
 }
 
 void PictureMgr::showPicture(int16 x, int16 y, int16 width, int16 height) {
-	debugC(8, kDebugLevelMain, "Show picture");
+	debugC(kDebugLevelPictures, "Show picture");
 
 	_gfx->render_Block(x, y, width, height);
 }
@@ -977,7 +977,7 @@ void PictureMgr::showPictureWithTransition() {
 	_width = SCRIPT_WIDTH;
 	_height = SCRIPT_HEIGHT;
 
-	debugC(8, kDebugLevelMain, "Show picture");
+	debugC(kDebugLevelPictures, "Show picture");
 
 	if (!_vm->_game.automaticRestoreGame) {
 		// only do transitions when we are not restoring a saved game


Commit: 99c022767afbed3e58ccff62f2367c4707761c16
    https://github.com/scummvm/scummvm/commit/99c022767afbed3e58ccff62f2367c4707761c16
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2024-12-19T00:38:46+02:00

Commit Message:
AGI: Implement PREAGI picture coordinate clipping

- Fixes Winnie wall color in first room
- Fixes Winnie water color behind bridge
- Fixes Winnie rabbit hole color
- Fixes Eeyore shack color

Fixes bug #14549

Changed paths:
    engines/agi/picture.cpp
    engines/agi/picture.h


diff --git a/engines/agi/picture.cpp b/engines/agi/picture.cpp
index a4c33abbeb2..2f47af5b72e 100644
--- a/engines/agi/picture.cpp
+++ b/engines/agi/picture.cpp
@@ -100,6 +100,38 @@ byte PictureMgr::getNextNibble() {
 	}
 }
 
+bool PictureMgr::getNextXCoordinate(byte &x) {
+	if (!(getNextParamByte(x))) {
+		return false;
+	}
+
+	if (_pictureVersion == AGIPIC_PREAGI) {
+		if (x >= _width) {
+			debugC(kDebugLevelPictures, "preagi: clipping x from %d to %d", x, _width - 1);
+			x = _width - 1; // 139
+		}
+	}
+	return true;
+}
+
+bool PictureMgr::getNextYCoordinate(byte &y) {
+	if (!(getNextParamByte(y))) {
+		return false;
+	}
+
+	if (_pictureVersion == AGIPIC_PREAGI) {
+		if (y > _height) {
+			debugC(kDebugLevelPictures, "preagi: clipping y from %d to %d", y, _height);
+			y = _height; // 159
+		}
+	}
+	return true;
+}
+
+bool PictureMgr::getNextCoordinates(byte &x, byte &y) {
+	return getNextXCoordinate(x) && getNextYCoordinate(y);
+}
+
 /**************************************************************************
 ** xCorner
 **
@@ -108,13 +140,13 @@ byte PictureMgr::getNextNibble() {
 void PictureMgr::xCorner(bool skipOtherCoords) {
 	byte x1, x2, y1, y2, dummy;
 
-	if (!(getNextParamByte(x1) && getNextParamByte(y1)))
+	if (!getNextCoordinates(x1, y1))
 		return;
 
 	putVirtPixel(x1, y1);
 
 	for (;;) {
-		if (!getNextParamByte(x2))
+		if (!getNextXCoordinate(x2))
 			break;
 
 		if (skipOtherCoords)
@@ -128,7 +160,7 @@ void PictureMgr::xCorner(bool skipOtherCoords) {
 			if (!getNextParamByte(dummy))
 				break;
 
-		if (!getNextParamByte(y2))
+		if (!getNextYCoordinate(y2))
 			break;
 
 		draw_Line(x1, y1, x1, y2);
@@ -144,7 +176,7 @@ void PictureMgr::xCorner(bool skipOtherCoords) {
 void PictureMgr::yCorner(bool skipOtherCoords) {
 	byte x1, x2, y1, y2, dummy;
 
-	if (!(getNextParamByte(x1) && getNextParamByte(y1)))
+	if (!getNextCoordinates(x1, y1))
 		return;
 
 	putVirtPixel(x1, y1);
@@ -154,12 +186,12 @@ void PictureMgr::yCorner(bool skipOtherCoords) {
 			if (!getNextParamByte(dummy))
 				break;
 
-		if (!getNextParamByte(y2))
+		if (!getNextYCoordinate(y2))
 			break;
 
 		draw_Line(x1, y1, x1, y2);
 		y1 = y2;
-		if (!getNextParamByte(x2))
+		if (!getNextXCoordinate(x2))
 			break;
 
 		if (skipOtherCoords)
@@ -288,7 +320,7 @@ void PictureMgr::plotBrush() {
 		}
 
 		byte x1, y1;
-		if (!(getNextParamByte(x1) && getNextParamByte(y1)))
+		if (!getNextCoordinates(x1, y1))
 			break;
 
 		plotPattern(x1, y1);
@@ -303,7 +335,7 @@ void PictureMgr::plotBrush_PreAGI() {
 
 	for (;;) {
 		byte x, y;
-		if (!(getNextParamByte(x) && getNextParamByte(y)))
+		if (!getNextCoordinates(x, y))
 			break;
 
 		plotPattern_PreAGI(x, y);
@@ -792,7 +824,7 @@ void PictureMgr::draw_Line(int16 x1, int16 y1, int16 x2, int16 y2) {
 void PictureMgr::draw_LineShort() {
 	byte x1, y1, disp;
 
-	if (!(getNextParamByte(x1) && getNextParamByte(y1)))
+	if (!getNextCoordinates(x1, y1))
 		return;
 
 	putVirtPixel(x1, y1);
@@ -823,13 +855,13 @@ void PictureMgr::draw_LineShort() {
 void PictureMgr::draw_LineAbsolute() {
 	byte x1, y1, x2, y2;
 
-	if (!(getNextParamByte(x1) && getNextParamByte(y1)))
+	if (!getNextCoordinates(x1, y1))
 		return;
 
 	putVirtPixel(x1, y1);
 
 	for (;;) {
-		if (!(getNextParamByte(x2) && getNextParamByte(y2)))
+		if (!getNextCoordinates(x2, y2))
 			break;
 
 		draw_Line(x1, y1, x2, y2);
@@ -840,10 +872,24 @@ void PictureMgr::draw_LineAbsolute() {
 
 // flood fill
 void PictureMgr::draw_Fill() {
-	byte x1, y1;
+	byte x, y;
+
+	while (getNextCoordinates(x, y)) {
+		// PreAGI: getNextCoordinates clips to (139, 159), and then
+		// flood fill checks if y >= 159 and decrements to 158.
+		// The flood fill check is not in in Apple II/C64/CoCo
+		// versions of Winnie, as can be seen by the table edge
+		// being a different color than Winnie's shirt in the first
+		// room, but the same color in DOS/Amiga (picture 28).
+		if (_pictureVersion == AGIPIC_PREAGI) {
+			if (y >= _height) { // 159
+				debugC(kDebugLevelPictures, "preagi: fill clipping y from %d to %d", y, _height - 1);
+				y = _height - 1; // 158
+			}
+		}
 
-	while (getNextParamByte(x1) && getNextParamByte(y1))
-		draw_Fill(x1, y1);
+		draw_Fill(x, y);
+	}
 }
 
 void PictureMgr::draw_Fill(int16 x, int16 y) {
diff --git a/engines/agi/picture.h b/engines/agi/picture.h
index 5cb92772cef..035f719d9b5 100644
--- a/engines/agi/picture.h
+++ b/engines/agi/picture.h
@@ -81,6 +81,10 @@ private:
 	bool getNextParamByte(byte &b);
 	byte getNextNibble();
 
+	bool getNextXCoordinate(byte &x);
+	bool getNextYCoordinate(byte &y);
+	bool getNextCoordinates(byte &x, byte &y);
+
 public:
 	void decodePicture(int16 resourceNr, bool clearScreen, bool agi256 = false, int16 width = _DEFAULT_WIDTH, int16 height = _DEFAULT_HEIGHT);
 	void decodePictureFromBuffer(byte *data, uint32 length, bool clearScreen, int16 width = _DEFAULT_WIDTH, int16 height = _DEFAULT_HEIGHT);


Commit: 5bfae4a27629f4538188c06b6d558c08cb6886cf
    https://github.com/scummvm/scummvm/commit/5bfae4a27629f4538188c06b6d558c08cb6886cf
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2024-12-19T00:38:46+02:00

Commit Message:
AGI: Fix PREAGI missing flood fills

Fixes Roo in Winnie the Pooh

Changed paths:
    engines/agi/picture.cpp


diff --git a/engines/agi/picture.cpp b/engines/agi/picture.cpp
index 2f47af5b72e..5aeedc0061a 100644
--- a/engines/agi/picture.cpp
+++ b/engines/agi/picture.cpp
@@ -578,9 +578,15 @@ void PictureMgr::drawPicturePreAGI() {
 		case 0xf7:
 			draw_LineShort();
 			break;
-		case 0xf8:
+		case 0xf8: {
+			// The screen-on flag does not prevent PreAGI flood fills.
+			// Winnie picture 7 (Roo) contains F1 before several fills.
+			byte prevScrOn = _scrOn;
+			_scrOn = true;
 			draw_Fill();
+			_scrOn = prevScrOn;
 			break;
+		}
 		case 0xf9:
 			plotBrush_PreAGI();
 			break;


Commit: e08244823981a5bf385296edcff0dd919bad5192
    https://github.com/scummvm/scummvm/commit/e08244823981a5bf385296edcff0dd919bad5192
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2024-12-19T00:38:46+02:00

Commit Message:
AGI: Fix PREAGI memory corruption when drawing pictures

Fixes memory corruption in Winnie the Pooh when a
tall object is drawn at the bottom of the screen.

The existing boundary checks in these functions occur
before the PreAGI offsets are applied.

Changed paths:
    engines/agi/picture.cpp


diff --git a/engines/agi/picture.cpp b/engines/agi/picture.cpp
index 5aeedc0061a..a5d3a85f74d 100644
--- a/engines/agi/picture.cpp
+++ b/engines/agi/picture.cpp
@@ -62,6 +62,12 @@ void PictureMgr::putVirtPixel(int x, int y) {
 	x += _xOffset;
 	y += _yOffset;
 
+	// validate coordinate after applying preagi offset.
+	// winnie objects go past the bottom of the screen.
+	if (x >= SCRIPT_WIDTH || y >= SCRIPT_HEIGHT) {
+		return;
+	}
+
 	byte drawMask= 0;
 	if (_priOn)
 		drawMask |= GFX_SCREEN_MASK_PRIORITY;
@@ -950,6 +956,12 @@ bool PictureMgr::draw_FillCheck(int16 x, int16 y) {
 	x += _xOffset;
 	y += _yOffset;
 
+	// validate coordinate after applying preagi offset.
+	// winnie objects go past the bottom of the screen.
+	if (x >= SCRIPT_WIDTH || y >= SCRIPT_HEIGHT) {
+		return false;
+	}
+
 	byte screenColor = _gfx->getColor(x, y);
 	byte screenPriority = _gfx->getPriority(x, y);
 




More information about the Scummvm-git-logs mailing list