Torque3D Documentation / _generateds / btCollision.cpp

btCollision.cpp

Engine/source/T3D/physics/bullet/btCollision.cpp

More...

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