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:
commit
b645c1f4c0
19 changed files with 481 additions and 28 deletions
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
29
components/bullethelpers/aabb.hpp
Normal file
29
components/bullethelpers/aabb.hpp
Normal 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
|
|
@ -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());
|
||||||
|
|
|
@ -61,4 +61,9 @@ namespace DetourNavigator
|
||||||
{
|
{
|
||||||
return mImpl.isEmpty();
|
return mImpl.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CachedRecastMeshManager::reportNavMeshChange(Version recastMeshVersion, Version navMeshVersion)
|
||||||
|
{
|
||||||
|
mImpl.reportNavMeshChange(recastMeshVersion, navMeshVersion);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>;
|
||||||
|
|
183
components/detournavigator/navmeshtileview.cpp
Normal file
183
components/detournavigator/navmeshtileview.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
31
components/detournavigator/navmeshtileview.hpp
Normal file
31
components/detournavigator/navmeshtileview.hpp
Normal 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
|
35
components/detournavigator/oscillatingrecastmeshobject.cpp
Normal file
35
components/detournavigator/oscillatingrecastmeshobject.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
28
components/detournavigator/oscillatingrecastmeshobject.hpp
Normal file
28
components/detournavigator/oscillatingrecastmeshobject.hpp
Normal 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
|
|
@ -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;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
21
components/detournavigator/version.hpp
Normal file
21
components/detournavigator/version.hpp
Normal 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
|
Loading…
Reference in a new issue