1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-16 03:29:55 +00:00

Make RecastMesh independent from the order of RecastMeshBuilder calls

To make sure RecastMesh objects are equal if built with the same data but in
different order. Will be used later when there will be more than one place
building RecasMesh objects.
This commit is contained in:
elsid 2021-07-11 21:43:19 +02:00
parent 07c70dfb73
commit af7059373c
No known key found for this signature in database
GPG key ID: B845CB9FEE18AB40
14 changed files with 335 additions and 316 deletions

View file

@ -87,6 +87,19 @@ namespace
});
}
template <class Random>
Mesh generateMesh(std::size_t triangles, Random& random)
{
std::uniform_real_distribution<float> distribution(0.0, 1.0);
std::vector<float> vertices;
std::vector<int> indices;
std::vector<AreaType> areaTypes;
generateVertices(std::back_inserter(vertices), triangles * 1.98, random);
generateIndices(std::back_inserter(indices), static_cast<int>(vertices.size() / 3) - 1, vertices.size() * 1.53, random);
generateAreaTypes(std::back_inserter(areaTypes), indices.size() / 3, random);
return Mesh(std::move(indices), std::move(vertices), std::move(areaTypes));
}
template <class Random>
Key generateKey(std::size_t triangles, Random& random)
{
@ -94,16 +107,10 @@ namespace
const TilePosition tilePosition = generateTilePosition(10000, random);
const std::size_t generation = std::uniform_int_distribution<std::size_t>(0, 100)(random);
const std::size_t revision = std::uniform_int_distribution<std::size_t>(0, 10000)(random);
std::vector<float> vertices;
generateVertices(std::back_inserter(vertices), triangles * 1.98, random);
std::vector<int> indices;
generateIndices(std::back_inserter(indices), static_cast<int>(vertices.size() / 3) - 1, vertices.size() * 1.53, random);
std::vector<AreaType> areaTypes;
generateAreaTypes(std::back_inserter(areaTypes), indices.size() / 3, random);
Mesh mesh = generateMesh(triangles, random);
std::vector<RecastMesh::Water> water;
generateWater(std::back_inserter(water), 2, random);
RecastMesh recastMesh(generation, revision, std::move(indices), std::move(vertices),
std::move(areaTypes), std::move(water));
RecastMesh recastMesh(generation, revision, std::move(mesh), std::move(water));
return Key {agentHalfExtents, tilePosition, std::move(recastMesh)};
}

View file

@ -128,17 +128,23 @@ namespace
return result;
}
Mesh makeMesh()
{
std::vector<int> indices {{0, 1, 2}};
std::vector<float> vertices {{0, 0, 0, 1, 0, 0, 1, 1, 0}};
std::vector<AreaType> areaTypes {1, AreaType_ground};
return Mesh(std::move(indices), std::move(vertices), std::move(areaTypes));
}
struct DetourNavigatorNavMeshTilesCacheTest : Test
{
const osg::Vec3f mAgentHalfExtents {1, 2, 3};
const TilePosition mTilePosition {0, 0};
const std::size_t mGeneration = 0;
const std::size_t mRevision = 0;
const std::vector<int> mIndices {{0, 1, 2}};
const std::vector<float> mVertices {{0, 0, 0, 1, 0, 0, 1, 1, 0}};
const std::vector<AreaType> mAreaTypes {1, AreaType_ground};
const Mesh mMesh {makeMesh()};
const std::vector<RecastMesh::Water> mWater {};
const RecastMesh mRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, mWater};
const RecastMesh mRecastMesh {mGeneration, mRevision, mMesh, mWater};
std::unique_ptr<PreparedNavMeshData> mPreparedNavMeshData {makePeparedNavMeshData(3)};
const std::size_t mRecastMeshSize = sizeof(mRecastMesh) + getSize(mRecastMesh);
@ -226,7 +232,7 @@ namespace
const std::size_t maxSize = 1;
NavMeshTilesCache cache(maxSize);
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
const RecastMesh unexistentRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, water};
const RecastMesh unexistentRecastMesh {mGeneration, mRevision, mMesh, water};
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, unexistentRecastMesh));
@ -238,7 +244,7 @@ namespace
NavMeshTilesCache cache(maxSize);
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, water};
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water};
auto anotherPreparedNavMeshData = makePeparedNavMeshData(3);
const auto copy = clone(*anotherPreparedNavMeshData);
@ -256,7 +262,7 @@ namespace
NavMeshTilesCache cache(maxSize);
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, water};
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water};
auto anotherPreparedNavMeshData = makePeparedNavMeshData(3);
const auto value = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh,
@ -272,13 +278,11 @@ namespace
const auto copy = clone(*mPreparedNavMeshData);
const std::vector<RecastMesh::Water> leastRecentlySetWater {1, RecastMesh::Water {1, btTransform::getIdentity()}};
const RecastMesh leastRecentlySetRecastMesh {mGeneration, mRevision, mIndices, mVertices,
mAreaTypes, leastRecentlySetWater};
const RecastMesh leastRecentlySetRecastMesh {mGeneration, mRevision, mMesh, leastRecentlySetWater};
auto leastRecentlySetData = makePeparedNavMeshData(3);
const std::vector<RecastMesh::Water> mostRecentlySetWater {1, RecastMesh::Water {2, btTransform::getIdentity()}};
const RecastMesh mostRecentlySetRecastMesh {mGeneration, mRevision, mIndices, mVertices,
mAreaTypes, mostRecentlySetWater};
const RecastMesh mostRecentlySetRecastMesh {mGeneration, mRevision, mMesh, mostRecentlySetWater};
auto mostRecentlySetData = makePeparedNavMeshData(3);
ASSERT_TRUE(cache.set(mAgentHalfExtents, mTilePosition, leastRecentlySetRecastMesh,
@ -300,14 +304,12 @@ namespace
NavMeshTilesCache cache(maxSize);
const std::vector<RecastMesh::Water> leastRecentlyUsedWater {1, RecastMesh::Water {1, btTransform::getIdentity()}};
const RecastMesh leastRecentlyUsedRecastMesh {mGeneration, mRevision, mIndices, mVertices,
mAreaTypes, leastRecentlyUsedWater};
const RecastMesh leastRecentlyUsedRecastMesh {mGeneration, mRevision, mMesh, leastRecentlyUsedWater};
auto leastRecentlyUsedData = makePeparedNavMeshData(3);
const auto leastRecentlyUsedCopy = clone(*leastRecentlyUsedData);
const std::vector<RecastMesh::Water> mostRecentlyUsedWater {1, RecastMesh::Water {2, btTransform::getIdentity()}};
const RecastMesh mostRecentlyUsedRecastMesh {mGeneration, mRevision, mIndices, mVertices,
mAreaTypes, mostRecentlyUsedWater};
const RecastMesh mostRecentlyUsedRecastMesh {mGeneration, mRevision, mMesh, mostRecentlyUsedWater};
auto mostRecentlyUsedData = makePeparedNavMeshData(3);
const auto mostRecentlyUsedCopy = clone(*mostRecentlyUsedData);
@ -341,7 +343,7 @@ namespace
NavMeshTilesCache cache(maxSize);
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, water};
const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mMesh, water};
auto tooLargeData = makePeparedNavMeshData(10);
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
@ -355,12 +357,11 @@ namespace
NavMeshTilesCache cache(maxSize);
const std::vector<RecastMesh::Water> anotherWater {1, RecastMesh::Water {1, btTransform::getIdentity()}};
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, anotherWater};
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, anotherWater};
auto anotherData = makePeparedNavMeshData(3);
const std::vector<RecastMesh::Water> tooLargeWater {1, RecastMesh::Water {2, btTransform::getIdentity()}};
const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mIndices, mVertices,
mAreaTypes, tooLargeWater};
const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mMesh, tooLargeWater};
auto tooLargeData = makePeparedNavMeshData(10);
const auto value = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh,
@ -380,8 +381,7 @@ namespace
NavMeshTilesCache cache(maxSize);
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices,
mAreaTypes, water};
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water};
auto anotherData = makePeparedNavMeshData(3);
const auto firstCopy = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
@ -400,7 +400,7 @@ namespace
NavMeshTilesCache cache(maxSize);
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, water};
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water};
auto anotherData = makePeparedNavMeshData(3);
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));

View file

@ -11,6 +11,8 @@
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
#include <DetourCommon.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
@ -50,9 +52,9 @@ namespace
{
RecastMeshBuilder builder(mSettings, mBounds);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>());
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>());
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>());
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>());
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>());
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>());
}
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_bhv_triangle_mesh_shape)
@ -64,13 +66,13 @@ namespace
RecastMeshBuilder builder(mSettings, mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
1, 0, -1,
-1, 0, 1,
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
-1, 0, -1,
}));
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
-1, 0, 1,
1, 0, -1,
})) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
}
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_transformed_bhv_triangle_mesh_shape)
@ -85,13 +87,13 @@ namespace
AreaType_ground
);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
2, 3, 0,
0, 3, 4,
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
0, 3, 0,
}));
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
0, 3, 4,
2, 3, 0,
})) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
}
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_heightfield_terrian_shape)
@ -101,14 +103,14 @@ namespace
RecastMeshBuilder builder(mSettings, mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
-0.5, 0, -0.5,
-0.5, 0, 0.5,
0.5, 0, -0.5,
0.5, 0, 0.5,
}));
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2, 2, 1, 3}));
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground, AreaType_ground}));
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({0, 1, 2, 2, 1, 3}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground, AreaType_ground}));
}
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_box_shape_should_produce_12_triangles)
@ -117,31 +119,31 @@ namespace
RecastMeshBuilder builder(mSettings, mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
1, 2, 1,
-1, 2, 1,
1, 2, -1,
-1, 2, -1,
1, -2, 1,
-1, -2, 1,
1, -2, -1,
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
-1, -2, -1,
})) << recastMesh->getVertices();
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({
0, 2, 3,
3, 1, 0,
0, 4, 6,
6, 2, 0,
0, 1, 5,
5, 4, 0,
7, 5, 1,
1, 3, 7,
7, 3, 2,
2, 6, 7,
7, 6, 4,
4, 5, 7,
})) << recastMesh->getIndices();
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>(12, AreaType_ground));
-1, -2, 1,
-1, 2, -1,
-1, 2, 1,
1, -2, -1,
1, -2, 1,
1, 2, -1,
1, 2, 1,
})) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({
0, 1, 3,
0, 2, 6,
0, 4, 5,
1, 5, 7,
2, 3, 7,
3, 2, 0,
4, 6, 7,
5, 1, 0,
6, 4, 0,
7, 3, 1,
7, 5, 4,
7, 6, 2,
})) << recastMesh->getMesh().getIndices();
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>(12, AreaType_ground));
}
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_compound_shape)
@ -164,7 +166,7 @@ namespace
AreaType_ground
);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
-1, -2, -1,
-1, -2, 1,
-1, 0, -1,
@ -177,24 +179,24 @@ namespace
1, 0, 1,
1, 2, -1,
1, 2, 1,
})) << recastMesh->getVertices();
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({
8, 3, 2,
11, 10, 4,
4, 5, 11,
11, 7, 6,
6, 10, 11,
11, 5, 1,
1, 7, 11,
})) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({
0, 1, 5,
5, 4, 0,
0, 4, 10,
10, 6, 0,
0, 6, 7,
1, 7, 11,
4, 5, 11,
5, 4, 0,
6, 10, 11,
7, 1, 0,
8, 3, 2,
8, 3, 9,
})) << recastMesh->getIndices();
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>(14, AreaType_ground));
10, 6, 0,
11, 5, 1,
11, 7, 6,
11, 10, 4,
})) << recastMesh->getMesh().getIndices();
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>(14, AreaType_ground));
}
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_transformed_compound_shape)
@ -211,13 +213,13 @@ namespace
AreaType_ground
);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
2, 3, 0,
0, 3, 4,
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
0, 3, 0,
}));
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
0, 3, 4,
2, 3, 0,
})) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
}
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_transformed_compound_shape_with_transformed_bhv_triangle_shape)
@ -235,13 +237,13 @@ namespace
AreaType_ground
);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
3, 12, 2,
1, 12, 10,
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
1, 12, 2,
}));
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
1, 12, 10,
3, 12, 2,
})) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
}
TEST_F(DetourNavigatorRecastMeshBuilderTest, without_bounds_add_bhv_triangle_shape_should_not_filter_by_bounds)
@ -257,16 +259,16 @@ namespace
AreaType_ground
);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
1, 0, -1,
-1, 0, 1,
-1, 0, -1,
-2, 0, -3,
-3, 0, -2,
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
-3, 0, -3,
}));
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2, 3, 4, 5}));
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>(2, AreaType_ground));
-3, 0, -2,
-2, 0, -3,
-1, 0, -1,
-1, 0, 1,
1, 0, -1,
})) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0, 5, 4, 3}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>(2, AreaType_ground));
}
TEST_F(DetourNavigatorRecastMeshBuilderTest, with_bounds_add_bhv_triangle_shape_should_filter_by_bounds)
@ -285,13 +287,13 @@ namespace
AreaType_ground
);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
-0.2f, 0, -0.3f,
-0.3f, 0, -0.2f,
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
-0.3f, 0, -0.3f,
}));
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
-0.3f, 0, -0.2f,
-0.2f, 0, -0.3f,
})) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
}
TEST_F(DetourNavigatorRecastMeshBuilderTest, with_bounds_add_rotated_by_x_bhv_triangle_shape_should_filter_by_bounds)
@ -310,13 +312,13 @@ namespace
AreaType_ground
);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_THAT(recastMesh->getVertices(), Pointwise(FloatNear(1e-5), std::vector<float>({
0, -0.70710659027099609375, -3.535533905029296875,
0, 0.707107067108154296875, -3.535533905029296875,
0, 2.384185791015625e-07, -4.24264049530029296875,
})));
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
EXPECT_THAT(recastMesh->getMesh().getVertices(), Pointwise(FloatNear(1e-5), std::vector<float>({
0, -0.707106769084930419921875, -3.535533905029296875,
0, 4.44089209850062616169452667236328125e-16, -4.24264049530029296875,
0, 0.707106769084930419921875, -3.535533905029296875,
}))) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({0, 2, 1}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
}
TEST_F(DetourNavigatorRecastMeshBuilderTest, with_bounds_add_rotated_by_y_bhv_triangle_shape_should_filter_by_bounds)
@ -335,13 +337,13 @@ namespace
AreaType_ground
);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_THAT(recastMesh->getVertices(), Pointwise(FloatNear(1e-5), std::vector<float>({
-3.535533905029296875, -0.70710659027099609375, 0,
-3.535533905029296875, 0.707107067108154296875, 0,
-4.24264049530029296875, 2.384185791015625e-07, 0,
})));
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
EXPECT_THAT(recastMesh->getMesh().getVertices(), Pointwise(FloatNear(1e-5), std::vector<float>({
-4.24264049530029296875, 4.44089209850062616169452667236328125e-16, 0,
-3.535533905029296875, -0.707106769084930419921875, 0,
-3.535533905029296875, 0.707106769084930419921875, 0,
}))) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({1, 2, 0}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
}
TEST_F(DetourNavigatorRecastMeshBuilderTest, with_bounds_add_rotated_by_z_bhv_triangle_shape_should_filter_by_bounds)
@ -360,13 +362,13 @@ namespace
AreaType_ground
);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_THAT(recastMesh->getVertices(), Pointwise(FloatNear(1e-5), std::vector<float>({
1.41421353816986083984375, 0, 1.1920928955078125e-07,
-1.41421353816986083984375, 0, -1.1920928955078125e-07,
1.1920928955078125e-07, 0, -1.41421353816986083984375,
})));
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
EXPECT_THAT(recastMesh->getMesh().getVertices(), Pointwise(FloatNear(1e-5), std::vector<float>({
-1.41421353816986083984375, 0, -1.1102230246251565404236316680908203125e-16,
1.1102230246251565404236316680908203125e-16, 0, -1.41421353816986083984375,
1.41421353816986083984375, 0, 1.1102230246251565404236316680908203125e-16,
}))) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 0, 1}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
}
TEST_F(DetourNavigatorRecastMeshBuilderTest, flags_values_should_be_corresponding_to_added_objects)
@ -389,16 +391,16 @@ namespace
AreaType_null
);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
1, 0, -1,
-1, 0, 1,
-1, 0, -1,
-2, 0, -3,
-3, 0, -2,
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
-3, 0, -3,
}));
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2, 3, 4, 5}));
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground, AreaType_null}));
-3, 0, -2,
-2, 0, -3,
-1, 0, -1,
-1, 0, 1,
1, 0, -1,
})) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0, 5, 4, 3}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_null, AreaType_ground}));
}
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_water_then_get_water_should_return_it)
@ -421,13 +423,13 @@ namespace
RecastMeshBuilder builder(mSettings, mBounds);
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
-1, 0, -1,
-1, 0, 1,
1, 0, -1,
1, 0, 1,
})) << recastMesh->getVertices();
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({2, 1, 0, 2, 1, 3}));
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground, AreaType_ground}));
})) << recastMesh->getMesh().getVertices();
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0, 2, 1, 3}));
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground, AreaType_ground}));
}
}

View file

@ -18,7 +18,7 @@ namespace DetourNavigator
file.exceptions(std::ios::failbit | std::ios::badbit);
file.precision(std::numeric_limits<float>::max_exponent10);
std::size_t count = 0;
for (auto v : recastMesh.getVertices())
for (float v : recastMesh.getMesh().getVertices())
{
if (count % 3 == 0)
{
@ -31,7 +31,7 @@ namespace DetourNavigator
}
file << '\n';
count = 0;
for (auto v : recastMesh.getIndices())
for (int v : recastMesh.getMesh().getIndices())
{
if (count % 3 == 0)
{

View file

@ -157,26 +157,26 @@ namespace
throw NavigatorException("Failed to create heightfield for navmesh");
}
bool rasterizeSolidObjectsTriangles(rcContext& context, const RecastMesh& recastMesh, const rcConfig& config,
bool rasterizeTriangles(rcContext& context, const Mesh& mesh, const rcConfig& config,
rcHeightfield& solid)
{
std::vector<unsigned char> areas(recastMesh.getAreaTypes().begin(), recastMesh.getAreaTypes().end());
std::vector<unsigned char> areas(mesh.getAreaTypes().begin(), mesh.getAreaTypes().end());
rcClearUnwalkableTriangles(
&context,
config.walkableSlopeAngle,
recastMesh.getVertices().data(),
static_cast<int>(recastMesh.getVerticesCount()),
recastMesh.getIndices().data(),
mesh.getVertices().data(),
static_cast<int>(mesh.getVerticesCount()),
mesh.getIndices().data(),
static_cast<int>(areas.size()),
areas.data()
);
return rcRasterizeTriangles(
&context,
recastMesh.getVertices().data(),
static_cast<int>(recastMesh.getVerticesCount()),
recastMesh.getIndices().data(),
mesh.getVertices().data(),
static_cast<int>(mesh.getVerticesCount()),
mesh.getIndices().data(),
areas.data(),
static_cast<int>(areas.size()),
solid,
@ -242,7 +242,7 @@ namespace
bool rasterizeTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
const rcConfig& config, const Settings& settings, rcHeightfield& solid)
{
if (!rasterizeSolidObjectsTriangles(context, recastMesh, config, solid))
if (!rasterizeTriangles(context, recastMesh.getMesh(), config, solid))
return false;
rasterizeWaterTriangles(context, agentHalfExtents, recastMesh, settings, config, solid);

View file

@ -42,7 +42,7 @@ namespace DetourNavigator
while (!mFreeItems.empty() && mUsedNavMeshDataSize + itemSize > mMaxNavMeshDataSize)
removeLeastRecentlyUsed();
RecastMeshData key {recastMesh.getIndices(), recastMesh.getVertices(), recastMesh.getAreaTypes(), recastMesh.getWater()};
RecastMeshData key {recastMesh.getMesh(), recastMesh.getWater()};
const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentHalfExtents, changedTile, std::move(key), itemSize);
const auto emplaced = mValues.emplace(std::make_tuple(agentHalfExtents, changedTile, std::cref(iterator->mRecastMeshData)), iterator);

View file

@ -22,28 +22,26 @@ namespace DetourNavigator
{
struct RecastMeshData
{
std::vector<int> mIndices;
std::vector<float> mVertices;
std::vector<AreaType> mAreaTypes;
Mesh mMesh;
std::vector<RecastMesh::Water> mWater;
};
inline bool operator <(const RecastMeshData& lhs, const RecastMeshData& rhs)
{
return std::tie(lhs.mIndices, lhs.mVertices, lhs.mAreaTypes, lhs.mWater)
< std::tie(rhs.mIndices, rhs.mVertices, rhs.mAreaTypes, rhs.mWater);
return std::tie(lhs.mMesh, lhs.mWater)
< std::tie(rhs.mMesh, rhs.mWater);
}
inline bool operator <(const RecastMeshData& lhs, const RecastMesh& rhs)
{
return std::tie(lhs.mIndices, lhs.mVertices, lhs.mAreaTypes, lhs.mWater)
< std::tie(rhs.getIndices(), rhs.getVertices(), rhs.getAreaTypes(), rhs.getWater());
return std::tie(lhs.mMesh, lhs.mWater)
< std::tie(rhs.getMesh(), rhs.getWater());
}
inline bool operator <(const RecastMesh& lhs, const RecastMeshData& rhs)
{
return std::tie(lhs.getIndices(), lhs.getVertices(), lhs.getAreaTypes(), lhs.getWater())
< std::tie(rhs.mIndices, rhs.mVertices, rhs.mAreaTypes, rhs.mWater);
return std::tie(lhs.getMesh(), lhs.getWater())
< std::tie(rhs.mMesh, rhs.mWater);
}
class NavMeshTilesCache

View file

@ -5,23 +5,28 @@
namespace DetourNavigator
{
RecastMesh::RecastMesh(std::size_t generation, std::size_t revision, std::vector<int> indices, std::vector<float> vertices,
std::vector<AreaType> areaTypes, std::vector<Water> water)
Mesh::Mesh(std::vector<int>&& indices, std::vector<float>&& vertices, std::vector<AreaType>&& areaTypes)
{
if (indices.size() / 3 != areaTypes.size())
throw InvalidArgument("Number of flags doesn't match number of triangles: triangles="
+ std::to_string(indices.size() / 3) + ", areaTypes=" + std::to_string(areaTypes.size()));
indices.shrink_to_fit();
vertices.shrink_to_fit();
areaTypes.shrink_to_fit();
mIndices = std::move(indices);
mVertices = std::move(vertices);
mAreaTypes = std::move(areaTypes);
}
RecastMesh::RecastMesh(std::size_t generation, std::size_t revision, Mesh mesh, std::vector<Water> water)
: mGeneration(generation)
, mRevision(revision)
, mIndices(std::move(indices))
, mVertices(std::move(vertices))
, mAreaTypes(std::move(areaTypes))
, mMesh(std::move(mesh))
, mWater(std::move(water))
{
if (getTrianglesCount() != mAreaTypes.size())
throw InvalidArgument("Number of flags doesn't match number of triangles: triangles="
+ std::to_string(getTrianglesCount()) + ", areaTypes=" + std::to_string(mAreaTypes.size()));
if (getVerticesCount())
rcCalcBounds(mVertices.data(), static_cast<int>(getVerticesCount()), mBounds.mMin.ptr(), mBounds.mMax.ptr());
mIndices.shrink_to_fit();
mVertices.shrink_to_fit();
mAreaTypes.shrink_to_fit();
if (mMesh.getVerticesCount() > 0)
rcCalcBounds(mMesh.getVertices().data(), static_cast<int>(mMesh.getVerticesCount()),
mBounds.mMin.ptr(), mBounds.mMax.ptr());
mWater.shrink_to_fit();
}
}

View file

@ -15,6 +15,36 @@
namespace DetourNavigator
{
class Mesh
{
public:
Mesh(std::vector<int>&& indices, std::vector<float>&& vertices, std::vector<AreaType>&& areaTypes);
const std::vector<int>& getIndices() const noexcept { return mIndices; }
const std::vector<float>& getVertices() const noexcept { return mVertices; }
const std::vector<AreaType>& getAreaTypes() const noexcept { return mAreaTypes; }
std::size_t getVerticesCount() const noexcept { return mVertices.size() / 3; }
std::size_t getTrianglesCount() const noexcept { return mAreaTypes.size(); }
private:
std::vector<int> mIndices;
std::vector<float> mVertices;
std::vector<AreaType> mAreaTypes;
friend inline bool operator<(const Mesh& lhs, const Mesh& rhs) noexcept
{
return std::tie(lhs.mIndices, lhs.mVertices, lhs.mAreaTypes)
< std::tie(rhs.mIndices, rhs.mVertices, rhs.mAreaTypes);
}
friend inline std::size_t getSize(const Mesh& value) noexcept
{
return value.mIndices.size() * sizeof(int)
+ value.mVertices.size() * sizeof(float)
+ value.mAreaTypes.size() * sizeof(AreaType);
}
};
class RecastMesh
{
public:
@ -24,8 +54,7 @@ namespace DetourNavigator
btTransform mTransform;
};
RecastMesh(std::size_t generation, std::size_t revision, std::vector<int> indices, std::vector<float> vertices,
std::vector<AreaType> areaTypes, std::vector<Water> water);
RecastMesh(std::size_t generation, std::size_t revision, Mesh mesh, std::vector<Water> water);
std::size_t getGeneration() const
{
@ -37,36 +66,13 @@ namespace DetourNavigator
return mRevision;
}
const std::vector<int>& getIndices() const
{
return mIndices;
}
const std::vector<float>& getVertices() const
{
return mVertices;
}
const std::vector<AreaType>& getAreaTypes() const
{
return mAreaTypes;
}
const Mesh& getMesh() const noexcept { return mMesh; }
const std::vector<Water>& getWater() const
{
return mWater;
}
std::size_t getVerticesCount() const
{
return mVertices.size() / 3;
}
std::size_t getTrianglesCount() const
{
return mIndices.size() / 3;
}
const Bounds& getBounds() const
{
return mBounds;
@ -75,32 +81,25 @@ namespace DetourNavigator
private:
std::size_t mGeneration;
std::size_t mRevision;
std::vector<int> mIndices;
std::vector<float> mVertices;
std::vector<AreaType> mAreaTypes;
Mesh mMesh;
std::vector<Water> mWater;
Bounds mBounds;
friend inline std::size_t getSize(const RecastMesh& recastMesh) noexcept
friend inline bool operator <(const RecastMesh& lhs, const RecastMesh& rhs) noexcept
{
const std::size_t indicesSize = recastMesh.mIndices.size() * sizeof(int);
const std::size_t verticesSize = recastMesh.mVertices.size() * sizeof(float);
const std::size_t areaTypesSize = recastMesh.mAreaTypes.size() * sizeof(AreaType);
const std::size_t waterSize = recastMesh.mWater.size() * sizeof(RecastMesh::Water);
return indicesSize + verticesSize + areaTypesSize + waterSize;
return std::tie(lhs.mMesh, lhs.mWater) < std::tie(rhs.mMesh, rhs.mWater);
}
friend inline std::size_t getSize(const RecastMesh& value) noexcept
{
return getSize(value.mMesh) + value.mWater.size() * sizeof(RecastMesh::Water);
}
};
inline bool operator<(const RecastMesh::Water& lhs, const RecastMesh::Water& rhs)
inline bool operator<(const RecastMesh::Water& lhs, const RecastMesh::Water& rhs) noexcept
{
return std::tie(lhs.mCellSize, lhs.mTransform) < std::tie(rhs.mCellSize, rhs.mTransform);
}
inline bool operator <(const RecastMesh& lhs, const RecastMesh& rhs)
{
return std::tie(lhs.getIndices(), lhs.getVertices(), lhs.getAreaTypes(), lhs.getWater())
< std::tie(rhs.getIndices(), rhs.getVertices(), rhs.getAreaTypes(), rhs.getWater());
}
}
#endif

View file

@ -17,8 +17,8 @@
#include <algorithm>
#include <cassert>
#include <tuple>
#include <array>
#include <vector>
namespace DetourNavigator
{
@ -26,40 +26,59 @@ namespace DetourNavigator
namespace
{
void optimizeRecastMesh(std::vector<int>& indices, std::vector<float>& vertices)
RecastMeshTriangle makeRecastMeshTriangle(const btVector3* vertices, const AreaType areaType, const Settings& settings)
{
std::vector<std::tuple<float, float, float>> uniqueVertices;
uniqueVertices.reserve(vertices.size() / 3);
RecastMeshTriangle result;
result.mAreaType = areaType;
for (std::size_t i = 0; i < 3; ++i)
result.mVertices[i] = toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(vertices[i]));
return result;
}
}
for (std::size_t i = 0, n = vertices.size() / 3; i < n; ++i)
uniqueVertices.emplace_back(vertices[i * 3], vertices[i * 3 + 1], vertices[i * 3 + 2]);
Mesh makeMesh(std::vector<RecastMeshTriangle>&& triangles)
{
std::vector<osg::Vec3f> uniqueVertices;
uniqueVertices.reserve(3 * triangles.size());
std::sort(uniqueVertices.begin(), uniqueVertices.end());
const auto end = std::unique(uniqueVertices.begin(), uniqueVertices.end());
uniqueVertices.erase(end, uniqueVertices.end());
for (const RecastMeshTriangle& v : triangles)
for (const osg::Vec3f& v : v.mVertices)
uniqueVertices.push_back(v);
if (uniqueVertices.size() == vertices.size() / 3)
return;
std::sort(uniqueVertices.begin(), uniqueVertices.end());
uniqueVertices.erase(std::unique(uniqueVertices.begin(), uniqueVertices.end()), uniqueVertices.end());
for (std::size_t i = 0, n = indices.size(); i < n; ++i)
std::vector<int> indices;
indices.reserve(3 * triangles.size());
std::vector<AreaType> areaTypes;
areaTypes.reserve(triangles.size());
for (const RecastMeshTriangle& v : triangles)
{
areaTypes.push_back(v.mAreaType);
for (const osg::Vec3f& v : v.mVertices)
{
const auto index = indices[i];
const auto vertex = std::make_tuple(vertices[index * 3], vertices[index * 3 + 1], vertices[index * 3 + 2]);
const auto it = std::lower_bound(uniqueVertices.begin(), uniqueVertices.end(), vertex);
const auto it = std::lower_bound(uniqueVertices.begin(), uniqueVertices.end(), v);
assert(it != uniqueVertices.end());
assert(*it == vertex);
indices[i] = std::distance(uniqueVertices.begin(), it);
}
vertices.resize(uniqueVertices.size() * 3);
for (std::size_t i = 0, n = uniqueVertices.size(); i < n; ++i)
{
vertices[i * 3] = std::get<0>(uniqueVertices[i]);
vertices[i * 3 + 1] = std::get<1>(uniqueVertices[i]);
vertices[i * 3 + 2] = std::get<2>(uniqueVertices[i]);
assert(*it == v);
indices.push_back(static_cast<int>(it - uniqueVertices.begin()));
}
}
triangles.clear();
std::vector<float> vertices;
vertices.reserve(3 * uniqueVertices.size());
for (const osg::Vec3f& v : uniqueVertices)
{
vertices.push_back(v.x());
vertices.push_back(v.y());
vertices.push_back(v.z());
}
return Mesh(std::move(indices), std::move(vertices), std::move(areaTypes));
}
RecastMeshBuilder::RecastMeshBuilder(const Settings& settings, const TileBounds& bounds)
@ -96,37 +115,26 @@ namespace DetourNavigator
void RecastMeshBuilder::addObject(const btConcaveShape& shape, const btTransform& transform,
const AreaType areaType)
{
return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* triangle, int, int)
return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* vertices, int, int)
{
for (std::size_t i = 3; i > 0; --i)
addTriangleVertex(triangle[i - 1]);
mAreaTypes.push_back(areaType);
RecastMeshTriangle triangle = makeRecastMeshTriangle(vertices, areaType, mSettings);
std::reverse(triangle.mVertices.begin(), triangle.mVertices.end());
mTriangles.emplace_back(triangle);
}));
}
void RecastMeshBuilder::addObject(const btHeightfieldTerrainShape& shape, const btTransform& transform,
const AreaType areaType)
{
return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* triangle, int, int)
return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* vertices, int, int)
{
for (std::size_t i = 0; i < 3; ++i)
addTriangleVertex(triangle[i]);
mAreaTypes.push_back(areaType);
mTriangles.emplace_back(makeRecastMeshTriangle(vertices, areaType, mSettings));
}));
}
void RecastMeshBuilder::addObject(const btBoxShape& shape, const btTransform& transform, const AreaType areaType)
{
const auto indexOffset = static_cast<int>(mVertices.size() / 3);
for (int vertex = 0, count = shape.getNumVertices(); vertex < count; ++vertex)
{
btVector3 position;
shape.getVertex(vertex, position);
addVertex(transform(position));
}
const std::array<int, 36> indices {{
constexpr std::array<int, 36> indices {{
0, 2, 3,
3, 1, 0,
0, 4, 6,
@ -141,10 +149,17 @@ namespace DetourNavigator
4, 5, 7,
}};
std::transform(indices.begin(), indices.end(), std::back_inserter(mIndices),
[&] (int index) { return index + indexOffset; });
std::generate_n(std::back_inserter(mAreaTypes), 12, [=] { return areaType; });
for (std::size_t i = 0; i < indices.size(); i += 3)
{
std::array<btVector3, 3> vertices;
for (std::size_t j = 0; j < 3; ++j)
{
btVector3 position;
shape.getVertex(indices[i + j], position);
vertices[j] = transform(position);
}
mTriangles.emplace_back(makeRecastMeshTriangle(vertices.data(), areaType, mSettings));
}
}
void RecastMeshBuilder::addWater(const int cellSize, const btTransform& transform)
@ -154,9 +169,10 @@ namespace DetourNavigator
std::shared_ptr<RecastMesh> RecastMeshBuilder::create(std::size_t generation, std::size_t revision) &&
{
optimizeRecastMesh(mIndices, mVertices);
std::sort(mTriangles.begin(), mTriangles.end());
std::sort(mWater.begin(), mWater.end());
return std::make_shared<RecastMesh>(generation, revision, std::move(mIndices), std::move(mVertices), std::move(mAreaTypes), std::move(mWater));
Mesh mesh = makeMesh(std::move(mTriangles));
return std::make_shared<RecastMesh>(generation, revision, std::move(mesh), std::move(mWater));
}
void RecastMeshBuilder::addObject(const btConcaveShape& shape, const btTransform& transform,
@ -218,18 +234,4 @@ namespace DetourNavigator
shape.processAllTriangles(&wrapper, aabbMin, aabbMax);
}
void RecastMeshBuilder::addTriangleVertex(const btVector3& worldPosition)
{
mIndices.push_back(static_cast<int>(mVertices.size() / 3));
addVertex(worldPosition);
}
void RecastMeshBuilder::addVertex(const btVector3& worldPosition)
{
const auto navMeshPosition = toNavMeshCoordinates(mSettings, Misc::Convert::makeOsgVec3f(worldPosition));
mVertices.push_back(navMeshPosition.x());
mVertices.push_back(navMeshPosition.y());
mVertices.push_back(navMeshPosition.z());
}
}

View file

@ -4,8 +4,16 @@
#include "recastmesh.hpp"
#include "tilebounds.hpp"
#include <osg/Vec3f>
#include <LinearMath/btTransform.h>
#include <array>
#include <functional>
#include <memory>
#include <tuple>
#include <vector>
class btBoxShape;
class btCollisionShape;
class btCompoundShape;
@ -17,6 +25,17 @@ namespace DetourNavigator
{
struct Settings;
struct RecastMeshTriangle
{
AreaType mAreaType;
std::array<osg::Vec3f, 3> mVertices;
friend inline bool operator<(const RecastMeshTriangle& lhs, const RecastMeshTriangle& rhs)
{
return std::tie(lhs.mAreaType, lhs.mVertices) < std::tie(rhs.mAreaType, rhs.mVertices);
}
};
class RecastMeshBuilder
{
public:
@ -39,19 +58,15 @@ namespace DetourNavigator
private:
std::reference_wrapper<const Settings> mSettings;
TileBounds mBounds;
std::vector<int> mIndices;
std::vector<float> mVertices;
std::vector<AreaType> mAreaTypes;
std::vector<RecastMeshTriangle> mTriangles;
std::vector<RecastMesh::Water> mWater;
void addObject(const btConcaveShape& shape, const btTransform& transform, btTriangleCallback&& callback);
void addObject(const btHeightfieldTerrainShape& shape, const btTransform& transform, btTriangleCallback&& callback);
void addTriangleVertex(const btVector3& worldPosition);
void addVertex(const btVector3& worldPosition);
};
Mesh makeMesh(std::vector<RecastMeshTriangle>&& triangles);
}
#endif

View file

@ -16,9 +16,8 @@ namespace DetourNavigator
const auto object = mObjects.lower_bound(id);
if (object != mObjects.end() && object->first == id)
return false;
const auto iterator = mObjectsOrder.emplace(mObjectsOrder.end(),
mObjects.emplace_hint(object, id,
OscillatingRecastMeshObject(RecastMeshObject(shape, transform, areaType), mRevision + 1));
mObjects.emplace_hint(object, id, iterator);
++mRevision;
return true;
}
@ -30,7 +29,7 @@ namespace DetourNavigator
return false;
const std::size_t lastChangeRevision = mLastNavMeshReportedChange.has_value()
? mLastNavMeshReportedChange->mRevision : mRevision;
if (!object->second->update(transform, areaType, lastChangeRevision, mTileBounds))
if (!object->second.update(transform, areaType, lastChangeRevision, mTileBounds))
return false;
++mRevision;
return true;
@ -41,8 +40,7 @@ namespace DetourNavigator
const auto object = mObjects.find(id);
if (object == mObjects.end())
return std::nullopt;
const RemovedRecastMeshObject result {object->second->getImpl().getShape(), object->second->getImpl().getTransform()};
mObjectsOrder.erase(object->second);
const RemovedRecastMeshObject result {object->second.getImpl().getShape(), object->second.getImpl().getTransform()};
mObjects.erase(object);
++mRevision;
return result;
@ -51,12 +49,8 @@ namespace DetourNavigator
bool RecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize,
const btTransform& transform)
{
const auto iterator = mWaterOrder.emplace(mWaterOrder.end(), Water {cellSize, transform});
if (!mWater.emplace(cellPosition, iterator).second)
{
mWaterOrder.erase(iterator);
if (!mWater.emplace(cellPosition, Water {cellSize, transform}).second)
return false;
}
++mRevision;
return true;
}
@ -67,8 +61,7 @@ namespace DetourNavigator
if (water == mWater.end())
return std::nullopt;
++mRevision;
const auto result = *water->second;
mWaterOrder.erase(water->second);
const Water result = water->second;
mWater.erase(water);
return result;
}
@ -76,9 +69,9 @@ namespace DetourNavigator
std::shared_ptr<RecastMesh> RecastMeshManager::getMesh()
{
RecastMeshBuilder builder(mSettings, mTileBounds);
for (const auto& v : mWaterOrder)
for (const auto& [k, v] : mWater)
builder.addWater(v.mCellSize, v.mTransform);
for (const auto& object : mObjectsOrder)
for (const auto& [k, object] : mObjects)
{
const RecastMeshObject& v = object.getImpl();
builder.addObject(v.getShape(), v.getTransform(), v.getAreaType());

View file

@ -9,7 +9,6 @@
#include <osg/Vec2i>
#include <list>
#include <map>
#include <optional>
#include <memory>
@ -68,10 +67,8 @@ namespace DetourNavigator
std::size_t mRevision = 0;
std::size_t mGeneration;
TileBounds mTileBounds;
std::list<OscillatingRecastMeshObject> mObjectsOrder;
std::map<ObjectId, std::list<OscillatingRecastMeshObject>::iterator> mObjects;
std::list<Water> mWaterOrder;
std::map<osg::Vec2i, std::list<Water>::iterator> mWater;
std::map<ObjectId, OscillatingRecastMeshObject> mObjects;
std::map<osg::Vec2i, Water> mWater;
std::optional<Report> mLastNavMeshReportedChange;
std::optional<Report> mLastNavMeshReport;
};

View file

@ -39,10 +39,11 @@ namespace SceneUtil
{
const osg::ref_ptr<osg::Group> group(new osg::Group);
DebugDraw debugDraw(*group, osg::Vec3f(0, 0, 0), 1.0f / settings.mRecastScaleFactor);
const auto normals = calculateNormals(recastMesh.getVertices(), recastMesh.getIndices());
const DetourNavigator::Mesh& mesh = recastMesh.getMesh();
const auto normals = calculateNormals(mesh.getVertices(), mesh.getIndices());
const auto texScale = 1.0f / (settings.mCellSize * 10.0f);
duDebugDrawTriMesh(&debugDraw, recastMesh.getVertices().data(), recastMesh.getVerticesCount(),
recastMesh.getIndices().data(), normals.data(), recastMesh.getTrianglesCount(), nullptr, texScale);
duDebugDrawTriMesh(&debugDraw, mesh.getVertices().data(), mesh.getVerticesCount(),
mesh.getIndices().data(), normals.data(), mesh.getTrianglesCount(), nullptr, texScale);
return group;
}
}