diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 6453889bcf..8a80153728 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -171,7 +171,7 @@ namespace MWRender osg::Vec3f worldCenter = osg::Vec3f(center.x(), center.y(), 0)*ESM::Land::REAL_SIZE; osg::Vec3f relativeViewPoint = viewPoint - worldCenter; - std::vector refs; + std::map refs; std::vector esm; const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); @@ -197,8 +197,8 @@ namespace MWRender if (std::find(cell->mMovedRefs.begin(), cell->mMovedRefs.end(), ref.mRefNum) != cell->mMovedRefs.end()) continue; int type = store.findStatic(Misc::StringUtils::lowerCase(ref.mRefID)); if (!typeFilter(type,size>=2)) continue; - if (deleted) continue; - refs.push_back(ref); + if (deleted) { refs.erase(ref.mRefNum); continue; } + refs[ref.mRefNum] = ref; } } catch (std::exception& e) @@ -210,18 +210,25 @@ namespace MWRender { ESM::CellRef ref = it->first; bool deleted = it->second; - if (deleted) continue; + if (deleted) { refs.erase(ref.mRefNum); continue; } int type = store.findStatic(Misc::StringUtils::lowerCase(ref.mRefID)); if (!typeFilter(type,size>=2)) continue; - refs.push_back(ref); + refs[ref.mRefNum] = ref; } } } + { + OpenThreads::ScopedLock lock(mDisabledMutex); + for (auto disabled : mDisabled) + refs.erase(disabled); + } + osg::Vec2f minBound = (center - osg::Vec2f(size/2.f, size/2.f)); osg::Vec2f maxBound = (center + osg::Vec2f(size/2.f, size/2.f)); - for (const ESM::CellRef& ref : refs) + for (const auto& pair : refs) { + const ESM::CellRef& ref = pair.second; std::string id = Misc::StringUtils::lowerCase(ref.mRefID); if (id == "prisonmarker" || id == "divinemarker" || id == "templemarker" || id == "northmarker") continue; // marker objects that have a hardcoded function in the game logic, should be hidden from the player @@ -299,4 +306,16 @@ namespace MWRender return Mask_Static; } + void ObjectPaging::enableObject(const ESM::RefNum & refnum, bool enabled) + { + OpenThreads::ScopedLock lock(mDisabledMutex); + if (enabled) mDisabled.erase(refnum); + else mDisabled.insert(refnum); + } + + void ObjectPaging::clear() + { + OpenThreads::ScopedLock lock(mDisabledMutex); + mDisabled.clear(); + } } diff --git a/apps/openmw/mwrender/objectpaging.hpp b/apps/openmw/mwrender/objectpaging.hpp index 6d66d078df..8c3c2b4935 100644 --- a/apps/openmw/mwrender/objectpaging.hpp +++ b/apps/openmw/mwrender/objectpaging.hpp @@ -5,6 +5,8 @@ #include #include +#include + namespace Resource { class SceneManager; @@ -33,10 +35,16 @@ namespace MWRender virtual unsigned int getNodeMask() override; + void enableObject(const ESM::RefNum & refnum, bool enabled); + void clear(); + private: Resource::SceneManager* mSceneManager; bool mMergeGeometry; float mMinSize; + + OpenThreads::Mutex mDisabledMutex; + std::set mDisabled; }; } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 9c92da767a..41cfc56a4d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1119,6 +1119,8 @@ namespace MWRender mSky->setMoonColour(false); notifyWorldSpaceChanged(); + if (mObjectPaging) + mObjectPaging->clear(); } MWRender::Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) @@ -1480,4 +1482,9 @@ namespace MWRender { mTerrain->setActiveGrid(grid); } + void RenderingManager::pagingEnableObject(const ESM::RefNum & refnum, bool enabled) + { + if (mObjectPaging) + mObjectPaging->enableObject(refnum, enabled); + } } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index dff76f95ec..6bf122232f 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -42,6 +42,7 @@ namespace osgViewer namespace ESM { struct Cell; + struct RefNum; } namespace Terrain @@ -240,6 +241,8 @@ namespace MWRender void setActiveGrid(const osg::Vec4i &grid); + void pagingEnableObject(const ESM::RefNum & refnum, bool enabled); + private: void updateProjectionMatrix(); void updateTextureFiltering(); diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 599f345b8a..6b737f2029 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -106,7 +106,7 @@ namespace template void readReferenceCollection (ESM::ESMReader& reader, - MWWorld::CellRefList& collection, const ESM::CellRef& cref, const std::map& contentFileMap) + MWWorld::CellRefList& collection, const ESM::CellRef& cref, const std::map& contentFileMap, MWWorld::CellStore* cellstore) { const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); @@ -142,6 +142,11 @@ namespace { // overwrite existing reference iter->load (state); + if (!iter->mData.isEnabled()) + { + iter->mData.enable(); + MWBase::Environment::get().getWorld()->disable(MWWorld::Ptr(&*iter, cellstore)); + } return; } @@ -809,107 +814,107 @@ namespace MWWorld { case ESM::REC_ACTI: - readReferenceCollection (reader, mActivators, cref, contentFileMap); + readReferenceCollection (reader, mActivators, cref, contentFileMap, this); break; case ESM::REC_ALCH: - readReferenceCollection (reader, mPotions, cref, contentFileMap); + readReferenceCollection (reader, mPotions, cref, contentFileMap, this); break; case ESM::REC_APPA: - readReferenceCollection (reader, mAppas, cref, contentFileMap); + readReferenceCollection (reader, mAppas, cref, contentFileMap, this); break; case ESM::REC_ARMO: - readReferenceCollection (reader, mArmors, cref, contentFileMap); + readReferenceCollection (reader, mArmors, cref, contentFileMap, this); break; case ESM::REC_BOOK: - readReferenceCollection (reader, mBooks, cref, contentFileMap); + readReferenceCollection (reader, mBooks, cref, contentFileMap, this); break; case ESM::REC_CLOT: - readReferenceCollection (reader, mClothes, cref, contentFileMap); + readReferenceCollection (reader, mClothes, cref, contentFileMap, this); break; case ESM::REC_CONT: - readReferenceCollection (reader, mContainers, cref, contentFileMap); + readReferenceCollection (reader, mContainers, cref, contentFileMap, this); break; case ESM::REC_CREA: - readReferenceCollection (reader, mCreatures, cref, contentFileMap); + readReferenceCollection (reader, mCreatures, cref, contentFileMap, this); break; case ESM::REC_DOOR: - readReferenceCollection (reader, mDoors, cref, contentFileMap); + readReferenceCollection (reader, mDoors, cref, contentFileMap, this); break; case ESM::REC_INGR: - readReferenceCollection (reader, mIngreds, cref, contentFileMap); + readReferenceCollection (reader, mIngreds, cref, contentFileMap, this); break; case ESM::REC_LEVC: - readReferenceCollection (reader, mCreatureLists, cref, contentFileMap); + readReferenceCollection (reader, mCreatureLists, cref, contentFileMap, this); break; case ESM::REC_LEVI: - readReferenceCollection (reader, mItemLists, cref, contentFileMap); + readReferenceCollection (reader, mItemLists, cref, contentFileMap, this); break; case ESM::REC_LIGH: - readReferenceCollection (reader, mLights, cref, contentFileMap); + readReferenceCollection (reader, mLights, cref, contentFileMap, this); break; case ESM::REC_LOCK: - readReferenceCollection (reader, mLockpicks, cref, contentFileMap); + readReferenceCollection (reader, mLockpicks, cref, contentFileMap, this); break; case ESM::REC_MISC: - readReferenceCollection (reader, mMiscItems, cref, contentFileMap); + readReferenceCollection (reader, mMiscItems, cref, contentFileMap, this); break; case ESM::REC_NPC_: - readReferenceCollection (reader, mNpcs, cref, contentFileMap); + readReferenceCollection (reader, mNpcs, cref, contentFileMap, this); break; case ESM::REC_PROB: - readReferenceCollection (reader, mProbes, cref, contentFileMap); + readReferenceCollection (reader, mProbes, cref, contentFileMap, this); break; case ESM::REC_REPA: - readReferenceCollection (reader, mRepairs, cref, contentFileMap); + readReferenceCollection (reader, mRepairs, cref, contentFileMap, this); break; case ESM::REC_STAT: - readReferenceCollection (reader, mStatics, cref, contentFileMap); + readReferenceCollection (reader, mStatics, cref, contentFileMap, this); break; case ESM::REC_WEAP: - readReferenceCollection (reader, mWeapons, cref, contentFileMap); + readReferenceCollection (reader, mWeapons, cref, contentFileMap, this); break; case ESM::REC_BODY: - readReferenceCollection (reader, mBodyParts, cref, contentFileMap); + readReferenceCollection (reader, mBodyParts, cref, contentFileMap, this); break; default: diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c51266bab6..0817a42263 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -814,6 +814,9 @@ namespace MWWorld if(mWorldScene->getActiveCells().find (reference.getCell()) != mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) mWorldScene->addObjectToScene (reference); + + if (reference.getCellRef().getRefNum().hasContentFile()) + mRendering->pagingEnableObject(reference.getCellRef().getRefNum(), true); } } @@ -838,20 +841,23 @@ namespace MWWorld void World::disable (const Ptr& reference) { + if (!reference.getRefData().isEnabled()) + return; + // disable is a no-op for items in containers if (!reference.isInCell()) return; - if (reference.getRefData().isEnabled()) - { - if (reference == getPlayerPtr()) - throw std::runtime_error("can not disable player object"); + if (reference == getPlayerPtr()) + throw std::runtime_error("can not disable player object"); - reference.getRefData().disable(); + reference.getRefData().disable(); - if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) - mWorldScene->removeObjectFromScene (reference); - } + if (reference.getCellRef().getRefNum().hasContentFile()) + mRendering->pagingEnableObject(reference.getCellRef().getRefNum(), false); + + if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) + mWorldScene->removeObjectFromScene (reference); } void World::advanceTime (double hours, bool incremental)