diff options
Diffstat (limited to 'engines/sci/graphics/plane32.cpp')
-rw-r--r-- | engines/sci/graphics/plane32.cpp | 730 |
1 files changed, 427 insertions, 303 deletions
diff --git a/engines/sci/graphics/plane32.cpp b/engines/sci/graphics/plane32.cpp index d0de5b5917..aa8cd52d42 100644 --- a/engines/sci/graphics/plane32.cpp +++ b/engines/sci/graphics/plane32.cpp @@ -21,12 +21,14 @@ */ #include "sci/console.h" +#include "sci/engine/features.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/remap32.h" #include "sci/graphics/screen.h" #include "sci/graphics/screen_item32.h" @@ -42,19 +44,21 @@ void DrawList::add(ScreenItem *screenItem, const Common::Rect &rect) { #pragma mark - #pragma mark Plane uint16 Plane::_nextObjectId = 20000; +uint32 Plane::_nextCreationId = 0; -Plane::Plane(const Common::Rect &gameRect) : -_width(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth), -_height(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight), -_pictureId(kPlanePicColored), +Plane::Plane(const Common::Rect &gameRect, PlanePictureCodes pictureId) : +_creationId(_nextCreationId++), +_pictureId(pictureId), _mirrored(false), +_type(kPlaneTypeColored), _back(0), -_priorityChanged(0), +_priorityChanged(false), _object(make_reg(0, _nextObjectId++)), _redrawAllCount(g_sci->_gfxFrameout->getScreenCount()), _created(g_sci->_gfxFrameout->getScreenCount()), _updated(0), _deleted(0), +_moved(0), _gameRect(gameRect) { convertGameRectToPlaneRect(); _priority = MAX(10000, g_sci->_gfxFrameout->getPlanes().getTopPlanePriority() + 1); @@ -63,8 +67,8 @@ _gameRect(gameRect) { } Plane::Plane(reg_t object) : -_width(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth), -_height(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight), +_creationId(_nextCreationId++), +_type(kPlaneTypeColored), _priorityChanged(false), _object(object), _redrawAllCount(g_sci->_gfxFrameout->getScreenCount()), @@ -76,10 +80,17 @@ _moved(0) { _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)) + 1; - _gameRect.bottom = readSelectorValue(segMan, object, SELECTOR(inBottom)) + 1; + if (g_sci->_features->usesAlternateSelectors()) { + _gameRect.left = readSelectorValue(segMan, object, SELECTOR(left)); + _gameRect.top = readSelectorValue(segMan, object, SELECTOR(top)); + _gameRect.right = readSelectorValue(segMan, object, SELECTOR(right)) + 1; + _gameRect.bottom = readSelectorValue(segMan, object, SELECTOR(bottom)) + 1; + } else { + _gameRect.left = readSelectorValue(segMan, object, SELECTOR(inLeft)); + _gameRect.top = readSelectorValue(segMan, object, SELECTOR(inTop)); + _gameRect.right = readSelectorValue(segMan, object, SELECTOR(inRight)) + 1; + _gameRect.bottom = readSelectorValue(segMan, object, SELECTOR(inBottom)) + 1; + } convertGameRectToPlaneRect(); _back = readSelectorValue(segMan, object, SELECTOR(back)); @@ -93,10 +104,10 @@ _moved(0) { } Plane::Plane(const Plane &other) : +_creationId(other._creationId), _pictureId(other._pictureId), _mirrored(other._mirrored), -_field_34(other._field_34), _field_38(other._field_38), -_field_3C(other._field_3C), _field_40(other._field_40), +_type(other._type), _back(other._back), _object(other._object), _priority(other._priority), @@ -106,6 +117,7 @@ _screenRect(other._screenRect), _screenItemList(other._screenItemList) {} void Plane::operator=(const Plane &other) { + _creationId = other._creationId; _gameRect = other._gameRect; _planeRect = other._planeRect; _vanishingPoint = other._vanishingPoint; @@ -114,16 +126,13 @@ void Plane::operator=(const Plane &other) { _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; + _nextCreationId = 0; } void Plane::convertGameRectToPlaneRect() { @@ -136,7 +145,7 @@ void Plane::convertGameRectToPlaneRect() { const Ratio ratioY = Ratio(screenHeight, scriptHeight); _planeRect = _gameRect; - mulru(_planeRect, ratioX, ratioY); + mulru(_planeRect, ratioX, ratioY, 1); } void Plane::printDebugInfo(Console *con) const { @@ -148,11 +157,12 @@ void Plane::printDebugInfo(Console *con) const { name = g_sci->getEngineState()->_segMan->getObjectName(_object); } - con->debugPrintf("%04x:%04x (%s): type %d, prio %d, pic %d, mirror %d, back %d\n", + con->debugPrintf("%04x:%04x (%s): type %d, prio %d, ins %u, pic %d, mirror %d, back %d\n", PRINT_REG(_object), name.c_str(), _type, _priority, + _creationId, _pictureId, _mirrored, _back @@ -171,17 +181,21 @@ void Plane::printDebugInfo(Console *con) const { void Plane::addPicInternal(const GuiResourceId pictureId, const Common::Point *position, const bool mirrorX) { uint16 celCount = 1000; + bool transparent = true; for (uint16 celNo = 0; celNo < celCount; ++celNo) { CelObjPic *celObj = new CelObjPic(pictureId, celNo); if (celCount == 1000) { celCount = celObj->_celCount; } + if (!celObj->_transparent) { + transparent = false; + } ScreenItem *screenItem = new ScreenItem(_object, celObj->_info); screenItem->_pictureId = pictureId; screenItem->_mirrorX = mirrorX; screenItem->_priority = celObj->_priority; - screenItem->_fixPriority = true; + screenItem->_fixedPriority = true; if (position != nullptr) { screenItem->_position = *position + celObj->_relativePosition; } else { @@ -192,19 +206,21 @@ void Plane::addPicInternal(const GuiResourceId pictureId, const Common::Point *p delete screenItem->_celObj; screenItem->_celObj = celObj; } + _type = (g_sci->_features->hasTransparentPicturePlanes() && transparent) ? kPlaneTypeTransparentPicture : kPlaneTypePicture; } -void Plane::addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX) { - deletePic(pictureId); +GuiResourceId Plane::addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX, const bool deleteDuplicate) { + if (deleteDuplicate) { + 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 + return _pictureId; } void Plane::changePic() { _pictureChanged = false; - if (_type != kPlaneTypePicture) { + if (_type != kPlaneTypePicture && _type != kPlaneTypeTransparentPicture) { return; } @@ -247,17 +263,23 @@ void Plane::deleteAllPics() { #pragma mark - #pragma mark Plane - Rendering +extern int splitRects(Common::Rect r, const Common::Rect &other, Common::Rect(&outRects)[4]); + 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) { - 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]); + for (PlaneList::size_type j = nextPlaneIndex; j < planeCount; ++j) { + if ( + planeList[j]->_type != kPlaneTypeTransparent && + planeList[j]->_type != kPlaneTypeTransparentPicture + ) { + 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); @@ -270,17 +292,20 @@ 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) { - 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]); + for (PlaneList::size_type j = nextPlaneIndex; j < planeCount; ++j) { + if ( + planeList[j]->_type != kPlaneTypeTransparent && + planeList[j]->_type != kPlaneTypeTransparentPicture + ) { + 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); @@ -293,85 +318,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 (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. + 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) { - 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); - } + // 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()) { + mergeToRectList(visibleItemScreenRect, eraseList); + } else { + eraseList.add(visibleItemScreenRect); } - } 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); - } + } + } + + if (!item->_created && !item->_updated) { + continue; + } + + 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); } } } @@ -381,39 +430,47 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList breakEraseListByPlanes(eraseList, planeList); breakDrawListByPlanes(drawList, planeList); - if (/* TODO: dword_C6288 */ false) { // "high resolution pictures"???? + // 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(); + + // 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) { - 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)) { - 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; } } } @@ -423,35 +480,52 @@ 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 (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 ( + item != nullptr && + !item->_created && !item->_updated && !item->_deleted && + rect.intersects(item->_screenRect) + ) { + drawList.add(item, rect.findIntersectingRect(item->_screenRect)); } } } } - if (/* TODO: g_Remap_numActiveRemaps */ false) { // no remaps active? + + if (g_sci->_gfxRemap32->getRemapCount() == 0) { // 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)); - } - } - } + // priority. + + // We only loop over "primary" items in the draw list, skipping + // 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) { + const DrawItem *drawListEntry = nullptr; + if (i < drawList.size()) { + drawListEntry = drawList[i]; + } + + for (ScreenItemList::size_type j = 0; j < screenItemCount; ++j) { + ScreenItem *newItem = nullptr; + if (j < _screenItemList.size()) { + newItem = _screenItemList[j]; + } + + if ( + drawListEntry != nullptr && newItem != nullptr && + !newItem->_created && !newItem->_updated && !newItem->_deleted + ) { + const ScreenItem *drawnItem = drawListEntry->screenItem; + + if ( + (newItem->_priority > drawnItem->_priority || (newItem->_priority == drawnItem->_priority && newItem->_creationId > drawnItem->_creationId)) && + drawListEntry->rect.intersects(newItem->_screenRect) + ) { + mergeToDrawList(j, drawListEntry->rect.findIntersectingRect(newItem->_screenRect), drawList); } } } @@ -459,27 +533,18 @@ 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) { // update item in visiblePlane if item is updated - if ( - item->_updated || - ( - forceUpdate && - visiblePlane != nullptr && - visiblePlane->_screenItemList.findByObject(item->_object) != nullptr - ) - ) { - *visiblePlane->_screenItemList[i] = *_screenItemList[i]; + if (visiblePlane != nullptr && ( + item->_updated || (forceUpdate && visiblePlane->_screenItemList.findByObject(item->_object) != nullptr))) { + *visiblePlane->_screenItemList[i] = *item; } if (item->_updated) { @@ -490,8 +555,7 @@ void Plane::decrementScreenItemArrayCounts(Plane *visiblePlane, const bool force if (item->_created) { item->_created--; if (visiblePlane != nullptr) { - ScreenItem *n = new ScreenItem(*item); - visiblePlane->_screenItemList.add(n); + visiblePlane->_screenItemList.add(new ScreenItem(*item)); } } @@ -499,177 +563,182 @@ 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 { - 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); - } +void Plane::filterDownEraseRects(DrawList &drawList, RectList &eraseList, RectList &higherEraseList) const { + const RectList::size_type higherEraseCount = higherEraseList.size(); + + if (_type == kPlaneTypeTransparent || _type == kPlaneTypeTransparentPicture) { + 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]; - 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); + if (splitCount > 0) { + 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) { - 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) { - 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 DrawList::size_type index, const Common::Rect &rect, DrawList &drawList) const { - RectList rects; - - Common::Rect r = _screenItemList[index]->_screenRect; +void Plane::mergeToDrawList(const ScreenItemList::size_type index, const Common::Rect &rect, DrawList &drawList) const { + RectList mergeList; + ScreenItem &item = *_screenItemList[index]; + Common::Rect r = item._screenRect; r.clip(rect); + mergeList.add(r); - rects.add(r); - ScreenItem *item = _screenItemList[index]; + for (RectList::size_type i = 0; i < mergeList.size(); ++i) { + r = *mergeList[i]; - 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); + 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]; - 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) { - 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]; - 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.getCelObj(); - 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); } } } @@ -683,21 +752,30 @@ 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() { - if (_pictureId == kPlanePicOpaque) { - _type = kPlaneTypeOpaque; - } else if (_pictureId == kPlanePicTransparent) { - _type = kPlaneTypeTransparent; - } else if (_pictureId == kPlanePicColored) { + switch (_pictureId) { + case kPlanePicColored: _type = kPlaneTypeColored; - } else { - _type = kPlaneTypePicture; + break; + case kPlanePicTransparent: + _type = kPlaneTypeTransparent; + break; + case kPlanePicOpaque: + _type = kPlaneTypeOpaque; + break; + case kPlanePicTransparentPicture: + if (g_sci->_features->hasTransparentPicturePlanes()) { + _type = kPlaneTypeTransparentPicture; + break; + } + // fall through for games without transparent picture planes + default: + if (!g_sci->_features->hasTransparentPicturePlanes() || _type != kPlaneTypeTransparentPicture) { + _type = kPlaneTypePicture; + } + break; } } @@ -718,10 +796,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) { @@ -742,12 +822,10 @@ 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(); - _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 @@ -758,10 +836,18 @@ 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)) + 1; - _gameRect.bottom = readSelectorValue(segMan, object, SELECTOR(inBottom)) + 1; + + if (g_sci->_features->usesAlternateSelectors()) { + _gameRect.left = readSelectorValue(segMan, object, SELECTOR(left)); + _gameRect.top = readSelectorValue(segMan, object, SELECTOR(top)); + _gameRect.right = readSelectorValue(segMan, object, SELECTOR(right)) + 1; + _gameRect.bottom = readSelectorValue(segMan, object, SELECTOR(bottom)) + 1; + } else { + _gameRect.left = readSelectorValue(segMan, object, SELECTOR(inLeft)); + _gameRect.top = readSelectorValue(segMan, object, SELECTOR(inTop)); + _gameRect.right = readSelectorValue(segMan, object, SELECTOR(inRight)) + 1; + _gameRect.bottom = readSelectorValue(segMan, object, SELECTOR(inBottom)) + 1; + } convertGameRectToPlaneRect(); _priority = readSelectorValue(segMan, object, SELECTOR(priority)); @@ -775,8 +861,48 @@ void Plane::update(const reg_t object) { _back = readSelectorValue(segMan, object, SELECTOR(back)); } +void Plane::scrollScreenItems(const int16 deltaX, const int16 deltaY, const bool scrollPics) { + _redrawAllCount = g_sci->_gfxFrameout->getScreenCount(); + + for (ScreenItemList::iterator it = _screenItemList.begin(); it != _screenItemList.end(); ++it) { + if (*it != nullptr) { + ScreenItem &screenItem = **it; + if (!screenItem._deleted && (screenItem._celInfo.type != kCelTypePic || scrollPics)) { + screenItem._position.x += deltaX; + screenItem._position.y += deltaY; + } + } + } +} + +void Plane::remapMarkRedraw() { + 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) { + insert(it, plane); + return; + } + } + + push_back(plane); +} + void PlaneList::clear() { for (iterator it = begin(); it != end(); ++it) { delete *it; @@ -794,6 +920,11 @@ void PlaneList::erase(Plane *plane) { } } +PlaneList::iterator PlaneList::erase(iterator it) { + delete *it; + return PlaneListBase::erase(it); +} + int PlaneList::findIndexByObject(const reg_t object) const { for (size_type i = 0; i < size(); ++i) { if ((*this)[i] != nullptr && (*this)[i]->_object == object) { @@ -836,15 +967,8 @@ int16 PlaneList::getTopSciPlanePriority() const { 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); +void PlaneList::remove_at(size_type index) { + delete PlaneListBase::remove_at(index); } -} +} // End of namespace Sci |