Map rendering

c++11
scrawl 10 years ago
parent 76dd3e4034
commit 3dcb167066

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

@ -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<MWWorld::CellStore*> cells) = 0;
virtual void removeCell(MWWorld::CellStore* cell) = 0;
};
}

@ -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<DoorMarker>& 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.

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

@ -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<float>& value);
void setFPS(float fps);

@ -35,7 +35,6 @@ namespace MWGui
, mLastRenderTime(0.0)
, mLoadingOnTime(0.0)
, mProgress(0)
, mVSyncWasEnabled(false)
{
mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize());

@ -67,8 +67,6 @@ namespace MWGui
std::vector<std::string> mSplashScreens;
bool mVSyncWasEnabled;
void changeWallpaper();
void draw();

@ -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<boost::shared_ptr<MyGUI::ITexture> > 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<osg::Texture2D> texture = mLocalMapRender->getMapTexture(mInterior, mapX, mapY);
if (texture)
{
boost::shared_ptr<MyGUI::ITexture> 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<MWWorld::Ptr>::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);
}
}

@ -3,6 +3,8 @@
#include <stdint.h>
#include <boost/shared_ptr.hpp>
#include "windowpinnablebase.hpp"
#include <components/esm/cellid.hpp>
@ -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<MyGUI::ImageBox*> mMapWidgets;
std::vector<MyGUI::ImageBox*> mFogWidgets;
std::vector<boost::shared_ptr<MyGUI::ITexture> > mMapTextures;
// Keep track of created marker widgets, just to easily remove them later.
std::vector<MyGUI::Widget*> mDoorMarkerWidgets;
std::vector<MyGUI::Widget*> 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);

@ -169,7 +169,7 @@ namespace MWGui
{
LocalMapBase::MarkerUserData data = *focus->getUserData<LocalMapBase::MarkerUserData>();
if (!MWBase::Environment::get().getWorld ()->isPositionExplored (data.nX, data.nY, data.cellX, data.cellY, data.interior))
if (!data.isPositionExplored())
return;
ToolTipInfo info;

@ -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<MWWorld::CellStore*> cells)
{
mLocalMapRender->requestMap(cells);
}
void WindowManager::removeCell(MWWorld::CellStore *cell)
{
mLocalMapRender->removeCell(cell);
}
}

@ -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<MWWorld::CellStore*> 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<std::string, std::string> mFallbackMap;

@ -1,5 +1,4 @@
#include "actor.hpp"
#include <osg/io_utils>
#include <osg/PositionAttitudeTransform>

@ -8,7 +8,6 @@
#include <osg/TexEnvCombine>
#include <osg/ComputeBoundsVisitor>
#include <osg/MatrixTransform>
#include <osg/io_utils>
#include <osg/Geode>
#include <components/nifosg/nifloader.hpp>

@ -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<SceneUtil::LightManager> lightManager = new SceneUtil::LightManager;
lightManager->setStartLight(1);
osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;

@ -1,74 +1,82 @@
#include "localmap.hpp"
#include <OgreMaterialManager.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreSceneManager.h>
#include <OgreSceneNode.h>
#include <OgreCamera.h>
#include <OgreTextureManager.h>
#include <OgreRenderTexture.h>
#include <OgreViewport.h>
#include <iostream>
#include <osg/LightModel>
#include <osg/Texture2D>
#include <osg/ComputeBoundsVisitor>
#include <osgViewer/Viewer>
#include <components/esm/fogstate.hpp>
#include <components/settings/settings.hpp>
#include <components/sceneutil/visitor.hpp>
#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<osg::Camera> 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<int>(std::ceil(length.x / sSize));
const int segsY = static_cast<int>(std::ceil(length.y / sSize));
const int segsX = static_cast<int>(std::ceil(length.x / mMapWorldSize));
const int segsY = static_cast<int>(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<osg::Camera> LocalMap::createOrthographicCamera(float x, float y, float width, float height, const osg::Vec3d& upVector, float zmin, float zmax)
{
mInterior = false;
osg::ref_ptr<osg::Camera> 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<osg::StateSet> 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<osg::LightModel> 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<osg::Light> 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<osg::LightSource> 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<osg::Camera> camera, int x, int y)
{
osg::ref_ptr<osg::Texture2D> 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<MWWorld::CellStore*> cells)
{
for (std::set<MWWorld::CellStore*>::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<osg::Texture2D> 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<osg::Texture2D>();
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<float>(sSize), static_cast<float>(sSize), name, true);
osg::ref_ptr<osg::Camera> 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<int>(std::ceil(length.x / sSize));
const int segsY = static_cast<int>(std::ceil(length.y / sSize));
mInteriorName = cell->getCell()->mName;
const int segsX = static_cast<int>(std::ceil(length.x() / mMapWorldSize));
const int segsY = static_cast<int>(std::ceil(length.y() / mMapWorldSize));
int i=0;
for (int x=0; x<segsX; ++x)
{
for (int y=0; y<segsY; ++y)
{
Vector2 start = min + Vector2(static_cast<Ogre::Real>(sSize*x), static_cast<Ogre::Real>(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<osg::Camera> 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<float>(sSize), static_cast<float>(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<char>& 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<int>(std::ceil((pos.x - min.x) / sSize) - 1);
y = static_cast<int>(std::ceil((pos.y - min.y) / sSize) - 1);
x = static_cast<int>(std::ceil((pos.x() - min.x()) / mMapWorldSize) - 1);
y = static_cast<int>(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<uint32> buffer;
// initialize to (0, 0, 0, 1)
buffer.resize(sFogOfWarResolution*sFogOfWarResolution, 0xFF000000);
mBuffers[resourceName] = buffer;
}
std::vector<uint32>& buffer = mBuffers[resourceName];
Ogre::Texture* tex = static_cast<Ogre::Texture*>(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<int>(std::ceil(pos.x / sSize) - 1);
y = static_cast<int>(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<int>(std::ceil(pos.x() / mMapWorldSize) - 1);
y = static_cast<int>(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
}
*/
}
}

@ -1,9 +1,13 @@
#ifndef GAME_RENDER_LOCALMAP_H
#define GAME_RENDER_LOCALMAP_H
#include <OgreAxisAlignedBox.h>
#include <OgreColourValue.h>
#include <OgreResource.h>
#include <set>
#include <vector>
#include <map>
#include <osg/BoundingBox>
#include <osg/Quat>
#include <osg/ref_ptr>
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<MWWorld::CellStore*> cells);
void removeCell (MWWorld::CellStore* cell);
osg::ref_ptr<osg::Texture2D> 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<osgViewer::Viewer> mViewer;
osg::ref_ptr<osg::Group> mRoot;
osg::ref_ptr<osg::Node> mSceneRoot;
typedef std::vector< osg::ref_ptr<osg::Camera> > CameraVector;
CameraVector mActiveCameras;
CameraVector mCamerasPendingRemoval;
typedef std::map<std::pair<int, int>, osg::ref_ptr<osg::Texture2D> > 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<osg::Camera> createOrthographicCamera(float left, float top, float width, float height, const osg::Vec3d& upVector, float zmin, float zmax);
void setupRenderToTexture(osg::ref_ptr<osg::Camera> 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 <std::string, std::vector<Ogre::uint32> > mBuffers;
//std::map <std::string, std::vector<Ogre::uint32> > 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;
};
}

@ -2,7 +2,6 @@
#include <cmath>
#include <osg/io_utils>
#include <osg/Group>
#include <osg/Geode>
#include <osg/PositionAttitudeTransform>
@ -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; i<userDataContainer->getNumUserObjects(); ++i)

@ -2,7 +2,6 @@
#include <stdexcept>
#include <osg/io_utils>
#include <osg/Light>
#include <osg/LightModel>
#include <osg/Fog>
@ -111,6 +110,7 @@ namespace MWRender
mViewer->setLightingMode(osgViewer::View::NO_LIGHT);
osg::ref_ptr<osg::LightSource> 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()

@ -8,10 +8,6 @@
#include <osg/Geometry>
#include <osg/PositionAttitudeTransform>
#include <osg/io_utils>
#include <osgUtil/CullVisitor>
#include <osg/TexEnvCombine>
#include <osg/TexMat>
@ -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<CameraRelativeTransform> 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;
}

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

@ -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<MWWorld::CellStore*> 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);

@ -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<ESM::GameSetting>().find("i1stPersonSneakDelta")->getFloat();
if(!paused && sneaking && !(swimming || inair))
mRendering->getCamera()->setSneakOffset(i1stPersonSneakDelta);
else
mRendering->getCamera()->setSneakOffset(0.f);
int blind = static_cast<int>(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<ESM::Static>& statics = cell->get<ESM::Static>();
MWWorld::LiveCellRef<ESM::Static>* 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);
}

@ -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<DoorMarker>& 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.

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

@ -4,7 +4,6 @@
#include <osg/TexMat>
#include <osg/Material>
#include <osg/Texture2D>
#include <osg/io_utils>
#include <osg/UserDataContainer>
#include <osgAnimation/MorphGeometry>

@ -9,8 +9,6 @@
#include <osg/ShapeDrawable>
#include <osg/ComputeBoundsVisitor>
#include <osg/io_utils>
// resource
#include <components/misc/stringops.hpp>
#include <components/misc/resourcehelpers.hpp>

@ -6,8 +6,6 @@
#include <components/nif/controlled.hpp>
#include <osg/io_utils>
#include "userdata.hpp"
namespace NifOsg

@ -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<osgUtil::CullVisitor*>(nv);
if (!(cv->getCurrentCamera()->getCullMask()&Mask_Lit))
{
traverse(node, nv);
return;
}
if (!mLightManager)
{
for (unsigned int i=0;i<nv->getNodePath().size(); ++i)

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

@ -6,7 +6,6 @@
#include <cstdlib>
#include <osg/MatrixTransform>
#include <osg/io_utils>
#include "skeleton.hpp"
#include "util.hpp"

Loading…
Cancel
Save