btCollision.cpp
Engine/source/T3D/physics/bullet/btCollision.cpp
Classes:
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "T3D/physics/bullet/btCollision.h" 26 27#include "math/mPoint3.h" 28#include "math/mMatrix.h" 29#include "T3D/physics/bullet/bt.h" 30#include "T3D/physics/bullet/btCasts.h" 31 32class btHeightfieldTerrainShapeCustom : public btHeightfieldTerrainShape 33{ 34 bool* mHoles; 35 36public: 37 btHeightfieldTerrainShapeCustom(const bool *holes, 38 int heightStickWidth, 39 int heightStickLength, 40 const void* heightfieldData, 41 btScalar heightScale, 42 btScalar minHeight, 43 btScalar maxHeight, 44 int upAxis, 45 PHY_ScalarType heightDataType, 46 bool flipQuadEdges) : btHeightfieldTerrainShape(heightStickWidth, 47 heightStickLength, 48 heightfieldData, 49 heightScale, 50 minHeight, 51 maxHeight, 52 upAxis, 53 heightDataType, 54 flipQuadEdges) 55 { 56 mHoles = new bool[heightStickWidth * heightStickLength]; 57 dMemcpy(mHoles, holes, heightStickWidth * heightStickLength * sizeof(bool)); 58 } 59 60 virtual ~btHeightfieldTerrainShapeCustom() 61 { 62 delete[] mHoles; 63 } 64 65 virtual void processAllTriangles(btTriangleCallback* callback, const btVector3& aabbMin, const btVector3& aabbMax) const; 66}; 67 68 69BtCollision::BtCollision() 70 : mCompound( NULL ), 71 mLocalXfm( true ) 72{ 73} 74 75BtCollision::~BtCollision() 76{ 77 SAFE_DELETE( mCompound ); 78 79 for ( U32 i=0; i < mShapes.size(); i++ ) 80 delete mShapes[i]; 81 82 for ( U32 i=0; i < mMeshInterfaces.size(); i++ ) 83 delete mMeshInterfaces[i]; 84} 85 86btCollisionShape* BtCollision::getShape() 87{ 88 if ( mCompound ) 89 return mCompound; 90 91 if ( mShapes.empty() ) 92 return NULL; 93 94 return mShapes.first(); 95} 96 97void BtCollision::_addShape( btCollisionShape *shape, const MatrixF &localXfm ) 98{ 99 AssertFatal( !shape->isCompound(), "BtCollision::_addShape - Shape should not be a compound!" ); 100 101 // Stick the shape into the array to delete later. Remember 102 // that the compound shape doesn't delete its children. 103 mShapes.push_back( shape ); 104 105 // If this is the first shape then just store the 106 // local transform and we're done. 107 if ( mShapes.size() == 1 ) 108 { 109 mLocalXfm = localXfm; 110 return; 111 } 112 113 // We use a compound to store the shapes with their 114 // local transforms... so create it if we haven't already. 115 if ( !mCompound ) 116 { 117 mCompound = new btCompoundShape(); 118 119 // There should only be one shape now... add it and 120 // clear the local transform. 121 mCompound->addChildShape( btCast<btTransform>( mLocalXfm ), mShapes.first() ); 122 mLocalXfm = MatrixF::Identity; 123 } 124 125 // Add the new shape to the compound. 126 mCompound->addChildShape( btCast<btTransform>( localXfm ), shape ); 127} 128 129void BtCollision::addPlane( const PlaneF &plane ) 130{ 131 // NOTE: Torque uses a negative D... thats why we flip it here. 132 btStaticPlaneShape *shape = new btStaticPlaneShape( btVector3( plane.x, plane.y, plane.z ), -plane.d ); 133 _addShape( shape, MatrixF::Identity ); 134} 135 136void BtCollision::addBox( const Point3F &halfWidth, 137 const MatrixF &localXfm ) 138{ 139 btBoxShape *shape = new btBoxShape( btVector3( halfWidth.x, halfWidth.y, halfWidth.z ) ); 140 shape->setMargin( 0.01f ); 141 _addShape( shape, localXfm ); 142} 143 144void BtCollision::addSphere( const F32 radius, 145 const MatrixF &localXfm ) 146{ 147 btSphereShape *shape = new btSphereShape( radius ); 148 shape->setMargin( 0.01f ); 149 _addShape( shape, localXfm ); 150} 151 152void BtCollision::addCapsule( F32 radius, 153 F32 height, 154 const MatrixF &localXfm ) 155{ 156 btCapsuleShape *shape = new btCapsuleShape( radius, height ); 157 shape->setMargin( 0.01f ); 158 _addShape( shape, localXfm ); 159} 160 161bool BtCollision::addConvex( const Point3F *points, 162 U32 count, 163 const MatrixF &localXfm ) 164{ 165 btConvexHullShape *shape = new btConvexHullShape( (btScalar*)points, count, sizeof( Point3F ) ); 166 shape->setMargin( 0.01f ); 167 _addShape( shape, localXfm ); 168 return true; 169} 170 171bool BtCollision::addTriangleMesh( const Point3F *vert, 172 U32 vertCount, 173 const U32 *index, 174 U32 triCount, 175 const MatrixF &localXfm ) 176{ 177 // Setup the interface for loading the triangles. 178 btTriangleMesh *meshInterface = new btTriangleMesh( true, false ); 179 for ( ; triCount-- ; ) 180 { 181 meshInterface->addTriangle( btCast<btVector3>( vert[ *( index + 0 ) ] ), 182 btCast<btVector3>( vert[ *( index + 1 ) ] ), 183 btCast<btVector3>( vert[ *( index + 2 ) ] ), 184 false ); 185 186 index += 3; 187 } 188 mMeshInterfaces.push_back( meshInterface ); 189 190 btBvhTriangleMeshShape *shape = new btBvhTriangleMeshShape( meshInterface, true, true ); 191 shape->setMargin( 0.01f ); 192 _addShape( shape, localXfm ); 193 194 return true; 195} 196 197bool BtCollision::addHeightfield( const U16 *heights, 198 const bool *holes, // TODO: Bullet height fields do not support holes 199 U32 blockSize, 200 F32 metersPerSample, 201 const MatrixF &localXfm ) 202{ 203 // We pass the absolute maximum and minimum of a U16 height 204 // field and not the actual min and max. This helps with 205 // placement. 206 const F32 heightScale = 0.03125f; 207 const F32 minHeight = 0; 208 const F32 maxHeight = 65535 * heightScale; 209 210 btHeightfieldTerrainShapeCustom* shape = new btHeightfieldTerrainShapeCustom(holes, 211 blockSize, blockSize, 212 reinterpret_cast<const void*>(heights), 213 heightScale, 214 0, 0xFFFF * heightScale, 215 2, // Z up! 216 PHY_SHORT, 217 false); 218 219 shape->setMargin( 0.01f ); 220 shape->setLocalScaling( btVector3( metersPerSample, metersPerSample, 1.0f ) ); 221 shape->setUseDiamondSubdivision( true ); 222 223 // The local axis of the heightfield is the exact center of 224 // its bounds defined as... 225 // 226 // ( blockSize * samplesPerMeter, blockSize * samplesPerMeter, maxHeight ) / 2.0f 227 // 228 // So we create a local transform to move it to the min point 229 // of the bounds so it matched Torque terrain. 230 Point3F offset( (F32)blockSize * metersPerSample / 2.0f, 231 (F32)blockSize * metersPerSample / 2.0f, 232 maxHeight / 2.0f ); 233 234 // And also bump it by half a sample square size. 235 offset.x -= metersPerSample / 2.0f; 236 offset.y -= metersPerSample / 2.0f; 237 238 MatrixF offsetXfm( true ); 239 offsetXfm.setPosition( offset ); 240 241 _addShape( shape, offsetXfm ); 242 243 return true; 244} 245 246void btHeightfieldTerrainShapeCustom::processAllTriangles(btTriangleCallback* callback, const btVector3& aabbMin, const btVector3& aabbMax) const 247{ 248 // scale down the input aabb's so they are in local (non-scaled) coordinates 249 btVector3 localAabbMin = aabbMin * btVector3(1.f / m_localScaling[0], 1.f / m_localScaling[1], 1.f / m_localScaling[2]); 250 btVector3 localAabbMax = aabbMax * btVector3(1.f / m_localScaling[0], 1.f / m_localScaling[1], 1.f / m_localScaling[2]); 251 252 // account for local origin 253 localAabbMin += m_localOrigin; 254 localAabbMax += m_localOrigin; 255 256 //quantize the aabbMin and aabbMax, and adjust the start/end ranges 257 int quantizedAabbMin[3]; 258 int quantizedAabbMax[3]; 259 quantizeWithClamp(quantizedAabbMin, localAabbMin, 0); 260 quantizeWithClamp(quantizedAabbMax, localAabbMax, 1); 261 262 // expand the min/max quantized values 263 // this is to catch the case where the input aabb falls between grid points! 264 for (int i = 0; i < 3; ++i) { 265 quantizedAabbMin[i]--; 266 quantizedAabbMax[i]++; 267 } 268 269 int startX = 0; 270 int endX = m_heightStickWidth - 1; 271 int startJ = 0; 272 int endJ = m_heightStickLength - 1; 273 274 switch (m_upAxis) 275 { 276 case 0: 277 { 278 if (quantizedAabbMin[1] > startX) 279 startX = quantizedAabbMin[1]; 280 if (quantizedAabbMax[1] < endX) 281 endX = quantizedAabbMax[1]; 282 if (quantizedAabbMin[2] > startJ) 283 startJ = quantizedAabbMin[2]; 284 if (quantizedAabbMax[2] < endJ) 285 endJ = quantizedAabbMax[2]; 286 break; 287 } 288 case 1: 289 { 290 if (quantizedAabbMin[0] > startX) 291 startX = quantizedAabbMin[0]; 292 if (quantizedAabbMax[0] < endX) 293 endX = quantizedAabbMax[0]; 294 if (quantizedAabbMin[2] > startJ) 295 startJ = quantizedAabbMin[2]; 296 if (quantizedAabbMax[2] < endJ) 297 endJ = quantizedAabbMax[2]; 298 break; 299 }; 300 case 2: 301 { 302 if (quantizedAabbMin[0] > startX) 303 startX = quantizedAabbMin[0]; 304 if (quantizedAabbMax[0] < endX) 305 endX = quantizedAabbMax[0]; 306 if (quantizedAabbMin[1] > startJ) 307 startJ = quantizedAabbMin[1]; 308 if (quantizedAabbMax[1] < endJ) 309 endJ = quantizedAabbMax[1]; 310 break; 311 } 312 default: 313 { 314 //need to get valid m_upAxis 315 btAssert(0); 316 } 317 } 318 319 for (int j = startJ; j < endJ; j++) 320 { 321 for (int x = startX; x < endX; x++) 322 { 323 U32 index = (m_heightStickLength - (m_heightStickLength - x - 1)) + (j * m_heightStickWidth); 324 325 if (mHoles && mHoles[getMax((S32)index - 1, 0)]) 326 continue; 327 328 btVector3 vertices[3]; 329 if (m_flipQuadEdges || (m_useDiamondSubdivision && !((j + x) & 1)) || (m_useZigzagSubdivision && !(j & 1))) 330 { 331 //first triangle 332 getVertex(x, j, vertices[0]); 333 getVertex(x, j + 1, vertices[1]); 334 getVertex(x + 1, j + 1, vertices[2]); 335 callback->processTriangle(vertices, x, j); 336 //second triangle 337 // getVertex(x,j,vertices[0]);//already got this vertex before, thanks to Danny Chapman 338 getVertex(x + 1, j + 1, vertices[1]); 339 getVertex(x + 1, j, vertices[2]); 340 callback->processTriangle(vertices, x, j); 341 } 342 else 343 { 344 //first triangle 345 getVertex(x, j, vertices[0]); 346 getVertex(x, j + 1, vertices[1]); 347 getVertex(x + 1, j, vertices[2]); 348 callback->processTriangle(vertices, x, j); 349 //second triangle 350 getVertex(x + 1, j, vertices[0]); 351 //getVertex(x,j+1,vertices[1]); 352 getVertex(x + 1, j + 1, vertices[2]); 353 callback->processTriangle(vertices, x, j); 354 } 355 } 356 } 357} 358