aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci')
-rw-r--r--engines/sci/graphics/frameout.cpp405
-rw-r--r--engines/sci/graphics/plane32.cpp520
-rw-r--r--engines/sci/graphics/plane32.h121
3 files changed, 626 insertions, 420 deletions
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index 4ec91dc6ad..62a77da5ef 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -553,133 +553,219 @@ void GfxFrameout::frameOut(const bool shouldShowBits, const Common::Rect &eraseR
// }
}
-// Determine the parts of 'r' that aren't overlapped by 'other'.
-// Returns -1 if r and other have no intersection.
-// Returns number of returned parts (in outRects) otherwise.
-// (In particular, this returns 0 if r is contained in other.)
+/**
+ * Determines the parts of `r` that aren't overlapped by `other`.
+ * Returns -1 if `r` and `other` have no intersection.
+ * Returns number of returned parts (in `outRects`) otherwise.
+ * (In particular, this returns 0 if `r` is contained in `other`.)
+ */
int splitRects(Common::Rect r, const Common::Rect &other, Common::Rect(&outRects)[4]) {
if (!r.intersects(other)) {
return -1;
}
- int count = 0;
+ int splitCount = 0;
if (r.top < other.top) {
- Common::Rect &t = outRects[count++];
+ Common::Rect &t = outRects[splitCount++];
t = r;
t.bottom = other.top;
r.top = other.top;
}
if (r.bottom > other.bottom) {
- Common::Rect &t = outRects[count++];
+ Common::Rect &t = outRects[splitCount++];
t = r;
t.top = other.bottom;
r.bottom = other.bottom;
}
if (r.left < other.left) {
- Common::Rect &t = outRects[count++];
+ Common::Rect &t = outRects[splitCount++];
t = r;
t.right = other.left;
r.left = other.left;
}
if (r.right > other.right) {
- Common::Rect &t = outRects[count++];
+ Common::Rect &t = outRects[splitCount++];
t = r;
t.left = other.right;
}
- return count;
+ return splitCount;
}
-void GfxFrameout::calcLists(ScreenItemListList &drawLists, EraseListList &eraseLists, const Common::Rect &calcRect) {
- RectList rectlist;
- Common::Rect outRects[4];
+/**
+ * Determines the parts of `middleRect` that aren't overlapped
+ * by `showRect`, optimised for contiguous memory writes.
+ * Returns -1 if `middleRect` and `showRect` have no intersection.
+ * Returns number of returned parts (in `outRects`) otherwise.
+ * (In particular, this returns 0 if `middleRect` is contained
+ * in `other`.)
+ *
+ * `middleRect` is modified directly to extend into the upper
+ * and lower rects.
+ */
+int splitRectsForRender(Common::Rect &middleRect, const Common::Rect &showRect, Common::Rect(&outRects)[2]) {
+ if (!middleRect.intersects(showRect)) {
+ return -1;
+ }
+
+ const int16 minLeft = MIN(middleRect.left, showRect.left);
+ const int16 maxRight = MAX(middleRect.right, showRect.right);
+
+ int16 upperLeft, upperTop, upperRight, upperMaxTop;
+ if (middleRect.top < showRect.top) {
+ upperLeft = middleRect.left;
+ upperTop = middleRect.top;
+ upperRight = middleRect.right;
+ upperMaxTop = showRect.top;
+ }
+ else {
+ upperLeft = showRect.left;
+ upperTop = showRect.top;
+ upperRight = showRect.right;
+ upperMaxTop = middleRect.top;
+ }
+
+ int16 lowerLeft, lowerRight, lowerBottom, lowerMinBottom;
+ if (middleRect.bottom > showRect.bottom) {
+ lowerLeft = middleRect.left;
+ lowerRight = middleRect.right;
+ lowerBottom = middleRect.bottom;
+ lowerMinBottom = showRect.bottom;
+ } else {
+ lowerLeft = showRect.left;
+ lowerRight = showRect.right;
+ lowerBottom = showRect.bottom;
+ lowerMinBottom = middleRect.bottom;
+ }
+
+ int splitCount = 0;
+ middleRect.left = minLeft;
+ middleRect.top = upperMaxTop;
+ middleRect.right = maxRight;
+ middleRect.bottom = lowerMinBottom;
+
+ if (upperTop != upperMaxTop) {
+ Common::Rect &upperRect = outRects[0];
+ upperRect.left = upperLeft;
+ upperRect.top = upperTop;
+ upperRect.right = upperRight;
+ upperRect.bottom = upperMaxTop;
+
+ // Merge upper rect into middle rect if possible
+ if (upperRect.left == middleRect.left && upperRect.right == middleRect.right) {
+ middleRect.top = upperRect.top;
+ } else {
+ ++splitCount;
+ }
+ }
+
+ if (lowerBottom != lowerMinBottom) {
+ Common::Rect &lowerRect = outRects[splitCount];
+ lowerRect.left = lowerLeft;
+ lowerRect.top = lowerMinBottom;
+ lowerRect.right = lowerRight;
+ lowerRect.bottom = lowerBottom;
+
+ // Merge lower rect into middle rect if possible
+ if (lowerRect.left == middleRect.left && lowerRect.right == middleRect.right) {
+ middleRect.bottom = lowerRect.bottom;
+ } else {
+ ++splitCount;
+ }
+ }
+
+ assert(splitCount <= 2);
+ return splitCount;
+}
// NOTE: The third rectangle parameter is only ever given a non-empty rect
// by VMD code, via `frameOut`
void GfxFrameout::calcLists(ScreenItemListList &drawLists, EraseListList &eraseLists, const Common::Rect &eraseRect) {
+ RectList eraseList;
+ Common::Rect outRects[4];
int deletedPlaneCount = 0;
- bool addedToRectList = false;
- int planeCount = _planes.size();
+ bool addedToEraseList = false;
bool foundTransparentPlane = false;
if (!eraseRect.isEmpty()) {
addedToEraseList = true;
- rectlist.add(eraseRect);
+ eraseList.add(eraseRect);
}
+ PlaneList::size_type planeCount = _planes.size();
for (int outerPlaneIndex = 0; outerPlaneIndex < planeCount; ++outerPlaneIndex) {
- Plane *outerPlane = _planes[outerPlaneIndex];
+ const Plane *outerPlane = _planes[outerPlaneIndex];
+ const Plane *visiblePlane = _visiblePlanes.findByObject(outerPlane->_object);
if (outerPlane->_type == kPlaneTypeTransparent) {
foundTransparentPlane = true;
}
- Plane *visiblePlane = _visiblePlanes.findByObject(outerPlane->_object);
-
if (outerPlane->_deleted) {
- if (visiblePlane != nullptr) {
- if (!visiblePlane->_screenRect.isEmpty()) {
- addedToRectList = true;
- rectlist.add(visiblePlane->_screenRect);
- }
+ if (visiblePlane != nullptr && !visiblePlane->_screenRect.isEmpty()) {
+ eraseList.add(visiblePlane->_screenRect);
+ addedToEraseList = true;
}
++deletedPlaneCount;
- } else if (visiblePlane != nullptr) {
- if (outerPlane->_updated) {
- --outerPlane->_updated;
-
- int splitcount = splitRects(visiblePlane->_screenRect, outerPlane->_screenRect, outRects);
- if (splitcount) {
- if (splitcount == -1) {
- if (!visiblePlane->_screenRect.isEmpty()) {
- rectlist.add(visiblePlane->_screenRect);
- }
+ } else if (visiblePlane != nullptr && outerPlane->_moved) {
+ // _moved will be decremented in the final loop through the planes,
+ // at the end of this function
+
+ {
+ const int splitCount = splitRects(visiblePlane->_screenRect, outerPlane->_screenRect, outRects);
+ if (splitCount) {
+ if (splitCount == -1 && !visiblePlane->_screenRect.isEmpty()) {
+ eraseList.add(visiblePlane->_screenRect);
} else {
- for (int i = 0; i < splitcount; ++i) {
- rectlist.add(outRects[i]);
+ for (int i = 0; i < splitCount; ++i) {
+ eraseList.add(outRects[i]);
}
}
-
- addedToRectList = true;
+ addedToEraseList = true;
}
+ }
- if (!outerPlane->_redrawAllCount) {
- int splitCount = splitRects(outerPlane->_screenRect, visiblePlane->_screenRect, outRects);
- if (splitCount) {
- for (int i = 0; i < splitCount; ++i) {
- rectlist.add(outRects[i]);
- }
- addedToRectList = true;
+ if (!outerPlane->_redrawAllCount) {
+ const int splitCount = splitRects(outerPlane->_screenRect, visiblePlane->_screenRect, outRects);
+ if (splitCount) {
+ for (int i = 0; i < splitCount; ++i) {
+ eraseList.add(outRects[i]);
}
+ addedToEraseList = true;
}
}
}
- if (addedToRectList) {
- for (RectList::iterator rect = rectlist.begin(); rect != rectlist.end(); ++rect) {
- for (int innerPlaneIndex = _planes.size() - 1; innerPlaneIndex >= 0; --innerPlaneIndex) {
- Plane *innerPlane = _planes[innerPlaneIndex];
-
- if (!innerPlane->_deleted && innerPlane->_type != kPlaneTypeTransparent && innerPlane->_screenRect.intersects(**rect)) {
- if (innerPlane->_redrawAllCount == 0) {
- eraseLists[innerPlaneIndex].add(innerPlane->_screenRect.findIntersectingRect(**rect));
+ if (addedToEraseList) {
+ for (int rectIndex = 0; rectIndex < eraseList.size(); ++rectIndex) {
+ const Common::Rect &rect = *eraseList[rectIndex];
+ for (int innerPlaneIndex = planeCount - 1; innerPlaneIndex >= 0; --innerPlaneIndex) {
+ const Plane &innerPlane = *_planes[innerPlaneIndex];
+
+ if (
+ !innerPlane._deleted &&
+ innerPlane._type != kPlaneTypeTransparent &&
+ innerPlane._screenRect.intersects(rect)
+ ) {
+ if (!innerPlane._redrawAllCount) {
+ eraseLists[innerPlaneIndex].add(innerPlane._screenRect.findIntersectingRect(rect));
}
- int splitCount = splitRects(**rect, innerPlane->_screenRect, outRects);
+ const int splitCount = splitRects(rect, innerPlane._screenRect, outRects);
for (int i = 0; i < splitCount; ++i) {
- rectlist.add(outRects[i]);
+ eraseList.add(outRects[i]);
}
- rectlist.erase(rect);
+ eraseList.erase_at(rectIndex);
break;
}
}
}
- rectlist.pack();
+ eraseList.pack();
}
}
@@ -691,9 +777,9 @@ void GfxFrameout::calcLists(ScreenItemListList &drawLists, EraseListList &eraseL
if (plane->_deleted) {
--plane->_deleted;
if (plane->_deleted <= 0) {
- PlaneList::iterator visiblePlaneIt = Common::find_if(_visiblePlanes.begin(), _visiblePlanes.end(), FindByObject<Plane *>(plane->_object));
- if (visiblePlaneIt != _visiblePlanes.end()) {
- _visiblePlanes.erase(visiblePlaneIt);
+ const int visiblePlaneIndex = _visiblePlanes.findIndexByObject(plane->_object);
+ if (visiblePlaneIndex != -1) {
+ _visiblePlanes.remove_at(visiblePlaneIndex);
}
_planes.remove_at(planeIndex);
@@ -708,107 +794,112 @@ void GfxFrameout::calcLists(ScreenItemListList &drawLists, EraseListList &eraseL
}
}
+ // Some planes may have been deleted, so re-retrieve count
planeCount = _planes.size();
- for (int outerIndex = 0; outerIndex < planeCount; ++outerIndex) {
+
+ for (PlaneList::size_type outerIndex = 0; outerIndex < planeCount; ++outerIndex) {
// "outer" just refers to the outer loop
- Plane *outerPlane = _planes[outerIndex];
- if (outerPlane->_priorityChanged) {
- --outerPlane->_priorityChanged;
+ Plane &outerPlane = *_planes[outerIndex];
+ if (outerPlane._priorityChanged) {
+ --outerPlane._priorityChanged;
- Plane *visibleOuterPlane = _visiblePlanes.findByObject(outerPlane->_object);
+ const Plane *visibleOuterPlane = _visiblePlanes.findByObject(outerPlane._object);
if (visibleOuterPlane == nullptr) {
- warning("calcLists could not find visible plane for %04x:%04x", PRINT_REG(outerPlane->_object));
+ warning("calcLists could not find visible plane for %04x:%04x", PRINT_REG(outerPlane._object));
continue;
}
- rectlist.add(outerPlane->_screenRect.findIntersectingRect(visibleOuterPlane->_screenRect));
+ eraseList.add(outerPlane._screenRect.findIntersectingRect(visibleOuterPlane->_screenRect));
- for (int innerIndex = planeCount - 1; innerIndex >= 0; --innerIndex) {
+ for (PlaneList::size_type innerIndex = planeCount - 1; innerIndex >= 0; --innerIndex) {
// "inner" just refers to the inner loop
- Plane *innerPlane = _planes[innerIndex];
- Plane *visibleInnerPlane = _visiblePlanes.findByObject(innerPlane->_object);
-
- int rectCount = rectlist.size();
- for (int rectIndex = 0; rectIndex < rectCount; ++rectIndex) {
- int splitCount = splitRects(*rectlist[rectIndex], _planes[innerIndex]->_screenRect, outRects);
+ const Plane &innerPlane = *_planes[innerIndex];
+ const Plane *visibleInnerPlane = _visiblePlanes.findByObject(innerPlane._object);
+ const RectList::size_type rectCount = eraseList.size();
+ for (RectList::size_type rectIndex = 0; rectIndex < rectCount; ++rectIndex) {
+ const int splitCount = splitRects(*eraseList[rectIndex], innerPlane._screenRect, outRects);
if (splitCount == 0) {
if (visibleInnerPlane != nullptr) {
// same priority, or relative priority between inner/outer changed
- if ((visibleOuterPlane->_priority - visibleInnerPlane->_priority) * (outerPlane->_priority - innerPlane->_priority) <= 0) {
- if (outerPlane->_priority <= innerPlane->_priority) {
- eraseLists[innerIndex].add(*rectlist[rectIndex]);
+ if ((visibleOuterPlane->_priority - visibleInnerPlane->_priority) * (outerPlane._priority - innerPlane._priority) <= 0) {
+ if (outerPlane._priority <= innerPlane._priority) {
+ eraseLists[innerIndex].add(*eraseList[rectIndex]);
} else {
- eraseLists[outerIndex].add(*rectlist[rectIndex]);
+ eraseLists[outerIndex].add(*eraseList[rectIndex]);
}
}
}
- rectlist.erase_at(rectIndex);
+ eraseList.erase_at(rectIndex);
} else if (splitCount != -1) {
for (int i = 0; i < splitCount; ++i) {
- rectlist.add(outRects[i]);
+ eraseList.add(outRects[i]);
}
if (visibleInnerPlane != nullptr) {
// same priority, or relative priority between inner/outer changed
- if ((visibleOuterPlane->_priority - visibleInnerPlane->_priority) * (outerPlane->_priority - innerPlane->_priority) <= 0) {
- *rectlist[rectIndex] = outerPlane->_screenRect.findIntersectingRect(innerPlane->_screenRect);
- if (outerPlane->_priority <= innerPlane->_priority) {
- eraseLists[innerIndex].add(*rectlist[rectIndex]);
- }
- else {
- eraseLists[outerIndex].add(*rectlist[rectIndex]);
+ if ((visibleOuterPlane->_priority - visibleInnerPlane->_priority) * (outerPlane._priority - innerPlane._priority) <= 0) {
+ *eraseList[rectIndex] = outerPlane._screenRect.findIntersectingRect(innerPlane._screenRect);
+
+ if (outerPlane._priority <= innerPlane._priority) {
+ eraseLists[innerIndex].add(*eraseList[rectIndex]);
+ } else {
+ eraseLists[outerIndex].add(*eraseList[rectIndex]);
}
}
}
- rectlist.erase_at(rectIndex);
+ eraseList.erase_at(rectIndex);
}
}
- rectlist.pack();
+ eraseList.pack();
}
}
}
- for (int planeIndex = 0; planeIndex < planeCount; ++planeIndex) {
- Plane *plane = _planes[planeIndex];
- Plane *visiblePlane = nullptr;
+ for (PlaneList::size_type planeIndex = 0; planeIndex < planeCount; ++planeIndex) {
+ Plane &plane = *_planes[planeIndex];
+ Plane *visiblePlane = _visiblePlanes.findByObject(plane._object);
- PlaneList::iterator visiblePlaneIt = Common::find_if(_visiblePlanes.begin(), _visiblePlanes.end(), FindByObject<Plane *>(plane->_object));
- if (visiblePlaneIt != _visiblePlanes.end()) {
- visiblePlane = *visiblePlaneIt;
- }
+ if (!plane._screenRect.isEmpty()) {
+ if (plane._redrawAllCount) {
+ plane.redrawAll(visiblePlane, _planes, drawLists[planeIndex], eraseLists[planeIndex]);
+ } else {
+ if (visiblePlane == nullptr) {
+ error("Missing visible plane for source plane %04x:%04x", PRINT_REG(plane._object));
+ }
- if (plane->_redrawAllCount) {
- plane->redrawAll(visiblePlane, _planes, drawLists[planeIndex], eraseLists[planeIndex]);
- } else {
- if (visiblePlane == nullptr) {
- error("Missing visible plane for source plane %04x:%04x", PRINT_REG(plane->_object));
+ plane.calcLists(*visiblePlane, _planes, drawLists[planeIndex], eraseLists[planeIndex]);
}
+ } else {
+ plane.decrementScreenItemArrayCounts(visiblePlane, false);
+ }
- plane->calcLists(*visiblePlane, _planes, drawLists[planeIndex], eraseLists[planeIndex]);
+ if (plane._moved) {
+ // the work for handling moved/resized planes was already done
+ // earlier in the function, we are just cleaning up now
+ --plane._moved;
}
- if (plane->_created) {
- _visiblePlanes.add(new Plane(*plane));
- --plane->_created;
- } else if (plane->_moved) {
- assert(visiblePlaneIt != _visiblePlanes.end());
- **visiblePlaneIt = *plane;
- --plane->_moved;
+ if (plane._created) {
+ _visiblePlanes.add(new Plane(plane));
+ --plane._created;
+ } else if (plane._updated) {
+ *visiblePlane = plane;
+ --plane._updated;
}
}
if (foundTransparentPlane) {
- for (int planeIndex = 0; planeIndex < planeCount; ++planeIndex) {
- for (int i = planeIndex + 1; i < planeCount; ++i) {
+ for (PlaneList::size_type planeIndex = 0; planeIndex < planeCount; ++planeIndex) {
+ for (PlaneList::size_type i = planeIndex + 1; i < planeCount; ++i) {
if (_planes[i]->_type == kPlaneTypeTransparent) {
_planes[i]->filterUpEraseRects(drawLists[i], eraseLists[planeIndex]);
}
}
if (_planes[planeIndex]->_type == kPlaneTypeTransparent) {
- for (int i = planeIndex - 1; i >= 0; --i) {
+ for (PlaneList::size_type i = planeIndex - 1; i >= 0; --i) {
_planes[i]->filterDownEraseRects(drawLists[i], eraseLists[i], eraseLists[planeIndex]);
}
@@ -817,7 +908,7 @@ void GfxFrameout::calcLists(ScreenItemListList &drawLists, EraseListList &eraseL
}
}
- for (int i = planeIndex + 1; i < planeCount; ++i) {
+ for (PlaneList::size_type i = planeIndex + 1; i < planeCount; ++i) {
if (_planes[i]->_type == kPlaneTypeTransparent) {
_planes[i]->filterUpDrawRects(drawLists[i], drawLists[planeIndex]);
}
@@ -831,17 +922,19 @@ void GfxFrameout::drawEraseList(const RectList &eraseList, const Plane &plane) {
return;
}
- for (RectList::const_iterator it = eraseList.begin(); it != eraseList.end(); ++it) {
- mergeToShowList(**it, _showList, _overdrawThreshold);
- _currentBuffer.fillRect(**it, plane._back);
+ const RectList::size_type eraseListSize = eraseList.size();
+ for (RectList::size_type i = 0; i < eraseListSize; ++i) {
+ mergeToShowList(*eraseList[i], _showList, _overdrawThreshold);
+ _currentBuffer.fillRect(*eraseList[i], plane._back);
}
}
void GfxFrameout::drawScreenItemList(const DrawList &screenItemList) {
- for (DrawList::const_iterator it = screenItemList.begin(); it != screenItemList.end(); ++it) {
- DrawItem &drawItem = **it;
+ const DrawList::size_type drawListSize = screenItemList.size();
+ for (DrawList::size_type i = 0; i < drawListSize; ++i) {
+ const DrawItem &drawItem = *screenItemList[i];
mergeToShowList(drawItem.rect, _showList, _overdrawThreshold);
- ScreenItem &screenItem = *drawItem.screenItem;
+ const ScreenItem &screenItem = *drawItem.screenItem;
// TODO: Remove
// debug("Drawing item %04x:%04x to %d %d %d %d", PRINT_REG(screenItem._object), PRINT_RECT(drawItem.rect));
CelObj &celObj = *screenItem._celObj;
@@ -850,32 +943,61 @@ void GfxFrameout::drawScreenItemList(const DrawList &screenItemList) {
}
void GfxFrameout::mergeToShowList(const Common::Rect &drawRect, RectList &showList, const int overdrawThreshold) {
- Common::Rect merged(drawRect);
-
- bool didDelete = true;
- RectList::size_type count = showList.size();
- while (didDelete && count) {
- didDelete = false;
-
- for (RectList::size_type i = 0; i < count; ++i) {
- Common::Rect existing = *showList[i];
- Common::Rect candidate;
- candidate.left = MIN(merged.left, existing.left);
- candidate.top = MIN(merged.top, existing.top);
- candidate.right = MAX(merged.right, existing.right);
- candidate.bottom = MAX(merged.bottom, existing.bottom);
-
- if (candidate.height() * candidate.width() - merged.width() * merged.height() - existing.width() * existing.height() <= overdrawThreshold) {
- merged = candidate;
- showList.erase_at(i);
- didDelete = true;
+ RectList mergeList;
+ Common::Rect merged;
+ mergeList.add(drawRect);
+
+ for (RectList::size_type i = 0; i < mergeList.size(); ++i) {
+ bool didMerge = false;
+ const Common::Rect &r1 = *mergeList[i];
+ if (!r1.isEmpty()) {
+ for (RectList::size_type j = 0; j < showList.size(); ++j) {
+ const Common::Rect &r2 = *showList[j];
+ if (!r2.isEmpty()) {
+ merged = r1;
+ merged.extend(r2);
+
+ int difference = merged.width() * merged.height();
+ difference -= r1.width() * r1.height();
+ difference -= r2.width() * r2.height();
+ if (r1.intersects(r2)) {
+ const Common::Rect overlap = r1.findIntersectingRect(r2);
+ difference += overlap.width() * overlap.height();
+ }
+
+ if (difference <= overdrawThreshold) {
+ mergeList.erase_at(i);
+ showList.erase_at(j);
+ mergeList.add(merged);
+ didMerge = true;
+ break;
+ } else {
+ Common::Rect outRects[2];
+ int splitCount = splitRectsForRender(*mergeList[i], *showList[j], outRects);
+ if (splitCount != -1) {
+ mergeList.add(*mergeList[i]);
+ mergeList.erase_at(i);
+ showList.erase_at(j);
+ didMerge = true;
+ while (splitCount--) {
+ mergeList.add(outRects[splitCount]);
+ }
+ break;
+ }
+ }
+ }
}
- }
- count = showList.pack();
+ if (didMerge) {
+ showList.pack();
+ }
+ }
}
- showList.add(merged);
+ mergeList.pack();
+ for (RectList::size_type i = 0; i < mergeList.size(); ++i) {
+ showList.add(*mergeList[i]);
+ }
}
void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry *showStyle) {
@@ -930,6 +1052,7 @@ void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry
}
} else {
for (int i = 0; i < ARRAYSIZE(sourcePalette.colors); ++i) {
+ // TODO: Limiting range 72 to 103 is NOT present in every game
if (styleRanges[i] == -1 || (styleRanges[i] == 0 && i > 71 && i < 104)) {
sourcePalette.colors[i] = nextPalette.colors[i];
sourcePalette.colors[i].used = true;
diff --git a/engines/sci/graphics/plane32.cpp b/engines/sci/graphics/plane32.cpp
index 3f0b035738..021ac523b8 100644
--- a/engines/sci/graphics/plane32.cpp
+++ b/engines/sci/graphics/plane32.cpp
@@ -240,16 +240,17 @@ void Plane::deleteAllPics() {
#pragma mark Plane - Rendering
void Plane::breakDrawListByPlanes(DrawList &drawList, const PlaneList &planeList) const {
- int index = planeList.findIndexByObject(_object);
+ const int nextPlaneIndex = planeList.findIndexByObject(_object) + 1;
+ const PlaneList::size_type planeCount = planeList.size();
for (DrawList::size_type i = 0; i < drawList.size(); ++i) {
- for (PlaneList::size_type j = index + 1; j < planeList.size(); ++j) {
+ for (PlaneList::size_type j = nextPlaneIndex; j < planeCount; ++j) {
if (planeList[j]->_type != kPlaneTypeTransparent) {
- Common::Rect ptr[4];
- int count = splitRects(drawList[i]->rect, planeList[j]->_screenRect, ptr);
- if (count != -1) {
- for (int k = count - 1; k >= 0; --k) {
- drawList.add(drawList[i]->screenItem, ptr[k]);
+ Common::Rect outRects[4];
+ int splitCount = splitRects(drawList[i]->rect, planeList[j]->_screenRect, outRects);
+ if (splitCount != -1) {
+ while (splitCount--) {
+ drawList.add(drawList[i]->screenItem, outRects[splitCount]);
}
drawList.erase_at(i);
@@ -262,17 +263,17 @@ void Plane::breakDrawListByPlanes(DrawList &drawList, const PlaneList &planeList
}
void Plane::breakEraseListByPlanes(RectList &eraseList, const PlaneList &planeList) const {
- int index = planeList.findIndexByObject(_object);
+ const int nextPlaneIndex = planeList.findIndexByObject(_object) + 1;
+ const PlaneList::size_type planeCount = planeList.size();
for (RectList::size_type i = 0; i < eraseList.size(); ++i) {
- for (PlaneList::size_type j = index + 1; j < planeList.size(); ++j) {
+ for (PlaneList::size_type j = nextPlaneIndex; j < planeCount; ++j) {
if (planeList[j]->_type != kPlaneTypeTransparent) {
- Common::Rect ptr[4];
-
- int count = splitRects(*eraseList[i], planeList[j]->_screenRect, ptr);
- if (count != -1) {
- for (int k = count - 1; k >= 0; --k) {
- eraseList.add(ptr[k]);
+ Common::Rect outRects[4];
+ int splitCount = splitRects(*eraseList[i], planeList[j]->_screenRect, outRects);
+ if (splitCount != -1) {
+ while (splitCount--) {
+ eraseList.add(outRects[splitCount]);
}
eraseList.erase_at(i);
@@ -285,94 +286,109 @@ void Plane::breakEraseListByPlanes(RectList &eraseList, const PlaneList &planeLi
}
void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList &drawList, RectList &eraseList) {
- ScreenItemList::size_type planeItemCount = _screenItemList.size();
- ScreenItemList::size_type visiblePlaneItemCount = visiblePlane._screenItemList.size();
+ const ScreenItemList::size_type screenItemCount = _screenItemList.size();
+ const ScreenItemList::size_type visiblePlaneItemCount = visiblePlane._screenItemList.size();
+
+ for (ScreenItemList::size_type i = 0; i < screenItemCount; ++i) {
+ // Items can be added to ScreenItemList and we don't want to process
+ // those new items, but the list also can grow smaller, so we need
+ // to check that we are still within the upper bound of the list and
+ // quit if we aren't any more
+ if (i >= _screenItemList.size()) {
+ break;
+ }
+
+ ScreenItem *item = _screenItemList[i];
+ if (item == nullptr) {
+ continue;
+ }
- for (ScreenItemList::size_type i = 0; i < planeItemCount; ++i) {
- ScreenItem *vitem = nullptr;
// NOTE: The original engine used an array without bounds checking
// so could just get the visible screen item directly; we need to
// verify that the index is actually within the valid range for
// the visible plane before accessing the item to avoid a range
// error.
+ const ScreenItem *visibleItem = nullptr;
if (i < visiblePlaneItemCount) {
- vitem = visiblePlane._screenItemList[i];
+ visibleItem = visiblePlane._screenItemList[i];
}
- ScreenItem *item = _screenItemList[i];
- if (i < _screenItemList.size() && item != nullptr) {
- if (item->_deleted) {
- // add item's rect to erase list
- if (
- i < visiblePlane._screenItemList.size() &&
- vitem != nullptr &&
- !vitem->_screenRect.isEmpty()
- ) {
- if (g_sci->_gfxRemap32->getRemapCount()) {
- mergeToRectList(vitem->_screenRect, eraseList);
- } else {
- eraseList.add(vitem->_screenRect);
- }
- }
- } else if (item->_created) {
- // add item to draw list
- item->calcRects(*this);
-
- if(!item->_screenRect.isEmpty()) {
- if (g_sci->_gfxRemap32->getRemapCount()) {
- drawList.add(item, item->_screenRect);
- mergeToRectList(item->_screenRect, eraseList);
- } else {
- drawList.add(item, item->_screenRect);
- }
- }
- } else if (item->_updated) {
- // add old rect to erase list, new item to draw list
- item->calcRects(*this);
+ // Keep erase rects for this screen item from drawing outside
+ // of its owner plane
+ Common::Rect visibleItemScreenRect;
+ if (visibleItem != nullptr) {
+ visibleItemScreenRect = visibleItem->_screenRect;
+ visibleItemScreenRect.clip(_screenRect);
+ }
+
+ if (item->_deleted) {
+ // Add item's rect to erase list
+ if (
+ visibleItem != nullptr &&
+ !visibleItemScreenRect.isEmpty()
+ ) {
if (g_sci->_gfxRemap32->getRemapCount()) {
- // if item and vitem don't overlap, ...
- if (item->_screenRect.isEmpty() ||
- i >= visiblePlaneItemCount ||
- vitem == nullptr ||
- vitem->_screenRect.isEmpty() ||
- !vitem->_screenRect.intersects(item->_screenRect)
- ) {
- // add item to draw list, and old rect to erase list
- if (!item->_screenRect.isEmpty()) {
- drawList.add(item, item->_screenRect);
- mergeToRectList(item->_screenRect, eraseList);
- }
- if (
- i < visiblePlaneItemCount &&
- vitem != nullptr &&
- !vitem->_screenRect.isEmpty()
- ) {
- mergeToRectList(vitem->_screenRect, eraseList);
- }
- } else {
- // otherwise, add bounding box of old+new to erase list,
- // and item to draw list
+ mergeToRectList(visibleItemScreenRect, eraseList);
+ } else {
+ eraseList.add(visibleItemScreenRect);
+ }
+ }
+ }
- // TODO: This was changed from disasm, verify please!
- Common::Rect extendedScreenRect = vitem->_screenRect;
- extendedScreenRect.extend(item->_screenRect);
+ if (!item->_created && !item->_updated) {
+ continue;
+ }
- drawList.add(item, item->_screenRect);
- mergeToRectList(extendedScreenRect, eraseList);
- }
+ item->calcRects(*this);
+ const Common::Rect itemScreenRect(item->_screenRect);
+
+ if (item->_created) {
+ // Add item to draw list
+ if(!itemScreenRect.isEmpty()) {
+ if (g_sci->_gfxRemap32->getRemapCount()) {
+ drawList.add(item, itemScreenRect);
+ mergeToRectList(itemScreenRect, eraseList);
} else {
- // if no active remaps, just add item to draw list and old rect
- // to erase list
- if (!item->_screenRect.isEmpty()) {
- drawList.add(item, item->_screenRect);
+ drawList.add(item, itemScreenRect);
+ }
+ }
+ } else {
+ // Add old rect to erase list, new item to draw list
+
+ if (g_sci->_gfxRemap32->getRemapCount()) {
+ // If item and visibleItem don't overlap...
+ if (itemScreenRect.isEmpty() ||
+ visibleItem == nullptr ||
+ visibleItemScreenRect.isEmpty() ||
+ !visibleItemScreenRect.intersects(itemScreenRect)
+ ) {
+ // ...add item to draw list, and old rect to erase list...
+ if (!itemScreenRect.isEmpty()) {
+ drawList.add(item, itemScreenRect);
+ mergeToRectList(itemScreenRect, eraseList);
}
- if (
- i < visiblePlaneItemCount &&
- vitem != nullptr &&
- !vitem->_screenRect.isEmpty()
- ) {
- eraseList.add(vitem->_screenRect);
+ if (visibleItem != nullptr && !visibleItemScreenRect.isEmpty()) {
+ mergeToRectList(visibleItemScreenRect, eraseList);
}
+ } else {
+ // ...otherwise, add bounding box of old+new to erase list,
+ // and item to draw list
+ Common::Rect extendedScreenRect = visibleItemScreenRect;
+ extendedScreenRect.extend(itemScreenRect);
+
+ drawList.add(item, itemScreenRect);
+ mergeToRectList(extendedScreenRect, eraseList);
+ }
+ } else {
+ // If no active remaps, just add item to draw list and old rect
+ // to erase list
+
+ // TODO: SCI3 update rects for VMD?
+ if (!itemScreenRect.isEmpty()) {
+ drawList.add(item, itemScreenRect);
+ }
+ if (visibleItem != nullptr && !visibleItemScreenRect.isEmpty()) {
+ eraseList.add(visibleItemScreenRect);
}
}
}
@@ -385,40 +401,44 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList
// We store the current size of the drawlist, as we want to loop
// over the currently inserted entries later.
DrawList::size_type drawListSizePrimary = drawList.size();
+ const RectList::size_type eraseListCount = eraseList.size();
- if (/* TODO: dword_C6288 */ false) { // "high resolution pictures"????
+ // TODO: Figure out which games need which rendering method
+ if (/* TODO: dword_C6288 */ false) { // "high resolution pictures"
_screenItemList.sort();
- bool encounteredPic = false;
- bool v81 = false;
+ bool pictureDrawn = false;
+ bool screenItemDrawn = false;
- for (RectList::size_type i = 0; i < eraseList.size(); ++i) {
- const Common::Rect *rect = eraseList[i];
+ for (RectList::size_type i = 0; i < eraseListCount; ++i) {
+ const Common::Rect &rect = *eraseList[i];
- for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) {
+ for (ScreenItemList::size_type j = 0; j < screenItemCount; ++j) {
ScreenItem *item = _screenItemList[j];
- if (j < _screenItemList.size() && item != nullptr) {
- if (rect->intersects(item->_screenRect)) {
- const Common::Rect intersection = rect->findIntersectingRect(item->_screenRect);
- if (!item->_deleted) {
- if (encounteredPic) {
- if (item->_celInfo.type == kCelTypePic) {
- if (v81 || item->_celInfo.celNo == 0) {
- drawList.add(item, intersection);
- }
- } else {
- if (!item->_updated && !item->_created) {
- drawList.add(item, intersection);
- }
- v81 = true;
+ if (item == nullptr) {
+ continue;
+ }
+
+ if (rect.intersects(item->_screenRect)) {
+ const Common::Rect intersection = rect.findIntersectingRect(item->_screenRect);
+ if (!item->_deleted) {
+ if (pictureDrawn) {
+ if (item->_celInfo.type == kCelTypePic) {
+ if (screenItemDrawn || item->_celInfo.celNo == 0) {
+ mergeToDrawList(j, intersection, drawList);
}
} else {
if (!item->_updated && !item->_created) {
- drawList.add(item, intersection);
- }
- if (item->_celInfo.type == kCelTypePic) {
- encounteredPic = true;
+ mergeToDrawList(j, intersection, drawList);
}
+ screenItemDrawn = true;
+ }
+ } else {
+ if (!item->_updated && !item->_created) {
+ mergeToDrawList(j, intersection, drawList);
+ }
+ if (item->_celInfo.type == kCelTypePic) {
+ pictureDrawn = true;
}
}
}
@@ -428,22 +448,23 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList
_screenItemList.unsort();
} else {
- // add all items overlapping the erase list to the draw list
- for (RectList::size_type i = 0; i < eraseList.size(); ++i) {
- for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) {
+ // Add all items overlapping the erase list to the draw list
+ for (RectList::size_type i = 0; i < eraseListCount; ++i) {
+ const Common::Rect &rect = *eraseList[i];
+ for (ScreenItemList::size_type j = 0; j < screenItemCount; ++j) {
ScreenItem *item = _screenItemList[j];
if (
item != nullptr &&
!item->_created && !item->_updated && !item->_deleted &&
- eraseList[i]->intersects(item->_screenRect)
+ rect.intersects(item->_screenRect)
) {
- drawList.add(item, eraseList[i]->findIntersectingRect(item->_screenRect));
+ drawList.add(item, rect.findIntersectingRect(item->_screenRect));
}
}
}
}
- if (g_sci->_gfxRemap32->getRemapCount() == 0) { // no remaps active?
+ if (g_sci->_gfxRemap32->getRemapCount() == 0) {
// Add all items that overlap with items in the drawlist and have higher
// priority.
@@ -451,23 +472,28 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList
// those that were added because of the erase list in the previous loop,
// or those to be added in this loop.
for (DrawList::size_type i = 0; i < drawListSizePrimary; ++i) {
- DrawItem *dli = drawList[i];
+ const DrawItem *drawListEntry = nullptr;
+ if (i < drawList.size()) {
+ drawListEntry = drawList[i];
+ }
- for (ScreenItemList::size_type j = 0; j < planeItemCount; ++j) {
- ScreenItem *sli = _screenItemList[j];
+ for (ScreenItemList::size_type j = 0; j < screenItemCount; ++j) {
+ ScreenItem *newItem = nullptr;
+ if (j < _screenItemList.size()) {
+ newItem = _screenItemList[j];
+ }
if (
- i < drawList.size() && dli != nullptr &&
- j < _screenItemList.size() && sli != nullptr &&
- !sli->_created && !sli->_updated && !sli->_deleted
+ drawListEntry != nullptr && newItem != nullptr &&
+ !newItem->_created && !newItem->_updated && !newItem->_deleted
) {
- ScreenItem *item = dli->screenItem;
+ const ScreenItem *drawnItem = drawListEntry->screenItem;
if (
- (sli->_priority > item->_priority || (sli->_priority == item->_priority && sli->_object > item->_object)) &&
- dli->rect.intersects(sli->_screenRect)
+ (newItem->_priority > drawnItem->_priority || (newItem->_priority == drawnItem->_priority && newItem->_object > drawnItem->_object)) &&
+ drawListEntry->rect.intersects(newItem->_screenRect)
) {
- drawList.add(sli, dli->rect.findIntersectingRect(sli->_screenRect));
+ mergeToDrawList(j, drawListEntry->rect.findIntersectingRect(newItem->_screenRect), drawList);
}
}
}
@@ -475,14 +501,11 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList
}
decrementScreenItemArrayCounts(&visiblePlane, false);
- _screenItemList.pack();
- visiblePlane._screenItemList.pack();
}
void Plane::decrementScreenItemArrayCounts(Plane *visiblePlane, const bool forceUpdate) {
- // The size of the screenItemList may change, so it is
- // critical to re-check the size on each iteration
- for (ScreenItemList::size_type i = 0; i < _screenItemList.size(); ++i) {
+ const ScreenItemList::size_type screenItemCount = _screenItemList.size();
+ for (ScreenItemList::size_type i = 0; i < screenItemCount; ++i) {
ScreenItem *item = _screenItemList[i];
if (item != nullptr) {
@@ -495,7 +518,7 @@ void Plane::decrementScreenItemArrayCounts(Plane *visiblePlane, const bool force
visiblePlane->_screenItemList.findByObject(item->_object) != nullptr
)
) {
- *visiblePlane->_screenItemList[i] = *_screenItemList[i];
+ *visiblePlane->_screenItemList[i] = *item;
}
if (item->_updated) {
@@ -514,175 +537,180 @@ void Plane::decrementScreenItemArrayCounts(Plane *visiblePlane, const bool force
if (item->_deleted) {
item->_deleted--;
if (!item->_deleted) {
- visiblePlane->_screenItemList.erase_at(i);
+ if (visiblePlane != nullptr && visiblePlane->_screenItemList.findByObject(item->_object) != nullptr) {
+ visiblePlane->_screenItemList.erase_at(i);
+ }
_screenItemList.erase_at(i);
}
}
}
}
+
+ _screenItemList.pack();
+ if (visiblePlane != nullptr) {
+ visiblePlane->_screenItemList.pack();
+ }
}
-void Plane::filterDownEraseRects(DrawList &drawList, RectList &eraseList, RectList &transparentEraseList) const {
+void Plane::filterDownEraseRects(DrawList &drawList, RectList &eraseList, RectList &higherEraseList) const {
+ const RectList::size_type higherEraseCount = higherEraseList.size();
+
if (_type == kPlaneTypeTransparent) {
- for (RectList::size_type i = 0; i < transparentEraseList.size(); ++i) {
- const Common::Rect *r = transparentEraseList[i];
- for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) {
- ScreenItem *item = _screenItemList[j];
- if (item != nullptr) {
- if (r->intersects(item->_screenRect)) {
- mergeToDrawList(j, *r, drawList);
- }
+ for (RectList::size_type i = 0; i < higherEraseCount; ++i) {
+ const Common::Rect &r = *higherEraseList[i];
+ const ScreenItemList::size_type screenItemCount = _screenItemList.size();
+ for (ScreenItemList::size_type j = 0; j < screenItemCount; ++j) {
+ const ScreenItem *item = _screenItemList[j];
+ if (item != nullptr && r.intersects(item->_screenRect)) {
+ mergeToDrawList(j, r, drawList);
}
}
}
} else {
- for (RectList::size_type i = 0; i < transparentEraseList.size(); ++i) {
- Common::Rect *r = transparentEraseList[i];
- if (r->intersects(_screenRect)) {
- r->clip(_screenRect);
- mergeToRectList(*r, eraseList);
-
- for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) {
- ScreenItem *item = _screenItemList[j];
-
- if (item != nullptr) {
- if (r->intersects(item->_screenRect)) {
- mergeToDrawList(j, *r, drawList);
- }
+ for (RectList::size_type i = 0; i < higherEraseCount; ++i) {
+ Common::Rect r = *higherEraseList[i];
+ if (r.intersects(_screenRect)) {
+ r.clip(_screenRect);
+ mergeToRectList(r, eraseList);
+
+ const ScreenItemList::size_type screenItemCount = _screenItemList.size();
+ for (ScreenItemList::size_type j = 0; j < screenItemCount; ++j) {
+ const ScreenItem *item = _screenItemList[j];
+ if (item != nullptr && r.intersects(item->_screenRect)) {
+ mergeToDrawList(j, r, drawList);
}
}
- Common::Rect ptr[4];
- const Common::Rect *r2 = transparentEraseList[i];
- int count = splitRects(*r2, *r, ptr);
- for (int k = count - 1; k >= 0; --k) {
- transparentEraseList.add(ptr[k]);
+ Common::Rect outRects[4];
+ const Common::Rect &r2 = *higherEraseList[i];
+ int splitCount = splitRects(r2, r, outRects);
+ while (splitCount--) {
+ higherEraseList.add(outRects[splitCount]);
}
- transparentEraseList.erase_at(i);
+ higherEraseList.erase_at(i);
}
}
- transparentEraseList.pack();
+ higherEraseList.pack();
}
}
-void Plane::filterUpDrawRects(DrawList &transparentDrawList, const DrawList &drawList) const {
- for (DrawList::size_type i = 0; i < drawList.size(); ++i) {
- const Common::Rect &r = drawList[i]->rect;
-
- for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) {
- ScreenItem *item = _screenItemList[j];
- if (item != nullptr) {
- if (r.intersects(item->_screenRect)) {
- mergeToDrawList(j, r, transparentDrawList);
- }
+void Plane::filterUpDrawRects(DrawList &drawList, const DrawList &lowerDrawList) const {
+ const DrawList::size_type lowerDrawCount = lowerDrawList.size();
+ for (DrawList::size_type i = 0; i < lowerDrawCount; ++i) {
+ const Common::Rect &r = lowerDrawList[i]->rect;
+ const ScreenItemList::size_type screenItemCount = _screenItemList.size();
+ for (ScreenItemList::size_type j = 0; j < screenItemCount; ++j) {
+ const ScreenItem *item = _screenItemList[j];
+ if (item != nullptr && r.intersects(item->_screenRect)) {
+ mergeToDrawList(j, r, drawList);
}
}
}
}
-void Plane::filterUpEraseRects(DrawList &drawList, RectList &eraseList) const {
- for (RectList::size_type i = 0; i < eraseList.size(); ++i) {
- const Common::Rect &r = *eraseList[i];
- for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) {
- ScreenItem *item = _screenItemList[j];
-
- if (item != nullptr) {
- if (r.intersects(item->_screenRect)) {
- mergeToDrawList(j, r, drawList);
- }
+void Plane::filterUpEraseRects(DrawList &drawList, const RectList &lowerEraseList) const {
+ const RectList::size_type lowerEraseCount = lowerEraseList.size();
+ for (RectList::size_type i = 0; i < lowerEraseCount; ++i) {
+ const Common::Rect &r = *lowerEraseList[i];
+ const ScreenItemList::size_type screenItemCount = _screenItemList.size();
+ for (ScreenItemList::size_type j = 0; j < screenItemCount; ++j) {
+ const ScreenItem *item = _screenItemList[j];
+ if (item != nullptr && r.intersects(item->_screenRect)) {
+ mergeToDrawList(j, r, drawList);
}
}
}
}
void Plane::mergeToDrawList(const ScreenItemList::size_type index, const Common::Rect &rect, DrawList &drawList) const {
- RectList rects;
-
- ScreenItem *item = _screenItemList[index];
- Common::Rect r = item->_screenRect;
+ RectList mergeList;
+ ScreenItem &item = *_screenItemList[index];
+ Common::Rect r = item._screenRect;
r.clip(rect);
- rects.add(r);
+ mergeList.add(r);
- for (RectList::size_type i = 0; i < rects.size(); ++i) {
- r = *rects[i];
+ for (RectList::size_type i = 0; i < mergeList.size(); ++i) {
+ r = *mergeList[i];
- for (DrawList::size_type j = 0; j < drawList.size(); ++j) {
- const DrawItem *drawitem = drawList[j];
- if (item->_object == drawitem->screenItem->_object) {
- if (drawitem->rect.contains(r)) {
- rects.erase_at(i);
+ const DrawList::size_type drawCount = drawList.size();
+ for (DrawList::size_type j = 0; j < drawCount; ++j) {
+ const DrawItem &drawItem = *drawList[j];
+ if (item._object == drawItem.screenItem->_object) {
+ if (drawItem.rect.contains(r)) {
+ mergeList.erase_at(i);
break;
}
Common::Rect outRects[4];
- const int count = splitRects(r, drawitem->rect, outRects);
- if (count != -1) {
- for (int k = count - 1; k >= 0; --k) {
- rects.add(outRects[k]);
+ int splitCount = splitRects(r, drawItem.rect, outRects);
+ if (splitCount != -1) {
+ while (splitCount--) {
+ mergeList.add(outRects[splitCount]);
}
- rects.erase_at(i);
+ mergeList.erase_at(i);
// proceed to the next rect
- r = *rects[++i];
+ r = *mergeList[++i];
}
}
}
}
- rects.pack();
+ mergeList.pack();
- for (RectList::size_type i = 0; i < rects.size(); ++i) {
- drawList.add(item, *rects[i]);
+ for (RectList::size_type i = 0; i < mergeList.size(); ++i) {
+ drawList.add(&item, *mergeList[i]);
}
}
-void Plane::mergeToRectList(const Common::Rect &rect, RectList &rectList) const {
- RectList temp;
- temp.add(rect);
+void Plane::mergeToRectList(const Common::Rect &rect, RectList &eraseList) const {
+ RectList mergeList;
+ Common::Rect r;
+ mergeList.add(rect);
- for (RectList::size_type i = 0; i < temp.size(); ++i) {
- Common::Rect r = *temp[i];
+ for (RectList::size_type i = 0; i < mergeList.size(); ++i) {
+ r = *mergeList[i];
- for (RectList::size_type j = 0; j < rectList.size(); ++j) {
- const Common::Rect *innerRect = rectList[j];
- if (innerRect->contains(r)) {
- temp.erase_at(i);
+ const RectList::size_type eraseCount = eraseList.size();
+ for (RectList::size_type j = 0; j < eraseCount; ++j) {
+ const Common::Rect &eraseRect = *eraseList[j];
+ if (eraseRect.contains(r)) {
+ mergeList.erase_at(i);
break;
}
- Common::Rect out[4];
- const int count = splitRects(r, *innerRect, out);
- if (count != -1) {
- for (int k = count - 1; k >= 0; --k) {
- temp.add(out[k]);
+ Common::Rect outRects[4];
+ int splitCount = splitRects(r, eraseRect, outRects);
+ if (splitCount != -1) {
+ while (splitCount--) {
+ mergeList.add(outRects[splitCount]);
}
- temp.erase_at(i);
+ mergeList.erase_at(i);
// proceed to the next rect
- r = *temp[++i];
+ r = *mergeList[++i];
}
}
}
- temp.pack();
+ mergeList.pack();
- for (RectList::size_type i = 0; i < temp.size(); ++i) {
- rectList.add(*temp[i]);
+ for (RectList::size_type i = 0; i < mergeList.size(); ++i) {
+ eraseList.add(*mergeList[i]);
}
}
void Plane::redrawAll(Plane *visiblePlane, const PlaneList &planeList, DrawList &drawList, RectList &eraseList) {
- for (ScreenItemList::const_iterator screenItemPtr = _screenItemList.begin(); screenItemPtr != _screenItemList.end(); ++screenItemPtr) {
- if (*screenItemPtr != nullptr) {
- ScreenItem &screenItem = **screenItemPtr;
- if (!screenItem._deleted) {
- screenItem.calcRects(*this);
- if (!screenItem._screenRect.isEmpty()) {
- drawList.add(&screenItem, screenItem._screenRect);
- }
+ const ScreenItemList::size_type screenItemCount = _screenItemList.size();
+ for (ScreenItemList::size_type i = 0; i < screenItemCount; ++i) {
+ ScreenItem *screenItem = _screenItemList[i];
+ if (screenItem != nullptr && !screenItem->_deleted) {
+ screenItem->calcRects(*this);
+ if (!screenItem->_screenRect.isEmpty()) {
+ mergeToDrawList(i, screenItem->_screenRect, drawList);
}
}
}
@@ -696,10 +724,6 @@ void Plane::redrawAll(Plane *visiblePlane, const PlaneList &planeList, DrawList
breakDrawListByPlanes(drawList, planeList);
--_redrawAllCount;
decrementScreenItemArrayCounts(visiblePlane, true);
- _screenItemList.pack();
- if (visiblePlane != nullptr) {
- visiblePlane->_screenItemList.pack();
- }
}
void Plane::setType() {
@@ -731,10 +755,12 @@ void Plane::sync(const Plane *other, const Common::Rect &screenRect) {
_planeRect.right > other->_planeRect.right ||
_planeRect.bottom > other->_planeRect.bottom
) {
+ // the plane moved or got larger
_redrawAllCount = g_sci->_gfxFrameout->getScreenCount();
- _updated = g_sci->_gfxFrameout->getScreenCount();
+ _moved = g_sci->_gfxFrameout->getScreenCount();
} else if (_planeRect != other->_planeRect) {
- _updated = g_sci->_gfxFrameout->getScreenCount();
+ // the plane got smaller
+ _moved = g_sci->_gfxFrameout->getScreenCount();
}
if (_priority != other->_priority) {
@@ -755,7 +781,7 @@ void Plane::sync(const Plane *other, const Common::Rect &screenRect) {
_deleted = 0;
if (_created == 0) {
- _moved = g_sci->_gfxFrameout->getScreenCount();
+ _updated = g_sci->_gfxFrameout->getScreenCount();
}
convertGameRectToPlaneRect();
@@ -801,18 +827,22 @@ void Plane::scrollScreenItems(const int16 deltaX, const int16 deltaY, const bool
}
void Plane::remapMarkRedraw() {
- for (ScreenItemList::const_iterator screenItemPtr = _screenItemList.begin(); screenItemPtr != _screenItemList.end(); ++screenItemPtr) {
- if (*screenItemPtr != nullptr) {
- ScreenItem &screenItem = **screenItemPtr;
- if (screenItem.getCelObj()._remap && !screenItem._deleted && !screenItem._created) {
- screenItem._updated = g_sci->_gfxFrameout->getScreenCount();
- }
+ ScreenItemList::size_type screenItemCount = _screenItemList.size();
+ for (ScreenItemList::size_type i = 0; i < screenItemCount; ++i) {
+ ScreenItem *screenItem = _screenItemList[i];
+ if (
+ screenItem != nullptr &&
+ !screenItem->_deleted && !screenItem->_created &&
+ screenItem->getCelObj()._remap
+ ) {
+ screenItem->_updated = g_sci->_gfxFrameout->getScreenCount();
}
}
}
#pragma mark -
#pragma mark PlaneList
+
void PlaneList::add(Plane *plane) {
for (iterator it = begin(); it != end(); ++it) {
if ((*it)->_priority > plane->_priority) {
diff --git a/engines/sci/graphics/plane32.h b/engines/sci/graphics/plane32.h
index c93fb5b64e..20cff40814 100644
--- a/engines/sci/graphics/plane32.h
+++ b/engines/sci/graphics/plane32.h
@@ -62,7 +62,14 @@ public:
#pragma mark DrawList
struct DrawItem {
+ /**
+ * The screen item to draw.
+ */
ScreenItem *screenItem;
+
+ /**
+ * The target rectangle of the draw operation.
+ */
Common::Rect rect;
inline bool operator<(const DrawItem &other) const {
@@ -189,16 +196,15 @@ public:
* not match
* - `deleted` is set when the plane is deleted by a
* kernel call
- * - `moved` is set when the plane is synchronised from
- * another plane and is not already in the "created"
- * state
+ * - `moved` is set when the plane has been moved or
+ * resized
*/
int _created, _updated, _deleted, _moved;
/**
* The vanishing point for the plane. Used when
- * calculating the correct scaling of the plane's screen
- * items according to their position.
+ * automatically calculating the correct scaling of the
+ * plane's screen items according to their position.
*/
Common::Point _vanishingPoint;
@@ -358,42 +364,33 @@ public:
private:
/**
* Splits all rects in the given draw list at the edges
- * of all non-transparent planes above the current
- * plane.
+ * of all higher-priority, non-transparent, intersecting
+ * planes.
*/
void breakDrawListByPlanes(DrawList &drawList, const PlaneList &planeList) const;
/**
- * Splits all rects in the given erase list rects at the
- * edges of all non-transparent planes above the current
- * plane.
+ * Splits all rects in the given erase list at the
+ * edges of higher-priority, non-transparent,
+ * intersecting planes.
*/
void breakEraseListByPlanes(RectList &eraseList, const PlaneList &planeList) const;
/**
- * Synchronises changes to screen items from the current
- * plane to the visible plane and deletes screen items
- * from the current plane that have been marked as
- * deleted. If `forceUpdate` is true, all screen items
- * on the visible plane will be updated, even if they
- * are not marked as having changed.
- */
- void decrementScreenItemArrayCounts(Plane *visiblePlane, const bool forceUpdate);
-
- /**
- * Merges the screen item from this plane at the given
- * index into the given draw list, clipped to the given
- * rect. TODO: Finish documenting
+ * Adds the screen item at `index` into `drawList`,
+ * ensuring it is only drawn within the bounds of
+ * `rect`. If an existing draw list entry exists
+ * for this screen item, it will be modified.
+ * Otherwise, a new entry will be added.
*/
void mergeToDrawList(const DrawList::size_type index, const Common::Rect &rect, DrawList &drawList) const;
/**
- * Adds the given rect into the given rect list,
- * merging it with other rects already inside the list,
- * if possible, to avoid overdraw. TODO: Finish
- * documenting
+ * Merges `rect` with an existing rect in `eraseList`,
+ * if possible. Otherwise, adds the rect as a new entry
+ * to `eraseList`.
*/
- void mergeToRectList(const Common::Rect &rect, RectList &rectList) const;
+ void mergeToRectList(const Common::Rect &rect, RectList &eraseList) const;
public:
/**
@@ -406,19 +403,73 @@ public:
void calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList &drawList, RectList &eraseList);
/**
- * TODO: Documentation
+ * Synchronises changes to screen items from the current
+ * plane to the visible plane and deletes screen items
+ * from the current plane that have been marked as
+ * deleted. If `forceUpdate` is true, all screen items
+ * on the visible plane will be updated, even if they
+ * are not marked as having changed.
+ */
+ void decrementScreenItemArrayCounts(Plane *visiblePlane, const bool forceUpdate);
+
+ /**
+ * This method is called from the highest priority plane
+ * to the lowest priority plane.
+ *
+ * Adds screen items from this plane to the draw list
+ * that must be redrawn because they intersect entries
+ * in the `higherEraseList`.
+ *
+ * If this plane is opaque, all intersecting erase rects
+ * in `lowerEraseList` are removed, as they would be
+ * completely overwritten by the contents of this plane.
+ *
+ * If this plane is transparent, erase rects from the
+ * `lowerEraseList` are added to the erase list for this
+ * plane, so that lower planes.
+ *
+ * @param drawList The draw list for this plane.
+ * @param eraseList The erase list for this plane.
+ * @param higherEraseList The erase list for a plane
+ * above this plane.
*/
- void filterDownEraseRects(DrawList &drawList, RectList &eraseList, RectList &transparentEraseList) const;
+ void filterDownEraseRects(DrawList &drawList, RectList &eraseList, RectList &higherEraseList) const;
/**
- * TODO: Documentation
+ * This method is called from the lowest priority plane
+ * to the highest priority plane.
+ *
+ * Adds screen items from this plane to the draw list
+ * that must be drawn because the lower plane is being
+ * redrawn and potentially transparent screen items
+ * from this plane would draw over the lower priority
+ * plane's screen items.
+ *
+ * This method applies only to transparent planes.
+ *
+ * @param drawList The draw list for this plane.
+ * @param eraseList The erase list for a plane below
+ * this plane.
*/
- void filterUpEraseRects(DrawList &drawList, RectList &eraseList) const;
+ void filterUpEraseRects(DrawList &drawList, const RectList &lowerEraseList) const;
/**
- * TODO: Documentation
+ * This method is called from the lowest priority plane
+ * to the highest priority plane.
+ *
+ * Adds screen items from this plane to the draw list
+ * that must be drawn because the lower plane is being
+ * redrawn and potentially transparent screen items
+ * from this plane would draw over the lower priority
+ * plane's screen items.
+ *
+ * This method applies only to transparent planes.
+ *
+ * @param drawList The draw list for this plane.
+ * @param lowerDrawList The draw list for a plane below
+ * this plane.
*/
- void filterUpDrawRects(DrawList &transparentDrawList, const DrawList &drawList) const;
+ void filterUpDrawRects(DrawList &drawList, const DrawList &lowerDrawList) const;
/**
* Updates all of the plane's non-deleted screen items
@@ -442,6 +493,8 @@ private:
using PlaneListBase::push_back;
public:
+ typedef int size_type;
+
// A method for finding the index of a plane inside a
// PlaneList is used because entries in the main plane
// list and visible plane list of GfxFrameout are