Merge branch 'localmap' into 'master'

Local map fixes

See merge request OpenMW/openmw!4919
This commit is contained in:
Evil Eye 2025-09-20 15:33:30 +00:00
commit 4d5b65a9cb
5 changed files with 108 additions and 80 deletions

View File

@ -635,7 +635,6 @@ namespace MWGui
mSpellBox->setUserData(MyGUI::Any::Null); mSpellBox->setUserData(MyGUI::Any::Null);
mActiveCell = nullptr; mActiveCell = nullptr;
mHasALastActiveCell = false;
} }
void HUD::customMarkerCreated(MyGUI::Widget* marker) void HUD::customMarkerCreated(MyGUI::Widget* marker)

View File

@ -38,7 +38,7 @@
namespace 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 constexpr float speed = 1.08f; // the zoom speed, it should be greater than 1
enum LocalMapWidgetDepth enum LocalMapWidgetDepth
@ -57,7 +57,10 @@ namespace
Global_ExploreOverlayLayer = 2, Global_ExploreOverlayLayer = 2,
Global_MapLayer = 3 Global_MapLayer = 3
}; };
}
namespace MWGui
{
/// @brief A widget that changes its color when hovered. /// @brief A widget that changes its color when hovered.
class MarkerWidget final : public MyGUI::Widget class MarkerWidget final : public MyGUI::Widget
{ {
@ -108,10 +111,6 @@ namespace
{ {
scrollView->setCanvasSize(widgetSize * (grid.width() + 1), widgetSize * (grid.height() + 1)); scrollView->setCanvasSize(widgetSize * (grid.width() + 1), widgetSize * (grid.height() + 1));
} }
}
namespace MWGui
{
void CustomMarkerCollection::addMarker(const ESM::CustomMarker& marker, bool triggerEvent) void CustomMarkerCollection::addMarker(const ESM::CustomMarker& marker, bool triggerEvent)
{ {
@ -217,7 +216,6 @@ namespace MWGui
mLocalMap = widget; mLocalMap = widget;
mCompass = compass; mCompass = compass;
mGrid = createRect({ 0, 0 }, cellDistance); mGrid = createRect({ 0, 0 }, cellDistance);
mExtCellDistance = cellDistance;
const int mapWidgetSize = Settings::map().mLocalMapWidgetSize; const int mapWidgetSize = Settings::map().mLocalMapWidgetSize;
setCanvasSize(mLocalMap, mGrid, mapWidgetSize); setCanvasSize(mLocalMap, mGrid, mapWidgetSize);
@ -293,7 +291,7 @@ namespace MWGui
return MyGUI::IntCoord(position.left - halfMarkerSize, position.top - halfMarkerSize, markerSize, markerSize); 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); MarkerUserData data(mLocalMapRender);
data.caption = name; data.caption = name;
@ -320,14 +318,15 @@ namespace MWGui
mLocalMap->setViewOffset(viewOffset); 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>()); MarkerUserData& markerPos(*widget->getUserData<MarkerUserData>());
auto position = getPosition(markerPos.cellX, markerPos.cellY, markerPos.nX, markerPos.nY); 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<MyGUI::Widget*>& LocalMapBase::currentDoorMarkersWidgets() std::vector<MarkerWidget*>& LocalMapBase::currentDoorMarkersWidgets()
{ {
return mActiveCell->isExterior() ? mExteriorDoorMarkerWidgets : mInteriorDoorMarkerWidgets; return mActiveCell->isExterior() ? mExteriorDoorMarkerWidgets : mInteriorDoorMarkerWidgets;
} }
@ -380,43 +379,73 @@ namespace MWGui
if (&cell == mActiveCell) if (&cell == mActiveCell)
return; // don't do anything if we're still in the same cell 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 x = cell.getGridX();
const int y = cell.getGridY(); const int y = cell.getGridY();
MyGUI::IntSize oldSize{ mGrid.width(), mGrid.height() }; const MyGUI::IntRect prevGrid = mGrid;
if (cell.isExterior()) if (cell.isExterior())
{ {
mGrid = createRect({ x, y }, mExtCellDistance); std::optional<MyGUI::IntRect> previousActiveGrid;
if (mActiveCell && mActiveCell->isExterior())
previousActiveGrid
= createRect({ mActiveCell->getGridX(), mActiveCell->getGridY() }, Constants::CellGridRadius);
mGrid = createRect({ x, y }, getLocalViewingDistance());
const MyGUI::IntRect activeGrid = createRect({ x, y }, Constants::CellGridRadius); const MyGUI::IntRect activeGrid = createRect({ x, y }, Constants::CellGridRadius);
mExteriorDoorMarkerWidgets.clear(); mExteriorDoorMarkerWidgets.clear();
for (auto& [coord, doors] : mExteriorDoorsByCell) for (auto it = mExteriorDoorsByCell.begin(); it != mExteriorDoorsByCell.end();)
{ {
if (!mHasALastActiveCell || !mGrid.inside({ coord.first, coord.second }) const auto& [coord, doors] = *it;
|| activeGrid.inside({ coord.first, coord.second })) 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()); mDoorMarkersToRecycle.insert(mDoorMarkersToRecycle.end(), doors.begin(), doors.end());
doors.clear(); for (MarkerWidget* widget : doors)
widget->setVisible(false);
it = mExteriorDoorsByCell.erase(it);
} }
else else
{
mExteriorDoorMarkerWidgets.insert(mExteriorDoorMarkerWidgets.end(), doors.begin(), doors.end()); mExteriorDoorMarkerWidgets.insert(mExteriorDoorMarkerWidgets.end(), doors.begin(), doors.end());
++it;
}
} }
for (auto& widget : mDoorMarkersToRecycle) if (mActiveCell && mActiveCell->isExterior())
widget->setVisible(false);
if (mHasALastActiveCell)
{ {
for (const auto& entry : mMaps) for (int cx = prevGrid.left; cx <= prevGrid.right; ++cx)
{ {
if (!mGrid.inside({ entry.mCellX, entry.mCellY })) for (int cy = prevGrid.top; cy <= prevGrid.bottom; ++cy)
mLocalMapRender->removeExteriorCell(entry.mCellX, entry.mCellY); {
if (!mGrid.inside({ cx, cy }))
mLocalMapRender->removeExteriorCell(cx, cy);
}
} }
} }
} }
else else
{
mGrid = mLocalMapRender->getInteriorGrid(); 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; mActiveCell = &cell;
@ -452,18 +481,15 @@ namespace MWGui
resetEntry(mMaps[i], false, nullptr); 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()); updateLocalMap();
// Delay the door markers update until scripts have been given a chance to run. // 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. // If we don't do this, door markers that should be disabled will still appear on the map.
mNeedDoorMarkersUpdate = true; mNeedDoorMarkersUpdate = true;
for (MyGUI::Widget* widget : currentDoorMarkersWidgets()) for (MyGUI::Widget* widget : currentDoorMarkersWidgets())
widget->setCoord(getMarkerCoordinates(widget, 8)); updateMarkerCoordinates(widget, 8);
if (mActiveCell->isExterior())
mHasALastActiveCell = true;
updateMagicMarkers(); updateMagicMarkers();
updateCustomMarkers(); updateCustomMarkers();
@ -588,7 +614,7 @@ namespace MWGui
bool needRedraw = false; bool needRedraw = false;
for (MapEntry& entry : mMaps) for (MapEntry& entry : mMaps)
{ {
if (widgetCropped(entry.mMapWidget, mLocalMap)) if (!entry.mMapWidget->getVisible() || widgetCropped(entry.mMapWidget, mLocalMap))
continue; continue;
if (!entry.mMapTexture) if (!entry.mMapTexture)
@ -623,6 +649,9 @@ namespace MWGui
entry.mFogTexture = std::make_unique<MyGUIPlatform::OSGTexture>(std::string(), nullptr); entry.mFogTexture = std::make_unique<MyGUIPlatform::OSGTexture>(std::string(), nullptr);
} }
needRedraw = true; needRedraw = true;
// Newly uncovered chunk, make sure to draw door markers right away instead of waiting for a cell
// transition
mNeedDoorMarkersUpdate = true;
} }
} }
if (needRedraw) if (needRedraw)
@ -635,15 +664,8 @@ namespace MWGui
MWBase::World* world = MWBase::Environment::get().getWorld(); MWBase::World* world = MWBase::Environment::get().getWorld();
MWWorld::WorldModel* worldModel = MWBase::Environment::get().getWorldModel(); MWWorld::WorldModel* worldModel = MWBase::Environment::get().getWorldModel();
mDoorMarkersToRecycle.insert(
mDoorMarkersToRecycle.end(), mInteriorDoorMarkerWidgets.begin(), mInteriorDoorMarkerWidgets.end());
mInteriorDoorMarkerWidgets.clear();
if (!mActiveCell->isExterior()) if (!mActiveCell->isExterior())
{ {
for (MyGUI::Widget* widget : mExteriorDoorMarkerWidgets)
widget->setVisible(false);
MWWorld::CellStore& cell = worldModel->getInterior(mActiveCell->getNameId()); MWWorld::CellStore& cell = worldModel->getInterior(mActiveCell->getNameId());
world->getDoorMarkers(cell, doors); world->getDoorMarkers(cell, doors);
} }
@ -651,13 +673,13 @@ namespace MWGui
{ {
for (MapEntry& entry : mMaps) for (MapEntry& entry : mMaps)
{ {
if (!entry.mMapTexture && !widgetCropped(entry.mMapWidget, mLocalMap)) if (!entry.mMapWidget->getVisible() || widgetCropped(entry.mMapWidget, mLocalMap))
world->getDoorMarkers(worldModel->getExterior(ESM::ExteriorCellLocation( continue;
entry.mCellX, entry.mCellY, ESM::Cell::sDefaultWorldspaceId)), if (mExteriorDoorsByCell.contains({ entry.mCellX, entry.mCellY }))
doors); continue;
ESM::ExteriorCellLocation id(entry.mCellX, entry.mCellY, ESM::Cell::sDefaultWorldspaceId);
world->getDoorMarkers(worldModel->getExterior(id), doors);
} }
if (doors.empty())
return;
} }
// Create a widget for each marker // Create a widget for each marker
@ -665,11 +687,10 @@ namespace MWGui
{ {
std::vector<std::string> destNotes; std::vector<std::string> destNotes;
CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(marker.dest); CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(marker.dest);
for (CustomMarkerCollection::ContainerType::const_iterator iter = markers.first; iter != markers.second; for (auto iter = markers.first; iter != markers.second; ++iter)
++iter)
destNotes.push_back(iter->second.mNote); destNotes.push_back(iter->second.mNote);
MyGUI::Widget* markerWidget = nullptr; MarkerWidget* markerWidget = nullptr;
MarkerUserData* data; MarkerUserData* data;
if (mDoorMarkersToRecycle.empty()) if (mDoorMarkersToRecycle.empty())
{ {
@ -680,7 +701,7 @@ namespace MWGui
} }
else else
{ {
markerWidget = (MarkerWidget*)mDoorMarkersToRecycle.back(); markerWidget = mDoorMarkersToRecycle.back();
mDoorMarkersToRecycle.pop_back(); mDoorMarkersToRecycle.pop_back();
data = markerWidget->getUserData<MarkerUserData>(); data = markerWidget->getUserData<MarkerUserData>();
@ -695,8 +716,8 @@ namespace MWGui
mExteriorDoorsByCell[{ data->cellX, data->cellY }].push_back(markerWidget); mExteriorDoorsByCell[{ data->cellX, data->cellY }].push_back(markerWidget);
} }
for (auto& widget : mDoorMarkersToRecycle) for (MyGUI::Widget* widget : currentDoorMarkersWidgets())
widget->setVisible(false); updateMarkerCoordinates(widget, 8);
} }
void LocalMapBase::updateMagicMarkers() void LocalMapBase::updateMagicMarkers()
@ -738,6 +759,8 @@ namespace MWGui
const auto size = MyGUI::IntSize(std::ceil(mapWidgetSize), std::ceil(mapWidgetSize)); const auto size = MyGUI::IntSize(std::ceil(mapWidgetSize), std::ceil(mapWidgetSize));
for (auto& entry : mMaps) for (auto& entry : mMaps)
{ {
if (!entry.mMapWidget->getVisible())
continue;
const auto position = getPosition(entry.mCellX, entry.mCellY, 0, 0); const auto position = getPosition(entry.mCellX, entry.mCellY, 0, 0);
entry.mMapWidget->setCoord({ position, size }); entry.mMapWidget->setCoord({ position, size });
entry.mFogWidget->setCoord({ position, size }); entry.mFogWidget->setCoord({ position, size });
@ -745,7 +768,7 @@ namespace MWGui
MarkerUserData markerPos(mLocalMapRender); MarkerUserData markerPos(mLocalMapRender);
for (MyGUI::Widget* widget : currentDoorMarkersWidgets()) for (MyGUI::Widget* widget : currentDoorMarkersWidgets())
widget->setCoord(getMarkerCoordinates(widget, 8)); updateMarkerCoordinates(widget, 8);
for (MyGUI::Widget* widget : mCustomMarkerWidgets) for (MyGUI::Widget* widget : mCustomMarkerWidgets)
{ {
@ -754,7 +777,7 @@ namespace MWGui
} }
for (MyGUI::Widget* widget : mMagicMarkerWidgets) for (MyGUI::Widget* widget : mMagicMarkerWidgets)
widget->setCoord(getMarkerCoordinates(widget, 8)); updateMarkerCoordinates(widget, 8);
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
@ -1368,8 +1391,7 @@ namespace MWGui
NoDrop::setAlpha(alpha); NoDrop::setAlpha(alpha);
// can't allow showing map with partial transparency, as the fog of war will also go transparent // 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 // and reveal parts of the map you shouldn't be able to see
for (MapEntry& entry : mMaps) mLocalMap->setVisible(alpha == 1);
entry.mMapWidget->setVisible(alpha == 1);
} }
void MapWindow::customMarkerCreated(MyGUI::Widget* marker) void MapWindow::customMarkerCreated(MyGUI::Widget* marker)

View File

@ -43,6 +43,7 @@ namespace SceneUtil
namespace MWGui namespace MWGui
{ {
class MarkerWidget;
class CustomMarkerCollection class CustomMarkerCollection
{ {
@ -119,7 +120,6 @@ namespace MWGui
MyGUI::ScrollView* mLocalMap = nullptr; MyGUI::ScrollView* mLocalMap = nullptr;
MyGUI::ImageBox* mCompass = nullptr; MyGUI::ImageBox* mCompass = nullptr;
float mLocalMapZoom = 1.f; float mLocalMapZoom = 1.f;
bool mHasALastActiveCell = false;
bool mFogOfWarToggled = true; bool mFogOfWarToggled = true;
bool mFogOfWarEnabled; bool mFogOfWarEnabled;
bool mNeedDoorMarkersUpdate = false; bool mNeedDoorMarkersUpdate = false;
@ -147,14 +147,14 @@ namespace MWGui
std::vector<MapEntry> mMaps; std::vector<MapEntry> mMaps;
// Keep track of created marker widgets, just to easily remove them later. // Keep track of created marker widgets, just to easily remove them later.
std::vector<MyGUI::Widget*> mExteriorDoorMarkerWidgets; std::vector<MarkerWidget*> mExteriorDoorMarkerWidgets;
std::map<std::pair<int, int>, std::vector<MyGUI::Widget*>> mExteriorDoorsByCell; std::map<std::pair<int, int>, std::vector<MarkerWidget*>> mExteriorDoorsByCell;
std::vector<MyGUI::Widget*> mInteriorDoorMarkerWidgets; std::vector<MarkerWidget*> mInteriorDoorMarkerWidgets;
std::vector<MyGUI::Widget*> mMagicMarkerWidgets; std::vector<MyGUI::Widget*> mMagicMarkerWidgets;
std::vector<MyGUI::Widget*> mCustomMarkerWidgets; std::vector<MyGUI::Widget*> mCustomMarkerWidgets;
std::vector<MyGUI::Widget*> mDoorMarkersToRecycle; std::vector<MarkerWidget*> mDoorMarkersToRecycle;
std::vector<MyGUI::Widget*>& currentDoorMarkersWidgets(); std::vector<MarkerWidget*>& currentDoorMarkersWidgets();
virtual void updateCustomMarkers(); virtual void updateCustomMarkers();
@ -164,12 +164,11 @@ namespace MWGui
MyGUI::IntPoint getMarkerPosition(float worldX, float worldY, MarkerUserData& markerPos) const; MyGUI::IntPoint getMarkerPosition(float worldX, float worldY, MarkerUserData& markerPos) const;
MyGUI::IntCoord getMarkerCoordinates( MyGUI::IntCoord getMarkerCoordinates(
float worldX, float worldY, MarkerUserData& markerPos, size_t markerSize) const; 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; void updateMarkerCoordinates(MyGUI::Widget* widget, size_t markerSize) const;
virtual void notifyPlayerUpdate() {} virtual void notifyPlayerUpdate() {}
virtual void centerView(); virtual void centerView();
virtual void notifyMapChanged() {}
virtual void customMarkerCreated(MyGUI::Widget* marker) {} virtual void customMarkerCreated(MyGUI::Widget* marker) {}
virtual void doorMarkerCreated(MyGUI::Widget* marker) {} virtual void doorMarkerCreated(MyGUI::Widget* marker) {}
@ -185,7 +184,6 @@ namespace MWGui
MWGui::LocalMapBase::MapEntry& addMapEntry(); MWGui::LocalMapBase::MapEntry& addMapEntry();
MyGUI::IntRect mGrid{ -1, -1, 1, 1 }; MyGUI::IntRect mGrid{ -1, -1, 1, 1 };
int mExtCellDistance = 0;
float mMarkerUpdateTimer = 0.f; float mMarkerUpdateTimer = 0.f;
float mLastDirectionX = 0.f; float mLastDirectionX = 0.f;

View File

@ -96,7 +96,7 @@ namespace MWRender
mRoot->removeChild(rtt); 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( return osg::Vec2f(
std::cos(angle) * (point.x() - center.x()) - std::sin(angle) * (point.y() - center.y()) + center.x(), std::cos(angle) * (point.x() - center.x()) - std::sin(angle) * (point.y() - center.y()) + center.x(),
@ -109,12 +109,15 @@ namespace MWRender
mInteriorSegments.clear(); mInteriorSegments.clear();
} }
void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) const
{ {
if (!mInterior) if (!mInterior)
{ {
const MapSegment& segment const auto it
= mExteriorSegments[std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())]; = 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) if (segment.mFogOfWarImage && segment.mHasFogState)
{ {
@ -146,7 +149,10 @@ namespace MWRender
{ {
for (int y = 0; y < segments.second; ++y) 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) if (!segment.mHasFogState)
continue; continue;
ESM::FogTexture& texture = fog->mFogTextures.emplace_back(); ESM::FogTexture& texture = fog->mFogTextures.emplace_back();
@ -186,7 +192,8 @@ namespace MWRender
MapSegment& segment = mExteriorSegments[std::make_pair(cellX, cellY)]; MapSegment& segment = mExteriorSegments[std::make_pair(cellX, cellY)];
const std::uint8_t neighbourFlags = getExteriorNeighbourFlags(cellX, cellY); const std::uint8_t neighbourFlags = getExteriorNeighbourFlags(cellX, cellY);
if ((segment.mLastRenderNeighbourFlags & neighbourFlags) == neighbourFlags) if (segment.mLastRenderNeighbourFlags != 0
&& (segment.mLastRenderNeighbourFlags & neighbourFlags) == neighbourFlags)
return; return;
requestExteriorMap(cell, segment); requestExteriorMap(cell, segment);
segment.mLastRenderNeighbourFlags = neighbourFlags; segment.mLastRenderNeighbourFlags = neighbourFlags;
@ -208,9 +215,7 @@ namespace MWRender
{ {
saveFogOfWar(cell); saveFogOfWar(cell);
if (cell->isExterior()) if (!cell->isExterior())
mExteriorSegments.erase({ cell->getCell()->getGridX(), cell->getCell()->getGridY() });
else
mInteriorSegments.clear(); mInteriorSegments.clear();
} }
@ -299,6 +304,7 @@ namespace MWRender
return; return;
mInterior = true; mInterior = true;
mExteriorSegments.clear();
mBounds = bounds; mBounds = bounds;
@ -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); pos = rotatePoint(pos, mCenter, mAngle);
@ -435,7 +441,7 @@ namespace MWRender
nY = 1.0f - (pos.y() - min.y() - mMapWorldSize * y) / mMapWorldSize; 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 min(mBounds.xMin(), mBounds.yMin());
osg::Vec2f pos(mMapWorldSize * (nX + x) + min.x(), mMapWorldSize * (1.0f - nY + y) + min.y()); osg::Vec2f pos(mMapWorldSize * (nX + x) + min.x(), mMapWorldSize * (1.0f - nY + y) + min.y());
@ -571,8 +577,11 @@ namespace MWRender
}; };
std::uint8_t result = 0; std::uint8_t result = 0;
for (const auto& [flag, dx, dy] : flags) 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; result |= flag;
}
return result; return result;
} }

View File

@ -83,14 +83,14 @@ namespace MWRender
* Save the fog of war for this cell to its CellStore. * 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. * @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 * 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) * 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; int mCellDistance;
float mAngle; 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 requestExteriorMap(const MWWorld::CellStore* cell, MapSegment& segment);
void requestInteriorMap(const MWWorld::CellStore* cell); void requestInteriorMap(const MWWorld::CellStore* cell);