[Scummvm-git-logs] scummvm master -> 196cadbe008789cb96c836dae2abf92a77f32aa1

AndywinXp noreply at scummvm.org
Tue Jun 11 12:49:00 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:
196cadbe00 SCUMM: HE: Implement original actor/object overlapping/erasing routines


Commit: 196cadbe008789cb96c836dae2abf92a77f32aa1
    https://github.com/scummvm/scummvm/commit/196cadbe008789cb96c836dae2abf92a77f32aa1
Author: AndywinXp (andywinxp at gmail.com)
Date: 2024-06-11T14:48:50+02:00

Commit Message:
SCUMM: HE: Implement original actor/object overlapping/erasing routines

This is the thing I held off doing during the HE gfx rewrite, only to find out
it was actually needed. As usual, a great number of changes for... only
one small bug fixed. This closes ticket #9619:
"SCUMM/HE: PUTTZOO- Kenya Animation Bug Persists"

I have tested a bunch of representative HE70+,80,90,95,98,99,100
entries and I didn't notice regressions.

HE versions under 70 have not been touched by this, as I'd like to
know if there are issues with actor/object overlaps BEFORE actually
starting disassembling 16-bit DOS executables...

Changed paths:
    engines/scumm/actor.cpp
    engines/scumm/actor.h
    engines/scumm/actor_he.h
    engines/scumm/akos.cpp
    engines/scumm/gfx.cpp
    engines/scumm/he/intern_he.h
    engines/scumm/he/script_v60he.cpp
    engines/scumm/he/script_v71he.cpp
    engines/scumm/he/script_v72he.cpp
    engines/scumm/metaengine.cpp
    engines/scumm/object.cpp
    engines/scumm/scumm.h
    engines/scumm/usage_bits.cpp


diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp
index eb88550f6e6..2b27a3c97a7 100644
--- a/engines/scumm/actor.cpp
+++ b/engines/scumm/actor.cpp
@@ -112,6 +112,16 @@ Actor::Actor(ScummEngine *scumm, int id) :
 		assert(_vm != nullptr);
 }
 
+ActorHE::ActorHE(ScummEngine *scumm, int id) : Actor(scumm,id) {
+	for (int i = 0; i < ARRAYSIZE(_screenUpdateTableMin); i++) {
+		_screenUpdateTableMin[i] = 0;
+	}
+
+	for (int i = 0; i < ARRAYSIZE(_screenUpdateTableMin); i++) {
+		_screenUpdateTableMax[i] = 0;
+	}
+}
+
 void ActorHE::initActor(int mode) {
 	Actor::initActor(mode);
 
@@ -121,6 +131,10 @@ void ActorHE::initActor(int mode) {
 		memset(_heTalkQueue, 0, sizeof(_heTalkQueue));
 	}
 
+	if (mode == 1) {
+		clearActorUpdateInfo();
+	}
+
 	if (mode == 1 || mode == -1) {
 		_heCondMask = 1;
 		_heNoTalkAnimation = 0;
@@ -607,6 +621,10 @@ int Actor_v3::calcMovementFactor(const Common::Point& next) {
 int Actor::actorWalkStep() {
 	_needRedraw = true;
 
+	if (_vm->_game.heversion >= 70) {
+		_needBgReset = true;
+	}
+
 	if (_vm->_game.version < 7) {
 		int nextFacing = updateActorDirection(true);
 		if ((_walkFrame != _frame && !(_moving & MF_IN_LEG)) || _facing != nextFacing)
@@ -1672,6 +1690,9 @@ void Actor::putActor(int dstX, int dstY, int newRoom) {
 	_room = newRoom;
 	_needRedraw = true;
 
+	if (_vm->_game.heversion >= 70)
+		_needBgReset = true;
+
 	if (_vm->VAR(_vm->VAR_EGO) == _number) {
 		_vm->_egoPositioned = true;
 	}
@@ -2221,6 +2242,9 @@ Actor *ScummEngine::derefActorSafe(int id, const char *errmsg) const {
 void ScummEngine::processActors() {
 	int numactors = 0;
 
+	if (_game.heversion >= 71 && ((ScummEngine_v71he *)this)->_disableActorDrawingFlag)
+		return;
+
 	// Make a list of all actors in this room
 	for (int i = 1; i < _numActors; i++) {
 		if (_game.version == 8 && _actors[i]->_layer < 0)
@@ -2304,13 +2328,13 @@ void ScummEngine::processActors() {
 	}
 
 	// Finally draw the now sorted actors
-	Actor** end = _sortedActors + numactors;
-	for (Actor** ac = _sortedActors; ac != end; ++ac) {
-		Actor* a = *ac;
+	Actor **end = _sortedActors + numactors;
+	for (Actor **ac = _sortedActors; ac != end; ++ac) {
+		Actor *a = *ac;
 
 		if (_game.version == 0) {
 			// 0x057B
-			Actor_v0 *a0 = (Actor_v0*) a;
+			Actor_v0 *a0 = (Actor_v0 *)a;
 			if (a0->_speaking & 1) {
 				a0->_speaking ^= 0xFE;
 				++_V0Delay._actorRedrawCount;
@@ -2440,6 +2464,10 @@ void Actor::drawActorCostume(bool hitTestMode) {
 	// If the actor is partially hidden, redraw it next frame.
 	if (bcr->drawCostume(_vm->_virtscr[kMainVirtScreen], _vm->_gdi->_numStrips, this, _drawToBackBuf) & 1) {
 		_needRedraw = (_vm->_game.version <= 6);
+
+		// TODO: Eventually check if true for HE6*
+		if (_vm->_game.heversion >= 70)
+			_needBgReset = true;
 	}
 
 	if (!hitTestMode) {
@@ -2504,6 +2532,8 @@ void ActorHE::prepareDrawActorCostume(BaseCostumeRenderer *bcr) {
 	// HE palette number must be set, before setting the costume palette
 	bcr->_paletteNum = _hePaletteNum;
 
+	clearActorUpdateInfo();
+
 	Actor::prepareDrawActorCostume(bcr);
 
 	bcr->_actorX += _heOffsX;
@@ -2629,6 +2659,9 @@ void Actor::startAnimActor(int f) {
 		_vm->_costumeLoader->costumeDecodeData(this, f, (uint) - 1);
 		_frame = f;
 	}
+
+	if (_vm->_game.heversion >= 70)
+		_needBgReset = true;
 }
 
 void Actor_v0::startAnimActor(int f) {
@@ -2758,6 +2791,9 @@ void Actor::animateCostume() {
 		_vm->_costumeLoader->loadCostume(_costume);
 		if (_vm->_costumeLoader->increaseAnims(this)) {
 			_needRedraw = true;
+			if (_vm->_game.heversion >= 70) {
+				_needBgReset = true;
+			}
 		}
 	}
 }
@@ -2846,37 +2882,100 @@ void Actor::animateLimb(int limb, int f) {
 #endif
 
 void ScummEngine::redrawAllActors() {
-	int i;
-
-	for (i = 1; i < _numActors; ++i) {
+	for (int i = 1; i < _numActors; ++i) {
 		_actors[i]->_needRedraw = true;
 		_actors[i]->_needBgReset = true;
 	}
 }
 
 void ScummEngine::setActorRedrawFlags() {
-	int i, j;
-
 	// Redraw all actors if a full redraw was requested.
 	// Also redraw all actors in COMI (see bug #1825 for details).
 	if (_fullRedraw || _game.version == 8 || (VAR_ALWAYS_REDRAW_ACTORS != 0xFF && VAR(VAR_ALWAYS_REDRAW_ACTORS) != 0)) {
-		for (j = 1; j < _numActors; j++) {
+		for (int j = 1; j < _numActors; j++) {
 			_actors[j]->_needRedraw = true;
 		}
 	} else {
-		if (_game.heversion >= 72) {
-			for (j = 1; j < _numActors; j++) {
-				if (_actors[j]->_costume && _actors[j]->_heShadow)
-					_actors[j]->_needRedraw = true;
+		for (int i = 0; i < _gdi->_numStrips; i++) {
+			int strip = _screenStartStrip + i;
+			if (testGfxAnyUsageBits(strip)) {
+				for (int j = 1; j < _numActors; j++) {
+					if (testGfxUsageBit(strip, j) && testGfxOtherUsageBits(strip, j)) {
+						_actors[j]->_needRedraw = true;
+					}
+				}
+			}
+		}
+	}
+}
+
+void ScummEngine_v70he::setActorRedrawFlags() {
+	if (_game.heversion >= 80 && (VAR_ALWAYS_REDRAW_ACTORS != 0xFF && VAR(VAR_ALWAYS_REDRAW_ACTORS) != 0)) {
+		for (int i = 1; i < _numActors; i++) {
+			if (_actors[i]->_costume) {
+				_actors[i]->_needRedraw = true;
+				_actors[i]->_needBgReset = true;
 			}
 		}
 
-		for (i = 0; i < _gdi->_numStrips; i++) {
+		return;
+	}
+
+	if (_game.heversion >= 95) {
+		for (int j = 1; j < _numActors; j++) {
+			if (_actors[j]->_costume && _actors[j]->_heShadow)
+				_actors[j]->_needRedraw = true;
+		}
+	}
+
+	bool repeatCheck = true;
+
+	while (repeatCheck) {
+		repeatCheck = false;
+
+		for (int i = 0; i < _gdi->_numStrips; i++) {
+			// Get actors on screen bits for this strip...
 			int strip = _screenStartStrip + i;
+
 			if (testGfxAnyUsageBits(strip)) {
-				for (j = 1; j < _numActors; j++) {
-					if (testGfxUsageBit(strip, j) && testGfxOtherUsageBits(strip, j)) {
-						_actors[j]->_needRedraw = true;
+				for (int act = 1; act < _numActors; act++) {
+					if (!(_actors[act]->_needRedraw && _actors[act]->_needBgReset)) {
+						if (testGfxUsageBit(strip, act) && testGfxOtherUsageBits(strip, act)) {
+							if (testGfxObjectUsageBits(strip)) {
+								if (!_actors[act]->_needRedraw)
+									repeatCheck = true;
+
+								if (!_actors[act]->_needBgReset)
+									repeatCheck = true;
+
+								_actors[act]->_needRedraw = true;
+								_actors[act]->_needBgReset = true;
+							} else {
+								// Check for vertical overlap...
+								for (int iact = 1; iact < _numActors; iact++) {
+									if ((iact != act) && testGfxUsageBit(strip, iact)) {
+										if (actorsOverlapInStrip(act, iact, i)) {
+											// Check for animation as well as animating...
+											if (_actors[act]->_needBgReset || _actors[iact]->_needBgReset ||
+												_actors[act]->_needRedraw || _actors[iact]->_needRedraw) {
+
+												if (!_actors[act]->_needRedraw)
+													repeatCheck = true;
+
+												if (!_actors[act]->_needBgReset)
+													repeatCheck = true;
+
+												_actors[act]->_needRedraw = true;
+												_actors[act]->_needBgReset = true;
+
+												repeatCheck = true;
+												break;
+											}
+										}
+									}
+								}
+							}
+						}
 					}
 				}
 			}
@@ -2885,16 +2984,12 @@ void ScummEngine::setActorRedrawFlags() {
 }
 
 void ScummEngine::resetActorBgs() {
-	int i, j;
-
-	for (i = 0; i < _gdi->_numStrips; i++) {
+	for (int i = 0; i < _gdi->_numStrips; i++) {
 		int strip = _screenStartStrip + i;
 		clearGfxUsageBit(strip, USAGE_BIT_DIRTY);
 		clearGfxUsageBit(strip, USAGE_BIT_RESTORED);
-		for (j = 1; j < _numActors; j++) {
-			if (_game.heversion != 0 && (((ActorHE *)_actors[j])->_generalFlags & ACTOR_GENERAL_FLAG_IGNORE_ERASE) != 0)
-				continue;
 
+		for (int j = 1; j < _numActors; j++) {
 			if (testGfxUsageBit(strip, j) &&
 				((_actors[j]->_top != 0x7fffffff && _actors[j]->_needRedraw) || _actors[j]->_needBgReset)) {
 				clearGfxUsageBit(strip, j);
@@ -2904,16 +2999,150 @@ void ScummEngine::resetActorBgs() {
 		}
 	}
 
-	for (i = 1; i < _numActors; i++) {
+	for (int i = 1; i < _numActors; i++) {
 		_actors[i]->_needBgReset = false;
 	}
 }
 
+void ScummEngine_v70he::resetActorBgs() {
+	for (int i = 0; i < _gdi->_numStrips; i++) {
+		int strip = _screenStartStrip + i;
+		clearGfxUsageBit(strip, USAGE_BIT_DIRTY);
+		clearGfxUsageBit(strip, USAGE_BIT_RESTORED);
+
+		for (int j = 1; j < _numActors; j++) {
+			if (!testGfxAnyUsageBits(strip))
+				break;
+
+			// The original also does this test, which
+			// apparently breaks a bunch of other stuff though,
+			// and doesn't help us in any way...
+			// 
+			// if (!testGfxOtherUsageBits(strip, j))
+			//	continue;
+
+			int actorMin, actorMax;
+
+			if (_screenWidth == 640) { // Hi-res
+				if (((ActorHE *)_actors[j])->_screenUpdateTableMin[i] < ((ActorHE *)_actors[j])->_screenUpdateTableMax[i]) {
+					actorMin = ((ActorHE *)_actors[j])->_screenUpdateTableMin[i];
+					actorMax = ((ActorHE *)_actors[j])->_screenUpdateTableMax[i] + 1;
+				} else {
+					actorMin = 0x7fffffff;
+					actorMax = 0;
+				}
+			} else {
+				actorMin = _actors[j]->_top;
+				actorMax = _actors[j]->_bottom;
+			}
+
+			// Kill the actors bit in this strip if told to erase
+			if (_actors[j]->_needBgReset) {
+				clearGfxUsageBit(strip, j);
+			}
+
+			if (actorMin != 0x7fffffff && _actors[j]->_needBgReset) {
+				bool disableDrawing = _game.heversion >= 71 && (((ScummEngine_v71he *)this)->_disableActorDrawingFlag);
+				if ((actorMax - actorMin) > 0 && !disableDrawing)
+					_gdi->resetBackground(actorMin, actorMax, i);
+			}		
+		}
+	}
+
+	for (int i = 1; i < _numActors; i++) {
+		_actors[i]->_needBgReset = false;
+	}
+}
+
+bool ScummEngine_v95he::prepareForActorErase() {
+	for (int i = 1; i < _numActors; i++) {
+		if (((ActorHE *)_actors[i])->_generalFlags & ACTOR_GENERAL_FLAG_IGNORE_ERASE) {
+			_actors[i]->_needBgReset = false;
+		}
+	}
+
+	for (int i = 1; i < _numActors; i++) {
+		if (_actors[i]->_needBgReset) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
+#define ACTOR_CONTIGUOUS_WITH_STRIP (!((jMax < actorMin) || (jMin > actorMax)))
+
+void ScummEngine_v95he::resetActorBgs() {
+	int jMin, jMax, lastStrip, actorMin, actorMax;
+
+	if (!prepareForActorErase()) {
+		return;
+	}
+
+	for (int i = 0; i < _gdi->_numStrips; i++) {
+		int strip = _screenStartStrip + i;
+		clearGfxUsageBit(strip, USAGE_BIT_DIRTY);
+		clearGfxUsageBit(strip, USAGE_BIT_RESTORED);
+
+		for (int act = 1; act < _numActors; act++) {
+			if (!testGfxAnyUsageBits(strip))
+				break;
+
+			// The original also does this test, which
+			// apparently breaks a bunch of other stuff though,
+			// and doesn't help us in any way...
+			//
+			//if (!(testGfxOtherUsageBits(strip, j) && _actors[j]->_needBgReset))
+			//	continue;
+
+			lastStrip = i;
+			actorMin = ((ActorHE *)_actors[act])->_screenUpdateTableMin[i];
+			actorMax = ((ActorHE *)_actors[act])->_screenUpdateTableMax[i] + 1;
+
+			for (int j = i; j < _gdi->_numStrips; j++) {
+				jMin = ((ActorHE *)_actors[act])->_screenUpdateTableMin[i];
+				jMax = ((ActorHE *)_actors[act])->_screenUpdateTableMax[i] + 1;
+
+				if (testGfxOtherUsageBits(strip, act) && ((jMin) < (jMax)) && ACTOR_CONTIGUOUS_WITH_STRIP) {
+					// Extend the restore area to include this strip
+					lastStrip = j;
+					actorMin = MIN<int>(actorMin, jMin);
+					actorMax = MAX<int>(actorMax, jMax);
+				} else {
+					break;
+				}
+			}
+
+			for (int j = i; j <= lastStrip; j++) {
+				clearGfxUsageBit(strip, act);
+			}
+
+			if (actorMin != 0x7fffffff && _actors[act]->_needBgReset) {
+				bool disableDrawing = (((ScummEngine_v71he *)this)->_disableActorDrawingFlag);
+				if ((actorMax - actorMin) > 0 && !disableDrawing)
+					_gdi->resetBackground(actorMin, actorMax, i);
+			}
+		}
+	}
+
+	for (int i = 1; i < _numActors; i++) {
+		_actors[i]->_needBgReset = false;
+	}
+}
+
+#undef ACTOR_CONTIGUOUS_WITH_STRIP
+
 // HE specific
 void ActorHE::drawActorToBackBuf(int x, int y) {
 	int curTop = _top;
 	int curBottom = _bottom;
 
+	int screenUpdateTableMin[80];
+	int screenUpdateTableMax[80];
+
+	memcpy(screenUpdateTableMin, _screenUpdateTableMin, sizeof(screenUpdateTableMin));
+	memcpy(screenUpdateTableMax, _screenUpdateTableMax, sizeof(screenUpdateTableMax));
+
 	_pos.x = x;
 	_pos.y = y;
 
@@ -2930,6 +3159,66 @@ void ActorHE::drawActorToBackBuf(int x, int y) {
 		_top = curTop;
 	if (_bottom < curBottom)
 		_bottom = curBottom;
+
+	for (int i = 0; i < 80; i++) {
+		if (screenUpdateTableMin[i] < _screenUpdateTableMin[i]) {
+			_screenUpdateTableMin[i] = screenUpdateTableMin[i];
+		}
+
+		if (screenUpdateTableMax[i] > _screenUpdateTableMax[i]) {
+			_screenUpdateTableMax[i] = screenUpdateTableMax[i];
+		}
+	}
+}
+
+void ActorHE::clearActorUpdateInfo() {
+	for (int i = 0; i < _vm->_gdi->_numStrips; i++) {
+		_screenUpdateTableMin[i] = _vm->_screenHeight;
+		_screenUpdateTableMax[i] = 0;
+	}
+}
+
+void ActorHE::setActorUpdateArea(int x1, int y1, int x2, int y2) {
+	int startStrip, endStrip;
+
+	if (y1 < 0) {
+		y1 = 0;
+	}
+
+	if (y2 >= _vm->_screenHeight) {
+		y2 = _vm->_screenHeight - 1;
+	}
+
+	startStrip = x1 / 8;
+	if (startStrip < 0) {
+		startStrip = 0;
+	}
+
+	if (startStrip >= _vm->_gdi->_numStrips) {
+		return;
+	}
+
+	endStrip = x2 / 8;
+	if (endStrip >= _vm->_gdi->_numStrips) {
+		endStrip = _vm->_gdi->_numStrips - 1;
+	}
+
+	for (int strip = startStrip; strip <= endStrip; strip++) {
+		if (y1 < _screenUpdateTableMin[strip]) {
+			_screenUpdateTableMin[strip] = y1;
+		}
+
+		if (y2 > _screenUpdateTableMax[strip]) {
+			_screenUpdateTableMax[strip] = y2;
+		}
+	}
+}
+
+bool ScummEngine_v60he::actorsOverlapInStrip(int actorA, int actorB, int stripNumber) {
+	ActorHE *actA = (ActorHE *)_actors[actorA];
+	ActorHE *actB = (ActorHE *)_actors[actorB];
+	return !((actB->_screenUpdateTableMax[stripNumber] < actA->_screenUpdateTableMin[stripNumber]) ||
+			 (actB->_screenUpdateTableMin[stripNumber] < actA->_screenUpdateTableMax[stripNumber]));
 }
 
 
@@ -3214,6 +3503,10 @@ void ActorHE::setActorCostume(int c) {
 	if (_vm->_game.heversion >= 61 && (c == -1  || c == -2)) {
 		_heSkipLimbs = (c == -1);
 		_needRedraw = true;
+		if (_vm->_game.heversion >= 70) {
+			_needBgReset = true;
+		}
+
 		return;
 	}
 
@@ -3687,8 +3980,7 @@ void ScummEngine_v71he::heFlushAuxQueues() {
 }
 
 void ScummEngine_v90he::heFlushAuxQueues() {
-	// TODO: VERIFY HE95
-	if (_game.heversion < 98) {
+	if (_game.heversion < 95) {
 		ScummEngine_v71he::heFlushAuxQueues();
 		return;
 	}
@@ -3781,7 +4073,6 @@ void ScummEngine_v90he::heFlushAuxQueues() {
 					(WizRawPixel *)foregroundBufferPtr, (WizRawPixel *)backgroundBufferPtr, auxFrameDataPtr,
 					pvs->w, pvs->h, x, y, w, h, nullptr, conversionTablePtr);
 			} else if (AKOS_AUXD_TYPE_WRLE_FRAME == type) {
-				// Where is the color table?
 				if ((x != 0) || (w != 640)) {
 					error("heFlushAuxQueue(): Actor %d invalid (%d,%d)[%d,%d]", whichActor, x, y, w, h);
 				}
@@ -3822,6 +4113,12 @@ void ScummEngine_v90he::heFlushAuxQueues() {
 				yOffset + (int16)READ_LE_UINT16(auxUpdateRectPtr + 6),
 				actorBits);
 
+			a->setActorUpdateArea(
+				xOffset + (int16)READ_LE_UINT16(auxUpdateRectPtr + 0),
+				yOffset + (int16)READ_LE_UINT16(auxUpdateRectPtr + 2),
+				xOffset + (int16)READ_LE_UINT16(auxUpdateRectPtr + 4),
+				yOffset + (int16)READ_LE_UINT16(auxUpdateRectPtr + 6));
+
 			auxUpdateRectPtr += 8;
 		}
 
diff --git a/engines/scumm/actor.h b/engines/scumm/actor.h
index 9e663c41ce4..b77dc154ebc 100644
--- a/engines/scumm/actor.h
+++ b/engines/scumm/actor.h
@@ -309,6 +309,11 @@ public:
 			_elevation = newElevation;
 			_needRedraw = true;
 		}
+
+		if (_vm->_game.heversion >= 70) {
+			_needRedraw = true;
+			_needBgReset = true;
+		}
 	}
 
 	void setPalette(int idx, int val) {
@@ -322,6 +327,10 @@ public:
 		if (sy != -1)
 			_scaley = sy;
 		_needRedraw = true;
+
+		if (_vm->_game.heversion >= 70) {
+			_needBgReset = true;
+		}
 	}
 
 	void classChanged(int cls, bool value);
diff --git a/engines/scumm/actor_he.h b/engines/scumm/actor_he.h
index 88169eaa548..262ad46aa3c 100644
--- a/engines/scumm/actor_he.h
+++ b/engines/scumm/actor_he.h
@@ -56,7 +56,7 @@ struct HEAuxFileRelInfo {
 
 class ActorHE : public Actor {
 public:
-	ActorHE(ScummEngine *scumm, int id) : Actor(scumm, id) {}
+	ActorHE(ScummEngine *scumm, int id);
 
 	void initActor(int mode) override;
 
@@ -75,6 +75,9 @@ public:
 	void setTalkCondition(int slot);
 	bool isTalkConditionSet(int slot) const;
 
+	void clearActorUpdateInfo();
+	void setActorUpdateArea(int x1, int y1, int x2, int y2);
+
 public:
 	/** This rect is used to clip actor drawing. */
 	Common::Rect _clipOverride;
@@ -86,6 +89,10 @@ public:
 	int _auxActor;
 	int32 _auxEraseX1, _auxEraseY1, _auxEraseX2, _auxEraseY2;
 
+	// 80 is the maximum number of strips that any hi-res HE game is going to have
+	int _screenUpdateTableMin[80];
+	int _screenUpdateTableMax[80];
+
 	struct {
 		int16 posX;
 		int16 posY;
diff --git a/engines/scumm/akos.cpp b/engines/scumm/akos.cpp
index 4da48a9458a..95bc790c6e0 100644
--- a/engines/scumm/akos.cpp
+++ b/engines/scumm/akos.cpp
@@ -855,9 +855,16 @@ byte AkosRenderer::paintCelByleRLE(int xMoveCur, int yMoveCur) {
 	if (_actorHitMode) {
 		if (_actorHitX < rect.left || _actorHitX >= rect.right || _actorHitY < rect.top || _actorHitY >= rect.bottom)
 			return 0;
-	} else
+	} else {
 		markRectAsDirty(rect);
 
+		if (_vm->_game.heversion >= 71) {
+			ActorHE *a = (ActorHE *)_vm->derefActor(_actorID, "paintCelByleRLE");
+			a->setActorUpdateArea(rect.left, rect.top, rect.right, rect.bottom + 1);
+		}
+	}
+
+
 	if (rect.top >= compData.boundsRect.bottom || rect.bottom <= compData.boundsRect.top)
 		return 0;
 
@@ -1079,6 +1086,11 @@ byte AkosRenderer::paintCelMajMin(int xMoveCur, int yMoveCur) {
 
 	markRectAsDirty(clip);
 
+	if (_vm->_game.heversion >= 71) {
+		ActorHE *a = (ActorHE *)_vm->derefActor(_actorID, "paintCelMajMin");
+		a->setActorUpdateArea(clip.left, clip.top, clip.right, clip.bottom);
+	}
+
 	skipX = 0;
 	skipY = 0;
 	curX = _width - 1;
@@ -1226,7 +1238,9 @@ byte AkosRenderer::hePaintCel(int actor, int drawToBack, int celX, int celY, int
 		_drawTop = a->_top;
 		_drawBottom = a->_bottom;
 
-		//SetActorUpdateArea(actor, destRect.x1, destRect.y1, destRect.x2, destRect.y2);
+		if (_vm->_game.heversion >= 71) {
+			((ActorHE *)a)->setActorUpdateArea(destRect.left, destRect.top, destRect.right, destRect.bottom);
+		}
 
 		// Get final plot point and flip source coords if necessary...
 		if (xFlipFlag) {
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index 2136a1a2f24..75b102b8c2b 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -2606,12 +2606,22 @@ void Gdi::drawBMAPObject(const byte *ptr, VirtScreen *vs, int obj, int x, int y,
 	int scrX = _vm->_screenStartStrip * 8 * _vm->_bytesPerPixel;
 	WizPxShrdBuffer dst(_vm->_virtscr[kMainVirtScreen].backBuf + scrX, false);
 
+	int scrWidth = _vm->_game.heversion > 98 ? _vm->_screenWidth : vs->w;
+	int scrHeight = _vm->_game.heversion > 98 ? _vm->_screenHeight : vs->h;
+
 	switch (code) {
 	case BMCOMP_RLE8BIT:
 	case BMCOMP_TRLE8BIT:
 	{
-		Common::Rect rScreen(0, 0, vs->w, vs->h);
-		((ScummEngine_v71he *)_vm)->_wiz->auxDecompTRLEImage(dst(), bmapPtr, vs->w, vs->h, x + scrX, y, w, h, &rScreen, nullptr);
+		Common::Rect rScreen(0, 0, scrWidth, scrHeight);
+		if (_vm->_game.heversion <= 98) {
+			rScreen.right -= 1;
+			rScreen.bottom -= 1;
+		}
+
+		int xCoord = x + (_vm->_game.heversion > 98 ? scrX : -scrX);
+
+		((ScummEngine_v71he *)_vm)->_wiz->auxDecompTRLEImage(dst(), bmapPtr, scrWidth, scrHeight, xCoord, y, w, h, &rScreen, nullptr);
 		break;
 	}
 	case BMCOMP_SOLID_COLOR_FILL:
@@ -2635,18 +2645,32 @@ void Gdi::drawBMAPObject(const byte *ptr, VirtScreen *vs, int obj, int x, int y,
 		error("Gdi::drawBMAPObject(): Unhandled code %d", code);
 	}
 
-	Common::Rect renderArea, clipArea;
+	Common::Rect renderArea, clipArea, backgroundCoords;
 
-	((ScummEngine_v71he *)_vm)->_wiz->makeSizedRectAt(&renderArea, x, y, w, h);
-	((ScummEngine_v71he *)_vm)->_wiz->makeSizedRect(&clipArea, vs->w, vs->h);
+	if (_vm->_game.heversion > 98) {
+		((ScummEngine_v71he *)_vm)->_wiz->makeSizedRectAt(&renderArea, x + scrX, y, w, h);			
 
-	((ScummEngine_v71he *)_vm)->_wiz->findRectOverlap(&renderArea, &clipArea);
+		((ScummEngine_v71he *)_vm)->_wiz->makeSizedRect(&clipArea, scrWidth, scrHeight);
+		((ScummEngine_v71he *)_vm)->_wiz->findRectOverlap(&renderArea, &clipArea);
 
-	// Unless the image was entirely clipped, copy newly decompressed
-	// pixels from the background buffer into the foreground buffer...
-	if (((ScummEngine_v71he *)_vm)->_wiz->isRectValid(renderArea)) {
-		((ScummEngine_v71he *)_vm)->backgroundToForegroundBlit(renderArea);
+		// Unless the image was entirely clipped, copy newly decompressed
+		// pixels from the background buffer into the foreground buffer...
+		if (((ScummEngine_v71he *)_vm)->_wiz->isRectValid(renderArea)) {
+			((ScummEngine_v71he *)_vm)->backgroundToForegroundBlit(renderArea);
+		}
+	} else {
+		((ScummEngine_v71he *)_vm)->_wiz->makeSizedRectAt(&renderArea, x, y, w, h);
+		((ScummEngine_v71he *)_vm)->_wiz->makeSizedRectAt(&backgroundCoords, scrX, 0, scrWidth, scrHeight);
+		((ScummEngine_v71he *)_vm)->_wiz->findRectOverlap(&renderArea, &backgroundCoords);
+
+		if (((ScummEngine_v71he *)_vm)->_wiz->isRectValid(renderArea)) {
+			// Convert the coords to buffer relative coords and then copy the
+			// background pixels to the foreground buffer as well...
+			((ScummEngine_v71he *)_vm)->_wiz->moveRect(&renderArea, -backgroundCoords.left, -backgroundCoords.top);
+			((ScummEngine_v71he *)_vm)->backgroundToForegroundBlit(renderArea);
+		}
 	}
+
 }
 
 void ScummEngine_v70he::backgroundToForegroundBlit(Common::Rect rect, int dirtybit) {
diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h
index b8e076ed075..e798e971bbe 100644
--- a/engines/scumm/he/intern_he.h
+++ b/engines/scumm/he/intern_he.h
@@ -90,6 +90,7 @@ public:
 
 	Common::Path generateFilename(const int room) const override;
 	void setActorClippingRect(int actor, int x1, int y1, int x2, int y2);
+	bool actorsOverlapInStrip(int actorA, int actorB, int stripNumber);
 
 	void resetScumm() override;
 
@@ -221,6 +222,7 @@ public:
 	Common::Path generateFilename(const int room) const override;
 
 	void backgroundToForegroundBlit(Common::Rect rect, int dirtybit = 0);
+	void setActorRedrawFlags() override;
 
 protected:
 	void allocateArrays() override;
@@ -249,6 +251,8 @@ protected:
 	void setCursorFromImg(uint img, uint room, uint imgindex) override;
 	void setDefaultCursor() override;
 
+	void resetActorBgs() override;
+
 	/* HE version 70 script opcodes */
 	void o70_soundOps();
 	void o70_pickupObject();
@@ -285,8 +289,6 @@ protected:
 		SO_SET_POLYGON_LOCAL = 248,
 	};
 
-	bool _disableActorDrawingFlag;
-
 public:
 	ScummEngine_v71he(OSystem *syst, const DetectorResult &dr);
 	~ScummEngine_v71he() override;
@@ -296,6 +298,7 @@ public:
 	byte *findWrappedBlock(uint32 tag, byte *ptr, int state, bool flagError);
 
 	Wiz *_wiz;
+	bool _disableActorDrawingFlag = false;
 
 	virtual int setupStringArray(int size);
 
@@ -577,6 +580,7 @@ class ScummEngine_v90he : public ScummEngine_v80he {
 	friend class MoviePlayer;
 	friend class Sprite;
 	friend class Wiz;
+	friend class ScummEngine_v99he;
 
 protected:
 	enum SubOpType {
@@ -801,9 +805,18 @@ public:
 #endif
 };
 
-class ScummEngine_v99he : public ScummEngine_v90he {
+class ScummEngine_v95he : public ScummEngine_v90he {
+public:
+	ScummEngine_v95he(OSystem *syst, const DetectorResult &dr) : ScummEngine_v90he(syst, dr) {}
+
+protected:
+	void resetActorBgs() override;
+	bool prepareForActorErase();
+};
+
+class ScummEngine_v99he : public ScummEngine_v95he {
 public:
-	ScummEngine_v99he(OSystem *syst, const DetectorResult &dr) : ScummEngine_v90he(syst, dr) {}
+	ScummEngine_v99he(OSystem *syst, const DetectorResult &dr) : ScummEngine_v95he(syst, dr) {}
 
 	void resetScumm() override;
 
diff --git a/engines/scumm/he/script_v60he.cpp b/engines/scumm/he/script_v60he.cpp
index 4be4d141c2b..1b4bcc8065e 100644
--- a/engines/scumm/he/script_v60he.cpp
+++ b/engines/scumm/he/script_v60he.cpp
@@ -616,6 +616,9 @@ void ScummEngine_v60he::o60_actorOps() {
 	case SO_SHADOW:
 		a->_shadowMode = pop();
 		a->_needRedraw = true;
+		if (_game.heversion >= 70) {
+			a->_needBgReset = true;
+		}
 		break;
 	case SO_TEXT_OFFSET:
 		a->_talkPosY = pop();
diff --git a/engines/scumm/he/script_v71he.cpp b/engines/scumm/he/script_v71he.cpp
index ef351cb306d..51ee55079a5 100644
--- a/engines/scumm/he/script_v71he.cpp
+++ b/engines/scumm/he/script_v71he.cpp
@@ -196,11 +196,14 @@ void ScummEngine_v71he::o71_kernelSetFunctions() {
 		_fullRedraw = true;
 		break;
 	case 24:
-		_disableActorDrawingFlag = 1;
-		redrawAllActors();
+		_disableActorDrawingFlag = true;
+		for (int i = 1; i < _numActors; ++i) {
+			_actors[i]->_needRedraw = false;
+			_actors[i]->_needBgReset = false;
+		}
 		break;
 	case 25:
-		_disableActorDrawingFlag = 0;
+		_disableActorDrawingFlag = false;
 		redrawAllActors();
 		break;
 	case 26:
diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp
index 1ef37b88ced..e7e9cb70d95 100644
--- a/engines/scumm/he/script_v72he.cpp
+++ b/engines/scumm/he/script_v72he.cpp
@@ -957,6 +957,8 @@ void ScummEngine_v72he::o72_actorOps() {
 	case SO_SHADOW:
 		a->_heShadow = pop();
 		a->_needRedraw = true;
+		a->_needBgReset = true;
+
 		break;
 	case SO_TEXT_OFFSET:
 		a->_talkPosY = pop();
diff --git a/engines/scumm/metaengine.cpp b/engines/scumm/metaengine.cpp
index 17fa8cad4ff..75e8e452558 100644
--- a/engines/scumm/metaengine.cpp
+++ b/engines/scumm/metaengine.cpp
@@ -431,6 +431,8 @@ Common::Error ScummMetaEngine::createInstance(OSystem *syst, Engine **engine) {
 			break;
 		case 98:
 		case 95:
+			*engine = new ScummEngine_v95he(syst, res);
+			break;
 		case 90:
 			*engine = new ScummEngine_v90he(syst, res);
 			break;
diff --git a/engines/scumm/object.cpp b/engines/scumm/object.cpp
index 9d8b87be325..da6e288cb9d 100644
--- a/engines/scumm/object.cpp
+++ b/engines/scumm/object.cpp
@@ -691,7 +691,7 @@ void ScummEngine::drawObject(int obj, int arg) {
 			continue;
 		if (arg < 0 && tmp <= _screenEndStrip + arg)
 			continue;
-		setGfxUsageBit(tmp, USAGE_BIT_DIRTY);
+		setGfxUsageBit(tmp, USAGE_BIT_DIRTY); // FIXME: HE70 onwards seems to use USAGE_BIT_RESTORED instead?
 		if (tmp < x)
 			x = tmp;
 		numstrip++;
@@ -739,7 +739,7 @@ void ScummEngine::drawObject(int obj, int arg) {
 			flags |= Gdi::dbDrawMaskOnAll;
 
 #ifdef ENABLE_HE
-		if (_game.heversion >= 70 && findResource(MKTAG('S','M','A','P'), ptr) == NULL)
+		if (_game.heversion >= 70 && !findResource(MKTAG('S','M','A','P'), ptr))
 			_gdi->drawBMAPObject(ptr, &_virtscr[kMainVirtScreen], obj, od.x_pos, od.y_pos, od.width, od.height);
 		else
 #endif
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index d4dc6c8f06d..2558fe969cb 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -1238,11 +1238,11 @@ protected:
 	void walkActors();
 	void playActorSounds();
 	void redrawAllActors();
-	void setActorRedrawFlags();
+	virtual void setActorRedrawFlags();
 	void putActors();
 	void showActors();
 	void resetV1ActorTalkColor();
-	void resetActorBgs();
+	virtual void resetActorBgs();
 	virtual void processActors();
 	void processUpperActors();
 	virtual int getActorFromPos(int x, int y);
@@ -1486,6 +1486,7 @@ protected:
 	}
 
 	bool testGfxAnyUsageBits(int strip);
+	bool testGfxObjectUsageBits(int strip); // Used for HE actors overlap calculations
 	bool testGfxOtherUsageBits(int strip, int bit);
 
 public:
diff --git a/engines/scumm/usage_bits.cpp b/engines/scumm/usage_bits.cpp
index fa17b693247..5f87e9b23c8 100644
--- a/engines/scumm/usage_bits.cpp
+++ b/engines/scumm/usage_bits.cpp
@@ -67,6 +67,11 @@ bool ScummEngine::testGfxAnyUsageBits(int strip) {
 	return false;
 }
 
+bool ScummEngine::testGfxObjectUsageBits(int strip) {
+	// Test whether any of the DIRTY or RESTORED bits is set
+	return testGfxUsageBit(strip, USAGE_BIT_DIRTY) || testGfxUsageBit(strip, USAGE_BIT_RESTORED);
+}
+
 bool ScummEngine::testGfxOtherUsageBits(int strip, int bit) {
 	// Don't exclude the DIRTY and RESTORED bits from the test
 	uint32 bitmask[3] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };




More information about the Scummvm-git-logs mailing list