Use normalized path in BulletShapeManager

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

@ -33,7 +33,8 @@ namespace
{ {
const ObjectId id(&shape); const ObjectId id(&shape);
osg::ref_ptr<Resource::BulletShape> bulletShape(new Resource::BulletShape); 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"; bulletShape->mFileHash = "test_hash";
ObjectTransform objectTransform; ObjectTransform objectTransform;
std::fill(std::begin(objectTransform.mPosition.pos), std::end(objectTransform.mPosition.pos), 0.1f); 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 = [&] { osg::ref_ptr<const Resource::BulletShape> shape = [&] {
try try
{ {
return bulletShapeManager.getShape(Misc::ResourceHelpers::correctMeshPath(model)); return bulletShapeManager.getShape(
VFS::Path::toNormalized(Misc::ResourceHelpers::correctMeshPath(model)));
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {

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

@ -53,7 +53,7 @@ namespace NifBullet
mShape->mFileName = nif.getFilename(); mShape->mFileName = nif.getFilename();
if (roots.empty()) 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; return mShape;
} }
@ -93,7 +93,7 @@ namespace NifBullet
} }
else else
{ {
warn("Invalid Bounding Box node bounds in file " + mShape->mFileName); warn("Invalid Bounding Box node bounds in file " + mShape->mFileName.value());
} }
return true; return true;
} }

@ -1,7 +1,6 @@
#ifndef OPENMW_COMPONENTS_RESOURCE_BULLETSHAPE_H #ifndef OPENMW_COMPONENTS_RESOURCE_BULLETSHAPE_H
#define OPENMW_COMPONENTS_RESOURCE_BULLETSHAPE_H #define OPENMW_COMPONENTS_RESOURCE_BULLETSHAPE_H
#include <array>
#include <map> #include <map>
#include <memory> #include <memory>
@ -12,6 +11,8 @@
#include <BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h> #include <BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h>
#include <BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h> #include <BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h>
#include <components/vfs/pathutil.hpp>
class btCollisionShape; class btCollisionShape;
namespace NifBullet 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. // we store the node's record index mapped to the child index of the shape in the btCompoundShape.
std::map<int, int> mAnimatedShapes; std::map<int, int> mAnimatedShapes;
std::string mFileName; VFS::Path::Normalized mFileName;
std::string mFileHash; std::string mFileHash;
VisualCollisionType mVisualCollisionType = VisualCollisionType::None; 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<BulletShape> shape;
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(normalized);
if (obj) if (Misc::getFileExtension(name.value()) == "nif")
shape = osg::ref_ptr<BulletShape>(static_cast<BulletShape*>(obj.get())); {
NifBullet::BulletNifLoader loader;
shape = loader.load(*mNifFileManager->get(name));
}
else 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; NodeToShapeVisitor visitor;
shape = loader.load(*mNifFileManager->get(normalized)); 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 NodeToShapeVisitor visitor;
node->accept(visitor);
osg::ref_ptr<const osg::Node> constNode(mSceneManager->getTemplate(normalized)); shape = visitor.getShape();
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
if (!shape) if (!shape)
{ return osg::ref_ptr<BulletShape>();
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);
}
} }
mCache->addEntryToObjectCache(normalized, shape); if (shape != nullptr)
{
shape->mFileName = name;
constNode->getUserValue(Misc::OsgUserValues::sFileHash, shape->mFileHash);
}
} }
mCache->addEntryToObjectCache(name.value(), shape);
return 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(name);
if (instance != nullptr)
osg::ref_ptr<BulletShapeInstance> instance = createInstance(normalized); mInstanceCache->addEntryToObjectCache(name, instance.get());
if (instance)
mInstanceCache->addEntryToObjectCache(normalized, instance.get());
return instance; 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); if (osg::ref_ptr<osg::Object> obj = mInstanceCache->takeFromObjectCache(name))
osg::ref_ptr<osg::Object> obj = mInstanceCache->takeFromObjectCache(normalized);
if (obj.get())
return static_cast<BulletShapeInstance*>(obj.get()); return static_cast<BulletShapeInstance*>(obj.get());
else return createInstance(name);
return createInstance(normalized);
} }
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 (osg::ref_ptr<const BulletShape> shape = getShape(name))
if (shape)
return makeInstance(std::move(shape)); return makeInstance(std::move(shape));
return osg::ref_ptr<BulletShapeInstance>(); return osg::ref_ptr<BulletShapeInstance>();
} }

@ -1,11 +1,10 @@
#ifndef OPENMW_COMPONENTS_BULLETSHAPEMANAGER_H #ifndef OPENMW_COMPONENTS_BULLETSHAPEMANAGER_H
#define OPENMW_COMPONENTS_BULLETSHAPEMANAGER_H #define OPENMW_COMPONENTS_BULLETSHAPEMANAGER_H
#include <map>
#include <string>
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <components/vfs/pathutil.hpp>
#include "bulletshape.hpp" #include "bulletshape.hpp"
#include "resourcemanager.hpp" #include "resourcemanager.hpp"
@ -30,16 +29,16 @@ namespace Resource
~BulletShapeManager(); ~BulletShapeManager();
/// @note May return a null pointer if the object has no shape. /// @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 /// 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. /// 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 /// @note The returned ref_ptr may be kept by the caller to ensure that the instance stays in cache for as long
/// as needed. /// 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. /// @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 /// @see ResourceManager::updateCache
void updateCache(double referenceTime) override; void updateCache(double referenceTime) override;
@ -49,7 +48,7 @@ namespace Resource
void reportStats(unsigned int frameNumber, osg::Stats* stats) const override; void reportStats(unsigned int frameNumber, osg::Stats* stats) const override;
private: private:
osg::ref_ptr<BulletShapeInstance> createInstance(const std::string& name); osg::ref_ptr<BulletShapeInstance> createInstance(VFS::Path::NormalizedView name);
osg::ref_ptr<MultiObjectCache> mInstanceCache; osg::ref_ptr<MultiObjectCache> mInstanceCache;
SceneManager* mSceneManager; SceneManager* mSceneManager;

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

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

@ -3,11 +3,12 @@
#include <map> #include <map>
#include <mutex> #include <mutex>
#include <string>
#include <osg/Referenced> #include <osg/Referenced>
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <components/vfs/pathutil.hpp>
#include "cachestats.hpp" #include "cachestats.hpp"
namespace osg namespace osg
@ -23,18 +24,15 @@ namespace Resource
class MultiObjectCache : public osg::Referenced class MultiObjectCache : public osg::Referenced
{ {
public: public:
MultiObjectCache();
~MultiObjectCache();
void removeUnreferencedObjectsInCache(); void removeUnreferencedObjectsInCache();
/** Remove all objects from the cache. */ /** Remove all objects from the cache. */
void clear(); 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. */ /** 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.*/ /** call releaseGLObjects on all objects attached to the object cache.*/
void releaseGLObjects(osg::State* state); void releaseGLObjects(osg::State* state);
@ -42,7 +40,7 @@ namespace Resource
CacheStats getStats() const; CacheStats getStats() const;
protected: 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; ObjectCacheMap _objectCache;
mutable std::mutex _objectCacheMutex; mutable std::mutex _objectCacheMutex;

Loading…
Cancel
Save