From 100cba6260a5c0c61fa22c7fb4162f38e1b8ab34 Mon Sep 17 00:00:00 2001 From: elsid Date: Tue, 29 Jun 2021 20:12:22 +0200 Subject: [PATCH 01/12] Use navigator field in Scene --- apps/openmw/mwworld/scene.cpp | 37 +++++++++++++++-------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 10c0ebe84c..f7c9b43fb6 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -370,7 +370,6 @@ namespace MWWorld if (!test) Log(Debug::Info) << "Deactivate cell " << cell->getCell()->getDescription(); - const auto navigator = MWBase::Environment::get().getWorld()->getNavigator(); ListAndResetObjectsVisitor visitor; cell->forEach(visitor); @@ -379,13 +378,13 @@ namespace MWWorld { if (const auto object = mPhysics->getObject(ptr)) { - navigator->removeObject(DetourNavigator::ObjectId(object)); + mNavigator.removeObject(DetourNavigator::ObjectId(object)); if (object->isAnimated()) mPhysics->remove(ptr); } else if (mPhysics->getActor(ptr)) { - navigator->removeAgent(world->getPathfindingHalfExtents(ptr)); + mNavigator.removeAgent(world->getPathfindingHalfExtents(ptr)); mRendering.removeActorPath(ptr); mPhysics->remove(ptr); } @@ -398,17 +397,17 @@ namespace MWWorld if (cell->getCell()->isExterior()) { if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) - navigator->removeObject(DetourNavigator::ObjectId(heightField)); + mNavigator.removeObject(DetourNavigator::ObjectId(heightField)); } if (cell->getCell()->hasWater()) - navigator->removeWater(osg::Vec2i(cellX, cellY)); + mNavigator.removeWater(osg::Vec2i(cellX, cellY)); if (const auto pathgrid = world->getStore().get().search(*cell->getCell())) - navigator->removePathgrid(*pathgrid); + mNavigator.removePathgrid(*pathgrid); const auto player = world->getPlayerPtr(); - navigator->update(player.getRefData().getPosition().asVec3()); + mNavigator.update(player.getRefData().getPosition().asVec3()); MWBase::Environment::get().getMechanicsManager()->drop (cell); @@ -433,7 +432,6 @@ namespace MWWorld Log(Debug::Info) << "Loading cell " << cell->getCell()->getDescription(); const auto world = MWBase::Environment::get().getWorld(); - const auto navigator = world->getNavigator(); const int cellX = cell->getCell()->getGridX(); const int cellY = cell->getCell()->getGridY(); @@ -441,12 +439,12 @@ namespace MWWorld if (!test && cell->getCell()->isExterior()) { if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) - navigator->addObject(DetourNavigator::ObjectId(heightField), *heightField->getShape(), + mNavigator.addObject(DetourNavigator::ObjectId(heightField), *heightField->getShape(), heightField->getCollisionObject()->getWorldTransform()); } if (const auto pathgrid = world->getStore().get().search(*cell->getCell())) - navigator->addPathgrid(*cell->getCell(), *pathgrid); + mNavigator.addPathgrid(*cell->getCell(), *pathgrid); // register local scripts // do this before insertCell, to make sure we don't add scripts from levelled creature spawning twice @@ -472,12 +470,12 @@ namespace MWWorld if (cell->getCell()->isExterior()) { if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) - navigator->addWater(osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE, + mNavigator.addWater(osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE, cell->getWaterLevel(), heightField->getCollisionObject()->getWorldTransform()); } else { - navigator->addWater(osg::Vec2i(cellX, cellY), std::numeric_limits::max(), + mNavigator.addWater(osg::Vec2i(cellX, cellY), std::numeric_limits::max(), cell->getWaterLevel(), btTransform::getIdentity()); } } @@ -486,7 +484,7 @@ namespace MWWorld const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - navigator->update(player.getRefData().getPosition().asVec3()); + mNavigator.update(player.getRefData().getPosition().asVec3()); if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx)) mRendering.configureAmbient(cell->getCell()); @@ -569,9 +567,8 @@ namespace MWWorld void Scene::playerMoved(const osg::Vec3f &pos) { - const auto navigator = MWBase::Environment::get().getWorld()->getNavigator(); const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - navigator->updatePlayerPosition(player.getRefData().getPosition().asVec3()); + mNavigator.updatePlayerPosition(player.getRefData().getPosition().asVec3()); if (!mCurrentCell || !mCurrentCell->isExterior()) return; @@ -996,9 +993,8 @@ namespace MWWorld addObject(ptr, *mPhysics, mRendering, mPagedRefs, false); addObject(ptr, *mPhysics, mNavigator); MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); - const auto navigator = MWBase::Environment::get().getWorld()->getNavigator(); const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - navigator->update(player.getRefData().getPosition().asVec3()); + mNavigator.update(player.getRefData().getPosition().asVec3()); } catch (std::exception& e) { @@ -1011,16 +1007,15 @@ namespace MWWorld MWBase::Environment::get().getMechanicsManager()->remove (ptr); MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); MWBase::Environment::get().getLuaManager()->objectRemovedFromScene(ptr); - const auto navigator = MWBase::Environment::get().getWorld()->getNavigator(); if (const auto object = mPhysics->getObject(ptr)) { - navigator->removeObject(DetourNavigator::ObjectId(object)); + mNavigator.removeObject(DetourNavigator::ObjectId(object)); const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - navigator->update(player.getRefData().getPosition().asVec3()); + mNavigator.update(player.getRefData().getPosition().asVec3()); } else if (mPhysics->getActor(ptr)) { - navigator->removeAgent(MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(ptr)); + mNavigator.removeAgent(MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(ptr)); } mPhysics->remove(ptr); mRendering.removeObject (ptr); From 07c70dfb738c970717b096cf3e323cdc1ed75595 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 3 Jul 2021 04:08:22 +0200 Subject: [PATCH 02/12] Remove unused local variables --- components/detournavigator/makenavmesh.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index 507ca078e9..42676f4294 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -160,8 +160,6 @@ namespace bool rasterizeSolidObjectsTriangles(rcContext& context, const RecastMesh& recastMesh, const rcConfig& config, rcHeightfield& solid) { - const osg::Vec2f tileBoundsMin(config.bmin[0], config.bmin[2]); - const osg::Vec2f tileBoundsMax(config.bmax[0], config.bmax[2]); std::vector areas(recastMesh.getAreaTypes().begin(), recastMesh.getAreaTypes().end()); rcClearUnwalkableTriangles( @@ -485,7 +483,6 @@ namespace DetourNavigator " changedTileDistance=" << getDistance(changedTile, playerTile); const auto params = *navMeshCacheItem->lockConst()->getImpl().getParams(); - const osg::Vec3f origin(params.orig[0], params.orig[1], params.orig[2]); if (!recastMesh) { From af7059373c3169e623aabb0e9615a9af214833e6 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 11 Jul 2021 21:43:19 +0200 Subject: [PATCH 03/12] 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; } } From d60edb36aadae13d007717e6e93332ba92e6d728 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 16 Jul 2021 20:19:11 +0200 Subject: [PATCH 04/12] Make RecastMesh independent from recast scale factor To avoid scaling until it's required by delaying coordinates conversion until navmesh generation. --- .../detournavigator/recastmeshbuilder.cpp | 224 +++++++++--------- components/detournavigator/makenavmesh.cpp | 18 +- .../detournavigator/recastmeshbuilder.cpp | 20 +- .../detournavigator/recastmeshbuilder.hpp | 7 +- .../detournavigator/recastmeshmanager.cpp | 6 +- components/sceneutil/recastmesh.cpp | 18 +- 6 files changed, 153 insertions(+), 140 deletions(-) diff --git a/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp b/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp index b11b10965b..0528205b58 100644 --- a/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp +++ b/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp @@ -1,7 +1,6 @@ #include "operators.hpp" #include -#include #include #include @@ -33,14 +32,12 @@ namespace struct DetourNavigatorRecastMeshBuilderTest : Test { - Settings mSettings; TileBounds mBounds; const std::size_t mGeneration = 0; const std::size_t mRevision = 0; DetourNavigatorRecastMeshBuilderTest() { - mSettings.mRecastScaleFactor = 1.0f; mBounds.mMin = osg::Vec2f(-std::numeric_limits::max() * std::numeric_limits::epsilon(), -std::numeric_limits::max() * std::numeric_limits::epsilon()); mBounds.mMax = osg::Vec2f(std::numeric_limits::max() * std::numeric_limits::epsilon(), @@ -50,7 +47,7 @@ namespace TEST_F(DetourNavigatorRecastMeshBuilderTest, create_for_empty_should_return_empty) { - RecastMeshBuilder builder(mSettings, mBounds); + RecastMeshBuilder builder(mBounds); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector()); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector()); @@ -63,13 +60,13 @@ namespace mesh.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0)); btBvhTriangleMeshShape shape(&mesh, true); - RecastMeshBuilder builder(mSettings, mBounds); + RecastMeshBuilder builder(mBounds); builder.addObject(static_cast(shape), btTransform::getIdentity(), AreaType_ground); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ - -1, 0, -1, - -1, 0, 1, - 1, 0, -1, + -1, -1, 0, + -1, 1, 0, + 1, -1, 0, })) << recastMesh->getMesh().getVertices(); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector({2, 1, 0})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({AreaType_ground})); @@ -80,7 +77,7 @@ namespace btTriangleMesh mesh; mesh.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0)); btBvhTriangleMeshShape shape(&mesh, true); - RecastMeshBuilder builder(mSettings, mBounds); + RecastMeshBuilder builder(mBounds); builder.addObject( static_cast(shape), btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)), @@ -88,9 +85,9 @@ namespace ); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ - 0, 3, 0, - 0, 3, 4, - 2, 3, 0, + 0, 0, 3, + 0, 4, 3, + 2, 0, 3, })) << recastMesh->getMesh().getVertices(); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector({2, 1, 0})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({AreaType_ground})); @@ -100,15 +97,15 @@ namespace { const std::array heightfieldData {{0, 0, 0, 0}}; btHeightfieldTerrainShape shape(2, 2, heightfieldData.data(), 1, 0, 0, 2, PHY_FLOAT, false); - RecastMeshBuilder builder(mSettings, mBounds); + RecastMeshBuilder builder(mBounds); builder.addObject(static_cast(shape), btTransform::getIdentity(), AreaType_ground); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); 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, - })); + -0.5, -0.5, 0, + -0.5, 0.5, 0, + 0.5, -0.5, 0, + 0.5, 0.5, 0, + })) << recastMesh->getMesh().getVertices(); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector({0, 1, 2, 2, 1, 3})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({AreaType_ground, AreaType_ground})); } @@ -116,32 +113,32 @@ namespace TEST_F(DetourNavigatorRecastMeshBuilderTest, add_box_shape_should_produce_12_triangles) { btBoxShape shape(btVector3(1, 1, 2)); - RecastMeshBuilder builder(mSettings, mBounds); + RecastMeshBuilder builder(mBounds); builder.addObject(static_cast(shape), btTransform::getIdentity(), AreaType_ground); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ - -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, -1, -2, + -1, -1, 2, + -1, 1, -2, + -1, 1, 2, + 1, -1, -2, + 1, -1, 2, + 1, 1, -2, + 1, 1, 2, })) << 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, + 0, 1, 5, + 0, 2, 3, + 0, 4, 6, + 1, 3, 7, + 2, 6, 7, + 3, 1, 0, + 4, 5, 7, + 5, 4, 0, + 6, 2, 0, + 7, 3, 2, + 7, 5, 1, + 7, 6, 4, })) << recastMesh->getMesh().getIndices(); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector(12, AreaType_ground)); } @@ -159,7 +156,7 @@ namespace shape.addChildShape(btTransform::getIdentity(), &triangle1); shape.addChildShape(btTransform::getIdentity(), &box); shape.addChildShape(btTransform::getIdentity(), &triangle2); - RecastMeshBuilder builder(mSettings, mBounds); + RecastMeshBuilder builder(mBounds); builder.addObject( static_cast(shape), btTransform::getIdentity(), @@ -167,34 +164,34 @@ namespace ); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ - -1, -2, -1, - -1, -2, 1, - -1, 0, -1, - -1, 0, 1, - -1, 2, -1, - -1, 2, 1, - 1, -2, -1, - 1, -2, 1, - 1, 0, -1, - 1, 0, 1, - 1, 2, -1, - 1, 2, 1, + -1, -1, -2, + -1, -1, 0, + -1, -1, 2, + -1, 1, -2, + -1, 1, 0, + -1, 1, 2, + 1, -1, -2, + 1, -1, 0, + 1, -1, 2, + 1, 1, -2, + 1, 1, 0, + 1, 1, 2, })) << recastMesh->getMesh().getVertices(); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector({ - 0, 1, 5, - 0, 4, 10, - 0, 6, 7, - 1, 7, 11, - 4, 5, 11, - 5, 4, 0, - 6, 10, 11, - 7, 1, 0, - 8, 3, 2, - 8, 3, 9, - 10, 6, 0, - 11, 5, 1, - 11, 7, 6, - 11, 10, 4, + 0, 2, 8, + 0, 3, 5, + 0, 6, 9, + 2, 5, 11, + 3, 9, 11, + 5, 2, 0, + 6, 8, 11, + 7, 4, 1, + 7, 4, 10, + 8, 6, 0, + 9, 3, 0, + 11, 5, 3, + 11, 8, 2, + 11, 9, 6, })) << recastMesh->getMesh().getIndices(); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector(14, AreaType_ground)); } @@ -206,7 +203,7 @@ namespace btBvhTriangleMeshShape triangle(&mesh, true); btCompoundShape shape; shape.addChildShape(btTransform::getIdentity(), &triangle); - RecastMeshBuilder builder(mSettings, mBounds); + RecastMeshBuilder builder(mBounds); builder.addObject( static_cast(shape), btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)), @@ -214,9 +211,9 @@ namespace ); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ - 0, 3, 0, - 0, 3, 4, - 2, 3, 0, + 0, 0, 3, + 0, 4, 3, + 2, 0, 3, })) << recastMesh->getMesh().getVertices(); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector({2, 1, 0})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({AreaType_ground})); @@ -230,7 +227,7 @@ namespace btCompoundShape shape; shape.addChildShape(btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)), &triangle); - RecastMeshBuilder builder(mSettings, mBounds); + RecastMeshBuilder builder(mBounds); builder.addObject( static_cast(shape), btTransform(btMatrix3x3::getIdentity().scaled(btVector3(1, 2, 3)), btVector3(1, 2, 3)), @@ -238,9 +235,9 @@ namespace ); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ - 1, 12, 2, - 1, 12, 10, - 3, 12, 2, + 1, 2, 12, + 1, 10, 12, + 3, 2, 12, })) << recastMesh->getMesh().getVertices(); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector({2, 1, 0})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({AreaType_ground})); @@ -252,7 +249,7 @@ namespace mesh.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0)); mesh.addTriangle(btVector3(-3, -3, 0), btVector3(-3, -2, 0), btVector3(-2, -3, 0)); btBvhTriangleMeshShape shape(&mesh, true); - RecastMeshBuilder builder(mSettings, mBounds); + RecastMeshBuilder builder(mBounds); builder.addObject( static_cast(shape), btTransform::getIdentity(), @@ -260,12 +257,12 @@ namespace ); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ - -3, 0, -3, - -3, 0, -2, - -2, 0, -3, - -1, 0, -1, - -1, 0, 1, - 1, 0, -1, + -3, -3, 0, + -3, -2, 0, + -2, -3, 0, + -1, -1, 0, + -1, 1, 0, + 1, -1, 0, })) << 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)); @@ -273,14 +270,13 @@ namespace TEST_F(DetourNavigatorRecastMeshBuilderTest, with_bounds_add_bhv_triangle_shape_should_filter_by_bounds) { - mSettings.mRecastScaleFactor = 0.1f; - mBounds.mMin = osg::Vec2f(-3, -3) * mSettings.mRecastScaleFactor; - mBounds.mMax = osg::Vec2f(-2, -2) * mSettings.mRecastScaleFactor; + mBounds.mMin = osg::Vec2f(-3, -3); + mBounds.mMax = osg::Vec2f(-2, -2); btTriangleMesh mesh; mesh.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0)); mesh.addTriangle(btVector3(-3, -3, 0), btVector3(-3, -2, 0), btVector3(-2, -3, 0)); btBvhTriangleMeshShape shape(&mesh, true); - RecastMeshBuilder builder(mSettings, mBounds); + RecastMeshBuilder builder(mBounds); builder.addObject( static_cast(shape), btTransform::getIdentity(), @@ -288,9 +284,9 @@ namespace ); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ - -0.3f, 0, -0.3f, - -0.3f, 0, -0.2f, - -0.2f, 0, -0.3f, + -3, -3, 0, + -3, -2, 0, + -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})); @@ -304,7 +300,7 @@ namespace mesh.addTriangle(btVector3(0, -1, -1), btVector3(0, -1, -1), btVector3(0, 1, -1)); mesh.addTriangle(btVector3(0, -3, -3), btVector3(0, -3, -2), btVector3(0, -2, -3)); btBvhTriangleMeshShape shape(&mesh, true); - RecastMeshBuilder builder(mSettings, mBounds); + RecastMeshBuilder builder(mBounds); builder.addObject( static_cast(shape), btTransform(btQuaternion(btVector3(1, 0, 0), @@ -313,11 +309,11 @@ namespace ); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); 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, + 0, -4.24264049530029296875, 4.44089209850062616169452667236328125e-16, + 0, -3.535533905029296875, -0.707106769084930419921875, + 0, -3.535533905029296875, 0.707106769084930419921875, }))) << recastMesh->getMesh().getVertices(); - EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector({0, 2, 1})); + EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector({1, 2, 0})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({AreaType_ground})); } @@ -329,7 +325,7 @@ namespace mesh.addTriangle(btVector3(-1, 0, -1), btVector3(-1, 0, 1), btVector3(1, 0, -1)); mesh.addTriangle(btVector3(-3, 0, -3), btVector3(-3, 0, -2), btVector3(-2, 0, -3)); btBvhTriangleMeshShape shape(&mesh, true); - RecastMeshBuilder builder(mSettings, mBounds); + RecastMeshBuilder builder(mBounds); builder.addObject( static_cast(shape), btTransform(btQuaternion(btVector3(0, 1, 0), @@ -338,9 +334,9 @@ namespace ); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); 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, + -4.24264049530029296875, 0, 4.44089209850062616169452667236328125e-16, + -3.535533905029296875, 0, -0.707106769084930419921875, + -3.535533905029296875, 0, 0.707106769084930419921875, }))) << recastMesh->getMesh().getVertices(); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector({1, 2, 0})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({AreaType_ground})); @@ -354,7 +350,7 @@ namespace mesh.addTriangle(btVector3(-1, -1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0)); mesh.addTriangle(btVector3(-3, -3, 0), btVector3(-3, -2, 0), btVector3(-2, -3, 0)); btBvhTriangleMeshShape shape(&mesh, true); - RecastMeshBuilder builder(mSettings, mBounds); + RecastMeshBuilder builder(mBounds); builder.addObject( static_cast(shape), btTransform(btQuaternion(btVector3(0, 0, 1), @@ -363,9 +359,9 @@ namespace ); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); 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, + -1.41421353816986083984375, -1.1102230246251565404236316680908203125e-16, 0, + 1.1102230246251565404236316680908203125e-16, -1.41421353816986083984375, 0, + 1.41421353816986083984375, 1.1102230246251565404236316680908203125e-16, 0, }))) << recastMesh->getMesh().getVertices(); EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector({2, 0, 1})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({AreaType_ground})); @@ -379,7 +375,7 @@ namespace btTriangleMesh mesh2; mesh2.addTriangle(btVector3(-3, -3, 0), btVector3(-3, -2, 0), btVector3(-2, -3, 0)); btBvhTriangleMeshShape shape2(&mesh2, true); - RecastMeshBuilder builder(mSettings, mBounds); + RecastMeshBuilder builder(mBounds); builder.addObject( static_cast(shape1), btTransform::getIdentity(), @@ -392,12 +388,12 @@ namespace ); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ - -3, 0, -3, - -3, 0, -2, - -2, 0, -3, - -1, 0, -1, - -1, 0, 1, - 1, 0, -1, + -3, -3, 0, + -3, -2, 0, + -2, -3, 0, + -1, -1, 0, + -1, 1, 0, + 1, -1, 0, })) << 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})); @@ -405,7 +401,7 @@ namespace TEST_F(DetourNavigatorRecastMeshBuilderTest, add_water_then_get_water_should_return_it) { - RecastMeshBuilder builder(mSettings, mBounds); + RecastMeshBuilder builder(mBounds); builder.addWater(1000, btTransform(btMatrix3x3::getIdentity(), btVector3(100, 200, 300))); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getWater(), std::vector({ @@ -420,14 +416,14 @@ namespace mesh.addTriangle(btVector3(1, 1, 0), btVector3(-1, 1, 0), btVector3(1, -1, 0)); btBvhTriangleMeshShape shape(&mesh, true); - RecastMeshBuilder builder(mSettings, mBounds); + RecastMeshBuilder builder(mBounds); builder.addObject(static_cast(shape), btTransform::getIdentity(), AreaType_ground); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getMesh().getVertices(), std::vector({ - -1, 0, -1, - -1, 0, 1, - 1, 0, -1, - 1, 0, 1, + -1, -1, 0, + -1, 1, 0, + 1, -1, 0, + 1, 1, 0, })) << 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/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index 7145bebae7..0824e9cb86 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -157,15 +157,23 @@ namespace throw NavigatorException("Failed to create heightfield for navmesh"); } - bool rasterizeTriangles(rcContext& context, const Mesh& mesh, const rcConfig& config, + bool rasterizeTriangles(rcContext& context, const Mesh& mesh, const Settings& settings, const rcConfig& config, rcHeightfield& solid) { std::vector areas(mesh.getAreaTypes().begin(), mesh.getAreaTypes().end()); + std::vector vertices = mesh.getVertices(); + + for (std::size_t i = 0; i < vertices.size(); i += 3) + { + for (std::size_t j = 0; j < 3; ++j) + vertices[i + j] = toNavMeshCoordinates(settings, vertices[i + j]); + std::swap(vertices[i + 1], vertices[i + 2]); + } rcClearUnwalkableTriangles( &context, config.walkableSlopeAngle, - mesh.getVertices().data(), + vertices.data(), static_cast(mesh.getVerticesCount()), mesh.getIndices().data(), static_cast(areas.size()), @@ -174,7 +182,7 @@ namespace return rcRasterizeTriangles( &context, - mesh.getVertices().data(), + vertices.data(), static_cast(mesh.getVerticesCount()), mesh.getIndices().data(), areas.data(), @@ -242,7 +250,7 @@ namespace bool rasterizeTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh, const rcConfig& config, const Settings& settings, rcHeightfield& solid) { - if (!rasterizeTriangles(context, recastMesh.getMesh(), config, solid)) + if (!rasterizeTriangles(context, recastMesh.getMesh(), settings, config, solid)) return false; rasterizeWaterTriangles(context, agentHalfExtents, recastMesh, settings, config, solid); @@ -491,6 +499,8 @@ namespace DetourNavigator } auto recastMeshBounds = recastMesh->getBounds(); + recastMeshBounds.mMin = toNavMeshCoordinates(settings, recastMeshBounds.mMin); + recastMeshBounds.mMax = toNavMeshCoordinates(settings, recastMeshBounds.mMax); for (const auto& water : recastMesh->getWater()) { diff --git a/components/detournavigator/recastmeshbuilder.cpp b/components/detournavigator/recastmeshbuilder.cpp index 8de82bee16..81fb6f21cf 100644 --- a/components/detournavigator/recastmeshbuilder.cpp +++ b/components/detournavigator/recastmeshbuilder.cpp @@ -1,12 +1,11 @@ #include "recastmeshbuilder.hpp" #include "debug.hpp" -#include "settings.hpp" -#include "settingsutils.hpp" #include "exceptions.hpp" #include #include #include +#include #include #include @@ -26,12 +25,12 @@ namespace DetourNavigator namespace { - RecastMeshTriangle makeRecastMeshTriangle(const btVector3* vertices, const AreaType areaType, const Settings& settings) + RecastMeshTriangle makeRecastMeshTriangle(const btVector3* vertices, const AreaType areaType) { RecastMeshTriangle result; result.mAreaType = areaType; for (std::size_t i = 0; i < 3; ++i) - result.mVertices[i] = toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(vertices[i])); + result.mVertices[i] = Misc::Convert::makeOsgVec3f(vertices[i]); return result; } } @@ -81,12 +80,9 @@ namespace DetourNavigator return Mesh(std::move(indices), std::move(vertices), std::move(areaTypes)); } - RecastMeshBuilder::RecastMeshBuilder(const Settings& settings, const TileBounds& bounds) - : mSettings(settings) - , mBounds(bounds) + RecastMeshBuilder::RecastMeshBuilder(const TileBounds& bounds) noexcept + : mBounds(bounds) { - mBounds.mMin /= mSettings.get().mRecastScaleFactor; - mBounds.mMax /= mSettings.get().mRecastScaleFactor; } void RecastMeshBuilder::addObject(const btCollisionShape& shape, const btTransform& transform, @@ -117,7 +113,7 @@ namespace DetourNavigator { return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* vertices, int, int) { - RecastMeshTriangle triangle = makeRecastMeshTriangle(vertices, areaType, mSettings); + RecastMeshTriangle triangle = makeRecastMeshTriangle(vertices, areaType); std::reverse(triangle.mVertices.begin(), triangle.mVertices.end()); mTriangles.emplace_back(triangle); })); @@ -128,7 +124,7 @@ namespace DetourNavigator { return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* vertices, int, int) { - mTriangles.emplace_back(makeRecastMeshTriangle(vertices, areaType, mSettings)); + mTriangles.emplace_back(makeRecastMeshTriangle(vertices, areaType)); })); } @@ -158,7 +154,7 @@ namespace DetourNavigator shape.getVertex(indices[i + j], position); vertices[j] = transform(position); } - mTriangles.emplace_back(makeRecastMeshTriangle(vertices.data(), areaType, mSettings)); + mTriangles.emplace_back(makeRecastMeshTriangle(vertices.data(), areaType)); } } diff --git a/components/detournavigator/recastmeshbuilder.hpp b/components/detournavigator/recastmeshbuilder.hpp index 1d163a406f..66d9128bdd 100644 --- a/components/detournavigator/recastmeshbuilder.hpp +++ b/components/detournavigator/recastmeshbuilder.hpp @@ -23,8 +23,6 @@ class btTriangleCallback; namespace DetourNavigator { - struct Settings; - struct RecastMeshTriangle { AreaType mAreaType; @@ -39,7 +37,7 @@ namespace DetourNavigator class RecastMeshBuilder { public: - RecastMeshBuilder(const Settings& settings, const TileBounds& bounds); + explicit RecastMeshBuilder(const TileBounds& bounds) noexcept; void addObject(const btCollisionShape& shape, const btTransform& transform, const AreaType areaType); @@ -56,8 +54,7 @@ namespace DetourNavigator std::shared_ptr create(std::size_t generation, std::size_t revision) &&; private: - std::reference_wrapper mSettings; - TileBounds mBounds; + const TileBounds mBounds; std::vector mTriangles; std::vector mWater; diff --git a/components/detournavigator/recastmeshmanager.cpp b/components/detournavigator/recastmeshmanager.cpp index ed77b4cef4..69f16df509 100644 --- a/components/detournavigator/recastmeshmanager.cpp +++ b/components/detournavigator/recastmeshmanager.cpp @@ -1,5 +1,6 @@ #include "recastmeshmanager.hpp" #include "recastmeshbuilder.hpp" +#include "settings.hpp" namespace DetourNavigator { @@ -68,7 +69,10 @@ namespace DetourNavigator std::shared_ptr RecastMeshManager::getMesh() { - RecastMeshBuilder builder(mSettings, mTileBounds); + TileBounds tileBounds = mTileBounds; + tileBounds.mMin /= mSettings.mRecastScaleFactor; + tileBounds.mMax /= mSettings.mRecastScaleFactor; + RecastMeshBuilder builder(tileBounds); for (const auto& [k, v] : mWater) builder.addWater(v.mCellSize, v.mTransform); for (const auto& [k, object] : mObjects) diff --git a/components/sceneutil/recastmesh.cpp b/components/sceneutil/recastmesh.cpp index ce92b16a0e..556fc3f3b5 100644 --- a/components/sceneutil/recastmesh.cpp +++ b/components/sceneutil/recastmesh.cpp @@ -8,6 +8,9 @@ #include +#include +#include + namespace { std::vector calculateNormals(const std::vector& vertices, const std::vector& indices) @@ -37,13 +40,20 @@ namespace SceneUtil osg::ref_ptr createRecastMeshGroup(const DetourNavigator::RecastMesh& recastMesh, const DetourNavigator::Settings& settings) { + using namespace DetourNavigator; + const osg::ref_ptr 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); const DetourNavigator::Mesh& mesh = recastMesh.getMesh(); - const auto normals = calculateNormals(mesh.getVertices(), mesh.getIndices()); + std::vector vertices = mesh.getVertices(); + + for (std::size_t i = 0; i < vertices.size(); i += 3) + std::swap(vertices[i + 1], vertices[i + 2]); + + const auto normals = calculateNormals(vertices, mesh.getIndices()); const auto texScale = 1.0f / (settings.mCellSize * 10.0f); - duDebugDrawTriMesh(&debugDraw, mesh.getVertices().data(), mesh.getVerticesCount(), - mesh.getIndices().data(), normals.data(), mesh.getTrianglesCount(), nullptr, texScale); + duDebugDrawTriMesh(&debugDraw, vertices.data(), static_cast(vertices.size() / 3), + mesh.getIndices().data(), normals.data(), static_cast(mesh.getIndices().size() / 3), nullptr, texScale); return group; } } From a1549321d759510ac3a73164b7bb10e376ea9593 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 14 Jul 2021 17:30:47 +0200 Subject: [PATCH 05/12] Move Water struct out of RecastMesh class --- .../detournavigator/navmeshtilescache.cpp | 4 +-- .../detournavigator/navmeshtilescache.cpp | 28 +++++++++---------- .../detournavigator/recastmeshbuilder.cpp | 6 ++-- components/detournavigator/makenavmesh.cpp | 2 +- .../detournavigator/navmeshtilescache.hpp | 2 +- components/detournavigator/recastmesh.hpp | 16 +++++------ .../detournavigator/recastmeshbuilder.cpp | 2 +- .../detournavigator/recastmeshbuilder.hpp | 2 +- 8 files changed, 31 insertions(+), 31 deletions(-) diff --git a/apps/benchmarks/detournavigator/navmeshtilescache.cpp b/apps/benchmarks/detournavigator/navmeshtilescache.cpp index 030162ab59..1d7358fa02 100644 --- a/apps/benchmarks/detournavigator/navmeshtilescache.cpp +++ b/apps/benchmarks/detournavigator/navmeshtilescache.cpp @@ -83,7 +83,7 @@ namespace std::uniform_real_distribution distribution(0.0, 1.0); std::generate_n(out, count, [&] { const btVector3 shift(distribution(random), distribution(random), distribution(random)); - return RecastMesh::Water {1, btTransform(btMatrix3x3::getIdentity(), shift)}; + return Water {1, btTransform(btMatrix3x3::getIdentity(), shift)}; }); } @@ -108,7 +108,7 @@ namespace const std::size_t generation = std::uniform_int_distribution(0, 100)(random); const std::size_t revision = std::uniform_int_distribution(0, 10000)(random); Mesh mesh = generateMesh(triangles, random); - std::vector water; + std::vector water; generateWater(std::back_inserter(water), 2, random); 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 fa607db371..137da9cd88 100644 --- a/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp +++ b/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp @@ -143,12 +143,12 @@ namespace const std::size_t mGeneration = 0; const std::size_t mRevision = 0; const Mesh mMesh {makeMesh()}; - const std::vector mWater {}; + const std::vector mWater {}; const RecastMesh mRecastMesh {mGeneration, mRevision, mMesh, mWater}; std::unique_ptr mPreparedNavMeshData {makePeparedNavMeshData(3)}; const std::size_t mRecastMeshSize = sizeof(mRecastMesh) + getSize(mRecastMesh); - const std::size_t mRecastMeshWithWaterSize = mRecastMeshSize + sizeof(RecastMesh::Water); + const std::size_t mRecastMeshWithWaterSize = mRecastMeshSize + sizeof(Water); const std::size_t mPreparedNavMeshDataSize = sizeof(*mPreparedNavMeshData) + getSize(*mPreparedNavMeshData); }; @@ -231,7 +231,7 @@ namespace { const std::size_t maxSize = 1; NavMeshTilesCache cache(maxSize); - const std::vector water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; + const std::vector water {1, Water {1, btTransform::getIdentity()}}; const RecastMesh unexistentRecastMesh {mGeneration, mRevision, mMesh, water}; cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); @@ -243,7 +243,7 @@ namespace const std::size_t maxSize = mRecastMeshWithWaterSize + mPreparedNavMeshDataSize; NavMeshTilesCache cache(maxSize); - const std::vector water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; + const std::vector water {1, Water {1, btTransform::getIdentity()}}; const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water}; auto anotherPreparedNavMeshData = makePeparedNavMeshData(3); const auto copy = clone(*anotherPreparedNavMeshData); @@ -261,7 +261,7 @@ namespace const std::size_t maxSize = mRecastMeshWithWaterSize + mPreparedNavMeshDataSize; NavMeshTilesCache cache(maxSize); - const std::vector water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; + const std::vector water {1, Water {1, btTransform::getIdentity()}}; const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water}; auto anotherPreparedNavMeshData = makePeparedNavMeshData(3); @@ -277,11 +277,11 @@ namespace NavMeshTilesCache cache(maxSize); const auto copy = clone(*mPreparedNavMeshData); - const std::vector leastRecentlySetWater {1, RecastMesh::Water {1, btTransform::getIdentity()}}; + const std::vector leastRecentlySetWater {1, Water {1, btTransform::getIdentity()}}; const RecastMesh leastRecentlySetRecastMesh {mGeneration, mRevision, mMesh, leastRecentlySetWater}; auto leastRecentlySetData = makePeparedNavMeshData(3); - const std::vector mostRecentlySetWater {1, RecastMesh::Water {2, btTransform::getIdentity()}}; + const std::vector mostRecentlySetWater {1, Water {2, btTransform::getIdentity()}}; const RecastMesh mostRecentlySetRecastMesh {mGeneration, mRevision, mMesh, mostRecentlySetWater}; auto mostRecentlySetData = makePeparedNavMeshData(3); @@ -303,12 +303,12 @@ namespace const std::size_t maxSize = 2 * (mRecastMeshWithWaterSize + mPreparedNavMeshDataSize); NavMeshTilesCache cache(maxSize); - const std::vector leastRecentlyUsedWater {1, RecastMesh::Water {1, btTransform::getIdentity()}}; + const std::vector leastRecentlyUsedWater {1, Water {1, btTransform::getIdentity()}}; 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 std::vector mostRecentlyUsedWater {1, Water {2, btTransform::getIdentity()}}; const RecastMesh mostRecentlyUsedRecastMesh {mGeneration, mRevision, mMesh, mostRecentlyUsedWater}; auto mostRecentlyUsedData = makePeparedNavMeshData(3); const auto mostRecentlyUsedCopy = clone(*mostRecentlyUsedData); @@ -342,7 +342,7 @@ namespace const std::size_t maxSize = 2 * (mRecastMeshWithWaterSize + mPreparedNavMeshDataSize); NavMeshTilesCache cache(maxSize); - const std::vector water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; + const std::vector water {1, Water {1, btTransform::getIdentity()}}; const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mMesh, water}; auto tooLargeData = makePeparedNavMeshData(10); @@ -356,11 +356,11 @@ namespace const std::size_t maxSize = 2 * (mRecastMeshWithWaterSize + mPreparedNavMeshDataSize); NavMeshTilesCache cache(maxSize); - const std::vector anotherWater {1, RecastMesh::Water {1, btTransform::getIdentity()}}; + const std::vector anotherWater {1, Water {1, btTransform::getIdentity()}}; const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, anotherWater}; auto anotherData = makePeparedNavMeshData(3); - const std::vector tooLargeWater {1, RecastMesh::Water {2, btTransform::getIdentity()}}; + const std::vector tooLargeWater {1, Water {2, btTransform::getIdentity()}}; const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mMesh, tooLargeWater}; auto tooLargeData = makePeparedNavMeshData(10); @@ -380,7 +380,7 @@ namespace const std::size_t maxSize = mRecastMeshWithWaterSize + mPreparedNavMeshDataSize; NavMeshTilesCache cache(maxSize); - const std::vector water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; + const std::vector water {1, Water {1, btTransform::getIdentity()}}; const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water}; auto anotherData = makePeparedNavMeshData(3); @@ -399,7 +399,7 @@ namespace const std::size_t maxSize = mRecastMeshWithWaterSize + mPreparedNavMeshDataSize; NavMeshTilesCache cache(maxSize); - const std::vector water {1, RecastMesh::Water {1, btTransform::getIdentity()}}; + const std::vector water {1, Water {1, btTransform::getIdentity()}}; const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water}; auto anotherData = makePeparedNavMeshData(3); diff --git a/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp b/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp index 0528205b58..56f94701f0 100644 --- a/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp +++ b/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp @@ -19,7 +19,7 @@ namespace DetourNavigator { - static inline bool operator ==(const RecastMesh::Water& lhs, const RecastMesh::Water& rhs) + static inline bool operator ==(const Water& lhs, const Water& rhs) { return lhs.mCellSize == rhs.mCellSize && lhs.mTransform == rhs.mTransform; } @@ -404,8 +404,8 @@ namespace RecastMeshBuilder builder(mBounds); builder.addWater(1000, btTransform(btMatrix3x3::getIdentity(), btVector3(100, 200, 300))); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); - EXPECT_EQ(recastMesh->getWater(), std::vector({ - RecastMesh::Water {1000, btTransform(btMatrix3x3::getIdentity(), btVector3(100, 200, 300))} + EXPECT_EQ(recastMesh->getWater(), std::vector({ + Water {1000, btTransform(btMatrix3x3::getIdentity(), btVector3(100, 200, 300))} })); } diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index 0824e9cb86..1e2d4d5167 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -34,7 +34,7 @@ namespace osg::Vec3f mMax; }; - WaterBounds getWaterBounds(const RecastMesh::Water& water, const Settings& settings, + WaterBounds getWaterBounds(const Water& water, const Settings& settings, const osg::Vec3f& agentHalfExtents) { if (water.mCellSize == std::numeric_limits::max()) diff --git a/components/detournavigator/navmeshtilescache.hpp b/components/detournavigator/navmeshtilescache.hpp index b6b9391e66..974420c158 100644 --- a/components/detournavigator/navmeshtilescache.hpp +++ b/components/detournavigator/navmeshtilescache.hpp @@ -23,7 +23,7 @@ namespace DetourNavigator struct RecastMeshData { Mesh mMesh; - std::vector mWater; + std::vector mWater; }; inline bool operator <(const RecastMeshData& lhs, const RecastMeshData& rhs) diff --git a/components/detournavigator/recastmesh.hpp b/components/detournavigator/recastmesh.hpp index 9989bab061..c70405c85c 100644 --- a/components/detournavigator/recastmesh.hpp +++ b/components/detournavigator/recastmesh.hpp @@ -45,15 +45,15 @@ namespace DetourNavigator } }; + struct Water + { + int mCellSize; + btTransform mTransform; + }; + class RecastMesh { public: - struct Water - { - int mCellSize; - btTransform mTransform; - }; - RecastMesh(std::size_t generation, std::size_t revision, Mesh mesh, std::vector water); std::size_t getGeneration() const @@ -92,11 +92,11 @@ namespace DetourNavigator friend inline std::size_t getSize(const RecastMesh& value) noexcept { - return getSize(value.mMesh) + value.mWater.size() * sizeof(RecastMesh::Water); + return getSize(value.mMesh) + value.mWater.size() * sizeof(Water); } }; - inline bool operator<(const RecastMesh::Water& lhs, const RecastMesh::Water& rhs) noexcept + inline bool operator<(const Water& lhs, const Water& rhs) noexcept { return std::tie(lhs.mCellSize, lhs.mTransform) < std::tie(rhs.mCellSize, rhs.mTransform); } diff --git a/components/detournavigator/recastmeshbuilder.cpp b/components/detournavigator/recastmeshbuilder.cpp index 81fb6f21cf..ad896c2a57 100644 --- a/components/detournavigator/recastmeshbuilder.cpp +++ b/components/detournavigator/recastmeshbuilder.cpp @@ -160,7 +160,7 @@ namespace DetourNavigator void RecastMeshBuilder::addWater(const int cellSize, const btTransform& transform) { - mWater.push_back(RecastMesh::Water {cellSize, transform}); + mWater.push_back(Water {cellSize, transform}); } std::shared_ptr RecastMeshBuilder::create(std::size_t generation, std::size_t revision) && diff --git a/components/detournavigator/recastmeshbuilder.hpp b/components/detournavigator/recastmeshbuilder.hpp index 66d9128bdd..2692e8f486 100644 --- a/components/detournavigator/recastmeshbuilder.hpp +++ b/components/detournavigator/recastmeshbuilder.hpp @@ -56,7 +56,7 @@ namespace DetourNavigator private: const TileBounds mBounds; std::vector mTriangles; - std::vector mWater; + std::vector mWater; void addObject(const btConcaveShape& shape, const btTransform& transform, btTriangleCallback&& callback); From da4ec31cd86b1765690ba0aa973fd52280a9b875 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 14 Jul 2021 21:39:39 +0200 Subject: [PATCH 06/12] Remove redundant RecastMeshManager::Water --- components/detournavigator/cachedrecastmeshmanager.cpp | 2 +- components/detournavigator/cachedrecastmeshmanager.hpp | 2 +- components/detournavigator/recastmeshmanager.cpp | 2 +- components/detournavigator/recastmeshmanager.hpp | 7 +------ components/detournavigator/tilecachedrecastmeshmanager.cpp | 4 ++-- components/detournavigator/tilecachedrecastmeshmanager.hpp | 2 +- 6 files changed, 7 insertions(+), 12 deletions(-) diff --git a/components/detournavigator/cachedrecastmeshmanager.cpp b/components/detournavigator/cachedrecastmeshmanager.cpp index 4666b66a83..38bc954342 100644 --- a/components/detournavigator/cachedrecastmeshmanager.cpp +++ b/components/detournavigator/cachedrecastmeshmanager.cpp @@ -42,7 +42,7 @@ namespace DetourNavigator return true; } - std::optional CachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition) + std::optional CachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition) { const auto water = mImpl.removeWater(cellPosition); if (water) diff --git a/components/detournavigator/cachedrecastmeshmanager.hpp b/components/detournavigator/cachedrecastmeshmanager.hpp index 96604c3628..e4a262bc6a 100644 --- a/components/detournavigator/cachedrecastmeshmanager.hpp +++ b/components/detournavigator/cachedrecastmeshmanager.hpp @@ -18,7 +18,7 @@ namespace DetourNavigator bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btTransform& transform); - std::optional removeWater(const osg::Vec2i& cellPosition); + std::optional removeWater(const osg::Vec2i& cellPosition); std::optional removeObject(const ObjectId id); diff --git a/components/detournavigator/recastmeshmanager.cpp b/components/detournavigator/recastmeshmanager.cpp index 69f16df509..267c3ee9a3 100644 --- a/components/detournavigator/recastmeshmanager.cpp +++ b/components/detournavigator/recastmeshmanager.cpp @@ -56,7 +56,7 @@ namespace DetourNavigator return true; } - std::optional RecastMeshManager::removeWater(const osg::Vec2i& cellPosition) + std::optional RecastMeshManager::removeWater(const osg::Vec2i& cellPosition) { const auto water = mWater.find(cellPosition); if (water == mWater.end()) diff --git a/components/detournavigator/recastmeshmanager.hpp b/components/detournavigator/recastmeshmanager.hpp index d67f287dfc..a1d6123062 100644 --- a/components/detournavigator/recastmeshmanager.hpp +++ b/components/detournavigator/recastmeshmanager.hpp @@ -4,6 +4,7 @@ #include "oscillatingrecastmeshobject.hpp" #include "objectid.hpp" #include "version.hpp" +#include "recastmesh.hpp" #include @@ -29,12 +30,6 @@ namespace DetourNavigator class RecastMeshManager { public: - struct Water - { - int mCellSize = 0; - btTransform mTransform; - }; - RecastMeshManager(const Settings& settings, const TileBounds& bounds, std::size_t generation); bool addObject(const ObjectId id, const btCollisionShape& shape, const btTransform& transform, diff --git a/components/detournavigator/tilecachedrecastmeshmanager.cpp b/components/detournavigator/tilecachedrecastmeshmanager.cpp index 42ae93e806..c19e43c498 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.cpp @@ -102,12 +102,12 @@ namespace DetourNavigator return result; } - std::optional TileCachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition) + std::optional TileCachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition) { const auto object = mWaterTilesPositions.find(cellPosition); if (object == mWaterTilesPositions.end()) return std::nullopt; - std::optional result; + std::optional result; for (const auto& tilePosition : object->second) { const auto tiles = mTiles.lock(); diff --git a/components/detournavigator/tilecachedrecastmeshmanager.hpp b/components/detournavigator/tilecachedrecastmeshmanager.hpp index 23ecc77634..087e3e1f36 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.hpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.hpp @@ -78,7 +78,7 @@ namespace DetourNavigator bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btTransform& transform); - std::optional removeWater(const osg::Vec2i& cellPosition); + std::optional removeWater(const osg::Vec2i& cellPosition); std::shared_ptr getMesh(const TilePosition& tilePosition); From 753767d6d96141796bd8acc3868a4c0b578fe40f Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 14 Jul 2021 21:54:41 +0200 Subject: [PATCH 07/12] Store only water shift Rotation is not used. --- .../detournavigator/navmeshtilescache.cpp | 6 ++-- apps/openmw/mwworld/scene.cpp | 9 ++++-- .../detournavigator/navigator.cpp | 8 +++--- .../detournavigator/navmeshtilescache.cpp | 28 +++++++++---------- .../detournavigator/recastmeshbuilder.cpp | 6 ++-- .../tilecachedrecastmeshmanager.cpp | 12 ++++---- .../cachedrecastmeshmanager.cpp | 4 +-- .../cachedrecastmeshmanager.hpp | 2 +- .../detournavigator/gettilespositions.hpp | 3 +- components/detournavigator/makenavmesh.cpp | 4 +-- components/detournavigator/navigator.hpp | 6 ++-- components/detournavigator/navigatorimpl.cpp | 6 ++-- components/detournavigator/navigatorimpl.hpp | 3 +- components/detournavigator/navigatorstub.hpp | 3 +- components/detournavigator/navmeshmanager.cpp | 12 ++++---- components/detournavigator/navmeshmanager.hpp | 4 +-- components/detournavigator/recastmesh.hpp | 8 +++--- .../detournavigator/recastmeshbuilder.cpp | 4 +-- .../detournavigator/recastmeshbuilder.hpp | 2 +- .../detournavigator/recastmeshmanager.cpp | 7 ++--- .../detournavigator/recastmeshmanager.hpp | 2 +- components/detournavigator/settingsutils.hpp | 6 ++-- .../tilecachedrecastmeshmanager.cpp | 8 +++--- .../tilecachedrecastmeshmanager.hpp | 2 +- 24 files changed, 77 insertions(+), 78 deletions(-) diff --git a/apps/benchmarks/detournavigator/navmeshtilescache.cpp b/apps/benchmarks/detournavigator/navmeshtilescache.cpp index 1d7358fa02..c6e6ecbdbc 100644 --- a/apps/benchmarks/detournavigator/navmeshtilescache.cpp +++ b/apps/benchmarks/detournavigator/navmeshtilescache.cpp @@ -80,10 +80,10 @@ namespace template void generateWater(OutputIterator out, std::size_t count, Random& random) { - std::uniform_real_distribution distribution(0.0, 1.0); + std::uniform_real_distribution distribution(0.0, 1.0); std::generate_n(out, count, [&] { - const btVector3 shift(distribution(random), distribution(random), distribution(random)); - return Water {1, btTransform(btMatrix3x3::getIdentity(), shift)}; + const osg::Vec3f shift(distribution(random), distribution(random), distribution(random)); + return Water {1, shift}; }); } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index f7c9b43fb6..61ef3e1538 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -470,13 +470,18 @@ namespace MWWorld if (cell->getCell()->isExterior()) { if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) + { + const btTransform& transform =heightField->getCollisionObject()->getWorldTransform(); mNavigator.addWater(osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE, - cell->getWaterLevel(), heightField->getCollisionObject()->getWorldTransform()); + osg::Vec3f(static_cast(transform.getOrigin().x()), + static_cast(transform.getOrigin().y()), + waterLevel)); + } } else { mNavigator.addWater(osg::Vec2i(cellX, cellY), std::numeric_limits::max(), - cell->getWaterLevel(), btTransform::getIdentity()); + osg::Vec3f(0, 0, waterLevel)); } } else diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index b0fec1a1a3..b815c50bbe 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -452,7 +452,7 @@ namespace shape.setLocalScaling(btVector3(128, 128, 1)); mNavigator->addAgent(mAgentHalfExtents); - mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, 300, btTransform::getIdentity()); + mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, osg::Vec3f(0, 0, 300)); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -499,7 +499,7 @@ namespace shape.setLocalScaling(btVector3(128, 128, 1)); mNavigator->addAgent(mAgentHalfExtents); - mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, -25, btTransform::getIdentity()); + mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, osg::Vec3f(0, 0, -25)); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -546,7 +546,7 @@ namespace mNavigator->addAgent(mAgentHalfExtents); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); - mNavigator->addWater(osg::Vec2i(0, 0), std::numeric_limits::max(), -25, btTransform::getIdentity()); + mNavigator->addWater(osg::Vec2i(0, 0), std::numeric_limits::max(), osg::Vec3f(0, 0, -25)); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -591,7 +591,7 @@ namespace shape.setLocalScaling(btVector3(128, 128, 1)); mNavigator->addAgent(mAgentHalfExtents); - mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, -25, btTransform::getIdentity()); + mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, osg::Vec3f(0, 0, -25)); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); diff --git a/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp b/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp index 137da9cd88..c9c2a6528b 100644 --- a/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp +++ b/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp @@ -7,9 +7,9 @@ #include #include -#include +#include -#include +#include #include @@ -231,7 +231,7 @@ namespace { const std::size_t maxSize = 1; NavMeshTilesCache cache(maxSize); - const std::vector water {1, Water {1, btTransform::getIdentity()}}; + const std::vector water {1, Water {1, osg::Vec3f()}}; const RecastMesh unexistentRecastMesh {mGeneration, mRevision, mMesh, water}; cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); @@ -243,7 +243,7 @@ namespace const std::size_t maxSize = mRecastMeshWithWaterSize + mPreparedNavMeshDataSize; NavMeshTilesCache cache(maxSize); - const std::vector water {1, Water {1, btTransform::getIdentity()}}; + const std::vector water {1, Water {1, osg::Vec3f()}}; const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water}; auto anotherPreparedNavMeshData = makePeparedNavMeshData(3); const auto copy = clone(*anotherPreparedNavMeshData); @@ -261,7 +261,7 @@ namespace const std::size_t maxSize = mRecastMeshWithWaterSize + mPreparedNavMeshDataSize; NavMeshTilesCache cache(maxSize); - const std::vector water {1, Water {1, btTransform::getIdentity()}}; + const std::vector water {1, Water {1, osg::Vec3f()}}; const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water}; auto anotherPreparedNavMeshData = makePeparedNavMeshData(3); @@ -277,11 +277,11 @@ namespace NavMeshTilesCache cache(maxSize); const auto copy = clone(*mPreparedNavMeshData); - const std::vector leastRecentlySetWater {1, Water {1, btTransform::getIdentity()}}; + const std::vector leastRecentlySetWater {1, Water {1, osg::Vec3f()}}; const RecastMesh leastRecentlySetRecastMesh {mGeneration, mRevision, mMesh, leastRecentlySetWater}; auto leastRecentlySetData = makePeparedNavMeshData(3); - const std::vector mostRecentlySetWater {1, Water {2, btTransform::getIdentity()}}; + const std::vector mostRecentlySetWater {1, Water {2, osg::Vec3f()}}; const RecastMesh mostRecentlySetRecastMesh {mGeneration, mRevision, mMesh, mostRecentlySetWater}; auto mostRecentlySetData = makePeparedNavMeshData(3); @@ -303,12 +303,12 @@ namespace const std::size_t maxSize = 2 * (mRecastMeshWithWaterSize + mPreparedNavMeshDataSize); NavMeshTilesCache cache(maxSize); - const std::vector leastRecentlyUsedWater {1, Water {1, btTransform::getIdentity()}}; + const std::vector leastRecentlyUsedWater {1, Water {1, osg::Vec3f()}}; const RecastMesh leastRecentlyUsedRecastMesh {mGeneration, mRevision, mMesh, leastRecentlyUsedWater}; auto leastRecentlyUsedData = makePeparedNavMeshData(3); const auto leastRecentlyUsedCopy = clone(*leastRecentlyUsedData); - const std::vector mostRecentlyUsedWater {1, Water {2, btTransform::getIdentity()}}; + const std::vector mostRecentlyUsedWater {1, Water {2, osg::Vec3f()}}; const RecastMesh mostRecentlyUsedRecastMesh {mGeneration, mRevision, mMesh, mostRecentlyUsedWater}; auto mostRecentlyUsedData = makePeparedNavMeshData(3); const auto mostRecentlyUsedCopy = clone(*mostRecentlyUsedData); @@ -342,7 +342,7 @@ namespace const std::size_t maxSize = 2 * (mRecastMeshWithWaterSize + mPreparedNavMeshDataSize); NavMeshTilesCache cache(maxSize); - const std::vector water {1, Water {1, btTransform::getIdentity()}}; + const std::vector water {1, Water {1, osg::Vec3f()}}; const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mMesh, water}; auto tooLargeData = makePeparedNavMeshData(10); @@ -356,11 +356,11 @@ namespace const std::size_t maxSize = 2 * (mRecastMeshWithWaterSize + mPreparedNavMeshDataSize); NavMeshTilesCache cache(maxSize); - const std::vector anotherWater {1, Water {1, btTransform::getIdentity()}}; + const std::vector anotherWater {1, Water {1, osg::Vec3f()}}; const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, anotherWater}; auto anotherData = makePeparedNavMeshData(3); - const std::vector tooLargeWater {1, Water {2, btTransform::getIdentity()}}; + const std::vector tooLargeWater {1, Water {2, osg::Vec3f()}}; const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mMesh, tooLargeWater}; auto tooLargeData = makePeparedNavMeshData(10); @@ -380,7 +380,7 @@ namespace const std::size_t maxSize = mRecastMeshWithWaterSize + mPreparedNavMeshDataSize; NavMeshTilesCache cache(maxSize); - const std::vector water {1, Water {1, btTransform::getIdentity()}}; + const std::vector water {1, Water {1, osg::Vec3f()}}; const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water}; auto anotherData = makePeparedNavMeshData(3); @@ -399,7 +399,7 @@ namespace const std::size_t maxSize = mRecastMeshWithWaterSize + mPreparedNavMeshDataSize; NavMeshTilesCache cache(maxSize); - const std::vector water {1, Water {1, btTransform::getIdentity()}}; + const std::vector water {1, Water {1, osg::Vec3f()}}; const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water}; auto anotherData = makePeparedNavMeshData(3); diff --git a/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp b/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp index 56f94701f0..ac565e36c0 100644 --- a/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp +++ b/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp @@ -21,7 +21,7 @@ namespace DetourNavigator { static inline bool operator ==(const Water& lhs, const Water& rhs) { - return lhs.mCellSize == rhs.mCellSize && lhs.mTransform == rhs.mTransform; + return lhs.mCellSize == rhs.mCellSize && lhs.mShift == rhs.mShift; } } @@ -402,10 +402,10 @@ namespace TEST_F(DetourNavigatorRecastMeshBuilderTest, add_water_then_get_water_should_return_it) { RecastMeshBuilder builder(mBounds); - builder.addWater(1000, btTransform(btMatrix3x3::getIdentity(), btVector3(100, 200, 300))); + builder.addWater(1000, osg::Vec3f(100, 200, 300)); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); EXPECT_EQ(recastMesh->getWater(), std::vector({ - Water {1000, btTransform(btMatrix3x3::getIdentity(), btVector3(100, 200, 300))} + Water {1000, osg::Vec3f(100, 200, 300)} })); } diff --git a/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp index fb0f97831a..59938ad2be 100644 --- a/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp @@ -254,7 +254,7 @@ namespace TileCachedRecastMeshManager manager(mSettings); const osg::Vec2i cellPosition(0, 0); const int cellSize = 8192; - EXPECT_TRUE(manager.addWater(cellPosition, cellSize, btTransform::getIdentity())); + EXPECT_TRUE(manager.addWater(cellPosition, cellSize, osg::Vec3f())); } TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_water_for_not_max_int_should_add_new_tiles) @@ -262,7 +262,7 @@ namespace TileCachedRecastMeshManager manager(mSettings); const osg::Vec2i cellPosition(0, 0); const int cellSize = 8192; - ASSERT_TRUE(manager.addWater(cellPosition, cellSize, btTransform::getIdentity())); + ASSERT_TRUE(manager.addWater(cellPosition, cellSize, osg::Vec3f())); for (int x = -6; x < 6; ++x) for (int y = -6; y < 6; ++y) ASSERT_TRUE(manager.hasTile(TilePosition(x, y))); @@ -275,7 +275,7 @@ namespace ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground)); const osg::Vec2i cellPosition(0, 0); const int cellSize = std::numeric_limits::max(); - ASSERT_TRUE(manager.addWater(cellPosition, cellSize, btTransform::getIdentity())); + ASSERT_TRUE(manager.addWater(cellPosition, cellSize, osg::Vec3f())); for (int x = -6; x < 6; ++x) for (int y = -6; y < 6; ++y) ASSERT_EQ(manager.hasTile(TilePosition(x, y)), -1 <= x && x <= 0 && -1 <= y && y <= 0); @@ -292,7 +292,7 @@ namespace TileCachedRecastMeshManager manager(mSettings); const osg::Vec2i cellPosition(0, 0); const int cellSize = 8192; - ASSERT_TRUE(manager.addWater(cellPosition, cellSize, btTransform::getIdentity())); + ASSERT_TRUE(manager.addWater(cellPosition, cellSize, osg::Vec3f())); const auto result = manager.removeWater(cellPosition); ASSERT_TRUE(result.has_value()); EXPECT_EQ(result->mCellSize, cellSize); @@ -303,7 +303,7 @@ namespace TileCachedRecastMeshManager manager(mSettings); const osg::Vec2i cellPosition(0, 0); const int cellSize = 8192; - ASSERT_TRUE(manager.addWater(cellPosition, cellSize, btTransform::getIdentity())); + ASSERT_TRUE(manager.addWater(cellPosition, cellSize, osg::Vec3f())); ASSERT_TRUE(manager.removeWater(cellPosition)); for (int x = -6; x < 6; ++x) for (int y = -6; y < 6; ++y) @@ -317,7 +317,7 @@ namespace ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground)); const osg::Vec2i cellPosition(0, 0); const int cellSize = 8192; - ASSERT_TRUE(manager.addWater(cellPosition, cellSize, btTransform::getIdentity())); + ASSERT_TRUE(manager.addWater(cellPosition, cellSize, osg::Vec3f())); ASSERT_TRUE(manager.removeWater(cellPosition)); for (int x = -6; x < 6; ++x) for (int y = -6; y < 6; ++y) diff --git a/components/detournavigator/cachedrecastmeshmanager.cpp b/components/detournavigator/cachedrecastmeshmanager.cpp index 38bc954342..1242b32318 100644 --- a/components/detournavigator/cachedrecastmeshmanager.cpp +++ b/components/detournavigator/cachedrecastmeshmanager.cpp @@ -34,9 +34,9 @@ namespace DetourNavigator } bool CachedRecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize, - const btTransform& transform) + const osg::Vec3f& shift) { - if (!mImpl.addWater(cellPosition, cellSize, transform)) + if (!mImpl.addWater(cellPosition, cellSize, shift)) return false; mCached.reset(); return true; diff --git a/components/detournavigator/cachedrecastmeshmanager.hpp b/components/detournavigator/cachedrecastmeshmanager.hpp index e4a262bc6a..247775e3e7 100644 --- a/components/detournavigator/cachedrecastmeshmanager.hpp +++ b/components/detournavigator/cachedrecastmeshmanager.hpp @@ -16,7 +16,7 @@ namespace DetourNavigator bool updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType); - bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btTransform& transform); + bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const osg::Vec3f& shift); std::optional removeWater(const osg::Vec2i& cellPosition); diff --git a/components/detournavigator/gettilespositions.hpp b/components/detournavigator/gettilespositions.hpp index e233795e68..27c8f7a4ac 100644 --- a/components/detournavigator/gettilespositions.hpp +++ b/components/detournavigator/gettilespositions.hpp @@ -50,10 +50,11 @@ namespace DetourNavigator } template - void getTilesPositions(const int cellSize, const btTransform& transform, + void getTilesPositions(const int cellSize, const osg::Vec3f& shift, const Settings& settings, Callback&& callback) { const auto halfCellSize = cellSize / 2; + const btTransform transform(btMatrix3x3::getIdentity(), Misc::Convert::toBullet(shift)); auto aabbMin = transform(btVector3(-halfCellSize, -halfCellSize, 0)); auto aabbMax = transform(btVector3(halfCellSize, halfCellSize, 0)); diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index 1e2d4d5167..ba1e93f50e 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -39,7 +39,7 @@ namespace { if (water.mCellSize == std::numeric_limits::max()) { - const auto transform = getSwimLevelTransform(settings, water.mTransform, agentHalfExtents.z()); + const auto transform = getSwimLevelTransform(settings, water.mShift, agentHalfExtents.z()); const auto min = toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(-1, -1, 0)))); const auto max = toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(1, 1, 0)))); return WaterBounds { @@ -49,7 +49,7 @@ namespace } else { - const auto transform = getSwimLevelTransform(settings, water.mTransform, agentHalfExtents.z()); + const auto transform = getSwimLevelTransform(settings, water.mShift, agentHalfExtents.z()); const auto halfCellSize = water.mCellSize / 2.0f; return WaterBounds { toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(-halfCellSize, -halfCellSize, 0)))), diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index 0dab7ba6b3..f7ee4ed96e 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -134,14 +134,12 @@ namespace DetourNavigator * @brief addWater is used to set water level at given world cell. * @param cellPosition allows to distinguish cells if there is many in current world. * @param cellSize set cell borders. std::numeric_limits::max() disables cell borders. - * @param level set z coordinate of water surface at the scene. - * @param transform set global shift of cell center. + * @param shift set global shift of cell center. * @return true if there was no water at given cell if cellSize != std::numeric_limits::max() or there is * at least single object is added to the scene, false if there is already water for given cell or there is no * any other objects. */ - virtual bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btScalar level, - const btTransform& transform) = 0; + virtual bool addWater(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift) = 0; /** * @brief removeWater to make it no more available at the scene. diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index 1aa4768de5..a6e1062fbb 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -102,11 +102,9 @@ namespace DetourNavigator return result; } - bool NavigatorImpl::addWater(const osg::Vec2i& cellPosition, const int cellSize, const btScalar level, - const btTransform& transform) + bool NavigatorImpl::addWater(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift) { - return mNavMeshManager.addWater(cellPosition, cellSize, - btTransform(transform.getBasis(), btVector3(transform.getOrigin().x(), transform.getOrigin().y(), level))); + return mNavMeshManager.addWater(cellPosition, cellSize, shift); } bool NavigatorImpl::removeWater(const osg::Vec2i& cellPosition) diff --git a/components/detournavigator/navigatorimpl.hpp b/components/detournavigator/navigatorimpl.hpp index 80c6957d79..3d021ec7e9 100644 --- a/components/detournavigator/navigatorimpl.hpp +++ b/components/detournavigator/navigatorimpl.hpp @@ -35,8 +35,7 @@ namespace DetourNavigator bool removeObject(const ObjectId id) override; - bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btScalar level, - const btTransform& transform) override; + bool addWater(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift) override; bool removeWater(const osg::Vec2i& cellPosition) override; diff --git a/components/detournavigator/navigatorstub.hpp b/components/detournavigator/navigatorstub.hpp index 0a08813938..cab8feaf39 100644 --- a/components/detournavigator/navigatorstub.hpp +++ b/components/detournavigator/navigatorstub.hpp @@ -54,8 +54,7 @@ namespace DetourNavigator return false; } - bool addWater(const osg::Vec2i& /*cellPosition*/, const int /*cellSize*/, const btScalar /*level*/, - const btTransform& /*transform*/) override + bool addWater(const osg::Vec2i& /*cellPosition*/, int /*cellSize*/, const osg::Vec3f& /*shift*/) override { return false; } diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index c42fb5c4be..767dfd59aa 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -72,11 +72,11 @@ namespace DetourNavigator return true; } - bool NavMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize, const btTransform& transform) + bool NavMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize, const osg::Vec3f& shift) { - if (!mRecastMeshManager.addWater(cellPosition, cellSize, transform)) + if (!mRecastMeshManager.addWater(cellPosition, cellSize, shift)) return false; - addChangedTiles(cellSize, transform, ChangeType::add); + addChangedTiles(cellSize, shift, ChangeType::add); return true; } @@ -85,7 +85,7 @@ namespace DetourNavigator const auto water = mRecastMeshManager.removeWater(cellPosition); if (!water) return false; - addChangedTiles(water->mCellSize, water->mTransform, ChangeType::remove); + addChangedTiles(water->mCellSize, water->mShift, ChangeType::remove); return true; } @@ -231,13 +231,13 @@ namespace DetourNavigator [&] (const TilePosition& v) { addChangedTile(v, changeType); }); } - void NavMeshManager::addChangedTiles(const int cellSize, const btTransform& transform, + void NavMeshManager::addChangedTiles(const int cellSize, const osg::Vec3f& shift, const ChangeType changeType) { if (cellSize == std::numeric_limits::max()) return; - getTilesPositions(cellSize, transform, mSettings, + getTilesPositions(cellSize, shift, mSettings, [&] (const TilePosition& v) { addChangedTile(v, changeType); }); } diff --git a/components/detournavigator/navmeshmanager.hpp b/components/detournavigator/navmeshmanager.hpp index b176515e3b..a93d8824e3 100644 --- a/components/detournavigator/navmeshmanager.hpp +++ b/components/detournavigator/navmeshmanager.hpp @@ -33,7 +33,7 @@ namespace DetourNavigator void addAgent(const osg::Vec3f& agentHalfExtents); - bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btTransform& transform); + bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const osg::Vec3f& shift); bool removeWater(const osg::Vec2i& cellPosition); @@ -68,7 +68,7 @@ namespace DetourNavigator void addChangedTiles(const btCollisionShape& shape, const btTransform& transform, const ChangeType changeType); - void addChangedTiles(const int cellSize, const btTransform& transform, const ChangeType changeType); + void addChangedTiles(const int cellSize, const osg::Vec3f& shift, const ChangeType changeType); void addChangedTile(const TilePosition& tilePosition, const ChangeType changeType); diff --git a/components/detournavigator/recastmesh.hpp b/components/detournavigator/recastmesh.hpp index c70405c85c..c1d01e48fd 100644 --- a/components/detournavigator/recastmesh.hpp +++ b/components/detournavigator/recastmesh.hpp @@ -6,13 +6,13 @@ #include +#include + #include #include #include #include -#include - namespace DetourNavigator { class Mesh @@ -48,7 +48,7 @@ namespace DetourNavigator struct Water { int mCellSize; - btTransform mTransform; + osg::Vec3f mShift; }; class RecastMesh @@ -98,7 +98,7 @@ namespace DetourNavigator inline bool operator<(const Water& lhs, const Water& rhs) noexcept { - return std::tie(lhs.mCellSize, lhs.mTransform) < std::tie(rhs.mCellSize, rhs.mTransform); + return std::tie(lhs.mCellSize, lhs.mShift) < std::tie(rhs.mCellSize, rhs.mShift); } } diff --git a/components/detournavigator/recastmeshbuilder.cpp b/components/detournavigator/recastmeshbuilder.cpp index ad896c2a57..1b2b5b08cd 100644 --- a/components/detournavigator/recastmeshbuilder.cpp +++ b/components/detournavigator/recastmeshbuilder.cpp @@ -158,9 +158,9 @@ namespace DetourNavigator } } - void RecastMeshBuilder::addWater(const int cellSize, const btTransform& transform) + void RecastMeshBuilder::addWater(const int cellSize, const osg::Vec3f& shift) { - mWater.push_back(Water {cellSize, transform}); + mWater.push_back(Water {cellSize, shift}); } std::shared_ptr RecastMeshBuilder::create(std::size_t generation, std::size_t revision) && diff --git a/components/detournavigator/recastmeshbuilder.hpp b/components/detournavigator/recastmeshbuilder.hpp index 2692e8f486..95dfc9cb52 100644 --- a/components/detournavigator/recastmeshbuilder.hpp +++ b/components/detournavigator/recastmeshbuilder.hpp @@ -49,7 +49,7 @@ namespace DetourNavigator void addObject(const btBoxShape& shape, const btTransform& transform, const AreaType areaType); - void addWater(const int mCellSize, const btTransform& transform); + void addWater(const int mCellSize, const osg::Vec3f& shift); std::shared_ptr create(std::size_t generation, std::size_t revision) &&; diff --git a/components/detournavigator/recastmeshmanager.cpp b/components/detournavigator/recastmeshmanager.cpp index 267c3ee9a3..336ecf3fe5 100644 --- a/components/detournavigator/recastmeshmanager.cpp +++ b/components/detournavigator/recastmeshmanager.cpp @@ -47,10 +47,9 @@ namespace DetourNavigator return result; } - bool RecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize, - const btTransform& transform) + bool RecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize, const osg::Vec3f& shift) { - if (!mWater.emplace(cellPosition, Water {cellSize, transform}).second) + if (!mWater.emplace(cellPosition, Water {cellSize, shift}).second) return false; ++mRevision; return true; @@ -74,7 +73,7 @@ namespace DetourNavigator tileBounds.mMax /= mSettings.mRecastScaleFactor; RecastMeshBuilder builder(tileBounds); for (const auto& [k, v] : mWater) - builder.addWater(v.mCellSize, v.mTransform); + builder.addWater(v.mCellSize, v.mShift); for (const auto& [k, object] : mObjects) { const RecastMeshObject& v = object.getImpl(); diff --git a/components/detournavigator/recastmeshmanager.hpp b/components/detournavigator/recastmeshmanager.hpp index a1d6123062..bcb716353a 100644 --- a/components/detournavigator/recastmeshmanager.hpp +++ b/components/detournavigator/recastmeshmanager.hpp @@ -37,7 +37,7 @@ namespace DetourNavigator bool updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType); - bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btTransform& transform); + bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const osg::Vec3f& shift); std::optional removeWater(const osg::Vec2i& cellPosition); diff --git a/components/detournavigator/settingsutils.hpp b/components/detournavigator/settingsutils.hpp index 245e4a7e56..cbd0205e7f 100644 --- a/components/detournavigator/settingsutils.hpp +++ b/components/detournavigator/settingsutils.hpp @@ -82,12 +82,12 @@ namespace DetourNavigator return - settings.mSwimHeightScale * agentHalfExtentsZ; } - inline btTransform getSwimLevelTransform(const Settings& settings, const btTransform& transform, + inline btTransform getSwimLevelTransform(const Settings& settings, const osg::Vec3f& shift, const float agentHalfExtentsZ) { return btTransform( - transform.getBasis(), - transform.getOrigin() + btVector3(0, 0, getSwimLevel(settings, agentHalfExtentsZ) - agentHalfExtentsZ) + btMatrix3x3::getIdentity(), + btVector3(shift.x(), shift.y(), shift.z() + getSwimLevel(settings, agentHalfExtentsZ) - agentHalfExtentsZ) ); } diff --git a/components/detournavigator/tilecachedrecastmeshmanager.cpp b/components/detournavigator/tilecachedrecastmeshmanager.cpp index c19e43c498..15851d7daa 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.cpp @@ -54,7 +54,7 @@ namespace DetourNavigator } bool TileCachedRecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize, - const btTransform& transform) + const osg::Vec3f& shift) { const auto border = getBorderSize(mSettings); @@ -67,7 +67,7 @@ namespace DetourNavigator const auto tiles = mTiles.lock(); for (auto& tile : *tiles) { - if (tile.second.addWater(cellPosition, cellSize, transform)) + if (tile.second.addWater(cellPosition, cellSize, shift)) { tilesPositions.push_back(tile.first); result = true; @@ -76,7 +76,7 @@ namespace DetourNavigator } else { - getTilesPositions(cellSize, transform, mSettings, [&] (const TilePosition& tilePosition) + getTilesPositions(cellSize, shift, mSettings, [&] (const TilePosition& tilePosition) { const auto tiles = mTiles.lock(); auto tile = tiles->find(tilePosition); @@ -88,7 +88,7 @@ namespace DetourNavigator tile = tiles->insert(std::make_pair(tilePosition, CachedRecastMeshManager(mSettings, tileBounds, mTilesGeneration))).first; } - if (tile->second.addWater(cellPosition, cellSize, transform)) + if (tile->second.addWater(cellPosition, cellSize, shift)) { tilesPositions.push_back(tilePosition); result = true; diff --git a/components/detournavigator/tilecachedrecastmeshmanager.hpp b/components/detournavigator/tilecachedrecastmeshmanager.hpp index 087e3e1f36..2c0faeca7d 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.hpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.hpp @@ -76,7 +76,7 @@ namespace DetourNavigator std::optional removeObject(const ObjectId id); - bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btTransform& transform); + bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const osg::Vec3f& shift); std::optional removeWater(const osg::Vec2i& cellPosition); From 5d6c93566ddeb15fe7398583ce90853cca3e2299 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 14 Jul 2021 22:00:16 +0200 Subject: [PATCH 08/12] Rename DetourNavigator::Water -> Cell --- .../detournavigator/navmeshtilescache.cpp | 4 +-- .../detournavigator/navmeshtilescache.cpp | 28 +++++++++---------- .../detournavigator/recastmeshbuilder.cpp | 8 +++--- .../tilecachedrecastmeshmanager.cpp | 2 +- .../cachedrecastmeshmanager.cpp | 2 +- .../cachedrecastmeshmanager.hpp | 2 +- components/detournavigator/makenavmesh.cpp | 6 ++-- components/detournavigator/navmeshmanager.cpp | 2 +- .../detournavigator/navmeshtilescache.hpp | 2 +- components/detournavigator/recastmesh.cpp | 2 +- components/detournavigator/recastmesh.hpp | 16 +++++------ .../detournavigator/recastmeshbuilder.cpp | 2 +- .../detournavigator/recastmeshbuilder.hpp | 2 +- .../detournavigator/recastmeshmanager.cpp | 8 +++--- .../detournavigator/recastmeshmanager.hpp | 4 +-- .../tilecachedrecastmeshmanager.cpp | 4 +-- .../tilecachedrecastmeshmanager.hpp | 2 +- 17 files changed, 48 insertions(+), 48 deletions(-) diff --git a/apps/benchmarks/detournavigator/navmeshtilescache.cpp b/apps/benchmarks/detournavigator/navmeshtilescache.cpp index c6e6ecbdbc..70ffdde3c9 100644 --- a/apps/benchmarks/detournavigator/navmeshtilescache.cpp +++ b/apps/benchmarks/detournavigator/navmeshtilescache.cpp @@ -83,7 +83,7 @@ namespace std::uniform_real_distribution distribution(0.0, 1.0); std::generate_n(out, count, [&] { const osg::Vec3f shift(distribution(random), distribution(random), distribution(random)); - return Water {1, shift}; + return Cell {1, shift}; }); } @@ -108,7 +108,7 @@ namespace const std::size_t generation = std::uniform_int_distribution(0, 100)(random); const std::size_t revision = std::uniform_int_distribution(0, 10000)(random); Mesh mesh = generateMesh(triangles, random); - std::vector water; + std::vector water; generateWater(std::back_inserter(water), 2, random); 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 c9c2a6528b..8c66f1a3ef 100644 --- a/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp +++ b/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp @@ -143,12 +143,12 @@ namespace const std::size_t mGeneration = 0; const std::size_t mRevision = 0; const Mesh mMesh {makeMesh()}; - const std::vector mWater {}; + const std::vector mWater {}; const RecastMesh mRecastMesh {mGeneration, mRevision, mMesh, mWater}; std::unique_ptr mPreparedNavMeshData {makePeparedNavMeshData(3)}; const std::size_t mRecastMeshSize = sizeof(mRecastMesh) + getSize(mRecastMesh); - const std::size_t mRecastMeshWithWaterSize = mRecastMeshSize + sizeof(Water); + const std::size_t mRecastMeshWithWaterSize = mRecastMeshSize + sizeof(Cell); const std::size_t mPreparedNavMeshDataSize = sizeof(*mPreparedNavMeshData) + getSize(*mPreparedNavMeshData); }; @@ -231,7 +231,7 @@ namespace { const std::size_t maxSize = 1; NavMeshTilesCache cache(maxSize); - const std::vector water {1, Water {1, osg::Vec3f()}}; + const std::vector water {1, Cell {1, osg::Vec3f()}}; const RecastMesh unexistentRecastMesh {mGeneration, mRevision, mMesh, water}; cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); @@ -243,7 +243,7 @@ namespace const std::size_t maxSize = mRecastMeshWithWaterSize + mPreparedNavMeshDataSize; NavMeshTilesCache cache(maxSize); - const std::vector water {1, Water {1, osg::Vec3f()}}; + const std::vector water {1, Cell {1, osg::Vec3f()}}; const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water}; auto anotherPreparedNavMeshData = makePeparedNavMeshData(3); const auto copy = clone(*anotherPreparedNavMeshData); @@ -261,7 +261,7 @@ namespace const std::size_t maxSize = mRecastMeshWithWaterSize + mPreparedNavMeshDataSize; NavMeshTilesCache cache(maxSize); - const std::vector water {1, Water {1, osg::Vec3f()}}; + const std::vector water {1, Cell {1, osg::Vec3f()}}; const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water}; auto anotherPreparedNavMeshData = makePeparedNavMeshData(3); @@ -277,11 +277,11 @@ namespace NavMeshTilesCache cache(maxSize); const auto copy = clone(*mPreparedNavMeshData); - const std::vector leastRecentlySetWater {1, Water {1, osg::Vec3f()}}; + const std::vector leastRecentlySetWater {1, Cell {1, osg::Vec3f()}}; const RecastMesh leastRecentlySetRecastMesh {mGeneration, mRevision, mMesh, leastRecentlySetWater}; auto leastRecentlySetData = makePeparedNavMeshData(3); - const std::vector mostRecentlySetWater {1, Water {2, osg::Vec3f()}}; + const std::vector mostRecentlySetWater {1, Cell {2, osg::Vec3f()}}; const RecastMesh mostRecentlySetRecastMesh {mGeneration, mRevision, mMesh, mostRecentlySetWater}; auto mostRecentlySetData = makePeparedNavMeshData(3); @@ -303,12 +303,12 @@ namespace const std::size_t maxSize = 2 * (mRecastMeshWithWaterSize + mPreparedNavMeshDataSize); NavMeshTilesCache cache(maxSize); - const std::vector leastRecentlyUsedWater {1, Water {1, osg::Vec3f()}}; + const std::vector leastRecentlyUsedWater {1, Cell {1, osg::Vec3f()}}; const RecastMesh leastRecentlyUsedRecastMesh {mGeneration, mRevision, mMesh, leastRecentlyUsedWater}; auto leastRecentlyUsedData = makePeparedNavMeshData(3); const auto leastRecentlyUsedCopy = clone(*leastRecentlyUsedData); - const std::vector mostRecentlyUsedWater {1, Water {2, osg::Vec3f()}}; + const std::vector mostRecentlyUsedWater {1, Cell {2, osg::Vec3f()}}; const RecastMesh mostRecentlyUsedRecastMesh {mGeneration, mRevision, mMesh, mostRecentlyUsedWater}; auto mostRecentlyUsedData = makePeparedNavMeshData(3); const auto mostRecentlyUsedCopy = clone(*mostRecentlyUsedData); @@ -342,7 +342,7 @@ namespace const std::size_t maxSize = 2 * (mRecastMeshWithWaterSize + mPreparedNavMeshDataSize); NavMeshTilesCache cache(maxSize); - const std::vector water {1, Water {1, osg::Vec3f()}}; + const std::vector water {1, Cell {1, osg::Vec3f()}}; const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mMesh, water}; auto tooLargeData = makePeparedNavMeshData(10); @@ -356,11 +356,11 @@ namespace const std::size_t maxSize = 2 * (mRecastMeshWithWaterSize + mPreparedNavMeshDataSize); NavMeshTilesCache cache(maxSize); - const std::vector anotherWater {1, Water {1, osg::Vec3f()}}; + const std::vector anotherWater {1, Cell {1, osg::Vec3f()}}; const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, anotherWater}; auto anotherData = makePeparedNavMeshData(3); - const std::vector tooLargeWater {1, Water {2, osg::Vec3f()}}; + const std::vector tooLargeWater {1, Cell {2, osg::Vec3f()}}; const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mMesh, tooLargeWater}; auto tooLargeData = makePeparedNavMeshData(10); @@ -380,7 +380,7 @@ namespace const std::size_t maxSize = mRecastMeshWithWaterSize + mPreparedNavMeshDataSize; NavMeshTilesCache cache(maxSize); - const std::vector water {1, Water {1, osg::Vec3f()}}; + const std::vector water {1, Cell {1, osg::Vec3f()}}; const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water}; auto anotherData = makePeparedNavMeshData(3); @@ -399,7 +399,7 @@ namespace const std::size_t maxSize = mRecastMeshWithWaterSize + mPreparedNavMeshDataSize; NavMeshTilesCache cache(maxSize); - const std::vector water {1, Water {1, osg::Vec3f()}}; + const std::vector water {1, Cell {1, osg::Vec3f()}}; const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water}; auto anotherData = makePeparedNavMeshData(3); diff --git a/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp b/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp index ac565e36c0..b6478f9ea6 100644 --- a/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp +++ b/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp @@ -19,9 +19,9 @@ namespace DetourNavigator { - static inline bool operator ==(const Water& lhs, const Water& rhs) + static inline bool operator ==(const Cell& lhs, const Cell& rhs) { - return lhs.mCellSize == rhs.mCellSize && lhs.mShift == rhs.mShift; + return lhs.mSize == rhs.mSize && lhs.mShift == rhs.mShift; } } @@ -404,8 +404,8 @@ namespace RecastMeshBuilder builder(mBounds); builder.addWater(1000, osg::Vec3f(100, 200, 300)); const auto recastMesh = std::move(builder).create(mGeneration, mRevision); - EXPECT_EQ(recastMesh->getWater(), std::vector({ - Water {1000, osg::Vec3f(100, 200, 300)} + EXPECT_EQ(recastMesh->getWater(), std::vector({ + Cell {1000, osg::Vec3f(100, 200, 300)} })); } diff --git a/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp index 59938ad2be..cb1f04b8b0 100644 --- a/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp @@ -295,7 +295,7 @@ namespace ASSERT_TRUE(manager.addWater(cellPosition, cellSize, osg::Vec3f())); const auto result = manager.removeWater(cellPosition); ASSERT_TRUE(result.has_value()); - EXPECT_EQ(result->mCellSize, cellSize); + EXPECT_EQ(result->mSize, cellSize); } TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, remove_water_for_existing_cell_should_remove_empty_tiles) diff --git a/components/detournavigator/cachedrecastmeshmanager.cpp b/components/detournavigator/cachedrecastmeshmanager.cpp index 1242b32318..cfbb77f238 100644 --- a/components/detournavigator/cachedrecastmeshmanager.cpp +++ b/components/detournavigator/cachedrecastmeshmanager.cpp @@ -42,7 +42,7 @@ namespace DetourNavigator return true; } - std::optional CachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition) + std::optional CachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition) { const auto water = mImpl.removeWater(cellPosition); if (water) diff --git a/components/detournavigator/cachedrecastmeshmanager.hpp b/components/detournavigator/cachedrecastmeshmanager.hpp index 247775e3e7..83eb5c1ec3 100644 --- a/components/detournavigator/cachedrecastmeshmanager.hpp +++ b/components/detournavigator/cachedrecastmeshmanager.hpp @@ -18,7 +18,7 @@ namespace DetourNavigator bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const osg::Vec3f& shift); - std::optional removeWater(const osg::Vec2i& cellPosition); + std::optional removeWater(const osg::Vec2i& cellPosition); std::optional removeObject(const ObjectId id); diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index ba1e93f50e..9c0f726540 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -34,10 +34,10 @@ namespace osg::Vec3f mMax; }; - WaterBounds getWaterBounds(const Water& water, const Settings& settings, + WaterBounds getWaterBounds(const Cell& water, const Settings& settings, const osg::Vec3f& agentHalfExtents) { - if (water.mCellSize == std::numeric_limits::max()) + if (water.mSize == std::numeric_limits::max()) { const auto transform = getSwimLevelTransform(settings, water.mShift, agentHalfExtents.z()); const auto min = toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(-1, -1, 0)))); @@ -50,7 +50,7 @@ namespace else { const auto transform = getSwimLevelTransform(settings, water.mShift, agentHalfExtents.z()); - const auto halfCellSize = water.mCellSize / 2.0f; + const auto halfCellSize = water.mSize / 2.0f; return WaterBounds { toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(-halfCellSize, -halfCellSize, 0)))), toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(halfCellSize, halfCellSize, 0)))) diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index 767dfd59aa..f2dd814d46 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -85,7 +85,7 @@ namespace DetourNavigator const auto water = mRecastMeshManager.removeWater(cellPosition); if (!water) return false; - addChangedTiles(water->mCellSize, water->mShift, ChangeType::remove); + addChangedTiles(water->mSize, water->mShift, ChangeType::remove); return true; } diff --git a/components/detournavigator/navmeshtilescache.hpp b/components/detournavigator/navmeshtilescache.hpp index 974420c158..d218ffdcee 100644 --- a/components/detournavigator/navmeshtilescache.hpp +++ b/components/detournavigator/navmeshtilescache.hpp @@ -23,7 +23,7 @@ namespace DetourNavigator struct RecastMeshData { Mesh mMesh; - std::vector mWater; + std::vector mWater; }; inline bool operator <(const RecastMeshData& lhs, const RecastMeshData& rhs) diff --git a/components/detournavigator/recastmesh.cpp b/components/detournavigator/recastmesh.cpp index 354be8207b..bf7a97caa8 100644 --- a/components/detournavigator/recastmesh.cpp +++ b/components/detournavigator/recastmesh.cpp @@ -18,7 +18,7 @@ namespace DetourNavigator mAreaTypes = std::move(areaTypes); } - RecastMesh::RecastMesh(std::size_t generation, std::size_t revision, Mesh mesh, std::vector water) + RecastMesh::RecastMesh(std::size_t generation, std::size_t revision, Mesh mesh, std::vector water) : mGeneration(generation) , mRevision(revision) , mMesh(std::move(mesh)) diff --git a/components/detournavigator/recastmesh.hpp b/components/detournavigator/recastmesh.hpp index c1d01e48fd..f316abf653 100644 --- a/components/detournavigator/recastmesh.hpp +++ b/components/detournavigator/recastmesh.hpp @@ -45,16 +45,16 @@ namespace DetourNavigator } }; - struct Water + struct Cell { - int mCellSize; + int mSize; osg::Vec3f mShift; }; class RecastMesh { public: - RecastMesh(std::size_t generation, std::size_t revision, Mesh mesh, std::vector water); + RecastMesh(std::size_t generation, std::size_t revision, Mesh mesh, std::vector water); std::size_t getGeneration() const { @@ -68,7 +68,7 @@ namespace DetourNavigator const Mesh& getMesh() const noexcept { return mMesh; } - const std::vector& getWater() const + const std::vector& getWater() const { return mWater; } @@ -82,7 +82,7 @@ namespace DetourNavigator std::size_t mGeneration; std::size_t mRevision; Mesh mMesh; - std::vector mWater; + std::vector mWater; Bounds mBounds; friend inline bool operator <(const RecastMesh& lhs, const RecastMesh& rhs) noexcept @@ -92,13 +92,13 @@ namespace DetourNavigator friend inline std::size_t getSize(const RecastMesh& value) noexcept { - return getSize(value.mMesh) + value.mWater.size() * sizeof(Water); + return getSize(value.mMesh) + value.mWater.size() * sizeof(Cell); } }; - inline bool operator<(const Water& lhs, const Water& rhs) noexcept + inline bool operator<(const Cell& lhs, const Cell& rhs) noexcept { - return std::tie(lhs.mCellSize, lhs.mShift) < std::tie(rhs.mCellSize, rhs.mShift); + return std::tie(lhs.mSize, lhs.mShift) < std::tie(rhs.mSize, rhs.mShift); } } diff --git a/components/detournavigator/recastmeshbuilder.cpp b/components/detournavigator/recastmeshbuilder.cpp index 1b2b5b08cd..b47d823199 100644 --- a/components/detournavigator/recastmeshbuilder.cpp +++ b/components/detournavigator/recastmeshbuilder.cpp @@ -160,7 +160,7 @@ namespace DetourNavigator void RecastMeshBuilder::addWater(const int cellSize, const osg::Vec3f& shift) { - mWater.push_back(Water {cellSize, shift}); + mWater.push_back(Cell {cellSize, shift}); } std::shared_ptr RecastMeshBuilder::create(std::size_t generation, std::size_t revision) && diff --git a/components/detournavigator/recastmeshbuilder.hpp b/components/detournavigator/recastmeshbuilder.hpp index 95dfc9cb52..d08ff94418 100644 --- a/components/detournavigator/recastmeshbuilder.hpp +++ b/components/detournavigator/recastmeshbuilder.hpp @@ -56,7 +56,7 @@ namespace DetourNavigator private: const TileBounds mBounds; std::vector mTriangles; - std::vector mWater; + std::vector mWater; void addObject(const btConcaveShape& shape, const btTransform& transform, btTriangleCallback&& callback); diff --git a/components/detournavigator/recastmeshmanager.cpp b/components/detournavigator/recastmeshmanager.cpp index 336ecf3fe5..e8ecee6027 100644 --- a/components/detournavigator/recastmeshmanager.cpp +++ b/components/detournavigator/recastmeshmanager.cpp @@ -49,19 +49,19 @@ namespace DetourNavigator bool RecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize, const osg::Vec3f& shift) { - if (!mWater.emplace(cellPosition, Water {cellSize, shift}).second) + if (!mWater.emplace(cellPosition, Cell {cellSize, shift}).second) return false; ++mRevision; return true; } - std::optional RecastMeshManager::removeWater(const osg::Vec2i& cellPosition) + std::optional RecastMeshManager::removeWater(const osg::Vec2i& cellPosition) { const auto water = mWater.find(cellPosition); if (water == mWater.end()) return std::nullopt; ++mRevision; - const Water result = water->second; + const Cell result = water->second; mWater.erase(water); return result; } @@ -73,7 +73,7 @@ namespace DetourNavigator tileBounds.mMax /= mSettings.mRecastScaleFactor; RecastMeshBuilder builder(tileBounds); for (const auto& [k, v] : mWater) - builder.addWater(v.mCellSize, v.mShift); + builder.addWater(v.mSize, v.mShift); for (const auto& [k, object] : mObjects) { const RecastMeshObject& v = object.getImpl(); diff --git a/components/detournavigator/recastmeshmanager.hpp b/components/detournavigator/recastmeshmanager.hpp index bcb716353a..266d6a9385 100644 --- a/components/detournavigator/recastmeshmanager.hpp +++ b/components/detournavigator/recastmeshmanager.hpp @@ -39,7 +39,7 @@ namespace DetourNavigator bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const osg::Vec3f& shift); - std::optional removeWater(const osg::Vec2i& cellPosition); + std::optional removeWater(const osg::Vec2i& cellPosition); std::optional removeObject(const ObjectId id); @@ -63,7 +63,7 @@ namespace DetourNavigator std::size_t mGeneration; TileBounds mTileBounds; std::map mObjects; - std::map mWater; + std::map mWater; std::optional mLastNavMeshReportedChange; std::optional mLastNavMeshReport; }; diff --git a/components/detournavigator/tilecachedrecastmeshmanager.cpp b/components/detournavigator/tilecachedrecastmeshmanager.cpp index 15851d7daa..1292e31d4e 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.cpp @@ -102,12 +102,12 @@ namespace DetourNavigator return result; } - std::optional TileCachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition) + std::optional TileCachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition) { const auto object = mWaterTilesPositions.find(cellPosition); if (object == mWaterTilesPositions.end()) return std::nullopt; - std::optional result; + std::optional result; for (const auto& tilePosition : object->second) { const auto tiles = mTiles.lock(); diff --git a/components/detournavigator/tilecachedrecastmeshmanager.hpp b/components/detournavigator/tilecachedrecastmeshmanager.hpp index 2c0faeca7d..4ea705f4cd 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.hpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.hpp @@ -78,7 +78,7 @@ namespace DetourNavigator bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const osg::Vec3f& shift); - std::optional removeWater(const osg::Vec2i& cellPosition); + std::optional removeWater(const osg::Vec2i& cellPosition); std::shared_ptr getMesh(const TilePosition& tilePosition); From 24b802b3d8683513006674f0c304f631606932ad Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 16 Jul 2021 00:09:05 +0200 Subject: [PATCH 09/12] Simplify adding water to recast mesh Remove redundant computations and conversions. --- components/detournavigator/makenavmesh.cpp | 81 ++++++++++---------- components/detournavigator/settingsutils.hpp | 18 ++--- 2 files changed, 46 insertions(+), 53 deletions(-) diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index 9c0f726540..797d73667b 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -28,32 +28,35 @@ namespace { using namespace DetourNavigator; - struct WaterBounds + struct Rectangle { - osg::Vec3f mMin; - osg::Vec3f mMax; + TileBounds mBounds; + float mHeight; }; - WaterBounds getWaterBounds(const Cell& water, const Settings& settings, + Rectangle getSwimRectangle(const Cell& water, const Settings& settings, const osg::Vec3f& agentHalfExtents) { if (water.mSize == std::numeric_limits::max()) { - const auto transform = getSwimLevelTransform(settings, water.mShift, agentHalfExtents.z()); - const auto min = toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(-1, -1, 0)))); - const auto max = toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(1, 1, 0)))); - return WaterBounds { - osg::Vec3f(-std::numeric_limits::max(), min.y(), -std::numeric_limits::max()), - osg::Vec3f(std::numeric_limits::max(), max.y(), std::numeric_limits::max()) + return Rectangle { + TileBounds { + osg::Vec2f(-std::numeric_limits::max(), -std::numeric_limits::max()), + osg::Vec2f(std::numeric_limits::max(), std::numeric_limits::max()) + }, + toNavMeshCoordinates(settings, getSwimLevel(settings, water.mShift.z(), agentHalfExtents.z())) }; } else { - const auto transform = getSwimLevelTransform(settings, water.mShift, agentHalfExtents.z()); - const auto halfCellSize = water.mSize / 2.0f; - return WaterBounds { - toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(-halfCellSize, -halfCellSize, 0)))), - toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(halfCellSize, halfCellSize, 0)))) + const osg::Vec2f shift(water.mShift.x(), water.mShift.y()); + const float halfCellSize = water.mSize / 2.0f; + return Rectangle { + TileBounds{ + toNavMeshCoordinates(settings, shift + osg::Vec2f(-halfCellSize, -halfCellSize)), + toNavMeshCoordinates(settings, shift + osg::Vec2f(halfCellSize, halfCellSize)) + }, + toNavMeshCoordinates(settings, getSwimLevel(settings, water.mShift.z(), agentHalfExtents.z())) }; } } @@ -192,49 +195,43 @@ namespace ); } - void rasterizeWaterTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh, + void rasterizeWaterTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const std::vector& cells, const Settings& settings, const rcConfig& config, rcHeightfield& solid) { const std::array areas {{AreaType_water, AreaType_water}}; - for (const auto& water : recastMesh.getWater()) + for (const Cell& cell : cells) { - const auto bounds = getWaterBounds(water, settings, agentHalfExtents); + const auto rectangle = getSwimRectangle(cell, settings, agentHalfExtents); const osg::Vec2f tileBoundsMin( - std::min(config.bmax[0], std::max(config.bmin[0], bounds.mMin.x())), - std::min(config.bmax[2], std::max(config.bmin[2], bounds.mMin.z())) + std::min(config.bmax[0], std::max(config.bmin[0], rectangle.mBounds.mMin.x())), + std::min(config.bmax[2], std::max(config.bmin[2], rectangle.mBounds.mMin.y())) ); const osg::Vec2f tileBoundsMax( - std::min(config.bmax[0], std::max(config.bmin[0], bounds.mMax.x())), - std::min(config.bmax[2], std::max(config.bmin[2], bounds.mMax.z())) + std::min(config.bmax[0], std::max(config.bmin[0], rectangle.mBounds.mMax.x())), + std::min(config.bmax[2], std::max(config.bmin[2], rectangle.mBounds.mMax.y())) ); if (tileBoundsMax == tileBoundsMin) continue; - const std::array vertices {{ - osg::Vec3f(tileBoundsMin.x(), bounds.mMin.y(), tileBoundsMin.y()), - osg::Vec3f(tileBoundsMin.x(), bounds.mMin.y(), tileBoundsMax.y()), - osg::Vec3f(tileBoundsMax.x(), bounds.mMin.y(), tileBoundsMax.y()), - osg::Vec3f(tileBoundsMax.x(), bounds.mMin.y(), tileBoundsMin.y()), - }}; + const std::array vertices { + tileBoundsMin.x(), rectangle.mHeight, tileBoundsMin.y(), + tileBoundsMin.x(), rectangle.mHeight, tileBoundsMax.y(), + tileBoundsMax.x(), rectangle.mHeight, tileBoundsMax.y(), + tileBoundsMax.x(), rectangle.mHeight, tileBoundsMin.y(), + }; - std::array convertedVertices; - auto convertedVerticesIt = convertedVertices.begin(); - - for (const auto& vertex : vertices) - convertedVerticesIt = std::copy(vertex.ptr(), vertex.ptr() + 3, convertedVerticesIt); - - const std::array indices {{ + const std::array indices { 0, 1, 2, 0, 2, 3, - }}; + }; const auto trianglesRasterized = rcRasterizeTriangles( &context, - convertedVertices.data(), - static_cast(convertedVertices.size() / 3), + vertices.data(), + static_cast(vertices.size() / 3), indices.data(), areas.data(), static_cast(areas.size()), @@ -253,7 +250,7 @@ namespace if (!rasterizeTriangles(context, recastMesh.getMesh(), settings, config, solid)) return false; - rasterizeWaterTriangles(context, agentHalfExtents, recastMesh, settings, config, solid); + rasterizeWaterTriangles(context, agentHalfExtents, recastMesh.getWater(), settings, config, solid); return true; } @@ -504,9 +501,9 @@ namespace DetourNavigator for (const auto& water : recastMesh->getWater()) { - const auto waterBounds = getWaterBounds(water, settings, agentHalfExtents); - recastMeshBounds.mMin.y() = std::min(recastMeshBounds.mMin.y(), waterBounds.mMin.y()); - recastMeshBounds.mMax.y() = std::max(recastMeshBounds.mMax.y(), waterBounds.mMax.y()); + const float height = toNavMeshCoordinates(settings, getSwimLevel(settings, water.mShift.z(), agentHalfExtents.z())); + recastMeshBounds.mMin.y() = std::min(recastMeshBounds.mMin.y(), height); + recastMeshBounds.mMax.y() = std::max(recastMeshBounds.mMax.y(), height); } if (isEmpty(recastMeshBounds)) diff --git a/components/detournavigator/settingsutils.hpp b/components/detournavigator/settingsutils.hpp index cbd0205e7f..258eb64c65 100644 --- a/components/detournavigator/settingsutils.hpp +++ b/components/detournavigator/settingsutils.hpp @@ -37,6 +37,11 @@ namespace DetourNavigator return value * settings.mRecastScaleFactor; } + inline osg::Vec2f toNavMeshCoordinates(const Settings& settings, osg::Vec2f position) + { + return position * settings.mRecastScaleFactor; + } + inline osg::Vec3f toNavMeshCoordinates(const Settings& settings, osg::Vec3f position) { std::swap(position.y(), position.z()); @@ -77,18 +82,9 @@ namespace DetourNavigator return static_cast(settings.mBorderSize) * settings.mCellSize; } - inline float getSwimLevel(const Settings& settings, const float agentHalfExtentsZ) + inline float getSwimLevel(const Settings& settings, const float waterLevel, const float agentHalfExtentsZ) { - return - settings.mSwimHeightScale * agentHalfExtentsZ; - } - - inline btTransform getSwimLevelTransform(const Settings& settings, const osg::Vec3f& shift, - const float agentHalfExtentsZ) - { - return btTransform( - btMatrix3x3::getIdentity(), - btVector3(shift.x(), shift.y(), shift.z() + getSwimLevel(settings, agentHalfExtentsZ) - agentHalfExtentsZ) - ); + return waterLevel - settings.mSwimHeightScale * agentHalfExtentsZ - agentHalfExtentsZ;; } inline float getRealTileSize(const Settings& settings) From fdee9db20c4cd2b281b7c17359844a169cd67f45 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 17 Jul 2021 13:32:57 +0200 Subject: [PATCH 10/12] Consider RecastMeshManager not empty when there is water --- .../tilecachedrecastmeshmanager.cpp | 14 ++++++++++++++ components/detournavigator/recastmeshmanager.cpp | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp index cb1f04b8b0..4c49e75dc9 100644 --- a/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp @@ -323,4 +323,18 @@ namespace for (int y = -6; y < 6; ++y) ASSERT_EQ(manager.hasTile(TilePosition(x, y)), -1 <= x && x <= 0 && -1 <= y && y <= 0); } + + TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, remove_object_should_not_remove_tile_with_water) + { + TileCachedRecastMeshManager manager(mSettings); + const osg::Vec2i cellPosition(0, 0); + const int cellSize = 8192; + const btBoxShape boxShape(btVector3(20, 20, 100)); + ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), boxShape, btTransform::getIdentity(), AreaType::AreaType_ground)); + ASSERT_TRUE(manager.addWater(cellPosition, cellSize, osg::Vec3f())); + ASSERT_TRUE(manager.removeObject(ObjectId(&boxShape))); + for (int x = -6; x < 6; ++x) + for (int y = -6; y < 6; ++y) + ASSERT_TRUE(manager.hasTile(TilePosition(x, y))); + } } diff --git a/components/detournavigator/recastmeshmanager.cpp b/components/detournavigator/recastmeshmanager.cpp index e8ecee6027..a6798ee8cd 100644 --- a/components/detournavigator/recastmeshmanager.cpp +++ b/components/detournavigator/recastmeshmanager.cpp @@ -84,7 +84,7 @@ namespace DetourNavigator bool RecastMeshManager::isEmpty() const { - return mObjects.empty(); + return mObjects.empty() && mWater.empty(); } void RecastMeshManager::reportNavMeshChange(const Version& recastMeshVersion, const Version& navMeshVersion) From 28b2f769c28116ef30f6ca8cf3c65dfe411917aa Mon Sep 17 00:00:00 2001 From: elsid Date: Mon, 19 Jul 2021 18:26:38 +0200 Subject: [PATCH 11/12] Update navmeshtilescache benchmark generators --- apps/benchmarks/detournavigator/navmeshtilescache.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/benchmarks/detournavigator/navmeshtilescache.cpp b/apps/benchmarks/detournavigator/navmeshtilescache.cpp index 70ffdde3c9..e31514afaf 100644 --- a/apps/benchmarks/detournavigator/navmeshtilescache.cpp +++ b/apps/benchmarks/detournavigator/navmeshtilescache.cpp @@ -94,8 +94,8 @@ namespace 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); + generateVertices(std::back_inserter(vertices), triangles * 1.946, random); + generateIndices(std::back_inserter(indices), static_cast(vertices.size() / 3) - 1, vertices.size() * 1.545, random); generateAreaTypes(std::back_inserter(areaTypes), indices.size() / 3, random); return Mesh(std::move(indices), std::move(vertices), std::move(areaTypes)); } @@ -109,12 +109,12 @@ namespace const std::size_t revision = std::uniform_int_distribution(0, 10000)(random); Mesh mesh = generateMesh(triangles, random); std::vector water; - generateWater(std::back_inserter(water), 2, random); + generateWater(std::back_inserter(water), 1, random); RecastMesh recastMesh(generation, revision, std::move(mesh), std::move(water)); return Key {agentHalfExtents, tilePosition, std::move(recastMesh)}; } - constexpr std::size_t trianglesPerTile = 310; + constexpr std::size_t trianglesPerTile = 438; template void generateKeys(OutputIterator out, std::size_t count, Random& random) From 9a5ec5fd0333375a2376bbb1b56a0472a9889415 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 14 Jul 2021 20:57:52 +0200 Subject: [PATCH 12/12] Store heightfields as array of heights instead of triangles To reduce size of RecastMesh and therefore cache size. --- .../detournavigator/navmeshtilescache.cpp | 51 +++- apps/openmw/mwworld/scene.cpp | 29 ++- .../detournavigator/navigator.cpp | 220 ++++++++++++++---- .../detournavigator/navmeshtilescache.cpp | 35 +-- .../detournavigator/recastmeshbuilder.cpp | 94 ++++++++ .../cachedrecastmeshmanager.cpp | 17 ++ .../cachedrecastmeshmanager.hpp | 8 +- .../detournavigator/heightfieldshape.hpp | 25 ++ components/detournavigator/makenavmesh.cpp | 124 ++++++---- components/detournavigator/navigator.hpp | 8 + components/detournavigator/navigatorimpl.cpp | 12 + components/detournavigator/navigatorimpl.hpp | 5 + components/detournavigator/navigatorstub.hpp | 11 + components/detournavigator/navmeshmanager.cpp | 18 ++ components/detournavigator/navmeshmanager.hpp | 6 + .../detournavigator/navmeshtilescache.cpp | 3 +- .../detournavigator/navmeshtilescache.hpp | 14 +- components/detournavigator/recastmesh.cpp | 27 ++- components/detournavigator/recastmesh.hpp | 55 ++++- .../detournavigator/recastmeshbuilder.cpp | 95 +++++++- .../detournavigator/recastmeshbuilder.hpp | 11 +- .../detournavigator/recastmeshmanager.cpp | 48 +++- .../detournavigator/recastmeshmanager.hpp | 17 +- components/detournavigator/tilebounds.hpp | 22 ++ .../tilecachedrecastmeshmanager.cpp | 62 +++++ .../tilecachedrecastmeshmanager.hpp | 7 + components/sceneutil/recastmesh.cpp | 15 +- 27 files changed, 900 insertions(+), 139 deletions(-) create mode 100644 components/detournavigator/heightfieldshape.hpp diff --git a/apps/benchmarks/detournavigator/navmeshtilescache.cpp b/apps/benchmarks/detournavigator/navmeshtilescache.cpp index e31514afaf..6c530db41c 100644 --- a/apps/benchmarks/detournavigator/navmeshtilescache.cpp +++ b/apps/benchmarks/detournavigator/navmeshtilescache.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include @@ -30,6 +31,14 @@ namespace return TilePosition(distribution(random), distribution(random)); } + template + TileBounds generateTileBounds(Random& random) + { + std::uniform_real_distribution distribution(0.0, 1.0); + const osg::Vec2f min(distribution(random), distribution(random)); + return TileBounds {min, min + osg::Vec2f(1.0, 1.0)}; + } + template osg::Vec3f generateAgentHalfExtents(float min, float max, Random& random) { @@ -94,12 +103,43 @@ namespace std::vector vertices; std::vector indices; std::vector areaTypes; - generateVertices(std::back_inserter(vertices), triangles * 1.946, random); - generateIndices(std::back_inserter(indices), static_cast(vertices.size() / 3) - 1, vertices.size() * 1.545, random); - generateAreaTypes(std::back_inserter(areaTypes), indices.size() / 3, random); + if (distribution(random) < 0.939) + { + generateVertices(std::back_inserter(vertices), triangles * 2.467, random); + generateIndices(std::back_inserter(indices), static_cast(vertices.size() / 3) - 1, vertices.size() * 1.279, random); + generateAreaTypes(std::back_inserter(areaTypes), indices.size() / 3, random); + } return Mesh(std::move(indices), std::move(vertices), std::move(areaTypes)); } + template + Heightfield generateHeightfield(Random& random) + { + std::uniform_real_distribution distribution(0.0, 1.0); + Heightfield result; + result.mBounds = generateTileBounds(random); + result.mMinHeight = distribution(random); + result.mMaxHeight = result.mMinHeight + 1.0; + result.mShift = osg::Vec3f(distribution(random), distribution(random), distribution(random)); + result.mScale = distribution(random); + result.mLength = static_cast(ESM::Land::LAND_SIZE); + std::generate_n(std::back_inserter(result.mHeights), ESM::Land::LAND_NUM_VERTS, [&] + { + return distribution(random); + }); + return result; + } + + template + FlatHeightfield generateFlatHeightfield(Random& random) + { + std::uniform_real_distribution distribution(0.0, 1.0); + FlatHeightfield result; + result.mBounds = generateTileBounds(random); + result.mHeight = distribution(random); + return result; + } + template Key generateKey(std::size_t triangles, Random& random) { @@ -110,11 +150,12 @@ namespace Mesh mesh = generateMesh(triangles, random); std::vector water; generateWater(std::back_inserter(water), 1, random); - RecastMesh recastMesh(generation, revision, std::move(mesh), std::move(water)); + RecastMesh recastMesh(generation, revision, std::move(mesh), std::move(water), + {generateHeightfield(random)}, {generateFlatHeightfield(random)}); return Key {agentHalfExtents, tilePosition, std::move(recastMesh)}; } - constexpr std::size_t trianglesPerTile = 438; + constexpr std::size_t trianglesPerTile = 239; template void generateKeys(OutputIterator out, std::size_t count, Random& random) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 61ef3e1538..1dc0f904bc 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -422,6 +423,8 @@ namespace MWWorld void Scene::activateCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn, bool test) { + using DetourNavigator::HeightfieldShape; + assert(mActiveCells.find(cell) == mActiveCells.end()); assert(mInactiveCells.find(cell) != mInactiveCells.end()); mActiveCells.insert(cell); @@ -439,8 +442,30 @@ namespace MWWorld if (!test && cell->getCell()->isExterior()) { if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) - mNavigator.addObject(DetourNavigator::ObjectId(heightField), *heightField->getShape(), - heightField->getCollisionObject()->getWorldTransform()); + { + const osg::Vec2i cellPosition(cellX, cellY); + const btVector3& origin = heightField->getCollisionObject()->getWorldTransform().getOrigin(); + const osg::Vec3f shift(origin.x(), origin.y(), origin.z()); + const osg::ref_ptr land = mRendering.getLandManager()->getLand(cellX, cellY); + const ESM::Land::LandData* const data = land == nullptr ? nullptr : land->getData(ESM::Land::DATA_VHGT); + const HeightfieldShape shape = [&] () -> HeightfieldShape + { + if (data == nullptr) + { + return DetourNavigator::HeightfieldPlane {static_cast(ESM::Land::DEFAULT_HEIGHT)}; + } + else + { + DetourNavigator::HeightfieldSurface heights; + heights.mHeights = data->mHeights; + heights.mSize = static_cast(ESM::Land::LAND_SIZE); + heights.mMinHeight = data->mMinHeight; + heights.mMaxHeight = data->mMaxHeight; + return heights; + } + } (); + mNavigator.addHeightfield(cellPosition, ESM::Land::REAL_SIZE, shift, shape); + } } if (const auto pathgrid = world->getStore().get().search(*cell->getCell())) diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index b815c50bbe..a75275079b 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -38,6 +39,9 @@ namespace float mStepSize; AreaCosts mAreaCosts; Loading::Listener mListener; + const osg::Vec2i mCellPosition {0, 0}; + const int mHeightfieldTileSize = ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1); + const osg::Vec3f mShift {0, 0, 0}; DetourNavigatorNavigatorTest() : mPlayerPosition(0, 0, 0) @@ -90,6 +94,19 @@ namespace return btHeightfieldTerrainShape(width, width, values.data(), heightScale, -greater, greater, upAxis, heightDataType, flipQuadEdges); } + template + HeightfieldSurface makeSquareHeightfieldSurface(const std::array& values) + { + const auto [min, max] = std::minmax_element(values.begin(), values.end()); + const float greater = std::max(std::abs(*min), std::abs(*max)); + HeightfieldSurface surface; + surface.mHeights = values.data(); + surface.mMinHeight = -greater; + surface.mMaxHeight = greater; + surface.mSize = static_cast(std::sqrt(size)); + return surface; + } + TEST_F(DetourNavigatorNavigatorTest, find_path_for_empty_should_return_empty) { EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), @@ -115,18 +132,17 @@ namespace TEST_F(DetourNavigatorNavigatorTest, update_then_find_path_should_return_path) { - const std::array heightfieldData {{ + constexpr std::array heightfieldData {{ 0, 0, 0, 0, 0, 0, -25, -25, -25, -25, 0, -25, -100, -100, -100, 0, -25, -100, -100, -100, 0, -25, -100, -100, -100, }}; - btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData); - shape.setLocalScaling(btVector3(128, 128, 1)); + const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); mNavigator->addAgent(mAgentHalfExtents); - mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); + mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::requiredTilesPresent); @@ -160,22 +176,21 @@ namespace TEST_F(DetourNavigatorNavigatorTest, add_object_should_change_navmesh) { - const std::array heightfieldData {{ + const std::array heightfieldData {{ 0, 0, 0, 0, 0, 0, -25, -25, -25, -25, 0, -25, -100, -100, -100, 0, -25, -100, -100, -100, 0, -25, -100, -100, -100, }}; - btHeightfieldTerrainShape heightfieldShape = makeSquareHeightfieldTerrainShape(heightfieldData); - heightfieldShape.setLocalScaling(btVector3(128, 128, 1)); + const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); btBoxShape boxShape(btVector3(20, 20, 100)); btCompoundShape compoundShape; compoundShape.addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), &boxShape); mNavigator->addAgent(mAgentHalfExtents); - mNavigator->addObject(ObjectId(&heightfieldShape), heightfieldShape, btTransform::getIdentity()); + mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -243,22 +258,21 @@ namespace TEST_F(DetourNavigatorNavigatorTest, update_changed_object_should_change_navmesh) { - const std::array heightfieldData {{ + const std::array heightfieldData {{ 0, 0, 0, 0, 0, 0, -25, -25, -25, -25, 0, -25, -100, -100, -100, 0, -25, -100, -100, -100, 0, -25, -100, -100, -100, }}; - btHeightfieldTerrainShape heightfieldShape = makeSquareHeightfieldTerrainShape(heightfieldData); - heightfieldShape.setLocalScaling(btVector3(128, 128, 1)); + const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); btBoxShape boxShape(btVector3(20, 20, 100)); btCompoundShape compoundShape; compoundShape.addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), &boxShape); mNavigator->addAgent(mAgentHalfExtents); - mNavigator->addObject(ObjectId(&heightfieldShape), heightfieldShape, btTransform::getIdentity()); + mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); mNavigator->addObject(ObjectId(&compoundShape), compoundShape, btTransform::getIdentity()); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -327,16 +341,16 @@ namespace )) << mPath; } - TEST_F(DetourNavigatorNavigatorTest, for_overlapping_heightfields_should_use_higher) + TEST_F(DetourNavigatorNavigatorTest, for_overlapping_heightfields_objects_should_use_higher) { - const std::array heightfieldData {{ + const std::array heightfieldData1 {{ 0, 0, 0, 0, 0, 0, -25, -25, -25, -25, 0, -25, -100, -100, -100, 0, -25, -100, -100, -100, 0, -25, -100, -100, -100, }}; - btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData); + btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData1); shape.setLocalScaling(btVector3(128, 128, 1)); const std::array heightfieldData2 {{ @@ -383,6 +397,31 @@ namespace )) << mPath; } + TEST_F(DetourNavigatorNavigatorTest, only_one_heightfield_per_cell_is_allowed) + { + const std::array heightfieldData1 {{ + 0, 0, 0, 0, 0, + 0, -25, -25, -25, -25, + 0, -25, -100, -100, -100, + 0, -25, -100, -100, -100, + 0, -25, -100, -100, -100, + }}; + const HeightfieldSurface surface1 = makeSquareHeightfieldSurface(heightfieldData1); + + const std::array heightfieldData2 {{ + -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, + }}; + const HeightfieldSurface surface2 = makeSquareHeightfieldSurface(heightfieldData2); + + mNavigator->addAgent(mAgentHalfExtents); + EXPECT_TRUE(mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface1.mSize - 1), mShift, surface1)); + EXPECT_FALSE(mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface2.mSize - 1), mShift, surface2)); + } + TEST_F(DetourNavigatorNavigatorTest, path_should_be_around_avoid_shape) { std::array heightfieldData {{ @@ -441,19 +480,18 @@ namespace TEST_F(DetourNavigatorNavigatorTest, path_should_be_over_water_ground_lower_than_water_with_only_swim_flag) { - std::array heightfieldData {{ + std::array heightfieldData {{ -50, -50, -50, -50, 0, -50, -100, -150, -100, -50, -50, -150, -200, -150, -100, -50, -100, -150, -100, -100, 0, -50, -100, -100, -100, }}; - btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData); - shape.setLocalScaling(btVector3(128, 128, 1)); + const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); mNavigator->addAgent(mAgentHalfExtents); mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, osg::Vec3f(0, 0, 300)); - mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); + mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -486,7 +524,7 @@ namespace TEST_F(DetourNavigatorNavigatorTest, path_should_be_over_water_when_ground_cross_water_with_swim_and_walk_flags) { - std::array heightfieldData {{ + std::array heightfieldData {{ 0, 0, 0, 0, 0, 0, 0, 0, -100, -100, -100, -100, -100, 0, 0, -100, -150, -150, -150, -100, 0, @@ -495,12 +533,11 @@ namespace 0, -100, -100, -100, -100, -100, 0, 0, 0, 0, 0, 0, 0, 0, }}; - btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData); - shape.setLocalScaling(btVector3(128, 128, 1)); + const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); mNavigator->addAgent(mAgentHalfExtents); - mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, osg::Vec3f(0, 0, -25)); - mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); + mNavigator->addWater(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), osg::Vec3f(0, 0, -25)); + mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -532,7 +569,7 @@ namespace TEST_F(DetourNavigatorNavigatorTest, path_should_be_over_water_when_ground_cross_water_with_max_int_cells_size_and_swim_and_walk_flags) { - std::array heightfieldData {{ + std::array heightfieldData {{ 0, 0, 0, 0, 0, 0, 0, 0, -100, -100, -100, -100, -100, 0, 0, -100, -150, -150, -150, -100, 0, @@ -541,11 +578,10 @@ namespace 0, -100, -100, -100, -100, -100, 0, 0, 0, 0, 0, 0, 0, 0, }}; - btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData); - shape.setLocalScaling(btVector3(128, 128, 1)); + const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); mNavigator->addAgent(mAgentHalfExtents); - mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); + mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); mNavigator->addWater(osg::Vec2i(0, 0), std::numeric_limits::max(), osg::Vec3f(0, 0, -25)); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -578,7 +614,7 @@ namespace TEST_F(DetourNavigatorNavigatorTest, path_should_be_over_ground_when_ground_cross_water_with_only_walk_flag) { - std::array heightfieldData {{ + std::array heightfieldData {{ 0, 0, 0, 0, 0, 0, 0, 0, -100, -100, -100, -100, -100, 0, 0, -100, -150, -150, -150, -100, 0, @@ -587,12 +623,11 @@ namespace 0, -100, -100, -100, -100, -100, 0, 0, 0, 0, 0, 0, 0, 0, }}; - btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData); - shape.setLocalScaling(btVector3(128, 128, 1)); + const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); mNavigator->addAgent(mAgentHalfExtents); mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, osg::Vec3f(0, 0, -25)); - mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); + mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -622,7 +657,7 @@ namespace )) << mPath; } - TEST_F(DetourNavigatorNavigatorTest, update_remove_and_update_then_find_path_should_return_path) + TEST_F(DetourNavigatorNavigatorTest, update_object_remove_and_update_then_find_path_should_return_path) { const std::array heightfieldData {{ 0, 0, 0, 0, 0, @@ -675,20 +710,71 @@ namespace )) << mPath; } - TEST_F(DetourNavigatorNavigatorTest, update_then_find_random_point_around_circle_should_return_position) + TEST_F(DetourNavigatorNavigatorTest, update_heightfield_remove_and_update_then_find_path_should_return_path) { - const std::array heightfieldData {{ + const std::array heightfieldData {{ 0, 0, 0, 0, 0, 0, -25, -25, -25, -25, 0, -25, -100, -100, -100, 0, -25, -100, -100, -100, 0, -25, -100, -100, -100, }}; - btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData); - shape.setLocalScaling(btVector3(128, 128, 1)); + const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); mNavigator->addAgent(mAgentHalfExtents); - mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); + mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); + mNavigator->update(mPlayerPosition); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); + + mNavigator->removeHeightfield(mCellPosition); + mNavigator->update(mPlayerPosition); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); + + mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); + mNavigator->update(mPlayerPosition); + mNavigator->wait(mListener, WaitConditionType::allJobsDone); + + EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); + + EXPECT_THAT(mPath, ElementsAre( + Vec3fEq(-204, 204, 1.99998295307159423828125), + Vec3fEq(-183.965301513671875, 183.965301513671875, 1.99998819828033447265625), + Vec3fEq(-163.9306182861328125, 163.9306182861328125, 1.99999344348907470703125), + Vec3fEq(-143.89593505859375, 143.89593505859375, -2.7206256389617919921875), + Vec3fEq(-123.86124420166015625, 123.86124420166015625, -13.1089839935302734375), + Vec3fEq(-103.8265533447265625, 103.8265533447265625, -23.4973468780517578125), + Vec3fEq(-83.7918548583984375, 83.7918548583984375, -33.885707855224609375), + Vec3fEq(-63.75716400146484375, 63.75716400146484375, -44.27407073974609375), + Vec3fEq(-43.72247314453125, 43.72247314453125, -54.662433624267578125), + Vec3fEq(-23.6877803802490234375, 23.6877803802490234375, -65.0507965087890625), + Vec3fEq(-3.653090000152587890625, 3.653090000152587890625, -75.43915557861328125), + Vec3fEq(16.3816013336181640625, -16.3816013336181640625, -69.749267578125), + Vec3fEq(36.416290283203125, -36.416290283203125, -60.4739532470703125), + Vec3fEq(56.450984954833984375, -56.450984954833984375, -51.1986236572265625), + Vec3fEq(76.4856719970703125, -76.4856719970703125, -41.92330169677734375), + Vec3fEq(96.52036285400390625, -96.52036285400390625, -31.46941375732421875), + Vec3fEq(116.5550537109375, -116.5550537109375, -19.597003936767578125), + Vec3fEq(136.5897369384765625, -136.5897369384765625, -7.724592685699462890625), + Vec3fEq(156.6244354248046875, -156.6244354248046875, 1.99999535083770751953125), + Vec3fEq(176.6591339111328125, -176.6591339111328125, 1.99999010562896728515625), + Vec3fEq(196.693817138671875, -196.693817138671875, 1.99998486042022705078125), + Vec3fEq(204, -204, 1.99998295307159423828125) + )) << mPath; + } + + TEST_F(DetourNavigatorNavigatorTest, update_then_find_random_point_around_circle_should_return_position) + { + const std::array heightfieldData {{ + 0, 0, 0, 0, 0, + 0, -25, -25, -25, -25, + 0, -25, -100, -100, -100, + 0, -25, -100, -100, -100, + 0, -25, -100, -100, -100, + }}; + const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); + + mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -709,21 +795,20 @@ namespace mSettings.mAsyncNavMeshUpdaterThreads = 2; mNavigator.reset(new NavigatorImpl(mSettings)); - const std::array heightfieldData {{ + const std::array heightfieldData {{ 0, 0, 0, 0, 0, 0, -25, -25, -25, -25, 0, -25, -100, -100, -100, 0, -25, -100, -100, -100, 0, -25, -100, -100, -100, }}; - btHeightfieldTerrainShape heightfieldShape = makeSquareHeightfieldTerrainShape(heightfieldData); - heightfieldShape.setLocalScaling(btVector3(128, 128, 1)); + const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const std::vector boxShapes(100, btVector3(20, 20, 100)); mNavigator->addAgent(mAgentHalfExtents); - mNavigator->addObject(ObjectId(&heightfieldShape), heightfieldShape, btTransform::getIdentity()); + mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); for (std::size_t i = 0; i < boxShapes.size(); ++i) { @@ -810,18 +895,17 @@ namespace TEST_F(DetourNavigatorNavigatorTest, update_then_raycast_should_return_position) { - const std::array heightfieldData {{ + const std::array heightfieldData {{ 0, 0, 0, 0, 0, 0, -25, -25, -25, -25, 0, -25, -100, -100, -100, 0, -25, -100, -100, -100, 0, -25, -100, -100, -100, }}; - btHeightfieldTerrainShape shape = makeSquareHeightfieldTerrainShape(heightfieldData); - shape.setLocalScaling(btVector3(128, 128, 1)); + const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); mNavigator->addAgent(mAgentHalfExtents); - mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); + mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); mNavigator->update(mPlayerPosition); mNavigator->wait(mListener, WaitConditionType::allJobsDone); @@ -833,22 +917,21 @@ namespace TEST_F(DetourNavigatorNavigatorTest, update_for_oscillating_object_that_does_not_change_navmesh_should_not_trigger_navmesh_update) { - const std::array heightfieldData {{ + const std::array heightfieldData {{ 0, 0, 0, 0, 0, 0, -25, -25, -25, -25, 0, -25, -100, -100, -100, 0, -25, -100, -100, -100, 0, -25, -100, -100, -100, }}; - btHeightfieldTerrainShape heightfieldShape = makeSquareHeightfieldTerrainShape(heightfieldData); - heightfieldShape.setLocalScaling(btVector3(128, 128, 1)); + const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const btBoxShape oscillatingBoxShape(btVector3(20, 20, 20)); const btVector3 oscillatingBoxShapePosition(32, 32, 400); const btBoxShape boderBoxShape(btVector3(50, 50, 50)); mNavigator->addAgent(mAgentHalfExtents); - mNavigator->addObject(ObjectId(&heightfieldShape), heightfieldShape, btTransform::getIdentity()); + mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * (surface.mSize - 1), mShift, surface); mNavigator->addObject(ObjectId(&oscillatingBoxShape), oscillatingBoxShape, btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition)); // add this box to make navmesh bound box independent from oscillatingBoxShape rotations @@ -881,4 +964,41 @@ namespace ASSERT_EQ(navMesh->getNavMeshRevision(), 4); } } + + TEST_F(DetourNavigatorNavigatorTest, should_provide_path_over_flat_heightfield) + { + const HeightfieldPlane plane {100}; + + mNavigator->addAgent(mAgentHalfExtents); + mNavigator->addHeightfield(mCellPosition, mHeightfieldTileSize * 4, mShift, plane); + mNavigator->update(mPlayerPosition); + mNavigator->wait(mListener, WaitConditionType::requiredTilesPresent); + + EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); + + EXPECT_THAT(mPath, ElementsAre( + Vec3fEq(-204, 204, 101.99999237060546875), + Vec3fEq(-183.965301513671875, 183.965301513671875, 101.99999237060546875), + Vec3fEq(-163.9306182861328125, 163.9306182861328125, 101.99999237060546875), + Vec3fEq(-143.89593505859375, 143.89593505859375, 101.99999237060546875), + Vec3fEq(-123.86124420166015625, 123.86124420166015625, 101.99999237060546875), + Vec3fEq(-103.8265533447265625, 103.8265533447265625, 101.99999237060546875), + Vec3fEq(-83.7918548583984375, 83.7918548583984375, 101.99999237060546875), + Vec3fEq(-63.75716400146484375, 63.75716400146484375, 101.99999237060546875), + Vec3fEq(-43.72247314453125, 43.72247314453125, 101.99999237060546875), + Vec3fEq(-23.6877803802490234375, 23.6877803802490234375, 101.99999237060546875), + Vec3fEq(-3.653090000152587890625, 3.653090000152587890625, 101.99999237060546875), + Vec3fEq(16.3816013336181640625, -16.3816013336181640625, 101.99999237060546875), + Vec3fEq(36.416290283203125, -36.416290283203125, 101.99999237060546875), + Vec3fEq(56.450984954833984375, -56.450984954833984375, 101.99999237060546875), + Vec3fEq(76.4856719970703125, -76.4856719970703125, 101.99999237060546875), + Vec3fEq(96.52036285400390625, -96.52036285400390625, 101.99999237060546875), + Vec3fEq(116.5550537109375, -116.5550537109375, 101.99999237060546875), + Vec3fEq(136.5897369384765625, -136.5897369384765625, 101.99999237060546875), + Vec3fEq(156.6244354248046875, -156.6244354248046875, 101.99999237060546875), + Vec3fEq(176.6591339111328125, -176.6591339111328125, 101.99999237060546875), + Vec3fEq(196.693817138671875, -196.693817138671875, 101.99999237060546875), + Vec3fEq(204, -204, 101.99999237060546875) + )) << mPath; + } } diff --git a/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp b/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp index 8c66f1a3ef..9405bd7739 100644 --- a/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp +++ b/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp @@ -144,7 +144,9 @@ namespace const std::size_t mRevision = 0; const Mesh mMesh {makeMesh()}; const std::vector mWater {}; - const RecastMesh mRecastMesh {mGeneration, mRevision, mMesh, mWater}; + const std::vector mHeightfields {}; + const std::vector mFlatHeightfields {}; + const RecastMesh mRecastMesh {mGeneration, mRevision, mMesh, mWater, mHeightfields, mFlatHeightfields}; std::unique_ptr mPreparedNavMeshData {makePeparedNavMeshData(3)}; const std::size_t mRecastMeshSize = sizeof(mRecastMesh) + getSize(mRecastMesh); @@ -232,7 +234,7 @@ namespace const std::size_t maxSize = 1; NavMeshTilesCache cache(maxSize); const std::vector water {1, Cell {1, osg::Vec3f()}}; - const RecastMesh unexistentRecastMesh {mGeneration, mRevision, mMesh, water}; + const RecastMesh unexistentRecastMesh {mGeneration, mRevision, mMesh, water, mHeightfields, mFlatHeightfields}; cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, unexistentRecastMesh)); @@ -244,7 +246,7 @@ namespace NavMeshTilesCache cache(maxSize); const std::vector water {1, Cell {1, osg::Vec3f()}}; - const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water}; + const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water, mHeightfields, mFlatHeightfields}; auto anotherPreparedNavMeshData = makePeparedNavMeshData(3); const auto copy = clone(*anotherPreparedNavMeshData); @@ -262,7 +264,7 @@ namespace NavMeshTilesCache cache(maxSize); const std::vector water {1, Cell {1, osg::Vec3f()}}; - const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water}; + const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water, mHeightfields, mFlatHeightfields}; auto anotherPreparedNavMeshData = makePeparedNavMeshData(3); const auto value = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, @@ -278,11 +280,13 @@ namespace const auto copy = clone(*mPreparedNavMeshData); const std::vector leastRecentlySetWater {1, Cell {1, osg::Vec3f()}}; - const RecastMesh leastRecentlySetRecastMesh {mGeneration, mRevision, mMesh, leastRecentlySetWater}; + const RecastMesh leastRecentlySetRecastMesh {mGeneration, mRevision, mMesh, leastRecentlySetWater, + mHeightfields, mFlatHeightfields}; auto leastRecentlySetData = makePeparedNavMeshData(3); const std::vector mostRecentlySetWater {1, Cell {2, osg::Vec3f()}}; - const RecastMesh mostRecentlySetRecastMesh {mGeneration, mRevision, mMesh, mostRecentlySetWater}; + const RecastMesh mostRecentlySetRecastMesh {mGeneration, mRevision, mMesh, mostRecentlySetWater, + mHeightfields, mFlatHeightfields}; auto mostRecentlySetData = makePeparedNavMeshData(3); ASSERT_TRUE(cache.set(mAgentHalfExtents, mTilePosition, leastRecentlySetRecastMesh, @@ -304,12 +308,14 @@ namespace NavMeshTilesCache cache(maxSize); const std::vector leastRecentlyUsedWater {1, Cell {1, osg::Vec3f()}}; - const RecastMesh leastRecentlyUsedRecastMesh {mGeneration, mRevision, mMesh, leastRecentlyUsedWater}; + const RecastMesh leastRecentlyUsedRecastMesh {mGeneration, mRevision, mMesh, leastRecentlyUsedWater, + mHeightfields, mFlatHeightfields}; auto leastRecentlyUsedData = makePeparedNavMeshData(3); const auto leastRecentlyUsedCopy = clone(*leastRecentlyUsedData); const std::vector mostRecentlyUsedWater {1, Cell {2, osg::Vec3f()}}; - const RecastMesh mostRecentlyUsedRecastMesh {mGeneration, mRevision, mMesh, mostRecentlyUsedWater}; + const RecastMesh mostRecentlyUsedRecastMesh {mGeneration, mRevision, mMesh, mostRecentlyUsedWater, + mHeightfields, mFlatHeightfields}; auto mostRecentlyUsedData = makePeparedNavMeshData(3); const auto mostRecentlyUsedCopy = clone(*mostRecentlyUsedData); @@ -343,7 +349,8 @@ namespace NavMeshTilesCache cache(maxSize); const std::vector water {1, Cell {1, osg::Vec3f()}}; - const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mMesh, water}; + const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mMesh, water, + mHeightfields, mFlatHeightfields}; auto tooLargeData = makePeparedNavMeshData(10); cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); @@ -357,11 +364,13 @@ namespace NavMeshTilesCache cache(maxSize); const std::vector anotherWater {1, Cell {1, osg::Vec3f()}}; - const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, anotherWater}; + const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, anotherWater, + mHeightfields, mFlatHeightfields}; auto anotherData = makePeparedNavMeshData(3); const std::vector tooLargeWater {1, Cell {2, osg::Vec3f()}}; - const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mMesh, tooLargeWater}; + const RecastMesh tooLargeRecastMesh {mGeneration, mRevision, mMesh, tooLargeWater, + mHeightfields, mFlatHeightfields}; auto tooLargeData = makePeparedNavMeshData(10); const auto value = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, @@ -381,7 +390,7 @@ namespace NavMeshTilesCache cache(maxSize); const std::vector water {1, Cell {1, osg::Vec3f()}}; - const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water}; + const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water, mHeightfields, mFlatHeightfields}; auto anotherData = makePeparedNavMeshData(3); const auto firstCopy = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)); @@ -400,7 +409,7 @@ namespace NavMeshTilesCache cache(maxSize); const std::vector water {1, Cell {1, osg::Vec3f()}}; - const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water}; + const RecastMesh anotherRecastMesh {mGeneration, mRevision, mMesh, water, mHeightfields, mFlatHeightfields}; 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 b6478f9ea6..73d86bd6ee 100644 --- a/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp +++ b/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp @@ -3,12 +3,16 @@ #include #include #include +#include +#include +#include #include #include #include #include #include +#include #include @@ -23,6 +27,35 @@ namespace DetourNavigator { return lhs.mSize == rhs.mSize && lhs.mShift == rhs.mShift; } + + static inline bool operator==(const Heightfield& lhs, const Heightfield& rhs) + { + return makeTuple(lhs) == makeTuple(rhs); + } + + static inline bool operator==(const FlatHeightfield& lhs, const FlatHeightfield& rhs) + { + return std::tie(lhs.mBounds, lhs.mHeight) == std::tie(rhs.mBounds, rhs.mHeight); + } + + static inline std::ostream& operator<<(std::ostream& s, const FlatHeightfield& v) + { + return s << "FlatHeightfield {" << v.mBounds << ", " << v.mHeight << "}"; + } + + static inline std::ostream& operator<<(std::ostream& s, const Heightfield& v) + { + s << "Heightfield {.mBounds=" << v.mBounds + << ", .mLength=" << int(v.mLength) + << ", .mMinHeight=" << v.mMinHeight + << ", .mMaxHeight=" << v.mMaxHeight + << ", .mShift=" << v.mShift + << ", .mScale=" << v.mScale + << ", .mHeights={"; + for (float h : v.mHeights) + s << h << ", "; + return s << "}}"; + } } namespace @@ -428,4 +461,65 @@ namespace EXPECT_EQ(recastMesh->getMesh().getIndices(), std::vector({2, 1, 0, 2, 1, 3})); EXPECT_EQ(recastMesh->getMesh().getAreaTypes(), std::vector({AreaType_ground, AreaType_ground})); } + + TEST_F(DetourNavigatorRecastMeshBuilderTest, add_flat_heightfield_should_add_intersection) + { + mBounds.mMin = osg::Vec2f(0, 0); + RecastMeshBuilder builder(mBounds); + builder.addHeightfield(1000, osg::Vec3f(1, 2, 3), 10); + const auto recastMesh = std::move(builder).create(mGeneration, mRevision); + EXPECT_EQ(recastMesh->getFlatHeightfields(), std::vector({ + FlatHeightfield {TileBounds {osg::Vec2f(0, 0), osg::Vec2f(501, 502)}, 13}, + })); + } + + TEST_F(DetourNavigatorRecastMeshBuilderTest, add_heightfield_inside_tile) + { + constexpr std::array heights {{ + 0, 1, 2, + 3, 4, 5, + 6, 7, 8, + }}; + RecastMeshBuilder builder(mBounds); + builder.addHeightfield(1000, osg::Vec3f(1, 2, 3), heights.data(), 3, 0, 8); + const auto recastMesh = std::move(builder).create(mGeneration, mRevision); + Heightfield expected; + expected.mBounds = TileBounds {osg::Vec2f(-499, -498), osg::Vec2f(501, 502)}; + expected.mLength = 3; + expected.mMinHeight = 0; + expected.mMaxHeight = 8; + expected.mShift = osg::Vec3f(-499, -498, 3); + expected.mScale = 500; + expected.mHeights = { + 0, 1, 2, + 3, 4, 5, + 6, 7, 8, + }; + EXPECT_EQ(recastMesh->getHeightfields(), std::vector({expected})); + } + + TEST_F(DetourNavigatorRecastMeshBuilderTest, add_heightfield_should_add_intersection) + { + constexpr std::array heights {{ + 0, 1, 2, + 3, 4, 5, + 6, 7, 8, + }}; + mBounds.mMin = osg::Vec2f(250, 250); + RecastMeshBuilder builder(mBounds); + builder.addHeightfield(1000, osg::Vec3f(-1, -2, 3), heights.data(), 3, 0, 8); + const auto recastMesh = std::move(builder).create(mGeneration, mRevision); + Heightfield expected; + expected.mBounds = TileBounds {osg::Vec2f(250, 250), osg::Vec2f(499, 498)}; + expected.mLength = 2; + expected.mMinHeight = 0; + expected.mMaxHeight = 8; + expected.mShift = osg::Vec3f(-1, -2, 3); + expected.mScale = 500; + expected.mHeights = { + 4, 5, + 7, 8, + }; + EXPECT_EQ(recastMesh->getHeightfields(), std::vector({expected})); + } } diff --git a/components/detournavigator/cachedrecastmeshmanager.cpp b/components/detournavigator/cachedrecastmeshmanager.cpp index cfbb77f238..154da806d7 100644 --- a/components/detournavigator/cachedrecastmeshmanager.cpp +++ b/components/detournavigator/cachedrecastmeshmanager.cpp @@ -50,6 +50,23 @@ namespace DetourNavigator return water; } + bool CachedRecastMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, + const osg::Vec3f& shift, const HeightfieldShape& shape) + { + if (!mImpl.addHeightfield(cellPosition, cellSize, shift, shape)) + return false; + mCached.reset(); + return true; + } + + std::optional CachedRecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition) + { + const auto cell = mImpl.removeHeightfield(cellPosition); + if (cell) + mCached.reset(); + return cell; + } + std::shared_ptr CachedRecastMeshManager::getMesh() { if (!mCached) diff --git a/components/detournavigator/cachedrecastmeshmanager.hpp b/components/detournavigator/cachedrecastmeshmanager.hpp index 83eb5c1ec3..ab7bb9e7cb 100644 --- a/components/detournavigator/cachedrecastmeshmanager.hpp +++ b/components/detournavigator/cachedrecastmeshmanager.hpp @@ -3,6 +3,7 @@ #include "recastmeshmanager.hpp" #include "version.hpp" +#include "heightfieldshape.hpp" namespace DetourNavigator { @@ -16,11 +17,16 @@ namespace DetourNavigator bool updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType); + std::optional removeObject(const ObjectId id); + bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const osg::Vec3f& shift); std::optional removeWater(const osg::Vec2i& cellPosition); - std::optional removeObject(const ObjectId id); + bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift, + const HeightfieldShape& shape); + + std::optional removeHeightfield(const osg::Vec2i& cellPosition); std::shared_ptr getMesh(); diff --git a/components/detournavigator/heightfieldshape.hpp b/components/detournavigator/heightfieldshape.hpp new file mode 100644 index 0000000000..48a273725b --- /dev/null +++ b/components/detournavigator/heightfieldshape.hpp @@ -0,0 +1,25 @@ +#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_HEIGHFIELDSHAPE_H +#define OPENMW_COMPONENTS_DETOURNAVIGATOR_HEIGHFIELDSHAPE_H + +#include +#include + +namespace DetourNavigator +{ + struct HeightfieldPlane + { + float mHeight; + }; + + struct HeightfieldSurface + { + const float* mHeights; + std::size_t mSize; + float mMinHeight; + float mMaxHeight; + }; + + using HeightfieldShape = std::variant; +} + +#endif diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index 797d73667b..07e9c7da66 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -9,8 +9,10 @@ #include "navmeshtilescache.hpp" #include "preparednavmeshdata.hpp" #include "navmeshdata.hpp" +#include "recastmeshbuilder.hpp" #include +#include #include #include @@ -195,64 +197,92 @@ namespace ); } - void rasterizeWaterTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const std::vector& cells, + bool rasterizeTriangles(rcContext& context, const Rectangle& rectangle, const rcConfig& config, + const unsigned char* areas, std::size_t areasSize, rcHeightfield& solid) + { + const osg::Vec2f tileBoundsMin( + std::clamp(rectangle.mBounds.mMin.x(), config.bmin[0], config.bmax[0]), + std::clamp(rectangle.mBounds.mMin.y(), config.bmin[2], config.bmax[2]) + ); + const osg::Vec2f tileBoundsMax( + std::clamp(rectangle.mBounds.mMax.x(), config.bmin[0], config.bmax[0]), + std::clamp(rectangle.mBounds.mMax.y(), config.bmin[2], config.bmax[2]) + ); + + if (tileBoundsMax == tileBoundsMin) + return true; + + const std::array vertices { + tileBoundsMin.x(), rectangle.mHeight, tileBoundsMin.y(), + tileBoundsMin.x(), rectangle.mHeight, tileBoundsMax.y(), + tileBoundsMax.x(), rectangle.mHeight, tileBoundsMax.y(), + tileBoundsMax.x(), rectangle.mHeight, tileBoundsMin.y(), + }; + + const std::array indices { + 0, 1, 2, + 0, 2, 3, + }; + + return rcRasterizeTriangles( + &context, + vertices.data(), + static_cast(vertices.size() / 3), + indices.data(), + areas, + static_cast(areasSize), + solid, + config.walkableClimb + ); + } + + bool rasterizeTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const std::vector& cells, const Settings& settings, const rcConfig& config, rcHeightfield& solid) { const std::array areas {{AreaType_water, AreaType_water}}; - for (const Cell& cell : cells) { - const auto rectangle = getSwimRectangle(cell, settings, agentHalfExtents); - - const osg::Vec2f tileBoundsMin( - std::min(config.bmax[0], std::max(config.bmin[0], rectangle.mBounds.mMin.x())), - std::min(config.bmax[2], std::max(config.bmin[2], rectangle.mBounds.mMin.y())) - ); - const osg::Vec2f tileBoundsMax( - std::min(config.bmax[0], std::max(config.bmin[0], rectangle.mBounds.mMax.x())), - std::min(config.bmax[2], std::max(config.bmin[2], rectangle.mBounds.mMax.y())) - ); - - if (tileBoundsMax == tileBoundsMin) - continue; - - const std::array vertices { - tileBoundsMin.x(), rectangle.mHeight, tileBoundsMin.y(), - tileBoundsMin.x(), rectangle.mHeight, tileBoundsMax.y(), - tileBoundsMax.x(), rectangle.mHeight, tileBoundsMax.y(), - tileBoundsMax.x(), rectangle.mHeight, tileBoundsMin.y(), - }; - - const std::array indices { - 0, 1, 2, - 0, 2, 3, - }; - - const auto trianglesRasterized = rcRasterizeTriangles( - &context, - vertices.data(), - static_cast(vertices.size() / 3), - indices.data(), - areas.data(), - static_cast(areas.size()), - solid, - config.walkableClimb - ); - - if (!trianglesRasterized) - throw NavigatorException("Failed to create rasterize water triangles for navmesh"); + const Rectangle rectangle = getSwimRectangle(cell, settings, agentHalfExtents); + if (!rasterizeTriangles(context, rectangle, config, areas.data(), areas.size(), solid)) + return false; } + return true; + } + + bool rasterizeTriangles(rcContext& context, const std::vector& heightfields, + const Settings& settings, const rcConfig& config, rcHeightfield& solid) + { + for (const FlatHeightfield& heightfield : heightfields) + { + const std::array areas {{AreaType_ground, AreaType_ground}}; + const Rectangle rectangle {heightfield.mBounds, toNavMeshCoordinates(settings, heightfield.mHeight)}; + if (!rasterizeTriangles(context, rectangle, config, areas.data(), areas.size(), solid)) + return false; + } + return true; + } + + bool rasterizeTriangles(rcContext& context, const std::vector& heightfields, + const Settings& settings, const rcConfig& config, rcHeightfield& solid) + { + using BulletHelpers::makeProcessTriangleCallback; + + for (const Heightfield& heightfield : heightfields) + { + const Mesh mesh = makeMesh(heightfield); + if (!rasterizeTriangles(context, mesh, settings, config, solid)) + return false; + } + return true; } bool rasterizeTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh, const rcConfig& config, const Settings& settings, rcHeightfield& solid) { - if (!rasterizeTriangles(context, recastMesh.getMesh(), settings, config, solid)) - return false; - - rasterizeWaterTriangles(context, agentHalfExtents, recastMesh.getWater(), settings, config, solid); - - return true; + return rasterizeTriangles(context, recastMesh.getMesh(), settings, config, solid) + && rasterizeTriangles(context, agentHalfExtents, recastMesh.getWater(), settings, config, solid) + && rasterizeTriangles(context, recastMesh.getHeightfields(), settings, config, solid) + && rasterizeTriangles(context, recastMesh.getFlatHeightfields(), settings, config, solid); } void buildCompactHeightfield(rcContext& context, const int walkableHeight, const int walkableClimb, diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index f7ee4ed96e..6e0f773fb6 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -8,6 +8,9 @@ #include "navmeshcacheitem.hpp" #include "recastmeshtiles.hpp" #include "waitconditiontype.hpp" +#include "heightfieldshape.hpp" + +#include namespace ESM { @@ -148,6 +151,11 @@ namespace DetourNavigator */ virtual bool removeWater(const osg::Vec2i& cellPosition) = 0; + virtual bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift, + const HeightfieldShape& shape) = 0; + + virtual bool removeHeightfield(const osg::Vec2i& cellPosition) = 0; + virtual void addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) = 0; virtual void removePathgrid(const ESM::Pathgrid& pathgrid) = 0; diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index a6e1062fbb..e256d8f76f 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -2,6 +2,7 @@ #include "debug.hpp" #include "settingsutils.hpp" +#include #include #include @@ -112,6 +113,17 @@ namespace DetourNavigator return mNavMeshManager.removeWater(cellPosition); } + bool NavigatorImpl::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift, + const HeightfieldShape& shape) + { + return mNavMeshManager.addHeightfield(cellPosition, cellSize, shift, shape); + } + + bool NavigatorImpl::removeHeightfield(const osg::Vec2i& cellPosition) + { + return mNavMeshManager.removeHeightfield(cellPosition); + } + void NavigatorImpl::addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) { Misc::CoordinateConverter converter(&cell); diff --git a/components/detournavigator/navigatorimpl.hpp b/components/detournavigator/navigatorimpl.hpp index 3d021ec7e9..35a6888551 100644 --- a/components/detournavigator/navigatorimpl.hpp +++ b/components/detournavigator/navigatorimpl.hpp @@ -39,6 +39,11 @@ namespace DetourNavigator bool removeWater(const osg::Vec2i& cellPosition) override; + bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift, + const HeightfieldShape& shape) override; + + bool removeHeightfield(const osg::Vec2i& cellPosition) override; + void addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) override; void removePathgrid(const ESM::Pathgrid& pathgrid) override; diff --git a/components/detournavigator/navigatorstub.hpp b/components/detournavigator/navigatorstub.hpp index cab8feaf39..2d2fc936ca 100644 --- a/components/detournavigator/navigatorstub.hpp +++ b/components/detournavigator/navigatorstub.hpp @@ -64,6 +64,17 @@ namespace DetourNavigator return false; } + bool addHeightfield(const osg::Vec2i& /*cellPosition*/, int /*cellSize*/, const osg::Vec3f& /*shift*/, + const HeightfieldShape& /*height*/) override + { + return false; + } + + bool removeHeightfield(const osg::Vec2i& /*cellPosition*/) override + { + return false; + } + void addPathgrid(const ESM::Cell& /*cell*/, const ESM::Pathgrid& /*pathgrid*/) override {} void removePathgrid(const ESM::Pathgrid& /*pathgrid*/) override {} diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index f2dd814d46..287a3c8ef9 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -89,6 +89,24 @@ namespace DetourNavigator return true; } + bool NavMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift, + const HeightfieldShape& shape) + { + if (!mRecastMeshManager.addHeightfield(cellPosition, cellSize, shift, shape)) + return false; + addChangedTiles(cellSize, shift, ChangeType::add); + return true; + } + + bool NavMeshManager::removeHeightfield(const osg::Vec2i& cellPosition) + { + const auto heightfield = mRecastMeshManager.removeHeightfield(cellPosition); + if (!heightfield) + return false; + addChangedTiles(heightfield->mSize, heightfield->mShift, ChangeType::remove); + return true; + } + void NavMeshManager::addAgent(const osg::Vec3f& agentHalfExtents) { auto cached = mCache.find(agentHalfExtents); diff --git a/components/detournavigator/navmeshmanager.hpp b/components/detournavigator/navmeshmanager.hpp index a93d8824e3..390ba41ec8 100644 --- a/components/detournavigator/navmeshmanager.hpp +++ b/components/detournavigator/navmeshmanager.hpp @@ -6,6 +6,7 @@ #include "offmeshconnectionsmanager.hpp" #include "recastmeshtiles.hpp" #include "waitconditiontype.hpp" +#include "heightfieldshape.hpp" #include @@ -37,6 +38,11 @@ namespace DetourNavigator bool removeWater(const osg::Vec2i& cellPosition); + bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift, + const HeightfieldShape& shape); + + bool removeHeightfield(const osg::Vec2i& cellPosition); + bool reset(const osg::Vec3f& agentHalfExtents); void addOffMeshConnection(const ObjectId id, const osg::Vec3f& start, const osg::Vec3f& end, const AreaType areaType); diff --git a/components/detournavigator/navmeshtilescache.cpp b/components/detournavigator/navmeshtilescache.cpp index c4f81727ab..4710a0a4f6 100644 --- a/components/detournavigator/navmeshtilescache.cpp +++ b/components/detournavigator/navmeshtilescache.cpp @@ -42,7 +42,8 @@ namespace DetourNavigator while (!mFreeItems.empty() && mUsedNavMeshDataSize + itemSize > mMaxNavMeshDataSize) removeLeastRecentlyUsed(); - RecastMeshData key {recastMesh.getMesh(), recastMesh.getWater()}; + RecastMeshData key {recastMesh.getMesh(), recastMesh.getWater(), + recastMesh.getHeightfields(), recastMesh.getFlatHeightfields()}; 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 d218ffdcee..06d6c69e9b 100644 --- a/components/detournavigator/navmeshtilescache.hpp +++ b/components/detournavigator/navmeshtilescache.hpp @@ -24,24 +24,26 @@ namespace DetourNavigator { Mesh mMesh; std::vector mWater; + std::vector mHeightfields; + std::vector mFlatHeightfields; }; inline bool operator <(const RecastMeshData& lhs, const RecastMeshData& rhs) { - return std::tie(lhs.mMesh, lhs.mWater) - < std::tie(rhs.mMesh, rhs.mWater); + return std::tie(lhs.mMesh, lhs.mWater, lhs.mHeightfields, lhs.mFlatHeightfields) + < std::tie(rhs.mMesh, rhs.mWater, rhs.mHeightfields, rhs.mFlatHeightfields); } inline bool operator <(const RecastMeshData& lhs, const RecastMesh& rhs) { - return std::tie(lhs.mMesh, lhs.mWater) - < std::tie(rhs.getMesh(), rhs.getWater()); + return std::tie(lhs.mMesh, lhs.mWater, lhs.mHeightfields, lhs.mFlatHeightfields) + < std::tie(rhs.getMesh(), rhs.getWater(), rhs.getHeightfields(), rhs.getFlatHeightfields()); } inline bool operator <(const RecastMesh& lhs, const RecastMeshData& rhs) { - return std::tie(lhs.getMesh(), lhs.getWater()) - < std::tie(rhs.mMesh, rhs.mWater); + return std::tie(lhs.getMesh(), lhs.getWater(), lhs.getHeightfields(), lhs.getFlatHeightfields()) + < std::tie(rhs.mMesh, rhs.mWater, rhs.mHeightfields, rhs.mFlatHeightfields); } class NavMeshTilesCache diff --git a/components/detournavigator/recastmesh.cpp b/components/detournavigator/recastmesh.cpp index bf7a97caa8..e2dea0ad6e 100644 --- a/components/detournavigator/recastmesh.cpp +++ b/components/detournavigator/recastmesh.cpp @@ -18,15 +18,40 @@ namespace DetourNavigator mAreaTypes = std::move(areaTypes); } - RecastMesh::RecastMesh(std::size_t generation, std::size_t revision, Mesh mesh, std::vector water) + RecastMesh::RecastMesh(std::size_t generation, std::size_t revision, Mesh mesh, std::vector water, + std::vector heightfields, std::vector flatHeightfields) : mGeneration(generation) , mRevision(revision) , mMesh(std::move(mesh)) , mWater(std::move(water)) + , mHeightfields(std::move(heightfields)) + , mFlatHeightfields(std::move(flatHeightfields)) { if (mMesh.getVerticesCount() > 0) rcCalcBounds(mMesh.getVertices().data(), static_cast(mMesh.getVerticesCount()), mBounds.mMin.ptr(), mBounds.mMax.ptr()); mWater.shrink_to_fit(); + mHeightfields.shrink_to_fit(); + for (Heightfield& v : mHeightfields) + v.mHeights.shrink_to_fit(); + for (const Heightfield& v : mHeightfields) + { + const auto [min, max] = std::minmax_element(v.mHeights.begin(), v.mHeights.end()); + mBounds.mMin.x() = std::min(mBounds.mMin.x(), v.mBounds.mMin.x()); + mBounds.mMin.y() = std::min(mBounds.mMin.y(), v.mBounds.mMin.y()); + mBounds.mMin.z() = std::min(mBounds.mMin.z(), *min); + mBounds.mMax.x() = std::max(mBounds.mMax.x(), v.mBounds.mMax.x()); + mBounds.mMax.y() = std::max(mBounds.mMax.y(), v.mBounds.mMax.y()); + mBounds.mMax.z() = std::max(mBounds.mMax.z(), *max); + } + for (const FlatHeightfield& v : mFlatHeightfields) + { + mBounds.mMin.x() = std::min(mBounds.mMin.x(), v.mBounds.mMin.x()); + mBounds.mMin.y() = std::min(mBounds.mMin.y(), v.mBounds.mMin.y()); + mBounds.mMin.z() = std::min(mBounds.mMin.z(), v.mHeight); + mBounds.mMax.x() = std::max(mBounds.mMax.x(), v.mBounds.mMax.x()); + mBounds.mMax.y() = std::max(mBounds.mMax.y(), v.mBounds.mMax.y()); + mBounds.mMax.z() = std::max(mBounds.mMax.z(), v.mHeight); + } } } diff --git a/components/detournavigator/recastmesh.hpp b/components/detournavigator/recastmesh.hpp index f316abf653..c8e160603b 100644 --- a/components/detournavigator/recastmesh.hpp +++ b/components/detournavigator/recastmesh.hpp @@ -3,6 +3,7 @@ #include "areatype.hpp" #include "bounds.hpp" +#include "tilebounds.hpp" #include @@ -12,6 +13,7 @@ #include #include #include +#include namespace DetourNavigator { @@ -51,10 +53,43 @@ namespace DetourNavigator osg::Vec3f mShift; }; + struct Heightfield + { + TileBounds mBounds; + std::uint8_t mLength; + float mMinHeight; + float mMaxHeight; + osg::Vec3f mShift; + float mScale; + std::vector mHeights; + }; + + inline auto makeTuple(const Heightfield& v) noexcept + { + return std::tie(v.mBounds, v.mLength, v.mMinHeight, v.mMaxHeight, v.mShift, v.mScale, v.mHeights); + } + + inline bool operator<(const Heightfield& lhs, const Heightfield& rhs) noexcept + { + return makeTuple(lhs) < makeTuple(rhs); + } + + struct FlatHeightfield + { + TileBounds mBounds; + float mHeight; + }; + + inline bool operator<(const FlatHeightfield& lhs, const FlatHeightfield& rhs) noexcept + { + return std::tie(lhs.mBounds, lhs.mHeight) < std::tie(rhs.mBounds, rhs.mHeight); + } + class RecastMesh { public: - RecastMesh(std::size_t generation, std::size_t revision, Mesh mesh, std::vector water); + RecastMesh(std::size_t generation, std::size_t revision, Mesh mesh, std::vector water, + std::vector heightfields, std::vector flatHeightfields); std::size_t getGeneration() const { @@ -73,6 +108,16 @@ namespace DetourNavigator return mWater; } + const std::vector& getHeightfields() const noexcept + { + return mHeightfields; + } + + const std::vector& getFlatHeightfields() const noexcept + { + return mFlatHeightfields; + } + const Bounds& getBounds() const { return mBounds; @@ -83,6 +128,8 @@ namespace DetourNavigator std::size_t mRevision; Mesh mMesh; std::vector mWater; + std::vector mHeightfields; + std::vector mFlatHeightfields; Bounds mBounds; friend inline bool operator <(const RecastMesh& lhs, const RecastMesh& rhs) noexcept @@ -92,7 +139,11 @@ namespace DetourNavigator friend inline std::size_t getSize(const RecastMesh& value) noexcept { - return getSize(value.mMesh) + value.mWater.size() * sizeof(Cell); + return getSize(value.mMesh) + value.mWater.size() * sizeof(Cell) + + value.mHeightfields.size() * sizeof(Heightfield) + + std::accumulate(value.mHeightfields.begin(), value.mHeightfields.end(), std::size_t {0}, + [] (std::size_t r, const Heightfield& v) { return r + v.mHeights.size() * sizeof(float); }) + + value.mFlatHeightfields.size() * sizeof(FlatHeightfield); } }; diff --git a/components/detournavigator/recastmeshbuilder.cpp b/components/detournavigator/recastmeshbuilder.cpp index b47d823199..6ee16cdc6c 100644 --- a/components/detournavigator/recastmeshbuilder.cpp +++ b/components/detournavigator/recastmeshbuilder.cpp @@ -33,9 +33,18 @@ namespace DetourNavigator result.mVertices[i] = Misc::Convert::makeOsgVec3f(vertices[i]); return result; } + + TileBounds maxCellTileBounds(int size, const osg::Vec3f& shift) + { + const float halfCellSize = size / 2; + return TileBounds { + osg::Vec2f(shift.x() - halfCellSize, shift.y() - halfCellSize), + osg::Vec2f(shift.x() + halfCellSize, shift.y() + halfCellSize) + }; + } } - Mesh makeMesh(std::vector&& triangles) + Mesh makeMesh(std::vector&& triangles, const osg::Vec3f& shift) { std::vector uniqueVertices; uniqueVertices.reserve(3 * triangles.size()); @@ -72,14 +81,46 @@ namespace DetourNavigator for (const osg::Vec3f& v : uniqueVertices) { - vertices.push_back(v.x()); - vertices.push_back(v.y()); - vertices.push_back(v.z()); + vertices.push_back(v.x() + shift.x()); + vertices.push_back(v.y() + shift.y()); + vertices.push_back(v.z() + shift.z()); } return Mesh(std::move(indices), std::move(vertices), std::move(areaTypes)); } + Mesh makeMesh(const Heightfield& heightfield) + { + using BulletHelpers::makeProcessTriangleCallback; + using Misc::Convert::toOsg; + + constexpr int upAxis = 2; + constexpr bool flipQuadEdges = false; +#if BT_BULLET_VERSION < 310 + std::vector heights(heightfield.mHeights.begin(), heightfield.mHeights.end()); + btHeightfieldTerrainShape shape(static_cast(heightfield.mHeights.size() / heightfield.mLength), + static_cast(heightfield.mLength), heights.data(), 1, + heightfield.mMinHeight, heightfield.mMaxHeight, upAxis, PHY_FLOAT, flipQuadEdges + ); +#else + btHeightfieldTerrainShape shape(static_cast(heightfield.mHeights.size() / heightfield.mLength), + static_cast(heightfield.mLength), heightfield.mHeights.data(), + heightfield.mMinHeight, heightfield.mMaxHeight, upAxis, flipQuadEdges); +#endif + shape.setLocalScaling(btVector3(heightfield.mScale, heightfield.mScale, 1)); + btVector3 aabbMin; + btVector3 aabbMax; + shape.getAabb(btTransform::getIdentity(), aabbMin, aabbMax); + std::vector triangles; + auto callback = makeProcessTriangleCallback([&] (btVector3* vertices, int, int) + { + triangles.emplace_back(makeRecastMeshTriangle(vertices, AreaType_ground)); + }); + shape.processAllTriangles(&callback, aabbMin, aabbMax); + const osg::Vec2f shift = (osg::Vec2f(aabbMax.x(), aabbMax.y()) - osg::Vec2f(aabbMin.x(), aabbMin.y())) * 0.5; + return makeMesh(std::move(triangles), heightfield.mShift + osg::Vec3f(shift.x(), shift.y(), 0)); + } + RecastMeshBuilder::RecastMeshBuilder(const TileBounds& bounds) noexcept : mBounds(bounds) { @@ -122,7 +163,7 @@ namespace DetourNavigator void RecastMeshBuilder::addObject(const btHeightfieldTerrainShape& shape, const btTransform& transform, const AreaType areaType) { - return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* vertices, int, int) + addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* vertices, int, int) { mTriangles.emplace_back(makeRecastMeshTriangle(vertices, areaType)); })); @@ -163,12 +204,54 @@ namespace DetourNavigator mWater.push_back(Cell {cellSize, shift}); } + void RecastMeshBuilder::addHeightfield(int cellSize, const osg::Vec3f& shift, float height) + { + if (const auto intersection = getIntersection(mBounds, maxCellTileBounds(cellSize, shift))) + mFlatHeightfields.emplace_back(FlatHeightfield {*intersection, height + shift.z()}); + } + + void RecastMeshBuilder::addHeightfield(int cellSize, const osg::Vec3f& shift, const float* heights, + std::size_t size, float minHeight, float maxHeight) + { + const auto intersection = getIntersection(mBounds, maxCellTileBounds(cellSize, shift)); + if (!intersection.has_value()) + return; + const float stepSize = static_cast(cellSize) / (size - 1); + const int halfCellSize = cellSize / 2; + const auto local = [&] (float v, float shift) { return (v - shift + halfCellSize) / stepSize; }; + const auto index = [&] (float v, int add) { return std::clamp(static_cast(v) + add, 0, size); }; + const std::size_t minX = index(std::round(local(intersection->mMin.x(), shift.x())), -1); + const std::size_t minY = index(std::round(local(intersection->mMin.y(), shift.y())), -1); + const std::size_t maxX = index(std::round(local(intersection->mMax.x(), shift.x())), 1); + const std::size_t maxY = index(std::round(local(intersection->mMax.y(), shift.y())), 1); + const std::size_t endX = std::min(maxX + 1, size); + const std::size_t endY = std::min(maxY + 1, size); + const std::size_t sliceSize = (endX - minX) * (endY - minY); + if (sliceSize == 0) + return; + std::vector tileHeights; + tileHeights.reserve(sliceSize); + for (std::size_t y = minY; y < endY; ++y) + for (std::size_t x = minX; x < endX; ++x) + tileHeights.push_back(heights[x + y * size]); + Heightfield heightfield; + heightfield.mBounds = *intersection; + heightfield.mLength = static_cast(endY - minY); + heightfield.mMinHeight = minHeight; + heightfield.mMaxHeight = maxHeight; + heightfield.mShift = shift + osg::Vec3f(minX, minY, 0) * stepSize - osg::Vec3f(halfCellSize, halfCellSize, 0); + heightfield.mScale = stepSize; + heightfield.mHeights = std::move(tileHeights); + mHeightfields.emplace_back(heightfield); + } + std::shared_ptr RecastMeshBuilder::create(std::size_t generation, std::size_t revision) && { std::sort(mTriangles.begin(), mTriangles.end()); std::sort(mWater.begin(), mWater.end()); Mesh mesh = makeMesh(std::move(mTriangles)); - return std::make_shared(generation, revision, std::move(mesh), std::move(mWater)); + return std::make_shared(generation, revision, std::move(mesh), std::move(mWater), + std::move(mHeightfields), std::move(mFlatHeightfields)); } void RecastMeshBuilder::addObject(const btConcaveShape& shape, const btTransform& transform, diff --git a/components/detournavigator/recastmeshbuilder.hpp b/components/detournavigator/recastmeshbuilder.hpp index d08ff94418..120e4b045a 100644 --- a/components/detournavigator/recastmeshbuilder.hpp +++ b/components/detournavigator/recastmeshbuilder.hpp @@ -51,19 +51,28 @@ namespace DetourNavigator void addWater(const int mCellSize, const osg::Vec3f& shift); + void addHeightfield(int cellSize, const osg::Vec3f& shift, float height); + + void addHeightfield(int cellSize, const osg::Vec3f& shift, const float* heights, std::size_t size, + float minHeight, float maxHeight); + std::shared_ptr create(std::size_t generation, std::size_t revision) &&; private: const TileBounds mBounds; std::vector mTriangles; std::vector mWater; + std::vector mHeightfields; + std::vector mFlatHeightfields; void addObject(const btConcaveShape& shape, const btTransform& transform, btTriangleCallback&& callback); void addObject(const btHeightfieldTerrainShape& shape, const btTransform& transform, btTriangleCallback&& callback); }; - Mesh makeMesh(std::vector&& triangles); + Mesh makeMesh(std::vector&& triangles, const osg::Vec3f& shift = osg::Vec3f()); + + Mesh makeMesh(const Heightfield& heightfield); } #endif diff --git a/components/detournavigator/recastmeshmanager.cpp b/components/detournavigator/recastmeshmanager.cpp index a6798ee8cd..151b3161c1 100644 --- a/components/detournavigator/recastmeshmanager.cpp +++ b/components/detournavigator/recastmeshmanager.cpp @@ -1,6 +1,30 @@ #include "recastmeshmanager.hpp" #include "recastmeshbuilder.hpp" #include "settings.hpp" +#include "heightfieldshape.hpp" + +#include + +#include + +namespace +{ + struct AddHeightfield + { + const DetourNavigator::Cell& mCell; + DetourNavigator::RecastMeshBuilder& mBuilder; + + void operator()(const DetourNavigator::HeightfieldSurface& v) + { + mBuilder.addHeightfield(mCell.mSize, mCell.mShift, v.mHeights, v.mSize, v.mMinHeight, v.mMaxHeight); + } + + void operator()(DetourNavigator::HeightfieldPlane v) + { + mBuilder.addHeightfield(mCell.mSize, mCell.mShift, v.mHeight); + } + }; +} namespace DetourNavigator { @@ -66,6 +90,26 @@ namespace DetourNavigator return result; } + bool RecastMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift, + const HeightfieldShape& shape) + { + if (!mHeightfields.emplace(cellPosition, Heightfield {Cell {cellSize, shift}, shape}).second) + return false; + ++mRevision; + return true; + } + + std::optional RecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition) + { + const auto it = mHeightfields.find(cellPosition); + if (it == mHeightfields.end()) + return std::nullopt; + ++mRevision; + const auto result = std::make_optional(it->second.mCell); + mHeightfields.erase(it); + return result; + } + std::shared_ptr RecastMeshManager::getMesh() { TileBounds tileBounds = mTileBounds; @@ -79,12 +123,14 @@ namespace DetourNavigator const RecastMeshObject& v = object.getImpl(); builder.addObject(v.getShape(), v.getTransform(), v.getAreaType()); } + for (const auto& [cellPosition, v] : mHeightfields) + std::visit(AddHeightfield {v.mCell, builder}, v.mShape); return std::move(builder).create(mGeneration, mRevision); } bool RecastMeshManager::isEmpty() const { - return mObjects.empty() && mWater.empty(); + return mObjects.empty() && mWater.empty() && mHeightfields.empty(); } void RecastMeshManager::reportNavMeshChange(const Version& recastMeshVersion, const Version& navMeshVersion) diff --git a/components/detournavigator/recastmeshmanager.hpp b/components/detournavigator/recastmeshmanager.hpp index 266d6a9385..88124c44cf 100644 --- a/components/detournavigator/recastmeshmanager.hpp +++ b/components/detournavigator/recastmeshmanager.hpp @@ -5,6 +5,7 @@ #include "objectid.hpp" #include "version.hpp" #include "recastmesh.hpp" +#include "heightfieldshape.hpp" #include @@ -13,6 +14,8 @@ #include #include #include +#include +#include class btCollisionShape; @@ -37,11 +40,16 @@ namespace DetourNavigator bool updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType); + std::optional removeObject(const ObjectId id); + bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const osg::Vec3f& shift); std::optional removeWater(const osg::Vec2i& cellPosition); - std::optional removeObject(const ObjectId id); + bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift, + const HeightfieldShape& shape); + + std::optional removeHeightfield(const osg::Vec2i& cellPosition); std::shared_ptr getMesh(); @@ -58,12 +66,19 @@ namespace DetourNavigator Version mNavMeshVersion; }; + struct Heightfield + { + Cell mCell; + HeightfieldShape mShape; + }; + const Settings& mSettings; std::size_t mRevision = 0; std::size_t mGeneration; TileBounds mTileBounds; std::map mObjects; std::map mWater; + std::map mHeightfields; std::optional mLastNavMeshReportedChange; std::optional mLastNavMeshReport; }; diff --git a/components/detournavigator/tilebounds.hpp b/components/detournavigator/tilebounds.hpp index 83fe2b6296..8557045342 100644 --- a/components/detournavigator/tilebounds.hpp +++ b/components/detournavigator/tilebounds.hpp @@ -3,6 +3,10 @@ #include +#include +#include +#include + namespace DetourNavigator { struct TileBounds @@ -10,6 +14,24 @@ namespace DetourNavigator osg::Vec2f mMin; osg::Vec2f mMax; }; + + inline bool operator<(const TileBounds& lhs, const TileBounds& rhs) noexcept + { + return std::tie(lhs.mMin, lhs.mMax) < std::tie(rhs.mMin, rhs.mMax); + } + + inline std::optional getIntersection(const TileBounds& a, const TileBounds& b) noexcept + { + const float minX = std::max(a.mMin.x(), b.mMin.x()); + const float maxX = std::min(a.mMax.x(), b.mMax.x()); + if (minX > maxX) + return std::nullopt; + const float minY = std::max(a.mMin.y(), b.mMin.y()); + const float maxY = std::min(a.mMax.y(), b.mMax.y()); + if (minY > maxY) + return std::nullopt; + return TileBounds {osg::Vec2f(minX, minY), osg::Vec2f(maxX, maxY)}; + } } #endif diff --git a/components/detournavigator/tilecachedrecastmeshmanager.cpp b/components/detournavigator/tilecachedrecastmeshmanager.cpp index 1292e31d4e..a37d24399d 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.cpp @@ -3,6 +3,8 @@ #include "gettilespositions.hpp" #include "settingsutils.hpp" +#include + #include #include @@ -128,6 +130,66 @@ namespace DetourNavigator return result; } + bool TileCachedRecastMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, + const osg::Vec3f& shift, const HeightfieldShape& shape) + { + const auto border = getBorderSize(mSettings); + + auto& tilesPositions = mHeightfieldTilesPositions[cellPosition]; + + bool result = false; + + getTilesPositions(cellSize, shift, mSettings, [&] (const TilePosition& tilePosition) + { + const auto tiles = mTiles.lock(); + auto tile = tiles->find(tilePosition); + if (tile == tiles->end()) + { + auto tileBounds = makeTileBounds(mSettings, tilePosition); + tileBounds.mMin -= osg::Vec2f(border, border); + tileBounds.mMax += osg::Vec2f(border, border); + tile = tiles->insert(std::make_pair(tilePosition, + CachedRecastMeshManager(mSettings, tileBounds, mTilesGeneration))).first; + } + if (tile->second.addHeightfield(cellPosition, cellSize, shift, shape)) + { + tilesPositions.push_back(tilePosition); + result = true; + } + }); + + if (result) + ++mRevision; + + return result; + } + + std::optional TileCachedRecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition) + { + const auto object = mHeightfieldTilesPositions.find(cellPosition); + if (object == mHeightfieldTilesPositions.end()) + return std::nullopt; + std::optional result; + for (const auto& tilePosition : object->second) + { + const auto tiles = mTiles.lock(); + const auto tile = tiles->find(tilePosition); + if (tile == tiles->end()) + continue; + const auto tileResult = tile->second.removeHeightfield(cellPosition); + if (tile->second.isEmpty()) + { + tiles->erase(tile); + ++mTilesGeneration; + } + if (tileResult && !result) + result = tileResult; + } + if (result) + ++mRevision; + return result; + } + std::shared_ptr TileCachedRecastMeshManager::getMesh(const TilePosition& tilePosition) { const auto tiles = mTiles.lock(); diff --git a/components/detournavigator/tilecachedrecastmeshmanager.hpp b/components/detournavigator/tilecachedrecastmeshmanager.hpp index 4ea705f4cd..f3292cbf9b 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.hpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.hpp @@ -6,6 +6,7 @@ #include "settingsutils.hpp" #include "gettilespositions.hpp" #include "version.hpp" +#include "heightfieldshape.hpp" #include @@ -80,6 +81,11 @@ namespace DetourNavigator std::optional removeWater(const osg::Vec2i& cellPosition); + bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const osg::Vec3f& shift, + const HeightfieldShape& shape); + + std::optional removeHeightfield(const osg::Vec2i& cellPosition); + std::shared_ptr getMesh(const TilePosition& tilePosition); bool hasTile(const TilePosition& tilePosition); @@ -100,6 +106,7 @@ namespace DetourNavigator Misc::ScopeGuarded> mTiles; std::unordered_map> mObjectsTilesPositions; std::map> mWaterTilesPositions; + std::map> mHeightfieldTilesPositions; std::size_t mRevision = 0; std::size_t mTilesGeneration = 0; diff --git a/components/sceneutil/recastmesh.cpp b/components/sceneutil/recastmesh.cpp index 556fc3f3b5..85f3e7177b 100644 --- a/components/sceneutil/recastmesh.cpp +++ b/components/sceneutil/recastmesh.cpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -45,15 +46,25 @@ namespace SceneUtil const osg::ref_ptr group(new osg::Group); DebugDraw debugDraw(*group, osg::Vec3f(0, 0, 0), 1.0f); const DetourNavigator::Mesh& mesh = recastMesh.getMesh(); + std::vector indices = mesh.getIndices(); std::vector vertices = mesh.getVertices(); + for (const Heightfield& heightfield : recastMesh.getHeightfields()) + { + const Mesh mesh = makeMesh(heightfield); + const int indexShift = static_cast(vertices.size() / 3); + std::copy(mesh.getVertices().begin(), mesh.getVertices().end(), std::back_inserter(vertices)); + std::transform(mesh.getIndices().begin(), mesh.getIndices().end(), std::back_inserter(indices), + [&] (int index) { return index + indexShift; }); + } + for (std::size_t i = 0; i < vertices.size(); i += 3) std::swap(vertices[i + 1], vertices[i + 2]); - const auto normals = calculateNormals(vertices, mesh.getIndices()); + const auto normals = calculateNormals(vertices, indices); const auto texScale = 1.0f / (settings.mCellSize * 10.0f); duDebugDrawTriMesh(&debugDraw, vertices.data(), static_cast(vertices.size() / 3), - mesh.getIndices().data(), normals.data(), static_cast(mesh.getIndices().size() / 3), nullptr, texScale); + indices.data(), normals.data(), static_cast(indices.size() / 3), nullptr, texScale); return group; } }