#include "mapwindow.hpp" #include #include #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwworld/player.hpp" #include "../mwrender/globalmap.hpp" #include "widgets.hpp" namespace MWGui { LocalMapBase::LocalMapBase() : mCurX(0) , mCurY(0) , mInterior(false) , mFogOfWar(true) , mLocalMap(NULL) , mMapDragAndDrop(false) , mPrefix() , mChanged(true) , mLayout(NULL) , mLastPositionX(0.0f) , mLastPositionY(0.0f) , mLastDirectionX(0.0f) , mLastDirectionY(0.0f) , mCompass(NULL) { } LocalMapBase::~LocalMapBase() { } void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop) { mLocalMap = widget; mLayout = layout; mMapDragAndDrop = mapDragAndDrop; mCompass = compass; // create 3x3 map widgets, 512x512 each, holding a 1024x1024 texture each const int widgetSize = 512; for (int mx=0; mx<3; ++mx) { for (int my=0; my<3; ++my) { MyGUI::ImageBox* map = mLocalMap->createWidget("ImageBox", MyGUI::IntCoord(mx*widgetSize, my*widgetSize, widgetSize, widgetSize), MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my)); MyGUI::ImageBox* fog = map->createWidget("ImageBox", MyGUI::IntCoord(0, 0, widgetSize, widgetSize), MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my) + "_fog"); if (!mMapDragAndDrop) { map->setNeedMouseFocus(false); fog->setNeedMouseFocus(false); } mMapWidgets.push_back(map); mFogWidgets.push_back(fog); } } } void LocalMapBase::setCellPrefix(const std::string& prefix) { mPrefix = prefix; mChanged = true; } void LocalMapBase::toggleFogOfWar() { mFogOfWar = !mFogOfWar; applyFogOfWar(); } void LocalMapBase::applyFogOfWar() { for (int mx=0; mx<3; ++mx) { for (int my=0; my<3; ++my) { std::string image = mPrefix+"_"+ boost::lexical_cast(mCurX + (mx-1)) + "_" + boost::lexical_cast(mCurY + (-1*(my-1))); MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; fog->setImageTexture(mFogOfWar ? ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" : "black.png" ) : ""); } } notifyMapChanged (); } void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) { applyFogOfWar (); } void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2) { 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 + (-1*(my-1))); MyGUI::ImageBox* box = mMapWidgets[my + 3*mx]; if (MyGUI::RenderManager::getInstance().getTexture(image) != 0) 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 - 4 + mx * 512, nY * 512 - 4 + my * 512, 8, 8); } else { Ogre::Vector2 position (marker.x, marker.y); MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy); widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8); } static int counter = 0; ++counter; MyGUI::Button* markerWidget = mLocalMap->createWidget("ButtonImage", widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); markerWidget->setImageResource("DoorMarker"); markerWidget->setUserString("ToolTipType", "Layout"); markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); markerWidget->setUserString("Caption_TextOneLine", marker.name); markerWidget->setUserString("IsMarker", "true"); markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused); markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused); 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 // based on the last setImageTexture call std::string tex = "textures\\compass.dds"; mCompass->setImageTexture(""); mCompass->setImageTexture(tex); } void LocalMapBase::setPlayerPos(const float x, const float y) { if (x == mLastPositionX && y == mLastPositionY) return; notifyPlayerUpdate (); MyGUI::IntSize size = mLocalMap->getCanvasSize(); MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height); MyGUI::IntCoord viewsize = mLocalMap->getCoord(); MyGUI::IntPoint pos(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top); mLocalMap->setViewOffset(pos); mCompass->setPosition(MyGUI::IntPoint(512+x*512-16, 512+y*512-16)); mLastPositionX = x; mLastPositionY = y; } void LocalMapBase::setPlayerDir(const float x, const float y) { if (x == mLastDirectionX && y == mLastDirectionY) return; notifyPlayerUpdate (); MyGUI::ISubWidget* main = mCompass->getSubWidgetMain(); MyGUI::RotatingSkin* rotatingSubskin = main->castType(); rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); float angle = std::atan2(x,y); rotatingSubskin->setAngle(angle); mLastDirectionX = x; mLastDirectionY = y; } // ------------------------------------------------------------------------------------------ MapWindow::MapWindow(const std::string& cacheDir) : MWGui::WindowPinnableBase("openmw_map_window.layout") , mGlobal(false) , mGlobalMap(0) , mGlobalMapRender(0) { setCoord(500,0,320,300); getWidget(mLocalMap, "LocalMap"); getWidget(mGlobalMap, "GlobalMap"); getWidget(mGlobalMapImage, "GlobalMapImage"); getWidget(mGlobalMapOverlay, "GlobalMapOverlay"); getWidget(mPlayerArrowLocal, "CompassLocal"); getWidget(mPlayerArrowGlobal, "CompassGlobal"); mGlobalMap->setVisible (false); getWidget(mButton, "WorldButton"); mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); mButton->setCaptionWithReplacing("#{sWorld}"); getWidget(mEventBoxGlobal, "EventBoxGlobal"); mEventBoxGlobal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); mEventBoxGlobal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); getWidget(mEventBoxLocal, "EventBoxLocal"); mEventBoxLocal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); mEventBoxLocal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); LocalMapBase::init(mLocalMap, mPlayerArrowLocal, this); } void MapWindow::renderGlobalMap(Loading::Listener* loadingListener) { mGlobalMapRender = new MWRender::GlobalMap(""); mGlobalMapRender->render(loadingListener); mGlobalMapImage->setImageTexture("GlobalMap.png"); mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); } MapWindow::~MapWindow() { delete mGlobalMapRender; } void MapWindow::setCellName(const std::string& cellName) { setTitle("#{sCell=" + cellName + "}"); } void MapWindow::addVisitedLocation(const std::string& name, int x, int y) { float worldX, worldY; mGlobalMapRender->cellTopLeftCornerToImageSpace (x, y, worldX, worldY); MyGUI::IntCoord widgetCoord( worldX * mGlobalMapRender->getWidth()+6, worldY * mGlobalMapRender->getHeight()+6, 12, 12); static int _counter=0; MyGUI::Button* markerWidget = mGlobalMapImage->createWidget("ButtonImage", widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(_counter)); markerWidget->setImageResource("DoorMarker"); markerWidget->setUserString("ToolTipType", "Layout"); markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); markerWidget->setUserString("Caption_TextOneLine", name); ++_counter; markerWidget = mEventBoxGlobal->createWidget("", widgetCoord, MyGUI::Align::Default); markerWidget->setNeedMouseFocus (true); markerWidget->setUserString("ToolTipType", "Layout"); markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); markerWidget->setUserString("Caption_TextOneLine", name); } void MapWindow::cellExplored(int x, int y) { mGlobalMapRender->exploreCell(x,y); } void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) { if (_id!=MyGUI::MouseButton::Left) return; mLastDragPos = MyGUI::IntPoint(_left, _top); } void MapWindow::onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) { if (_id!=MyGUI::MouseButton::Left) return; MyGUI::IntPoint diff = MyGUI::IntPoint(_left, _top) - mLastDragPos; if (!mGlobal) mLocalMap->setViewOffset( mLocalMap->getViewOffset() + diff ); else mGlobalMap->setViewOffset( mGlobalMap->getViewOffset() + diff ); mLastDragPos = MyGUI::IntPoint(_left, _top); } void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) { mGlobal = !mGlobal; mGlobalMap->setVisible(mGlobal); mLocalMap->setVisible(!mGlobal); mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : "#{sWorld}"); if (mGlobal) globalMapUpdatePlayer (); } void MapWindow::onPinToggled() { MWBase::Environment::get().getWindowManager()->setMinimapVisibility(!mPinned); } void MapWindow::open() { mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); for (unsigned int i=0; igetChildCount (); ++i) { if (mGlobalMapImage->getChildAt (i)->getName().substr(0,6) == "Marker") mGlobalMapImage->getChildAt (i)->castType()->setImageResource("DoorMarker"); } globalMapUpdatePlayer(); mPlayerArrowGlobal->setImageTexture ("textures\\compass.dds"); } void MapWindow::globalMapUpdatePlayer () { Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y); float worldX, worldY; mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); worldX *= mGlobalMapRender->getWidth(); worldY *= mGlobalMapRender->getHeight(); // for interiors, we have no choice other than using the last position & direction. /// \todo save this last position in the savegame? if (MWBase::Environment::get().getWorld ()->isCellExterior ()) { mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16)); MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain(); MyGUI::RotatingSkin* rotatingSubskin = main->castType(); rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); float angle = std::atan2(dir.x, dir.y); rotatingSubskin->setAngle(angle); // set the view offset so that player is in the center MyGUI::IntSize viewsize = mGlobalMap->getSize(); MyGUI::IntPoint viewoffs(0.5*viewsize.width - worldX, 0.5*viewsize.height - worldY); mGlobalMap->setViewOffset(viewoffs); } } void MapWindow::notifyPlayerUpdate () { globalMapUpdatePlayer (); } void MapWindow::notifyMapChanged () { // workaround to prevent the map from drawing on top of the button MyGUI::IntCoord oldCoord = mButton->getCoord (); MyGUI::Gui::getInstance().destroyWidget (mButton); mButton = mMainWidget->createWidget("MW_Button", oldCoord, MyGUI::Align::Bottom | MyGUI::Align::Right); mButton->setProperty ("ExpandDirection", "Left"); mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : "#{sWorld}"); } }