From 80b7dec57159d04d06bcec3fe410e526146c0420 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 15 Jul 2023 22:45:05 +0300 Subject: [PATCH] Prevent object paging from leaking Vvardenfell into other exteriors --- apps/openmw/mwrender/objectpaging.cpp | 53 ++++++++++++++++------- apps/openmw/mwrender/objectpaging.hpp | 10 ++++- apps/openmw/mwrender/renderingmanager.cpp | 3 +- 3 files changed, 48 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 4e964b7e6d..c3c473de6b 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -453,8 +453,9 @@ namespace MWRender } }; - ObjectPaging::ObjectPaging(Resource::SceneManager* sceneManager) + ObjectPaging::ObjectPaging(Resource::SceneManager* sceneManager, ESM::RefId worldspace) : GenericResourceManager(nullptr) + , Terrain::QuadTreeWorld::ChunkManager(worldspace) , mSceneManager(sceneManager) , mRefTrackerLocked(false) { @@ -466,19 +467,11 @@ namespace MWRender mMinSizeCostMultiplier = Settings::Manager::getFloat("object paging min size cost multiplier", "Terrain"); } - osg::ref_ptr ObjectPaging::createChunk(float size, const osg::Vec2f& center, bool activeGrid, - const osg::Vec3f& viewPoint, bool compile, unsigned char lod) + std::map ObjectPaging::collectESM3References( + float size, const osg::Vec2i& startCell, ESM::ReadersCache& readers) const { - osg::Vec2i startCell = osg::Vec2i(std::floor(center.x() - size / 2.f), std::floor(center.y() - size / 2.f)); - - osg::Vec3f worldCenter = osg::Vec3f(center.x(), center.y(), 0) * ESM::Land::REAL_SIZE; - osg::Vec3f relativeViewPoint = viewPoint - worldCenter; - std::map refs; - ESM::ReadersCache readers; - const auto& world = MWBase::Environment::get().getWorld(); - const auto& store = world->getStore(); - + const auto& store = MWBase::Environment::get().getWorld()->getStore(); for (int cellX = startCell.x(); cellX < startCell.x() + size; ++cellX) { for (int cellY = startCell.y(); cellY < startCell.y() + size; ++cellY) @@ -537,6 +530,30 @@ namespace MWRender } } } + return refs; + } + + osg::ref_ptr ObjectPaging::createChunk(float size, const osg::Vec2f& center, bool activeGrid, + const osg::Vec3f& viewPoint, bool compile, unsigned char lod) + { + osg::Vec2i startCell = osg::Vec2i(std::floor(center.x() - size / 2.f), std::floor(center.y() - size / 2.f)); + + osg::Vec3f worldCenter = osg::Vec3f(center.x(), center.y(), 0) * getCellSize(mWorldspace); + osg::Vec3f relativeViewPoint = viewPoint - worldCenter; + + std::map refs; + ESM::ReadersCache readers; + const auto& world = MWBase::Environment::get().getWorld(); + const auto& store = world->getStore(); + + if (mWorldspace == ESM::Cell::sDefaultWorldspaceId) + { + refs = collectESM3References(size, startCell, readers); + } + else + { + // TODO + } if (activeGrid) { @@ -563,11 +580,12 @@ namespace MWRender // Since ObjectPaging does not handle VisController, we can just ignore both types of nodes. constexpr auto copyMask = ~Mask_UpdateVisitor; - const auto smallestDistanceToChunk = (size > 1 / 8.f) ? (size * ESM::Land::REAL_SIZE) : 0.f; + auto cellSize = getCellSize(mWorldspace); + const auto smallestDistanceToChunk = (size > 1 / 8.f) ? (size * cellSize) : 0.f; const auto higherDistanceToChunk = [&] { if (!activeGrid) return smallestDistanceToChunk + 1; - return ((size < 1) ? 5 : 3) * ESM::Land::REAL_SIZE * size + 1; + return ((size < 1) ? 5 : 3) * cellSize * size + 1; }(); AnalyzeVisitor analyzeVisitor(copyMask); @@ -581,7 +599,7 @@ namespace MWRender osg::Vec3f pos = ref.mPos.asVec3(); if (size < 1.f) { - osg::Vec3f cellPos = pos / ESM::Land::REAL_SIZE; + osg::Vec3f cellPos = pos / cellSize; if ((minBound.x() > std::floor(minBound.x()) && cellPos.x() < minBound.x()) || (minBound.y() > std::floor(minBound.y()) && cellPos.y() < minBound.y()) || (maxBound.x() < std::ceil(maxBound.x()) && cellPos.x() >= maxBound.x()) @@ -858,7 +876,7 @@ namespace MWRender { if (mActiveGridOnly && !std::get<2>(id)) return false; - pos /= ESM::Land::REAL_SIZE; + pos /= getCellSize(mWorldspace); clampToCell(pos); osg::Vec2f center = std::get<0>(id); float halfSize = std::get<1>(id) / 2; @@ -872,6 +890,7 @@ namespace MWRender } osg::Vec3f mPosition; osg::Vec2i mCell; + ESM::RefId mWorldspace; std::set mToClear; bool mActiveGridOnly = false; }; @@ -895,6 +914,7 @@ namespace MWRender ClearCacheFunctor ccf; ccf.mPosition = pos; ccf.mCell = cell; + ccf.mWorldspace = mWorldspace; mCache->call(ccf); if (ccf.mToClear.empty()) return false; @@ -921,6 +941,7 @@ namespace MWRender ccf.mPosition = pos; ccf.mCell = cell; ccf.mActiveGridOnly = true; + ccf.mWorldspace = mWorldspace; mCache->call(ccf); if (ccf.mToClear.empty()) return false; diff --git a/apps/openmw/mwrender/objectpaging.hpp b/apps/openmw/mwrender/objectpaging.hpp index ff84534c30..d677c172f2 100644 --- a/apps/openmw/mwrender/objectpaging.hpp +++ b/apps/openmw/mwrender/objectpaging.hpp @@ -16,6 +16,11 @@ namespace MWWorld class ESMStore; } +namespace ESM +{ + class ReadersCache; +} + namespace MWRender { @@ -24,7 +29,7 @@ namespace MWRender class ObjectPaging : public Resource::GenericResourceManager, public Terrain::QuadTreeWorld::ChunkManager { public: - ObjectPaging(Resource::SceneManager* sceneManager); + ObjectPaging(Resource::SceneManager* sceneManager, ESM::RefId worldspace); ~ObjectPaging() = default; osg::ref_ptr getChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags, @@ -78,6 +83,9 @@ namespace MWRender const RefTracker& getRefTracker() const { return mRefTracker; } RefTracker& getWritableRefTracker() { return mRefTrackerLocked ? mRefTrackerNew : mRefTracker; } + std::map collectESM3References( + float size, const osg::Vec2i& startCell, ESM::ReadersCache& readers) const; + std::mutex mSizeCacheMutex; typedef std::map SizeCache; SizeCache mSizeCache; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7fa0b40fc3..f9058fa18a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1342,7 +1342,8 @@ namespace MWRender lodFactor, vertexLodMod, maxCompGeometrySize, debugChunks, worldspace); if (Settings::Manager::getBool("object paging", "Terrain")) { - newChunkMgr.mObjectPaging = std::make_unique(mResourceSystem->getSceneManager()); + newChunkMgr.mObjectPaging + = std::make_unique(mResourceSystem->getSceneManager(), worldspace); quadTreeWorld->addChunkManager(newChunkMgr.mObjectPaging.get()); mResourceSystem->addResourceManager(newChunkMgr.mObjectPaging.get()); }