aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Snover2016-03-18 13:08:37 -0500
committerColin Snover2016-03-18 13:08:37 -0500
commite25d928a9cb82d458c7f592ec81576f0d57d8eca (patch)
tree6fc1c40adc8bebf6174fcc49f3514d576ae0a1b6
parent856f3ae6489b3f9aec62043c58c3961baf619f16 (diff)
downloadscummvm-rg350-e25d928a9cb82d458c7f592ec81576f0d57d8eca.tar.gz
scummvm-rg350-e25d928a9cb82d458c7f592ec81576f0d57d8eca.tar.bz2
scummvm-rg350-e25d928a9cb82d458c7f592ec81576f0d57d8eca.zip
SCI32: Fix crashes in kIsOnMe caused by stale CelObjs
-rw-r--r--engines/sci/graphics/celobj32.h4
-rw-r--r--engines/sci/graphics/frameout.cpp9
-rw-r--r--engines/sci/graphics/screen_item32.cpp12
3 files changed, 23 insertions, 2 deletions
diff --git a/engines/sci/graphics/celobj32.h b/engines/sci/graphics/celobj32.h
index 600ae82d32..0bb4b03ae2 100644
--- a/engines/sci/graphics/celobj32.h
+++ b/engines/sci/graphics/celobj32.h
@@ -104,6 +104,10 @@ struct CelInfo32 {
bitmap == other.bitmap
);
}
+
+ inline bool operator!=(const CelInfo32 &other) {
+ return !(*this == other);
+ }
};
class CelObj;
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index b654cbf2b9..062cd8b600 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -1381,7 +1381,7 @@ void GfxFrameout::kernelFrameOut(const bool shouldShowBits) {
#pragma mark Mouse cursor
reg_t GfxFrameout::kernelIsOnMe(const reg_t object, const Common::Point &position, bool checkPixel) const {
- reg_t planeObject = readSelector(_segMan, object, SELECTOR(plane));
+ const reg_t planeObject = readSelector(_segMan, object, SELECTOR(plane));
Plane *plane = _visiblePlanes.findByObject(planeObject);
if (plane == nullptr) {
return make_reg(0, 0);
@@ -1392,6 +1392,13 @@ reg_t GfxFrameout::kernelIsOnMe(const reg_t object, const Common::Point &positio
return make_reg(0, 0);
}
+ // NOTE: The original engine passed a copy of the ScreenItem into isOnMe
+ // as a hack around the fact that the screen items in `_visiblePlanes`
+ // did not have their `_celObj` pointers cleared when their CelInfo was
+ // updated by `Plane::decrementScreenItemArrayCounts`. We handle this
+ // this more intelligently by clearing `_celObj` in the copy assignment
+ // operator, which is only ever called by `decrementScreenItemArrayCounts`
+ // anyway.
return make_reg(0, isOnMe(*screenItem, *plane, position, checkPixel));
}
diff --git a/engines/sci/graphics/screen_item32.cpp b/engines/sci/graphics/screen_item32.cpp
index c44d3e96f1..c3fdbb6845 100644
--- a/engines/sci/graphics/screen_item32.cpp
+++ b/engines/sci/graphics/screen_item32.cpp
@@ -115,7 +115,17 @@ _screenRect(other._screenRect) {
}
void ScreenItem::operator=(const ScreenItem &other) {
- _celInfo = other._celInfo;
+ // NOTE: The original engine did not check for differences in `_celInfo`
+ // to clear `_celObj` here; instead, it unconditionally set `_celInfo`,
+ // didn't clear `_celObj`, and did hacky stuff in `kIsOnMe` to avoid
+ // testing a mismatched `_celObj`. See `GfxFrameout::kernelIsOnMe` for
+ // more detail.
+ if (_celInfo != other._celInfo) {
+ _celInfo = other._celInfo;
+ delete _celObj;
+ _celObj = nullptr;
+ }
+
_screenRect = other._screenRect;
_mirrorX = other._mirrorX;
_useInsetRect = other._useInsetRect;