mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-07 18:31:37 +00:00
897 lines
26 KiB
C++
897 lines
26 KiB
C++
/* 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, PlanePictureCodes pictureId) :
|
|
_width(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth),
|
|
_height(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight),
|
|
_pictureId(pictureId),
|
|
_mirrored(false),
|
|
_back(0),
|
|
_priorityChanged(0),
|
|
_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);
|
|
setType();
|
|
_screenRect = _planeRect;
|
|
}
|
|
|
|
Plane::Plane(reg_t object) :
|
|
_width(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth),
|
|
_height(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight),
|
|
_priorityChanged(false),
|
|
_object(object),
|
|
_redrawAllCount(g_sci->_gfxFrameout->getScreenCount()),
|
|
_created(g_sci->_gfxFrameout->getScreenCount()),
|
|
_updated(0),
|
|
_deleted(0),
|
|
_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)) + 1;
|
|
_gameRect.bottom = readSelectorValue(segMan, object, SELECTOR(inBottom)) + 1;
|
|
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) :
|
|
_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),
|
|
_back(other._back),
|
|
_object(other._object),
|
|
_priority(other._priority),
|
|
_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 + celObj->_relativePosition;
|
|
} 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 (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.
|
|
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 &&
|
|
!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->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->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 extendedScreenRect = vitem->_screenRect;
|
|
extendedScreenRect.extend(item->_screenRect);
|
|
|
|
drawList.add(item, item->_screenRect);
|
|
mergeToRectList(extendedScreenRect, 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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove parts of eraselist/drawlist that are covered by other planes
|
|
breakEraseListByPlanes(eraseList, planeList);
|
|
breakDrawListByPlanes(drawList, planeList);
|
|
|
|
// 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();
|
|
|
|
// NOTE: Setting this to true fixes the menu bars in GK1
|
|
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) {
|
|
const 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)) {
|
|
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;
|
|
}
|
|
} 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 (
|
|
item != nullptr &&
|
|
!item->_created && !item->_updated && !item->_deleted &&
|
|
eraseList[i]->intersects(item->_screenRect)
|
|
) {
|
|
drawList.add(item, eraseList[i]->findIntersectingRect(item->_screenRect));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (/* TODO: g_Remap_numActiveRemaps == 0 */ true) { // no remaps active?
|
|
// Add all items that overlap with items in the drawlist and have higher
|
|
// 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) {
|
|
DrawItem *dli = drawList[i];
|
|
|
|
for (ScreenItemList::size_type j = 0; j < planeItemCount; ++j) {
|
|
ScreenItem *sli = _screenItemList[j];
|
|
|
|
if (
|
|
i < drawList.size() && dli != nullptr &&
|
|
j < _screenItemList.size() && sli != nullptr &&
|
|
!sli->_created && !sli->_updated && !sli->_deleted
|
|
) {
|
|
ScreenItem *item = dli->screenItem;
|
|
|
|
if (
|
|
(sli->_priority > item->_priority || (sli->_priority == item->_priority && sli->_object > item->_object)) &&
|
|
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 &&
|
|
visiblePlane->_screenItemList.findByObject(item->_object) != nullptr
|
|
)
|
|
) {
|
|
*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) {
|
|
visiblePlane->_screenItemList.add(new ScreenItem(*item));
|
|
}
|
|
}
|
|
|
|
// 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) {
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} 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];
|
|
const 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) {
|
|
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::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::mergeToDrawList(const ScreenItemList::size_type index, const Common::Rect &rect, DrawList &drawList) const {
|
|
RectList rects;
|
|
|
|
ScreenItem *item = _screenItemList[index];
|
|
Common::Rect r = item->_screenRect;
|
|
r.clip(rect);
|
|
rects.add(r);
|
|
|
|
for (RectList::size_type i = 0; i < rects.size(); ++i) {
|
|
r = *rects[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);
|
|
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]);
|
|
}
|
|
|
|
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 r = *temp[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);
|
|
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]);
|
|
}
|
|
|
|
temp.erase_at(i);
|
|
|
|
// proceed to the next rect
|
|
r = *temp[++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.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)) + 1;
|
|
_gameRect.bottom = readSelectorValue(segMan, object, SELECTOR(inBottom)) + 1;
|
|
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));
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#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;
|
|
}
|
|
|
|
PlaneListBase::clear();
|
|
}
|
|
|
|
void PlaneList::erase(Plane *plane) {
|
|
for (iterator it = begin(); it != end(); ++it) {
|
|
if (*it == plane) {
|
|
erase(it);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
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) {
|
|
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::remove_at(size_type index) {
|
|
delete PlaneListBase::remove_at(index);
|
|
}
|
|
|
|
} // End of namespace Sci
|