From 5834b4baa55416856a395a0d1f462b3a921de81d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 28 Aug 2012 17:30:34 +0200 Subject: [PATCH] door markers on the local map --- apps/openmw/mwbase/world.hpp | 15 ++++ apps/openmw/mwgui/hud.cpp | 4 +- apps/openmw/mwgui/hud.hpp | 1 + apps/openmw/mwgui/map_window.cpp | 86 ++++++++++++++++++++++- apps/openmw/mwgui/map_window.hpp | 9 +++ apps/openmw/mwgui/tooltips.cpp | 18 ++++- apps/openmw/mwrender/localmap.cpp | 45 ++++++++---- apps/openmw/mwrender/localmap.hpp | 12 ++++ apps/openmw/mwrender/renderingmanager.cpp | 10 +++ apps/openmw/mwrender/renderingmanager.hpp | 6 ++ apps/openmw/mwworld/worldimp.cpp | 58 +++++++++++++++ apps/openmw/mwworld/worldimp.hpp | 9 +++ files/mygui/openmw_hud.layout | 9 ++- 13 files changed, 260 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 9c801cbff..19405fb7a 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -65,6 +65,12 @@ namespace MWBase Render_Compositors }; + struct DoorMarker + { + std::string name; + float x, y; // world position + }; + World() {} virtual ~World() {} @@ -108,6 +114,15 @@ namespace MWBase virtual Ogre::Vector2 getNorthVector (MWWorld::CellStore* cell) = 0; ///< get north vector (OGRE coordinates) for given interior cell + virtual std::vector getDoorMarkers (MWWorld::CellStore* cell) = 0; + ///< get a list of teleport door markers for a given cell, to be displayed on the local map + + virtual void getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) = 0; + ///< see MWRender::LocalMap::getInteriorMapPosition + + virtual bool isPositionExplored (float nX, float nY, int x, int y, bool interior) = 0; + ///< see MWRender::LocalMap::isPositionExplored + virtual MWWorld::Globals::Data& getGlobalVariable (const std::string& name) = 0; virtual MWWorld::Globals::Data getGlobalVariable (const std::string& name) const = 0; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 20b9765d0..b14833553 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -60,7 +60,6 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) getWidget(mHealth, "Health"); getWidget(mMagicka, "Magicka"); getWidget(mStamina, "Stamina"); - mHealthManaStaminaBaseLeft = mHealthFrame->getLeft(); MyGUI::Widget *healthFrame, *magickaFrame, *fatigueFrame; @@ -93,9 +92,10 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) getWidget(mMinimapBox, "MiniMapBox"); mMinimapBoxBaseRight = viewSize.width - mMinimapBox->getRight(); - mMinimapBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); getWidget(mMinimap, "MiniMap"); getWidget(mCompass, "Compass"); + getWidget(mMinimapButton, "MiniMapButton"); + mMinimapButton->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); getWidget(mCellNameBox, "CellName"); getWidget(mWeaponSpellBox, "WeaponSpellName"); diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 49ed6a698..de4228e87 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -50,6 +50,7 @@ namespace MWGui MyGUI::ImageBox *mWeapImage, *mSpellImage; MyGUI::ProgressPtr mWeapStatus, mSpellStatus; MyGUI::Widget *mEffectBox, *mMinimapBox; + MyGUI::Button* mMinimapButton; MyGUI::ImageBox* mEffect1; MyGUI::ScrollView* mMinimap; MyGUI::ImageBox* mCompass; diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 1ffedaac4..fb9d78147 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -1,9 +1,13 @@ #include "map_window.hpp" -#include "../mwbase/windowmanager.hpp" - #include +#include + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" + using namespace MWGui; LocalMapBase::LocalMapBase() @@ -92,10 +96,21 @@ void LocalMapBase::applyFogOfWar() void LocalMapBase::setActiveCell(const int x, const int y, bool interior) { if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) return; // don't do anything if we're still in the same cell + + // clear all previous markers + for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) + { + if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker") + { + MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i)); + } + } + for (int mx=0; mx<3; ++mx) { for (int my=0; my<3; ++my) { + // map std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" + boost::lexical_cast(y + (interior ? (my-1) : -1*(my-1))); @@ -108,12 +123,79 @@ void LocalMapBase::setActiveCell(const int x, const int y, bool interior) box->setImageTexture(image); else box->setImageTexture("black.png"); + + + // door markers + + // interior map only consists of one cell, so handle the markers only once + if (interior && (mx != 2 || my != 2)) + continue; + + MWWorld::CellStore* cell; + if (interior) + cell = MWBase::Environment::get().getWorld ()->getInterior (mPrefix); + else + cell = MWBase::Environment::get().getWorld ()->getExterior (x+mx-1, y-(my-1)); + + std::vector doors = MWBase::Environment::get().getWorld ()->getDoorMarkers (cell); + + for (std::vector::iterator it = doors.begin(); it != doors.end(); ++it) + { + MWBase::World::DoorMarker marker = *it; + + // convert world coordinates to normalized cell coordinates + MyGUI::IntCoord widgetCoord; + float nX,nY; + int cellDx, cellDy; + if (!interior) + { + const int cellSize = 8192; + + nX = (marker.x - cellSize * (x+mx-1)) / cellSize; + nY = 1 - (marker.y - cellSize * (y-(my-1))) / cellSize; + + widgetCoord = MyGUI::IntCoord(nX * 512 - 3 + mx * 512, nY * 512 - 3 + my * 512, 7, 7); + } + else + { + Ogre::Vector2 position (marker.x, -marker.y); + MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy); + + widgetCoord = MyGUI::IntCoord(nX * 512 - 3 + (1+cellDx-x) * 512, nY * 512 - 3 + (1+cellDy-y) * 512, 7, 7); + } + + std::cout << "widgetCoord " << widgetCoord.left << " " << widgetCoord.top << " nX " << nX << " nY " << nY << " xy " << x << " " << y << std::endl; + + static int counter = 0; + ++counter; + MyGUI::ImageBox* markerWidget = mLocalMap->createWidget("ImageBox", + widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); + markerWidget->setImageTexture ("textures\\door_icon.dds"); + markerWidget->setImageCoord (MyGUI::IntCoord(0,0,7,7)); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTip"); + markerWidget->setUserString("Caption_Text", marker.name); + markerWidget->setUserString("IsMarker", "true"); + + MarkerPosition markerPos; + markerPos.interior = interior; + markerPos.cellX = interior ? cellDx : x + mx - 1; + markerPos.cellY = interior ? cellDy : y + ((my - 1)*-1); + markerPos.nX = nX; + markerPos.nY = nY; + + markerWidget->setUserData(markerPos); + } + + } } mInterior = interior; mCurX = x; mCurY = y; mChanged = false; + + // fog of war applyFogOfWar(); // set the compass texture again, because MyGUI determines sorting of ImageBox widgets diff --git a/apps/openmw/mwgui/map_window.hpp b/apps/openmw/mwgui/map_window.hpp index 447c16901..c69d8986c 100644 --- a/apps/openmw/mwgui/map_window.hpp +++ b/apps/openmw/mwgui/map_window.hpp @@ -18,6 +18,15 @@ namespace MWGui void toggleFogOfWar(); + struct MarkerPosition + { + bool interior; + int cellX; + int cellY; + float nX; + float nY; + }; + protected: int mCurX, mCurY; bool mInterior; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index edc787cef..16ee27923 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -12,6 +12,7 @@ #include "../mwworld/class.hpp" +#include "map_window.hpp" #include "widgets.hpp" using namespace MWGui; @@ -150,7 +151,19 @@ void ToolTips::onFrame(float frameDuration) { return; } - else if (type == "ItemPtr") + + // special handling for markers on the local map: the tooltip should only be visible + // if the marker is not hidden due to the fog of war. + if (focus->getUserString ("IsMarker") == "true") + { + LocalMapBase::MarkerPosition pos = *focus->getUserData(); + + if (!MWBase::Environment::get().getWorld ()->isPositionExplored (pos.nX, pos.nY, pos.cellX, pos.cellY, pos.interior)) + return; + } + + + if (type == "ItemPtr") { mFocusObject = *focus->getUserData(); tooltipSize = getToolTipViaPtr(false); @@ -199,7 +212,8 @@ void ToolTips::onFrame(float frameDuration) it != userStrings.end(); ++it) { if (it->first == "ToolTipType" - || it->first == "ToolTipLayout") + || it->first == "ToolTipLayout" + || it->first == "IsMarker") continue; diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 0e85d32e0..e254a2f0a 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -270,6 +270,34 @@ void LocalMap::render(const float x, const float y, mRendering->getScene()->setFog(FOG_LINEAR, clr, 0, fStart, fEnd); } +void LocalMap::getInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y) +{ + pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().z), mAngle); + + Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z); + + x = std::ceil((pos.x - min.x)/sSize)-1; + y = std::ceil((pos.y - min.y)/sSize)-1; + + nX = (pos.x - min.x - sSize*x)/sSize; + nY = (pos.y - min.y - sSize*y)/sSize; +} + +bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interior) +{ + std::string texName = (interior ? mInteriorName + "_" : "Cell_") + coordStr(x, y); + + if (mBuffers.find(texName) == mBuffers.end()) + return false; + + int texU = (sFogOfWarResolution-1) * nX; + int texV = (sFogOfWarResolution-1) * nY; + + Ogre::uint32 clr = mBuffers[texName][texV * sFogOfWarResolution + texU]; + uint8 alpha = (clr >> 24); + return alpha < 200; +} + void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaternion& orientation) { if (sFogOfWarSkip != 0) @@ -281,14 +309,12 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni // retrieve the x,y grid coordinates the player is in int x,y; - Vector3 _pos(position.x, 0, position.z); - Vector2 pos(_pos.x, _pos.z); + float u,v; - if (mInterior) - { - pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().z), mAngle); - } + Vector2 pos(position.x, position.z); + if (mInterior) + getInteriorMapPosition(pos, u,v, x,y); Vector3 playerdirection = mCameraRotNode->convertWorldToLocalOrientation(orientation).zAxis(); @@ -303,14 +329,10 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni } else { - x = std::ceil((pos.x - min.x)/sSize)-1; - y = std::ceil((pos.y - min.y)/sSize)-1; - MWBase::Environment::get().getWindowManager()->setInteriorMapTexture(x,y); } // convert from world coordinates to texture UV coordinates - float u,v; std::string texBaseName; if (!mInterior) { @@ -320,9 +342,6 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni } else { - u = (pos.x - min.x - sSize*x)/sSize; - v = (pos.y - min.y - sSize*y)/sSize; - texBaseName = mInteriorName + "_"; } diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index c5cd908fc..056d2498a 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -58,6 +58,18 @@ namespace MWRender */ void saveFogOfWar(MWWorld::CellStore* cell); + + /** + * Get the interior map texture index and normalized position + * on this texture, given a world position (in ogre coordinates) + */ + void getInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y); + + /** + * Check if a given position is explored by the player (i.e. not obscured by fog of war) + */ + bool isPositionExplored (float nX, float nY, int x, int y, bool interior); + private: OEngine::Render::OgreRenderer* mRendering; MWRender::RenderingManager* mRenderingManager; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 2d29e8f55..edeb0fe12 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -863,4 +863,14 @@ void RenderingManager::getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float mPlayer->getSightAngles(pitch, yaw); } +void RenderingManager::getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) +{ + return mLocalMap->getInteriorMapPosition (position, nX, nY, x, y); +} + +bool RenderingManager::isPositionExplored (float nX, float nY, int x, int y, bool interior) +{ + return mLocalMap->isPositionExplored(nX, nY, x, y, interior); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index b6bfcbf97..de2449150 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -184,6 +184,12 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList static bool waterShaderSupported(); + virtual void getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y); + ///< see MWRender::LocalMap::getInteriorMapPosition + + virtual bool isPositionExplored (float nX, float nY, int x, int y, bool interior); + ///< see MWRender::LocalMap::isPositionExplored + protected: virtual void windowResized(Ogre::RenderWindow* rw); virtual void windowClosed(Ogre::RenderWindow* rw); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0ad733e70..8e9d981c1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1031,6 +1031,64 @@ namespace MWWorld return d; } + std::vector World::getDoorMarkers (CellStore* cell) + { + std::vector result; + + MWWorld::CellRefList doors = cell->doors; + std::list< MWWorld::LiveCellRef > refList = doors.list; + for (std::list< MWWorld::LiveCellRef >::iterator it = refList.begin(); it != refList.end(); ++it) + { + MWWorld::LiveCellRef ref = *it; + + if (ref.ref.teleport) + { + World::DoorMarker newMarker; + + std::string dest; + if (ref.ref.destCell != "") + { + // door leads to an interior, use interior name + dest = ref.ref.destCell; + } + else + { + // door leads to exterior, use cell name (if any), otherwise translated region name + int x,y; + positionToIndex (ref.ref.doorDest.pos[0], ref.ref.doorDest.pos[1], x, y); + const ESM::Cell* cell = mStore.cells.findExt(x,y); + if (cell->name != "") + dest = cell->name; + else + { + const ESM::Region* region = mStore.regions.search(cell->region); + dest = region->name; + } + } + + newMarker.name = dest; + + ESM::Position pos = ref.mData.getPosition (); + + newMarker.x = pos.pos[0]; + newMarker.y = pos.pos[1]; + result.push_back(newMarker); + } + } + + return result; + } + + void World::getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) + { + mRendering->getInteriorMapPosition(position, nX, nY, x, y); + } + + bool World::isPositionExplored (float nX, float nY, int x, int y, bool interior) + { + return mRendering->isPositionExplored(nX, nY, x, y, interior); + } + void World::setWaterHeight(const float height) { mRendering->setWaterHeight(height); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 51216e3a5..1d932bce2 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -140,6 +140,15 @@ namespace MWWorld virtual Ogre::Vector2 getNorthVector (CellStore* cell); ///< get north vector (OGRE coordinates) for given interior cell + virtual std::vector getDoorMarkers (MWWorld::CellStore* cell); + ///< get a list of teleport door markers for a given cell, to be displayed on the local map + + virtual void getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y); + ///< see MWRender::LocalMap::getInteriorMapPosition + + virtual bool isPositionExplored (float nX, float nY, int x, int y, bool interior); + ///< see MWRender::LocalMap::isPositionExplored + virtual Globals::Data& getGlobalVariable (const std::string& name); virtual Globals::Data getGlobalVariable (const std::string& name) const; diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index cf353a205..e4c6f0765 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -76,18 +76,21 @@ - + - - + + + + +