1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-21 06:53:53 +00:00

Merge branch 'navmesh_ignore' into 'master'

Do not trigger NavMesh update when RecastMesh update should not change NavMesh (#4917)

See merge request OpenMW/openmw!762
This commit is contained in:
psi29a 2021-04-18 21:53:43 +00:00
commit b645c1f4c0
19 changed files with 481 additions and 28 deletions

View file

@ -127,6 +127,7 @@
Feature #3983: Wizard: Add link to buy Morrowind Feature #3983: Wizard: Add link to buy Morrowind
Feature #4894: Consider actors as obstacles for pathfinding Feature #4894: Consider actors as obstacles for pathfinding
Feature #4899: Alpha-To-Coverage Anti-Aliasing for alpha testing Feature #4899: Alpha-To-Coverage Anti-Aliasing for alpha testing
Feature #4917: Do not trigger NavMesh update when RecastMesh update should not change NavMesh
Feature #4977: Use the "default icon.tga" when an item's icon is not found Feature #4977: Use the "default icon.tga" when an item's icon is not found
Feature #5043: Head Bobbing Feature #5043: Head Bobbing
Feature #5199: OpenMW-CS: Improve scene view colors Feature #5199: OpenMW-CS: Improve scene view colors

View file

@ -835,4 +835,55 @@ namespace
ASSERT_THAT(result, Optional(Vec3fEq(mEnd.x(), mEnd.y(), 1.87719))); ASSERT_THAT(result, Optional(Vec3fEq(mEnd.x(), mEnd.y(), 1.87719)));
} }
TEST_F(DetourNavigatorNavigatorTest, update_for_oscillating_object_that_does_not_change_navmesh_should_not_trigger_navmesh_update)
{
const std::array<btScalar, 5 * 5> heightfieldData {{
0, 0, 0, 0, 0,
0, -25, -25, -25, -25,
0, -25, -100, -100, -100,
0, -25, -100, -100, -100,
0, -25, -100, -100, -100,
}};
btHeightfieldTerrainShape heightfieldShape = makeSquareHeightfieldTerrainShape(heightfieldData);
heightfieldShape.setLocalScaling(btVector3(128, 128, 1));
const btBoxShape oscillatingBoxShape(btVector3(20, 20, 20));
const btVector3 oscillatingBoxShapePosition(32, 32, 400);
const btBoxShape boderBoxShape(btVector3(50, 50, 50));
mNavigator->addAgent(mAgentHalfExtents);
mNavigator->addObject(ObjectId(&heightfieldShape), heightfieldShape, btTransform::getIdentity());
mNavigator->addObject(ObjectId(&oscillatingBoxShape), oscillatingBoxShape,
btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition));
// add this box to make navmesh bound box independent from oscillatingBoxShape rotations
mNavigator->addObject(ObjectId(&boderBoxShape), boderBoxShape,
btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition + btVector3(0, 0, 200)));
mNavigator->update(mPlayerPosition);
mNavigator->wait();
const auto navMeshes = mNavigator->getNavMeshes();
ASSERT_EQ(navMeshes.size(), 1);
{
const auto navMesh = navMeshes.begin()->second->lockConst();
ASSERT_EQ(navMesh->getGeneration(), 1);
ASSERT_EQ(navMesh->getNavMeshRevision(), 4);
}
for (int n = 0; n < 10; ++n)
{
const btTransform transform(btQuaternion(btVector3(0, 0, 1), n * 2 * osg::PI / 10),
oscillatingBoxShapePosition);
mNavigator->updateObject(ObjectId(&oscillatingBoxShape), oscillatingBoxShape, transform);
mNavigator->update(mPlayerPosition);
mNavigator->wait();
}
ASSERT_EQ(navMeshes.size(), 1);
{
const auto navMesh = navMeshes.begin()->second->lockConst();
ASSERT_EQ(navMesh->getGeneration(), 1);
ASSERT_EQ(navMesh->getNavMeshRevision(), 4);
}
}
} }

View file

@ -182,6 +182,8 @@ add_component_dir(detournavigator
navigator navigator
findrandompointaroundcircle findrandompointaroundcircle
raycast raycast
navmeshtileview
oscillatingrecastmeshobject
) )
set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui

View file

@ -0,0 +1,29 @@
#ifndef OPENMW_COMPONENTS_BULLETHELPERS_AABB_H
#define OPENMW_COMPONENTS_BULLETHELPERS_AABB_H
#include <LinearMath/btVector3.h>
#include <LinearMath/btTransform.h>
#include <BulletCollision/CollisionShapes/btCollisionShape.h>
#include <BulletCollision/Gimpact/btBoxCollision.h>
inline bool operator==(const btAABB& lhs, const btAABB& rhs)
{
return lhs.m_min == rhs.m_min && lhs.m_max == rhs.m_max;
}
inline bool operator!=(const btAABB& lhs, const btAABB& rhs)
{
return !(lhs == rhs);
}
namespace BulletHelpers
{
inline btAABB getAabb(const btCollisionShape& shape, const btTransform& transform)
{
btAABB result;
shape.getAabb(transform, result.m_min, result.m_max);
return result;
}
}
#endif

View file

@ -2,6 +2,7 @@
#include "debug.hpp" #include "debug.hpp"
#include "makenavmesh.hpp" #include "makenavmesh.hpp"
#include "settings.hpp" #include "settings.hpp"
#include "version.hpp"
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/misc/thread.hpp> #include <components/misc/thread.hpp>
@ -180,6 +181,19 @@ namespace DetourNavigator
const auto status = updateNavMesh(job.mAgentHalfExtents, recastMesh.get(), job.mChangedTile, playerTile, const auto status = updateNavMesh(job.mAgentHalfExtents, recastMesh.get(), job.mChangedTile, playerTile,
offMeshConnections, mSettings, navMeshCacheItem, mNavMeshTilesCache); offMeshConnections, mSettings, navMeshCacheItem, mNavMeshTilesCache);
if (recastMesh != nullptr)
{
Version navMeshVersion;
{
const auto locked = navMeshCacheItem->lockConst();
navMeshVersion.mGeneration = locked->getGeneration();
navMeshVersion.mRevision = locked->getNavMeshRevision();
}
mRecastMeshManager.get().reportNavMeshChange(job.mChangedTile,
Version {recastMesh->getGeneration(), recastMesh->getRevision()},
navMeshVersion);
}
const auto finish = std::chrono::steady_clock::now(); const auto finish = std::chrono::steady_clock::now();
writeDebugFiles(job, recastMesh.get()); writeDebugFiles(job, recastMesh.get());

View file

@ -61,4 +61,9 @@ namespace DetourNavigator
{ {
return mImpl.isEmpty(); return mImpl.isEmpty();
} }
void CachedRecastMeshManager::reportNavMeshChange(Version recastMeshVersion, Version navMeshVersion)
{
mImpl.reportNavMeshChange(recastMeshVersion, navMeshVersion);
}
} }

View file

@ -2,6 +2,7 @@
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_CACHEDRECASTMESHMANAGER_H #define OPENMW_COMPONENTS_DETOURNAVIGATOR_CACHEDRECASTMESHMANAGER_H
#include "recastmeshmanager.hpp" #include "recastmeshmanager.hpp"
#include "version.hpp"
namespace DetourNavigator namespace DetourNavigator
{ {
@ -25,6 +26,8 @@ namespace DetourNavigator
bool isEmpty() const; bool isEmpty() const;
void reportNavMeshChange(Version recastMeshVersion, Version navMeshVersion);
private: private:
RecastMeshManager mImpl; RecastMeshManager mImpl;
std::shared_ptr<RecastMesh> mCached; std::shared_ptr<RecastMesh> mCached;

View file

@ -5,6 +5,7 @@
#include "tileposition.hpp" #include "tileposition.hpp"
#include "navmeshtilescache.hpp" #include "navmeshtilescache.hpp"
#include "dtstatus.hpp" #include "dtstatus.hpp"
#include "navmeshtileview.hpp"
#include <components/misc/guarded.hpp> #include <components/misc/guarded.hpp>
@ -141,6 +142,12 @@ namespace DetourNavigator
template <class T> template <class T>
UpdateNavMeshStatus updateTile(const TilePosition& position, T&& navMeshData) UpdateNavMeshStatus updateTile(const TilePosition& position, T&& navMeshData)
{ {
const dtMeshTile* currentTile = getTile(position);
if (currentTile != nullptr
&& asNavMeshTileConstView(*currentTile) == asNavMeshTileConstView(getRawData(navMeshData)))
{
return UpdateNavMeshStatus::ignored;
}
const auto removed = removeTileImpl(position); const auto removed = removeTileImpl(position);
const auto addStatus = addTileImpl(getRawData(navMeshData), getSize(navMeshData)); const auto addStatus = addTileImpl(getRawData(navMeshData), getSize(navMeshData));
if (dtStatusSucceed(addStatus)) if (dtStatusSucceed(addStatus))
@ -206,6 +213,12 @@ namespace DetourNavigator
int* const dataSize = nullptr; int* const dataSize = nullptr;
return dtStatusSucceed(mImpl->removeTile(tileRef, data, dataSize)); return dtStatusSucceed(mImpl->removeTile(tileRef, data, dataSize));
} }
const dtMeshTile* getTile(const TilePosition& position) const
{
const int layer = 0;
return mImpl->getTileAt(position.x(), position.y(), layer);
}
}; };
using GuardedNavMeshCacheItem = Misc::ScopeGuarded<NavMeshCacheItem>; using GuardedNavMeshCacheItem = Misc::ScopeGuarded<NavMeshCacheItem>;

View file

@ -0,0 +1,183 @@
#include "navmeshtileview.hpp"
#include <DetourCommon.h>
#include <DetourNavMesh.h>
#include <algorithm>
#include <cassert>
#include <stdexcept>
#include <tuple>
namespace
{
template <typename T>
struct Ref
{
T& mRef;
explicit Ref(T& ref) : mRef(ref) {}
friend bool operator==(const Ref& lhs, const Ref& rhs)
{
return lhs.mRef == rhs.mRef;
}
};
template <typename T, std::size_t size>
struct ArrayRef
{
T (&mRef)[size];
explicit ArrayRef(T (&ref)[size]) : mRef(ref) {}
friend bool operator==(const ArrayRef& lhs, const ArrayRef& rhs)
{
return std::equal(std::begin(lhs.mRef), std::end(lhs.mRef), std::begin(rhs.mRef));
}
};
template <typename T>
struct Span
{
T* mBegin;
T* mEnd;
explicit Span(T* data, int size) : mBegin(data), mEnd(data + static_cast<std::size_t>(size)) {}
friend bool operator==(const Span& lhs, const Span& rhs)
{
// size is already equal if headers are equal
assert((lhs.mEnd - lhs.mBegin) == (rhs.mEnd - rhs.mBegin));
return std::equal(lhs.mBegin, lhs.mEnd, rhs.mBegin);
}
};
auto makeTuple(const dtMeshHeader& v)
{
return std::tuple(
v.x,
v.y,
v.layer,
v.userId,
v.polyCount,
v.vertCount,
v.maxLinkCount,
v.detailMeshCount,
v.detailVertCount,
v.detailTriCount,
v.bvNodeCount,
v.offMeshConCount,
v.offMeshBase,
v.walkableHeight,
v.walkableRadius,
v.walkableClimb,
v.detailVertCount,
ArrayRef(v.bmin),
ArrayRef(v.bmax),
v.bvQuantFactor
);
}
auto makeTuple(const dtPoly& v)
{
return std::tuple(ArrayRef(v.verts), ArrayRef(v.neis), v.flags, v.vertCount, v.areaAndtype);
}
auto makeTuple(const dtPolyDetail& v)
{
return std::tuple(v.vertBase, v.triBase, v.vertCount, v.triCount);
}
auto makeTuple(const dtBVNode& v)
{
return std::tuple(ArrayRef(v.bmin), ArrayRef(v.bmax), v.i);
}
auto makeTuple(const dtOffMeshConnection& v)
{
return std::tuple(ArrayRef(v.pos), v.rad, v.poly, v.flags, v.side, v.userId);
}
auto makeTuple(const DetourNavigator::NavMeshTileConstView& v)
{
return std::tuple(
Ref(*v.mHeader),
Span(v.mPolys, v.mHeader->polyCount),
Span(v.mVerts, v.mHeader->vertCount),
Span(v.mDetailMeshes, v.mHeader->detailMeshCount),
Span(v.mDetailVerts, v.mHeader->detailVertCount),
Span(v.mDetailTris, v.mHeader->detailTriCount),
Span(v.mBvTree, v.mHeader->bvNodeCount),
Span(v.mOffMeshCons, v.mHeader->offMeshConCount)
);
}
}
template <class T>
inline auto operator==(const T& lhs, const T& rhs)
-> std::enable_if_t<std::is_same_v<std::void_t<decltype(makeTuple(lhs))>, void>, bool>
{
return makeTuple(lhs) == makeTuple(rhs);
}
namespace DetourNavigator
{
NavMeshTileConstView asNavMeshTileConstView(const unsigned char* data)
{
const dtMeshHeader* header = reinterpret_cast<const dtMeshHeader*>(data);
if (header->magic != DT_NAVMESH_MAGIC)
throw std::logic_error("Invalid navmesh magic");
if (header->version != DT_NAVMESH_VERSION)
throw std::logic_error("Invalid navmesh version");
// Similar code to https://github.com/recastnavigation/recastnavigation/blob/c5cbd53024c8a9d8d097a4371215e3342d2fdc87/Detour/Source/DetourNavMesh.cpp#L978-L996
const int headerSize = dtAlign4(sizeof(dtMeshHeader));
const int vertsSize = dtAlign4(sizeof(float) * 3 * header->vertCount);
const int polysSize = dtAlign4(sizeof(dtPoly) * header->polyCount);
const int linksSize = dtAlign4(sizeof(dtLink) * (header->maxLinkCount));
const int detailMeshesSize = dtAlign4(sizeof(dtPolyDetail) * header->detailMeshCount);
const int detailVertsSize = dtAlign4(sizeof(float) * 3 * header->detailVertCount);
const int detailTrisSize = dtAlign4(sizeof(unsigned char) * 4 * header->detailTriCount);
const int bvtreeSize = dtAlign4(sizeof(dtBVNode) * header->bvNodeCount);
const int offMeshLinksSize = dtAlign4(sizeof(dtOffMeshConnection) * header->offMeshConCount);
const unsigned char* ptr = data + headerSize;
NavMeshTileConstView view;
view.mHeader = header;
view.mVerts = dtGetThenAdvanceBufferPointer<const float>(ptr, vertsSize);
view.mPolys = dtGetThenAdvanceBufferPointer<const dtPoly>(ptr, polysSize);
ptr += linksSize;
view.mDetailMeshes = dtGetThenAdvanceBufferPointer<const dtPolyDetail>(ptr, detailMeshesSize);
view.mDetailVerts = dtGetThenAdvanceBufferPointer<const float>(ptr, detailVertsSize);
view.mDetailTris = dtGetThenAdvanceBufferPointer<const unsigned char>(ptr, detailTrisSize);
view.mBvTree = dtGetThenAdvanceBufferPointer<const dtBVNode>(ptr, bvtreeSize);
view.mOffMeshCons = dtGetThenAdvanceBufferPointer<const dtOffMeshConnection>(ptr, offMeshLinksSize);
return view;
}
NavMeshTileConstView asNavMeshTileConstView(const dtMeshTile& tile)
{
NavMeshTileConstView view;
view.mHeader = tile.header;
view.mPolys = tile.polys;
view.mVerts = tile.verts;
view.mDetailMeshes = tile.detailMeshes;
view.mDetailVerts = tile.detailVerts;
view.mDetailTris = tile.detailTris;
view.mBvTree = tile.bvTree;
view.mOffMeshCons = tile.offMeshCons;
return view;
}
bool operator==(const NavMeshTileConstView& lhs, const NavMeshTileConstView& rhs)
{
return makeTuple(lhs) == makeTuple(rhs);
}
}

View file

@ -0,0 +1,31 @@
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_NAVMESHTILEVIEW_H
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_NAVMESHTILEVIEW_H
struct dtMeshHeader;
struct dtPoly;
struct dtPolyDetail;
struct dtBVNode;
struct dtOffMeshConnection;
struct dtMeshTile;
namespace DetourNavigator
{
struct NavMeshTileConstView
{
const dtMeshHeader* mHeader;
const dtPoly* mPolys;
const float* mVerts;
const dtPolyDetail* mDetailMeshes;
const float* mDetailVerts;
const unsigned char* mDetailTris;
const dtBVNode* mBvTree;
const dtOffMeshConnection* mOffMeshCons;
friend bool operator==(const NavMeshTileConstView& lhs, const NavMeshTileConstView& rhs);
};
NavMeshTileConstView asNavMeshTileConstView(const unsigned char* data);
NavMeshTileConstView asNavMeshTileConstView(const dtMeshTile& tile);
}
#endif

View file

@ -0,0 +1,35 @@
#include "oscillatingrecastmeshobject.hpp"
#include <components/bullethelpers/aabb.hpp>
namespace DetourNavigator
{
OscillatingRecastMeshObject::OscillatingRecastMeshObject(RecastMeshObject impl, std::size_t lastChangeRevision)
: mImpl(std::move(impl))
, mLastChangeRevision(lastChangeRevision)
, mAabb(BulletHelpers::getAabb(mImpl.getShape(), mImpl.getTransform()))
{
}
bool OscillatingRecastMeshObject::update(const btTransform& transform, const AreaType areaType,
std::size_t lastChangeRevision)
{
const btTransform oldTransform = mImpl.getTransform();
if (!mImpl.update(transform, areaType))
return false;
if (transform == oldTransform)
return true;
if (mLastChangeRevision != lastChangeRevision)
{
mLastChangeRevision = lastChangeRevision;
// btAABB doesn't have copy-assignment operator
const btAABB aabb = BulletHelpers::getAabb(mImpl.getShape(), transform);
mAabb.m_min = aabb.m_min;
mAabb.m_max = aabb.m_max;
return true;
}
const btAABB currentAabb = mAabb;
mAabb.merge(BulletHelpers::getAabb(mImpl.getShape(), transform));
return currentAabb != mAabb;
}
}

View file

@ -0,0 +1,28 @@
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_OSCILLATINGRECASTMESHOBJECT_H
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_OSCILLATINGRECASTMESHOBJECT_H
#include "areatype.hpp"
#include "recastmeshobject.hpp"
#include <LinearMath/btTransform.h>
#include <BulletCollision/Gimpact/btBoxCollision.h>
namespace DetourNavigator
{
class OscillatingRecastMeshObject
{
public:
explicit OscillatingRecastMeshObject(RecastMeshObject impl, std::size_t lastChangeRevision);
bool update(const btTransform& transform, const AreaType areaType, std::size_t lastChangeRevision);
const RecastMeshObject& getImpl() const { return mImpl; }
private:
RecastMeshObject mImpl;
std::size_t mLastChangeRevision;
btAABB mAabb;
};
}
#endif

View file

@ -13,7 +13,8 @@ namespace DetourNavigator
bool RecastMeshManager::addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, bool RecastMeshManager::addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform,
const AreaType areaType) const AreaType areaType)
{ {
const auto iterator = mObjectsOrder.emplace(mObjectsOrder.end(), RecastMeshObject(shape, transform, areaType)); const auto iterator = mObjectsOrder.emplace(mObjectsOrder.end(),
OscillatingRecastMeshObject(RecastMeshObject(shape, transform, areaType), mRevision + 1));
if (!mObjects.emplace(id, iterator).second) if (!mObjects.emplace(id, iterator).second)
{ {
mObjectsOrder.erase(iterator); mObjectsOrder.erase(iterator);
@ -28,7 +29,9 @@ namespace DetourNavigator
const auto object = mObjects.find(id); const auto object = mObjects.find(id);
if (object == mObjects.end()) if (object == mObjects.end())
return false; return false;
if (!object->second->update(transform, areaType)) const std::size_t lastChangeRevision = mLastNavMeshReportedChange.has_value()
? mLastNavMeshReportedChange->mRevision : mRevision;
if (!object->second->update(transform, areaType, lastChangeRevision))
return false; return false;
++mRevision; ++mRevision;
return true; return true;
@ -39,7 +42,7 @@ namespace DetourNavigator
const auto object = mObjects.find(id); const auto object = mObjects.find(id);
if (object == mObjects.end()) if (object == mObjects.end())
return std::nullopt; return std::nullopt;
const RemovedRecastMeshObject result {object->second->getShape(), object->second->getTransform()}; const RemovedRecastMeshObject result {object->second->getImpl().getShape(), object->second->getImpl().getTransform()};
mObjectsOrder.erase(object->second); mObjectsOrder.erase(object->second);
mObjects.erase(object); mObjects.erase(object);
++mRevision; ++mRevision;
@ -74,7 +77,7 @@ namespace DetourNavigator
std::shared_ptr<RecastMesh> RecastMeshManager::getMesh() std::shared_ptr<RecastMesh> RecastMeshManager::getMesh()
{ {
rebuild(); rebuild();
return mMeshBuilder.create(mGeneration, mLastBuildRevision); return mMeshBuilder.create(mGeneration, mRevision);
} }
bool RecastMeshManager::isEmpty() const bool RecastMeshManager::isEmpty() const
@ -82,15 +85,27 @@ namespace DetourNavigator
return mObjects.empty(); return mObjects.empty();
} }
void RecastMeshManager::reportNavMeshChange(Version recastMeshVersion, Version navMeshVersion)
{
if (recastMeshVersion.mGeneration != mGeneration)
return;
if (mLastNavMeshReport.has_value() && navMeshVersion < mLastNavMeshReport->mNavMeshVersion)
return;
mLastNavMeshReport = {recastMeshVersion.mRevision, navMeshVersion};
if (!mLastNavMeshReportedChange.has_value()
|| mLastNavMeshReportedChange->mNavMeshVersion < mLastNavMeshReport->mNavMeshVersion)
mLastNavMeshReportedChange = mLastNavMeshReport;
}
void RecastMeshManager::rebuild() void RecastMeshManager::rebuild()
{ {
if (mLastBuildRevision == mRevision)
return;
mMeshBuilder.reset(); mMeshBuilder.reset();
for (const auto& v : mWaterOrder) for (const auto& v : mWaterOrder)
mMeshBuilder.addWater(v.mCellSize, v.mTransform); mMeshBuilder.addWater(v.mCellSize, v.mTransform);
for (const auto& v : mObjectsOrder) for (const auto& object : mObjectsOrder)
{
const RecastMeshObject& v = object.getImpl();
mMeshBuilder.addObject(v.getShape(), v.getTransform(), v.getAreaType()); mMeshBuilder.addObject(v.getShape(), v.getTransform(), v.getAreaType());
mLastBuildRevision = mRevision; }
} }
} }

View file

@ -2,8 +2,9 @@
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTMESHMANAGER_H #define OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTMESHMANAGER_H
#include "recastmeshbuilder.hpp" #include "recastmeshbuilder.hpp"
#include "recastmeshobject.hpp" #include "oscillatingrecastmeshobject.hpp"
#include "objectid.hpp" #include "objectid.hpp"
#include "version.hpp"
#include <LinearMath/btTransform.h> #include <LinearMath/btTransform.h>
@ -50,15 +51,24 @@ namespace DetourNavigator
bool isEmpty() const; bool isEmpty() const;
void reportNavMeshChange(Version recastMeshVersion, Version navMeshVersion);
private: private:
struct Report
{
std::size_t mRevision;
Version mNavMeshVersion;
};
std::size_t mRevision = 0; std::size_t mRevision = 0;
std::size_t mLastBuildRevision = 0;
std::size_t mGeneration; std::size_t mGeneration;
RecastMeshBuilder mMeshBuilder; RecastMeshBuilder mMeshBuilder;
std::list<RecastMeshObject> mObjectsOrder; std::list<OscillatingRecastMeshObject> mObjectsOrder;
std::unordered_map<ObjectId, std::list<RecastMeshObject>::iterator> mObjects; std::unordered_map<ObjectId, std::list<OscillatingRecastMeshObject>::iterator> mObjects;
std::list<Water> mWaterOrder; std::list<Water> mWaterOrder;
std::map<osg::Vec2i, std::list<Water>::iterator> mWater; std::map<osg::Vec2i, std::list<Water>::iterator> mWater;
std::optional<Report> mLastNavMeshReportedChange;
std::optional<Report> mLastNavMeshReport;
void rebuild(); void rebuild();
}; };

View file

@ -8,6 +8,22 @@
namespace DetourNavigator namespace DetourNavigator
{ {
namespace
{
bool updateCompoundObject(const btCompoundShape& shape, const AreaType areaType,
std::vector<RecastMeshObject>& children)
{
assert(static_cast<std::size_t>(shape.getNumChildShapes()) == children.size());
bool result = false;
for (int i = 0, num = shape.getNumChildShapes(); i < num; ++i)
{
assert(shape.getChildShape(i) == std::addressof(children[static_cast<std::size_t>(i)].getShape()));
result = children[static_cast<std::size_t>(i)].update(shape.getChildTransform(i), areaType) || result;
}
return result;
}
}
RecastMeshObject::RecastMeshObject(const btCollisionShape& shape, const btTransform& transform, RecastMeshObject::RecastMeshObject(const btCollisionShape& shape, const btTransform& transform,
const AreaType areaType) const AreaType areaType)
: mShape(shape) : mShape(shape)
@ -42,19 +58,6 @@ namespace DetourNavigator
return result; return result;
} }
bool RecastMeshObject::updateCompoundObject(const btCompoundShape& shape,
const AreaType areaType, std::vector<RecastMeshObject>& children)
{
assert(static_cast<std::size_t>(shape.getNumChildShapes()) == children.size());
bool result = false;
for (int i = 0, num = shape.getNumChildShapes(); i < num; ++i)
{
assert(shape.getChildShape(i) == std::addressof(children[static_cast<std::size_t>(i)].mShape.get()));
result = children[static_cast<std::size_t>(i)].update(shape.getChildTransform(i), areaType) || result;
}
return result;
}
std::vector<RecastMeshObject> makeChildrenObjects(const btCollisionShape& shape, const AreaType areaType) std::vector<RecastMeshObject> makeChildrenObjects(const btCollisionShape& shape, const AreaType areaType)
{ {
if (shape.isCompound()) if (shape.isCompound())

View file

@ -41,9 +41,6 @@ namespace DetourNavigator
AreaType mAreaType; AreaType mAreaType;
btVector3 mLocalScaling; btVector3 mLocalScaling;
std::vector<RecastMeshObject> mChildren; std::vector<RecastMeshObject> mChildren;
static bool updateCompoundObject(const btCompoundShape& shape, const AreaType areaType,
std::vector<RecastMeshObject>& children);
}; };
std::vector<RecastMeshObject> makeChildrenObjects(const btCollisionShape& shape, const AreaType areaType); std::vector<RecastMeshObject> makeChildrenObjects(const btCollisionShape& shape, const AreaType areaType);

View file

@ -145,6 +145,15 @@ namespace DetourNavigator
return mRevision; return mRevision;
} }
void TileCachedRecastMeshManager::reportNavMeshChange(const TilePosition& tilePosition, Version recastMeshVersion, Version navMeshVersion)
{
const auto tiles = mTiles.lock();
const auto it = tiles->find(tilePosition);
if (it == tiles->end())
return;
it->second.reportNavMeshChange(recastMeshVersion, navMeshVersion);
}
bool TileCachedRecastMeshManager::addTile(const ObjectId id, const btCollisionShape& shape, bool TileCachedRecastMeshManager::addTile(const ObjectId id, const btCollisionShape& shape,
const btTransform& transform, const AreaType areaType, const TilePosition& tilePosition, float border, const btTransform& transform, const AreaType areaType, const TilePosition& tilePosition, float border,
std::map<TilePosition, CachedRecastMeshManager>& tiles) std::map<TilePosition, CachedRecastMeshManager>& tiles)

View file

@ -5,6 +5,7 @@
#include "tileposition.hpp" #include "tileposition.hpp"
#include "settingsutils.hpp" #include "settingsutils.hpp"
#include "gettilespositions.hpp" #include "gettilespositions.hpp"
#include "version.hpp"
#include <components/misc/guarded.hpp> #include <components/misc/guarded.hpp>
@ -88,6 +89,8 @@ namespace DetourNavigator
std::size_t getRevision() const; std::size_t getRevision() const;
void reportNavMeshChange(const TilePosition& tilePosition, Version recastMeshVersion, Version navMeshVersion);
private: private:
const Settings& mSettings; const Settings& mSettings;
Misc::ScopeGuarded<std::map<TilePosition, CachedRecastMeshManager>> mTiles; Misc::ScopeGuarded<std::map<TilePosition, CachedRecastMeshManager>> mTiles;

View file

@ -0,0 +1,21 @@
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_VERSION_H
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_VERSION_H
#include <cstddef>
#include <tuple>
namespace DetourNavigator
{
struct Version
{
std::size_t mGeneration;
std::size_t mRevision;
friend inline bool operator<(const Version& lhs, const Version& rhs)
{
return std::tie(lhs.mGeneration, lhs.mRevision) < std::tie(rhs.mGeneration, rhs.mRevision);
}
};
}
#endif