Draw and recycle door markers consistently

This commit is contained in:
Evil Eye 2025-09-10 21:29:40 +02:00
parent 082b9a5461
commit 6e45e562a8
2 changed files with 53 additions and 31 deletions

View File

@ -319,11 +319,12 @@ namespace MWGui
mLocalMap->setViewOffset(viewOffset);
}
MyGUI::IntCoord LocalMapBase::getMarkerCoordinates(MyGUI::Widget* widget, size_t markerSize) const
void LocalMapBase::updateMarkerCoordinates(MyGUI::Widget* widget, size_t markerSize) const
{
MarkerUserData& markerPos(*widget->getUserData<MarkerUserData>());
auto position = getPosition(markerPos.cellX, markerPos.cellY, markerPos.nX, markerPos.nY);
return MyGUI::IntCoord(position.left - markerSize / 2, position.top - markerSize / 2, markerSize, markerSize);
MyGUI::IntCoord coord(position.left - markerSize / 2, position.top - markerSize / 2, markerSize, markerSize);
widget->setCoord(coord);
}
std::vector<MarkerWidget*>& LocalMapBase::currentDoorMarkersWidgets()
@ -379,6 +380,13 @@ namespace MWGui
if (&cell == mActiveCell)
return; // don't do anything if we're still in the same cell
// Remove all interior door markers
mDoorMarkersToRecycle.insert(
mDoorMarkersToRecycle.end(), mInteriorDoorMarkerWidgets.begin(), mInteriorDoorMarkerWidgets.end());
for (MarkerWidget* widget : mInteriorDoorMarkerWidgets)
widget->setVisible(false);
mInteriorDoorMarkerWidgets.clear();
const int x = cell.getGridX();
const int y = cell.getGridY();
@ -386,26 +394,47 @@ namespace MWGui
if (cell.isExterior())
{
std::optional<MyGUI::IntRect> previousActiveGrid;
if (mActiveCell && mActiveCell->isExterior())
previousActiveGrid
= createRect({ mActiveCell->getGridX(), mActiveCell->getGridY() }, Constants::CellGridRadius);
mGrid = createRect({ x, y }, mExtCellDistance);
const MyGUI::IntRect activeGrid = createRect({ x, y }, Constants::CellGridRadius);
mExteriorDoorMarkerWidgets.clear();
for (auto& [coord, doors] : mExteriorDoorsByCell)
for (auto it = mExteriorDoorsByCell.begin(); it != mExteriorDoorsByCell.end();)
{
if (!mGrid.inside({ coord.first, coord.second }) || activeGrid.inside({ coord.first, coord.second }))
const auto& [coord, doors] = *it;
const MyGUI::IntPoint pos(coord.first, coord.second);
// Remove markers that fall outside the rendered map and ones that are new to the active grid.
// Scripts can enable/disable doors, requiring us to update the markers. Morrowind.exe only updates
// markers when a cell is added to the active grid.
if (!mGrid.inside(pos)
|| (previousActiveGrid && !previousActiveGrid->inside(pos) && activeGrid.inside(pos)))
{
mDoorMarkersToRecycle.insert(mDoorMarkersToRecycle.end(), doors.begin(), doors.end());
doors.clear();
}
else
mExteriorDoorMarkerWidgets.insert(mExteriorDoorMarkerWidgets.end(), doors.begin(), doors.end());
}
for (auto& widget : mDoorMarkersToRecycle)
for (MarkerWidget* widget : doors)
widget->setVisible(false);
it = mExteriorDoorsByCell.erase(it);
}
else
{
mExteriorDoorMarkerWidgets.insert(mExteriorDoorMarkerWidgets.end(), doors.begin(), doors.end());
++it;
}
}
}
else
{
mGrid = mLocalMapRender->getInteriorGrid();
// Remove all exterior door markers
mDoorMarkersToRecycle.insert(
mDoorMarkersToRecycle.end(), mExteriorDoorMarkerWidgets.begin(), mExteriorDoorMarkerWidgets.end());
for (MarkerWidget* widget : mExteriorDoorMarkerWidgets)
widget->setVisible(false);
mExteriorDoorMarkerWidgets.clear();
mExteriorDoorsByCell.clear();
}
mActiveCell = &cell;
@ -449,7 +478,7 @@ namespace MWGui
mNeedDoorMarkersUpdate = true;
for (MyGUI::Widget* widget : currentDoorMarkersWidgets())
widget->setCoord(getMarkerCoordinates(widget, 8));
updateMarkerCoordinates(widget, 8);
updateMagicMarkers();
updateCustomMarkers();
@ -609,6 +638,9 @@ namespace MWGui
entry.mFogTexture = std::make_unique<MyGUIPlatform::OSGTexture>(std::string(), nullptr);
}
needRedraw = true;
// Newly uncovered chunk, make sure to draw door markers right away instead of waiting for a cell
// transition
mNeedDoorMarkersUpdate = true;
}
}
if (needRedraw)
@ -621,16 +653,8 @@ namespace MWGui
MWBase::World* world = MWBase::Environment::get().getWorld();
MWWorld::WorldModel* worldModel = MWBase::Environment::get().getWorldModel();
const bool recycledMarkers = !mInteriorDoorMarkerWidgets.empty();
mDoorMarkersToRecycle.insert(
mDoorMarkersToRecycle.end(), mInteriorDoorMarkerWidgets.begin(), mInteriorDoorMarkerWidgets.end());
mInteriorDoorMarkerWidgets.clear();
if (!mActiveCell->isExterior())
{
for (MarkerWidget* widget : mExteriorDoorMarkerWidgets)
widget->setVisible(false);
MWWorld::CellStore& cell = worldModel->getInterior(mActiveCell->getNameId());
world->getDoorMarkers(cell, doors);
}
@ -638,13 +662,13 @@ namespace MWGui
{
for (MapEntry& entry : mMaps)
{
if (!entry.mMapTexture && entry.mMapWidget->getVisible() && !widgetCropped(entry.mMapWidget, mLocalMap))
world->getDoorMarkers(worldModel->getExterior(ESM::ExteriorCellLocation(
entry.mCellX, entry.mCellY, ESM::Cell::sDefaultWorldspaceId)),
doors);
if (!entry.mMapWidget->getVisible() || widgetCropped(entry.mMapWidget, mLocalMap))
continue;
if (mExteriorDoorsByCell.contains({ entry.mCellX, entry.mCellY }))
continue;
ESM::ExteriorCellLocation id(entry.mCellX, entry.mCellY, ESM::Cell::sDefaultWorldspaceId);
world->getDoorMarkers(worldModel->getExterior(id), doors);
}
if (doors.empty() && !recycledMarkers)
return;
}
// Create a widget for each marker
@ -652,8 +676,7 @@ namespace MWGui
{
std::vector<std::string> destNotes;
CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(marker.dest);
for (CustomMarkerCollection::ContainerType::const_iterator iter = markers.first; iter != markers.second;
++iter)
for (auto iter = markers.first; iter != markers.second; ++iter)
destNotes.push_back(iter->second.mNote);
MarkerWidget* markerWidget = nullptr;
@ -682,8 +705,8 @@ namespace MWGui
mExteriorDoorsByCell[{ data->cellX, data->cellY }].push_back(markerWidget);
}
for (auto& widget : mDoorMarkersToRecycle)
widget->setVisible(false);
for (MyGUI::Widget* widget : currentDoorMarkersWidgets())
updateMarkerCoordinates(widget, 8);
}
void LocalMapBase::updateMagicMarkers()
@ -732,7 +755,7 @@ namespace MWGui
MarkerUserData markerPos(mLocalMapRender);
for (MyGUI::Widget* widget : currentDoorMarkersWidgets())
widget->setCoord(getMarkerCoordinates(widget, 8));
updateMarkerCoordinates(widget, 8);
for (MyGUI::Widget* widget : mCustomMarkerWidgets)
{
@ -741,7 +764,7 @@ namespace MWGui
}
for (MyGUI::Widget* widget : mMagicMarkerWidgets)
widget->setCoord(getMarkerCoordinates(widget, 8));
updateMarkerCoordinates(widget, 8);
}
// ------------------------------------------------------------------------------------------

View File

@ -165,11 +165,10 @@ namespace MWGui
MyGUI::IntCoord getMarkerCoordinates(
float worldX, float worldY, MarkerUserData& markerPos, size_t markerSize) const;
MarkerWidget* createDoorMarker(const std::string& name, float x, float y) const;
MyGUI::IntCoord getMarkerCoordinates(MyGUI::Widget* widget, size_t markerSize) const;
void updateMarkerCoordinates(MyGUI::Widget* widget, size_t markerSize) const;
virtual void notifyPlayerUpdate() {}
virtual void centerView();
virtual void notifyMapChanged() {}
virtual void customMarkerCreated(MyGUI::Widget* marker) {}
virtual void doorMarkerCreated(MyGUI::Widget* marker) {}