mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-04-16 17:42:31 +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:
commit
200ccfab69
@ -27,6 +27,7 @@
|
|||||||
Bug #6174: Spellmaking and Enchanting sliders differences from vanilla
|
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 #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 #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 #5489: MCP: Telekinesis fix for activators
|
||||||
Feature #5996: Support Lua scripts in OpenMW
|
Feature #5996: Support Lua scripts in OpenMW
|
||||||
Feature #6017: Separate persistent and temporary cell references when saving
|
Feature #6017: Separate persistent and temporary cell references when saving
|
||||||
|
@ -192,6 +192,7 @@ bool Launcher::AdvancedPage::loadSettings()
|
|||||||
if (showOwnedIndex >= 0 && showOwnedIndex <= 3)
|
if (showOwnedIndex >= 0 && showOwnedIndex <= 3)
|
||||||
showOwnedComboBox->setCurrentIndex(showOwnedIndex);
|
showOwnedComboBox->setCurrentIndex(showOwnedIndex);
|
||||||
loadSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
|
loadSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
|
||||||
|
loadSettingBool(useZoomOnMapCheckBox, "allow zooming", "Map");
|
||||||
loadSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
|
loadSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
|
||||||
scalingSpinBox->setValue(Settings::Manager::getFloat("scaling factor", "GUI"));
|
scalingSpinBox->setValue(Settings::Manager::getFloat("scaling factor", "GUI"));
|
||||||
}
|
}
|
||||||
@ -352,6 +353,7 @@ void Launcher::AdvancedPage::saveSettings()
|
|||||||
if (showOwnedCurrentIndex != Settings::Manager::getInt("show owned", "Game"))
|
if (showOwnedCurrentIndex != Settings::Manager::getInt("show owned", "Game"))
|
||||||
Settings::Manager::setInt("show owned", "Game", showOwnedCurrentIndex);
|
Settings::Manager::setInt("show owned", "Game", showOwnedCurrentIndex);
|
||||||
saveSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
|
saveSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
|
||||||
|
saveSettingBool(useZoomOnMapCheckBox, "allow zooming", "Map");
|
||||||
saveSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
|
saveSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
|
||||||
float uiScalingFactor = scalingSpinBox->value();
|
float uiScalingFactor = scalingSpinBox->value();
|
||||||
if (uiScalingFactor != Settings::Manager::getFloat("scaling factor", "GUI"))
|
if (uiScalingFactor != Settings::Manager::getFloat("scaling factor", "GUI"))
|
||||||
|
@ -30,10 +30,13 @@
|
|||||||
#include "confirmationdialog.hpp"
|
#include "confirmationdialog.hpp"
|
||||||
#include "tooltips.hpp"
|
#include "tooltips.hpp"
|
||||||
|
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
const int cellSize = Constants::CellSizeInUnits;
|
const int cellSize = Constants::CellSizeInUnits;
|
||||||
|
constexpr float speed = 1.08; //the zoom speed, it should be greater than 1
|
||||||
|
|
||||||
enum LocalMapWidgetDepth
|
enum LocalMapWidgetDepth
|
||||||
{
|
{
|
||||||
@ -84,6 +87,23 @@ namespace
|
|||||||
setColour(mHoverColour);
|
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
|
namespace MWGui
|
||||||
@ -167,13 +187,12 @@ namespace MWGui
|
|||||||
, mFogOfWarToggled(true)
|
, mFogOfWarToggled(true)
|
||||||
, mFogOfWarEnabled(fogOfWarEnabled)
|
, mFogOfWarEnabled(fogOfWarEnabled)
|
||||||
, mMapWidgetSize(0)
|
, mMapWidgetSize(0)
|
||||||
, mNumCells(0)
|
, mNumCells(1)
|
||||||
, mCellDistance(0)
|
, mCellDistance(0)
|
||||||
, mCustomMarkers(markers)
|
, mCustomMarkers(markers)
|
||||||
, mMarkerUpdateTimer(0.0f)
|
, mMarkerUpdateTimer(0.0f)
|
||||||
, mLastDirectionX(0.0f)
|
, mLastDirectionX(0.0f)
|
||||||
, mLastDirectionY(0.0f)
|
, mLastDirectionY(0.0f)
|
||||||
, mNeedDoorMarkersUpdate(false)
|
|
||||||
{
|
{
|
||||||
mCustomMarkers.eventMarkersChanged += MyGUI::newDelegate(this, &LocalMapBase::updateCustomMarkers);
|
mCustomMarkers.eventMarkersChanged += MyGUI::newDelegate(this, &LocalMapBase::updateCustomMarkers);
|
||||||
}
|
}
|
||||||
@ -183,12 +202,12 @@ 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)
|
void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int cellDistance)
|
||||||
{
|
{
|
||||||
mLocalMap = widget;
|
mLocalMap = widget;
|
||||||
mCompass = compass;
|
mCompass = compass;
|
||||||
mMapWidgetSize = std::max(1, Settings::Manager::getInt("local map widget size", "Map"));
|
mMapWidgetSize = std::max(1, Settings::Manager::getInt("local map widget size", "Map"));
|
||||||
mCellDistance = Constants::CellGridRadius;
|
mCellDistance = cellDistance;
|
||||||
mNumCells = mCellDistance * 2 + 1;
|
mNumCells = mCellDistance * 2 + 1;
|
||||||
|
|
||||||
mLocalMap->setCanvasSize(mMapWidgetSize*mNumCells, mMapWidgetSize*mNumCells);
|
mLocalMap->setCanvasSize(mMapWidgetSize*mNumCells, mMapWidgetSize*mNumCells);
|
||||||
@ -234,65 +253,94 @@ namespace MWGui
|
|||||||
|
|
||||||
void LocalMapBase::applyFogOfWar()
|
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)
|
if (!mFogOfWarToggled || !mFogOfWarEnabled)
|
||||||
{
|
{
|
||||||
fog->setImageTexture("");
|
for (auto& entry : mMaps)
|
||||||
|
{
|
||||||
|
entry.mFogWidget->setImageTexture("");
|
||||||
entry.mFogTexture.reset();
|
entry.mFogTexture.reset();
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
redraw();
|
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
|
// normalized cell coordinates
|
||||||
float nX,nY;
|
float nX,nY;
|
||||||
|
|
||||||
if (!mInterior)
|
if (!mInterior)
|
||||||
{
|
{
|
||||||
int cellX, cellY;
|
|
||||||
MWBase::Environment::get().getWorld()->positionToIndex(worldX, worldY, cellX, cellY);
|
MWBase::Environment::get().getWorld()->positionToIndex(worldX, worldY, cellX, cellY);
|
||||||
nX = (worldX - cellSize * cellX) / cellSize;
|
nX = (worldX - cellSize * cellX) / cellSize;
|
||||||
// Image space is -Y up, cells are Y up
|
// Image space is -Y up, cells are Y up
|
||||||
nY = 1 - (worldY - cellSize * cellY) / cellSize;
|
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
|
else
|
||||||
{
|
mLocalMapRender->worldToInteriorMapPosition({ worldX, worldY }, nX, nY, cellX, cellY);
|
||||||
int cellX, cellY;
|
|
||||||
osg::Vec2f worldPos (worldX, worldY);
|
|
||||||
mLocalMapRender->worldToInteriorMapPosition(worldPos, nX, nY, cellX, cellY);
|
|
||||||
|
|
||||||
markerPos.cellX = cellX;
|
markerPos.cellX = cellX;
|
||||||
markerPos.cellY = cellY;
|
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.nX = nX;
|
||||||
markerPos.nY = nY;
|
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()
|
void LocalMapBase::updateCustomMarkers()
|
||||||
@ -317,13 +365,8 @@ namespace MWGui
|
|||||||
const ESM::CustomMarker& marker = it->second;
|
const ESM::CustomMarker& marker = it->second;
|
||||||
|
|
||||||
MarkerUserData markerPos (mLocalMapRender);
|
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",
|
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->setDepth(Local_MarkerAboveFogLayer);
|
||||||
markerWidget->setUserString("ToolTipType", "Layout");
|
markerWidget->setUserString("ToolTipType", "Layout");
|
||||||
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
|
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
|
||||||
@ -346,6 +389,38 @@ namespace MWGui
|
|||||||
if (x==mCurX && y==mCurY && mInterior==interior && !mChanged)
|
if (x==mCurX && y==mCurY && mInterior==interior && !mChanged)
|
||||||
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
|
||||||
|
|
||||||
|
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;
|
mCurX = x;
|
||||||
mCurY = y;
|
mCurY = y;
|
||||||
mInterior = interior;
|
mInterior = interior;
|
||||||
@ -366,9 +441,11 @@ namespace MWGui
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delay the door markers update until scripts have been given a chance to run.
|
for (MyGUI::Widget* widget : currentDoorMarkersWidgets())
|
||||||
// If we don't do this, door markers that should be disabled will still appear on the map.
|
widget->setCoord(getMarkerCoordinates(widget, 8));
|
||||||
mNeedDoorMarkersUpdate = true;
|
|
||||||
|
if (!mInterior)
|
||||||
|
mHasALastActiveCell = true;
|
||||||
|
|
||||||
updateMagicMarkers();
|
updateMagicMarkers();
|
||||||
updateCustomMarkers();
|
updateCustomMarkers();
|
||||||
@ -385,21 +462,26 @@ namespace MWGui
|
|||||||
mLocalMap->getParent()->_updateChilds();
|
mLocalMap->getParent()->_updateChilds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float LocalMapBase::getWidgetSize() const
|
||||||
|
{
|
||||||
|
return mLocalMapZoom * mMapWidgetSize;
|
||||||
|
}
|
||||||
|
|
||||||
void LocalMapBase::setPlayerPos(int cellX, int cellY, const float nx, const float ny)
|
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));
|
MyGUI::IntPoint pos = getPosition(cellX, cellY, nx, ny) - MyGUI::IntPoint{ 16, 16 };
|
||||||
pos.left += (cellX - mCurX) * mMapWidgetSize;
|
|
||||||
pos.top -= (cellY - mCurY) * mMapWidgetSize;
|
|
||||||
|
|
||||||
if (pos != mCompass->getPosition())
|
if (pos != mCompass->getPosition())
|
||||||
{
|
{
|
||||||
notifyPlayerUpdate ();
|
notifyPlayerUpdate ();
|
||||||
|
|
||||||
mCompass->setPosition(pos);
|
mCompass->setPosition(pos);
|
||||||
MyGUI::IntPoint middle (pos.left+16, pos.top+16);
|
}
|
||||||
MyGUI::IntCoord viewsize = mLocalMap->getCoord();
|
osg::Vec2f curPos((cellX + nx) * cellSize, (cellY + 1 - ny) * cellSize);
|
||||||
MyGUI::IntPoint viewOffset((viewsize.width / 2) - middle.left, (viewsize.height / 2) - middle.top);
|
if ((curPos - mCurPos).length2() > 0.001)
|
||||||
mLocalMap->setViewOffset(viewOffset);
|
{
|
||||||
|
mCurPos = curPos;
|
||||||
|
centerView();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,28 +531,21 @@ namespace MWGui
|
|||||||
{
|
{
|
||||||
const ESM::Position& worldPos = ptr.getRefData().getPosition();
|
const ESM::Position& worldPos = ptr.getRefData().getPosition();
|
||||||
MarkerUserData markerPos (mLocalMapRender);
|
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;
|
++counter;
|
||||||
MyGUI::ImageBox* markerWidget = mLocalMap->createWidget<MyGUI::ImageBox>("ImageBox",
|
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->setDepth(Local_MarkerAboveFogLayer);
|
||||||
markerWidget->setImageTexture(markerTexture);
|
markerWidget->setImageTexture(markerTexture);
|
||||||
markerWidget->setImageCoord(MyGUI::IntCoord(0,0,8,8));
|
markerWidget->setImageCoord(MyGUI::IntCoord(0,0,8,8));
|
||||||
markerWidget->setNeedMouseFocus(false);
|
markerWidget->setNeedMouseFocus(false);
|
||||||
|
markerWidget->setUserData(markerPos);
|
||||||
mMagicMarkerWidgets.push_back(markerWidget);
|
mMagicMarkerWidgets.push_back(markerWidget);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalMapBase::onFrame(float dt)
|
void LocalMapBase::onFrame(float dt)
|
||||||
{
|
|
||||||
if (mNeedDoorMarkersUpdate)
|
|
||||||
{
|
{
|
||||||
updateDoorMarkers();
|
updateDoorMarkers();
|
||||||
mNeedDoorMarkersUpdate = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mMarkerUpdateTimer += dt;
|
mMarkerUpdateTimer += dt;
|
||||||
|
|
||||||
@ -545,34 +620,32 @@ namespace MWGui
|
|||||||
|
|
||||||
void LocalMapBase::updateDoorMarkers()
|
void LocalMapBase::updateDoorMarkers()
|
||||||
{
|
{
|
||||||
// clear all previous door markers
|
std::vector<MWBase::World::DoorMarker> doors;
|
||||||
for (MyGUI::Widget* widget : mDoorMarkerWidgets)
|
|
||||||
MyGUI::Gui::getInstance().destroyWidget(widget);
|
|
||||||
mDoorMarkerWidgets.clear();
|
|
||||||
|
|
||||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
|
|
||||||
// Retrieve the door markers we want to show
|
mDoorMarkersToRecycle.insert(mDoorMarkersToRecycle.end(), mInteriorDoorMarkerWidgets.begin(), mInteriorDoorMarkerWidgets.end());
|
||||||
std::vector<MWBase::World::DoorMarker> doors;
|
mInteriorDoorMarkerWidgets.clear();
|
||||||
|
|
||||||
if (mInterior)
|
if (mInterior)
|
||||||
{
|
{
|
||||||
|
for (MyGUI::Widget* widget : mExteriorDoorMarkerWidgets)
|
||||||
|
widget->setVisible(false);
|
||||||
|
|
||||||
MWWorld::CellStore* cell = world->getInterior (mPrefix);
|
MWWorld::CellStore* cell = world->getInterior (mPrefix);
|
||||||
world->getDoorMarkers(cell, doors);
|
world->getDoorMarkers(cell, doors);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int dX=-mCellDistance; dX<=mCellDistance; ++dX)
|
for (MapEntry& entry : mMaps)
|
||||||
{
|
{
|
||||||
for (int dY=-mCellDistance; dY<=mCellDistance; ++dY)
|
if (!entry.mMapTexture && !widgetCropped(entry.mMapWidget, mLocalMap))
|
||||||
{
|
world->getDoorMarkers(world->getExterior(entry.mCellX, entry.mCellY), doors);
|
||||||
MWWorld::CellStore* cell = world->getExterior (mCurX+dX, mCurY+dY);
|
|
||||||
world->getDoorMarkers(cell, doors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (doors.empty())
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a widget for each marker
|
// Create a widget for each marker
|
||||||
int counter = 0;
|
|
||||||
for (MWBase::World::DoorMarker& marker : doors)
|
for (MWBase::World::DoorMarker& marker : doors)
|
||||||
{
|
{
|
||||||
std::vector<std::string> destNotes;
|
std::vector<std::string> destNotes;
|
||||||
@ -580,28 +653,33 @@ namespace MWGui
|
|||||||
for (CustomMarkerCollection::ContainerType::const_iterator iter = markers.first; iter != markers.second; ++iter)
|
for (CustomMarkerCollection::ContainerType::const_iterator iter = markers.first; iter != markers.second; ++iter)
|
||||||
destNotes.push_back(iter->second.mNote);
|
destNotes.push_back(iter->second.mNote);
|
||||||
|
|
||||||
MarkerUserData data (mLocalMapRender);
|
MyGUI::Widget* markerWidget = nullptr;
|
||||||
data.notes = destNotes;
|
MarkerUserData* data;
|
||||||
data.caption = marker.name;
|
if (mDoorMarkersToRecycle.empty())
|
||||||
MyGUI::IntPoint widgetPos = getMarkerPosition(marker.x, marker.y, data);
|
{
|
||||||
MyGUI::IntCoord widgetCoord(widgetPos.left - 4,
|
markerWidget = createDoorMarker(marker.name, destNotes, marker.x, marker.y);
|
||||||
widgetPos.top - 4,
|
data = markerWidget->getUserData<MarkerUserData>();
|
||||||
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);
|
|
||||||
doorMarkerCreated(markerWidget);
|
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()
|
void LocalMapBase::updateMagicMarkers()
|
||||||
@ -623,23 +701,46 @@ namespace MWGui
|
|||||||
&& (!mInterior || Misc::StringUtils::ciEqual(markedCell->getCell()->mName, mPrefix)))
|
&& (!mInterior || Misc::StringUtils::ciEqual(markedCell->getCell()->mName, mPrefix)))
|
||||||
{
|
{
|
||||||
MarkerUserData markerPos (mLocalMapRender);
|
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",
|
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->setDepth(Local_MarkerAboveFogLayer);
|
||||||
markerWidget->setImageTexture("textures\\menu_map_smark.dds");
|
markerWidget->setImageTexture("textures\\menu_map_smark.dds");
|
||||||
markerWidget->setNeedMouseFocus(false);
|
markerWidget->setNeedMouseFocus(false);
|
||||||
|
markerWidget->setUserData(markerPos);
|
||||||
mMagicMarkerWidgets.push_back(markerWidget);
|
mMagicMarkerWidgets.push_back(markerWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
redraw();
|
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)
|
MapWindow::MapWindow(CustomMarkerCollection &customMarkers, DragAndDrop* drag, MWRender::LocalMap* localMapRender, SceneUtil::WorkQueue* workQueue)
|
||||||
: WindowPinnableBase("openmw_map_window.layout")
|
: WindowPinnableBase("openmw_map_window.layout")
|
||||||
, LocalMapBase(customMarkers, localMapRender)
|
, LocalMapBase(customMarkers, localMapRender)
|
||||||
@ -690,14 +791,16 @@ namespace MWGui
|
|||||||
getWidget(mEventBoxGlobal, "EventBoxGlobal");
|
getWidget(mEventBoxGlobal, "EventBoxGlobal");
|
||||||
mEventBoxGlobal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag);
|
mEventBoxGlobal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag);
|
||||||
mEventBoxGlobal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart);
|
mEventBoxGlobal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart);
|
||||||
|
mEventBoxGlobal->eventMouseWheel += MyGUI::newDelegate(this, &MapWindow::onMapZoomed);
|
||||||
mEventBoxGlobal->setDepth(Global_ExploreOverlayLayer);
|
mEventBoxGlobal->setDepth(Global_ExploreOverlayLayer);
|
||||||
|
|
||||||
getWidget(mEventBoxLocal, "EventBoxLocal");
|
getWidget(mEventBoxLocal, "EventBoxLocal");
|
||||||
mEventBoxLocal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag);
|
mEventBoxLocal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag);
|
||||||
mEventBoxLocal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart);
|
mEventBoxLocal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart);
|
||||||
mEventBoxLocal->eventMouseButtonDoubleClick += MyGUI::newDelegate(this, &MapWindow::onMapDoubleClicked);
|
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);
|
mGlobalMap->setVisible(mGlobal);
|
||||||
mLocalMap->setVisible(!mGlobal);
|
mLocalMap->setVisible(!mGlobal);
|
||||||
@ -745,10 +848,11 @@ namespace MWGui
|
|||||||
MyGUI::IntPoint clickedPos = MyGUI::InputManager::getInstance().getMousePosition();
|
MyGUI::IntPoint clickedPos = MyGUI::InputManager::getInstance().getMousePosition();
|
||||||
|
|
||||||
MyGUI::IntPoint widgetPos = clickedPos - mEventBoxLocal->getAbsolutePosition();
|
MyGUI::IntPoint widgetPos = clickedPos - mEventBoxLocal->getAbsolutePosition();
|
||||||
int x = int(widgetPos.left/float(mMapWidgetSize))-mCellDistance;
|
auto mapWidgetSize = getWidgetSize();
|
||||||
int y = (int(widgetPos.top/float(mMapWidgetSize))-mCellDistance)*-1;
|
int x = int(widgetPos.left/float(mapWidgetSize))-mCellDistance;
|
||||||
float nX = widgetPos.left/float(mMapWidgetSize) - int(widgetPos.left/float(mMapWidgetSize));
|
int y = (int(widgetPos.top/float(mapWidgetSize))-mCellDistance)*-1;
|
||||||
float nY = widgetPos.top/float(mMapWidgetSize) - int(widgetPos.top/float(mMapWidgetSize));
|
float nX = widgetPos.left/float(mapWidgetSize) - int(widgetPos.left/float(mapWidgetSize));
|
||||||
|
float nY = widgetPos.top/float(mapWidgetSize) - int(widgetPos.top/float(mapWidgetSize));
|
||||||
x += mCurX;
|
x += mCurX;
|
||||||
y += mCurY;
|
y += mCurY;
|
||||||
|
|
||||||
@ -781,6 +885,106 @@ namespace MWGui
|
|||||||
mEditNoteDialog.setText("");
|
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)
|
void MapWindow::onChangeScrollWindowCoord(MyGUI::Widget* sender)
|
||||||
{
|
{
|
||||||
MyGUI::IntCoord currentCoordinates = sender->getCoord();
|
MyGUI::IntCoord currentCoordinates = sender->getCoord();
|
||||||
@ -804,8 +1008,7 @@ namespace MWGui
|
|||||||
void MapWindow::renderGlobalMap()
|
void MapWindow::renderGlobalMap()
|
||||||
{
|
{
|
||||||
mGlobalMapRender->render();
|
mGlobalMapRender->render();
|
||||||
mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight());
|
resizeGlobalMap();
|
||||||
mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MapWindow::~MapWindow()
|
MapWindow::~MapWindow()
|
||||||
@ -818,28 +1021,25 @@ namespace MWGui
|
|||||||
setTitle("#{sCell=" + cellName + "}");
|
setTitle("#{sCell=" + cellName + "}");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapWindow::addVisitedLocation(const std::string& name, int x, int y)
|
MyGUI::IntCoord MapWindow::createMarkerCoords(float x, float y, float agregatedWeight) const
|
||||||
{
|
|
||||||
CellId cell;
|
|
||||||
cell.first = x;
|
|
||||||
cell.second = y;
|
|
||||||
if (mMarkers.insert(cell).second)
|
|
||||||
{
|
{
|
||||||
float worldX, worldY;
|
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;
|
const float markerSize = getMarkerSize(agregatedWeight);
|
||||||
int offset = mGlobalMapRender->getCellSize()/2 - markerSize/2;
|
const float halfMarkerSize = markerSize / 2.0f;
|
||||||
MyGUI::IntCoord widgetCoord(
|
return MyGUI::IntCoord(
|
||||||
static_cast<int>(worldX * mGlobalMapRender->getWidth()+offset),
|
static_cast<int>(worldX - halfMarkerSize),
|
||||||
static_cast<int>(worldY * mGlobalMapRender->getHeight() + offset),
|
static_cast<int>(worldY - halfMarkerSize),
|
||||||
markerSize, markerSize);
|
markerSize, markerSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
MyGUI::Widget* MapWindow::createMarker(const std::string& name, float x, float y, float agregatedWeight)
|
||||||
|
{
|
||||||
MyGUI::Widget* markerWidget = mGlobalMap->createWidget<MyGUI::Widget>("MarkerButton",
|
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 + "}");
|
markerWidget->setUserString("Caption_TextOneLine", "#{sCell=" + name + "}");
|
||||||
|
|
||||||
setGlobalMapMarkerTooltip(markerWidget, x, y);
|
setGlobalMapMarkerTooltip(markerWidget, x, y);
|
||||||
|
|
||||||
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
|
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
|
||||||
@ -848,8 +1048,46 @@ namespace MWGui
|
|||||||
markerWidget->setColour(MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=normal}")));
|
markerWidget->setColour(MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=normal}")));
|
||||||
markerWidget->setDepth(Global_MarkerLayer);
|
markerWidget->setDepth(Global_MarkerLayer);
|
||||||
markerWidget->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag);
|
markerWidget->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag);
|
||||||
|
markerWidget->eventMouseWheel += MyGUI::newDelegate(this, &MapWindow::onMapZoomed);
|
||||||
markerWidget->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart);
|
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()
|
void MapWindow::updateCustomMarkers()
|
||||||
{
|
{
|
||||||
LocalMapBase::updateCustomMarkers();
|
LocalMapBase::updateCustomMarkers();
|
||||||
|
|
||||||
for (auto& widgetPair : mGlobalMapMarkers)
|
for (auto& [widgetPair, ignore]: mGlobalMapMarkers)
|
||||||
{
|
setGlobalMapMarkerTooltip(widgetPair.widget, widgetPair.position.x(), widgetPair.position.y());
|
||||||
int x = widgetPair.first.first;
|
|
||||||
int y = widgetPair.first.second;
|
|
||||||
MyGUI::Widget* markerWidget = widgetPair.second;
|
|
||||||
setGlobalMapMarkerTooltip(markerWidget, x, y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id)
|
void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id)
|
||||||
@ -934,9 +1187,6 @@ namespace MWGui
|
|||||||
|
|
||||||
mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" :
|
mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" :
|
||||||
"#{sWorld}");
|
"#{sWorld}");
|
||||||
|
|
||||||
if (mGlobal)
|
|
||||||
globalMapUpdatePlayer ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapWindow::onPinToggled()
|
void MapWindow::onPinToggled()
|
||||||
@ -978,19 +1228,21 @@ namespace MWGui
|
|||||||
setGlobalMapPlayerDir(mLastDirectionX, mLastDirectionY);
|
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)
|
void MapWindow::setGlobalMapPlayerPosition(float worldX, float worldY)
|
||||||
{
|
{
|
||||||
float x, y;
|
float x, y;
|
||||||
mGlobalMapRender->worldPosToImageSpace (worldX, worldY, x, y);
|
worldPosToGlobalMapImageSpace(worldX, worldY, x, y);
|
||||||
x *= mGlobalMapRender->getWidth();
|
|
||||||
y *= mGlobalMapRender->getHeight();
|
|
||||||
|
|
||||||
mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(static_cast<int>(x - 16), static_cast<int>(y - 16)));
|
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)
|
void MapWindow::setGlobalMapPlayerDir(const float x, const float y)
|
||||||
@ -1027,8 +1279,9 @@ namespace MWGui
|
|||||||
mChanged = true;
|
mChanged = true;
|
||||||
|
|
||||||
for (auto& widgetPair : mGlobalMapMarkers)
|
for (auto& widgetPair : mGlobalMapMarkers)
|
||||||
MyGUI::Gui::getInstance().destroyWidget(widgetPair.second);
|
MyGUI::Gui::getInstance().destroyWidget(widgetPair.first.widget);
|
||||||
mGlobalMapMarkers.clear();
|
mGlobalMapMarkers.clear();
|
||||||
|
mGlobalMapMarkersByName.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapWindow::write(ESM::ESMWriter &writer, Loading::Listener& progress)
|
void MapWindow::write(ESM::ESMWriter &writer, Loading::Listener& progress)
|
||||||
@ -1075,12 +1328,14 @@ namespace MWGui
|
|||||||
marker->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag);
|
marker->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag);
|
||||||
marker->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart);
|
marker->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart);
|
||||||
marker->eventMouseButtonDoubleClick += MyGUI::newDelegate(this, &MapWindow::onCustomMarkerDoubleClicked);
|
marker->eventMouseButtonDoubleClick += MyGUI::newDelegate(this, &MapWindow::onCustomMarkerDoubleClicked);
|
||||||
|
marker->eventMouseWheel += MyGUI::newDelegate(this, &MapWindow::onMapZoomed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapWindow::doorMarkerCreated(MyGUI::Widget *marker)
|
void MapWindow::doorMarkerCreated(MyGUI::Widget *marker)
|
||||||
{
|
{
|
||||||
marker->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag);
|
marker->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag);
|
||||||
marker->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart);
|
marker->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart);
|
||||||
|
marker->eventMouseWheel += MyGUI::newDelegate(this, &MapWindow::onMapZoomed);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <components/esm/cellid.hpp>
|
#include <components/esm/cellid.hpp>
|
||||||
|
|
||||||
#include <components/esm/custommarkerstate.hpp>
|
#include <components/esm/custommarkerstate.hpp>
|
||||||
|
#include <components/misc/constants.hpp>
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
@ -72,7 +73,7 @@ namespace MWGui
|
|||||||
public:
|
public:
|
||||||
LocalMapBase(CustomMarkerCollection& markers, MWRender::LocalMap* localMapRender, bool fogOfWarEnabled = true);
|
LocalMapBase(CustomMarkerCollection& markers, MWRender::LocalMap* localMapRender, bool fogOfWarEnabled = true);
|
||||||
virtual ~LocalMapBase();
|
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 setCellPrefix(const std::string& prefix);
|
||||||
void setActiveCell(const int x, const int y, bool interior=false);
|
void setActiveCell(const int x, const int y, bool interior=false);
|
||||||
@ -107,9 +108,15 @@ namespace MWGui
|
|||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void updateLocalMap();
|
||||||
|
|
||||||
|
float mLocalMapZoom = 1.f;
|
||||||
MWRender::LocalMap* mLocalMapRender;
|
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;
|
bool mInterior;
|
||||||
MyGUI::ScrollView* mLocalMap;
|
MyGUI::ScrollView* mLocalMap;
|
||||||
MyGUI::ImageBox* mCompass;
|
MyGUI::ImageBox* mCompass;
|
||||||
@ -141,17 +148,27 @@ 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*> 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*> mMagicMarkerWidgets;
|
||||||
std::vector<MyGUI::Widget*> mCustomMarkerWidgets;
|
std::vector<MyGUI::Widget*> mCustomMarkerWidgets;
|
||||||
|
std::vector<MyGUI::Widget*> mDoorMarkersToRecycle;
|
||||||
|
|
||||||
|
std::vector<MyGUI::Widget*>& currentDoorMarkersWidgets();
|
||||||
|
|
||||||
virtual void updateCustomMarkers();
|
virtual void updateCustomMarkers();
|
||||||
|
|
||||||
void applyFogOfWar();
|
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 notifyPlayerUpdate() {}
|
||||||
|
virtual void centerView();
|
||||||
virtual void notifyMapChanged() {}
|
virtual void notifyMapChanged() {}
|
||||||
|
|
||||||
virtual void customMarkerCreated(MyGUI::Widget* marker) {}
|
virtual void customMarkerCreated(MyGUI::Widget* marker) {}
|
||||||
@ -163,6 +180,7 @@ namespace MWGui
|
|||||||
void addDetectionMarkers(int type);
|
void addDetectionMarkers(int type);
|
||||||
|
|
||||||
void redraw();
|
void redraw();
|
||||||
|
float getWidgetSize() const;
|
||||||
|
|
||||||
float mMarkerUpdateTimer;
|
float mMarkerUpdateTimer;
|
||||||
|
|
||||||
@ -171,7 +189,6 @@ namespace MWGui
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void updateDoorMarkers();
|
void updateDoorMarkers();
|
||||||
bool mNeedDoorMarkersUpdate;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class EditNoteDialog : public MWGui::WindowModal
|
class EditNoteDialog : public MWGui::WindowModal
|
||||||
@ -244,6 +261,9 @@ namespace MWGui
|
|||||||
void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
|
void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
|
||||||
void onWorldButtonClicked(MyGUI::Widget* _sender);
|
void onWorldButtonClicked(MyGUI::Widget* _sender);
|
||||||
void onMapDoubleClicked(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 onCustomMarkerDoubleClicked(MyGUI::Widget* sender);
|
||||||
void onNoteEditOk();
|
void onNoteEditOk();
|
||||||
void onNoteEditDelete();
|
void onNoteEditDelete();
|
||||||
@ -252,6 +272,12 @@ namespace MWGui
|
|||||||
void onChangeScrollWindowCoord(MyGUI::Widget* sender);
|
void onChangeScrollWindowCoord(MyGUI::Widget* sender);
|
||||||
void globalMapUpdatePlayer();
|
void globalMapUpdatePlayer();
|
||||||
void setGlobalMapMarkerTooltip(MyGUI::Widget* widget, int x, int y);
|
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;
|
MyGUI::ScrollView* mGlobalMap;
|
||||||
std::unique_ptr<MyGUI::ITexture> mGlobalMapTexture;
|
std::unique_ptr<MyGUI::ITexture> mGlobalMapTexture;
|
||||||
@ -273,9 +299,21 @@ namespace MWGui
|
|||||||
MyGUI::Button* mEventBoxGlobal;
|
MyGUI::Button* mEventBoxGlobal;
|
||||||
MyGUI::Button* mEventBoxLocal;
|
MyGUI::Button* mEventBoxLocal;
|
||||||
|
|
||||||
|
float mGlobalMapZoom = 1.0f;
|
||||||
MWRender::GlobalMap* mGlobalMapRender;
|
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;
|
EditNoteDialog mEditNoteDialog;
|
||||||
ESM::CustomMarker mEditingMarker;
|
ESM::CustomMarker mEditingMarker;
|
||||||
@ -288,6 +326,7 @@ namespace MWGui
|
|||||||
|
|
||||||
void notifyPlayerUpdate() override;
|
void notifyPlayerUpdate() override;
|
||||||
|
|
||||||
|
void centerView() override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -270,17 +270,9 @@ namespace MWRender
|
|||||||
|
|
||||||
void GlobalMap::worldPosToImageSpace(float x, float z, float& imageX, float& imageY)
|
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);
|
imageY = (1.f-float(z / float(Constants::CellSizeInUnits) - mMinY) / (mMaxY - mMinY + 1)) * getHeight();
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalMap::requestOverlayTextureUpdate(int x, int y, int width, int height, osg::ref_ptr<osg::Texture2D> texture, bool clear, bool cpuCopy,
|
void GlobalMap::requestOverlayTextureUpdate(int x, int y, int width, int height, osg::ref_ptr<osg::Texture2D> texture, bool clear, bool cpuCopy,
|
||||||
|
@ -41,12 +41,8 @@ namespace MWRender
|
|||||||
int getWidth() const { return mWidth; }
|
int getWidth() const { return mWidth; }
|
||||||
int getHeight() const { return mHeight; }
|
int getHeight() const { return mHeight; }
|
||||||
|
|
||||||
int getCellSize() const { return mCellSize; }
|
|
||||||
|
|
||||||
void worldPosToImageSpace(float x, float z, float& imageX, float& imageY);
|
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);
|
void exploreCell (int cellX, int cellY, osg::ref_ptr<osg::Texture2D> localMapTexture);
|
||||||
|
|
||||||
/// Clears the overlay
|
/// Clears the overlay
|
||||||
|
@ -118,14 +118,15 @@ const osg::Vec2f LocalMap::rotatePoint(const osg::Vec2f& point, const osg::Vec2f
|
|||||||
|
|
||||||
void LocalMap::clear()
|
void LocalMap::clear()
|
||||||
{
|
{
|
||||||
mSegments.clear();
|
mExteriorSegments.clear();
|
||||||
|
mInteriorSegments.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalMap::saveFogOfWar(MWWorld::CellStore* cell)
|
void LocalMap::saveFogOfWar(MWWorld::CellStore* cell)
|
||||||
{
|
{
|
||||||
if (!mInterior)
|
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)
|
if (segment.mFogOfWarImage && segment.mHasFogState)
|
||||||
{
|
{
|
||||||
@ -155,7 +156,7 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell)
|
|||||||
{
|
{
|
||||||
for (int y = 0; y < segments.second; ++y)
|
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();
|
fog->mFogTextures.emplace_back();
|
||||||
|
|
||||||
@ -249,26 +250,10 @@ void LocalMap::setupRenderToTexture(osg::ref_ptr<osg::Camera> camera, int x, int
|
|||||||
mRoot->addChild(camera);
|
mRoot->addChild(camera);
|
||||||
mActiveCameras.push_back(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;
|
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)
|
void LocalMap::requestMap(const MWWorld::CellStore* cell)
|
||||||
{
|
{
|
||||||
if (cell->isExterior())
|
if (cell->isExterior())
|
||||||
@ -276,13 +261,13 @@ void LocalMap::requestMap(const MWWorld::CellStore* cell)
|
|||||||
int cellX = cell->getCell()->getGridX();
|
int cellX = cell->getCell()->getGridX();
|
||||||
int cellY = cell->getCell()->getGridY();
|
int cellY = cell->getCell()->getGridY();
|
||||||
|
|
||||||
MapSegment& segment = mSegments[std::make_pair(cellX, cellY)];
|
MapSegment& segment = mExteriorSegments[std::make_pair(cellX, cellY)];
|
||||||
if (!needUpdate(segment.mGrid, mCurrentGrid, cellX, cellY))
|
if (!segment.needUpdate)
|
||||||
return;
|
return;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
segment.mGrid = mCurrentGrid;
|
|
||||||
requestExteriorMap(cell);
|
requestExteriorMap(cell);
|
||||||
|
segment.needUpdate = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -292,27 +277,27 @@ void LocalMap::requestMap(const MWWorld::CellStore* cell)
|
|||||||
void LocalMap::addCell(MWWorld::CellStore *cell)
|
void LocalMap::addCell(MWWorld::CellStore *cell)
|
||||||
{
|
{
|
||||||
if (cell->isExterior())
|
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)
|
void LocalMap::removeCell(MWWorld::CellStore *cell)
|
||||||
{
|
{
|
||||||
saveFogOfWar(cell);
|
saveFogOfWar(cell);
|
||||||
|
|
||||||
if (cell->isExterior())
|
if (!cell->isExterior())
|
||||||
{
|
mInteriorSegments.clear();
|
||||||
std::pair<int, int> coords = std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY());
|
|
||||||
mSegments.erase(coords);
|
|
||||||
mCurrentGrid.erase(coords);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
mSegments.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<osg::Texture2D> LocalMap::getMapTexture(int x, int y)
|
osg::ref_ptr<osg::Texture2D> LocalMap::getMapTexture(int x, int y)
|
||||||
{
|
{
|
||||||
SegmentMap::iterator found = mSegments.find(std::make_pair(x, y));
|
auto& segments(mInterior ? mInteriorSegments : mExteriorSegments);
|
||||||
if (found == mSegments.end())
|
SegmentMap::iterator found = segments.find(std::make_pair(x, y));
|
||||||
|
if (found == segments.end())
|
||||||
return osg::ref_ptr<osg::Texture2D>();
|
return osg::ref_ptr<osg::Texture2D>();
|
||||||
else
|
else
|
||||||
return found->second.mMapTexture;
|
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)
|
osg::ref_ptr<osg::Texture2D> LocalMap::getFogOfWarTexture(int x, int y)
|
||||||
{
|
{
|
||||||
SegmentMap::iterator found = mSegments.find(std::make_pair(x, y));
|
auto& segments(mInterior ? mInteriorSegments : mExteriorSegments);
|
||||||
if (found == mSegments.end())
|
SegmentMap::iterator found = segments.find(std::make_pair(x, y));
|
||||||
|
if (found == segments.end())
|
||||||
return osg::ref_ptr<osg::Texture2D>();
|
return osg::ref_ptr<osg::Texture2D>();
|
||||||
else
|
else
|
||||||
return found->second.mFogOfWarTexture;
|
return found->second.mFogOfWarTexture;
|
||||||
@ -371,7 +357,7 @@ void LocalMap::requestExteriorMap(const MWWorld::CellStore* cell)
|
|||||||
osg::Vec3d(0,1,0), zmin, zmax);
|
osg::Vec3d(0,1,0), zmin, zmax);
|
||||||
setupRenderToTexture(camera, cell->getCell()->getGridX(), cell->getCell()->getGridY());
|
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 (!segment.mFogOfWarImage)
|
||||||
{
|
{
|
||||||
if (cell->getFog())
|
if (cell->getFog())
|
||||||
@ -512,7 +498,7 @@ void LocalMap::requestInteriorMap(const MWWorld::CellStore* cell)
|
|||||||
setupRenderToTexture(camera, x, y);
|
setupRenderToTexture(camera, x, y);
|
||||||
|
|
||||||
auto coords = std::make_pair(x,y);
|
auto coords = std::make_pair(x,y);
|
||||||
MapSegment& segment = mSegments[coords];
|
MapSegment& segment = mInteriorSegments[coords];
|
||||||
if (!segment.mFogOfWarImage)
|
if (!segment.mFogOfWarImage)
|
||||||
{
|
{
|
||||||
bool loaded = false;
|
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)
|
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)
|
if (!segment.mFogOfWarImage)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -630,7 +617,8 @@ void LocalMap::updatePlayer (const osg::Vec3f& position, const osg::Quat& orient
|
|||||||
int texX = x + mx;
|
int texX = x + mx;
|
||||||
int texY = y + my*-1;
|
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)
|
if (!segment.mFogOfWarImage || !segment.mMapTexture)
|
||||||
continue;
|
continue;
|
||||||
|
@ -50,6 +50,7 @@ namespace MWRender
|
|||||||
void requestMap (const MWWorld::CellStore* cell);
|
void requestMap (const MWWorld::CellStore* cell);
|
||||||
|
|
||||||
void addCell(MWWorld::CellStore* cell);
|
void addCell(MWWorld::CellStore* cell);
|
||||||
|
void removeExteriorCell(int x, int y);
|
||||||
|
|
||||||
void removeCell (MWWorld::CellStore* cell);
|
void removeCell (MWWorld::CellStore* cell);
|
||||||
|
|
||||||
@ -126,13 +127,14 @@ namespace MWRender
|
|||||||
osg::ref_ptr<osg::Texture2D> mFogOfWarTexture;
|
osg::ref_ptr<osg::Texture2D> mFogOfWarTexture;
|
||||||
osg::ref_ptr<osg::Image> mFogOfWarImage;
|
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;
|
bool mHasFogState;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<std::pair<int, int>, MapSegment> SegmentMap;
|
typedef std::map<std::pair<int, int>, MapSegment> SegmentMap;
|
||||||
SegmentMap mSegments;
|
SegmentMap mExteriorSegments;
|
||||||
|
SegmentMap mInteriorSegments;
|
||||||
|
|
||||||
int mMapResolution;
|
int mMapResolution;
|
||||||
|
|
||||||
|
@ -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 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.
|
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.
|
||||||
|
@ -199,6 +199,12 @@ local map widget size = 512
|
|||||||
# If true, map in world mode, otherwise in local mode
|
# If true, map in world mode, otherwise in local mode
|
||||||
global = false
|
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]
|
[GUI]
|
||||||
|
|
||||||
# Scales GUI window and widget size. (<1.0 is smaller, >1.0 is larger).
|
# Scales GUI window and widget size. (<1.0 is smaller, >1.0 is larger).
|
||||||
|
@ -1006,6 +1006,16 @@ True: In non-combat mode camera is positioned behind the character's shoulder. C
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="useZoomOnMapCheckBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Enable zooming on local and global maps.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Can zoom on maps</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="graphicHerbalismCheckBox">
|
<widget class="QCheckBox" name="graphicHerbalismCheckBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user