mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-04 12:39:55 +00:00
Merge branch 'vfs_normalized_path_17' into 'master'
Use normalized path for groundcover (#8138) See merge request OpenMW/openmw!4403
This commit is contained in:
commit
4ac1b13871
@ -1,5 +1,7 @@
|
|||||||
#include "groundcover.hpp"
|
#include "groundcover.hpp"
|
||||||
|
|
||||||
|
#include <span>
|
||||||
|
|
||||||
#include <osg/AlphaFunc>
|
#include <osg/AlphaFunc>
|
||||||
#include <osg/BlendFunc>
|
#include <osg/BlendFunc>
|
||||||
#include <osg/ComputeBoundsVisitor>
|
#include <osg/ComputeBoundsVisitor>
|
||||||
@ -46,13 +48,13 @@ namespace MWRender
|
|||||||
class InstancedComputeNearFarCullCallback : public osg::DrawableCullCallback
|
class InstancedComputeNearFarCullCallback : public osg::DrawableCullCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InstancedComputeNearFarCullCallback(const std::vector<Groundcover::GroundcoverEntry>& instances,
|
explicit InstancedComputeNearFarCullCallback(std::span<const Groundcover::GroundcoverEntry> instances,
|
||||||
const osg::Vec3& chunkPosition, const osg::BoundingBox& instanceBounds)
|
const osg::Vec3& chunkPosition, const osg::BoundingBox& instanceBounds)
|
||||||
: mInstanceMatrices()
|
: mInstanceMatrices()
|
||||||
, mInstanceBounds(instanceBounds)
|
, mInstanceBounds(instanceBounds)
|
||||||
{
|
{
|
||||||
mInstanceMatrices.reserve(instances.size());
|
mInstanceMatrices.reserve(instances.size());
|
||||||
for (const auto& instance : instances)
|
for (const Groundcover::GroundcoverEntry& instance : instances)
|
||||||
mInstanceMatrices.emplace_back(computeInstanceMatrix(instance, chunkPosition));
|
mInstanceMatrices.emplace_back(computeInstanceMatrix(instance, chunkPosition));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,7 +193,8 @@ namespace MWRender
|
|||||||
class InstancingVisitor : public osg::NodeVisitor
|
class InstancingVisitor : public osg::NodeVisitor
|
||||||
{
|
{
|
||||||
public:
|
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)
|
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
|
||||||
, mInstances(instances)
|
, mInstances(instances)
|
||||||
, mChunkPosition(chunkPosition)
|
, mChunkPosition(chunkPosition)
|
||||||
@ -252,7 +255,7 @@ namespace MWRender
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Groundcover::GroundcoverEntry> mInstances;
|
std::span<const Groundcover::GroundcoverEntry> mInstances;
|
||||||
osg::Vec3f mChunkPosition;
|
osg::Vec3f mChunkPosition;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -411,12 +414,15 @@ namespace MWRender
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& pair : refs)
|
for (auto& [refNum, cellRef] : refs)
|
||||||
{
|
{
|
||||||
ESM::CellRef& ref = pair.second;
|
const VFS::Path::NormalizedView model = mGroundcoverStore.getGroundcoverModel(cellRef.mRefID);
|
||||||
const std::string& model = mGroundcoverStore.getGroundcoverModel(ref.mRefID);
|
if (model.empty())
|
||||||
if (!model.empty())
|
continue;
|
||||||
instances[model].emplace_back(std::move(ref));
|
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::ref_ptr<osg::Group> group = new osg::Group;
|
||||||
osg::Vec3f worldCenter = osg::Vec3f(center.x(), center.y(), 0) * ESM::Land::REAL_SIZE;
|
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::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_DRAWABLES | osg::CopyOp::DEEP_COPY_USERDATA | osg::CopyOp::DEEP_COPY_ARRAYS
|
||||||
| osg::CopyOp::DEEP_COPY_PRIMITIVES));
|
| osg::CopyOp::DEEP_COPY_PRIMITIVES));
|
||||||
@ -436,7 +442,7 @@ namespace MWRender
|
|||||||
// Keep link to original mesh to keep it in cache
|
// Keep link to original mesh to keep it in cache
|
||||||
group->getOrCreateUserDataContainer()->addUserObject(new Resource::TemplateRef(temp));
|
group->getOrCreateUserDataContainer()->addUserObject(new Resource::TemplateRef(temp));
|
||||||
|
|
||||||
InstancingVisitor visitor(pair.second, worldCenter);
|
InstancingVisitor visitor(entries, worldCenter);
|
||||||
node->accept(visitor);
|
node->accept(visitor);
|
||||||
group->addChild(node);
|
group->addChild(node);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <components/esm3/loadcell.hpp>
|
#include <components/esm3/loadcell.hpp>
|
||||||
#include <components/resource/scenemanager.hpp>
|
#include <components/resource/scenemanager.hpp>
|
||||||
#include <components/terrain/quadtreeworld.hpp>
|
#include <components/terrain/quadtreeworld.hpp>
|
||||||
|
#include <components/vfs/pathutil.hpp>
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
@ -46,13 +47,14 @@ namespace MWRender
|
|||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using InstanceMap = std::map<VFS::Path::Normalized, std::vector<GroundcoverEntry>, std::less<>>;
|
||||||
|
|
||||||
Resource::SceneManager* mSceneManager;
|
Resource::SceneManager* mSceneManager;
|
||||||
float mDensity;
|
float mDensity;
|
||||||
osg::ref_ptr<osg::StateSet> mStateset;
|
osg::ref_ptr<osg::StateSet> mStateset;
|
||||||
osg::ref_ptr<osg::Program> mProgramTemplate;
|
osg::ref_ptr<osg::Program> mProgramTemplate;
|
||||||
const MWWorld::GroundcoverStore& mGroundcoverStore;
|
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);
|
osg::ref_ptr<osg::Node> createChunk(InstanceMap& instances, const osg::Vec2f& center);
|
||||||
void collectInstances(InstanceMap& instances, float size, const osg::Vec2f& center);
|
void collectInstances(InstanceMap& instances, float size, const osg::Vec2f& center);
|
||||||
};
|
};
|
||||||
|
@ -21,29 +21,27 @@ namespace MWWorld
|
|||||||
query.mLoadCells = true;
|
query.mLoadCells = true;
|
||||||
|
|
||||||
ESM::ReadersCache readers;
|
ESM::ReadersCache readers;
|
||||||
const ::EsmLoader::EsmData content
|
::EsmLoader::EsmData content
|
||||||
= ::EsmLoader::loadEsmData(query, groundcoverFiles, fileCollections, readers, encoder, listener);
|
= ::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)
|
for (const ESM::Static& stat : statics)
|
||||||
{
|
{
|
||||||
std::string model = Misc::StringUtils::lowerCase(stat.mModel);
|
VFS::Path::Normalized model = VFS::Path::toNormalized(stat.mModel);
|
||||||
std::replace(model.begin(), model.end(), '/', '\\');
|
if (!model.value().starts_with(prefix))
|
||||||
if (!model.starts_with(prefix))
|
|
||||||
continue;
|
continue;
|
||||||
mMeshCache[stat.mId] = Misc::ResourceHelpers::correctMeshPath(model);
|
mMeshCache[stat.mId] = Misc::ResourceHelpers::correctMeshPath(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const ESM::Static& stat : content.mStatics)
|
for (const ESM::Static& stat : content.mStatics)
|
||||||
{
|
{
|
||||||
std::string model = Misc::StringUtils::lowerCase(stat.mModel);
|
VFS::Path::Normalized model = VFS::Path::toNormalized(stat.mModel);
|
||||||
std::replace(model.begin(), model.end(), '/', '\\');
|
if (!model.value().starts_with(prefix))
|
||||||
if (!model.starts_with(prefix))
|
|
||||||
continue;
|
continue;
|
||||||
mMeshCache[stat.mId] = Misc::ResourceHelpers::correctMeshPath(model);
|
mMeshCache[stat.mId] = Misc::ResourceHelpers::correctMeshPath(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const ESM::Cell& cell : content.mCells)
|
for (ESM::Cell& cell : content.mCells)
|
||||||
{
|
{
|
||||||
if (!cell.isExterior())
|
if (!cell.isExterior())
|
||||||
continue;
|
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
|
void GroundcoverStore::initCell(ESM::Cell& cell, int cellX, int cellY) const
|
||||||
{
|
{
|
||||||
cell.blank();
|
cell.blank();
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
#define GAME_MWWORLD_GROUNDCOVER_STORE_H
|
#define GAME_MWWORLD_GROUNDCOVER_STORE_H
|
||||||
|
|
||||||
#include <components/esm/refid.hpp>
|
#include <components/esm/refid.hpp>
|
||||||
|
#include <components/vfs/pathutil.hpp>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -36,7 +38,7 @@ namespace MWWorld
|
|||||||
class GroundcoverStore
|
class GroundcoverStore
|
||||||
{
|
{
|
||||||
private:
|
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;
|
std::map<std::pair<int, int>, std::vector<ESM::ESM_Context>> mCellContexts;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -44,7 +46,14 @@ namespace MWWorld
|
|||||||
const std::vector<std::string>& groundcoverFiles, ToUTF8::Utf8Encoder* encoder,
|
const std::vector<std::string>& groundcoverFiles, ToUTF8::Utf8Encoder* encoder,
|
||||||
Loading::Listener* listener);
|
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;
|
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 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 NormalizedView& rhs) = default;
|
||||||
|
|
||||||
friend constexpr bool operator==(const NormalizedView& lhs, const auto& rhs) { return lhs.mValue == rhs; }
|
friend constexpr bool operator==(const NormalizedView& lhs, const auto& rhs) { return lhs.mValue == rhs; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user