1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-04-15 23:42:20 +00:00

Merge branch 'Allow-Zoom-levels-on-the-World-Map' into 'master'

Allow Zoom levels on the World Map

See merge request OpenMW/openmw!275
This commit is contained in:
Petr Mikheev 2021-07-25 20:19:11 +00:00
commit 200ccfab69
11 changed files with 529 additions and 215 deletions

View File

@ -27,6 +27,7 @@
Bug #6174: Spellmaking and Enchanting sliders differences from vanilla
Feature #2554: Modifying an object triggers the instances table to scroll to the corresponding record
Feature #2780: A way to see current OpenMW version in the console
Feature #3616: Allow Zoom levels on the World Map
Feature #5489: MCP: Telekinesis fix for activators
Feature #5996: Support Lua scripts in OpenMW
Feature #6017: Separate persistent and temporary cell references when saving

View File

@ -192,6 +192,7 @@ bool Launcher::AdvancedPage::loadSettings()
if (showOwnedIndex >= 0 && showOwnedIndex <= 3)
showOwnedComboBox->setCurrentIndex(showOwnedIndex);
loadSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
loadSettingBool(useZoomOnMapCheckBox, "allow zooming", "Map");
loadSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
scalingSpinBox->setValue(Settings::Manager::getFloat("scaling factor", "GUI"));
}
@ -352,6 +353,7 @@ void Launcher::AdvancedPage::saveSettings()
if (showOwnedCurrentIndex != Settings::Manager::getInt("show owned", "Game"))
Settings::Manager::setInt("show owned", "Game", showOwnedCurrentIndex);
saveSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
saveSettingBool(useZoomOnMapCheckBox, "allow zooming", "Map");
saveSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
float uiScalingFactor = scalingSpinBox->value();
if (uiScalingFactor != Settings::Manager::getFloat("scaling factor", "GUI"))

View File

@ -30,10 +30,13 @@
#include "confirmationdialog.hpp"
#include "tooltips.hpp"
#include <numeric>
namespace
{
const int cellSize = Constants::CellSizeInUnits;
constexpr float speed = 1.08; //the zoom speed, it should be greater than 1
enum LocalMapWidgetDepth
{
@ -84,6 +87,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
@ -167,13 +187,12 @@ namespace MWGui
, mFogOfWarToggled(true)
, mFogOfWarEnabled(fogOfWarEnabled)
, mMapWidgetSize(0)
, mNumCells(0)
, mNumCells(1)
, mCellDistance(0)
, mCustomMarkers(markers)
, mMarkerUpdateTimer(0.0f)
, mLastDirectionX(0.0f)
, mLastDirectionY(0.0f)
, mNeedDoorMarkersUpdate(false)
{
mCustomMarkers.eventMarkersChanged += MyGUI::newDelegate(this, &LocalMapBase::updateCustomMarkers);
}
@ -183,12 +202,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);
@ -234,65 +253,94 @@ namespace MWGui
void LocalMapBase::applyFogOfWar()
{
for (int mx=0; mx<mNumCells; ++mx)
{
for (int my=0; my<mNumCells; ++my)
{
MapEntry& entry = mMaps[my + mNumCells*mx];
MyGUI::ImageBox* fog = entry.mFogWidget;
if (!mFogOfWarToggled || !mFogOfWarEnabled)
{
fog->setImageTexture("");
for (auto& entry : mMaps)
{
entry.mFogWidget->setImageTexture("");
entry.mFogTexture.reset();
continue;
}
}
}
redraw();
}
MyGUI::IntPoint LocalMapBase::getMarkerPosition(float worldX, float worldY, MarkerUserData& markerPos)
MyGUI::IntPoint LocalMapBase::getPosition(int cellX, int cellY, float nX, float nY) const
{
MyGUI::IntPoint widgetPos;
// normalized cell coordinates
auto mapWidgetSize = getWidgetSize();
return MyGUI::IntPoint(
std::round(nX * mapWidgetSize + (mCellDistance + (cellX - mCurX)) * mapWidgetSize),
std::round(nY * mapWidgetSize + (mCellDistance - (cellY - mCurY)) * mapWidgetSize)
);
}
MyGUI::IntPoint LocalMapBase::getMarkerPosition(float worldX, float worldY, MarkerUserData& markerPos) const
{
int cellX, cellY;
// normalized cell coordinates
float nX,nY;
if (!mInterior)
{
int cellX, cellY;
MWBase::Environment::get().getWorld()->positionToIndex(worldX, worldY, cellX, cellY);
nX = (worldX - cellSize * cellX) / cellSize;
// Image space is -Y up, cells are Y up
nY = 1 - (worldY - cellSize * cellY) / cellSize;
float cellDx = static_cast<float>(cellX - mCurX);
float cellDy = static_cast<float>(cellY - mCurY);
markerPos.cellX = cellX;
markerPos.cellY = cellY;
widgetPos = MyGUI::IntPoint(static_cast<int>(nX * mMapWidgetSize + (mCellDistance + cellDx) * mMapWidgetSize),
static_cast<int>(nY * mMapWidgetSize + (mCellDistance - cellDy) * mMapWidgetSize));
}
else
{
int cellX, cellY;
osg::Vec2f worldPos (worldX, worldY);
mLocalMapRender->worldToInteriorMapPosition(worldPos, nX, nY, cellX, cellY);
mLocalMapRender->worldToInteriorMapPosition({ worldX, worldY }, nX, nY, cellX, cellY);
markerPos.cellX = cellX;
markerPos.cellY = cellY;
// Image space is -Y up, cells are Y up
widgetPos = MyGUI::IntPoint(static_cast<int>(nX * mMapWidgetSize + (mCellDistance + (cellX - mCurX)) * mMapWidgetSize),
static_cast<int>(nY * mMapWidgetSize + (mCellDistance - (cellY - mCurY)) * mMapWidgetSize));
}
markerPos.nX = nX;
markerPos.nY = nY;
return widgetPos;
return getPosition(markerPos.cellX, markerPos.cellY, markerPos.nX, markerPos.nY);
}
MyGUI::IntCoord LocalMapBase::getMarkerCoordinates(float worldX, float worldY, MarkerUserData& markerPos, size_t markerSize) const
{
int halfMarkerSize = markerSize / 2;
auto position = getMarkerPosition(worldX, worldY, markerPos);
return MyGUI::IntCoord(position.left - halfMarkerSize, position.top - halfMarkerSize, markerSize, markerSize);
}
MyGUI::Widget* LocalMapBase::createDoorMarker(const std::string& name, const MyGUI::VectorString& notes, float x, float y) const
{
MarkerUserData data(mLocalMapRender);
data.notes = notes;
data.caption = name;
MarkerWidget* markerWidget = mLocalMap->createWidget<MarkerWidget>("MarkerButton",
getMarkerCoordinates(x, y, data, 8), MyGUI::Align::Default);
markerWidget->setNormalColour(MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=normal}")));
markerWidget->setHoverColour(MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=normal_over}")));
markerWidget->setDepth(Local_MarkerLayer);
markerWidget->setNeedMouseFocus(true);
// Used by tooltips to not show the tooltip if marker is hidden by fog of war
markerWidget->setUserString("ToolTipType", "MapMarker");
markerWidget->setUserData(data);
return markerWidget;
}
void LocalMapBase::centerView()
{
MyGUI::IntPoint pos = mCompass->getPosition() + MyGUI::IntPoint{ 16, 16 };
MyGUI::IntSize viewsize = mLocalMap->getSize();
MyGUI::IntPoint viewOffset((viewsize.width / 2) - pos.left, (viewsize.height / 2) - pos.top);
mLocalMap->setViewOffset(viewOffset);
}
MyGUI::IntCoord LocalMapBase::getMarkerCoordinates(MyGUI::Widget* widget, size_t markerSize) const
{
MarkerUserData& markerPos(*widget->getUserData<MarkerUserData>());
auto position = getPosition(markerPos.cellX, markerPos.cellY, markerPos.nX, markerPos.nY);
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()
@ -317,13 +365,8 @@ namespace MWGui
const ESM::CustomMarker& marker = it->second;
MarkerUserData markerPos (mLocalMapRender);
MyGUI::IntPoint widgetPos = getMarkerPosition(marker.mWorldX, marker.mWorldY, markerPos);
MyGUI::IntCoord widgetCoord(widgetPos.left - 8,
widgetPos.top - 8,
16, 16);
MarkerWidget* markerWidget = mLocalMap->createWidget<MarkerWidget>("CustomMarkerButton",
widgetCoord, MyGUI::Align::Default);
getMarkerCoordinates(marker.mWorldX, marker.mWorldY, markerPos, 16), MyGUI::Align::Default);
markerWidget->setDepth(Local_MarkerAboveFogLayer);
markerWidget->setUserString("ToolTipType", "Layout");
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
@ -346,6 +389,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;
@ -366,9 +441,11 @@ namespace MWGui
}
}
// 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;
for (MyGUI::Widget* widget : currentDoorMarkersWidgets())
widget->setCoord(getMarkerCoordinates(widget, 8));
if (!mInterior)
mHasALastActiveCell = true;
updateMagicMarkers();
updateCustomMarkers();
@ -385,21 +462,26 @@ namespace MWGui
mLocalMap->getParent()->_updateChilds();
}
float LocalMapBase::getWidgetSize() const
{
return mLocalMapZoom * mMapWidgetSize;
}
void LocalMapBase::setPlayerPos(int cellX, int cellY, const float nx, const float ny)
{
MyGUI::IntPoint pos(static_cast<int>(mMapWidgetSize * mCellDistance + nx*mMapWidgetSize - 16), static_cast<int>(mMapWidgetSize * mCellDistance + ny*mMapWidgetSize - 16));
pos.left += (cellX - mCurX) * mMapWidgetSize;
pos.top -= (cellY - mCurY) * mMapWidgetSize;
MyGUI::IntPoint pos = getPosition(cellX, cellY, nx, ny) - MyGUI::IntPoint{ 16, 16 };
if (pos != mCompass->getPosition())
{
notifyPlayerUpdate ();
mCompass->setPosition(pos);
MyGUI::IntPoint middle (pos.left+16, pos.top+16);
MyGUI::IntCoord viewsize = mLocalMap->getCoord();
MyGUI::IntPoint viewOffset((viewsize.width / 2) - middle.left, (viewsize.height / 2) - middle.top);
mLocalMap->setViewOffset(viewOffset);
}
osg::Vec2f curPos((cellX + nx) * cellSize, (cellY + 1 - ny) * cellSize);
if ((curPos - mCurPos).length2() > 0.001)
{
mCurPos = curPos;
centerView();
}
}
@ -449,28 +531,21 @@ namespace MWGui
{
const ESM::Position& worldPos = ptr.getRefData().getPosition();
MarkerUserData markerPos (mLocalMapRender);
MyGUI::IntPoint widgetPos = getMarkerPosition(worldPos.pos[0], worldPos.pos[1], markerPos);
MyGUI::IntCoord widgetCoord(widgetPos.left - 4,
widgetPos.top - 4,
8, 8);
++counter;
MyGUI::ImageBox* markerWidget = mLocalMap->createWidget<MyGUI::ImageBox>("ImageBox",
widgetCoord, MyGUI::Align::Default);
getMarkerCoordinates(worldPos.pos[0], worldPos.pos[1], markerPos, 8), MyGUI::Align::Default);
markerWidget->setDepth(Local_MarkerAboveFogLayer);
markerWidget->setImageTexture(markerTexture);
markerWidget->setImageCoord(MyGUI::IntCoord(0,0,8,8));
markerWidget->setNeedMouseFocus(false);
markerWidget->setUserData(markerPos);
mMagicMarkerWidgets.push_back(markerWidget);
}
}
void LocalMapBase::onFrame(float dt)
{
if (mNeedDoorMarkersUpdate)
{
updateDoorMarkers();
mNeedDoorMarkersUpdate = false;
}
mMarkerUpdateTimer += dt;
@ -545,34 +620,32 @@ 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 dX=-mCellDistance; dX<=mCellDistance; ++dX)
for (MapEntry& entry : mMaps)
{
for (int dY=-mCellDistance; dY<=mCellDistance; ++dY)
{
MWWorld::CellStore* cell = world->getExterior (mCurX+dX, mCurY+dY);
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
int counter = 0;
for (MWBase::World::DoorMarker& marker : doors)
{
std::vector<std::string> destNotes;
@ -580,28 +653,33 @@ namespace MWGui
for (CustomMarkerCollection::ContainerType::const_iterator iter = markers.first; iter != markers.second; ++iter)
destNotes.push_back(iter->second.mNote);
MarkerUserData data (mLocalMapRender);
data.notes = destNotes;
data.caption = marker.name;
MyGUI::IntPoint widgetPos = getMarkerPosition(marker.x, marker.y, data);
MyGUI::IntCoord widgetCoord(widgetPos.left - 4,
widgetPos.top - 4,
8, 8);
++counter;
MarkerWidget* markerWidget = mLocalMap->createWidget<MarkerWidget>("MarkerButton",
widgetCoord, MyGUI::Align::Default);
markerWidget->setNormalColour(MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=normal}")));
markerWidget->setHoverColour(MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=normal_over}")));
markerWidget->setDepth(Local_MarkerLayer);
markerWidget->setNeedMouseFocus(true);
// Used by tooltips to not show the tooltip if marker is hidden by fog of war
markerWidget->setUserString("ToolTipType", "MapMarker");
markerWidget->setUserData(data);
MyGUI::Widget* markerWidget = nullptr;
MarkerUserData* data;
if (mDoorMarkersToRecycle.empty())
{
markerWidget = createDoorMarker(marker.name, destNotes, marker.x, marker.y);
data = markerWidget->getUserData<MarkerUserData>();
doorMarkerCreated(markerWidget);
mDoorMarkerWidgets.push_back(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);
}
currentDoorMarkersWidgets().push_back(markerWidget);
if (!mInterior)
mExteriorDoorsByCell[{data->cellX, data->cellY}].push_back(markerWidget);
}
for (auto& widget : mDoorMarkersToRecycle)
widget->setVisible(false);
}
void LocalMapBase::updateMagicMarkers()
@ -623,23 +701,46 @@ namespace MWGui
&& (!mInterior || Misc::StringUtils::ciEqual(markedCell->getCell()->mName, mPrefix)))
{
MarkerUserData markerPos (mLocalMapRender);
MyGUI::IntPoint widgetPos = getMarkerPosition(markedPosition.pos[0], markedPosition.pos[1], markerPos);
MyGUI::IntCoord widgetCoord(widgetPos.left - 4,
widgetPos.top - 4,
8, 8);
MyGUI::ImageBox* markerWidget = mLocalMap->createWidget<MyGUI::ImageBox>("ImageBox",
widgetCoord, MyGUI::Align::Default);
getMarkerCoordinates(markedPosition.pos[0], markedPosition.pos[1], markerPos, 8), MyGUI::Align::Default);
markerWidget->setDepth(Local_MarkerAboveFogLayer);
markerWidget->setImageTexture("textures\\menu_map_smark.dds");
markerWidget->setNeedMouseFocus(false);
markerWidget->setUserData(markerPos);
mMagicMarkerWidgets.push_back(markerWidget);
}
redraw();
}
// ------------------------------------------------------------------------------------------
void LocalMapBase::updateLocalMap()
{
auto mapWidgetSize = getWidgetSize();
mLocalMap->setCanvasSize(mapWidgetSize * mNumCells, mapWidgetSize * mNumCells);
const auto size = MyGUI::IntSize(std::ceil(mapWidgetSize), std::ceil(mapWidgetSize));
for (auto& entry : mMaps)
{
const auto position = getPosition(entry.mCellX, entry.mCellY, 0, 0);
entry.mMapWidget->setCoord({ position, size });
entry.mFogWidget->setCoord({ position, size });
}
MarkerUserData markerPos(mLocalMapRender);
for (MyGUI::Widget* widget : currentDoorMarkersWidgets())
widget->setCoord(getMarkerCoordinates(widget, 8));
for (MyGUI::Widget* widget : mCustomMarkerWidgets)
{
const auto& marker = *widget->getUserData<ESM::CustomMarker>();
widget->setCoord(getMarkerCoordinates(marker.mWorldX, marker.mWorldY, markerPos, 16));
}
for (MyGUI::Widget* widget : mMagicMarkerWidgets)
widget->setCoord(getMarkerCoordinates(widget, 8));
}
// ------------------------------------------------------------------------------------------
MapWindow::MapWindow(CustomMarkerCollection &customMarkers, DragAndDrop* drag, MWRender::LocalMap* localMapRender, SceneUtil::WorkQueue* workQueue)
: WindowPinnableBase("openmw_map_window.layout")
, LocalMapBase(customMarkers, localMapRender)
@ -690,14 +791,16 @@ namespace MWGui
getWidget(mEventBoxGlobal, "EventBoxGlobal");
mEventBoxGlobal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag);
mEventBoxGlobal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart);
mEventBoxGlobal->eventMouseWheel += MyGUI::newDelegate(this, &MapWindow::onMapZoomed);
mEventBoxGlobal->setDepth(Global_ExploreOverlayLayer);
getWidget(mEventBoxLocal, "EventBoxLocal");
mEventBoxLocal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag);
mEventBoxLocal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart);
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);
@ -745,10 +848,11 @@ namespace MWGui
MyGUI::IntPoint clickedPos = MyGUI::InputManager::getInstance().getMousePosition();
MyGUI::IntPoint widgetPos = clickedPos - mEventBoxLocal->getAbsolutePosition();
int x = int(widgetPos.left/float(mMapWidgetSize))-mCellDistance;
int y = (int(widgetPos.top/float(mMapWidgetSize))-mCellDistance)*-1;
float nX = widgetPos.left/float(mMapWidgetSize) - int(widgetPos.left/float(mMapWidgetSize));
float nY = widgetPos.top/float(mMapWidgetSize) - int(widgetPos.top/float(mMapWidgetSize));
auto mapWidgetSize = getWidgetSize();
int x = int(widgetPos.left/float(mapWidgetSize))-mCellDistance;
int y = (int(widgetPos.top/float(mapWidgetSize))-mCellDistance)*-1;
float nX = widgetPos.left/float(mapWidgetSize) - int(widgetPos.left/float(mapWidgetSize));
float nY = widgetPos.top/float(mapWidgetSize) - int(widgetPos.top/float(mapWidgetSize));
x += mCurX;
y += mCurY;
@ -781,6 +885,106 @@ namespace MWGui
mEditNoteDialog.setText("");
}
void MapWindow::onMapZoomed(MyGUI::Widget* sender, int rel)
{
const static int localWidgetSize = Settings::Manager::getInt("local map widget size", "Map");
const static int globalCellSize = Settings::Manager::getInt("global map cell size", "Map");
const bool zoomOut = rel < 0;
const bool zoomIn = !zoomOut;
const double speedDiff = zoomOut ? 1.0 / speed : speed;
const float localMapSizeInUnits = localWidgetSize * mNumCells;
const float currentMinLocalMapZoom = std::max({
(float(globalCellSize) * 4.f) / float(localWidgetSize),
float(mLocalMap->getWidth()) / localMapSizeInUnits,
float(mLocalMap->getHeight()) / localMapSizeInUnits
});
if (mGlobal)
{
const float currentGlobalZoom = mGlobalMapZoom;
const float currentMinGlobalMapZoom = std::min(
float(mGlobalMap->getWidth()) / float(mGlobalMapRender->getWidth()),
float(mGlobalMap->getHeight()) / float(mGlobalMapRender->getHeight())
);
mGlobalMapZoom *= speedDiff;
if (zoomIn && mGlobalMapZoom > 4.f)
{
mGlobalMapZoom = currentGlobalZoom;
mLocalMapZoom = currentMinLocalMapZoom;
onWorldButtonClicked(nullptr);
updateLocalMap();
return; //the zoom in is too big
}
if (zoomOut && mGlobalMapZoom < currentMinGlobalMapZoom)
{
mGlobalMapZoom = currentGlobalZoom;
return; //the zoom out is too big, we have reach the borders of the widget
}
}
else
{
auto const currentLocalZoom = mLocalMapZoom;
mLocalMapZoom *= speedDiff;
if (zoomIn && mLocalMapZoom > 4.0f)
{
mLocalMapZoom = currentLocalZoom;
return; //the zoom in is too big
}
if (zoomOut && mLocalMapZoom < currentMinLocalMapZoom)
{
mLocalMapZoom = currentLocalZoom;
float zoomRatio = 4.f/ mGlobalMapZoom;
mGlobalMapZoom = 4.f;
onWorldButtonClicked(nullptr);
zoomOnCursor(zoomRatio);
return; //the zoom out is too big, we switch to the global map
}
}
zoomOnCursor(speedDiff);
}
void MapWindow::zoomOnCursor(float speedDiff)
{
auto map = mGlobal ? mGlobalMap : mLocalMap;
auto cursor = MyGUI::InputManager::getInstance().getMousePosition() - map->getAbsolutePosition();
auto centerView = map->getViewOffset() - cursor;
mGlobal? updateGlobalMap() : updateLocalMap();
map->setViewOffset(MyGUI::IntPoint(
std::round(centerView.left * speedDiff) + cursor.left,
std::round(centerView.top * speedDiff) + cursor.top
));
}
void MapWindow::updateGlobalMap()
{
resizeGlobalMap();
float x = mCurPos.x(), y = mCurPos.y();
if (mInterior)
{
auto pos = MWBase::Environment::get().getWorld()->getPlayer().getLastKnownExteriorPosition();
x = pos.x(), y = pos.y();
}
setGlobalMapPlayerPosition(x, y);
for (auto& [marker, col] : mGlobalMapMarkers)
{
marker.widget->setCoord(createMarkerCoords(marker.position.x(), marker.position.y(), col.size()));
marker.widget->setVisible(marker.widget->getHeight() >= 6);
}
}
void MapWindow::onChangeScrollWindowCoord(MyGUI::Widget* sender)
{
MyGUI::IntCoord currentCoordinates = sender->getCoord();
@ -804,8 +1008,7 @@ namespace MWGui
void MapWindow::renderGlobalMap()
{
mGlobalMapRender->render();
mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight());
mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight());
resizeGlobalMap();
}
MapWindow::~MapWindow()
@ -818,28 +1021,25 @@ namespace MWGui
setTitle("#{sCell=" + cellName + "}");
}
void MapWindow::addVisitedLocation(const std::string& name, int x, int y)
{
CellId cell;
cell.first = x;
cell.second = y;
if (mMarkers.insert(cell).second)
MyGUI::IntCoord MapWindow::createMarkerCoords(float x, float y, float agregatedWeight) const
{
float worldX, worldY;
mGlobalMapRender->cellTopLeftCornerToImageSpace (x, y, worldX, worldY);
worldPosToGlobalMapImageSpace((x + 0.5f) * Constants::CellSizeInUnits, (y + 0.5f)* Constants::CellSizeInUnits, worldX, worldY);
int markerSize = 12;
int offset = mGlobalMapRender->getCellSize()/2 - markerSize/2;
MyGUI::IntCoord widgetCoord(
static_cast<int>(worldX * mGlobalMapRender->getWidth()+offset),
static_cast<int>(worldY * mGlobalMapRender->getHeight() + offset),
const float markerSize = getMarkerSize(agregatedWeight);
const float halfMarkerSize = markerSize / 2.0f;
return MyGUI::IntCoord(
static_cast<int>(worldX - halfMarkerSize),
static_cast<int>(worldY - halfMarkerSize),
markerSize, markerSize);
}
MyGUI::Widget* MapWindow::createMarker(const std::string& name, float x, float y, float agregatedWeight)
{
MyGUI::Widget* markerWidget = mGlobalMap->createWidget<MyGUI::Widget>("MarkerButton",
widgetCoord, MyGUI::Align::Default);
createMarkerCoords(x, y, agregatedWeight), MyGUI::Align::Default);
markerWidget->setVisible(markerWidget->getHeight() >= 6.0);
markerWidget->setUserString("Caption_TextOneLine", "#{sCell=" + name + "}");
setGlobalMapMarkerTooltip(markerWidget, x, y);
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
@ -848,8 +1048,46 @@ namespace MWGui
markerWidget->setColour(MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=normal}")));
markerWidget->setDepth(Global_MarkerLayer);
markerWidget->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag);
markerWidget->eventMouseWheel += MyGUI::newDelegate(this, &MapWindow::onMapZoomed);
markerWidget->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart);
mGlobalMapMarkers[std::make_pair(x,y)] = markerWidget;
return markerWidget;
}
void MapWindow::addVisitedLocation(const std::string& name, int x, int y)
{
CellId cell;
cell.first = x;
cell.second = y;
if (mMarkers.insert(cell).second)
{
MapMarkerType mapMarkerWidget = { osg::Vec2f(x, y), createMarker(name, x, y, 0) };
mGlobalMapMarkers.emplace(mapMarkerWidget, std::vector<MapMarkerType>());
std::string name_ = name.substr(0, name.find(','));
auto& entry = mGlobalMapMarkersByName[name_];
if (!entry.widget)
{
entry = { osg::Vec2f(x, y), entry.widget }; //update the coords
entry.widget = createMarker(name_, entry.position.x(), entry.position.y(), 1);
mGlobalMapMarkers.emplace(entry, std::vector<MapMarkerType>{ entry });
}
else
{
auto it = mGlobalMapMarkers.find(entry);
auto& marker = const_cast<MapMarkerType&>(it->first);
auto& elements = it->second;
elements.emplace_back(mapMarkerWidget);
//we compute the barycenter of the entry elements => it will be the place on the world map for the agregated widget
marker.position = std::accumulate(elements.begin(), elements.end(), osg::Vec2f(0.f, 0.f), [](const auto& left, const auto& right) {
return left + right.position;
}) / float(elements.size());
marker.widget->setCoord(createMarkerCoords(marker.position.x(), marker.position.y(), elements.size()));
marker.widget->setVisible(marker.widget->getHeight() >= 6);
}
}
}
@ -891,17 +1129,32 @@ namespace MWGui
}
}
float MapWindow::getMarkerSize(size_t agregatedWeight) const
{
float markerSize = 12.f * mGlobalMapZoom;
if (mGlobalMapZoom < 1)
return markerSize * std::sqrt(agregatedWeight); //we want to see agregated object
return agregatedWeight ? 0 : markerSize; //we want to see only original markers (i.e. non agregated)
}
void MapWindow::resizeGlobalMap()
{
mGlobalMap->setCanvasSize(mGlobalMapRender->getWidth() * mGlobalMapZoom, mGlobalMapRender->getHeight() * mGlobalMapZoom);
mGlobalMapImage->setSize(mGlobalMapRender->getWidth() * mGlobalMapZoom, mGlobalMapRender->getHeight() * mGlobalMapZoom);
}
void MapWindow::worldPosToGlobalMapImageSpace(float x, float y, float& imageX, float& imageY) const
{
mGlobalMapRender->worldPosToImageSpace(x, y, imageX, imageY);
imageX *= mGlobalMapZoom, imageY *= mGlobalMapZoom;
}
void MapWindow::updateCustomMarkers()
{
LocalMapBase::updateCustomMarkers();
for (auto& widgetPair : mGlobalMapMarkers)
{
int x = widgetPair.first.first;
int y = widgetPair.first.second;
MyGUI::Widget* markerWidget = widgetPair.second;
setGlobalMapMarkerTooltip(markerWidget, x, y);
}
for (auto& [widgetPair, ignore]: mGlobalMapMarkers)
setGlobalMapMarkerTooltip(widgetPair.widget, widgetPair.position.x(), widgetPair.position.y());
}
void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id)
@ -934,9 +1187,6 @@ namespace MWGui
mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" :
"#{sWorld}");
if (mGlobal)
globalMapUpdatePlayer ();
}
void MapWindow::onPinToggled()
@ -978,19 +1228,21 @@ namespace MWGui
setGlobalMapPlayerDir(mLastDirectionX, mLastDirectionY);
}
void MapWindow::centerView()
{
LocalMapBase::centerView();
// set the view offset so that player is in the center
MyGUI::IntSize viewsize = mGlobalMap->getSize();
MyGUI::IntPoint pos = mPlayerArrowGlobal->getPosition() + MyGUI::IntPoint{ 16,16 };
MyGUI::IntPoint viewoffs(static_cast<int>(viewsize.width * 0.5f - pos.left), static_cast<int>(viewsize.height * 0.5f - pos.top));
mGlobalMap->setViewOffset(viewoffs);
}
void MapWindow::setGlobalMapPlayerPosition(float worldX, float worldY)
{
float x, y;
mGlobalMapRender->worldPosToImageSpace (worldX, worldY, x, y);
x *= mGlobalMapRender->getWidth();
y *= mGlobalMapRender->getHeight();
worldPosToGlobalMapImageSpace(worldX, worldY, x, y);
mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(static_cast<int>(x - 16), static_cast<int>(y - 16)));
// set the view offset so that player is in the center
MyGUI::IntSize viewsize = mGlobalMap->getSize();
MyGUI::IntPoint viewoffs(static_cast<int>(viewsize.width * 0.5f - x), static_cast<int>(viewsize.height *0.5 - y));
mGlobalMap->setViewOffset(viewoffs);
}
void MapWindow::setGlobalMapPlayerDir(const float x, const float y)
@ -1027,8 +1279,9 @@ namespace MWGui
mChanged = true;
for (auto& widgetPair : mGlobalMapMarkers)
MyGUI::Gui::getInstance().destroyWidget(widgetPair.second);
MyGUI::Gui::getInstance().destroyWidget(widgetPair.first.widget);
mGlobalMapMarkers.clear();
mGlobalMapMarkersByName.clear();
}
void MapWindow::write(ESM::ESMWriter &writer, Loading::Listener& progress)
@ -1075,12 +1328,14 @@ namespace MWGui
marker->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag);
marker->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart);
marker->eventMouseButtonDoubleClick += MyGUI::newDelegate(this, &MapWindow::onCustomMarkerDoubleClicked);
marker->eventMouseWheel += MyGUI::newDelegate(this, &MapWindow::onMapZoomed);
}
void MapWindow::doorMarkerCreated(MyGUI::Widget *marker)
{
marker->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag);
marker->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart);
marker->eventMouseWheel += MyGUI::newDelegate(this, &MapWindow::onMapZoomed);
}
// -------------------------------------------------------------------

View File

@ -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);
@ -107,9 +108,15 @@ namespace MWGui
};
protected:
void updateLocalMap();
float mLocalMapZoom = 1.f;
MWRender::LocalMap* mLocalMapRender;
int mCurX, mCurY;
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;
@ -141,17 +148,27 @@ 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();
void applyFogOfWar();
MyGUI::IntPoint getMarkerPosition (float worldX, float worldY, MarkerUserData& markerPos);
MyGUI::IntPoint getPosition(int cellX, int cellY, float nx, float ny) const;
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, const MyGUI::VectorString& notes, float x, float y) const;
MyGUI::IntCoord getMarkerCoordinates(MyGUI::Widget* widget, size_t markerSize) const;
virtual void notifyPlayerUpdate() {}
virtual void centerView();
virtual void notifyMapChanged() {}
virtual void customMarkerCreated(MyGUI::Widget* marker) {}
@ -163,6 +180,7 @@ namespace MWGui
void addDetectionMarkers(int type);
void redraw();
float getWidgetSize() const;
float mMarkerUpdateTimer;
@ -171,7 +189,6 @@ namespace MWGui
private:
void updateDoorMarkers();
bool mNeedDoorMarkersUpdate;
};
class EditNoteDialog : public MWGui::WindowModal
@ -244,6 +261,9 @@ namespace MWGui
void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
void onWorldButtonClicked(MyGUI::Widget* _sender);
void onMapDoubleClicked(MyGUI::Widget* sender);
void onMapZoomed(MyGUI::Widget* sender, int rel);
void zoomOnCursor(float speedDiff);
void updateGlobalMap();
void onCustomMarkerDoubleClicked(MyGUI::Widget* sender);
void onNoteEditOk();
void onNoteEditDelete();
@ -252,6 +272,12 @@ namespace MWGui
void onChangeScrollWindowCoord(MyGUI::Widget* sender);
void globalMapUpdatePlayer();
void setGlobalMapMarkerTooltip(MyGUI::Widget* widget, int x, int y);
float getMarkerSize(size_t agregatedWeight) const;
void resizeGlobalMap();
void worldPosToGlobalMapImageSpace(float x, float z, float& imageX, float& imageY) const;
MyGUI::IntCoord createMarkerCoords(float x, float y, float agregatedWeight) const;
MyGUI::Widget* createMarker(const std::string& name, float x, float y, float agregatedWeight);
MyGUI::ScrollView* mGlobalMap;
std::unique_ptr<MyGUI::ITexture> mGlobalMapTexture;
@ -273,9 +299,21 @@ namespace MWGui
MyGUI::Button* mEventBoxGlobal;
MyGUI::Button* mEventBoxLocal;
float mGlobalMapZoom = 1.0f;
MWRender::GlobalMap* mGlobalMapRender;
std::map<std::pair<int, int>, MyGUI::Widget*> mGlobalMapMarkers;
struct MapMarkerType
{
osg::Vec2f position;
MyGUI::Widget* widget = nullptr;
bool operator<(const MapMarkerType& right) const {
return widget < right.widget;
}
};
std::map<std::string, MapMarkerType> mGlobalMapMarkersByName;
std::map<MapMarkerType, std::vector<MapMarkerType>> mGlobalMapMarkers;
EditNoteDialog mEditNoteDialog;
ESM::CustomMarker mEditingMarker;
@ -288,6 +326,7 @@ namespace MWGui
void notifyPlayerUpdate() override;
void centerView() override;
};
}
#endif

View File

@ -270,17 +270,9 @@ namespace MWRender
void GlobalMap::worldPosToImageSpace(float x, float z, float& imageX, float& imageY)
{
imageX = float(x / float(Constants::CellSizeInUnits) - mMinX) / (mMaxX - mMinX + 1);
imageX = (float(x / float(Constants::CellSizeInUnits) - mMinX) / (mMaxX - mMinX + 1)) * getWidth();
imageY = 1.f-float(z / float(Constants::CellSizeInUnits) - mMinY) / (mMaxY - mMinY + 1);
}
void GlobalMap::cellTopLeftCornerToImageSpace(int x, int y, float& imageX, float& imageY)
{
imageX = float(x - mMinX) / (mMaxX - mMinX + 1);
// NB y + 1, because we want the top left corner, not bottom left where the origin of the cell is
imageY = 1.f-float(y - mMinY + 1) / (mMaxY - mMinY + 1);
imageY = (1.f-float(z / float(Constants::CellSizeInUnits) - mMinY) / (mMaxY - mMinY + 1)) * getHeight();
}
void GlobalMap::requestOverlayTextureUpdate(int x, int y, int width, int height, osg::ref_ptr<osg::Texture2D> texture, bool clear, bool cpuCopy,

View File

@ -41,12 +41,8 @@ namespace MWRender
int getWidth() const { return mWidth; }
int getHeight() const { return mHeight; }
int getCellSize() const { return mCellSize; }
void worldPosToImageSpace(float x, float z, float& imageX, float& imageY);
void cellTopLeftCornerToImageSpace(int x, int y, float& imageX, float& imageY);
void exploreCell (int cellX, int cellY, osg::ref_ptr<osg::Texture2D> localMapTexture);
/// Clears the overlay

View File

@ -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;

View File

@ -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;

View File

@ -103,3 +103,26 @@ and typically require more panning to see all available portions of the map.
This larger size also enables an overall greater level of detail if the local map resolution setting is also increased.
This setting can not be configured except by editing the settings configuration file.
allow zooming
-------------
:Type: boolean
:Range: True/False
:Default: False
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.

View File

@ -199,6 +199,12 @@ local map widget size = 512
# If true, map in world mode, otherwise in local mode
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).

View File

@ -1006,6 +1006,16 @@ True: In non-combat mode camera is positioned behind the character's shoulder. C
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="useZoomOnMapCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable zooming on local and global maps.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Can zoom on maps</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="graphicHerbalismCheckBox">
<property name="toolTip">