Merge branch 'vfs_normalized_path_15' into 'master'

Use normalized path in BulletShapeManager and PreloadItem (#8138)

See merge request OpenMW/openmw!4391
pull/3236/head
Alexei Kotov 3 months ago
commit 0590aa181d

@ -33,7 +33,8 @@ namespace
{
const ObjectId id(&shape);
osg::ref_ptr<Resource::BulletShape> bulletShape(new Resource::BulletShape);
bulletShape->mFileName = "test.nif";
constexpr VFS::Path::NormalizedView test("test.nif");
bulletShape->mFileName = test;
bulletShape->mFileHash = "test_hash";
ObjectTransform objectTransform;
std::fill(std::begin(objectTransform.mPosition.pos), std::end(objectTransform.mPosition.pos), 0.1f);

@ -131,7 +131,8 @@ namespace NavMeshTool
osg::ref_ptr<const Resource::BulletShape> shape = [&] {
try
{
return bulletShapeManager.getShape(Misc::ResourceHelpers::correctMeshPath(model));
return bulletShapeManager.getShape(
VFS::Path::toNormalized(Misc::ResourceHelpers::correctMeshPath(model)));
}
catch (const std::exception& e)
{

@ -412,9 +412,9 @@ namespace MWPhysics
if (ptr.mRef->mData.mPhysicsPostponed)
return;
std::string animationMesh = mesh;
if (ptr.getClass().useAnim())
animationMesh = Misc::ResourceHelpers::correctActorModelPath(mesh, mResourceSystem->getVFS());
const VFS::Path::Normalized animationMesh = ptr.getClass().useAnim()
? Misc::ResourceHelpers::correctActorModelPath(mesh, mResourceSystem->getVFS())
: mesh;
osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance = mShapeManager->getInstance(animationMesh);
if (!shapeInstance || !shapeInstance->mCollisionShape)
return;
@ -562,7 +562,8 @@ namespace MWPhysics
void PhysicsSystem::addActor(const MWWorld::Ptr& ptr, const std::string& mesh)
{
std::string animationMesh = Misc::ResourceHelpers::correctActorModelPath(mesh, mResourceSystem->getVFS());
const VFS::Path::Normalized animationMesh
= Misc::ResourceHelpers::correctActorModelPath(mesh, mResourceSystem->getVFS());
osg::ref_ptr<const Resource::BulletShape> shape = mShapeManager->getShape(animationMesh);
// Try to get shape from basic model as fallback for creatures
@ -570,7 +571,7 @@ namespace MWPhysics
{
if (animationMesh != mesh)
{
shape = mShapeManager->getShape(mesh);
shape = mShapeManager->getShape(VFS::Path::toNormalized(mesh));
}
}
@ -590,7 +591,8 @@ namespace MWPhysics
int PhysicsSystem::addProjectile(
const MWWorld::Ptr& caster, const osg::Vec3f& position, const std::string& mesh, bool computeRadius)
{
osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance = mShapeManager->getInstance(mesh);
osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance
= mShapeManager->getInstance(VFS::Path::toNormalized(mesh));
assert(shapeInstance);
float radius = computeRadius ? shapeInstance->mCollisionBox.mExtents.length() / 2.f : 1.f;

@ -385,7 +385,7 @@ namespace MWRender
if (!weaponNode->getNumChildren())
{
osg::ref_ptr<osg::Node> fallbackNode
= mResourceSystem->getSceneManager()->getInstance(VFS::Path::toNormalized(mesh), weaponNode);
= mResourceSystem->getSceneManager()->getInstance(mesh, weaponNode);
resetControllers(fallbackNode);
}

@ -11,6 +11,7 @@
#include <components/esm3/loadcell.hpp>
#include <components/loadinglistener/reporter.hpp>
#include <components/misc/constants.hpp>
#include <components/misc/pathhelpers.hpp>
#include <components/misc/resourcehelpers.hpp>
#include <components/misc/strings/algorithm.hpp>
#include <components/misc/strings/lower.hpp>
@ -105,8 +106,8 @@ namespace MWWorld
}
}
std::string mesh;
std::string kfname;
VFS::Path::Normalized mesh;
VFS::Path::Normalized kfname;
for (std::string_view path : mMeshes)
{
if (mAbort)
@ -121,19 +122,15 @@ namespace MWWorld
if (!vfs.exists(mesh))
continue;
size_t slashpos = mesh.find_last_of("/\\");
if (slashpos != std::string::npos && slashpos != mesh.size() - 1)
if (Misc::getFileName(mesh).starts_with('x') && Misc::getFileExtension(mesh) == "nif")
{
if (Misc::StringUtils::toLower(mesh[slashpos + 1]) == 'x'
&& Misc::StringUtils::ciEndsWith(mesh, ".nif"))
{
kfname = mesh;
kfname.replace(kfname.size() - 4, 4, ".kf");
if (vfs.exists(kfname))
mPreloadedObjects.insert(mKeyframeManager->get(kfname));
}
kfname = mesh;
kfname.changeExtension("kf");
if (vfs.exists(kfname))
mPreloadedObjects.insert(mKeyframeManager->get(kfname));
}
mPreloadedObjects.insert(mSceneManager->getTemplate(VFS::Path::toNormalized(mesh)));
mPreloadedObjects.insert(mSceneManager->getTemplate(mesh));
if (mPreloadInstances)
mPreloadedObjects.insert(mBulletShapeManager->cacheInstance(mesh));
else

@ -53,7 +53,7 @@ namespace NifBullet
mShape->mFileName = nif.getFilename();
if (roots.empty())
{
warn("Found no root nodes in NIF file " + mShape->mFileName);
warn("Found no root nodes in NIF file " + mShape->mFileName.value());
return mShape;
}
@ -93,7 +93,7 @@ namespace NifBullet
}
else
{
warn("Invalid Bounding Box node bounds in file " + mShape->mFileName);
warn("Invalid Bounding Box node bounds in file " + mShape->mFileName.value());
}
return true;
}

@ -1,7 +1,6 @@
#ifndef OPENMW_COMPONENTS_RESOURCE_BULLETSHAPE_H
#define OPENMW_COMPONENTS_RESOURCE_BULLETSHAPE_H
#include <array>
#include <map>
#include <memory>
@ -12,6 +11,8 @@
#include <BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h>
#include <BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h>
#include <components/vfs/pathutil.hpp>
class btCollisionShape;
namespace NifBullet
@ -56,7 +57,7 @@ namespace Resource
// we store the node's record index mapped to the child index of the shape in the btCompoundShape.
std::map<int, int> mAnimatedShapes;
std::string mFileName;
VFS::Path::Normalized mFileName;
std::string mFileHash;
VisualCollisionType mVisualCollisionType = VisualCollisionType::None;

@ -106,93 +106,83 @@ namespace Resource
{
}
BulletShapeManager::~BulletShapeManager() {}
BulletShapeManager::~BulletShapeManager() = default;
osg::ref_ptr<const BulletShape> BulletShapeManager::getShape(const std::string& name)
osg::ref_ptr<const BulletShape> BulletShapeManager::getShape(VFS::Path::NormalizedView name)
{
const VFS::Path::Normalized normalized(name);
if (osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(name))
return osg::ref_ptr<BulletShape>(static_cast<BulletShape*>(obj.get()));
osg::ref_ptr<BulletShape> shape;
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(normalized);
if (obj)
shape = osg::ref_ptr<BulletShape>(static_cast<BulletShape*>(obj.get()));
if (Misc::getFileExtension(name.value()) == "nif")
{
NifBullet::BulletNifLoader loader;
shape = loader.load(*mNifFileManager->get(name));
}
else
{
if (Misc::getFileExtension(normalized) == "nif")
// TODO: support .bullet shape files
osg::ref_ptr<const osg::Node> constNode(mSceneManager->getTemplate(name));
// const-trickery required because there is no const version of NodeVisitor
osg::ref_ptr<osg::Node> node(const_cast<osg::Node*>(constNode.get()));
// Check first if there's a custom collision node
unsigned int visitAllNodesMask = 0xffffffff;
SceneUtil::FindByNameVisitor nameFinder("Collision");
nameFinder.setTraversalMask(visitAllNodesMask);
nameFinder.setNodeMaskOverride(visitAllNodesMask);
node->accept(nameFinder);
if (nameFinder.mFoundNode)
{
NifBullet::BulletNifLoader loader;
shape = loader.load(*mNifFileManager->get(normalized));
NodeToShapeVisitor visitor;
visitor.setTraversalMask(visitAllNodesMask);
visitor.setNodeMaskOverride(visitAllNodesMask);
nameFinder.mFoundNode->accept(visitor);
shape = visitor.getShape();
}
else
// Generate a collision shape from the mesh
if (!shape)
{
// TODO: support .bullet shape files
osg::ref_ptr<const osg::Node> constNode(mSceneManager->getTemplate(normalized));
osg::ref_ptr<osg::Node> node(const_cast<osg::Node*>(
constNode.get())); // const-trickery required because there is no const version of NodeVisitor
// Check first if there's a custom collision node
unsigned int visitAllNodesMask = 0xffffffff;
SceneUtil::FindByNameVisitor nameFinder("Collision");
nameFinder.setTraversalMask(visitAllNodesMask);
nameFinder.setNodeMaskOverride(visitAllNodesMask);
node->accept(nameFinder);
if (nameFinder.mFoundNode)
{
NodeToShapeVisitor visitor;
visitor.setTraversalMask(visitAllNodesMask);
visitor.setNodeMaskOverride(visitAllNodesMask);
nameFinder.mFoundNode->accept(visitor);
shape = visitor.getShape();
}
// Generate a collision shape from the mesh
NodeToShapeVisitor visitor;
node->accept(visitor);
shape = visitor.getShape();
if (!shape)
{
NodeToShapeVisitor visitor;
node->accept(visitor);
shape = visitor.getShape();
if (!shape)
return osg::ref_ptr<BulletShape>();
}
if (shape != nullptr)
{
shape->mFileName = normalized;
constNode->getUserValue(Misc::OsgUserValues::sFileHash, shape->mFileHash);
}
return osg::ref_ptr<BulletShape>();
}
mCache->addEntryToObjectCache(normalized, shape);
if (shape != nullptr)
{
shape->mFileName = name;
constNode->getUserValue(Misc::OsgUserValues::sFileHash, shape->mFileHash);
}
}
mCache->addEntryToObjectCache(name.value(), shape);
return shape;
}
osg::ref_ptr<BulletShapeInstance> BulletShapeManager::cacheInstance(const std::string& name)
osg::ref_ptr<BulletShapeInstance> BulletShapeManager::cacheInstance(VFS::Path::NormalizedView name)
{
const std::string normalized = VFS::Path::normalizeFilename(name);
osg::ref_ptr<BulletShapeInstance> instance = createInstance(normalized);
if (instance)
mInstanceCache->addEntryToObjectCache(normalized, instance.get());
osg::ref_ptr<BulletShapeInstance> instance = createInstance(name);
if (instance != nullptr)
mInstanceCache->addEntryToObjectCache(name, instance.get());
return instance;
}
osg::ref_ptr<BulletShapeInstance> BulletShapeManager::getInstance(const std::string& name)
osg::ref_ptr<BulletShapeInstance> BulletShapeManager::getInstance(VFS::Path::NormalizedView name)
{
const std::string normalized = VFS::Path::normalizeFilename(name);
osg::ref_ptr<osg::Object> obj = mInstanceCache->takeFromObjectCache(normalized);
if (obj.get())
if (osg::ref_ptr<osg::Object> obj = mInstanceCache->takeFromObjectCache(name))
return static_cast<BulletShapeInstance*>(obj.get());
else
return createInstance(normalized);
return createInstance(name);
}
osg::ref_ptr<BulletShapeInstance> BulletShapeManager::createInstance(const std::string& name)
osg::ref_ptr<BulletShapeInstance> BulletShapeManager::createInstance(VFS::Path::NormalizedView name)
{
osg::ref_ptr<const BulletShape> shape = getShape(name);
if (shape)
if (osg::ref_ptr<const BulletShape> shape = getShape(name))
return makeInstance(std::move(shape));
return osg::ref_ptr<BulletShapeInstance>();
}

@ -1,11 +1,10 @@
#ifndef OPENMW_COMPONENTS_BULLETSHAPEMANAGER_H
#define OPENMW_COMPONENTS_BULLETSHAPEMANAGER_H
#include <map>
#include <string>
#include <osg/ref_ptr>
#include <components/vfs/pathutil.hpp>
#include "bulletshape.hpp"
#include "resourcemanager.hpp"
@ -30,16 +29,16 @@ namespace Resource
~BulletShapeManager();
/// @note May return a null pointer if the object has no shape.
osg::ref_ptr<const BulletShape> getShape(const std::string& name);
osg::ref_ptr<const BulletShape> getShape(VFS::Path::NormalizedView name);
/// Create an instance of the given shape and cache it for later use, so that future calls to getInstance() can
/// simply return the cached instance instead of having to create a new one.
/// @note The returned ref_ptr may be kept by the caller to ensure that the instance stays in cache for as long
/// as needed.
osg::ref_ptr<BulletShapeInstance> cacheInstance(const std::string& name);
osg::ref_ptr<BulletShapeInstance> cacheInstance(VFS::Path::NormalizedView name);
/// @note May return a null pointer if the object has no shape.
osg::ref_ptr<BulletShapeInstance> getInstance(const std::string& name);
osg::ref_ptr<BulletShapeInstance> getInstance(VFS::Path::NormalizedView name);
/// @see ResourceManager::updateCache
void updateCache(double referenceTime) override;
@ -49,7 +48,7 @@ namespace Resource
void reportStats(unsigned int frameNumber, osg::Stats* stats) const override;
private:
osg::ref_ptr<BulletShapeInstance> createInstance(const std::string& name);
osg::ref_ptr<BulletShapeInstance> createInstance(VFS::Path::NormalizedView name);
osg::ref_ptr<MultiObjectCache> mInstanceCache;
SceneManager* mSceneManager;

@ -16,10 +16,6 @@
#include <osg/ref_ptr>
#include <algorithm>
#include <memory>
#include <stdexcept>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
@ -97,7 +93,7 @@ namespace Resource
for (CellRef& cellRef : cellRefs)
{
std::string model(getModel(esmData, cellRef.mRefId, cellRef.mType));
VFS::Path::Normalized model(getModel(esmData, cellRef.mRefId, cellRef.mType));
if (model.empty())
continue;
@ -107,7 +103,8 @@ namespace Resource
osg::ref_ptr<const Resource::BulletShape> shape = [&] {
try
{
return bulletShapeManager.getShape("meshes/" + model);
constexpr VFS::Path::NormalizedView prefix("meshes");
return bulletShapeManager.getShape(prefix / model);
}
catch (const std::exception& e)
{

@ -6,11 +6,6 @@
namespace Resource
{
MultiObjectCache::MultiObjectCache() {}
MultiObjectCache::~MultiObjectCache() {}
void MultiObjectCache::removeUnreferencedObjectsInCache()
{
std::vector<osg::ref_ptr<osg::Object>> objectsToRemove;
@ -44,7 +39,7 @@ namespace Resource
_objectCache.clear();
}
void MultiObjectCache::addEntryToObjectCache(const std::string& filename, osg::Object* object)
void MultiObjectCache::addEntryToObjectCache(VFS::Path::NormalizedView filename, osg::Object* object)
{
if (!object)
{
@ -52,23 +47,23 @@ namespace Resource
return;
}
std::lock_guard<std::mutex> lock(_objectCacheMutex);
_objectCache.insert(std::make_pair(filename, object));
_objectCache.emplace(filename, object);
}
osg::ref_ptr<osg::Object> MultiObjectCache::takeFromObjectCache(const std::string& fileName)
osg::ref_ptr<osg::Object> MultiObjectCache::takeFromObjectCache(VFS::Path::NormalizedView fileName)
{
std::lock_guard<std::mutex> lock(_objectCacheMutex);
++mGet;
ObjectCacheMap::iterator found = _objectCache.find(fileName);
if (found == _objectCache.end())
return osg::ref_ptr<osg::Object>();
else
const auto it = _objectCache.find(fileName);
if (it != _objectCache.end())
{
osg::ref_ptr<osg::Object> object = std::move(found->second);
_objectCache.erase(found);
osg::ref_ptr<osg::Object> object = std::move(it->second);
_objectCache.erase(it);
++mHit;
return object;
}
return nullptr;
}
void MultiObjectCache::releaseGLObjects(osg::State* state)

@ -3,11 +3,12 @@
#include <map>
#include <mutex>
#include <string>
#include <osg/Referenced>
#include <osg/ref_ptr>
#include <components/vfs/pathutil.hpp>
#include "cachestats.hpp"
namespace osg
@ -23,18 +24,15 @@ namespace Resource
class MultiObjectCache : public osg::Referenced
{
public:
MultiObjectCache();
~MultiObjectCache();
void removeUnreferencedObjectsInCache();
/** Remove all objects from the cache. */
void clear();
void addEntryToObjectCache(const std::string& filename, osg::Object* object);
void addEntryToObjectCache(VFS::Path::NormalizedView filename, osg::Object* object);
/** Take an Object from cache. Return nullptr if no object found. */
osg::ref_ptr<osg::Object> takeFromObjectCache(const std::string& fileName);
osg::ref_ptr<osg::Object> takeFromObjectCache(VFS::Path::NormalizedView fileName);
/** call releaseGLObjects on all objects attached to the object cache.*/
void releaseGLObjects(osg::State* state);
@ -42,7 +40,7 @@ namespace Resource
CacheStats getStats() const;
protected:
typedef std::multimap<std::string, osg::ref_ptr<osg::Object>> ObjectCacheMap;
typedef std::multimap<VFS::Path::Normalized, osg::ref_ptr<osg::Object>, std::less<>> ObjectCacheMap;
ObjectCacheMap _objectCache;
mutable std::mutex _objectCacheMutex;

Loading…
Cancel
Save