From 6d9063e544d4b69c8f2760a818066606c024184b Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 8 Sep 2025 17:45:02 +0200 Subject: [PATCH 01/10] Make LocalMap methods const --- apps/openmw/mwrender/localmap.cpp | 20 +++++++++++++------- apps/openmw/mwrender/localmap.hpp | 8 ++++---- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 86999d753c..5f79ad03bc 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -96,7 +96,7 @@ namespace MWRender mRoot->removeChild(rtt); } - const osg::Vec2f LocalMap::rotatePoint(const osg::Vec2f& point, const osg::Vec2f& center, const float angle) + const osg::Vec2f LocalMap::rotatePoint(const osg::Vec2f& point, const osg::Vec2f& center, const float angle) const { return osg::Vec2f( std::cos(angle) * (point.x() - center.x()) - std::sin(angle) * (point.y() - center.y()) + center.x(), @@ -109,12 +109,15 @@ namespace MWRender mInteriorSegments.clear(); } - void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) + void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) const { if (!mInterior) { - const MapSegment& segment - = mExteriorSegments[std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())]; + const auto it + = mExteriorSegments.find(std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())); + if (it == mExteriorSegments.end()) + return; + const MapSegment& segment = it->second; if (segment.mFogOfWarImage && segment.mHasFogState) { @@ -146,7 +149,10 @@ namespace MWRender { for (int y = 0; y < segments.second; ++y) { - const MapSegment& segment = mInteriorSegments[std::make_pair(x, y)]; + const auto it = mInteriorSegments.find(std::make_pair(x, y)); + if (it == mInteriorSegments.end()) + continue; + const MapSegment& segment = it->second; if (!segment.mHasFogState) continue; ESM::FogTexture& texture = fog->mFogTextures.emplace_back(); @@ -422,7 +428,7 @@ namespace MWRender } } - void LocalMap::worldToInteriorMapPosition(osg::Vec2f pos, float& nX, float& nY, int& x, int& y) + void LocalMap::worldToInteriorMapPosition(osg::Vec2f pos, float& nX, float& nY, int& x, int& y) const { pos = rotatePoint(pos, mCenter, mAngle); @@ -435,7 +441,7 @@ namespace MWRender nY = 1.0f - (pos.y() - min.y() - mMapWorldSize * y) / mMapWorldSize; } - osg::Vec2f LocalMap::interiorMapToWorldPosition(float nX, float nY, int x, int y) + osg::Vec2f LocalMap::interiorMapToWorldPosition(float nX, float nY, int x, int y) const { osg::Vec2f min(mBounds.xMin(), mBounds.yMin()); osg::Vec2f pos(mMapWorldSize * (nX + x) + min.x(), mMapWorldSize * (1.0f - nY + y) + min.y()); diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index bf7844f2c1..af745376b4 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -83,14 +83,14 @@ namespace MWRender * Save the fog of war for this cell to its CellStore. * @remarks This should be called when unloading a cell, and for all active cells prior to saving the game. */ - void saveFogOfWar(MWWorld::CellStore* cell); + void saveFogOfWar(MWWorld::CellStore* cell) const; /** * Get the interior map texture index and normalized position on this texture, given a world position */ - void worldToInteriorMapPosition(osg::Vec2f pos, float& nX, float& nY, int& x, int& y); + void worldToInteriorMapPosition(osg::Vec2f pos, float& nX, float& nY, int& x, int& y) const; - osg::Vec2f interiorMapToWorldPosition(float nX, float nY, int x, int y); + osg::Vec2f interiorMapToWorldPosition(float nX, float nY, int x, int y) const; /** * Check if a given position is explored by the player (i.e. not obscured by fog of war) @@ -149,7 +149,7 @@ namespace MWRender int mCellDistance; float mAngle; - const osg::Vec2f rotatePoint(const osg::Vec2f& point, const osg::Vec2f& center, const float angle); + const osg::Vec2f rotatePoint(const osg::Vec2f& point, const osg::Vec2f& center, const float angle) const; void requestExteriorMap(const MWWorld::CellStore* cell, MapSegment& segment); void requestInteriorMap(const MWWorld::CellStore* cell); From cdd2ea02b4fec1d35ebab6cc1dff3913686ca774 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 8 Sep 2025 18:12:05 +0200 Subject: [PATCH 02/10] Remove logically redundant code --- apps/openmw/mwgui/hud.cpp | 1 - apps/openmw/mwgui/mapwindow.cpp | 15 +-------------- apps/openmw/mwgui/mapwindow.hpp | 1 - apps/openmw/mwrender/localmap.cpp | 5 ----- apps/openmw/mwrender/localmap.hpp | 1 - 5 files changed, 1 insertion(+), 22 deletions(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 56f18e9b0e..03539ecd9f 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -635,7 +635,6 @@ namespace MWGui mSpellBox->setUserData(MyGUI::Any::Null); mActiveCell = nullptr; - mHasALastActiveCell = false; } void HUD::customMarkerCreated(MyGUI::Widget* marker) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index f80871d3ef..57806fa6d3 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -393,8 +393,7 @@ namespace MWGui mExteriorDoorMarkerWidgets.clear(); for (auto& [coord, doors] : mExteriorDoorsByCell) { - if (!mHasALastActiveCell || !mGrid.inside({ coord.first, coord.second }) - || activeGrid.inside({ coord.first, coord.second })) + if (!mGrid.inside({ coord.first, coord.second }) || activeGrid.inside({ coord.first, coord.second })) { mDoorMarkersToRecycle.insert(mDoorMarkersToRecycle.end(), doors.begin(), doors.end()); doors.clear(); @@ -405,15 +404,6 @@ namespace MWGui for (auto& widget : mDoorMarkersToRecycle) widget->setVisible(false); - - if (mHasALastActiveCell) - { - for (const auto& entry : mMaps) - { - if (!mGrid.inside({ entry.mCellX, entry.mCellY })) - mLocalMapRender->removeExteriorCell(entry.mCellX, entry.mCellY); - } - } } else mGrid = mLocalMapRender->getInteriorGrid(); @@ -462,9 +452,6 @@ namespace MWGui for (MyGUI::Widget* widget : currentDoorMarkersWidgets()) widget->setCoord(getMarkerCoordinates(widget, 8)); - if (mActiveCell->isExterior()) - mHasALastActiveCell = true; - updateMagicMarkers(); updateCustomMarkers(); } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index eb49f8673e..ee49d915dc 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -119,7 +119,6 @@ namespace MWGui MyGUI::ScrollView* mLocalMap = nullptr; MyGUI::ImageBox* mCompass = nullptr; float mLocalMapZoom = 1.f; - bool mHasALastActiveCell = false; bool mFogOfWarToggled = true; bool mFogOfWarEnabled; bool mNeedDoorMarkersUpdate = false; diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 5f79ad03bc..f0279a5340 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -205,11 +205,6 @@ namespace MWRender std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY()), MapSegment{}); } - void LocalMap::removeExteriorCell(int x, int y) - { - mExteriorSegments.erase({ x, y }); - } - void LocalMap::removeCell(MWWorld::CellStore* cell) { saveFogOfWar(cell); diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index af745376b4..650a34f655 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -55,7 +55,6 @@ namespace MWRender void requestMap(const MWWorld::CellStore* cell); void addCell(MWWorld::CellStore* cell); - void removeExteriorCell(int x, int y); void removeCell(MWWorld::CellStore* cell); From 75a04776b0eddfd12c9b9fa1b9ca3fa24dc16ff3 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 8 Sep 2025 19:35:37 +0200 Subject: [PATCH 03/10] Remove the need to cast door marker widgets --- apps/openmw/mwgui/mapwindow.cpp | 19 +++++++++---------- apps/openmw/mwgui/mapwindow.hpp | 13 +++++++------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 57806fa6d3..12bda65d1e 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -38,7 +38,7 @@ namespace { - const int cellSize = Constants::CellSizeInUnits; + constexpr int cellSize = Constants::CellSizeInUnits; constexpr float speed = 1.08f; // the zoom speed, it should be greater than 1 enum LocalMapWidgetDepth @@ -57,7 +57,10 @@ namespace Global_ExploreOverlayLayer = 2, Global_MapLayer = 3 }; +} +namespace MWGui +{ /// @brief A widget that changes its color when hovered. class MarkerWidget final : public MyGUI::Widget { @@ -108,10 +111,6 @@ namespace { scrollView->setCanvasSize(widgetSize * (grid.width() + 1), widgetSize * (grid.height() + 1)); } -} - -namespace MWGui -{ void CustomMarkerCollection::addMarker(const ESM::CustomMarker& marker, bool triggerEvent) { @@ -293,7 +292,7 @@ namespace MWGui return MyGUI::IntCoord(position.left - halfMarkerSize, position.top - halfMarkerSize, markerSize, markerSize); } - MyGUI::Widget* LocalMapBase::createDoorMarker(const std::string& name, float x, float y) const + MarkerWidget* LocalMapBase::createDoorMarker(const std::string& name, float x, float y) const { MarkerUserData data(mLocalMapRender); data.caption = name; @@ -327,7 +326,7 @@ namespace MWGui return MyGUI::IntCoord(position.left - markerSize / 2, position.top - markerSize / 2, markerSize, markerSize); } - std::vector& LocalMapBase::currentDoorMarkersWidgets() + std::vector& LocalMapBase::currentDoorMarkersWidgets() { return mActiveCell->isExterior() ? mExteriorDoorMarkerWidgets : mInteriorDoorMarkerWidgets; } @@ -628,7 +627,7 @@ namespace MWGui if (!mActiveCell->isExterior()) { - for (MyGUI::Widget* widget : mExteriorDoorMarkerWidgets) + for (MarkerWidget* widget : mExteriorDoorMarkerWidgets) widget->setVisible(false); MWWorld::CellStore& cell = worldModel->getInterior(mActiveCell->getNameId()); @@ -656,7 +655,7 @@ namespace MWGui ++iter) destNotes.push_back(iter->second.mNote); - MyGUI::Widget* markerWidget = nullptr; + MarkerWidget* markerWidget = nullptr; MarkerUserData* data; if (mDoorMarkersToRecycle.empty()) { @@ -667,7 +666,7 @@ namespace MWGui } else { - markerWidget = (MarkerWidget*)mDoorMarkersToRecycle.back(); + markerWidget = mDoorMarkersToRecycle.back(); mDoorMarkersToRecycle.pop_back(); data = markerWidget->getUserData(); diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index ee49d915dc..36cff714dc 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -43,6 +43,7 @@ namespace SceneUtil namespace MWGui { + class MarkerWidget; class CustomMarkerCollection { @@ -146,14 +147,14 @@ namespace MWGui std::vector mMaps; // Keep track of created marker widgets, just to easily remove them later. - std::vector mExteriorDoorMarkerWidgets; - std::map, std::vector> mExteriorDoorsByCell; - std::vector mInteriorDoorMarkerWidgets; + std::vector mExteriorDoorMarkerWidgets; + std::map, std::vector> mExteriorDoorsByCell; + std::vector mInteriorDoorMarkerWidgets; std::vector mMagicMarkerWidgets; std::vector mCustomMarkerWidgets; - std::vector mDoorMarkersToRecycle; + std::vector mDoorMarkersToRecycle; - std::vector& currentDoorMarkersWidgets(); + std::vector& currentDoorMarkersWidgets(); virtual void updateCustomMarkers(); @@ -163,7 +164,7 @@ namespace MWGui MyGUI::IntPoint getMarkerPosition(float worldX, float worldY, MarkerUserData& markerPos) const; MyGUI::IntCoord getMarkerCoordinates( float worldX, float worldY, MarkerUserData& markerPos, size_t markerSize) const; - MyGUI::Widget* createDoorMarker(const std::string& name, float x, float y) const; + MarkerWidget* createDoorMarker(const std::string& name, float x, float y) const; MyGUI::IntCoord getMarkerCoordinates(MyGUI::Widget* widget, size_t markerSize) const; virtual void notifyPlayerUpdate() {} From 2ba2f2830aa73cb2d96d54829cd218265c7b4983 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 8 Sep 2025 21:49:12 +0200 Subject: [PATCH 04/10] Prevent door markers from being rendered when they shouldn't be --- apps/openmw/mwgui/mapwindow.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 12bda65d1e..7003dc6987 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -621,6 +621,7 @@ 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(); @@ -637,12 +638,12 @@ namespace MWGui { for (MapEntry& entry : mMaps) { - if (!entry.mMapTexture && !widgetCropped(entry.mMapWidget, mLocalMap)) + 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 (doors.empty()) + if (doors.empty() && !recycledMarkers) return; } From 082b9a5461815682343c2dd999b853b139a57d53 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Wed, 10 Sep 2025 16:52:34 +0200 Subject: [PATCH 05/10] Only count rendered neighbours --- apps/openmw/mwrender/localmap.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index f0279a5340..d12b4480f2 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -192,7 +192,8 @@ namespace MWRender MapSegment& segment = mExteriorSegments[std::make_pair(cellX, cellY)]; const std::uint8_t neighbourFlags = getExteriorNeighbourFlags(cellX, cellY); - if ((segment.mLastRenderNeighbourFlags & neighbourFlags) == neighbourFlags) + if (segment.mLastRenderNeighbourFlags != 0 + && (segment.mLastRenderNeighbourFlags & neighbourFlags) == neighbourFlags) return; requestExteriorMap(cell, segment); segment.mLastRenderNeighbourFlags = neighbourFlags; @@ -572,8 +573,11 @@ namespace MWRender }; std::uint8_t result = 0; for (const auto& [flag, dx, dy] : flags) - if (mExteriorSegments.contains(std::pair(cellX + dx, cellY + dy))) + { + auto it = mExteriorSegments.find(std::pair(cellX + dx, cellY + dy)); + if (it != mExteriorSegments.end() && it->second.mMapTexture) result |= flag; + } return result; } From 6e45e562a8590c3bd91f884e9f4ac55474acb219 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Wed, 10 Sep 2025 21:29:40 +0200 Subject: [PATCH 06/10] Draw and recycle door markers consistently --- apps/openmw/mwgui/mapwindow.cpp | 81 +++++++++++++++++++++------------ apps/openmw/mwgui/mapwindow.hpp | 3 +- 2 files changed, 53 insertions(+), 31 deletions(-) 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) {} From d6ce23aba7717777f67397691fe9f764053ccf8a Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 11 Sep 2025 17:03:06 +0200 Subject: [PATCH 07/10] Properly account for map tile visibility --- apps/openmw/mwgui/mapwindow.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 788b6517ec..ab35f3e25c 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -603,7 +603,7 @@ namespace MWGui bool needRedraw = false; for (MapEntry& entry : mMaps) { - if (widgetCropped(entry.mMapWidget, mLocalMap)) + if (!entry.mMapWidget->getVisible() || widgetCropped(entry.mMapWidget, mLocalMap)) continue; if (!entry.mMapTexture) @@ -748,6 +748,8 @@ namespace MWGui const auto size = MyGUI::IntSize(std::ceil(mapWidgetSize), std::ceil(mapWidgetSize)); for (auto& entry : mMaps) { + if (!entry.mMapWidget->getVisible()) + continue; const auto position = getPosition(entry.mCellX, entry.mCellY, 0, 0); entry.mMapWidget->setCoord({ position, size }); entry.mFogWidget->setCoord({ position, size }); @@ -1377,8 +1379,7 @@ namespace MWGui NoDrop::setAlpha(alpha); // can't allow showing map with partial transparency, as the fog of war will also go transparent // and reveal parts of the map you shouldn't be able to see - for (MapEntry& entry : mMaps) - entry.mMapWidget->setVisible(alpha == 1); + mLocalMap->setVisible(alpha == 1); } void MapWindow::customMarkerCreated(MyGUI::Widget* marker) From 50601b773331e8d48ac596e619e7037ed3506d6c Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 11 Sep 2025 17:04:07 +0200 Subject: [PATCH 08/10] Remove rendered segments outside the map grid again --- apps/openmw/mwgui/mapwindow.cpp | 16 ++++++++++++++-- apps/openmw/mwrender/localmap.cpp | 10 +++++++--- apps/openmw/mwrender/localmap.hpp | 1 + 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index ab35f3e25c..fa2c03e9be 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -390,7 +390,7 @@ namespace MWGui const int x = cell.getGridX(); const int y = cell.getGridY(); - MyGUI::IntSize oldSize{ mGrid.width(), mGrid.height() }; + const MyGUI::IntRect prevGrid = mGrid; if (cell.isExterior()) { @@ -423,6 +423,18 @@ namespace MWGui ++it; } } + + if (mActiveCell && mActiveCell->isExterior()) + { + for (int cx = prevGrid.left; cx <= prevGrid.right; ++cx) + { + for (int cy = prevGrid.top; cy <= prevGrid.bottom; ++cy) + { + if (!mGrid.inside({ cx, cy })) + mLocalMapRender->removeExteriorCell(cx, cy); + } + } + } } else { @@ -470,7 +482,7 @@ namespace MWGui resetEntry(mMaps[i], false, nullptr); } - if (oldSize != MyGUI::IntSize{ mGrid.width(), mGrid.height() }) + if (prevGrid.width() != mGrid.width() || prevGrid.height() != mGrid.height()) setCanvasSize(mLocalMap, mGrid, getWidgetSize()); // Delay the door markers update until scripts have been given a chance to run. diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index d12b4480f2..c5d36a65a5 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -206,13 +206,16 @@ namespace MWRender std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY()), MapSegment{}); } + void LocalMap::removeExteriorCell(int x, int y) + { + mExteriorSegments.erase({ x, y }); + } + void LocalMap::removeCell(MWWorld::CellStore* cell) { saveFogOfWar(cell); - if (cell->isExterior()) - mExteriorSegments.erase({ cell->getCell()->getGridX(), cell->getCell()->getGridY() }); - else + if (!cell->isExterior()) mInteriorSegments.clear(); } @@ -301,6 +304,7 @@ namespace MWRender return; mInterior = true; + mExteriorSegments.clear(); mBounds = bounds; diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 650a34f655..af745376b4 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -55,6 +55,7 @@ namespace MWRender void requestMap(const MWWorld::CellStore* cell); void addCell(MWWorld::CellStore* cell); + void removeExteriorCell(int x, int y); void removeCell(MWWorld::CellStore* cell); From 423261b7214efd0cd44495f05fbab1399ad82bc9 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 11 Sep 2025 17:05:34 +0200 Subject: [PATCH 09/10] Account for view distance changes --- apps/openmw/mwgui/mapwindow.cpp | 3 +-- apps/openmw/mwgui/mapwindow.hpp | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index fa2c03e9be..2f9225ed42 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -216,7 +216,6 @@ namespace MWGui mLocalMap = widget; mCompass = compass; mGrid = createRect({ 0, 0 }, cellDistance); - mExtCellDistance = cellDistance; const int mapWidgetSize = Settings::map().mLocalMapWidgetSize; setCanvasSize(mLocalMap, mGrid, mapWidgetSize); @@ -398,7 +397,7 @@ namespace MWGui if (mActiveCell && mActiveCell->isExterior()) previousActiveGrid = createRect({ mActiveCell->getGridX(), mActiveCell->getGridY() }, Constants::CellGridRadius); - mGrid = createRect({ x, y }, mExtCellDistance); + mGrid = createRect({ x, y }, getLocalViewingDistance()); const MyGUI::IntRect activeGrid = createRect({ x, y }, Constants::CellGridRadius); mExteriorDoorMarkerWidgets.clear(); diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 1c212cbe88..9bbc0a84c8 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -184,7 +184,6 @@ namespace MWGui MWGui::LocalMapBase::MapEntry& addMapEntry(); MyGUI::IntRect mGrid{ -1, -1, 1, 1 }; - int mExtCellDistance = 0; float mMarkerUpdateTimer = 0.f; float mLastDirectionX = 0.f; From 5b4a156a0482e7391a905865fd278aa796e7f2a0 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 11 Sep 2025 19:15:25 +0200 Subject: [PATCH 10/10] Properly update the map when changing the view distance --- apps/openmw/mwgui/mapwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 2f9225ed42..1e74b4ffbb 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -482,7 +482,7 @@ namespace MWGui } if (prevGrid.width() != mGrid.width() || prevGrid.height() != mGrid.height()) - setCanvasSize(mLocalMap, mGrid, getWidgetSize()); + updateLocalMap(); // Delay the door markers update until scripts have been given a chance to run. // If we don't do this, door markers that should be disabled will still appear on the map.