[Local map] Use the distance view in the local map

dont-compose-content
CedricMocquillon 4 years ago committed by Cédric Mocquillon
parent ed04ebe9ff
commit 8c87defddf

@ -85,6 +85,23 @@ namespace
setColour(mHoverColour);
}
};
MyGUI::IntRect createRect(const MyGUI::IntPoint& center, int radius)
{
return { center.left - radius, center.top + radius, center.left + radius, center.top - radius };
}
int getLocalViewingDistance()
{
if (!Settings::Manager::getBool("allow zooming", "Map"))
return Constants::CellGridRadius;
if (!Settings::Manager::getBool("distant terrain", "Terrain"))
return Constants::CellGridRadius;
const float localViewingDistanceCoef = Settings::Manager::getFloat("local viewing distance coef", "Map");
const int viewingDistance = Settings::Manager::getInt("viewing distance", "Camera");
const int localViewingDistanceInCells = (viewingDistance * localViewingDistanceCoef) / double(Constants::CellSizeInUnits);
return std::max(Constants::CellGridRadius, localViewingDistanceInCells);
}
}
namespace MWGui
@ -174,7 +191,6 @@ namespace MWGui
, mMarkerUpdateTimer(0.0f)
, mLastDirectionX(0.0f)
, mLastDirectionY(0.0f)
, mNeedDoorMarkersUpdate(false)
{
mCustomMarkers.eventMarkersChanged += MyGUI::newDelegate(this, &LocalMapBase::updateCustomMarkers);
}
@ -184,12 +200,12 @@ namespace MWGui
mCustomMarkers.eventMarkersChanged -= MyGUI::newDelegate(this, &LocalMapBase::updateCustomMarkers);
}
void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass)
void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int cellDistance)
{
mLocalMap = widget;
mCompass = compass;
mMapWidgetSize = std::max(1, Settings::Manager::getInt("local map widget size", "Map"));
mCellDistance = Constants::CellGridRadius;
mCellDistance = cellDistance;
mNumCells = mCellDistance * 2 + 1;
mLocalMap->setCanvasSize(mMapWidgetSize*mNumCells, mMapWidgetSize*mNumCells);
@ -320,6 +336,11 @@ namespace MWGui
return MyGUI::IntCoord(position.left - markerSize / 2, position.top - markerSize / 2, markerSize, markerSize);
}
std::vector<MyGUI::Widget*>& LocalMapBase::currentDoorMarkersWidgets()
{
return mInterior ? mInteriorDoorMarkerWidgets : mExteriorDoorMarkerWidgets;
}
void LocalMapBase::updateCustomMarkers()
{
for (MyGUI::Widget* widget : mCustomMarkerWidgets)
@ -366,6 +387,38 @@ namespace MWGui
if (x==mCurX && y==mCurY && mInterior==interior && !mChanged)
return; // don't do anything if we're still in the same cell
if (!interior && !(x == mCurX && y == mCurY))
{
const MyGUI::IntRect intersection = {
std::max(x, mCurX) - mCellDistance, std::max(y, mCurY) - mCellDistance,
std::min(x, mCurX) + mCellDistance, std::min(y, mCurY) + mCellDistance
};
const MyGUI::IntRect activeGrid = createRect({ x, y }, Constants::CellGridRadius);
const MyGUI::IntRect currentView = createRect({ x, y }, mCellDistance);
mExteriorDoorMarkerWidgets.clear();
for (auto& [coord, doors] : mExteriorDoorsByCell)
{
if (!mHasALastActiveCell || !currentView.inside({ coord.first, coord.second }) || activeGrid.inside({ coord.first, coord.second }))
{
mDoorMarkersToRecycle.insert(mDoorMarkersToRecycle.end(), doors.begin(), doors.end());
doors.clear();
}
else
mExteriorDoorMarkerWidgets.insert(mExteriorDoorMarkerWidgets.end(), doors.begin(), doors.end());
}
for (auto& widget : mDoorMarkersToRecycle)
widget->setVisible(false);
for (auto const& cell : mMaps)
{
if (mHasALastActiveCell && !intersection.inside({ cell.mCellX, cell.mCellY }))
mLocalMapRender->removeExteriorCell(cell.mCellX, cell.mCellY);
}
}
mCurX = x;
mCurY = y;
mInterior = interior;
@ -386,12 +439,11 @@ namespace MWGui
}
}
for (MyGUI::Widget* widget : mDoorMarkerWidgets)
for (MyGUI::Widget* widget : currentDoorMarkersWidgets())
widget->setCoord(getMarkerCoordinates(widget, 8));
// 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.
mNeedDoorMarkersUpdate = true;
if (!mInterior)
mHasALastActiveCell = true;
updateMagicMarkers();
updateCustomMarkers();
@ -491,11 +543,7 @@ namespace MWGui
void LocalMapBase::onFrame(float dt)
{
if (mNeedDoorMarkersUpdate)
{
updateDoorMarkers();
mNeedDoorMarkersUpdate = false;
}
updateDoorMarkers();
mMarkerUpdateTimer += dt;
@ -570,30 +618,29 @@ namespace MWGui
void LocalMapBase::updateDoorMarkers()
{
// clear all previous door markers
for (MyGUI::Widget* widget : mDoorMarkerWidgets)
MyGUI::Gui::getInstance().destroyWidget(widget);
mDoorMarkerWidgets.clear();
std::vector<MWBase::World::DoorMarker> doors;
MWBase::World* world = MWBase::Environment::get().getWorld();
// Retrieve the door markers we want to show
std::vector<MWBase::World::DoorMarker> doors;
mDoorMarkersToRecycle.insert(mDoorMarkersToRecycle.end(), mInteriorDoorMarkerWidgets.begin(), mInteriorDoorMarkerWidgets.end());
mInteriorDoorMarkerWidgets.clear();
if (mInterior)
{
for (MyGUI::Widget* widget : mExteriorDoorMarkerWidgets)
widget->setVisible(false);
MWWorld::CellStore* cell = world->getInterior (mPrefix);
world->getDoorMarkers(cell, doors);
}
else
{
for (int x = mCurX - mCellDistance; x <= mCurX + mCellDistance; ++x)
for (MapEntry& entry : mMaps)
{
for (int y = mCurY - mCellDistance; y <= mCurY + mCellDistance; ++y)
{
MWWorld::CellStore* cell = world->getExterior (x, y);
world->getDoorMarkers(cell, doors);
}
if (!entry.mMapTexture && !widgetCropped(entry.mMapWidget, mLocalMap))
world->getDoorMarkers(world->getExterior(entry.mCellX, entry.mCellY), doors);
}
if (doors.empty())
return;
}
// Create a widget for each marker
@ -604,11 +651,33 @@ namespace MWGui
for (CustomMarkerCollection::ContainerType::const_iterator iter = markers.first; iter != markers.second; ++iter)
destNotes.push_back(iter->second.mNote);
MyGUI::Widget* markerWidget = createDoorMarker(marker.name, destNotes, marker.x, marker.y);
doorMarkerCreated(markerWidget);
MyGUI::Widget* markerWidget = nullptr;
MarkerUserData* data;
if (mDoorMarkersToRecycle.empty())
{
markerWidget = createDoorMarker(marker.name, destNotes, marker.x, marker.y);
data = markerWidget->getUserData<MarkerUserData>();
doorMarkerCreated(markerWidget);
}
else
{
markerWidget = (MarkerWidget*)mDoorMarkersToRecycle.back();
mDoorMarkersToRecycle.pop_back();
data = markerWidget->getUserData<MarkerUserData>();
data->notes = destNotes;
data->caption = marker.name;
markerWidget->setCoord(getMarkerCoordinates(marker.x, marker.y, *data, 8));
markerWidget->setVisible(true);
}
mDoorMarkerWidgets.push_back(markerWidget);
currentDoorMarkersWidgets().push_back(markerWidget);
if (!mInterior)
mExteriorDoorsByCell[{data->cellX, data->cellY}].push_back(markerWidget);
}
for (auto& widget : mDoorMarkersToRecycle)
widget->setVisible(false);
}
void LocalMapBase::updateMagicMarkers()
@ -656,7 +725,7 @@ namespace MWGui
}
MarkerUserData markerPos(mLocalMapRender);
for (MyGUI::Widget* widget : mDoorMarkerWidgets)
for (MyGUI::Widget* widget : currentDoorMarkersWidgets())
widget->setCoord(getMarkerCoordinates(widget, 8));
for (MyGUI::Widget* widget : mCustomMarkerWidgets)
@ -670,7 +739,6 @@ namespace MWGui
}
// ------------------------------------------------------------------------------------------
MapWindow::MapWindow(CustomMarkerCollection &customMarkers, DragAndDrop* drag, MWRender::LocalMap* localMapRender, SceneUtil::WorkQueue* workQueue)
: WindowPinnableBase("openmw_map_window.layout")
, LocalMapBase(customMarkers, localMapRender)
@ -730,7 +798,7 @@ namespace MWGui
mEventBoxLocal->eventMouseButtonDoubleClick += MyGUI::newDelegate(this, &MapWindow::onMapDoubleClicked);
mEventBoxLocal->eventMouseWheel += MyGUI::newDelegate(this, &MapWindow::onMapZoomed);
LocalMapBase::init(mLocalMap, mPlayerArrowLocal);
LocalMapBase::init(mLocalMap, mPlayerArrowLocal, getLocalViewingDistance());
mGlobalMap->setVisible(mGlobal);
mLocalMap->setVisible(!mGlobal);

@ -9,6 +9,7 @@
#include <components/esm/cellid.hpp>
#include <components/esm/custommarkerstate.hpp>
#include <components/misc/constants.hpp>
namespace MWRender
{
@ -72,7 +73,7 @@ namespace MWGui
public:
LocalMapBase(CustomMarkerCollection& markers, MWRender::LocalMap* localMapRender, bool fogOfWarEnabled = true);
virtual ~LocalMapBase();
void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass);
void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int cellDistance = Constants::CellGridRadius);
void setCellPrefix(const std::string& prefix);
void setActiveCell(const int x, const int y, bool interior=false);
@ -113,7 +114,9 @@ namespace MWGui
MWRender::LocalMap* mLocalMapRender;
int mCurX, mCurY; //the position of the active cell on the global map (in cell coords)
bool mHasALastActiveCell = false;
osg::Vec2f mCurPos; //the position of the player in the world (in cell coords)
bool mInterior;
MyGUI::ScrollView* mLocalMap;
MyGUI::ImageBox* mCompass;
@ -145,9 +148,14 @@ namespace MWGui
std::vector<MapEntry> mMaps;
// Keep track of created marker widgets, just to easily remove them later.
std::vector<MyGUI::Widget*> mDoorMarkerWidgets;
std::vector<MyGUI::Widget*> mExteriorDoorMarkerWidgets;
std::map<std::pair<int, int>, std::vector<MyGUI::Widget*>> mExteriorDoorsByCell;
std::vector<MyGUI::Widget*> mInteriorDoorMarkerWidgets;
std::vector<MyGUI::Widget*> mMagicMarkerWidgets;
std::vector<MyGUI::Widget*> mCustomMarkerWidgets;
std::vector<MyGUI::Widget*> mDoorMarkersToRecycle;
std::vector<MyGUI::Widget*>& currentDoorMarkersWidgets();
virtual void updateCustomMarkers();
@ -181,7 +189,6 @@ namespace MWGui
private:
void updateDoorMarkers();
bool mNeedDoorMarkersUpdate;
};
class EditNoteDialog : public MWGui::WindowModal

@ -118,14 +118,15 @@ const osg::Vec2f LocalMap::rotatePoint(const osg::Vec2f& point, const osg::Vec2f
void LocalMap::clear()
{
mSegments.clear();
mExteriorSegments.clear();
mInteriorSegments.clear();
}
void LocalMap::saveFogOfWar(MWWorld::CellStore* cell)
{
if (!mInterior)
{
const MapSegment& segment = mSegments[std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())];
const MapSegment& segment = mExteriorSegments[std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())];
if (segment.mFogOfWarImage && segment.mHasFogState)
{
@ -155,7 +156,7 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell)
{
for (int y = 0; y < segments.second; ++y)
{
const MapSegment& segment = mSegments[std::make_pair(x,y)];
const MapSegment& segment = mInteriorSegments[std::make_pair(x,y)];
fog->mFogTextures.emplace_back();
@ -249,26 +250,10 @@ void LocalMap::setupRenderToTexture(osg::ref_ptr<osg::Camera> camera, int x, int
mRoot->addChild(camera);
mActiveCameras.push_back(camera);
MapSegment& segment = mSegments[std::make_pair(x, y)];
MapSegment& segment = mInterior? mInteriorSegments[std::make_pair(x, y)] : mExteriorSegments[std::make_pair(x, y)];
segment.mMapTexture = texture;
}
bool needUpdate(std::set<std::pair<int, int> >& renderedGrid, std::set<std::pair<int, int> >& currentGrid, int cellX, int cellY)
{
// if all the cells of the current grid are contained in the rendered grid then we can keep the old render
for (int dx=-1;dx<2;dx+=1)
{
for (int dy=-1;dy<2;dy+=1)
{
bool haveInRenderedGrid = renderedGrid.find(std::make_pair(cellX+dx,cellY+dy)) != renderedGrid.end();
bool haveInCurrentGrid = currentGrid.find(std::make_pair(cellX+dx,cellY+dy)) != currentGrid.end();
if (haveInCurrentGrid && !haveInRenderedGrid)
return true;
}
}
return false;
}
void LocalMap::requestMap(const MWWorld::CellStore* cell)
{
if (cell->isExterior())
@ -276,13 +261,13 @@ void LocalMap::requestMap(const MWWorld::CellStore* cell)
int cellX = cell->getCell()->getGridX();
int cellY = cell->getCell()->getGridY();
MapSegment& segment = mSegments[std::make_pair(cellX, cellY)];
if (!needUpdate(segment.mGrid, mCurrentGrid, cellX, cellY))
MapSegment& segment = mExteriorSegments[std::make_pair(cellX, cellY)];
if (!segment.needUpdate)
return;
else
{
segment.mGrid = mCurrentGrid;
requestExteriorMap(cell);
segment.needUpdate = false;
}
}
else
@ -292,27 +277,27 @@ void LocalMap::requestMap(const MWWorld::CellStore* cell)
void LocalMap::addCell(MWWorld::CellStore *cell)
{
if (cell->isExterior())
mCurrentGrid.emplace(cell->getCell()->getGridX(), cell->getCell()->getGridY());
mExteriorSegments[std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())].needUpdate = true;
}
void LocalMap::removeExteriorCell(int x, int y)
{
mExteriorSegments.erase({ x, y });
}
void LocalMap::removeCell(MWWorld::CellStore *cell)
{
saveFogOfWar(cell);
if (cell->isExterior())
{
std::pair<int, int> coords = std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY());
mSegments.erase(coords);
mCurrentGrid.erase(coords);
}
else
mSegments.clear();
if (!cell->isExterior())
mInteriorSegments.clear();
}
osg::ref_ptr<osg::Texture2D> LocalMap::getMapTexture(int x, int y)
{
SegmentMap::iterator found = mSegments.find(std::make_pair(x, y));
if (found == mSegments.end())
auto& segments(mInterior ? mInteriorSegments : mExteriorSegments);
SegmentMap::iterator found = segments.find(std::make_pair(x, y));
if (found == segments.end())
return osg::ref_ptr<osg::Texture2D>();
else
return found->second.mMapTexture;
@ -320,8 +305,9 @@ osg::ref_ptr<osg::Texture2D> LocalMap::getMapTexture(int x, int y)
osg::ref_ptr<osg::Texture2D> LocalMap::getFogOfWarTexture(int x, int y)
{
SegmentMap::iterator found = mSegments.find(std::make_pair(x, y));
if (found == mSegments.end())
auto& segments(mInterior ? mInteriorSegments : mExteriorSegments);
SegmentMap::iterator found = segments.find(std::make_pair(x, y));
if (found == segments.end())
return osg::ref_ptr<osg::Texture2D>();
else
return found->second.mFogOfWarTexture;
@ -371,7 +357,7 @@ void LocalMap::requestExteriorMap(const MWWorld::CellStore* cell)
osg::Vec3d(0,1,0), zmin, zmax);
setupRenderToTexture(camera, cell->getCell()->getGridX(), cell->getCell()->getGridY());
MapSegment& segment = mSegments[std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())];
MapSegment& segment = mExteriorSegments[std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())];
if (!segment.mFogOfWarImage)
{
if (cell->getFog())
@ -512,7 +498,7 @@ void LocalMap::requestInteriorMap(const MWWorld::CellStore* cell)
setupRenderToTexture(camera, x, y);
auto coords = std::make_pair(x,y);
MapSegment& segment = mSegments[coords];
MapSegment& segment = mInteriorSegments[coords];
if (!segment.mFogOfWarImage)
{
bool loaded = false;
@ -558,7 +544,8 @@ osg::Vec2f LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, int
bool LocalMap::isPositionExplored (float nX, float nY, int x, int y)
{
const MapSegment& segment = mSegments[std::make_pair(x, y)];
auto& segments(mInterior ? mInteriorSegments : mExteriorSegments);
const MapSegment& segment = segments[std::make_pair(x, y)];
if (!segment.mFogOfWarImage)
return false;
@ -630,7 +617,8 @@ void LocalMap::updatePlayer (const osg::Vec3f& position, const osg::Quat& orient
int texX = x + mx;
int texY = y + my*-1;
MapSegment& segment = mSegments[std::make_pair(texX, texY)];
auto& segments(mInterior ? mInteriorSegments : mExteriorSegments);
MapSegment& segment = segments[std::make_pair(texX, texY)];
if (!segment.mFogOfWarImage || !segment.mMapTexture)
continue;

@ -50,6 +50,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);
@ -126,13 +127,14 @@ namespace MWRender
osg::ref_ptr<osg::Texture2D> mFogOfWarTexture;
osg::ref_ptr<osg::Image> mFogOfWarImage;
Grid mGrid; // the grid that was active at the time of rendering this segment
bool needUpdate = true;
bool mHasFogState;
};
typedef std::map<std::pair<int, int>, MapSegment> SegmentMap;
SegmentMap mSegments;
SegmentMap mExteriorSegments;
SegmentMap mInteriorSegments;
int mMapResolution;

@ -114,3 +114,15 @@ allow zooming
If this setting is true the user can zoom in/out on local and global map with the mouse wheel.
This setting can be controlled in Advanced tab of the launcher.
local viewing distance coef
---------------------------
:Type: float
:Range: > 0 and <= 1
:Default: 0.5
This setting controls viewing distance on local map. It is the coefficient of the viewing distance viewable on the local map if 'distant terrain' is enabled otherwise you will see the default value (a 3x3 square centered on the player).
If view distance is changed in settings menu during the game, then viewable distance on the local map is not updated.
This setting can not be configured except by editing the settings configuration file.

@ -202,6 +202,9 @@ global = false
# If true, allow zoom on local and global maps
allow zooming = false
# The local view distance coefficient (1.0 is full view distance if distant terrain is enabled)
local viewing distance coef = 0.5
[GUI]
# Scales GUI window and widget size. (<1.0 is smaller, >1.0 is larger).

Loading…
Cancel
Save