From 5b38b17baf090976496825446dbe9bbd6a20252e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Mar 2012 15:28:18 +0100 Subject: [PATCH] local map rendering (nothing to see yet, as it is not displayed in GUI) --- apps/openmw/CMakeLists.txt | 3 +- apps/openmw/mwrender/localmap.cpp | 160 ++++++++++++++++++++++ apps/openmw/mwrender/localmap.hpp | 48 +++++++ apps/openmw/mwrender/objects.cpp | 12 ++ apps/openmw/mwrender/objects.hpp | 4 + apps/openmw/mwrender/renderingmanager.cpp | 11 ++ apps/openmw/mwrender/renderingmanager.hpp | 6 + apps/openmw/mwworld/scene.cpp | 3 +- 8 files changed, 245 insertions(+), 2 deletions(-) create mode 100644 apps/openmw/mwrender/localmap.cpp create mode 100644 apps/openmw/mwrender/localmap.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 39cd99cf6c..2af808e9aa 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -14,7 +14,8 @@ set(GAME_HEADER source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender - renderingmanager debugging sky player animation npcanimation creatureanimation actors objects renderinginterface + renderingmanager debugging sky player animation npcanimation creatureanimation actors objects + renderinginterface localmap ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp new file mode 100644 index 0000000000..3e3ff77dbd --- /dev/null +++ b/apps/openmw/mwrender/localmap.cpp @@ -0,0 +1,160 @@ +#include "localmap.hpp" +#include "renderingmanager.hpp" + +#include +#include + +#include + +using namespace MWRender; +using namespace Ogre; + +#define CACHE_EXTENSION ".jpg" + +#define MAP_RESOLUTION 1024 // 1024*1024 pixels for a 8192*8192 area in world units + +LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend) +{ + mRendering = rend; + + mCellCamera = mRendering->getScene()->createCamera("CellCamera"); + mCellCamera->setProjectionType(PT_ORTHOGRAPHIC); + // look down -y + const float sqrt0pt5 = 0.707106781; + mCellCamera->setOrientation(Quaternion(sqrt0pt5, -sqrt0pt5, 0, 0)); + + // Debug overlay to view the maps + /* + render(0, 0, 10000, 10000, 8192, 8192, "Cell_0_0"); + + MaterialPtr mat = MaterialManager::getSingleton().create("testMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + mat->getTechnique(0)->getPass(0)->createTextureUnitState("Cell_0_0"); + + OverlayManager& ovm = OverlayManager::getSingleton(); + + Overlay* mOverlay = ovm.create( "testOverlay" ); + + OverlayContainer* overlay_panel; + overlay_panel = (OverlayContainer*)ovm.createOverlayElement("Panel", "testPanel"); + + overlay_panel->_setPosition(0, 0); + overlay_panel->_setDimensions(0.5, 0.5); + + overlay_panel->setMaterialName( "testMaterial" ); + overlay_panel->show(); + mOverlay->add2D(overlay_panel); + mOverlay->show(); + */ +} + +void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell) +{ + std::string name = "Cell_" + StringConverter::toString(cell->cell->data.gridX) + + "_" + StringConverter::toString(cell->cell->data.gridY); + + const int x = cell->cell->data.gridX; + const int y = cell->cell->data.gridY; + + render((x+0.5)*8192, (-y-0.5)*8192, -10000, 10000, 8192, 8192, name); +} + +void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, + AxisAlignedBox bounds) +{ + Vector2 z(bounds.getMaximum().y, bounds.getMinimum().y); + Vector2 min(bounds.getMinimum().x, bounds.getMinimum().z); + Vector2 max(bounds.getMaximum().x, bounds.getMaximum().z); + + /// \todo why is this workaround needed? + min *= 1.3; + max *= 1.3; + + Vector2 length = max-min; + Vector2 center(bounds.getCenter().x, bounds.getCenter().z); + + // divide into 8192*8192 segments + const int segsX = std::ceil( length.x / 8192 ); + const int segsY = std::ceil( length.y / 8192 ); + + for (int x=0; xcell->name + "_" + StringConverter::toString(x) + "_" + StringConverter::toString(y)); + } + } +} + +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) +{ + // disable fog + // changing FOG_MODE is not a solution when using shaders, thus we have to push linear start/end + const float fStart = mRendering->getScene()->getFogStart(); + const float fEnd = mRendering->getScene()->getFogEnd(); + const ColourValue& clr = mRendering->getScene()->getFogColour(); + mRendering->getScene()->setFog(FOG_LINEAR, clr, 0, 1000000, 10000000); + + // make everything visible + mRendering->getScene()->setAmbientLight(ColourValue(1,1,1)); + + mCellCamera->setPosition(Vector3(x, zhigh, y)); + mCellCamera->setFarClipDistance( (zhigh-zlow) * 1.1 ); + + mCellCamera->setOrthoWindow(xw, yw); + + TexturePtr tex; + // try loading from memory + tex = TextureManager::getSingleton().getByName(texture); + if (tex.isNull()) + { + // try loading from disk + //if (boost::filesystem::exists(texture+CACHE_EXTENSION)) + //{ + /// \todo + //} + //else + { + // render + tex = TextureManager::getSingleton().createManual( + texture, + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + TEX_TYPE_2D, + xw*MAP_RESOLUTION/8192, yw*MAP_RESOLUTION/8192, + 0, + PF_R8G8B8, + TU_RENDERTARGET); + + RenderTarget* rtt = tex->getBuffer()->getRenderTarget(); + rtt->setAutoUpdated(false); + Viewport* vp = rtt->addViewport(mCellCamera); + vp->setOverlaysEnabled(false); + vp->setShadowsEnabled(false); + vp->setBackgroundColour(ColourValue(0, 0, 0)); + //vp->setVisibilityMask( ... ); + + rtt->update(); + + /// \todo + // save to cache for next time + //rtt->writeContentsToFile("./" + texture + CACHE_EXTENSION); + } + } + + + /* + if (!MaterialManager::getSingleton().getByName("testMaterial").isNull()) + { + MaterialPtr mat = MaterialManager::getSingleton().getByName("testMaterial"); + mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(texture); + } + */ + + // re-enable fog + mRendering->getScene()->setFog(FOG_LINEAR, clr, 0, fStart, fEnd); +} diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp new file mode 100644 index 0000000000..ac62031f4b --- /dev/null +++ b/apps/openmw/mwrender/localmap.hpp @@ -0,0 +1,48 @@ +#ifndef _GAME_RENDER_LOCALMAP_H +#define _GAME_RENDER_LOCALMAP_H + +#include "../mwworld/ptr.hpp" + +#include + +namespace MWRender +{ + /// + /// \brief Local map rendering + /// + class LocalMap + { + public: + LocalMap(OEngine::Render::OgreRenderer*); + + /** + * Request the local map for an exterior cell. + * It will either be loaded from a disk cache, + * or rendered if it is not already cached. + * @param exterior cell + */ + void requestMap (MWWorld::Ptr::CellStore* cell); + + /** + * Request the local map for an interior cell. + * It will either be loaded from a disk cache, + * or rendered if it is not already cached. + * @param interior cell + * @param bounding box of the cell + */ + void requestMap (MWWorld::Ptr::CellStore* cell, + Ogre::AxisAlignedBox bounds); + + private: + OEngine::Render::OgreRenderer* mRendering; + + Ogre::Camera* mCellCamera; + + void render(const float x, const float y, + const float zlow, const float zhigh, + const float xw, const float yw, + const std::string& texture); + }; + +} +#endif diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 717064ada5..e4e7212275 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -109,6 +109,9 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) // If it is set too low: // - there will be too many batches. sg->setRegionDimensions(Ogre::Vector3(2500,2500,2500)); + + mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL; + mBounds[ptr.getCell()].merge(ent->getBoundingBox()); } else { @@ -116,6 +119,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) } sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale()); + mBounds[ptr.getCell()].merge(insert->_getDerivedPosition()); mRenderer.getScene()->destroyEntity(ent); } @@ -202,6 +206,9 @@ void Objects::removeCell(MWWorld::Ptr::CellStore* store) mRenderer.getScene()->destroyStaticGeometry (sg); sg = 0; } + + if(mBounds.find(store) != mBounds.end()) + mBounds.erase(store); } void Objects::buildStaticGeometry(ESMS::CellStore& cell) @@ -212,3 +219,8 @@ void Objects::buildStaticGeometry(ESMS::CellStore& cell) sg->build(); } } + +Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell) +{ + return mBounds[cell]; +} diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index d58455b9f3..1ca81331d1 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -14,6 +14,7 @@ class Objects{ OEngine::Render::OgreRenderer &mRenderer; std::map mCellSceneNodes; std::map mStaticGeometry; + std::map mBounds; Ogre::SceneNode* mMwRoot; bool mIsStatic; static int uniqueID; @@ -42,6 +43,9 @@ public: void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh); void insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, float radius); + Ogre::AxisAlignedBox getDimensions(MWWorld::Ptr::CellStore*); + ///< get a bounding box that encloses all objects in the specified cell + bool deleteObject (const MWWorld::Ptr& ptr); ///< \return found? diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7b58a80d76..41f4e72d69 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -55,6 +55,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode); mSun = 0; + + mLocalMap = new MWRender::LocalMap(&mRendering); } RenderingManager::~RenderingManager () @@ -62,6 +64,7 @@ RenderingManager::~RenderingManager () //TODO: destroy mSun? delete mPlayer; delete mSkyManager; + delete mLocalMap; } MWRender::SkyManager* RenderingManager::getSkyManager() @@ -322,4 +325,12 @@ void RenderingManager::setGlare(bool glare) mSkyManager->setGlare(glare); } +void RenderingManager::requestMap(MWWorld::Ptr::CellStore* cell) +{ + if (!(cell->cell->data.flags & ESM::Cell::Interior)) + mLocalMap->requestMap(cell); + else + mLocalMap->requestMap(cell, mObjects.getDimensions(cell)); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index d84ee43e00..65aa46b01d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -24,6 +24,7 @@ #include "objects.hpp" #include "actors.hpp" #include "player.hpp" +#include "localmap.hpp" namespace Ogre { @@ -102,6 +103,9 @@ class RenderingManager: private RenderingInterface { int skyGetSecundaPhase() const; void skySetMoonColour (bool red); void configureAmbient(ESMS::CellStore &mCell); + + void requestMap (MWWorld::Ptr::CellStore* cell); + ///< request the local map for a cell /// configure fog according to cell void configureFog(ESMS::CellStore &mCell); @@ -148,6 +152,8 @@ class RenderingManager: private RenderingInterface { MWRender::Player *mPlayer; MWRender::Debugging mDebugging; + + MWRender::LocalMap* mLocalMap; }; } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 47d5f1a2de..e7a3f2d5dc 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -101,7 +101,8 @@ namespace MWWorld insertCell(*cell, mEnvironment); mRendering.cellAdded (cell); mRendering.configureAmbient(*cell); - + mRendering.requestMap(cell); + mRendering.configureAmbient(*cell); }