mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 18:29:55 +00:00
Store changed tiles in TileCachedRecastMeshManager
This commit is contained in:
parent
5815faecda
commit
e2d566b89d
14 changed files with 344 additions and 407 deletions
|
@ -318,13 +318,13 @@ namespace NavMeshTool
|
||||||
const CollisionShape shape(object.getShapeInstance(), *object.getCollisionObject().getCollisionShape(), object.getObjectTransform());
|
const CollisionShape shape(object.getShapeInstance(), *object.getCollisionObject().getCollisionShape(), object.getObjectTransform());
|
||||||
|
|
||||||
navMeshInput.mTileCachedRecastMeshManager.addObject(objectId, shape, transform,
|
navMeshInput.mTileCachedRecastMeshManager.addObject(objectId, shape, transform,
|
||||||
DetourNavigator::AreaType_ground, [] (const auto&) {});
|
DetourNavigator::AreaType_ground);
|
||||||
|
|
||||||
if (const btCollisionShape* avoid = object.getShapeInstance()->mAvoidCollisionShape.get())
|
if (const btCollisionShape* avoid = object.getShapeInstance()->mAvoidCollisionShape.get())
|
||||||
{
|
{
|
||||||
const CollisionShape avoidShape(object.getShapeInstance(), *avoid, object.getObjectTransform());
|
const CollisionShape avoidShape(object.getShapeInstance(), *avoid, object.getObjectTransform());
|
||||||
navMeshInput.mTileCachedRecastMeshManager.addObject(objectId, avoidShape, transform,
|
navMeshInput.mTileCachedRecastMeshManager.addObject(objectId, avoidShape, transform,
|
||||||
DetourNavigator::AreaType_null, [] (const auto&) {});
|
DetourNavigator::AreaType_null);
|
||||||
}
|
}
|
||||||
|
|
||||||
data.mObjects.emplace_back(std::move(object));
|
data.mObjects.emplace_back(std::move(object));
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <components/resource/bulletshape.hpp>
|
#include <components/resource/bulletshape.hpp>
|
||||||
|
|
||||||
#include <BulletCollision/CollisionDispatch/btCollisionObject.h>
|
#include <BulletCollision/CollisionDispatch/btCollisionObject.h>
|
||||||
|
#include <BulletCollision/Gimpact/btBoxCollision.h>
|
||||||
#include <LinearMath/btVector3.h>
|
#include <LinearMath/btVector3.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace
|
||||||
osg::ref_ptr<Resource::BulletShapeInstance>(new Resource::BulletShapeInstance(bulletShape)),
|
osg::ref_ptr<Resource::BulletShapeInstance>(new Resource::BulletShapeInstance(bulletShape)),
|
||||||
shape, objectTransform
|
shape, objectTransform
|
||||||
);
|
);
|
||||||
recastMeshManager.addObject(id, collisionShape, btTransform::getIdentity(), AreaType_ground, [] (auto) {});
|
recastMeshManager.addObject(id, collisionShape, btTransform::getIdentity(), AreaType_ground);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DetourNavigatorAsyncNavMeshUpdaterTest : Test
|
struct DetourNavigatorAsyncNavMeshUpdaterTest : Test
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#include <BulletCollision/CollisionShapes/btBoxShape.h>
|
#include <BulletCollision/CollisionShapes/btBoxShape.h>
|
||||||
|
|
||||||
|
#include <osg/io_utils>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
|
@ -16,8 +18,6 @@ namespace
|
||||||
struct DetourNavigatorTileCachedRecastMeshManagerTest : Test
|
struct DetourNavigatorTileCachedRecastMeshManagerTest : Test
|
||||||
{
|
{
|
||||||
RecastSettings mSettings;
|
RecastSettings mSettings;
|
||||||
std::vector<TilePosition> mAddedTiles;
|
|
||||||
std::vector<std::pair<TilePosition, ChangeType>> mChangedTiles;
|
|
||||||
const ObjectTransform mObjectTransform {ESM::Position {{0, 0, 0}, {0, 0, 0}}, 0.0f};
|
const ObjectTransform mObjectTransform {ESM::Position {{0, 0, 0}, {0, 0, 0}}, 0.0f};
|
||||||
const osg::ref_ptr<const Resource::BulletShape> mShape = new Resource::BulletShape;
|
const osg::ref_ptr<const Resource::BulletShape> mShape = new Resource::BulletShape;
|
||||||
const osg::ref_ptr<const Resource::BulletShapeInstance> mInstance = new Resource::BulletShapeInstance(mShape);
|
const osg::ref_ptr<const Resource::BulletShapeInstance> mInstance = new Resource::BulletShapeInstance(mShape);
|
||||||
|
@ -29,16 +29,6 @@ namespace
|
||||||
mSettings.mRecastScaleFactor = 0.017647058823529415f;
|
mSettings.mRecastScaleFactor = 0.017647058823529415f;
|
||||||
mSettings.mTileSize = 64;
|
mSettings.mTileSize = 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onAddedTile(const TilePosition& tilePosition)
|
|
||||||
{
|
|
||||||
mAddedTiles.push_back(tilePosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onChangedTile(const TilePosition& tilePosition, ChangeType changeType)
|
|
||||||
{
|
|
||||||
mChangedTiles.emplace_back(tilePosition, changeType);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_for_empty_should_return_nullptr)
|
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_for_empty_should_return_nullptr)
|
||||||
|
@ -66,7 +56,7 @@ namespace
|
||||||
TileCachedRecastMeshManager manager(mSettings);
|
TileCachedRecastMeshManager manager(mSettings);
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||||
EXPECT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {}));
|
EXPECT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_object_for_existing_object_should_return_false)
|
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_object_for_existing_object_should_return_false)
|
||||||
|
@ -74,8 +64,8 @@ namespace
|
||||||
TileCachedRecastMeshManager manager(mSettings);
|
TileCachedRecastMeshManager manager(mSettings);
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||||
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {});
|
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||||
EXPECT_FALSE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {}));
|
EXPECT_FALSE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_object_should_add_tiles)
|
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_object_should_add_tiles)
|
||||||
|
@ -84,13 +74,13 @@ namespace
|
||||||
manager.setWorldspace("worldspace");
|
manager.setWorldspace("worldspace");
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||||
ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {}));
|
ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground));
|
||||||
for (int x = -1; x < 1; ++x)
|
for (int x = -1; x < 1; ++x)
|
||||||
for (int y = -1; y < 1; ++y)
|
for (int y = -1; y < 1; ++y)
|
||||||
ASSERT_NE(manager.getMesh("worldspace", TilePosition(x, y)), nullptr);
|
ASSERT_NE(manager.getMesh("worldspace", TilePosition(x, y)), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_object_should_return_added_tiles)
|
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_object_should_return_add_changed_tiles)
|
||||||
{
|
{
|
||||||
TileCachedRecastMeshManager manager(mSettings);
|
TileCachedRecastMeshManager manager(mSettings);
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
|
@ -99,12 +89,11 @@ namespace
|
||||||
bounds.mMin = osg::Vec2f(182, 182);
|
bounds.mMin = osg::Vec2f(182, 182);
|
||||||
bounds.mMax = osg::Vec2f(1000, 1000);
|
bounds.mMax = osg::Vec2f(1000, 1000);
|
||||||
manager.setBounds(bounds);
|
manager.setBounds(bounds);
|
||||||
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground,
|
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||||
[&] (const auto& v) { onAddedTile(v); });
|
EXPECT_THAT(manager.takeChangedTiles(), ElementsAre(std::pair(TilePosition(0, 0), ChangeType::add)));
|
||||||
EXPECT_THAT(mAddedTiles, ElementsAre(TilePosition(0, 0)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, update_object_for_changed_object_should_return_changed_tiles)
|
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, update_object_for_changed_object_should_add_changed_tiles)
|
||||||
{
|
{
|
||||||
TileCachedRecastMeshManager manager(mSettings);
|
TileCachedRecastMeshManager manager(mSettings);
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
|
@ -114,10 +103,10 @@ namespace
|
||||||
bounds.mMin = osg::Vec2f(-1000, -1000);
|
bounds.mMin = osg::Vec2f(-1000, -1000);
|
||||||
bounds.mMax = osg::Vec2f(1000, 1000);
|
bounds.mMax = osg::Vec2f(1000, 1000);
|
||||||
manager.setBounds(bounds);
|
manager.setBounds(bounds);
|
||||||
manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground, [] (auto) {});
|
manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground);
|
||||||
EXPECT_TRUE(manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground,
|
manager.takeChangedTiles();
|
||||||
[&] (const auto& ... v) { onChangedTile(v ...); }));
|
EXPECT_TRUE(manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground));
|
||||||
EXPECT_THAT(mChangedTiles, ElementsAre(
|
EXPECT_THAT(manager.takeChangedTiles(), ElementsAre(
|
||||||
std::pair(TilePosition(-1, -1), ChangeType::add),
|
std::pair(TilePosition(-1, -1), ChangeType::add),
|
||||||
std::pair(TilePosition(-1, 0), ChangeType::add),
|
std::pair(TilePosition(-1, 0), ChangeType::add),
|
||||||
std::pair(TilePosition(0, -1), ChangeType::update),
|
std::pair(TilePosition(0, -1), ChangeType::update),
|
||||||
|
@ -127,15 +116,30 @@ namespace
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, update_object_for_not_changed_object_should_return_empty)
|
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, update_object_for_not_changed_object_should_not_add_changed_tiles)
|
||||||
{
|
{
|
||||||
TileCachedRecastMeshManager manager(mSettings);
|
TileCachedRecastMeshManager manager(mSettings);
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||||
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {});
|
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||||
EXPECT_FALSE(manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground,
|
manager.takeChangedTiles();
|
||||||
[&] (const auto& ... v) { onChangedTile(v ...); }));
|
EXPECT_FALSE(manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground));
|
||||||
EXPECT_THAT(mChangedTiles, IsEmpty());
|
EXPECT_THAT(manager.takeChangedTiles(), IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, remove_object_should_return_add_changed_tiles)
|
||||||
|
{
|
||||||
|
TileCachedRecastMeshManager manager(mSettings);
|
||||||
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
|
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||||
|
TileBounds bounds;
|
||||||
|
bounds.mMin = osg::Vec2f(182, 182);
|
||||||
|
bounds.mMax = osg::Vec2f(1000, 1000);
|
||||||
|
manager.setBounds(bounds);
|
||||||
|
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||||
|
manager.takeChangedTiles();
|
||||||
|
manager.removeObject(ObjectId(&boxShape));
|
||||||
|
EXPECT_THAT(manager.takeChangedTiles(), ElementsAre(std::pair(TilePosition(0, 0), ChangeType::remove)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_after_add_object_should_return_recast_mesh_for_each_used_tile)
|
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_after_add_object_should_return_recast_mesh_for_each_used_tile)
|
||||||
|
@ -144,7 +148,7 @@ namespace
|
||||||
manager.setWorldspace("worldspace");
|
manager.setWorldspace("worldspace");
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||||
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {});
|
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr);
|
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr);
|
||||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr);
|
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr);
|
||||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr);
|
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr);
|
||||||
|
@ -157,7 +161,7 @@ namespace
|
||||||
manager.setWorldspace("worldspace");
|
manager.setWorldspace("worldspace");
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||||
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {});
|
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||||
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(1, 0)), nullptr);
|
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(1, 0)), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,13 +178,13 @@ namespace
|
||||||
const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0));
|
const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0));
|
||||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||||
|
|
||||||
manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground, [] (auto) {});
|
manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground);
|
||||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr);
|
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr);
|
||||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, 0)), nullptr);
|
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, 0)), nullptr);
|
||||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(1, 0)), nullptr);
|
EXPECT_NE(manager.getMesh("worldspace", TilePosition(1, 0)), nullptr);
|
||||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(1, -1)), nullptr);
|
EXPECT_NE(manager.getMesh("worldspace", TilePosition(1, -1)), nullptr);
|
||||||
|
|
||||||
manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto, auto) {});
|
manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr);
|
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr);
|
||||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr);
|
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr);
|
||||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr);
|
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr);
|
||||||
|
@ -196,11 +200,11 @@ namespace
|
||||||
const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0));
|
const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0));
|
||||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||||
|
|
||||||
manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground, [] (auto) {});
|
manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground);
|
||||||
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr);
|
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr);
|
||||||
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr);
|
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr);
|
||||||
|
|
||||||
manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto, auto) {});
|
manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||||
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(1, 0)), nullptr);
|
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(1, 0)), nullptr);
|
||||||
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(1, -1)), nullptr);
|
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(1, -1)), nullptr);
|
||||||
}
|
}
|
||||||
|
@ -211,7 +215,7 @@ namespace
|
||||||
manager.setWorldspace("worldspace");
|
manager.setWorldspace("worldspace");
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||||
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {});
|
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||||
manager.removeObject(ObjectId(&boxShape));
|
manager.removeObject(ObjectId(&boxShape));
|
||||||
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr);
|
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr);
|
||||||
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr);
|
EXPECT_EQ(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr);
|
||||||
|
@ -226,13 +230,13 @@ namespace
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||||
|
|
||||||
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {});
|
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr);
|
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr);
|
||||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr);
|
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr);
|
||||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr);
|
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr);
|
||||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, 0)), nullptr);
|
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, 0)), nullptr);
|
||||||
|
|
||||||
manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto, auto) {});
|
manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr);
|
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr);
|
||||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr);
|
EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr);
|
||||||
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr);
|
EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr);
|
||||||
|
@ -245,7 +249,7 @@ namespace
|
||||||
const auto initialRevision = manager.getRevision();
|
const auto initialRevision = manager.getRevision();
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||||
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {});
|
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||||
EXPECT_EQ(manager.getRevision(), initialRevision + 1);
|
EXPECT_EQ(manager.getRevision(), initialRevision + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,9 +258,9 @@ namespace
|
||||||
TileCachedRecastMeshManager manager(mSettings);
|
TileCachedRecastMeshManager manager(mSettings);
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||||
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {});
|
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||||
const auto beforeAddRevision = manager.getRevision();
|
const auto beforeAddRevision = manager.getRevision();
|
||||||
EXPECT_FALSE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {}));
|
EXPECT_FALSE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground));
|
||||||
EXPECT_EQ(manager.getRevision(), beforeAddRevision);
|
EXPECT_EQ(manager.getRevision(), beforeAddRevision);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,9 +270,9 @@ namespace
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0));
|
const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0));
|
||||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||||
manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground, [] (auto) {});
|
manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground);
|
||||||
const auto beforeUpdateRevision = manager.getRevision();
|
const auto beforeUpdateRevision = manager.getRevision();
|
||||||
manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto, auto) {});
|
manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||||
EXPECT_EQ(manager.getRevision(), beforeUpdateRevision + 1);
|
EXPECT_EQ(manager.getRevision(), beforeUpdateRevision + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,9 +282,9 @@ namespace
|
||||||
manager.setWorldspace("worldspace");
|
manager.setWorldspace("worldspace");
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||||
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {});
|
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||||
const auto beforeUpdateRevision = manager.getRevision();
|
const auto beforeUpdateRevision = manager.getRevision();
|
||||||
manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto, auto) {});
|
manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||||
EXPECT_EQ(manager.getRevision(), beforeUpdateRevision);
|
EXPECT_EQ(manager.getRevision(), beforeUpdateRevision);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,7 +293,7 @@ namespace
|
||||||
TileCachedRecastMeshManager manager(mSettings);
|
TileCachedRecastMeshManager manager(mSettings);
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||||
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {});
|
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||||
const auto beforeRemoveRevision = manager.getRevision();
|
const auto beforeRemoveRevision = manager.getRevision();
|
||||||
manager.removeObject(ObjectId(&boxShape));
|
manager.removeObject(ObjectId(&boxShape));
|
||||||
EXPECT_EQ(manager.getRevision(), beforeRemoveRevision + 1);
|
EXPECT_EQ(manager.getRevision(), beforeRemoveRevision + 1);
|
||||||
|
@ -303,12 +307,17 @@ namespace
|
||||||
EXPECT_EQ(manager.getRevision(), beforeRemoveRevision);
|
EXPECT_EQ(manager.getRevision(), beforeRemoveRevision);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_water_for_new_water_should_return_true)
|
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_water_for_new_water_should_add_changed_tiles)
|
||||||
{
|
{
|
||||||
TileCachedRecastMeshManager manager(mSettings);
|
TileCachedRecastMeshManager manager(mSettings);
|
||||||
const osg::Vec2i cellPosition(0, 0);
|
const osg::Vec2i cellPosition(0, 0);
|
||||||
const int cellSize = 8192;
|
const int cellSize = 8192;
|
||||||
EXPECT_TRUE(manager.addWater(cellPosition, cellSize, 0.0f));
|
manager.addWater(cellPosition, cellSize, 0.0f);
|
||||||
|
const auto changedTiles = manager.takeChangedTiles();
|
||||||
|
EXPECT_EQ(changedTiles.begin()->first, TilePosition(-1, -1));
|
||||||
|
EXPECT_EQ(changedTiles.rbegin()->first, TilePosition(11, 11));
|
||||||
|
for (const auto& [k, v] : changedTiles)
|
||||||
|
EXPECT_EQ(v, ChangeType::add) << k;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_water_for_not_max_int_should_add_new_tiles)
|
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_water_for_not_max_int_should_add_new_tiles)
|
||||||
|
@ -317,7 +326,7 @@ namespace
|
||||||
manager.setWorldspace("worldspace");
|
manager.setWorldspace("worldspace");
|
||||||
const osg::Vec2i cellPosition(0, 0);
|
const osg::Vec2i cellPosition(0, 0);
|
||||||
const int cellSize = 8192;
|
const int cellSize = 8192;
|
||||||
ASSERT_TRUE(manager.addWater(cellPosition, cellSize, 0.0f));
|
manager.addWater(cellPosition, cellSize, 0.0f);
|
||||||
for (int x = -1; x < 12; ++x)
|
for (int x = -1; x < 12; ++x)
|
||||||
for (int y = -1; y < 12; ++y)
|
for (int y = -1; y < 12; ++y)
|
||||||
ASSERT_NE(manager.getMesh("worldspace", TilePosition(x, y)), nullptr);
|
ASSERT_NE(manager.getMesh("worldspace", TilePosition(x, y)), nullptr);
|
||||||
|
@ -329,30 +338,35 @@ namespace
|
||||||
manager.setWorldspace("worldspace");
|
manager.setWorldspace("worldspace");
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||||
ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {}));
|
ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground));
|
||||||
const osg::Vec2i cellPosition(0, 0);
|
const osg::Vec2i cellPosition(0, 0);
|
||||||
const int cellSize = std::numeric_limits<int>::max();
|
const int cellSize = std::numeric_limits<int>::max();
|
||||||
ASSERT_TRUE(manager.addWater(cellPosition, cellSize, 0.0f));
|
manager.addWater(cellPosition, cellSize, 0.0f);
|
||||||
for (int x = -6; x < 6; ++x)
|
for (int x = -6; x < 6; ++x)
|
||||||
for (int y = -6; y < 6; ++y)
|
for (int y = -6; y < 6; ++y)
|
||||||
ASSERT_EQ(manager.getMesh("worldspace", TilePosition(x, y)) != nullptr, -1 <= x && x <= 0 && -1 <= y && y <= 0);
|
ASSERT_EQ(manager.getMesh("worldspace", TilePosition(x, y)) != nullptr, -1 <= x && x <= 0 && -1 <= y && y <= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, remove_water_for_absent_cell_should_return_nullopt)
|
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, remove_water_for_absent_cell_should_not_add_changed_tiles)
|
||||||
{
|
{
|
||||||
TileCachedRecastMeshManager manager(mSettings);
|
TileCachedRecastMeshManager manager(mSettings);
|
||||||
EXPECT_EQ(manager.removeWater(osg::Vec2i(0, 0)), std::nullopt);
|
manager.removeWater(osg::Vec2i(0, 0));
|
||||||
|
EXPECT_THAT(manager.takeChangedTiles(), ElementsAre());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, remove_water_for_existing_cell_should_return_removed_water)
|
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, remove_water_for_existing_cell_should_add_changed_tiles)
|
||||||
{
|
{
|
||||||
TileCachedRecastMeshManager manager(mSettings);
|
TileCachedRecastMeshManager manager(mSettings);
|
||||||
const osg::Vec2i cellPosition(0, 0);
|
const osg::Vec2i cellPosition(0, 0);
|
||||||
const int cellSize = 8192;
|
const int cellSize = 8192;
|
||||||
ASSERT_TRUE(manager.addWater(cellPosition, cellSize, 0.0f));
|
manager.addWater(cellPosition, cellSize, 0.0f);
|
||||||
const auto result = manager.removeWater(cellPosition);
|
manager.takeChangedTiles();
|
||||||
ASSERT_TRUE(result.has_value());
|
manager.removeWater(cellPosition);
|
||||||
EXPECT_EQ(result->mCellSize, cellSize);
|
const auto changedTiles = manager.takeChangedTiles();
|
||||||
|
EXPECT_EQ(changedTiles.begin()->first, TilePosition(-1, -1));
|
||||||
|
EXPECT_EQ(changedTiles.rbegin()->first, TilePosition(11, 11));
|
||||||
|
for (const auto& [k, v] : changedTiles)
|
||||||
|
EXPECT_EQ(v, ChangeType::remove) << k;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, remove_water_for_existing_cell_should_remove_empty_tiles)
|
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, remove_water_for_existing_cell_should_remove_empty_tiles)
|
||||||
|
@ -361,8 +375,8 @@ namespace
|
||||||
manager.setWorldspace("worldspace");
|
manager.setWorldspace("worldspace");
|
||||||
const osg::Vec2i cellPosition(0, 0);
|
const osg::Vec2i cellPosition(0, 0);
|
||||||
const int cellSize = 8192;
|
const int cellSize = 8192;
|
||||||
ASSERT_TRUE(manager.addWater(cellPosition, cellSize, 0.0f));
|
manager.addWater(cellPosition, cellSize, 0.0f);
|
||||||
ASSERT_TRUE(manager.removeWater(cellPosition));
|
manager.removeWater(cellPosition);
|
||||||
for (int x = -6; x < 6; ++x)
|
for (int x = -6; x < 6; ++x)
|
||||||
for (int y = -6; y < 6; ++y)
|
for (int y = -6; y < 6; ++y)
|
||||||
ASSERT_EQ(manager.getMesh("worldspace", TilePosition(x, y)), nullptr);
|
ASSERT_EQ(manager.getMesh("worldspace", TilePosition(x, y)), nullptr);
|
||||||
|
@ -374,11 +388,11 @@ namespace
|
||||||
manager.setWorldspace("worldspace");
|
manager.setWorldspace("worldspace");
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||||
ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {}));
|
ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground));
|
||||||
const osg::Vec2i cellPosition(0, 0);
|
const osg::Vec2i cellPosition(0, 0);
|
||||||
const int cellSize = 8192;
|
const int cellSize = 8192;
|
||||||
ASSERT_TRUE(manager.addWater(cellPosition, cellSize, 0.0f));
|
manager.addWater(cellPosition, cellSize, 0.0f);
|
||||||
ASSERT_TRUE(manager.removeWater(cellPosition));
|
manager.removeWater(cellPosition);
|
||||||
for (int x = -6; x < 6; ++x)
|
for (int x = -6; x < 6; ++x)
|
||||||
for (int y = -6; y < 6; ++y)
|
for (int y = -6; y < 6; ++y)
|
||||||
ASSERT_EQ(manager.getMesh("worldspace", TilePosition(x, y)) != nullptr, -1 <= x && x <= 0 && -1 <= y && y <= 0);
|
ASSERT_EQ(manager.getMesh("worldspace", TilePosition(x, y)) != nullptr, -1 <= x && x <= 0 && -1 <= y && y <= 0);
|
||||||
|
@ -392,9 +406,9 @@ namespace
|
||||||
const int cellSize = 8192;
|
const int cellSize = 8192;
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
const CollisionShape shape(mInstance, boxShape, mObjectTransform);
|
||||||
ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {}));
|
ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground));
|
||||||
ASSERT_TRUE(manager.addWater(cellPosition, cellSize, 0.0f));
|
manager.addWater(cellPosition, cellSize, 0.0f);
|
||||||
ASSERT_TRUE(manager.removeObject(ObjectId(&boxShape)));
|
manager.removeObject(ObjectId(&boxShape));
|
||||||
for (int x = -1; x < 12; ++x)
|
for (int x = -1; x < 12; ++x)
|
||||||
for (int y = -1; y < 12; ++y)
|
for (int y = -1; y < 12; ++y)
|
||||||
ASSERT_NE(manager.getMesh("worldspace", TilePosition(x, y)), nullptr);
|
ASSERT_NE(manager.getMesh("worldspace", TilePosition(x, y)), nullptr);
|
||||||
|
@ -406,14 +420,14 @@ namespace
|
||||||
manager.setWorldspace("worldspace");
|
manager.setWorldspace("worldspace");
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
const CollisionShape shape(nullptr, boxShape, mObjectTransform);
|
const CollisionShape shape(nullptr, boxShape, mObjectTransform);
|
||||||
ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {}));
|
ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground));
|
||||||
manager.setWorldspace("other");
|
manager.setWorldspace("other");
|
||||||
for (int x = -1; x < 1; ++x)
|
for (int x = -1; x < 1; ++x)
|
||||||
for (int y = -1; y < 1; ++y)
|
for (int y = -1; y < 1; ++y)
|
||||||
ASSERT_EQ(manager.getMesh("other", TilePosition(x, y)), nullptr);
|
ASSERT_EQ(manager.getMesh("other", TilePosition(x, y)), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, set_bounds_should_return_changed_tiles)
|
TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, set_bounds_should_add_changed_tiles)
|
||||||
{
|
{
|
||||||
TileCachedRecastMeshManager manager(mSettings);
|
TileCachedRecastMeshManager manager(mSettings);
|
||||||
const btBoxShape boxShape(btVector3(20, 20, 100));
|
const btBoxShape boxShape(btVector3(20, 20, 100));
|
||||||
|
@ -422,10 +436,12 @@ namespace
|
||||||
bounds.mMin = osg::Vec2f(182, 0);
|
bounds.mMin = osg::Vec2f(182, 0);
|
||||||
bounds.mMax = osg::Vec2f(1000, 1000);
|
bounds.mMax = osg::Vec2f(1000, 1000);
|
||||||
manager.setBounds(bounds);
|
manager.setBounds(bounds);
|
||||||
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, [] (auto) {});
|
manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground);
|
||||||
bounds.mMin = osg::Vec2f(-1000, -1000);
|
bounds.mMin = osg::Vec2f(-1000, -1000);
|
||||||
bounds.mMax = osg::Vec2f(0, -182);
|
bounds.mMax = osg::Vec2f(0, -182);
|
||||||
EXPECT_THAT(manager.setBounds(bounds), ElementsAre(
|
manager.takeChangedTiles();
|
||||||
|
manager.setBounds(bounds);
|
||||||
|
EXPECT_THAT(manager.takeChangedTiles(), ElementsAre(
|
||||||
std::pair(TilePosition(-1, -1), ChangeType::add),
|
std::pair(TilePosition(-1, -1), ChangeType::add),
|
||||||
std::pair(TilePosition(0, 0), ChangeType::remove)
|
std::pair(TilePosition(0, 0), ChangeType::remove)
|
||||||
));
|
));
|
||||||
|
|
|
@ -23,12 +23,12 @@ namespace DetourNavigator
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<RemovedRecastMeshObject> CachedRecastMeshManager::removeObject(const ObjectId id)
|
bool CachedRecastMeshManager::removeObject(const ObjectId id)
|
||||||
{
|
{
|
||||||
auto object = mImpl.removeObject(id);
|
const bool result = mImpl.removeObject(id);
|
||||||
if (object)
|
if (result)
|
||||||
mOutdatedCache = true;
|
mOutdatedCache = true;
|
||||||
return object;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CachedRecastMeshManager::addWater(const osg::Vec2i& cellPosition, int cellSize, float level)
|
bool CachedRecastMeshManager::addWater(const osg::Vec2i& cellPosition, int cellSize, float level)
|
||||||
|
@ -39,12 +39,12 @@ namespace DetourNavigator
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Water> CachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition)
|
bool CachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition)
|
||||||
{
|
{
|
||||||
const auto water = mImpl.removeWater(cellPosition);
|
const bool result = mImpl.removeWater(cellPosition);
|
||||||
if (water)
|
if (result)
|
||||||
mOutdatedCache = true;
|
mOutdatedCache = true;
|
||||||
return water;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CachedRecastMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize,
|
bool CachedRecastMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize,
|
||||||
|
@ -56,12 +56,12 @@ namespace DetourNavigator
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<SizedHeightfieldShape> CachedRecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition)
|
bool CachedRecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition)
|
||||||
{
|
{
|
||||||
const auto heightfield = mImpl.removeHeightfield(cellPosition);
|
const bool result = mImpl.removeHeightfield(cellPosition);
|
||||||
if (heightfield)
|
if (result)
|
||||||
mOutdatedCache = true;
|
mOutdatedCache = true;
|
||||||
return heightfield;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<RecastMesh> CachedRecastMeshManager::getMesh()
|
std::shared_ptr<RecastMesh> CachedRecastMeshManager::getMesh()
|
||||||
|
|
|
@ -21,15 +21,15 @@ namespace DetourNavigator
|
||||||
|
|
||||||
bool updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType);
|
bool updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType);
|
||||||
|
|
||||||
std::optional<RemovedRecastMeshObject> removeObject(const ObjectId id);
|
bool removeObject(const ObjectId id);
|
||||||
|
|
||||||
bool addWater(const osg::Vec2i& cellPosition, int cellSize, float level);
|
bool addWater(const osg::Vec2i& cellPosition, int cellSize, float level);
|
||||||
|
|
||||||
std::optional<Water> removeWater(const osg::Vec2i& cellPosition);
|
bool removeWater(const osg::Vec2i& cellPosition);
|
||||||
|
|
||||||
bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape);
|
bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape);
|
||||||
|
|
||||||
std::optional<SizedHeightfieldShape> removeHeightfield(const osg::Vec2i& cellPosition);
|
bool removeHeightfield(const osg::Vec2i& cellPosition);
|
||||||
|
|
||||||
std::shared_ptr<RecastMesh> getMesh();
|
std::shared_ptr<RecastMesh> getMesh();
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,11 @@ namespace DetourNavigator
|
||||||
add = 2,
|
add = 2,
|
||||||
update = 3,
|
update = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline ChangeType addChangeType(const ChangeType current, const ChangeType add)
|
||||||
|
{
|
||||||
|
return current == add ? current : ChangeType::mixed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -149,8 +149,7 @@ namespace DetourNavigator
|
||||||
void NavigatorImpl::update(const osg::Vec3f& playerPosition)
|
void NavigatorImpl::update(const osg::Vec3f& playerPosition)
|
||||||
{
|
{
|
||||||
removeUnusedNavMeshes();
|
removeUnusedNavMeshes();
|
||||||
for (const auto& v : mAgents)
|
mNavMeshManager.update(playerPosition);
|
||||||
mNavMeshManager.update(playerPosition, v.first);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavigatorImpl::wait(Loading::Listener& listener, WaitConditionType waitConditionType)
|
void NavigatorImpl::wait(Loading::Listener& listener, WaitConditionType waitConditionType)
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "settings.hpp"
|
#include "settings.hpp"
|
||||||
#include "waitconditiontype.hpp"
|
#include "waitconditiontype.hpp"
|
||||||
#include "settingsutils.hpp"
|
#include "settingsutils.hpp"
|
||||||
|
#include "cachedrecastmeshmanager.hpp"
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/bullethelpers/heightfield.hpp>
|
#include <components/bullethelpers/heightfield.hpp>
|
||||||
|
@ -20,13 +21,6 @@
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
using DetourNavigator::ChangeType;
|
|
||||||
|
|
||||||
ChangeType addChangeType(const ChangeType current, const ChangeType add)
|
|
||||||
{
|
|
||||||
return current == add ? current : ChangeType::mixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Safely reset shared_ptr with definite underlying object destrutor call.
|
/// Safely reset shared_ptr with definite underlying object destrutor call.
|
||||||
/// Assuming there is another thread holding copy of this shared_ptr or weak_ptr to this shared_ptr.
|
/// Assuming there is another thread holding copy of this shared_ptr or weak_ptr to this shared_ptr.
|
||||||
template <class T>
|
template <class T>
|
||||||
|
@ -78,75 +72,44 @@ namespace DetourNavigator
|
||||||
{
|
{
|
||||||
const TileBounds bounds = makeBounds(mSettings.mRecast, osg::Vec2f(playerPosition.x(), playerPosition.y()),
|
const TileBounds bounds = makeBounds(mSettings.mRecast, osg::Vec2f(playerPosition.x(), playerPosition.y()),
|
||||||
mSettings.mMaxTilesNumber);
|
mSettings.mMaxTilesNumber);
|
||||||
const auto changedTiles = mRecastMeshManager.setBounds(bounds);
|
mRecastMeshManager.setBounds(bounds);
|
||||||
for (const auto& [agent, cache] : mCache)
|
|
||||||
{
|
|
||||||
auto& tiles = mChangedTiles[agent];
|
|
||||||
for (const auto& [tilePosition, changeType] : changedTiles)
|
|
||||||
{
|
|
||||||
auto tile = tiles.find(tilePosition);
|
|
||||||
if (tile == tiles.end())
|
|
||||||
tiles.emplace_hint(tile, tilePosition, changeType);
|
|
||||||
else
|
|
||||||
tile->second = addChangeType(tile->second, changeType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NavMeshManager::addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform,
|
bool NavMeshManager::addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform,
|
||||||
const AreaType areaType)
|
const AreaType areaType)
|
||||||
{
|
{
|
||||||
return mRecastMeshManager.addObject(id, shape, transform, areaType,
|
return mRecastMeshManager.addObject(id, shape, transform, areaType);
|
||||||
[&] (const TilePosition& tile) { addChangedTile(tile, ChangeType::add); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NavMeshManager::updateObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform,
|
bool NavMeshManager::updateObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform,
|
||||||
const AreaType areaType)
|
const AreaType areaType)
|
||||||
{
|
{
|
||||||
return mRecastMeshManager.updateObject(id, shape, transform, areaType,
|
return mRecastMeshManager.updateObject(id, shape, transform, areaType);
|
||||||
[&] (const TilePosition& tile, ChangeType changeType) { addChangedTile(tile, changeType); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavMeshManager::removeObject(const ObjectId id)
|
void NavMeshManager::removeObject(const ObjectId id)
|
||||||
{
|
{
|
||||||
const auto object = mRecastMeshManager.removeObject(id);
|
mRecastMeshManager.removeObject(id);
|
||||||
if (!object)
|
|
||||||
return;
|
|
||||||
addChangedTiles(object->mShape, object->mTransform, ChangeType::remove);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavMeshManager::addWater(const osg::Vec2i& cellPosition, int cellSize, float level)
|
void NavMeshManager::addWater(const osg::Vec2i& cellPosition, int cellSize, float level)
|
||||||
{
|
{
|
||||||
if (!mRecastMeshManager.addWater(cellPosition, cellSize, level))
|
mRecastMeshManager.addWater(cellPosition, cellSize, level);
|
||||||
return;
|
|
||||||
const btVector3 shift = Misc::Convert::toBullet(getWaterShift3d(cellPosition, cellSize, level));
|
|
||||||
addChangedTiles(cellSize, shift, ChangeType::add);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavMeshManager::removeWater(const osg::Vec2i& cellPosition)
|
void NavMeshManager::removeWater(const osg::Vec2i& cellPosition)
|
||||||
{
|
{
|
||||||
const auto water = mRecastMeshManager.removeWater(cellPosition);
|
mRecastMeshManager.removeWater(cellPosition);
|
||||||
if (!water)
|
|
||||||
return;
|
|
||||||
const btVector3 shift = Misc::Convert::toBullet(getWaterShift3d(cellPosition, water->mCellSize, water->mLevel));
|
|
||||||
addChangedTiles(water->mCellSize, shift, ChangeType::remove);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape)
|
void NavMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape)
|
||||||
{
|
{
|
||||||
if (!mRecastMeshManager.addHeightfield(cellPosition, cellSize, shape))
|
mRecastMeshManager.addHeightfield(cellPosition, cellSize, shape);
|
||||||
return;
|
|
||||||
const btVector3 shift = getHeightfieldShift(shape, cellPosition, cellSize);
|
|
||||||
addChangedTiles(cellSize, shift, ChangeType::add);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavMeshManager::removeHeightfield(const osg::Vec2i& cellPosition)
|
void NavMeshManager::removeHeightfield(const osg::Vec2i& cellPosition)
|
||||||
{
|
{
|
||||||
const auto heightfield = mRecastMeshManager.removeHeightfield(cellPosition);
|
mRecastMeshManager.removeHeightfield(cellPosition);
|
||||||
if (!heightfield)
|
|
||||||
return;
|
|
||||||
const btVector3 shift = getHeightfieldShift(heightfield->mShape, cellPosition, heightfield->mCellSize);
|
|
||||||
addChangedTiles(heightfield->mCellSize, shift, ChangeType::remove);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavMeshManager::addAgent(const AgentBounds& agentBounds)
|
void NavMeshManager::addAgent(const AgentBounds& agentBounds)
|
||||||
|
@ -156,6 +119,7 @@ namespace DetourNavigator
|
||||||
return;
|
return;
|
||||||
mCache.insert(std::make_pair(agentBounds,
|
mCache.insert(std::make_pair(agentBounds,
|
||||||
std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), ++mGenerationCounter)));
|
std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), ++mGenerationCounter)));
|
||||||
|
mPlayerTile.reset();
|
||||||
Log(Debug::Debug) << "cache add for agent=" << agentBounds;
|
Log(Debug::Debug) << "cache add for agent=" << agentBounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,9 +131,7 @@ namespace DetourNavigator
|
||||||
if (!resetIfUnique(it->second))
|
if (!resetIfUnique(it->second))
|
||||||
return false;
|
return false;
|
||||||
mCache.erase(agentBounds);
|
mCache.erase(agentBounds);
|
||||||
mChangedTiles.erase(agentBounds);
|
mPlayerTile.reset();
|
||||||
mPlayerTile.erase(agentBounds);
|
|
||||||
mLastRecastMeshManagerRevision.erase(agentBounds);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,54 +142,49 @@ namespace DetourNavigator
|
||||||
const auto startTilePosition = getTilePosition(mSettings.mRecast, start);
|
const auto startTilePosition = getTilePosition(mSettings.mRecast, start);
|
||||||
const auto endTilePosition = getTilePosition(mSettings.mRecast, end);
|
const auto endTilePosition = getTilePosition(mSettings.mRecast, end);
|
||||||
|
|
||||||
addChangedTile(startTilePosition, ChangeType::add);
|
mRecastMeshManager.addChangedTile(startTilePosition, ChangeType::add);
|
||||||
|
|
||||||
if (startTilePosition != endTilePosition)
|
if (startTilePosition != endTilePosition)
|
||||||
addChangedTile(endTilePosition, ChangeType::add);
|
mRecastMeshManager.addChangedTile(endTilePosition, ChangeType::add);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavMeshManager::removeOffMeshConnections(const ObjectId id)
|
void NavMeshManager::removeOffMeshConnections(const ObjectId id)
|
||||||
{
|
{
|
||||||
const auto changedTiles = mOffMeshConnectionsManager.remove(id);
|
const auto changedTiles = mOffMeshConnectionsManager.remove(id);
|
||||||
for (const auto& tile : changedTiles)
|
for (const auto& tile : changedTiles)
|
||||||
addChangedTile(tile, ChangeType::update);
|
mRecastMeshManager.addChangedTile(tile, ChangeType::update);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavMeshManager::update(const osg::Vec3f& playerPosition, const AgentBounds& agentBounds)
|
void NavMeshManager::update(const osg::Vec3f& playerPosition)
|
||||||
{
|
{
|
||||||
const auto playerTile = getTilePosition(mSettings.mRecast, toNavMeshCoordinates(mSettings.mRecast, playerPosition));
|
const auto playerTile = getTilePosition(mSettings.mRecast,
|
||||||
auto& lastRevision = mLastRecastMeshManagerRevision[agentBounds];
|
toNavMeshCoordinates(mSettings.mRecast, playerPosition));
|
||||||
auto lastPlayerTile = mPlayerTile.find(agentBounds);
|
if (mLastRecastMeshManagerRevision == mRecastMeshManager.getRevision()
|
||||||
if (lastRevision == mRecastMeshManager.getRevision() && lastPlayerTile != mPlayerTile.end()
|
&& mPlayerTile.has_value() && *mPlayerTile == playerTile)
|
||||||
&& lastPlayerTile->second == playerTile)
|
|
||||||
return;
|
return;
|
||||||
lastRevision = mRecastMeshManager.getRevision();
|
mLastRecastMeshManagerRevision = mRecastMeshManager.getRevision();
|
||||||
if (lastPlayerTile == mPlayerTile.end())
|
mPlayerTile = playerTile;
|
||||||
lastPlayerTile = mPlayerTile.insert(std::make_pair(agentBounds, playerTile)).first;
|
const auto changedTiles = mRecastMeshManager.takeChangedTiles();
|
||||||
else
|
for (const auto& [agentBounds, cached] : mCache)
|
||||||
lastPlayerTile->second = playerTile;
|
update(agentBounds, playerTile, cached, changedTiles);
|
||||||
std::map<TilePosition, ChangeType> tilesToPost;
|
|
||||||
const auto cached = getCached(agentBounds);
|
|
||||||
if (!cached)
|
|
||||||
{
|
|
||||||
std::ostringstream stream;
|
|
||||||
stream << "Agent with half extents is not found: " << agentBounds;
|
|
||||||
throw InvalidArgument(stream.str());
|
|
||||||
}
|
}
|
||||||
const auto changedTiles = mChangedTiles.find(agentBounds);
|
|
||||||
|
void NavMeshManager::update(const AgentBounds& agentBounds, const TilePosition& playerTile,
|
||||||
|
const SharedNavMeshCacheItem& cached, const std::map<osg::Vec2i, ChangeType>& changedTiles)
|
||||||
|
{
|
||||||
|
std::map<TilePosition, ChangeType> tilesToPost;
|
||||||
{
|
{
|
||||||
const auto locked = cached->lockConst();
|
const auto locked = cached->lockConst();
|
||||||
const auto& navMesh = locked->getImpl();
|
const auto& navMesh = locked->getImpl();
|
||||||
if (changedTiles != mChangedTiles.end())
|
for (const auto& [tilePosition, changeType] : changedTiles)
|
||||||
{
|
{
|
||||||
for (const auto& tile : changedTiles->second)
|
if (navMesh.getTileAt(tilePosition.x(), tilePosition.y(), 0))
|
||||||
if (navMesh.getTileAt(tile.first.x(), tile.first.y(), 0))
|
|
||||||
{
|
{
|
||||||
auto tileToPost = tilesToPost.find(tile.first);
|
auto tileToPost = tilesToPost.find(tilePosition);
|
||||||
if (tileToPost == tilesToPost.end())
|
if (tileToPost == tilesToPost.end())
|
||||||
tilesToPost.insert(tile);
|
tilesToPost.emplace(tilePosition, changeType);
|
||||||
else
|
else
|
||||||
tileToPost->second = addChangeType(tileToPost->second, tile.second);
|
tileToPost->second = addChangeType(tileToPost->second, changeType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto maxTiles = std::min(mSettings.mMaxTilesNumber, navMesh.getParams()->maxTiles);
|
const auto maxTiles = std::min(mSettings.mMaxTilesNumber, navMesh.getParams()->maxTiles);
|
||||||
|
@ -238,19 +195,16 @@ namespace DetourNavigator
|
||||||
const auto shouldAdd = shouldAddTile(tile, playerTile, maxTiles);
|
const auto shouldAdd = shouldAddTile(tile, playerTile, maxTiles);
|
||||||
const auto presentInNavMesh = bool(navMesh.getTileAt(tile.x(), tile.y(), 0));
|
const auto presentInNavMesh = bool(navMesh.getTileAt(tile.x(), tile.y(), 0));
|
||||||
if (shouldAdd && !presentInNavMesh)
|
if (shouldAdd && !presentInNavMesh)
|
||||||
tilesToPost.insert(std::make_pair(tile, locked->isEmptyTile(tile) ? ChangeType::update : ChangeType::add));
|
tilesToPost.emplace(tile, locked->isEmptyTile(tile) ? ChangeType::update : ChangeType::add);
|
||||||
else if (!shouldAdd && presentInNavMesh)
|
else if (!shouldAdd && presentInNavMesh)
|
||||||
tilesToPost.insert(std::make_pair(tile, ChangeType::mixed));
|
tilesToPost.emplace(tile, ChangeType::mixed);
|
||||||
else
|
else
|
||||||
recastMeshManager.reportNavMeshChange(recastMeshManager.getVersion(), Version {0, 0});
|
recastMeshManager.reportNavMeshChange(recastMeshManager.getVersion(), Version {0, 0});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
mAsyncNavMeshUpdater.post(agentBounds, cached, playerTile, mRecastMeshManager.getWorldspace(), tilesToPost);
|
mAsyncNavMeshUpdater.post(agentBounds, cached, playerTile, mRecastMeshManager.getWorldspace(), tilesToPost);
|
||||||
if (changedTiles != mChangedTiles.end())
|
|
||||||
changedTiles->second.clear();
|
|
||||||
Log(Debug::Debug) << "Cache update posted for agent=" << agentBounds <<
|
Log(Debug::Debug) << "Cache update posted for agent=" << agentBounds <<
|
||||||
" playerTile=" << lastPlayerTile->second <<
|
" playerTile=" << playerTile << " recastMeshManagerRevision=" << mLastRecastMeshManagerRevision;
|
||||||
" recastMeshManagerRevision=" << lastRevision;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavMeshManager::wait(Loading::Listener& listener, WaitConditionType waitConditionType)
|
void NavMeshManager::wait(Loading::Listener& listener, WaitConditionType waitConditionType)
|
||||||
|
@ -286,37 +240,6 @@ namespace DetourNavigator
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavMeshManager::addChangedTiles(const btCollisionShape& shape, const btTransform& transform,
|
|
||||||
const ChangeType changeType)
|
|
||||||
{
|
|
||||||
const auto bounds = mRecastMeshManager.getBounds();
|
|
||||||
getTilesPositions(makeTilesPositionsRange(shape, transform, bounds, mSettings.mRecast),
|
|
||||||
[&] (const TilePosition& v) { addChangedTile(v, changeType); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void NavMeshManager::addChangedTiles(const int cellSize, const btVector3& shift,
|
|
||||||
const ChangeType changeType)
|
|
||||||
{
|
|
||||||
if (cellSize == std::numeric_limits<int>::max())
|
|
||||||
return;
|
|
||||||
|
|
||||||
getTilesPositions(makeTilesPositionsRange(cellSize, shift, mSettings.mRecast),
|
|
||||||
[&] (const TilePosition& v) { addChangedTile(v, changeType); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void NavMeshManager::addChangedTile(const TilePosition& tilePosition, const ChangeType changeType)
|
|
||||||
{
|
|
||||||
for (const auto& cached : mCache)
|
|
||||||
{
|
|
||||||
auto& tiles = mChangedTiles[cached.first];
|
|
||||||
auto tile = tiles.find(tilePosition);
|
|
||||||
if (tile == tiles.end())
|
|
||||||
tiles.insert(std::make_pair(tilePosition, changeType));
|
|
||||||
else
|
|
||||||
tile->second = addChangeType(tile->second, changeType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedNavMeshCacheItem NavMeshManager::getCached(const AgentBounds& agentBounds) const
|
SharedNavMeshCacheItem NavMeshManager::getCached(const AgentBounds& agentBounds) const
|
||||||
{
|
{
|
||||||
const auto cached = mCache.find(agentBounds);
|
const auto cached = mCache.find(agentBounds);
|
||||||
|
|
|
@ -50,7 +50,7 @@ namespace DetourNavigator
|
||||||
|
|
||||||
void removeOffMeshConnections(const ObjectId id);
|
void removeOffMeshConnections(const ObjectId id);
|
||||||
|
|
||||||
void update(const osg::Vec3f& playerPosition, const AgentBounds& agentBounds);
|
void update(const osg::Vec3f& playerPosition);
|
||||||
|
|
||||||
void wait(Loading::Listener& listener, WaitConditionType waitConditionType);
|
void wait(Loading::Listener& listener, WaitConditionType waitConditionType);
|
||||||
|
|
||||||
|
@ -69,18 +69,14 @@ namespace DetourNavigator
|
||||||
OffMeshConnectionsManager mOffMeshConnectionsManager;
|
OffMeshConnectionsManager mOffMeshConnectionsManager;
|
||||||
AsyncNavMeshUpdater mAsyncNavMeshUpdater;
|
AsyncNavMeshUpdater mAsyncNavMeshUpdater;
|
||||||
std::map<AgentBounds, SharedNavMeshCacheItem> mCache;
|
std::map<AgentBounds, SharedNavMeshCacheItem> mCache;
|
||||||
std::map<AgentBounds, std::map<TilePosition, ChangeType>> mChangedTiles;
|
|
||||||
std::size_t mGenerationCounter = 0;
|
std::size_t mGenerationCounter = 0;
|
||||||
std::map<AgentBounds, TilePosition> mPlayerTile;
|
std::optional<TilePosition> mPlayerTile;
|
||||||
std::map<AgentBounds, std::size_t> mLastRecastMeshManagerRevision;
|
std::size_t mLastRecastMeshManagerRevision = 0;
|
||||||
|
|
||||||
void addChangedTiles(const btCollisionShape& shape, const btTransform& transform, const ChangeType changeType);
|
inline SharedNavMeshCacheItem getCached(const AgentBounds& agentBounds) const;
|
||||||
|
|
||||||
void addChangedTiles(const int cellSize, const btVector3& shift, const ChangeType changeType);
|
inline void update(const AgentBounds& agentBounds, const TilePosition& playerTile,
|
||||||
|
const SharedNavMeshCacheItem& cached, const std::map<osg::Vec2i, ChangeType>& changedTiles);
|
||||||
void addChangedTile(const TilePosition& tilePosition, const ChangeType changeType);
|
|
||||||
|
|
||||||
SharedNavMeshCacheItem getCached(const AgentBounds& agentBounds) const;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,16 +62,15 @@ namespace DetourNavigator
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<RemovedRecastMeshObject> RecastMeshManager::removeObject(const ObjectId id)
|
bool RecastMeshManager::removeObject(const ObjectId id)
|
||||||
{
|
{
|
||||||
const std::lock_guard lock(mMutex);
|
const std::lock_guard lock(mMutex);
|
||||||
const auto object = mObjects.find(id);
|
const auto object = mObjects.find(id);
|
||||||
if (object == mObjects.end())
|
if (object == mObjects.end())
|
||||||
return std::nullopt;
|
return false;
|
||||||
const RemovedRecastMeshObject result {object->second.getImpl().getShape(), object->second.getImpl().getTransform()};
|
|
||||||
mObjects.erase(object);
|
mObjects.erase(object);
|
||||||
++mRevision;
|
++mRevision;
|
||||||
return result;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RecastMeshManager::addWater(const osg::Vec2i& cellPosition, int cellSize, float level)
|
bool RecastMeshManager::addWater(const osg::Vec2i& cellPosition, int cellSize, float level)
|
||||||
|
@ -83,16 +82,15 @@ namespace DetourNavigator
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Water> RecastMeshManager::removeWater(const osg::Vec2i& cellPosition)
|
bool RecastMeshManager::removeWater(const osg::Vec2i& cellPosition)
|
||||||
{
|
{
|
||||||
const std::lock_guard lock(mMutex);
|
const std::lock_guard lock(mMutex);
|
||||||
const auto water = mWater.find(cellPosition);
|
const auto water = mWater.find(cellPosition);
|
||||||
if (water == mWater.end())
|
if (water == mWater.end())
|
||||||
return std::nullopt;
|
return false;
|
||||||
++mRevision;
|
++mRevision;
|
||||||
Water result = water->second;
|
|
||||||
mWater.erase(water);
|
mWater.erase(water);
|
||||||
return result;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RecastMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize,
|
bool RecastMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize,
|
||||||
|
@ -105,16 +103,15 @@ namespace DetourNavigator
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<SizedHeightfieldShape> RecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition)
|
bool RecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition)
|
||||||
{
|
{
|
||||||
const std::lock_guard lock(mMutex);
|
const std::lock_guard lock(mMutex);
|
||||||
const auto it = mHeightfields.find(cellPosition);
|
const auto it = mHeightfields.find(cellPosition);
|
||||||
if (it == mHeightfields.end())
|
if (it == mHeightfields.end())
|
||||||
return std::nullopt;
|
return false;
|
||||||
++mRevision;
|
++mRevision;
|
||||||
auto result = std::make_optional(it->second);
|
|
||||||
mHeightfields.erase(it);
|
mHeightfields.erase(it);
|
||||||
return result;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<RecastMesh> RecastMeshManager::getMesh() const
|
std::shared_ptr<RecastMesh> RecastMeshManager::getMesh() const
|
||||||
|
|
|
@ -23,12 +23,6 @@ namespace DetourNavigator
|
||||||
struct Settings;
|
struct Settings;
|
||||||
class RecastMesh;
|
class RecastMesh;
|
||||||
|
|
||||||
struct RemovedRecastMeshObject
|
|
||||||
{
|
|
||||||
std::reference_wrapper<const btCollisionShape> mShape;
|
|
||||||
btTransform mTransform;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SizedHeightfieldShape
|
struct SizedHeightfieldShape
|
||||||
{
|
{
|
||||||
int mCellSize;
|
int mCellSize;
|
||||||
|
@ -45,15 +39,15 @@ namespace DetourNavigator
|
||||||
|
|
||||||
bool updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType);
|
bool updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType);
|
||||||
|
|
||||||
std::optional<RemovedRecastMeshObject> removeObject(const ObjectId id);
|
bool removeObject(const ObjectId id);
|
||||||
|
|
||||||
bool addWater(const osg::Vec2i& cellPosition, int cellSize, float level);
|
bool addWater(const osg::Vec2i& cellPosition, int cellSize, float level);
|
||||||
|
|
||||||
std::optional<Water> removeWater(const osg::Vec2i& cellPosition);
|
bool removeWater(const osg::Vec2i& cellPosition);
|
||||||
|
|
||||||
bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape);
|
bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape);
|
||||||
|
|
||||||
std::optional<SizedHeightfieldShape> removeHeightfield(const osg::Vec2i& cellPosition);
|
bool removeHeightfield(const osg::Vec2i& cellPosition);
|
||||||
|
|
||||||
std::shared_ptr<RecastMesh> getMesh() const;
|
std::shared_ptr<RecastMesh> getMesh() const;
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "gettilespositions.hpp"
|
#include "gettilespositions.hpp"
|
||||||
#include "settingsutils.hpp"
|
#include "settingsutils.hpp"
|
||||||
#include "changetype.hpp"
|
#include "changetype.hpp"
|
||||||
|
#include "cachedrecastmeshmanager.hpp"
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/misc/convert.hpp>
|
#include <components/misc/convert.hpp>
|
||||||
|
@ -18,6 +19,13 @@ namespace DetourNavigator
|
||||||
osg::Vec2f(-std::numeric_limits<float>::max(), -std::numeric_limits<float>::max()),
|
osg::Vec2f(-std::numeric_limits<float>::max(), -std::numeric_limits<float>::max()),
|
||||||
osg::Vec2f(std::numeric_limits<float>::max(), std::numeric_limits<float>::max())
|
osg::Vec2f(std::numeric_limits<float>::max(), std::numeric_limits<float>::max())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool updateTile(const ObjectId id, const btTransform& transform, const AreaType areaType,
|
||||||
|
const TilePosition& tilePosition, std::map<TilePosition, std::shared_ptr<CachedRecastMeshManager>>& tiles)
|
||||||
|
{
|
||||||
|
const auto tile = tiles.find(tilePosition);
|
||||||
|
return tile != tiles.end() && tile->second->updateObject(id, transform, areaType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TileCachedRecastMeshManager::TileCachedRecastMeshManager(const RecastSettings& settings)
|
TileCachedRecastMeshManager::TileCachedRecastMeshManager(const RecastSettings& settings)
|
||||||
|
@ -26,18 +34,12 @@ namespace DetourNavigator
|
||||||
, mRange(makeTilesPositionsRange(mBounds.mMin, mBounds.mMax, mSettings))
|
, mRange(makeTilesPositionsRange(mBounds.mMin, mBounds.mMax, mSettings))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
TileBounds TileCachedRecastMeshManager::getBounds() const
|
void TileCachedRecastMeshManager::setBounds(const TileBounds& bounds)
|
||||||
{
|
{
|
||||||
return mBounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::pair<TilePosition, ChangeType>> TileCachedRecastMeshManager::setBounds(const TileBounds& bounds)
|
|
||||||
{
|
|
||||||
std::vector<std::pair<TilePosition, ChangeType>> changedTiles;
|
|
||||||
|
|
||||||
if (mBounds == bounds)
|
if (mBounds == bounds)
|
||||||
return changedTiles;
|
return;
|
||||||
|
|
||||||
|
bool changed = false;
|
||||||
const auto newRange = makeTilesPositionsRange(bounds.mMin, bounds.mMax, mSettings);
|
const auto newRange = makeTilesPositionsRange(bounds.mMin, bounds.mMax, mSettings);
|
||||||
|
|
||||||
if (mBounds != infiniteTileBounds)
|
if (mBounds != infiniteTileBounds)
|
||||||
|
@ -58,7 +60,10 @@ namespace DetourNavigator
|
||||||
return;
|
return;
|
||||||
data.mTiles.erase(it);
|
data.mTiles.erase(it);
|
||||||
if (removeTile(id, position, locked->mTiles))
|
if (removeTile(id, position, locked->mTiles))
|
||||||
changedTiles.emplace_back(position, ChangeType::remove);
|
{
|
||||||
|
addChangedTile(position, ChangeType::remove);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
getTilesPositions(getIntersection(mRange, objectRange), onOldTilePosition);
|
getTilesPositions(getIntersection(mRange, objectRange), onOldTilePosition);
|
||||||
|
|
||||||
|
@ -69,23 +74,18 @@ namespace DetourNavigator
|
||||||
if (addTile(id, data.mShape, data.mTransform, data.mAreaType, position, locked->mTiles))
|
if (addTile(id, data.mShape, data.mTransform, data.mAreaType, position, locked->mTiles))
|
||||||
{
|
{
|
||||||
data.mTiles.insert(position);
|
data.mTiles.insert(position);
|
||||||
changedTiles.emplace_back(position, ChangeType::add);
|
addChangedTile(position, ChangeType::add);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
getTilesPositions(getIntersection(newRange, objectRange), onNewTilePosition);
|
getTilesPositions(getIntersection(newRange, objectRange), onNewTilePosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(changedTiles.begin(), changedTiles.end());
|
|
||||||
changedTiles.erase(std::unique(changedTiles.begin(), changedTiles.end()), changedTiles.end());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!changedTiles.empty())
|
if (changed)
|
||||||
++mRevision;
|
++mRevision;
|
||||||
|
|
||||||
mBounds = bounds;
|
mBounds = bounds;
|
||||||
mRange = newRange;
|
mRange = newRange;
|
||||||
|
|
||||||
return changedTiles;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TileCachedRecastMeshManager::getWorldspace() const
|
std::string TileCachedRecastMeshManager::getWorldspace() const
|
||||||
|
@ -102,47 +102,125 @@ namespace DetourNavigator
|
||||||
locked->mWorldspace = worldspace;
|
locked->mWorldspace = worldspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<RemovedRecastMeshObject> TileCachedRecastMeshManager::removeObject(const ObjectId id)
|
bool TileCachedRecastMeshManager::addObject(const ObjectId id, const CollisionShape& shape,
|
||||||
|
const btTransform& transform, const AreaType areaType)
|
||||||
|
{
|
||||||
|
auto it = mObjects.find(id);
|
||||||
|
if (it != mObjects.end())
|
||||||
|
return false;
|
||||||
|
const TilesPositionsRange objectRange = makeTilesPositionsRange(shape.getShape(), transform, mSettings);
|
||||||
|
const TilesPositionsRange range = getIntersection(mRange, objectRange);
|
||||||
|
std::set<TilePosition> tilesPositions;
|
||||||
|
if (range.mBegin != range.mEnd)
|
||||||
|
{
|
||||||
|
const auto locked = mWorldspaceTiles.lock();
|
||||||
|
getTilesPositions(range,
|
||||||
|
[&] (const TilePosition& tilePosition)
|
||||||
|
{
|
||||||
|
if (addTile(id, shape, transform, areaType, tilePosition, locked->mTiles))
|
||||||
|
{
|
||||||
|
tilesPositions.insert(tilePosition);
|
||||||
|
addChangedTile(tilePosition, ChangeType::add);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
mObjects.emplace_hint(it, id, ObjectData {shape, transform, areaType, std::move(tilesPositions)});
|
||||||
|
++mRevision;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TileCachedRecastMeshManager::updateObject(const ObjectId id, const CollisionShape& shape,
|
||||||
|
const btTransform& transform, AreaType areaType)
|
||||||
{
|
{
|
||||||
const auto object = mObjects.find(id);
|
const auto object = mObjects.find(id);
|
||||||
if (object == mObjects.end())
|
if (object == mObjects.end())
|
||||||
return std::nullopt;
|
return false;
|
||||||
std::optional<RemovedRecastMeshObject> result;
|
auto& data = object->second;
|
||||||
|
bool changed = false;
|
||||||
|
std::set<TilePosition> newTiles;
|
||||||
|
{
|
||||||
|
const TilesPositionsRange objectRange = makeTilesPositionsRange(shape.getShape(), transform, mSettings);
|
||||||
|
const TilesPositionsRange range = getIntersection(mRange, objectRange);
|
||||||
|
const auto locked = mWorldspaceTiles.lock();
|
||||||
|
const auto onTilePosition = [&] (const TilePosition& tilePosition)
|
||||||
|
{
|
||||||
|
if (data.mTiles.find(tilePosition) != data.mTiles.end())
|
||||||
|
{
|
||||||
|
newTiles.insert(tilePosition);
|
||||||
|
if (updateTile(id, transform, areaType, tilePosition, locked->mTiles))
|
||||||
|
{
|
||||||
|
addChangedTile(tilePosition, ChangeType::update);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (addTile(id, shape, transform, areaType, tilePosition, locked->mTiles))
|
||||||
|
{
|
||||||
|
newTiles.insert(tilePosition);
|
||||||
|
addChangedTile(tilePosition, ChangeType::add);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
getTilesPositions(range, onTilePosition);
|
||||||
|
for (const auto& tile : data.mTiles)
|
||||||
|
{
|
||||||
|
if (newTiles.find(tile) == newTiles.end() && removeTile(id, tile, locked->mTiles))
|
||||||
|
{
|
||||||
|
addChangedTile(tile, ChangeType::remove);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
data.mTiles = std::move(newTiles);
|
||||||
|
++mRevision;
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileCachedRecastMeshManager::removeObject(const ObjectId id)
|
||||||
|
{
|
||||||
|
const auto object = mObjects.find(id);
|
||||||
|
if (object == mObjects.end())
|
||||||
|
return;
|
||||||
|
bool changed = false;
|
||||||
{
|
{
|
||||||
const auto locked = mWorldspaceTiles.lock();
|
const auto locked = mWorldspaceTiles.lock();
|
||||||
for (const auto& tilePosition : object->second.mTiles)
|
for (const auto& tilePosition : object->second.mTiles)
|
||||||
{
|
{
|
||||||
const auto removed = removeTile(id, tilePosition, locked->mTiles);
|
if (removeTile(id, tilePosition, locked->mTiles))
|
||||||
if (removed && !result)
|
{
|
||||||
result = removed;
|
addChangedTile(tilePosition, ChangeType::remove);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mObjects.erase(object);
|
mObjects.erase(object);
|
||||||
if (result)
|
if (changed)
|
||||||
++mRevision;
|
++mRevision;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TileCachedRecastMeshManager::addWater(const osg::Vec2i& cellPosition, int cellSize, float level)
|
void TileCachedRecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize, const float level)
|
||||||
{
|
{
|
||||||
const auto it = mWaterTilesPositions.find(cellPosition);
|
const auto it = mWaterTilesPositions.find(cellPosition);
|
||||||
if (it != mWaterTilesPositions.end())
|
if (it != mWaterTilesPositions.end())
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
std::vector<TilePosition>& tilesPositions = mWaterTilesPositions.emplace_hint(
|
std::vector<TilePosition>& tilesPositions = mWaterTilesPositions.emplace_hint(
|
||||||
it, cellPosition, std::vector<TilePosition>())->second;
|
it, cellPosition, std::vector<TilePosition>())->second;
|
||||||
|
|
||||||
bool result = false;
|
bool changed = false;
|
||||||
|
|
||||||
if (cellSize == std::numeric_limits<int>::max())
|
if (cellSize == std::numeric_limits<int>::max())
|
||||||
{
|
{
|
||||||
const auto locked = mWorldspaceTiles.lock();
|
const auto locked = mWorldspaceTiles.lock();
|
||||||
for (auto& tile : locked->mTiles)
|
for (auto& [tilePosition, data] : locked->mTiles)
|
||||||
{
|
{
|
||||||
if (tile.second->addWater(cellPosition, cellSize, level))
|
if (data->addWater(cellPosition, cellSize, level))
|
||||||
{
|
{
|
||||||
tilesPositions.push_back(tile.first);
|
tilesPositions.push_back(tilePosition);
|
||||||
result = true;
|
addChangedTile(tilePosition, ChangeType::add);
|
||||||
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,23 +241,22 @@ namespace DetourNavigator
|
||||||
if (tile->second->addWater(cellPosition, cellSize, level))
|
if (tile->second->addWater(cellPosition, cellSize, level))
|
||||||
{
|
{
|
||||||
tilesPositions.push_back(tilePosition);
|
tilesPositions.push_back(tilePosition);
|
||||||
result = true;
|
addChangedTile(tilePosition, ChangeType::add);
|
||||||
|
changed = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result)
|
if (changed)
|
||||||
++mRevision;
|
++mRevision;
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Water> TileCachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition)
|
void TileCachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition)
|
||||||
{
|
{
|
||||||
const auto object = mWaterTilesPositions.find(cellPosition);
|
const auto object = mWaterTilesPositions.find(cellPosition);
|
||||||
if (object == mWaterTilesPositions.end())
|
if (object == mWaterTilesPositions.end())
|
||||||
return std::nullopt;
|
return;
|
||||||
std::optional<Water> result;
|
bool changed = false;
|
||||||
{
|
{
|
||||||
const auto worldspaceTiles = mWorldspaceTiles.lock();
|
const auto worldspaceTiles = mWorldspaceTiles.lock();
|
||||||
for (const auto& tilePosition : object->second)
|
for (const auto& tilePosition : object->second)
|
||||||
|
@ -187,34 +264,35 @@ namespace DetourNavigator
|
||||||
const auto tile = worldspaceTiles->mTiles.find(tilePosition);
|
const auto tile = worldspaceTiles->mTiles.find(tilePosition);
|
||||||
if (tile == worldspaceTiles->mTiles.end())
|
if (tile == worldspaceTiles->mTiles.end())
|
||||||
continue;
|
continue;
|
||||||
const auto tileResult = tile->second->removeWater(cellPosition);
|
if (tile->second->removeWater(cellPosition))
|
||||||
|
{
|
||||||
|
addChangedTile(tilePosition, ChangeType::remove);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
if (tile->second->isEmpty())
|
if (tile->second->isEmpty())
|
||||||
{
|
{
|
||||||
worldspaceTiles->mTiles.erase(tile);
|
worldspaceTiles->mTiles.erase(tile);
|
||||||
++mTilesGeneration;
|
++mTilesGeneration;
|
||||||
}
|
}
|
||||||
if (tileResult && !result)
|
|
||||||
result = tileResult;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mWaterTilesPositions.erase(object);
|
mWaterTilesPositions.erase(object);
|
||||||
if (result)
|
if (changed)
|
||||||
++mRevision;
|
++mRevision;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TileCachedRecastMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize,
|
void TileCachedRecastMeshManager::addHeightfield(const osg::Vec2i& cellPosition, const int cellSize,
|
||||||
const HeightfieldShape& shape)
|
const HeightfieldShape& shape)
|
||||||
{
|
{
|
||||||
const auto it = mHeightfieldTilesPositions.find(cellPosition);
|
const auto it = mHeightfieldTilesPositions.find(cellPosition);
|
||||||
if (it != mHeightfieldTilesPositions.end())
|
if (it != mHeightfieldTilesPositions.end())
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
std::vector<TilePosition>& tilesPositions = mHeightfieldTilesPositions.emplace_hint(
|
std::vector<TilePosition>& tilesPositions = mHeightfieldTilesPositions.emplace_hint(
|
||||||
it, cellPosition, std::vector<TilePosition>())->second;
|
it, cellPosition, std::vector<TilePosition>())->second;
|
||||||
const btVector3 shift = getHeightfieldShift(shape, cellPosition, cellSize);
|
const btVector3 shift = getHeightfieldShift(shape, cellPosition, cellSize);
|
||||||
|
|
||||||
bool result = false;
|
bool changed = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
const auto worldspaceTiles = mWorldspaceTiles.lock();
|
const auto worldspaceTiles = mWorldspaceTiles.lock();
|
||||||
|
@ -231,23 +309,22 @@ namespace DetourNavigator
|
||||||
if (tile->second->addHeightfield(cellPosition, cellSize, shape))
|
if (tile->second->addHeightfield(cellPosition, cellSize, shape))
|
||||||
{
|
{
|
||||||
tilesPositions.push_back(tilePosition);
|
tilesPositions.push_back(tilePosition);
|
||||||
result = true;
|
addChangedTile(tilePosition, ChangeType::add);
|
||||||
|
changed = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result)
|
if (changed)
|
||||||
++mRevision;
|
++mRevision;
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<SizedHeightfieldShape> TileCachedRecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition)
|
void TileCachedRecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition)
|
||||||
{
|
{
|
||||||
const auto object = mHeightfieldTilesPositions.find(cellPosition);
|
const auto object = mHeightfieldTilesPositions.find(cellPosition);
|
||||||
if (object == mHeightfieldTilesPositions.end())
|
if (object == mHeightfieldTilesPositions.end())
|
||||||
return std::nullopt;
|
return;
|
||||||
std::optional<SizedHeightfieldShape> result;
|
bool changed = false;
|
||||||
{
|
{
|
||||||
const auto worldspaceTiles = mWorldspaceTiles.lock();
|
const auto worldspaceTiles = mWorldspaceTiles.lock();
|
||||||
for (const auto& tilePosition : object->second)
|
for (const auto& tilePosition : object->second)
|
||||||
|
@ -255,20 +332,21 @@ namespace DetourNavigator
|
||||||
const auto tile = worldspaceTiles->mTiles.find(tilePosition);
|
const auto tile = worldspaceTiles->mTiles.find(tilePosition);
|
||||||
if (tile == worldspaceTiles->mTiles.end())
|
if (tile == worldspaceTiles->mTiles.end())
|
||||||
continue;
|
continue;
|
||||||
const auto tileResult = tile->second->removeHeightfield(cellPosition);
|
if (tile->second->removeHeightfield(cellPosition))
|
||||||
|
{
|
||||||
|
addChangedTile(tilePosition, ChangeType::remove);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
if (tile->second->isEmpty())
|
if (tile->second->isEmpty())
|
||||||
{
|
{
|
||||||
worldspaceTiles->mTiles.erase(tile);
|
worldspaceTiles->mTiles.erase(tile);
|
||||||
++mTilesGeneration;
|
++mTilesGeneration;
|
||||||
}
|
}
|
||||||
if (tileResult && !result)
|
|
||||||
result = tileResult;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mHeightfieldTilesPositions.erase(object);
|
mHeightfieldTilesPositions.erase(object);
|
||||||
if (result)
|
if (changed)
|
||||||
++mRevision;
|
++mRevision;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<RecastMesh> TileCachedRecastMeshManager::getMesh(std::string_view worldspace, const TilePosition& tilePosition) const
|
std::shared_ptr<RecastMesh> TileCachedRecastMeshManager::getMesh(std::string_view worldspace, const TilePosition& tilePosition) const
|
||||||
|
@ -292,11 +370,6 @@ namespace DetourNavigator
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t TileCachedRecastMeshManager::getRevision() const
|
|
||||||
{
|
|
||||||
return mRevision;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TileCachedRecastMeshManager::reportNavMeshChange(const TilePosition& tilePosition, Version recastMeshVersion, Version navMeshVersion) const
|
void TileCachedRecastMeshManager::reportNavMeshChange(const TilePosition& tilePosition, Version recastMeshVersion, Version navMeshVersion) const
|
||||||
{
|
{
|
||||||
const auto locked = mWorldspaceTiles.lockConst();
|
const auto locked = mWorldspaceTiles.lockConst();
|
||||||
|
@ -306,6 +379,15 @@ namespace DetourNavigator
|
||||||
it->second->reportNavMeshChange(recastMeshVersion, navMeshVersion);
|
it->second->reportNavMeshChange(recastMeshVersion, navMeshVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TileCachedRecastMeshManager::addChangedTile(const TilePosition& tilePosition, ChangeType changeType)
|
||||||
|
{
|
||||||
|
auto tile = mChangedTiles.find(tilePosition);
|
||||||
|
if (tile == mChangedTiles.end())
|
||||||
|
mChangedTiles.emplace(tilePosition, changeType);
|
||||||
|
else
|
||||||
|
tile->second = addChangeType(tile->second, changeType);
|
||||||
|
}
|
||||||
|
|
||||||
bool TileCachedRecastMeshManager::addTile(const ObjectId id, const CollisionShape& shape,
|
bool TileCachedRecastMeshManager::addTile(const ObjectId id, const CollisionShape& shape,
|
||||||
const btTransform& transform, const AreaType areaType, const TilePosition& tilePosition,
|
const btTransform& transform, const AreaType areaType, const TilePosition& tilePosition,
|
||||||
TilesMap& tiles)
|
TilesMap& tiles)
|
||||||
|
@ -320,26 +402,19 @@ namespace DetourNavigator
|
||||||
return tile->second->addObject(id, shape, transform, areaType);
|
return tile->second->addObject(id, shape, transform, areaType);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TileCachedRecastMeshManager::updateTile(const ObjectId id, const btTransform& transform,
|
bool TileCachedRecastMeshManager::removeTile(const ObjectId id,
|
||||||
const AreaType areaType, const TilePosition& tilePosition, TilesMap& tiles)
|
|
||||||
{
|
|
||||||
const auto tile = tiles.find(tilePosition);
|
|
||||||
return tile != tiles.end() && tile->second->updateObject(id, transform, areaType);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<RemovedRecastMeshObject> TileCachedRecastMeshManager::removeTile(const ObjectId id,
|
|
||||||
const TilePosition& tilePosition, TilesMap& tiles)
|
const TilePosition& tilePosition, TilesMap& tiles)
|
||||||
{
|
{
|
||||||
const auto tile = tiles.find(tilePosition);
|
const auto tile = tiles.find(tilePosition);
|
||||||
if (tile == tiles.end())
|
if (tile == tiles.end())
|
||||||
return std::optional<RemovedRecastMeshObject>();
|
return false;
|
||||||
auto tileResult = tile->second->removeObject(id);
|
const bool result = tile->second->removeObject(id);
|
||||||
if (tile->second->isEmpty())
|
if (tile->second->isEmpty())
|
||||||
{
|
{
|
||||||
tiles.erase(tile);
|
tiles.erase(tile);
|
||||||
++mTilesGeneration;
|
++mTilesGeneration;
|
||||||
}
|
}
|
||||||
return tileResult;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<CachedRecastMeshManager> TileCachedRecastMeshManager::getManager(std::string_view worldspace,
|
std::shared_ptr<CachedRecastMeshManager> TileCachedRecastMeshManager::getManager(std::string_view worldspace,
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_TILECACHEDRECASTMESHMANAGER_H
|
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_TILECACHEDRECASTMESHMANAGER_H
|
||||||
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_TILECACHEDRECASTMESHMANAGER_H
|
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_TILECACHEDRECASTMESHMANAGER_H
|
||||||
|
|
||||||
#include "cachedrecastmeshmanager.hpp"
|
|
||||||
#include "tileposition.hpp"
|
#include "tileposition.hpp"
|
||||||
#include "gettilespositions.hpp"
|
#include "gettilespositions.hpp"
|
||||||
#include "version.hpp"
|
#include "version.hpp"
|
||||||
#include "heightfieldshape.hpp"
|
#include "heightfieldshape.hpp"
|
||||||
#include "changetype.hpp"
|
#include "changetype.hpp"
|
||||||
|
#include "objectid.hpp"
|
||||||
|
#include "areatype.hpp"
|
||||||
|
#include "recastmeshobject.hpp"
|
||||||
|
|
||||||
#include <components/misc/guarded.hpp>
|
#include <components/misc/guarded.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -18,104 +19,33 @@
|
||||||
|
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
{
|
{
|
||||||
|
class CachedRecastMeshManager;
|
||||||
|
class RecastMesh;
|
||||||
|
|
||||||
class TileCachedRecastMeshManager
|
class TileCachedRecastMeshManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit TileCachedRecastMeshManager(const RecastSettings& settings);
|
explicit TileCachedRecastMeshManager(const RecastSettings& settings);
|
||||||
|
|
||||||
TileBounds getBounds() const;
|
void setBounds(const TileBounds& bounds);
|
||||||
|
|
||||||
std::vector<std::pair<TilePosition, ChangeType>> setBounds(const TileBounds& bounds);
|
|
||||||
|
|
||||||
std::string getWorldspace() const;
|
std::string getWorldspace() const;
|
||||||
|
|
||||||
void setWorldspace(std::string_view worldspace);
|
void setWorldspace(std::string_view worldspace);
|
||||||
|
|
||||||
template <class OnChangedTile>
|
bool addObject(ObjectId id, const CollisionShape& shape, const btTransform& transform, AreaType areaType);
|
||||||
bool addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform,
|
|
||||||
const AreaType areaType, OnChangedTile&& onChangedTile)
|
|
||||||
{
|
|
||||||
auto it = mObjects.find(id);
|
|
||||||
if (it != mObjects.end())
|
|
||||||
return false;
|
|
||||||
const TilesPositionsRange objectRange = makeTilesPositionsRange(shape.getShape(), transform, mSettings);
|
|
||||||
const TilesPositionsRange range = getIntersection(mRange, objectRange);
|
|
||||||
std::set<TilePosition> tilesPositions;
|
|
||||||
if (range.mBegin != range.mEnd)
|
|
||||||
{
|
|
||||||
const auto locked = mWorldspaceTiles.lock();
|
|
||||||
getTilesPositions(range,
|
|
||||||
[&] (const TilePosition& tilePosition)
|
|
||||||
{
|
|
||||||
if (addTile(id, shape, transform, areaType, tilePosition, locked->mTiles))
|
|
||||||
tilesPositions.insert(tilePosition);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
it = mObjects.emplace_hint(it, id, ObjectData {shape, transform, areaType, std::move(tilesPositions)});
|
|
||||||
std::for_each(it->second.mTiles.begin(), it->second.mTiles.end(), std::forward<OnChangedTile>(onChangedTile));
|
|
||||||
++mRevision;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class OnChangedTile>
|
bool updateObject(ObjectId id, const CollisionShape& shape, const btTransform& transform, AreaType areaType);
|
||||||
bool updateObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform,
|
|
||||||
const AreaType areaType, OnChangedTile&& onChangedTile)
|
|
||||||
{
|
|
||||||
const auto object = mObjects.find(id);
|
|
||||||
if (object == mObjects.end())
|
|
||||||
return false;
|
|
||||||
auto& data = object->second;
|
|
||||||
bool changed = false;
|
|
||||||
std::set<TilePosition> newTiles;
|
|
||||||
{
|
|
||||||
const TilesPositionsRange objectRange = makeTilesPositionsRange(shape.getShape(), transform, mSettings);
|
|
||||||
const TilesPositionsRange range = getIntersection(mRange, objectRange);
|
|
||||||
const auto locked = mWorldspaceTiles.lock();
|
|
||||||
const auto onTilePosition = [&] (const TilePosition& tilePosition)
|
|
||||||
{
|
|
||||||
if (data.mTiles.find(tilePosition) != data.mTiles.end())
|
|
||||||
{
|
|
||||||
newTiles.insert(tilePosition);
|
|
||||||
if (updateTile(id, transform, areaType, tilePosition, locked->mTiles))
|
|
||||||
{
|
|
||||||
onChangedTile(tilePosition, ChangeType::update);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (addTile(id, shape, transform, areaType, tilePosition, locked->mTiles))
|
|
||||||
{
|
|
||||||
newTiles.insert(tilePosition);
|
|
||||||
onChangedTile(tilePosition, ChangeType::add);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
getTilesPositions(range, onTilePosition);
|
|
||||||
for (const auto& tile : data.mTiles)
|
|
||||||
{
|
|
||||||
if (newTiles.find(tile) == newTiles.end() && removeTile(id, tile, locked->mTiles))
|
|
||||||
{
|
|
||||||
onChangedTile(tile, ChangeType::remove);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (changed)
|
|
||||||
{
|
|
||||||
data.mTiles = std::move(newTiles);
|
|
||||||
++mRevision;
|
|
||||||
}
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<RemovedRecastMeshObject> removeObject(const ObjectId id);
|
void removeObject(ObjectId id);
|
||||||
|
|
||||||
bool addWater(const osg::Vec2i& cellPosition, int cellSize, float level);
|
void addWater(const osg::Vec2i& cellPosition, int cellSize, float level);
|
||||||
|
|
||||||
std::optional<Water> removeWater(const osg::Vec2i& cellPosition);
|
void removeWater(const osg::Vec2i& cellPosition);
|
||||||
|
|
||||||
bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape);
|
void addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape);
|
||||||
|
|
||||||
std::optional<SizedHeightfieldShape> removeHeightfield(const osg::Vec2i& cellPosition);
|
void removeHeightfield(const osg::Vec2i& cellPosition);
|
||||||
|
|
||||||
std::shared_ptr<RecastMesh> getMesh(std::string_view worldspace, const TilePosition& tilePosition) const;
|
std::shared_ptr<RecastMesh> getMesh(std::string_view worldspace, const TilePosition& tilePosition) const;
|
||||||
|
|
||||||
|
@ -131,10 +61,14 @@ namespace DetourNavigator
|
||||||
function(tilePosition, *recastMeshManager);
|
function(tilePosition, *recastMeshManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t getRevision() const;
|
std::size_t getRevision() const { return mRevision; }
|
||||||
|
|
||||||
void reportNavMeshChange(const TilePosition& tilePosition, Version recastMeshVersion, Version navMeshVersion) const;
|
void reportNavMeshChange(const TilePosition& tilePosition, Version recastMeshVersion, Version navMeshVersion) const;
|
||||||
|
|
||||||
|
void addChangedTile(const TilePosition& tilePosition, ChangeType changeType);
|
||||||
|
|
||||||
|
std::map<osg::Vec2i, ChangeType> takeChangedTiles() { return std::move(mChangedTiles); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using TilesMap = std::map<TilePosition, std::shared_ptr<CachedRecastMeshManager>>;
|
using TilesMap = std::map<TilePosition, std::shared_ptr<CachedRecastMeshManager>>;
|
||||||
|
|
||||||
|
@ -159,17 +93,14 @@ namespace DetourNavigator
|
||||||
std::unordered_map<ObjectId, ObjectData> mObjects;
|
std::unordered_map<ObjectId, ObjectData> mObjects;
|
||||||
std::map<osg::Vec2i, std::vector<TilePosition>> mWaterTilesPositions;
|
std::map<osg::Vec2i, std::vector<TilePosition>> mWaterTilesPositions;
|
||||||
std::map<osg::Vec2i, std::vector<TilePosition>> mHeightfieldTilesPositions;
|
std::map<osg::Vec2i, std::vector<TilePosition>> mHeightfieldTilesPositions;
|
||||||
|
std::map<osg::Vec2i, ChangeType> mChangedTiles;
|
||||||
std::size_t mRevision = 0;
|
std::size_t mRevision = 0;
|
||||||
std::size_t mTilesGeneration = 0;
|
std::size_t mTilesGeneration = 0;
|
||||||
|
|
||||||
bool addTile(const ObjectId id, const CollisionShape& shape, const btTransform& transform,
|
inline bool addTile(ObjectId id, const CollisionShape& shape, const btTransform& transform,
|
||||||
const AreaType areaType, const TilePosition& tilePosition, TilesMap& tiles);
|
AreaType areaType, const TilePosition& tilePosition, TilesMap& tiles);
|
||||||
|
|
||||||
static bool updateTile(const ObjectId id, const btTransform& transform, const AreaType areaType,
|
inline bool removeTile(ObjectId id, const TilePosition& tilePosition, TilesMap& tiles);
|
||||||
const TilePosition& tilePosition, TilesMap& tiles);
|
|
||||||
|
|
||||||
std::optional<RemovedRecastMeshObject> removeTile(const ObjectId id, const TilePosition& tilePosition,
|
|
||||||
TilesMap& tiles);
|
|
||||||
|
|
||||||
inline std::shared_ptr<CachedRecastMeshManager> getManager(std::string_view worldspace,
|
inline std::shared_ptr<CachedRecastMeshManager> getManager(std::string_view worldspace,
|
||||||
const TilePosition& tilePosition) const;
|
const TilePosition& tilePosition) const;
|
||||||
|
|
Loading…
Reference in a new issue