#include "heightfield.hpp" #include "mtphysics.hpp" #include #include #include #include #include #include #if BT_BULLET_VERSION < 310 // Older Bullet versions only support `btScalar` heightfields. // Our heightfield data is `float`. // // These functions handle conversion from `float` to `double` when // `btScalar` is `double` (`BT_USE_DOUBLE_PRECISION`). namespace { template auto makeHeights(const T* heights, int verts) -> std::enable_if_t::value, std::vector> { return {}; } template auto makeHeights(const T* heights, int verts) -> std::enable_if_t::value, std::vector> { return std::vector(heights, heights + static_cast(verts * verts)); } 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(); } } #endif namespace MWPhysics { HeightField::HeightField(const float* heights, int x, int y, int size, int verts, float minH, float maxH, const osg::Object* holdObject, PhysicsTaskScheduler* scheduler) : mHoldObject(holdObject) #if BT_BULLET_VERSION < 310 , mHeights(makeHeights(heights, verts)) #endif , mTaskScheduler(scheduler) { #if BT_BULLET_VERSION < 310 mShape = std::make_unique( verts, verts, getHeights(heights, mHeights), 1, minH, maxH, 2, PHY_FLOAT, false); #else mShape = std::make_unique(verts, verts, heights, minH, maxH, 2, false); #endif mShape->setUseDiamondSubdivision(true); const float scaling = static_cast(size) / static_cast(verts - 1); mShape->setLocalScaling(btVector3(scaling, scaling, 1)); #if BT_BULLET_VERSION >= 289 // Accelerates some collision tests. // // Note: The accelerator data structure in Bullet is only used // in some operations. This could be improved, see: // https://github.com/bulletphysics/bullet3/issues/3276 mShape->buildAccelerator(); #endif const btTransform transform( btQuaternion::getIdentity(), BulletHelpers::getHeightfieldShift(x, y, size, minH, maxH)); mCollisionObject = std::make_unique(); mCollisionObject->setCollisionShape(mShape.get()); mCollisionObject->setWorldTransform(transform); mTaskScheduler->addCollisionObject( mCollisionObject.get(), CollisionType_HeightMap, CollisionType_Actor | CollisionType_Projectile); } HeightField::~HeightField() { mTaskScheduler->removeCollisionObject(mCollisionObject.get()); } btCollisionObject* HeightField::getCollisionObject() { return mCollisionObject.get(); } const btCollisionObject* HeightField::getCollisionObject() const { return mCollisionObject.get(); } const btHeightfieldTerrainShape* HeightField::getShape() const { return mShape.get(); } }