Merge branch 'coc' into 'master'

Use a grid based on computed bounds for interiors

See merge request OpenMW/openmw!4459
master
psi29a 1 month ago
commit fe15803239

@ -102,6 +102,11 @@ namespace
return ESM::Cell::generateIdForCell(true, {}, x, y); return ESM::Cell::generateIdForCell(true, {}, x, y);
return cell.getId(); return cell.getId();
} }
void setCanvasSize(MyGUI::ScrollView* scrollView, const MyGUI::IntRect& grid, int widgetSize)
{
scrollView->setCanvasSize(widgetSize * (grid.width() + 1), widgetSize * (grid.height() + 1));
}
} }
namespace MWGui namespace MWGui
@ -177,18 +182,8 @@ namespace MWGui
LocalMapBase::LocalMapBase( LocalMapBase::LocalMapBase(
CustomMarkerCollection& markers, MWRender::LocalMap* localMapRender, bool fogOfWarEnabled) CustomMarkerCollection& markers, MWRender::LocalMap* localMapRender, bool fogOfWarEnabled)
: mLocalMapRender(localMapRender) : mLocalMapRender(localMapRender)
, mActiveCell(nullptr)
, mLocalMap(nullptr)
, mCompass(nullptr)
, mFogOfWarToggled(true)
, mFogOfWarEnabled(fogOfWarEnabled) , mFogOfWarEnabled(fogOfWarEnabled)
, mNumCells(1)
, mCellDistance(0)
, mCustomMarkers(markers) , mCustomMarkers(markers)
, mMarkerUpdateTimer(0.0f)
, mLastDirectionX(0.0f)
, mLastDirectionY(0.0f)
, mNeedDoorMarkersUpdate(false)
{ {
mCustomMarkers.eventMarkersChanged += MyGUI::newDelegate(this, &LocalMapBase::updateCustomMarkers); mCustomMarkers.eventMarkersChanged += MyGUI::newDelegate(this, &LocalMapBase::updateCustomMarkers);
} }
@ -198,41 +193,40 @@ namespace MWGui
mCustomMarkers.eventMarkersChanged -= MyGUI::newDelegate(this, &LocalMapBase::updateCustomMarkers); mCustomMarkers.eventMarkersChanged -= MyGUI::newDelegate(this, &LocalMapBase::updateCustomMarkers);
} }
void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int cellDistance) MWGui::LocalMapBase::MapEntry& LocalMapBase::addMapEntry()
{ {
mLocalMap = widget;
mCompass = compass;
mCellDistance = cellDistance;
mNumCells = mCellDistance * 2 + 1;
const int mapWidgetSize = Settings::map().mLocalMapWidgetSize; const int mapWidgetSize = Settings::map().mLocalMapWidgetSize;
MyGUI::ImageBox* map = mLocalMap->createWidget<MyGUI::ImageBox>(
mLocalMap->setCanvasSize(mapWidgetSize * mNumCells, mapWidgetSize * mNumCells); "ImageBox", MyGUI::IntCoord(0, 0, mapWidgetSize, mapWidgetSize), MyGUI::Align::Top | MyGUI::Align::Left);
mCompass->setDepth(Local_CompassLayer);
mCompass->setNeedMouseFocus(false);
for (int mx = 0; mx < mNumCells; ++mx)
{
for (int my = 0; my < mNumCells; ++my)
{
MyGUI::ImageBox* map = mLocalMap->createWidget<MyGUI::ImageBox>("ImageBox",
MyGUI::IntCoord(mx * mapWidgetSize, my * mapWidgetSize, mapWidgetSize, mapWidgetSize),
MyGUI::Align::Top | MyGUI::Align::Left);
map->setDepth(Local_MapLayer); map->setDepth(Local_MapLayer);
MyGUI::ImageBox* fog = mLocalMap->createWidget<MyGUI::ImageBox>("ImageBox", MyGUI::ImageBox* fog = mLocalMap->createWidget<MyGUI::ImageBox>(
MyGUI::IntCoord(mx * mapWidgetSize, my * mapWidgetSize, mapWidgetSize, mapWidgetSize), "ImageBox", MyGUI::IntCoord(0, 0, mapWidgetSize, mapWidgetSize), MyGUI::Align::Top | MyGUI::Align::Left);
MyGUI::Align::Top | MyGUI::Align::Left);
fog->setDepth(Local_FogLayer); fog->setDepth(Local_FogLayer);
fog->setColour(MyGUI::Colour(0, 0, 0)); fog->setColour(MyGUI::Colour(0, 0, 0));
map->setNeedMouseFocus(false); map->setNeedMouseFocus(false);
fog->setNeedMouseFocus(false); fog->setNeedMouseFocus(false);
mMaps.emplace_back(map, fog); return mMaps.emplace_back(map, fog);
}
} }
void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int cellDistance)
{
mLocalMap = widget;
mCompass = compass;
mGrid = createRect({ 0, 0 }, cellDistance);
mExtCellDistance = cellDistance;
const int mapWidgetSize = Settings::map().mLocalMapWidgetSize;
setCanvasSize(mLocalMap, mGrid, mapWidgetSize);
mCompass->setDepth(Local_CompassLayer);
mCompass->setNeedMouseFocus(false);
int numCells = (mGrid.width() + 1) * (mGrid.height() + 1);
for (int i = 0; i < numCells; ++i)
addMapEntry();
} }
bool LocalMapBase::toggleFogOfWar() bool LocalMapBase::toggleFogOfWar()
@ -260,8 +254,8 @@ namespace MWGui
{ {
// normalized cell coordinates // normalized cell coordinates
auto mapWidgetSize = getWidgetSize(); auto mapWidgetSize = getWidgetSize();
return MyGUI::IntPoint(std::round((nX + mCellDistance + cellX - mActiveCell->getGridX()) * mapWidgetSize), return MyGUI::IntPoint(std::round((nX + cellX - mGrid.left) * mapWidgetSize),
std::round((nY + mCellDistance - cellY + mActiveCell->getGridY()) * mapWidgetSize)); std::round((nY - cellY + mGrid.bottom) * mapWidgetSize));
} }
MyGUI::IntPoint LocalMapBase::getMarkerPosition(float worldX, float worldY, MarkerUserData& markerPos) const MyGUI::IntPoint LocalMapBase::getMarkerPosition(float worldX, float worldY, MarkerUserData& markerPos) const
@ -344,19 +338,10 @@ namespace MWGui
mCustomMarkerWidgets.clear(); mCustomMarkerWidgets.clear();
if (!mActiveCell) if (!mActiveCell)
return; return;
for (int dX = -mCellDistance; dX <= mCellDistance; ++dX) auto updateMarkers = [this](CustomMarkerCollection::RangeType markers) {
{ for (auto it = markers.first; it != markers.second; ++it)
for (int dY = -mCellDistance; dY <= mCellDistance; ++dY)
{
ESM::RefId cellRefId
= getCellIdInWorldSpace(*mActiveCell, mActiveCell->getGridX() + dX, mActiveCell->getGridY() + dY);
CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellRefId);
for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second;
++it)
{ {
const ESM::CustomMarker& marker = it->second; const ESM::CustomMarker& marker = it->second;
MarkerUserData markerPos(mLocalMapRender); MarkerUserData markerPos(mLocalMapRender);
MarkerWidget* markerWidget = mLocalMap->createWidget<MarkerWidget>("CustomMarkerButton", MarkerWidget* markerWidget = mLocalMap->createWidget<MarkerWidget>("CustomMarkerButton",
getMarkerCoordinates(marker.mWorldX, marker.mWorldY, markerPos, 16), MyGUI::Align::Default); getMarkerCoordinates(marker.mWorldX, marker.mWorldY, markerPos, 16), MyGUI::Align::Default);
@ -371,8 +356,20 @@ namespace MWGui
customMarkerCreated(markerWidget); customMarkerCreated(markerWidget);
mCustomMarkerWidgets.push_back(markerWidget); mCustomMarkerWidgets.push_back(markerWidget);
} }
};
if (mActiveCell->isExterior())
{
for (int x = mGrid.left; x <= mGrid.right; ++x)
{
for (int y = mGrid.top; y <= mGrid.bottom; ++y)
{
ESM::RefId cellRefId = getCellIdInWorldSpace(*mActiveCell, x, y);
updateMarkers(mCustomMarkers.getMarkers(cellRefId));
} }
} }
}
else
updateMarkers(mCustomMarkers.getMarkers(mActiveCell->getId()));
redraw(); redraw();
} }
@ -385,15 +382,17 @@ namespace MWGui
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() };
if (cell.isExterior()) if (cell.isExterior())
{ {
mGrid = createRect({ x, y }, mExtCellDistance);
const MyGUI::IntRect activeGrid = createRect({ x, y }, Constants::CellGridRadius); const MyGUI::IntRect activeGrid = createRect({ x, y }, Constants::CellGridRadius);
const MyGUI::IntRect currentView = createRect({ x, y }, mCellDistance);
mExteriorDoorMarkerWidgets.clear(); mExteriorDoorMarkerWidgets.clear();
for (auto& [coord, doors] : mExteriorDoorsByCell) for (auto& [coord, doors] : mExteriorDoorsByCell)
{ {
if (!mHasALastActiveCell || !currentView.inside({ coord.first, coord.second }) if (!mHasALastActiveCell || !mGrid.inside({ coord.first, coord.second })
|| activeGrid.inside({ coord.first, coord.second })) || activeGrid.inside({ coord.first, coord.second }))
{ {
mDoorMarkersToRecycle.insert(mDoorMarkersToRecycle.end(), doors.begin(), doors.end()); mDoorMarkersToRecycle.insert(mDoorMarkersToRecycle.end(), doors.begin(), doors.end());
@ -410,28 +409,50 @@ namespace MWGui
{ {
for (const auto& entry : mMaps) for (const auto& entry : mMaps)
{ {
if (!currentView.inside({ entry.mCellX, entry.mCellY })) if (!mGrid.inside({ entry.mCellX, entry.mCellY }))
mLocalMapRender->removeExteriorCell(entry.mCellX, entry.mCellY); mLocalMapRender->removeExteriorCell(entry.mCellX, entry.mCellY);
} }
} }
} }
else
mGrid = mLocalMapRender->getInteriorGrid();
mActiveCell = &cell; mActiveCell = &cell;
for (int mx = 0; mx < mNumCells; ++mx) constexpr auto resetEntry = [](MapEntry& entry, bool visible, const MyGUI::IntPoint* position) {
{ entry.mMapWidget->setVisible(visible);
for (int my = 0; my < mNumCells; ++my) entry.mFogWidget->setVisible(visible);
if (position)
{ {
MapEntry& entry = mMaps[my + mNumCells * mx]; entry.mMapWidget->setPosition(*position);
entry.mFogWidget->setPosition(*position);
}
entry.mMapWidget->setRenderItemTexture(nullptr); entry.mMapWidget->setRenderItemTexture(nullptr);
entry.mFogWidget->setRenderItemTexture(nullptr); entry.mFogWidget->setRenderItemTexture(nullptr);
entry.mMapTexture.reset(); entry.mMapTexture.reset();
entry.mFogTexture.reset(); entry.mFogTexture.reset();
};
entry.mCellX = x + (mx - mCellDistance); std::size_t usedEntries = 0;
entry.mCellY = y - (my - mCellDistance); for (int cx = mGrid.left; cx <= mGrid.right; ++cx)
{
for (int cy = mGrid.top; cy <= mGrid.bottom; ++cy)
{
MapEntry& entry = usedEntries < mMaps.size() ? mMaps[usedEntries] : addMapEntry();
entry.mCellX = cx;
entry.mCellY = cy;
MyGUI::IntPoint position = getPosition(cx, cy, 0, 0);
resetEntry(entry, true, &position);
++usedEntries;
} }
} }
for (std::size_t i = usedEntries; i < mMaps.size(); ++i)
{
resetEntry(mMaps[i], false, nullptr);
}
if (oldSize != MyGUI::IntSize{ mGrid.width(), mGrid.height() })
setCanvasSize(mLocalMap, mGrid, getWidgetSize());
// 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.
@ -558,15 +579,7 @@ namespace MWGui
{ {
MyGUI::IntRect coord = widget->getAbsoluteRect(); MyGUI::IntRect coord = widget->getAbsoluteRect();
MyGUI::IntRect croppedCoord = cropTo->getAbsoluteRect(); MyGUI::IntRect croppedCoord = cropTo->getAbsoluteRect();
if (coord.left < croppedCoord.left && coord.right < croppedCoord.left) return !coord.intersect(croppedCoord);
return true;
if (coord.left > croppedCoord.right && coord.right > croppedCoord.right)
return true;
if (coord.top < croppedCoord.top && coord.bottom < croppedCoord.top)
return true;
if (coord.top > croppedCoord.bottom && coord.bottom > croppedCoord.bottom)
return true;
return false;
} }
void LocalMapBase::updateRequiredMaps() void LocalMapBase::updateRequiredMaps()
@ -719,7 +732,7 @@ namespace MWGui
void LocalMapBase::updateLocalMap() void LocalMapBase::updateLocalMap()
{ {
auto mapWidgetSize = getWidgetSize(); auto mapWidgetSize = getWidgetSize();
mLocalMap->setCanvasSize(mapWidgetSize * mNumCells, mapWidgetSize * mNumCells); setCanvasSize(mLocalMap, mGrid, getWidgetSize());
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)
@ -864,12 +877,10 @@ namespace MWGui
MyGUI::IntPoint widgetPos = clickedPos - mEventBoxLocal->getAbsolutePosition(); MyGUI::IntPoint widgetPos = clickedPos - mEventBoxLocal->getAbsolutePosition();
auto mapWidgetSize = getWidgetSize(); auto mapWidgetSize = getWidgetSize();
int x = int(widgetPos.left / float(mapWidgetSize)) - mCellDistance; int x = int(widgetPos.left / float(mapWidgetSize)) + mGrid.left;
int y = (int(widgetPos.top / float(mapWidgetSize)) - mCellDistance) * -1; int y = mGrid.bottom - int(widgetPos.top / float(mapWidgetSize));
float nX = widgetPos.left / float(mapWidgetSize) - int(widgetPos.left / float(mapWidgetSize)); float nX = widgetPos.left / float(mapWidgetSize) - int(widgetPos.left / float(mapWidgetSize));
float nY = widgetPos.top / float(mapWidgetSize) - int(widgetPos.top / float(mapWidgetSize)); float nY = widgetPos.top / float(mapWidgetSize) - int(widgetPos.top / float(mapWidgetSize));
x += mActiveCell->getGridX();
y += mActiveCell->getGridY();
osg::Vec2f worldPos; osg::Vec2f worldPos;
if (!mActiveCell->isExterior()) if (!mActiveCell->isExterior())
@ -899,11 +910,11 @@ namespace MWGui
const bool zoomOut = rel < 0; const bool zoomOut = rel < 0;
const bool zoomIn = !zoomOut; const bool zoomIn = !zoomOut;
const double speedDiff = zoomOut ? 1.0 / speed : speed; const double speedDiff = zoomOut ? 1.0 / speed : speed;
const float localMapSizeInUnits = localWidgetSize * mNumCells;
const float currentMinLocalMapZoom = std::max({ (float(Settings::map().mGlobalMapCellSize) * 4.f) const float currentMinLocalMapZoom
/ float(localWidgetSize), = std::max({ (float(Settings::map().mGlobalMapCellSize) * 4.f) / float(localWidgetSize),
float(mLocalMap->getWidth()) / localMapSizeInUnits, float(mLocalMap->getHeight()) / localMapSizeInUnits }); float(mLocalMap->getWidth()) / (localWidgetSize * (mGrid.width() + 1)),
float(mLocalMap->getHeight()) / (localWidgetSize * (mGrid.height() + 1)) });
if (Settings::map().mGlobal) if (Settings::map().mGlobal)
{ {

@ -112,20 +112,17 @@ namespace MWGui
protected: protected:
void updateLocalMap(); void updateLocalMap();
float mLocalMapZoom = 1.f;
MWRender::LocalMap* mLocalMapRender; MWRender::LocalMap* mLocalMapRender;
const MWWorld::Cell* mActiveCell = nullptr;
const MWWorld::Cell* mActiveCell;
bool mHasALastActiveCell = false;
osg::Vec2f mCurPos; // the position of the player in the world (in cell coords) osg::Vec2f mCurPos; // the position of the player in the world (in cell coords)
MyGUI::ScrollView* mLocalMap; MyGUI::ScrollView* mLocalMap = nullptr;
MyGUI::ImageBox* mCompass; MyGUI::ImageBox* mCompass = nullptr;
bool mFogOfWarToggled; float mLocalMapZoom = 1.f;
bool mHasALastActiveCell = false;
bool mFogOfWarToggled = true;
bool mFogOfWarEnabled; bool mFogOfWarEnabled;
bool mNeedDoorMarkersUpdate = false;
int mNumCells; // for convenience, mCellDistance * 2 + 1
int mCellDistance;
// Stores markers that were placed by a player. May be shared between multiple map views. // Stores markers that were placed by a player. May be shared between multiple map views.
CustomMarkerCollection& mCustomMarkers; CustomMarkerCollection& mCustomMarkers;
@ -185,12 +182,14 @@ namespace MWGui
void redraw(); void redraw();
float getWidgetSize() const; float getWidgetSize() const;
float mMarkerUpdateTimer; MWGui::LocalMapBase::MapEntry& addMapEntry();
float mLastDirectionX; MyGUI::IntRect mGrid{ -1, -1, 1, 1 };
float mLastDirectionY; int mExtCellDistance = 0;
float mMarkerUpdateTimer = 0.f;
bool mNeedDoorMarkersUpdate; float mLastDirectionX = 0.f;
float mLastDirectionY = 0.f;
private: private:
void updateDoorMarkers(); void updateDoorMarkers();

@ -587,6 +587,12 @@ namespace MWRender
return result; return result;
} }
MyGUI::IntRect LocalMap::getInteriorGrid() const
{
auto segments = divideIntoSegments(mBounds, mMapWorldSize);
return { 0, 0, segments.first - 1, segments.second - 1 };
}
void LocalMap::MapSegment::createFogOfWarTexture() void LocalMap::MapSegment::createFogOfWarTexture()
{ {
if (mFogOfWarTexture) if (mFogOfWarTexture)

@ -6,6 +6,7 @@
#include <set> #include <set>
#include <vector> #include <vector>
#include <MyGUI_Types.h>
#include <osg/BoundingBox> #include <osg/BoundingBox>
#include <osg/Quat> #include <osg/Quat>
#include <osg/ref_ptr> #include <osg/ref_ptr>
@ -98,6 +99,8 @@ namespace MWRender
osg::Group* getRoot(); osg::Group* getRoot();
MyGUI::IntRect getInteriorGrid() const;
private: private:
osg::ref_ptr<osg::Group> mRoot; osg::ref_ptr<osg::Group> mRoot;
osg::ref_ptr<osg::Node> mSceneRoot; osg::ref_ptr<osg::Node> mSceneRoot;

Loading…
Cancel
Save