Skip to content

Commit

Permalink
Merge branch 'vfs_normalized_path_15' into 'master'
Browse files Browse the repository at this point in the history
Use normalized path in BulletShapeManager and PreloadItem (#8138)

See merge request OpenMW/openmw!4391
  • Loading branch information
Capostrophic committed Sep 30, 2024
2 parents ac21cf3 + 63e984b commit 0590aa1
Show file tree
Hide file tree
Showing 12 changed files with 103 additions and 122 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion apps/navmeshtool/worldspacedata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
14 changes: 8 additions & 6 deletions apps/openmw/mwphysics/physicssystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -562,15 +562,16 @@ 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
if (!ptr.getClass().isNpc() && shape && shape->mCollisionBox.mExtents.length2() == 0)
{
if (animationMesh != mesh)
{
shape = mShapeManager->getShape(mesh);
shape = mShapeManager->getShape(VFS::Path::toNormalized(mesh));
}
}

Expand All @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion apps/openmw/mwrender/actoranimation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
23 changes: 10 additions & 13 deletions apps/openmw/mwworld/cellpreloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions components/nifbullet/bulletnifloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}
Expand Down
5 changes: 3 additions & 2 deletions components/resource/bulletshape.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#ifndef OPENMW_COMPONENTS_RESOURCE_BULLETSHAPE_H
#define OPENMW_COMPONENTS_RESOURCE_BULLETSHAPE_H

#include <array>
#include <map>
#include <memory>

Expand All @@ -12,6 +11,8 @@
#include <BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h>
#include <BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h>

#include <components/vfs/pathutil.hpp>

class btCollisionShape;

namespace NifBullet
Expand Down Expand Up @@ -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;
Expand Down
114 changes: 52 additions & 62 deletions components/resource/bulletshapemanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>();
}
Expand Down
13 changes: 6 additions & 7 deletions components/resource/bulletshapemanager.hpp
Original file line number Diff line number Diff line change
@@ -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"

Expand All @@ -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;
Expand All @@ -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;
Expand Down
9 changes: 3 additions & 6 deletions components/resource/foreachbulletobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@
#include <osg/ref_ptr>

#include <algorithm>
#include <memory>
#include <stdexcept>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

Expand Down Expand Up @@ -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;

Expand All @@ -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)
{
Expand Down
Loading

0 comments on commit 0590aa1

Please sign in to comment.