mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 05:29:54 +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>
|
template <class Random>
|
||||||
Key generateKey(std::size_t triangles, Random& random)
|
Key generateKey(std::size_t triangles, Random& random)
|
||||||
{
|
{
|
||||||
|
@ -94,16 +107,10 @@ namespace
|
||||||
const TilePosition tilePosition = generateTilePosition(10000, random);
|
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 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);
|
const std::size_t revision = std::uniform_int_distribution<std::size_t>(0, 10000)(random);
|
||||||
std::vector<float> vertices;
|
Mesh mesh = generateMesh(triangles, random);
|
||||||
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);
|
|
||||||
std::vector<RecastMesh::Water> water;
|
std::vector<RecastMesh::Water> water;
|
||||||
generateWater(std::back_inserter(water), 2, random);
|
generateWater(std::back_inserter(water), 2, random);
|
||||||
RecastMesh recastMesh(generation, revision, std::move(indices), std::move(vertices),
|
RecastMesh recastMesh(generation, revision, std::move(mesh), std::move(water));
|
||||||
std::move(areaTypes), std::move(water));
|
|
||||||
return Key {agentHalfExtents, tilePosition, std::move(recastMesh)};
|
return Key {agentHalfExtents, tilePosition, std::move(recastMesh)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -128,17 +128,23 @@ namespace
|
||||||
return result;
|
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
|
struct DetourNavigatorNavMeshTilesCacheTest : Test
|
||||||
{
|
{
|
||||||
const osg::Vec3f mAgentHalfExtents {1, 2, 3};
|
const osg::Vec3f mAgentHalfExtents {1, 2, 3};
|
||||||
const TilePosition mTilePosition {0, 0};
|
const TilePosition mTilePosition {0, 0};
|
||||||
const std::size_t mGeneration = 0;
|
const std::size_t mGeneration = 0;
|
||||||
const std::size_t mRevision = 0;
|
const std::size_t mRevision = 0;
|
||||||
const std::vector<int> mIndices {{0, 1, 2}};
|
const Mesh mMesh {makeMesh()};
|
||||||
const std::vector<float> mVertices {{0, 0, 0, 1, 0, 0, 1, 1, 0}};
|
|
||||||
const std::vector<AreaType> mAreaTypes {1, AreaType_ground};
|
|
||||||
const std::vector<RecastMesh::Water> mWater {};
|
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)};
|
std::unique_ptr<PreparedNavMeshData> mPreparedNavMeshData {makePeparedNavMeshData(3)};
|
||||||
|
|
||||||
const std::size_t mRecastMeshSize = sizeof(mRecastMesh) + getSize(mRecastMesh);
|
const std::size_t mRecastMeshSize = sizeof(mRecastMesh) + getSize(mRecastMesh);
|
||||||
|
@ -226,7 +232,7 @@ namespace
|
||||||
const std::size_t maxSize = 1;
|
const std::size_t maxSize = 1;
|
||||||
NavMeshTilesCache cache(maxSize);
|
NavMeshTilesCache cache(maxSize);
|
||||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
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));
|
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||||
EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, unexistentRecastMesh));
|
EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, unexistentRecastMesh));
|
||||||
|
@ -238,7 +244,7 @@ namespace
|
||||||
NavMeshTilesCache cache(maxSize);
|
NavMeshTilesCache cache(maxSize);
|
||||||
|
|
||||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
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);
|
auto anotherPreparedNavMeshData = makePeparedNavMeshData(3);
|
||||||
const auto copy = clone(*anotherPreparedNavMeshData);
|
const auto copy = clone(*anotherPreparedNavMeshData);
|
||||||
|
|
||||||
|
@ -256,7 +262,7 @@ namespace
|
||||||
NavMeshTilesCache cache(maxSize);
|
NavMeshTilesCache cache(maxSize);
|
||||||
|
|
||||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
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);
|
auto anotherPreparedNavMeshData = makePeparedNavMeshData(3);
|
||||||
|
|
||||||
const auto value = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh,
|
const auto value = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh,
|
||||||
|
@ -272,13 +278,11 @@ namespace
|
||||||
const auto copy = clone(*mPreparedNavMeshData);
|
const auto copy = clone(*mPreparedNavMeshData);
|
||||||
|
|
||||||
const std::vector<RecastMesh::Water> leastRecentlySetWater {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
const std::vector<RecastMesh::Water> leastRecentlySetWater {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||||
const RecastMesh leastRecentlySetRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
const RecastMesh leastRecentlySetRecastMesh {mGeneration, mRevision, mMesh, leastRecentlySetWater};
|
||||||
mAreaTypes, leastRecentlySetWater};
|
|
||||||
auto leastRecentlySetData = makePeparedNavMeshData(3);
|
auto leastRecentlySetData = makePeparedNavMeshData(3);
|
||||||
|
|
||||||
const std::vector<RecastMesh::Water> mostRecentlySetWater {1, RecastMesh::Water {2, btTransform::getIdentity()}};
|
const std::vector<RecastMesh::Water> mostRecentlySetWater {1, RecastMesh::Water {2, btTransform::getIdentity()}};
|
||||||
const RecastMesh mostRecentlySetRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
const RecastMesh mostRecentlySetRecastMesh {mGeneration, mRevision, mMesh, mostRecentlySetWater};
|
||||||
mAreaTypes, mostRecentlySetWater};
|
|
||||||
auto mostRecentlySetData = makePeparedNavMeshData(3);
|
auto mostRecentlySetData = makePeparedNavMeshData(3);
|
||||||
|
|
||||||
ASSERT_TRUE(cache.set(mAgentHalfExtents, mTilePosition, leastRecentlySetRecastMesh,
|
ASSERT_TRUE(cache.set(mAgentHalfExtents, mTilePosition, leastRecentlySetRecastMesh,
|
||||||
|
@ -300,14 +304,12 @@ namespace
|
||||||
NavMeshTilesCache cache(maxSize);
|
NavMeshTilesCache cache(maxSize);
|
||||||
|
|
||||||
const std::vector<RecastMesh::Water> leastRecentlyUsedWater {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
const std::vector<RecastMesh::Water> leastRecentlyUsedWater {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||||
const RecastMesh leastRecentlyUsedRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
const RecastMesh leastRecentlyUsedRecastMesh {mGeneration, mRevision, mMesh, leastRecentlyUsedWater};
|
||||||
mAreaTypes, leastRecentlyUsedWater};
|
|
||||||
auto leastRecentlyUsedData = makePeparedNavMeshData(3);
|
auto leastRecentlyUsedData = makePeparedNavMeshData(3);
|
||||||
const auto leastRecentlyUsedCopy = clone(*leastRecentlyUsedData);
|
const auto leastRecentlyUsedCopy = clone(*leastRecentlyUsedData);
|
||||||
|
|
||||||
const std::vector<RecastMesh::Water> mostRecentlyUsedWater {1, RecastMesh::Water {2, btTransform::getIdentity()}};
|
const std::vector<RecastMesh::Water> mostRecentlyUsedWater {1, RecastMesh::Water {2, btTransform::getIdentity()}};
|
||||||
const RecastMesh mostRecentlyUsedRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
const RecastMesh mostRecentlyUsedRecastMesh {mGeneration, mRevision, mMesh, mostRecentlyUsedWater};
|
||||||
mAreaTypes, mostRecentlyUsedWater};
|
|
||||||
auto mostRecentlyUsedData = makePeparedNavMeshData(3);
|
auto mostRecentlyUsedData = makePeparedNavMeshData(3);
|
||||||
const auto mostRecentlyUsedCopy = clone(*mostRecentlyUsedData);
|
const auto mostRecentlyUsedCopy = clone(*mostRecentlyUsedData);
|
||||||
|
|
||||||
|
@ -341,7 +343,7 @@ namespace
|
||||||
NavMeshTilesCache cache(maxSize);
|
NavMeshTilesCache cache(maxSize);
|
||||||
|
|
||||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
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);
|
auto tooLargeData = makePeparedNavMeshData(10);
|
||||||
|
|
||||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||||
|
@ -355,12 +357,11 @@ namespace
|
||||||
NavMeshTilesCache cache(maxSize);
|
NavMeshTilesCache cache(maxSize);
|
||||||
|
|
||||||
const std::vector<RecastMesh::Water> anotherWater {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
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);
|
auto anotherData = makePeparedNavMeshData(3);
|
||||||
|
|
||||||
const std::vector<RecastMesh::Water> tooLargeWater {1, RecastMesh::Water {2, btTransform::getIdentity()}};
|
const std::vector<RecastMesh::Water> tooLargeWater {1, RecastMesh::Water {2, btTransform::getIdentity()}};
|
||||||
const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mMesh, tooLargeWater};
|
||||||
mAreaTypes, tooLargeWater};
|
|
||||||
auto tooLargeData = makePeparedNavMeshData(10);
|
auto tooLargeData = makePeparedNavMeshData(10);
|
||||||
|
|
||||||
const auto value = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh,
|
const auto value = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh,
|
||||||
|
@ -380,8 +381,7 @@ namespace
|
||||||
NavMeshTilesCache cache(maxSize);
|
NavMeshTilesCache cache(maxSize);
|
||||||
|
|
||||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
||||||
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mIndices, mVertices,
|
const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water};
|
||||||
mAreaTypes, water};
|
|
||||||
auto anotherData = makePeparedNavMeshData(3);
|
auto anotherData = makePeparedNavMeshData(3);
|
||||||
|
|
||||||
const auto firstCopy = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
const auto firstCopy = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||||
|
@ -400,7 +400,7 @@ namespace
|
||||||
NavMeshTilesCache cache(maxSize);
|
NavMeshTilesCache cache(maxSize);
|
||||||
|
|
||||||
const std::vector<RecastMesh::Water> water {1, RecastMesh::Water {1, btTransform::getIdentity()}};
|
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);
|
auto anotherData = makePeparedNavMeshData(3);
|
||||||
|
|
||||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
||||||
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
|
#include <BulletCollision/CollisionShapes/btCompoundShape.h>
|
||||||
|
|
||||||
|
#include <DetourCommon.h>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
|
@ -50,9 +52,9 @@ namespace
|
||||||
{
|
{
|
||||||
RecastMeshBuilder builder(mSettings, mBounds);
|
RecastMeshBuilder builder(mSettings, mBounds);
|
||||||
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
||||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>());
|
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>());
|
||||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>());
|
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>());
|
||||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>());
|
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_bhv_triangle_mesh_shape)
|
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_bhv_triangle_mesh_shape)
|
||||||
|
@ -64,13 +66,13 @@ namespace
|
||||||
RecastMeshBuilder builder(mSettings, mBounds);
|
RecastMeshBuilder builder(mSettings, mBounds);
|
||||||
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
|
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
|
||||||
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
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,
|
||||||
}));
|
-1, 0, 1,
|
||||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
1, 0, -1,
|
||||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
})) << 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)
|
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_transformed_bhv_triangle_mesh_shape)
|
||||||
|
@ -85,13 +87,13 @@ namespace
|
||||||
AreaType_ground
|
AreaType_ground
|
||||||
);
|
);
|
||||||
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
||||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
|
||||||
2, 3, 0,
|
|
||||||
0, 3, 4,
|
|
||||||
0, 3, 0,
|
0, 3, 0,
|
||||||
}));
|
0, 3, 4,
|
||||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
2, 3, 0,
|
||||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
})) << 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)
|
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_heightfield_terrian_shape)
|
||||||
|
@ -101,14 +103,14 @@ namespace
|
||||||
RecastMeshBuilder builder(mSettings, mBounds);
|
RecastMeshBuilder builder(mSettings, mBounds);
|
||||||
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
|
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
|
||||||
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
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,
|
||||||
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->getMesh().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().getAreaTypes(), std::vector<AreaType>({AreaType_ground, AreaType_ground}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_box_shape_should_produce_12_triangles)
|
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_box_shape_should_produce_12_triangles)
|
||||||
|
@ -117,31 +119,31 @@ namespace
|
||||||
RecastMeshBuilder builder(mSettings, mBounds);
|
RecastMeshBuilder builder(mSettings, mBounds);
|
||||||
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
|
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
|
||||||
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
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, 2, -1,
|
|
||||||
-1, 2, -1,
|
|
||||||
1, -2, 1,
|
|
||||||
-1, -2, 1,
|
|
||||||
1, -2, -1,
|
|
||||||
-1, -2, -1,
|
-1, -2, -1,
|
||||||
})) << recastMesh->getVertices();
|
-1, -2, 1,
|
||||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({
|
-1, 2, -1,
|
||||||
0, 2, 3,
|
-1, 2, 1,
|
||||||
3, 1, 0,
|
1, -2, -1,
|
||||||
0, 4, 6,
|
1, -2, 1,
|
||||||
6, 2, 0,
|
1, 2, -1,
|
||||||
0, 1, 5,
|
1, 2, 1,
|
||||||
5, 4, 0,
|
})) << recastMesh->getMesh().getVertices();
|
||||||
7, 5, 1,
|
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({
|
||||||
1, 3, 7,
|
0, 1, 3,
|
||||||
7, 3, 2,
|
0, 2, 6,
|
||||||
2, 6, 7,
|
0, 4, 5,
|
||||||
7, 6, 4,
|
1, 5, 7,
|
||||||
4, 5, 7,
|
2, 3, 7,
|
||||||
})) << recastMesh->getIndices();
|
3, 2, 0,
|
||||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>(12, AreaType_ground));
|
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)
|
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_compound_shape)
|
||||||
|
@ -164,7 +166,7 @@ namespace
|
||||||
AreaType_ground
|
AreaType_ground
|
||||||
);
|
);
|
||||||
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
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, -2, 1,
|
-1, -2, 1,
|
||||||
-1, 0, -1,
|
-1, 0, -1,
|
||||||
|
@ -177,24 +179,24 @@ namespace
|
||||||
1, 0, 1,
|
1, 0, 1,
|
||||||
1, 2, -1,
|
1, 2, -1,
|
||||||
1, 2, 1,
|
1, 2, 1,
|
||||||
})) << recastMesh->getVertices();
|
})) << recastMesh->getMesh().getVertices();
|
||||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({
|
EXPECT_EQ(recastMesh->getMesh().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,
|
|
||||||
0, 1, 5,
|
0, 1, 5,
|
||||||
5, 4, 0,
|
|
||||||
0, 4, 10,
|
0, 4, 10,
|
||||||
10, 6, 0,
|
|
||||||
0, 6, 7,
|
0, 6, 7,
|
||||||
|
1, 7, 11,
|
||||||
|
4, 5, 11,
|
||||||
|
5, 4, 0,
|
||||||
|
6, 10, 11,
|
||||||
7, 1, 0,
|
7, 1, 0,
|
||||||
|
8, 3, 2,
|
||||||
8, 3, 9,
|
8, 3, 9,
|
||||||
})) << recastMesh->getIndices();
|
10, 6, 0,
|
||||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>(14, AreaType_ground));
|
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)
|
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_transformed_compound_shape)
|
||||||
|
@ -211,13 +213,13 @@ namespace
|
||||||
AreaType_ground
|
AreaType_ground
|
||||||
);
|
);
|
||||||
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
||||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
|
||||||
2, 3, 0,
|
|
||||||
0, 3, 4,
|
|
||||||
0, 3, 0,
|
0, 3, 0,
|
||||||
}));
|
0, 3, 4,
|
||||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
2, 3, 0,
|
||||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
})) << 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)
|
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_transformed_compound_shape_with_transformed_bhv_triangle_shape)
|
||||||
|
@ -235,13 +237,13 @@ namespace
|
||||||
AreaType_ground
|
AreaType_ground
|
||||||
);
|
);
|
||||||
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
||||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector<float>({
|
||||||
3, 12, 2,
|
|
||||||
1, 12, 10,
|
|
||||||
1, 12, 2,
|
1, 12, 2,
|
||||||
}));
|
1, 12, 10,
|
||||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
3, 12, 2,
|
||||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
})) << 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)
|
TEST_F(DetourNavigatorRecastMeshBuilderTest, without_bounds_add_bhv_triangle_shape_should_not_filter_by_bounds)
|
||||||
|
@ -257,16 +259,16 @@ namespace
|
||||||
AreaType_ground
|
AreaType_ground
|
||||||
);
|
);
|
||||||
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
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,
|
|
||||||
-2, 0, -3,
|
|
||||||
-3, 0, -2,
|
|
||||||
-3, 0, -3,
|
-3, 0, -3,
|
||||||
}));
|
-3, 0, -2,
|
||||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2, 3, 4, 5}));
|
-2, 0, -3,
|
||||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>(2, AreaType_ground));
|
-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)
|
TEST_F(DetourNavigatorRecastMeshBuilderTest, with_bounds_add_bhv_triangle_shape_should_filter_by_bounds)
|
||||||
|
@ -285,13 +287,13 @@ namespace
|
||||||
AreaType_ground
|
AreaType_ground
|
||||||
);
|
);
|
||||||
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
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.2f, 0, -0.3f,
|
|
||||||
-0.3f, 0, -0.2f,
|
|
||||||
-0.3f, 0, -0.3f,
|
-0.3f, 0, -0.3f,
|
||||||
}));
|
-0.3f, 0, -0.2f,
|
||||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
-0.2f, 0, -0.3f,
|
||||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
})) << 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)
|
TEST_F(DetourNavigatorRecastMeshBuilderTest, with_bounds_add_rotated_by_x_bhv_triangle_shape_should_filter_by_bounds)
|
||||||
|
@ -310,13 +312,13 @@ namespace
|
||||||
AreaType_ground
|
AreaType_ground
|
||||||
);
|
);
|
||||||
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
||||||
EXPECT_THAT(recastMesh->getVertices(), Pointwise(FloatNear(1e-5), std::vector<float>({
|
EXPECT_THAT(recastMesh->getMesh().getVertices(), Pointwise(FloatNear(1e-5), std::vector<float>({
|
||||||
0, -0.70710659027099609375, -3.535533905029296875,
|
0, -0.707106769084930419921875, -3.535533905029296875,
|
||||||
0, 0.707107067108154296875, -3.535533905029296875,
|
0, 4.44089209850062616169452667236328125e-16, -4.24264049530029296875,
|
||||||
0, 2.384185791015625e-07, -4.24264049530029296875,
|
0, 0.707106769084930419921875, -3.535533905029296875,
|
||||||
})));
|
}))) << recastMesh->getMesh().getVertices();
|
||||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({0, 2, 1}));
|
||||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
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)
|
TEST_F(DetourNavigatorRecastMeshBuilderTest, with_bounds_add_rotated_by_y_bhv_triangle_shape_should_filter_by_bounds)
|
||||||
|
@ -335,13 +337,13 @@ namespace
|
||||||
AreaType_ground
|
AreaType_ground
|
||||||
);
|
);
|
||||||
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
||||||
EXPECT_THAT(recastMesh->getVertices(), Pointwise(FloatNear(1e-5), std::vector<float>({
|
EXPECT_THAT(recastMesh->getMesh().getVertices(), Pointwise(FloatNear(1e-5), std::vector<float>({
|
||||||
-3.535533905029296875, -0.70710659027099609375, 0,
|
-4.24264049530029296875, 4.44089209850062616169452667236328125e-16, 0,
|
||||||
-3.535533905029296875, 0.707107067108154296875, 0,
|
-3.535533905029296875, -0.707106769084930419921875, 0,
|
||||||
-4.24264049530029296875, 2.384185791015625e-07, 0,
|
-3.535533905029296875, 0.707106769084930419921875, 0,
|
||||||
})));
|
}))) << recastMesh->getMesh().getVertices();
|
||||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({1, 2, 0}));
|
||||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
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)
|
TEST_F(DetourNavigatorRecastMeshBuilderTest, with_bounds_add_rotated_by_z_bhv_triangle_shape_should_filter_by_bounds)
|
||||||
|
@ -360,13 +362,13 @@ namespace
|
||||||
AreaType_ground
|
AreaType_ground
|
||||||
);
|
);
|
||||||
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
||||||
EXPECT_THAT(recastMesh->getVertices(), Pointwise(FloatNear(1e-5), std::vector<float>({
|
EXPECT_THAT(recastMesh->getMesh().getVertices(), Pointwise(FloatNear(1e-5), std::vector<float>({
|
||||||
1.41421353816986083984375, 0, 1.1920928955078125e-07,
|
-1.41421353816986083984375, 0, -1.1102230246251565404236316680908203125e-16,
|
||||||
-1.41421353816986083984375, 0, -1.1920928955078125e-07,
|
1.1102230246251565404236316680908203125e-16, 0, -1.41421353816986083984375,
|
||||||
1.1920928955078125e-07, 0, -1.41421353816986083984375,
|
1.41421353816986083984375, 0, 1.1102230246251565404236316680908203125e-16,
|
||||||
})));
|
}))) << recastMesh->getMesh().getVertices();
|
||||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 0, 1}));
|
||||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorRecastMeshBuilderTest, flags_values_should_be_corresponding_to_added_objects)
|
TEST_F(DetourNavigatorRecastMeshBuilderTest, flags_values_should_be_corresponding_to_added_objects)
|
||||||
|
@ -389,16 +391,16 @@ namespace
|
||||||
AreaType_null
|
AreaType_null
|
||||||
);
|
);
|
||||||
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
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,
|
|
||||||
-2, 0, -3,
|
|
||||||
-3, 0, -2,
|
|
||||||
-3, 0, -3,
|
-3, 0, -3,
|
||||||
}));
|
-3, 0, -2,
|
||||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2, 3, 4, 5}));
|
-2, 0, -3,
|
||||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground, AreaType_null}));
|
-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)
|
TEST_F(DetourNavigatorRecastMeshBuilderTest, add_water_then_get_water_should_return_it)
|
||||||
|
@ -421,13 +423,13 @@ namespace
|
||||||
RecastMeshBuilder builder(mSettings, mBounds);
|
RecastMeshBuilder builder(mSettings, mBounds);
|
||||||
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
|
builder.addObject(static_cast<const btCollisionShape&>(shape), btTransform::getIdentity(), AreaType_ground);
|
||||||
const auto recastMesh = std::move(builder).create(mGeneration, mRevision);
|
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,
|
||||||
1, 0, -1,
|
1, 0, -1,
|
||||||
1, 0, 1,
|
1, 0, 1,
|
||||||
})) << recastMesh->getVertices();
|
})) << recastMesh->getMesh().getVertices();
|
||||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({2, 1, 0, 2, 1, 3}));
|
EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector<int>({2, 1, 0, 2, 1, 3}));
|
||||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground, AreaType_ground}));
|
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.exceptions(std::ios::failbit | std::ios::badbit);
|
||||||
file.precision(std::numeric_limits<float>::max_exponent10);
|
file.precision(std::numeric_limits<float>::max_exponent10);
|
||||||
std::size_t count = 0;
|
std::size_t count = 0;
|
||||||
for (auto v : recastMesh.getVertices())
|
for (float v : recastMesh.getMesh().getVertices())
|
||||||
{
|
{
|
||||||
if (count % 3 == 0)
|
if (count % 3 == 0)
|
||||||
{
|
{
|
||||||
|
@ -31,7 +31,7 @@ namespace DetourNavigator
|
||||||
}
|
}
|
||||||
file << '\n';
|
file << '\n';
|
||||||
count = 0;
|
count = 0;
|
||||||
for (auto v : recastMesh.getIndices())
|
for (int v : recastMesh.getMesh().getIndices())
|
||||||
{
|
{
|
||||||
if (count % 3 == 0)
|
if (count % 3 == 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -157,26 +157,26 @@ namespace
|
||||||
throw NavigatorException("Failed to create heightfield for navmesh");
|
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)
|
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(
|
rcClearUnwalkableTriangles(
|
||||||
&context,
|
&context,
|
||||||
config.walkableSlopeAngle,
|
config.walkableSlopeAngle,
|
||||||
recastMesh.getVertices().data(),
|
mesh.getVertices().data(),
|
||||||
static_cast<int>(recastMesh.getVerticesCount()),
|
static_cast<int>(mesh.getVerticesCount()),
|
||||||
recastMesh.getIndices().data(),
|
mesh.getIndices().data(),
|
||||||
static_cast<int>(areas.size()),
|
static_cast<int>(areas.size()),
|
||||||
areas.data()
|
areas.data()
|
||||||
);
|
);
|
||||||
|
|
||||||
return rcRasterizeTriangles(
|
return rcRasterizeTriangles(
|
||||||
&context,
|
&context,
|
||||||
recastMesh.getVertices().data(),
|
mesh.getVertices().data(),
|
||||||
static_cast<int>(recastMesh.getVerticesCount()),
|
static_cast<int>(mesh.getVerticesCount()),
|
||||||
recastMesh.getIndices().data(),
|
mesh.getIndices().data(),
|
||||||
areas.data(),
|
areas.data(),
|
||||||
static_cast<int>(areas.size()),
|
static_cast<int>(areas.size()),
|
||||||
solid,
|
solid,
|
||||||
|
@ -242,7 +242,7 @@ namespace
|
||||||
bool rasterizeTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
|
bool rasterizeTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
|
||||||
const rcConfig& config, const Settings& settings, rcHeightfield& solid)
|
const rcConfig& config, const Settings& settings, rcHeightfield& solid)
|
||||||
{
|
{
|
||||||
if (!rasterizeSolidObjectsTriangles(context, recastMesh, config, solid))
|
if (!rasterizeTriangles(context, recastMesh.getMesh(), config, solid))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
rasterizeWaterTriangles(context, agentHalfExtents, recastMesh, settings, config, solid);
|
rasterizeWaterTriangles(context, agentHalfExtents, recastMesh, settings, config, solid);
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace DetourNavigator
|
||||||
while (!mFreeItems.empty() && mUsedNavMeshDataSize + itemSize > mMaxNavMeshDataSize)
|
while (!mFreeItems.empty() && mUsedNavMeshDataSize + itemSize > mMaxNavMeshDataSize)
|
||||||
removeLeastRecentlyUsed();
|
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 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);
|
const auto emplaced = mValues.emplace(std::make_tuple(agentHalfExtents, changedTile, std::cref(iterator->mRecastMeshData)), iterator);
|
||||||
|
|
|
@ -22,28 +22,26 @@ namespace DetourNavigator
|
||||||
{
|
{
|
||||||
struct RecastMeshData
|
struct RecastMeshData
|
||||||
{
|
{
|
||||||
std::vector<int> mIndices;
|
Mesh mMesh;
|
||||||
std::vector<float> mVertices;
|
|
||||||
std::vector<AreaType> mAreaTypes;
|
|
||||||
std::vector<RecastMesh::Water> mWater;
|
std::vector<RecastMesh::Water> mWater;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool operator <(const RecastMeshData& lhs, const RecastMeshData& rhs)
|
inline bool operator <(const RecastMeshData& lhs, const RecastMeshData& rhs)
|
||||||
{
|
{
|
||||||
return std::tie(lhs.mIndices, lhs.mVertices, lhs.mAreaTypes, lhs.mWater)
|
return std::tie(lhs.mMesh, lhs.mWater)
|
||||||
< std::tie(rhs.mIndices, rhs.mVertices, rhs.mAreaTypes, rhs.mWater);
|
< std::tie(rhs.mMesh, rhs.mWater);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator <(const RecastMeshData& lhs, const RecastMesh& rhs)
|
inline bool operator <(const RecastMeshData& lhs, const RecastMesh& rhs)
|
||||||
{
|
{
|
||||||
return std::tie(lhs.mIndices, lhs.mVertices, lhs.mAreaTypes, lhs.mWater)
|
return std::tie(lhs.mMesh, lhs.mWater)
|
||||||
< std::tie(rhs.getIndices(), rhs.getVertices(), rhs.getAreaTypes(), rhs.getWater());
|
< std::tie(rhs.getMesh(), rhs.getWater());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator <(const RecastMesh& lhs, const RecastMeshData& rhs)
|
inline bool operator <(const RecastMesh& lhs, const RecastMeshData& rhs)
|
||||||
{
|
{
|
||||||
return std::tie(lhs.getIndices(), lhs.getVertices(), lhs.getAreaTypes(), lhs.getWater())
|
return std::tie(lhs.getMesh(), lhs.getWater())
|
||||||
< std::tie(rhs.mIndices, rhs.mVertices, rhs.mAreaTypes, rhs.mWater);
|
< std::tie(rhs.mMesh, rhs.mWater);
|
||||||
}
|
}
|
||||||
|
|
||||||
class NavMeshTilesCache
|
class NavMeshTilesCache
|
||||||
|
|
|
@ -5,23 +5,28 @@
|
||||||
|
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
{
|
{
|
||||||
RecastMesh::RecastMesh(std::size_t generation, std::size_t revision, std::vector<int> indices, std::vector<float> vertices,
|
Mesh::Mesh(std::vector<int>&& indices, std::vector<float>&& vertices, std::vector<AreaType>&& areaTypes)
|
||||||
std::vector<AreaType> areaTypes, std::vector<Water> water)
|
{
|
||||||
|
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)
|
: mGeneration(generation)
|
||||||
, mRevision(revision)
|
, mRevision(revision)
|
||||||
, mIndices(std::move(indices))
|
, mMesh(std::move(mesh))
|
||||||
, mVertices(std::move(vertices))
|
|
||||||
, mAreaTypes(std::move(areaTypes))
|
|
||||||
, mWater(std::move(water))
|
, mWater(std::move(water))
|
||||||
{
|
{
|
||||||
if (getTrianglesCount() != mAreaTypes.size())
|
if (mMesh.getVerticesCount() > 0)
|
||||||
throw InvalidArgument("Number of flags doesn't match number of triangles: triangles="
|
rcCalcBounds(mMesh.getVertices().data(), static_cast<int>(mMesh.getVerticesCount()),
|
||||||
+ std::to_string(getTrianglesCount()) + ", areaTypes=" + std::to_string(mAreaTypes.size()));
|
mBounds.mMin.ptr(), mBounds.mMax.ptr());
|
||||||
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();
|
|
||||||
mWater.shrink_to_fit();
|
mWater.shrink_to_fit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,36 @@
|
||||||
|
|
||||||
namespace DetourNavigator
|
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
|
class RecastMesh
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -24,8 +54,7 @@ namespace DetourNavigator
|
||||||
btTransform mTransform;
|
btTransform mTransform;
|
||||||
};
|
};
|
||||||
|
|
||||||
RecastMesh(std::size_t generation, std::size_t revision, std::vector<int> indices, std::vector<float> vertices,
|
RecastMesh(std::size_t generation, std::size_t revision, Mesh mesh, std::vector<Water> water);
|
||||||
std::vector<AreaType> areaTypes, std::vector<Water> water);
|
|
||||||
|
|
||||||
std::size_t getGeneration() const
|
std::size_t getGeneration() const
|
||||||
{
|
{
|
||||||
|
@ -37,36 +66,13 @@ namespace DetourNavigator
|
||||||
return mRevision;
|
return mRevision;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<int>& getIndices() const
|
const Mesh& getMesh() const noexcept { return mMesh; }
|
||||||
{
|
|
||||||
return mIndices;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<float>& getVertices() const
|
|
||||||
{
|
|
||||||
return mVertices;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<AreaType>& getAreaTypes() const
|
|
||||||
{
|
|
||||||
return mAreaTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Water>& getWater() const
|
const std::vector<Water>& getWater() const
|
||||||
{
|
{
|
||||||
return mWater;
|
return mWater;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t getVerticesCount() const
|
|
||||||
{
|
|
||||||
return mVertices.size() / 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t getTrianglesCount() const
|
|
||||||
{
|
|
||||||
return mIndices.size() / 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Bounds& getBounds() const
|
const Bounds& getBounds() const
|
||||||
{
|
{
|
||||||
return mBounds;
|
return mBounds;
|
||||||
|
@ -75,32 +81,25 @@ namespace DetourNavigator
|
||||||
private:
|
private:
|
||||||
std::size_t mGeneration;
|
std::size_t mGeneration;
|
||||||
std::size_t mRevision;
|
std::size_t mRevision;
|
||||||
std::vector<int> mIndices;
|
Mesh mMesh;
|
||||||
std::vector<float> mVertices;
|
|
||||||
std::vector<AreaType> mAreaTypes;
|
|
||||||
std::vector<Water> mWater;
|
std::vector<Water> mWater;
|
||||||
Bounds mBounds;
|
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);
|
return std::tie(lhs.mMesh, lhs.mWater) < std::tie(rhs.mMesh, rhs.mWater);
|
||||||
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);
|
friend inline std::size_t getSize(const RecastMesh& value) noexcept
|
||||||
return indicesSize + verticesSize + areaTypesSize + waterSize;
|
{
|
||||||
|
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);
|
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
|
#endif
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <tuple>
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace DetourNavigator
|
namespace DetourNavigator
|
||||||
{
|
{
|
||||||
|
@ -26,40 +26,59 @@ namespace DetourNavigator
|
||||||
|
|
||||||
namespace
|
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;
|
RecastMeshTriangle result;
|
||||||
uniqueVertices.reserve(vertices.size() / 3);
|
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)
|
Mesh makeMesh(std::vector<RecastMeshTriangle>&& triangles)
|
||||||
uniqueVertices.emplace_back(vertices[i * 3], vertices[i * 3 + 1], vertices[i * 3 + 2]);
|
{
|
||||||
|
std::vector<osg::Vec3f> uniqueVertices;
|
||||||
|
uniqueVertices.reserve(3 * triangles.size());
|
||||||
|
|
||||||
std::sort(uniqueVertices.begin(), uniqueVertices.end());
|
for (const RecastMeshTriangle& v : triangles)
|
||||||
const auto end = std::unique(uniqueVertices.begin(), uniqueVertices.end());
|
for (const osg::Vec3f& v : v.mVertices)
|
||||||
uniqueVertices.erase(end, uniqueVertices.end());
|
uniqueVertices.push_back(v);
|
||||||
|
|
||||||
if (uniqueVertices.size() == vertices.size() / 3)
|
std::sort(uniqueVertices.begin(), uniqueVertices.end());
|
||||||
return;
|
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 it = std::lower_bound(uniqueVertices.begin(), uniqueVertices.end(), v);
|
||||||
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);
|
|
||||||
assert(it != uniqueVertices.end());
|
assert(it != uniqueVertices.end());
|
||||||
assert(*it == vertex);
|
assert(*it == v);
|
||||||
indices[i] = std::distance(uniqueVertices.begin(), it);
|
indices.push_back(static_cast<int>(it - uniqueVertices.begin()));
|
||||||
}
|
|
||||||
|
|
||||||
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]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
RecastMeshBuilder::RecastMeshBuilder(const Settings& settings, const TileBounds& bounds)
|
||||||
|
@ -96,37 +115,26 @@ namespace DetourNavigator
|
||||||
void RecastMeshBuilder::addObject(const btConcaveShape& shape, const btTransform& transform,
|
void RecastMeshBuilder::addObject(const btConcaveShape& shape, const btTransform& transform,
|
||||||
const AreaType areaType)
|
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)
|
RecastMeshTriangle triangle = makeRecastMeshTriangle(vertices, areaType, mSettings);
|
||||||
addTriangleVertex(triangle[i - 1]);
|
std::reverse(triangle.mVertices.begin(), triangle.mVertices.end());
|
||||||
mAreaTypes.push_back(areaType);
|
mTriangles.emplace_back(triangle);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecastMeshBuilder::addObject(const btHeightfieldTerrainShape& shape, const btTransform& transform,
|
void RecastMeshBuilder::addObject(const btHeightfieldTerrainShape& shape, const btTransform& transform,
|
||||||
const AreaType areaType)
|
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)
|
mTriangles.emplace_back(makeRecastMeshTriangle(vertices, areaType, mSettings));
|
||||||
addTriangleVertex(triangle[i]);
|
|
||||||
mAreaTypes.push_back(areaType);
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecastMeshBuilder::addObject(const btBoxShape& shape, const btTransform& transform, const AreaType areaType)
|
void RecastMeshBuilder::addObject(const btBoxShape& shape, const btTransform& transform, const AreaType areaType)
|
||||||
{
|
{
|
||||||
const auto indexOffset = static_cast<int>(mVertices.size() / 3);
|
constexpr std::array<int, 36> indices {{
|
||||||
|
|
||||||
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 {{
|
|
||||||
0, 2, 3,
|
0, 2, 3,
|
||||||
3, 1, 0,
|
3, 1, 0,
|
||||||
0, 4, 6,
|
0, 4, 6,
|
||||||
|
@ -141,10 +149,17 @@ namespace DetourNavigator
|
||||||
4, 5, 7,
|
4, 5, 7,
|
||||||
}};
|
}};
|
||||||
|
|
||||||
std::transform(indices.begin(), indices.end(), std::back_inserter(mIndices),
|
for (std::size_t i = 0; i < indices.size(); i += 3)
|
||||||
[&] (int index) { return index + indexOffset; });
|
{
|
||||||
|
std::array<btVector3, 3> vertices;
|
||||||
std::generate_n(std::back_inserter(mAreaTypes), 12, [=] { return areaType; });
|
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)
|
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) &&
|
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());
|
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,
|
void RecastMeshBuilder::addObject(const btConcaveShape& shape, const btTransform& transform,
|
||||||
|
@ -218,18 +234,4 @@ namespace DetourNavigator
|
||||||
|
|
||||||
shape.processAllTriangles(&wrapper, aabbMin, aabbMax);
|
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 "recastmesh.hpp"
|
||||||
#include "tilebounds.hpp"
|
#include "tilebounds.hpp"
|
||||||
|
|
||||||
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
#include <LinearMath/btTransform.h>
|
#include <LinearMath/btTransform.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <tuple>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class btBoxShape;
|
class btBoxShape;
|
||||||
class btCollisionShape;
|
class btCollisionShape;
|
||||||
class btCompoundShape;
|
class btCompoundShape;
|
||||||
|
@ -17,6 +25,17 @@ namespace DetourNavigator
|
||||||
{
|
{
|
||||||
struct Settings;
|
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
|
class RecastMeshBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -39,19 +58,15 @@ namespace DetourNavigator
|
||||||
private:
|
private:
|
||||||
std::reference_wrapper<const Settings> mSettings;
|
std::reference_wrapper<const Settings> mSettings;
|
||||||
TileBounds mBounds;
|
TileBounds mBounds;
|
||||||
std::vector<int> mIndices;
|
std::vector<RecastMeshTriangle> mTriangles;
|
||||||
std::vector<float> mVertices;
|
|
||||||
std::vector<AreaType> mAreaTypes;
|
|
||||||
std::vector<RecastMesh::Water> mWater;
|
std::vector<RecastMesh::Water> mWater;
|
||||||
|
|
||||||
void addObject(const btConcaveShape& shape, const btTransform& transform, btTriangleCallback&& callback);
|
void addObject(const btConcaveShape& shape, const btTransform& transform, btTriangleCallback&& callback);
|
||||||
|
|
||||||
void addObject(const btHeightfieldTerrainShape& 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
|
#endif
|
||||||
|
|
|
@ -16,9 +16,8 @@ namespace DetourNavigator
|
||||||
const auto object = mObjects.lower_bound(id);
|
const auto object = mObjects.lower_bound(id);
|
||||||
if (object != mObjects.end() && object->first == id)
|
if (object != mObjects.end() && object->first == id)
|
||||||
return false;
|
return false;
|
||||||
const auto iterator = mObjectsOrder.emplace(mObjectsOrder.end(),
|
mObjects.emplace_hint(object, id,
|
||||||
OscillatingRecastMeshObject(RecastMeshObject(shape, transform, areaType), mRevision + 1));
|
OscillatingRecastMeshObject(RecastMeshObject(shape, transform, areaType), mRevision + 1));
|
||||||
mObjects.emplace_hint(object, id, iterator);
|
|
||||||
++mRevision;
|
++mRevision;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +29,7 @@ namespace DetourNavigator
|
||||||
return false;
|
return false;
|
||||||
const std::size_t lastChangeRevision = mLastNavMeshReportedChange.has_value()
|
const std::size_t lastChangeRevision = mLastNavMeshReportedChange.has_value()
|
||||||
? mLastNavMeshReportedChange->mRevision : mRevision;
|
? mLastNavMeshReportedChange->mRevision : mRevision;
|
||||||
if (!object->second->update(transform, areaType, lastChangeRevision, mTileBounds))
|
if (!object->second.update(transform, areaType, lastChangeRevision, mTileBounds))
|
||||||
return false;
|
return false;
|
||||||
++mRevision;
|
++mRevision;
|
||||||
return true;
|
return true;
|
||||||
|
@ -41,8 +40,7 @@ namespace DetourNavigator
|
||||||
const auto object = mObjects.find(id);
|
const auto object = mObjects.find(id);
|
||||||
if (object == mObjects.end())
|
if (object == mObjects.end())
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
const RemovedRecastMeshObject result {object->second->getImpl().getShape(), object->second->getImpl().getTransform()};
|
const RemovedRecastMeshObject result {object->second.getImpl().getShape(), object->second.getImpl().getTransform()};
|
||||||
mObjectsOrder.erase(object->second);
|
|
||||||
mObjects.erase(object);
|
mObjects.erase(object);
|
||||||
++mRevision;
|
++mRevision;
|
||||||
return result;
|
return result;
|
||||||
|
@ -51,12 +49,8 @@ namespace DetourNavigator
|
||||||
bool RecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize,
|
bool RecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize,
|
||||||
const btTransform& transform)
|
const btTransform& transform)
|
||||||
{
|
{
|
||||||
const auto iterator = mWaterOrder.emplace(mWaterOrder.end(), Water {cellSize, transform});
|
if (!mWater.emplace(cellPosition, Water {cellSize, transform}).second)
|
||||||
if (!mWater.emplace(cellPosition, iterator).second)
|
|
||||||
{
|
|
||||||
mWaterOrder.erase(iterator);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
++mRevision;
|
++mRevision;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -67,8 +61,7 @@ namespace DetourNavigator
|
||||||
if (water == mWater.end())
|
if (water == mWater.end())
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
++mRevision;
|
++mRevision;
|
||||||
const auto result = *water->second;
|
const Water result = water->second;
|
||||||
mWaterOrder.erase(water->second);
|
|
||||||
mWater.erase(water);
|
mWater.erase(water);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -76,9 +69,9 @@ namespace DetourNavigator
|
||||||
std::shared_ptr<RecastMesh> RecastMeshManager::getMesh()
|
std::shared_ptr<RecastMesh> RecastMeshManager::getMesh()
|
||||||
{
|
{
|
||||||
RecastMeshBuilder builder(mSettings, mTileBounds);
|
RecastMeshBuilder builder(mSettings, mTileBounds);
|
||||||
for (const auto& v : mWaterOrder)
|
for (const auto& [k, v] : mWater)
|
||||||
builder.addWater(v.mCellSize, v.mTransform);
|
builder.addWater(v.mCellSize, v.mTransform);
|
||||||
for (const auto& object : mObjectsOrder)
|
for (const auto& [k, object] : mObjects)
|
||||||
{
|
{
|
||||||
const RecastMeshObject& v = object.getImpl();
|
const RecastMeshObject& v = object.getImpl();
|
||||||
builder.addObject(v.getShape(), v.getTransform(), v.getAreaType());
|
builder.addObject(v.getShape(), v.getTransform(), v.getAreaType());
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
#include <osg/Vec2i>
|
#include <osg/Vec2i>
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -68,10 +67,8 @@ namespace DetourNavigator
|
||||||
std::size_t mRevision = 0;
|
std::size_t mRevision = 0;
|
||||||
std::size_t mGeneration;
|
std::size_t mGeneration;
|
||||||
TileBounds mTileBounds;
|
TileBounds mTileBounds;
|
||||||
std::list<OscillatingRecastMeshObject> mObjectsOrder;
|
std::map<ObjectId, OscillatingRecastMeshObject> mObjects;
|
||||||
std::map<ObjectId, std::list<OscillatingRecastMeshObject>::iterator> mObjects;
|
std::map<osg::Vec2i, Water> mWater;
|
||||||
std::list<Water> mWaterOrder;
|
|
||||||
std::map<osg::Vec2i, std::list<Water>::iterator> mWater;
|
|
||||||
std::optional<Report> mLastNavMeshReportedChange;
|
std::optional<Report> mLastNavMeshReportedChange;
|
||||||
std::optional<Report> mLastNavMeshReport;
|
std::optional<Report> mLastNavMeshReport;
|
||||||
};
|
};
|
||||||
|
|
|
@ -39,10 +39,11 @@ namespace SceneUtil
|
||||||
{
|
{
|
||||||
const osg::ref_ptr<osg::Group> group(new osg::Group);
|
const osg::ref_ptr<osg::Group> group(new osg::Group);
|
||||||
DebugDraw debugDraw(*group, osg::Vec3f(0, 0, 0), 1.0f / settings.mRecastScaleFactor);
|
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);
|
const auto texScale = 1.0f / (settings.mCellSize * 10.0f);
|
||||||
duDebugDrawTriMesh(&debugDraw, recastMesh.getVertices().data(), recastMesh.getVerticesCount(),
|
duDebugDrawTriMesh(&debugDraw, mesh.getVertices().data(), mesh.getVerticesCount(),
|
||||||
recastMesh.getIndices().data(), normals.data(), recastMesh.getTrianglesCount(), nullptr, texScale);
|
mesh.getIndices().data(), normals.data(), mesh.getTrianglesCount(), nullptr, texScale);
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue