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:
parent
07c70dfb73
commit
af7059373c
14 changed files with 335 additions and 316 deletions
|
@ -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)};
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue