[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