aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/graphics/plane32.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/graphics/plane32.cpp')
-rw-r--r--engines/sci/graphics/plane32.cpp841
1 files changed, 841 insertions, 0 deletions
diff --git a/engines/sci/graphics/plane32.cpp b/engines/sci/graphics/plane32.cpp
new file mode 100644
index 0000000000..548e7e9d17
--- /dev/null
+++ b/engines/sci/graphics/plane32.cpp
@@ -0,0 +1,841 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "sci/console.h"
+#include "sci/engine/kernel.h"
+#include "sci/engine/selector.h"
+#include "sci/engine/state.h"
+#include "sci/graphics/frameout.h"
+#include "sci/graphics/lists32.h"
+#include "sci/graphics/plane32.h"
+#include "sci/graphics/screen.h"
+#include "sci/graphics/screen_item32.h"
+
+namespace Sci {
+#pragma mark DrawList
+void DrawList::add(ScreenItem *screenItem, const Common::Rect &rect) {
+ DrawItem *drawItem = new DrawItem;
+ drawItem->screenItem = screenItem;
+ drawItem->rect = rect;
+ DrawListBase::add(drawItem);
+}
+
+#pragma mark -
+#pragma mark Plane
+uint16 Plane::_nextObjectId = 20000;
+
+Plane::Plane(const Common::Rect &gameRect) :
+_gameRect(gameRect),
+_object(make_reg(0, _nextObjectId++)),
+_back(0),
+_pictureId(kPlanePicColored),
+_mirrored(false),
+_width(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth),
+_height(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight),
+_deleted(0),
+_updated(0),
+_priorityChanged(0),
+_created(g_sci->_gfxFrameout->getScreenCount()),
+_redrawAllCount(g_sci->_gfxFrameout->getScreenCount()) {
+ convertGameRectToPlaneRect();
+ _priority = MAX(10000, g_sci->_gfxFrameout->getPlanes().getTopPlanePriority() + 1);
+ setType();
+ _screenRect = _planeRect;
+}
+
+Plane::Plane(reg_t object) :
+_object(object),
+_width(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth),
+_height(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight),
+_created(g_sci->_gfxFrameout->getScreenCount()),
+_redrawAllCount(g_sci->_gfxFrameout->getScreenCount()),
+_deleted(0),
+_updated(0),
+_priorityChanged(false),
+_moved(0) {
+ SegManager *segMan = g_sci->getEngineState()->_segMan;
+ _vanishingPoint.x = readSelectorValue(segMan, object, SELECTOR(vanishingX));
+ _vanishingPoint.y = readSelectorValue(segMan, object, SELECTOR(vanishingY));
+
+ _gameRect.left = readSelectorValue(segMan, object, SELECTOR(inLeft));
+ _gameRect.top = readSelectorValue(segMan, object, SELECTOR(inTop));
+ _gameRect.right = readSelectorValue(segMan, object, SELECTOR(inRight));
+ _gameRect.bottom = readSelectorValue(segMan, object, SELECTOR(inBottom));
+ convertGameRectToPlaneRect();
+
+ _back = readSelectorValue(segMan, object, SELECTOR(back));
+ _priority = readSelectorValue(segMan, object, SELECTOR(priority));
+ _pictureId = readSelectorValue(segMan, object, SELECTOR(picture));
+ setType();
+
+ _mirrored = readSelectorValue(segMan, object, SELECTOR(mirrored));
+ _screenRect = _planeRect;
+ changePic();
+}
+
+Plane::Plane(const Plane &other) :
+_object(other._object),
+_priority(other._priority),
+_pictureId(other._pictureId),
+_mirrored(other._mirrored),
+_back(other._back),
+_field_34(other._field_34), _field_38(other._field_38),
+_field_3C(other._field_3C), _field_40(other._field_40),
+_planeRect(other._planeRect),
+_gameRect(other._gameRect),
+_screenRect(other._screenRect),
+_screenItemList(other._screenItemList) {}
+
+void Plane::operator=(const Plane &other) {
+ _gameRect = other._gameRect;
+ _planeRect = other._planeRect;
+ _vanishingPoint = other._vanishingPoint;
+ _pictureId = other._pictureId;
+ _type = other._type;
+ _mirrored = other._mirrored;
+ _priority = other._priority;
+ _back = other._back;
+ _width = other._width;
+ _field_34 = other._field_34;
+ _height = other._height;
+ _screenRect = other._screenRect;
+ _field_3C = other._field_3C;
+ _priorityChanged = other._priorityChanged;
+}
+
+void Plane::init() {
+ _nextObjectId = 20000;
+}
+
+void Plane::convertGameRectToPlaneRect() {
+ const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
+ const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
+ const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+
+ const Ratio ratioX = Ratio(screenWidth, scriptWidth);
+ const Ratio ratioY = Ratio(screenHeight, scriptHeight);
+
+ _planeRect = _gameRect;
+ mulru(_planeRect, ratioX, ratioY, 1);
+}
+
+void Plane::printDebugInfo(Console *con) const {
+ Common::String name;
+
+ if (_object.isNumber()) {
+ name = "-scummvm-";
+ } else {
+ name = g_sci->getEngineState()->_segMan->getObjectName(_object);
+ }
+
+ con->debugPrintf("%04x:%04x (%s): type %d, prio %d, pic %d, mirror %d, back %d\n",
+ PRINT_REG(_object),
+ name.c_str(),
+ _type,
+ _priority,
+ _pictureId,
+ _mirrored,
+ _back
+ );
+ con->debugPrintf(" game rect: (%d, %d, %d, %d), plane rect: (%d, %d, %d, %d)\n screen rect: (%d, %d, %d, %d)\n",
+ PRINT_RECT(_gameRect),
+ PRINT_RECT(_planeRect),
+ PRINT_RECT(_screenRect)
+ );
+ con->debugPrintf(" # screen items: %d\n", _screenItemList.size());
+}
+
+#pragma mark -
+#pragma mark Plane - Pic
+
+void Plane::addPicInternal(const GuiResourceId pictureId, const Common::Point *position, const bool mirrorX) {
+
+ uint16 celCount = 1000;
+ for (uint16 celNo = 0; celNo < celCount; ++celNo) {
+ CelObjPic *celObj = new CelObjPic(pictureId, celNo);
+ if (celCount == 1000) {
+ celCount = celObj->_celCount;
+ }
+
+ ScreenItem *screenItem = new ScreenItem(_object, celObj->_info);
+ screenItem->_pictureId = pictureId;
+ screenItem->_mirrorX = mirrorX;
+ screenItem->_priority = celObj->_priority;
+ screenItem->_fixPriority = true;
+ if (position != nullptr) {
+ screenItem->_position = *position;
+ } else {
+ screenItem->_position = celObj->_relativePosition;
+ }
+ _screenItemList.add(screenItem);
+
+ delete screenItem->_celObj;
+ screenItem->_celObj = celObj;
+ }
+}
+
+void Plane::addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX) {
+ deletePic(pictureId);
+ addPicInternal(pictureId, &position, mirrorX);
+ // NOTE: In SCI engine this method returned the pictureId of the
+ // plane, but this return value was never used
+}
+
+void Plane::changePic() {
+ _pictureChanged = false;
+
+ if (_type != kPlaneTypePicture) {
+ return;
+ }
+
+ addPicInternal(_pictureId, nullptr, _mirrored);
+}
+
+void Plane::deletePic(const GuiResourceId pictureId) {
+ for (ScreenItemList::iterator it = _screenItemList.begin(); it != _screenItemList.end(); ++it) {
+ ScreenItem *screenItem = *it;
+ if (screenItem->_pictureId == pictureId) {
+ screenItem->_created = 0;
+ screenItem->_updated = 0;
+ screenItem->_deleted = g_sci->_gfxFrameout->getScreenCount();
+ }
+ }
+}
+
+void Plane::deletePic(const GuiResourceId oldPictureId, const GuiResourceId newPictureId) {
+ deletePic(oldPictureId);
+ _pictureId = newPictureId;
+}
+
+void Plane::deleteAllPics() {
+ for (ScreenItemList::iterator it = _screenItemList.begin(); it != _screenItemList.end(); ++it) {
+ ScreenItem *screenItem = *it;
+ if (screenItem != nullptr && screenItem->_celInfo.type == kCelTypePic) {
+ if (screenItem->_created == 0) {
+ screenItem->_created = 0;
+ screenItem->_updated = 0;
+ screenItem->_deleted = g_sci->_gfxFrameout->getScreenCount();
+ } else {
+ _screenItemList.erase(it);
+ }
+ }
+ }
+
+ _screenItemList.pack();
+}
+
+#pragma mark -
+#pragma mark Plane - Rendering
+
+void Plane::breakDrawListByPlanes(DrawList &drawList, const PlaneList &planeList) const {
+ int index = planeList.findIndexByObject(_object);
+
+ for (DrawList::size_type i = 0; i < drawList.size(); ++i) {
+ for (PlaneList::size_type j = index + 1; j < planeList.size(); ++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]);
+ }
+
+ drawList.erase_at(i);
+ break;
+ }
+ }
+ }
+ }
+ drawList.pack();
+}
+
+void Plane::breakEraseListByPlanes(RectList &eraseList, const PlaneList &planeList) const {
+ int index = planeList.findIndexByObject(_object);
+
+ for (RectList::size_type i = 0; i < eraseList.size(); ++i) {
+ for (PlaneList::size_type j = index + 1; j < planeList.size(); ++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]);
+ }
+
+ eraseList.erase_at(i);
+ break;
+ }
+ }
+ }
+ }
+ eraseList.pack();
+}
+
+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();
+
+ for (PlaneList::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.
+ if (i < visiblePlaneItemCount) {
+ vitem = 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) {
+ if (!vitem->_screenRect.isEmpty()) {
+ if (/* TODO: g_Remap_numActiveRemaps */ false) { // active remaps?
+ mergeToRectList(vitem->_screenRect, eraseList);
+ } else {
+ eraseList.add(vitem->_screenRect);
+ }
+ }
+ }
+ } else if (item->_created) {
+ // add item to draw list
+ item->getCelObj();
+ item->calcRects(*this);
+
+ if(!item->_screenRect.isEmpty()) {
+ if (/* TODO: g_Remap_numActiveRemaps */ false) { // active remaps?
+ 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->getCelObj();
+ item->calcRects(*this);
+ if (/* TODO: g_Remap_numActiveRemaps */ false) { // active remaps
+ // 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
+
+ // TODO: This was changed from disasm, verify please!
+ Common::Rect extendedScreenItem = vitem->_screenRect;
+ extendedScreenItem.extend(item->_screenRect);
+ drawList.add(item, item->_screenRect);
+ mergeToRectList(extendedScreenItem, 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);
+ }
+ if (i < visiblePlaneItemCount && vitem != nullptr && !vitem->_screenRect.isEmpty()) {
+ eraseList.add(vitem->_screenRect);
+ }
+ }
+ }
+ }
+ }
+
+ breakEraseListByPlanes(eraseList, planeList);
+ breakDrawListByPlanes(drawList, planeList);
+
+ if (/* TODO: dword_C6288 */ false) { // "high resolution pictures"????
+ _screenItemList.sort();
+ bool encounteredPic = false;
+ bool v81 = false;
+
+ for (RectList::size_type i = 0; i < eraseList.size(); ++i) {
+ Common::Rect *rect = eraseList[i];
+
+ for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) {
+ ScreenItem *item = _screenItemList[j];
+
+ if (j < _screenItemList.size() && item != nullptr) {
+ if (rect->intersects(item->_screenRect)) {
+ 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;
+ }
+ } else {
+ if (!item->_updated && !item->_created) {
+ drawList.add(item, intersection);
+ }
+ if (item->_celInfo.type == kCelTypePic) {
+ encounteredPic = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ _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) {
+ ScreenItem *item = _screenItemList[j];
+ if (j < _screenItemList.size() && item != nullptr && !item->_updated && !item->_deleted && !item->_created && eraseList[i]->intersects(item->_screenRect)) {
+ drawList.add(item, eraseList[i]->findIntersectingRect(item->_screenRect));
+ }
+ }
+ }
+ }
+ if (/* TODO: g_Remap_numActiveRemaps */ false) { // no remaps active?
+ // Add all items that overlap with items in the drawlist and have higher
+ // priority
+ for (DrawList::size_type i = 0; i < drawList.size(); ++i) {
+ DrawItem *dli = drawList[i];
+
+ for (PlaneList::size_type j = 0; j < planeItemCount; ++j) {
+ ScreenItem *sli = _screenItemList[j];
+
+ if (i < drawList.size() && dli) {
+ if (j < _screenItemList.size() && sli) {
+ if (!sli->_updated && !sli->_deleted && !sli->_created) {
+ ScreenItem *item = dli->screenItem;
+ if (sli->_priority > item->_priority || (sli->_priority == item->_priority && sli->_object > item->_object)) {
+ if (dli->rect.intersects(sli->_screenRect)) {
+ drawList.add(sli, dli->rect.findIntersectingRect(sli->_screenRect));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ 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) {
+ ScreenItem *item = _screenItemList[i];
+
+ if (item != nullptr) {
+ // update item in visiblePlane if item is updated
+ if (
+ item->_updated ||
+ (
+ forceUpdate &&
+ visiblePlane != nullptr &&
+ Common::find(visiblePlane->_screenItemList.begin(), visiblePlane->_screenItemList.end(), item) != visiblePlane->_screenItemList.end()
+ )
+ ) {
+ *visiblePlane->_screenItemList[i] = *_screenItemList[i];
+ }
+
+ if (item->_updated) {
+ item->_updated--;
+ }
+
+ // create new item in visiblePlane if item was added
+ if (item->_created) {
+ item->_created--;
+ if (visiblePlane != nullptr) {
+ ScreenItem *n = new ScreenItem(*item);
+ visiblePlane->_screenItemList.add(n);
+ }
+ }
+
+ // delete item from both planes if it was deleted
+ if (item->_deleted) {
+ item->_deleted--;
+ if (!item->_deleted) {
+ visiblePlane->_screenItemList.erase_at(i);
+ _screenItemList.erase_at(i);
+ }
+ }
+ }
+ }
+}
+
+void Plane::filterDownEraseRects(DrawList &drawList, RectList &eraseList, RectList &transparentEraseList) const {
+ if (_type == kPlaneTypeTransparent) {
+ for (RectList::size_type i = 0; i < transparentEraseList.size(); ++i) {
+ 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);
+ }
+ }
+ }
+ }
+ } 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);
+ }
+ }
+ }
+
+ Common::Rect ptr[4];
+ Common::Rect *r2 = transparentEraseList[i];
+ int count = splitRects(*r2, *r, ptr);
+ for (int k = count - 1; k >= 0; --k) {
+ transparentEraseList.add(ptr[k]);
+ }
+ transparentEraseList.erase_at(i);
+ }
+ }
+
+ transparentEraseList.pack();
+ }
+}
+
+void Plane::filterUpDrawRects(DrawList &transparentDrawList, const DrawList &drawList) const {
+ for (DrawList::size_type i = 0; i < drawList.size(); ++i) {
+ 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::filterUpEraseRects(DrawList &drawList, RectList &eraseList) const {
+ for (RectList::size_type i = 0; i < eraseList.size(); ++i) {
+ 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::mergeToDrawList(const DrawList::size_type index, const Common::Rect &rect, DrawList &drawList) const {
+ RectList rects;
+
+ Common::Rect r = _screenItemList[index]->_screenRect;
+ r.clip(rect);
+
+ rects.add(r);
+ ScreenItem *item = _screenItemList[index];
+
+ for (RectList::size_type i = 0; i < rects.size(); ++i) {
+ r = *rects[i];
+
+ for (DrawList::size_type j = 0; j < drawList.size(); ++j) {
+ DrawItem *drawitem = drawList[j];
+ if (item->_object == drawitem->screenItem->_object) {
+ if (drawitem->rect.contains(r)) {
+ rects.erase_at(i);
+ break;
+ }
+
+ Common::Rect outRects[4];
+ int count = splitRects(r, drawitem->rect, outRects);
+ if (count != -1) {
+ for (int k = count - 1; k >= 0; --k) {
+ rects.add(outRects[k]);
+ }
+
+ rects.erase_at(i);
+
+ // proceed to the next rect
+ r = *rects[++i];
+ }
+ }
+ }
+ }
+
+ rects.pack();
+
+ for (RectList::size_type i = 0; i < rects.size(); ++i) {
+ drawList.add(item, *rects[i]);
+ }
+}
+
+void Plane::mergeToRectList(const Common::Rect &rect, RectList &rectList) const {
+ RectList temp;
+ temp.add(rect);
+
+ for (RectList::size_type i = 0; i < temp.size(); ++i) {
+ Common::Rect *outerRect = temp[i];
+ for (RectList::size_type j = 0; j < rectList.size(); ++j) {
+ Common::Rect *innerRect = rectList[i];
+ if (innerRect->intersects(*outerRect)) {
+ Common::Rect out[4];
+ int count = splitRects(*outerRect, *innerRect, out);
+ for (int k = count - 1; k >= 0; --k) {
+ temp.add(out[k]);
+ }
+ temp.erase_at(i);
+ } else {
+ temp.erase_at(i);
+ }
+ }
+ }
+
+ temp.pack();
+
+ for (RectList::size_type i = 0; i < temp.size(); ++i) {
+ rectList.add(*temp[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.getCelObj();
+ screenItem.calcRects(*this);
+ if (!screenItem._screenRect.isEmpty()) {
+ drawList.add(&screenItem, screenItem._screenRect);
+ }
+ }
+ }
+ }
+
+ eraseList.clear();
+
+ if (!_screenRect.isEmpty() && _type != kPlaneTypePicture && _type != kPlaneTypeOpaque) {
+ eraseList.add(_screenRect);
+ }
+ breakEraseListByPlanes(eraseList, planeList);
+ breakDrawListByPlanes(drawList, planeList);
+ --_redrawAllCount;
+ decrementScreenItemArrayCounts(visiblePlane, true);
+ _screenItemList.pack();
+ if (visiblePlane != nullptr) {
+ visiblePlane->_screenItemList.pack();
+ }
+}
+
+void Plane::setType() {
+ if (_pictureId == kPlanePicOpaque) {
+ _type = kPlaneTypeOpaque;
+ } else if (_pictureId == kPlanePicTransparent) {
+ _type = kPlaneTypeTransparent;
+ } else if (_pictureId == kPlanePicColored) {
+ _type = kPlaneTypeColored;
+ } else {
+ _type = kPlaneTypePicture;
+ }
+}
+
+void Plane::sync(const Plane *other, const Common::Rect &screenRect) {
+ if (other == nullptr) {
+ if (_pictureChanged) {
+ deleteAllPics();
+ setType();
+ changePic();
+ _redrawAllCount = g_sci->_gfxFrameout->getScreenCount();
+ } else {
+ setType();
+ }
+ } else {
+ if (
+ _planeRect.top != other->_planeRect.top ||
+ _planeRect.left != other->_planeRect.left ||
+ _planeRect.right > other->_planeRect.right ||
+ _planeRect.bottom > other->_planeRect.bottom
+ ) {
+ _redrawAllCount = g_sci->_gfxFrameout->getScreenCount();
+ _updated = g_sci->_gfxFrameout->getScreenCount();
+ } else if (_planeRect != other->_planeRect) {
+ _updated = g_sci->_gfxFrameout->getScreenCount();
+ }
+
+ if (_priority != other->_priority) {
+ _priorityChanged = g_sci->_gfxFrameout->getScreenCount();
+ }
+
+ if (_pictureId != other->_pictureId || _mirrored != other->_mirrored || _pictureChanged) {
+ deleteAllPics();
+ setType();
+ changePic();
+ _redrawAllCount = g_sci->_gfxFrameout->getScreenCount();
+ }
+
+ if (_back != other->_back) {
+ _redrawAllCount = g_sci->_gfxFrameout->getScreenCount();
+ }
+ }
+
+ _deleted = 0;
+ if (_created == 0) {
+ _moved = g_sci->_gfxFrameout->getScreenCount();
+ }
+
+ convertGameRectToPlaneRect();
+ _width = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ _height = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+ _screenRect = _planeRect;
+ // NOTE: screenRect originally was retrieved through globals
+ // instead of being passed into the function
+ clipScreenRect(screenRect);
+}
+
+void Plane::update(const reg_t object) {
+ SegManager *segMan = g_sci->getEngineState()->_segMan;
+ _vanishingPoint.x = readSelectorValue(segMan, object, SELECTOR(vanishingX));
+ _vanishingPoint.y = readSelectorValue(segMan, object, SELECTOR(vanishingY));
+ _gameRect.left = readSelectorValue(segMan, object, SELECTOR(inLeft));
+ _gameRect.top = readSelectorValue(segMan, object, SELECTOR(inTop));
+ _gameRect.right = readSelectorValue(segMan, object, SELECTOR(inRight));
+ _gameRect.bottom = readSelectorValue(segMan, object, SELECTOR(inBottom));
+ convertGameRectToPlaneRect();
+
+ _priority = readSelectorValue(segMan, object, SELECTOR(priority));
+ GuiResourceId pictureId = readSelectorValue(segMan, object, SELECTOR(picture));
+ if (_pictureId != pictureId) {
+ _pictureId = pictureId;
+ _pictureChanged = true;
+ }
+
+ _mirrored = readSelectorValue(segMan, object, SELECTOR(mirrored));
+ _back = readSelectorValue(segMan, object, SELECTOR(back));
+}
+
+#pragma mark -
+#pragma mark PlaneList
+void PlaneList::clear() {
+ for (iterator it = begin(); it != end(); ++it) {
+ delete *it;
+ }
+
+ PlaneListBase::clear();
+}
+
+void PlaneList::erase(Plane *plane) {
+ for (iterator it = begin(); it != end(); ++it) {
+ if (*it == plane) {
+ erase(it);
+ break;
+ }
+ }
+}
+
+int PlaneList::findIndexByObject(const reg_t object) const {
+ for (size_type i = 0; i < size(); ++i) {
+ if ((*this)[i] != nullptr && (*this)[i]->_object == object) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+Plane *PlaneList::findByObject(const reg_t object) const {
+ const_iterator planeIt = Common::find_if(begin(), end(), FindByObject<Plane *>(object));
+
+ if (planeIt == end()) {
+ return nullptr;
+ }
+
+ return *planeIt;
+}
+
+int16 PlaneList::getTopPlanePriority() const {
+ if (size() > 0) {
+ return (*this)[size() - 1]->_priority;
+ }
+
+ return 0;
+}
+
+int16 PlaneList::getTopSciPlanePriority() const {
+ int16 priority = 0;
+
+ for (const_iterator it = begin(); it != end(); ++it) {
+ if ((*it)->_priority >= 10000) {
+ break;
+ }
+
+ priority = (*it)->_priority;
+ }
+
+ return priority;
+}
+
+void PlaneList::add(Plane *plane) {
+ for (iterator it = begin(); it != end(); ++it) {
+ if ((*it)->_priority < plane->_priority) {
+ insert(it, plane);
+ return;
+ }
+ }
+
+ push_back(plane);
+}
+
+}