From 6a3d27ce82128e9b257868f7cd21450b8472cca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Mocquillon?= Date: Wed, 31 Aug 2022 22:02:19 +0200 Subject: [PATCH] Add a dictionary to retrieve the LOD mesh name of a mesh cache --- apps/openmw/mwrender/objectpaging.cpp | 16 +++++++- apps/openmw/mwrender/objectpaging.hpp | 7 +++- components/misc/pathhelpers.hpp | 7 +++- components/misc/resourcehelpers.cpp | 37 +++++++++++++++++++ components/misc/resourcehelpers.hpp | 1 + .../reference/modding/settings/terrain.rst | 9 +++++ files/settings-default.cfg | 3 ++ 7 files changed, 76 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 53af609a71..563d2ce23c 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -76,6 +76,7 @@ namespace MWRender osg::ref_ptr ObjectPaging::getChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags, bool activeGrid, const osg::Vec3f& viewPoint, bool compile) { + lod = static_cast(lodFlags >> (4 * 4)); if (activeGrid && !mActiveGrid) return nullptr; @@ -86,7 +87,7 @@ namespace MWRender return static_cast(obj.get()); else { - osg::ref_ptr node = createChunk(size, center, activeGrid, viewPoint, compile); + osg::ref_ptr node = createChunk(size, center, activeGrid, viewPoint, compile, lod); mCache->addEntryToObjectCache(id, node.get()); return node; } @@ -411,7 +412,7 @@ 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) + 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)); @@ -548,6 +549,17 @@ namespace MWRender } } + if (!activeGrid) + { + std::lock_guard lock(mLODNameCacheMutex); + LODNameCacheKey key{ model, lod }; + LODNameCache::const_iterator found = mLODNameCache.lower_bound(key); + if (found != mLODNameCache.end() && found->first == key) + model = found->second; + else + model = mLODNameCache.insert(found, { key, Misc::ResourceHelpers::getLODMeshName(model, mSceneManager->getVFS(), lod) })->second; + } + osg::ref_ptr cnode = mSceneManager->getTemplate(model, false); if (activeGrid) diff --git a/apps/openmw/mwrender/objectpaging.hpp b/apps/openmw/mwrender/objectpaging.hpp index 4820f150ab..246cef178f 100644 --- a/apps/openmw/mwrender/objectpaging.hpp +++ b/apps/openmw/mwrender/objectpaging.hpp @@ -29,7 +29,7 @@ namespace MWRender osg::ref_ptr getChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags, bool activeGrid, const osg::Vec3f& viewPoint, bool compile) override; - osg::ref_ptr createChunk(float size, const osg::Vec2f& center, bool activeGrid, const osg::Vec3f& viewPoint, bool compile); + osg::ref_ptr createChunk(float size, const osg::Vec2f& center, bool activeGrid, const osg::Vec3f& viewPoint, bool compile, unsigned char lod); unsigned int getNodeMask() override; @@ -75,6 +75,11 @@ namespace MWRender std::mutex mSizeCacheMutex; typedef std::map SizeCache; SizeCache mSizeCache; + + std::mutex mLODNameCacheMutex; + typedef std::pair LODNameCacheKey; //Key: mesh name, lod level + typedef std::map LODNameCache; //Cache: key, mesh name to use + LODNameCache mLODNameCache; }; class RefnumMarker : public osg::Object diff --git a/components/misc/pathhelpers.hpp b/components/misc/pathhelpers.hpp index ee6ba8e0d5..5a6d3feb55 100644 --- a/components/misc/pathhelpers.hpp +++ b/components/misc/pathhelpers.hpp @@ -5,9 +5,14 @@ namespace Misc { + inline size_t findExtension(std::string_view file) + { + return file.find_last_of('.'); + } + inline std::string_view getFileExtension(std::string_view file) { - if (auto extPos = file.find_last_of('.'); extPos != std::string::npos) + if (auto extPos = findExtension(file); extPos != std::string::npos) { file.remove_prefix(extPos + 1); return file; diff --git a/components/misc/resourcehelpers.cpp b/components/misc/resourcehelpers.cpp index 6c8a732c78..aa19855ae1 100644 --- a/components/misc/resourcehelpers.cpp +++ b/components/misc/resourcehelpers.cpp @@ -4,9 +4,11 @@ #include #include +#include #include #include +#include #include namespace @@ -164,3 +166,38 @@ bool Misc::ResourceHelpers::isHiddenMarker(std::string_view id) { return Misc::StringUtils::ciEqual(id, "prisonmarker") || Misc::StringUtils::ciEqual(id, "divinemarker") || Misc::StringUtils::ciEqual(id, "templemarker") || Misc::StringUtils::ciEqual(id, "northmarker"); } + +namespace +{ +std::string getLODMeshNameImpl(std::string resPath, const VFS::Manager* vfs, std::string_view pattern) +{ + if (auto w = Misc::findExtension(resPath); w != std::string::npos) + resPath.insert(w, pattern); + return vfs->normalizeFilename(resPath); +} + +std::string getBestLODMeshName(std::string const& resPath, const VFS::Manager* vfs, std::string_view pattern) +{ + if (const auto& result = getLODMeshNameImpl(resPath, vfs, pattern); vfs->exists(result)) + return result; + return resPath; +} +} + +std::string Misc::ResourceHelpers::getLODMeshName(std::string resPath, const VFS::Manager* vfs, unsigned char lod) +{ + static const std::string distantMeshPattern = Settings::Manager::getString("distant mesh pattern", "Terrain"); + std::string meshName = getBestLODMeshName(resPath, vfs, distantMeshPattern + "_" + std::to_string(lod)); + if (meshName != resPath) + return meshName; + + for (char l = lod; l >= 0; --l) + { + std::stringstream patern; + patern << distantMeshPattern << "_" << int(l); + meshName = getBestLODMeshName(resPath, vfs, patern.str()); + if (meshName != resPath) + return meshName; + } + return getBestLODMeshName(resPath, vfs, distantMeshPattern); +} diff --git a/components/misc/resourcehelpers.hpp b/components/misc/resourcehelpers.hpp index 18a69c9419..537c05c462 100644 --- a/components/misc/resourcehelpers.hpp +++ b/components/misc/resourcehelpers.hpp @@ -30,6 +30,7 @@ namespace Misc /// marker objects that have a hardcoded function in the game logic, should be hidden from the player bool isHiddenMarker(std::string_view id); + std::string getLODMeshName(std::string resPath, const VFS::Manager* vfs, unsigned char lod = 0); } } diff --git a/docs/source/reference/modding/settings/terrain.rst b/docs/source/reference/modding/settings/terrain.rst index 0aa7d9bd1b..dfcf225f1a 100644 --- a/docs/source/reference/modding/settings/terrain.rst +++ b/docs/source/reference/modding/settings/terrain.rst @@ -205,3 +205,12 @@ object paging min size cost multiplier This setting adjusts the calculated cost of merging an object used in the mentioned functionality. The larger this value is, the less expensive objects can be before they are discarded. See the formula above to figure out the math. + +distant mesh pattern +------------------ + +:Type: string +:Range: +:Default: _dist + +The mesh filename pattern to look for when detecting distant meshes (it will replace original mesh outside active grid) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 8a6fc40fd7..f3cc953967 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -119,6 +119,9 @@ object paging min size merge factor = 0.3 # Controls how inexpensive an object needs to be to utilize 'min size merge factor'. object paging min size cost multiplier = 25 +# The mesh filename pattern to look for when detecting distant meshes (it will replace original mesh outside active grid) +distant mesh pattern = _dist + [Fog] # If true, use extended fog parameters for distant terrain not controlled by