Use normalized path for groundcover

pull/3236/head
elsid 3 months ago
parent a50f857eb1
commit d1ccb4b804
No known key found for this signature in database
GPG Key ID: 4DE04C198CBA7625

@ -1,5 +1,7 @@
#include "groundcover.hpp"
#include <span>
#include <osg/AlphaFunc>
#include <osg/BlendFunc>
#include <osg/ComputeBoundsVisitor>
@ -46,13 +48,13 @@ namespace MWRender
class InstancedComputeNearFarCullCallback : public osg::DrawableCullCallback
{
public:
InstancedComputeNearFarCullCallback(const std::vector<Groundcover::GroundcoverEntry>& instances,
explicit InstancedComputeNearFarCullCallback(std::span<const Groundcover::GroundcoverEntry> instances,
const osg::Vec3& chunkPosition, const osg::BoundingBox& instanceBounds)
: mInstanceMatrices()
, mInstanceBounds(instanceBounds)
{
mInstanceMatrices.reserve(instances.size());
for (const auto& instance : instances)
for (const Groundcover::GroundcoverEntry& instance : instances)
mInstanceMatrices.emplace_back(computeInstanceMatrix(instance, chunkPosition));
}
@ -191,7 +193,8 @@ namespace MWRender
class InstancingVisitor : public osg::NodeVisitor
{
public:
InstancingVisitor(std::vector<Groundcover::GroundcoverEntry>& instances, osg::Vec3f& chunkPosition)
explicit InstancingVisitor(
std::span<const Groundcover::GroundcoverEntry> instances, osg::Vec3f& chunkPosition)
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
, mInstances(instances)
, mChunkPosition(chunkPosition)
@ -252,7 +255,7 @@ namespace MWRender
}
private:
std::vector<Groundcover::GroundcoverEntry> mInstances;
std::span<const Groundcover::GroundcoverEntry> mInstances;
osg::Vec3f mChunkPosition;
};
@ -411,12 +414,15 @@ namespace MWRender
}
}
for (auto& pair : refs)
for (auto& [refNum, cellRef] : refs)
{
ESM::CellRef& ref = pair.second;
const std::string& model = mGroundcoverStore.getGroundcoverModel(ref.mRefID);
if (!model.empty())
instances[model].emplace_back(std::move(ref));
const VFS::Path::NormalizedView model = mGroundcoverStore.getGroundcoverModel(cellRef.mRefID);
if (model.empty())
continue;
auto it = instances.find(model);
if (it == instances.end())
it = instances.emplace_hint(it, VFS::Path::Normalized(model), std::vector<GroundcoverEntry>());
it->second.emplace_back(std::move(cellRef));
}
}
}
@ -426,9 +432,9 @@ namespace MWRender
{
osg::ref_ptr<osg::Group> group = new osg::Group;
osg::Vec3f worldCenter = osg::Vec3f(center.x(), center.y(), 0) * ESM::Land::REAL_SIZE;
for (auto& pair : instances)
for (const auto& [model, entries] : instances)
{
const osg::Node* temp = mSceneManager->getTemplate(VFS::Path::toNormalized(pair.first));
const osg::Node* temp = mSceneManager->getTemplate(model);
osg::ref_ptr<osg::Node> node = static_cast<osg::Node*>(temp->clone(osg::CopyOp::DEEP_COPY_NODES
| osg::CopyOp::DEEP_COPY_DRAWABLES | osg::CopyOp::DEEP_COPY_USERDATA | osg::CopyOp::DEEP_COPY_ARRAYS
| osg::CopyOp::DEEP_COPY_PRIMITIVES));
@ -436,7 +442,7 @@ namespace MWRender
// Keep link to original mesh to keep it in cache
group->getOrCreateUserDataContainer()->addUserObject(new Resource::TemplateRef(temp));
InstancingVisitor visitor(pair.second, worldCenter);
InstancingVisitor visitor(entries, worldCenter);
node->accept(visitor);
group->addChild(node);
}

@ -4,6 +4,7 @@
#include <components/esm3/loadcell.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/terrain/quadtreeworld.hpp>
#include <components/vfs/pathutil.hpp>
namespace MWWorld
{
@ -46,13 +47,14 @@ namespace MWRender
};
private:
using InstanceMap = std::map<VFS::Path::Normalized, std::vector<GroundcoverEntry>, std::less<>>;
Resource::SceneManager* mSceneManager;
float mDensity;
osg::ref_ptr<osg::StateSet> mStateset;
osg::ref_ptr<osg::Program> mProgramTemplate;
const MWWorld::GroundcoverStore& mGroundcoverStore;
typedef std::map<std::string, std::vector<GroundcoverEntry>> InstanceMap;
osg::ref_ptr<osg::Node> createChunk(InstanceMap& instances, const osg::Vec2f& center);
void collectInstances(InstanceMap& instances, float size, const osg::Vec2f& center);
};

@ -21,29 +21,27 @@ namespace MWWorld
query.mLoadCells = true;
ESM::ReadersCache readers;
const ::EsmLoader::EsmData content
::EsmLoader::EsmData content
= ::EsmLoader::loadEsmData(query, groundcoverFiles, fileCollections, readers, encoder, listener);
static constexpr std::string_view prefix = "grass\\";
static constexpr std::string_view prefix = "grass/";
for (const ESM::Static& stat : statics)
{
std::string model = Misc::StringUtils::lowerCase(stat.mModel);
std::replace(model.begin(), model.end(), '/', '\\');
if (!model.starts_with(prefix))
VFS::Path::Normalized model = VFS::Path::toNormalized(stat.mModel);
if (!model.value().starts_with(prefix))
continue;
mMeshCache[stat.mId] = Misc::ResourceHelpers::correctMeshPath(model);
}
for (const ESM::Static& stat : content.mStatics)
{
std::string model = Misc::StringUtils::lowerCase(stat.mModel);
std::replace(model.begin(), model.end(), '/', '\\');
if (!model.starts_with(prefix))
VFS::Path::Normalized model = VFS::Path::toNormalized(stat.mModel);
if (!model.value().starts_with(prefix))
continue;
mMeshCache[stat.mId] = Misc::ResourceHelpers::correctMeshPath(model);
}
for (const ESM::Cell& cell : content.mCells)
for (ESM::Cell& cell : content.mCells)
{
if (!cell.isExterior())
continue;
@ -52,15 +50,6 @@ namespace MWWorld
}
}
std::string GroundcoverStore::getGroundcoverModel(const ESM::RefId& id) const
{
auto search = mMeshCache.find(id);
if (search == mMeshCache.end())
return std::string();
return search->second;
}
void GroundcoverStore::initCell(ESM::Cell& cell, int cellX, int cellY) const
{
cell.blank();

@ -2,6 +2,8 @@
#define GAME_MWWORLD_GROUNDCOVER_STORE_H
#include <components/esm/refid.hpp>
#include <components/vfs/pathutil.hpp>
#include <map>
#include <string>
#include <vector>
@ -36,7 +38,7 @@ namespace MWWorld
class GroundcoverStore
{
private:
std::map<ESM::RefId, std::string> mMeshCache;
std::map<ESM::RefId, VFS::Path::Normalized> mMeshCache;
std::map<std::pair<int, int>, std::vector<ESM::ESM_Context>> mCellContexts;
public:
@ -44,7 +46,14 @@ namespace MWWorld
const std::vector<std::string>& groundcoverFiles, ToUTF8::Utf8Encoder* encoder,
Loading::Listener* listener);
std::string getGroundcoverModel(const ESM::RefId& id) const;
VFS::Path::NormalizedView getGroundcoverModel(ESM::RefId id) const
{
auto it = mMeshCache.find(id);
if (it == mMeshCache.end())
return {};
return it->second;
}
void initCell(ESM::Cell& cell, int cellX, int cellY) const;
};
}

@ -94,6 +94,8 @@ namespace VFS::Path
constexpr std::string_view value() const noexcept { return mValue; }
constexpr bool empty() const noexcept { return mValue.empty(); }
friend constexpr bool operator==(const NormalizedView& lhs, const NormalizedView& rhs) = default;
friend constexpr bool operator==(const NormalizedView& lhs, const auto& rhs) { return lhs.mValue == rhs; }

Loading…
Cancel
Save