1 #include "heightfield.hpp" 2 #include "mtphysics.hpp" 3 4 #include <osg/Object> 5 6 #include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h> 7 #include <BulletCollision/CollisionDispatch/btCollisionObject.h> 8 9 #include <LinearMath/btTransform.h> 10 11 #include <type_traits> 12 13 #if BT_BULLET_VERSION < 310 14 // Older Bullet versions only support `btScalar` heightfields. 15 // Our heightfield data is `float`. 16 // 17 // These functions handle conversion from `float` to `double` when 18 // `btScalar` is `double` (`BT_USE_DOUBLE_PRECISION`). 19 namespace 20 { 21 template <class T> makeHeights(const T * heights,float sqrtVerts)22 auto makeHeights(const T* heights, float sqrtVerts) 23 -> std::enable_if_t<std::is_same<btScalar, T>::value, std::vector<btScalar>> 24 { 25 return {}; 26 } 27 28 template <class T> makeHeights(const T * heights,float sqrtVerts)29 auto makeHeights(const T* heights, float sqrtVerts) 30 -> std::enable_if_t<!std::is_same<btScalar, T>::value, std::vector<btScalar>> 31 { 32 return std::vector<btScalar>(heights, heights + static_cast<std::ptrdiff_t>(sqrtVerts * sqrtVerts)); 33 } 34 35 template <class T> getHeights(const T * floatHeights,const std::vector<btScalar> &)36 auto getHeights(const T* floatHeights, const std::vector<btScalar>&) 37 -> std::enable_if_t<std::is_same<btScalar, T>::value, const btScalar*> 38 { 39 return floatHeights; 40 } 41 42 template <class T> getHeights(const T *,const std::vector<btScalar> & btScalarHeights)43 auto getHeights(const T*, const std::vector<btScalar>& btScalarHeights) 44 -> std::enable_if_t<!std::is_same<btScalar, T>::value, const btScalar*> 45 { 46 return btScalarHeights.data(); 47 } 48 } 49 #endif 50 51 namespace MWPhysics 52 { HeightField()53 HeightField::HeightField() {} 54 HeightField(const HeightField &,const osg::CopyOp &)55 HeightField::HeightField(const HeightField&, const osg::CopyOp&) {} 56 HeightField(const float * heights,int x,int y,float triSize,float sqrtVerts,float minH,float maxH,const osg::Object * holdObject,PhysicsTaskScheduler * scheduler)57 HeightField::HeightField(const float* heights, int x, int y, float triSize, float sqrtVerts, float minH, float maxH, const osg::Object* holdObject, PhysicsTaskScheduler* scheduler) 58 : mHoldObject(holdObject) 59 #if BT_BULLET_VERSION < 310 60 , mHeights(makeHeights(heights, sqrtVerts)) 61 #endif 62 , mTaskScheduler(scheduler) 63 { 64 #if BT_BULLET_VERSION < 310 65 mShape = std::make_unique<btHeightfieldTerrainShape>( 66 sqrtVerts, sqrtVerts, 67 getHeights(heights, mHeights), 68 1, 69 minH, maxH, 2, 70 PHY_FLOAT, false 71 ); 72 #else 73 mShape = std::make_unique<btHeightfieldTerrainShape>( 74 sqrtVerts, sqrtVerts, heights, minH, maxH, 2, false); 75 #endif 76 mShape->setUseDiamondSubdivision(true); 77 mShape->setLocalScaling(btVector3(triSize, triSize, 1)); 78 79 #if BT_BULLET_VERSION >= 289 80 // Accelerates some collision tests. 81 // 82 // Note: The accelerator data structure in Bullet is only used 83 // in some operations. This could be improved, see: 84 // https://github.com/bulletphysics/bullet3/issues/3276 85 mShape->buildAccelerator(); 86 #endif 87 88 btTransform transform(btQuaternion::getIdentity(), 89 btVector3((x+0.5f) * triSize * (sqrtVerts-1), 90 (y+0.5f) * triSize * (sqrtVerts-1), 91 (maxH+minH)*0.5f)); 92 93 mCollisionObject = std::make_unique<btCollisionObject>(); 94 mCollisionObject->setCollisionShape(mShape.get()); 95 mCollisionObject->setWorldTransform(transform); 96 mTaskScheduler->addCollisionObject(mCollisionObject.get(), CollisionType_HeightMap, CollisionType_Actor|CollisionType_Projectile); 97 } 98 ~HeightField()99 HeightField::~HeightField() 100 { 101 mTaskScheduler->removeCollisionObject(mCollisionObject.get()); 102 } 103 getCollisionObject()104 btCollisionObject* HeightField::getCollisionObject() 105 { 106 return mCollisionObject.get(); 107 } 108 getCollisionObject() const109 const btCollisionObject* HeightField::getCollisionObject() const 110 { 111 return mCollisionObject.get(); 112 } 113 getShape() const114 const btHeightfieldTerrainShape* HeightField::getShape() const 115 { 116 return mShape.get(); 117 } 118 } 119