Finally upgraded to latest Bullet subversion, about to release 2.71. Some recent changes in extern/bullet2 need to be re-applied, will check with Benoit. Ray tests in 0_FPS_Template.blend is broken, didn't figure out why yet.

HELP BUILD SYSTEM MAINTAINERS: Please help with updating all build systems: the newly added files need to be added. Note that the src/SoftBody has been added for future extension of real-time soft bodies.
This commit is contained in:
Erwin Coumans
2008-09-03 02:27:16 +00:00
parent 33ac84e888
commit 1926e84650
221 changed files with 24976 additions and 5260 deletions

View File

@@ -23,11 +23,145 @@ subject to the following restrictions:
#ifndef BULLET_C_API_H #ifndef BULLET_C_API_H
#define BULLET_C_API_H #define BULLET_C_API_H
#define PL_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name
#ifdef BT_USE_DOUBLE_PRECISION
typedef double plReal;
#else
typedef float plReal;
#endif
typedef plReal plVector3[3];
typedef plReal plQuaternion[4];
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
double plNearestPoints(float p1[3], float p2[3], float p3[3], float q1[3], float q2[3], float q3[3], float *pa, float *pb, float normal[3]); /* Particular physics SDK */
PL_DECLARE_HANDLE(plPhysicsSdkHandle);
/* Dynamics world, belonging to some physics SDK */
PL_DECLARE_HANDLE(plDynamicsWorldHandle);
/* Rigid Body that can be part of a Dynamics World */
PL_DECLARE_HANDLE(plRigidBodyHandle);
/* Collision Shape/Geometry, property of a Rigid Body */
PL_DECLARE_HANDLE(plCollisionShapeHandle);
/* Constraint for Rigid Bodies */
PL_DECLARE_HANDLE(plConstraintHandle);
/* Triangle Mesh interface */
PL_DECLARE_HANDLE(plMeshInterfaceHandle);
/* Broadphase Scene/Proxy Handles */
PL_DECLARE_HANDLE(plCollisionBroadphaseHandle);
PL_DECLARE_HANDLE(plBroadphaseProxyHandle);
PL_DECLARE_HANDLE(plCollisionWorldHandle);
/*
Create and Delete a Physics SDK
*/
extern plPhysicsSdkHandle plNewBulletSdk(); //this could be also another sdk, like ODE, PhysX etc.
extern void plDeletePhysicsSdk(plPhysicsSdkHandle physicsSdk);
/* Collision World, not strictly necessary, you can also just create a Dynamics World with Rigid Bodies which internally manages the Collision World with Collision Objects */
typedef void(*btBroadphaseCallback)(void* clientData, void* object1,void* object2);
extern plCollisionBroadphaseHandle plCreateSapBroadphase(btBroadphaseCallback beginCallback,btBroadphaseCallback endCallback);
extern void plDestroyBroadphase(plCollisionBroadphaseHandle bp);
extern plBroadphaseProxyHandle plCreateProxy(plCollisionBroadphaseHandle bp, void* clientData, plReal minX,plReal minY,plReal minZ, plReal maxX,plReal maxY, plReal maxZ);
extern void plDestroyProxy(plCollisionBroadphaseHandle bp, plBroadphaseProxyHandle proxyHandle);
extern void plSetBoundingBox(plBroadphaseProxyHandle proxyHandle, plReal minX,plReal minY,plReal minZ, plReal maxX,plReal maxY, plReal maxZ);
/* todo: add pair cache support with queries like add/remove/find pair */
extern plCollisionWorldHandle plCreateCollisionWorld(plPhysicsSdkHandle physicsSdk);
/* todo: add/remove objects */
/* Dynamics World */
extern plDynamicsWorldHandle plCreateDynamicsWorld(plPhysicsSdkHandle physicsSdk);
extern void plDeleteDynamicsWorld(plDynamicsWorldHandle world);
extern void plStepSimulation(plDynamicsWorldHandle, plReal timeStep);
extern void plAddRigidBody(plDynamicsWorldHandle world, plRigidBodyHandle object);
extern void plRemoveRigidBody(plDynamicsWorldHandle world, plRigidBodyHandle object);
/* Rigid Body */
extern plRigidBodyHandle plCreateRigidBody( void* user_data, float mass, plCollisionShapeHandle cshape );
extern void plDeleteRigidBody(plRigidBodyHandle body);
/* Collision Shape definition */
extern plCollisionShapeHandle plNewSphereShape(plReal radius);
extern plCollisionShapeHandle plNewBoxShape(plReal x, plReal y, plReal z);
extern plCollisionShapeHandle plNewCapsuleShape(plReal radius, plReal height);
extern plCollisionShapeHandle plNewConeShape(plReal radius, plReal height);
extern plCollisionShapeHandle plNewCylinderShape(plReal radius, plReal height);
extern plCollisionShapeHandle plNewCompoundShape();
extern void plAddChildShape(plCollisionShapeHandle compoundShape,plCollisionShapeHandle childShape, plVector3 childPos,plQuaternion childOrn);
extern void plDeleteShape(plCollisionShapeHandle shape);
/* Convex Meshes */
extern plCollisionShapeHandle plNewConvexHullShape();
extern void plAddVertex(plCollisionShapeHandle convexHull, plReal x,plReal y,plReal z);
/* Concave static triangle meshes */
extern plMeshInterfaceHandle plNewMeshInterface();
extern void plAddTriangle(plMeshInterfaceHandle meshHandle, plVector3 v0,plVector3 v1,plVector3 v2);
extern plCollisionShapeHandle plNewStaticTriangleMeshShape(plMeshInterfaceHandle);
extern void plSetScaling(plCollisionShapeHandle shape, plVector3 scaling);
/* SOLID has Response Callback/Table/Management */
/* PhysX has Triggers, User Callbacks and filtering */
/* ODE has the typedef void dNearCallback (void *data, dGeomID o1, dGeomID o2); */
/* typedef void plUpdatedPositionCallback(void* userData, plRigidBodyHandle rbHandle, plVector3 pos); */
/* typedef void plUpdatedOrientationCallback(void* userData, plRigidBodyHandle rbHandle, plQuaternion orientation); */
/* get world transform */
extern void plGetOpenGLMatrix(plRigidBodyHandle object, plReal* matrix);
extern void plGetPosition(plRigidBodyHandle object,plVector3 position);
extern void plGetOrientation(plRigidBodyHandle object,plQuaternion orientation);
/* set world transform (position/orientation) */
extern void plSetPosition(plRigidBodyHandle object, const plVector3 position);
extern void plSetOrientation(plRigidBodyHandle object, const plQuaternion orientation);
extern void plSetEuler(plReal yaw,plReal pitch,plReal roll, plQuaternion orient);
typedef struct plRayCastResult {
plRigidBodyHandle m_body;
plCollisionShapeHandle m_shape;
plVector3 m_positionWorld;
plVector3 m_normalWorld;
} plRayCastResult;
extern int plRayCast(plDynamicsWorldHandle world, const plVector3 rayStart, const plVector3 rayEnd, plRayCastResult res);
/* Sweep API */
/* extern plRigidBodyHandle plObjectCast(plDynamicsWorldHandle world, const plVector3 rayStart, const plVector3 rayEnd, plVector3 hitpoint, plVector3 normal); */
/* Continuous Collision Detection API */
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -21,640 +21,18 @@
#include <assert.h> #include <assert.h>
#ifdef DEBUG_BROADPHASE btAxisSweep3::btAxisSweep3(const btPoint3& worldAabbMin,const btPoint3& worldAabbMax, unsigned short int maxHandles, btOverlappingPairCache* pairCache)
#include <stdio.h> :btAxisSweep3Internal<unsigned short int>(worldAabbMin,worldAabbMax,0xfffe,0xffff,maxHandles,pairCache)
void btAxisSweep3::debugPrintAxis(int axis, bool checkCardinality)
{ {
int numEdges = m_pHandles[0].m_maxEdges[axis];
printf("SAP Axis %d, numEdges=%d\n",axis,numEdges);
int i;
for (i=0;i<numEdges+1;i++)
{
Edge* pEdge = m_pEdges[axis] + i;
Handle* pHandlePrev = getHandle(pEdge->m_handle);
int handleIndex = pEdge->IsMax()? pHandlePrev->m_maxEdges[axis] : pHandlePrev->m_minEdges[axis];
char beginOrEnd;
beginOrEnd=pEdge->IsMax()?'E':'B';
printf(" [%c,h=%d,p=%x,i=%d]\n",beginOrEnd,pEdge->m_handle,pEdge->m_pos,handleIndex);
}
if (checkCardinality)
assert(numEdges == m_numHandles*2+1);
}
#endif //DEBUG_BROADPHASE
btBroadphaseProxy* btAxisSweep3::createProxy( const btVector3& min, const btVector3& max,int shapeType,void* userPtr,short int collisionFilterGroup,short int collisionFilterMask)
{
(void)shapeType;
BP_FP_INT_TYPE handleId = addHandle(min,max, userPtr,collisionFilterGroup,collisionFilterMask);
Handle* handle = getHandle(handleId);
return handle;
}
void btAxisSweep3::destroyProxy(btBroadphaseProxy* proxy)
{
Handle* handle = static_cast<Handle*>(proxy);
removeHandle(handle->m_handleId);
}
void btAxisSweep3::setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax)
{
Handle* handle = static_cast<Handle*>(proxy);
updateHandle(handle->m_handleId,aabbMin,aabbMax);
}
btAxisSweep3::btAxisSweep3(const btPoint3& worldAabbMin,const btPoint3& worldAabbMax, int maxHandles)
:btOverlappingPairCache()
{
m_invalidPair = 0;
//assert(bounds.HasVolume());
// 1 handle is reserved as sentinel // 1 handle is reserved as sentinel
btAssert(maxHandles > 1 && maxHandles < BP_MAX_HANDLES); btAssert(maxHandles > 1 && maxHandles < 32767);
// init bounds
m_worldAabbMin = worldAabbMin;
m_worldAabbMax = worldAabbMax;
btVector3 aabbSize = m_worldAabbMax - m_worldAabbMin;
BP_FP_INT_TYPE maxInt = BP_HANDLE_SENTINEL;
m_quantize = btVector3(btScalar(maxInt),btScalar(maxInt),btScalar(maxInt)) / aabbSize;
// allocate handles buffer and put all handles on free list
m_pHandles = new Handle[maxHandles];
m_maxHandles = maxHandles;
m_numHandles = 0;
// handle 0 is reserved as the null index, and is also used as the sentinel
m_firstFreeHandle = 1;
{
for (BP_FP_INT_TYPE i = m_firstFreeHandle; i < maxHandles; i++)
m_pHandles[i].SetNextFree(i + 1);
m_pHandles[maxHandles - 1].SetNextFree(0);
}
{
// allocate edge buffers
for (int i = 0; i < 3; i++)
m_pEdges[i] = new Edge[maxHandles * 2];
}
//removed overlap management
// make boundary sentinels
m_pHandles[0].m_clientObject = 0;
for (int axis = 0; axis < 3; axis++)
{
m_pHandles[0].m_minEdges[axis] = 0;
m_pHandles[0].m_maxEdges[axis] = 1;
m_pEdges[axis][0].m_pos = 0;
m_pEdges[axis][0].m_handle = 0;
m_pEdges[axis][1].m_pos = BP_HANDLE_SENTINEL;
m_pEdges[axis][1].m_handle = 0;
#ifdef DEBUG_BROADPHASE
debugPrintAxis(axis);
#endif //DEBUG_BROADPHASE
}
} }
btAxisSweep3::~btAxisSweep3()
bt32BitAxisSweep3::bt32BitAxisSweep3(const btPoint3& worldAabbMin,const btPoint3& worldAabbMax, unsigned int maxHandles , btOverlappingPairCache* pairCache )
:btAxisSweep3Internal<unsigned int>(worldAabbMin,worldAabbMax,0xfffffffe,0x7fffffff,maxHandles,pairCache)
{ {
// 1 handle is reserved as sentinel
for (int i = 2; i >= 0; i--) btAssert(maxHandles > 1 && maxHandles < 2147483647);
delete[] m_pEdges[i];
delete[] m_pHandles;
}
void btAxisSweep3::quantize(BP_FP_INT_TYPE* out, const btPoint3& point, int isMax) const
{
btPoint3 clampedPoint(point);
clampedPoint.setMax(m_worldAabbMin);
clampedPoint.setMin(m_worldAabbMax);
btVector3 v = (clampedPoint - m_worldAabbMin) * m_quantize;
out[0] = (BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v.getX() & BP_HANDLE_MASK) | isMax);
out[1] = (BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v.getY() & BP_HANDLE_MASK) | isMax);
out[2] = (BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v.getZ() & BP_HANDLE_MASK) | isMax);
}
BP_FP_INT_TYPE btAxisSweep3::allocHandle()
{
assert(m_firstFreeHandle);
BP_FP_INT_TYPE handle = m_firstFreeHandle;
m_firstFreeHandle = getHandle(handle)->GetNextFree();
m_numHandles++;
return handle;
}
void btAxisSweep3::freeHandle(BP_FP_INT_TYPE handle)
{
assert(handle > 0 && handle < m_maxHandles);
getHandle(handle)->SetNextFree(m_firstFreeHandle);
m_firstFreeHandle = handle;
m_numHandles--;
}
BP_FP_INT_TYPE btAxisSweep3::addHandle(const btPoint3& aabbMin,const btPoint3& aabbMax, void* pOwner,short int collisionFilterGroup,short int collisionFilterMask)
{
// quantize the bounds
BP_FP_INT_TYPE min[3], max[3];
quantize(min, aabbMin, 0);
quantize(max, aabbMax, 1);
// allocate a handle
BP_FP_INT_TYPE handle = allocHandle();
assert(handle!= 0xcdcd);
Handle* pHandle = getHandle(handle);
pHandle->m_handleId = handle;
//pHandle->m_pOverlaps = 0;
pHandle->m_clientObject = pOwner;
pHandle->m_collisionFilterGroup = collisionFilterGroup;
pHandle->m_collisionFilterMask = collisionFilterMask;
// compute current limit of edge arrays
BP_FP_INT_TYPE limit = m_numHandles * 2;
// insert new edges just inside the max boundary edge
for (BP_FP_INT_TYPE axis = 0; axis < 3; axis++)
{
m_pHandles[0].m_maxEdges[axis] += 2;
m_pEdges[axis][limit + 1] = m_pEdges[axis][limit - 1];
m_pEdges[axis][limit - 1].m_pos = min[axis];
m_pEdges[axis][limit - 1].m_handle = handle;
m_pEdges[axis][limit].m_pos = max[axis];
m_pEdges[axis][limit].m_handle = handle;
pHandle->m_minEdges[axis] = limit - 1;
pHandle->m_maxEdges[axis] = limit;
}
// now sort the new edges to their correct position
sortMinDown(0, pHandle->m_minEdges[0], false);
sortMaxDown(0, pHandle->m_maxEdges[0], false);
sortMinDown(1, pHandle->m_minEdges[1], false);
sortMaxDown(1, pHandle->m_maxEdges[1], false);
sortMinDown(2, pHandle->m_minEdges[2], true);
sortMaxDown(2, pHandle->m_maxEdges[2], true);
return handle;
}
void btAxisSweep3::removeHandle(BP_FP_INT_TYPE handle)
{
Handle* pHandle = getHandle(handle);
//explicitly remove the pairs containing the proxy
//we could do it also in the sortMinUp (passing true)
//todo: compare performance
removeOverlappingPairsContainingProxy(pHandle);
// compute current limit of edge arrays
int limit = m_numHandles * 2;
int axis;
for (axis = 0;axis<3;axis++)
{
m_pHandles[0].m_maxEdges[axis] -= 2;
}
// remove the edges by sorting them up to the end of the list
for ( axis = 0; axis < 3; axis++)
{
Edge* pEdges = m_pEdges[axis];
BP_FP_INT_TYPE max = pHandle->m_maxEdges[axis];
pEdges[max].m_pos = BP_HANDLE_SENTINEL;
sortMaxUp(axis,max,false);
BP_FP_INT_TYPE i = pHandle->m_minEdges[axis];
pEdges[i].m_pos = BP_HANDLE_SENTINEL;
sortMinUp(axis,i,false);
pEdges[limit-1].m_handle = 0;
pEdges[limit-1].m_pos = BP_HANDLE_SENTINEL;
#ifdef DEBUG_BROADPHASE
debugPrintAxis(axis,false);
#endif //DEBUG_BROADPHASE
}
// free the handle
freeHandle(handle);
}
extern int gOverlappingPairs;
void btAxisSweep3::refreshOverlappingPairs()
{
}
void btAxisSweep3::processAllOverlappingPairs(btOverlapCallback* callback)
{
//perform a sort, to find duplicates and to sort 'invalid' pairs to the end
m_overlappingPairArray.heapSort(btBroadphasePairSortPredicate());
//remove the 'invalid' ones
#ifdef USE_POPBACK_REMOVAL
while (m_invalidPair>0)
{
m_invalidPair--;
m_overlappingPairArray.pop_back();
}
#else
m_overlappingPairArray.resize(m_overlappingPairArray.size() - m_invalidPair);
m_invalidPair = 0;
#endif
int i;
btBroadphasePair previousPair;
previousPair.m_pProxy0 = 0;
previousPair.m_pProxy1 = 0;
previousPair.m_algorithm = 0;
for (i=0;i<m_overlappingPairArray.size();i++)
{
btBroadphasePair& pair = m_overlappingPairArray[i];
bool isDuplicate = (pair == previousPair);
previousPair = pair;
bool needsRemoval = false;
if (!isDuplicate)
{
bool hasOverlap = testOverlap(pair.m_pProxy0,pair.m_pProxy1);
if (hasOverlap)
{
needsRemoval = callback->processOverlap(pair);
} else
{
needsRemoval = true;
}
} else
{
//remove duplicate
needsRemoval = true;
//should have no algorithm
btAssert(!pair.m_algorithm);
}
if (needsRemoval)
{
cleanOverlappingPair(pair);
// m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1);
// m_overlappingPairArray.pop_back();
pair.m_pProxy0 = 0;
pair.m_pProxy1 = 0;
m_invalidPair++;
gOverlappingPairs--;
}
}
}
bool btAxisSweep3::testOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1)
{
const Handle* pHandleA = static_cast<Handle*>(proxy0);
const Handle* pHandleB = static_cast<Handle*>(proxy1);
//optimization 1: check the array index (memory address), instead of the m_pos
for (int axis = 0; axis < 3; axis++)
{
if (pHandleA->m_maxEdges[axis] < pHandleB->m_minEdges[axis] ||
pHandleB->m_maxEdges[axis] < pHandleA->m_minEdges[axis])
{
return false;
}
}
return true;
}
bool btAxisSweep3::testOverlap(int ignoreAxis,const Handle* pHandleA, const Handle* pHandleB)
{
//optimization 1: check the array index (memory address), instead of the m_pos
for (int axis = 0; axis < 3; axis++)
{
if (axis != ignoreAxis)
{
if (pHandleA->m_maxEdges[axis] < pHandleB->m_minEdges[axis] ||
pHandleB->m_maxEdges[axis] < pHandleA->m_minEdges[axis])
{
return false;
}
}
}
//optimization 2: only 2 axis need to be tested (conflicts with 'delayed removal' optimization)
/*for (int axis = 0; axis < 3; axis++)
{
if (m_pEdges[axis][pHandleA->m_maxEdges[axis]].m_pos < m_pEdges[axis][pHandleB->m_minEdges[axis]].m_pos ||
m_pEdges[axis][pHandleB->m_maxEdges[axis]].m_pos < m_pEdges[axis][pHandleA->m_minEdges[axis]].m_pos)
{
return false;
}
}
*/
return true;
}
void btAxisSweep3::updateHandle(BP_FP_INT_TYPE handle, const btPoint3& aabbMin,const btPoint3& aabbMax)
{
// assert(bounds.IsFinite());
//assert(bounds.HasVolume());
Handle* pHandle = getHandle(handle);
// quantize the new bounds
BP_FP_INT_TYPE min[3], max[3];
quantize(min, aabbMin, 0);
quantize(max, aabbMax, 1);
// update changed edges
for (int axis = 0; axis < 3; axis++)
{
BP_FP_INT_TYPE emin = pHandle->m_minEdges[axis];
BP_FP_INT_TYPE emax = pHandle->m_maxEdges[axis];
int dmin = (int)min[axis] - (int)m_pEdges[axis][emin].m_pos;
int dmax = (int)max[axis] - (int)m_pEdges[axis][emax].m_pos;
m_pEdges[axis][emin].m_pos = min[axis];
m_pEdges[axis][emax].m_pos = max[axis];
// expand (only adds overlaps)
if (dmin < 0)
sortMinDown(axis, emin);
if (dmax > 0)
sortMaxUp(axis, emax);
// shrink (only removes overlaps)
if (dmin > 0)
sortMinUp(axis, emin);
if (dmax < 0)
sortMaxDown(axis, emax);
#ifdef DEBUG_BROADPHASE
debugPrintAxis(axis);
#endif //DEBUG_BROADPHASE
}
}
// sorting a min edge downwards can only ever *add* overlaps
void btAxisSweep3::sortMinDown(int axis, BP_FP_INT_TYPE edge, bool updateOverlaps)
{
Edge* pEdge = m_pEdges[axis] + edge;
Edge* pPrev = pEdge - 1;
Handle* pHandleEdge = getHandle(pEdge->m_handle);
while (pEdge->m_pos < pPrev->m_pos)
{
Handle* pHandlePrev = getHandle(pPrev->m_handle);
if (pPrev->IsMax())
{
// if previous edge is a maximum check the bounds and add an overlap if necessary
if (updateOverlaps && testOverlap(axis,pHandleEdge, pHandlePrev))
{
addOverlappingPair(pHandleEdge,pHandlePrev);
//AddOverlap(pEdge->m_handle, pPrev->m_handle);
}
// update edge reference in other handle
pHandlePrev->m_maxEdges[axis]++;
}
else
pHandlePrev->m_minEdges[axis]++;
pHandleEdge->m_minEdges[axis]--;
// swap the edges
Edge swap = *pEdge;
*pEdge = *pPrev;
*pPrev = swap;
// decrement
pEdge--;
pPrev--;
}
#ifdef DEBUG_BROADPHASE
debugPrintAxis(axis);
#endif //DEBUG_BROADPHASE
}
// sorting a min edge upwards can only ever *remove* overlaps
void btAxisSweep3::sortMinUp(int axis, BP_FP_INT_TYPE edge, bool updateOverlaps)
{
Edge* pEdge = m_pEdges[axis] + edge;
Edge* pNext = pEdge + 1;
Handle* pHandleEdge = getHandle(pEdge->m_handle);
while (pNext->m_handle && (pEdge->m_pos >= pNext->m_pos))
{
Handle* pHandleNext = getHandle(pNext->m_handle);
if (pNext->IsMax())
{
// if next edge is maximum remove any overlap between the two handles
if (updateOverlaps)
{
/*
Handle* handle0 = getHandle(pEdge->m_handle);
Handle* handle1 = getHandle(pNext->m_handle);
btBroadphasePair tmpPair(*handle0,*handle1);
removeOverlappingPair(tmpPair);
*/
}
// update edge reference in other handle
pHandleNext->m_maxEdges[axis]--;
}
else
pHandleNext->m_minEdges[axis]--;
pHandleEdge->m_minEdges[axis]++;
// swap the edges
Edge swap = *pEdge;
*pEdge = *pNext;
*pNext = swap;
// increment
pEdge++;
pNext++;
}
}
// sorting a max edge downwards can only ever *remove* overlaps
void btAxisSweep3::sortMaxDown(int axis, BP_FP_INT_TYPE edge, bool updateOverlaps)
{
Edge* pEdge = m_pEdges[axis] + edge;
Edge* pPrev = pEdge - 1;
Handle* pHandleEdge = getHandle(pEdge->m_handle);
while (pEdge->m_pos < pPrev->m_pos)
{
Handle* pHandlePrev = getHandle(pPrev->m_handle);
if (!pPrev->IsMax())
{
// if previous edge was a minimum remove any overlap between the two handles
if (updateOverlaps)
{
//this is done during the overlappingpairarray iteration/narrowphase collision
/*
Handle* handle0 = getHandle(pEdge->m_handle);
Handle* handle1 = getHandle(pPrev->m_handle);
btBroadphasePair* pair = findPair(handle0,handle1);
//assert(pair);
if (pair)
{
removeOverlappingPair(*pair);
}
*/
}
// update edge reference in other handle
pHandlePrev->m_minEdges[axis]++;;
}
else
pHandlePrev->m_maxEdges[axis]++;
pHandleEdge->m_maxEdges[axis]--;
// swap the edges
Edge swap = *pEdge;
*pEdge = *pPrev;
*pPrev = swap;
// decrement
pEdge--;
pPrev--;
}
#ifdef DEBUG_BROADPHASE
debugPrintAxis(axis);
#endif //DEBUG_BROADPHASE
}
// sorting a max edge upwards can only ever *add* overlaps
void btAxisSweep3::sortMaxUp(int axis, BP_FP_INT_TYPE edge, bool updateOverlaps)
{
Edge* pEdge = m_pEdges[axis] + edge;
Edge* pNext = pEdge + 1;
Handle* pHandleEdge = getHandle(pEdge->m_handle);
while (pNext->m_handle && (pEdge->m_pos >= pNext->m_pos))
{
Handle* pHandleNext = getHandle(pNext->m_handle);
if (!pNext->IsMax())
{
// if next edge is a minimum check the bounds and add an overlap if necessary
if (updateOverlaps && testOverlap(axis, pHandleEdge, pHandleNext))
{
Handle* handle0 = getHandle(pEdge->m_handle);
Handle* handle1 = getHandle(pNext->m_handle);
addOverlappingPair(handle0,handle1);
}
// update edge reference in other handle
pHandleNext->m_minEdges[axis]--;
}
else
pHandleNext->m_maxEdges[axis]--;
pHandleEdge->m_maxEdges[axis]++;
// swap the edges
Edge swap = *pEdge;
*pEdge = *pNext;
*pNext = swap;
// increment
pEdge++;
pNext++;
}
} }

View File

@@ -19,34 +19,25 @@
#ifndef AXIS_SWEEP_3_H #ifndef AXIS_SWEEP_3_H
#define AXIS_SWEEP_3_H #define AXIS_SWEEP_3_H
#include "../../LinearMath/btPoint3.h" #include "LinearMath/btPoint3.h"
#include "../../LinearMath/btVector3.h" #include "LinearMath/btVector3.h"
#include "btOverlappingPairCache.h" #include "btOverlappingPairCache.h"
#include "btBroadphaseInterface.h"
#include "btBroadphaseProxy.h" #include "btBroadphaseProxy.h"
#include "btOverlappingPairCallback.h"
//Enable BP_USE_FIXEDPOINT_INT_32 if you need more then 32767 objects
//#define BP_USE_FIXEDPOINT_INT_32 1
#ifdef BP_USE_FIXEDPOINT_INT_32
#define BP_FP_INT_TYPE unsigned int
#define BP_MAX_HANDLES 1500000 //arbitrary maximum number of handles
#define BP_HANDLE_SENTINEL 0x7fffffff
#define BP_HANDLE_MASK 0xfffffffe
#else
#define BP_FP_INT_TYPE unsigned short int
#define BP_MAX_HANDLES 32767
#define BP_HANDLE_SENTINEL 0xffff
#define BP_HANDLE_MASK 0xfffe
#endif //BP_USE_FIXEDPOINT_INT_32
//#define DEBUG_BROADPHASE 1 //#define DEBUG_BROADPHASE 1
/// btAxisSweep3 is an efficient implementation of the 3d axis sweep and prune broadphase. /// The internal templace class btAxisSweep3Internal implements the sweep and prune broadphase.
/// It uses arrays rather then lists for storage of the 3 axis. Also it operates using integer coordinates instead of floats. /// It uses quantized integers to represent the begin and end points for each of the 3 axis.
/// The testOverlap check is optimized to check the array index, rather then the actual AABB coordinates/pos /// Dont use this class directly, use btAxisSweep3 or bt32BitAxisSweep3 instead.
class btAxisSweep3 : public btOverlappingPairCache template <typename BP_FP_INT_TYPE>
class btAxisSweep3Internal : public btBroadphaseInterface
{ {
protected:
BP_FP_INT_TYPE m_bpHandleMask;
BP_FP_INT_TYPE m_handleSentinel;
public: public:
@@ -57,40 +48,52 @@ public:
BP_FP_INT_TYPE m_pos; // low bit is min/max BP_FP_INT_TYPE m_pos; // low bit is min/max
BP_FP_INT_TYPE m_handle; BP_FP_INT_TYPE m_handle;
BP_FP_INT_TYPE IsMax() const {return m_pos & 1;} BP_FP_INT_TYPE IsMax() const {return static_cast<BP_FP_INT_TYPE>(m_pos & 1);}
}; };
public: public:
//This breaks the Intel compiler, see http://softwarecommunity.intel.com/isn/Community/en-US/forums/thread/30253577.aspx
class Handle : public btBroadphaseProxy class Handle : public btBroadphaseProxy
//ATTRIBUTE_ALIGNED16(class) Handle : public btBroadphaseProxy
{ {
public: public:
BT_DECLARE_ALIGNED_ALLOCATOR();
// indexes into the edge arrays // indexes into the edge arrays
BP_FP_INT_TYPE m_minEdges[3], m_maxEdges[3]; // 6 * 2 = 12 BP_FP_INT_TYPE m_minEdges[3], m_maxEdges[3]; // 6 * 2 = 12
BP_FP_INT_TYPE m_handleId; // BP_FP_INT_TYPE m_uniqueId;
BP_FP_INT_TYPE m_pad; BP_FP_INT_TYPE m_pad;
//void* m_pOwner; this is now in btBroadphaseProxy.m_clientObject //void* m_pOwner; this is now in btBroadphaseProxy.m_clientObject
inline void SetNextFree(BP_FP_INT_TYPE next) {m_minEdges[0] = next;} SIMD_FORCE_INLINE void SetNextFree(BP_FP_INT_TYPE next) {m_minEdges[0] = next;}
inline BP_FP_INT_TYPE GetNextFree() const {return m_minEdges[0];} SIMD_FORCE_INLINE BP_FP_INT_TYPE GetNextFree() const {return m_minEdges[0];}
}; // 24 bytes + 24 for Edge structures = 44 bytes total per entry }; // 24 bytes + 24 for Edge structures = 44 bytes total per entry
private: protected:
btPoint3 m_worldAabbMin; // overall system bounds btPoint3 m_worldAabbMin; // overall system bounds
btPoint3 m_worldAabbMax; // overall system bounds btPoint3 m_worldAabbMax; // overall system bounds
btVector3 m_quantize; // scaling factor for quantization btVector3 m_quantize; // scaling factor for quantization
BP_FP_INT_TYPE m_numHandles; // number of active handles BP_FP_INT_TYPE m_numHandles; // number of active handles
int m_maxHandles; // max number of handles BP_FP_INT_TYPE m_maxHandles; // max number of handles
Handle* m_pHandles; // handles pool Handle* m_pHandles; // handles pool
void* m_pHandlesRawPtr;
BP_FP_INT_TYPE m_firstFreeHandle; // free handles list BP_FP_INT_TYPE m_firstFreeHandle; // free handles list
Edge* m_pEdges[3]; // edge arrays for the 3 axes (each array has m_maxHandles * 2 + 2 sentinel entries) Edge* m_pEdges[3]; // edge arrays for the 3 axes (each array has m_maxHandles * 2 + 2 sentinel entries)
void* m_pEdgesRawPtr[3];
int m_invalidPair; btOverlappingPairCache* m_pairCache;
///btOverlappingPairCallback is an additional optional user callback for adding/removing overlapping pairs, similar interface to btOverlappingPairCache.
btOverlappingPairCallback* m_userPairCallback;
bool m_ownsPairCache;
int m_invalidPair;
// allocation/deallocation // allocation/deallocation
BP_FP_INT_TYPE allocHandle(); BP_FP_INT_TYPE allocHandle();
@@ -108,29 +111,801 @@ private:
void quantize(BP_FP_INT_TYPE* out, const btPoint3& point, int isMax) const; void quantize(BP_FP_INT_TYPE* out, const btPoint3& point, int isMax) const;
void sortMinDown(int axis, BP_FP_INT_TYPE edge, bool updateOverlaps = true); void sortMinDown(int axis, BP_FP_INT_TYPE edge, btDispatcher* dispatcher, bool updateOverlaps );
void sortMinUp(int axis, BP_FP_INT_TYPE edge, bool updateOverlaps = true); void sortMinUp(int axis, BP_FP_INT_TYPE edge, btDispatcher* dispatcher, bool updateOverlaps );
void sortMaxDown(int axis, BP_FP_INT_TYPE edge, bool updateOverlaps = true); void sortMaxDown(int axis, BP_FP_INT_TYPE edge, btDispatcher* dispatcher, bool updateOverlaps );
void sortMaxUp(int axis, BP_FP_INT_TYPE edge, bool updateOverlaps = true); void sortMaxUp(int axis, BP_FP_INT_TYPE edge, btDispatcher* dispatcher, bool updateOverlaps );
public: public:
btAxisSweep3(const btPoint3& worldAabbMin,const btPoint3& worldAabbMax, int maxHandles = 16384);
virtual ~btAxisSweep3();
virtual void refreshOverlappingPairs(); btAxisSweep3Internal(const btPoint3& worldAabbMin,const btPoint3& worldAabbMax, BP_FP_INT_TYPE handleMask, BP_FP_INT_TYPE handleSentinel, BP_FP_INT_TYPE maxHandles = 16384, btOverlappingPairCache* pairCache=0);
virtual ~btAxisSweep3Internal();
BP_FP_INT_TYPE getNumHandles() const
{
return m_numHandles;
}
virtual void calculateOverlappingPairs(btDispatcher* dispatcher);
BP_FP_INT_TYPE addHandle(const btPoint3& aabbMin,const btPoint3& aabbMax, void* pOwner,short int collisionFilterGroup,short int collisionFilterMask); BP_FP_INT_TYPE addHandle(const btPoint3& aabbMin,const btPoint3& aabbMax, void* pOwner,short int collisionFilterGroup,short int collisionFilterMask,btDispatcher* dispatcher,void* multiSapProxy);
void removeHandle(BP_FP_INT_TYPE handle); void removeHandle(BP_FP_INT_TYPE handle,btDispatcher* dispatcher);
void updateHandle(BP_FP_INT_TYPE handle, const btPoint3& aabbMin,const btPoint3& aabbMax); void updateHandle(BP_FP_INT_TYPE handle, const btPoint3& aabbMin,const btPoint3& aabbMax,btDispatcher* dispatcher);
inline Handle* getHandle(BP_FP_INT_TYPE index) const {return m_pHandles + index;} SIMD_FORCE_INLINE Handle* getHandle(BP_FP_INT_TYPE index) const {return m_pHandles + index;}
void processAllOverlappingPairs(btOverlapCallback* callback); void processAllOverlappingPairs(btOverlapCallback* callback);
//Broadphase Interface //Broadphase Interface
virtual btBroadphaseProxy* createProxy( const btVector3& min, const btVector3& max,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask); virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask,btDispatcher* dispatcher,void* multiSapProxy);
virtual void destroyProxy(btBroadphaseProxy* proxy); virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher);
virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax); virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax,btDispatcher* dispatcher);
bool testOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1);
bool testAabbOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1);
btOverlappingPairCache* getOverlappingPairCache()
{
return m_pairCache;
}
const btOverlappingPairCache* getOverlappingPairCache() const
{
return m_pairCache;
}
void setOverlappingPairUserCallback(btOverlappingPairCallback* pairCallback)
{
m_userPairCallback = pairCallback;
}
const btOverlappingPairCallback* getOverlappingPairUserCallback() const
{
return m_userPairCallback;
}
///getAabb returns the axis aligned bounding box in the 'global' coordinate frame
///will add some transform later
virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const
{
aabbMin = m_worldAabbMin;
aabbMax = m_worldAabbMax;
}
virtual void printStats()
{
/* printf("btAxisSweep3.h\n");
printf("numHandles = %d, maxHandles = %d\n",m_numHandles,m_maxHandles);
printf("aabbMin=%f,%f,%f,aabbMax=%f,%f,%f\n",m_worldAabbMin.getX(),m_worldAabbMin.getY(),m_worldAabbMin.getZ(),
m_worldAabbMax.getX(),m_worldAabbMax.getY(),m_worldAabbMax.getZ());
*/
}
};
////////////////////////////////////////////////////////////////////
#ifdef DEBUG_BROADPHASE
#include <stdio.h>
template <typename BP_FP_INT_TYPE>
void btAxisSweep3<BP_FP_INT_TYPE>::debugPrintAxis(int axis, bool checkCardinality)
{
int numEdges = m_pHandles[0].m_maxEdges[axis];
printf("SAP Axis %d, numEdges=%d\n",axis,numEdges);
int i;
for (i=0;i<numEdges+1;i++)
{
Edge* pEdge = m_pEdges[axis] + i;
Handle* pHandlePrev = getHandle(pEdge->m_handle);
int handleIndex = pEdge->IsMax()? pHandlePrev->m_maxEdges[axis] : pHandlePrev->m_minEdges[axis];
char beginOrEnd;
beginOrEnd=pEdge->IsMax()?'E':'B';
printf(" [%c,h=%d,p=%x,i=%d]\n",beginOrEnd,pEdge->m_handle,pEdge->m_pos,handleIndex);
}
if (checkCardinality)
assert(numEdges == m_numHandles*2+1);
}
#endif //DEBUG_BROADPHASE
template <typename BP_FP_INT_TYPE>
btBroadphaseProxy* btAxisSweep3Internal<BP_FP_INT_TYPE>::createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr,short int collisionFilterGroup,short int collisionFilterMask,btDispatcher* dispatcher,void* multiSapProxy)
{
(void)shapeType;
BP_FP_INT_TYPE handleId = addHandle(aabbMin,aabbMax, userPtr,collisionFilterGroup,collisionFilterMask,dispatcher,multiSapProxy);
Handle* handle = getHandle(handleId);
return handle;
}
template <typename BP_FP_INT_TYPE>
void btAxisSweep3Internal<BP_FP_INT_TYPE>::destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher)
{
Handle* handle = static_cast<Handle*>(proxy);
removeHandle(static_cast<BP_FP_INT_TYPE>(handle->m_uniqueId), dispatcher);
}
template <typename BP_FP_INT_TYPE>
void btAxisSweep3Internal<BP_FP_INT_TYPE>::setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax,btDispatcher* dispatcher)
{
Handle* handle = static_cast<Handle*>(proxy);
updateHandle(static_cast<BP_FP_INT_TYPE>(handle->m_uniqueId), aabbMin, aabbMax,dispatcher);
}
template <typename BP_FP_INT_TYPE>
btAxisSweep3Internal<BP_FP_INT_TYPE>::btAxisSweep3Internal(const btPoint3& worldAabbMin,const btPoint3& worldAabbMax, BP_FP_INT_TYPE handleMask, BP_FP_INT_TYPE handleSentinel,BP_FP_INT_TYPE userMaxHandles, btOverlappingPairCache* pairCache )
:m_bpHandleMask(handleMask),
m_handleSentinel(handleSentinel),
m_pairCache(pairCache),
m_userPairCallback(0),
m_ownsPairCache(false),
m_invalidPair(0)
{
BP_FP_INT_TYPE maxHandles = static_cast<BP_FP_INT_TYPE>(userMaxHandles+1);//need to add one sentinel handle
if (!m_pairCache)
{
void* ptr = btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16);
m_pairCache = new(ptr) btHashedOverlappingPairCache();
m_ownsPairCache = true;
}
//assert(bounds.HasVolume());
// init bounds
m_worldAabbMin = worldAabbMin;
m_worldAabbMax = worldAabbMax;
btVector3 aabbSize = m_worldAabbMax - m_worldAabbMin;
BP_FP_INT_TYPE maxInt = m_handleSentinel;
m_quantize = btVector3(btScalar(maxInt),btScalar(maxInt),btScalar(maxInt)) / aabbSize;
// allocate handles buffer and put all handles on free list
m_pHandlesRawPtr = btAlignedAlloc(sizeof(Handle)*maxHandles,16);
m_pHandles = new(m_pHandlesRawPtr) Handle[maxHandles];
m_maxHandles = maxHandles;
m_numHandles = 0;
// handle 0 is reserved as the null index, and is also used as the sentinel
m_firstFreeHandle = 1;
{
for (BP_FP_INT_TYPE i = m_firstFreeHandle; i < maxHandles; i++)
m_pHandles[i].SetNextFree(static_cast<BP_FP_INT_TYPE>(i + 1));
m_pHandles[maxHandles - 1].SetNextFree(0);
}
{
// allocate edge buffers
for (int i = 0; i < 3; i++)
{
m_pEdgesRawPtr[i] = btAlignedAlloc(sizeof(Edge)*maxHandles*2,16);
m_pEdges[i] = new(m_pEdgesRawPtr[i]) Edge[maxHandles * 2];
}
}
//removed overlap management
// make boundary sentinels
m_pHandles[0].m_clientObject = 0;
for (int axis = 0; axis < 3; axis++)
{
m_pHandles[0].m_minEdges[axis] = 0;
m_pHandles[0].m_maxEdges[axis] = 1;
m_pEdges[axis][0].m_pos = 0;
m_pEdges[axis][0].m_handle = 0;
m_pEdges[axis][1].m_pos = m_handleSentinel;
m_pEdges[axis][1].m_handle = 0;
#ifdef DEBUG_BROADPHASE
debugPrintAxis(axis);
#endif //DEBUG_BROADPHASE
}
}
template <typename BP_FP_INT_TYPE>
btAxisSweep3Internal<BP_FP_INT_TYPE>::~btAxisSweep3Internal()
{
for (int i = 2; i >= 0; i--)
{
btAlignedFree(m_pEdgesRawPtr[i]);
}
btAlignedFree(m_pHandlesRawPtr);
if (m_ownsPairCache)
{
m_pairCache->~btOverlappingPairCache();
btAlignedFree(m_pairCache);
}
}
template <typename BP_FP_INT_TYPE>
void btAxisSweep3Internal<BP_FP_INT_TYPE>::quantize(BP_FP_INT_TYPE* out, const btPoint3& point, int isMax) const
{
btPoint3 clampedPoint(point);
clampedPoint.setMax(m_worldAabbMin);
clampedPoint.setMin(m_worldAabbMax);
btVector3 v = (clampedPoint - m_worldAabbMin) * m_quantize;
out[0] = (BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v.getX() & m_bpHandleMask) | isMax);
out[1] = (BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v.getY() & m_bpHandleMask) | isMax);
out[2] = (BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v.getZ() & m_bpHandleMask) | isMax);
}
template <typename BP_FP_INT_TYPE>
BP_FP_INT_TYPE btAxisSweep3Internal<BP_FP_INT_TYPE>::allocHandle()
{
assert(m_firstFreeHandle);
BP_FP_INT_TYPE handle = m_firstFreeHandle;
m_firstFreeHandle = getHandle(handle)->GetNextFree();
m_numHandles++;
return handle;
}
template <typename BP_FP_INT_TYPE>
void btAxisSweep3Internal<BP_FP_INT_TYPE>::freeHandle(BP_FP_INT_TYPE handle)
{
assert(handle > 0 && handle < m_maxHandles);
getHandle(handle)->SetNextFree(m_firstFreeHandle);
m_firstFreeHandle = handle;
m_numHandles--;
}
template <typename BP_FP_INT_TYPE>
BP_FP_INT_TYPE btAxisSweep3Internal<BP_FP_INT_TYPE>::addHandle(const btPoint3& aabbMin,const btPoint3& aabbMax, void* pOwner,short int collisionFilterGroup,short int collisionFilterMask,btDispatcher* dispatcher,void* multiSapProxy)
{
// quantize the bounds
BP_FP_INT_TYPE min[3], max[3];
quantize(min, aabbMin, 0);
quantize(max, aabbMax, 1);
// allocate a handle
BP_FP_INT_TYPE handle = allocHandle();
Handle* pHandle = getHandle(handle);
pHandle->m_uniqueId = static_cast<int>(handle);
//pHandle->m_pOverlaps = 0;
pHandle->m_clientObject = pOwner;
pHandle->m_collisionFilterGroup = collisionFilterGroup;
pHandle->m_collisionFilterMask = collisionFilterMask;
pHandle->m_multiSapParentProxy = multiSapProxy;
// compute current limit of edge arrays
BP_FP_INT_TYPE limit = static_cast<BP_FP_INT_TYPE>(m_numHandles * 2);
// insert new edges just inside the max boundary edge
for (BP_FP_INT_TYPE axis = 0; axis < 3; axis++)
{
m_pHandles[0].m_maxEdges[axis] += 2;
m_pEdges[axis][limit + 1] = m_pEdges[axis][limit - 1];
m_pEdges[axis][limit - 1].m_pos = min[axis];
m_pEdges[axis][limit - 1].m_handle = handle;
m_pEdges[axis][limit].m_pos = max[axis];
m_pEdges[axis][limit].m_handle = handle;
pHandle->m_minEdges[axis] = static_cast<BP_FP_INT_TYPE>(limit - 1);
pHandle->m_maxEdges[axis] = limit;
}
// now sort the new edges to their correct position
sortMinDown(0, pHandle->m_minEdges[0], dispatcher,false);
sortMaxDown(0, pHandle->m_maxEdges[0], dispatcher,false);
sortMinDown(1, pHandle->m_minEdges[1], dispatcher,false);
sortMaxDown(1, pHandle->m_maxEdges[1], dispatcher,false);
sortMinDown(2, pHandle->m_minEdges[2], dispatcher,true);
sortMaxDown(2, pHandle->m_maxEdges[2], dispatcher,true);
return handle;
}
template <typename BP_FP_INT_TYPE>
void btAxisSweep3Internal<BP_FP_INT_TYPE>::removeHandle(BP_FP_INT_TYPE handle,btDispatcher* dispatcher)
{
Handle* pHandle = getHandle(handle);
//explicitly remove the pairs containing the proxy
//we could do it also in the sortMinUp (passing true)
//todo: compare performance
if (!m_pairCache->hasDeferredRemoval())
{
m_pairCache->removeOverlappingPairsContainingProxy(pHandle,dispatcher);
}
// compute current limit of edge arrays
int limit = static_cast<int>(m_numHandles * 2);
int axis;
for (axis = 0;axis<3;axis++)
{
m_pHandles[0].m_maxEdges[axis] -= 2;
}
// remove the edges by sorting them up to the end of the list
for ( axis = 0; axis < 3; axis++)
{
Edge* pEdges = m_pEdges[axis];
BP_FP_INT_TYPE max = pHandle->m_maxEdges[axis];
pEdges[max].m_pos = m_handleSentinel;
sortMaxUp(axis,max,dispatcher,false);
BP_FP_INT_TYPE i = pHandle->m_minEdges[axis];
pEdges[i].m_pos = m_handleSentinel;
sortMinUp(axis,i,dispatcher,false);
pEdges[limit-1].m_handle = 0;
pEdges[limit-1].m_pos = m_handleSentinel;
#ifdef DEBUG_BROADPHASE
debugPrintAxis(axis,false);
#endif //DEBUG_BROADPHASE
}
// free the handle
freeHandle(handle);
}
extern int gOverlappingPairs;
//#include <stdio.h>
template <typename BP_FP_INT_TYPE>
void btAxisSweep3Internal<BP_FP_INT_TYPE>::calculateOverlappingPairs(btDispatcher* dispatcher)
{
if (m_pairCache->hasDeferredRemoval())
{
btBroadphasePairArray& overlappingPairArray = m_pairCache->getOverlappingPairArray();
//perform a sort, to find duplicates and to sort 'invalid' pairs to the end
overlappingPairArray.quickSort(btBroadphasePairSortPredicate());
overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair);
m_invalidPair = 0;
int i;
btBroadphasePair previousPair;
previousPair.m_pProxy0 = 0;
previousPair.m_pProxy1 = 0;
previousPair.m_algorithm = 0;
for (i=0;i<overlappingPairArray.size();i++)
{
btBroadphasePair& pair = overlappingPairArray[i];
bool isDuplicate = (pair == previousPair);
previousPair = pair;
bool needsRemoval = false;
if (!isDuplicate)
{
bool hasOverlap = testAabbOverlap(pair.m_pProxy0,pair.m_pProxy1);
if (hasOverlap)
{
needsRemoval = false;//callback->processOverlap(pair);
} else
{
needsRemoval = true;
}
} else
{
//remove duplicate
needsRemoval = true;
//should have no algorithm
btAssert(!pair.m_algorithm);
}
if (needsRemoval)
{
m_pairCache->cleanOverlappingPair(pair,dispatcher);
// m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1);
// m_overlappingPairArray.pop_back();
pair.m_pProxy0 = 0;
pair.m_pProxy1 = 0;
m_invalidPair++;
gOverlappingPairs--;
}
}
///if you don't like to skip the invalid pairs in the array, execute following code:
#define CLEAN_INVALID_PAIRS 1
#ifdef CLEAN_INVALID_PAIRS
//perform a sort, to sort 'invalid' pairs to the end
overlappingPairArray.quickSort(btBroadphasePairSortPredicate());
overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair);
m_invalidPair = 0;
#endif//CLEAN_INVALID_PAIRS
//printf("overlappingPairArray.size()=%d\n",overlappingPairArray.size());
}
}
template <typename BP_FP_INT_TYPE>
bool btAxisSweep3Internal<BP_FP_INT_TYPE>::testAabbOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1)
{
const Handle* pHandleA = static_cast<Handle*>(proxy0);
const Handle* pHandleB = static_cast<Handle*>(proxy1);
//optimization 1: check the array index (memory address), instead of the m_pos
for (int axis = 0; axis < 3; axis++)
{
if (pHandleA->m_maxEdges[axis] < pHandleB->m_minEdges[axis] ||
pHandleB->m_maxEdges[axis] < pHandleA->m_minEdges[axis])
{
return false;
}
}
return true;
}
template <typename BP_FP_INT_TYPE>
bool btAxisSweep3Internal<BP_FP_INT_TYPE>::testOverlap(int ignoreAxis,const Handle* pHandleA, const Handle* pHandleB)
{
//optimization 1: check the array index (memory address), instead of the m_pos
for (int axis = 0; axis < 3; axis++)
{
if (axis != ignoreAxis)
{
if (pHandleA->m_maxEdges[axis] < pHandleB->m_minEdges[axis] ||
pHandleB->m_maxEdges[axis] < pHandleA->m_minEdges[axis])
{
return false;
}
}
}
//optimization 2: only 2 axis need to be tested (conflicts with 'delayed removal' optimization)
/*for (int axis = 0; axis < 3; axis++)
{
if (m_pEdges[axis][pHandleA->m_maxEdges[axis]].m_pos < m_pEdges[axis][pHandleB->m_minEdges[axis]].m_pos ||
m_pEdges[axis][pHandleB->m_maxEdges[axis]].m_pos < m_pEdges[axis][pHandleA->m_minEdges[axis]].m_pos)
{
return false;
}
}
*/
return true;
}
template <typename BP_FP_INT_TYPE>
void btAxisSweep3Internal<BP_FP_INT_TYPE>::updateHandle(BP_FP_INT_TYPE handle, const btPoint3& aabbMin,const btPoint3& aabbMax,btDispatcher* dispatcher)
{
// assert(bounds.IsFinite());
//assert(bounds.HasVolume());
Handle* pHandle = getHandle(handle);
// quantize the new bounds
BP_FP_INT_TYPE min[3], max[3];
quantize(min, aabbMin, 0);
quantize(max, aabbMax, 1);
// update changed edges
for (int axis = 0; axis < 3; axis++)
{
BP_FP_INT_TYPE emin = pHandle->m_minEdges[axis];
BP_FP_INT_TYPE emax = pHandle->m_maxEdges[axis];
int dmin = (int)min[axis] - (int)m_pEdges[axis][emin].m_pos;
int dmax = (int)max[axis] - (int)m_pEdges[axis][emax].m_pos;
m_pEdges[axis][emin].m_pos = min[axis];
m_pEdges[axis][emax].m_pos = max[axis];
// expand (only adds overlaps)
if (dmin < 0)
sortMinDown(axis, emin,dispatcher,true);
if (dmax > 0)
sortMaxUp(axis, emax,dispatcher,true);
// shrink (only removes overlaps)
if (dmin > 0)
sortMinUp(axis, emin,dispatcher,true);
if (dmax < 0)
sortMaxDown(axis, emax,dispatcher,true);
#ifdef DEBUG_BROADPHASE
debugPrintAxis(axis);
#endif //DEBUG_BROADPHASE
}
}
// sorting a min edge downwards can only ever *add* overlaps
template <typename BP_FP_INT_TYPE>
void btAxisSweep3Internal<BP_FP_INT_TYPE>::sortMinDown(int axis, BP_FP_INT_TYPE edge, btDispatcher* /* dispatcher */, bool updateOverlaps)
{
Edge* pEdge = m_pEdges[axis] + edge;
Edge* pPrev = pEdge - 1;
Handle* pHandleEdge = getHandle(pEdge->m_handle);
while (pEdge->m_pos < pPrev->m_pos)
{
Handle* pHandlePrev = getHandle(pPrev->m_handle);
if (pPrev->IsMax())
{
// if previous edge is a maximum check the bounds and add an overlap if necessary
if (updateOverlaps && testOverlap(axis,pHandleEdge, pHandlePrev))
{
m_pairCache->addOverlappingPair(pHandleEdge,pHandlePrev);
if (m_userPairCallback)
m_userPairCallback->addOverlappingPair(pHandleEdge,pHandlePrev);
//AddOverlap(pEdge->m_handle, pPrev->m_handle);
}
// update edge reference in other handle
pHandlePrev->m_maxEdges[axis]++;
}
else
pHandlePrev->m_minEdges[axis]++;
pHandleEdge->m_minEdges[axis]--;
// swap the edges
Edge swap = *pEdge;
*pEdge = *pPrev;
*pPrev = swap;
// decrement
pEdge--;
pPrev--;
}
#ifdef DEBUG_BROADPHASE
debugPrintAxis(axis);
#endif //DEBUG_BROADPHASE
}
// sorting a min edge upwards can only ever *remove* overlaps
template <typename BP_FP_INT_TYPE>
void btAxisSweep3Internal<BP_FP_INT_TYPE>::sortMinUp(int axis, BP_FP_INT_TYPE edge, btDispatcher* dispatcher, bool updateOverlaps)
{
Edge* pEdge = m_pEdges[axis] + edge;
Edge* pNext = pEdge + 1;
Handle* pHandleEdge = getHandle(pEdge->m_handle);
while (pNext->m_handle && (pEdge->m_pos >= pNext->m_pos))
{
Handle* pHandleNext = getHandle(pNext->m_handle);
if (pNext->IsMax())
{
// if next edge is maximum remove any overlap between the two handles
if (updateOverlaps)
{
Handle* handle0 = getHandle(pEdge->m_handle);
Handle* handle1 = getHandle(pNext->m_handle);
m_pairCache->removeOverlappingPair(handle0,handle1,dispatcher);
if (m_userPairCallback)
m_userPairCallback->removeOverlappingPair(handle0,handle1,dispatcher);
}
// update edge reference in other handle
pHandleNext->m_maxEdges[axis]--;
}
else
pHandleNext->m_minEdges[axis]--;
pHandleEdge->m_minEdges[axis]++;
// swap the edges
Edge swap = *pEdge;
*pEdge = *pNext;
*pNext = swap;
// increment
pEdge++;
pNext++;
}
}
// sorting a max edge downwards can only ever *remove* overlaps
template <typename BP_FP_INT_TYPE>
void btAxisSweep3Internal<BP_FP_INT_TYPE>::sortMaxDown(int axis, BP_FP_INT_TYPE edge, btDispatcher* dispatcher, bool updateOverlaps)
{
Edge* pEdge = m_pEdges[axis] + edge;
Edge* pPrev = pEdge - 1;
Handle* pHandleEdge = getHandle(pEdge->m_handle);
while (pEdge->m_pos < pPrev->m_pos)
{
Handle* pHandlePrev = getHandle(pPrev->m_handle);
if (!pPrev->IsMax())
{
// if previous edge was a minimum remove any overlap between the two handles
if (updateOverlaps)
{
//this is done during the overlappingpairarray iteration/narrowphase collision
Handle* handle0 = getHandle(pEdge->m_handle);
Handle* handle1 = getHandle(pPrev->m_handle);
m_pairCache->removeOverlappingPair(handle0,handle1,dispatcher);
if (m_userPairCallback)
m_userPairCallback->removeOverlappingPair(handle0,handle1,dispatcher);
}
// update edge reference in other handle
pHandlePrev->m_minEdges[axis]++;;
}
else
pHandlePrev->m_maxEdges[axis]++;
pHandleEdge->m_maxEdges[axis]--;
// swap the edges
Edge swap = *pEdge;
*pEdge = *pPrev;
*pPrev = swap;
// decrement
pEdge--;
pPrev--;
}
#ifdef DEBUG_BROADPHASE
debugPrintAxis(axis);
#endif //DEBUG_BROADPHASE
}
// sorting a max edge upwards can only ever *add* overlaps
template <typename BP_FP_INT_TYPE>
void btAxisSweep3Internal<BP_FP_INT_TYPE>::sortMaxUp(int axis, BP_FP_INT_TYPE edge, btDispatcher* /* dispatcher */, bool updateOverlaps)
{
Edge* pEdge = m_pEdges[axis] + edge;
Edge* pNext = pEdge + 1;
Handle* pHandleEdge = getHandle(pEdge->m_handle);
while (pNext->m_handle && (pEdge->m_pos >= pNext->m_pos))
{
Handle* pHandleNext = getHandle(pNext->m_handle);
if (!pNext->IsMax())
{
// if next edge is a minimum check the bounds and add an overlap if necessary
if (updateOverlaps && testOverlap(axis, pHandleEdge, pHandleNext))
{
Handle* handle0 = getHandle(pEdge->m_handle);
Handle* handle1 = getHandle(pNext->m_handle);
m_pairCache->addOverlappingPair(handle0,handle1);
if (m_userPairCallback)
m_userPairCallback->addOverlappingPair(handle0,handle1);
}
// update edge reference in other handle
pHandleNext->m_minEdges[axis]--;
}
else
pHandleNext->m_maxEdges[axis]--;
pHandleEdge->m_maxEdges[axis]++;
// swap the edges
Edge swap = *pEdge;
*pEdge = *pNext;
*pNext = swap;
// increment
pEdge++;
pNext++;
}
}
////////////////////////////////////////////////////////////////////
/// The btAxisSweep3 is an efficient implementation of the 3d axis sweep and prune broadphase.
/// It uses arrays rather then lists for storage of the 3 axis. Also it operates using 16 bit integer coordinates instead of floats.
/// For large worlds and many objects, use bt32BitAxisSweep3 or btDbvtBroadphase instead. bt32BitAxisSweep3 has higher precision and allows more then 16384 objects at the cost of more memory and bit of performance.
class btAxisSweep3 : public btAxisSweep3Internal<unsigned short int>
{
public:
btAxisSweep3(const btPoint3& worldAabbMin,const btPoint3& worldAabbMax, unsigned short int maxHandles = 16384, btOverlappingPairCache* pairCache = 0);
};
/// The bt32BitAxisSweep3 allows higher precision quantization and more objects compared to the btAxisSweep3 sweep and prune.
/// This comes at the cost of more memory per handle, and a bit slower performance.
/// It uses arrays rather then lists for storage of the 3 axis.
class bt32BitAxisSweep3 : public btAxisSweep3Internal<unsigned int>
{
public:
bt32BitAxisSweep3(const btPoint3& worldAabbMin,const btPoint3& worldAabbMax, unsigned int maxHandles = 1500000, btOverlappingPairCache* pairCache = 0);
}; };

View File

@@ -20,20 +20,34 @@ subject to the following restrictions:
struct btDispatcherInfo; struct btDispatcherInfo;
class btDispatcher; class btDispatcher;
struct btBroadphaseProxy; #include "btBroadphaseProxy.h"
#include "../../LinearMath/btVector3.h" class btOverlappingPairCache;
///BroadphaseInterface for aabb-overlapping object pairs #include "LinearMath/btVector3.h"
///The btBroadphaseInterface class provides an interface to detect aabb-overlapping object pairs.
///Some implementations for this broadphase interface include btAxisSweep3, bt32BitAxisSweep3 and btDbvtBroadphase.
///The actual overlapping pair management, storage, adding and removing of pairs is dealt by the btOverlappingPairCache class.
class btBroadphaseInterface class btBroadphaseInterface
{ {
public: public:
virtual ~btBroadphaseInterface() {} virtual ~btBroadphaseInterface() {}
virtual btBroadphaseProxy* createProxy( const btVector3& min, const btVector3& max,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask) =0; virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy) =0;
virtual void destroyProxy(btBroadphaseProxy* proxy)=0; virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher)=0;
virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax)=0; virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher)=0;
virtual void cleanProxyFromPairs(btBroadphaseProxy* proxy)=0;
///calculateOverlappingPairs is optional: incremental algorithms (sweep and prune) might do it during the set aabb
virtual void calculateOverlappingPairs(btDispatcher* dispatcher)=0;
virtual btOverlappingPairCache* getOverlappingPairCache()=0;
virtual const btOverlappingPairCache* getOverlappingPairCache() const =0;
///getAabb returns the axis aligned bounding box in the 'global' coordinate frame
///will add some transform later
virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const =0;
virtual void printStats() = 0;
}; };

View File

@@ -16,7 +16,8 @@ subject to the following restrictions:
#ifndef BROADPHASE_PROXY_H #ifndef BROADPHASE_PROXY_H
#define BROADPHASE_PROXY_H #define BROADPHASE_PROXY_H
#include "../../LinearMath/btScalar.h" //for SIMD_FORCE_INLINE #include "LinearMath/btScalar.h" //for SIMD_FORCE_INLINE
#include "LinearMath/btAlignedAllocator.h"
/// btDispatcher uses these types /// btDispatcher uses these types
@@ -38,6 +39,7 @@ IMPLICIT_CONVEX_SHAPES_START_HERE,
CONE_SHAPE_PROXYTYPE, CONE_SHAPE_PROXYTYPE,
CONVEX_SHAPE_PROXYTYPE, CONVEX_SHAPE_PROXYTYPE,
CYLINDER_SHAPE_PROXYTYPE, CYLINDER_SHAPE_PROXYTYPE,
UNIFORM_SCALING_SHAPE_PROXYTYPE,
MINKOWSKI_SUM_SHAPE_PROXYTYPE, MINKOWSKI_SUM_SHAPE_PROXYTYPE,
MINKOWSKI_DIFFERENCE_SHAPE_PROXYTYPE, MINKOWSKI_DIFFERENCE_SHAPE_PROXYTYPE,
//concave shapes //concave shapes
@@ -50,6 +52,8 @@ CONCAVE_SHAPES_START_HERE,
TERRAIN_SHAPE_PROXYTYPE, TERRAIN_SHAPE_PROXYTYPE,
///Used for GIMPACT Trimesh integration ///Used for GIMPACT Trimesh integration
GIMPACT_SHAPE_PROXYTYPE, GIMPACT_SHAPE_PROXYTYPE,
///Multimaterial mesh
MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE,
EMPTY_SHAPE_PROXYTYPE, EMPTY_SHAPE_PROXYTYPE,
STATIC_PLANE_PROXYTYPE, STATIC_PLANE_PROXYTYPE,
@@ -57,13 +61,18 @@ CONCAVE_SHAPES_END_HERE,
COMPOUND_SHAPE_PROXYTYPE, COMPOUND_SHAPE_PROXYTYPE,
SOFTBODY_SHAPE_PROXYTYPE,
MAX_BROADPHASE_COLLISION_TYPES MAX_BROADPHASE_COLLISION_TYPES
}; };
///btBroadphaseProxy ///The btBroadphaseProxy is the main class that can be used with the Bullet broadphases.
struct btBroadphaseProxy ///It stores collision shape type information, collision filter information and a client object, typically a btCollisionObject or btRigidBody.
ATTRIBUTE_ALIGNED16(struct) btBroadphaseProxy
{ {
BT_DECLARE_ALIGNED_ALLOCATOR();
///optional filtering to cull potential collisions ///optional filtering to cull potential collisions
enum CollisionFilterGroups enum CollisionFilterGroups
@@ -73,44 +82,60 @@ struct btBroadphaseProxy
KinematicFilter = 4, KinematicFilter = 4,
DebrisFilter = 8, DebrisFilter = 8,
SensorTrigger = 16, SensorTrigger = 16,
AllFilter = DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorTrigger AllFilter = -1 //all bits sets: DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorTrigger
}; };
//Usually the client btCollisionObject or Rigidbody class //Usually the client btCollisionObject or Rigidbody class
void* m_clientObject; void* m_clientObject;
short int m_collisionFilterGroup; short int m_collisionFilterGroup;
short int m_collisionFilterMask; short int m_collisionFilterMask;
//used for memory pools void* m_multiSapParentProxy;
btBroadphaseProxy() :m_clientObject(0){}
btBroadphaseProxy(void* userPtr,short int collisionFilterGroup, short int collisionFilterMask)
int m_uniqueId;//m_uniqueId is introduced for paircache. could get rid of this, by calculating the address offset etc.
SIMD_FORCE_INLINE int getUid() const
{
return m_uniqueId;
}
//used for memory pools
btBroadphaseProxy() :m_clientObject(0),m_multiSapParentProxy(0)
{
}
btBroadphaseProxy(void* userPtr,short int collisionFilterGroup, short int collisionFilterMask,void* multiSapParentProxy=0)
:m_clientObject(userPtr), :m_clientObject(userPtr),
m_collisionFilterGroup(collisionFilterGroup), m_collisionFilterGroup(collisionFilterGroup),
m_collisionFilterMask(collisionFilterMask) m_collisionFilterMask(collisionFilterMask)
{ {
m_multiSapParentProxy = multiSapParentProxy;
} }
static inline bool isPolyhedral(int proxyType)
static SIMD_FORCE_INLINE bool isPolyhedral(int proxyType)
{ {
return (proxyType < IMPLICIT_CONVEX_SHAPES_START_HERE); return (proxyType < IMPLICIT_CONVEX_SHAPES_START_HERE);
} }
static inline bool isConvex(int proxyType) static SIMD_FORCE_INLINE bool isConvex(int proxyType)
{ {
return (proxyType < CONCAVE_SHAPES_START_HERE); return (proxyType < CONCAVE_SHAPES_START_HERE);
} }
static inline bool isConcave(int proxyType) static SIMD_FORCE_INLINE bool isConcave(int proxyType)
{ {
return ((proxyType > CONCAVE_SHAPES_START_HERE) && return ((proxyType > CONCAVE_SHAPES_START_HERE) &&
(proxyType < CONCAVE_SHAPES_END_HERE)); (proxyType < CONCAVE_SHAPES_END_HERE));
} }
static inline bool isCompound(int proxyType) static SIMD_FORCE_INLINE bool isCompound(int proxyType)
{ {
return (proxyType == COMPOUND_SHAPE_PROXYTYPE); return (proxyType == COMPOUND_SHAPE_PROXYTYPE);
} }
static inline bool isInfinite(int proxyType) static SIMD_FORCE_INLINE bool isInfinite(int proxyType)
{ {
return (proxyType == STATIC_PLANE_PROXYTYPE); return (proxyType == STATIC_PLANE_PROXYTYPE);
} }
@@ -124,8 +149,9 @@ struct btBroadphaseProxy;
/// contains a pair of aabb-overlapping objects ///The btBroadphasePair class contains a pair of aabb-overlapping objects.
struct btBroadphasePair ///A btDispatcher can search a btCollisionAlgorithm that performs exact/narrowphase collision detection on the actual collision shapes.
ATTRIBUTE_ALIGNED16(struct) btBroadphasePair
{ {
btBroadphasePair () btBroadphasePair ()
: :
@@ -136,6 +162,8 @@ struct btBroadphasePair
{ {
} }
BT_DECLARE_ALIGNED_ALLOCATOR();
btBroadphasePair(const btBroadphasePair& other) btBroadphasePair(const btBroadphasePair& other)
: m_pProxy0(other.m_pProxy0), : m_pProxy0(other.m_pProxy0),
m_pProxy1(other.m_pProxy1), m_pProxy1(other.m_pProxy1),
@@ -181,6 +209,7 @@ SIMD_FORCE_INLINE bool operator<(const btBroadphasePair& a, const btBroadphasePa
*/ */
class btBroadphasePairSortPredicate class btBroadphasePairSortPredicate
{ {
public: public:

View File

@@ -18,6 +18,6 @@ subject to the following restrictions:
btCollisionAlgorithm::btCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) btCollisionAlgorithm::btCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci)
{ {
m_dispatcher = ci.m_dispatcher; m_dispatcher = ci.m_dispatcher1;
} }

View File

@@ -16,7 +16,8 @@ subject to the following restrictions:
#ifndef COLLISION_ALGORITHM_H #ifndef COLLISION_ALGORITHM_H
#define COLLISION_ALGORITHM_H #define COLLISION_ALGORITHM_H
#include "../../LinearMath/btScalar.h" #include "LinearMath/btScalar.h"
#include "LinearMath/btAlignedObjectArray.h"
struct btBroadphaseProxy; struct btBroadphaseProxy;
class btDispatcher; class btDispatcher;
@@ -25,21 +26,22 @@ class btCollisionObject;
struct btDispatcherInfo; struct btDispatcherInfo;
class btPersistentManifold; class btPersistentManifold;
typedef btAlignedObjectArray<btPersistentManifold*> btManifoldArray;
struct btCollisionAlgorithmConstructionInfo struct btCollisionAlgorithmConstructionInfo
{ {
btCollisionAlgorithmConstructionInfo() btCollisionAlgorithmConstructionInfo()
:m_dispatcher(0), :m_dispatcher1(0),
m_manifold(0) m_manifold(0)
{ {
} }
btCollisionAlgorithmConstructionInfo(btDispatcher* dispatcher,int temp) btCollisionAlgorithmConstructionInfo(btDispatcher* dispatcher,int temp)
:m_dispatcher(dispatcher) :m_dispatcher1(dispatcher)
{ {
(void)temp; (void)temp;
} }
btDispatcher* m_dispatcher; btDispatcher* m_dispatcher1;
btPersistentManifold* m_manifold; btPersistentManifold* m_manifold;
int getDispatcherId(); int getDispatcherId();
@@ -71,6 +73,7 @@ public:
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) = 0; virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) = 0;
virtual void getAllContactManifolds(btManifoldArray& manifoldArray) = 0;
}; };

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,344 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///btDbvtBroadphase implementation by Nathanael Presson
#include "btDbvtBroadphase.h"
//
// Profiling
//
#if DBVT_BP_PROFILE
#include <stdio.h>
struct ProfileScope
{
ProfileScope(btClock& clock,unsigned long& value)
{
m_clock=&clock;
m_value=&value;
m_base=clock.getTimeMicroseconds();
}
~ProfileScope()
{
(*m_value)+=m_clock->getTimeMicroseconds()-m_base;
}
btClock* m_clock;
unsigned long* m_value;
unsigned long m_base;
};
#define SPC(_value_) ProfileScope spc_scope(m_clock,_value_)
#else
#define SPC(_value_)
#endif
//
// Helpers
//
//
template <typename T>
static inline void listappend(T* item,T*& list)
{
item->links[0]=0;
item->links[1]=list;
if(list) list->links[0]=item;
list=item;
}
//
template <typename T>
static inline void listremove(T* item,T*& list)
{
if(item->links[0]) item->links[0]->links[1]=item->links[1]; else list=item->links[1];
if(item->links[1]) item->links[1]->links[0]=item->links[0];
}
//
template <typename T>
static inline int listcount(T* root)
{
int n=0;
while(root) { ++n;root=root->links[1]; }
return(n);
}
//
template <typename T>
static inline void clear(T& value)
{
static const struct ZeroDummy : T {} zerodummy;
value=zerodummy;
}
//
// Colliders
//
/* Tree collider */
struct btDbvtTreeCollider : btDbvt::ICollide
{
btDbvtBroadphase* pbp;
btDbvtTreeCollider(btDbvtBroadphase* p) : pbp(p) {}
void Process(const btDbvtNode* na,const btDbvtNode* nb)
{
btDbvtProxy* pa=(btDbvtProxy*)na->data;
btDbvtProxy* pb=(btDbvtProxy*)nb->data;
#if DBVT_BP_DISCRETPAIRS
if(Intersect(pa->aabb,pb->aabb))
#endif
{
if(pa>pb) btSwap(pa,pb);
pbp->m_paircache->addOverlappingPair(pa,pb);
}
}
};
//
// btDbvtBroadphase
//
//
btDbvtBroadphase::btDbvtBroadphase(btOverlappingPairCache* paircache)
{
m_releasepaircache = (paircache!=0)?false:true;
m_predictedframes = 2;
m_stageCurrent = 0;
m_fupdates = 1;
m_dupdates = 1;
m_paircache = paircache?
paircache :
new(btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16)) btHashedOverlappingPairCache();
m_gid = 0;
m_pid = 0;
for(int i=0;i<=STAGECOUNT;++i)
{
m_stageRoots[i]=0;
}
#if DBVT_BP_PROFILE
clear(m_profiling);
#endif
}
//
btDbvtBroadphase::~btDbvtBroadphase()
{
if(m_releasepaircache)
{
m_paircache->~btOverlappingPairCache();
btAlignedFree(m_paircache);
}
}
//
btBroadphaseProxy* btDbvtBroadphase::createProxy( const btVector3& aabbMin,
const btVector3& aabbMax,
int /*shapeType*/,
void* userPtr,
short int collisionFilterGroup,
short int collisionFilterMask,
btDispatcher* /*dispatcher*/,
void* /*multiSapProxy*/)
{
btDbvtProxy* proxy=new(btAlignedAlloc(sizeof(btDbvtProxy),16)) btDbvtProxy( userPtr,
collisionFilterGroup,
collisionFilterMask);
proxy->aabb = btDbvtVolume::FromMM(aabbMin,aabbMax);
proxy->leaf = m_sets[0].insert(proxy->aabb,proxy);
proxy->stage = m_stageCurrent;
proxy->m_uniqueId = ++m_gid;
listappend(proxy,m_stageRoots[m_stageCurrent]);
return(proxy);
}
//
void btDbvtBroadphase::destroyProxy( btBroadphaseProxy* absproxy,
btDispatcher* dispatcher)
{
btDbvtProxy* proxy=(btDbvtProxy*)absproxy;
if(proxy->stage==STAGECOUNT)
m_sets[1].remove(proxy->leaf);
else
m_sets[0].remove(proxy->leaf);
listremove(proxy,m_stageRoots[proxy->stage]);
m_paircache->removeOverlappingPairsContainingProxy(proxy,dispatcher);
btAlignedFree(proxy);
}
//
void btDbvtBroadphase::setAabb( btBroadphaseProxy* absproxy,
const btVector3& aabbMin,
const btVector3& aabbMax,
btDispatcher* /*dispatcher*/)
{
btDbvtProxy* proxy=(btDbvtProxy*)absproxy;
btDbvtVolume aabb=btDbvtVolume::FromMM(aabbMin,aabbMax);
if(NotEqual(aabb,proxy->leaf->volume))
{
if(proxy->stage==STAGECOUNT)
{/* fixed -> dynamic set */
m_sets[1].remove(proxy->leaf);
proxy->leaf=m_sets[0].insert(aabb,proxy);
}
else
{/* dynamic set */
if(Intersect(proxy->leaf->volume,aabb))
{/* Moving */
const btVector3 delta=(aabbMin+aabbMax)/2-proxy->aabb.Center();
#ifdef DBVT_BP_MARGIN
m_sets[0].update(proxy->leaf,aabb,delta*m_predictedframes,DBVT_BP_MARGIN);
#else
m_sets[0].update(proxy->leaf,aabb,delta*m_predictedframes);
#endif
}
else
{/* Teleporting */
m_sets[0].update(proxy->leaf,aabb);
}
}
listremove(proxy,m_stageRoots[proxy->stage]);
proxy->aabb = aabb;
proxy->stage = m_stageCurrent;
listappend(proxy,m_stageRoots[m_stageCurrent]);
}
}
//
void btDbvtBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher)
{
collide(dispatcher);
#if DBVT_BP_PROFILE
if(0==(m_pid%DBVT_BP_PROFILING_RATE))
{
printf("fixed(%u) dynamics(%u) pairs(%u)\r\n",m_sets[1].m_leaves,m_sets[0].m_leaves,m_paircache->getNumOverlappingPairs());
unsigned int total=m_profiling.m_total;
if(total<=0) total=1;
printf("ddcollide: %u%% (%uus)\r\n",(50+m_profiling.m_ddcollide*100)/total,m_profiling.m_ddcollide/DBVT_BP_PROFILING_RATE);
printf("fdcollide: %u%% (%uus)\r\n",(50+m_profiling.m_fdcollide*100)/total,m_profiling.m_fdcollide/DBVT_BP_PROFILING_RATE);
printf("cleanup: %u%% (%uus)\r\n",(50+m_profiling.m_cleanup*100)/total,m_profiling.m_cleanup/DBVT_BP_PROFILING_RATE);
printf("total: %uus\r\n",total/DBVT_BP_PROFILING_RATE);
const unsigned long sum=m_profiling.m_ddcollide+
m_profiling.m_fdcollide+
m_profiling.m_cleanup;
printf("leaked: %u%% (%uus)\r\n",100-((50+sum*100)/total),(total-sum)/DBVT_BP_PROFILING_RATE);
printf("job counts: %u%%\r\n",(m_profiling.m_jobcount*100)/((m_sets[0].m_leaves+m_sets[1].m_leaves)*DBVT_BP_PROFILING_RATE));
clear(m_profiling);
m_clock.reset();
}
#endif
}
//
void btDbvtBroadphase::collide(btDispatcher* dispatcher)
{
SPC(m_profiling.m_total);
/* optimize */
m_sets[0].optimizeIncremental(1+(m_sets[0].m_leaves*m_dupdates)/100);
m_sets[1].optimizeIncremental(1+(m_sets[1].m_leaves*m_fupdates)/100);
/* dynamic -> fixed set */
m_stageCurrent=(m_stageCurrent+1)%STAGECOUNT;
btDbvtProxy* current=m_stageRoots[m_stageCurrent];
if(current)
{
btDbvtTreeCollider collider(this);
do {
btDbvtProxy* next=current->links[1];
listremove(current,m_stageRoots[current->stage]);
listappend(current,m_stageRoots[STAGECOUNT]);
btDbvt::collideTT(m_sets[1].m_root,current->leaf,collider);
m_sets[0].remove(current->leaf);
current->leaf = m_sets[1].insert(current->aabb,current);
current->stage = STAGECOUNT;
current = next;
} while(current);
}
/* collide dynamics */
{
btDbvtTreeCollider collider(this);
{
SPC(m_profiling.m_fdcollide);
btDbvt::collideTT(m_sets[0].m_root,m_sets[1].m_root,collider);
}
{
SPC(m_profiling.m_ddcollide);
btDbvt::collideTT(m_sets[0].m_root,m_sets[0].m_root,collider);
}
}
/* clean up */
{
SPC(m_profiling.m_cleanup);
btBroadphasePairArray& pairs=m_paircache->getOverlappingPairArray();
if(pairs.size()>0)
{
for(int i=0,ni=pairs.size();i<ni;++i)
{
btBroadphasePair& p=pairs[i];
btDbvtProxy* pa=(btDbvtProxy*)p.m_pProxy0;
btDbvtProxy* pb=(btDbvtProxy*)p.m_pProxy1;
if(!Intersect(pa->aabb,pb->aabb))
{
if(pa>pb) btSwap(pa,pb);
m_paircache->removeOverlappingPair(pa,pb,dispatcher);
--ni;--i;
}
}
}
}
++m_pid;
}
//
void btDbvtBroadphase::optimize()
{
m_sets[0].optimizeTopDown();
m_sets[1].optimizeTopDown();
}
//
btOverlappingPairCache* btDbvtBroadphase::getOverlappingPairCache()
{
return(m_paircache);
}
//
const btOverlappingPairCache* btDbvtBroadphase::getOverlappingPairCache() const
{
return(m_paircache);
}
//
void btDbvtBroadphase::getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const
{
ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds;
if(!m_sets[0].empty())
if(!m_sets[1].empty()) Merge( m_sets[0].m_root->volume,
m_sets[1].m_root->volume,bounds);
else
bounds=m_sets[0].m_root->volume;
else if(!m_sets[1].empty()) bounds=m_sets[1].m_root->volume;
else
bounds=btDbvtVolume::FromCR(btVector3(0,0,0),0);
aabbMin=bounds.Mins();
aabbMax=bounds.Maxs();
}
//
void btDbvtBroadphase::printStats()
{}
#if DBVT_BP_PROFILE
#undef SPC
#endif

View File

@@ -0,0 +1,103 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///btDbvtBroadphase implementation by Nathanael Presson
#ifndef BT_DBVT_BROADPHASE_H
#define BT_DBVT_BROADPHASE_H
#include "BulletCollision/BroadphaseCollision/btDbvt.h"
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
//
// Compile time config
//
#define DBVT_BP_PROFILE 0
#define DBVT_BP_DISCRETPAIRS 1
#define DBVT_BP_MARGIN (btScalar)0.05
#if DBVT_BP_PROFILE
#define DBVT_BP_PROFILING_RATE 256
#include "LinearMath/btQuickprof.h"
#endif
//
// btDbvtProxy
//
struct btDbvtProxy : btBroadphaseProxy
{
/* Fields */
btDbvtAabbMm aabb;
btDbvtNode* leaf;
btDbvtProxy* links[2];
int stage;
/* ctor */
btDbvtProxy(void* userPtr,short int collisionFilterGroup, short int collisionFilterMask) :
btBroadphaseProxy(userPtr,collisionFilterGroup,collisionFilterMask)
{
links[0]=links[1]=0;
}
};
typedef btAlignedObjectArray<btDbvtProxy*> btDbvtProxyArray;
///The btDbvtBroadphase implements a broadphase using two dynamic AABB bounding volume hierarchies/trees (see btDbvt).
///One tree is used for static/non-moving objects, and another tree is used for dynamic objects. Objects can move from one tree to the other.
///This is a very fast broadphase, especially for very dynamic worlds where many objects are moving. Its insert/add and remove of objects is generally faster than the sweep and prune broadphases btAxisSweep3 and bt32BitAxisSweep3.
struct btDbvtBroadphase : btBroadphaseInterface
{
/* Config */
enum {
DYNAMIC_SET = 0, /* Dynamic set index */
FIXED_SET = 1, /* Fixed set index */
STAGECOUNT = 2 /* Number of stages */
};
/* Fields */
btDbvt m_sets[2]; // Dbvt sets
btDbvtProxy* m_stageRoots[STAGECOUNT+1]; // Stages list
btOverlappingPairCache* m_paircache; // Pair cache
btScalar m_predictedframes; // Frames predicted
int m_stageCurrent; // Current stage
int m_fupdates; // % of fixed updates per frame
int m_dupdates; // % of dynamic updates per frame
int m_pid; // Parse id
int m_gid; // Gen id
bool m_releasepaircache; // Release pair cache on delete
#if DBVT_BP_PROFILE
btClock m_clock;
struct {
unsigned long m_total;
unsigned long m_ddcollide;
unsigned long m_fdcollide;
unsigned long m_cleanup;
unsigned long m_jobcount;
} m_profiling;
#endif
/* Methods */
btDbvtBroadphase(btOverlappingPairCache* paircache=0);
~btDbvtBroadphase();
void collide(btDispatcher* dispatcher);
void optimize();
/* btBroadphaseInterface Implementation */
btBroadphaseProxy* createProxy(const btVector3& aabbMin,const btVector3& aabbMax,int shapeType,void* userPtr,short int collisionFilterGroup,short int collisionFilterMask,btDispatcher* dispatcher,void* multiSapProxy);
void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher);
void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax,btDispatcher* dispatcher);
void calculateOverlappingPairs(btDispatcher* dispatcher);
btOverlappingPairCache* getOverlappingPairCache();
const btOverlappingPairCache* getOverlappingPairCache() const;
void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const;
void printStats();
};
#endif

View File

@@ -16,7 +16,7 @@ subject to the following restrictions:
#ifndef _DISPATCHER_H #ifndef _DISPATCHER_H
#define _DISPATCHER_H #define _DISPATCHER_H
#include "../../LinearMath/btScalar.h" #include "LinearMath/btScalar.h"
class btCollisionAlgorithm; class btCollisionAlgorithm;
struct btBroadphaseProxy; struct btBroadphaseProxy;
@@ -43,7 +43,9 @@ struct btDispatcherInfo
m_useContinuous(false), m_useContinuous(false),
m_debugDraw(0), m_debugDraw(0),
m_enableSatConvex(false), m_enableSatConvex(false),
m_enableSPU(false), m_enableSPU(true),
m_useEpa(true),
m_allowedCcdPenetration(btScalar(0.04)),
m_stackAllocator(0) m_stackAllocator(0)
{ {
@@ -51,17 +53,19 @@ struct btDispatcherInfo
btScalar m_timeStep; btScalar m_timeStep;
int m_stepCount; int m_stepCount;
int m_dispatchFunc; int m_dispatchFunc;
btScalar m_timeOfImpact; mutable btScalar m_timeOfImpact;
bool m_useContinuous; bool m_useContinuous;
class btIDebugDraw* m_debugDraw; class btIDebugDraw* m_debugDraw;
bool m_enableSatConvex; bool m_enableSatConvex;
bool m_enableSPU; bool m_enableSPU;
bool m_useEpa;
btScalar m_allowedCcdPenetration;
btStackAlloc* m_stackAllocator; btStackAlloc* m_stackAllocator;
}; };
/// btDispatcher can be used in combination with broadphase to dispatch overlapping pairs. ///The btDispatcher interface class can be used in combination with broadphase to dispatch calculations for overlapping pairs.
/// For example for pairwise collision detection or user callbacks (game logic). ///For example for pairwise collision detection, calculating contact points stored in btPersistentManifold or user callbacks (game logic).
class btDispatcher class btDispatcher
{ {
@@ -81,12 +85,18 @@ public:
virtual bool needsResponse(btCollisionObject* body0,btCollisionObject* body1)=0; virtual bool needsResponse(btCollisionObject* body0,btCollisionObject* body1)=0;
virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,btDispatcherInfo& dispatchInfo)=0; virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo,btDispatcher* dispatcher) =0;
virtual int getNumManifolds() const = 0; virtual int getNumManifolds() const = 0;
virtual btPersistentManifold* getManifoldByIndexInternal(int index) = 0; virtual btPersistentManifold* getManifoldByIndexInternal(int index) = 0;
virtual btPersistentManifold** getInternalManifoldPointer() = 0;
virtual void* allocateCollisionAlgorithm(int size) = 0;
virtual void freeCollisionAlgorithm(void* ptr) = 0;
}; };

View File

@@ -0,0 +1,466 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "btMultiSapBroadphase.h"
#include "btSimpleBroadphase.h"
#include "LinearMath/btAabbUtil2.h"
#include "btQuantizedBvh.h"
/// btSapBroadphaseArray m_sapBroadphases;
/// btOverlappingPairCache* m_overlappingPairs;
extern int gOverlappingPairs;
/*
class btMultiSapSortedOverlappingPairCache : public btSortedOverlappingPairCache
{
public:
virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1)
{
return btSortedOverlappingPairCache::addOverlappingPair((btBroadphaseProxy*)proxy0->m_multiSapParentProxy,(btBroadphaseProxy*)proxy1->m_multiSapParentProxy);
}
};
*/
btMultiSapBroadphase::btMultiSapBroadphase(int /*maxProxies*/,btOverlappingPairCache* pairCache)
:m_overlappingPairs(pairCache),
m_optimizedAabbTree(0),
m_ownsPairCache(false),
m_invalidPair(0)
{
if (!m_overlappingPairs)
{
m_ownsPairCache = true;
void* mem = btAlignedAlloc(sizeof(btSortedOverlappingPairCache),16);
m_overlappingPairs = new (mem)btSortedOverlappingPairCache();
}
struct btMultiSapOverlapFilterCallback : public btOverlapFilterCallback
{
virtual ~btMultiSapOverlapFilterCallback()
{}
// return true when pairs need collision
virtual bool needBroadphaseCollision(btBroadphaseProxy* childProxy0,btBroadphaseProxy* childProxy1) const
{
btBroadphaseProxy* multiProxy0 = (btBroadphaseProxy*)childProxy0->m_multiSapParentProxy;
btBroadphaseProxy* multiProxy1 = (btBroadphaseProxy*)childProxy1->m_multiSapParentProxy;
bool collides = (multiProxy0->m_collisionFilterGroup & multiProxy1->m_collisionFilterMask) != 0;
collides = collides && (multiProxy1->m_collisionFilterGroup & multiProxy0->m_collisionFilterMask);
return collides;
}
};
void* mem = btAlignedAlloc(sizeof(btMultiSapOverlapFilterCallback),16);
m_filterCallback = new (mem)btMultiSapOverlapFilterCallback();
m_overlappingPairs->setOverlapFilterCallback(m_filterCallback);
// mem = btAlignedAlloc(sizeof(btSimpleBroadphase),16);
// m_simpleBroadphase = new (mem) btSimpleBroadphase(maxProxies,m_overlappingPairs);
}
btMultiSapBroadphase::~btMultiSapBroadphase()
{
if (m_ownsPairCache)
{
m_overlappingPairs->~btOverlappingPairCache();
btAlignedFree(m_overlappingPairs);
}
}
void btMultiSapBroadphase::buildTree(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax)
{
m_optimizedAabbTree = new btQuantizedBvh();
m_optimizedAabbTree->setQuantizationValues(bvhAabbMin,bvhAabbMax);
QuantizedNodeArray& nodes = m_optimizedAabbTree->getLeafNodeArray();
for (int i=0;i<m_sapBroadphases.size();i++)
{
btQuantizedBvhNode node;
btVector3 aabbMin,aabbMax;
m_sapBroadphases[i]->getBroadphaseAabb(aabbMin,aabbMax);
m_optimizedAabbTree->quantize(&node.m_quantizedAabbMin[0],aabbMin,0);
m_optimizedAabbTree->quantize(&node.m_quantizedAabbMax[0],aabbMax,1);
int partId = 0;
node.m_escapeIndexOrTriangleIndex = (partId<<(31-MAX_NUM_PARTS_IN_BITS)) | i;
nodes.push_back(node);
}
m_optimizedAabbTree->buildInternal();
}
btBroadphaseProxy* btMultiSapBroadphase::createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* /*ignoreMe*/)
{
//void* ignoreMe -> we could think of recursive multi-sap, if someone is interested
void* mem = btAlignedAlloc(sizeof(btMultiSapProxy),16);
btMultiSapProxy* proxy = new (mem)btMultiSapProxy(aabbMin, aabbMax,shapeType,userPtr, collisionFilterGroup,collisionFilterMask);
m_multiSapProxies.push_back(proxy);
///this should deal with inserting/removal into child broadphases
setAabb(proxy,aabbMin,aabbMax,dispatcher);
return proxy;
}
void btMultiSapBroadphase::destroyProxy(btBroadphaseProxy* /*proxy*/,btDispatcher* /*dispatcher*/)
{
///not yet
btAssert(0);
}
void btMultiSapBroadphase::addToChildBroadphase(btMultiSapProxy* parentMultiSapProxy, btBroadphaseProxy* childProxy, btBroadphaseInterface* childBroadphase)
{
void* mem = btAlignedAlloc(sizeof(btBridgeProxy),16);
btBridgeProxy* bridgeProxyRef = new(mem) btBridgeProxy;
bridgeProxyRef->m_childProxy = childProxy;
bridgeProxyRef->m_childBroadphase = childBroadphase;
parentMultiSapProxy->m_bridgeProxies.push_back(bridgeProxyRef);
}
bool boxIsContainedWithinBox(const btVector3& amin,const btVector3& amax,const btVector3& bmin,const btVector3& bmax);
bool boxIsContainedWithinBox(const btVector3& amin,const btVector3& amax,const btVector3& bmin,const btVector3& bmax)
{
return
amin.getX() >= bmin.getX() && amax.getX() <= bmax.getX() &&
amin.getY() >= bmin.getY() && amax.getY() <= bmax.getY() &&
amin.getZ() >= bmin.getZ() && amax.getZ() <= bmax.getZ();
}
//#include <stdio.h>
void btMultiSapBroadphase::setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher)
{
btMultiSapProxy* multiProxy = static_cast<btMultiSapProxy*>(proxy);
multiProxy->m_aabbMin = aabbMin;
multiProxy->m_aabbMax = aabbMax;
// bool fullyContained = false;
// bool alreadyInSimple = false;
struct MyNodeOverlapCallback : public btNodeOverlapCallback
{
btMultiSapBroadphase* m_multiSap;
btMultiSapProxy* m_multiProxy;
btDispatcher* m_dispatcher;
MyNodeOverlapCallback(btMultiSapBroadphase* multiSap,btMultiSapProxy* multiProxy,btDispatcher* dispatcher)
:m_multiSap(multiSap),
m_multiProxy(multiProxy),
m_dispatcher(dispatcher)
{
}
virtual void processNode(int /*nodeSubPart*/, int broadphaseIndex)
{
btBroadphaseInterface* childBroadphase = m_multiSap->getBroadphaseArray()[broadphaseIndex];
int containingBroadphaseIndex = -1;
//already found?
for (int i=0;i<m_multiProxy->m_bridgeProxies.size();i++)
{
if (m_multiProxy->m_bridgeProxies[i]->m_childBroadphase == childBroadphase)
{
containingBroadphaseIndex = i;
break;
}
}
if (containingBroadphaseIndex<0)
{
//add it
btBroadphaseProxy* childProxy = childBroadphase->createProxy(m_multiProxy->m_aabbMin,m_multiProxy->m_aabbMax,m_multiProxy->m_shapeType,m_multiProxy->m_clientObject,m_multiProxy->m_collisionFilterGroup,m_multiProxy->m_collisionFilterMask, m_dispatcher,m_multiProxy);
m_multiSap->addToChildBroadphase(m_multiProxy,childProxy,childBroadphase);
}
}
};
MyNodeOverlapCallback myNodeCallback(this,multiProxy,dispatcher);
m_optimizedAabbTree->reportAabbOverlappingNodex(&myNodeCallback,aabbMin,aabbMax);
int i;
for ( i=0;i<multiProxy->m_bridgeProxies.size();i++)
{
btVector3 worldAabbMin,worldAabbMax;
multiProxy->m_bridgeProxies[i]->m_childBroadphase->getBroadphaseAabb(worldAabbMin,worldAabbMax);
bool overlapsBroadphase = TestAabbAgainstAabb2(worldAabbMin,worldAabbMax,multiProxy->m_aabbMin,multiProxy->m_aabbMax);
if (!overlapsBroadphase)
{
//remove it now
btBridgeProxy* bridgeProxy = multiProxy->m_bridgeProxies[i];
btBroadphaseProxy* childProxy = bridgeProxy->m_childProxy;
bridgeProxy->m_childBroadphase->destroyProxy(childProxy,dispatcher);
multiProxy->m_bridgeProxies.swap( i,multiProxy->m_bridgeProxies.size()-1);
multiProxy->m_bridgeProxies.pop_back();
}
}
/*
if (1)
{
//find broadphase that contain this multiProxy
int numChildBroadphases = getBroadphaseArray().size();
for (int i=0;i<numChildBroadphases;i++)
{
btBroadphaseInterface* childBroadphase = getBroadphaseArray()[i];
btVector3 worldAabbMin,worldAabbMax;
childBroadphase->getBroadphaseAabb(worldAabbMin,worldAabbMax);
bool overlapsBroadphase = TestAabbAgainstAabb2(worldAabbMin,worldAabbMax,multiProxy->m_aabbMin,multiProxy->m_aabbMax);
// fullyContained = fullyContained || boxIsContainedWithinBox(worldAabbMin,worldAabbMax,multiProxy->m_aabbMin,multiProxy->m_aabbMax);
int containingBroadphaseIndex = -1;
//if already contains this
for (int i=0;i<multiProxy->m_bridgeProxies.size();i++)
{
if (multiProxy->m_bridgeProxies[i]->m_childBroadphase == childBroadphase)
{
containingBroadphaseIndex = i;
}
alreadyInSimple = alreadyInSimple || (multiProxy->m_bridgeProxies[i]->m_childBroadphase == m_simpleBroadphase);
}
if (overlapsBroadphase)
{
if (containingBroadphaseIndex<0)
{
btBroadphaseProxy* childProxy = childBroadphase->createProxy(aabbMin,aabbMax,multiProxy->m_shapeType,multiProxy->m_clientObject,multiProxy->m_collisionFilterGroup,multiProxy->m_collisionFilterMask, dispatcher);
childProxy->m_multiSapParentProxy = multiProxy;
addToChildBroadphase(multiProxy,childProxy,childBroadphase);
}
} else
{
if (containingBroadphaseIndex>=0)
{
//remove
btBridgeProxy* bridgeProxy = multiProxy->m_bridgeProxies[containingBroadphaseIndex];
btBroadphaseProxy* childProxy = bridgeProxy->m_childProxy;
bridgeProxy->m_childBroadphase->destroyProxy(childProxy,dispatcher);
multiProxy->m_bridgeProxies.swap( containingBroadphaseIndex,multiProxy->m_bridgeProxies.size()-1);
multiProxy->m_bridgeProxies.pop_back();
}
}
}
///If we are in no other child broadphase, stick the proxy in the global 'simple' broadphase (brute force)
///hopefully we don't end up with many entries here (can assert/provide feedback on stats)
if (0)//!multiProxy->m_bridgeProxies.size())
{
///we don't pass the userPtr but our multisap proxy. We need to patch this, before processing an actual collision
///this is needed to be able to calculate the aabb overlap
btBroadphaseProxy* childProxy = m_simpleBroadphase->createProxy(aabbMin,aabbMax,multiProxy->m_shapeType,multiProxy->m_clientObject,multiProxy->m_collisionFilterGroup,multiProxy->m_collisionFilterMask, dispatcher);
childProxy->m_multiSapParentProxy = multiProxy;
addToChildBroadphase(multiProxy,childProxy,m_simpleBroadphase);
}
}
if (!multiProxy->m_bridgeProxies.size())
{
///we don't pass the userPtr but our multisap proxy. We need to patch this, before processing an actual collision
///this is needed to be able to calculate the aabb overlap
btBroadphaseProxy* childProxy = m_simpleBroadphase->createProxy(aabbMin,aabbMax,multiProxy->m_shapeType,multiProxy->m_clientObject,multiProxy->m_collisionFilterGroup,multiProxy->m_collisionFilterMask, dispatcher);
childProxy->m_multiSapParentProxy = multiProxy;
addToChildBroadphase(multiProxy,childProxy,m_simpleBroadphase);
}
*/
//update
for ( i=0;i<multiProxy->m_bridgeProxies.size();i++)
{
btBridgeProxy* bridgeProxyRef = multiProxy->m_bridgeProxies[i];
bridgeProxyRef->m_childBroadphase->setAabb(bridgeProxyRef->m_childProxy,aabbMin,aabbMax,dispatcher);
}
}
bool stopUpdating=false;
class btMultiSapBroadphasePairSortPredicate
{
public:
bool operator() ( const btBroadphasePair& a1, const btBroadphasePair& b1 )
{
btMultiSapBroadphase::btMultiSapProxy* aProxy0 = a1.m_pProxy0 ? (btMultiSapBroadphase::btMultiSapProxy*)a1.m_pProxy0->m_multiSapParentProxy : 0;
btMultiSapBroadphase::btMultiSapProxy* aProxy1 = a1.m_pProxy1 ? (btMultiSapBroadphase::btMultiSapProxy*)a1.m_pProxy1->m_multiSapParentProxy : 0;
btMultiSapBroadphase::btMultiSapProxy* bProxy0 = b1.m_pProxy0 ? (btMultiSapBroadphase::btMultiSapProxy*)b1.m_pProxy0->m_multiSapParentProxy : 0;
btMultiSapBroadphase::btMultiSapProxy* bProxy1 = b1.m_pProxy1 ? (btMultiSapBroadphase::btMultiSapProxy*)b1.m_pProxy1->m_multiSapParentProxy : 0;
return aProxy0 > bProxy0 ||
(aProxy0 == bProxy0 && aProxy1 > bProxy1) ||
(aProxy0 == bProxy0 && aProxy1 == bProxy1 && a1.m_algorithm > b1.m_algorithm);
}
};
///calculateOverlappingPairs is optional: incremental algorithms (sweep and prune) might do it during the set aabb
void btMultiSapBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher)
{
// m_simpleBroadphase->calculateOverlappingPairs(dispatcher);
if (!stopUpdating && getOverlappingPairCache()->hasDeferredRemoval())
{
btBroadphasePairArray& overlappingPairArray = getOverlappingPairCache()->getOverlappingPairArray();
// quicksort(overlappingPairArray,0,overlappingPairArray.size());
overlappingPairArray.quickSort(btMultiSapBroadphasePairSortPredicate());
//perform a sort, to find duplicates and to sort 'invalid' pairs to the end
// overlappingPairArray.heapSort(btMultiSapBroadphasePairSortPredicate());
overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair);
m_invalidPair = 0;
int i;
btBroadphasePair previousPair;
previousPair.m_pProxy0 = 0;
previousPair.m_pProxy1 = 0;
previousPair.m_algorithm = 0;
for (i=0;i<overlappingPairArray.size();i++)
{
btBroadphasePair& pair = overlappingPairArray[i];
btMultiSapProxy* aProxy0 = pair.m_pProxy0 ? (btMultiSapProxy*)pair.m_pProxy0->m_multiSapParentProxy : 0;
btMultiSapProxy* aProxy1 = pair.m_pProxy1 ? (btMultiSapProxy*)pair.m_pProxy1->m_multiSapParentProxy : 0;
btMultiSapProxy* bProxy0 = previousPair.m_pProxy0 ? (btMultiSapProxy*)previousPair.m_pProxy0->m_multiSapParentProxy : 0;
btMultiSapProxy* bProxy1 = previousPair.m_pProxy1 ? (btMultiSapProxy*)previousPair.m_pProxy1->m_multiSapParentProxy : 0;
bool isDuplicate = (aProxy0 == bProxy0) && (aProxy1 == bProxy1);
previousPair = pair;
bool needsRemoval = false;
if (!isDuplicate)
{
bool hasOverlap = testAabbOverlap(pair.m_pProxy0,pair.m_pProxy1);
if (hasOverlap)
{
needsRemoval = false;//callback->processOverlap(pair);
} else
{
needsRemoval = true;
}
} else
{
//remove duplicate
needsRemoval = true;
//should have no algorithm
btAssert(!pair.m_algorithm);
}
if (needsRemoval)
{
getOverlappingPairCache()->cleanOverlappingPair(pair,dispatcher);
// m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1);
// m_overlappingPairArray.pop_back();
pair.m_pProxy0 = 0;
pair.m_pProxy1 = 0;
m_invalidPair++;
gOverlappingPairs--;
}
}
///if you don't like to skip the invalid pairs in the array, execute following code:
#define CLEAN_INVALID_PAIRS 1
#ifdef CLEAN_INVALID_PAIRS
//perform a sort, to sort 'invalid' pairs to the end
//overlappingPairArray.heapSort(btMultiSapBroadphasePairSortPredicate());
overlappingPairArray.quickSort(btMultiSapBroadphasePairSortPredicate());
overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair);
m_invalidPair = 0;
#endif//CLEAN_INVALID_PAIRS
//printf("overlappingPairArray.size()=%d\n",overlappingPairArray.size());
}
}
bool btMultiSapBroadphase::testAabbOverlap(btBroadphaseProxy* childProxy0,btBroadphaseProxy* childProxy1)
{
btMultiSapProxy* multiSapProxy0 = (btMultiSapProxy*)childProxy0->m_multiSapParentProxy;
btMultiSapProxy* multiSapProxy1 = (btMultiSapProxy*)childProxy1->m_multiSapParentProxy;
return TestAabbAgainstAabb2(multiSapProxy0->m_aabbMin,multiSapProxy0->m_aabbMax,
multiSapProxy1->m_aabbMin,multiSapProxy1->m_aabbMax);
}
void btMultiSapBroadphase::printStats()
{
/* printf("---------------------------------\n");
printf("btMultiSapBroadphase.h\n");
printf("numHandles = %d\n",m_multiSapProxies.size());
//find broadphase that contain this multiProxy
int numChildBroadphases = getBroadphaseArray().size();
for (int i=0;i<numChildBroadphases;i++)
{
btBroadphaseInterface* childBroadphase = getBroadphaseArray()[i];
childBroadphase->printStats();
}
*/
}

View File

@@ -0,0 +1,144 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_MULTI_SAP_BROADPHASE
#define BT_MULTI_SAP_BROADPHASE
#include "btBroadphaseInterface.h"
#include "LinearMath/btAlignedObjectArray.h"
#include "btOverlappingPairCache.h"
class btBroadphaseInterface;
class btSimpleBroadphase;
typedef btAlignedObjectArray<btBroadphaseInterface*> btSapBroadphaseArray;
///The btMultiSapBroadphase is a broadphase that contains multiple SAP broadphases.
///The user can add SAP broadphases that cover the world. A btBroadphaseProxy can be in multiple child broadphases at the same time.
///A btQuantizedBvh acceleration structures finds overlapping SAPs for each btBroadphaseProxy.
///See http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=328
///and http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1329
class btMultiSapBroadphase :public btBroadphaseInterface
{
btSapBroadphaseArray m_sapBroadphases;
btSimpleBroadphase* m_simpleBroadphase;
btOverlappingPairCache* m_overlappingPairs;
class btQuantizedBvh* m_optimizedAabbTree;
bool m_ownsPairCache;
btOverlapFilterCallback* m_filterCallback;
int m_invalidPair;
struct btBridgeProxy
{
btBroadphaseProxy* m_childProxy;
btBroadphaseInterface* m_childBroadphase;
};
public:
struct btMultiSapProxy : public btBroadphaseProxy
{
///array with all the entries that this proxy belongs to
btAlignedObjectArray<btBridgeProxy*> m_bridgeProxies;
btVector3 m_aabbMin;
btVector3 m_aabbMax;
int m_shapeType;
/* void* m_userPtr;
short int m_collisionFilterGroup;
short int m_collisionFilterMask;
*/
btMultiSapProxy(const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask)
:btBroadphaseProxy(userPtr,collisionFilterGroup,collisionFilterMask),
m_aabbMin(aabbMin),
m_aabbMax(aabbMax),
m_shapeType(shapeType)
{
m_multiSapParentProxy =this;
}
};
protected:
btAlignedObjectArray<btMultiSapProxy*> m_multiSapProxies;
public:
btMultiSapBroadphase(int maxProxies = 16384,btOverlappingPairCache* pairCache=0);
btSapBroadphaseArray& getBroadphaseArray()
{
return m_sapBroadphases;
}
const btSapBroadphaseArray& getBroadphaseArray() const
{
return m_sapBroadphases;
}
virtual ~btMultiSapBroadphase();
virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy);
virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher);
virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher);
void addToChildBroadphase(btMultiSapProxy* parentMultiSapProxy, btBroadphaseProxy* childProxy, btBroadphaseInterface* childBroadphase);
///calculateOverlappingPairs is optional: incremental algorithms (sweep and prune) might do it during the set aabb
virtual void calculateOverlappingPairs(btDispatcher* dispatcher);
bool testAabbOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1);
virtual btOverlappingPairCache* getOverlappingPairCache()
{
return m_overlappingPairs;
}
virtual const btOverlappingPairCache* getOverlappingPairCache() const
{
return m_overlappingPairs;
}
///getAabb returns the axis aligned bounding box in the 'global' coordinate frame
///will add some transform later
virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const
{
aabbMin.setValue(-1e30f,-1e30f,-1e30f);
aabbMax.setValue(1e30f,1e30f,1e30f);
}
void buildTree(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax);
virtual void printStats();
void quicksort (btBroadphasePairArray& a, int lo, int hi);
};
#endif //BT_MULTI_SAP_BROADPHASE

View File

@@ -1,4 +1,3 @@
/* /*
Bullet Continuous Collision Detection and Physics Library Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
@@ -21,44 +20,43 @@ subject to the following restrictions:
#include "btDispatcher.h" #include "btDispatcher.h"
#include "btCollisionAlgorithm.h" #include "btCollisionAlgorithm.h"
#include <stdio.h>
int gOverlappingPairs = 0; int gOverlappingPairs = 0;
btOverlappingPairCache::btOverlappingPairCache(): int gRemovePairs =0;
m_blockedForChanges(false), int gAddedPairs =0;
m_overlapFilterCallback(0) int gFindPairs =0;
//m_NumOverlapBroadphasePair(0)
btHashedOverlappingPairCache::btHashedOverlappingPairCache():
m_overlapFilterCallback(0),
m_blockedForChanges(false)
{ {
int initialAllocatedSize= 2;
m_overlappingPairArray.reserve(initialAllocatedSize);
growTables();
} }
btOverlappingPairCache::~btOverlappingPairCache()
btHashedOverlappingPairCache::~btHashedOverlappingPairCache()
{ {
//todo/test: show we erase/delete data, or is it automatic //todo/test: show we erase/delete data, or is it automatic
} }
void btOverlappingPairCache::removeOverlappingPair(btBroadphasePair& findPair)
{
int findIndex = m_overlappingPairArray.findLinearSearch(findPair);
if (findIndex < m_overlappingPairArray.size())
{
gOverlappingPairs--;
btBroadphasePair& pair = m_overlappingPairArray[findIndex];
cleanOverlappingPair(pair);
m_overlappingPairArray.swap(findIndex,m_overlappingPairArray.size()-1);
m_overlappingPairArray.pop_back();
}
}
void btHashedOverlappingPairCache::cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher)
void btOverlappingPairCache::cleanOverlappingPair(btBroadphasePair& pair)
{ {
if (pair.m_algorithm) if (pair.m_algorithm)
{ {
{ {
delete pair.m_algorithm;; pair.m_algorithm->~btCollisionAlgorithm();
dispatcher->freeCollisionAlgorithm(pair.m_algorithm);
pair.m_algorithm=0; pair.m_algorithm=0;
} }
} }
@@ -67,60 +65,20 @@ void btOverlappingPairCache::cleanOverlappingPair(btBroadphasePair& pair)
void btHashedOverlappingPairCache::cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher)
void btOverlappingPairCache::addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1)
{
//don't add overlap with own
assert(proxy0 != proxy1);
if (!needsBroadphaseCollision(proxy0,proxy1))
return;
btBroadphasePair pair(*proxy0,*proxy1);
m_overlappingPairArray.push_back(pair);
gOverlappingPairs++;
}
///this findPair becomes really slow. Either sort the list to speedup the query, or
///use a different solution. It is mainly used for Removing overlapping pairs. Removal could be delayed.
///we could keep a linked list in each proxy, and store pair in one of the proxies (with lowest memory address)
///Also we can use a 2D bitmap, which can be useful for a future GPU implementation
btBroadphasePair* btOverlappingPairCache::findPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1)
{
if (!needsBroadphaseCollision(proxy0,proxy1))
return 0;
btBroadphasePair tmpPair(*proxy0,*proxy1);
int findIndex = m_overlappingPairArray.findLinearSearch(tmpPair);
if (findIndex < m_overlappingPairArray.size())
{
//assert(it != m_overlappingPairSet.end());
btBroadphasePair* pair = &m_overlappingPairArray[findIndex];
return pair;
}
return 0;
}
void btOverlappingPairCache::cleanProxyFromPairs(btBroadphaseProxy* proxy)
{ {
class CleanPairCallback : public btOverlapCallback class CleanPairCallback : public btOverlapCallback
{ {
btBroadphaseProxy* m_cleanProxy; btBroadphaseProxy* m_cleanProxy;
btOverlappingPairCache* m_pairCache; btOverlappingPairCache* m_pairCache;
btDispatcher* m_dispatcher;
public: public:
CleanPairCallback(btBroadphaseProxy* cleanProxy,btOverlappingPairCache* pairCache) CleanPairCallback(btBroadphaseProxy* cleanProxy,btOverlappingPairCache* pairCache,btDispatcher* dispatcher)
:m_cleanProxy(cleanProxy), :m_cleanProxy(cleanProxy),
m_pairCache(pairCache) m_pairCache(pairCache),
m_dispatcher(dispatcher)
{ {
} }
virtual bool processOverlap(btBroadphasePair& pair) virtual bool processOverlap(btBroadphasePair& pair)
@@ -128,22 +86,23 @@ void btOverlappingPairCache::cleanProxyFromPairs(btBroadphaseProxy* proxy)
if ((pair.m_pProxy0 == m_cleanProxy) || if ((pair.m_pProxy0 == m_cleanProxy) ||
(pair.m_pProxy1 == m_cleanProxy)) (pair.m_pProxy1 == m_cleanProxy))
{ {
m_pairCache->cleanOverlappingPair(pair); m_pairCache->cleanOverlappingPair(pair,m_dispatcher);
} }
return false; return false;
} }
}; };
CleanPairCallback cleanPairs(proxy,this); CleanPairCallback cleanPairs(proxy,this,dispatcher);
processAllOverlappingPairs(&cleanPairs); processAllOverlappingPairs(&cleanPairs,dispatcher);
} }
void btOverlappingPairCache::removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy)
void btHashedOverlappingPairCache::removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher)
{ {
class RemovePairCallback : public btOverlapCallback class RemovePairCallback : public btOverlapCallback
@@ -166,12 +125,346 @@ void btOverlappingPairCache::removeOverlappingPairsContainingProxy(btBroadphaseP
RemovePairCallback removeCallback(proxy); RemovePairCallback removeCallback(proxy);
processAllOverlappingPairs(&removeCallback); processAllOverlappingPairs(&removeCallback,dispatcher);
} }
void btOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback* callback)
btBroadphasePair* btHashedOverlappingPairCache::findPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1)
{
gFindPairs++;
if(proxy0>proxy1) btSwap(proxy0,proxy1);
int proxyId1 = proxy0->getUid();
int proxyId2 = proxy1->getUid();
/*if (proxyId1 > proxyId2)
btSwap(proxyId1, proxyId2);*/
int hash = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1), static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity()-1));
if (hash >= m_hashTable.size())
{
return NULL;
}
int index = m_hashTable[hash];
while (index != BT_NULL_PAIR && equalsPair(m_overlappingPairArray[index], proxyId1, proxyId2) == false)
{
index = m_next[index];
}
if (index == BT_NULL_PAIR)
{
return NULL;
}
btAssert(index < m_overlappingPairArray.size());
return &m_overlappingPairArray[index];
}
//#include <stdio.h>
void btHashedOverlappingPairCache::growTables()
{
int newCapacity = m_overlappingPairArray.capacity();
if (m_hashTable.size() < newCapacity)
{
//grow hashtable and next table
int curHashtableSize = m_hashTable.size();
m_hashTable.resize(newCapacity);
m_next.resize(newCapacity);
int i;
for (i= 0; i < newCapacity; ++i)
{
m_hashTable[i] = BT_NULL_PAIR;
}
for (i = 0; i < newCapacity; ++i)
{
m_next[i] = BT_NULL_PAIR;
}
for(i=0;i<curHashtableSize;i++)
{
const btBroadphasePair& pair = m_overlappingPairArray[i];
int proxyId1 = pair.m_pProxy0->getUid();
int proxyId2 = pair.m_pProxy1->getUid();
/*if (proxyId1 > proxyId2)
btSwap(proxyId1, proxyId2);*/
int hashValue = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1),static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity()-1)); // New hash value with new mask
m_next[i] = m_hashTable[hashValue];
m_hashTable[hashValue] = i;
}
}
}
btBroadphasePair* btHashedOverlappingPairCache::internalAddPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1)
{
if(proxy0>proxy1) btSwap(proxy0,proxy1);
int proxyId1 = proxy0->getUid();
int proxyId2 = proxy1->getUid();
/*if (proxyId1 > proxyId2)
btSwap(proxyId1, proxyId2);*/
int hash = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1),static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity()-1)); // New hash value with new mask
btBroadphasePair* pair = internalFindPair(proxy0, proxy1, hash);
if (pair != NULL)
{
return pair;
}
/*for(int i=0;i<m_overlappingPairArray.size();++i)
{
if( (m_overlappingPairArray[i].m_pProxy0==proxy0)&&
(m_overlappingPairArray[i].m_pProxy1==proxy1))
{
printf("Adding duplicated %u<>%u\r\n",proxyId1,proxyId2);
internalFindPair(proxy0, proxy1, hash);
}
}*/
int count = m_overlappingPairArray.size();
int oldCapacity = m_overlappingPairArray.capacity();
void* mem = &m_overlappingPairArray.expand();
int newCapacity = m_overlappingPairArray.capacity();
if (oldCapacity < newCapacity)
{
growTables();
//hash with new capacity
hash = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1),static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity()-1));
}
pair = new (mem) btBroadphasePair(*proxy0,*proxy1);
// pair->m_pProxy0 = proxy0;
// pair->m_pProxy1 = proxy1;
pair->m_algorithm = 0;
pair->m_userInfo = 0;
m_next[count] = m_hashTable[hash];
m_hashTable[hash] = count;
return pair;
}
void* btHashedOverlappingPairCache::removeOverlappingPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1,btDispatcher* dispatcher)
{
gRemovePairs++;
if(proxy0>proxy1) btSwap(proxy0,proxy1);
int proxyId1 = proxy0->getUid();
int proxyId2 = proxy1->getUid();
/*if (proxyId1 > proxyId2)
btSwap(proxyId1, proxyId2);*/
int hash = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1),static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity()-1));
btBroadphasePair* pair = internalFindPair(proxy0, proxy1, hash);
if (pair == NULL)
{
return 0;
}
cleanOverlappingPair(*pair,dispatcher);
void* userData = pair->m_userInfo;
btAssert(pair->m_pProxy0->getUid() == proxyId1);
btAssert(pair->m_pProxy1->getUid() == proxyId2);
int pairIndex = int(pair - &m_overlappingPairArray[0]);
btAssert(pairIndex < m_overlappingPairArray.size());
// Remove the pair from the hash table.
int index = m_hashTable[hash];
btAssert(index != BT_NULL_PAIR);
int previous = BT_NULL_PAIR;
while (index != pairIndex)
{
previous = index;
index = m_next[index];
}
if (previous != BT_NULL_PAIR)
{
btAssert(m_next[previous] == pairIndex);
m_next[previous] = m_next[pairIndex];
}
else
{
m_hashTable[hash] = m_next[pairIndex];
}
// We now move the last pair into spot of the
// pair being removed. We need to fix the hash
// table indices to support the move.
int lastPairIndex = m_overlappingPairArray.size() - 1;
// If the removed pair is the last pair, we are done.
if (lastPairIndex == pairIndex)
{
m_overlappingPairArray.pop_back();
return userData;
}
// Remove the last pair from the hash table.
const btBroadphasePair* last = &m_overlappingPairArray[lastPairIndex];
/* missing swap here too, Nat. */
int lastHash = static_cast<int>(getHash(static_cast<unsigned int>(last->m_pProxy0->getUid()), static_cast<unsigned int>(last->m_pProxy1->getUid())) & (m_overlappingPairArray.capacity()-1));
index = m_hashTable[lastHash];
btAssert(index != BT_NULL_PAIR);
previous = BT_NULL_PAIR;
while (index != lastPairIndex)
{
previous = index;
index = m_next[index];
}
if (previous != BT_NULL_PAIR)
{
btAssert(m_next[previous] == lastPairIndex);
m_next[previous] = m_next[lastPairIndex];
}
else
{
m_hashTable[lastHash] = m_next[lastPairIndex];
}
// Copy the last pair into the remove pair's spot.
m_overlappingPairArray[pairIndex] = m_overlappingPairArray[lastPairIndex];
// Insert the last pair into the hash table
m_next[pairIndex] = m_hashTable[lastHash];
m_hashTable[lastHash] = pairIndex;
m_overlappingPairArray.pop_back();
return userData;
}
//#include <stdio.h>
void btHashedOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback* callback,btDispatcher* dispatcher)
{
int i;
// printf("m_overlappingPairArray.size()=%d\n",m_overlappingPairArray.size());
for (i=0;i<m_overlappingPairArray.size();)
{
btBroadphasePair* pair = &m_overlappingPairArray[i];
if (callback->processOverlap(*pair))
{
removeOverlappingPair(pair->m_pProxy0,pair->m_pProxy1,dispatcher);
gOverlappingPairs--;
} else
{
i++;
}
}
}
void* btSortedOverlappingPairCache::removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1, btDispatcher* dispatcher )
{
if (!hasDeferredRemoval())
{
btBroadphasePair findPair(*proxy0,*proxy1);
int findIndex = m_overlappingPairArray.findLinearSearch(findPair);
if (findIndex < m_overlappingPairArray.size())
{
gOverlappingPairs--;
btBroadphasePair& pair = m_overlappingPairArray[findIndex];
void* userData = pair.m_userInfo;
cleanOverlappingPair(pair,dispatcher);
m_overlappingPairArray.swap(findIndex,m_overlappingPairArray.capacity()-1);
m_overlappingPairArray.pop_back();
return userData;
}
}
return 0;
}
btBroadphasePair* btSortedOverlappingPairCache::addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1)
{
//don't add overlap with own
assert(proxy0 != proxy1);
if (!needsBroadphaseCollision(proxy0,proxy1))
return 0;
void* mem = &m_overlappingPairArray.expand();
btBroadphasePair* pair = new (mem) btBroadphasePair(*proxy0,*proxy1);
gOverlappingPairs++;
gAddedPairs++;
return pair;
}
///this findPair becomes really slow. Either sort the list to speedup the query, or
///use a different solution. It is mainly used for Removing overlapping pairs. Removal could be delayed.
///we could keep a linked list in each proxy, and store pair in one of the proxies (with lowest memory address)
///Also we can use a 2D bitmap, which can be useful for a future GPU implementation
btBroadphasePair* btSortedOverlappingPairCache::findPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1)
{
if (!needsBroadphaseCollision(proxy0,proxy1))
return 0;
btBroadphasePair tmpPair(*proxy0,*proxy1);
int findIndex = m_overlappingPairArray.findLinearSearch(tmpPair);
if (findIndex < m_overlappingPairArray.size())
{
//assert(it != m_overlappingPairSet.end());
btBroadphasePair* pair = &m_overlappingPairArray[findIndex];
return pair;
}
return 0;
}
//#include <stdio.h>
void btSortedOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback* callback,btDispatcher* dispatcher)
{ {
int i; int i;
@@ -182,9 +475,9 @@ void btOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback* callb
btBroadphasePair* pair = &m_overlappingPairArray[i]; btBroadphasePair* pair = &m_overlappingPairArray[i];
if (callback->processOverlap(*pair)) if (callback->processOverlap(*pair))
{ {
cleanOverlappingPair(*pair); cleanOverlappingPair(*pair,dispatcher);
m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); m_overlappingPairArray.swap(i,m_overlappingPairArray.capacity()-1);
m_overlappingPairArray.pop_back(); m_overlappingPairArray.pop_back();
gOverlappingPairs--; gOverlappingPairs--;
} else } else
@@ -194,3 +487,93 @@ void btOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback* callb
} }
} }
btSortedOverlappingPairCache::btSortedOverlappingPairCache():
m_blockedForChanges(false),
m_hasDeferredRemoval(true),
m_overlapFilterCallback(0)
{
int initialAllocatedSize= 2;
m_overlappingPairArray.reserve(initialAllocatedSize);
}
btSortedOverlappingPairCache::~btSortedOverlappingPairCache()
{
//todo/test: show we erase/delete data, or is it automatic
}
void btSortedOverlappingPairCache::cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher)
{
if (pair.m_algorithm)
{
{
pair.m_algorithm->~btCollisionAlgorithm();
dispatcher->freeCollisionAlgorithm(pair.m_algorithm);
pair.m_algorithm=0;
gRemovePairs--;
}
}
}
void btSortedOverlappingPairCache::cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher)
{
class CleanPairCallback : public btOverlapCallback
{
btBroadphaseProxy* m_cleanProxy;
btOverlappingPairCache* m_pairCache;
btDispatcher* m_dispatcher;
public:
CleanPairCallback(btBroadphaseProxy* cleanProxy,btOverlappingPairCache* pairCache,btDispatcher* dispatcher)
:m_cleanProxy(cleanProxy),
m_pairCache(pairCache),
m_dispatcher(dispatcher)
{
}
virtual bool processOverlap(btBroadphasePair& pair)
{
if ((pair.m_pProxy0 == m_cleanProxy) ||
(pair.m_pProxy1 == m_cleanProxy))
{
m_pairCache->cleanOverlappingPair(pair,m_dispatcher);
}
return false;
}
};
CleanPairCallback cleanPairs(proxy,this,dispatcher);
processAllOverlappingPairs(&cleanPairs,dispatcher);
}
void btSortedOverlappingPairCache::removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher)
{
class RemovePairCallback : public btOverlapCallback
{
btBroadphaseProxy* m_obsoleteProxy;
public:
RemovePairCallback(btBroadphaseProxy* obsoleteProxy)
:m_obsoleteProxy(obsoleteProxy)
{
}
virtual bool processOverlap(btBroadphasePair& pair)
{
return ((pair.m_pProxy0 == m_obsoleteProxy) ||
(pair.m_pProxy1 == m_obsoleteProxy));
}
};
RemovePairCallback removeCallback(proxy);
processAllOverlappingPairs(&removeCallback,dispatcher);
}

View File

@@ -1,4 +1,3 @@
/* /*
Bullet Continuous Collision Detection and Physics Library Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
@@ -20,9 +19,13 @@ subject to the following restrictions:
#include "btBroadphaseInterface.h" #include "btBroadphaseInterface.h"
#include "btBroadphaseProxy.h" #include "btBroadphaseProxy.h"
#include "../../LinearMath/btPoint3.h" #include "btOverlappingPairCallback.h"
#include "../../LinearMath/btAlignedObjectArray.h"
#include "LinearMath/btPoint3.h"
#include "LinearMath/btAlignedObjectArray.h"
class btDispatcher;
typedef btAlignedObjectArray<btBroadphasePair> btBroadphasePairArray;
struct btOverlapCallback struct btOverlapCallback
{ {
@@ -30,6 +33,7 @@ struct btOverlapCallback
{} {}
//return true for deletion of the pair //return true for deletion of the pair
virtual bool processOverlap(btBroadphasePair& pair) = 0; virtual bool processOverlap(btBroadphasePair& pair) = 0;
}; };
struct btOverlapFilterCallback struct btOverlapFilterCallback
@@ -40,38 +44,261 @@ struct btOverlapFilterCallback
virtual bool needBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const = 0; virtual bool needBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const = 0;
}; };
///btOverlappingPairCache maintains the objects with overlapping AABB
extern int gRemovePairs;
extern int gAddedPairs;
extern int gFindPairs;
const int BT_NULL_PAIR=0xffffffff;
///The btOverlappingPairCache provides an interface for overlapping pair management (add, remove, storage), used by the btBroadphaseInterface broadphases.
///The btHashedOverlappingPairCache and btSortedOverlappingPairCache classes are two implementations.
class btOverlappingPairCache : public btOverlappingPairCallback
{
public:
virtual ~btOverlappingPairCache() {} // this is needed so we can get to the derived class destructor
virtual btBroadphasePair* getOverlappingPairArrayPtr() = 0;
virtual const btBroadphasePair* getOverlappingPairArrayPtr() const = 0;
virtual btBroadphasePairArray& getOverlappingPairArray() = 0;
virtual void cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher) = 0;
virtual int getNumOverlappingPairs() const = 0;
virtual void cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher) = 0;
virtual void setOverlapFilterCallback(btOverlapFilterCallback* callback) = 0;
virtual void processAllOverlappingPairs(btOverlapCallback*,btDispatcher* dispatcher) = 0;
virtual btBroadphasePair* findPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) = 0;
virtual bool hasDeferredRemoval() = 0;
};
/// Hash-space based Pair Cache, thanks to Erin Catto, Box2D, http://www.box2d.org, and Pierre Terdiman, Codercorner, http://codercorner.com
class btHashedOverlappingPairCache : public btOverlappingPairCache
{
btBroadphasePairArray m_overlappingPairArray;
btOverlapFilterCallback* m_overlapFilterCallback;
bool m_blockedForChanges;
public:
btHashedOverlappingPairCache();
virtual ~btHashedOverlappingPairCache();
void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher);
virtual void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher);
SIMD_FORCE_INLINE bool needsBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const
{
if (m_overlapFilterCallback)
return m_overlapFilterCallback->needBroadphaseCollision(proxy0,proxy1);
bool collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0;
collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask);
return collides;
}
// Add a pair and return the new pair. If the pair already exists,
// no new pair is created and the old one is returned.
virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1)
{
gAddedPairs++;
if (!needsBroadphaseCollision(proxy0,proxy1))
return 0;
return internalAddPair(proxy0,proxy1);
}
void cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher);
virtual void processAllOverlappingPairs(btOverlapCallback*,btDispatcher* dispatcher);
virtual btBroadphasePair* getOverlappingPairArrayPtr()
{
return &m_overlappingPairArray[0];
}
const btBroadphasePair* getOverlappingPairArrayPtr() const
{
return &m_overlappingPairArray[0];
}
btBroadphasePairArray& getOverlappingPairArray()
{
return m_overlappingPairArray;
}
const btBroadphasePairArray& getOverlappingPairArray() const
{
return m_overlappingPairArray;
}
void cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher);
btBroadphasePair* findPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1);
int GetCount() const { return m_overlappingPairArray.size(); }
// btBroadphasePair* GetPairs() { return m_pairs; }
btOverlapFilterCallback* getOverlapFilterCallback()
{
return m_overlapFilterCallback;
}
void setOverlapFilterCallback(btOverlapFilterCallback* callback)
{
m_overlapFilterCallback = callback;
}
int getNumOverlappingPairs() const
{
return m_overlappingPairArray.size();
}
private:
btBroadphasePair* internalAddPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1);
void growTables();
SIMD_FORCE_INLINE bool equalsPair(const btBroadphasePair& pair, int proxyId1, int proxyId2)
{
return pair.m_pProxy0->getUid() == proxyId1 && pair.m_pProxy1->getUid() == proxyId2;
}
/*
// Thomas Wang's hash, see: http://www.concentric.net/~Ttwang/tech/inthash.htm
// This assumes proxyId1 and proxyId2 are 16-bit.
SIMD_FORCE_INLINE int getHash(int proxyId1, int proxyId2)
{
int key = (proxyId2 << 16) | proxyId1;
key = ~key + (key << 15);
key = key ^ (key >> 12);
key = key + (key << 2);
key = key ^ (key >> 4);
key = key * 2057;
key = key ^ (key >> 16);
return key;
}
*/
SIMD_FORCE_INLINE unsigned int getHash(unsigned int proxyId1, unsigned int proxyId2)
{
int key = static_cast<int>(((unsigned int)proxyId1) | (((unsigned int)proxyId2) <<16));
// Thomas Wang's hash
key += ~(key << 15);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key += ~(key << 11);
key ^= (key >> 16);
return static_cast<unsigned int>(key);
}
SIMD_FORCE_INLINE btBroadphasePair* internalFindPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1, int hash)
{
int proxyId1 = proxy0->getUid();
int proxyId2 = proxy1->getUid();
#if 0 // wrong, 'equalsPair' use unsorted uids, copy-past devil striked again. Nat.
if (proxyId1 > proxyId2)
btSwap(proxyId1, proxyId2);
#endif
int index = m_hashTable[hash];
while( index != BT_NULL_PAIR && equalsPair(m_overlappingPairArray[index], proxyId1, proxyId2) == false)
{
index = m_next[index];
}
if ( index == BT_NULL_PAIR )
{
return NULL;
}
btAssert(index < m_overlappingPairArray.size());
return &m_overlappingPairArray[index];
}
virtual bool hasDeferredRemoval()
{
return false;
}
public:
btAlignedObjectArray<int> m_hashTable;
btAlignedObjectArray<int> m_next;
};
///btSortedOverlappingPairCache maintains the objects with overlapping AABB
///Typically managed by the Broadphase, Axis3Sweep or btSimpleBroadphase ///Typically managed by the Broadphase, Axis3Sweep or btSimpleBroadphase
class btOverlappingPairCache : public btBroadphaseInterface class btSortedOverlappingPairCache : public btOverlappingPairCache
{ {
protected: protected:
//avoid brute-force finding all the time //avoid brute-force finding all the time
btAlignedObjectArray<btBroadphasePair> m_overlappingPairArray; btBroadphasePairArray m_overlappingPairArray;
//during the dispatch, check that user doesn't destroy/create proxy //during the dispatch, check that user doesn't destroy/create proxy
bool m_blockedForChanges; bool m_blockedForChanges;
///by default, do the removal during the pair traversal
bool m_hasDeferredRemoval;
//if set, use the callback instead of the built in filter in needBroadphaseCollision //if set, use the callback instead of the built in filter in needBroadphaseCollision
btOverlapFilterCallback* m_overlapFilterCallback; btOverlapFilterCallback* m_overlapFilterCallback;
public: public:
btOverlappingPairCache(); btSortedOverlappingPairCache();
virtual ~btOverlappingPairCache(); virtual ~btSortedOverlappingPairCache();
virtual void processAllOverlappingPairs(btOverlapCallback*); virtual void processAllOverlappingPairs(btOverlapCallback*,btDispatcher* dispatcher);
void removeOverlappingPair(btBroadphasePair& pair); void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher);
void cleanOverlappingPair(btBroadphasePair& pair); void cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher);
void addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1);
btBroadphasePair* findPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); btBroadphasePair* findPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1);
void cleanProxyFromPairs(btBroadphaseProxy* proxy); void cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher);
void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy); void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher);
inline bool needsBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const inline bool needsBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const
@@ -84,10 +311,19 @@ class btOverlappingPairCache : public btBroadphaseInterface
return collides; return collides;
} }
btBroadphasePairArray& getOverlappingPairArray()
{
return m_overlappingPairArray;
}
const btBroadphasePairArray& getOverlappingPairArray() const
{
return m_overlappingPairArray;
}
virtual void refreshOverlappingPairs() =0;
btBroadphasePair* getOverlappingPairArrayPtr() btBroadphasePair* getOverlappingPairArrayPtr()
{ {
@@ -114,7 +350,88 @@ class btOverlappingPairCache : public btBroadphaseInterface
m_overlapFilterCallback = callback; m_overlapFilterCallback = callback;
} }
virtual bool hasDeferredRemoval()
{
return m_hasDeferredRemoval;
}
}; };
///btNullPairCache skips add/removal of overlapping pairs. Userful for benchmarking and testing.
class btNullPairCache : public btOverlappingPairCache
{
btBroadphasePairArray m_overlappingPairArray;
public:
virtual btBroadphasePair* getOverlappingPairArrayPtr()
{
return &m_overlappingPairArray[0];
}
const btBroadphasePair* getOverlappingPairArrayPtr() const
{
return &m_overlappingPairArray[0];
}
btBroadphasePairArray& getOverlappingPairArray()
{
return m_overlappingPairArray;
}
virtual void cleanOverlappingPair(btBroadphasePair& /*pair*/,btDispatcher* /*dispatcher*/)
{
}
virtual int getNumOverlappingPairs() const
{
return 0;
}
virtual void cleanProxyFromPairs(btBroadphaseProxy* /*proxy*/,btDispatcher* /*dispatcher*/)
{
}
virtual void setOverlapFilterCallback(btOverlapFilterCallback* /*callback*/)
{
}
virtual void processAllOverlappingPairs(btOverlapCallback*,btDispatcher* /*dispatcher*/)
{
}
virtual btBroadphasePair* findPair(btBroadphaseProxy* /*proxy0*/, btBroadphaseProxy* /*proxy1*/)
{
return 0;
}
virtual bool hasDeferredRemoval()
{
return true;
}
virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* /*proxy0*/,btBroadphaseProxy* /*proxy1*/)
{
return 0;
}
virtual void* removeOverlappingPair(btBroadphaseProxy* /*proxy0*/,btBroadphaseProxy* /*proxy1*/,btDispatcher* /*dispatcher*/)
{
return 0;
}
virtual void removeOverlappingPairsContainingProxy(btBroadphaseProxy* /*proxy0*/,btDispatcher* /*dispatcher*/)
{
}
};
#endif //OVERLAPPING_PAIR_CACHE_H #endif //OVERLAPPING_PAIR_CACHE_H

View File

@@ -0,0 +1,40 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef OVERLAPPING_PAIR_CALLBACK_H
#define OVERLAPPING_PAIR_CALLBACK_H
class btDispatcher;
struct btBroadphasePair;
///The btOverlappingPairCallback class is an additional optional broadphase user callback for adding/removing overlapping pairs, similar interface to btOverlappingPairCache.
class btOverlappingPairCallback
{
public:
virtual ~btOverlappingPairCallback()
{
}
virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) = 0;
virtual void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher) = 0;
virtual void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy0,btDispatcher* dispatcher) = 0;
};
#endif //OVERLAPPING_PAIR_CALLBACK_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,486 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef QUANTIZED_BVH_H
#define QUANTIZED_BVH_H
//#define DEBUG_CHECK_DEQUANTIZATION 1
#ifdef DEBUG_CHECK_DEQUANTIZATION
#ifdef __SPU__
#define printf spu_printf
#endif //__SPU__
#include <stdio.h>
#include <stdlib.h>
#endif //DEBUG_CHECK_DEQUANTIZATION
#include "LinearMath/btVector3.h"
#include "LinearMath/btAlignedAllocator.h"
//http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrf__m128.asp
//Note: currently we have 16 bytes per quantized node
#define MAX_SUBTREE_SIZE_IN_BYTES 2048
// 10 gives the potential for 1024 parts, with at most 2^21 (2097152) (minus one
// actually) triangles each (since the sign bit is reserved
#define MAX_NUM_PARTS_IN_BITS 10
///btQuantizedBvhNode is a compressed aabb node, 16 bytes.
///Node can be used for leafnode or internal node. Leafnodes can point to 32-bit triangle index (non-negative range).
ATTRIBUTE_ALIGNED16 (struct) btQuantizedBvhNode
{
BT_DECLARE_ALIGNED_ALLOCATOR();
//12 bytes
unsigned short int m_quantizedAabbMin[3];
unsigned short int m_quantizedAabbMax[3];
//4 bytes
int m_escapeIndexOrTriangleIndex;
bool isLeafNode() const
{
//skipindex is negative (internal node), triangleindex >=0 (leafnode)
return (m_escapeIndexOrTriangleIndex >= 0);
}
int getEscapeIndex() const
{
btAssert(!isLeafNode());
return -m_escapeIndexOrTriangleIndex;
}
int getTriangleIndex() const
{
btAssert(isLeafNode());
// Get only the lower bits where the triangle index is stored
return (m_escapeIndexOrTriangleIndex&~((~0)<<(31-MAX_NUM_PARTS_IN_BITS)));
}
int getPartId() const
{
btAssert(isLeafNode());
// Get only the highest bits where the part index is stored
return (m_escapeIndexOrTriangleIndex>>(31-MAX_NUM_PARTS_IN_BITS));
}
}
;
/// btOptimizedBvhNode contains both internal and leaf node information.
/// Total node size is 44 bytes / node. You can use the compressed version of 16 bytes.
ATTRIBUTE_ALIGNED16 (struct) btOptimizedBvhNode
{
BT_DECLARE_ALIGNED_ALLOCATOR();
//32 bytes
btVector3 m_aabbMinOrg;
btVector3 m_aabbMaxOrg;
//4
int m_escapeIndex;
//8
//for child nodes
int m_subPart;
int m_triangleIndex;
int m_padding[5];//bad, due to alignment
};
///btBvhSubtreeInfo provides info to gather a subtree of limited size
ATTRIBUTE_ALIGNED16(class) btBvhSubtreeInfo
{
public:
BT_DECLARE_ALIGNED_ALLOCATOR();
//12 bytes
unsigned short int m_quantizedAabbMin[3];
unsigned short int m_quantizedAabbMax[3];
//4 bytes, points to the root of the subtree
int m_rootNodeIndex;
//4 bytes
int m_subtreeSize;
int m_padding[3];
btBvhSubtreeInfo()
{
//memset(&m_padding[0], 0, sizeof(m_padding));
}
void setAabbFromQuantizeNode(const btQuantizedBvhNode& quantizedNode)
{
m_quantizedAabbMin[0] = quantizedNode.m_quantizedAabbMin[0];
m_quantizedAabbMin[1] = quantizedNode.m_quantizedAabbMin[1];
m_quantizedAabbMin[2] = quantizedNode.m_quantizedAabbMin[2];
m_quantizedAabbMax[0] = quantizedNode.m_quantizedAabbMax[0];
m_quantizedAabbMax[1] = quantizedNode.m_quantizedAabbMax[1];
m_quantizedAabbMax[2] = quantizedNode.m_quantizedAabbMax[2];
}
}
;
class btNodeOverlapCallback
{
public:
virtual ~btNodeOverlapCallback() {};
virtual void processNode(int subPart, int triangleIndex) = 0;
};
#include "LinearMath/btAlignedAllocator.h"
#include "LinearMath/btAlignedObjectArray.h"
///for code readability:
typedef btAlignedObjectArray<btOptimizedBvhNode> NodeArray;
typedef btAlignedObjectArray<btQuantizedBvhNode> QuantizedNodeArray;
typedef btAlignedObjectArray<btBvhSubtreeInfo> BvhSubtreeInfoArray;
///The btQuantizedBvh class stores an AABB tree that can be quickly traversed on CPU and Cell SPU.
///It is used by the btBvhTriangleMeshShape as midphase, and by the btMultiSapBroadphase.
///It is recommended to use quantization for better performance and lower memory requirements.
ATTRIBUTE_ALIGNED16(class) btQuantizedBvh
{
protected:
NodeArray m_leafNodes;
NodeArray m_contiguousNodes;
QuantizedNodeArray m_quantizedLeafNodes;
QuantizedNodeArray m_quantizedContiguousNodes;
int m_curNodeIndex;
//quantization data
bool m_useQuantization;
btVector3 m_bvhAabbMin;
btVector3 m_bvhAabbMax;
btVector3 m_bvhQuantization;
public:
BT_DECLARE_ALIGNED_ALLOCATOR();
enum btTraversalMode
{
TRAVERSAL_STACKLESS = 0,
TRAVERSAL_STACKLESS_CACHE_FRIENDLY,
TRAVERSAL_RECURSIVE
};
protected:
btTraversalMode m_traversalMode;
BvhSubtreeInfoArray m_SubtreeHeaders;
//This is only used for serialization so we don't have to add serialization directly to btAlignedObjectArray
int m_subtreeHeaderCount;
///two versions, one for quantized and normal nodes. This allows code-reuse while maintaining readability (no template/macro!)
///this might be refactored into a virtual, it is usually not calculated at run-time
void setInternalNodeAabbMin(int nodeIndex, const btVector3& aabbMin)
{
if (m_useQuantization)
{
quantize(&m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0] ,aabbMin,0);
} else
{
m_contiguousNodes[nodeIndex].m_aabbMinOrg = aabbMin;
}
}
void setInternalNodeAabbMax(int nodeIndex,const btVector3& aabbMax)
{
if (m_useQuantization)
{
quantize(&m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0],aabbMax,1);
} else
{
m_contiguousNodes[nodeIndex].m_aabbMaxOrg = aabbMax;
}
}
btVector3 getAabbMin(int nodeIndex) const
{
if (m_useQuantization)
{
return unQuantize(&m_quantizedLeafNodes[nodeIndex].m_quantizedAabbMin[0]);
}
//non-quantized
return m_leafNodes[nodeIndex].m_aabbMinOrg;
}
btVector3 getAabbMax(int nodeIndex) const
{
if (m_useQuantization)
{
return unQuantize(&m_quantizedLeafNodes[nodeIndex].m_quantizedAabbMax[0]);
}
//non-quantized
return m_leafNodes[nodeIndex].m_aabbMaxOrg;
}
void setInternalNodeEscapeIndex(int nodeIndex, int escapeIndex)
{
if (m_useQuantization)
{
m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex = -escapeIndex;
}
else
{
m_contiguousNodes[nodeIndex].m_escapeIndex = escapeIndex;
}
}
void mergeInternalNodeAabb(int nodeIndex,const btVector3& newAabbMin,const btVector3& newAabbMax)
{
if (m_useQuantization)
{
unsigned short int quantizedAabbMin[3];
unsigned short int quantizedAabbMax[3];
quantize(quantizedAabbMin,newAabbMin,0);
quantize(quantizedAabbMax,newAabbMax,1);
for (int i=0;i<3;i++)
{
if (m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[i] > quantizedAabbMin[i])
m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[i] = quantizedAabbMin[i];
if (m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[i] < quantizedAabbMax[i])
m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[i] = quantizedAabbMax[i];
}
} else
{
//non-quantized
m_contiguousNodes[nodeIndex].m_aabbMinOrg.setMin(newAabbMin);
m_contiguousNodes[nodeIndex].m_aabbMaxOrg.setMax(newAabbMax);
}
}
void swapLeafNodes(int firstIndex,int secondIndex);
void assignInternalNodeFromLeafNode(int internalNode,int leafNodeIndex);
protected:
void buildTree (int startIndex,int endIndex);
int calcSplittingAxis(int startIndex,int endIndex);
int sortAndCalcSplittingIndex(int startIndex,int endIndex,int splitAxis);
void walkStacklessTree(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const;
void walkStacklessQuantizedTreeAgainstRay(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin, const btVector3& aabbMax, int startNodeIndex,int endNodeIndex) const;
void walkStacklessQuantizedTree(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax,int startNodeIndex,int endNodeIndex) const;
///tree traversal designed for small-memory processors like PS3 SPU
void walkStacklessQuantizedTreeCacheFriendly(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const;
///use the 16-byte stackless 'skipindex' node tree to do a recursive traversal
void walkRecursiveQuantizedTreeAgainstQueryAabb(const btQuantizedBvhNode* currentNode,btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const;
///use the 16-byte stackless 'skipindex' node tree to do a recursive traversal
void walkRecursiveQuantizedTreeAgainstQuantizedTree(const btQuantizedBvhNode* treeNodeA,const btQuantizedBvhNode* treeNodeB,btNodeOverlapCallback* nodeCallback) const;
#define USE_BANCHLESS 1
#ifdef USE_BANCHLESS
//This block replaces the block below and uses no branches, and replaces the 8 bit return with a 32 bit return for improved performance (~3x on XBox 360)
SIMD_FORCE_INLINE unsigned testQuantizedAabbAgainstQuantizedAabb(unsigned short int* aabbMin1,unsigned short int* aabbMax1,const unsigned short int* aabbMin2,const unsigned short int* aabbMax2) const
{
return static_cast<unsigned int>(btSelect((unsigned)((aabbMin1[0] <= aabbMax2[0]) & (aabbMax1[0] >= aabbMin2[0])
& (aabbMin1[2] <= aabbMax2[2]) & (aabbMax1[2] >= aabbMin2[2])
& (aabbMin1[1] <= aabbMax2[1]) & (aabbMax1[1] >= aabbMin2[1])),
1, 0));
}
#else
SIMD_FORCE_INLINE bool testQuantizedAabbAgainstQuantizedAabb(unsigned short int* aabbMin1,unsigned short int* aabbMax1,const unsigned short int* aabbMin2,const unsigned short int* aabbMax2) const
{
bool overlap = true;
overlap = (aabbMin1[0] > aabbMax2[0] || aabbMax1[0] < aabbMin2[0]) ? false : overlap;
overlap = (aabbMin1[2] > aabbMax2[2] || aabbMax1[2] < aabbMin2[2]) ? false : overlap;
overlap = (aabbMin1[1] > aabbMax2[1] || aabbMax1[1] < aabbMin2[1]) ? false : overlap;
return overlap;
}
#endif //USE_BANCHLESS
void updateSubtreeHeaders(int leftChildNodexIndex,int rightChildNodexIndex);
public:
btQuantizedBvh();
virtual ~btQuantizedBvh();
///***************************************** expert/internal use only *************************
void setQuantizationValues(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax,btScalar quantizationMargin=btScalar(1.0));
QuantizedNodeArray& getLeafNodeArray() { return m_quantizedLeafNodes; }
///buildInternal is expert use only: assumes that setQuantizationValues and LeafNodeArray are initialized
void buildInternal();
///***************************************** expert/internal use only *************************
void reportAabbOverlappingNodex(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const;
void reportRayOverlappingNodex (btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget) const;
void reportBoxCastOverlappingNodex(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin,const btVector3& aabbMax) const;
SIMD_FORCE_INLINE void quantize(unsigned short* out, const btVector3& point,int isMax) const
{
btAssert(m_useQuantization);
btAssert(point.getX() <= m_bvhAabbMax.getX());
btAssert(point.getY() <= m_bvhAabbMax.getY());
btAssert(point.getZ() <= m_bvhAabbMax.getZ());
btAssert(point.getX() >= m_bvhAabbMin.getX());
btAssert(point.getY() >= m_bvhAabbMin.getY());
btAssert(point.getZ() >= m_bvhAabbMin.getZ());
btVector3 v = (point - m_bvhAabbMin) * m_bvhQuantization;
///Make sure rounding is done in a way that unQuantize(quantizeWithClamp(...)) is conservative
///end-points always set the first bit, so that they are sorted properly (so that neighbouring AABBs overlap properly)
///todo: double-check this
if (isMax)
{
out[0] = (unsigned short) (((unsigned short)(v.getX()+btScalar(1.)) | 1));
out[1] = (unsigned short) (((unsigned short)(v.getY()+btScalar(1.)) | 1));
out[2] = (unsigned short) (((unsigned short)(v.getZ()+btScalar(1.)) | 1));
} else
{
out[0] = (unsigned short) (((unsigned short)(v.getX()) & 0xfffe));
out[1] = (unsigned short) (((unsigned short)(v.getY()) & 0xfffe));
out[2] = (unsigned short) (((unsigned short)(v.getZ()) & 0xfffe));
}
#ifdef DEBUG_CHECK_DEQUANTIZATION
btVector3 newPoint = unQuantize(out);
if (isMax)
{
if (newPoint.getX() < point.getX())
{
printf("unconservative X, diffX = %f, oldX=%f,newX=%f\n",newPoint.getX()-point.getX(), newPoint.getX(),point.getX());
}
if (newPoint.getY() < point.getY())
{
printf("unconservative Y, diffY = %f, oldY=%f,newY=%f\n",newPoint.getY()-point.getY(), newPoint.getY(),point.getY());
}
if (newPoint.getZ() < point.getZ())
{
printf("unconservative Z, diffZ = %f, oldZ=%f,newZ=%f\n",newPoint.getZ()-point.getZ(), newPoint.getZ(),point.getZ());
}
} else
{
if (newPoint.getX() > point.getX())
{
printf("unconservative X, diffX = %f, oldX=%f,newX=%f\n",newPoint.getX()-point.getX(), newPoint.getX(),point.getX());
}
if (newPoint.getY() > point.getY())
{
printf("unconservative Y, diffY = %f, oldY=%f,newY=%f\n",newPoint.getY()-point.getY(), newPoint.getY(),point.getY());
}
if (newPoint.getZ() > point.getZ())
{
printf("unconservative Z, diffZ = %f, oldZ=%f,newZ=%f\n",newPoint.getZ()-point.getZ(), newPoint.getZ(),point.getZ());
}
}
#endif //DEBUG_CHECK_DEQUANTIZATION
}
SIMD_FORCE_INLINE void quantizeWithClamp(unsigned short* out, const btVector3& point2,int isMax) const
{
btAssert(m_useQuantization);
btVector3 clampedPoint(point2);
clampedPoint.setMax(m_bvhAabbMin);
clampedPoint.setMin(m_bvhAabbMax);
quantize(out,clampedPoint,isMax);
}
SIMD_FORCE_INLINE btVector3 unQuantize(const unsigned short* vecIn) const
{
btVector3 vecOut;
vecOut.setValue(
(btScalar)(vecIn[0]) / (m_bvhQuantization.getX()),
(btScalar)(vecIn[1]) / (m_bvhQuantization.getY()),
(btScalar)(vecIn[2]) / (m_bvhQuantization.getZ()));
vecOut += m_bvhAabbMin;
return vecOut;
}
///setTraversalMode let's you choose between stackless, recursive or stackless cache friendly tree traversal. Note this is only implemented for quantized trees.
void setTraversalMode(btTraversalMode traversalMode)
{
m_traversalMode = traversalMode;
}
SIMD_FORCE_INLINE QuantizedNodeArray& getQuantizedNodeArray()
{
return m_quantizedContiguousNodes;
}
SIMD_FORCE_INLINE BvhSubtreeInfoArray& getSubtreeInfoArray()
{
return m_SubtreeHeaders;
}
/////Calculate space needed to store BVH for serialization
unsigned calculateSerializeBufferSize();
/// Data buffer MUST be 16 byte aligned
virtual bool serialize(void *o_alignedDataBuffer, unsigned i_dataBufferSize, bool i_swapEndian);
///deSerializeInPlace loads and initializes a BVH from a buffer in memory 'in place'
static btQuantizedBvh *deSerializeInPlace(void *i_alignedDataBuffer, unsigned int i_dataBufferSize, bool i_swapEndian);
static unsigned int getAlignmentSerializationPadding();
SIMD_FORCE_INLINE bool isQuantized()
{
return m_useQuantization;
}
private:
// Special "copy" constructor that allows for in-place deserialization
// Prevents btVector3's default constructor from being called, but doesn't inialize much else
// ownsMemory should most likely be false if deserializing, and if you are not, don't call this (it also changes the function signature, which we need)
btQuantizedBvh(btQuantizedBvh &other, bool ownsMemory);
}
;
#endif //QUANTIZED_BVH_H

View File

@@ -14,83 +14,86 @@ subject to the following restrictions:
*/ */
#include "btSimpleBroadphase.h" #include "btSimpleBroadphase.h"
#include <BulletCollision/BroadphaseCollision/btDispatcher.h> #include "BulletCollision/BroadphaseCollision/btDispatcher.h"
#include <BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h> #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
#include "LinearMath/btVector3.h" #include "LinearMath/btVector3.h"
#include "LinearMath/btTransform.h" #include "LinearMath/btTransform.h"
#include "LinearMath/btMatrix3x3.h" #include "LinearMath/btMatrix3x3.h"
#include <new> #include <new>
extern int gOverlappingPairs;
void btSimpleBroadphase::validate() void btSimpleBroadphase::validate()
{ {
for (int i=0;i<m_numProxies;i++) for (int i=0;i<m_numHandles;i++)
{ {
for (int j=i+1;j<m_numProxies;j++) for (int j=i+1;j<m_numHandles;j++)
{ {
assert(m_pProxies[i] != m_pProxies[j]); btAssert(&m_pHandles[i] != &m_pHandles[j]);
} }
} }
} }
btSimpleBroadphase::btSimpleBroadphase(int maxProxies) btSimpleBroadphase::btSimpleBroadphase(int maxProxies, btOverlappingPairCache* overlappingPairCache)
:btOverlappingPairCache(), :m_pairCache(overlappingPairCache),
m_firstFreeProxy(0), m_ownsPairCache(false),
m_numProxies(0), m_invalidPair(0)
m_maxProxies(maxProxies)
{ {
m_proxies = new btSimpleBroadphaseProxy[maxProxies]; if (!overlappingPairCache)
m_freeProxies = new int[maxProxies];
m_pProxies = new btSimpleBroadphaseProxy*[maxProxies];
int i;
for (i=0;i<m_maxProxies;i++)
{ {
m_freeProxies[i] = i; void* mem = btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16);
m_pairCache = new (mem)btHashedOverlappingPairCache();
m_ownsPairCache = true;
} }
// allocate handles buffer and put all handles on free list
m_pHandlesRawPtr = btAlignedAlloc(sizeof(btSimpleBroadphaseProxy)*maxProxies,16);
m_pHandles = new(m_pHandlesRawPtr) btSimpleBroadphaseProxy[maxProxies];
m_maxHandles = maxProxies;
m_numHandles = 0;
m_firstFreeHandle = 0;
m_firstAllocatedHandle = -1;
{
for (int i = m_firstFreeHandle; i < maxProxies; i++)
{
m_pHandles[i].SetNextFree(i + 1);
m_pHandles[i].m_uniqueId = i+2;//any UID will do, we just avoid too trivial values (0,1) for debugging purposes
m_pHandles[i].SetNextAllocated(-1);
}
m_pHandles[maxProxies - 1].SetNextFree(0);
m_pHandles[maxProxies - 1].SetNextAllocated(-1);
}
} }
btSimpleBroadphase::~btSimpleBroadphase() btSimpleBroadphase::~btSimpleBroadphase()
{ {
delete[] m_proxies; btAlignedFree(m_pHandlesRawPtr);
delete []m_freeProxies;
delete [] m_pProxies;
/*int i; if (m_ownsPairCache)
for (i=m_numProxies-1;i>=0;i--)
{ {
BP_Proxy* proxy = m_pProxies[i]; m_pairCache->~btOverlappingPairCache();
destroyProxy(proxy); btAlignedFree(m_pairCache);
} }
*/
} }
btBroadphaseProxy* btSimpleBroadphase::createProxy( const btVector3& min, const btVector3& max,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask) btBroadphaseProxy* btSimpleBroadphase::createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* /*dispatcher*/,void* multiSapProxy)
{ {
if (m_numProxies >= m_maxProxies) if (m_numHandles >= m_maxHandles)
{ {
assert(0); btAssert(0);
return 0; //should never happen, but don't let the game crash ;-) return 0; //should never happen, but don't let the game crash ;-)
} }
assert(min[0]<= max[0] && min[1]<= max[1] && min[2]<= max[2]); assert(aabbMin[0]<= aabbMax[0] && aabbMin[1]<= aabbMax[1] && aabbMin[2]<= aabbMax[2]);
int freeIndex= m_freeProxies[m_firstFreeProxy]; int newHandleIndex = allocHandle();
btSimpleBroadphaseProxy* proxy = new (&m_proxies[freeIndex])btSimpleBroadphaseProxy(min,max,shapeType,userPtr,collisionFilterGroup,collisionFilterMask); btSimpleBroadphaseProxy* proxy = new (&m_pHandles[newHandleIndex])btSimpleBroadphaseProxy(aabbMin,aabbMax,shapeType,userPtr,collisionFilterGroup,collisionFilterMask,multiSapProxy);
m_firstFreeProxy++;
btSimpleBroadphaseProxy* proxy1 = &m_proxies[0];
int index = int(proxy - proxy1);
btAssert(index == freeIndex);
m_pProxies[m_numProxies] = proxy;
m_numProxies++;
//validate();
return proxy; return proxy;
} }
@@ -124,34 +127,19 @@ protected:
}; };
}; };
void btSimpleBroadphase::destroyProxy(btBroadphaseProxy* proxyOrg) void btSimpleBroadphase::destroyProxy(btBroadphaseProxy* proxyOrg,btDispatcher* dispatcher)
{ {
int i;
btSimpleBroadphaseProxy* proxy0 = static_cast<btSimpleBroadphaseProxy*>(proxyOrg); btSimpleBroadphaseProxy* proxy0 = static_cast<btSimpleBroadphaseProxy*>(proxyOrg);
btSimpleBroadphaseProxy* proxy1 = &m_proxies[0]; freeHandle(proxy0);
int index = int(proxy0 - proxy1); m_pairCache->removeOverlappingPairsContainingProxy(proxyOrg,dispatcher);
btAssert (index < m_maxProxies);
m_freeProxies[--m_firstFreeProxy] = index;
removeOverlappingPairsContainingProxy(proxyOrg);
for (i=0;i<m_numProxies;i++)
{
if (m_pProxies[i] == proxyOrg)
{
m_pProxies[i] = m_pProxies[m_numProxies-1];
break;
}
}
m_numProxies--;
//validate(); //validate();
} }
void btSimpleBroadphase::setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax) void btSimpleBroadphase::setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* /*dispatcher*/)
{ {
btSimpleBroadphaseProxy* sbp = getSimpleProxyFromProxy(proxy); btSimpleBroadphaseProxy* sbp = getSimpleProxyFromProxy(proxy);
sbp->m_min = aabbMin; sbp->m_min = aabbMin;
@@ -186,37 +174,137 @@ public:
} }
}; };
void btSimpleBroadphase::refreshOverlappingPairs() void btSimpleBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher)
{ {
//first check for new overlapping pairs //first check for new overlapping pairs
int i,j; int i,j;
for (i=0;i<m_numProxies;i++) if (m_firstAllocatedHandle >= 0)
{ {
btBroadphaseProxy* proxy0 = m_pProxies[i];
for (j=i+1;j<m_numProxies;j++)
{
btBroadphaseProxy* proxy1 = m_pProxies[j];
btSimpleBroadphaseProxy* p0 = getSimpleProxyFromProxy(proxy0);
btSimpleBroadphaseProxy* p1 = getSimpleProxyFromProxy(proxy1);
if (aabbOverlap(p0,p1)) btSimpleBroadphaseProxy* proxy0 = &m_pHandles[m_firstAllocatedHandle];
for (i=0;i<m_numHandles;i++)
{
btSimpleBroadphaseProxy* proxy1 = &m_pHandles[m_firstAllocatedHandle];
for (j=0;j<m_numHandles;j++)
{ {
if ( !findPair(proxy0,proxy1))
if (proxy0 != proxy1)
{ {
addOverlappingPair(proxy0,proxy1); btSimpleBroadphaseProxy* p0 = getSimpleProxyFromProxy(proxy0);
btSimpleBroadphaseProxy* p1 = getSimpleProxyFromProxy(proxy1);
if (aabbOverlap(p0,p1))
{
if ( !m_pairCache->findPair(proxy0,proxy1))
{
m_pairCache->addOverlappingPair(proxy0,proxy1);
}
} else
{
if (!m_pairCache->hasDeferredRemoval())
{
if ( m_pairCache->findPair(proxy0,proxy1))
{
m_pairCache->removeOverlappingPair(proxy0,proxy1,dispatcher);
}
}
}
} }
proxy1 = &m_pHandles[proxy1->GetNextAllocated()];
} }
proxy0 = &m_pHandles[proxy0->GetNextAllocated()];
}
if (m_ownsPairCache && m_pairCache->hasDeferredRemoval())
{
btBroadphasePairArray& overlappingPairArray = m_pairCache->getOverlappingPairArray();
//perform a sort, to find duplicates and to sort 'invalid' pairs to the end
overlappingPairArray.quickSort(btBroadphasePairSortPredicate());
overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair);
m_invalidPair = 0;
btBroadphasePair previousPair;
previousPair.m_pProxy0 = 0;
previousPair.m_pProxy1 = 0;
previousPair.m_algorithm = 0;
for (i=0;i<overlappingPairArray.size();i++)
{
btBroadphasePair& pair = overlappingPairArray[i];
bool isDuplicate = (pair == previousPair);
previousPair = pair;
bool needsRemoval = false;
if (!isDuplicate)
{
bool hasOverlap = testAabbOverlap(pair.m_pProxy0,pair.m_pProxy1);
if (hasOverlap)
{
needsRemoval = false;//callback->processOverlap(pair);
} else
{
needsRemoval = true;
}
} else
{
//remove duplicate
needsRemoval = true;
//should have no algorithm
btAssert(!pair.m_algorithm);
}
if (needsRemoval)
{
m_pairCache->cleanOverlappingPair(pair,dispatcher);
// m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1);
// m_overlappingPairArray.pop_back();
pair.m_pProxy0 = 0;
pair.m_pProxy1 = 0;
m_invalidPair++;
gOverlappingPairs--;
}
}
///if you don't like to skip the invalid pairs in the array, execute following code:
#define CLEAN_INVALID_PAIRS 1
#ifdef CLEAN_INVALID_PAIRS
//perform a sort, to sort 'invalid' pairs to the end
overlappingPairArray.quickSort(btBroadphasePairSortPredicate());
overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair);
m_invalidPair = 0;
#endif//CLEAN_INVALID_PAIRS
} }
} }
CheckOverlapCallback checkOverlap;
processAllOverlappingPairs(&checkOverlap);
} }
bool btSimpleBroadphase::testAabbOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1)
{
btSimpleBroadphaseProxy* p0 = getSimpleProxyFromProxy(proxy0);
btSimpleBroadphaseProxy* p1 = getSimpleProxyFromProxy(proxy1);
return aabbOverlap(p0,p1);
}

View File

@@ -24,35 +24,78 @@ struct btSimpleBroadphaseProxy : public btBroadphaseProxy
{ {
btVector3 m_min; btVector3 m_min;
btVector3 m_max; btVector3 m_max;
int m_nextFree;
int m_nextAllocated;
// int m_handleId;
btSimpleBroadphaseProxy() {}; btSimpleBroadphaseProxy() {};
btSimpleBroadphaseProxy(const btPoint3& minpt,const btPoint3& maxpt,int shapeType,void* userPtr,short int collisionFilterGroup,short int collisionFilterMask) btSimpleBroadphaseProxy(const btPoint3& minpt,const btPoint3& maxpt,int shapeType,void* userPtr,short int collisionFilterGroup,short int collisionFilterMask,void* multiSapProxy)
:btBroadphaseProxy(userPtr,collisionFilterGroup,collisionFilterMask), :btBroadphaseProxy(userPtr,collisionFilterGroup,collisionFilterMask,multiSapProxy),
m_min(minpt),m_max(maxpt) m_min(minpt),m_max(maxpt)
{ {
(void)shapeType; (void)shapeType;
} }
SIMD_FORCE_INLINE void SetNextFree(int next) {m_nextFree = next;}
SIMD_FORCE_INLINE int GetNextFree() const {return m_nextFree;}
SIMD_FORCE_INLINE void SetNextAllocated(int next) {m_nextAllocated = next;}
SIMD_FORCE_INLINE int GetNextAllocated() const {return m_nextAllocated;}
}; };
///SimpleBroadphase is a brute force aabb culling broadphase based on O(n^2) aabb checks ///The SimpleBroadphase is just a unit-test for btAxisSweep3, bt32BitAxisSweep3, or btDbvtBroadphase, so use those classes instead.
class btSimpleBroadphase : public btOverlappingPairCache ///It is a brute force aabb culling broadphase based on O(n^2) aabb checks
class btSimpleBroadphase : public btBroadphaseInterface
{ {
protected: protected:
btSimpleBroadphaseProxy* m_proxies; int m_numHandles; // number of active handles
int* m_freeProxies; int m_maxHandles; // max number of handles
int m_firstFreeProxy; btSimpleBroadphaseProxy* m_pHandles; // handles pool
void* m_pHandlesRawPtr;
int m_firstFreeHandle; // free handles list
int m_firstAllocatedHandle;
btSimpleBroadphaseProxy** m_pProxies; int allocHandle()
int m_numProxies; {
int freeHandle = m_firstFreeHandle;
m_firstFreeHandle = m_pHandles[freeHandle].GetNextFree();
m_pHandles[freeHandle].SetNextAllocated(m_firstAllocatedHandle);
m_firstAllocatedHandle = freeHandle;
m_numHandles++;
return freeHandle;
}
void freeHandle(btSimpleBroadphaseProxy* proxy)
{
int handle = int(proxy-m_pHandles);
btAssert(handle >= 0 && handle < m_maxHandles);
proxy->SetNextFree(m_firstFreeHandle);
m_firstFreeHandle = handle;
m_firstAllocatedHandle = proxy->GetNextAllocated();
proxy->SetNextAllocated(-1);
m_numHandles--;
}
btOverlappingPairCache* m_pairCache;
bool m_ownsPairCache;
int m_invalidPair;
int m_maxProxies;
inline btSimpleBroadphaseProxy* getSimpleProxyFromProxy(btBroadphaseProxy* proxy) inline btSimpleBroadphaseProxy* getSimpleProxyFromProxy(btBroadphaseProxy* proxy)
@@ -67,26 +110,48 @@ protected:
protected: protected:
virtual void refreshOverlappingPairs();
public: public:
btSimpleBroadphase(int maxProxies=16384); btSimpleBroadphase(int maxProxies=16384,btOverlappingPairCache* overlappingPairCache=0);
virtual ~btSimpleBroadphase(); virtual ~btSimpleBroadphase();
static bool aabbOverlap(btSimpleBroadphaseProxy* proxy0,btSimpleBroadphaseProxy* proxy1); static bool aabbOverlap(btSimpleBroadphaseProxy* proxy0,btSimpleBroadphaseProxy* proxy1);
virtual btBroadphaseProxy* createProxy( const btVector3& min, const btVector3& max,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask); virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy);
virtual void calculateOverlappingPairs(btDispatcher* dispatcher);
virtual void destroyProxy(btBroadphaseProxy* proxy); virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher);
virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax); virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher);
btOverlappingPairCache* getOverlappingPairCache()
{
return m_pairCache;
}
const btOverlappingPairCache* getOverlappingPairCache() const
{
return m_pairCache;
}
bool testAabbOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1);
///getAabb returns the axis aligned bounding box in the 'global' coordinate frame
///will add some transform later
virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const
{
aabbMin.setValue(-1e30f,-1e30f,-1e30f);
aabbMax.setValue(1e30f,1e30f,1e30f);
}
virtual void printStats()
{
// printf("btSimpleBroadphase.h\n");
// printf("numHandles = %d, maxHandles = %d\n",m_numHandles,m_maxHandles);
}
}; };

View File

@@ -26,7 +26,7 @@ m_triangle(triangle)
} }
void SphereTriangleDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw) void SphereTriangleDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults)
{ {
(void)debugDraw; (void)debugDraw;
@@ -42,7 +42,16 @@ void SphereTriangleDetector::getClosestPoints(const ClosestPointInput& input,Res
if (collide(sphereInTr.getOrigin(),point,normal,depth,timeOfImpact)) if (collide(sphereInTr.getOrigin(),point,normal,depth,timeOfImpact))
{ {
output.addContactPoint(transformB.getBasis()*normal,transformB*point,depth); if (swapResults)
{
btVector3 normalOnB = transformB.getBasis()*normal;
btVector3 normalOnA = -normalOnB;
btVector3 pointOnA = transformB*point+normalOnB*depth;
output.addContactPoint(normalOnA,pointOnA,depth);
} else
{
output.addContactPoint(transformB.getBasis()*normal,transformB*point,depth);
}
} }
} }
@@ -53,6 +62,8 @@ void SphereTriangleDetector::getClosestPoints(const ClosestPointInput& input,Res
// See also geometrictools.com // See also geometrictools.com
// Basic idea: D = |p - (lo + t0*lv)| where t0 = lv . (p - lo) / lv . lv // Basic idea: D = |p - (lo + t0*lv)| where t0 = lv . (p - lo) / lv . lv
btScalar SegmentSqrDistance(const btVector3& from, const btVector3& to,const btVector3 &p, btVector3 &nearest);
btScalar SegmentSqrDistance(const btVector3& from, const btVector3& to,const btVector3 &p, btVector3 &nearest) { btScalar SegmentSqrDistance(const btVector3& from, const btVector3& to,const btVector3 &p, btVector3 &nearest) {
btVector3 diff = p - from; btVector3 diff = p - from;
btVector3 v = to - from; btVector3 v = to - from;

View File

@@ -16,8 +16,8 @@ subject to the following restrictions:
#ifndef SPHERE_TRIANGLE_DETECTOR_H #ifndef SPHERE_TRIANGLE_DETECTOR_H
#define SPHERE_TRIANGLE_DETECTOR_H #define SPHERE_TRIANGLE_DETECTOR_H
#include "../NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" #include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h"
#include "../../LinearMath/btPoint3.h" #include "LinearMath/btPoint3.h"
class btSphereShape; class btSphereShape;
@@ -28,7 +28,7 @@ class btTriangleShape;
/// sphere-triangle to match the btDiscreteCollisionDetectorInterface /// sphere-triangle to match the btDiscreteCollisionDetectorInterface
struct SphereTriangleDetector : public btDiscreteCollisionDetectorInterface struct SphereTriangleDetector : public btDiscreteCollisionDetectorInterface
{ {
virtual void getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw); virtual void getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults=false);
SphereTriangleDetector(btSphereShape* sphere,btTriangleShape* triangle); SphereTriangleDetector(btSphereShape* sphere,btTriangleShape* triangle);

View File

@@ -0,0 +1,85 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "btBoxBoxCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
#include "BulletCollision/CollisionShapes/btBoxShape.h"
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
#include "btBoxBoxDetector.h"
#define USE_PERSISTENT_CONTACTS 1
btBoxBoxCollisionAlgorithm::btBoxBoxCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* obj0,btCollisionObject* obj1)
: btCollisionAlgorithm(ci),
m_ownManifold(false),
m_manifoldPtr(mf)
{
if (!m_manifoldPtr && m_dispatcher->needsCollision(obj0,obj1))
{
m_manifoldPtr = m_dispatcher->getNewManifold(obj0,obj1);
m_ownManifold = true;
}
}
btBoxBoxCollisionAlgorithm::~btBoxBoxCollisionAlgorithm()
{
if (m_ownManifold)
{
if (m_manifoldPtr)
m_dispatcher->releaseManifold(m_manifoldPtr);
}
}
void btBoxBoxCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)
{
if (!m_manifoldPtr)
return;
btCollisionObject* col0 = body0;
btCollisionObject* col1 = body1;
btBoxShape* box0 = (btBoxShape*)col0->getCollisionShape();
btBoxShape* box1 = (btBoxShape*)col1->getCollisionShape();
/// report a contact. internally this will be kept persistent, and contact reduction is done
resultOut->setPersistentManifold(m_manifoldPtr);
#ifndef USE_PERSISTENT_CONTACTS
m_manifoldPtr->clearManifold();
#endif //USE_PERSISTENT_CONTACTS
btDiscreteCollisionDetectorInterface::ClosestPointInput input;
input.m_maximumDistanceSquared = 1e30f;
input.m_transformA = body0->getWorldTransform();
input.m_transformB = body1->getWorldTransform();
btBoxBoxDetector detector(box0,box1);
detector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw);
#ifdef USE_PERSISTENT_CONTACTS
// refreshContactPoints is only necessary when using persistent contact points. otherwise all points are newly added
if (m_ownManifold)
{
resultOut->refreshContactPoints();
}
#endif //USE_PERSISTENT_CONTACTS
}
btScalar btBoxBoxCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* /*body0*/,btCollisionObject* /*body1*/,const btDispatcherInfo& /*dispatchInfo*/,btManifoldResult* /*resultOut*/)
{
//not yet
return 1.f;
}

View File

@@ -0,0 +1,66 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BOX_BOX__COLLISION_ALGORITHM_H
#define BOX_BOX__COLLISION_ALGORITHM_H
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
#include "BulletCollision/BroadphaseCollision/btDispatcher.h"
#include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h"
class btPersistentManifold;
///box-box collision detection
class btBoxBoxCollisionAlgorithm : public btCollisionAlgorithm
{
bool m_ownManifold;
btPersistentManifold* m_manifoldPtr;
public:
btBoxBoxCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci)
: btCollisionAlgorithm(ci) {}
virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut);
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut);
btBoxBoxCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1);
virtual ~btBoxBoxCollisionAlgorithm();
virtual void getAllContactManifolds(btManifoldArray& manifoldArray)
{
if (m_manifoldPtr && m_ownManifold)
{
manifoldArray.push_back(m_manifoldPtr);
}
}
struct CreateFunc :public btCollisionAlgorithmCreateFunc
{
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1)
{
int bbsize = sizeof(btBoxBoxCollisionAlgorithm);
void* ptr = ci.m_dispatcher1->allocateCollisionAlgorithm(bbsize);
return new(ptr) btBoxBoxCollisionAlgorithm(0,ci,body0,body1);
}
};
};
#endif //BOX_BOX__COLLISION_ALGORITHM_H

View File

@@ -0,0 +1,683 @@
/*
* Box-Box collision detection re-distributed under the ZLib license with permission from Russell L. Smith
* Original version is from Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith.
* All rights reserved. Email: russ@q12.org Web: www.q12.org
Bullet Continuous Collision Detection and Physics Library
Bullet is Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///ODE box-box collision detection is adapted to work with Bullet
#include "btBoxBoxDetector.h"
#include "BulletCollision/CollisionShapes/btBoxShape.h"
#include <float.h>
#include <string.h>
btBoxBoxDetector::btBoxBoxDetector(btBoxShape* box1,btBoxShape* box2)
: m_box1(box1),
m_box2(box2)
{
}
// given two boxes (p1,R1,side1) and (p2,R2,side2), collide them together and
// generate contact points. this returns 0 if there is no contact otherwise
// it returns the number of contacts generated.
// `normal' returns the contact normal.
// `depth' returns the maximum penetration depth along that normal.
// `return_code' returns a number indicating the type of contact that was
// detected:
// 1,2,3 = box 2 intersects with a face of box 1
// 4,5,6 = box 1 intersects with a face of box 2
// 7..15 = edge-edge contact
// `maxc' is the maximum number of contacts allowed to be generated, i.e.
// the size of the `contact' array.
// `contact' and `skip' are the contact array information provided to the
// collision functions. this function only fills in the position and depth
// fields.
struct dContactGeom;
#define dDOTpq(a,b,p,q) ((a)[0]*(b)[0] + (a)[p]*(b)[q] + (a)[2*(p)]*(b)[2*(q)])
#define dInfinity FLT_MAX
/*PURE_INLINE btScalar dDOT (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,1); }
PURE_INLINE btScalar dDOT13 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,3); }
PURE_INLINE btScalar dDOT31 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,3,1); }
PURE_INLINE btScalar dDOT33 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,3,3); }
*/
static btScalar dDOT (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,1); }
static btScalar dDOT44 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,4,4); }
static btScalar dDOT41 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,4,1); }
static btScalar dDOT14 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,4); }
#define dMULTIPLYOP1_331(A,op,B,C) \
{\
(A)[0] op dDOT41((B),(C)); \
(A)[1] op dDOT41((B+1),(C)); \
(A)[2] op dDOT41((B+2),(C)); \
}
#define dMULTIPLYOP0_331(A,op,B,C) \
{ \
(A)[0] op dDOT((B),(C)); \
(A)[1] op dDOT((B+4),(C)); \
(A)[2] op dDOT((B+8),(C)); \
}
#define dMULTIPLY1_331(A,B,C) dMULTIPLYOP1_331(A,=,B,C)
#define dMULTIPLY0_331(A,B,C) dMULTIPLYOP0_331(A,=,B,C)
typedef btScalar dMatrix3[4*3];
void dLineClosestApproach (const btVector3& pa, const btVector3& ua,
const btVector3& pb, const btVector3& ub,
btScalar *alpha, btScalar *beta);
void dLineClosestApproach (const btVector3& pa, const btVector3& ua,
const btVector3& pb, const btVector3& ub,
btScalar *alpha, btScalar *beta)
{
btVector3 p;
p[0] = pb[0] - pa[0];
p[1] = pb[1] - pa[1];
p[2] = pb[2] - pa[2];
btScalar uaub = dDOT(ua,ub);
btScalar q1 = dDOT(ua,p);
btScalar q2 = -dDOT(ub,p);
btScalar d = 1-uaub*uaub;
if (d <= btScalar(0.0001f)) {
// @@@ this needs to be made more robust
*alpha = 0;
*beta = 0;
}
else {
d = 1.f/d;
*alpha = (q1 + uaub*q2)*d;
*beta = (uaub*q1 + q2)*d;
}
}
// find all the intersection points between the 2D rectangle with vertices
// at (+/-h[0],+/-h[1]) and the 2D quadrilateral with vertices (p[0],p[1]),
// (p[2],p[3]),(p[4],p[5]),(p[6],p[7]).
//
// the intersection points are returned as x,y pairs in the 'ret' array.
// the number of intersection points is returned by the function (this will
// be in the range 0 to 8).
static int intersectRectQuad2 (btScalar h[2], btScalar p[8], btScalar ret[16])
{
// q (and r) contain nq (and nr) coordinate points for the current (and
// chopped) polygons
int nq=4,nr=0;
btScalar buffer[16];
btScalar *q = p;
btScalar *r = ret;
for (int dir=0; dir <= 1; dir++) {
// direction notation: xy[0] = x axis, xy[1] = y axis
for (int sign=-1; sign <= 1; sign += 2) {
// chop q along the line xy[dir] = sign*h[dir]
btScalar *pq = q;
btScalar *pr = r;
nr = 0;
for (int i=nq; i > 0; i--) {
// go through all points in q and all lines between adjacent points
if (sign*pq[dir] < h[dir]) {
// this point is inside the chopping line
pr[0] = pq[0];
pr[1] = pq[1];
pr += 2;
nr++;
if (nr & 8) {
q = r;
goto done;
}
}
btScalar *nextq = (i > 1) ? pq+2 : q;
if ((sign*pq[dir] < h[dir]) ^ (sign*nextq[dir] < h[dir])) {
// this line crosses the chopping line
pr[1-dir] = pq[1-dir] + (nextq[1-dir]-pq[1-dir]) /
(nextq[dir]-pq[dir]) * (sign*h[dir]-pq[dir]);
pr[dir] = sign*h[dir];
pr += 2;
nr++;
if (nr & 8) {
q = r;
goto done;
}
}
pq += 2;
}
q = r;
r = (q==ret) ? buffer : ret;
nq = nr;
}
}
done:
if (q != ret) memcpy (ret,q,nr*2*sizeof(btScalar));
return nr;
}
#define M__PI 3.14159265f
// given n points in the plane (array p, of size 2*n), generate m points that
// best represent the whole set. the definition of 'best' here is not
// predetermined - the idea is to select points that give good box-box
// collision detection behavior. the chosen point indexes are returned in the
// array iret (of size m). 'i0' is always the first entry in the array.
// n must be in the range [1..8]. m must be in the range [1..n]. i0 must be
// in the range [0..n-1].
void cullPoints2 (int n, btScalar p[], int m, int i0, int iret[]);
void cullPoints2 (int n, btScalar p[], int m, int i0, int iret[])
{
// compute the centroid of the polygon in cx,cy
int i,j;
btScalar a,cx,cy,q;
if (n==1) {
cx = p[0];
cy = p[1];
}
else if (n==2) {
cx = btScalar(0.5)*(p[0] + p[2]);
cy = btScalar(0.5)*(p[1] + p[3]);
}
else {
a = 0;
cx = 0;
cy = 0;
for (i=0; i<(n-1); i++) {
q = p[i*2]*p[i*2+3] - p[i*2+2]*p[i*2+1];
a += q;
cx += q*(p[i*2]+p[i*2+2]);
cy += q*(p[i*2+1]+p[i*2+3]);
}
q = p[n*2-2]*p[1] - p[0]*p[n*2-1];
a = 1.f/(btScalar(3.0)*(a+q));
cx = a*(cx + q*(p[n*2-2]+p[0]));
cy = a*(cy + q*(p[n*2-1]+p[1]));
}
// compute the angle of each point w.r.t. the centroid
btScalar A[8];
for (i=0; i<n; i++) A[i] = btAtan2(p[i*2+1]-cy,p[i*2]-cx);
// search for points that have angles closest to A[i0] + i*(2*pi/m).
int avail[8];
for (i=0; i<n; i++) avail[i] = 1;
avail[i0] = 0;
iret[0] = i0;
iret++;
for (j=1; j<m; j++) {
a = btScalar(j)*(2*M__PI/m) + A[i0];
if (a > M__PI) a -= 2*M__PI;
btScalar maxdiff=1e9,diff;
#ifndef dNODEBUG
*iret = i0; // iret is not allowed to keep this value
#endif
for (i=0; i<n; i++) {
if (avail[i]) {
diff = btFabs (A[i]-a);
if (diff > M__PI) diff = 2*M__PI - diff;
if (diff < maxdiff) {
maxdiff = diff;
*iret = i;
}
}
}
#ifndef dNODEBUG
btAssert (*iret != i0); // ensure iret got set
#endif
avail[*iret] = 0;
iret++;
}
}
int dBoxBox2 (const btVector3& p1, const dMatrix3 R1,
const btVector3& side1, const btVector3& p2,
const dMatrix3 R2, const btVector3& side2,
btVector3& normal, btScalar *depth, int *return_code,
int maxc, dContactGeom * /*contact*/, int /*skip*/,btDiscreteCollisionDetectorInterface::Result& output);
int dBoxBox2 (const btVector3& p1, const dMatrix3 R1,
const btVector3& side1, const btVector3& p2,
const dMatrix3 R2, const btVector3& side2,
btVector3& normal, btScalar *depth, int *return_code,
int maxc, dContactGeom * /*contact*/, int /*skip*/,btDiscreteCollisionDetectorInterface::Result& output)
{
const btScalar fudge_factor = btScalar(1.05);
btVector3 p,pp,normalC;
const btScalar *normalR = 0;
btScalar A[3],B[3],R11,R12,R13,R21,R22,R23,R31,R32,R33,
Q11,Q12,Q13,Q21,Q22,Q23,Q31,Q32,Q33,s,s2,l;
int i,j,invert_normal,code;
// get vector from centers of box 1 to box 2, relative to box 1
p = p2 - p1;
dMULTIPLY1_331 (pp,R1,p); // get pp = p relative to body 1
// get side lengths / 2
A[0] = side1[0]*btScalar(0.5);
A[1] = side1[1]*btScalar(0.5);
A[2] = side1[2]*btScalar(0.5);
B[0] = side2[0]*btScalar(0.5);
B[1] = side2[1]*btScalar(0.5);
B[2] = side2[2]*btScalar(0.5);
// Rij is R1'*R2, i.e. the relative rotation between R1 and R2
R11 = dDOT44(R1+0,R2+0); R12 = dDOT44(R1+0,R2+1); R13 = dDOT44(R1+0,R2+2);
R21 = dDOT44(R1+1,R2+0); R22 = dDOT44(R1+1,R2+1); R23 = dDOT44(R1+1,R2+2);
R31 = dDOT44(R1+2,R2+0); R32 = dDOT44(R1+2,R2+1); R33 = dDOT44(R1+2,R2+2);
Q11 = btFabs(R11); Q12 = btFabs(R12); Q13 = btFabs(R13);
Q21 = btFabs(R21); Q22 = btFabs(R22); Q23 = btFabs(R23);
Q31 = btFabs(R31); Q32 = btFabs(R32); Q33 = btFabs(R33);
// for all 15 possible separating axes:
// * see if the axis separates the boxes. if so, return 0.
// * find the depth of the penetration along the separating axis (s2)
// * if this is the largest depth so far, record it.
// the normal vector will be set to the separating axis with the smallest
// depth. note: normalR is set to point to a column of R1 or R2 if that is
// the smallest depth normal so far. otherwise normalR is 0 and normalC is
// set to a vector relative to body 1. invert_normal is 1 if the sign of
// the normal should be flipped.
#define TST(expr1,expr2,norm,cc) \
s2 = btFabs(expr1) - (expr2); \
if (s2 > 0) return 0; \
if (s2 > s) { \
s = s2; \
normalR = norm; \
invert_normal = ((expr1) < 0); \
code = (cc); \
}
s = -dInfinity;
invert_normal = 0;
code = 0;
// separating axis = u1,u2,u3
TST (pp[0],(A[0] + B[0]*Q11 + B[1]*Q12 + B[2]*Q13),R1+0,1);
TST (pp[1],(A[1] + B[0]*Q21 + B[1]*Q22 + B[2]*Q23),R1+1,2);
TST (pp[2],(A[2] + B[0]*Q31 + B[1]*Q32 + B[2]*Q33),R1+2,3);
// separating axis = v1,v2,v3
TST (dDOT41(R2+0,p),(A[0]*Q11 + A[1]*Q21 + A[2]*Q31 + B[0]),R2+0,4);
TST (dDOT41(R2+1,p),(A[0]*Q12 + A[1]*Q22 + A[2]*Q32 + B[1]),R2+1,5);
TST (dDOT41(R2+2,p),(A[0]*Q13 + A[1]*Q23 + A[2]*Q33 + B[2]),R2+2,6);
// note: cross product axes need to be scaled when s is computed.
// normal (n1,n2,n3) is relative to box 1.
#undef TST
#define TST(expr1,expr2,n1,n2,n3,cc) \
s2 = btFabs(expr1) - (expr2); \
if (s2 > 0) return 0; \
l = btSqrt((n1)*(n1) + (n2)*(n2) + (n3)*(n3)); \
if (l > 0) { \
s2 /= l; \
if (s2*fudge_factor > s) { \
s = s2; \
normalR = 0; \
normalC[0] = (n1)/l; normalC[1] = (n2)/l; normalC[2] = (n3)/l; \
invert_normal = ((expr1) < 0); \
code = (cc); \
} \
}
// separating axis = u1 x (v1,v2,v3)
TST(pp[2]*R21-pp[1]*R31,(A[1]*Q31+A[2]*Q21+B[1]*Q13+B[2]*Q12),0,-R31,R21,7);
TST(pp[2]*R22-pp[1]*R32,(A[1]*Q32+A[2]*Q22+B[0]*Q13+B[2]*Q11),0,-R32,R22,8);
TST(pp[2]*R23-pp[1]*R33,(A[1]*Q33+A[2]*Q23+B[0]*Q12+B[1]*Q11),0,-R33,R23,9);
// separating axis = u2 x (v1,v2,v3)
TST(pp[0]*R31-pp[2]*R11,(A[0]*Q31+A[2]*Q11+B[1]*Q23+B[2]*Q22),R31,0,-R11,10);
TST(pp[0]*R32-pp[2]*R12,(A[0]*Q32+A[2]*Q12+B[0]*Q23+B[2]*Q21),R32,0,-R12,11);
TST(pp[0]*R33-pp[2]*R13,(A[0]*Q33+A[2]*Q13+B[0]*Q22+B[1]*Q21),R33,0,-R13,12);
// separating axis = u3 x (v1,v2,v3)
TST(pp[1]*R11-pp[0]*R21,(A[0]*Q21+A[1]*Q11+B[1]*Q33+B[2]*Q32),-R21,R11,0,13);
TST(pp[1]*R12-pp[0]*R22,(A[0]*Q22+A[1]*Q12+B[0]*Q33+B[2]*Q31),-R22,R12,0,14);
TST(pp[1]*R13-pp[0]*R23,(A[0]*Q23+A[1]*Q13+B[0]*Q32+B[1]*Q31),-R23,R13,0,15);
#undef TST
if (!code) return 0;
// if we get to this point, the boxes interpenetrate. compute the normal
// in global coordinates.
if (normalR) {
normal[0] = normalR[0];
normal[1] = normalR[4];
normal[2] = normalR[8];
}
else {
dMULTIPLY0_331 (normal,R1,normalC);
}
if (invert_normal) {
normal[0] = -normal[0];
normal[1] = -normal[1];
normal[2] = -normal[2];
}
*depth = -s;
// compute contact point(s)
if (code > 6) {
// an edge from box 1 touches an edge from box 2.
// find a point pa on the intersecting edge of box 1
btVector3 pa;
btScalar sign;
for (i=0; i<3; i++) pa[i] = p1[i];
for (j=0; j<3; j++) {
sign = (dDOT14(normal,R1+j) > 0) ? btScalar(1.0) : btScalar(-1.0);
for (i=0; i<3; i++) pa[i] += sign * A[j] * R1[i*4+j];
}
// find a point pb on the intersecting edge of box 2
btVector3 pb;
for (i=0; i<3; i++) pb[i] = p2[i];
for (j=0; j<3; j++) {
sign = (dDOT14(normal,R2+j) > 0) ? btScalar(-1.0) : btScalar(1.0);
for (i=0; i<3; i++) pb[i] += sign * B[j] * R2[i*4+j];
}
btScalar alpha,beta;
btVector3 ua,ub;
for (i=0; i<3; i++) ua[i] = R1[((code)-7)/3 + i*4];
for (i=0; i<3; i++) ub[i] = R2[((code)-7)%3 + i*4];
dLineClosestApproach (pa,ua,pb,ub,&alpha,&beta);
for (i=0; i<3; i++) pa[i] += ua[i]*alpha;
for (i=0; i<3; i++) pb[i] += ub[i]*beta;
{
//contact[0].pos[i] = btScalar(0.5)*(pa[i]+pb[i]);
//contact[0].depth = *depth;
btVector3 pointInWorld;
#ifdef USE_CENTER_POINT
for (i=0; i<3; i++)
pointInWorld[i] = (pa[i]+pb[i])*btScalar(0.5);
output.addContactPoint(-normal,pointInWorld,-*depth);
#else
output.addContactPoint(-normal,pb,-*depth);
#endif //
*return_code = code;
}
return 1;
}
// okay, we have a face-something intersection (because the separating
// axis is perpendicular to a face). define face 'a' to be the reference
// face (i.e. the normal vector is perpendicular to this) and face 'b' to be
// the incident face (the closest face of the other box).
const btScalar *Ra,*Rb,*pa,*pb,*Sa,*Sb;
if (code <= 3) {
Ra = R1;
Rb = R2;
pa = p1;
pb = p2;
Sa = A;
Sb = B;
}
else {
Ra = R2;
Rb = R1;
pa = p2;
pb = p1;
Sa = B;
Sb = A;
}
// nr = normal vector of reference face dotted with axes of incident box.
// anr = absolute values of nr.
btVector3 normal2,nr,anr;
if (code <= 3) {
normal2[0] = normal[0];
normal2[1] = normal[1];
normal2[2] = normal[2];
}
else {
normal2[0] = -normal[0];
normal2[1] = -normal[1];
normal2[2] = -normal[2];
}
dMULTIPLY1_331 (nr,Rb,normal2);
anr[0] = btFabs (nr[0]);
anr[1] = btFabs (nr[1]);
anr[2] = btFabs (nr[2]);
// find the largest compontent of anr: this corresponds to the normal
// for the indident face. the other axis numbers of the indicent face
// are stored in a1,a2.
int lanr,a1,a2;
if (anr[1] > anr[0]) {
if (anr[1] > anr[2]) {
a1 = 0;
lanr = 1;
a2 = 2;
}
else {
a1 = 0;
a2 = 1;
lanr = 2;
}
}
else {
if (anr[0] > anr[2]) {
lanr = 0;
a1 = 1;
a2 = 2;
}
else {
a1 = 0;
a2 = 1;
lanr = 2;
}
}
// compute center point of incident face, in reference-face coordinates
btVector3 center;
if (nr[lanr] < 0) {
for (i=0; i<3; i++) center[i] = pb[i] - pa[i] + Sb[lanr] * Rb[i*4+lanr];
}
else {
for (i=0; i<3; i++) center[i] = pb[i] - pa[i] - Sb[lanr] * Rb[i*4+lanr];
}
// find the normal and non-normal axis numbers of the reference box
int codeN,code1,code2;
if (code <= 3) codeN = code-1; else codeN = code-4;
if (codeN==0) {
code1 = 1;
code2 = 2;
}
else if (codeN==1) {
code1 = 0;
code2 = 2;
}
else {
code1 = 0;
code2 = 1;
}
// find the four corners of the incident face, in reference-face coordinates
btScalar quad[8]; // 2D coordinate of incident face (x,y pairs)
btScalar c1,c2,m11,m12,m21,m22;
c1 = dDOT14 (center,Ra+code1);
c2 = dDOT14 (center,Ra+code2);
// optimize this? - we have already computed this data above, but it is not
// stored in an easy-to-index format. for now it's quicker just to recompute
// the four dot products.
m11 = dDOT44 (Ra+code1,Rb+a1);
m12 = dDOT44 (Ra+code1,Rb+a2);
m21 = dDOT44 (Ra+code2,Rb+a1);
m22 = dDOT44 (Ra+code2,Rb+a2);
{
btScalar k1 = m11*Sb[a1];
btScalar k2 = m21*Sb[a1];
btScalar k3 = m12*Sb[a2];
btScalar k4 = m22*Sb[a2];
quad[0] = c1 - k1 - k3;
quad[1] = c2 - k2 - k4;
quad[2] = c1 - k1 + k3;
quad[3] = c2 - k2 + k4;
quad[4] = c1 + k1 + k3;
quad[5] = c2 + k2 + k4;
quad[6] = c1 + k1 - k3;
quad[7] = c2 + k2 - k4;
}
// find the size of the reference face
btScalar rect[2];
rect[0] = Sa[code1];
rect[1] = Sa[code2];
// intersect the incident and reference faces
btScalar ret[16];
int n = intersectRectQuad2 (rect,quad,ret);
if (n < 1) return 0; // this should never happen
// convert the intersection points into reference-face coordinates,
// and compute the contact position and depth for each point. only keep
// those points that have a positive (penetrating) depth. delete points in
// the 'ret' array as necessary so that 'point' and 'ret' correspond.
btScalar point[3*8]; // penetrating contact points
btScalar dep[8]; // depths for those points
btScalar det1 = 1.f/(m11*m22 - m12*m21);
m11 *= det1;
m12 *= det1;
m21 *= det1;
m22 *= det1;
int cnum = 0; // number of penetrating contact points found
for (j=0; j < n; j++) {
btScalar k1 = m22*(ret[j*2]-c1) - m12*(ret[j*2+1]-c2);
btScalar k2 = -m21*(ret[j*2]-c1) + m11*(ret[j*2+1]-c2);
for (i=0; i<3; i++) point[cnum*3+i] =
center[i] + k1*Rb[i*4+a1] + k2*Rb[i*4+a2];
dep[cnum] = Sa[codeN] - dDOT(normal2,point+cnum*3);
if (dep[cnum] >= 0) {
ret[cnum*2] = ret[j*2];
ret[cnum*2+1] = ret[j*2+1];
cnum++;
}
}
if (cnum < 1) return 0; // this should never happen
// we can't generate more contacts than we actually have
if (maxc > cnum) maxc = cnum;
if (maxc < 1) maxc = 1;
if (cnum <= maxc) {
// we have less contacts than we need, so we use them all
for (j=0; j < cnum; j++) {
//AddContactPoint...
//dContactGeom *con = CONTACT(contact,skip*j);
//for (i=0; i<3; i++) con->pos[i] = point[j*3+i] + pa[i];
//con->depth = dep[j];
btVector3 pointInWorld;
for (i=0; i<3; i++)
pointInWorld[i] = point[j*3+i] + pa[i];
output.addContactPoint(-normal,pointInWorld,-dep[j]);
}
}
else {
// we have more contacts than are wanted, some of them must be culled.
// find the deepest point, it is always the first contact.
int i1 = 0;
btScalar maxdepth = dep[0];
for (i=1; i<cnum; i++) {
if (dep[i] > maxdepth) {
maxdepth = dep[i];
i1 = i;
}
}
int iret[8];
cullPoints2 (cnum,ret,maxc,i1,iret);
for (j=0; j < maxc; j++) {
// dContactGeom *con = CONTACT(contact,skip*j);
// for (i=0; i<3; i++) con->pos[i] = point[iret[j]*3+i] + pa[i];
// con->depth = dep[iret[j]];
btVector3 posInWorld;
for (i=0; i<3; i++)
posInWorld[i] = point[iret[j]*3+i] + pa[i];
output.addContactPoint(-normal,posInWorld,-dep[iret[j]]);
}
cnum = maxc;
}
*return_code = code;
return cnum;
}
void btBoxBoxDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* /*debugDraw*/,bool /*swapResults*/)
{
const btTransform& transformA = input.m_transformA;
const btTransform& transformB = input.m_transformB;
int skip = 0;
dContactGeom *contact = 0;
dMatrix3 R1;
dMatrix3 R2;
for (int j=0;j<3;j++)
{
R1[0+4*j] = transformA.getBasis()[j].x();
R2[0+4*j] = transformB.getBasis()[j].x();
R1[1+4*j] = transformA.getBasis()[j].y();
R2[1+4*j] = transformB.getBasis()[j].y();
R1[2+4*j] = transformA.getBasis()[j].z();
R2[2+4*j] = transformB.getBasis()[j].z();
}
btVector3 normal;
btScalar depth;
int return_code;
int maxc = 4;
dBoxBox2 (transformA.getOrigin(),
R1,
2.f*m_box1->getHalfExtentsWithMargin(),
transformB.getOrigin(),
R2,
2.f*m_box2->getHalfExtentsWithMargin(),
normal, &depth, &return_code,
maxc, contact, skip,
output
);
}

View File

@@ -0,0 +1,44 @@
/*
* Box-Box collision detection re-distributed under the ZLib license with permission from Russell L. Smith
* Original version is from Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith.
* All rights reserved. Email: russ@q12.org Web: www.q12.org
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BOX_BOX_DETECTOR_H
#define BOX_BOX_DETECTOR_H
class btBoxShape;
#include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h"
/// btBoxBoxDetector wraps the ODE box-box collision detector
/// re-distributed under the Zlib license with permission from Russell L. Smith
struct btBoxBoxDetector : public btDiscreteCollisionDetectorInterface
{
btBoxShape* m_box1;
btBoxShape* m_box2;
public:
btBoxBoxDetector(btBoxShape* box1,btBoxShape* box2);
virtual ~btBoxBoxDetector() {};
virtual void getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults=false);
};
#endif //BT_BOX_BOX_DETECTOR_H

View File

@@ -0,0 +1,47 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_COLLISION_CONFIGURATION
#define BT_COLLISION_CONFIGURATION
struct btCollisionAlgorithmCreateFunc;
class btStackAlloc;
class btPoolAllocator;
///btCollisionConfiguration allows to configure Bullet collision detection
///stack allocator size, default collision algorithms and persistent manifold pool size
///todo: describe the meaning
class btCollisionConfiguration
{
public:
virtual ~btCollisionConfiguration()
{
}
///memory pools
virtual btPoolAllocator* getPersistentManifoldPool() = 0;
virtual btPoolAllocator* getCollisionAlgorithmPool() = 0;
virtual btStackAlloc* getStackAllocator() = 0;
virtual btCollisionAlgorithmCreateFunc* getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1) =0;
};
#endif //BT_COLLISION_CONFIGURATION

View File

@@ -16,7 +16,7 @@ subject to the following restrictions:
#ifndef COLLISION_CREATE_FUNC #ifndef COLLISION_CREATE_FUNC
#define COLLISION_CREATE_FUNC #define COLLISION_CREATE_FUNC
#include "../../LinearMath/btAlignedObjectArray.h" #include "LinearMath/btAlignedObjectArray.h"
typedef btAlignedObjectArray<class btCollisionObject*> btCollisionObjectArray; typedef btAlignedObjectArray<class btCollisionObject*> btCollisionObjectArray;
class btCollisionAlgorithm; class btCollisionAlgorithm;
class btCollisionObject; class btCollisionObject;

View File

@@ -19,69 +19,39 @@ subject to the following restrictions:
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h"
#include "BulletCollision/CollisionShapes/btCollisionShape.h" #include "BulletCollision/CollisionShapes/btCollisionShape.h"
#include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h"
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
#include "LinearMath/btPoolAllocator.h"
#include "BulletCollision/CollisionDispatch/btCollisionConfiguration.h"
int gNumManifold = 0; int gNumManifold = 0;
#ifdef BT_DEBUG
#include <stdio.h> #include <stdio.h>
#endif
btCollisionDispatcher::btCollisionDispatcher(bool noDefaultAlgorithms):
m_count(0),
m_useIslands(true),
m_convexConvexCreateFunc(0),
m_convexConcaveCreateFunc(0),
m_swappedConvexConcaveCreateFunc(0),
m_compoundCreateFunc(0),
m_swappedCompoundCreateFunc(0),
m_emptyCreateFunc(0)
{
(void)noDefaultAlgorithms;
int i;
setNearCallback(defaultNearCallback); btCollisionDispatcher::btCollisionDispatcher (btCollisionConfiguration* collisionConfiguration):
m_emptyCreateFunc = new btEmptyAlgorithm::CreateFunc;
for (i=0;i<MAX_BROADPHASE_COLLISION_TYPES;i++)
{
for (int j=0;j<MAX_BROADPHASE_COLLISION_TYPES;j++)
{
m_doubleDispatch[i][j] = m_emptyCreateFunc;
}
}
}
//if you want to not link with the default collision algorithms, you can
//define BT_EXCLUDE_DEFAULT_COLLISIONALGORITHM_REGISTRATION
//in your Bullet library build system
#ifndef BT_EXCLUDE_DEFAULT_COLLISIONALGORITHM_REGISTRATION
btCollisionDispatcher::btCollisionDispatcher ():
m_count(0), m_count(0),
m_useIslands(true) m_useIslands(true),
m_staticWarningReported(false),
m_collisionConfiguration(collisionConfiguration)
{ {
int i; int i;
setNearCallback(defaultNearCallback); setNearCallback(defaultNearCallback);
//default CreationFunctions, filling the m_doubleDispatch table m_collisionAlgorithmPoolAllocator = collisionConfiguration->getCollisionAlgorithmPool();
m_convexConvexCreateFunc = new btConvexConvexAlgorithm::CreateFunc;
m_convexConcaveCreateFunc = new btConvexConcaveCollisionAlgorithm::CreateFunc; m_persistentManifoldPoolAllocator = collisionConfiguration->getPersistentManifoldPool();
m_swappedConvexConcaveCreateFunc = new btConvexConcaveCollisionAlgorithm::SwappedCreateFunc;
m_compoundCreateFunc = new btCompoundCollisionAlgorithm::CreateFunc;
m_swappedCompoundCreateFunc = new btCompoundCollisionAlgorithm::SwappedCreateFunc;
m_emptyCreateFunc = new btEmptyAlgorithm::CreateFunc;
for (i=0;i<MAX_BROADPHASE_COLLISION_TYPES;i++) for (i=0;i<MAX_BROADPHASE_COLLISION_TYPES;i++)
{ {
for (int j=0;j<MAX_BROADPHASE_COLLISION_TYPES;j++) for (int j=0;j<MAX_BROADPHASE_COLLISION_TYPES;j++)
{ {
m_doubleDispatch[i][j] = internalFindCreateFunc(i,j); m_doubleDispatch[i][j] = m_collisionConfiguration->getCollisionAlgorithmCreateFunc(i,j);
assert(m_doubleDispatch[i][j]); assert(m_doubleDispatch[i][j]);
} }
} }
@@ -89,8 +59,6 @@ btCollisionDispatcher::btCollisionDispatcher ():
}; };
#endif //BT_EXCLUDE_DEFAULT_COLLISIONALGORITHM_REGISTRATION
void btCollisionDispatcher::registerCollisionCreateFunc(int proxyType0, int proxyType1, btCollisionAlgorithmCreateFunc *createFunc) void btCollisionDispatcher::registerCollisionCreateFunc(int proxyType0, int proxyType1, btCollisionAlgorithmCreateFunc *createFunc)
{ {
@@ -99,12 +67,6 @@ void btCollisionDispatcher::registerCollisionCreateFunc(int proxyType0, int prox
btCollisionDispatcher::~btCollisionDispatcher() btCollisionDispatcher::~btCollisionDispatcher()
{ {
delete m_convexConvexCreateFunc;
delete m_convexConcaveCreateFunc;
delete m_swappedConvexConcaveCreateFunc;
delete m_compoundCreateFunc;
delete m_swappedCompoundCreateFunc;
delete m_emptyCreateFunc;
} }
btPersistentManifold* btCollisionDispatcher::getNewManifold(void* b0,void* b1) btPersistentManifold* btCollisionDispatcher::getNewManifold(void* b0,void* b1)
@@ -117,7 +79,18 @@ btPersistentManifold* btCollisionDispatcher::getNewManifold(void* b0,void* b1)
btCollisionObject* body0 = (btCollisionObject*)b0; btCollisionObject* body0 = (btCollisionObject*)b0;
btCollisionObject* body1 = (btCollisionObject*)b1; btCollisionObject* body1 = (btCollisionObject*)b1;
btPersistentManifold* manifold = new btPersistentManifold (body0,body1); void* mem = 0;
if (m_persistentManifoldPoolAllocator->getFreeCount())
{
mem = m_persistentManifoldPoolAllocator->allocate(sizeof(btPersistentManifold));
} else
{
mem = btAlignedAlloc(sizeof(btPersistentManifold),16);
}
btPersistentManifold* manifold = new(mem) btPersistentManifold (body0,body1,0);
manifold->m_index1a = m_manifoldsPtr.size();
m_manifoldsPtr.push_back(manifold); m_manifoldsPtr.push_back(manifold);
return manifold; return manifold;
@@ -137,13 +110,19 @@ void btCollisionDispatcher::releaseManifold(btPersistentManifold* manifold)
//printf("releaseManifold: gNumManifold %d\n",gNumManifold); //printf("releaseManifold: gNumManifold %d\n",gNumManifold);
clearManifold(manifold); clearManifold(manifold);
///todo: this can be improved a lot, linear search might be slow part! int findIndex = manifold->m_index1a;
int findIndex = m_manifoldsPtr.findLinearSearch(manifold); btAssert(findIndex < m_manifoldsPtr.size());
if (findIndex < m_manifoldsPtr.size()) m_manifoldsPtr.swap(findIndex,m_manifoldsPtr.size()-1);
m_manifoldsPtr[findIndex]->m_index1a = findIndex;
m_manifoldsPtr.pop_back();
manifold->~btPersistentManifold();
if (m_persistentManifoldPoolAllocator->validPtr(manifold))
{ {
m_manifoldsPtr.swap(findIndex,m_manifoldsPtr.size()-1); m_persistentManifoldPoolAllocator->freeMemory(manifold);
m_manifoldsPtr.pop_back(); } else
delete manifold; {
btAlignedFree(manifold);
} }
} }
@@ -152,99 +131,19 @@ void btCollisionDispatcher::releaseManifold(btPersistentManifold* manifold)
btCollisionAlgorithm* btCollisionDispatcher::findAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold) btCollisionAlgorithm* btCollisionDispatcher::findAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold)
{ {
#ifdef USE_DISPATCH_REGISTRY_ARRAY
btCollisionAlgorithmConstructionInfo ci; btCollisionAlgorithmConstructionInfo ci;
ci.m_dispatcher = this;
ci.m_dispatcher1 = this;
ci.m_manifold = sharedManifold; ci.m_manifold = sharedManifold;
btCollisionAlgorithm* algo = m_doubleDispatch[body0->getCollisionShape()->getShapeType()][body1->getCollisionShape()->getShapeType()] btCollisionAlgorithm* algo = m_doubleDispatch[body0->getCollisionShape()->getShapeType()][body1->getCollisionShape()->getShapeType()]->CreateCollisionAlgorithm(ci,body0,body1);
->CreateCollisionAlgorithm(ci,body0,body1);
#else
btCollisionAlgorithm* algo = internalFindAlgorithm(body0,body1);
#endif //USE_DISPATCH_REGISTRY_ARRAY
return algo; return algo;
} }
#ifndef BT_EXCLUDE_DEFAULT_COLLISIONALGORITHM_REGISTRATION
btCollisionAlgorithmCreateFunc* btCollisionDispatcher::internalFindCreateFunc(int proxyType0,int proxyType1)
{
if (btBroadphaseProxy::isConvex(proxyType0) && btBroadphaseProxy::isConvex(proxyType1))
{
return m_convexConvexCreateFunc;
}
if (btBroadphaseProxy::isConvex(proxyType0) && btBroadphaseProxy::isConcave(proxyType1))
{
return m_convexConcaveCreateFunc;
}
if (btBroadphaseProxy::isConvex(proxyType1) && btBroadphaseProxy::isConcave(proxyType0))
{
return m_swappedConvexConcaveCreateFunc;
}
if (btBroadphaseProxy::isCompound(proxyType0))
{
return m_compoundCreateFunc;
} else
{
if (btBroadphaseProxy::isCompound(proxyType1))
{
return m_swappedCompoundCreateFunc;
}
}
//failed to find an algorithm
return m_emptyCreateFunc;
}
#endif //BT_EXCLUDE_DEFAULT_COLLISIONALGORITHM_REGISTRATION
#ifndef USE_DISPATCH_REGISTRY_ARRAY
btCollisionAlgorithm* btCollisionDispatcher::internalFindAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold)
{
m_count++;
btCollisionAlgorithmConstructionInfo ci;
ci.m_dispatcher = this;
if (body0->getCollisionShape()->isConvex() && body1->getCollisionShape()->isConvex() )
{
return new btConvexConvexAlgorithm(sharedManifold,ci,body0,body1);
}
if (body0->getCollisionShape()->isConvex() && body1->getCollisionShape()->isConcave())
{
return new btConvexConcaveCollisionAlgorithm(ci,body0,body1,false);
}
if (body1->getCollisionShape()->isConvex() && body0->getCollisionShape()->isConcave())
{
return new btConvexConcaveCollisionAlgorithm(ci,body0,body1,true);
}
if (body0->getCollisionShape()->isCompound())
{
return new btCompoundCollisionAlgorithm(ci,body0,body1,false);
} else
{
if (body1->getCollisionShape()->isCompound())
{
return new btCompoundCollisionAlgorithm(ci,body0,body1,true);
}
}
//failed to find an algorithm
return new btEmptyAlgorithm(ci);
}
#endif //USE_DISPATCH_REGISTRY_ARRAY
bool btCollisionDispatcher::needsResponse(btCollisionObject* body0,btCollisionObject* body1) bool btCollisionDispatcher::needsResponse(btCollisionObject* body0,btCollisionObject* body1)
{ {
@@ -264,13 +163,19 @@ bool btCollisionDispatcher::needsCollision(btCollisionObject* body0,btCollisionO
bool needsCollision = true; bool needsCollision = true;
//broadphase filtering already deals with this #ifdef BT_DEBUG
if ((body0->isStaticObject() || body0->isKinematicObject()) && if (!m_staticWarningReported)
(body1->isStaticObject() || body1->isKinematicObject()))
{ {
printf("warning btCollisionDispatcher::needsCollision: static-static collision!\n"); //broadphase filtering already deals with this
if ((body0->isStaticObject() || body0->isKinematicObject()) &&
(body1->isStaticObject() || body1->isKinematicObject()))
{
m_staticWarningReported = true;
printf("warning btCollisionDispatcher::needsCollision: static-static collision!\n");
}
} }
#endif //BT_DEBUG
if ((!body0->isActive()) && (!body1->isActive())) if ((!body0->isActive()) && (!body1->isActive()))
needsCollision = false; needsCollision = false;
else if (!body0->checkCollideWith(body1)) else if (!body0->checkCollideWith(body1))
@@ -286,23 +191,25 @@ bool btCollisionDispatcher::needsCollision(btCollisionObject* body0,btCollisionO
///this is useful for the collision dispatcher. ///this is useful for the collision dispatcher.
class btCollisionPairCallback : public btOverlapCallback class btCollisionPairCallback : public btOverlapCallback
{ {
btDispatcherInfo& m_dispatchInfo; const btDispatcherInfo& m_dispatchInfo;
btCollisionDispatcher* m_dispatcher; btCollisionDispatcher* m_dispatcher;
public: public:
btCollisionPairCallback(btDispatcherInfo& dispatchInfo,btCollisionDispatcher* dispatcher) btCollisionPairCallback(const btDispatcherInfo& dispatchInfo,btCollisionDispatcher* dispatcher)
:m_dispatchInfo(dispatchInfo), :m_dispatchInfo(dispatchInfo),
m_dispatcher(dispatcher) m_dispatcher(dispatcher)
{ {
} }
btCollisionPairCallback& operator=(btCollisionPairCallback& other) /*btCollisionPairCallback& operator=(btCollisionPairCallback& other)
{ {
m_dispatchInfo = other.m_dispatchInfo; m_dispatchInfo = other.m_dispatchInfo;
m_dispatcher = other.m_dispatcher; m_dispatcher = other.m_dispatcher;
return *this; return *this;
} }
*/
virtual ~btCollisionPairCallback() {} virtual ~btCollisionPairCallback() {}
@@ -316,13 +223,14 @@ public:
}; };
void btCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,btDispatcherInfo& dispatchInfo)
void btCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo,btDispatcher* dispatcher)
{ {
//m_blockedForChanges = true; //m_blockedForChanges = true;
btCollisionPairCallback collisionCallback(dispatchInfo,this); btCollisionPairCallback collisionCallback(dispatchInfo,this);
pairCache->processAllOverlappingPairs(&collisionCallback); pairCache->processAllOverlappingPairs(&collisionCallback,dispatcher);
//m_blockedForChanges = false; //m_blockedForChanges = false;
@@ -332,7 +240,7 @@ void btCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pa
//by default, Bullet will use this near callback //by default, Bullet will use this near callback
void btCollisionDispatcher::defaultNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, btDispatcherInfo& dispatchInfo) void btCollisionDispatcher::defaultNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo)
{ {
btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject; btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject;
btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject; btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject;
@@ -365,3 +273,26 @@ void btCollisionDispatcher::defaultNearCallback(btBroadphasePair& collisionPair,
} }
} }
void* btCollisionDispatcher::allocateCollisionAlgorithm(int size)
{
if (m_collisionAlgorithmPoolAllocator->getFreeCount())
{
return m_collisionAlgorithmPoolAllocator->allocate(size);
}
//warn user for overflow?
return btAlignedAlloc(static_cast<size_t>(size), 16);
}
void btCollisionDispatcher::freeCollisionAlgorithm(void* ptr)
{
if (m_collisionAlgorithmPoolAllocator->validPtr(ptr))
{
m_collisionAlgorithmPoolAllocator->freeMemory(ptr);
} else
{
btAlignedFree(ptr);
}
}

View File

@@ -16,17 +16,18 @@ subject to the following restrictions:
#ifndef COLLISION__DISPATCHER_H #ifndef COLLISION__DISPATCHER_H
#define COLLISION__DISPATCHER_H #define COLLISION__DISPATCHER_H
#include "../BroadphaseCollision/btDispatcher.h" #include "BulletCollision/BroadphaseCollision/btDispatcher.h"
#include "../NarrowPhaseCollision/btPersistentManifold.h" #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
#include "../CollisionDispatch/btManifoldResult.h" #include "BulletCollision/CollisionDispatch/btManifoldResult.h"
#include "../BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
#include "../../LinearMath/btAlignedObjectArray.h" #include "LinearMath/btAlignedObjectArray.h"
class btIDebugDraw; class btIDebugDraw;
class btOverlappingPairCache; class btOverlappingPairCache;
class btPoolAllocator;
class btCollisionConfiguration;
#include "btCollisionCreateFunc.h" #include "btCollisionCreateFunc.h"
@@ -34,7 +35,7 @@ class btOverlappingPairCache;
class btCollisionDispatcher; class btCollisionDispatcher;
///user can override this nearcallback for collision filtering and more finegrained control over collision detection ///user can override this nearcallback for collision filtering and more finegrained control over collision detection
typedef void (*btNearCallback)(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, btDispatcherInfo& dispatchInfo); typedef void (*btNearCallback)(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo);
///btCollisionDispatcher supports algorithms that handle ConvexConvex and ConvexConcave collision pairs. ///btCollisionDispatcher supports algorithms that handle ConvexConvex and ConvexConcave collision pairs.
@@ -46,26 +47,22 @@ class btCollisionDispatcher : public btDispatcher
btAlignedObjectArray<btPersistentManifold*> m_manifoldsPtr; btAlignedObjectArray<btPersistentManifold*> m_manifoldsPtr;
bool m_useIslands; bool m_useIslands;
bool m_staticWarningReported;
btManifoldResult m_defaultManifoldResult; btManifoldResult m_defaultManifoldResult;
btNearCallback m_nearCallback; btNearCallback m_nearCallback;
btPoolAllocator* m_collisionAlgorithmPoolAllocator;
btPoolAllocator* m_persistentManifoldPoolAllocator;
btCollisionAlgorithmCreateFunc* m_doubleDispatch[MAX_BROADPHASE_COLLISION_TYPES][MAX_BROADPHASE_COLLISION_TYPES]; btCollisionAlgorithmCreateFunc* m_doubleDispatch[MAX_BROADPHASE_COLLISION_TYPES][MAX_BROADPHASE_COLLISION_TYPES];
btCollisionAlgorithmCreateFunc* internalFindCreateFunc(int proxyType0,int proxyType1);
//default CreationFunctions, filling the m_doubleDispatch table btCollisionConfiguration* m_collisionConfiguration;
btCollisionAlgorithmCreateFunc* m_convexConvexCreateFunc;
btCollisionAlgorithmCreateFunc* m_convexConcaveCreateFunc;
btCollisionAlgorithmCreateFunc* m_swappedConvexConcaveCreateFunc;
btCollisionAlgorithmCreateFunc* m_compoundCreateFunc;
btCollisionAlgorithmCreateFunc* m_swappedCompoundCreateFunc;
btCollisionAlgorithmCreateFunc* m_emptyCreateFunc;
#ifndef USE_DISPATCH_REGISTRY_ARRAY
btCollisionAlgorithm* internalFindAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold = 0);
#endif //USE_DISPATCH_REGISTRY_ARRAY
public: public:
@@ -92,11 +89,7 @@ public:
return m_manifoldsPtr[index]; return m_manifoldsPtr[index];
} }
///the default constructor creates/register default collision algorithms, for convex, compound and concave shape support btCollisionDispatcher (btCollisionConfiguration* collisionConfiguration);
btCollisionDispatcher ();
///a special constructor that doesn't create/register the default collision algorithms
btCollisionDispatcher(bool noDefaultAlgorithms);
virtual ~btCollisionDispatcher(); virtual ~btCollisionDispatcher();
@@ -114,7 +107,7 @@ public:
virtual bool needsResponse(btCollisionObject* body0,btCollisionObject* body1); virtual bool needsResponse(btCollisionObject* body0,btCollisionObject* body1);
virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,btDispatcherInfo& dispatchInfo); virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo,btDispatcher* dispatcher) ;
void setNearCallback(btNearCallback nearCallback) void setNearCallback(btNearCallback nearCallback)
{ {
@@ -127,7 +120,26 @@ public:
} }
//by default, Bullet will use this near callback //by default, Bullet will use this near callback
static void defaultNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, btDispatcherInfo& dispatchInfo); static void defaultNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo);
virtual void* allocateCollisionAlgorithm(int size);
virtual void freeCollisionAlgorithm(void* ptr);
btCollisionConfiguration* getCollisionConfiguration()
{
return m_collisionConfiguration;
}
const btCollisionConfiguration* getCollisionConfiguration() const
{
return m_collisionConfiguration;
}
void setCollisionConfiguration(btCollisionConfiguration* config)
{
m_collisionConfiguration = config;
}
}; };

View File

@@ -13,15 +13,22 @@ subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include "btCollisionObject.h" #include "btCollisionObject.h"
btCollisionObject::btCollisionObject() btCollisionObject::btCollisionObject()
: m_broadphaseHandle(0), : m_broadphaseHandle(0),
m_collisionShape(0), m_collisionShape(0),
m_collisionFlags(0), m_rootCollisionShape(0),
m_collisionFlags(btCollisionObject::CF_STATIC_OBJECT),
m_islandTag1(-1),
m_companionId(-1),
m_activationState1(1), m_activationState1(1),
m_deactivationTime(btScalar(0.)), m_deactivationTime(btScalar(0.)),
m_friction(btScalar(0.5)),
m_restitution(btScalar(0.)),
m_userObjectPointer(0), m_userObjectPointer(0),
m_internalType(CO_COLLISION_OBJECT),
m_hitFraction(btScalar(1.)), m_hitFraction(btScalar(1.)),
m_ccdSweptSphereRadius(btScalar(0.)), m_ccdSweptSphereRadius(btScalar(0.)),
m_ccdSquareMotionThreshold(btScalar(0.)), m_ccdSquareMotionThreshold(btScalar(0.)),
@@ -55,3 +62,4 @@ void btCollisionObject::activate(bool forceActivation)
} }

View File

@@ -16,7 +16,7 @@ subject to the following restrictions:
#ifndef COLLISION_OBJECT_H #ifndef COLLISION_OBJECT_H
#define COLLISION_OBJECT_H #define COLLISION_OBJECT_H
#include "../../LinearMath/btTransform.h" #include "LinearMath/btTransform.h"
//island management, m_activationState1 //island management, m_activationState1
#define ACTIVE_TAG 1 #define ACTIVE_TAG 1
@@ -27,7 +27,8 @@ subject to the following restrictions:
struct btBroadphaseProxy; struct btBroadphaseProxy;
class btCollisionShape; class btCollisionShape;
#include "../../LinearMath/btMotionState.h" #include "LinearMath/btMotionState.h"
#include "LinearMath/btAlignedAllocator.h"
@@ -50,6 +51,11 @@ protected:
btVector3 m_interpolationAngularVelocity; btVector3 m_interpolationAngularVelocity;
btBroadphaseProxy* m_broadphaseHandle; btBroadphaseProxy* m_broadphaseHandle;
btCollisionShape* m_collisionShape; btCollisionShape* m_collisionShape;
///m_rootCollisionShape is temporarily used to store the original collision shape
///The m_collisionShape might be temporarily replaced by a child collision shape during collision detection purposes
///If it is NULL, the m_collisionShape is not temporarily replaced.
btCollisionShape* m_rootCollisionShape;
int m_collisionFlags; int m_collisionFlags;
@@ -65,8 +71,9 @@ protected:
///users can point to their objects, m_userPointer is not used by Bullet, see setUserPointer/getUserPointer ///users can point to their objects, m_userPointer is not used by Bullet, see setUserPointer/getUserPointer
void* m_userObjectPointer; void* m_userObjectPointer;
///m_internalOwner is reserved to point to Bullet's btRigidBody. Don't use this, use m_userObjectPointer instead. ///m_internalType is reserved to distinguish Bullet's btCollisionObject, btRigidBody, btSoftBody etc.
void* m_internalOwner; ///do not assign your own m_internalType unless you write a new dynamics object class.
int m_internalType;
///time of impact calculation ///time of impact calculation
btScalar m_hitFraction; btScalar m_hitFraction;
@@ -82,13 +89,15 @@ protected:
char m_pad[7]; char m_pad[7];
virtual bool checkCollideWithOverride(btCollisionObject* co) virtual bool checkCollideWithOverride(btCollisionObject* /* co */)
{ {
return true; return true;
} }
public: public:
BT_DECLARE_ALIGNED_ALLOCATOR();
enum CollisionFlags enum CollisionFlags
{ {
CF_STATIC_OBJECT= 1, CF_STATIC_OBJECT= 1,
@@ -97,29 +106,35 @@ public:
CF_CUSTOM_MATERIAL_CALLBACK = 8//this allows per-triangle material (friction/restitution) CF_CUSTOM_MATERIAL_CALLBACK = 8//this allows per-triangle material (friction/restitution)
}; };
enum CollisionObjectTypes
{
CO_COLLISION_OBJECT =1,
CO_RIGID_BODY,
CO_SOFT_BODY
};
inline bool mergesSimulationIslands() const SIMD_FORCE_INLINE bool mergesSimulationIslands() const
{ {
///static objects, kinematic and object without contact response don't merge islands ///static objects, kinematic and object without contact response don't merge islands
return ((m_collisionFlags & (CF_STATIC_OBJECT | CF_KINEMATIC_OBJECT | CF_NO_CONTACT_RESPONSE) )==0); return ((m_collisionFlags & (CF_STATIC_OBJECT | CF_KINEMATIC_OBJECT | CF_NO_CONTACT_RESPONSE) )==0);
} }
inline bool isStaticObject() const { SIMD_FORCE_INLINE bool isStaticObject() const {
return (m_collisionFlags & CF_STATIC_OBJECT) != 0; return (m_collisionFlags & CF_STATIC_OBJECT) != 0;
} }
inline bool isKinematicObject() const SIMD_FORCE_INLINE bool isKinematicObject() const
{ {
return (m_collisionFlags & CF_KINEMATIC_OBJECT) != 0; return (m_collisionFlags & CF_KINEMATIC_OBJECT) != 0;
} }
inline bool isStaticOrKinematicObject() const SIMD_FORCE_INLINE bool isStaticOrKinematicObject() const
{ {
return (m_collisionFlags & (CF_KINEMATIC_OBJECT | CF_STATIC_OBJECT)) != 0 ; return (m_collisionFlags & (CF_KINEMATIC_OBJECT | CF_STATIC_OBJECT)) != 0 ;
} }
inline bool hasContactResponse() const { SIMD_FORCE_INLINE bool hasContactResponse() const {
return (m_collisionFlags & CF_NO_CONTACT_RESPONSE)==0; return (m_collisionFlags & CF_NO_CONTACT_RESPONSE)==0;
} }
@@ -131,20 +146,35 @@ public:
void setCollisionShape(btCollisionShape* collisionShape) void setCollisionShape(btCollisionShape* collisionShape)
{ {
m_collisionShape = collisionShape; m_collisionShape = collisionShape;
m_rootCollisionShape = collisionShape;
} }
const btCollisionShape* getCollisionShape() const SIMD_FORCE_INLINE const btCollisionShape* getCollisionShape() const
{ {
return m_collisionShape; return m_collisionShape;
} }
btCollisionShape* getCollisionShape() SIMD_FORCE_INLINE btCollisionShape* getCollisionShape()
{ {
return m_collisionShape; return m_collisionShape;
} }
SIMD_FORCE_INLINE const btCollisionShape* getRootCollisionShape() const
{
return m_rootCollisionShape;
}
SIMD_FORCE_INLINE btCollisionShape* getRootCollisionShape()
{
return m_rootCollisionShape;
}
///Avoid using this internal API call
///internalSetTemporaryCollisionShape is used to temporary replace the actual collision shape by a child collision shape.
void internalSetTemporaryCollisionShape(btCollisionShape* collisionShape)
{
m_collisionShape = collisionShape;
}
int getActivationState() const { return m_activationState1;} int getActivationState() const { return m_activationState1;}
@@ -186,14 +216,9 @@ public:
} }
///reserved for Bullet internal usage ///reserved for Bullet internal usage
void* getInternalOwner() int getInternalType() const
{ {
return m_internalOwner; return m_internalType;
}
const void* getInternalOwner() const
{
return m_internalOwner;
} }
btTransform& getWorldTransform() btTransform& getWorldTransform()
@@ -331,6 +356,7 @@ public:
m_userObjectPointer = userPointer; m_userObjectPointer = userPointer;
} }
inline bool checkCollideWith(btCollisionObject* co) inline bool checkCollideWith(btCollisionObject* co)
{ {
if (m_checkCollideWith) if (m_checkCollideWith)
@@ -338,9 +364,6 @@ public:
return true; return true;
} }
};
}
;
#endif //COLLISION_OBJECT_H #endif //COLLISION_OBJECT_H

View File

@@ -4,8 +4,8 @@ Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty. This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software. In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely, including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions: subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
@@ -18,59 +18,57 @@ subject to the following restrictions:
#include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h"
#include "BulletCollision/CollisionShapes/btCollisionShape.h" #include "BulletCollision/CollisionShapes/btCollisionShape.h"
#include "BulletCollision/CollisionShapes/btConvexShape.h" #include "BulletCollision/CollisionShapes/btConvexShape.h"
#include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h"
#include "BulletCollision/CollisionShapes/btSphereShape.h" //for raycasting #include "BulletCollision/CollisionShapes/btSphereShape.h" //for raycasting
#include "BulletCollision/CollisionShapes/btTriangleMeshShape.h" //for raycasting #include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" //for raycasting
#include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h" #include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h"
#include "BulletCollision/CollisionShapes/btCompoundShape.h" #include "BulletCollision/CollisionShapes/btCompoundShape.h"
#include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h"
#include "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h"
#include "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h"
#include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h"
#include "LinearMath/btAabbUtil2.h" #include "LinearMath/btAabbUtil2.h"
#include "LinearMath/btQuickprof.h" #include "LinearMath/btQuickprof.h"
#include "LinearMath/btStackAlloc.h" #include "LinearMath/btStackAlloc.h"
//When the user doesn't provide dispatcher or broadphase, create basic versions (and delete them in destructor) //When the user doesn't provide dispatcher or broadphase, create basic versions (and delete them in destructor)
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
#include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h" #include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h"
#include "BulletCollision/CollisionDispatch/btCollisionConfiguration.h"
btCollisionWorld::btCollisionWorld(btDispatcher* dispatcher,btOverlappingPairCache* pairCache, int stackSize) btCollisionWorld::btCollisionWorld(btDispatcher* dispatcher,btBroadphaseInterface* pairCache, btCollisionConfiguration* collisionConfiguration)
:m_dispatcher1(dispatcher), :m_dispatcher1(dispatcher),
m_broadphasePairCache(pairCache), m_broadphasePairCache(pairCache),
m_ownsDispatcher(false), m_debugDrawer(0)
m_ownsBroadphasePairCache(false)
{ {
m_stackAlloc = new btStackAlloc(stackSize); m_stackAlloc = collisionConfiguration->getStackAllocator();
m_dispatchInfo.m_stackAllocator = m_stackAlloc; m_dispatchInfo.m_stackAllocator = m_stackAlloc;
} }
btCollisionWorld::~btCollisionWorld() btCollisionWorld::~btCollisionWorld()
{ {
m_stackAlloc->destroy();
delete m_stackAlloc;
//clean up remaining objects //clean up remaining objects
int i; int i;
for (i=0;i<m_collisionObjects.size();i++) for (i=0;i<m_collisionObjects.size();i++)
{ {
btCollisionObject* collisionObject= m_collisionObjects[i]; btCollisionObject* collisionObject= m_collisionObjects[i];
btBroadphaseProxy* bp = collisionObject->getBroadphaseHandle(); btBroadphaseProxy* bp = collisionObject->getBroadphaseHandle();
if (bp) if (bp)
{ {
// //
// only clear the cached algorithms // only clear the cached algorithms
// //
getBroadphase()->cleanProxyFromPairs(bp); getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(bp,m_dispatcher1);
getBroadphase()->destroyProxy(bp); getBroadphase()->destroyProxy(bp,m_dispatcher1);
} }
} }
if (m_ownsDispatcher)
delete m_dispatcher1;
if (m_ownsBroadphasePairCache)
delete m_broadphasePairCache;
} }
@@ -105,66 +103,100 @@ void btCollisionWorld::addCollisionObject(btCollisionObject* collisionObject,sho
type, type,
collisionObject, collisionObject,
collisionFilterGroup, collisionFilterGroup,
collisionFilterMask collisionFilterMask,
m_dispatcher1,0
)) ; )) ;
} }
void btCollisionWorld::updateAabbs()
{
BT_PROFILE("updateAabbs");
btTransform predictedTrans;
for ( int i=0;i<m_collisionObjects.size();i++)
{
btCollisionObject* colObj = m_collisionObjects[i];
//only update aabb of active objects
if (colObj->isActive())
{
btPoint3 minAabb,maxAabb;
colObj->getCollisionShape()->getAabb(colObj->getWorldTransform(), minAabb,maxAabb);
btBroadphaseInterface* bp = (btBroadphaseInterface*)m_broadphasePairCache;
//moving objects should be moderately sized, probably something wrong if not
if ( colObj->isStaticObject() || ((maxAabb-minAabb).length2() < btScalar(1e12)))
{
bp->setAabb(colObj->getBroadphaseHandle(),minAabb,maxAabb, m_dispatcher1);
} else
{
//something went wrong, investigate
//this assert is unwanted in 3D modelers (danger of loosing work)
colObj->setActivationState(DISABLE_SIMULATION);
static bool reportMe = true;
if (reportMe && m_debugDrawer)
{
reportMe = false;
m_debugDrawer->reportErrorWarning("Overflow in AABB, object removed from simulation");
m_debugDrawer->reportErrorWarning("If you can reproduce this, please email bugs@continuousphysics.com\n");
m_debugDrawer->reportErrorWarning("Please include above information, your Platform, version of OS.\n");
m_debugDrawer->reportErrorWarning("Thanks.\n");
}
}
}
}
}
void btCollisionWorld::performDiscreteCollisionDetection() void btCollisionWorld::performDiscreteCollisionDetection()
{ {
BT_PROFILE("performDiscreteCollisionDetection");
btDispatcherInfo& dispatchInfo = getDispatchInfo(); btDispatcherInfo& dispatchInfo = getDispatchInfo();
BEGIN_PROFILE("perform Broadphase Collision Detection"); updateAabbs();
//update aabb (of all moved objects)
btVector3 aabbMin,aabbMax;
for (int i=0;i<m_collisionObjects.size();i++)
{ {
m_collisionObjects[i]->getCollisionShape()->getAabb(m_collisionObjects[i]->getWorldTransform(),aabbMin,aabbMax); BT_PROFILE("calculateOverlappingPairs");
m_broadphasePairCache->setAabb(m_collisionObjects[i]->getBroadphaseHandle(),aabbMin,aabbMax); m_broadphasePairCache->calculateOverlappingPairs(m_dispatcher1);
} }
m_broadphasePairCache->refreshOverlappingPairs();
END_PROFILE("perform Broadphase Collision Detection");
BEGIN_PROFILE("performDiscreteCollisionDetection");
btDispatcher* dispatcher = getDispatcher(); btDispatcher* dispatcher = getDispatcher();
if (dispatcher) {
dispatcher->dispatchAllCollisionPairs(m_broadphasePairCache,dispatchInfo); BT_PROFILE("dispatchAllCollisionPairs");
if (dispatcher)
END_PROFILE("performDiscreteCollisionDetection"); dispatcher->dispatchAllCollisionPairs(m_broadphasePairCache->getOverlappingPairCache(),dispatchInfo,m_dispatcher1);
}
} }
void btCollisionWorld::removeCollisionObject(btCollisionObject* collisionObject) void btCollisionWorld::removeCollisionObject(btCollisionObject* collisionObject)
{ {
//bool removeFromBroadphase = false; //bool removeFromBroadphase = false;
{ {
btBroadphaseProxy* bp = collisionObject->getBroadphaseHandle(); btBroadphaseProxy* bp = collisionObject->getBroadphaseHandle();
if (bp) if (bp)
{ {
// //
// only clear the cached algorithms // only clear the cached algorithms
// //
getBroadphase()->cleanProxyFromPairs(bp); getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(bp,m_dispatcher1);
getBroadphase()->destroyProxy(bp); getBroadphase()->destroyProxy(bp,m_dispatcher1);
collisionObject->setBroadphaseHandle(0); collisionObject->setBroadphaseHandle(0);
} }
} }
@@ -181,192 +213,457 @@ void btCollisionWorld::rayTestSingle(const btTransform& rayFromTrans,const btTra
btCollisionObject* collisionObject, btCollisionObject* collisionObject,
const btCollisionShape* collisionShape, const btCollisionShape* collisionShape,
const btTransform& colObjWorldTransform, const btTransform& colObjWorldTransform,
RayResultCallback& resultCallback, RayResultCallback& resultCallback)
short int collisionFilterMask,
bool faceNormal)
{ {
btSphereShape pointShape(btScalar(0.0)); btSphereShape pointShape(btScalar(0.0));
pointShape.setMargin(0.f); pointShape.setMargin(0.f);
const btConvexShape* castShape = &pointShape;
objectQuerySingle(&pointShape,rayFromTrans,rayToTrans, if (collisionShape->isConvex())
collisionObject, {
collisionShape, btConvexCast::CastResult castResult;
colObjWorldTransform, castResult.m_fraction = resultCallback.m_closestHitFraction;
resultCallback,collisionFilterMask,faceNormal);
btConvexShape* convexShape = (btConvexShape*) collisionShape;
btVoronoiSimplexSolver simplexSolver;
#define USE_SUBSIMPLEX_CONVEX_CAST 1
#ifdef USE_SUBSIMPLEX_CONVEX_CAST
btSubsimplexConvexCast convexCaster(castShape,convexShape,&simplexSolver);
#else
//btGjkConvexCast convexCaster(castShape,convexShape,&simplexSolver);
//btContinuousConvexCollision convexCaster(castShape,convexShape,&simplexSolver,0);
#endif //#USE_SUBSIMPLEX_CONVEX_CAST
if (convexCaster.calcTimeOfImpact(rayFromTrans,rayToTrans,colObjWorldTransform,colObjWorldTransform,castResult))
{
//add hit
if (castResult.m_normal.length2() > btScalar(0.0001))
{
if (castResult.m_fraction < resultCallback.m_closestHitFraction)
{
#ifdef USE_SUBSIMPLEX_CONVEX_CAST
//rotate normal into worldspace
castResult.m_normal = rayFromTrans.getBasis() * castResult.m_normal;
#endif //USE_SUBSIMPLEX_CONVEX_CAST
castResult.m_normal.normalize();
btCollisionWorld::LocalRayResult localRayResult
(
collisionObject,
0,
castResult.m_normal,
castResult.m_fraction
);
bool normalInWorldSpace = true;
resultCallback.addSingleResult(localRayResult, normalInWorldSpace);
}
}
}
} else {
if (collisionShape->isConcave())
{
if (collisionShape->getShapeType()==TRIANGLE_MESH_SHAPE_PROXYTYPE)
{
///optimized version for btBvhTriangleMeshShape
btBvhTriangleMeshShape* triangleMesh = (btBvhTriangleMeshShape*)collisionShape;
btTransform worldTocollisionObject = colObjWorldTransform.inverse();
btVector3 rayFromLocal = worldTocollisionObject * rayFromTrans.getOrigin();
btVector3 rayToLocal = worldTocollisionObject * rayToTrans.getOrigin();
//ConvexCast::CastResult
struct BridgeTriangleRaycastCallback : public btTriangleRaycastCallback
{
btCollisionWorld::RayResultCallback* m_resultCallback;
btCollisionObject* m_collisionObject;
btTriangleMeshShape* m_triangleMesh;
BridgeTriangleRaycastCallback( const btVector3& from,const btVector3& to,
btCollisionWorld::RayResultCallback* resultCallback, btCollisionObject* collisionObject,btTriangleMeshShape* triangleMesh):
btTriangleRaycastCallback(from,to),
m_resultCallback(resultCallback),
m_collisionObject(collisionObject),
m_triangleMesh(triangleMesh)
{
}
virtual btScalar reportHit(const btVector3& hitNormalLocal, btScalar hitFraction, int partId, int triangleIndex )
{
btCollisionWorld::LocalShapeInfo shapeInfo;
shapeInfo.m_shapePart = partId;
shapeInfo.m_triangleIndex = triangleIndex;
btCollisionWorld::LocalRayResult rayResult
(m_collisionObject,
&shapeInfo,
hitNormalLocal,
hitFraction);
bool normalInWorldSpace = false;
return m_resultCallback->addSingleResult(rayResult,normalInWorldSpace);
}
};
BridgeTriangleRaycastCallback rcb(rayFromLocal,rayToLocal,&resultCallback,collisionObject,triangleMesh);
rcb.m_hitFraction = resultCallback.m_closestHitFraction;
triangleMesh->performRaycast(&rcb,rayFromLocal,rayToLocal);
} else
{
btTriangleMeshShape* triangleMesh = (btTriangleMeshShape*)collisionShape;
btTransform worldTocollisionObject = colObjWorldTransform.inverse();
btVector3 rayFromLocal = worldTocollisionObject * rayFromTrans.getOrigin();
btVector3 rayToLocal = worldTocollisionObject * rayToTrans.getOrigin();
//ConvexCast::CastResult
struct BridgeTriangleRaycastCallback : public btTriangleRaycastCallback
{
btCollisionWorld::RayResultCallback* m_resultCallback;
btCollisionObject* m_collisionObject;
btTriangleMeshShape* m_triangleMesh;
BridgeTriangleRaycastCallback( const btVector3& from,const btVector3& to,
btCollisionWorld::RayResultCallback* resultCallback, btCollisionObject* collisionObject,btTriangleMeshShape* triangleMesh):
btTriangleRaycastCallback(from,to),
m_resultCallback(resultCallback),
m_collisionObject(collisionObject),
m_triangleMesh(triangleMesh)
{
}
virtual btScalar reportHit(const btVector3& hitNormalLocal, btScalar hitFraction, int partId, int triangleIndex )
{
btCollisionWorld::LocalShapeInfo shapeInfo;
shapeInfo.m_shapePart = partId;
shapeInfo.m_triangleIndex = triangleIndex;
btCollisionWorld::LocalRayResult rayResult
(m_collisionObject,
&shapeInfo,
hitNormalLocal,
hitFraction);
bool normalInWorldSpace = false;
return m_resultCallback->addSingleResult(rayResult,normalInWorldSpace);
}
};
BridgeTriangleRaycastCallback rcb(rayFromLocal,rayToLocal,&resultCallback,collisionObject,triangleMesh);
rcb.m_hitFraction = resultCallback.m_closestHitFraction;
btVector3 rayAabbMinLocal = rayFromLocal;
rayAabbMinLocal.setMin(rayToLocal);
btVector3 rayAabbMaxLocal = rayFromLocal;
rayAabbMaxLocal.setMax(rayToLocal);
triangleMesh->processAllTriangles(&rcb,rayAabbMinLocal,rayAabbMaxLocal);
}
} else {
//todo: use AABB tree or other BVH acceleration structure!
if (collisionShape->isCompound())
{
const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(collisionShape);
int i=0;
for (i=0;i<compoundShape->getNumChildShapes();i++)
{
btTransform childTrans = compoundShape->getChildTransform(i);
const btCollisionShape* childCollisionShape = compoundShape->getChildShape(i);
btTransform childWorldTrans = colObjWorldTransform * childTrans;
rayTestSingle(rayFromTrans,rayToTrans,
collisionObject,
childCollisionShape,
childWorldTrans,
resultCallback);
}
}
}
}
} }
void btCollisionWorld::objectQuerySingle(const btConvexShape* castShape,const btTransform& rayFromTrans,const btTransform& rayToTrans, void btCollisionWorld::objectQuerySingle(const btConvexShape* castShape,const btTransform& convexFromTrans,const btTransform& convexToTrans,
btCollisionObject* collisionObject, btCollisionObject* collisionObject,
const btCollisionShape* collisionShape, const btCollisionShape* collisionShape,
const btTransform& colObjWorldTransform, const btTransform& colObjWorldTransform,
RayResultCallback& resultCallback, ConvexResultCallback& resultCallback, btScalar allowedPenetration)
short int collisionFilterMask,
bool faceNormal)
{ {
if (collisionShape->isConvex()) if (collisionShape->isConvex())
{
btConvexCast::CastResult castResult;
castResult.m_allowedPenetration = allowedPenetration;
castResult.m_fraction = btScalar(1.);//??
btConvexShape* convexShape = (btConvexShape*) collisionShape;
btVoronoiSimplexSolver simplexSolver;
btGjkEpaPenetrationDepthSolver gjkEpaPenetrationSolver;
btContinuousConvexCollision convexCaster1(castShape,convexShape,&simplexSolver,&gjkEpaPenetrationSolver);
//btGjkConvexCast convexCaster2(castShape,convexShape,&simplexSolver);
//btSubsimplexConvexCast convexCaster3(castShape,convexShape,&simplexSolver);
btConvexCast* castPtr = &convexCaster1;
if (castPtr->calcTimeOfImpact(convexFromTrans,convexToTrans,colObjWorldTransform,colObjWorldTransform,castResult))
{
//add hit
if (castResult.m_normal.length2() > btScalar(0.0001))
{ {
btConvexCast::CastResult castResult; if (castResult.m_fraction < resultCallback.m_closestHitFraction)
castResult.m_fraction = btScalar(1.);//??
btConvexShape* convexShape = (btConvexShape*) collisionShape;
btVoronoiSimplexSolver simplexSolver;
btSubsimplexConvexCast convexCaster(castShape,convexShape,&simplexSolver);
//GjkConvexCast convexCaster(castShape,convexShape,&simplexSolver);
//ContinuousConvexCollision convexCaster(castShape,convexShape,&simplexSolver,0);
if (convexCaster.calcTimeOfImpact(rayFromTrans,rayToTrans,colObjWorldTransform,colObjWorldTransform,castResult))
{ {
//add hit castResult.m_normal.normalize();
if (castResult.m_normal.length2() > btScalar(0.0001)) btCollisionWorld::LocalConvexResult localConvexResult
{
castResult.m_normal.normalize();
if (castResult.m_fraction < resultCallback.m_closestHitFraction)
{
btCollisionWorld::LocalRayResult localRayResult
( (
collisionObject, collisionObject,
0, 0,
castResult.m_normal, castResult.m_normal,
castResult.m_hitPoint,
castResult.m_fraction castResult.m_fraction
); );
resultCallback.AddSingleResult(localRayResult); bool normalInWorldSpace = true;
resultCallback.addSingleResult(localConvexResult, normalInWorldSpace);
}
}
} }
} }
else }
} else {
if (collisionShape->isConcave())
{
if (collisionShape->getShapeType()==TRIANGLE_MESH_SHAPE_PROXYTYPE)
{ {
btBvhTriangleMeshShape* triangleMesh = (btBvhTriangleMeshShape*)collisionShape;
if (collisionShape->isConcave()) btTransform worldTocollisionObject = colObjWorldTransform.inverse();
{ btVector3 convexFromLocal = worldTocollisionObject * convexFromTrans.getOrigin();
btVector3 convexToLocal = worldTocollisionObject * convexToTrans.getOrigin();
// rotation of box in local mesh space = MeshRotation^-1 * ConvexToRotation
btTransform rotationXform = btTransform(worldTocollisionObject.getBasis() * convexToTrans.getBasis());
btTriangleMeshShape* triangleMesh = (btTriangleMeshShape*)collisionShape; //ConvexCast::CastResult
struct BridgeTriangleConvexcastCallback : public btTriangleConvexcastCallback
btTransform worldTocollisionObject = colObjWorldTransform.inverse(); {
btCollisionWorld::ConvexResultCallback* m_resultCallback;
btCollisionObject* m_collisionObject;
btTriangleMeshShape* m_triangleMesh;
btVector3 rayFromLocal = worldTocollisionObject * rayFromTrans.getOrigin(); BridgeTriangleConvexcastCallback(const btConvexShape* castShape, const btTransform& from,const btTransform& to,
btVector3 rayToLocal = worldTocollisionObject * rayToTrans.getOrigin(); btCollisionWorld::ConvexResultCallback* resultCallback, btCollisionObject* collisionObject,btTriangleMeshShape* triangleMesh, const btTransform& triangleToWorld):
btTriangleConvexcastCallback(castShape, from,to, triangleToWorld, triangleMesh->getMargin()),
//ConvexCast::CastResult m_resultCallback(resultCallback),
m_collisionObject(collisionObject),
struct BridgeTriangleRaycastCallback : public btTriangleRaycastCallback m_triangleMesh(triangleMesh)
{ {
btCollisionWorld::RayResultCallback* m_resultCallback;
btCollisionObject* m_collisionObject;
btTriangleMeshShape* m_triangleMesh;
BridgeTriangleRaycastCallback( const btVector3& from,const btVector3& to,bool faceNormal,
btCollisionWorld::RayResultCallback* resultCallback, btCollisionObject* collisionObject,btTriangleMeshShape* triangleMesh):
btTriangleRaycastCallback(from,to,faceNormal),
m_resultCallback(resultCallback),
m_collisionObject(collisionObject),
m_triangleMesh(triangleMesh)
{
}
virtual btScalar reportHit(const btVector3& hitNormalLocal, btScalar hitFraction, int partId, int triangleIndex )
{
btCollisionWorld::LocalShapeInfo shapeInfo;
shapeInfo.m_shapePart = partId;
shapeInfo.m_triangleIndex = triangleIndex;
shapeInfo.m_triangleShape = m_triangleMesh;
btCollisionWorld::LocalRayResult rayResult
(m_collisionObject,
&shapeInfo,
hitNormalLocal,
hitFraction);
return m_resultCallback->AddSingleResult(rayResult);
}
};
BridgeTriangleRaycastCallback rcb(rayFromLocal,rayToLocal,faceNormal,&resultCallback,collisionObject,triangleMesh);
rcb.m_hitFraction = resultCallback.m_closestHitFraction;
btVector3 rayAabbMinLocal = rayFromLocal;
rayAabbMinLocal.setMin(rayToLocal);
btVector3 rayAabbMaxLocal = rayFromLocal;
rayAabbMaxLocal.setMax(rayToLocal);
triangleMesh->processAllTriangles(&rcb,rayAabbMinLocal,rayAabbMaxLocal);
} else
{
//todo: use AABB tree or other BVH acceleration structure!
if (collisionShape->isCompound())
{
const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(collisionShape);
int i=0;
for (i=0;i<compoundShape->getNumChildShapes();i++)
{
btTransform childTrans = compoundShape->getChildTransform(i);
const btCollisionShape* childCollisionShape = compoundShape->getChildShape(i);
btTransform childWorldTrans = colObjWorldTransform * childTrans;
objectQuerySingle(castShape, rayFromTrans,rayToTrans,
collisionObject,
childCollisionShape,
childWorldTrans,
resultCallback, collisionFilterMask, faceNormal);
}
} }
virtual btScalar reportHit(const btVector3& hitNormalLocal, const btVector3& hitPointLocal, btScalar hitFraction, int partId, int triangleIndex )
{
btCollisionWorld::LocalShapeInfo shapeInfo;
shapeInfo.m_shapePart = partId;
shapeInfo.m_triangleIndex = triangleIndex;
if (hitFraction <= m_resultCallback->m_closestHitFraction)
{
btCollisionWorld::LocalConvexResult convexResult
(m_collisionObject,
&shapeInfo,
hitNormalLocal,
hitPointLocal,
hitFraction);
bool normalInWorldSpace = true;
return m_resultCallback->addSingleResult(convexResult,normalInWorldSpace);
}
return hitFraction;
} }
};
BridgeTriangleConvexcastCallback tccb(castShape, convexFromTrans,convexToTrans,&resultCallback,collisionObject,triangleMesh, colObjWorldTransform);
tccb.m_hitFraction = resultCallback.m_closestHitFraction;
btVector3 boxMinLocal, boxMaxLocal;
castShape->getAabb(rotationXform, boxMinLocal, boxMaxLocal);
triangleMesh->performConvexcast(&tccb,convexFromLocal,convexToLocal,boxMinLocal, boxMaxLocal);
} else
{
btBvhTriangleMeshShape* triangleMesh = (btBvhTriangleMeshShape*)collisionShape;
btTransform worldTocollisionObject = colObjWorldTransform.inverse();
btVector3 convexFromLocal = worldTocollisionObject * convexFromTrans.getOrigin();
btVector3 convexToLocal = worldTocollisionObject * convexToTrans.getOrigin();
// rotation of box in local mesh space = MeshRotation^-1 * ConvexToRotation
btTransform rotationXform = btTransform(worldTocollisionObject.getBasis() * convexToTrans.getBasis());
//ConvexCast::CastResult
struct BridgeTriangleConvexcastCallback : public btTriangleConvexcastCallback
{
btCollisionWorld::ConvexResultCallback* m_resultCallback;
btCollisionObject* m_collisionObject;
btTriangleMeshShape* m_triangleMesh;
BridgeTriangleConvexcastCallback(const btConvexShape* castShape, const btTransform& from,const btTransform& to,
btCollisionWorld::ConvexResultCallback* resultCallback, btCollisionObject* collisionObject,btTriangleMeshShape* triangleMesh, const btTransform& triangleToWorld):
btTriangleConvexcastCallback(castShape, from,to, triangleToWorld, triangleMesh->getMargin()),
m_resultCallback(resultCallback),
m_collisionObject(collisionObject),
m_triangleMesh(triangleMesh)
{
}
virtual btScalar reportHit(const btVector3& hitNormalLocal, const btVector3& hitPointLocal, btScalar hitFraction, int partId, int triangleIndex )
{
btCollisionWorld::LocalShapeInfo shapeInfo;
shapeInfo.m_shapePart = partId;
shapeInfo.m_triangleIndex = triangleIndex;
if (hitFraction <= m_resultCallback->m_closestHitFraction)
{
btCollisionWorld::LocalConvexResult convexResult
(m_collisionObject,
&shapeInfo,
hitNormalLocal,
hitPointLocal,
hitFraction);
bool normalInWorldSpace = false;
return m_resultCallback->addSingleResult(convexResult,normalInWorldSpace);
}
return hitFraction;
}
};
BridgeTriangleConvexcastCallback tccb(castShape, convexFromTrans,convexToTrans,&resultCallback,collisionObject,triangleMesh, colObjWorldTransform);
tccb.m_hitFraction = resultCallback.m_closestHitFraction;
btVector3 boxMinLocal, boxMaxLocal;
castShape->getAabb(rotationXform, boxMinLocal, boxMaxLocal);
btVector3 rayAabbMinLocal = convexFromLocal;
rayAabbMinLocal.setMin(convexToLocal);
btVector3 rayAabbMaxLocal = convexFromLocal;
rayAabbMaxLocal.setMax(convexToLocal);
rayAabbMinLocal += boxMinLocal;
rayAabbMaxLocal += boxMaxLocal;
triangleMesh->processAllTriangles(&tccb,rayAabbMinLocal,rayAabbMaxLocal);
} }
} else {
//todo: use AABB tree or other BVH acceleration structure!
if (collisionShape->isCompound())
{
const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(collisionShape);
int i=0;
for (i=0;i<compoundShape->getNumChildShapes();i++)
{
btTransform childTrans = compoundShape->getChildTransform(i);
const btCollisionShape* childCollisionShape = compoundShape->getChildShape(i);
btTransform childWorldTrans = colObjWorldTransform * childTrans;
objectQuerySingle(castShape, convexFromTrans,convexToTrans,
collisionObject,
childCollisionShape,
childWorldTrans,
resultCallback, allowedPenetration);
}
}
}
}
} }
void btCollisionWorld::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback,short int collisionFilterMask, bool faceNormal) void btCollisionWorld::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const
{ {
btTransform rayFromTrans,rayToTrans; btTransform rayFromTrans,rayToTrans;
rayFromTrans.setIdentity(); rayFromTrans.setIdentity();
rayFromTrans.setOrigin(rayFromWorld); rayFromTrans.setOrigin(rayFromWorld);
rayToTrans.setIdentity(); rayToTrans.setIdentity();
rayToTrans.setOrigin(rayToWorld); rayToTrans.setOrigin(rayToWorld);
/// go over all objects, and if the ray intersects their aabb, do a ray-shape query using convexCaster (CCD) /// go over all objects, and if the ray intersects their aabb, do a ray-shape query using convexCaster (CCD)
int i;
for (i=0;i<m_collisionObjects.size();i++)
{
///terminate further ray tests, once the closestHitFraction reached zero
if (resultCallback.m_closestHitFraction == btScalar(0.f))
break;
btCollisionObject* collisionObject= m_collisionObjects[i];
//only perform raycast if filterMask matches
if(resultCallback.needsCollision(collisionObject->getBroadphaseHandle())) {
//RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject();
btVector3 collisionObjectAabbMin,collisionObjectAabbMax;
collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax);
btScalar hitLambda = resultCallback.m_closestHitFraction;
btVector3 hitNormal;
if (btRayAabb(rayFromWorld,rayToWorld,collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,hitNormal))
{
rayTestSingle(rayFromTrans,rayToTrans,
collisionObject,
collisionObject->getCollisionShape(),
collisionObject->getWorldTransform(),
resultCallback);
}
}
}
}
void btCollisionWorld::convexSweepTest(const btConvexShape* castShape, const btTransform& convexFromWorld, const btTransform& convexToWorld, ConvexResultCallback& resultCallback) const
{
btTransform convexFromTrans,convexToTrans;
convexFromTrans = convexFromWorld;
convexToTrans = convexToWorld;
btVector3 castShapeAabbMin, castShapeAabbMax;
/* Compute AABB that encompasses angular movement */
{
btVector3 linVel, angVel;
btTransformUtil::calculateVelocity (convexFromTrans, convexToTrans, 1.0, linVel, angVel);
btTransform R;
R.setIdentity ();
R.setRotation (convexFromTrans.getRotation());
castShape->calculateTemporalAabb (R, linVel, angVel, 1.0, castShapeAabbMin, castShapeAabbMax);
}
/// go over all objects, and if the ray intersects their aabb + cast shape aabb,
// do a ray-shape query using convexCaster (CCD)
int i; int i;
for (i=0;i<m_collisionObjects.size();i++) for (i=0;i<m_collisionObjects.size();i++)
{ {
btCollisionObject* collisionObject= m_collisionObjects[i]; btCollisionObject* collisionObject= m_collisionObjects[i];
//only perform raycast if filterMask matches //only perform raycast if filterMask matches
if(collisionObject->getBroadphaseHandle()->m_collisionFilterGroup & collisionFilterMask) { if(resultCallback.needsCollision(collisionObject->getBroadphaseHandle())) {
//RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject(); //RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject();
btVector3 collisionObjectAabbMin,collisionObjectAabbMax; btVector3 collisionObjectAabbMin,collisionObjectAabbMax;
collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax); collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax);
AabbExpand (collisionObjectAabbMin, collisionObjectAabbMax, castShapeAabbMin, castShapeAabbMax);
btScalar hitLambda = btScalar(1.); //could use resultCallback.m_closestHitFraction, but needs testing btScalar hitLambda = btScalar(1.); //could use resultCallback.m_closestHitFraction, but needs testing
btVector3 hitNormal; btVector3 hitNormal;
if (btRayAabb(rayFromWorld,rayToWorld,collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,hitNormal)) if (btRayAabb(convexFromWorld.getOrigin(),convexToWorld.getOrigin(),collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,hitNormal))
{ {
// before testing this object, verify that it is not filtered out objectQuerySingle(castShape, convexFromTrans,convexToTrans,
if (resultCallback.NeedRayCast(collisionObject)) collisionObject,
{ collisionObject->getCollisionShape(),
rayTestSingle(rayFromTrans,rayToTrans, collisionObject->getWorldTransform(),
collisionObject, resultCallback,
collisionObject->getCollisionShape(), getDispatchInfo().m_allowedCcdPenetration);
collisionObject->getWorldTransform(), }
resultCallback,
collisionFilterMask,
faceNormal);
}
}
} }
} }

View File

@@ -68,12 +68,12 @@ class btStackAlloc;
class btCollisionShape; class btCollisionShape;
class btConvexShape; class btConvexShape;
class btBroadphaseInterface; class btBroadphaseInterface;
#include "../../LinearMath/btVector3.h" #include "LinearMath/btVector3.h"
#include "../../LinearMath/btTransform.h" #include "LinearMath/btTransform.h"
#include "btCollisionObject.h" #include "btCollisionObject.h"
#include "btCollisionDispatcher.h" //for definition of btCollisionObjectArray #include "btCollisionDispatcher.h" //for definition of btCollisionObjectArray
#include "../BroadphaseCollision/btOverlappingPairCache.h" #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
#include "../../LinearMath/btAlignedObjectArray.h" #include "LinearMath/btAlignedObjectArray.h"
///CollisionWorld is interface and container for the collision detection ///CollisionWorld is interface and container for the collision detection
class btCollisionWorld class btCollisionWorld
@@ -90,18 +90,22 @@ protected:
btStackAlloc* m_stackAlloc; btStackAlloc* m_stackAlloc;
btOverlappingPairCache* m_broadphasePairCache; btBroadphaseInterface* m_broadphasePairCache;
bool m_ownsDispatcher;
bool m_ownsBroadphasePairCache;
btIDebugDraw* m_debugDrawer;
public: public:
//this constructor doesn't own the dispatcher and paircache/broadphase //this constructor doesn't own the dispatcher and paircache/broadphase
btCollisionWorld(btDispatcher* dispatcher,btOverlappingPairCache* pairCache, int stackSize = 2*1024*1024); btCollisionWorld(btDispatcher* dispatcher,btBroadphaseInterface* broadphasePairCache, btCollisionConfiguration* collisionConfiguration);
virtual ~btCollisionWorld(); virtual ~btCollisionWorld();
void setBroadphase(btBroadphaseInterface* pairCache)
{
m_broadphasePairCache = pairCache;
}
btBroadphaseInterface* getBroadphase() btBroadphaseInterface* getBroadphase()
{ {
@@ -110,7 +114,7 @@ public:
btOverlappingPairCache* getPairCache() btOverlappingPairCache* getPairCache()
{ {
return m_broadphasePairCache; return m_broadphasePairCache->getOverlappingPairCache();
} }
@@ -119,14 +123,32 @@ public:
return m_dispatcher1; return m_dispatcher1;
} }
const btDispatcher* getDispatcher() const
{
return m_dispatcher1;
}
virtual void updateAabbs();
virtual void setDebugDrawer(btIDebugDraw* debugDrawer)
{
m_debugDrawer = debugDrawer;
}
virtual btIDebugDraw* getDebugDrawer()
{
return m_debugDrawer;
}
///LocalShapeInfo gives extra information for complex shapes ///LocalShapeInfo gives extra information for complex shapes
///Currently, only btTriangleMeshShape is available, so it just contains triangleIndex and subpart ///Currently, only btTriangleMeshShape is available, so it just contains triangleIndex and subpart
struct LocalShapeInfo struct LocalShapeInfo
{ {
int m_shapePart; int m_shapePart;
int m_triangleIndex; int m_triangleIndex;
// needed in case of compound shape
const btCollisionShape* m_triangleShape; //const btCollisionShape* m_shapeTemp;
//const btTransform* m_shapeLocalTransform; //const btTransform* m_shapeLocalTransform;
}; };
@@ -153,32 +175,43 @@ public:
///RayResultCallback is used to report new raycast results ///RayResultCallback is used to report new raycast results
struct RayResultCallback struct RayResultCallback
{ {
btScalar m_closestHitFraction;
btCollisionObject* m_collisionObject;
short int m_collisionFilterGroup;
short int m_collisionFilterMask;
virtual ~RayResultCallback() virtual ~RayResultCallback()
{ {
} }
btScalar m_closestHitFraction; bool hasHit() const
bool HasHit()
{ {
return (m_closestHitFraction < btScalar(1.)); return (m_collisionObject != 0);
} }
RayResultCallback() RayResultCallback()
:m_closestHitFraction(btScalar(1.)) :m_closestHitFraction(btScalar(1.)),
m_collisionObject(0),
m_collisionFilterGroup(btBroadphaseProxy::DefaultFilter),
m_collisionFilterMask(btBroadphaseProxy::AllFilter)
{ {
} }
virtual bool NeedRayCast(btCollisionObject* object)
virtual bool needsCollision(btBroadphaseProxy* proxy0) const
{ {
return true; bool collides = (proxy0->m_collisionFilterGroup & m_collisionFilterMask) != 0;
collides = collides && (m_collisionFilterGroup & proxy0->m_collisionFilterMask);
return collides;
} }
virtual btScalar AddSingleResult(LocalRayResult& rayResult) = 0;
virtual btScalar addSingleResult(LocalRayResult& rayResult,bool normalInWorldSpace) = 0;
}; };
struct ClosestRayResultCallback : public RayResultCallback struct ClosestRayResultCallback : public RayResultCallback
{ {
ClosestRayResultCallback(const btVector3& rayFromWorld,const btVector3& rayToWorld) ClosestRayResultCallback(const btVector3& rayFromWorld,const btVector3& rayToWorld)
:m_rayFromWorld(rayFromWorld), :m_rayFromWorld(rayFromWorld),
m_rayToWorld(rayToWorld), m_rayToWorld(rayToWorld)
m_collisionObject(0)
{ {
} }
@@ -187,24 +220,121 @@ public:
btVector3 m_hitNormalWorld; btVector3 m_hitNormalWorld;
btVector3 m_hitPointWorld; btVector3 m_hitPointWorld;
btCollisionObject* m_collisionObject;
virtual btScalar addSingleResult(LocalRayResult& rayResult,bool normalInWorldSpace)
virtual btScalar AddSingleResult(LocalRayResult& rayResult)
{ {
//caller already does the filter on the m_closestHitFraction
//caller already does the filter on the m_closestHitFraction btAssert(rayResult.m_hitFraction <= m_closestHitFraction);
assert(rayResult.m_hitFraction <= m_closestHitFraction);
m_closestHitFraction = rayResult.m_hitFraction; m_closestHitFraction = rayResult.m_hitFraction;
m_collisionObject = rayResult.m_collisionObject; m_collisionObject = rayResult.m_collisionObject;
m_hitNormalWorld = m_collisionObject->getWorldTransform().getBasis()*rayResult.m_hitNormalLocal; if (normalInWorldSpace)
{
m_hitNormalWorld = rayResult.m_hitNormalLocal;
} else
{
///need to transform normal into worldspace
m_hitNormalWorld = m_collisionObject->getWorldTransform().getBasis()*rayResult.m_hitNormalLocal;
}
m_hitPointWorld.setInterpolate3(m_rayFromWorld,m_rayToWorld,rayResult.m_hitFraction); m_hitPointWorld.setInterpolate3(m_rayFromWorld,m_rayToWorld,rayResult.m_hitFraction);
return rayResult.m_hitFraction; return rayResult.m_hitFraction;
} }
}; };
struct LocalConvexResult
{
LocalConvexResult(btCollisionObject* hitCollisionObject,
LocalShapeInfo* localShapeInfo,
const btVector3& hitNormalLocal,
const btVector3& hitPointLocal,
btScalar hitFraction
)
:m_hitCollisionObject(hitCollisionObject),
m_localShapeInfo(localShapeInfo),
m_hitNormalLocal(hitNormalLocal),
m_hitPointLocal(hitPointLocal),
m_hitFraction(hitFraction)
{
}
btCollisionObject* m_hitCollisionObject;
LocalShapeInfo* m_localShapeInfo;
btVector3 m_hitNormalLocal;
btVector3 m_hitPointLocal;
btScalar m_hitFraction;
};
///RayResultCallback is used to report new raycast results
struct ConvexResultCallback
{
btScalar m_closestHitFraction;
short int m_collisionFilterGroup;
short int m_collisionFilterMask;
ConvexResultCallback()
:m_closestHitFraction(btScalar(1.)),
m_collisionFilterGroup(btBroadphaseProxy::DefaultFilter),
m_collisionFilterMask(btBroadphaseProxy::AllFilter)
{
}
virtual ~ConvexResultCallback()
{
}
bool hasHit() const
{
return (m_closestHitFraction < btScalar(1.));
}
virtual bool needsCollision(btBroadphaseProxy* proxy0) const
{
bool collides = (proxy0->m_collisionFilterGroup & m_collisionFilterMask) != 0;
collides = collides && (m_collisionFilterGroup & proxy0->m_collisionFilterMask);
return collides;
}
virtual btScalar addSingleResult(LocalConvexResult& convexResult,bool normalInWorldSpace) = 0;
};
struct ClosestConvexResultCallback : public ConvexResultCallback
{
ClosestConvexResultCallback(const btVector3& convexFromWorld,const btVector3& convexToWorld)
:m_convexFromWorld(convexFromWorld),
m_convexToWorld(convexToWorld),
m_hitCollisionObject(0)
{
}
btVector3 m_convexFromWorld;//used to calculate hitPointWorld from hitFraction
btVector3 m_convexToWorld;
btVector3 m_hitNormalWorld;
btVector3 m_hitPointWorld;
btCollisionObject* m_hitCollisionObject;
virtual btScalar addSingleResult(LocalConvexResult& convexResult,bool normalInWorldSpace)
{
//caller already does the filter on the m_closestHitFraction
btAssert(convexResult.m_hitFraction <= m_closestHitFraction);
m_closestHitFraction = convexResult.m_hitFraction;
m_hitCollisionObject = convexResult.m_hitCollisionObject;
if (normalInWorldSpace)
{
m_hitNormalWorld = convexResult.m_hitNormalLocal;
} else
{
///need to transform normal into worldspace
m_hitNormalWorld = m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal;
}
m_hitPointWorld = convexResult.m_hitPointLocal;
return convexResult.m_hitFraction;
}
};
int getNumCollisionObjects() const int getNumCollisionObjects() const
{ {
@@ -213,7 +343,12 @@ public:
/// rayTest performs a raycast on all objects in the btCollisionWorld, and calls the resultCallback /// rayTest performs a raycast on all objects in the btCollisionWorld, and calls the resultCallback
/// This allows for several queries: first hit, all hits, any hit, dependent on the value returned by the callback. /// This allows for several queries: first hit, all hits, any hit, dependent on the value returned by the callback.
void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback, short int collisionFilterMask=-1, bool faceNormal=false); void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const;
// convexTest performs a swept convex cast on all objects in the btCollisionWorld, and calls the resultCallback
// This allows for several queries: first hit, all hits, any hit, dependent on the value return by the callback.
void convexSweepTest (const btConvexShape* castShape, const btTransform& from, const btTransform& to, ConvexResultCallback& resultCallback) const;
/// rayTestSingle performs a raycast call and calls the resultCallback. It is used internally by rayTest. /// rayTestSingle performs a raycast call and calls the resultCallback. It is used internally by rayTest.
/// In a future implementation, we consider moving the ray test as a virtual method in btCollisionShape. /// In a future implementation, we consider moving the ray test as a virtual method in btCollisionShape.
@@ -222,20 +357,16 @@ public:
btCollisionObject* collisionObject, btCollisionObject* collisionObject,
const btCollisionShape* collisionShape, const btCollisionShape* collisionShape,
const btTransform& colObjWorldTransform, const btTransform& colObjWorldTransform,
RayResultCallback& resultCallback, RayResultCallback& resultCallback);
short int collisionFilterMask=-1,
bool faceNormal=false);
/// objectQuerySingle performs a collision detection query and calls the resultCallback. It is used internally by rayTest. /// objectQuerySingle performs a collision detection query and calls the resultCallback. It is used internally by rayTest.
static void objectQuerySingle(const btConvexShape* castShape, const btTransform& rayFromTrans,const btTransform& rayToTrans, static void objectQuerySingle(const btConvexShape* castShape, const btTransform& rayFromTrans,const btTransform& rayToTrans,
btCollisionObject* collisionObject, btCollisionObject* collisionObject,
const btCollisionShape* collisionShape, const btCollisionShape* collisionShape,
const btTransform& colObjWorldTransform, const btTransform& colObjWorldTransform,
RayResultCallback& resultCallback, ConvexResultCallback& resultCallback, btScalar allowedPenetration);
short int collisionFilterMask=-1,
bool faceNormal=false);
void addCollisionObject(btCollisionObject* collisionObject,short int collisionFilterGroup=1,short int collisionFilterMask=1); void addCollisionObject(btCollisionObject* collisionObject,short int collisionFilterGroup=btBroadphaseProxy::DefaultFilter,short int collisionFilterMask=btBroadphaseProxy::AllFilter);
btCollisionObjectArray& getCollisionObjectArray() btCollisionObjectArray& getCollisionObjectArray()
{ {
@@ -257,6 +388,11 @@ public:
return m_dispatchInfo; return m_dispatchInfo;
} }
const btDispatcherInfo& getDispatchInfo() const
{
return m_dispatchInfo;
}
}; };

View File

@@ -19,7 +19,8 @@ subject to the following restrictions:
btCompoundCollisionAlgorithm::btCompoundCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped) btCompoundCollisionAlgorithm::btCompoundCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped)
:m_isSwapped(isSwapped) :btCollisionAlgorithm(ci),
m_isSwapped(isSwapped)
{ {
btCollisionObject* colObj = m_isSwapped? body1 : body0; btCollisionObject* colObj = m_isSwapped? body1 : body0;
btCollisionObject* otherObj = m_isSwapped? body0 : body1; btCollisionObject* otherObj = m_isSwapped? body0 : body1;
@@ -32,11 +33,11 @@ btCompoundCollisionAlgorithm::btCompoundCollisionAlgorithm( const btCollisionAlg
m_childCollisionAlgorithms.resize(numChildren); m_childCollisionAlgorithms.resize(numChildren);
for (i=0;i<numChildren;i++) for (i=0;i<numChildren;i++)
{ {
btCollisionShape* tmpShape = colObj->getCollisionShape();
btCollisionShape* childShape = compoundShape->getChildShape(i); btCollisionShape* childShape = compoundShape->getChildShape(i);
btCollisionShape* orgShape = colObj->getCollisionShape(); colObj->internalSetTemporaryCollisionShape( childShape );
colObj->setCollisionShape( childShape ); m_childCollisionAlgorithms[i] = ci.m_dispatcher1->findAlgorithm(colObj,otherObj);
m_childCollisionAlgorithms[i] = ci.m_dispatcher->findAlgorithm(colObj,otherObj); colObj->internalSetTemporaryCollisionShape( tmpShape );
colObj->setCollisionShape( orgShape );
} }
} }
@@ -47,7 +48,8 @@ btCompoundCollisionAlgorithm::~btCompoundCollisionAlgorithm()
int i; int i;
for (i=0;i<numChildren;i++) for (i=0;i<numChildren;i++)
{ {
delete m_childCollisionAlgorithms[i]; m_childCollisionAlgorithms[i]->~btCollisionAlgorithm();
m_dispatcher->freeCollisionAlgorithm(m_childCollisionAlgorithms[i]);
} }
} }
@@ -75,17 +77,21 @@ void btCompoundCollisionAlgorithm::processCollision (btCollisionObject* body0,bt
//backup //backup
btTransform orgTrans = colObj->getWorldTransform(); btTransform orgTrans = colObj->getWorldTransform();
btCollisionShape* orgShape = colObj->getCollisionShape(); btTransform orgInterpolationTrans = colObj->getInterpolationWorldTransform();
const btTransform& childTrans = compoundShape->getChildTransform(i); const btTransform& childTrans = compoundShape->getChildTransform(i);
//btTransform newChildWorldTrans = orgTrans*childTrans ; btTransform newChildWorldTrans = orgTrans*childTrans ;
colObj->setWorldTransform( orgTrans*childTrans ); colObj->setWorldTransform( newChildWorldTrans);
colObj->setInterpolationWorldTransform(newChildWorldTrans);
//the contactpoint is still projected back using the original inverted worldtrans //the contactpoint is still projected back using the original inverted worldtrans
colObj->setCollisionShape( childShape ); btCollisionShape* tmpShape = colObj->getCollisionShape();
colObj->internalSetTemporaryCollisionShape( childShape );
m_childCollisionAlgorithms[i]->processCollision(colObj,otherObj,dispatchInfo,resultOut); m_childCollisionAlgorithms[i]->processCollision(colObj,otherObj,dispatchInfo,resultOut);
//revert back //revert back
colObj->setCollisionShape( orgShape); colObj->internalSetTemporaryCollisionShape( tmpShape);
colObj->setWorldTransform( orgTrans ); colObj->setWorldTransform( orgTrans );
colObj->setInterpolationWorldTransform(orgInterpolationTrans);
} }
} }
@@ -117,20 +123,20 @@ btScalar btCompoundCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject*
//backup //backup
btTransform orgTrans = colObj->getWorldTransform(); btTransform orgTrans = colObj->getWorldTransform();
btCollisionShape* orgShape = colObj->getCollisionShape();
const btTransform& childTrans = compoundShape->getChildTransform(i); const btTransform& childTrans = compoundShape->getChildTransform(i);
//btTransform newChildWorldTrans = orgTrans*childTrans ; //btTransform newChildWorldTrans = orgTrans*childTrans ;
colObj->setWorldTransform( orgTrans*childTrans ); colObj->setWorldTransform( orgTrans*childTrans );
colObj->setCollisionShape( childShape ); btCollisionShape* tmpShape = colObj->getCollisionShape();
colObj->internalSetTemporaryCollisionShape( childShape );
btScalar frac = m_childCollisionAlgorithms[i]->calculateTimeOfImpact(colObj,otherObj,dispatchInfo,resultOut); btScalar frac = m_childCollisionAlgorithms[i]->calculateTimeOfImpact(colObj,otherObj,dispatchInfo,resultOut);
if (frac<hitFraction) if (frac<hitFraction)
{ {
hitFraction = frac; hitFraction = frac;
} }
//revert back //revert back
colObj->setCollisionShape( orgShape); colObj->internalSetTemporaryCollisionShape( tmpShape);
colObj->setWorldTransform( orgTrans); colObj->setWorldTransform( orgTrans);
} }
return hitFraction; return hitFraction;

View File

@@ -16,15 +16,16 @@ subject to the following restrictions:
#ifndef COMPOUND_COLLISION_ALGORITHM_H #ifndef COMPOUND_COLLISION_ALGORITHM_H
#define COMPOUND_COLLISION_ALGORITHM_H #define COMPOUND_COLLISION_ALGORITHM_H
#include "../BroadphaseCollision/btCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
#include "../BroadphaseCollision/btDispatcher.h" #include "BulletCollision/BroadphaseCollision/btDispatcher.h"
#include "../BroadphaseCollision/btBroadphaseInterface.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h"
#include "../NarrowPhaseCollision/btPersistentManifold.h" #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
class btDispatcher; class btDispatcher;
#include "../BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
#include "btCollisionCreateFunc.h" #include "btCollisionCreateFunc.h"
#include "../../LinearMath/btAlignedObjectArray.h" #include "LinearMath/btAlignedObjectArray.h"
class btDispatcher;
/// btCompoundCollisionAlgorithm supports collision between CompoundCollisionShapes and other collision shapes /// btCompoundCollisionAlgorithm supports collision between CompoundCollisionShapes and other collision shapes
/// Place holder, not fully implemented yet /// Place holder, not fully implemented yet
@@ -43,11 +44,21 @@ public:
btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut);
virtual void getAllContactManifolds(btManifoldArray& manifoldArray)
{
int i;
for (i=0;i<m_childCollisionAlgorithms.size();i++)
{
m_childCollisionAlgorithms[i]->getAllContactManifolds(manifoldArray);
}
}
struct CreateFunc :public btCollisionAlgorithmCreateFunc struct CreateFunc :public btCollisionAlgorithmCreateFunc
{ {
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1)
{ {
return new btCompoundCollisionAlgorithm(ci,body0,body1,false); void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btCompoundCollisionAlgorithm));
return new(mem) btCompoundCollisionAlgorithm(ci,body0,body1,false);
} }
}; };
@@ -55,7 +66,8 @@ public:
{ {
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1)
{ {
return new btCompoundCollisionAlgorithm(ci,body0,body1,true); void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btCompoundCollisionAlgorithm));
return new(mem) btCompoundCollisionAlgorithm(ci,body0,body1,true);
} }
}; };

View File

@@ -29,7 +29,7 @@ subject to the following restrictions:
btConvexConcaveCollisionAlgorithm::btConvexConcaveCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1,bool isSwapped) btConvexConcaveCollisionAlgorithm::btConvexConcaveCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1,bool isSwapped)
: btCollisionAlgorithm(ci), : btCollisionAlgorithm(ci),
m_isSwapped(isSwapped), m_isSwapped(isSwapped),
m_btConvexTriangleCallback(ci.m_dispatcher,body0,body1,isSwapped) m_btConvexTriangleCallback(ci.m_dispatcher1,body0,body1,isSwapped)
{ {
} }
@@ -37,6 +37,13 @@ btConvexConcaveCollisionAlgorithm::~btConvexConcaveCollisionAlgorithm()
{ {
} }
void btConvexConcaveCollisionAlgorithm::getAllContactManifolds(btManifoldArray& manifoldArray)
{
if (m_btConvexTriangleCallback.m_manifoldPtr)
{
manifoldArray.push_back(m_btConvexTriangleCallback.m_manifoldPtr);
}
}
btConvexTriangleCallback::btConvexTriangleCallback(btDispatcher* dispatcher,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped): btConvexTriangleCallback::btConvexTriangleCallback(btDispatcher* dispatcher,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped):
@@ -79,7 +86,7 @@ void btConvexTriangleCallback::processTriangle(btVector3* triangle,int partId, i
//aabb filter is already applied! //aabb filter is already applied!
btCollisionAlgorithmConstructionInfo ci; btCollisionAlgorithmConstructionInfo ci;
ci.m_dispatcher = m_dispatcher; ci.m_dispatcher1 = m_dispatcher;
btCollisionObject* ob = static_cast<btCollisionObject*>(m_triBody); btCollisionObject* ob = static_cast<btCollisionObject*>(m_triBody);
@@ -109,13 +116,11 @@ void btConvexTriangleCallback::processTriangle(btVector3* triangle,int partId, i
{ {
btTriangleShape tm(triangle[0],triangle[1],triangle[2]); btTriangleShape tm(triangle[0],triangle[1],triangle[2]);
tm.setMargin(m_collisionMarginTriangle); tm.setMargin(m_collisionMarginTriangle);
btCollisionShape* tmpShape = ob->getCollisionShape(); btCollisionShape* tmpShape = ob->getCollisionShape();
ob->setCollisionShape( &tm ); ob->internalSetTemporaryCollisionShape( &tm );
btCollisionAlgorithm* colAlgo = ci.m_dispatcher1->findAlgorithm(m_convexBody,m_triBody,m_manifoldPtr);
btCollisionAlgorithm* colAlgo = ci.m_dispatcher->findAlgorithm(m_convexBody,m_triBody,m_manifoldPtr);
///this should use the btDispatcher, so the actual registered algorithm is used ///this should use the btDispatcher, so the actual registered algorithm is used
// btConvexConvexAlgorithm cvxcvxalgo(m_manifoldPtr,ci,m_convexBody,m_triBody); // btConvexConvexAlgorithm cvxcvxalgo(m_manifoldPtr,ci,m_convexBody,m_triBody);
@@ -123,12 +128,11 @@ void btConvexTriangleCallback::processTriangle(btVector3* triangle,int partId, i
// cvxcvxalgo.setShapeIdentifiers(-1,-1,partId,triangleIndex); // cvxcvxalgo.setShapeIdentifiers(-1,-1,partId,triangleIndex);
// cvxcvxalgo.processCollision(m_convexBody,m_triBody,*m_dispatchInfoPtr,m_resultOut); // cvxcvxalgo.processCollision(m_convexBody,m_triBody,*m_dispatchInfoPtr,m_resultOut);
colAlgo->processCollision(m_convexBody,m_triBody,*m_dispatchInfoPtr,m_resultOut); colAlgo->processCollision(m_convexBody,m_triBody,*m_dispatchInfoPtr,m_resultOut);
delete colAlgo; colAlgo->~btCollisionAlgorithm();
ob->setCollisionShape( tmpShape ); ci.m_dispatcher1->freeCollisionAlgorithm(colAlgo);
ob->internalSetTemporaryCollisionShape( tmpShape);
} }
} }
@@ -188,9 +192,10 @@ void btConvexConcaveCollisionAlgorithm::processCollision (btCollisionObject* bod
concaveShape->processAllTriangles( &m_btConvexTriangleCallback,m_btConvexTriangleCallback.getAabbMin(),m_btConvexTriangleCallback.getAabbMax()); concaveShape->processAllTriangles( &m_btConvexTriangleCallback,m_btConvexTriangleCallback.getAabbMin(),m_btConvexTriangleCallback.getAabbMax());
resultOut->refreshContactPoints();
} }
} }
} }

View File

@@ -16,13 +16,13 @@ subject to the following restrictions:
#ifndef CONVEX_CONCAVE_COLLISION_ALGORITHM_H #ifndef CONVEX_CONCAVE_COLLISION_ALGORITHM_H
#define CONVEX_CONCAVE_COLLISION_ALGORITHM_H #define CONVEX_CONCAVE_COLLISION_ALGORITHM_H
#include "../BroadphaseCollision/btCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
#include "../BroadphaseCollision/btDispatcher.h" #include "BulletCollision/BroadphaseCollision/btDispatcher.h"
#include "../BroadphaseCollision/btBroadphaseInterface.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h"
#include "../CollisionShapes/btTriangleCallback.h" #include "BulletCollision/CollisionShapes/btTriangleCallback.h"
#include "../NarrowPhaseCollision/btPersistentManifold.h" #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
class btDispatcher; class btDispatcher;
#include "../BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
#include "btCollisionCreateFunc.h" #include "btCollisionCreateFunc.h"
///For each triangle in the concave mesh that overlaps with the AABB of a convex (m_convexProxy), processTriangle is called. ///For each triangle in the concave mesh that overlaps with the AABB of a convex (m_convexProxy), processTriangle is called.
@@ -55,11 +55,11 @@ int m_triangleCount;
void clearCache(); void clearCache();
inline const btVector3& getAabbMin() const SIMD_FORCE_INLINE const btVector3& getAabbMin() const
{ {
return m_aabbMin; return m_aabbMin;
} }
inline const btVector3& getAabbMax() const SIMD_FORCE_INLINE const btVector3& getAabbMax() const
{ {
return m_aabbMax; return m_aabbMax;
} }
@@ -88,13 +88,16 @@ public:
btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut);
virtual void getAllContactManifolds(btManifoldArray& manifoldArray);
void clearCache(); void clearCache();
struct CreateFunc :public btCollisionAlgorithmCreateFunc struct CreateFunc :public btCollisionAlgorithmCreateFunc
{ {
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1)
{ {
return new btConvexConcaveCollisionAlgorithm(ci,body0,body1,false); void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexConcaveCollisionAlgorithm));
return new(mem) btConvexConcaveCollisionAlgorithm(ci,body0,body1,false);
} }
}; };
@@ -102,7 +105,8 @@ public:
{ {
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1)
{ {
return new btConvexConcaveCollisionAlgorithm(ci,body0,body1,true); void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexConcaveCollisionAlgorithm));
return new(mem) btConvexConcaveCollisionAlgorithm(ci,body0,body1,true);
} }
}; };

View File

@@ -15,7 +15,7 @@ subject to the following restrictions:
#include "btConvexConvexAlgorithm.h" #include "btConvexConvexAlgorithm.h"
#include <stdio.h> //#include <stdio.h>
#include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" #include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h"
#include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h"
#include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h"
@@ -33,7 +33,6 @@ subject to the following restrictions:
#include "BulletCollision/CollisionShapes/btMinkowskiSumShape.h"
#include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h"
#include "BulletCollision/CollisionShapes/btSphereShape.h" #include "BulletCollision/CollisionShapes/btSphereShape.h"
@@ -48,26 +47,16 @@ subject to the following restrictions:
btConvexConvexAlgorithm::CreateFunc::CreateFunc()
{
m_ownsSolvers = true;
m_simplexSolver = new btVoronoiSimplexSolver();
m_pdSolver = new btGjkEpaPenetrationDepthSolver;
}
btConvexConvexAlgorithm::CreateFunc::CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver) btConvexConvexAlgorithm::CreateFunc::CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver)
{ {
m_ownsSolvers = false;
m_simplexSolver = simplexSolver; m_simplexSolver = simplexSolver;
m_pdSolver = pdSolver; m_pdSolver = pdSolver;
} }
btConvexConvexAlgorithm::CreateFunc::~CreateFunc() btConvexConvexAlgorithm::CreateFunc::~CreateFunc()
{ {
if (m_ownsSolvers){
delete m_simplexSolver;
delete m_pdSolver;
}
} }
btConvexConvexAlgorithm::btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver) btConvexConvexAlgorithm::btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver)
@@ -152,6 +141,11 @@ void btConvexConvexAlgorithm ::processCollision (btCollisionObject* body0,btColl
m_gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); m_gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw);
#endif #endif
if (m_ownManifold)
{
resultOut->refreshContactPoints();
}
} }

View File

@@ -16,12 +16,13 @@ subject to the following restrictions:
#ifndef CONVEX_CONVEX_ALGORITHM_H #ifndef CONVEX_CONVEX_ALGORITHM_H
#define CONVEX_CONVEX_ALGORITHM_H #define CONVEX_CONVEX_ALGORITHM_H
#include "../BroadphaseCollision/btCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
#include "../NarrowPhaseCollision/btGjkPairDetector.h" #include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h"
#include "../NarrowPhaseCollision/btPersistentManifold.h" #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
#include "../BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
#include "../NarrowPhaseCollision/btVoronoiSimplexSolver.h" #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h"
#include "btCollisionCreateFunc.h" #include "btCollisionCreateFunc.h"
#include "btCollisionDispatcher.h"
class btConvexPenetrationDepthSolver; class btConvexPenetrationDepthSolver;
@@ -46,6 +47,14 @@ public:
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut);
virtual void getAllContactManifolds(btManifoldArray& manifoldArray)
{
///should we use m_ownManifold to avoid adding duplicates?
if (m_manifoldPtr && m_ownManifold)
manifoldArray.push_back(m_manifoldPtr);
}
void setLowLevelOfDetail(bool useLowLevel); void setLowLevelOfDetail(bool useLowLevel);
@@ -58,15 +67,15 @@ public:
{ {
btConvexPenetrationDepthSolver* m_pdSolver; btConvexPenetrationDepthSolver* m_pdSolver;
btSimplexSolverInterface* m_simplexSolver; btSimplexSolverInterface* m_simplexSolver;
bool m_ownsSolvers;
CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver); CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver);
CreateFunc();
virtual ~CreateFunc(); virtual ~CreateFunc();
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1)
{ {
return new btConvexConvexAlgorithm(ci.m_manifold,ci,body0,body1,m_simplexSolver,m_pdSolver); void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexConvexAlgorithm));
return new(mem) btConvexConvexAlgorithm(ci.m_manifold,ci,body0,body1,m_simplexSolver,m_pdSolver);
} }
}; };

View File

@@ -0,0 +1,108 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "btConvexPlaneCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
#include "BulletCollision/CollisionShapes/btConvexShape.h"
#include "BulletCollision/CollisionShapes/btStaticPlaneShape.h"
//#include <stdio.h>
btConvexPlaneCollisionAlgorithm::btConvexPlaneCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped)
: btCollisionAlgorithm(ci),
m_ownManifold(false),
m_manifoldPtr(mf),
m_isSwapped(isSwapped)
{
btCollisionObject* convexObj = m_isSwapped? col1 : col0;
btCollisionObject* planeObj = m_isSwapped? col0 : col1;
if (!m_manifoldPtr && m_dispatcher->needsCollision(convexObj,planeObj))
{
m_manifoldPtr = m_dispatcher->getNewManifold(convexObj,planeObj);
m_ownManifold = true;
}
}
btConvexPlaneCollisionAlgorithm::~btConvexPlaneCollisionAlgorithm()
{
if (m_ownManifold)
{
if (m_manifoldPtr)
m_dispatcher->releaseManifold(m_manifoldPtr);
}
}
void btConvexPlaneCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)
{
(void)dispatchInfo;
(void)resultOut;
if (!m_manifoldPtr)
return;
btCollisionObject* convexObj = m_isSwapped? body1 : body0;
btCollisionObject* planeObj = m_isSwapped? body0: body1;
btConvexShape* convexShape = (btConvexShape*) convexObj->getCollisionShape();
btStaticPlaneShape* planeShape = (btStaticPlaneShape*) planeObj->getCollisionShape();
bool hasCollision = false;
const btVector3& planeNormal = planeShape->getPlaneNormal();
const btScalar& planeConstant = planeShape->getPlaneConstant();
btTransform planeInConvex;
planeInConvex= convexObj->getWorldTransform().inverse() * planeObj->getWorldTransform();
btTransform convexInPlaneTrans;
convexInPlaneTrans= planeObj->getWorldTransform().inverse() * convexObj->getWorldTransform();
btVector3 vtx = convexShape->localGetSupportingVertex(planeInConvex.getBasis()*-planeNormal);
btVector3 vtxInPlane = convexInPlaneTrans(vtx);
btScalar distance = (planeNormal.dot(vtxInPlane) - planeConstant);
btVector3 vtxInPlaneProjected = vtxInPlane - distance*planeNormal;
btVector3 vtxInPlaneWorld = planeObj->getWorldTransform() * vtxInPlaneProjected;
hasCollision = distance < m_manifoldPtr->getContactBreakingThreshold();
resultOut->setPersistentManifold(m_manifoldPtr);
if (hasCollision)
{
/// report a contact. internally this will be kept persistent, and contact reduction is done
btVector3 normalOnSurfaceB = planeObj->getWorldTransform().getBasis() * planeNormal;
btVector3 pOnB = vtxInPlaneWorld;
resultOut->addContactPoint(normalOnSurfaceB,pOnB,distance);
}
if (m_ownManifold)
{
if (m_manifoldPtr->getNumContacts())
{
resultOut->refreshContactPoints();
}
}
}
btScalar btConvexPlaneCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)
{
(void)resultOut;
(void)dispatchInfo;
(void)col0;
(void)col1;
//not yet
return btScalar(1.);
}

View File

@@ -0,0 +1,71 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef CONVEX_PLANE_COLLISION_ALGORITHM_H
#define CONVEX_PLANE_COLLISION_ALGORITHM_H
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
#include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h"
class btPersistentManifold;
#include "btCollisionDispatcher.h"
#include "LinearMath/btVector3.h"
/// btSphereBoxCollisionAlgorithm provides sphere-box collision detection.
/// Other features are frame-coherency (persistent data) and collision response.
class btConvexPlaneCollisionAlgorithm : public btCollisionAlgorithm
{
bool m_ownManifold;
btPersistentManifold* m_manifoldPtr;
bool m_isSwapped;
public:
btConvexPlaneCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped);
virtual ~btConvexPlaneCollisionAlgorithm();
virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut);
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut);
virtual void getAllContactManifolds(btManifoldArray& manifoldArray)
{
if (m_manifoldPtr && m_ownManifold)
{
manifoldArray.push_back(m_manifoldPtr);
}
}
struct CreateFunc :public btCollisionAlgorithmCreateFunc
{
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1)
{
void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexPlaneCollisionAlgorithm));
if (!m_swapped)
{
return new(mem) btConvexPlaneCollisionAlgorithm(0,ci,body0,body1,false);
} else
{
return new(mem) btConvexPlaneCollisionAlgorithm(0,ci,body0,body1,true);
}
}
};
};
#endif //CONVEX_PLANE_COLLISION_ALGORITHM_H

View File

@@ -0,0 +1,281 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "btDefaultCollisionConfiguration.h"
#include "BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h"
#include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h"
#include "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h"
#include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h"
#include "LinearMath/btStackAlloc.h"
#include "LinearMath/btPoolAllocator.h"
btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(const btDefaultCollisionConstructionInfo& constructionInfo)
//btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(btStackAlloc* stackAlloc,btPoolAllocator* persistentManifoldPool,btPoolAllocator* collisionAlgorithmPool)
{
void* mem = btAlignedAlloc(sizeof(btVoronoiSimplexSolver),16);
m_simplexSolver = new (mem)btVoronoiSimplexSolver();
#define USE_EPA 1
#ifdef USE_EPA
mem = btAlignedAlloc(sizeof(btGjkEpaPenetrationDepthSolver),16);
m_pdSolver = new (mem)btGjkEpaPenetrationDepthSolver;
#else
mem = btAlignedAlloc(sizeof(btMinkowskiPenetrationDepthSolver),16);
m_pdSolver = new (mem)btMinkowskiPenetrationDepthSolver;
#endif//USE_EPA
//default CreationFunctions, filling the m_doubleDispatch table
mem = btAlignedAlloc(sizeof(btConvexConvexAlgorithm::CreateFunc),16);
m_convexConvexCreateFunc = new(mem) btConvexConvexAlgorithm::CreateFunc(m_simplexSolver,m_pdSolver);
mem = btAlignedAlloc(sizeof(btConvexConcaveCollisionAlgorithm::CreateFunc),16);
m_convexConcaveCreateFunc = new (mem)btConvexConcaveCollisionAlgorithm::CreateFunc;
mem = btAlignedAlloc(sizeof(btConvexConcaveCollisionAlgorithm::CreateFunc),16);
m_swappedConvexConcaveCreateFunc = new (mem)btConvexConcaveCollisionAlgorithm::SwappedCreateFunc;
mem = btAlignedAlloc(sizeof(btCompoundCollisionAlgorithm::CreateFunc),16);
m_compoundCreateFunc = new (mem)btCompoundCollisionAlgorithm::CreateFunc;
mem = btAlignedAlloc(sizeof(btCompoundCollisionAlgorithm::SwappedCreateFunc),16);
m_swappedCompoundCreateFunc = new (mem)btCompoundCollisionAlgorithm::SwappedCreateFunc;
mem = btAlignedAlloc(sizeof(btEmptyAlgorithm::CreateFunc),16);
m_emptyCreateFunc = new(mem) btEmptyAlgorithm::CreateFunc;
mem = btAlignedAlloc(sizeof(btSphereSphereCollisionAlgorithm::CreateFunc),16);
m_sphereSphereCF = new(mem) btSphereSphereCollisionAlgorithm::CreateFunc;
mem = btAlignedAlloc(sizeof(btSphereBoxCollisionAlgorithm::CreateFunc),16);
m_sphereBoxCF = new(mem) btSphereBoxCollisionAlgorithm::CreateFunc;
mem = btAlignedAlloc(sizeof(btSphereBoxCollisionAlgorithm::CreateFunc),16);
m_boxSphereCF = new (mem)btSphereBoxCollisionAlgorithm::CreateFunc;
m_boxSphereCF->m_swapped = true;
mem = btAlignedAlloc(sizeof(btSphereTriangleCollisionAlgorithm::CreateFunc),16);
m_sphereTriangleCF = new (mem)btSphereTriangleCollisionAlgorithm::CreateFunc;
mem = btAlignedAlloc(sizeof(btSphereTriangleCollisionAlgorithm::CreateFunc),16);
m_triangleSphereCF = new (mem)btSphereTriangleCollisionAlgorithm::CreateFunc;
m_triangleSphereCF->m_swapped = true;
mem = btAlignedAlloc(sizeof(btBoxBoxCollisionAlgorithm::CreateFunc),16);
m_boxBoxCF = new(mem)btBoxBoxCollisionAlgorithm::CreateFunc;
//convex versus plane
mem = btAlignedAlloc (sizeof(btConvexPlaneCollisionAlgorithm::CreateFunc),16);
m_convexPlaneCF = new (mem) btConvexPlaneCollisionAlgorithm::CreateFunc;
mem = btAlignedAlloc (sizeof(btConvexPlaneCollisionAlgorithm::CreateFunc),16);
m_planeConvexCF = new (mem) btConvexPlaneCollisionAlgorithm::CreateFunc;
m_planeConvexCF->m_swapped = true;
///calculate maximum element size, big enough to fit any collision algorithm in the memory pool
int maxSize = sizeof(btConvexConvexAlgorithm);
int maxSize2 = sizeof(btConvexConcaveCollisionAlgorithm);
int maxSize3 = sizeof(btCompoundCollisionAlgorithm);
int maxSize4 = sizeof(btEmptyAlgorithm);
int collisionAlgorithmMaxElementSize = btMax(maxSize,maxSize2);
collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize3);
collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize4);
if (constructionInfo.m_stackAlloc)
{
m_ownsStackAllocator = false;
this->m_stackAlloc = constructionInfo.m_stackAlloc;
} else
{
m_ownsStackAllocator = true;
void* mem = btAlignedAlloc(sizeof(btStackAlloc),16);
m_stackAlloc = new(mem)btStackAlloc(constructionInfo.m_defaultStackAllocatorSize);
}
if (constructionInfo.m_persistentManifoldPool)
{
m_ownsPersistentManifoldPool = false;
m_persistentManifoldPool = constructionInfo.m_persistentManifoldPool;
} else
{
m_ownsPersistentManifoldPool = true;
void* mem = btAlignedAlloc(sizeof(btPoolAllocator),16);
m_persistentManifoldPool = new (mem) btPoolAllocator(sizeof(btPersistentManifold),constructionInfo.m_defaultMaxPersistentManifoldPoolSize);
}
if (constructionInfo.m_collisionAlgorithmPool)
{
m_ownsCollisionAlgorithmPool = false;
m_collisionAlgorithmPool = constructionInfo.m_collisionAlgorithmPool;
} else
{
m_ownsCollisionAlgorithmPool = true;
void* mem = btAlignedAlloc(sizeof(btPoolAllocator),16);
m_collisionAlgorithmPool = new(mem) btPoolAllocator(collisionAlgorithmMaxElementSize,constructionInfo.m_defaultMaxCollisionAlgorithmPoolSize);
}
}
btDefaultCollisionConfiguration::~btDefaultCollisionConfiguration()
{
if (m_ownsStackAllocator)
{
m_stackAlloc->destroy();
m_stackAlloc->~btStackAlloc();
btAlignedFree(m_stackAlloc);
}
if (m_ownsCollisionAlgorithmPool)
{
m_collisionAlgorithmPool->~btPoolAllocator();
btAlignedFree(m_collisionAlgorithmPool);
}
if (m_ownsPersistentManifoldPool)
{
m_persistentManifoldPool->~btPoolAllocator();
btAlignedFree(m_persistentManifoldPool);
}
m_convexConvexCreateFunc->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_convexConvexCreateFunc);
m_convexConcaveCreateFunc->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_convexConcaveCreateFunc);
m_swappedConvexConcaveCreateFunc->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_swappedConvexConcaveCreateFunc);
m_compoundCreateFunc->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_compoundCreateFunc);
m_swappedCompoundCreateFunc->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_swappedCompoundCreateFunc);
m_emptyCreateFunc->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_emptyCreateFunc);
m_sphereSphereCF->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_sphereSphereCF);
m_sphereBoxCF->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_sphereBoxCF);
m_boxSphereCF->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_boxSphereCF);
m_sphereTriangleCF->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_sphereTriangleCF);
m_triangleSphereCF->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_triangleSphereCF);
m_boxBoxCF->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_boxBoxCF);
m_convexPlaneCF->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_convexPlaneCF);
m_planeConvexCF->~btCollisionAlgorithmCreateFunc();
btAlignedFree( m_planeConvexCF);
m_simplexSolver->~btVoronoiSimplexSolver();
btAlignedFree(m_simplexSolver);
m_pdSolver->~btConvexPenetrationDepthSolver();
btAlignedFree(m_pdSolver);
}
btCollisionAlgorithmCreateFunc* btDefaultCollisionConfiguration::getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1)
{
if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE) && (proxyType1==SPHERE_SHAPE_PROXYTYPE))
{
return m_sphereSphereCF;
}
if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE) && (proxyType1==BOX_SHAPE_PROXYTYPE))
{
return m_sphereBoxCF;
}
if ((proxyType0 == BOX_SHAPE_PROXYTYPE ) && (proxyType1==SPHERE_SHAPE_PROXYTYPE))
{
return m_boxSphereCF;
}
if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE ) && (proxyType1==TRIANGLE_SHAPE_PROXYTYPE))
{
return m_sphereTriangleCF;
}
if ((proxyType0 == TRIANGLE_SHAPE_PROXYTYPE ) && (proxyType1==SPHERE_SHAPE_PROXYTYPE))
{
return m_triangleSphereCF;
}
if ((proxyType0 == BOX_SHAPE_PROXYTYPE) && (proxyType1 == BOX_SHAPE_PROXYTYPE))
{
return m_boxBoxCF;
}
if (btBroadphaseProxy::isConvex(proxyType0) && (proxyType1 == STATIC_PLANE_PROXYTYPE))
{
return m_convexPlaneCF;
}
if (btBroadphaseProxy::isConvex(proxyType1) && (proxyType0 == STATIC_PLANE_PROXYTYPE))
{
return m_planeConvexCF;
}
if (btBroadphaseProxy::isConvex(proxyType0) && btBroadphaseProxy::isConvex(proxyType1))
{
return m_convexConvexCreateFunc;
}
if (btBroadphaseProxy::isConvex(proxyType0) && btBroadphaseProxy::isConcave(proxyType1))
{
return m_convexConcaveCreateFunc;
}
if (btBroadphaseProxy::isConvex(proxyType1) && btBroadphaseProxy::isConcave(proxyType0))
{
return m_swappedConvexConcaveCreateFunc;
}
if (btBroadphaseProxy::isCompound(proxyType0))
{
return m_compoundCreateFunc;
} else
{
if (btBroadphaseProxy::isCompound(proxyType1))
{
return m_swappedCompoundCreateFunc;
}
}
//failed to find an algorithm
return m_emptyCreateFunc;
}

View File

@@ -0,0 +1,112 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_DEFAULT_COLLISION_CONFIGURATION
#define BT_DEFAULT_COLLISION_CONFIGURATION
#include "btCollisionConfiguration.h"
class btVoronoiSimplexSolver;
class btConvexPenetrationDepthSolver;
struct btDefaultCollisionConstructionInfo
{
btStackAlloc* m_stackAlloc;
btPoolAllocator* m_persistentManifoldPool;
btPoolAllocator* m_collisionAlgorithmPool;
int m_defaultMaxPersistentManifoldPoolSize;
int m_defaultMaxCollisionAlgorithmPoolSize;
int m_defaultStackAllocatorSize;
btDefaultCollisionConstructionInfo()
:m_stackAlloc(0),
m_persistentManifoldPool(0),
m_collisionAlgorithmPool(0),
m_defaultMaxPersistentManifoldPoolSize(65535),
m_defaultMaxCollisionAlgorithmPoolSize(65535),
m_defaultStackAllocatorSize(5*1024*1024)
{
}
};
///btCollisionConfiguration allows to configure Bullet collision detection
///stack allocator, pool memory allocators
///todo: describe the meaning
class btDefaultCollisionConfiguration : public btCollisionConfiguration
{
int m_persistentManifoldPoolSize;
btStackAlloc* m_stackAlloc;
bool m_ownsStackAllocator;
btPoolAllocator* m_persistentManifoldPool;
bool m_ownsPersistentManifoldPool;
btPoolAllocator* m_collisionAlgorithmPool;
bool m_ownsCollisionAlgorithmPool;
//default simplex/penetration depth solvers
btVoronoiSimplexSolver* m_simplexSolver;
btConvexPenetrationDepthSolver* m_pdSolver;
//default CreationFunctions, filling the m_doubleDispatch table
btCollisionAlgorithmCreateFunc* m_convexConvexCreateFunc;
btCollisionAlgorithmCreateFunc* m_convexConcaveCreateFunc;
btCollisionAlgorithmCreateFunc* m_swappedConvexConcaveCreateFunc;
btCollisionAlgorithmCreateFunc* m_compoundCreateFunc;
btCollisionAlgorithmCreateFunc* m_swappedCompoundCreateFunc;
btCollisionAlgorithmCreateFunc* m_emptyCreateFunc;
btCollisionAlgorithmCreateFunc* m_sphereSphereCF;
btCollisionAlgorithmCreateFunc* m_sphereBoxCF;
btCollisionAlgorithmCreateFunc* m_boxSphereCF;
btCollisionAlgorithmCreateFunc* m_boxBoxCF;
btCollisionAlgorithmCreateFunc* m_sphereTriangleCF;
btCollisionAlgorithmCreateFunc* m_triangleSphereCF;
btCollisionAlgorithmCreateFunc* m_planeConvexCF;
btCollisionAlgorithmCreateFunc* m_convexPlaneCF;
public:
btDefaultCollisionConfiguration(const btDefaultCollisionConstructionInfo& constructionInfo = btDefaultCollisionConstructionInfo());
virtual ~btDefaultCollisionConfiguration();
///memory pools
virtual btPoolAllocator* getPersistentManifoldPool()
{
return m_persistentManifoldPool;
}
virtual btPoolAllocator* getCollisionAlgorithmPool()
{
return m_collisionAlgorithmPool;
}
virtual btStackAlloc* getStackAllocator()
{
return m_stackAlloc;
}
virtual btCollisionAlgorithmCreateFunc* getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1);
};
#endif //BT_DEFAULT_COLLISION_CONFIGURATION

View File

@@ -15,8 +15,9 @@ subject to the following restrictions:
#ifndef EMPTY_ALGORITH #ifndef EMPTY_ALGORITH
#define EMPTY_ALGORITH #define EMPTY_ALGORITH
#include "../BroadphaseCollision/btCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
#include "btCollisionCreateFunc.h" #include "btCollisionCreateFunc.h"
#include "btCollisionDispatcher.h"
#define ATTRIBUTE_ALIGNED(a) #define ATTRIBUTE_ALIGNED(a)
@@ -33,13 +34,18 @@ public:
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut);
virtual void getAllContactManifolds(btManifoldArray& manifoldArray)
{
}
struct CreateFunc :public btCollisionAlgorithmCreateFunc struct CreateFunc :public btCollisionAlgorithmCreateFunc
{ {
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1)
{ {
(void)body0; (void)body0;
(void)body1; (void)body1;
return new btEmptyAlgorithm(ci); void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btEmptyAlgorithm));
return new(mem) btEmptyAlgorithm(ci);
} }
}; };

View File

@@ -79,12 +79,30 @@ void btManifoldResult::addContactPoint(const btVector3& normalOnBInWorld,const b
} }
btManifoldPoint newPt(localA,localB,normalOnBInWorld,depth); btManifoldPoint newPt(localA,localB,normalOnBInWorld,depth);
newPt.m_positionWorldOnA = pointA;
newPt.m_positionWorldOnB = pointInWorld;
int insertIndex = m_manifoldPtr->getCacheEntry(newPt); int insertIndex = m_manifoldPtr->getCacheEntry(newPt);
newPt.m_combinedFriction = calculateCombinedFriction(m_body0,m_body1); newPt.m_combinedFriction = calculateCombinedFriction(m_body0,m_body1);
newPt.m_combinedRestitution = calculateCombinedRestitution(m_body0,m_body1); newPt.m_combinedRestitution = calculateCombinedRestitution(m_body0,m_body1);
//BP mod, store contact triangles.
newPt.m_partId0 = m_partId0;
newPt.m_partId1 = m_partId1;
newPt.m_index0 = m_index0;
newPt.m_index1 = m_index1;
///todo, check this for any side effects
if (insertIndex >= 0)
{
//const btManifoldPoint& oldPoint = m_manifoldPtr->getContactPoint(insertIndex);
m_manifoldPtr->replaceContactPoint(newPt,insertIndex);
} else
{
insertIndex = m_manifoldPtr->addManifoldPoint(newPt);
}
//User can override friction and/or restitution //User can override friction and/or restitution
if (gContactAddedCallback && if (gContactAddedCallback &&
//and if either of the two bodies requires custom material //and if either of the two bodies requires custom material
@@ -94,16 +112,8 @@ void btManifoldResult::addContactPoint(const btVector3& normalOnBInWorld,const b
//experimental feature info, for per-triangle material etc. //experimental feature info, for per-triangle material etc.
btCollisionObject* obj0 = isSwapped? m_body1 : m_body0; btCollisionObject* obj0 = isSwapped? m_body1 : m_body0;
btCollisionObject* obj1 = isSwapped? m_body0 : m_body1; btCollisionObject* obj1 = isSwapped? m_body0 : m_body1;
(*gContactAddedCallback)(newPt,obj0,m_partId0,m_index0,obj1,m_partId1,m_index1); (*gContactAddedCallback)(m_manifoldPtr->getContactPoint(insertIndex),obj0,m_partId0,m_index0,obj1,m_partId1,m_index1);
} }
if (insertIndex >= 0)
{
//const btManifoldPoint& oldPoint = m_manifoldPtr->getContactPoint(insertIndex);
m_manifoldPtr->replaceContactPoint(newPt,insertIndex);
} else
{
m_manifoldPtr->AddManifoldPoint(newPt);
}
} }

View File

@@ -18,12 +18,12 @@ subject to the following restrictions:
#define MANIFOLD_RESULT_H #define MANIFOLD_RESULT_H
class btCollisionObject; class btCollisionObject;
class btPersistentManifold; #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
class btManifoldPoint; class btManifoldPoint;
#include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" #include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h"
#include "../../LinearMath/btTransform.h" #include "LinearMath/btTransform.h"
typedef bool (*ContactAddedCallback)(btManifoldPoint& cp, const btCollisionObject* colObj0,int partId0,int index0,const btCollisionObject* colObj1,int partId1,int index1); typedef bool (*ContactAddedCallback)(btManifoldPoint& cp, const btCollisionObject* colObj0,int partId0,int index0,const btCollisionObject* colObj1,int partId1,int index1);
extern ContactAddedCallback gContactAddedCallback; extern ContactAddedCallback gContactAddedCallback;
@@ -60,6 +60,15 @@ public:
m_manifoldPtr = manifoldPtr; m_manifoldPtr = manifoldPtr;
} }
const btPersistentManifold* getPersistentManifold() const
{
return m_manifoldPtr;
}
btPersistentManifold* getPersistentManifold()
{
return m_manifoldPtr;
}
virtual void setShapeIdentifiers(int partId0,int index0, int partId1,int index1) virtual void setShapeIdentifiers(int partId0,int index0, int partId1,int index1)
{ {
m_partId0=partId0; m_partId0=partId0;
@@ -70,6 +79,22 @@ public:
virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth); virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth);
SIMD_FORCE_INLINE void refreshContactPoints()
{
btAssert(m_manifoldPtr);
if (!m_manifoldPtr->getNumContacts())
return;
bool isSwapped = m_manifoldPtr->getBody0() != m_body0;
if (isSwapped)
{
m_manifoldPtr->refreshContactPoints(m_rootTransB,m_rootTransA);
} else
{
m_manifoldPtr->refreshContactPoints(m_rootTransA,m_rootTransB);
}
}
}; };

View File

@@ -1,3 +1,17 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "LinearMath/btScalar.h" #include "LinearMath/btScalar.h"
@@ -7,7 +21,7 @@
#include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h"
#include "BulletCollision/CollisionDispatch/btCollisionWorld.h" #include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
#include <stdio.h> //#include <stdio.h>
#include "LinearMath/btQuickprof.h" #include "LinearMath/btQuickprof.h"
btSimulationIslandManager::btSimulationIslandManager() btSimulationIslandManager::btSimulationIslandManager()
@@ -25,17 +39,17 @@ void btSimulationIslandManager::initUnionFind(int n)
} }
void btSimulationIslandManager::findUnions(btDispatcher* dispatcher) void btSimulationIslandManager::findUnions(btDispatcher* /* dispatcher */,btCollisionWorld* colWorld)
{ {
{ {
for (int i=0;i<dispatcher->getNumManifolds();i++) btBroadphasePair* pairPtr = colWorld->getPairCache()->getOverlappingPairArrayPtr();
{
const btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal(i);
//static objects (invmass btScalar(0.)) don't merge !
const btCollisionObject* colObj0 = static_cast<const btCollisionObject*>(manifold->getBody0()); for (int i=0;i<colWorld->getPairCache()->getNumOverlappingPairs();i++)
const btCollisionObject* colObj1 = static_cast<const btCollisionObject*>(manifold->getBody1()); {
const btBroadphasePair& collisionPair = pairPtr[i];
btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject;
btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject;
if (((colObj0) && ((colObj0)->mergesSimulationIslands())) && if (((colObj0) && ((colObj0)->mergesSimulationIslands())) &&
((colObj1) && ((colObj1)->mergesSimulationIslands()))) ((colObj1) && ((colObj1)->mergesSimulationIslands())))
@@ -71,7 +85,7 @@ void btSimulationIslandManager::updateActivationState(btCollisionWorld* colWorld
} }
// do the union find // do the union find
findUnions(dispatcher); findUnions(dispatcher,colWorld);
@@ -129,30 +143,13 @@ class btPersistentManifoldSortPredicate
}; };
void btSimulationIslandManager::buildIslands(btDispatcher* dispatcher,btCollisionObjectArray& collisionObjects)
//
// todo: this is random access, it can be walked 'cache friendly'!
//
void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,btCollisionObjectArray& collisionObjects, IslandCallback* callback)
{ {
BT_PROFILE("islandUnionFindAndQuickSort");
m_islandmanifold.resize(0);
/*if (0)
{
int maxNumManifolds = dispatcher->getNumManifolds();
btCollisionDispatcher* colDis = (btCollisionDispatcher*)dispatcher;
btPersistentManifold** manifold = colDis->getInternalManifoldPointer();
callback->ProcessIsland(&collisionObjects[0],collisionObjects.size(),manifold,maxNumManifolds, 0);
return;
}
*/
BEGIN_PROFILE("islandUnionFindAndHeapSort");
//we are going to sort the unionfind array, and store the element id in the size //we are going to sort the unionfind array, and store the element id in the size
//afterwards, we clean unionfind, to make sure no-one uses it anymore //afterwards, we clean unionfind, to make sure no-one uses it anymore
@@ -183,7 +180,7 @@ void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,
btCollisionObject* colObj0 = collisionObjects[i]; btCollisionObject* colObj0 = collisionObjects[i];
if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1)) if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1))
{ {
printf("error in island management\n"); // printf("error in island management\n");
} }
assert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1)); assert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
@@ -210,7 +207,7 @@ void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,
btCollisionObject* colObj0 = collisionObjects[i]; btCollisionObject* colObj0 = collisionObjects[i];
if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1)) if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1))
{ {
printf("error in island management\n"); // printf("error in island management\n");
} }
assert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1)); assert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
@@ -231,7 +228,7 @@ void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,
btCollisionObject* colObj0 = collisionObjects[i]; btCollisionObject* colObj0 = collisionObjects[i];
if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1)) if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1))
{ {
printf("error in island management\n"); // printf("error in island management\n");
} }
assert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1)); assert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
@@ -247,11 +244,17 @@ void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,
} }
} }
btAlignedObjectArray<btPersistentManifold*> islandmanifold;
int i; int i;
int maxNumManifolds = dispatcher->getNumManifolds(); int maxNumManifolds = dispatcher->getNumManifolds();
islandmanifold.reserve(maxNumManifolds);
#define SPLIT_ISLANDS 1
#ifdef SPLIT_ISLANDS
#endif //SPLIT_ISLANDS
for (i=0;i<maxNumManifolds ;i++) for (i=0;i<maxNumManifolds ;i++)
{ {
btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal(i); btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal(i);
@@ -265,29 +268,52 @@ void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,
{ {
//kinematic objects don't merge islands, but wake up all connected objects //kinematic objects don't merge islands, but wake up all connected objects
if (colObj0->isStaticOrKinematicObject() && colObj0->getActivationState() != ISLAND_SLEEPING) if (colObj0->isKinematicObject() && colObj0->getActivationState() != ISLAND_SLEEPING)
{ {
colObj1->activate(); colObj1->activate();
} }
if (colObj1->isStaticOrKinematicObject() && colObj1->getActivationState() != ISLAND_SLEEPING) if (colObj1->isKinematicObject() && colObj1->getActivationState() != ISLAND_SLEEPING)
{ {
colObj0->activate(); colObj0->activate();
} }
#ifdef SPLIT_ISLANDS
//filtering for response // //filtering for response
if (dispatcher->needsResponse(colObj0,colObj1)) if (dispatcher->needsResponse(colObj0,colObj1))
islandmanifold.push_back(manifold); m_islandmanifold.push_back(manifold);
#endif //SPLIT_ISLANDS
} }
} }
}
int numManifolds = int (islandmanifold.size());
//
// todo: this is random access, it can be walked 'cache friendly'!
//
void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,btCollisionObjectArray& collisionObjects, IslandCallback* callback)
{
buildIslands(dispatcher,collisionObjects);
int endIslandIndex=1;
int startIslandIndex;
int numElem = getUnionFind().getNumElements();
BT_PROFILE("processIslands");
#ifndef SPLIT_ISLANDS
btPersistentManifold** manifold = dispatcher->getInternalManifoldPointer();
callback->ProcessIsland(&collisionObjects[0],collisionObjects.size(),manifold,maxNumManifolds, -1);
#else
// Sort manifolds, based on islands // Sort manifolds, based on islands
// Sort the vector using predicate and std::sort // Sort the vector using predicate and std::sort
//std::sort(islandmanifold.begin(), islandmanifold.end(), btPersistentManifoldSortPredicate); //std::sort(islandmanifold.begin(), islandmanifold.end(), btPersistentManifoldSortPredicate);
int numManifolds = int (m_islandmanifold.size());
//we should do radix sort, it it much faster (O(n) instead of O (n log2(n)) //we should do radix sort, it it much faster (O(n) instead of O (n log2(n))
islandmanifold.heapSort(btPersistentManifoldSortPredicate()); m_islandmanifold.quickSort(btPersistentManifoldSortPredicate());
//now process all active islands (sets of manifolds for now) //now process all active islands (sets of manifolds for now)
@@ -296,10 +322,9 @@ void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,
//int islandId; //int islandId;
END_PROFILE("islandUnionFindAndHeapSort");
btAlignedObjectArray<btCollisionObject*> islandBodies;
// printf("Start Islands\n");
//traverse the simulation islands, and call the solver, unless all objects are sleeping/deactivated //traverse the simulation islands, and call the solver, unless all objects are sleeping/deactivated
for ( startIslandIndex=0;startIslandIndex<numElem;startIslandIndex = endIslandIndex) for ( startIslandIndex=0;startIslandIndex<numElem;startIslandIndex = endIslandIndex)
@@ -313,7 +338,7 @@ void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,
{ {
int i = getUnionFind().getElement(endIslandIndex).m_sz; int i = getUnionFind().getElement(endIslandIndex).m_sz;
btCollisionObject* colObj0 = collisionObjects[i]; btCollisionObject* colObj0 = collisionObjects[i];
islandBodies.push_back(colObj0); m_islandBodies.push_back(colObj0);
if (!colObj0->isActive()) if (!colObj0->isActive())
islandSleeping = true; islandSleeping = true;
} }
@@ -325,12 +350,12 @@ void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,
if (startManifoldIndex<numManifolds) if (startManifoldIndex<numManifolds)
{ {
int curIslandId = getIslandId(islandmanifold[startManifoldIndex]); int curIslandId = getIslandId(m_islandmanifold[startManifoldIndex]);
if (curIslandId == islandId) if (curIslandId == islandId)
{ {
startManifold = &islandmanifold[startManifoldIndex]; startManifold = &m_islandmanifold[startManifoldIndex];
for (endManifoldIndex = startManifoldIndex+1;(endManifoldIndex<numManifolds) && (islandId == getIslandId(islandmanifold[endManifoldIndex]));endManifoldIndex++) for (endManifoldIndex = startManifoldIndex+1;(endManifoldIndex<numManifolds) && (islandId == getIslandId(m_islandmanifold[endManifoldIndex]));endManifoldIndex++)
{ {
} }
@@ -342,7 +367,8 @@ void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,
if (!islandSleeping) if (!islandSleeping)
{ {
callback->ProcessIsland(&islandBodies[0],islandBodies.size(),startManifold,numIslandManifolds, islandId); callback->ProcessIsland(&m_islandBodies[0],m_islandBodies.size(),startManifold,numIslandManifolds, islandId);
// printf("Island callback of size:%d bodies, %d manifolds\n",islandBodies.size(),numIslandManifolds);
} }
if (numIslandManifolds) if (numIslandManifolds)
@@ -350,8 +376,9 @@ void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,
startManifoldIndex = endManifoldIndex; startManifoldIndex = endManifoldIndex;
} }
islandBodies.resize(0); m_islandBodies.resize(0);
} }
#endif //SPLIT_ISLANDS
} }

View File

@@ -16,18 +16,26 @@ subject to the following restrictions:
#ifndef SIMULATION_ISLAND_MANAGER_H #ifndef SIMULATION_ISLAND_MANAGER_H
#define SIMULATION_ISLAND_MANAGER_H #define SIMULATION_ISLAND_MANAGER_H
#include "../CollisionDispatch/btUnionFind.h" #include "BulletCollision/CollisionDispatch/btUnionFind.h"
#include "btCollisionCreateFunc.h" #include "btCollisionCreateFunc.h"
#include "LinearMath/btAlignedObjectArray.h"
class btCollisionObject; class btCollisionObject;
class btCollisionWorld; class btCollisionWorld;
class btDispatcher; class btDispatcher;
class btPersistentManifold;
///SimulationIslandManager creates and handles simulation islands, using btUnionFind ///SimulationIslandManager creates and handles simulation islands, using btUnionFind
class btSimulationIslandManager class btSimulationIslandManager
{ {
btUnionFind m_unionFind; btUnionFind m_unionFind;
btAlignedObjectArray<btPersistentManifold*> m_islandmanifold;
btAlignedObjectArray<btCollisionObject* > m_islandBodies;
public: public:
btSimulationIslandManager(); btSimulationIslandManager();
virtual ~btSimulationIslandManager(); virtual ~btSimulationIslandManager();
@@ -42,7 +50,7 @@ public:
virtual void storeIslandActivationState(btCollisionWorld* world); virtual void storeIslandActivationState(btCollisionWorld* world);
void findUnions(btDispatcher* dispatcher); void findUnions(btDispatcher* dispatcher,btCollisionWorld* colWorld);
@@ -55,6 +63,8 @@ public:
void buildAndProcessIslands(btDispatcher* dispatcher,btCollisionObjectArray& collisionObjects, IslandCallback* callback); void buildAndProcessIslands(btDispatcher* dispatcher,btCollisionObjectArray& collisionObjects, IslandCallback* callback);
void buildIslands(btDispatcher* dispatcher,btCollisionObjectArray& collisionObjects);
}; };
#endif //SIMULATION_ISLAND_MANAGER_H #endif //SIMULATION_ISLAND_MANAGER_H

View File

@@ -68,18 +68,25 @@ void btSphereBoxCollisionAlgorithm::processCollision (btCollisionObject* body0,b
btScalar dist = getSphereDistance(boxObj,pOnBox,pOnSphere,sphereCenter,radius); btScalar dist = getSphereDistance(boxObj,pOnBox,pOnSphere,sphereCenter,radius);
resultOut->setPersistentManifold(m_manifoldPtr);
if (dist < SIMD_EPSILON) if (dist < SIMD_EPSILON)
{ {
btVector3 normalOnSurfaceB = (pOnBox- pOnSphere).normalize(); btVector3 normalOnSurfaceB = (pOnBox- pOnSphere).normalize();
/// report a contact. internally this will be kept persistent, and contact reduction is done /// report a contact. internally this will be kept persistent, and contact reduction is done
resultOut->setPersistentManifold(m_manifoldPtr);
resultOut->addContactPoint(normalOnSurfaceB,pOnBox,dist); resultOut->addContactPoint(normalOnSurfaceB,pOnBox,dist);
} }
if (m_ownManifold)
{
if (m_manifoldPtr->getNumContacts())
{
resultOut->refreshContactPoints();
}
}
} }
@@ -102,8 +109,8 @@ btScalar btSphereBoxCollisionAlgorithm::getSphereDistance(btCollisionObject* box
btVector3 bounds[2]; btVector3 bounds[2];
btBoxShape* boxShape= (btBoxShape*)boxObj->getCollisionShape(); btBoxShape* boxShape= (btBoxShape*)boxObj->getCollisionShape();
bounds[0] = -boxShape->getHalfExtents(); bounds[0] = -boxShape->getHalfExtentsWithoutMargin();
bounds[1] = boxShape->getHalfExtents(); bounds[1] = boxShape->getHalfExtentsWithoutMargin();
margins = boxShape->getMargin();//also add sphereShape margin? margins = boxShape->getMargin();//also add sphereShape margin?
@@ -209,6 +216,10 @@ btScalar btSphereBoxCollisionAlgorithm::getSpherePenetration( btCollisionObject*
btVector3 p0, tmp, prel, n[6], normal; btVector3 p0, tmp, prel, n[6], normal;
btScalar fSep = btScalar(-10000000.0), fSepThis; btScalar fSep = btScalar(-10000000.0), fSepThis;
// set p0 and normal to a default value to shup up GCC
p0.setValue(btScalar(0.), btScalar(0.), btScalar(0.));
normal.setValue(btScalar(0.), btScalar(0.), btScalar(0.));
n[0].setValue( btScalar(-1.0), btScalar(0.0), btScalar(0.0) ); n[0].setValue( btScalar(-1.0), btScalar(0.0), btScalar(0.0) );
n[1].setValue( btScalar(0.0), btScalar(-1.0), btScalar(0.0) ); n[1].setValue( btScalar(0.0), btScalar(-1.0), btScalar(0.0) );
n[2].setValue( btScalar(0.0), btScalar(0.0), btScalar(-1.0) ); n[2].setValue( btScalar(0.0), btScalar(0.0), btScalar(-1.0) );

View File

@@ -16,11 +16,13 @@ subject to the following restrictions:
#ifndef SPHERE_BOX_COLLISION_ALGORITHM_H #ifndef SPHERE_BOX_COLLISION_ALGORITHM_H
#define SPHERE_BOX_COLLISION_ALGORITHM_H #define SPHERE_BOX_COLLISION_ALGORITHM_H
#include "../BroadphaseCollision/btCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
#include "../BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
#include "../CollisionDispatch/btCollisionCreateFunc.h" #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h"
class btPersistentManifold; class btPersistentManifold;
#include "../../LinearMath/btVector3.h" #include "btCollisionDispatcher.h"
#include "LinearMath/btVector3.h"
/// btSphereBoxCollisionAlgorithm provides sphere-box collision detection. /// btSphereBoxCollisionAlgorithm provides sphere-box collision detection.
/// Other features are frame-coherency (persistent data) and collision response. /// Other features are frame-coherency (persistent data) and collision response.
@@ -40,6 +42,14 @@ public:
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut);
virtual void getAllContactManifolds(btManifoldArray& manifoldArray)
{
if (m_manifoldPtr && m_ownManifold)
{
manifoldArray.push_back(m_manifoldPtr);
}
}
btScalar getSphereDistance( btCollisionObject* boxObj,btVector3& v3PointOnBox, btVector3& v3PointOnSphere, const btVector3& v3SphereCenter, btScalar fRadius ); btScalar getSphereDistance( btCollisionObject* boxObj,btVector3& v3PointOnBox, btVector3& v3PointOnSphere, const btVector3& v3SphereCenter, btScalar fRadius );
btScalar getSpherePenetration( btCollisionObject* boxObj, btVector3& v3PointOnBox, btVector3& v3PointOnSphere, const btVector3& v3SphereCenter, btScalar fRadius, const btVector3& aabbMin, const btVector3& aabbMax); btScalar getSpherePenetration( btCollisionObject* boxObj, btVector3& v3PointOnBox, btVector3& v3PointOnSphere, const btVector3& v3SphereCenter, btScalar fRadius, const btVector3& aabbMin, const btVector3& aabbMax);
@@ -48,12 +58,13 @@ public:
{ {
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1)
{ {
void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btSphereBoxCollisionAlgorithm));
if (!m_swapped) if (!m_swapped)
{ {
return new btSphereBoxCollisionAlgorithm(0,ci,body0,body1,false); return new(mem) btSphereBoxCollisionAlgorithm(0,ci,body0,body1,false);
} else } else
{ {
return new btSphereBoxCollisionAlgorithm(0,ci,body0,body1,true); return new(mem) btSphereBoxCollisionAlgorithm(0,ci,body0,body1,true);
} }
} }
}; };

View File

@@ -46,6 +46,8 @@ void btSphereSphereCollisionAlgorithm::processCollision (btCollisionObject* col0
if (!m_manifoldPtr) if (!m_manifoldPtr)
return; return;
resultOut->setPersistentManifold(m_manifoldPtr);
btSphereShape* sphere0 = (btSphereShape*)col0->getCollisionShape(); btSphereShape* sphere0 = (btSphereShape*)col0->getCollisionShape();
btSphereShape* sphere1 = (btSphereShape*)col1->getCollisionShape(); btSphereShape* sphere1 = (btSphereShape*)col1->getCollisionShape();
@@ -54,23 +56,34 @@ void btSphereSphereCollisionAlgorithm::processCollision (btCollisionObject* col0
btScalar radius0 = sphere0->getRadius(); btScalar radius0 = sphere0->getRadius();
btScalar radius1 = sphere1->getRadius(); btScalar radius1 = sphere1->getRadius();
//m_manifoldPtr->clearManifold(); //don't do this, it disables warmstarting
///iff distance positive, don't generate a new contact ///iff distance positive, don't generate a new contact
if ( len > (radius0+radius1)) if ( len > (radius0+radius1))
{
return; return;
}
///distance (negative means penetration) ///distance (negative means penetration)
btScalar dist = len - (radius0+radius1); btScalar dist = len - (radius0+radius1);
btVector3 normalOnSurfaceB = diff / len; btVector3 normalOnSurfaceB(1,0,0);
if (len > SIMD_EPSILON)
{
normalOnSurfaceB = diff / len;
}
///point on A (worldspace) ///point on A (worldspace)
btVector3 pos0 = col0->getWorldTransform().getOrigin() - radius0 * normalOnSurfaceB; btVector3 pos0 = col0->getWorldTransform().getOrigin() - radius0 * normalOnSurfaceB;
///point on B (worldspace) ///point on B (worldspace)
btVector3 pos1 = col1->getWorldTransform().getOrigin() + radius1* normalOnSurfaceB; btVector3 pos1 = col1->getWorldTransform().getOrigin() + radius1* normalOnSurfaceB;
/// report a contact. internally this will be kept persistent, and contact reduction is done /// report a contact. internally this will be kept persistent, and contact reduction is done
resultOut->setPersistentManifold(m_manifoldPtr);
resultOut->addContactPoint(normalOnSurfaceB,pos1,dist); resultOut->addContactPoint(normalOnSurfaceB,pos1,dist);
//no resultOut->refreshContactPoints(); needed, because of clearManifold (all points are new)
} }
btScalar btSphereSphereCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) btScalar btSphereSphereCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)

View File

@@ -16,9 +16,11 @@ subject to the following restrictions:
#ifndef SPHERE_SPHERE_COLLISION_ALGORITHM_H #ifndef SPHERE_SPHERE_COLLISION_ALGORITHM_H
#define SPHERE_SPHERE_COLLISION_ALGORITHM_H #define SPHERE_SPHERE_COLLISION_ALGORITHM_H
#include "../BroadphaseCollision/btCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
#include "../BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
#include "../CollisionDispatch/btCollisionCreateFunc.h" #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h"
#include "btCollisionDispatcher.h"
class btPersistentManifold; class btPersistentManifold;
/// btSphereSphereCollisionAlgorithm provides sphere-sphere collision detection. /// btSphereSphereCollisionAlgorithm provides sphere-sphere collision detection.
@@ -39,6 +41,13 @@ public:
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut);
virtual void getAllContactManifolds(btManifoldArray& manifoldArray)
{
if (m_manifoldPtr && m_ownManifold)
{
manifoldArray.push_back(m_manifoldPtr);
}
}
virtual ~btSphereSphereCollisionAlgorithm(); virtual ~btSphereSphereCollisionAlgorithm();
@@ -46,7 +55,8 @@ public:
{ {
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1)
{ {
return new btSphereSphereCollisionAlgorithm(0,ci,body0,body1); void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btSphereSphereCollisionAlgorithm));
return new(mem) btSphereSphereCollisionAlgorithm(0,ci,body0,body1);
} }
}; };

View File

@@ -48,8 +48,11 @@ void btSphereTriangleCollisionAlgorithm::processCollision (btCollisionObject* co
if (!m_manifoldPtr) if (!m_manifoldPtr)
return; return;
btSphereShape* sphere = (btSphereShape*)col0->getCollisionShape(); btCollisionObject* sphereObj = m_swapped? col1 : col0;
btTriangleShape* triangle = (btTriangleShape*)col1->getCollisionShape(); btCollisionObject* triObj = m_swapped? col0 : col1;
btSphereShape* sphere = (btSphereShape*)sphereObj->getCollisionShape();
btTriangleShape* triangle = (btTriangleShape*)triObj->getCollisionShape();
/// report a contact. internally this will be kept persistent, and contact reduction is done /// report a contact. internally this will be kept persistent, and contact reduction is done
resultOut->setPersistentManifold(m_manifoldPtr); resultOut->setPersistentManifold(m_manifoldPtr);
@@ -57,11 +60,16 @@ void btSphereTriangleCollisionAlgorithm::processCollision (btCollisionObject* co
btDiscreteCollisionDetectorInterface::ClosestPointInput input; btDiscreteCollisionDetectorInterface::ClosestPointInput input;
input.m_maximumDistanceSquared = btScalar(1e30);//todo: tighter bounds input.m_maximumDistanceSquared = btScalar(1e30);//todo: tighter bounds
input.m_transformA = col0->getWorldTransform(); input.m_transformA = sphereObj->getWorldTransform();
input.m_transformB = col1->getWorldTransform(); input.m_transformB = triObj->getWorldTransform();
detector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); bool swapResults = m_swapped && !m_ownManifold;
detector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw,swapResults);
if (m_ownManifold)
resultOut->refreshContactPoints();
} }
btScalar btSphereTriangleCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) btScalar btSphereTriangleCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)

View File

@@ -16,10 +16,11 @@ subject to the following restrictions:
#ifndef SPHERE_TRIANGLE_COLLISION_ALGORITHM_H #ifndef SPHERE_TRIANGLE_COLLISION_ALGORITHM_H
#define SPHERE_TRIANGLE_COLLISION_ALGORITHM_H #define SPHERE_TRIANGLE_COLLISION_ALGORITHM_H
#include "../BroadphaseCollision/btCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
#include "../BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
#include "../CollisionDispatch/btCollisionCreateFunc.h" #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h"
class btPersistentManifold; class btPersistentManifold;
#include "btCollisionDispatcher.h"
/// btSphereSphereCollisionAlgorithm provides sphere-sphere collision detection. /// btSphereSphereCollisionAlgorithm provides sphere-sphere collision detection.
/// Other features are frame-coherency (persistent data) and collision response. /// Other features are frame-coherency (persistent data) and collision response.
@@ -40,6 +41,13 @@ public:
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut);
virtual void getAllContactManifolds(btManifoldArray& manifoldArray)
{
if (m_manifoldPtr && m_ownManifold)
{
manifoldArray.push_back(m_manifoldPtr);
}
}
virtual ~btSphereTriangleCollisionAlgorithm(); virtual ~btSphereTriangleCollisionAlgorithm();
@@ -49,7 +57,9 @@ public:
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1)
{ {
return new btSphereTriangleCollisionAlgorithm(ci.m_manifold,ci,body0,body1,m_swapped); void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btSphereTriangleCollisionAlgorithm));
return new(mem) btSphereTriangleCollisionAlgorithm(ci.m_manifold,ci,body0,body1,m_swapped);
} }
}; };

View File

@@ -18,6 +18,7 @@ subject to the following restrictions:
btUnionFind::~btUnionFind() btUnionFind::~btUnionFind()
{ {
Free(); Free();
@@ -76,8 +77,7 @@ void btUnionFind::sortIslands()
// Sort the vector using predicate and std::sort // Sort the vector using predicate and std::sort
//std::sort(m_elements.begin(), m_elements.end(), btUnionFindElementSortPredicate); //std::sort(m_elements.begin(), m_elements.end(), btUnionFindElementSortPredicate);
//perhaps use radix sort? m_elements.quickSort(btUnionFindElementSortPredicate());
m_elements.heapSort(btUnionFindElementSortPredicate());
} }

View File

@@ -16,7 +16,7 @@ subject to the following restrictions:
#ifndef UNION_FIND_H #ifndef UNION_FIND_H
#define UNION_FIND_H #define UNION_FIND_H
#include "../../LinearMath/btAlignedObjectArray.h" #include "LinearMath/btAlignedObjectArray.h"
#define USE_PATH_COMPRESSION 1 #define USE_PATH_COMPRESSION 1
@@ -46,11 +46,11 @@ class btUnionFind
void reset(int N); void reset(int N);
inline int getNumElements() const SIMD_FORCE_INLINE int getNumElements() const
{ {
return int(m_elements.size()); return int(m_elements.size());
} }
inline bool isRoot(int x) const SIMD_FORCE_INLINE bool isRoot(int x) const
{ {
return (x == m_elements[x].m_id); return (x == m_elements[x].m_id);
} }

View File

@@ -15,16 +15,13 @@ subject to the following restrictions:
#include "btBoxShape.h" #include "btBoxShape.h"
btVector3 btBoxShape::getHalfExtents() const
{
return m_implicitShapeDimensions * m_localScaling;
}
//{ //{
void btBoxShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const void btBoxShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const
{ {
btVector3 halfExtents = getHalfExtents(); const btVector3& halfExtents = getHalfExtentsWithoutMargin();
btMatrix3x3 abs_b = t.getBasis().absolute(); btMatrix3x3 abs_b = t.getBasis().absolute();
btPoint3 center = t.getOrigin(); btPoint3 center = t.getOrigin();
@@ -40,10 +37,10 @@ void btBoxShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabb
} }
void btBoxShape::calculateLocalInertia(btScalar mass,btVector3& inertia) void btBoxShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const
{ {
//btScalar margin = btScalar(0.); //btScalar margin = btScalar(0.);
btVector3 halfExtents = getHalfExtents(); btVector3 halfExtents = getHalfExtentsWithMargin();
btScalar lx=btScalar(2.)*(halfExtents.x()); btScalar lx=btScalar(2.)*(halfExtents.x());
btScalar ly=btScalar(2.)*(halfExtents.y()); btScalar ly=btScalar(2.)*(halfExtents.y());

View File

@@ -18,11 +18,11 @@ subject to the following restrictions:
#include "btPolyhedralConvexShape.h" #include "btPolyhedralConvexShape.h"
#include "btCollisionMargin.h" #include "btCollisionMargin.h"
#include "../BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
#include "../../LinearMath/btPoint3.h" #include "LinearMath/btPoint3.h"
#include "../../LinearMath/btSimdMinMax.h" #include "LinearMath/btMinMax.h"
///btBoxShape implements both a feature based (vertex/edge/plane) and implicit (getSupportingVertex) Box ///The btBoxShape is a box primitive around the origin, its sides axis aligned with length specified by half extents, in local shape coordinates. When used as part of a btCollisionObject or btRigidBody it will be an oriented box in world space.
class btBoxShape: public btPolyhedralConvexShape class btBoxShape: public btPolyhedralConvexShape
{ {
@@ -31,47 +31,52 @@ class btBoxShape: public btPolyhedralConvexShape
public: public:
btVector3 getHalfExtents() const; btVector3 getHalfExtentsWithMargin() const
{
btVector3 halfExtents = getHalfExtentsWithoutMargin();
btVector3 margin(getMargin(),getMargin(),getMargin());
halfExtents += margin;
return halfExtents;
}
const btVector3& getHalfExtentsWithoutMargin() const
{
return m_implicitShapeDimensions;//changed in Bullet 2.63: assume the scaling and margin are included
}
virtual int getShapeType() const { return BOX_SHAPE_PROXYTYPE;} virtual int getShapeType() const { return BOX_SHAPE_PROXYTYPE;}
virtual btVector3 localGetSupportingVertex(const btVector3& vec) const virtual btVector3 localGetSupportingVertex(const btVector3& vec) const
{ {
btVector3 halfExtents = getHalfExtentsWithoutMargin();
btVector3 margin(getMargin(),getMargin(),getMargin());
halfExtents += margin;
btVector3 halfExtents = getHalfExtents(); return btVector3(btFsels(vec.x(), halfExtents.x(), -halfExtents.x()),
btFsels(vec.y(), halfExtents.y(), -halfExtents.y()),
btVector3 supVertex; btFsels(vec.z(), halfExtents.z(), -halfExtents.z()));
supVertex = btPoint3(vec.x() < btScalar(0.0) ? -halfExtents.x() : halfExtents.x(),
vec.y() < btScalar(0.0) ? -halfExtents.y() : halfExtents.y(),
vec.z() < btScalar(0.0) ? -halfExtents.z() : halfExtents.z());
return supVertex;
} }
virtual inline btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const SIMD_FORCE_INLINE btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const
{ {
btVector3 halfExtents = getHalfExtents(); const btVector3& halfExtents = getHalfExtentsWithoutMargin();
btVector3 margin(getMargin(),getMargin(),getMargin());
halfExtents -= margin; return btVector3(btFsels(vec.x(), halfExtents.x(), -halfExtents.x()),
btFsels(vec.y(), halfExtents.y(), -halfExtents.y()),
return btVector3(vec.x() < btScalar(0.0) ? -halfExtents.x() : halfExtents.x(), btFsels(vec.z(), halfExtents.z(), -halfExtents.z()));
vec.y() < btScalar(0.0) ? -halfExtents.y() : halfExtents.y(),
vec.z() < btScalar(0.0) ? -halfExtents.z() : halfExtents.z());
} }
virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const
{ {
btVector3 halfExtents = getHalfExtents(); const btVector3& halfExtents = getHalfExtentsWithoutMargin();
btVector3 margin(getMargin(),getMargin(),getMargin());
halfExtents -= margin;
for (int i=0;i<numVectors;i++) for (int i=0;i<numVectors;i++)
{ {
const btVector3& vec = vectors[i]; const btVector3& vec = vectors[i];
supportVerticesOut[i].setValue(vec.x() < btScalar(0.0) ? -halfExtents.x() : halfExtents.x(), supportVerticesOut[i].setValue(btFsels(vec.x(), halfExtents.x(), -halfExtents.x()),
vec.y() < btScalar(0.0) ? -halfExtents.y() : halfExtents.y(), btFsels(vec.y(), halfExtents.y(), -halfExtents.y()),
vec.z() < btScalar(0.0) ? -halfExtents.z() : halfExtents.z()); btFsels(vec.z(), halfExtents.z(), -halfExtents.z()));
} }
} }
@@ -79,14 +84,38 @@ public:
btBoxShape( const btVector3& boxHalfExtents) btBoxShape( const btVector3& boxHalfExtents)
{ {
m_implicitShapeDimensions = boxHalfExtents; btVector3 margin(getMargin(),getMargin(),getMargin());
m_implicitShapeDimensions = (boxHalfExtents * m_localScaling) - margin;
}; };
virtual void setMargin(btScalar collisionMargin)
{
//correct the m_implicitShapeDimensions for the margin
btVector3 oldMargin(getMargin(),getMargin(),getMargin());
btVector3 implicitShapeDimensionsWithMargin = m_implicitShapeDimensions+oldMargin;
btConvexInternalShape::setMargin(collisionMargin);
btVector3 newMargin(getMargin(),getMargin(),getMargin());
m_implicitShapeDimensions = implicitShapeDimensionsWithMargin - newMargin;
}
virtual void setLocalScaling(const btVector3& scaling)
{
btVector3 oldMargin(getMargin(),getMargin(),getMargin());
btVector3 implicitShapeDimensionsWithMargin = m_implicitShapeDimensions+oldMargin;
btVector3 unScaledImplicitShapeDimensionsWithMargin = implicitShapeDimensionsWithMargin / m_localScaling;
btConvexInternalShape::setLocalScaling(scaling);
m_implicitShapeDimensions = (unScaledImplicitShapeDimensionsWithMargin * m_localScaling) - oldMargin;
}
virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const;
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia); virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const;
virtual void getPlane(btVector3& planeNormal,btPoint3& planeSupport,int i ) const virtual void getPlane(btVector3& planeNormal,btPoint3& planeSupport,int i ) const
{ {
@@ -116,7 +145,7 @@ public:
virtual void getVertex(int i,btVector3& vtx) const virtual void getVertex(int i,btVector3& vtx) const
{ {
btVector3 halfExtents = getHalfExtents(); btVector3 halfExtents = getHalfExtentsWithoutMargin();
vtx = btVector3( vtx = btVector3(
halfExtents.x() * (1-(i&1)) - halfExtents.x() * (i&1), halfExtents.x() * (1-(i&1)) - halfExtents.x() * (i&1),
@@ -127,7 +156,7 @@ public:
virtual void getPlaneEquation(btVector4& plane,int i) const virtual void getPlaneEquation(btVector4& plane,int i) const
{ {
btVector3 halfExtents = getHalfExtents(); btVector3 halfExtents = getHalfExtentsWithoutMargin();
switch (i) switch (i)
{ {
@@ -234,7 +263,7 @@ public:
virtual bool isInside(const btPoint3& pt,btScalar tolerance) const virtual bool isInside(const btPoint3& pt,btScalar tolerance) const
{ {
btVector3 halfExtents = getHalfExtents(); btVector3 halfExtents = getHalfExtentsWithoutMargin();
//btScalar minDist = 2*tolerance; //btScalar minDist = 2*tolerance;
@@ -250,7 +279,7 @@ public:
//debugging //debugging
virtual char* getName()const virtual const char* getName()const
{ {
return "Box"; return "Box";
} }
@@ -291,3 +320,4 @@ public:
#endif //OBB_BOX_MINKOWSKI_H #endif //OBB_BOX_MINKOWSKI_H

View File

@@ -18,32 +18,56 @@ subject to the following restrictions:
#include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" #include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h"
#include "BulletCollision/CollisionShapes/btOptimizedBvh.h" #include "BulletCollision/CollisionShapes/btOptimizedBvh.h"
///Bvh Concave triangle mesh is a static-triangle mesh shape with Bounding Volume Hierarchy optimization. ///Bvh Concave triangle mesh is a static-triangle mesh shape with Bounding Volume Hierarchy optimization.
///Uses an interface to access the triangles to allow for sharing graphics/physics triangles. ///Uses an interface to access the triangles to allow for sharing graphics/physics triangles.
btBvhTriangleMeshShape::btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression) btBvhTriangleMeshShape::btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression, bool buildBvh)
:btTriangleMeshShape(meshInterface),m_useQuantizedAabbCompression(useQuantizedAabbCompression) :btTriangleMeshShape(meshInterface),
m_bvh(0),
m_useQuantizedAabbCompression(useQuantizedAabbCompression),
m_ownsBvh(false)
{ {
//construct bvh from meshInterface //construct bvh from meshInterface
#ifndef DISABLE_BVH #ifndef DISABLE_BVH
m_bvh = new btOptimizedBvh();
btVector3 bvhAabbMin,bvhAabbMax; btVector3 bvhAabbMin,bvhAabbMax;
meshInterface->calculateAabbBruteForce(bvhAabbMin,bvhAabbMax); if(meshInterface->hasPremadeAabb())
m_bvh->build(meshInterface,m_useQuantizedAabbCompression,bvhAabbMin,bvhAabbMax); {
meshInterface->getPremadeAabb(&bvhAabbMin, &bvhAabbMax);
}
else
{
meshInterface->calculateAabbBruteForce(bvhAabbMin,bvhAabbMax);
}
if (buildBvh)
{
void* mem = btAlignedAlloc(sizeof(btOptimizedBvh),16);
m_bvh = new (mem) btOptimizedBvh();
m_bvh->build(meshInterface,m_useQuantizedAabbCompression,bvhAabbMin,bvhAabbMax);
m_ownsBvh = true;
}
#endif //DISABLE_BVH #endif //DISABLE_BVH
} }
btBvhTriangleMeshShape::btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression,const btVector3& bvhAabbMin,const btVector3& bvhAabbMax) btBvhTriangleMeshShape::btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression,const btVector3& bvhAabbMin,const btVector3& bvhAabbMax,bool buildBvh)
:btTriangleMeshShape(meshInterface),m_useQuantizedAabbCompression(useQuantizedAabbCompression) :btTriangleMeshShape(meshInterface),
m_bvh(0),
m_useQuantizedAabbCompression(useQuantizedAabbCompression),
m_ownsBvh(false)
{ {
//construct bvh from meshInterface //construct bvh from meshInterface
#ifndef DISABLE_BVH #ifndef DISABLE_BVH
m_bvh = new btOptimizedBvh(); if (buildBvh)
m_bvh->build(meshInterface,m_useQuantizedAabbCompression,bvhAabbMin,bvhAabbMax); {
void* mem = btAlignedAlloc(sizeof(btOptimizedBvh),16);
m_bvh = new (mem) btOptimizedBvh();
m_bvh->build(meshInterface,m_useQuantizedAabbCompression,bvhAabbMin,bvhAabbMax);
m_ownsBvh = true;
}
#endif //DISABLE_BVH #endif //DISABLE_BVH
@@ -58,16 +82,140 @@ void btBvhTriangleMeshShape::partialRefitTree(const btVector3& aabbMin,const btV
} }
void btBvhTriangleMeshShape::refitTree() void btBvhTriangleMeshShape::refitTree(const btVector3& aabbMin,const btVector3& aabbMax)
{ {
m_bvh->refit( m_meshInterface ); m_bvh->refit( m_meshInterface, aabbMin,aabbMax );
recalcLocalAabb(); recalcLocalAabb();
} }
btBvhTriangleMeshShape::~btBvhTriangleMeshShape() btBvhTriangleMeshShape::~btBvhTriangleMeshShape()
{ {
delete m_bvh; if (m_ownsBvh)
{
m_bvh->~btOptimizedBvh();
btAlignedFree(m_bvh);
}
}
void btBvhTriangleMeshShape::performRaycast (btTriangleCallback* callback, const btVector3& raySource, const btVector3& rayTarget)
{
struct MyNodeOverlapCallback : public btNodeOverlapCallback
{
btStridingMeshInterface* m_meshInterface;
btTriangleCallback* m_callback;
MyNodeOverlapCallback(btTriangleCallback* callback,btStridingMeshInterface* meshInterface)
:m_meshInterface(meshInterface),
m_callback(callback)
{
}
virtual void processNode(int nodeSubPart, int nodeTriangleIndex)
{
btVector3 m_triangle[3];
const unsigned char *vertexbase;
int numverts;
PHY_ScalarType type;
int stride;
const unsigned char *indexbase;
int indexstride;
int numfaces;
PHY_ScalarType indicestype;
m_meshInterface->getLockedReadOnlyVertexIndexBase(
&vertexbase,
numverts,
type,
stride,
&indexbase,
indexstride,
numfaces,
indicestype,
nodeSubPart);
unsigned int* gfxbase = (unsigned int*)(indexbase+nodeTriangleIndex*indexstride);
btAssert(indicestype==PHY_INTEGER||indicestype==PHY_SHORT);
const btVector3& meshScaling = m_meshInterface->getScaling();
for (int j=2;j>=0;j--)
{
int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j];
btScalar* graphicsbase = (btScalar*)(vertexbase+graphicsindex*stride);
m_triangle[j] = btVector3(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),graphicsbase[2]*meshScaling.getZ());
}
/* Perform ray vs. triangle collision here */
m_callback->processTriangle(m_triangle,nodeSubPart,nodeTriangleIndex);
m_meshInterface->unLockReadOnlyVertexBase(nodeSubPart);
}
};
MyNodeOverlapCallback myNodeCallback(callback,m_meshInterface);
m_bvh->reportRayOverlappingNodex(&myNodeCallback,raySource,rayTarget);
}
void btBvhTriangleMeshShape::performConvexcast (btTriangleCallback* callback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin, const btVector3& aabbMax)
{
struct MyNodeOverlapCallback : public btNodeOverlapCallback
{
btStridingMeshInterface* m_meshInterface;
btTriangleCallback* m_callback;
MyNodeOverlapCallback(btTriangleCallback* callback,btStridingMeshInterface* meshInterface)
:m_meshInterface(meshInterface),
m_callback(callback)
{
}
virtual void processNode(int nodeSubPart, int nodeTriangleIndex)
{
btVector3 m_triangle[3];
const unsigned char *vertexbase;
int numverts;
PHY_ScalarType type;
int stride;
const unsigned char *indexbase;
int indexstride;
int numfaces;
PHY_ScalarType indicestype;
m_meshInterface->getLockedReadOnlyVertexIndexBase(
&vertexbase,
numverts,
type,
stride,
&indexbase,
indexstride,
numfaces,
indicestype,
nodeSubPart);
unsigned int* gfxbase = (unsigned int*)(indexbase+nodeTriangleIndex*indexstride);
btAssert(indicestype==PHY_INTEGER||indicestype==PHY_SHORT);
const btVector3& meshScaling = m_meshInterface->getScaling();
for (int j=2;j>=0;j--)
{
int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j];
btScalar* graphicsbase = (btScalar*)(vertexbase+graphicsindex*stride);
m_triangle[j] = btVector3(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),graphicsbase[2]*meshScaling.getZ());
}
/* Perform ray vs. triangle collision here */
m_callback->processTriangle(m_triangle,nodeSubPart,nodeTriangleIndex);
m_meshInterface->unLockReadOnlyVertexBase(nodeSubPart);
}
};
MyNodeOverlapCallback myNodeCallback(callback,m_meshInterface);
m_bvh->reportBoxCastOverlappingNodex (&myNodeCallback, raySource, rayTarget, aabbMin, aabbMax);
} }
//perform bvh tree traversal and report overlapping triangles to 'callback' //perform bvh tree traversal and report overlapping triangles to 'callback'
@@ -118,13 +266,14 @@ void btBvhTriangleMeshShape::processAllTriangles(btTriangleCallback* callback,co
indicestype, indicestype,
nodeSubPart); nodeSubPart);
int* gfxbase = (int*)(indexbase+nodeTriangleIndex*indexstride); unsigned int* gfxbase = (unsigned int*)(indexbase+nodeTriangleIndex*indexstride);
btAssert(indicestype==PHY_INTEGER||indicestype==PHY_SHORT);
const btVector3& meshScaling = m_meshInterface->getScaling(); const btVector3& meshScaling = m_meshInterface->getScaling();
for (int j=2;j>=0;j--) for (int j=2;j>=0;j--)
{ {
int graphicsindex = gfxbase[j]; int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j];
#ifdef DEBUG_TRIANGLE_MESH #ifdef DEBUG_TRIANGLE_MESH
@@ -157,17 +306,37 @@ void btBvhTriangleMeshShape::processAllTriangles(btTriangleCallback* callback,co
} }
void btBvhTriangleMeshShape::setLocalScaling(const btVector3& scaling)
void btBvhTriangleMeshShape::setLocalScaling(const btVector3& scaling)
{ {
if ((getLocalScaling() -scaling).length2() > SIMD_EPSILON) if ((getLocalScaling() -scaling).length2() > SIMD_EPSILON)
{ {
btTriangleMeshShape::setLocalScaling(scaling); btTriangleMeshShape::setLocalScaling(scaling);
delete m_bvh; if (m_ownsBvh)
///m_localAabbMin/m_localAabbMax is already re-calculated in btTriangleMeshShape. We could just scale aabb, but this needs some more work {
m_bvh = new btOptimizedBvh(); m_bvh->~btOptimizedBvh();
//rebuild the bvh... btAlignedFree(m_bvh);
m_bvh->build(m_meshInterface,m_useQuantizedAabbCompression,m_localAabbMin,m_localAabbMax); }
///m_localAabbMin/m_localAabbMax is already re-calculated in btTriangleMeshShape. We could just scale aabb, but this needs some more work
} void* mem = btAlignedAlloc(sizeof(btOptimizedBvh),16);
m_bvh = new(mem) btOptimizedBvh();
//rebuild the bvh...
m_bvh->build(m_meshInterface,m_useQuantizedAabbCompression,m_localAabbMin,m_localAabbMax);
m_ownsBvh = true;
}
} }
void btBvhTriangleMeshShape::setOptimizedBvh(btOptimizedBvh* bvh, const btVector3& scaling)
{
btAssert(!m_bvh);
btAssert(!m_ownsBvh);
m_bvh = bvh;
m_ownsBvh = false;
// update the scaling without rebuilding the bvh
if ((getLocalScaling() -scaling).length2() > SIMD_EPSILON)
{
btTriangleMeshShape::setLocalScaling(scaling);
}
}

View File

@@ -18,45 +18,55 @@ subject to the following restrictions:
#include "btTriangleMeshShape.h" #include "btTriangleMeshShape.h"
#include "btOptimizedBvh.h" #include "btOptimizedBvh.h"
#include "LinearMath/btAlignedAllocator.h"
///Bvh Concave triangle mesh is a static-triangle mesh shape with Bounding Volume Hierarchy optimization.
///Uses an interface to access the triangles to allow for sharing graphics/physics triangles. ///The btBvhTriangleMeshShape is a static-triangle mesh shape with several optimizations, such as bounding volume hierarchy and cache friendly traversal for PlayStation 3 Cell SPU. It is recommended to enable useQuantizedAabbCompression for better memory usage.
///It takes a triangle mesh as input, for example a btTriangleMesh or btTriangleIndexVertexArray. The btBvhTriangleMeshShape class allows for triangle mesh deformations by a refit or partialRefit method.
///Instead of building the bounding volume hierarchy acceleration structure, it is also possible to serialize (save) and deserialize (load) the structure from disk.
///See Demos\ConcaveDemo\ConcavePhysicsDemo.cpp for an example.
ATTRIBUTE_ALIGNED16(class) btBvhTriangleMeshShape : public btTriangleMeshShape ATTRIBUTE_ALIGNED16(class) btBvhTriangleMeshShape : public btTriangleMeshShape
{ {
btOptimizedBvh* m_bvh; btOptimizedBvh* m_bvh;
bool m_useQuantizedAabbCompression; bool m_useQuantizedAabbCompression;
bool m_pad[12];////need padding due to alignment bool m_ownsBvh;
bool m_pad[11];////need padding due to alignment
public: public:
btBvhTriangleMeshShape() :btTriangleMeshShape(0) {}; BT_DECLARE_ALIGNED_ALLOCATOR();
btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression);
btBvhTriangleMeshShape() :btTriangleMeshShape(0),m_bvh(0),m_ownsBvh(false) {};
btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression, bool buildBvh = true);
///optionally pass in a larger bvh aabb, used for quantization. This allows for deformations within this aabb ///optionally pass in a larger bvh aabb, used for quantization. This allows for deformations within this aabb
btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression,const btVector3& bvhAabbMin,const btVector3& bvhAabbMax); btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression,const btVector3& bvhAabbMin,const btVector3& bvhAabbMax, bool buildBvh = true);
virtual ~btBvhTriangleMeshShape(); virtual ~btBvhTriangleMeshShape();
bool getOwnsBvh () const
/* {
return m_ownsBvh;
}
virtual int getShapeType() const virtual int getShapeType() const
{ {
return TRIANGLE_MESH_SHAPE_PROXYTYPE; return TRIANGLE_MESH_SHAPE_PROXYTYPE;
} }
*/
void performRaycast (btTriangleCallback* callback, const btVector3& raySource, const btVector3& rayTarget);
void performConvexcast (btTriangleCallback* callback, const btVector3& boxSource, const btVector3& boxTarget, const btVector3& boxMin, const btVector3& boxMax);
virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const; virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const;
void refitTree(); void refitTree(const btVector3& aabbMin,const btVector3& aabbMax);
///for a fast incremental refit of parts of the tree. Note: the entire AABB of the tree will become more conservative, it never shrinks ///for a fast incremental refit of parts of the tree. Note: the entire AABB of the tree will become more conservative, it never shrinks
void partialRefitTree(const btVector3& aabbMin,const btVector3& aabbMax); void partialRefitTree(const btVector3& aabbMin,const btVector3& aabbMax);
//debugging //debugging
virtual char* getName()const {return "BVHTRIANGLEMESH";} virtual const char* getName()const {return "BVHTRIANGLEMESH";}
virtual void setLocalScaling(const btVector3& scaling); virtual void setLocalScaling(const btVector3& scaling);
@@ -65,6 +75,10 @@ public:
{ {
return m_bvh; return m_bvh;
} }
void setOptimizedBvh(btOptimizedBvh* bvh, const btVector3& localScaling=btVector3(1,1,1));
bool usesQuantizedAabbCompression() const bool usesQuantizedAabbCompression() const
{ {
return m_useQuantizedAabbCompression; return m_useQuantizedAabbCompression;

View File

@@ -21,6 +21,7 @@ subject to the following restrictions:
btCapsuleShape::btCapsuleShape(btScalar radius, btScalar height) btCapsuleShape::btCapsuleShape(btScalar radius, btScalar height)
{ {
m_upAxis = 1;
m_implicitShapeDimensions.setValue(radius,0.5f*height,radius); m_implicitShapeDimensions.setValue(radius,0.5f*height,radius);
} }
@@ -50,7 +51,9 @@ btCapsuleShape::btCapsuleShape(btScalar radius, btScalar height)
{ {
btVector3 pos(0,getHalfHeight(),0); btVector3 pos(0,0,0);
pos[getUpAxis()] = getHalfHeight();
vtx = pos +vec*m_localScaling*(radius) - vec * getMargin(); vtx = pos +vec*m_localScaling*(radius) - vec * getMargin();
newDot = vec.dot(vtx); newDot = vec.dot(vtx);
if (newDot > maxDot) if (newDot > maxDot)
@@ -60,7 +63,9 @@ btCapsuleShape::btCapsuleShape(btScalar radius, btScalar height)
} }
} }
{ {
btVector3 pos(0,-getHalfHeight(),0); btVector3 pos(0,0,0);
pos[getUpAxis()] = -getHalfHeight();
vtx = pos +vec*m_localScaling*(radius) - vec * getMargin(); vtx = pos +vec*m_localScaling*(radius) - vec * getMargin();
newDot = vec.dot(vtx); newDot = vec.dot(vtx);
if (newDot > maxDot) if (newDot > maxDot)
@@ -88,7 +93,8 @@ btCapsuleShape::btCapsuleShape(btScalar radius, btScalar height)
btVector3 vtx; btVector3 vtx;
btScalar newDot; btScalar newDot;
{ {
btVector3 pos(0,getHalfHeight(),0); btVector3 pos(0,0,0);
pos[getUpAxis()] = getHalfHeight();
vtx = pos +vec*m_localScaling*(radius) - vec * getMargin(); vtx = pos +vec*m_localScaling*(radius) - vec * getMargin();
newDot = vec.dot(vtx); newDot = vec.dot(vtx);
if (newDot > maxDot) if (newDot > maxDot)
@@ -98,7 +104,8 @@ btCapsuleShape::btCapsuleShape(btScalar radius, btScalar height)
} }
} }
{ {
btVector3 pos(0,-getHalfHeight(),0); btVector3 pos(0,0,0);
pos[getUpAxis()] = -getHalfHeight();
vtx = pos +vec*m_localScaling*(radius) - vec * getMargin(); vtx = pos +vec*m_localScaling*(radius) - vec * getMargin();
newDot = vec.dot(vtx); newDot = vec.dot(vtx);
if (newDot > maxDot) if (newDot > maxDot)
@@ -112,7 +119,7 @@ btCapsuleShape::btCapsuleShape(btScalar radius, btScalar height)
} }
void btCapsuleShape::calculateLocalInertia(btScalar mass,btVector3& inertia) void btCapsuleShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const
{ {
//as an approximation, take the inertia of the box that bounds the spheres //as an approximation, take the inertia of the box that bounds the spheres
@@ -122,7 +129,8 @@ void btCapsuleShape::calculateLocalInertia(btScalar mass,btVector3& inertia)
btScalar radius = getRadius(); btScalar radius = getRadius();
btVector3 halfExtents(radius,radius+getHalfHeight(),radius); btVector3 halfExtents(radius,radius,radius);
halfExtents[getUpAxis()]+=getHalfHeight();
btScalar margin = CONVEX_DISTANCE_MARGIN; btScalar margin = CONVEX_DISTANCE_MARGIN;
@@ -140,6 +148,22 @@ void btCapsuleShape::calculateLocalInertia(btScalar mass,btVector3& inertia)
} }
btCapsuleShapeX::btCapsuleShapeX(btScalar radius,btScalar height)
{
m_upAxis = 0;
m_implicitShapeDimensions.setValue(0.5f*height, radius,radius);
}
btCapsuleShapeZ::btCapsuleShapeZ(btScalar radius,btScalar height)
{
m_upAxis = 2;
m_implicitShapeDimensions.setValue(radius,radius,0.5f*height);
}

View File

@@ -16,20 +16,27 @@ subject to the following restrictions:
#ifndef BT_CAPSULE_SHAPE_H #ifndef BT_CAPSULE_SHAPE_H
#define BT_CAPSULE_SHAPE_H #define BT_CAPSULE_SHAPE_H
#include "btConvexShape.h" #include "btConvexInternalShape.h"
#include "../BroadphaseCollision/btBroadphaseProxy.h" // for the types #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types
///btCapsuleShape represents a capsule around the Y axis ///The btCapsuleShape represents a capsule around the Y axis, there is also the btCapsuleShapeX aligned around the X axis and btCapsuleShapeZ around the Z axis.
///A more general solution that can represent capsules is the btMultiSphereShape ///The total height is height+2*radius, so the height is just the height between the center of each 'sphere' of the capsule caps.
class btCapsuleShape : public btConvexShape ///The btCapsuleShape is a convex hull of two spheres. The btMultiSphereShape is a more general collision shape that takes the convex hull of multiple sphere, so it can also represent a capsule when just using two spheres.
class btCapsuleShape : public btConvexInternalShape
{ {
protected:
int m_upAxis;
protected:
///only used for btCapsuleShapeZ and btCapsuleShapeX subclasses.
btCapsuleShape() {};
public: public:
btCapsuleShape(btScalar radius,btScalar height); btCapsuleShape(btScalar radius,btScalar height);
///CollisionShape Interface ///CollisionShape Interface
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia); virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const;
/// btConvexShape Interface /// btConvexShape Interface
virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const;
@@ -38,23 +45,75 @@ public:
virtual int getShapeType() const { return CAPSULE_SHAPE_PROXYTYPE; } virtual int getShapeType() const { return CAPSULE_SHAPE_PROXYTYPE; }
virtual char* getName()const virtual void getAabb (const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const
{
btVector3 halfExtents(getRadius(),getRadius(),getRadius());
halfExtents[m_upAxis] = getRadius() + getHalfHeight();
btMatrix3x3 abs_b = t.getBasis().absolute();
btPoint3 center = t.getOrigin();
btVector3 extent = btVector3(abs_b[0].dot(halfExtents),abs_b[1].dot(halfExtents),abs_b[2].dot(halfExtents));
extent += btVector3(getMargin(),getMargin(),getMargin());
aabbMin = center - extent;
aabbMax = center + extent;
}
virtual const char* getName()const
{ {
return "CapsuleShape"; return "CapsuleShape";
} }
int getUpAxis() const
{
return m_upAxis;
}
btScalar getRadius() const btScalar getRadius() const
{ {
return m_implicitShapeDimensions.getX(); int radiusAxis = (m_upAxis+2)%3;
return m_implicitShapeDimensions[radiusAxis];
} }
btScalar getHalfHeight() const btScalar getHalfHeight() const
{ {
return m_implicitShapeDimensions.getY(); return m_implicitShapeDimensions[m_upAxis];
} }
}; };
///btCapsuleShapeX represents a capsule around the Z axis
///the total height is height+2*radius, so the height is just the height between the center of each 'sphere' of the capsule caps.
class btCapsuleShapeX : public btCapsuleShape
{
public:
btCapsuleShapeX(btScalar radius,btScalar height);
//debugging
virtual const char* getName()const
{
return "CapsuleX";
}
};
///btCapsuleShapeZ represents a capsule around the Z axis
///the total height is height+2*radius, so the height is just the height between the center of each 'sphere' of the capsule caps.
class btCapsuleShapeZ : public btCapsuleShape
{
public:
btCapsuleShapeZ(btScalar radius,btScalar height);
//debugging
virtual const char* getName()const
{
return "CapsuleZ";
}
};
#endif //BT_CAPSULE_SHAPE_H #endif //BT_CAPSULE_SHAPE_H

View File

@@ -21,7 +21,12 @@ subject to the following restrictions:
can be used by probes that are checking whether the can be used by probes that are checking whether the
library is actually installed. library is actually installed.
*/ */
extern "C" void btBulletCollisionProbe () {} extern "C"
{
void btBulletCollisionProbe ();
void btBulletCollisionProbe () {}
}
@@ -46,7 +51,7 @@ btScalar btCollisionShape::getAngularMotionDisc() const
return disc; return disc;
} }
void btCollisionShape::calculateTemporalAabb(const btTransform& curTrans,const btVector3& linvel,const btVector3& angvel,btScalar timeStep, btVector3& temporalAabbMin,btVector3& temporalAabbMax) void btCollisionShape::calculateTemporalAabb(const btTransform& curTrans,const btVector3& linvel,const btVector3& angvel,btScalar timeStep, btVector3& temporalAabbMin,btVector3& temporalAabbMax) const
{ {
//start with static aabb //start with static aabb
getAabb(curTrans,temporalAabbMin,temporalAabbMax); getAabb(curTrans,temporalAabbMin,temporalAabbMax);

View File

@@ -16,18 +16,21 @@ subject to the following restrictions:
#ifndef COLLISION_SHAPE_H #ifndef COLLISION_SHAPE_H
#define COLLISION_SHAPE_H #define COLLISION_SHAPE_H
#include "../../LinearMath/btTransform.h" #include "LinearMath/btTransform.h"
#include "../../LinearMath/btVector3.h" #include "LinearMath/btVector3.h"
#include "../../LinearMath/btMatrix3x3.h" #include "LinearMath/btMatrix3x3.h"
#include "../../LinearMath/btPoint3.h" #include "LinearMath/btPoint3.h"
#include "../BroadphaseCollision/btBroadphaseProxy.h" //for the shape types #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" //for the shape types
///btCollisionShape provides interface for collision shapes that can be shared among btCollisionObjects. ///The btCollisionShape class provides an interface for collision shapes that can be shared among btCollisionObjects.
class btCollisionShape class btCollisionShape
{ {
void* m_userPointer;
public: public:
btCollisionShape() btCollisionShape() : m_userPointer(0)
{ {
} }
virtual ~btCollisionShape() virtual ~btCollisionShape()
@@ -45,30 +48,30 @@ public:
///calculateTemporalAabb calculates the enclosing aabb for the moving object over interval [0..timeStep) ///calculateTemporalAabb calculates the enclosing aabb for the moving object over interval [0..timeStep)
///result is conservative ///result is conservative
void calculateTemporalAabb(const btTransform& curTrans,const btVector3& linvel,const btVector3& angvel,btScalar timeStep, btVector3& temporalAabbMin,btVector3& temporalAabbMax); void calculateTemporalAabb(const btTransform& curTrans,const btVector3& linvel,const btVector3& angvel,btScalar timeStep, btVector3& temporalAabbMin,btVector3& temporalAabbMax) const;
#ifndef __SPU__ #ifndef __SPU__
inline bool isPolyhedral() const SIMD_FORCE_INLINE bool isPolyhedral() const
{ {
return btBroadphaseProxy::isPolyhedral(getShapeType()); return btBroadphaseProxy::isPolyhedral(getShapeType());
} }
inline bool isConvex() const SIMD_FORCE_INLINE bool isConvex() const
{ {
return btBroadphaseProxy::isConvex(getShapeType()); return btBroadphaseProxy::isConvex(getShapeType());
} }
inline bool isConcave() const SIMD_FORCE_INLINE bool isConcave() const
{ {
return btBroadphaseProxy::isConcave(getShapeType()); return btBroadphaseProxy::isConcave(getShapeType());
} }
inline bool isCompound() const SIMD_FORCE_INLINE bool isCompound() const
{ {
return btBroadphaseProxy::isCompound(getShapeType()); return btBroadphaseProxy::isCompound(getShapeType());
} }
///isInfinite is used to catch simulation error (aabb check) ///isInfinite is used to catch simulation error (aabb check)
inline bool isInfinite() const SIMD_FORCE_INLINE bool isInfinite() const
{ {
return btBroadphaseProxy::isInfinite(getShapeType()); return btBroadphaseProxy::isInfinite(getShapeType());
} }
@@ -76,11 +79,11 @@ public:
virtual int getShapeType() const=0; virtual int getShapeType() const=0;
virtual void setLocalScaling(const btVector3& scaling) =0; virtual void setLocalScaling(const btVector3& scaling) =0;
virtual const btVector3& getLocalScaling() const =0; virtual const btVector3& getLocalScaling() const =0;
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) = 0; virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const = 0;
//debugging support //debugging support
virtual char* getName()const =0 ; virtual const char* getName()const =0 ;
#endif //__SPU__ #endif //__SPU__
@@ -88,6 +91,18 @@ public:
virtual void setMargin(btScalar margin) = 0; virtual void setMargin(btScalar margin) = 0;
virtual btScalar getMargin() const = 0; virtual btScalar getMargin() const = 0;
///optional user data pointer
void setUserPointer(void* userPtr)
{
m_userPointer = userPtr;
}
void* getUserPointer() const
{
return m_userPointer;
}
}; };
#endif //COLLISION_SHAPE_H #endif //COLLISION_SHAPE_H

View File

@@ -35,8 +35,15 @@ btCompoundShape::~btCompoundShape()
void btCompoundShape::addChildShape(const btTransform& localTransform,btCollisionShape* shape) void btCompoundShape::addChildShape(const btTransform& localTransform,btCollisionShape* shape)
{ {
m_childTransforms.push_back(localTransform); //m_childTransforms.push_back(localTransform);
m_childShapes.push_back(shape); //m_childShapes.push_back(shape);
btCompoundShapeChild child;
child.m_transform = localTransform;
child.m_childShape = shape;
child.m_childShapeType = shape->getShapeType();
child.m_childMargin = shape->getMargin();
m_children.push_back(child);
//extend the local aabbMin/aabbMax //extend the local aabbMin/aabbMax
btVector3 localAabbMin,localAabbMax; btVector3 localAabbMin,localAabbMax;
@@ -55,9 +62,53 @@ void btCompoundShape::addChildShape(const btTransform& localTransform,btCollisio
} }
} }
void btCompoundShape::removeChildShape(btCollisionShape* shape)
{
bool done_removing;
// Find the children containing the shape specified, and remove those children.
do
{
done_removing = true;
for(int i = 0; i < m_children.size(); i++)
{
if(m_children[i].m_childShape == shape)
{
m_children.remove(m_children[i]);
done_removing = false; // Do another iteration pass after removing from the vector
break;
}
}
}
while (!done_removing);
recalculateLocalAabb();
}
void btCompoundShape::recalculateLocalAabb()
///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version {
// Recalculate the local aabb
// Brute force, it iterates over all the shapes left.
m_localAabbMin = btVector3(btScalar(1e30),btScalar(1e30),btScalar(1e30));
m_localAabbMax = btVector3(btScalar(-1e30),btScalar(-1e30),btScalar(-1e30));
//extend the local aabbMin/aabbMax
for (int j = 0; j < m_children.size(); j++)
{
btVector3 localAabbMin,localAabbMax;
m_children[j].m_childShape->getAabb(m_children[j].m_transform, localAabbMin, localAabbMax);
for (int i=0;i<3;i++)
{
if (m_localAabbMin[i] > localAabbMin[i])
m_localAabbMin[i] = localAabbMin[i];
if (m_localAabbMax[i] < localAabbMax[i])
m_localAabbMax[i] = localAabbMax[i];
}
}
}
///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version
void btCompoundShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax) const void btCompoundShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax) const
{ {
btVector3 localHalfExtents = btScalar(0.5)*(m_localAabbMax-m_localAabbMin); btVector3 localHalfExtents = btScalar(0.5)*(m_localAabbMax-m_localAabbMin);
@@ -76,7 +127,7 @@ void btCompoundShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVect
aabbMax = center + extent; aabbMax = center + extent;
} }
void btCompoundShape::calculateLocalInertia(btScalar mass,btVector3& inertia) void btCompoundShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const
{ {
//approximation: take the inertia from the aabb for now //approximation: take the inertia from the aabb for now
btTransform ident; btTransform ident;

View File

@@ -18,58 +18,95 @@ subject to the following restrictions:
#include "btCollisionShape.h" #include "btCollisionShape.h"
#include "../../LinearMath/btVector3.h" #include "LinearMath/btVector3.h"
#include "../../LinearMath/btTransform.h" #include "LinearMath/btTransform.h"
#include "../../LinearMath/btMatrix3x3.h" #include "LinearMath/btMatrix3x3.h"
#include "btCollisionMargin.h" #include "btCollisionMargin.h"
#include "../../LinearMath/btAlignedObjectArray.h" #include "LinearMath/btAlignedObjectArray.h"
class btOptimizedBvh; class btOptimizedBvh;
/// btCompoundShape allows to store multiple other btCollisionShapes
/// This allows for concave collision objects. This is more general then the Static Concave btTriangleMeshShape. ATTRIBUTE_ALIGNED16(struct) btCompoundShapeChild
class btCompoundShape : public btCollisionShape
{ {
btAlignedObjectArray<btTransform> m_childTransforms; BT_DECLARE_ALIGNED_ALLOCATOR();
btAlignedObjectArray<btCollisionShape*> m_childShapes;
btTransform m_transform;
btCollisionShape* m_childShape;
int m_childShapeType;
btScalar m_childMargin;
};
SIMD_FORCE_INLINE bool operator==(const btCompoundShapeChild& c1, const btCompoundShapeChild& c2)
{
return ( c1.m_transform == c2.m_transform &&
c1.m_childShape == c2.m_childShape &&
c1.m_childShapeType == c2.m_childShapeType &&
c1.m_childMargin == c2.m_childMargin );
}
/// btCompoundShape allows to store multiple other btCollisionShapes
/// This allows for moving concave collision objects. This is more general then the static concave btBvhTriangleMeshShape.
ATTRIBUTE_ALIGNED16(class) btCompoundShape : public btCollisionShape
{
//btAlignedObjectArray<btTransform> m_childTransforms;
//btAlignedObjectArray<btCollisionShape*> m_childShapes;
btAlignedObjectArray<btCompoundShapeChild> m_children;
btVector3 m_localAabbMin; btVector3 m_localAabbMin;
btVector3 m_localAabbMax; btVector3 m_localAabbMax;
btOptimizedBvh* m_aabbTree; btOptimizedBvh* m_aabbTree;
public: public:
BT_DECLARE_ALIGNED_ALLOCATOR();
btCompoundShape(); btCompoundShape();
virtual ~btCompoundShape(); virtual ~btCompoundShape();
void addChildShape(const btTransform& localTransform,btCollisionShape* shape); void addChildShape(const btTransform& localTransform,btCollisionShape* shape);
/** Remove all children shapes that contain the specified shape. */
virtual void removeChildShape(btCollisionShape* shape);
int getNumChildShapes() const int getNumChildShapes() const
{ {
return int (m_childShapes.size()); return int (m_children.size());
} }
btCollisionShape* getChildShape(int index) btCollisionShape* getChildShape(int index)
{ {
return m_childShapes[index]; return m_children[index].m_childShape;
} }
const btCollisionShape* getChildShape(int index) const const btCollisionShape* getChildShape(int index) const
{ {
return m_childShapes[index]; return m_children[index].m_childShape;
} }
btTransform& getChildTransform(int index) btTransform getChildTransform(int index)
{ {
return m_childTransforms[index]; return m_children[index].m_transform;
} }
const btTransform& getChildTransform(int index) const const btTransform getChildTransform(int index) const
{ {
return m_childTransforms[index]; return m_children[index].m_transform;
}
btCompoundShapeChild* getChildList()
{
return &m_children[0];
} }
///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version
void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const;
/** Re-calculate the local Aabb. Is called at the end of removeChildShapes.
Use this yourself if you modify the children or their transforms. */
virtual void recalculateLocalAabb();
virtual void setLocalScaling(const btVector3& scaling) virtual void setLocalScaling(const btVector3& scaling)
{ {
@@ -80,7 +117,7 @@ public:
return m_localScaling; return m_localScaling;
} }
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia); virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const;
virtual int getShapeType() const { return COMPOUND_SHAPE_PROXYTYPE;} virtual int getShapeType() const { return COMPOUND_SHAPE_PROXYTYPE;}
@@ -92,7 +129,7 @@ public:
{ {
return m_collisionMargin; return m_collisionMargin;
} }
virtual char* getName()const virtual const char* getName()const
{ {
return "Compound"; return "Compound";
} }

View File

@@ -17,12 +17,12 @@ subject to the following restrictions:
#define CONCAVE_SHAPE_H #define CONCAVE_SHAPE_H
#include "btCollisionShape.h" #include "btCollisionShape.h"
#include "../BroadphaseCollision/btBroadphaseProxy.h" // for the types #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types
#include "btTriangleCallback.h" #include "btTriangleCallback.h"
///Concave shape proves an interface concave shapes that can produce triangles that overlapping a given AABB. ///The btConcaveShape class provides an interface for non-moving (static) concave shapes.
///Static triangle mesh, infinite plane, height field/landscapes are example that implement this interface. ///It has been implemented by the btStaticPlaneShape, btBvhTriangleMeshShape and btHeightfieldTerrainShape.
class btConcaveShape : public btCollisionShape class btConcaveShape : public btCollisionShape
{ {
protected: protected:

View File

@@ -16,11 +16,11 @@ subject to the following restrictions:
#ifndef CONE_MINKOWSKI_H #ifndef CONE_MINKOWSKI_H
#define CONE_MINKOWSKI_H #define CONE_MINKOWSKI_H
#include "btConvexShape.h" #include "btConvexInternalShape.h"
#include "../BroadphaseCollision/btBroadphaseProxy.h" // for the types #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types
///btConeShape implements a Cone shape, around the Y axis ///The btConeShape implements a cone shape primitive, centered around the origin and aligned with the Y axis. The btConeShapeX is aligned around the X axis and btConeShapeZ around the Z axis.
class btConeShape : public btConvexShape class btConeShape : public btConvexInternalShape
{ {
@@ -42,7 +42,7 @@ public:
btScalar getHeight() const { return m_height;} btScalar getHeight() const { return m_height;}
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const
{ {
btTransform identity; btTransform identity;
identity.setIdentity(); identity.setIdentity();
@@ -72,7 +72,7 @@ public:
virtual int getShapeType() const { return CONE_SHAPE_PROXYTYPE; } virtual int getShapeType() const { return CONE_SHAPE_PROXYTYPE; }
virtual char* getName()const virtual const char* getName()const
{ {
return "Cone"; return "Cone";
} }

View File

@@ -17,18 +17,17 @@ subject to the following restrictions:
#define CONVEX_HULL_SHAPE_H #define CONVEX_HULL_SHAPE_H
#include "btPolyhedralConvexShape.h" #include "btPolyhedralConvexShape.h"
#include "../BroadphaseCollision/btBroadphaseProxy.h" // for the types #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types
#include "../../LinearMath/btAlignedObjectArray.h" #include "LinearMath/btAlignedObjectArray.h"
///ConvexHullShape implements an implicit (getSupportingVertex) Convex Hull of a Point Cloud (vertices) ///The btConvexHullShape implements an implicit convex hull of an array of vertices.
///No connectivity is needed. localGetSupportingVertex iterates linearly though all vertices. ///Bullet provides a general and fast collision detector for convex shapes based on GJK and EPA using localGetSupportingVertex.
///on modern hardware, due to cache coherency this isn't that bad. Complex algorithms tend to trash the cash.
///(memory is much slower then the cpu)
ATTRIBUTE_ALIGNED16(class) btConvexHullShape : public btPolyhedralConvexShape ATTRIBUTE_ALIGNED16(class) btConvexHullShape : public btPolyhedralConvexShape
{ {
btAlignedObjectArray<btPoint3> m_points; btAlignedObjectArray<btPoint3> m_points;
public: public:
BT_DECLARE_ALIGNED_ALLOCATOR();
///this constructor optionally takes in a pointer to points. Each point is assumed to be 3 consecutive btScalar (x,y,z), the striding defines the number of bytes between each point, in memory. ///this constructor optionally takes in a pointer to points. Each point is assumed to be 3 consecutive btScalar (x,y,z), the striding defines the number of bytes between each point, in memory.
@@ -43,7 +42,12 @@ public:
return &m_points[0]; return &m_points[0];
} }
int getNumPoints() const btPoint3* getPoints() const
{
return &m_points[0];
}
int getNumPoints() const
{ {
return m_points.size(); return m_points.size();
} }
@@ -56,7 +60,7 @@ public:
virtual int getShapeType()const { return CONVEX_HULL_SHAPE_PROXYTYPE; } virtual int getShapeType()const { return CONVEX_HULL_SHAPE_PROXYTYPE; }
//debugging //debugging
virtual char* getName()const {return "Convex";} virtual const char* getName()const {return "Convex";}
virtual int getNumVertices() const; virtual int getNumVertices() const;

View File

@@ -0,0 +1,78 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "btConvexInternalShape.h"
btConvexInternalShape::btConvexInternalShape()
: m_localScaling(btScalar(1.),btScalar(1.),btScalar(1.)),
m_collisionMargin(CONVEX_DISTANCE_MARGIN)
{
}
void btConvexInternalShape::setLocalScaling(const btVector3& scaling)
{
m_localScaling = scaling;
}
void btConvexInternalShape::getAabbSlow(const btTransform& trans,btVector3&minAabb,btVector3&maxAabb) const
{
btScalar margin = getMargin();
for (int i=0;i<3;i++)
{
btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.));
vec[i] = btScalar(1.);
btVector3 sv = localGetSupportingVertex(vec*trans.getBasis());
btVector3 tmp = trans(sv);
maxAabb[i] = tmp[i]+margin;
vec[i] = btScalar(-1.);
tmp = trans(localGetSupportingVertex(vec*trans.getBasis()));
minAabb[i] = tmp[i]-margin;
}
};
btVector3 btConvexInternalShape::localGetSupportingVertex(const btVector3& vec)const
{
#ifndef __SPU__
btVector3 supVertex = localGetSupportingVertexWithoutMargin(vec);
if ( getMargin()!=btScalar(0.) )
{
btVector3 vecnorm = vec;
if (vecnorm .length2() < (SIMD_EPSILON*SIMD_EPSILON))
{
vecnorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.));
}
vecnorm.normalize();
supVertex+= getMargin() * vecnorm;
}
return supVertex;
#else
return btVector3(0,0,0);
#endif //__SPU__
}

View File

@@ -0,0 +1,98 @@
#ifndef BT_CONVEX_INTERNAL_SHAPE_H
#define BT_CONVEX_INTERNAL_SHAPE_H
#include "btConvexShape.h"
///The btConvexInternalShape is an internal base class, shared by most convex shape implementations.
class btConvexInternalShape : public btConvexShape
{
protected:
//local scaling. collisionMargin is not scaled !
btVector3 m_localScaling;
btVector3 m_implicitShapeDimensions;
btScalar m_collisionMargin;
btScalar m_padding;
public:
btConvexInternalShape();
virtual ~btConvexInternalShape()
{
}
virtual btVector3 localGetSupportingVertex(const btVector3& vec)const;
#ifndef __SPU__
virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec) const= 0;
//notice that the vectors should be unit length
virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const= 0;
#endif //#ifndef __SPU__
const btVector3& getImplicitShapeDimensions() const
{
return m_implicitShapeDimensions;
}
///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version
void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const
{
getAabbSlow(t,aabbMin,aabbMax);
}
virtual void getAabbSlow(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const;
virtual void setLocalScaling(const btVector3& scaling);
virtual const btVector3& getLocalScaling() const
{
return m_localScaling;
}
const btVector3& getLocalScalingNV() const
{
return m_localScaling;
}
virtual void setMargin(btScalar margin)
{
m_collisionMargin = margin;
}
virtual btScalar getMargin() const
{
return m_collisionMargin;
}
btScalar getMarginNV() const
{
return m_collisionMargin;
}
virtual int getNumPreferredPenetrationDirections() const
{
return 0;
}
virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const
{
(void)penetrationVector;
(void)index;
btAssert(0);
}
};
#endif //BT_CONVEX_INTERNAL_SHAPE_H

View File

@@ -16,62 +16,3 @@ subject to the following restrictions:
#include "btConvexShape.h" #include "btConvexShape.h"
btConvexShape::btConvexShape()
: m_localScaling(btScalar(1.),btScalar(1.),btScalar(1.)),
m_collisionMargin(CONVEX_DISTANCE_MARGIN)
{
}
void btConvexShape::setLocalScaling(const btVector3& scaling)
{
m_localScaling = scaling;
}
void btConvexShape::getAabbSlow(const btTransform& trans,btVector3&minAabb,btVector3&maxAabb) const
{
btScalar margin = getMargin();
for (int i=0;i<3;i++)
{
btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.));
vec[i] = btScalar(1.);
btVector3 sv = localGetSupportingVertex(vec*trans.getBasis());
btVector3 tmp = trans(sv);
maxAabb[i] = tmp[i]+margin;
vec[i] = btScalar(-1.);
tmp = trans(localGetSupportingVertex(vec*trans.getBasis()));
minAabb[i] = tmp[i]-margin;
}
};
btVector3 btConvexShape::localGetSupportingVertex(const btVector3& vec)const
{
#ifndef __SPU__
btVector3 supVertex = localGetSupportingVertexWithoutMargin(vec);
if ( getMargin()!=btScalar(0.) )
{
btVector3 vecnorm = vec;
if (vecnorm .length2() < (SIMD_EPSILON*SIMD_EPSILON))
{
vecnorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.));
}
vecnorm.normalize();
supVertex+= getMargin() * vecnorm;
}
return supVertex;
#else
return btVector3(0,0,0);
#endif //__SPU__
}

View File

@@ -18,37 +18,25 @@ subject to the following restrictions:
#include "btCollisionShape.h" #include "btCollisionShape.h"
#include "../../LinearMath/btVector3.h" #include "LinearMath/btVector3.h"
#include "../../LinearMath/btTransform.h" #include "LinearMath/btTransform.h"
#include "../../LinearMath/btMatrix3x3.h" #include "LinearMath/btMatrix3x3.h"
#include "btCollisionMargin.h" #include "btCollisionMargin.h"
#include "LinearMath/btAlignedAllocator.h"
//todo: get rid of this btConvexCastResult thing! //todo: get rid of this btConvexCastResult thing!
struct btConvexCastResult; struct btConvexCastResult;
#define MAX_PREFERRED_PENETRATION_DIRECTIONS 10 #define MAX_PREFERRED_PENETRATION_DIRECTIONS 10
/// btConvexShape is an abstract shape interface. /// The btConvexShape is an abstract shape interface, implemented by all convex shapes such as btBoxShape, btConvexHullShape etc.
/// The explicit part provides plane-equations, the implicit part provides GetClosestPoint interface. /// It describes general convex shapes using the localGetSupportingVertex interface, used by collision detectors such as btGjkPairDetector.
/// used in combination with GJK or btConvexCast
ATTRIBUTE_ALIGNED16(class) btConvexShape : public btCollisionShape ATTRIBUTE_ALIGNED16(class) btConvexShape : public btCollisionShape
{ {
protected:
//local scaling. collisionMargin is not scaled !
btVector3 m_localScaling;
btVector3 m_implicitShapeDimensions;
btScalar m_collisionMargin;
btScalar m_padding[2];
public: public:
btConvexShape();
BT_DECLARE_ALIGNED_ALLOCATOR();
virtual ~btConvexShape() virtual ~btConvexShape()
{ {
@@ -56,7 +44,7 @@ public:
} }
virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; virtual btVector3 localGetSupportingVertex(const btVector3& vec)const =0;
#ifndef __SPU__ #ifndef __SPU__
virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec) const= 0; virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec) const= 0;
@@ -64,63 +52,24 @@ public:
virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const= 0; virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const= 0;
#endif //#ifndef __SPU__ #endif //#ifndef __SPU__
const btVector3& getImplicitShapeDimensions() const
{
return m_implicitShapeDimensions;
}
///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version
void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const =0;
{
getAabbSlow(t,aabbMin,aabbMax);
}
virtual void getAabbSlow(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const =0;
virtual void setLocalScaling(const btVector3& scaling) =0;
virtual const btVector3& getLocalScaling() const =0;
virtual void setMargin(btScalar margin)=0;
virtual btScalar getMargin() const=0;
virtual int getNumPreferredPenetrationDirections() const=0;
virtual void getAabbSlow(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const=0;
};
virtual void setLocalScaling(const btVector3& scaling);
virtual const btVector3& getLocalScaling() const
{
return m_localScaling;
}
const btVector3& getLocalScalingNV() const
{
return m_localScaling;
}
virtual void setMargin(btScalar margin)
{
m_collisionMargin = margin;
}
virtual btScalar getMargin() const
{
return m_collisionMargin;
}
btScalar getMarginNV() const
{
return m_collisionMargin;
}
virtual int getNumPreferredPenetrationDirections() const
{
return 0;
}
virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const
{
(void)penetrationVector;
(void)index;
btAssert(0);
}
}
;

View File

@@ -19,10 +19,11 @@ subject to the following restrictions:
#include "BulletCollision/CollisionShapes/btStridingMeshInterface.h" #include "BulletCollision/CollisionShapes/btStridingMeshInterface.h"
btConvexTriangleMeshShape ::btConvexTriangleMeshShape (btStridingMeshInterface* meshInterface) btConvexTriangleMeshShape ::btConvexTriangleMeshShape (btStridingMeshInterface* meshInterface, bool calcAabb)
:m_stridingMesh(meshInterface) :m_stridingMesh(meshInterface)
{ {
recalcLocalAabb(); if ( calcAabb )
recalcLocalAabb();
} }

View File

@@ -3,20 +3,24 @@
#include "btPolyhedralConvexShape.h" #include "btPolyhedralConvexShape.h"
#include "../BroadphaseCollision/btBroadphaseProxy.h" // for the types #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types
/// btConvexTriangleMeshShape is a convex hull of a triangle mesh. If you just have a point cloud, you can use btConvexHullShape instead. /// The btConvexTriangleMeshShape is a convex hull of a triangle mesh, but the performance is not as good as btConvexHullShape.
/// It uses the btStridingMeshInterface instead of a point cloud. This can avoid the duplication of the triangle mesh data. /// A small benefit of this class is that it uses the btStridingMeshInterface, so you can avoid the duplication of the triangle mesh data. Nevertheless, most users should use the much better performing btConvexHullShape instead.
class btConvexTriangleMeshShape : public btPolyhedralConvexShape class btConvexTriangleMeshShape : public btPolyhedralConvexShape
{ {
class btStridingMeshInterface* m_stridingMesh; class btStridingMeshInterface* m_stridingMesh;
public: public:
btConvexTriangleMeshShape(btStridingMeshInterface* meshInterface); btConvexTriangleMeshShape(btStridingMeshInterface* meshInterface, bool calcAabb = true);
class btStridingMeshInterface* getStridingMesh() class btStridingMeshInterface* getMeshInterface()
{
return m_stridingMesh;
}
const class btStridingMeshInterface* getMeshInterface() const
{ {
return m_stridingMesh; return m_stridingMesh;
} }
@@ -28,7 +32,7 @@ public:
virtual int getShapeType()const { return CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE; } virtual int getShapeType()const { return CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE; }
//debugging //debugging
virtual char* getName()const {return "ConvexTrimesh";} virtual const char* getName()const {return "ConvexTrimesh";}
virtual int getNumVertices() const; virtual int getNumVertices() const;
virtual int getNumEdges() const; virtual int getNumEdges() const;
@@ -49,3 +53,4 @@ public:
#endif //CONVEX_TRIANGLEMESH_SHAPE_H #endif //CONVEX_TRIANGLEMESH_SHAPE_H

View File

@@ -45,7 +45,7 @@ void btCylinderShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3&
} }
inline btVector3 CylinderLocalSupportX(const btVector3& halfExtents,const btVector3& v) SIMD_FORCE_INLINE btVector3 CylinderLocalSupportX(const btVector3& halfExtents,const btVector3& v)
{ {
const int cylinderUpAxis = 0; const int cylinderUpAxis = 0;
const int XX = 1; const int XX = 1;
@@ -163,24 +163,24 @@ const int ZZ = 1;
btVector3 btCylinderShapeX::localGetSupportingVertexWithoutMargin(const btVector3& vec)const btVector3 btCylinderShapeX::localGetSupportingVertexWithoutMargin(const btVector3& vec)const
{ {
return CylinderLocalSupportX(getHalfExtents(),vec); return CylinderLocalSupportX(getHalfExtentsWithoutMargin(),vec);
} }
btVector3 btCylinderShapeZ::localGetSupportingVertexWithoutMargin(const btVector3& vec)const btVector3 btCylinderShapeZ::localGetSupportingVertexWithoutMargin(const btVector3& vec)const
{ {
return CylinderLocalSupportZ(getHalfExtents(),vec); return CylinderLocalSupportZ(getHalfExtentsWithoutMargin(),vec);
} }
btVector3 btCylinderShape::localGetSupportingVertexWithoutMargin(const btVector3& vec)const btVector3 btCylinderShape::localGetSupportingVertexWithoutMargin(const btVector3& vec)const
{ {
return CylinderLocalSupportY(getHalfExtents(),vec); return CylinderLocalSupportY(getHalfExtentsWithoutMargin(),vec);
} }
void btCylinderShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const void btCylinderShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const
{ {
for (int i=0;i<numVectors;i++) for (int i=0;i<numVectors;i++)
{ {
supportVerticesOut[i] = CylinderLocalSupportY(getHalfExtents(),vectors[i]); supportVerticesOut[i] = CylinderLocalSupportY(getHalfExtentsWithoutMargin(),vectors[i]);
} }
} }
@@ -188,7 +188,7 @@ void btCylinderShapeZ::batchedUnitVectorGetSupportingVertexWithoutMargin(const b
{ {
for (int i=0;i<numVectors;i++) for (int i=0;i<numVectors;i++)
{ {
supportVerticesOut[i] = CylinderLocalSupportZ(getHalfExtents(),vectors[i]); supportVerticesOut[i] = CylinderLocalSupportZ(getHalfExtentsWithoutMargin(),vectors[i]);
} }
} }
@@ -199,7 +199,7 @@ void btCylinderShapeX::batchedUnitVectorGetSupportingVertexWithoutMargin(const b
{ {
for (int i=0;i<numVectors;i++) for (int i=0;i<numVectors;i++)
{ {
supportVerticesOut[i] = CylinderLocalSupportX(getHalfExtents(),vectors[i]); supportVerticesOut[i] = CylinderLocalSupportX(getHalfExtentsWithoutMargin(),vectors[i]);
} }
} }

View File

@@ -17,10 +17,10 @@ subject to the following restrictions:
#define CYLINDER_MINKOWSKI_H #define CYLINDER_MINKOWSKI_H
#include "btBoxShape.h" #include "btBoxShape.h"
#include "../BroadphaseCollision/btBroadphaseProxy.h" // for the types #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types
#include "../../LinearMath/btVector3.h" #include "LinearMath/btVector3.h"
/// implements cylinder shape interface /// The btCylinderShape class implements a cylinder shape primitive, centered around the origin. Its central axis aligned with the Y axis. btCylinderShapeX is aligned with the X axis and btCylinderShapeZ around the Z axis.
class btCylinderShape : public btBoxShape class btCylinderShape : public btBoxShape
{ {
@@ -60,7 +60,7 @@ public:
//use box inertia //use box inertia
// virtual void calculateLocalInertia(btScalar mass,btVector3& inertia); // virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const;
virtual int getShapeType() const virtual int getShapeType() const
{ {
@@ -74,11 +74,11 @@ public:
virtual btScalar getRadius() const virtual btScalar getRadius() const
{ {
return getHalfExtents().getX(); return getHalfExtentsWithMargin().getX();
} }
//debugging //debugging
virtual char* getName()const virtual const char* getName()const
{ {
return "CylinderY"; return "CylinderY";
} }
@@ -96,14 +96,14 @@ public:
virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const;
//debugging //debugging
virtual char* getName()const virtual const char* getName()const
{ {
return "CylinderX"; return "CylinderX";
} }
virtual btScalar getRadius() const virtual btScalar getRadius() const
{ {
return getHalfExtents().getY(); return getHalfExtentsWithMargin().getY();
} }
}; };
@@ -121,14 +121,14 @@ public:
return 2; return 2;
} }
//debugging //debugging
virtual char* getName()const virtual const char* getName()const
{ {
return "CylinderZ"; return "CylinderZ";
} }
virtual btScalar getRadius() const virtual btScalar getRadius() const
{ {
return getHalfExtents().getX(); return getHalfExtentsWithMargin().getX();
} }
}; };

View File

@@ -40,7 +40,7 @@ void btEmptyShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aa
} }
void btEmptyShape::calculateLocalInertia(btScalar ,btVector3& ) void btEmptyShape::calculateLocalInertia(btScalar ,btVector3& ) const
{ {
btAssert(0); btAssert(0);
} }

View File

@@ -18,16 +18,16 @@ subject to the following restrictions:
#include "btConcaveShape.h" #include "btConcaveShape.h"
#include "../../LinearMath/btVector3.h" #include "LinearMath/btVector3.h"
#include "../../LinearMath/btTransform.h" #include "LinearMath/btTransform.h"
#include "../../LinearMath/btMatrix3x3.h" #include "LinearMath/btMatrix3x3.h"
#include "btCollisionMargin.h" #include "btCollisionMargin.h"
/// btEmptyShape is a collision shape without actual collision detection. /// The btEmptyShape is a collision shape without actual collision detection shape, so most users should ignore this class.
///It can be replaced by another shape during runtime /// It can be replaced by another shape during runtime, but the inertia tensor should be recomputed.
class btEmptyShape : public btConcaveShape class btEmptyShape : public btConcaveShape
{ {
public: public:
@@ -49,12 +49,12 @@ public:
return m_localScaling; return m_localScaling;
} }
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia); virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const;
virtual int getShapeType() const { return EMPTY_SHAPE_PROXYTYPE;} virtual int getShapeType() const { return EMPTY_SHAPE_PROXYTYPE;}
virtual char* getName()const virtual const char* getName()const
{ {
return "Empty"; return "Empty";
} }

View File

@@ -18,16 +18,18 @@ subject to the following restrictions:
#include "LinearMath/btTransformUtil.h" #include "LinearMath/btTransformUtil.h"
btHeightfieldTerrainShape::btHeightfieldTerrainShape(int width,int length,void* heightfieldData,btScalar maxHeight,int upAxis,bool useFloatData,bool flipQuadEdges) btHeightfieldTerrainShape::btHeightfieldTerrainShape(int heightStickWidth, int heightStickLength,void* heightfieldData,btScalar maxHeight,int upAxis,bool useFloatData,bool flipQuadEdges)
:m_localScaling(btScalar(1.),btScalar(1.),btScalar(1.)), : m_heightStickWidth(heightStickWidth),
m_width(width), m_heightStickLength(heightStickLength),
m_length(length),
m_heightfieldDataUnknown(heightfieldData),
m_maxHeight(maxHeight), m_maxHeight(maxHeight),
m_upAxis(upAxis), m_width((btScalar)heightStickWidth-1),
m_length((btScalar)heightStickLength-1),
m_heightfieldDataUnknown(heightfieldData),
m_useFloatData(useFloatData), m_useFloatData(useFloatData),
m_flipQuadEdges(flipQuadEdges), m_flipQuadEdges(flipQuadEdges),
m_useDiamondSubdivision(false) m_useDiamondSubdivision(false),
m_upAxis(upAxis),
m_localScaling(btScalar(1.),btScalar(1.),btScalar(1.))
{ {
@@ -43,25 +45,25 @@ m_useDiamondSubdivision(false)
case 0: case 0:
{ {
halfExtents.setValue( halfExtents.setValue(
m_maxHeight, btScalar(m_maxHeight),
m_width, btScalar(m_width), //?? don't know if this should change
m_length); btScalar(m_length));
break; break;
} }
case 1: case 1:
{ {
halfExtents.setValue( halfExtents.setValue(
m_width, btScalar(m_width),
m_maxHeight, btScalar(m_maxHeight),
m_length); btScalar(m_length));
break; break;
}; };
case 2: case 2:
{ {
halfExtents.setValue( halfExtents.setValue(
m_width, btScalar(m_width),
m_length, btScalar(m_length),
m_maxHeight btScalar(m_maxHeight)
); );
break; break;
} }
@@ -114,11 +116,11 @@ btScalar btHeightfieldTerrainShape::getHeightFieldValue(int x,int y) const
btScalar val = 0.f; btScalar val = 0.f;
if (m_useFloatData) if (m_useFloatData)
{ {
val = m_heightfieldDataFloat[(y*m_width)+x]; val = m_heightfieldDataFloat[(y*m_heightStickWidth)+x];
} else } else
{ {
//assume unsigned short int //assume unsigned short int
unsigned char heightFieldValue = m_heightfieldDataUnsignedChar[(y*m_width)+x]; unsigned char heightFieldValue = m_heightfieldDataUnsignedChar[(y*m_heightStickWidth)+x];
val = heightFieldValue* (m_maxHeight/btScalar(65535)); val = heightFieldValue* (m_maxHeight/btScalar(65535));
} }
return val; return val;
@@ -133,8 +135,8 @@ void btHeightfieldTerrainShape::getVertex(int x,int y,btVector3& vertex) const
btAssert(x>=0); btAssert(x>=0);
btAssert(y>=0); btAssert(y>=0);
btAssert(x<m_width); btAssert(x<m_heightStickWidth);
btAssert(y<m_length); btAssert(y<m_heightStickLength);
btScalar height = getHeightFieldValue(x,y); btScalar height = getHeightFieldValue(x,y);
@@ -145,25 +147,25 @@ void btHeightfieldTerrainShape::getVertex(int x,int y,btVector3& vertex) const
{ {
vertex.setValue( vertex.setValue(
height, height,
(-m_width/2 ) + x, (-m_width/btScalar(2.0)) + x,
(-m_length/2 ) + y (-m_length/btScalar(2.0) ) + y
); );
break; break;
} }
case 1: case 1:
{ {
vertex.setValue( vertex.setValue(
(-m_width/2 ) + x, (-m_width/btScalar(2.0)) + x,
height, height,
(-m_length/2 ) + y (-m_length/btScalar(2.0)) + y
); );
break; break;
}; };
case 2: case 2:
{ {
vertex.setValue( vertex.setValue(
(-m_width/2 ) + x, (-m_width/btScalar(2.0)) + x,
(-m_length/2 ) + y, (-m_length/btScalar(2.0)) + y,
height height
); );
break; break;
@@ -180,21 +182,20 @@ void btHeightfieldTerrainShape::getVertex(int x,int y,btVector3& vertex) const
} }
void btHeightfieldTerrainShape::quantizeWithClamp(int* out, const btVector3& point) const void btHeightfieldTerrainShape::quantizeWithClamp(int* out, const btVector3& point,int /*isMax*/) const
{ {
btVector3 clampedPoint(point); btVector3 clampedPoint(point);
clampedPoint.setMax(m_localAabbMin); clampedPoint.setMax(m_localAabbMin);
clampedPoint.setMin(m_localAabbMax); clampedPoint.setMin(m_localAabbMax);
btVector3 v = (clampedPoint );// * m_quantization; btVector3 v = (clampedPoint);// - m_bvhAabbMin) * m_bvhQuantization;
out[0] = (int)(v.getX());
out[1] = (int)(v.getY());
out[2] = (int)(v.getZ());
//correct for
//TODO: optimization: check out how to removed this btFabs
out[0] = (int)(v.getX() + v.getX() / btFabs(v.getX())* btScalar(0.5) );
out[1] = (int)(v.getY() + v.getY() / btFabs(v.getY())* btScalar(0.5) );
out[2] = (int)(v.getZ() + v.getZ() / btFabs(v.getZ())* btScalar(0.5) );
} }
@@ -212,24 +213,24 @@ void btHeightfieldTerrainShape::processAllTriangles(btTriangleCallback* callback
btVector3 localAabbMin = aabbMin*btVector3(1.f/m_localScaling[0],1.f/m_localScaling[1],1.f/m_localScaling[2]); btVector3 localAabbMin = aabbMin*btVector3(1.f/m_localScaling[0],1.f/m_localScaling[1],1.f/m_localScaling[2]);
btVector3 localAabbMax = aabbMax*btVector3(1.f/m_localScaling[0],1.f/m_localScaling[1],1.f/m_localScaling[2]); btVector3 localAabbMax = aabbMax*btVector3(1.f/m_localScaling[0],1.f/m_localScaling[1],1.f/m_localScaling[2]);
quantizeWithClamp(quantizedAabbMin, localAabbMin); quantizeWithClamp(quantizedAabbMin, localAabbMin,0);
quantizeWithClamp(quantizedAabbMax, localAabbMax); quantizeWithClamp(quantizedAabbMax, localAabbMax,1);
int startX=0; int startX=0;
int endX=m_width-1; int endX=m_heightStickWidth-1;
int startJ=0; int startJ=0;
int endJ=m_length-1; int endJ=m_heightStickLength-1;
switch (m_upAxis) switch (m_upAxis)
{ {
case 0: case 0:
{ {
quantizedAabbMin[1]+=m_width/2-1; quantizedAabbMin[1]+=m_heightStickWidth/2-1;
quantizedAabbMax[1]+=m_width/2+1; quantizedAabbMax[1]+=m_heightStickWidth/2+1;
quantizedAabbMin[2]+=m_length/2-1; quantizedAabbMin[2]+=m_heightStickLength/2-1;
quantizedAabbMax[2]+=m_length/2+1; quantizedAabbMax[2]+=m_heightStickLength/2+1;
if (quantizedAabbMin[1]>startX) if (quantizedAabbMin[1]>startX)
startX = quantizedAabbMin[1]; startX = quantizedAabbMin[1];
@@ -243,10 +244,10 @@ void btHeightfieldTerrainShape::processAllTriangles(btTriangleCallback* callback
} }
case 1: case 1:
{ {
quantizedAabbMin[0]+=m_width/2-1; quantizedAabbMin[0]+=m_heightStickWidth/2-1;
quantizedAabbMax[0]+=m_width/2+1; quantizedAabbMax[0]+=m_heightStickWidth/2+1;
quantizedAabbMin[2]+=m_length/2-1; quantizedAabbMin[2]+=m_heightStickLength/2-1;
quantizedAabbMax[2]+=m_length/2+1; quantizedAabbMax[2]+=m_heightStickLength/2+1;
if (quantizedAabbMin[0]>startX) if (quantizedAabbMin[0]>startX)
startX = quantizedAabbMin[0]; startX = quantizedAabbMin[0];
@@ -260,10 +261,10 @@ void btHeightfieldTerrainShape::processAllTriangles(btTriangleCallback* callback
}; };
case 2: case 2:
{ {
quantizedAabbMin[0]+=m_width/2-1; quantizedAabbMin[0]+=m_heightStickWidth/2-1;
quantizedAabbMax[0]+=m_width/2+1; quantizedAabbMax[0]+=m_heightStickWidth/2+1;
quantizedAabbMin[1]+=m_length/2-1; quantizedAabbMin[1]+=m_heightStickLength/2-1;
quantizedAabbMax[1]+=m_length/2+1; quantizedAabbMax[1]+=m_heightStickLength/2+1;
if (quantizedAabbMin[0]>startX) if (quantizedAabbMin[0]>startX)
startX = quantizedAabbMin[0]; startX = quantizedAabbMin[0];
@@ -290,7 +291,7 @@ void btHeightfieldTerrainShape::processAllTriangles(btTriangleCallback* callback
for(int x=startX; x<endX; x++) for(int x=startX; x<endX; x++)
{ {
btVector3 vertices[3]; btVector3 vertices[3];
if (m_flipQuadEdges || (m_useDiamondSubdivision && ((j+x) & 1))) if (m_flipQuadEdges || (m_useDiamondSubdivision && !((j+x) & 1)))
{ {
//first triangle //first triangle
getVertex(x,j,vertices[0]); getVertex(x,j,vertices[0]);
@@ -322,7 +323,7 @@ void btHeightfieldTerrainShape::processAllTriangles(btTriangleCallback* callback
} }
void btHeightfieldTerrainShape::calculateLocalInertia(btScalar ,btVector3& inertia) void btHeightfieldTerrainShape::calculateLocalInertia(btScalar ,btVector3& inertia) const
{ {
//moving concave objects not supported //moving concave objects not supported

View File

@@ -18,7 +18,8 @@ subject to the following restrictions:
#include "btConcaveShape.h" #include "btConcaveShape.h"
///btHeightfieldTerrainShape simulates a 2D heightfield terrain ///The btHeightfieldTerrainShape simulates a 2D heightfield terrain collision shape. You can also use the more general btBvhTriangleMeshShape instead.
///An example implementation of btHeightfieldTerrainShape is provided in Demos/VehicleDemo/VehicleDemo.cpp
class btHeightfieldTerrainShape : public btConcaveShape class btHeightfieldTerrainShape : public btConcaveShape
{ {
protected: protected:
@@ -26,9 +27,11 @@ protected:
btVector3 m_localAabbMax; btVector3 m_localAabbMax;
///terrain data ///terrain data
int m_width; int m_heightStickWidth;
int m_length; int m_heightStickLength;
btScalar m_maxHeight; btScalar m_maxHeight;
btScalar m_width;
btScalar m_length;
union union
{ {
unsigned char* m_heightfieldDataUnsignedChar; unsigned char* m_heightfieldDataUnsignedChar;
@@ -45,7 +48,7 @@ protected:
btVector3 m_localScaling; btVector3 m_localScaling;
virtual btScalar getHeightFieldValue(int x,int y) const; virtual btScalar getHeightFieldValue(int x,int y) const;
void quantizeWithClamp(int* out, const btVector3& point) const; void quantizeWithClamp(int* out, const btVector3& point,int isMax) const;
void getVertex(int x,int y,btVector3& vertex) const; void getVertex(int x,int y,btVector3& vertex) const;
inline bool testQuantizedAabbAgainstQuantizedAabb(int* aabbMin1, int* aabbMax1,const int* aabbMin2,const int* aabbMax2) const inline bool testQuantizedAabbAgainstQuantizedAabb(int* aabbMin1, int* aabbMax1,const int* aabbMin2,const int* aabbMax2) const
@@ -58,7 +61,7 @@ protected:
} }
public: public:
btHeightfieldTerrainShape(int width,int height,void* heightfieldData, btScalar maxHeight,int upAxis,bool useFloatData,bool flipQuadEdges); btHeightfieldTerrainShape(int heightStickWidth,int heightStickHeight,void* heightfieldData, btScalar maxHeight,int upAxis,bool useFloatData,bool flipQuadEdges);
virtual ~btHeightfieldTerrainShape(); virtual ~btHeightfieldTerrainShape();
@@ -74,14 +77,14 @@ public:
virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const; virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const;
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia); virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const;
virtual void setLocalScaling(const btVector3& scaling); virtual void setLocalScaling(const btVector3& scaling);
virtual const btVector3& getLocalScaling() const; virtual const btVector3& getLocalScaling() const;
//debugging //debugging
virtual char* getName()const {return "HEIGHTFIELD";} virtual const char* getName()const {return "HEIGHTFIELD";}
}; };

View File

@@ -0,0 +1,34 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2008 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/// This file was created by Alex Silverman
#ifndef MATERIAL_H
#define MATERIAL_H
// Material class to be used by btMultimaterialTriangleMeshShape to store triangle properties
class btMaterial
{
// public members so that materials can change due to world events
public:
btScalar m_friction;
btScalar m_restitution;
int pad[2];
btMaterial(){}
btMaterial(btScalar fric, btScalar rest) { m_friction = fric; m_restitution = rest; }
};
#endif // MATERIAL_H

View File

@@ -26,9 +26,9 @@ m_shapeB(shapeB)
btVector3 btMinkowskiSumShape::localGetSupportingVertexWithoutMargin(const btVector3& vec)const btVector3 btMinkowskiSumShape::localGetSupportingVertexWithoutMargin(const btVector3& vec)const
{ {
btVector3 supVertexA = m_transA(m_shapeA->localGetSupportingVertexWithoutMargin(vec*m_transA.getBasis())); btVector3 supVertexA = m_transA(m_shapeA->localGetSupportingVertexWithoutMargin(-vec*m_transA.getBasis()));
btVector3 supVertexB = m_transB(m_shapeB->localGetSupportingVertexWithoutMargin(vec*m_transB.getBasis())); btVector3 supVertexB = m_transB(m_shapeB->localGetSupportingVertexWithoutMargin(vec*m_transB.getBasis()));
return supVertexA + supVertexB; return supVertexA - supVertexB;
} }
void btMinkowskiSumShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const void btMinkowskiSumShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const
@@ -49,7 +49,7 @@ btScalar btMinkowskiSumShape::getMargin() const
} }
void btMinkowskiSumShape::calculateLocalInertia(btScalar mass,btVector3& inertia) void btMinkowskiSumShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const
{ {
(void)mass; (void)mass;
btAssert(0); btAssert(0);

View File

@@ -16,11 +16,11 @@ subject to the following restrictions:
#ifndef MINKOWSKI_SUM_SHAPE_H #ifndef MINKOWSKI_SUM_SHAPE_H
#define MINKOWSKI_SUM_SHAPE_H #define MINKOWSKI_SUM_SHAPE_H
#include "btConvexShape.h" #include "btConvexInternalShape.h"
#include "../BroadphaseCollision/btBroadphaseProxy.h" // for the types #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types
/// btMinkowskiSumShape represents implicit (getSupportingVertex) based minkowski sum of two convex implicit shapes. /// The btMinkowskiSumShape is only for advanced users. This shape represents implicit based minkowski sum of two convex implicit shapes.
class btMinkowskiSumShape : public btConvexShape class btMinkowskiSumShape : public btConvexInternalShape
{ {
btTransform m_transA; btTransform m_transA;
@@ -37,7 +37,7 @@ public:
virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const;
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia); virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const;
void setTransformA(const btTransform& transA) { m_transA = transA;} void setTransformA(const btTransform& transA) { m_transA = transA;}
void setTransformB(const btTransform& transB) { m_transB = transB;} void setTransformB(const btTransform& transB) { m_transB = transB;}
@@ -53,7 +53,7 @@ public:
const btConvexShape* getShapeA() const { return m_shapeA;} const btConvexShape* getShapeA() const { return m_shapeA;}
const btConvexShape* getShapeB() const { return m_shapeB;} const btConvexShape* getShapeB() const { return m_shapeB;}
virtual char* getName()const virtual const char* getName()const
{ {
return "MinkowskiSum"; return "MinkowskiSum";
} }

View File

@@ -47,7 +47,7 @@ btMultiSphereShape::btMultiSphereShape (const btVector3& inertiaHalfExtents,cons
btVector3 vec = vec0; btVector3 vec = vec0;
btScalar lenSqr = vec.length2(); btScalar lenSqr = vec.length2();
if (lenSqr < btScalar(0.0001)) if (lenSqr < (SIMD_EPSILON*SIMD_EPSILON))
{ {
vec.setValue(1,0,0); vec.setValue(1,0,0);
} else } else
@@ -116,7 +116,7 @@ btMultiSphereShape::btMultiSphereShape (const btVector3& inertiaHalfExtents,cons
void btMultiSphereShape::calculateLocalInertia(btScalar mass,btVector3& inertia) void btMultiSphereShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const
{ {
//as an approximation, take the inertia of the box that bounds the spheres //as an approximation, take the inertia of the box that bounds the spheres

View File

@@ -16,13 +16,14 @@ subject to the following restrictions:
#ifndef MULTI_SPHERE_MINKOWSKI_H #ifndef MULTI_SPHERE_MINKOWSKI_H
#define MULTI_SPHERE_MINKOWSKI_H #define MULTI_SPHERE_MINKOWSKI_H
#include "btConvexShape.h" #include "btConvexInternalShape.h"
#include "../BroadphaseCollision/btBroadphaseProxy.h" // for the types #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types
#define MAX_NUM_SPHERES 5 #define MAX_NUM_SPHERES 5
///btMultiSphereShape represents implicit convex hull of a collection of spheres (using getSupportingVertex) ///The btMultiSphereShape represents the convex hull of a collection of spheres. You can create special capsules or other smooth volumes.
class btMultiSphereShape : public btConvexShape ///It is possible to animate the spheres for deformation.
class btMultiSphereShape : public btConvexInternalShape
{ {
@@ -39,7 +40,7 @@ public:
btMultiSphereShape (const btVector3& inertiaHalfExtents,const btVector3* positions,const btScalar* radi,int numSpheres); btMultiSphereShape (const btVector3& inertiaHalfExtents,const btVector3* positions,const btScalar* radi,int numSpheres);
///CollisionShape Interface ///CollisionShape Interface
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia); virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const;
/// btConvexShape Interface /// btConvexShape Interface
virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const;
@@ -63,7 +64,7 @@ public:
virtual int getShapeType() const { return MULTI_SPHERE_SHAPE_PROXYTYPE; } virtual int getShapeType() const { return MULTI_SPHERE_SHAPE_PROXYTYPE; }
virtual char* getName()const virtual const char* getName()const
{ {
return "MultiSphere"; return "MultiSphere";
} }

View File

@@ -0,0 +1,45 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2008 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/// This file was created by Alex Silverman
#include "BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h"
#include "BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.h"
//#include "BulletCollision/CollisionShapes/btOptimizedBvh.h"
///Obtains the material for a specific triangle
const btMaterial * btMultimaterialTriangleMeshShape::getMaterialProperties(int partID, int triIndex)
{
const unsigned char * materialBase = 0;
int numMaterials;
PHY_ScalarType materialType;
int materialStride;
const unsigned char * triangleMaterialBase = 0;
int numTriangles;
int triangleMaterialStride;
PHY_ScalarType triangleType;
((btTriangleIndexVertexMaterialArray*)m_meshInterface)->getLockedReadOnlyMaterialBase(&materialBase, numMaterials, materialType, materialStride,
&triangleMaterialBase, numTriangles, triangleMaterialStride, triangleType, partID);
// return the pointer to the place with the friction for the triangle
// TODO: This depends on whether it's a moving mesh or not
// BUG IN GIMPACT
//return (btScalar*)(&materialBase[triangleMaterialBase[(triIndex-1) * triangleMaterialStride] * materialStride]);
int * matInd = (int *)(&(triangleMaterialBase[(triIndex * triangleMaterialStride)]));
btMaterial *matVal = (btMaterial *)(&(materialBase[*matInd * materialStride]));
return (matVal);
}

View File

@@ -0,0 +1,124 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2008 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/// This file was created by Alex Silverman
#ifndef BVH_TRIANGLE_MATERIAL_MESH_SHAPE_H
#define BVH_TRIANGLE_MATERIAL_MESH_SHAPE_H
#include "btBvhTriangleMeshShape.h"
#include "btMaterial.h"
///The BvhTriangleMaterialMeshShape extends the btBvhTriangleMeshShape. Its main contribution is the interface into a material array, which allows per-triangle friction and restitution.
ATTRIBUTE_ALIGNED16(class) btMultimaterialTriangleMeshShape : public btBvhTriangleMeshShape
{
btAlignedObjectArray <btMaterial*> m_materialList;
int ** m_triangleMaterials;
public:
BT_DECLARE_ALIGNED_ALLOCATOR();
btMultimaterialTriangleMeshShape(): btBvhTriangleMeshShape() {}
btMultimaterialTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression, bool buildBvh = true):
btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression, buildBvh)
{
btVector3 m_triangle[3];
const unsigned char *vertexbase;
int numverts;
PHY_ScalarType type;
int stride;
const unsigned char *indexbase;
int indexstride;
int numfaces;
PHY_ScalarType indicestype;
//m_materialLookup = (int**)(btAlignedAlloc(sizeof(int*) * meshInterface->getNumSubParts(), 16));
for(int i = 0; i < meshInterface->getNumSubParts(); i++)
{
m_meshInterface->getLockedReadOnlyVertexIndexBase(
&vertexbase,
numverts,
type,
stride,
&indexbase,
indexstride,
numfaces,
indicestype,
i);
//m_materialLookup[i] = (int*)(btAlignedAlloc(sizeof(int) * numfaces, 16));
}
}
///optionally pass in a larger bvh aabb, used for quantization. This allows for deformations within this aabb
btMultimaterialTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression,const btVector3& bvhAabbMin,const btVector3& bvhAabbMax, bool buildBvh = true):
btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression, bvhAabbMin, bvhAabbMax, buildBvh)
{
btVector3 m_triangle[3];
const unsigned char *vertexbase;
int numverts;
PHY_ScalarType type;
int stride;
const unsigned char *indexbase;
int indexstride;
int numfaces;
PHY_ScalarType indicestype;
//m_materialLookup = (int**)(btAlignedAlloc(sizeof(int*) * meshInterface->getNumSubParts(), 16));
for(int i = 0; i < meshInterface->getNumSubParts(); i++)
{
m_meshInterface->getLockedReadOnlyVertexIndexBase(
&vertexbase,
numverts,
type,
stride,
&indexbase,
indexstride,
numfaces,
indicestype,
i);
//m_materialLookup[i] = (int*)(btAlignedAlloc(sizeof(int) * numfaces * 2, 16));
}
}
virtual ~btMultimaterialTriangleMeshShape()
{
/*
for(int i = 0; i < m_meshInterface->getNumSubParts(); i++)
{
btAlignedFree(m_materialValues[i]);
m_materialLookup[i] = NULL;
}
btAlignedFree(m_materialValues);
m_materialLookup = NULL;
*/
}
virtual int getShapeType() const
{
return MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE;
}
//debugging
virtual const char* getName()const {return "MULTIMATERIALTRIANGLEMESH";}
///Obtains the material for a specific triangle
const btMaterial * getMaterialProperties(int partID, int triIndex);
}
;
#endif //BVH_TRIANGLE_MATERIAL_MESH_SHAPE_H

View File

@@ -19,13 +19,12 @@ subject to the following restrictions:
#include "LinearMath/btIDebugDraw.h" #include "LinearMath/btIDebugDraw.h"
btOptimizedBvh::btOptimizedBvh()
btOptimizedBvh::btOptimizedBvh() : m_useQuantization(false),
m_traversalMode(TRAVERSAL_STACKLESS_CACHE_FRIENDLY)
//m_traversalMode(TRAVERSAL_STACKLESS)
//m_traversalMode(TRAVERSAL_RECURSIVE)
{ {
}
btOptimizedBvh::~btOptimizedBvh()
{
} }
@@ -80,7 +79,7 @@ void btOptimizedBvh::build(btStridingMeshInterface* triangles, bool useQuantized
struct QuantizedNodeTriangleCallback : public btInternalTriangleIndexCallback struct QuantizedNodeTriangleCallback : public btInternalTriangleIndexCallback
{ {
QuantizedNodeArray& m_triangleNodes; QuantizedNodeArray& m_triangleNodes;
const btOptimizedBvh* m_optimizedTree; // for quantization const btQuantizedBvh* m_optimizedTree; // for quantization
QuantizedNodeTriangleCallback& operator=(QuantizedNodeTriangleCallback& other) QuantizedNodeTriangleCallback& operator=(QuantizedNodeTriangleCallback& other)
{ {
@@ -89,14 +88,16 @@ void btOptimizedBvh::build(btStridingMeshInterface* triangles, bool useQuantized
return *this; return *this;
} }
QuantizedNodeTriangleCallback(QuantizedNodeArray& triangleNodes,const btOptimizedBvh* tree) QuantizedNodeTriangleCallback(QuantizedNodeArray& triangleNodes,const btQuantizedBvh* tree)
:m_triangleNodes(triangleNodes),m_optimizedTree(tree) :m_triangleNodes(triangleNodes),m_optimizedTree(tree)
{ {
} }
virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int triangleIndex) virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int triangleIndex)
{ {
btAssert(partId==0); // The partId and triangle index must fit in the same (positive) integer
btAssert(partId < (1<<MAX_NUM_PARTS_IN_BITS));
btAssert(triangleIndex < (1<<(31-MAX_NUM_PARTS_IN_BITS)));
//negative indices are reserved for escapeIndex //negative indices are reserved for escapeIndex
btAssert(triangleIndex>=0); btAssert(triangleIndex>=0);
@@ -111,10 +112,29 @@ void btOptimizedBvh::build(btStridingMeshInterface* triangles, bool useQuantized
aabbMin.setMin(triangle[2]); aabbMin.setMin(triangle[2]);
aabbMax.setMax(triangle[2]); aabbMax.setMax(triangle[2]);
m_optimizedTree->quantizeWithClamp(&node.m_quantizedAabbMin[0],aabbMin); //PCK: add these checks for zero dimensions of aabb
m_optimizedTree->quantizeWithClamp(&node.m_quantizedAabbMax[0],aabbMax); const btScalar MIN_AABB_DIMENSION = btScalar(0.002);
const btScalar MIN_AABB_HALF_DIMENSION = btScalar(0.001);
if (aabbMax.x() - aabbMin.x() < MIN_AABB_DIMENSION)
{
aabbMax.setX(aabbMax.x() + MIN_AABB_HALF_DIMENSION);
aabbMin.setX(aabbMin.x() - MIN_AABB_HALF_DIMENSION);
}
if (aabbMax.y() - aabbMin.y() < MIN_AABB_DIMENSION)
{
aabbMax.setY(aabbMax.y() + MIN_AABB_HALF_DIMENSION);
aabbMin.setY(aabbMin.y() - MIN_AABB_HALF_DIMENSION);
}
if (aabbMax.z() - aabbMin.z() < MIN_AABB_DIMENSION)
{
aabbMax.setZ(aabbMax.z() + MIN_AABB_HALF_DIMENSION);
aabbMin.setZ(aabbMin.z() - MIN_AABB_HALF_DIMENSION);
}
node.m_escapeIndexOrTriangleIndex = triangleIndex; m_optimizedTree->quantize(&node.m_quantizedAabbMin[0],aabbMin,0);
m_optimizedTree->quantize(&node.m_quantizedAabbMax[0],aabbMax,1);
node.m_escapeIndexOrTriangleIndex = (partId<<(31-MAX_NUM_PARTS_IN_BITS)) | triangleIndex;
m_triangleNodes.push_back(node); m_triangleNodes.push_back(node);
} }
@@ -170,10 +190,45 @@ void btOptimizedBvh::build(btStridingMeshInterface* triangles, bool useQuantized
subtree.m_rootNodeIndex = 0; subtree.m_rootNodeIndex = 0;
subtree.m_subtreeSize = m_quantizedContiguousNodes[0].isLeafNode() ? 1 : m_quantizedContiguousNodes[0].getEscapeIndex(); subtree.m_subtreeSize = m_quantizedContiguousNodes[0].isLeafNode() ? 1 : m_quantizedContiguousNodes[0].getEscapeIndex();
} }
//PCK: update the copy of the size
m_subtreeHeaderCount = m_SubtreeHeaders.size();
//PCK: clear m_quantizedLeafNodes and m_leafNodes, they are temporary
m_quantizedLeafNodes.clear();
m_leafNodes.clear();
} }
void btOptimizedBvh::refit(btStridingMeshInterface* meshInterface,const btVector3& aabbMin,const btVector3& aabbMax)
{
if (m_useQuantization)
{
setQuantizationValues(aabbMin,aabbMax);
updateBvhNodes(meshInterface,0,m_curNodeIndex,0);
///now update all subtree headers
int i;
for (i=0;i<m_SubtreeHeaders.size();i++)
{
btBvhSubtreeInfo& subtree = m_SubtreeHeaders[i];
subtree.setAabbFromQuantizeNode(m_quantizedContiguousNodes[subtree.m_rootNodeIndex]);
}
} else
{
}
}
void btOptimizedBvh::refitPartial(btStridingMeshInterface* meshInterface,const btVector3& aabbMin,const btVector3& aabbMax) void btOptimizedBvh::refitPartial(btStridingMeshInterface* meshInterface,const btVector3& aabbMin,const btVector3& aabbMax)
{ {
//incrementally initialize quantization values //incrementally initialize quantization values
@@ -193,16 +248,17 @@ void btOptimizedBvh::refitPartial(btStridingMeshInterface* meshInterface,const b
unsigned short quantizedQueryAabbMin[3]; unsigned short quantizedQueryAabbMin[3];
unsigned short quantizedQueryAabbMax[3]; unsigned short quantizedQueryAabbMax[3];
quantizeWithClamp(&quantizedQueryAabbMin[0],aabbMin); quantize(&quantizedQueryAabbMin[0],aabbMin,0);
quantizeWithClamp(&quantizedQueryAabbMax[0],aabbMax); quantize(&quantizedQueryAabbMax[0],aabbMax,1);
int i; int i;
for (i=0;i<this->m_SubtreeHeaders.size();i++) for (i=0;i<this->m_SubtreeHeaders.size();i++)
{ {
btBvhSubtreeInfo& subtree = m_SubtreeHeaders[i]; btBvhSubtreeInfo& subtree = m_SubtreeHeaders[i];
bool overlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,subtree.m_quantizedAabbMin,subtree.m_quantizedAabbMax); //PCK: unsigned instead of bool
if (overlap) unsigned overlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,subtree.m_quantizedAabbMin,subtree.m_quantizedAabbMax);
if (overlap != 0)
{ {
updateBvhNodes(meshInterface,subtree.m_rootNodeIndex,subtree.m_rootNodeIndex+subtree.m_subtreeSize,i); updateBvhNodes(meshInterface,subtree.m_rootNodeIndex,subtree.m_rootNodeIndex+subtree.m_subtreeSize,i);
@@ -212,36 +268,23 @@ void btOptimizedBvh::refitPartial(btStridingMeshInterface* meshInterface,const b
} }
///just for debugging, to visualize the individual patches/subtrees
#ifdef DEBUG_PATCH_COLORS
btVector3 color[4]=
{
btVector3(255,0,0),
btVector3(0,255,0),
btVector3(0,0,255),
btVector3(0,255,255)
};
#endif //DEBUG_PATCH_COLORS
void btOptimizedBvh::updateBvhNodes(btStridingMeshInterface* meshInterface,int firstNode,int endNode,int index) void btOptimizedBvh::updateBvhNodes(btStridingMeshInterface* meshInterface,int firstNode,int endNode,int index)
{ {
(void)index; (void)index;
btAssert(m_useQuantization); btAssert(m_useQuantization);
int nodeSubPart=0; int curNodeSubPart=-1;
//get access info to trianglemesh data //get access info to trianglemesh data
const unsigned char *vertexbase; const unsigned char *vertexbase = 0;
int numverts; int numverts = 0;
PHY_ScalarType type; PHY_ScalarType type = PHY_INTEGER;
int stride; int stride = 0;
const unsigned char *indexbase; const unsigned char *indexbase = 0;
int indexstride; int indexstride = 0;
int numfaces; int numfaces = 0;
PHY_ScalarType indicestype; PHY_ScalarType indicestype = PHY_INTEGER;
meshInterface->getLockedReadOnlyVertexIndexBase(&vertexbase,numverts, type,stride,&indexbase,indexstride,numfaces,indicestype,nodeSubPart);
btVector3 triangleVerts[3]; btVector3 triangleVerts[3];
btVector3 aabbMin,aabbMax; btVector3 aabbMin,aabbMax;
@@ -256,16 +299,24 @@ void btOptimizedBvh::updateBvhNodes(btStridingMeshInterface* meshInterface,int f
if (curNode.isLeafNode()) if (curNode.isLeafNode())
{ {
//recalc aabb from triangle data //recalc aabb from triangle data
int nodeSubPart = curNode.getPartId();
int nodeTriangleIndex = curNode.getTriangleIndex(); int nodeTriangleIndex = curNode.getTriangleIndex();
if (nodeSubPart != curNodeSubPart)
{
if (curNodeSubPart >= 0)
meshInterface->unLockReadOnlyVertexBase(curNodeSubPart);
meshInterface->getLockedReadOnlyVertexIndexBase(&vertexbase,numverts, type,stride,&indexbase,indexstride,numfaces,indicestype,nodeSubPart);
btAssert(indicestype==PHY_INTEGER||indicestype==PHY_SHORT);
}
//triangles->getLockedReadOnlyVertexIndexBase(vertexBase,numVerts, //triangles->getLockedReadOnlyVertexIndexBase(vertexBase,numVerts,
int* gfxbase = (int*)(indexbase+nodeTriangleIndex*indexstride); unsigned int* gfxbase = (unsigned int*)(indexbase+nodeTriangleIndex*indexstride);
for (int j=2;j>=0;j--) for (int j=2;j>=0;j--)
{ {
int graphicsindex = gfxbase[j]; int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j];
btScalar* graphicsbase = (btScalar*)(vertexbase+graphicsindex*stride); btScalar* graphicsbase = (btScalar*)(vertexbase+graphicsindex*stride);
#ifdef DEBUG_PATCH_COLORS #ifdef DEBUG_PATCH_COLORS
btVector3 mycolor = color[index&3]; btVector3 mycolor = color[index&3];
@@ -292,8 +343,8 @@ void btOptimizedBvh::updateBvhNodes(btStridingMeshInterface* meshInterface,int f
aabbMin.setMin(triangleVerts[2]); aabbMin.setMin(triangleVerts[2]);
aabbMax.setMax(triangleVerts[2]); aabbMax.setMax(triangleVerts[2]);
quantizeWithClamp(&curNode.m_quantizedAabbMin[0],aabbMin); quantize(&curNode.m_quantizedAabbMin[0],aabbMin,0);
quantizeWithClamp(&curNode.m_quantizedAabbMax[0],aabbMax); quantize(&curNode.m_quantizedAabbMax[0],aabbMax,1);
} else } else
{ {
@@ -321,525 +372,17 @@ void btOptimizedBvh::updateBvhNodes(btStridingMeshInterface* meshInterface,int f
} }
meshInterface->unLockReadOnlyVertexBase(nodeSubPart); if (curNodeSubPart >= 0)
meshInterface->unLockReadOnlyVertexBase(curNodeSubPart);
} }
void btOptimizedBvh::setQuantizationValues(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax,btScalar quantizationMargin) ///deSerializeInPlace loads and initializes a BVH from a buffer in memory 'in place'
btOptimizedBvh* btOptimizedBvh::deSerializeInPlace(void *i_alignedDataBuffer, unsigned int i_dataBufferSize, bool i_swapEndian)
{ {
//enlarge the AABB to avoid division by zero when initializing the quantization values btQuantizedBvh* bvh = btQuantizedBvh::deSerializeInPlace(i_alignedDataBuffer,i_dataBufferSize,i_swapEndian);
btVector3 clampValue(quantizationMargin,quantizationMargin,quantizationMargin);
m_bvhAabbMin = bvhAabbMin - clampValue;
m_bvhAabbMax = bvhAabbMax + clampValue;
btVector3 aabbSize = m_bvhAabbMax - m_bvhAabbMin;
m_bvhQuantization = btVector3(btScalar(65535.0),btScalar(65535.0),btScalar(65535.0)) / aabbSize;
}
void btOptimizedBvh::refit(btStridingMeshInterface* meshInterface)
{
if (m_useQuantization)
{
//calculate new aabb
btVector3 aabbMin,aabbMax;
meshInterface->calculateAabbBruteForce(aabbMin,aabbMax);
setQuantizationValues(aabbMin,aabbMax);
updateBvhNodes(meshInterface,0,m_curNodeIndex,0);
///now update all subtree headers
int i;
for (i=0;i<m_SubtreeHeaders.size();i++)
{
btBvhSubtreeInfo& subtree = m_SubtreeHeaders[i];
subtree.setAabbFromQuantizeNode(m_quantizedContiguousNodes[subtree.m_rootNodeIndex]);
}
} else
{
}
}
btOptimizedBvh::~btOptimizedBvh()
{
}
#ifdef DEBUG_TREE_BUILDING
int gStackDepth = 0;
int gMaxStackDepth = 0;
#endif //DEBUG_TREE_BUILDING
void btOptimizedBvh::buildTree (int startIndex,int endIndex)
{
#ifdef DEBUG_TREE_BUILDING
gStackDepth++;
if (gStackDepth > gMaxStackDepth)
gMaxStackDepth = gStackDepth;
#endif //DEBUG_TREE_BUILDING
int splitAxis, splitIndex, i;
int numIndices =endIndex-startIndex;
int curIndex = m_curNodeIndex;
assert(numIndices>0);
if (numIndices==1)
{
#ifdef DEBUG_TREE_BUILDING
gStackDepth--;
#endif //DEBUG_TREE_BUILDING
assignInternalNodeFromLeafNode(m_curNodeIndex,startIndex);
m_curNodeIndex++;
return;
}
//calculate Best Splitting Axis and where to split it. Sort the incoming 'leafNodes' array within range 'startIndex/endIndex'.
splitAxis = calcSplittingAxis(startIndex,endIndex); //we don't add additional data so just do a static upcast
return static_cast<btOptimizedBvh*>(bvh);
splitIndex = sortAndCalcSplittingIndex(startIndex,endIndex,splitAxis);
int internalNodeIndex = m_curNodeIndex;
setInternalNodeAabbMax(m_curNodeIndex,btVector3(btScalar(-1e30),btScalar(-1e30),btScalar(-1e30)));
setInternalNodeAabbMin(m_curNodeIndex,btVector3(btScalar(1e30),btScalar(1e30),btScalar(1e30)));
for (i=startIndex;i<endIndex;i++)
{
mergeInternalNodeAabb(m_curNodeIndex,getAabbMin(i),getAabbMax(i));
}
m_curNodeIndex++;
//internalNode->m_escapeIndex;
int leftChildNodexIndex = m_curNodeIndex;
//build left child tree
buildTree(startIndex,splitIndex);
int rightChildNodexIndex = m_curNodeIndex;
//build right child tree
buildTree(splitIndex,endIndex);
#ifdef DEBUG_TREE_BUILDING
gStackDepth--;
#endif //DEBUG_TREE_BUILDING
int escapeIndex = m_curNodeIndex - curIndex;
if (m_useQuantization)
{
//escapeIndex is the number of nodes of this subtree
const int sizeQuantizedNode =sizeof(btQuantizedBvhNode);
const int treeSizeInBytes = escapeIndex * sizeQuantizedNode;
if (treeSizeInBytes > MAX_SUBTREE_SIZE_IN_BYTES)
{
updateSubtreeHeaders(leftChildNodexIndex,rightChildNodexIndex);
}
}
setInternalNodeEscapeIndex(internalNodeIndex,escapeIndex);
}
void btOptimizedBvh::updateSubtreeHeaders(int leftChildNodexIndex,int rightChildNodexIndex)
{
btAssert(m_useQuantization);
btQuantizedBvhNode& leftChildNode = m_quantizedContiguousNodes[leftChildNodexIndex];
int leftSubTreeSize = leftChildNode.isLeafNode() ? 1 : leftChildNode.getEscapeIndex();
int leftSubTreeSizeInBytes = leftSubTreeSize * sizeof(btQuantizedBvhNode);
btQuantizedBvhNode& rightChildNode = m_quantizedContiguousNodes[rightChildNodexIndex];
int rightSubTreeSize = rightChildNode.isLeafNode() ? 1 : rightChildNode.getEscapeIndex();
int rightSubTreeSizeInBytes = rightSubTreeSize * sizeof(btQuantizedBvhNode);
if(leftSubTreeSizeInBytes <= MAX_SUBTREE_SIZE_IN_BYTES)
{
btBvhSubtreeInfo& subtree = m_SubtreeHeaders.expand();
subtree.setAabbFromQuantizeNode(leftChildNode);
subtree.m_rootNodeIndex = leftChildNodexIndex;
subtree.m_subtreeSize = leftSubTreeSize;
}
if(rightSubTreeSizeInBytes <= MAX_SUBTREE_SIZE_IN_BYTES)
{
btBvhSubtreeInfo& subtree = m_SubtreeHeaders.expand();
subtree.setAabbFromQuantizeNode(rightChildNode);
subtree.m_rootNodeIndex = rightChildNodexIndex;
subtree.m_subtreeSize = rightSubTreeSize;
}
}
int btOptimizedBvh::sortAndCalcSplittingIndex(int startIndex,int endIndex,int splitAxis)
{
int i;
int splitIndex =startIndex;
int numIndices = endIndex - startIndex;
btScalar splitValue;
btVector3 means(btScalar(0.),btScalar(0.),btScalar(0.));
for (i=startIndex;i<endIndex;i++)
{
btVector3 center = btScalar(0.5)*(getAabbMax(i)+getAabbMin(i));
means+=center;
}
means *= (btScalar(1.)/(btScalar)numIndices);
splitValue = means[splitAxis];
//sort leafNodes so all values larger then splitValue comes first, and smaller values start from 'splitIndex'.
for (i=startIndex;i<endIndex;i++)
{
btVector3 center = btScalar(0.5)*(getAabbMax(i)+getAabbMin(i));
if (center[splitAxis] > splitValue)
{
//swap
swapLeafNodes(i,splitIndex);
splitIndex++;
}
}
//if the splitIndex causes unbalanced trees, fix this by using the center in between startIndex and endIndex
//otherwise the tree-building might fail due to stack-overflows in certain cases.
//unbalanced1 is unsafe: it can cause stack overflows
//bool unbalanced1 = ((splitIndex==startIndex) || (splitIndex == (endIndex-1)));
//unbalanced2 should work too: always use center (perfect balanced trees)
//bool unbalanced2 = true;
//this should be safe too:
int rangeBalancedIndices = numIndices/3;
bool unbalanced = ((splitIndex<=(startIndex+rangeBalancedIndices)) || (splitIndex >=(endIndex-1-rangeBalancedIndices)));
if (unbalanced)
{
splitIndex = startIndex+ (numIndices>>1);
}
bool unbal = (splitIndex==startIndex) || (splitIndex == (endIndex));
btAssert(!unbal);
return splitIndex;
}
int btOptimizedBvh::calcSplittingAxis(int startIndex,int endIndex)
{
int i;
btVector3 means(btScalar(0.),btScalar(0.),btScalar(0.));
btVector3 variance(btScalar(0.),btScalar(0.),btScalar(0.));
int numIndices = endIndex-startIndex;
for (i=startIndex;i<endIndex;i++)
{
btVector3 center = btScalar(0.5)*(getAabbMax(i)+getAabbMin(i));
means+=center;
}
means *= (btScalar(1.)/(btScalar)numIndices);
for (i=startIndex;i<endIndex;i++)
{
btVector3 center = btScalar(0.5)*(getAabbMax(i)+getAabbMin(i));
btVector3 diff2 = center-means;
diff2 = diff2 * diff2;
variance += diff2;
}
variance *= (btScalar(1.)/ ((btScalar)numIndices-1) );
return variance.maxAxis();
}
void btOptimizedBvh::reportAabbOverlappingNodex(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const
{
//either choose recursive traversal (walkTree) or stackless (walkStacklessTree)
if (m_useQuantization)
{
///quantize query AABB
unsigned short int quantizedQueryAabbMin[3];
unsigned short int quantizedQueryAabbMax[3];
quantizeWithClamp(quantizedQueryAabbMin,aabbMin);
quantizeWithClamp(quantizedQueryAabbMax,aabbMax);
switch (m_traversalMode)
{
case TRAVERSAL_STACKLESS:
walkStacklessQuantizedTree(nodeCallback,quantizedQueryAabbMin,quantizedQueryAabbMax,0,m_curNodeIndex);
break;
case TRAVERSAL_STACKLESS_CACHE_FRIENDLY:
walkStacklessQuantizedTreeCacheFriendly(nodeCallback,quantizedQueryAabbMin,quantizedQueryAabbMax);
break;
case TRAVERSAL_RECURSIVE:
{
const btQuantizedBvhNode* rootNode = &m_quantizedContiguousNodes[0];
walkRecursiveQuantizedTreeAgainstQueryAabb(rootNode,nodeCallback,quantizedQueryAabbMin,quantizedQueryAabbMax);
}
break;
default:
//unsupported
btAssert(0);
}
} else
{
walkStacklessTree(nodeCallback,aabbMin,aabbMax);
}
}
int maxIterations = 0;
void btOptimizedBvh::walkStacklessTree(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const
{
btAssert(!m_useQuantization);
const btOptimizedBvhNode* rootNode = &m_contiguousNodes[0];
int escapeIndex, curIndex = 0;
int walkIterations = 0;
bool aabbOverlap, isLeafNode;
while (curIndex < m_curNodeIndex)
{
//catch bugs in tree data
assert (walkIterations < m_curNodeIndex);
walkIterations++;
aabbOverlap = TestAabbAgainstAabb2(aabbMin,aabbMax,rootNode->m_aabbMinOrg,rootNode->m_aabbMaxOrg);
isLeafNode = rootNode->m_escapeIndex == -1;
if (isLeafNode && aabbOverlap)
{
nodeCallback->processNode(rootNode->m_subPart,rootNode->m_triangleIndex);
}
if (aabbOverlap || isLeafNode)
{
rootNode++;
curIndex++;
} else
{
escapeIndex = rootNode->m_escapeIndex;
rootNode += escapeIndex;
curIndex += escapeIndex;
}
}
if (maxIterations < walkIterations)
maxIterations = walkIterations;
}
/*
///this was the original recursive traversal, before we optimized towards stackless traversal
void btOptimizedBvh::walkTree(btOptimizedBvhNode* rootNode,btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const
{
bool isLeafNode, aabbOverlap = TestAabbAgainstAabb2(aabbMin,aabbMax,rootNode->m_aabbMin,rootNode->m_aabbMax);
if (aabbOverlap)
{
isLeafNode = (!rootNode->m_leftChild && !rootNode->m_rightChild);
if (isLeafNode)
{
nodeCallback->processNode(rootNode);
} else
{
walkTree(rootNode->m_leftChild,nodeCallback,aabbMin,aabbMax);
walkTree(rootNode->m_rightChild,nodeCallback,aabbMin,aabbMax);
}
}
}
*/
void btOptimizedBvh::walkRecursiveQuantizedTreeAgainstQueryAabb(const btQuantizedBvhNode* currentNode,btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const
{
btAssert(m_useQuantization);
bool aabbOverlap, isLeafNode;
aabbOverlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,currentNode->m_quantizedAabbMin,currentNode->m_quantizedAabbMax);
isLeafNode = currentNode->isLeafNode();
if (aabbOverlap)
{
if (isLeafNode)
{
nodeCallback->processNode(0,currentNode->getTriangleIndex());
} else
{
//process left and right children
const btQuantizedBvhNode* leftChildNode = currentNode+1;
walkRecursiveQuantizedTreeAgainstQueryAabb(leftChildNode,nodeCallback,quantizedQueryAabbMin,quantizedQueryAabbMax);
const btQuantizedBvhNode* rightChildNode = leftChildNode->isLeafNode() ? leftChildNode+1:leftChildNode+leftChildNode->getEscapeIndex();
walkRecursiveQuantizedTreeAgainstQueryAabb(rightChildNode,nodeCallback,quantizedQueryAabbMin,quantizedQueryAabbMax);
}
}
}
void btOptimizedBvh::walkStacklessQuantizedTree(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax,int startNodeIndex,int endNodeIndex) const
{
btAssert(m_useQuantization);
int curIndex = startNodeIndex;
int walkIterations = 0;
int subTreeSize = endNodeIndex - startNodeIndex;
const btQuantizedBvhNode* rootNode = &m_quantizedContiguousNodes[startNodeIndex];
int escapeIndex;
bool aabbOverlap, isLeafNode;
while (curIndex < endNodeIndex)
{
//#define VISUALLY_ANALYZE_BVH 1
#ifdef VISUALLY_ANALYZE_BVH
//some code snippet to debugDraw aabb, to visually analyze bvh structure
static int drawPatch = 0;
//need some global access to a debugDrawer
extern btIDebugDraw* debugDrawerPtr;
if (curIndex==drawPatch)
{
btVector3 aabbMin,aabbMax;
aabbMin = unQuantize(rootNode->m_quantizedAabbMin);
aabbMax = unQuantize(rootNode->m_quantizedAabbMax);
btVector3 color(1,0,0);
debugDrawerPtr->drawAabb(aabbMin,aabbMax,color);
}
#endif//VISUALLY_ANALYZE_BVH
//catch bugs in tree data
assert (walkIterations < subTreeSize);
walkIterations++;
aabbOverlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,rootNode->m_quantizedAabbMin,rootNode->m_quantizedAabbMax);
isLeafNode = rootNode->isLeafNode();
if (isLeafNode && aabbOverlap)
{
nodeCallback->processNode(0,rootNode->getTriangleIndex());
}
if (aabbOverlap || isLeafNode)
{
rootNode++;
curIndex++;
} else
{
escapeIndex = rootNode->getEscapeIndex();
rootNode += escapeIndex;
curIndex += escapeIndex;
}
}
if (maxIterations < walkIterations)
maxIterations = walkIterations;
}
//This traversal can be called from Playstation 3 SPU
void btOptimizedBvh::walkStacklessQuantizedTreeCacheFriendly(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const
{
btAssert(m_useQuantization);
int i;
for (i=0;i<this->m_SubtreeHeaders.size();i++)
{
const btBvhSubtreeInfo& subtree = m_SubtreeHeaders[i];
bool overlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,subtree.m_quantizedAabbMin,subtree.m_quantizedAabbMax);
if (overlap)
{
walkStacklessQuantizedTree(nodeCallback,quantizedQueryAabbMin,quantizedQueryAabbMax,
subtree.m_rootNodeIndex,
subtree.m_rootNodeIndex+subtree.m_subtreeSize);
}
}
}
void btOptimizedBvh::reportSphereOverlappingNodex(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const
{
(void)nodeCallback;
(void)aabbMin;
(void)aabbMax;
//not yet, please use aabb
btAssert(0);
}
void btOptimizedBvh::quantizeWithClamp(unsigned short* out, const btVector3& point) const
{
btAssert(m_useQuantization);
btVector3 clampedPoint(point);
clampedPoint.setMax(m_bvhAabbMin);
clampedPoint.setMin(m_bvhAabbMax);
btVector3 v = (clampedPoint - m_bvhAabbMin) * m_bvhQuantization;
out[0] = (unsigned short)(v.getX()+0.5f);
out[1] = (unsigned short)(v.getY()+0.5f);
out[2] = (unsigned short)(v.getZ()+0.5f);
}
btVector3 btOptimizedBvh::unQuantize(const unsigned short* vecIn) const
{
btVector3 vecOut;
vecOut.setValue(
(btScalar)(vecIn[0]) / (m_bvhQuantization.getX()),
(btScalar)(vecIn[1]) / (m_bvhQuantization.getY()),
(btScalar)(vecIn[2]) / (m_bvhQuantization.getZ()));
vecOut += m_bvhAabbMin;
return vecOut;
}
void btOptimizedBvh::swapLeafNodes(int i,int splitIndex)
{
if (m_useQuantization)
{
btQuantizedBvhNode tmp = m_quantizedLeafNodes[i];
m_quantizedLeafNodes[i] = m_quantizedLeafNodes[splitIndex];
m_quantizedLeafNodes[splitIndex] = tmp;
} else
{
btOptimizedBvhNode tmp = m_leafNodes[i];
m_leafNodes[i] = m_leafNodes[splitIndex];
m_leafNodes[splitIndex] = tmp;
}
}
void btOptimizedBvh::assignInternalNodeFromLeafNode(int internalNode,int leafNodeIndex)
{
if (m_useQuantization)
{
m_quantizedContiguousNodes[internalNode] = m_quantizedLeafNodes[leafNodeIndex];
} else
{
m_contiguousNodes[internalNode] = m_leafNodes[leafNodeIndex];
}
} }

View File

@@ -16,315 +16,48 @@ subject to the following restrictions:
#ifndef OPTIMIZED_BVH_H #ifndef OPTIMIZED_BVH_H
#define OPTIMIZED_BVH_H #define OPTIMIZED_BVH_H
#include "BulletCollision/BroadphaseCollision/btQuantizedBvh.h"
#include "../../LinearMath/btVector3.h"
//http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrf__m128.asp
class btStridingMeshInterface; class btStridingMeshInterface;
//Note: currently we have 16 bytes per quantized node
#define MAX_SUBTREE_SIZE_IN_BYTES 2048
///The btOptimizedBvh extends the btQuantizedBvh to create AABB tree for triangle meshes, through the btStridingMeshInterface.
///btQuantizedBvhNode is a compressed aabb node, 16 bytes. ATTRIBUTE_ALIGNED16(class) btOptimizedBvh : public btQuantizedBvh
///Node can be used for leafnode or internal node. Leafnodes can point to 32-bit triangle index (non-negative range).
ATTRIBUTE_ALIGNED16 (struct) btQuantizedBvhNode
{ {
//12 bytes
unsigned short int m_quantizedAabbMin[3];
unsigned short int m_quantizedAabbMax[3];
//4 bytes
int m_escapeIndexOrTriangleIndex;
bool isLeafNode() const
{
//skipindex is negative (internal node), triangleindex >=0 (leafnode)
return (m_escapeIndexOrTriangleIndex >= 0);
}
int getEscapeIndex() const
{
btAssert(!isLeafNode());
return -m_escapeIndexOrTriangleIndex;
}
int getTriangleIndex() const
{
btAssert(isLeafNode());
return m_escapeIndexOrTriangleIndex;
}
}
;
/// btOptimizedBvhNode contains both internal and leaf node information.
/// Total node size is 44 bytes / node. You can use the compressed version of 16 bytes.
ATTRIBUTE_ALIGNED16 (struct) btOptimizedBvhNode
{
//32 bytes
btVector3 m_aabbMinOrg;
btVector3 m_aabbMaxOrg;
//4
int m_escapeIndex;
//8
//for child nodes
int m_subPart;
int m_triangleIndex;
int m_padding[5];//bad, due to alignment
};
///btBvhSubtreeInfo provides info to gather a subtree of limited size
ATTRIBUTE_ALIGNED16(class) btBvhSubtreeInfo
{
public: public:
//12 bytes BT_DECLARE_ALIGNED_ALLOCATOR();
unsigned short int m_quantizedAabbMin[3];
unsigned short int m_quantizedAabbMax[3];
//4 bytes, points to the root of the subtree
int m_rootNodeIndex;
//4 bytes
int m_subtreeSize;
int m_padding[3];
void setAabbFromQuantizeNode(const btQuantizedBvhNode& quantizedNode)
{
m_quantizedAabbMin[0] = quantizedNode.m_quantizedAabbMin[0];
m_quantizedAabbMin[1] = quantizedNode.m_quantizedAabbMin[1];
m_quantizedAabbMin[2] = quantizedNode.m_quantizedAabbMin[2];
m_quantizedAabbMax[0] = quantizedNode.m_quantizedAabbMax[0];
m_quantizedAabbMax[1] = quantizedNode.m_quantizedAabbMax[1];
m_quantizedAabbMax[2] = quantizedNode.m_quantizedAabbMax[2];
}
}
;
class btNodeOverlapCallback
{
public:
virtual ~btNodeOverlapCallback() {};
virtual void processNode(int subPart, int triangleIndex) = 0;
};
#include "../../LinearMath/btAlignedAllocator.h"
#include "../../LinearMath/btAlignedObjectArray.h"
///for code readability:
typedef btAlignedObjectArray<btOptimizedBvhNode> NodeArray;
typedef btAlignedObjectArray<btQuantizedBvhNode> QuantizedNodeArray;
typedef btAlignedObjectArray<btBvhSubtreeInfo> BvhSubtreeInfoArray;
///OptimizedBvh store an AABB tree that can be quickly traversed on CPU (and SPU,GPU in future)
ATTRIBUTE_ALIGNED16(class) btOptimizedBvh
{
NodeArray m_leafNodes;
NodeArray m_contiguousNodes;
QuantizedNodeArray m_quantizedLeafNodes;
QuantizedNodeArray m_quantizedContiguousNodes;
int m_curNodeIndex;
//quantization data
bool m_useQuantization;
btVector3 m_bvhAabbMin;
btVector3 m_bvhAabbMax;
btVector3 m_bvhQuantization;
enum btTraversalMode
{
TRAVERSAL_STACKLESS = 0,
TRAVERSAL_STACKLESS_CACHE_FRIENDLY,
TRAVERSAL_RECURSIVE
};
btTraversalMode m_traversalMode;
BvhSubtreeInfoArray m_SubtreeHeaders;
///two versions, one for quantized and normal nodes. This allows code-reuse while maintaining readability (no template/macro!)
///this might be refactored into a virtual, it is usually not calculated at run-time
void setInternalNodeAabbMin(int nodeIndex, const btVector3& aabbMin)
{
if (m_useQuantization)
{
quantizeWithClamp(&m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0] ,aabbMin);
} else
{
m_contiguousNodes[nodeIndex].m_aabbMinOrg = aabbMin;
}
}
void setInternalNodeAabbMax(int nodeIndex,const btVector3& aabbMax)
{
if (m_useQuantization)
{
quantizeWithClamp(&m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0],aabbMax);
} else
{
m_contiguousNodes[nodeIndex].m_aabbMaxOrg = aabbMax;
}
}
btVector3 getAabbMin(int nodeIndex) const
{
if (m_useQuantization)
{
return unQuantize(&m_quantizedLeafNodes[nodeIndex].m_quantizedAabbMin[0]);
}
//non-quantized
return m_leafNodes[nodeIndex].m_aabbMinOrg;
}
btVector3 getAabbMax(int nodeIndex) const
{
if (m_useQuantization)
{
return unQuantize(&m_quantizedLeafNodes[nodeIndex].m_quantizedAabbMax[0]);
}
//non-quantized
return m_leafNodes[nodeIndex].m_aabbMaxOrg;
}
void setQuantizationValues(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax,btScalar quantizationMargin=btScalar(1.0));
void setInternalNodeEscapeIndex(int nodeIndex, int escapeIndex)
{
if (m_useQuantization)
{
m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex = -escapeIndex;
}
else
{
m_contiguousNodes[nodeIndex].m_escapeIndex = escapeIndex;
}
}
void mergeInternalNodeAabb(int nodeIndex,const btVector3& newAabbMin,const btVector3& newAabbMax)
{
if (m_useQuantization)
{
unsigned short int quantizedAabbMin[3];
unsigned short int quantizedAabbMax[3];
quantizeWithClamp(quantizedAabbMin,newAabbMin);
quantizeWithClamp(quantizedAabbMax,newAabbMax);
for (int i=0;i<3;i++)
{
if (m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[i] > quantizedAabbMin[i])
m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[i] = quantizedAabbMin[i];
if (m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[i] < quantizedAabbMax[i])
m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[i] = quantizedAabbMax[i];
}
} else
{
//non-quantized
m_contiguousNodes[nodeIndex].m_aabbMinOrg.setMin(newAabbMin);
m_contiguousNodes[nodeIndex].m_aabbMaxOrg.setMax(newAabbMax);
}
}
void swapLeafNodes(int firstIndex,int secondIndex);
void assignInternalNodeFromLeafNode(int internalNode,int leafNodeIndex);
protected: protected:
void buildTree (int startIndex,int endIndex);
int calcSplittingAxis(int startIndex,int endIndex);
int sortAndCalcSplittingIndex(int startIndex,int endIndex,int splitAxis);
void walkStacklessTree(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const;
void walkStacklessQuantizedTree(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax,int startNodeIndex,int endNodeIndex) const;
///tree traversal designed for small-memory processors like PS3 SPU
void walkStacklessQuantizedTreeCacheFriendly(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const;
///use the 16-byte stackless 'skipindex' node tree to do a recursive traversal
void walkRecursiveQuantizedTreeAgainstQueryAabb(const btQuantizedBvhNode* currentNode,btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const;
///use the 16-byte stackless 'skipindex' node tree to do a recursive traversal
void walkRecursiveQuantizedTreeAgainstQuantizedTree(const btQuantizedBvhNode* treeNodeA,const btQuantizedBvhNode* treeNodeB,btNodeOverlapCallback* nodeCallback) const;
inline bool testQuantizedAabbAgainstQuantizedAabb(unsigned short int* aabbMin1,unsigned short int* aabbMax1,const unsigned short int* aabbMin2,const unsigned short int* aabbMax2) const
{
bool overlap = true;
overlap = (aabbMin1[0] > aabbMax2[0] || aabbMax1[0] < aabbMin2[0]) ? false : overlap;
overlap = (aabbMin1[2] > aabbMax2[2] || aabbMax1[2] < aabbMin2[2]) ? false : overlap;
overlap = (aabbMin1[1] > aabbMax2[1] || aabbMax1[1] < aabbMin2[1]) ? false : overlap;
return overlap;
}
void updateSubtreeHeaders(int leftChildNodexIndex,int rightChildNodexIndex);
public: public:
btOptimizedBvh(); btOptimizedBvh();
virtual ~btOptimizedBvh(); virtual ~btOptimizedBvh();
void build(btStridingMeshInterface* triangles,bool useQuantizedAabbCompression, const btVector3& bvhAabbMin, const btVector3& bvhAabbMax); void build(btStridingMeshInterface* triangles,bool useQuantizedAabbCompression, const btVector3& bvhAabbMin, const btVector3& bvhAabbMax);
void reportAabbOverlappingNodex(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const; void refit(btStridingMeshInterface* triangles,const btVector3& aabbMin,const btVector3& aabbMax);
void reportSphereOverlappingNodex(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const;
void quantizeWithClamp(unsigned short* out, const btVector3& point) const;
btVector3 unQuantize(const unsigned short* vecIn) const;
///setTraversalMode let's you choose between stackless, recursive or stackless cache friendly tree traversal. Note this is only implemented for quantized trees.
void setTraversalMode(btTraversalMode traversalMode)
{
m_traversalMode = traversalMode;
}
void refit(btStridingMeshInterface* triangles);
void refitPartial(btStridingMeshInterface* triangles,const btVector3& aabbMin, const btVector3& aabbMax); void refitPartial(btStridingMeshInterface* triangles,const btVector3& aabbMin, const btVector3& aabbMax);
void updateBvhNodes(btStridingMeshInterface* meshInterface,int firstNode,int endNode,int index); void updateBvhNodes(btStridingMeshInterface* meshInterface,int firstNode,int endNode,int index);
/// Data buffer MUST be 16 byte aligned
QuantizedNodeArray& getQuantizedNodeArray() virtual bool serialize(void *o_alignedDataBuffer, unsigned i_dataBufferSize, bool i_swapEndian)
{
return m_quantizedContiguousNodes;
}
BvhSubtreeInfoArray& getSubtreeInfoArray()
{ {
return m_SubtreeHeaders; return btQuantizedBvh::serialize(o_alignedDataBuffer,i_dataBufferSize,i_swapEndian);
} }
} ///deSerializeInPlace loads and initializes a BVH from a buffer in memory 'in place'
; static btOptimizedBvh *deSerializeInPlace(void *i_alignedDataBuffer, unsigned int i_dataBufferSize, bool i_swapEndian);
};
#endif //OPTIMIZED_BVH_H #endif //OPTIMIZED_BVH_H

View File

@@ -13,7 +13,7 @@ subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include <BulletCollision/CollisionShapes/btPolyhedralConvexShape.h> #include "BulletCollision/CollisionShapes/btPolyhedralConvexShape.h"
btPolyhedralConvexShape::btPolyhedralConvexShape() btPolyhedralConvexShape::btPolyhedralConvexShape()
:m_localAabbMin(1,1,1), :m_localAabbMin(1,1,1),
@@ -95,7 +95,7 @@ void btPolyhedralConvexShape::batchedUnitVectorGetSupportingVertexWithoutMargin(
void btPolyhedralConvexShape::calculateLocalInertia(btScalar mass,btVector3& inertia) void btPolyhedralConvexShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const
{ {
//not yet, return box inertia //not yet, return box inertia
@@ -128,10 +128,46 @@ void btPolyhedralConvexShape::getAabb(const btTransform& trans,btVector3& aabbMi
void btPolyhedralConvexShape::setLocalScaling(const btVector3& scaling)
{
btConvexInternalShape::setLocalScaling(scaling);
recalcLocalAabb();
}
void btPolyhedralConvexShape::recalcLocalAabb() void btPolyhedralConvexShape::recalcLocalAabb()
{ {
m_isLocalAabbValid = true; m_isLocalAabbValid = true;
#if 1
static const btVector3 _directions[] =
{
btVector3( 1., 0., 0.),
btVector3( 0., 1., 0.),
btVector3( 0., 0., 1.),
btVector3( -1., 0., 0.),
btVector3( 0., -1., 0.),
btVector3( 0., 0., -1.)
};
btVector3 _supporting[] =
{
btVector3( 0., 0., 0.),
btVector3( 0., 0., 0.),
btVector3( 0., 0., 0.),
btVector3( 0., 0., 0.),
btVector3( 0., 0., 0.),
btVector3( 0., 0., 0.)
};
batchedUnitVectorGetSupportingVertexWithoutMargin(_directions, _supporting, 6);
for ( int i = 0; i < 3; ++i )
{
m_localAabbMax[i] = _supporting[i][i] + m_collisionMargin;
m_localAabbMin[i] = _supporting[i + 3][i] - m_collisionMargin;
}
#else
for (int i=0;i<3;i++) for (int i=0;i<3;i++)
{ {
@@ -143,6 +179,8 @@ void btPolyhedralConvexShape::recalcLocalAabb()
tmp = localGetSupportingVertex(vec); tmp = localGetSupportingVertex(vec);
m_localAabbMin[i] = tmp[i]-m_collisionMargin; m_localAabbMin[i] = tmp[i]-m_collisionMargin;
} }
#endif
} }

View File

@@ -16,13 +16,13 @@ subject to the following restrictions:
#ifndef BU_SHAPE #ifndef BU_SHAPE
#define BU_SHAPE #define BU_SHAPE
#include "../../LinearMath/btPoint3.h" #include "LinearMath/btPoint3.h"
#include "../../LinearMath/btMatrix3x3.h" #include "LinearMath/btMatrix3x3.h"
#include "btConvexShape.h" #include "btConvexInternalShape.h"
///PolyhedralConvexShape is an interface class for feature based (vertex/edge/face) convex shapes. ///The btPolyhedralConvexShape is an internal interface class for polyhedral convex shapes.
class btPolyhedralConvexShape : public btConvexShape class btPolyhedralConvexShape : public btConvexInternalShape
{ {
protected: protected:
@@ -38,7 +38,7 @@ public:
virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const;
virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const;
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia); virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const;
inline void getNonvirtualAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax, btScalar margin) const inline void getNonvirtualAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax, btScalar margin) const
@@ -73,6 +73,8 @@ public:
virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const;
virtual void setLocalScaling(const btVector3& scaling);
void recalcLocalAabb(); void recalcLocalAabb();
virtual int getNumVertices() const = 0 ; virtual int getNumVertices() const = 0 ;

View File

@@ -0,0 +1,164 @@
/*
btbtShapeHull implemented by John McCutchan.
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "btShapeHull.h"
#include "LinearMath/btConvexHull.h"
#define NUM_UNITSPHERE_POINTS 42
static btVector3 btUnitSpherePoints[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2] =
{
btVector3(btScalar(0.000000) , btScalar(-0.000000),btScalar(-1.000000)),
btVector3(btScalar(0.723608) , btScalar(-0.525725),btScalar(-0.447219)),
btVector3(btScalar(-0.276388) , btScalar(-0.850649),btScalar(-0.447219)),
btVector3(btScalar(-0.894426) , btScalar(-0.000000),btScalar(-0.447216)),
btVector3(btScalar(-0.276388) , btScalar(0.850649),btScalar(-0.447220)),
btVector3(btScalar(0.723608) , btScalar(0.525725),btScalar(-0.447219)),
btVector3(btScalar(0.276388) , btScalar(-0.850649),btScalar(0.447220)),
btVector3(btScalar(-0.723608) , btScalar(-0.525725),btScalar(0.447219)),
btVector3(btScalar(-0.723608) , btScalar(0.525725),btScalar(0.447219)),
btVector3(btScalar(0.276388) , btScalar(0.850649),btScalar(0.447219)),
btVector3(btScalar(0.894426) , btScalar(0.000000),btScalar(0.447216)),
btVector3(btScalar(-0.000000) , btScalar(0.000000),btScalar(1.000000)),
btVector3(btScalar(0.425323) , btScalar(-0.309011),btScalar(-0.850654)),
btVector3(btScalar(-0.162456) , btScalar(-0.499995),btScalar(-0.850654)),
btVector3(btScalar(0.262869) , btScalar(-0.809012),btScalar(-0.525738)),
btVector3(btScalar(0.425323) , btScalar(0.309011),btScalar(-0.850654)),
btVector3(btScalar(0.850648) , btScalar(-0.000000),btScalar(-0.525736)),
btVector3(btScalar(-0.525730) , btScalar(-0.000000),btScalar(-0.850652)),
btVector3(btScalar(-0.688190) , btScalar(-0.499997),btScalar(-0.525736)),
btVector3(btScalar(-0.162456) , btScalar(0.499995),btScalar(-0.850654)),
btVector3(btScalar(-0.688190) , btScalar(0.499997),btScalar(-0.525736)),
btVector3(btScalar(0.262869) , btScalar(0.809012),btScalar(-0.525738)),
btVector3(btScalar(0.951058) , btScalar(0.309013),btScalar(0.000000)),
btVector3(btScalar(0.951058) , btScalar(-0.309013),btScalar(0.000000)),
btVector3(btScalar(0.587786) , btScalar(-0.809017),btScalar(0.000000)),
btVector3(btScalar(0.000000) , btScalar(-1.000000),btScalar(0.000000)),
btVector3(btScalar(-0.587786) , btScalar(-0.809017),btScalar(0.000000)),
btVector3(btScalar(-0.951058) , btScalar(-0.309013),btScalar(-0.000000)),
btVector3(btScalar(-0.951058) , btScalar(0.309013),btScalar(-0.000000)),
btVector3(btScalar(-0.587786) , btScalar(0.809017),btScalar(-0.000000)),
btVector3(btScalar(-0.000000) , btScalar(1.000000),btScalar(-0.000000)),
btVector3(btScalar(0.587786) , btScalar(0.809017),btScalar(-0.000000)),
btVector3(btScalar(0.688190) , btScalar(-0.499997),btScalar(0.525736)),
btVector3(btScalar(-0.262869) , btScalar(-0.809012),btScalar(0.525738)),
btVector3(btScalar(-0.850648) , btScalar(0.000000),btScalar(0.525736)),
btVector3(btScalar(-0.262869) , btScalar(0.809012),btScalar(0.525738)),
btVector3(btScalar(0.688190) , btScalar(0.499997),btScalar(0.525736)),
btVector3(btScalar(0.525730) , btScalar(0.000000),btScalar(0.850652)),
btVector3(btScalar(0.162456) , btScalar(-0.499995),btScalar(0.850654)),
btVector3(btScalar(-0.425323) , btScalar(-0.309011),btScalar(0.850654)),
btVector3(btScalar(-0.425323) , btScalar(0.309011),btScalar(0.850654)),
btVector3(btScalar(0.162456) , btScalar(0.499995),btScalar(0.850654))
};
btShapeHull::btShapeHull (const btConvexShape* shape)
{
m_shape = shape;
m_vertices.clear ();
m_indices.clear();
m_numIndices = 0;
}
btShapeHull::~btShapeHull ()
{
m_indices.clear();
m_vertices.clear ();
}
bool
btShapeHull::buildHull (btScalar /*margin*/)
{
int numSampleDirections = NUM_UNITSPHERE_POINTS;
{
int numPDA = m_shape->getNumPreferredPenetrationDirections();
if (numPDA)
{
for (int i=0;i<numPDA;i++)
{
btVector3 norm;
m_shape->getPreferredPenetrationDirection(i,norm);
btUnitSpherePoints[numSampleDirections] = norm;
numSampleDirections++;
}
}
}
btVector3 supportPoints[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2];
int i;
for (i = 0; i < numSampleDirections; i++)
{
supportPoints[i] = m_shape->localGetSupportingVertex(btUnitSpherePoints[i]);
}
HullDesc hd;
hd.mFlags = QF_TRIANGLES;
hd.mVcount = static_cast<unsigned int>(numSampleDirections);
#ifdef BT_USE_DOUBLE_PRECISION
hd.mVertices = &supportPoints[0];
hd.mVertexStride = sizeof(btVector3);
#else
hd.mVertices = &supportPoints[0];
hd.mVertexStride = sizeof (btVector3);
#endif
HullLibrary hl;
HullResult hr;
if (hl.CreateConvexHull (hd, hr) == QE_FAIL)
{
return false;
}
m_vertices.resize (static_cast<int>(hr.mNumOutputVertices));
for (i = 0; i < static_cast<int>(hr.mNumOutputVertices); i++)
{
m_vertices[i] = hr.m_OutputVertices[i];
}
m_numIndices = hr.mNumIndices;
m_indices.resize(static_cast<int>(m_numIndices));
for (i = 0; i < static_cast<int>(m_numIndices); i++)
{
m_indices[i] = hr.m_Indices[i];
}
// free temporary hull result that we just copied
hl.ReleaseResult (hr);
return true;
}
int
btShapeHull::numTriangles () const
{
return static_cast<int>(m_numIndices / 3);
}
int
btShapeHull::numVertices () const
{
return m_vertices.size ();
}
int
btShapeHull::numIndices () const
{
return static_cast<int>(m_numIndices);
}

View File

@@ -0,0 +1,56 @@
/*
btShapeHull implemented by John McCutchan.
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2008 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef _SHAPE_HULL_H
#define _SHAPE_HULL_H
#include "LinearMath/btAlignedObjectArray.h"
#include "BulletCollision/CollisionShapes/btConvexShape.h"
///The btShapeHull class takes a btConvexShape, builds a simplified convex hull using btConvexHull and provides triangle indices and vertices.
///It can be useful for to simplify a complex convex object and for visualization of a non-polyhedral convex object.
///It approximates the convex hull using the supporting vertex of 42 directions.
class btShapeHull
{
public:
btShapeHull (const btConvexShape* shape);
~btShapeHull ();
bool buildHull (btScalar margin);
int numTriangles () const;
int numVertices () const;
int numIndices () const;
const btVector3* getVertexPointer() const
{
return &m_vertices[0];
}
const unsigned int* getIndexPointer() const
{
return &m_indices[0];
}
protected:
btAlignedObjectArray<btVector3> m_vertices;
btAlignedObjectArray<unsigned int> m_indices;
unsigned int m_numIndices;
const btConvexShape* m_shape;
};
#endif //_SHAPE_HULL_H

View File

@@ -68,7 +68,7 @@ void btSphereShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& a
void btSphereShape::calculateLocalInertia(btScalar mass,btVector3& inertia) void btSphereShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const
{ {
btScalar elem = btScalar(0.4) * mass * getMargin()*getMargin(); btScalar elem = btScalar(0.4) * mass * getMargin()*getMargin();
inertia.setValue(elem,elem,elem); inertia.setValue(elem,elem,elem);

View File

@@ -16,15 +16,17 @@ subject to the following restrictions:
#ifndef SPHERE_MINKOWSKI_H #ifndef SPHERE_MINKOWSKI_H
#define SPHERE_MINKOWSKI_H #define SPHERE_MINKOWSKI_H
#include "btConvexShape.h" #include "btConvexInternalShape.h"
#include "../BroadphaseCollision/btBroadphaseProxy.h" // for the types #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types
///btSphereShape implements an implicit (getSupportingVertex) Sphere ///The btSphereShape implements an implicit sphere, centered around a local origin with radius.
ATTRIBUTE_ALIGNED16(class) btSphereShape : public btConvexShape ATTRIBUTE_ALIGNED16(class) btSphereShape : public btConvexInternalShape
{ {
public: public:
BT_DECLARE_ALIGNED_ALLOCATOR();
btSphereShape (btScalar radius); btSphereShape (btScalar radius);
@@ -34,26 +36,26 @@ public:
virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const;
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia); virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const;
virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const;
virtual int getShapeType() const { return SPHERE_SHAPE_PROXYTYPE; } virtual int getShapeType() const { return SPHERE_SHAPE_PROXYTYPE; }
btScalar getRadius() const { return m_implicitShapeDimensions.getX();} btScalar getRadius() const { return m_implicitShapeDimensions.getX() * m_localScaling.getX();}
//debugging //debugging
virtual char* getName()const {return "SPHERE";} virtual const char* getName()const {return "SPHERE";}
virtual void setMargin(btScalar margin) virtual void setMargin(btScalar margin)
{ {
btConvexShape::setMargin(margin); btConvexInternalShape::setMargin(margin);
} }
virtual btScalar getMargin() const virtual btScalar getMargin() const
{ {
//to improve gjk behaviour, use radius+margin as the full margin, so never get into the penetration case //to improve gjk behaviour, use radius+margin as the full margin, so never get into the penetration case
//this means, non-uniform scaling is not supported anymore //this means, non-uniform scaling is not supported anymore
return m_localScaling.getX() * getRadius() + btConvexShape::getMargin(); return getRadius();
} }

View File

@@ -19,10 +19,11 @@ subject to the following restrictions:
btStaticPlaneShape::btStaticPlaneShape(const btVector3& planeNormal,btScalar planeConstant) btStaticPlaneShape::btStaticPlaneShape(const btVector3& planeNormal,btScalar planeConstant)
:m_planeNormal(planeNormal), :m_planeNormal(planeNormal.normalized()),
m_planeConstant(planeConstant), m_planeConstant(planeConstant),
m_localScaling(btScalar(0.),btScalar(0.),btScalar(0.)) m_localScaling(btScalar(0.),btScalar(0.),btScalar(0.))
{ {
// btAssert( btFuzzyZero(m_planeNormal.length() - btScalar(1.)) );
} }
@@ -86,7 +87,7 @@ void btStaticPlaneShape::processAllTriangles(btTriangleCallback* callback,const
} }
void btStaticPlaneShape::calculateLocalInertia(btScalar mass,btVector3& inertia) void btStaticPlaneShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const
{ {
(void)mass; (void)mass;

View File

@@ -19,8 +19,7 @@ subject to the following restrictions:
#include "btConcaveShape.h" #include "btConcaveShape.h"
///StaticPlaneShape simulates an 'infinite' plane by dynamically reporting triangles approximated by intersection of the plane with the AABB. ///The btStaticPlaneShape simulates an infinite non-moving (static) collision plane.
///Assumed is that the other objects is not also infinite, so a reasonable sized AABB.
class btStaticPlaneShape : public btConcaveShape class btStaticPlaneShape : public btConcaveShape
{ {
protected: protected:
@@ -46,14 +45,23 @@ public:
virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const; virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const;
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia); virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const;
virtual void setLocalScaling(const btVector3& scaling); virtual void setLocalScaling(const btVector3& scaling);
virtual const btVector3& getLocalScaling() const; virtual const btVector3& getLocalScaling() const;
const btVector3& getPlaneNormal() const
{
return m_planeNormal;
}
const btScalar& getPlaneConstant() const
{
return m_planeConstant;
}
//debugging //debugging
virtual char* getName()const {return "STATICPLANE";} virtual const char* getName()const {return "STATICPLANE";}
}; };

Some files were not shown because too many files have changed in this diff Show More