From af7059373c3169e623aabb0e9615a9af214833e6 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 11 Jul 2021 21:43:19 +0200 Subject: [PATCH] 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. --- .../detournavigator/navmeshtilescache.cpp | 23 +- .../detournavigator/navmeshtilescache.cpp | 44 ++-- .../detournavigator/recastmeshbuilder.cpp | 236 +++++++++--------- components/detournavigator/debug.cpp | 4 +- components/detournavigator/makenavmesh.cpp | 18 +- .../detournavigator/navmeshtilescache.cpp | 2 +- .../detournavigator/navmeshtilescache.hpp | 16 +- components/detournavigator/recastmesh.cpp | 31 ++- components/detournavigator/recastmesh.hpp | 83 +++--- .../detournavigator/recastmeshbuilder.cpp | 130 +++++----- .../detournavigator/recastmeshbuilder.hpp | 29 ++- .../detournavigator/recastmeshmanager.cpp | 21 +- .../detournavigator/recastmeshmanager.hpp | 7 +- components/sceneutil/recastmesh.cpp | 7 +- 14 files changed, 335 insertions(+), 316 deletions(-) diff --git a/apps/benchmarks/detournavigator/navmeshtilescache.cpp b/apps/benchmarks/detournavigator/navmeshtilescache.cpp index 487562f404..030162ab59 100644 --- a/apps/benchmarks/detournavigator/navmeshtilescache.cpp +++ b/apps/benchmarks/detournavigator/navmeshtilescache.cpp @@ -87,6 +87,19 @@ namespace }); } + template + Mesh generateMesh(std::size_t triangles, Random& random) + { + std::uniform_real_distribution distribution(0.0, 1.0); + std::vector vertices; + std::vector indices; + std::vector areaTypes; + generateVertices(std::back_inserter(vertices), triangles * 1.98, random); + generateIndices(std::back_inserter(indices), static_cast(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 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(0, 100)(random); const std::size_t revision = std::uniform_int_distribution(0, 10000)(random); - std::vector vertices; - generateVertices(std::back_inserter(vertices), triangles * 1.98, random); - std::vector indices; - generateIndices(std::back_inserter(indices), static_cast(vertices.size() / 3) - 1, vertices.size() * 1.53, random); - std::vector areaTypes; - generateAreaTypes(std::back_inserter(areaTypes), indices.size() / 3, random); + Mesh mesh = generateMesh(triangles, random); std::vector 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)}; } diff --git a/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp b/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp index 17c1b955cf..fa607db371 100644 --- a/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp +++ b/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp @@ -128,17 +128,23 @@ namespace return result; } + Mesh makeMesh() + { + std::vector indices {{0, 1, 2}}; + std::vector vertices {{0, 0, 0, 1, 0, 0, 1, 1, 0}}; + std::vector 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 mIndices {{0, 1, 2}}; - const std::vector mVertices {{0, 0, 0, 1, 0, 0, 1, 1, 0}}; - const std::vector mAreaTypes {1, AreaType_ground}; + const Mesh mMesh {makeMesh()}; const std::vector mWater {}; - const RecastMesh mRecastMesh {mGeneration, mRevision, mIndices, mVertices, mAreaTypes, mWater}; + const RecastMesh mRecastMesh {mGeneration, mRevision, mMesh, mWater}; std::unique_ptr 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 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 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 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 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 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 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 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 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 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 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 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 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)); diff --git a/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp b/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp index 2624389b70..b11b10965b 100644 --- a/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp +++ b/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp @@ -11,6 +11,8 @@ #include #include +#include + #include #include @@ -50,9 +52,9 @@ namespace { RecastMeshBuilder builder(mSettings, mBounds); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); - EXPECT_EQ(recastMesh->getVertices(), std::vector()); - EXPECT_EQ(recastMesh->getIndices(), std::vector()); - EXPECT_EQ(recastMesh->getAreaTypes(), std::vector()); + EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector()); + EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector()); + EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector()); } TEST_F(DetourNavigatorRecastMeshBuilderTest, add_bhv_triangle_mesh_shape) @@ -64,13 +66,13 @@ namespace RecastMeshBuilder builder(mSettings, mBounds); builder.addObject(static_cast(shape), btTransform::getIdentity(), AreaType_ground); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); - EXPECT_EQ(recastMesh->getVertices(), std::vector({ - 1, 0, -1, - -1, 0, 1, + EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ -1, 0, -1, - })); - EXPECT_EQ(recastMesh->getIndices(), std::vector({0, 1, 2})); - EXPECT_EQ(recastMesh->getAreaTypes(), std::vector({AreaType_ground})); + -1, 0, 1, + 1, 0, -1, + })) << recastMesh->getMesh().getVertices(); + EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector({2, 1, 0})); + EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({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({ - 2, 3, 0, - 0, 3, 4, + EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ 0, 3, 0, - })); - EXPECT_EQ(recastMesh->getIndices(), std::vector({0, 1, 2})); - EXPECT_EQ(recastMesh->getAreaTypes(), std::vector({AreaType_ground})); + 0, 3, 4, + 2, 3, 0, + })) << recastMesh->getMesh().getVertices(); + EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector({2, 1, 0})); + EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({AreaType_ground})); } TEST_F(DetourNavigatorRecastMeshBuilderTest, add_heightfield_terrian_shape) @@ -101,14 +103,14 @@ namespace RecastMeshBuilder builder(mSettings, mBounds); builder.addObject(static_cast(shape), btTransform::getIdentity(), AreaType_ground); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); - EXPECT_EQ(recastMesh->getVertices(), std::vector({ + EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ -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({0, 1, 2, 2, 1, 3})); - EXPECT_EQ(recastMesh->getAreaTypes(), std::vector({AreaType_ground, AreaType_ground})); + EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector({0, 1, 2, 2, 1, 3})); + EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({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(shape), btTransform::getIdentity(), AreaType_ground); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); - EXPECT_EQ(recastMesh->getVertices(), std::vector({ - 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({ -1, -2, -1, - })) << recastMesh->getVertices(); - EXPECT_EQ(recastMesh->getIndices(), std::vector({ - 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(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({ + 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(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({ + EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ -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({ - 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({ 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(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(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({ - 2, 3, 0, - 0, 3, 4, + EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ 0, 3, 0, - })); - EXPECT_EQ(recastMesh->getIndices(), std::vector({0, 1, 2})); - EXPECT_EQ(recastMesh->getAreaTypes(), std::vector({AreaType_ground})); + 0, 3, 4, + 2, 3, 0, + })) << recastMesh->getMesh().getVertices(); + EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector({2, 1, 0})); + EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({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({ - 3, 12, 2, - 1, 12, 10, + EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ 1, 12, 2, - })); - EXPECT_EQ(recastMesh->getIndices(), std::vector({0, 1, 2})); - EXPECT_EQ(recastMesh->getAreaTypes(), std::vector({AreaType_ground})); + 1, 12, 10, + 3, 12, 2, + })) << recastMesh->getMesh().getVertices(); + EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector({2, 1, 0})); + EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({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({ - 1, 0, -1, - -1, 0, 1, - -1, 0, -1, - -2, 0, -3, - -3, 0, -2, + EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ -3, 0, -3, - })); - EXPECT_EQ(recastMesh->getIndices(), std::vector({0, 1, 2, 3, 4, 5})); - EXPECT_EQ(recastMesh->getAreaTypes(), std::vector(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({2, 1, 0, 5, 4, 3})); + EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector(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({ - -0.2f, 0, -0.3f, - -0.3f, 0, -0.2f, + EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ -0.3f, 0, -0.3f, - })); - EXPECT_EQ(recastMesh->getIndices(), std::vector({0, 1, 2})); - EXPECT_EQ(recastMesh->getAreaTypes(), std::vector({AreaType_ground})); + -0.3f, 0, -0.2f, + -0.2f, 0, -0.3f, + })) << recastMesh->getMesh().getVertices(); + EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector({2, 1, 0})); + EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({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({ - 0, -0.70710659027099609375, -3.535533905029296875, - 0, 0.707107067108154296875, -3.535533905029296875, - 0, 2.384185791015625e-07, -4.24264049530029296875, - }))); - EXPECT_EQ(recastMesh->getIndices(), std::vector({0, 1, 2})); - EXPECT_EQ(recastMesh->getAreaTypes(), std::vector({AreaType_ground})); + EXPECT_THAT(recastMesh->getMesh().getVertices(), Pointwise(FloatNear(1e-5), std::vector({ + 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({0, 2, 1})); + EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({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({ - -3.535533905029296875, -0.70710659027099609375, 0, - -3.535533905029296875, 0.707107067108154296875, 0, - -4.24264049530029296875, 2.384185791015625e-07, 0, - }))); - EXPECT_EQ(recastMesh->getIndices(), std::vector({0, 1, 2})); - EXPECT_EQ(recastMesh->getAreaTypes(), std::vector({AreaType_ground})); + EXPECT_THAT(recastMesh->getMesh().getVertices(), Pointwise(FloatNear(1e-5), std::vector({ + -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({1, 2, 0})); + EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({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({ - 1.41421353816986083984375, 0, 1.1920928955078125e-07, - -1.41421353816986083984375, 0, -1.1920928955078125e-07, - 1.1920928955078125e-07, 0, -1.41421353816986083984375, - }))); - EXPECT_EQ(recastMesh->getIndices(), std::vector({0, 1, 2})); - EXPECT_EQ(recastMesh->getAreaTypes(), std::vector({AreaType_ground})); + EXPECT_THAT(recastMesh->getMesh().getVertices(), Pointwise(FloatNear(1e-5), std::vector({ + -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({2, 0, 1})); + EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({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({ - 1, 0, -1, - -1, 0, 1, - -1, 0, -1, - -2, 0, -3, - -3, 0, -2, + EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ -3, 0, -3, - })); - EXPECT_EQ(recastMesh->getIndices(), std::vector({0, 1, 2, 3, 4, 5})); - EXPECT_EQ(recastMesh->getAreaTypes(), std::vector({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({2, 1, 0, 5, 4, 3})); + EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({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(shape), btTransform::getIdentity(), AreaType_ground); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); - EXPECT_EQ(recastMesh->getVertices(), std::vector({ + EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ -1, 0, -1, -1, 0, 1, 1, 0, -1, 1, 0, 1, - })) << recastMesh->getVertices(); - EXPECT_EQ(recastMesh->getIndices(), std::vector({2, 1, 0, 2, 1, 3})); - EXPECT_EQ(recastMesh->getAreaTypes(), std::vector({AreaType_ground, AreaType_ground})); + })) << recastMesh->getMesh().getVertices(); + EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector({2, 1, 0, 2, 1, 3})); + EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({AreaType_ground, AreaType_ground})); } } diff --git a/components/detournavigator/debug.cpp b/components/detournavigator/debug.cpp index c3d67b1848..4cb5b248b0 100644 --- a/components/detournavigator/debug.cpp +++ b/components/detournavigator/debug.cpp @@ -18,7 +18,7 @@ namespace DetourNavigator file.exceptions(std::ios::failbit | std::ios::badbit); file.precision(std::numeric_limits::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) { diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index 42676f4294..7145bebae7 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -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 areas(recastMesh.getAreaTypes().begin(), recastMesh.getAreaTypes().end()); + std::vector areas(mesh.getAreaTypes().begin(), mesh.getAreaTypes().end()); rcClearUnwalkableTriangles( &context, config.walkableSlopeAngle, - recastMesh.getVertices().data(), - static_cast(recastMesh.getVerticesCount()), - recastMesh.getIndices().data(), + mesh.getVertices().data(), + static_cast(mesh.getVerticesCount()), + mesh.getIndices().data(), static_cast(areas.size()), areas.data() ); return rcRasterizeTriangles( &context, - recastMesh.getVertices().data(), - static_cast(recastMesh.getVerticesCount()), - recastMesh.getIndices().data(), + mesh.getVertices().data(), + static_cast(mesh.getVerticesCount()), + mesh.getIndices().data(), areas.data(), static_cast(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); diff --git a/components/detournavigator/navmeshtilescache.cpp b/components/detournavigator/navmeshtilescache.cpp index 7c29f734ea..c4f81727ab 100644 --- a/components/detournavigator/navmeshtilescache.cpp +++ b/components/detournavigator/navmeshtilescache.cpp @@ -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); diff --git a/components/detournavigator/navmeshtilescache.hpp b/components/detournavigator/navmeshtilescache.hpp index 37c0be7211..b6b9391e66 100644 --- a/components/detournavigator/navmeshtilescache.hpp +++ b/components/detournavigator/navmeshtilescache.hpp @@ -22,28 +22,26 @@ namespace DetourNavigator { struct RecastMeshData { - std::vector mIndices; - std::vector mVertices; - std::vector mAreaTypes; + Mesh mMesh; std::vector 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 diff --git a/components/detournavigator/recastmesh.cpp b/components/detournavigator/recastmesh.cpp index 00d6ae556a..354be8207b 100644 --- a/components/detournavigator/recastmesh.cpp +++ b/components/detournavigator/recastmesh.cpp @@ -5,23 +5,28 @@ namespace DetourNavigator { - RecastMesh::RecastMesh(std::size_t generation, std::size_t revision, std::vector indices, std::vector vertices, - std::vector areaTypes, std::vector water) + Mesh::Mesh(std::vector&& indices, std::vector&& vertices, std::vector&& 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) : 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(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(mMesh.getVerticesCount()), + mBounds.mMin.ptr(), mBounds.mMax.ptr()); mWater.shrink_to_fit(); } } diff --git a/components/detournavigator/recastmesh.hpp b/components/detournavigator/recastmesh.hpp index 7f5758a85e..9989bab061 100644 --- a/components/detournavigator/recastmesh.hpp +++ b/components/detournavigator/recastmesh.hpp @@ -15,6 +15,36 @@ namespace DetourNavigator { + class Mesh + { + public: + Mesh(std::vector&& indices, std::vector&& vertices, std::vector&& areaTypes); + + const std::vector& getIndices() const noexcept { return mIndices; } + const std::vector& getVertices() const noexcept { return mVertices; } + const std::vector& 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 mIndices; + std::vector mVertices; + std::vector 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 indices, std::vector vertices, - std::vector areaTypes, std::vector water); + RecastMesh(std::size_t generation, std::size_t revision, Mesh mesh, std::vector water); std::size_t getGeneration() const { @@ -37,36 +66,13 @@ namespace DetourNavigator return mRevision; } - const std::vector& getIndices() const - { - return mIndices; - } - - const std::vector& getVertices() const - { - return mVertices; - } - - const std::vector& getAreaTypes() const - { - return mAreaTypes; - } + const Mesh& getMesh() const noexcept { return mMesh; } const std::vector& 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 mIndices; - std::vector mVertices; - std::vector mAreaTypes; + Mesh mMesh; std::vector 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 diff --git a/components/detournavigator/recastmeshbuilder.cpp b/components/detournavigator/recastmeshbuilder.cpp index 8ecbf1ec8e..8de82bee16 100644 --- a/components/detournavigator/recastmeshbuilder.cpp +++ b/components/detournavigator/recastmeshbuilder.cpp @@ -17,8 +17,8 @@ #include #include -#include #include +#include namespace DetourNavigator { @@ -26,40 +26,59 @@ namespace DetourNavigator namespace { - void optimizeRecastMesh(std::vector& indices, std::vector& vertices) + RecastMeshTriangle makeRecastMeshTriangle(const btVector3* vertices, const AreaType areaType, const Settings& settings) { - std::vector> 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&& triangles) + { + std::vector 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 indices; + indices.reserve(3 * triangles.size()); + std::vector 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(it - uniqueVertices.begin())); } } + + triangles.clear(); + + std::vector 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(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 indices {{ + constexpr std::array 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 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 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(generation, revision, std::move(mIndices), std::move(mVertices), std::move(mAreaTypes), std::move(mWater)); + Mesh mesh = makeMesh(std::move(mTriangles)); + return std::make_shared(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(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()); - } } diff --git a/components/detournavigator/recastmeshbuilder.hpp b/components/detournavigator/recastmeshbuilder.hpp index cb1b79377a..1d163a406f 100644 --- a/components/detournavigator/recastmeshbuilder.hpp +++ b/components/detournavigator/recastmeshbuilder.hpp @@ -4,8 +4,16 @@ #include "recastmesh.hpp" #include "tilebounds.hpp" +#include + #include +#include +#include +#include +#include +#include + class btBoxShape; class btCollisionShape; class btCompoundShape; @@ -17,6 +25,17 @@ namespace DetourNavigator { struct Settings; + struct RecastMeshTriangle + { + AreaType mAreaType; + std::array 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 mSettings; TileBounds mBounds; - std::vector mIndices; - std::vector mVertices; - std::vector mAreaTypes; + std::vector mTriangles; std::vector 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&& triangles); } #endif diff --git a/components/detournavigator/recastmeshmanager.cpp b/components/detournavigator/recastmeshmanager.cpp index e7afeb2848..ed77b4cef4 100644 --- a/components/detournavigator/recastmeshmanager.cpp +++ b/components/detournavigator/recastmeshmanager.cpp @@ -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 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()); diff --git a/components/detournavigator/recastmeshmanager.hpp b/components/detournavigator/recastmeshmanager.hpp index 956170d3b4..d67f287dfc 100644 --- a/components/detournavigator/recastmeshmanager.hpp +++ b/components/detournavigator/recastmeshmanager.hpp @@ -9,7 +9,6 @@ #include -#include #include #include #include @@ -68,10 +67,8 @@ namespace DetourNavigator std::size_t mRevision = 0; std::size_t mGeneration; TileBounds mTileBounds; - std::list mObjectsOrder; - std::map::iterator> mObjects; - std::list mWaterOrder; - std::map::iterator> mWater; + std::map mObjects; + std::map mWater; std::optional mLastNavMeshReportedChange; std::optional mLastNavMeshReport; }; diff --git a/components/sceneutil/recastmesh.cpp b/components/sceneutil/recastmesh.cpp index 2716f46832..ce92b16a0e 100644 --- a/components/sceneutil/recastmesh.cpp +++ b/components/sceneutil/recastmesh.cpp @@ -39,10 +39,11 @@ namespace SceneUtil { const osg::ref_ptr 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; } }