diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 08dba334f..9bfd86709 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -596,7 +596,7 @@ void OMW::Engine::go() { double dt = frameTimer.time_s(); frameTimer.setStartTick(); - //dt = std::min(dt, 0.2); + dt = std::min(dt, 0.2); double simulationTime = frame(dt); mViewer->frame(simulationTime); diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index d1f1ad3a3..37112477e 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -178,12 +178,6 @@ namespace MWBase virtual void changeCell(MWWorld::CellStore* cell) = 0; ///< change the active cell - virtual void setPlayerPos(int cellX, int cellY, const float x, const float y) = 0; - ///< set player position in map space - - virtual void setPlayerDir(const float x, const float y) = 0; - ///< set player view direction in map space - virtual void setFocusObject(const MWWorld::Ptr& focus) = 0; virtual void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) = 0; @@ -358,6 +352,9 @@ namespace MWBase virtual std::string correctIconPath(const std::string& path) = 0; virtual std::string correctBookartPath(const std::string& path, int width, int height) = 0; virtual std::string correctTexturePath(const std::string& path) = 0; + + virtual void requestMap(std::set cells) = 0; + virtual void removeCell(MWWorld::CellStore* cell) = 0; }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 6d1bc34bc..c0e2ade0f 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -142,21 +142,12 @@ namespace MWBase virtual bool isCellQuasiExterior() const = 0; - virtual Ogre::Vector2 getNorthVector (MWWorld::CellStore* cell) = 0; + virtual osg::Vec2f getNorthVector (MWWorld::CellStore* cell) = 0; ///< get north vector for given interior cell virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector& out) = 0; ///< get a list of teleport door markers for a given cell, to be displayed on the local map - virtual void worldToInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) = 0; - ///< see MWRender::LocalMap::worldToInteriorMapPosition - - virtual Ogre::Vector2 interiorMapToWorldPosition (float nX, float nY, int x, int y) = 0; - ///< see MWRender::LocalMap::interiorMapToWorldPosition - - virtual bool isPositionExplored (float nX, float nY, int x, int y, bool interior) = 0; - ///< see MWRender::LocalMap::isPositionExplored - virtual void setGlobalInt (const std::string& name, int value) = 0; ///< Set value independently from real type. diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index a1e027f89..43df37b6d 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -70,9 +70,9 @@ namespace MWGui }; - HUD::HUD(CustomMarkerCollection &customMarkers, bool showFps, DragAndDrop* dragAndDrop) + HUD::HUD(CustomMarkerCollection &customMarkers, bool showFps, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender) : Layout("openmw_hud.layout") - , LocalMapBase(customMarkers) + , LocalMapBase(customMarkers, localMapRender) , mHealth(NULL) , mMagicka(NULL) , mStamina(NULL) diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 9eed9811a..72fc06f6a 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -19,7 +19,7 @@ namespace MWGui class HUD : public Layout, public LocalMapBase { public: - HUD(CustomMarkerCollection& customMarkers, bool fpsVisible, DragAndDrop* dragAndDrop); + HUD(CustomMarkerCollection& customMarkers, bool fpsVisible, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender); virtual ~HUD(); void setValue (const std::string& id, const MWMechanics::DynamicStat& value); void setFPS(float fps); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index cdb2d6bdf..1f084402b 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -35,7 +35,6 @@ namespace MWGui , mLastRenderTime(0.0) , mLoadingOnTime(0.0) , mProgress(0) - , mVSyncWasEnabled(false) { mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize()); diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index a1e6e4d21..baacc7133 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -67,8 +67,6 @@ namespace MWGui std::vector mSplashScreens; - bool mVSyncWasEnabled; - void changeWallpaper(); void draw(); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 28fd13335..95de175a3 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -26,6 +26,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwrender/globalmap.hpp" +#include "../mwrender/localmap.hpp" #include "widgets.hpp" #include "confirmationdialog.hpp" @@ -142,8 +143,9 @@ namespace MWGui // ------------------------------------------------------ - LocalMapBase::LocalMapBase(CustomMarkerCollection &markers) - : mCurX(0) + LocalMapBase::LocalMapBase(CustomMarkerCollection &markers, MWRender::LocalMap* localMapRender) + : mLocalMapRender(localMapRender) + , mCurX(0) , mCurY(0) , mInterior(false) , mLocalMap(NULL) @@ -260,8 +262,8 @@ namespace MWGui else { int cellX, cellY; - Ogre::Vector2 worldPos (worldX, worldY); - MWBase::Environment::get().getWorld ()->worldToInteriorMapPosition (worldPos, nX, nY, cellX, cellY); + osg::Vec2f worldPos (worldX, worldY); + mLocalMapRender->worldToInteriorMapPosition(worldPos, nX, nY, cellX, cellY); markerPos.cellX = cellX; markerPos.cellY = cellY; @@ -301,7 +303,7 @@ namespace MWGui continue; } - MarkerUserData markerPos; + MarkerUserData markerPos (mLocalMapRender); MyGUI::IntPoint widgetPos = getMarkerPosition(marker.mWorldX, marker.mWorldY, markerPos); MyGUI::IntCoord widgetCoord(widgetPos.left - 8, @@ -342,24 +344,30 @@ namespace MWGui mDoorMarkerWidgets.clear(); // Update the map textures -#if 0 + std::vector > textures; for (int mx=0; mx<3; ++mx) { for (int my=0; my<3; ++my) { - // map - std::string image = mPrefix+"_"+ MyGUI::utility::toString(x + (mx-1)) + "_" - + MyGUI::utility::toString(y + (-1*(my-1))); + int mapX = x + (mx-1); + int mapY = y + (-1*(my-1)); MyGUI::ImageBox* box = mMapWidgets[my + 3*mx]; - if (MyGUI::RenderManager::getInstance().getTexture(image) != 0) - box->setImageTexture(image); + osg::ref_ptr texture = mLocalMapRender->getMapTexture(mInterior, mapX, mapY); + if (texture) + { + boost::shared_ptr guiTex (new osgMyGUI::OSGTexture(texture)); + textures.push_back(guiTex); + box->setRenderItemTexture(guiTex.get()); + box->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); + } else - box->setImageTexture("black"); + box->setRenderItemTexture(NULL); } } -#endif + mMapTextures.swap(textures); + MWBase::World* world = MWBase::Environment::get().getWorld(); // Retrieve the door markers we want to show @@ -394,7 +402,7 @@ namespace MWGui destNotes.push_back(it->mNote); } - MarkerUserData data; + MarkerUserData data (mLocalMapRender); data.notes = destNotes; data.caption = marker.name; MyGUI::IntPoint widgetPos = getMarkerPosition(marker.x, marker.y, data); @@ -490,7 +498,7 @@ namespace MWGui for (std::vector::iterator it = markers.begin(); it != markers.end(); ++it) { const ESM::Position& worldPos = it->getRefData().getPosition(); - MarkerUserData markerPos; + MarkerUserData markerPos (mLocalMapRender); MyGUI::IntPoint widgetPos = getMarkerPosition(worldPos.pos[0], worldPos.pos[1], markerPos); MyGUI::IntCoord widgetCoord(widgetPos.left - 4, widgetPos.top - 4, @@ -535,7 +543,7 @@ namespace MWGui if (markedCell && markedCell->isExterior() == !mInterior && (!mInterior || Misc::StringUtils::ciEqual(markedCell->getCell()->mName, mPrefix))) { - MarkerUserData markerPos; + MarkerUserData markerPos (mLocalMapRender); MyGUI::IntPoint widgetPos = getMarkerPosition(markedPosition.pos[0], markedPosition.pos[1], markerPos); MyGUI::IntCoord widgetCoord(widgetPos.left - 4, widgetPos.top - 4, @@ -553,9 +561,9 @@ namespace MWGui // ------------------------------------------------------------------------------------------ - MapWindow::MapWindow(CustomMarkerCollection &customMarkers, DragAndDrop* drag, const std::string& cacheDir) + MapWindow::MapWindow(CustomMarkerCollection &customMarkers, DragAndDrop* drag, MWRender::LocalMap* localMapRender) : WindowPinnableBase("openmw_map_window.layout") - , LocalMapBase(customMarkers) + , LocalMapBase(customMarkers, localMapRender) , NoDrop(drag, mMainWidget) , mGlobalMap(0) , mGlobalMapTexture(NULL) @@ -662,19 +670,19 @@ namespace MWGui x += mCurX; y += mCurY; - Ogre::Vector2 worldPos; + osg::Vec2f worldPos; if (mInterior) { - worldPos = MWBase::Environment::get().getWorld()->interiorMapToWorldPosition(nX, nY, x, y); + worldPos = mLocalMapRender->interiorMapToWorldPosition(nX, nY, x, y); } else { - worldPos.x = (x + nX) * cellSize; - worldPos.y = (y + (1.0f-nY)) * cellSize; + worldPos.x() = (x + nX) * cellSize; + worldPos.y() = (y + (1.0f-nY)) * cellSize; } - mEditingMarker.mWorldX = worldPos.x; - mEditingMarker.mWorldY = worldPos.y; + mEditingMarker.mWorldX = worldPos.x(); + mEditingMarker.mWorldY = worldPos.y(); mEditingMarker.mCell.mPaged = !mInterior; if (mInterior) @@ -993,4 +1001,9 @@ namespace MWGui eventDeleteClicked(); } + bool LocalMapBase::MarkerUserData::isPositionExplored() const + { + return mLocalMapRender->isPositionExplored(nX, nY, cellX, cellY, interior); + } + } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 1e1e2c97e..92cd880f4 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -3,6 +3,8 @@ #include +#include + #include "windowpinnablebase.hpp" #include @@ -12,6 +14,7 @@ namespace MWRender { class GlobalMap; + class LocalMap; } namespace ESM @@ -52,7 +55,7 @@ namespace MWGui class LocalMapBase { public: - LocalMapBase(CustomMarkerCollection& markers); + LocalMapBase(CustomMarkerCollection& markers, MWRender::LocalMap* localMapRender); virtual ~LocalMapBase(); void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int mapWidgetSize); @@ -67,6 +70,14 @@ namespace MWGui struct MarkerUserData { + MarkerUserData(MWRender::LocalMap* map) + : mLocalMapRender(map) + { + } + + bool isPositionExplored() const; + + MWRender::LocalMap* mLocalMapRender; bool interior; int cellX; int cellY; @@ -77,6 +88,8 @@ namespace MWGui }; protected: + MWRender::LocalMap* mLocalMapRender; + int mCurX, mCurY; bool mInterior; MyGUI::ScrollView* mLocalMap; @@ -93,6 +106,8 @@ namespace MWGui std::vector mMapWidgets; std::vector mFogWidgets; + std::vector > mMapTextures; + // Keep track of created marker widgets, just to easily remove them later. std::vector mDoorMarkerWidgets; std::vector mMagicMarkerWidgets; @@ -153,7 +168,7 @@ namespace MWGui class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase, public NoDrop { public: - MapWindow(CustomMarkerCollection& customMarkers, DragAndDrop* drag, const std::string& cacheDir); + MapWindow(CustomMarkerCollection& customMarkers, DragAndDrop* drag, MWRender::LocalMap* localMapRender); virtual ~MapWindow(); void setCellName(const std::string& cellName); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 43acbeaab..5dd201068 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -169,7 +169,7 @@ namespace MWGui { LocalMapBase::MarkerUserData data = *focus->getUserData(); - if (!MWBase::Environment::get().getWorld ()->isPositionExplored (data.nX, data.nY, data.cellX, data.cellY, data.interior)) + if (!data.isPositionExplored()) return; ToolTipInfo info; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5649908fc..e4ecdad53 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -53,6 +53,8 @@ #include "../mwmechanics/stat.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwrender/localmap.hpp" + #include "../mwsound/soundmanagerimp.hpp" #include "console.hpp" @@ -115,6 +117,7 @@ namespace MWGui , mCurrentModals() , mHud(NULL) , mMap(NULL) + , mLocalMapRender(NULL) , mMenu(NULL) , mToolTips(NULL) , mStatsWindow(NULL) @@ -266,7 +269,8 @@ namespace MWGui mRecharge = new Recharge(); mMenu = new MainMenu(w, h, mResourceSystem->getVFS()); - mMap = new MapWindow(mCustomMarkers, mDragAndDrop, ""); + mLocalMapRender = new MWRender::LocalMap(mViewer); + mMap = new MapWindow(mCustomMarkers, mDragAndDrop, mLocalMapRender); trackWindow(mMap, "map"); mStatsWindow = new StatsWindow(mDragAndDrop); trackWindow(mStatsWindow, "stats"); @@ -284,7 +288,7 @@ namespace MWGui trackWindow(mDialogueWindow, "dialogue"); mContainerWindow = new ContainerWindow(mDragAndDrop); trackWindow(mContainerWindow, "container"); - mHud = new HUD(mCustomMarkers, Settings::Manager::getInt("fps", "HUD"), mDragAndDrop); + mHud = new HUD(mCustomMarkers, Settings::Manager::getInt("fps", "HUD"), mDragAndDrop, mLocalMapRender); mToolTips = new ToolTips(); mScrollWindow = new ScrollWindow(); mBookWindow = new BookWindow(); @@ -383,6 +387,7 @@ namespace MWGui delete mMessageBoxManager; delete mHud; delete mMap; + delete mLocalMapRender; delete mMenu; delete mStatsWindow; delete mJournal; @@ -886,6 +891,31 @@ namespace MWGui return default_; } + void WindowManager::updateMap() + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + osg::Vec3f playerPosition = player.getRefData().getPosition().asVec3(); + osg::Quat playerOrientation (-player.getRefData().getPosition().rot[2], osg::Vec3(0,0,1)); + + osg::Vec3f playerdirection; + int x,y; + float u,v; + mLocalMapRender->updatePlayer(playerPosition, playerOrientation, u, v, x, y, playerdirection); + + if (!player.getCell()->isExterior()) + { + mMap->setActiveCell(x, y, true); + mHud->setActiveCell(x, y, true); + } + // else: need to know the current grid center, call setActiveCell from MWWorld::Scene + + mMap->setPlayerDir(playerdirection.x(), playerdirection.y()); + mMap->setPlayerPos(x, y, u, v); + mHud->setPlayerDir(playerdirection.x(), playerdirection.y()); + mHud->setPlayerPos(x, y, u, v); + } + void WindowManager::onFrame (float frameDuration) { mMessageBoxManager->onFrame(frameDuration); @@ -894,6 +924,9 @@ namespace MWGui mMenu->update(frameDuration); + if (mLocalMapRender) + mLocalMapRender->cleanupCameras(); + if (MWBase::Environment::get().getStateManager()->getState()== MWBase::StateManager::State_NoGame) return; @@ -908,6 +941,8 @@ namespace MWGui mInventoryWindow->onFrame(); + updateMap(); + mStatsWindow->onFrame(frameDuration); mMap->onFrame(frameDuration); mSpellWindow->onFrame(frameDuration); @@ -968,29 +1003,10 @@ namespace MWGui void WindowManager::setActiveMap(int x, int y, bool interior) { - if (!interior) - { - mMap->setCellPrefix("Cell"); - mHud->setCellPrefix("Cell"); - } - mMap->setActiveCell(x,y, interior); mHud->setActiveCell(x,y, interior); } - void WindowManager::setPlayerPos(int cellX, int cellY, const float x, const float y) - { - mMap->setPlayerPos(cellX, cellY, x, y); - mHud->setPlayerPos(cellX, cellY, x, y); - } - - void WindowManager::setPlayerDir(const float x, const float y) - { - mMap->setPlayerDir(x,y); - mMap->setGlobalMapPlayerDir(x, y); - mHud->setPlayerDir(x,y); - } - void WindowManager::setDrowningBarVisibility(bool visible) { mHud->setDrowningBarVisible(visible); @@ -1990,4 +2006,14 @@ namespace MWGui tex->unlock(); } + void WindowManager::requestMap(std::set cells) + { + mLocalMapRender->requestMap(cells); + } + + void WindowManager::removeCell(MWWorld::CellStore *cell) + { + mLocalMapRender->removeCell(cell); + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index d07f2fb98..c0184d4b6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -67,6 +67,11 @@ namespace Gui class FontLoader; } +namespace MWRender +{ + class LocalMap; +} + namespace MWGui { class WindowBase; @@ -191,8 +196,6 @@ namespace MWGui virtual void updateSkillArea(); ///< update display of skills, factions, birth sign, reputation and bounty virtual void changeCell(MWWorld::CellStore* cell); ///< change the active cell - virtual void setPlayerPos(int cellX, int cellY, const float x, const float y); ///< set player position in map space - virtual void setPlayerDir(const float x, const float y); ///< set player view direction in map space virtual void setFocusObject(const MWWorld::Ptr& focus); virtual void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); @@ -363,6 +366,9 @@ namespace MWGui virtual std::string correctBookartPath(const std::string& path, int width, int height); virtual std::string correctTexturePath(const std::string& path); + void requestMap(std::set cells); + void removeCell(MWWorld::CellStore* cell); + private: Resource::ResourceSystem* mResourceSystem; @@ -386,6 +392,7 @@ namespace MWGui HUD *mHud; MapWindow *mMap; + MWRender::LocalMap* mLocalMapRender; MainMenu *mMenu; ToolTips *mToolTips; StatsWindow *mStatsWindow; @@ -473,6 +480,8 @@ namespace MWGui void updateVisible(); // Update visibility of all windows based on mode, shown and allowed settings + void updateMap(); + float mFPS; std::map mFallbackMap; diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 1a712461e..7084af862 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -1,5 +1,4 @@ #include "actor.hpp" -#include #include diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1c436d440..1f78f0dd8 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index cc6b4a9bb..62c732051 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -16,6 +16,7 @@ #include "../mwworld/inventorystore.hpp" #include "npcanimation.hpp" +#include "vismask.hpp" namespace MWRender { @@ -81,6 +82,8 @@ namespace MWRender mCamera->attach(osg::Camera::COLOR_BUFFER, mTexture); mCamera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); + mCamera->setNodeMask(Mask_RenderToTexture); + osg::ref_ptr lightManager = new SceneUtil::LightManager; lightManager->setStartLight(1); osg::ref_ptr stateset = new osg::StateSet; diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index f675fe1d8..8ab16283e 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -1,74 +1,82 @@ #include "localmap.hpp" -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include + +#include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -#include "../mwbase/windowmanager.hpp" -#include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" +#include "vismask.hpp" + +namespace +{ + + class CameraUpdateCallback : public osg::NodeCallback + { + public: + CameraUpdateCallback(osg::Camera* cam, MWRender::LocalMap* parent) + : mCamera(cam), mParent(parent) + { + } + + virtual void operator()(osg::Node*, osg::NodeVisitor*) + { + mParent->markForRemoval(mCamera); + + // Note, we intentionally do not traverse children here. The map camera's scene data is the same as the master camera's, + // so it has been updated already. + //traverse(node, nv); + } + + private: + osg::ref_ptr mCamera; + MWRender::LocalMap* mParent; + }; + +} -using namespace MWRender; -using namespace Ogre; +namespace MWRender +{ -LocalMap::LocalMap() - : mMapResolution(Settings::Manager::getInt("local map resolution", "Map")) +LocalMap::LocalMap(osgViewer::Viewer* viewer) + : mViewer(viewer) + , mMapResolution(Settings::Manager::getInt("local map resolution", "Map")) + , mMapWorldSize(8192.f) , mAngle(0.f) , mInterior(false) { - // mCellCamera = mRendering->getScene()->createCamera("CellCamera"); - mCellCamera->setProjectionType(PT_ORTHOGRAPHIC); - - mCameraNode->attachObject(mCellCamera); - - mLight->setType (Ogre::Light::LT_DIRECTIONAL); - mLight->setDirection (Ogre::Vector3(0.3f, 0.3f, -0.7f)); - mLight->setVisible (false); - mLight->setDiffuseColour (ColourValue(0.7f,0.7f,0.7f)); - - mRenderTexture = TextureManager::getSingleton().createManual( - "localmap/rtt", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - mMapResolution, mMapResolution, - 0, - PF_R8G8B8, - TU_RENDERTARGET); - - mRenderTarget = mRenderTexture->getBuffer()->getRenderTarget(); - mRenderTarget->setAutoUpdated(false); - Viewport* vp = mRenderTarget->addViewport(mCellCamera); - vp->setOverlaysEnabled(false); - vp->setShadowsEnabled(false); - vp->setBackgroundColour(ColourValue(0, 0, 0)); - vp->setMaterialScheme("local_map"); -} + mRoot = mViewer->getSceneData()->asGroup(); -LocalMap::~LocalMap() -{ + SceneUtil::FindByNameVisitor find("Scene Root"); + mRoot->accept(find); + mSceneRoot = find.mFoundNode; + if (!mSceneRoot) + throw std::runtime_error("no scene root found"); } -const Ogre::Vector2 LocalMap::rotatePoint(const Ogre::Vector2& p, const Ogre::Vector2& c, const float angle) +LocalMap::~LocalMap() { - return Vector2( Math::Cos(angle) * (p.x - c.x) - Math::Sin(angle) * (p.y - c.y) + c.x, - Math::Sin(angle) * (p.x - c.x) + Math::Cos(angle) * (p.y - c.y) + c.y); + for (CameraVector::iterator it = mActiveCameras.begin(); it != mActiveCameras.end(); ++it) + mRoot->removeChild(*it); + for (CameraVector::iterator it = mCamerasPendingRemoval.begin(); it != mCamerasPendingRemoval.end(); ++it) + mRoot->removeChild(*it); } -std::string LocalMap::coordStr(const int x, const int y) +const osg::Vec2f LocalMap::rotatePoint(const osg::Vec2f& p, const osg::Vec2f& c, const float angle) { - return StringConverter::toString(x) + "_" + StringConverter::toString(y); + return osg::Vec2f( std::cos(angle) * (p.x() - c.x()) - std::sin(angle) * (p.y() - c.y()) + c.x(), + std::sin(angle) * (p.x() - c.x()) + std::cos(angle) * (p.y() - c.y()) + c.y()); } void LocalMap::clear() @@ -103,8 +111,8 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y); Vector2 length = max-min; - const int segsX = static_cast(std::ceil(length.x / sSize)); - const int segsY = static_cast(std::ceil(length.y / sSize)); + const int segsX = static_cast(std::ceil(length.x / mMapWorldSize)); + const int segsY = static_cast(std::ceil(length.y / mMapWorldSize)); mInteriorName = cell->getCell()->mName; @@ -148,24 +156,145 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) */ } -void LocalMap::requestMap(MWWorld::CellStore* cell, float zMin, float zMax) +osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, float width, float height, const osg::Vec3d& upVector, float zmin, float zmax) { - mInterior = false; + osg::ref_ptr camera (new osg::Camera); + + camera->setProjectionMatrixAsOrtho(-width/2, width/2, -height/2, height/2, 5, (zmax-zmin) + 10); + camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); + camera->setViewMatrixAsLookAt(osg::Vec3d(x, y, zmax + 5), osg::Vec3d(x, y, zmin), upVector); + camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); + camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); + camera->setClearColor(osg::Vec4(0.f, 0.f, 0.f, 1.f)); + camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + camera->setRenderOrder(osg::Camera::PRE_RENDER); + + camera->setCullMask(MWRender::Mask_Scene); + camera->setNodeMask(Mask_RenderToTexture); + + osg::ref_ptr stateset = new osg::StateSet; + stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON); + stateset->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + stateset->setMode(GL_FOG, osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE); + + osg::ref_ptr lightmodel = new osg::LightModel; + lightmodel->setAmbientIntensity(osg::Vec4(0.3f, 0.3f, 0.3f, 1.f)); + stateset->setAttributeAndModes(lightmodel, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + osg::ref_ptr light = new osg::Light; + light->setPosition(osg::Vec4(-0.3f, -0.3f, 0.7f, 0.f)); + light->setDiffuse(osg::Vec4(0.7f, 0.7f, 0.7f, 1.f)); + light->setAmbient(osg::Vec4(0,0,0,1)); + light->setSpecular(osg::Vec4(0,0,0,0)); + light->setLightNum(0); + light->setConstantAttenuation(1.f); + light->setLinearAttenuation(0.f); + light->setQuadraticAttenuation(0.f); + + osg::ref_ptr lightSource = new osg::LightSource; + lightSource->setLight(light); + + lightSource->setStateSetModes(*stateset, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + camera->addChild(lightSource); + camera->setStateSet(stateset); + camera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); + camera->setViewport(0, 0, mMapResolution, mMapResolution); + camera->setUpdateCallback(new CameraUpdateCallback(camera, this)); + + return camera; +} - mCameraRotNode->setOrientation(Quaternion::IDENTITY); - mCellCamera->setOrientation(Quaternion(Ogre::Math::Cos(Ogre::Degree(0)/2.f), 0, 0, -Ogre::Math::Sin(Ogre::Degree(0)/2.f))); +void LocalMap::setupRenderToTexture(osg::ref_ptr camera, int x, int y) +{ + osg::ref_ptr texture (new osg::Texture2D); + texture->setTextureSize(mMapResolution, mMapResolution); + texture->setInternalFormat(GL_RGB); + texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + + camera->attach(osg::Camera::COLOR_BUFFER, texture); + + camera->addChild(mSceneRoot); + mRoot->addChild(camera); + mActiveCameras.push_back(camera); + mTextures[std::make_pair(x, y)] = texture; +} + +void LocalMap::requestMap(std::set cells) +{ + for (std::set::iterator it = cells.begin(); it != cells.end(); ++it) + { + MWWorld::CellStore* cell = *it; + if (cell->isExterior()) + requestExteriorMap(cell); + else + requestInteriorMap(cell); + } +} + +void LocalMap::removeCell(MWWorld::CellStore *cell) +{ + if (cell->isExterior()) + mTextures.erase(std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())); + else + mTextures.clear(); +} + +osg::ref_ptr LocalMap::getMapTexture(bool interior, int x, int y) +{ + TextureMap::iterator found = mTextures.find(std::make_pair(x, y)); + if (found == mTextures.end()) + return osg::ref_ptr(); + else + return found->second; +} + +void LocalMap::markForRemoval(osg::Camera *cam) +{ + CameraVector::iterator found = std::find(mActiveCameras.begin(), mActiveCameras.end(), cam); + if (found == mActiveCameras.end()) + { + std::cerr << "trying to remove an inactive camera" << std::endl; + return; + } + mActiveCameras.erase(found); + mCamerasPendingRemoval.push_back(cam); +} + +void LocalMap::cleanupCameras() +{ + if (mCamerasPendingRemoval.empty()) + return; + + for (CameraVector::iterator it = mCamerasPendingRemoval.begin(); it != mCamerasPendingRemoval.end(); ++it) + { + (*it)->removeChildren(0, (*it)->getNumChildren()); + (*it)->setGraphicsContext(NULL); + mRoot->removeChild(*it); + } + + + mCamerasPendingRemoval.clear(); +} + +void LocalMap::requestExteriorMap(MWWorld::CellStore* cell) +{ + mInterior = false; int x = cell->getCell()->getGridX(); int y = cell->getCell()->getGridY(); - std::string name = "Cell_"+coordStr(x, y); + osg::BoundingSphere bound = mViewer->getSceneData()->getBound(); + float zmin = bound.center().z() - bound.radius(); + float zmax = bound.center().z() + bound.radius(); - mCameraPosNode->setPosition(Vector3(0,0,0)); - - // Note: using force=true for exterior cell maps. - // They must be updated even if they were visited before, because the set of surrounding active cells might be different - // (and objects in a different cell can "bleed" into another cell's map if they cross the border) - render((x+0.5f)*sSize, (y+0.5f)*sSize, zMin, zMax, static_cast(sSize), static_cast(sSize), name, true); + osg::ref_ptr camera = createOrthographicCamera(x*mMapWorldSize + mMapWorldSize/2.f, y*mMapWorldSize + mMapWorldSize/2.f, mMapWorldSize, mMapWorldSize, + osg::Vec3d(0,1,0), zmin, zmax); + setupRenderToTexture(camera, cell->getCell()->getGridX(), cell->getCell()->getGridY()); /* if (mBuffers.find(name) == mBuffers.end()) @@ -178,12 +307,17 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, float zMin, float zMax) */ } -void LocalMap::requestMap(MWWorld::CellStore* cell, - AxisAlignedBox bounds) +void LocalMap::requestInteriorMap(MWWorld::CellStore* cell) { + osg::ComputeBoundsVisitor computeBoundsVisitor; + computeBoundsVisitor.setTraversalMask(Mask_Scene); + mSceneRoot->accept(computeBoundsVisitor); + + osg::BoundingBox bounds = computeBoundsVisitor.getBoundingBox(); + // If we're in an empty cell, bail out // The operations in this function are only valid for finite bounds - if (bounds.isNull ()) + if (!bounds.valid() || bounds.radius2() == 0.0) return; mInterior = true; @@ -191,41 +325,31 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, mBounds = bounds; // Get the cell's NorthMarker rotation. This is used to rotate the entire map. - const Vector2& north = MWBase::Environment::get().getWorld()->getNorthVector(cell); - Radian angle = Ogre::Math::ATan2 (north.x, north.y); - mAngle = angle.valueRadians(); + osg::Vec2f north = MWBase::Environment::get().getWorld()->getNorthVector(cell); + + mAngle = std::atan2(north.x(), north.y()); // Rotate the cell and merge the rotated corners to the bounding box - Vector2 _center(bounds.getCenter().x, bounds.getCenter().y); - Vector3 _c1 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_BOTTOM); - Vector3 _c2 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_BOTTOM); - Vector3 _c3 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_TOP); - Vector3 _c4 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_TOP); - - Vector2 c1(_c1.x, _c1.y); - Vector2 c2(_c2.x, _c2.y); - Vector2 c3(_c3.x, _c3.y); - Vector2 c4(_c4.x, _c4.y); - c1 = rotatePoint(c1, _center, mAngle); - c2 = rotatePoint(c2, _center, mAngle); - c3 = rotatePoint(c3, _center, mAngle); - c4 = rotatePoint(c4, _center, mAngle); - mBounds.merge(Vector3(c1.x, c1.y, 0)); - mBounds.merge(Vector3(c2.x, c2.y, 0)); - mBounds.merge(Vector3(c3.x, c3.y, 0)); - mBounds.merge(Vector3(c4.x, c4.y, 0)); + osg::Vec2f _center(bounds.center().x(), bounds.center().y()); + for (int i=0; i<8; ++i) + { + osg::Vec3f corner = mBounds.corner(i); + osg::Vec2f corner2d (corner.x(), corner.y()); + corner2d = rotatePoint(corner2d, _center, mAngle); + mBounds.expandBy(osg::Vec3f(corner2d.x(), corner2d.y(), 0)); + } // Do NOT change padding! This will break older savegames. // If the padding really needs to be changed, then it must be saved in the ESM::FogState and // assume the old (500) value as default for older savegames. - const Ogre::Real padding = 500.0f; + const float padding = 500.0f; // Apply a little padding - mBounds.setMinimum (mBounds.getMinimum() - Vector3(padding,padding,0)); - mBounds.setMaximum (mBounds.getMaximum() + Vector3(padding,padding,0)); + mBounds.set(mBounds._min - osg::Vec3f(padding,padding,0.f), + mBounds._max + osg::Vec3f(padding,padding,0.f)); - float zMin = mBounds.getMinimum().z; - float zMax = mBounds.getMaximum().z; + float zMin = mBounds.zMin(); + float zMax = mBounds.zMax(); // If there is fog state in the CellStore (e.g. when it came from a savegame) we need to do some checks // to see if this state is still valid. @@ -244,8 +368,8 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, Ogre::Vector3 minDiff = newMin - mBounds.getMinimum(); Ogre::Vector3 maxDiff = newMax - mBounds.getMaximum(); - if (std::abs(minDiff.x) > 500 || std::abs(minDiff.y) > 500 - || std::abs(maxDiff.x) > 500 || std::abs(maxDiff.y) > 500 + if (std::abs(minDiff.x) > padding || std::abs(minDiff.y) > padding + || std::abs(maxDiff.x) > padding || std::abs(maxDiff.y) > padding || std::abs(mAngle - fog->mNorthMarkerAngle) > Ogre::Degree(5).valueRadians()) { // Nuke it @@ -260,35 +384,35 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, } */ - Vector2 center(mBounds.getCenter().x, mBounds.getCenter().y); - - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); - Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y); + osg::Vec2f min(mBounds.xMin(), mBounds.yMin()); + osg::Vec2f max(mBounds.xMax(), mBounds.yMax()); - Vector2 length = max-min; + osg::Vec2f length = max-min; - mCellCamera->setOrientation(Quaternion::IDENTITY); - mCameraRotNode->setOrientation(Quaternion(Math::Cos(mAngle/2.f), 0, 0, -Math::Sin(mAngle/2.f))); - - mCameraPosNode->setPosition(Vector3(center.x, center.y, 0)); + osg::Vec2f center(bounds.center().x(), bounds.center().y()); // divide into segments - const int segsX = static_cast(std::ceil(length.x / sSize)); - const int segsY = static_cast(std::ceil(length.y / sSize)); - - mInteriorName = cell->getCell()->mName; + const int segsX = static_cast(std::ceil(length.x() / mMapWorldSize)); + const int segsY = static_cast(std::ceil(length.y() / mMapWorldSize)); - int i=0; for (int x=0; x(sSize*x), static_cast(sSize*y)); - Vector2 newcenter = start + sSize/2; + osg::Vec2f start = min + osg::Vec2f(mMapWorldSize*x, mMapWorldSize*y); + osg::Vec2f newcenter = start + osg::Vec2f(mMapWorldSize/2.f, mMapWorldSize/2.f); + + osg::Quat cameraOrient (mAngle, osg::Vec3d(0,0,-1)); + osg::Vec2f a = newcenter - center; + osg::Vec3f rotatedCenter = cameraOrient * (osg::Vec3f(a.x(), a.y(), 0)); + + osg::Vec2f pos = osg::Vec2f(rotatedCenter.x(), rotatedCenter.y()) + center; - std::string texturePrefix = cell->getCell()->mName + "_" + coordStr(x,y); + osg::ref_ptr camera = createOrthographicCamera(pos.x(), pos.y(), + mMapWorldSize, mMapWorldSize, + osg::Vec3f(north.x(), north.y(), 0.f), zMin, zMax); - render(newcenter.x - center.x, newcenter.y - center.y, zMin, zMax, static_cast(sSize), static_cast(sSize), texturePrefix); + setupRenderToTexture(camera, x, y); /* if (!cell->getFog()) @@ -305,14 +429,13 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, loadFogOfWar(texturePrefix, esm); } */ - ++i; } } } +/* void LocalMap::createFogOfWar(const std::string& texturePrefix) { - /* const std::string texName = texturePrefix + "_fog"; TexturePtr tex = createFogOfWarTexture(texName); @@ -328,34 +451,12 @@ void LocalMap::createFogOfWar(const std::string& texturePrefix) tex->getBuffer()->unlock(); mBuffers[texturePrefix] = buffer; - */ -} - -Ogre::TexturePtr LocalMap::createFogOfWarTexture(const std::string &texName) -{ - TexturePtr tex;// = TextureManager::getSingleton().getByName(texName); - /* - * if (tex.isNull()) - { - tex = TextureManager::getSingleton().createManual( - texName, - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - sFogOfWarResolution, sFogOfWarResolution, - 0, - PF_A8R8G8B8, - TU_DYNAMIC_WRITE_ONLY, - this // ManualResourceLoader required if the texture contents are lost (due to lost devices nonsense that can occur with D3D) - ); - } - */ - - return tex; } +*/ +/* void LocalMap::loadFogOfWar (const std::string& texturePrefix, ESM::FogTexture& esm) { - /* std::vector& data = esm.mImageData; Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size())); Ogre::Image image; @@ -377,89 +478,35 @@ void LocalMap::loadFogOfWar (const std::string& texturePrefix, ESM::FogTexture& memcpy(&buffer[0], image.getData(), image.getSize()); mBuffers[texturePrefix] = buffer; - */ -} - -void LocalMap::render(const float x, const float y, - const float zlow, const float zhigh, - const float xw, const float yw, const std::string& texture, bool force) -{ - mCellCamera->setFarClipDistance( (zhigh-zlow) + 2000 ); - mCellCamera->setNearClipDistance(50); - - mCellCamera->setOrthoWindow(xw, yw); - mCameraNode->setPosition(Vector3(x, y, zhigh+1000)); - - // disable fog (only necessary for fixed function, the shader based - // materials already do this through local_map material configuration) - //mRendering->getScene()->setFog(FOG_NONE); - - // set up lighting - //Ogre::ColourValue oldAmbient = mRendering->getScene()->getAmbientLight(); - //mRendering->getScene()->setAmbientLight(Ogre::ColourValue(0.3f, 0.3f, 0.3f)); - //mRenderingManager->disableLights(true); - mLight->setVisible(true); - - TexturePtr tex; - // try loading from memory - tex = TextureManager::getSingleton().getByName(texture); - if (tex.isNull()) - { - // render - mRenderTarget->update(); - - // create a new texture and blit to it - Ogre::TexturePtr tex = TextureManager::getSingleton().createManual( - texture, - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - mMapResolution, mMapResolution, - 0, - PF_R8G8B8); - tex->getBuffer()->blit(mRenderTexture->getBuffer()); - } - else if (force) - { - mRenderTarget->update(); - tex->getBuffer()->blit(mRenderTexture->getBuffer()); - } - - //mRenderingManager->enableLights(true); - mLight->setVisible(false); - - // re-enable fog - //mRendering->getScene()->setFog(FOG_LINEAR, oldFogColour, 0, oldFogStart, oldFogEnd); - //mRendering->getScene()->setAmbientLight(oldAmbient); } +*/ -void LocalMap::worldToInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y) +void LocalMap::worldToInteriorMapPosition (osg::Vec2f pos, float& nX, float& nY, int& x, int& y) { - pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().y), mAngle); + pos = rotatePoint(pos, osg::Vec2f(mBounds.center().x(), mBounds.center().y()), mAngle); - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); + osg::Vec2f min(mBounds.xMin(), mBounds.yMin()); - x = static_cast(std::ceil((pos.x - min.x) / sSize) - 1); - y = static_cast(std::ceil((pos.y - min.y) / sSize) - 1); + x = static_cast(std::ceil((pos.x() - min.x()) / mMapWorldSize) - 1); + y = static_cast(std::ceil((pos.y() - min.y()) / mMapWorldSize) - 1); - nX = (pos.x - min.x - sSize*x)/sSize; - nY = 1.0f-(pos.y - min.y - sSize*y)/sSize; + nX = (pos.x() - min.x() - mMapWorldSize*x)/mMapWorldSize; + nY = 1.0f-(pos.y() - min.y() - mMapWorldSize*y)/mMapWorldSize; } -Ogre::Vector2 LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, int y) +osg::Vec2f LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, int y) { - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); - Ogre::Vector2 pos; + osg::Vec2f min(mBounds.xMin(), mBounds.yMin()); + osg::Vec2f pos (mMapWorldSize * (nX + x) + min.x(), + mMapWorldSize * (1.0f-nY + y) + min.y()); - pos.x = sSize * (nX + x) + min.x; - pos.y = sSize * (1.0f-nY + y) + min.y; - - pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().y), -mAngle); + pos = rotatePoint(pos, osg::Vec2f(mBounds.center().x(), mBounds.center().y()), -mAngle); return pos; } bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interior) { - return false; + return true; /* std::string texName = (interior ? mInteriorName + "_" : "Cell_") + coordStr(x, y); @@ -478,33 +525,8 @@ bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interi */ } -void LocalMap::loadResource(Ogre::Resource* resource) -{ - /* - std::string resourceName = resource->getName(); - size_t pos = resourceName.find("_fog"); - if (pos != std::string::npos) - resourceName = resourceName.substr(0, pos); - if (mBuffers.find(resourceName) == mBuffers.end()) - { - // create a buffer to use for dynamic operations - std::vector buffer; - - // initialize to (0, 0, 0, 1) - buffer.resize(sFogOfWarResolution*sFogOfWarResolution, 0xFF000000); - mBuffers[resourceName] = buffer; - } - - std::vector& buffer = mBuffers[resourceName]; - - Ogre::Texture* tex = static_cast(resource); - tex->createInternalResources(); - memcpy(tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4); - tex->getBuffer()->unlock(); - */ -} - -void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaternion& orientation) +void LocalMap::updatePlayer (const osg::Vec3f& position, const osg::Quat& orientation, + float& u, float& v, int& x, int& y, osg::Vec3f& direction) { /* if (sFogOfWarSkip != 0) @@ -513,42 +535,32 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni if (++count % sFogOfWarSkip != 0) return; } + */ // retrieve the x,y grid coordinates the player is in - int x,y; - float u,v; - - Vector2 pos(position.x, position.y); + osg::Vec2f pos(position.x(), position.y()); if (mInterior) - worldToInteriorMapPosition(pos, u,v, x,y); - - Vector3 playerdirection = mCameraRotNode->convertWorldToLocalOrientation(orientation).yAxis(); - - if (!mInterior) { - x = static_cast(std::ceil(pos.x / sSize) - 1); - y = static_cast(std::ceil(pos.y / sSize) - 1); - } - else - MWBase::Environment::get().getWindowManager()->setActiveMap(x,y,mInterior); + worldToInteriorMapPosition(pos, u,v, x,y); - // convert from world coordinates to texture UV coordinates - std::string texBaseName; - if (!mInterior) - { - u = std::abs((pos.x - (sSize*x))/sSize); - v = 1.0f-std::abs((pos.y - (sSize*y))/sSize); - texBaseName = "Cell_"; + osg::Quat cameraOrient (mAngle, osg::Vec3(0,0,-1)); + direction = orientation * cameraOrient.inverse() * osg::Vec3f(0,1,0); } else { - texBaseName = mInteriorName + "_"; + direction = orientation * osg::Vec3f(0,1,0); + + x = static_cast(std::ceil(pos.x() / mMapWorldSize) - 1); + y = static_cast(std::ceil(pos.y() / mMapWorldSize) - 1); + + // convert from world coordinates to texture UV coordinates + u = std::abs((pos.x() - (mMapWorldSize*x))/mMapWorldSize); + v = 1.0f-std::abs((pos.y() - (mMapWorldSize*y))/mMapWorldSize); } - MWBase::Environment::get().getWindowManager()->setPlayerPos(x, y, u, v); - MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, playerdirection.y); + /* // explore radius (squared) const float exploreRadius = (mInterior ? 0.1f : 0.3f) * (sFogOfWarResolution-1); // explore radius from 0 to sFogOfWarResolution-1 const float sqrExploreRadius = Math::Sqr(exploreRadius); @@ -614,3 +626,5 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni } */ } + +} diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index d0d7d73d2..8160c325c 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -1,9 +1,13 @@ #ifndef GAME_RENDER_LOCALMAP_H #define GAME_RENDER_LOCALMAP_H -#include -#include -#include +#include +#include +#include + +#include +#include +#include namespace MWWorld { @@ -15,52 +19,57 @@ namespace ESM struct FogTexture; } -namespace MWRender +namespace osgViewer { - class RenderingManager; + class Viewer; +} +namespace osg +{ + class Texture2D; + class Camera; + class Group; + class Node; +} + +namespace MWRender +{ /// /// \brief Local map rendering /// class LocalMap { public: - LocalMap(); + LocalMap(osgViewer::Viewer* viewer); ~LocalMap(); - virtual void loadResource(Ogre::Resource* resource); - /** * Clear all savegame-specific data (i.e. fog of war textures) */ void clear(); - /** - * Request the local map for an exterior cell. - * @remarks It will either be loaded from a disk cache, - * or rendered if it is not already cached. - * @param cell exterior cell - * @param zMin min height of objects or terrain in cell - * @param zMax max height of objects or terrain in cell - */ - void requestMap (MWWorld::CellStore* cell, float zMin, float zMax); + void requestMap (std::set cells); + + void removeCell (MWWorld::CellStore* cell); + + osg::ref_ptr getMapTexture (bool interior, int x, int y); + + void markForRemoval(osg::Camera* cam); /** - * Request the local map for an interior cell. - * @remarks It will either be loaded from a disk cache, - * or rendered if it is not already cached. - * @param cell interior cell - * @param bounds bounding box of the cell + * Removes cameras that have already been rendered. Should be called every frame to ensure that + * we do not render the same map more than once. Note, this cleanup is difficult to implement in an + * automated fashion, since we can't alter the scene graph structure from within an update callback. */ - void requestMap (MWWorld::CellStore* cell, - Ogre::AxisAlignedBox bounds); + void cleanupCameras(); /** - * Set the position & direction of the player. + * Set the position & direction of the player, and returns the position in map space through the reference parameters. * @remarks This is used to draw a "fog of war" effect * to hide areas on the map the player has not discovered yet. */ - void updatePlayer (const Ogre::Vector3& position, const Ogre::Quaternion& orientation); + void updatePlayer (const osg::Vec3f& position, const osg::Quat& orientation, + float& u, float& v, int& x, int& y, osg::Vec3f& direction); /** * Save the fog of war for this cell to its CellStore. @@ -72,9 +81,9 @@ namespace MWRender * Get the interior map texture index and normalized position * on this texture, given a world position */ - void worldToInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y); + void worldToInteriorMapPosition (osg::Vec2f pos, float& nX, float& nY, int& x, int& y); - Ogre::Vector2 interiorMapToWorldPosition (float nX, float nY, int x, int y); + osg::Vec2f interiorMapToWorldPosition (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) @@ -82,6 +91,20 @@ namespace MWRender bool isPositionExplored (float nX, float nY, int x, int y, bool interior); private: + osg::ref_ptr mViewer; + + osg::ref_ptr mRoot; + osg::ref_ptr mSceneRoot; + + typedef std::vector< osg::ref_ptr > CameraVector; + + CameraVector mActiveCameras; + + CameraVector mCamerasPendingRemoval; + + typedef std::map, osg::ref_ptr > TextureMap; + TextureMap mTextures; + int mMapResolution; // the dynamic texture is a bottleneck, so don't set this too high @@ -91,46 +114,34 @@ namespace MWRender static const int sFogOfWarSkip = 2; // size of a map segment (for exteriors, 1 cell) - static const int sSize = 8192; - - Ogre::Camera* mCellCamera; - Ogre::SceneNode* mCameraNode; - Ogre::SceneNode* mCameraPosNode; - Ogre::SceneNode* mCameraRotNode; - - // directional light from a fixed angle - Ogre::Light* mLight; + float mMapWorldSize; float mAngle; - const Ogre::Vector2 rotatePoint(const Ogre::Vector2& p, const Ogre::Vector2& c, const float angle); + const osg::Vec2f rotatePoint(const osg::Vec2f& p, const osg::Vec2f& c, const float angle); - /// @param force Always render, even if we already have a cached map - void render(const float x, const float y, - const float zlow, const float zhigh, - const float xw, const float yw, - const std::string& texture, bool force=false); + void requestExteriorMap(MWWorld::CellStore* cell); + void requestInteriorMap(MWWorld::CellStore* cell); + + osg::ref_ptr createOrthographicCamera(float left, float top, float width, float height, const osg::Vec3d& upVector, float zmin, float zmax); + void setupRenderToTexture(osg::ref_ptr camera, int x, int y); // Creates a fog of war texture and initializes it to full black - void createFogOfWar(const std::string& texturePrefix); + //void createFogOfWar(const std::string& texturePrefix); // Loads a fog of war texture from its ESM struct - void loadFogOfWar(const std::string& texturePrefix, ESM::FogTexture& esm); // FogTexture not const because MemoryDataStream doesn't accept it - - Ogre::TexturePtr createFogOfWarTexture(const std::string& name); - - std::string coordStr(const int x, const int y); + //void loadFogOfWar(const std::string& texturePrefix, ESM::FogTexture& esm); // FogTexture not const because MemoryDataStream doesn't accept it // A buffer for the "fog of war" textures of the current cell. // Both interior and exterior maps are possibly divided into multiple textures. - std::map > mBuffers; + //std::map > mBuffers; // The render texture we will use to create the map images - Ogre::TexturePtr mRenderTexture; - Ogre::RenderTarget* mRenderTarget; + //Ogre::TexturePtr mRenderTexture; + //Ogre::RenderTarget* mRenderTarget; bool mInterior; - Ogre::AxisAlignedBox mBounds; - std::string mInteriorName; + osg::BoundingBox mBounds; + //std::string mInteriorName; }; } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index cb53105a7..816002753 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -2,7 +2,6 @@ #include -#include #include #include #include @@ -206,6 +205,10 @@ void Objects::removeCell(const MWWorld::CellStore* store) void Objects::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { + osg::Node* objectNode = cur.getRefData().getBaseNode(); + if (!objectNode) + return; + MWWorld::CellStore *newCell = cur.getCell(); osg::Group* cellnode; @@ -217,8 +220,6 @@ void Objects::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) cellnode = mCellSceneNodes[newCell]; } - osg::Node* objectNode = cur.getRefData().getBaseNode(); - osg::UserDataContainer* userDataContainer = objectNode->getUserDataContainer(); if (userDataContainer) for (unsigned int i=0; igetNumUserObjects(); ++i) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e60b35524..b1c26812c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -2,7 +2,6 @@ #include -#include #include #include #include @@ -111,6 +110,7 @@ namespace MWRender mViewer->setLightingMode(osgViewer::View::NO_LIGHT); osg::ref_ptr source = new osg::LightSource; + source->setNodeMask(SceneUtil::Mask_Lit); mSunLight = new osg::Light; source->setLight(mSunLight); mSunLight->setDiffuse(osg::Vec4f(0,0,0,1)); @@ -123,6 +123,7 @@ namespace MWRender lightRoot->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); lightRoot->setNodeMask(Mask_Scene); + lightRoot->setName("Scene Root"); mSky.reset(new SkyManager(lightRoot, resourceSystem->getSceneManager())); @@ -342,8 +343,12 @@ namespace MWRender intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); osgUtil::IntersectionVisitor intersectionVisitor(intersector); + int mask = intersectionVisitor.getTraversalMask(); + mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect); if (ignorePlayer) - intersectionVisitor.setTraversalMask(intersectionVisitor.getTraversalMask() & (~Mask_Player)); + mask &= ~(Mask_Player); + + intersectionVisitor.setTraversalMask(mask); mViewer->getCamera()->accept(intersectionVisitor); @@ -451,12 +456,8 @@ namespace MWRender void RenderingManager::updateProjectionMatrix() { - double fovy, aspect, zNear, zFar; - mViewer->getCamera()->getProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); - fovy = mFieldOfView; - zNear = mNearClip; - zFar = mViewDistance; - mViewer->getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + double aspect = mViewer->getCamera()->getViewport()->aspectRatio(); + mViewer->getCamera()->setProjectionMatrixAsPerspective(mFieldOfView, aspect, mNearClip, mViewDistance); } void RenderingManager::updateTextureFiltering() diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 43c88427e..990f3a5d9 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -8,10 +8,6 @@ #include #include -#include - -#include - #include #include @@ -34,7 +30,7 @@ #include "../mwworld/fallback.hpp" -#include "renderingmanager.hpp" +#include "vismask.hpp" namespace { @@ -506,6 +502,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mSecundaEnabled(true) { osg::ref_ptr skyroot (new CameraRelativeTransform); + skyroot->setNodeMask(Mask_Sky); parentNode->addChild(skyroot); mRootNode = skyroot; @@ -652,7 +649,7 @@ void SkyManager::setEnabled(bool enabled) if (!enabled) clearRain(); - mRootNode->setNodeMask(enabled ? ~((unsigned int)(0)) : 0); + mRootNode->setNodeMask(enabled ? Mask_Sky : 0); mEnabled = enabled; } diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 7382438d1..c9ac35c67 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -14,10 +14,16 @@ namespace MWRender Mask_Debug = (1<<2), Mask_Actor = (1<<3), Mask_Player = (1<<4), + Mask_Sky = (1<<5), // top level masks - Mask_Scene = (1<<5), - Mask_GUI = (1<<6) + Mask_Scene = (1<<6), + Mask_GUI = (1<<7), + + // Set on cameras within the main scene graph + Mask_RenderToTexture = (1<<8) + + // reserved: (1<<16) for SceneUtil::Mask_Lit }; } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 397ebbe75..939fbe873 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -172,8 +172,13 @@ namespace MWWorld { // Note: exterior cell maps must be updated, even if they were visited before, because the set of surrounding cells might be different // (and objects in a different cell can "bleed" into another cells map if they cross the border) - //for (CellStoreCollection::iterator active = mActiveCells.begin(); active!=mActiveCells.end(); ++active) - //mRendering.requestMap(*active); + std::set cellsToUpdate; + for (CellStoreCollection::iterator active = mActiveCells.begin(); active!=mActiveCells.end(); ++active) + { + cellsToUpdate.insert(*active); + } + MWBase::Environment::get().getWindowManager()->requestMap(cellsToUpdate); + mNeedMapUpdate = false; if (mCurrentCell->isExterior()) @@ -213,6 +218,7 @@ namespace MWWorld MWBase::Environment::get().getMechanicsManager()->drop (*iter); mRendering.removeCell(*iter); + MWBase::Environment::get().getWindowManager()->removeCell(*iter); MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 57b8b67a4..e20904d71 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -162,14 +162,11 @@ namespace MWWorld mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0) { mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); - //mPhysEngine = mPhysics->getEngine(); #if 0 mProjectileManager.reset(new ProjectileManager(renderer.getScene(), *mPhysEngine)); #endif mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem); - //mPhysEngine->setSceneManager(renderer.getScene()); - mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); mEsm.resize(contentFiles.size()); @@ -1591,24 +1588,38 @@ namespace MWWorld updateWindowManager (); updateSoundListener(); - /* - if (!paused && mPlayer->getPlayer().getCell()->isExterior()) + + updatePlayer(paused); + } + + void World::updatePlayer(bool paused) + { + MWWorld::Ptr player = getPlayerPtr(); + + // TODO: move to MWWorld::Player + + if (player.getCell()->isExterior()) { - ESM::Position pos = mPlayer->getPlayer().getRefData().getPosition(); + ESM::Position pos = player.getRefData().getPosition(); mPlayer->setLastKnownExteriorPosition(Ogre::Vector3(pos.pos)); } - */ + + if (player.getClass().getNpcStats(player).isWerewolf()) + MWBase::Environment::get().getWindowManager()->setWerewolfOverlay(mRendering->getCamera()->isFirstPerson()); // Sink the camera while sneaking - bool sneaking = getPlayerPtr().getClass().getCreatureStats(getPlayerPtr()).getStance(MWMechanics::CreatureStats::Stance_Sneak); - bool inair = !isOnGround(getPlayerPtr()); - bool swimming = isSwimming(getPlayerPtr()); + bool sneaking = player.getClass().getCreatureStats(getPlayerPtr()).getStance(MWMechanics::CreatureStats::Stance_Sneak); + bool inair = !isOnGround(player); + bool swimming = isSwimming(player); static const float i1stPersonSneakDelta = getStore().get().find("i1stPersonSneakDelta")->getFloat(); if(!paused && sneaking && !(swimming || inair)) mRendering->getCamera()->setSneakOffset(i1stPersonSneakDelta); else mRendering->getCamera()->setSneakOffset(0.f); + + int blind = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude()); + MWBase::Environment::get().getWindowManager()->setBlindness(std::max(0, std::min(100, blind))); } void World::updateSoundListener() @@ -1701,16 +1712,16 @@ namespace MWWorld mWeatherManager->modRegion(regionid, chances); } - Ogre::Vector2 World::getNorthVector (CellStore* cell) + osg::Vec2f World::getNorthVector (CellStore* cell) { MWWorld::CellRefList& statics = cell->get(); MWWorld::LiveCellRef* ref = statics.find("northmarker"); if (!ref) - return Ogre::Vector2(0, 1); + return osg::Vec2f(0, 1); - Ogre::Quaternion orient (Ogre::Radian(-ref->mData.getPosition().rot[2]), Ogre::Vector3::UNIT_Z); - Ogre::Vector3 dir = orient * Ogre::Vector3(0,1,0); - Ogre::Vector2 d = Ogre::Vector2(dir.x, dir.y); + osg::Quat orient (-ref->mData.getPosition().rot[2], osg::Vec3f(0,0,1)); + osg::Vec3f dir = orient * osg::Vec3f(0,1,0); + osg::Vec2f d (dir.x(), dir.y()); return d; } @@ -1756,24 +1767,9 @@ namespace MWWorld } } - void World::worldToInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) - { - //mRendering->worldToInteriorMapPosition(position, nX, nY, x, y); - } - - Ogre::Vector2 World::interiorMapToWorldPosition(float nX, float nY, int x, int y) - { - return Ogre::Vector2();//mRendering->interiorMapToWorldPosition(nX, nY, x, y); - } - - bool World::isPositionExplored (float nX, float nY, int x, int y, bool interior) - { - return 0;//mRendering->isPositionExplored(nX, nY, x, y, interior); - } - void World::setWaterHeight(const float height) { - //mPhysics->setWaterHeight(height); + mPhysics->setWaterHeight(height); //mRendering->setWaterHeight(height); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index e217f4bc4..dedfebdf2 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -121,6 +121,7 @@ namespace MWWorld void updateSoundListener(); void updateWindowManager (); + void updatePlayer(bool paused); MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer=true); void removeContainerScripts(const Ptr& reference); @@ -218,21 +219,12 @@ namespace MWWorld virtual bool isCellQuasiExterior() const; - virtual Ogre::Vector2 getNorthVector (CellStore* cell); + virtual osg::Vec2f getNorthVector (CellStore* cell); ///< get north vector for given interior cell virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector& out); ///< get a list of teleport door markers for a given cell, to be displayed on the local map - virtual void worldToInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y); - ///< see MWRender::LocalMap::worldToInteriorMapPosition - - virtual Ogre::Vector2 interiorMapToWorldPosition (float nX, float nY, int x, int y); - ///< see MWRender::LocalMap::interiorMapToWorldPosition - - virtual bool isPositionExplored (float nX, float nY, int x, int y, bool interior); - ///< see MWRender::LocalMap::isPositionExplored - virtual void setGlobalInt (const std::string& name, int value); ///< Set value independently from real type. diff --git a/components/myguiplatform/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp index 2a32dd9f3..0a846b227 100644 --- a/components/myguiplatform/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -86,7 +86,7 @@ namespace osgMyGUI if (!mTextureManager) throw std::runtime_error("No texturemanager set"); - mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::REPEAT, osg::Texture2D::REPEAT); + mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::CLAMP_TO_EDGE, osg::Texture2D::CLAMP_TO_EDGE); // FIXME mFormat = MyGUI::PixelFormat::R8G8B8; diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index d676bc3f8..06d5d8792 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index adf7e94b4..5fdf964c4 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -9,8 +9,6 @@ #include #include -#include - // resource #include #include diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index b733987d0..ac304bdf3 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -6,8 +6,6 @@ #include -#include - #include "userdata.hpp" namespace NifOsg diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index ce7a343da..e53a55bf3 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -226,6 +226,7 @@ namespace SceneUtil LightSource::LightSource() : mRadius(0.f) { + setNodeMask(Mask_Lit); setUpdateCallback(new CollectLightCallback); } @@ -233,6 +234,12 @@ namespace SceneUtil { osgUtil::CullVisitor* cv = static_cast(nv); + if (!(cv->getCurrentCamera()->getCullMask()&Mask_Lit)) + { + traverse(node, nv); + return; + } + if (!mLightManager) { for (unsigned int i=0;igetNodePath().size(); ++i) diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 1cd73589a..dd0c2d3e6 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -9,6 +9,9 @@ namespace SceneUtil { + // This mask should be included in the Cull and Update visitor's traversal mask if lighting is desired. + const int Mask_Lit = (1<<16); + /// LightSource managed by a LightManager. class LightSource : public osg::Node { diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 065ee60d9..dd6b9a499 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -6,7 +6,6 @@ #include #include -#include #include "skeleton.hpp" #include "util.hpp"