diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 7003dc6987..788b6517ec 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -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()); 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& 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 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(); + for (MarkerWidget* widget : doors) + widget->setVisible(false); + it = mExteriorDoorsByCell.erase(it); } else + { mExteriorDoorMarkerWidgets.insert(mExteriorDoorMarkerWidgets.end(), doors.begin(), doors.end()); + ++it; + } } - - for (auto& widget : mDoorMarkersToRecycle) - widget->setVisible(false); } 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(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 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); } // ------------------------------------------------------------------------------------------ diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 36cff714dc..1c212cbe88 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -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) {}