diff --git a/apps/openmw/mwphysics/heightfield.cpp b/apps/openmw/mwphysics/heightfield.cpp index 52aed9c072..e1448116bf 100644 --- a/apps/openmw/mwphysics/heightfield.cpp +++ b/apps/openmw/mwphysics/heightfield.cpp @@ -7,12 +7,48 @@ #include +#include + +namespace +{ + template + auto makeHeights(const T* heights, float sqrtVerts) + -> std::enable_if_t::value, std::vector> + { + return {}; + } + + template + auto makeHeights(const T* heights, float sqrtVerts) + -> std::enable_if_t::value, std::vector> + { + return std::vector(heights, heights + static_cast(sqrtVerts * sqrtVerts)); + } + + template + auto getHeights(const T* floatHeights, const std::vector&) + -> std::enable_if_t::value, const btScalar*> + { + return floatHeights; + } + + template + auto getHeights(const T*, const std::vector& btScalarHeights) + -> std::enable_if_t::value, const btScalar*> + { + return btScalarHeights.data(); + } +} + namespace MWPhysics { HeightField::HeightField(const float* heights, int x, int y, float triSize, float sqrtVerts, float minH, float maxH, const osg::Object* holdObject) + : mHeights(makeHeights(heights, sqrtVerts)) { mShape = new btHeightfieldTerrainShape( - sqrtVerts, sqrtVerts, heights, 1, + sqrtVerts, sqrtVerts, + getHeights(heights, mHeights), + 1, minH, maxH, 2, PHY_FLOAT, false ); diff --git a/apps/openmw/mwphysics/heightfield.hpp b/apps/openmw/mwphysics/heightfield.hpp index f248186db3..2ba58afff8 100644 --- a/apps/openmw/mwphysics/heightfield.hpp +++ b/apps/openmw/mwphysics/heightfield.hpp @@ -3,6 +3,10 @@ #include +#include + +#include + class btCollisionObject; class btHeightfieldTerrainShape; @@ -27,6 +31,7 @@ namespace MWPhysics btHeightfieldTerrainShape* mShape; btCollisionObject* mCollisionObject; osg::ref_ptr mHoldObject; + std::vector mHeights; void operator=(const HeightField&); HeightField(const HeightField&); diff --git a/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp b/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp index 6c474765de..c86dee6e55 100644 --- a/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp +++ b/apps/openmw_test_suite/detournavigator/recastmeshbuilder.cpp @@ -363,11 +363,11 @@ namespace AreaType_ground ); const auto recastMesh = builder.create(mGeneration, mRevision); - EXPECT_EQ(recastMesh->getVertices(), std::vector({ + 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})); } diff --git a/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp b/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp index 36f2512462..6ec94fd68f 100644 --- a/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp +++ b/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp @@ -9,6 +9,8 @@ #include #include +#include + namespace { template @@ -30,6 +32,34 @@ namespace shape.processAllTriangles(&callback, aabbMin, aabbMax); return result; } + + bool isNear(btScalar lhs, btScalar rhs) + { + return std::abs(lhs - rhs) <= 1e-5; + } + + bool isNear(const btVector3& lhs, const btVector3& rhs) + { + return std::equal( + static_cast(lhs), + static_cast(lhs) + 3, + static_cast(rhs), + [] (btScalar lhs, btScalar rhs) { return isNear(lhs, rhs); } + ); + } + + bool isNear(const btMatrix3x3& lhs, const btMatrix3x3& rhs) + { + for (int i = 0; i < 3; ++i) + if (!isNear(lhs[i], rhs[i])) + return false; + return true; + } + + bool isNear(const btTransform& lhs, const btTransform& rhs) + { + return isNear(lhs.getOrigin(), rhs.getOrigin()) && isNear(lhs.getBasis(), rhs.getBasis()); + } } static std::ostream& operator <<(std::ostream& stream, const btVector3& value) @@ -157,7 +187,7 @@ static bool operator ==(const btCompoundShape& lhs, const btCompoundShape& rhs) for (int i = 0; i < lhs.getNumChildShapes(); ++i) { if (!compareObjects(lhs.getChildShape(i), rhs.getChildShape(i)) - || !(lhs.getChildTransform(i) == rhs.getChildTransform(i))) + || !isNear(lhs.getChildTransform(i), rhs.getChildTransform(i))) return false; } return true; @@ -165,13 +195,13 @@ static bool operator ==(const btCompoundShape& lhs, const btCompoundShape& rhs) static bool operator ==(const btBoxShape& lhs, const btBoxShape& rhs) { - return lhs.getLocalScaling() == rhs.getLocalScaling() + return isNear(lhs.getLocalScaling(), rhs.getLocalScaling()) && lhs.getHalfExtentsWithoutMargin() == rhs.getHalfExtentsWithoutMargin(); } static bool operator ==(const btBvhTriangleMeshShape& lhs, const btBvhTriangleMeshShape& rhs) { - return lhs.getLocalScaling() == rhs.getLocalScaling() + return isNear(lhs.getLocalScaling(), rhs.getLocalScaling()) && lhs.usesQuantizedAabbCompression() == rhs.usesQuantizedAabbCompression() && lhs.getOwnsBvh() == rhs.getOwnsBvh() && getTriangles(lhs) == getTriangles(rhs);