From 9fb5cef287e2e518df7c6c58c73722c18721c528 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 May 2014 15:40:00 +0200 Subject: [PATCH 01/10] Oops, committed debug code --- apps/openmw/mwgui/mapwindow.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 89517d7d1..a4cd61c84 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -93,11 +93,6 @@ namespace MWGui { mFogOfWar = !mFogOfWar; applyFogOfWar(); - - // clear all previous door markers - for (std::vector::iterator it = mDoorMarkerWidgets.begin(); it != mDoorMarkerWidgets.end(); ++it) - MyGUI::Gui::getInstance().destroyWidget(*it); - mDoorMarkerWidgets.clear(); } void LocalMapBase::applyFogOfWar() From b358cf24230e4438767aaae23fc914921a29ab25 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 May 2014 18:14:35 +0200 Subject: [PATCH 02/10] Fix a potential crash when loading script locals from savegame --- apps/openmw/mwworld/livecellref.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/livecellref.cpp b/apps/openmw/mwworld/livecellref.cpp index f312c2159..4a610b45c 100644 --- a/apps/openmw/mwworld/livecellref.cpp +++ b/apps/openmw/mwworld/livecellref.cpp @@ -20,10 +20,15 @@ void MWWorld::LiveCellRefBase::loadImp (const ESM::ObjectState& state) if (state.mHasLocals) { std::string scriptId = mClass->getScript (ptr); - - mData.setLocals (*MWBase::Environment::get().getWorld()->getStore(). - get().find (scriptId)); - mData.getLocals().read (state.mLocals, scriptId); + // Make sure we still have a script. It could have been coming from a content file that is no longer active. + if (!scriptId.empty()) + { + if (const ESM::Script* script = MWBase::Environment::get().getWorld()->getStore().get().search (scriptId)) + { + mData.setLocals (*script); + mData.getLocals().read (state.mLocals, scriptId); + } + } } mClass->readAdditionalState (ptr, state); From dab4db87fff2866e215833c2e93751f5510de511 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 May 2014 23:47:00 +0200 Subject: [PATCH 03/10] Fix a bug in marker placement for interior maps --- apps/openmw/mwgui/mapwindow.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index a4cd61c84..b6b1bd89a 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -160,8 +160,9 @@ namespace MWGui markerPos.cellX = cellX; markerPos.cellY = cellY; - widgetPos = MyGUI::IntPoint(nX * 512 + (1+cellX-mCurX) * 512, - nY * 512 + (1+cellY-mCurY) * 512); + // Image space is -Y up, cells are Y up + widgetPos = MyGUI::IntPoint(nX * 512 + (1+(cellX-mCurX)) * 512, + nY * 512 + (1-(cellY-mCurY)) * 512); } markerPos.nX = nX; From 3ad28ec5aad024f2338e23e78c644ee826258b2a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 May 2014 00:09:02 +0200 Subject: [PATCH 04/10] Set a proper Page size for all scrollbars. Fixes scrollbars only moving very slowly when interacting with them (as opposed to using mousewheel on the content) --- files/mygui/openmw_list.skin.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/files/mygui/openmw_list.skin.xml b/files/mygui/openmw_list.skin.xml index 7972527ac..4dbc3da45 100644 --- a/files/mygui/openmw_list.skin.xml +++ b/files/mygui/openmw_list.skin.xml @@ -10,6 +10,10 @@ + + + + @@ -47,6 +51,10 @@ + + + + From 07d9845aa00a3c467c1df9d9ac114b6f45106b52 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 May 2014 00:10:28 +0200 Subject: [PATCH 05/10] Fix a bug in ESMStore code that checks for duplicate record insertions --- apps/openmw/mwworld/esmstore.hpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index ea6d3d006..c6c9c1ffe 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -166,16 +166,17 @@ namespace MWWorld template const T *insert(const T &x) { + std::ostringstream id; + id << "$dynamic" << mDynamicCount++; + Store &store = const_cast &>(get()); - if (store.search(x.mId) != 0) { + if (store.search(id.str()) != 0) { std::ostringstream msg; - msg << "Try to override existing record '" << x.mId << "'"; + msg << "Try to override existing record '" << id.str() << "'"; throw std::runtime_error(msg.str()); } T record = x; - std::ostringstream id; - id << "$dynamic" << mDynamicCount++; record.mId = id.str(); T *ptr = store.insert(record); @@ -189,10 +190,13 @@ namespace MWWorld template const T *insertStatic(const T &x) { + std::ostringstream id; + id << "$dynamic" << mDynamicCount++; + Store &store = const_cast &>(get()); - if (store.search(x.mId) != 0) { + if (store.search(id.str()) != 0) { std::ostringstream msg; - msg << "Try to override existing record '" << x.mId << "'"; + msg << "Try to override existing record '" << id.str() << "'"; throw std::runtime_error(msg.str()); } T record = x; @@ -225,17 +229,18 @@ namespace MWWorld template <> inline const ESM::NPC *ESMStore::insert(const ESM::NPC &npc) { + std::ostringstream id; + id << "$dynamic" << mDynamicCount++; + if (Misc::StringUtils::ciEqual(npc.mId, "player")) { return mNpcs.insert(npc); - } else if (mNpcs.search(npc.mId) != 0) { + } else if (mNpcs.search(id.str()) != 0) { std::ostringstream msg; - msg << "Try to override existing record '" << npc.mId << "'"; + msg << "Try to override existing record '" << id.str() << "'"; throw std::runtime_error(msg.str()); } ESM::NPC record = npc; - std::ostringstream id; - id << "$dynamic" << mDynamicCount++; record.mId = id.str(); ESM::NPC *ptr = mNpcs.insert(record); From 041319c43e4fcf059c7bcc28976e504c08fd3820 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 May 2014 00:32:22 +0200 Subject: [PATCH 06/10] Fixes #1234: Store dynamic record counter in savegame to prevent name clashes --- apps/openmw/mwstate/statemanagerimp.cpp | 1 + apps/openmw/mwworld/esmstore.cpp | 16 ++++++++++++++-- components/esm/defs.hpp | 1 + 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index c718eeced..c89041710 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -314,6 +314,7 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl case ESM::REC_PLAY: case ESM::REC_CSTA: case ESM::REC_WTHR: + case ESM::REC_DYNA: MWBase::Environment::get().getWorld()->readRecord (reader, n.val, contentFileMap); break; diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index ebe0aa08a..a769e7f67 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -141,8 +141,8 @@ void ESMStore::setUp() int ESMStore::countSavedGameRecords() const { - return - mPotions.getDynamicSize() + return 1 // DYNA (dynamic name counter) + +mPotions.getDynamicSize() +mArmors.getDynamicSize() +mBooks.getDynamicSize() +mClasses.getDynamicSize() @@ -155,6 +155,13 @@ void ESMStore::setUp() void ESMStore::write (ESM::ESMWriter& writer, Loading::Listener& progress) const { + writer.startRecord(ESM::REC_DYNA); + writer.startSubRecord("COUN"); + writer.writeT(mDynamicCount); + writer.endRecord("COUN"); + writer.endRecord(ESM::REC_DYNA); + progress.increaseProgress(); + mPotions.write (writer, progress); mArmors.write (writer, progress); mBooks.write (writer, progress); @@ -197,6 +204,11 @@ void ESMStore::setUp() return true; + case ESM::REC_DYNA: + reader.getSubNameIs("COUN"); + reader.getHT(mDynamicCount); + return true; + default: return false; diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index b2a1637f1..5a99d0c2e 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -100,6 +100,7 @@ enum RecNameInts REC_DIAS = 0x53414944, REC_WTHR = 0x52485457, REC_KEYS = FourCC<'K','E','Y','S'>::value, + REC_DYNA = FourCC<'D','Y','N','A'>::value, // format 1 REC_FILT = 0x544C4946 From 7b46e9f914228e02c1702f785c57fdb17ea651aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 May 2014 01:05:49 +0200 Subject: [PATCH 07/10] Get rid of no longer needed widget names --- apps/openmw/mwgui/mapwindow.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index b6b1bd89a..dc22dcb22 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -65,11 +65,11 @@ namespace MWGui { MyGUI::ImageBox* map = mLocalMap->createWidget("ImageBox", MyGUI::IntCoord(mx*widgetSize, my*widgetSize, widgetSize, widgetSize), - MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my)); + MyGUI::Align::Top | MyGUI::Align::Left); MyGUI::ImageBox* fog = map->createWidget("ImageBox", MyGUI::IntCoord(0, 0, widgetSize, widgetSize), - MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my) + "_fog"); + MyGUI::Align::Top | MyGUI::Align::Left); if (!mMapDragAndDrop) { @@ -237,7 +237,7 @@ namespace MWGui 8, 8); ++counter; MyGUI::Button* markerWidget = mLocalMap->createWidget("ButtonImage", - widgetCoord, MyGUI::Align::Default, "Door" + boost::lexical_cast(counter)); + widgetCoord, MyGUI::Align::Default); markerWidget->setImageResource("DoorMarker"); markerWidget->setUserString("ToolTipType", "Layout"); markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); @@ -339,7 +339,7 @@ namespace MWGui 8, 8); ++counter; MyGUI::ImageBox* markerWidget = mLocalMap->createWidget("ImageBox", - widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); + widgetCoord, MyGUI::Align::Default); markerWidget->setImageTexture(markerTexture); markerWidget->setUserString("IsMarker", "true"); markerWidget->setUserData(markerPos); @@ -371,7 +371,7 @@ namespace MWGui widgetPos.top - 4, 8, 8); MyGUI::ImageBox* markerWidget = mLocalMap->createWidget("ImageBox", - widgetCoord, MyGUI::Align::Default, "MarkerMarked"); + widgetCoord, MyGUI::Align::Default); markerWidget->setImageTexture("textures\\menu_map_smark.dds"); markerWidget->setUserString("IsMarker", "true"); markerWidget->setUserData(markerPos); @@ -443,7 +443,7 @@ namespace MWGui static int _counter=0; MyGUI::Button* markerWidget = mGlobalMapOverlay->createWidget("ButtonImage", - widgetCoord, MyGUI::Align::Default, "Door" + boost::lexical_cast(_counter)); + widgetCoord, MyGUI::Align::Default); markerWidget->setImageResource("DoorMarker"); markerWidget->setUserString("ToolTipType", "Layout"); markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); From a4a9794417ff6c89197a2ebddb8b6012add7ecc4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 May 2014 02:07:28 +0200 Subject: [PATCH 08/10] Savegame: store fog of war (Closes #1177) --- apps/openmw/mwrender/localmap.cpp | 267 ++++++++++++++++------ apps/openmw/mwrender/localmap.hpp | 31 ++- apps/openmw/mwrender/renderingmanager.cpp | 10 +- apps/openmw/mwrender/renderingmanager.hpp | 7 +- apps/openmw/mwworld/cells.cpp | 4 + apps/openmw/mwworld/cellstore.cpp | 26 +++ apps/openmw/mwworld/cellstore.hpp | 20 ++ apps/openmw/mwworld/worldimp.cpp | 10 + components/CMakeLists.txt | 2 +- components/esm/cellstate.cpp | 7 +- components/esm/cellstate.hpp | 4 +- components/esm/fogstate.cpp | 40 ++++ components/esm/fogstate.hpp | 38 +++ 13 files changed, 380 insertions(+), 86 deletions(-) create mode 100644 components/esm/fogstate.cpp create mode 100644 components/esm/fogstate.hpp diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 0f6d782a6..41885da33 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -9,6 +9,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -46,7 +48,6 @@ LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManag LocalMap::~LocalMap() { - deleteBuffers(); } const Ogre::Vector2 LocalMap::rotatePoint(const Ogre::Vector2& p, const Ogre::Vector2& c, const float angle) @@ -55,59 +56,83 @@ const Ogre::Vector2 LocalMap::rotatePoint(const Ogre::Vector2& p, const Ogre::Ve Math::Sin(angle) * (p.x - c.x) + Math::Cos(angle) * (p.y - c.y) + c.y); } -void LocalMap::deleteBuffers() +std::string LocalMap::coordStr(const int x, const int y) { - mBuffers.clear(); + return StringConverter::toString(x) + "_" + StringConverter::toString(y); } -void LocalMap::saveTexture(const std::string& texname, const std::string& filename) +void LocalMap::clear() { - TexturePtr tex = TextureManager::getSingleton().getByName(texname); - if (tex.isNull()) return; - HardwarePixelBufferSharedPtr readbuffer = tex->getBuffer(); - readbuffer->lock(HardwareBuffer::HBL_NORMAL ); - const PixelBox &readrefpb = readbuffer->getCurrentLock(); - uchar *readrefdata = static_cast(readrefpb.data); - - Image img; - img = img.loadDynamicImage (readrefdata, tex->getWidth(), - tex->getHeight(), tex->getFormat()); - img.save("./" + filename); - - readbuffer->unlock(); -} - -std::string LocalMap::coordStr(const int x, const int y) -{ - return StringConverter::toString(x) + "_" + StringConverter::toString(y); + // Not actually removing the Textures here. That doesnt appear to work properly. It seems MyGUI still keeps some pointers. + mBuffers.clear(); } void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) { if (!mInterior) { - /*saveTexture("Cell_"+coordStr(mCellX, mCellY)+"_fog", - "Cell_"+coordStr(mCellX, mCellY)+"_fog.png");*/ + std::string textureName = "Cell_"+coordStr(cell->getCell()->getGridX(), cell->getCell()->getGridY())+"_fog"; + std::auto_ptr fog (new ESM::FogState()); + fog->mFogTextures.push_back(ESM::FogTexture()); + + TexturePtr tex = TextureManager::getSingleton().getByName(textureName); + if (tex.isNull()) + return; + + Ogre::Image image; + tex->convertToImage(image); + + Ogre::DataStreamPtr encoded = image.encode("tga"); + fog->mFogTextures.back().mImageData.resize(encoded->size()); + encoded->read(&fog->mFogTextures.back().mImageData[0], encoded->size()); + + cell->setFog(fog.release()); } else { Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y); Vector2 length = max-min; - - // divide into segments const int segsX = std::ceil( length.x / sSize ); const int segsY = std::ceil( length.y / sSize ); + mInteriorName = cell->getCell()->mName; + + std::auto_ptr fog (new ESM::FogState()); + + fog->mBounds.mMinX = mBounds.getMinimum().x; + fog->mBounds.mMaxX = mBounds.getMaximum().x; + fog->mBounds.mMinY = mBounds.getMinimum().y; + fog->mBounds.mMaxY = mBounds.getMaximum().y; + fog->mNorthMarkerAngle = mAngle; + + fog->mFogTextures.reserve(segsX*segsY); + for (int x=0; xgetCell()->mName + "_" + coordStr(x,y) + "_fog"; + + TexturePtr tex = TextureManager::getSingleton().getByName(textureName); + if (tex.isNull()) + return; + + Ogre::Image image; + tex->convertToImage(image); + + fog->mFogTextures.push_back(ESM::FogTexture()); + + Ogre::DataStreamPtr encoded = image.encode("tga"); + fog->mFogTextures.back().mImageData.resize(encoded->size()); + encoded->read(&fog->mFogTextures.back().mImageData[0], encoded->size()); + + fog->mFogTextures.back().mX = x; + fog->mFogTextures.back().mY = y; } } + + cell->setFog(fog.release()); } } @@ -126,29 +151,34 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, float zMin, float zMax) mCameraPosNode->setPosition(Vector3(0,0,0)); render((x+0.5)*sSize, (y+0.5)*sSize, zMin, zMax, sSize, sSize, name); + + if (mBuffers.find(name) == mBuffers.end()) + { + if (cell->getFog()) + loadFogOfWar(name, cell->getFog()->mFogTextures.back()); + else + createFogOfWar(name); + } } void LocalMap::requestMap(MWWorld::CellStore* cell, AxisAlignedBox bounds) { - // if we're in an empty cell, don't bother rendering anything + // If we're in an empty cell, bail out + // The operations in this function are only valid for finite bounds if (bounds.isNull ()) return; mInterior = true; - mBounds = bounds; - float zMin = mBounds.getMinimum().z; - float zMax = mBounds.getMaximum().z; + 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); + Radian angle = Ogre::Math::ATan2 (north.x, north.y) + Ogre::Degree(2); mAngle = angle.valueRadians(); - mCellCamera->setOrientation(Quaternion::IDENTITY); - mCameraRotNode->setOrientation(Quaternion(Math::Cos(mAngle/2.f), 0, 0, -Math::Sin(mAngle/2.f))); - - // rotate the cell and merge the rotated corners to the bounding box + // 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); @@ -168,9 +198,48 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, mBounds.merge(Vector3(c3.x, c3.y, 0)); mBounds.merge(Vector3(c4.x, c4.y, 0)); - // apply a little padding - mBounds.setMinimum (mBounds.getMinimum() - Vector3(500,500,0)); - mBounds.setMaximum (mBounds.getMaximum() + Vector3(500,500,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 int padding = 500; + + // Apply a little padding + mBounds.setMinimum (mBounds.getMinimum() - Vector3(padding,padding,0)); + mBounds.setMaximum (mBounds.getMaximum() + Vector3(padding,padding,0)); + + float zMin = mBounds.getMinimum().z; + float zMax = mBounds.getMaximum().z; + + // 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. + // Both the cell bounds and the NorthMarker rotation could be changed by the content files or exchanged models. + // If they changed by too much (for bounds, < padding is considered acceptable) then parts of the interior might not + // be covered by the map anymore. + // The following code detects this, and discards the CellStore's fog state if it needs to. + if (cell->getFog()) + { + ESM::FogState* fog = cell->getFog(); + + Ogre::Vector3 newMin (fog->mBounds.mMinX, fog->mBounds.mMinY, zMin); + Ogre::Vector3 newMax (fog->mBounds.mMaxX, fog->mBounds.mMaxY, zMax); + + 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 + || std::abs(mAngle - fog->mNorthMarkerAngle) > Ogre::Degree(5).valueRadians()) + { + // Nuke it + cell->setFog(NULL); + } + else + { + // Looks sane, use it + mBounds = Ogre::AxisAlignedBox(newMin, newMax); + mAngle = fog->mNorthMarkerAngle; + } + } Vector2 center(mBounds.getCenter().x, mBounds.getCenter().y); @@ -179,6 +248,9 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, Vector2 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)); // divide into segments @@ -187,19 +259,96 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, mInteriorName = cell->getCell()->mName; + int i=0; for (int x=0; xgetCell()->mName + "_" + coordStr(x,y); + + render(newcenter.x - center.x, newcenter.y - center.y, zMin, zMax, sSize, sSize, texturePrefix); + + if (!cell->getFog()) + createFogOfWar(texturePrefix); + else + { + ESM::FogState* fog = cell->getFog(); + + // We are using the same bounds and angle as we were using when the textures were originally made. Segments should come out the same. + assert (i < int(fog->mFogTextures.size())); - render(newcenter.x - center.x, newcenter.y - center.y, zMin, zMax, sSize, sSize, - cell->getCell()->mName + "_" + coordStr(x,y)); + ESM::FogTexture& esm = fog->mFogTextures[i]; + loadFogOfWar(texturePrefix, esm); + } + ++i; } } } +void LocalMap::createFogOfWar(const std::string& texturePrefix) +{ + const std::string texName = texturePrefix + "_fog"; + TexturePtr tex = createFogOfWarTexture(texName); + + // create a buffer to use for dynamic operations + std::vector buffer; + + // initialize to (0, 0, 0, 1) + buffer.resize(sFogOfWarResolution*sFogOfWarResolution, (255 << 24)); + + // upload to the texture + memcpy(tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4); + 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_DISCARDABLE); + } + else + tex->unload(); + + 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; + image.load(stream, "tga"); + + assert (image.getWidth() == sFogOfWarResolution && image.getHeight() == sFogOfWarResolution); + + std::string texName = texturePrefix + "_fog"; + + Ogre::TexturePtr tex = createFogOfWarTexture(texName); + + tex->loadImage(image); + + // create a buffer to use for dynamic operations + std::vector buffer; + buffer.resize(sFogOfWarResolution*sFogOfWarResolution); + 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) @@ -249,31 +398,6 @@ void LocalMap::render(const float x, const float y, vp->setMaterialScheme("local_map"); rtt->update(); - - // create "fog of war" texture - TexturePtr tex2 = TextureManager::getSingleton().createManual( - texture + "_fog", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - xw*sFogOfWarResolution/sSize, yw*sFogOfWarResolution/sSize, - 0, - PF_A8R8G8B8, - TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); - - // create a buffer to use for dynamic operations - std::vector buffer; - buffer.resize(sFogOfWarResolution*sFogOfWarResolution); - - // initialize to (0, 0, 0, 1) - for (int p=0; pgetBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4); - tex2->getBuffer()->unlock(); - - mBuffers[texture] = buffer; } mRenderingManager->enableLights(true); @@ -304,6 +428,9 @@ bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interi if (mBuffers.find(texName) == mBuffers.end()) return false; + nX = std::max(0.f, std::min(1.f, nX)); + nY = std::max(0.f, std::min(1.f, nY)); + int texU = (sFogOfWarResolution-1) * nX; int texV = (sFogOfWarResolution-1) * nY; @@ -414,6 +541,8 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni } // copy to the texture + // NOTE: Could be optimized later. We actually only need to update the region that changed. + // Not a big deal at the moment, the FoW is only 32x32 anyway. memcpy(tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &aBuffer[0], sFogOfWarResolution*sFogOfWarResolution*4); tex->getBuffer()->unlock(); } diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 638469d2d..1d480872e 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -11,6 +11,11 @@ namespace MWWorld class CellStore; } +namespace ESM +{ + class FogTexture; +} + namespace MWRender { class RenderingManager; @@ -24,6 +29,11 @@ namespace MWRender LocalMap(OEngine::Render::OgreRenderer*, MWRender::RenderingManager* rendering); ~LocalMap(); + /** + * 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, @@ -54,10 +64,8 @@ namespace MWRender void updatePlayer (const Ogre::Vector3& position, const Ogre::Quaternion& orientation); /** - * Save the fog of war for the current cell to disk. - * @remarks This should be called before loading a - * new cell, as well as when the game is quit. - * @param current cell + * Save the fog of war for this cell to its CellStore. + * @remarks This should be called when unloading a cell, and for all active cells prior to saving the game. */ void saveFogOfWar(MWWorld::CellStore* cell); @@ -104,17 +112,20 @@ namespace MWRender const float xw, const float yw, const std::string& texture); - void saveTexture(const std::string& texname, const std::string& filename); + // Creates a fog of war texture and initializes it to full black + 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); - // a buffer for the "fog of war" texture of the current cell. - // interior cells could be divided into multiple textures, - // so we store in a map. + // 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; - void deleteBuffers(); - bool mInterior; int mCellX, mCellY; Ogre::AxisAlignedBox mBounds; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 19d26a176..948f85b5e 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -216,13 +216,14 @@ OEngine::Render::Fader* RenderingManager::getFader() return mRendering.getFader(); } - MWRender::Camera* RenderingManager::getCamera() const +MWRender::Camera* RenderingManager::getCamera() const { return mCamera; } void RenderingManager::removeCell (MWWorld::CellStore *store) { + mLocalMap->saveFogOfWar(store); mObjects->removeCell(store); mActors->removeCell(store); mDebugging->cellRemoved(store); @@ -671,7 +672,7 @@ void RenderingManager::requestMap(MWWorld::CellStore* cell) mLocalMap->requestMap(cell, mObjects->getDimensions(cell)); } -void RenderingManager::preCellChange(MWWorld::CellStore* cell) +void RenderingManager::writeFog(MWWorld::CellStore* cell) { mLocalMap->saveFogOfWar(cell); } @@ -1057,4 +1058,9 @@ void RenderingManager::spawnEffect(const std::string &model, const std::string & mEffectManager->addEffect(model, texture, worldPosition, scale); } +void RenderingManager::clear() +{ + mLocalMap->clear(); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 423a7078a..eb6827292 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -107,12 +107,15 @@ public: void cellAdded (MWWorld::CellStore *store); void waterAdded(MWWorld::CellStore *store); + /// Clear all savegame-specific data (i.e. fog of war textures) + void clear(); + void enableTerrain(bool enable); void removeWater(); - void preCellChange (MWWorld::CellStore* store); - ///< this event is fired immediately before changing cell + /// Write current fog of war for this cell to the CellStore + void writeFog (MWWorld::CellStore* store); void addObject (const MWWorld::Ptr& ptr); void removeObject (const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 7f2a87eec..3b758f866 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -78,6 +78,7 @@ void MWWorld::Cells::writeCell (ESM::ESMWriter& writer, CellStore& cell) const writer.startRecord (ESM::REC_CSTA); cellState.mId.save (writer); cellState.save (writer); + cell.writeFog(writer); cell.writeReferences (writer); writer.endRecord (ESM::REC_CSTA); } @@ -319,6 +320,9 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, int32_t type, state.load (reader); cellStore->loadState (state); + if (state.mHasFogOfWar) + cellStore->readFog(reader); + if (cellStore->getState()!=CellStore::State_Loaded) cellStore->load (mStore, mReader); diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 1c39d2c07..39f6538bb 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -533,6 +534,21 @@ namespace MWWorld state.mWaterLevel = mWaterLevel; state.mWaterLevel = mWaterLevel; + state.mHasFogOfWar = (mFogState.get() ? 1 : 0); + } + + void CellStore::writeFog(ESM::ESMWriter &writer) const + { + if (mFogState.get()) + { + mFogState->save(writer, mCell->mData.mFlags & ESM::Cell::Interior); + } + } + + void CellStore::readFog(ESM::ESMReader &reader) + { + mFogState.reset(new ESM::FogState()); + mFogState->load(reader); } void CellStore::writeReferences (ESM::ESMWriter& writer) const @@ -697,4 +713,14 @@ namespace MWWorld { return mPathgridGraph.aStarSearch(start, end); } + + void CellStore::setFog(ESM::FogState *fog) + { + mFogState.reset(fog); + } + + ESM::FogState* CellStore::getFog() const + { + return mFogState.get(); + } } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 88b49ed1c..cc3036647 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -3,22 +3,28 @@ #include #include +#include #include "livecellref.hpp" #include "esmstore.hpp" #include "cellreflist.hpp" +#include + #include "../mwmechanics/pathgrid.hpp" // TODO: maybe belongs in mwworld namespace ESM { struct CellState; + struct FogState; } namespace MWWorld { class Ptr; + + /// \brief Mutable state of a cell class CellStore { @@ -31,6 +37,11 @@ namespace MWWorld private: + // Even though fog actually belongs to the player and not cells, + // it makes sense to store it here since we need it once for each cell. + // Note this is NULL until the cell is explored to save some memory + boost::shared_ptr mFogState; + const ESM::Cell *mCell; State mState; bool mHasState; @@ -84,6 +95,11 @@ namespace MWWorld void setWaterLevel (float level); + void setFog (ESM::FogState* fog); + ///< \note Takes ownership of the pointer + + ESM::FogState* getFog () const; + int count() const; ///< Return total number of references, including deleted ones. @@ -134,6 +150,10 @@ namespace MWWorld void saveState (ESM::CellState& state) const; + void writeFog (ESM::ESMWriter& writer) const; + + void readFog (ESM::ESMReader& reader); + void writeReferences (ESM::ESMWriter& writer) const; void readReferences (ESM::ESMReader& reader, const std::map& contentFileMap); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index de9c8f04a..ba36d4a86 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -231,6 +231,8 @@ namespace MWWorld void World::clear() { + mRendering->clear(); + mLocalScripts.clear(); mPlayer->clear(); @@ -277,6 +279,14 @@ namespace MWWorld void World::write (ESM::ESMWriter& writer, Loading::Listener& progress) const { + // Active cells could have a dirty fog of war, sync it to the CellStore first + for (Scene::CellStoreCollection::const_iterator iter (mWorldScene->getActiveCells().begin()); + iter!=mWorldScene->getActiveCells().end(); ++iter) + { + CellStore* cellstore = *iter; + mRendering->writeFog(cellstore); + } + mCells.write (writer, progress); mStore.write (writer, progress); mGlobalVariables.write (writer, progress); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 1c60dfb83..3dd5df295 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -45,7 +45,7 @@ add_component_dir (esm loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate - npcstats creaturestats weatherstate quickkeys + npcstats creaturestats weatherstate quickkeys fogstate ) add_component_dir (misc diff --git a/components/esm/cellstate.cpp b/components/esm/cellstate.cpp index 1f7e8197e..541a359c6 100644 --- a/components/esm/cellstate.cpp +++ b/components/esm/cellstate.cpp @@ -8,10 +8,15 @@ void ESM::CellState::load (ESMReader &esm) { mWaterLevel = 0; esm.getHNOT (mWaterLevel, "WLVL"); + + mHasFogOfWar = false; + esm.getHNOT (mHasFogOfWar, "HFOW"); } void ESM::CellState::save (ESMWriter &esm) const { if (!mId.mPaged) esm.writeHNT ("WLVL", mWaterLevel); -} \ No newline at end of file + + esm.writeHNT("HFOW", mHasFogOfWar); +} diff --git a/components/esm/cellstate.hpp b/components/esm/cellstate.hpp index cd0db3067..88918a3ab 100644 --- a/components/esm/cellstate.hpp +++ b/components/esm/cellstate.hpp @@ -17,9 +17,11 @@ namespace ESM float mWaterLevel; + int mHasFogOfWar; // Do we have fog of war state (0 or 1)? (see fogstate.hpp) + void load (ESMReader &esm); void save (ESMWriter &esm) const; }; } -#endif \ No newline at end of file +#endif diff --git a/components/esm/fogstate.cpp b/components/esm/fogstate.cpp new file mode 100644 index 000000000..18235066d --- /dev/null +++ b/components/esm/fogstate.cpp @@ -0,0 +1,40 @@ +#include "fogstate.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +void ESM::FogState::load (ESMReader &esm) +{ + esm.getHNOT(mBounds, "BOUN"); + esm.getHNOT(mNorthMarkerAngle, "ANGL"); + while (esm.isNextSub("FTEX")) + { + esm.getSubHeader(); + FogTexture tex; + + esm.getT(tex.mX); + esm.getT(tex.mY); + + size_t imageSize = esm.getSubSize()-sizeof(int)*2; + tex.mImageData.resize(imageSize); + esm.getExact(&tex.mImageData[0], imageSize); + mFogTextures.push_back(tex); + } +} + +void ESM::FogState::save (ESMWriter &esm, bool interiorCell) const +{ + if (interiorCell) + { + esm.writeHNT("BOUN", mBounds); + esm.writeHNT("ANGL", mNorthMarkerAngle); + } + for (std::vector::const_iterator it = mFogTextures.begin(); it != mFogTextures.end(); ++it) + { + esm.startSubRecord("FTEX"); + esm.writeT(it->mX); + esm.writeT(it->mY); + esm.write(&it->mImageData[0], it->mImageData.size()); + esm.endRecord("FTEX"); + } +} diff --git a/components/esm/fogstate.hpp b/components/esm/fogstate.hpp new file mode 100644 index 000000000..4a5619e51 --- /dev/null +++ b/components/esm/fogstate.hpp @@ -0,0 +1,38 @@ +#ifndef OPENMW_ESM_FOGSTATE_H +#define OPENMW_ESM_FOGSTATE_H + +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + struct FogTexture + { + int mX, mY; // Only used for interior cells + std::vector mImageData; + }; + + // format 0, saved games only + // Fog of war state + struct FogState + { + // Only used for interior cells + float mNorthMarkerAngle; + struct Bounds + { + float mMinX; + float mMinY; + float mMaxX; + float mMaxY; + } mBounds; + + std::vector mFogTextures; + + void load (ESMReader &esm); + void save (ESMWriter &esm, bool interiorCell) const; + }; +} + +#endif From c98bea2a8807f86bfd0d802c1de54b58ff62e912 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 May 2014 02:27:43 +0200 Subject: [PATCH 09/10] Moved local map update to LocalMap::updatePlayer to fix a brief desync on cell transitions due to sFogOfWarSkip --- apps/openmw/mwbase/windowmanager.hpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 8 +++----- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ++-- apps/openmw/mwrender/localmap.cpp | 5 +---- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 9e5230af6..39cfc47ed 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -200,8 +200,8 @@ namespace MWBase virtual bool getFullHelp() const = 0; - virtual void setInteriorMapTexture(const int x, const int y) = 0; - ///< set the index of the map texture that should be used (for interiors) + virtual void setActiveMap(int x, int y, bool interior) = 0; + ///< set the indices of the map texture that should be used /// sets the visibility of the drowning bar virtual void setDrowningBarVisibility(bool visible) = 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6a15c8e33..e3baf84fb 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -766,8 +766,6 @@ namespace MWGui mMap->setCellPrefix("Cell"); mHud->setCellPrefix("Cell"); - mMap->setActiveCell (cell->getCell()->getGridX(), cell->getCell()->getGridY()); - mHud->setActiveCell (cell->getCell()->getGridX(), cell->getCell()->getGridY()); } else { @@ -783,10 +781,10 @@ namespace MWGui } } - void WindowManager::setInteriorMapTexture(const int x, const int y) + void WindowManager::setActiveMap(int x, int y, bool interior) { - mMap->setActiveCell(x,y, true); - mHud->setActiveCell(x,y, true); + mMap->setActiveCell(x,y, interior); + mHud->setActiveCell(x,y, interior); } void WindowManager::setPlayerPos(const float x, const float y) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index e31013b45..7617a4463 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -192,8 +192,8 @@ namespace MWGui virtual void toggleFullHelp(); ///< show extra info in item tooltips (owner, script) virtual bool getFullHelp() const; - virtual void setInteriorMapTexture(const int x, const int y); - ///< set the index of the map texture that should be used (for interiors) + virtual void setActiveMap(int x, int y, bool interior); + ///< set the indices of the map texture that should be used /// sets the visibility of the drowning bar virtual void setDrowningBarVisibility(bool visible); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 41885da33..e1694d892 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -466,10 +466,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni mCellX = x; mCellY = y; } - else - { - MWBase::Environment::get().getWindowManager()->setInteriorMapTexture(x,y); - } + MWBase::Environment::get().getWindowManager()->setActiveMap(x,y,mInterior); // convert from world coordinates to texture UV coordinates std::string texBaseName; From c39a0368cf4150afbe64295aadcd9ae3c2a5f041 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 11 May 2014 02:38:39 +0200 Subject: [PATCH 10/10] Bug #618: Make local map textures static in an attempt to fix the disappearing maps with D3D. Also removed problematic DISCARDABLE flag for fog of war textures. --- apps/openmw/mwrender/localmap.cpp | 43 +++++++++++++++++++------------ apps/openmw/mwrender/localmap.hpp | 5 +++- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index e1694d892..56b2326ec 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -44,6 +44,24 @@ LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManag mLight->setDirection (Ogre::Vector3(0.3, 0.3, -0.7)); mLight->setVisible (false); mLight->setDiffuseColour (ColourValue(0.7,0.7,0.7)); + + mRenderTexture = TextureManager::getSingleton().createManual( + "localmap/rtt", + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + TEX_TYPE_2D, + sMapResolution, sMapResolution, + 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->setVisibilityMask(RV_Map); + vp->setMaterialScheme("local_map"); } LocalMap::~LocalMap() @@ -318,7 +336,7 @@ Ogre::TexturePtr LocalMap::createFogOfWarTexture(const std::string &texName) sFogOfWarResolution, sFogOfWarResolution, 0, PF_A8R8G8B8, - TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); + TU_DYNAMIC_WRITE_ONLY); } else tex->unload(); @@ -378,26 +396,17 @@ void LocalMap::render(const float x, const float y, if (tex.isNull()) { // render - tex = TextureManager::getSingleton().createManual( + 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, - xw*sMapResolution/sSize, yw*sMapResolution/sSize, + sMapResolution, sMapResolution, 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(RV_Map); - vp->setMaterialScheme("local_map"); - - rtt->update(); + PF_R8G8B8); + tex->getBuffer()->blit(mRenderTexture->getBuffer()); } mRenderingManager->enableLights(true); diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 1d480872e..941171527 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -84,7 +84,6 @@ namespace MWRender OEngine::Render::OgreRenderer* mRendering; MWRender::RenderingManager* mRenderingManager; - // 1024*1024 pixels for a cell static const int sMapResolution = 512; // the dynamic texture is a bottleneck, so don't set this too high @@ -126,6 +125,10 @@ namespace MWRender // Both interior and exterior maps are possibly divided into multiple textures. std::map > mBuffers; + // The render texture we will use to create the map images + Ogre::TexturePtr mRenderTexture; + Ogre::RenderTarget* mRenderTarget; + bool mInterior; int mCellX, mCellY; Ogre::AxisAlignedBox mBounds;