BulletMultiThreaded (SPU/multi-core): added compound shape support and concave-convex (swapped case). Thanks to Marten Svanfeldt

This commit is contained in:
ejcoumans
2007-08-02 20:16:58 +00:00
parent 8a1d556e93
commit 5279f9e129
6 changed files with 1040 additions and 779 deletions

View File

@@ -1,211 +1,213 @@
/* /*
Bullet Continuous Collision Detection and Physics Library Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com
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.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 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. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include "SpuGatheringCollisionDispatcher.h" #include "SpuGatheringCollisionDispatcher.h"
#include "SpuCollisionTaskProcess.h" #include "SpuCollisionTaskProcess.h"
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
#include "BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h" #include "BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h"
#include "SpuContactManifoldCollisionAlgorithm.h" #include "SpuContactManifoldCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h"
#include "BulletCollision/CollisionShapes/btCollisionShape.h" #include "BulletCollision/CollisionShapes/btCollisionShape.h"
SpuGatheringCollisionDispatcher::SpuGatheringCollisionDispatcher(class btThreadSupportInterface* threadInterface, unsigned int maxNumOutstandingTasks) SpuGatheringCollisionDispatcher::SpuGatheringCollisionDispatcher(class btThreadSupportInterface* threadInterface, unsigned int maxNumOutstandingTasks)
:m_spuCollisionTaskProcess(0), :m_spuCollisionTaskProcess(0),
m_threadInterface(threadInterface), m_threadInterface(threadInterface),
m_maxNumOutstandingTasks(maxNumOutstandingTasks) m_maxNumOutstandingTasks(maxNumOutstandingTasks)
{ {
} }
bool SpuGatheringCollisionDispatcher::supportsDispatchPairOnSpu(int proxyType0,int proxyType1) bool SpuGatheringCollisionDispatcher::supportsDispatchPairOnSpu(int proxyType0,int proxyType1)
{ {
bool supported0 = ( bool supported0 = (
(proxyType0 == BOX_SHAPE_PROXYTYPE) || (proxyType0 == BOX_SHAPE_PROXYTYPE) ||
(proxyType0 == TRIANGLE_SHAPE_PROXYTYPE) || (proxyType0 == TRIANGLE_SHAPE_PROXYTYPE) ||
(proxyType0 == SPHERE_SHAPE_PROXYTYPE) || (proxyType0 == SPHERE_SHAPE_PROXYTYPE) ||
(proxyType0 == CAPSULE_SHAPE_PROXYTYPE) || (proxyType0 == CAPSULE_SHAPE_PROXYTYPE) ||
(proxyType0 == CYLINDER_SHAPE_PROXYTYPE) || (proxyType0 == CYLINDER_SHAPE_PROXYTYPE) ||
// (proxyType0 == CONE_SHAPE_PROXYTYPE) || // (proxyType0 == CONE_SHAPE_PROXYTYPE) ||
(proxyType0 == TRIANGLE_MESH_SHAPE_PROXYTYPE) || (proxyType0 == TRIANGLE_MESH_SHAPE_PROXYTYPE) ||
(proxyType0 == CONVEX_HULL_SHAPE_PROXYTYPE) (proxyType0 == CONVEX_HULL_SHAPE_PROXYTYPE)||
); (proxyType0 == COMPOUND_SHAPE_PROXYTYPE)
);
bool supported1 = (
(proxyType1 == BOX_SHAPE_PROXYTYPE) || bool supported1 = (
(proxyType1 == TRIANGLE_SHAPE_PROXYTYPE) || (proxyType1 == BOX_SHAPE_PROXYTYPE) ||
(proxyType1 == SPHERE_SHAPE_PROXYTYPE) || (proxyType1 == TRIANGLE_SHAPE_PROXYTYPE) ||
(proxyType1 == CAPSULE_SHAPE_PROXYTYPE) || (proxyType1 == SPHERE_SHAPE_PROXYTYPE) ||
(proxyType1 == CYLINDER_SHAPE_PROXYTYPE) || (proxyType1 == CAPSULE_SHAPE_PROXYTYPE) ||
// (proxyType1 == CONE_SHAPE_PROXYTYPE) || (proxyType1 == CYLINDER_SHAPE_PROXYTYPE) ||
(proxyType1 == TRIANGLE_MESH_SHAPE_PROXYTYPE) || // (proxyType1 == CONE_SHAPE_PROXYTYPE) ||
(proxyType1 == CONVEX_HULL_SHAPE_PROXYTYPE) (proxyType1 == TRIANGLE_MESH_SHAPE_PROXYTYPE) ||
); (proxyType1 == CONVEX_HULL_SHAPE_PROXYTYPE) ||
(proxyType1 == COMPOUND_SHAPE_PROXYTYPE)
return supported0 && supported1; );
}
return supported0 && supported1;
}
SpuGatheringCollisionDispatcher::~SpuGatheringCollisionDispatcher()
{
if (m_spuCollisionTaskProcess) SpuGatheringCollisionDispatcher::~SpuGatheringCollisionDispatcher()
delete m_spuCollisionTaskProcess; {
if (m_spuCollisionTaskProcess)
} delete m_spuCollisionTaskProcess;
#include "stdio.h" }
#include "stdio.h"
///interface for iterating all overlapping collision pairs, no matter how those pairs are stored (array, set, map etc)
///this is useful for the collision dispatcher.
class btSpuCollisionPairCallback : public btOverlapCallback ///interface for iterating all overlapping collision pairs, no matter how those pairs are stored (array, set, map etc)
{ ///this is useful for the collision dispatcher.
btDispatcherInfo& m_dispatchInfo; class btSpuCollisionPairCallback : public btOverlapCallback
SpuGatheringCollisionDispatcher* m_dispatcher; {
btDispatcherInfo& m_dispatchInfo;
public: SpuGatheringCollisionDispatcher* m_dispatcher;
btSpuCollisionPairCallback(btDispatcherInfo& dispatchInfo,SpuGatheringCollisionDispatcher* dispatcher) public:
:m_dispatchInfo(dispatchInfo),
m_dispatcher(dispatcher) btSpuCollisionPairCallback(btDispatcherInfo& dispatchInfo,SpuGatheringCollisionDispatcher* dispatcher)
{ :m_dispatchInfo(dispatchInfo),
} m_dispatcher(dispatcher)
{
virtual bool processOverlap(btBroadphasePair& collisionPair) }
{
virtual bool processOverlap(btBroadphasePair& collisionPair)
{
//PPU version
//(*m_dispatcher->getNearCallback())(collisionPair,*m_dispatcher,m_dispatchInfo);
//PPU version
//only support discrete collision detection for now, we could fallback on PPU/unoptimized version for TOI/CCD //(*m_dispatcher->getNearCallback())(collisionPair,*m_dispatcher,m_dispatchInfo);
btAssert(m_dispatchInfo.m_dispatchFunc == btDispatcherInfo::DISPATCH_DISCRETE);
//only support discrete collision detection for now, we could fallback on PPU/unoptimized version for TOI/CCD
//by default, Bullet will use this near callback btAssert(m_dispatchInfo.m_dispatchFunc == btDispatcherInfo::DISPATCH_DISCRETE);
{
///userInfo is used to determine if the SPU has to handle this case or not (skip PPU tasks) //by default, Bullet will use this near callback
if (!collisionPair.m_userInfo) {
{ ///userInfo is used to determine if the SPU has to handle this case or not (skip PPU tasks)
collisionPair.m_userInfo = (void*) 1; if (!collisionPair.m_userInfo)
} {
if (!collisionPair.m_algorithm) collisionPair.m_userInfo = (void*) 1;
{ }
btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject; if (!collisionPair.m_algorithm)
btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject; {
btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject;
btCollisionAlgorithmConstructionInfo ci; btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject;
ci.m_dispatcher = m_dispatcher;
ci.m_manifold = 0; btCollisionAlgorithmConstructionInfo ci;
ci.m_dispatcher = m_dispatcher;
if (m_dispatcher->needsCollision(colObj0,colObj1)) ci.m_manifold = 0;
{
int proxyType0 = colObj0->getCollisionShape()->getShapeType(); if (m_dispatcher->needsCollision(colObj0,colObj1))
int proxyType1 = colObj1->getCollisionShape()->getShapeType(); {
if (m_dispatcher->supportsDispatchPairOnSpu(proxyType0,proxyType1)) int proxyType0 = colObj0->getCollisionShape()->getShapeType();
{ int proxyType1 = colObj1->getCollisionShape()->getShapeType();
collisionPair.m_algorithm = new SpuContactManifoldCollisionAlgorithm(ci,colObj0,colObj1); if (m_dispatcher->supportsDispatchPairOnSpu(proxyType0,proxyType1))
collisionPair.m_userInfo = (void*) 2; {
} else collisionPair.m_algorithm = new SpuContactManifoldCollisionAlgorithm(ci,colObj0,colObj1);
{ collisionPair.m_userInfo = (void*) 2;
collisionPair.m_algorithm = m_dispatcher->findAlgorithm(colObj0,colObj1); } else
collisionPair.m_userInfo = (void*)3; {
} collisionPair.m_algorithm = m_dispatcher->findAlgorithm(colObj0,colObj1);
} else collisionPair.m_userInfo = (void*)3;
{ }
//create an empty algorithm } else
collisionPair.m_algorithm = new btEmptyAlgorithm(ci); {
} //create an empty algorithm
} collisionPair.m_algorithm = new btEmptyAlgorithm(ci);
} }
return false; }
} }
}; return false;
}
void SpuGatheringCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,btDispatcherInfo& dispatchInfo) };
{
void SpuGatheringCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,btDispatcherInfo& dispatchInfo)
if (dispatchInfo.m_enableSPU) {
{
if (!m_spuCollisionTaskProcess) if (dispatchInfo.m_enableSPU)
m_spuCollisionTaskProcess = new SpuCollisionTaskProcess(m_threadInterface,m_maxNumOutstandingTasks); {
if (!m_spuCollisionTaskProcess)
m_spuCollisionTaskProcess->initialize2(); m_spuCollisionTaskProcess = new SpuCollisionTaskProcess(m_threadInterface,m_maxNumOutstandingTasks);
///modified version of btCollisionDispatcher::dispatchAllCollisionPairs: m_spuCollisionTaskProcess->initialize2();
{
btSpuCollisionPairCallback collisionCallback(dispatchInfo,this); ///modified version of btCollisionDispatcher::dispatchAllCollisionPairs:
{
pairCache->processAllOverlappingPairs(&collisionCallback); btSpuCollisionPairCallback collisionCallback(dispatchInfo,this);
}
pairCache->processAllOverlappingPairs(&collisionCallback);
//send one big batch }
int numTotalPairs = pairCache->getNumOverlappingPairs();
btBroadphasePair* pairPtr = pairCache->getOverlappingPairArrayPtr(); //send one big batch
int i; int numTotalPairs = pairCache->getNumOverlappingPairs();
for (i=0;i<numTotalPairs;) btBroadphasePair* pairPtr = pairCache->getOverlappingPairArrayPtr();
{ int i;
//Performance Hint: tweak this number during benchmarking for (i=0;i<numTotalPairs;)
static const int pairRange = SPU_BATCHSIZE_BROADPHASE_PAIRS; {
int endIndex = (i+pairRange) < numTotalPairs ? i+pairRange : numTotalPairs; //Performance Hint: tweak this number during benchmarking
m_spuCollisionTaskProcess->addWorkToTask(pairPtr,i,endIndex); static const int pairRange = SPU_BATCHSIZE_BROADPHASE_PAIRS;
i = endIndex; int endIndex = (i+pairRange) < numTotalPairs ? i+pairRange : numTotalPairs;
} m_spuCollisionTaskProcess->addWorkToTask(pairPtr,i,endIndex);
i = endIndex;
//handle PPU fallback pairs }
for (i=0;i<numTotalPairs;i++)
{ //handle PPU fallback pairs
btBroadphasePair& collisionPair = pairPtr[i]; for (i=0;i<numTotalPairs;i++)
if (collisionPair.m_userInfo == (void*)3) {
{ btBroadphasePair& collisionPair = pairPtr[i];
if (collisionPair.m_algorithm) if (collisionPair.m_userInfo == (void*)3)
{ {
btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject; if (collisionPair.m_algorithm)
btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject; {
btManifoldResult contactPointResult(colObj0,colObj1); btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject;
btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject;
if (dispatchInfo.m_dispatchFunc == btDispatcherInfo::DISPATCH_DISCRETE) btManifoldResult contactPointResult(colObj0,colObj1);
{
//discrete collision detection query if (dispatchInfo.m_dispatchFunc == btDispatcherInfo::DISPATCH_DISCRETE)
collisionPair.m_algorithm->processCollision(colObj0,colObj1,dispatchInfo,&contactPointResult); {
} else //discrete collision detection query
{ collisionPair.m_algorithm->processCollision(colObj0,colObj1,dispatchInfo,&contactPointResult);
//continuous collision detection query, time of impact (toi) } else
btScalar toi = collisionPair.m_algorithm->calculateTimeOfImpact(colObj0,colObj1,dispatchInfo,&contactPointResult); {
if (dispatchInfo.m_timeOfImpact > toi) //continuous collision detection query, time of impact (toi)
dispatchInfo.m_timeOfImpact = toi; btScalar toi = collisionPair.m_algorithm->calculateTimeOfImpact(colObj0,colObj1,dispatchInfo,&contactPointResult);
if (dispatchInfo.m_timeOfImpact > toi)
} dispatchInfo.m_timeOfImpact = toi;
}
} }
} }
}
//make sure all SPU work is done }
m_spuCollisionTaskProcess->flush2();
//make sure all SPU work is done
} else m_spuCollisionTaskProcess->flush2();
{
///PPU fallback } else
///!Need to make sure to clear all 'algorithms' when switching between SPU and PPU {
btCollisionDispatcher::dispatchAllCollisionPairs(pairCache,dispatchInfo); ///PPU fallback
} ///!Need to make sure to clear all 'algorithms' when switching between SPU and PPU
} btCollisionDispatcher::dispatchAllCollisionPairs(pairCache,dispatchInfo);
}
}

View File

@@ -1,171 +1,193 @@
/* /*
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/
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.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 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. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include "SpuContactResult.h" #include "SpuContactResult.h"
//#define DEBUG_SPU_COLLISION_DETECTION 1 //#define DEBUG_SPU_COLLISION_DETECTION 1
#include "SpuContactResult.h" #include "SpuContactResult.h"
SpuContactResult::SpuContactResult() SpuContactResult::SpuContactResult()
{ {
m_manifoldAddress = 0; m_manifoldAddress = 0;
m_spuManifold = NULL; m_spuManifold = NULL;
m_RequiresWriteBack = false; m_RequiresWriteBack = false;
} }
SpuContactResult::~SpuContactResult() SpuContactResult::~SpuContactResult()
{ {
g_manifoldDmaExport.swapBuffers(); g_manifoldDmaExport.swapBuffers();
} }
void SpuContactResult::setContactInfo(btPersistentManifold* spuManifold, uint64_t manifoldAddress,const btTransform& worldTrans0,const btTransform& worldTrans1) void SpuContactResult::setContactInfo(btPersistentManifold* spuManifold, uint64_t manifoldAddress,const btTransform& worldTrans0,const btTransform& worldTrans1, bool isSwapped)
{ {
// spu_printf("SpuContactResult::setContactInfo\n"); //spu_printf("SpuContactResult::setContactInfo ManifoldAddress: %lu\n", manifoldAddress);
m_rootWorldTransform0 = worldTrans0; m_rootWorldTransform0 = worldTrans0;
m_rootWorldTransform1 = worldTrans1; m_rootWorldTransform1 = worldTrans1;
m_manifoldAddress = manifoldAddress; m_manifoldAddress = manifoldAddress;
m_spuManifold = spuManifold; m_spuManifold = spuManifold;
} m_isSwapped = isSwapped;
}
void SpuContactResult::setShapeIdentifiers(int partId0,int index0, int partId1,int index1)
{ void SpuContactResult::setShapeIdentifiers(int partId0,int index0, int partId1,int index1)
{
}
}
///return true if it requires a dma transfer back
bool ManifoldResultAddContactPoint(const btVector3& normalOnBInWorld, ///return true if it requires a dma transfer back
const btVector3& pointInWorld, bool ManifoldResultAddContactPoint(const btVector3& normalOnBInWorld,
float depth, const btVector3& pointInWorld,
btPersistentManifold* manifoldPtr, float depth,
btTransform& transA, btPersistentManifold* manifoldPtr,
btTransform& transB btTransform& transA,
) btTransform& transB,
{ bool isSwapped)
{
float contactTreshold = manifoldPtr->getContactBreakingThreshold();
float contactTreshold = manifoldPtr->getContactBreakingThreshold();
//spu_printf("SPU: add contactpoint, depth:%f, contactTreshold %f, manifoldPtr %llx\n",depth,contactTreshold,manifoldPtr);
//spu_printf("SPU: add contactpoint, depth:%f, contactTreshold %f, manifoldPtr %llx\n",depth,contactTreshold,manifoldPtr);
#ifdef DEBUG_SPU_COLLISION_DETECTION
spu_printf("SPU: contactTreshold %f\n",contactTreshold); #ifdef DEBUG_SPU_COLLISION_DETECTION
#endif //DEBUG_SPU_COLLISION_DETECTION spu_printf("SPU: contactTreshold %f\n",contactTreshold);
if (depth > manifoldPtr->getContactBreakingThreshold()) #endif //DEBUG_SPU_COLLISION_DETECTION
return false; if (depth > manifoldPtr->getContactBreakingThreshold())
return false;
//provide inverses or just calculate?
btTransform transAInv = transA.inverse();//m_body0->m_cachedInvertedWorldTransform; //provide inverses or just calculate?
btTransform transBInv= transB.inverse();//m_body1->m_cachedInvertedWorldTransform; btTransform transAInv = transA.inverse();//m_body0->m_cachedInvertedWorldTransform;
btTransform transBInv= transB.inverse();//m_body1->m_cachedInvertedWorldTransform;
btVector3 pointA = pointInWorld + normalOnBInWorld * depth;
btVector3 localA = transAInv(pointA ); btVector3 pointA;
btVector3 localB = transBInv(pointInWorld); btVector3 localA;
btManifoldPoint newPt(localA,localB,normalOnBInWorld,depth); btVector3 localB;
btVector3 normal;
int insertIndex = manifoldPtr->getCacheEntry(newPt);
if (insertIndex >= 0) if (isSwapped)
{ {
// manifoldPtr->replaceContactPoint(newPt,insertIndex); normal = normalOnBInWorld * -1;
// return true; pointA = pointInWorld + normal * depth;
localA = transAInv(pointA );
#ifdef DEBUG_SPU_COLLISION_DETECTION localB = transBInv(pointInWorld);
spu_printf("SPU: same contact detected, nothing done\n"); /*localA = transBInv(pointA );
#endif //DEBUG_SPU_COLLISION_DETECTION localB = transAInv(pointInWorld);*/
// This is not needed, just use the old info! saves a DMA transfer as well }
} else else
{ {
normal = normalOnBInWorld;
newPt.m_combinedFriction = 0.25f;//calculateCombinedFriction(m_body0,m_body1); pointA = pointInWorld + normal * depth;
newPt.m_combinedRestitution = 0.0f;//calculateCombinedRestitution(m_body0,m_body1); localA = transAInv(pointA );
localB = transBInv(pointInWorld);
/* }
//potential TODO: SPU callbacks, either immediate (local on the SPU), or deferred
//User can override friction and/or restitution btManifoldPoint newPt(localA,localB,normal,depth);
if (gContactAddedCallback &&
//and if either of the two bodies requires custom material int insertIndex = manifoldPtr->getCacheEntry(newPt);
((m_body0->m_collisionFlags & btCollisionObject::customMaterialCallback) || if (insertIndex >= 0)
(m_body1->m_collisionFlags & btCollisionObject::customMaterialCallback))) {
{ // manifoldPtr->replaceContactPoint(newPt,insertIndex);
//experimental feature info, for per-triangle material etc. // return true;
(*gContactAddedCallback)(newPt,m_body0,m_partId0,m_index0,m_body1,m_partId1,m_index1);
} #ifdef DEBUG_SPU_COLLISION_DETECTION
*/ spu_printf("SPU: same contact detected, nothing done\n");
manifoldPtr->AddManifoldPoint(newPt); #endif //DEBUG_SPU_COLLISION_DETECTION
return true; // This is not needed, just use the old info! saves a DMA transfer as well
} else
} {
return false;
newPt.m_combinedFriction = 0.25f;//calculateCombinedFriction(m_body0,m_body1);
} newPt.m_combinedRestitution = 0.0f;//calculateCombinedRestitution(m_body0,m_body1);
/*
void SpuContactResult::writeDoubleBufferedManifold(btPersistentManifold* lsManifold, btPersistentManifold* mmManifold) //potential TODO: SPU callbacks, either immediate (local on the SPU), or deferred
{ //User can override friction and/or restitution
memcpy(g_manifoldDmaExport.getFront(),lsManifold,sizeof(btPersistentManifold)); if (gContactAddedCallback &&
//and if either of the two bodies requires custom material
g_manifoldDmaExport.swapBuffers(); ((m_body0->m_collisionFlags & btCollisionObject::customMaterialCallback) ||
g_manifoldDmaExport.backBufferDmaPut((uint64_t)mmManifold, sizeof(btPersistentManifold), DMA_TAG(9)); (m_body1->m_collisionFlags & btCollisionObject::customMaterialCallback)))
// Should there be any kind of wait here? What if somebody tries to use this tag again? What if we call this function again really soon? {
//no, the swapBuffers does the wait //experimental feature info, for per-triangle material etc.
} (*gContactAddedCallback)(newPt,m_body0,m_partId0,m_index0,m_body1,m_partId1,m_index1);
}
void SpuContactResult::addContactPoint(const btVector3& normalOnBInWorld,const btPoint3& pointInWorld,float depth) */
{ manifoldPtr->AddManifoldPoint(newPt);
// spu_printf("*** SpuContactResult::addContactPoint: depth = %f\n",depth); return true;
#ifdef DEBUG_SPU_COLLISION_DETECTION }
// int sman = sizeof(rage::phManifold); return false;
// spu_printf("sizeof_manifold = %i\n",sman);
#endif //DEBUG_SPU_COLLISION_DETECTION }
btPersistentManifold* localManifold = m_spuManifold;
void SpuContactResult::writeDoubleBufferedManifold(btPersistentManifold* lsManifold, btPersistentManifold* mmManifold)
btVector3 normalB(normalOnBInWorld.getX(),normalOnBInWorld.getY(),normalOnBInWorld.getZ()); {
btVector3 pointWrld(pointInWorld.getX(),pointInWorld.getY(),pointInWorld.getZ()); memcpy(g_manifoldDmaExport.getFront(),lsManifold,sizeof(btPersistentManifold));
//process the contact point g_manifoldDmaExport.swapBuffers();
const bool retVal = ManifoldResultAddContactPoint(normalB, g_manifoldDmaExport.backBufferDmaPut((uint64_t)mmManifold, sizeof(btPersistentManifold), DMA_TAG(9));
pointWrld, // Should there be any kind of wait here? What if somebody tries to use this tag again? What if we call this function again really soon?
depth, //no, the swapBuffers does the wait
localManifold, }
m_rootWorldTransform0,
m_rootWorldTransform1 void SpuContactResult::addContactPoint(const btVector3& normalOnBInWorld,const btPoint3& pointInWorld,float depth)
); {
m_RequiresWriteBack = m_RequiresWriteBack || retVal; //spu_printf("*** SpuContactResult::addContactPoint: depth = %f\n",depth);
}
#ifdef DEBUG_SPU_COLLISION_DETECTION
void SpuContactResult::flush() // int sman = sizeof(rage::phManifold);
{ // spu_printf("sizeof_manifold = %i\n",sman);
if (m_RequiresWriteBack) #endif //DEBUG_SPU_COLLISION_DETECTION
{
#ifdef DEBUG_SPU_COLLISION_DETECTION btPersistentManifold* localManifold = m_spuManifold;
spu_printf("SPU: Start rage::phManifold Write (Put) DMA\n");
#endif //DEBUG_SPU_COLLISION_DETECTION btVector3 normalB(normalOnBInWorld.getX(),normalOnBInWorld.getY(),normalOnBInWorld.getZ());
// spu_printf("writeDoubleBufferedManifold\n"); btVector3 pointWrld(pointInWorld.getX(),pointInWorld.getY(),pointInWorld.getZ());
writeDoubleBufferedManifold(m_spuManifold, (btPersistentManifold*)m_manifoldAddress);
#ifdef DEBUG_SPU_COLLISION_DETECTION //process the contact point
spu_printf("SPU: Finished (Put) DMA\n"); const bool retVal = ManifoldResultAddContactPoint(normalB,
#endif //DEBUG_SPU_COLLISION_DETECTION pointWrld,
} depth,
m_spuManifold = NULL; localManifold,
m_RequiresWriteBack = false; m_rootWorldTransform0,
} m_rootWorldTransform1,
m_isSwapped);
m_RequiresWriteBack = m_RequiresWriteBack || retVal;
}
void SpuContactResult::flush()
{
if (m_RequiresWriteBack)
{
#ifdef DEBUG_SPU_COLLISION_DETECTION
spu_printf("SPU: Start SpuContactResult::flush (Put) DMA\n");
spu_printf("Num contacts:%d\n", m_spuManifold->getNumContacts());
spu_printf("Manifold address: %llu\n", m_manifoldAddress);
#endif //DEBUG_SPU_COLLISION_DETECTION
// spu_printf("writeDoubleBufferedManifold\n");
writeDoubleBufferedManifold(m_spuManifold, (btPersistentManifold*)m_manifoldAddress);
#ifdef DEBUG_SPU_COLLISION_DETECTION
spu_printf("SPU: Finished (Put) DMA\n");
#endif //DEBUG_SPU_COLLISION_DETECTION
}
m_spuManifold = NULL;
m_RequiresWriteBack = false;
}

View File

@@ -1,110 +1,111 @@
/* /*
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/
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.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 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. 3. This notice may not be removed or altered from any source distribution.
*/ */
#ifndef SPU_CONTACT_RESULT2_H #ifndef SPU_CONTACT_RESULT2_H
#define SPU_CONTACT_RESULT2_H #define SPU_CONTACT_RESULT2_H
#ifndef WIN32 #ifndef WIN32
#include <stdint.h> #include <stdint.h>
#endif #endif
#include "../SpuDoubleBuffer.h" #include "../SpuDoubleBuffer.h"
#include "LinearMath/btTransform.h" #include "LinearMath/btTransform.h"
#include "LinearMath/btPoint3.h" #include "LinearMath/btPoint3.h"
#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
struct SpuCollisionPairInput struct SpuCollisionPairInput
{ {
uint64_t m_collisionShapes[2]; uint64_t m_collisionShapes[2];
void* m_spuCollisionShapes[2]; void* m_spuCollisionShapes[2];
uint64_t m_persistentManifoldPtr; uint64_t m_persistentManifoldPtr;
btVector3 m_primitiveDimensions0; btVector3 m_primitiveDimensions0;
btVector3 m_primitiveDimensions1; btVector3 m_primitiveDimensions1;
int m_shapeType0; int m_shapeType0;
int m_shapeType1; int m_shapeType1;
float m_collisionMargin0; float m_collisionMargin0;
float m_collisionMargin1; float m_collisionMargin1;
btTransform m_worldTransform0; btTransform m_worldTransform0;
btTransform m_worldTransform1; btTransform m_worldTransform1;
bool m_isSwapped; bool m_isSwapped;
}; };
struct SpuClosestPointInput struct SpuClosestPointInput
{ {
SpuClosestPointInput() SpuClosestPointInput()
:m_maximumDistanceSquared(float(1e30)), :m_maximumDistanceSquared(float(1e30)),
m_stackAlloc(0) m_stackAlloc(0)
{ {
} }
btTransform m_transformA; btTransform m_transformA;
btTransform m_transformB; btTransform m_transformB;
float m_maximumDistanceSquared; float m_maximumDistanceSquared;
class btStackAlloc* m_stackAlloc; class btStackAlloc* m_stackAlloc;
struct SpuConvexPolyhedronVertexData* m_convexVertexData; struct SpuConvexPolyhedronVertexData* m_convexVertexData;
}; };
///SpuContactResult exports the contact points using double-buffered DMA transfers, only when needed ///SpuContactResult exports the contact points using double-buffered DMA transfers, only when needed
///So when an existing contact point is duplicated, no transfer/refresh is performed. ///So when an existing contact point is duplicated, no transfer/refresh is performed.
class SpuContactResult class SpuContactResult
{ {
btTransform m_rootWorldTransform0; btTransform m_rootWorldTransform0;
btTransform m_rootWorldTransform1; btTransform m_rootWorldTransform1;
uint64_t m_manifoldAddress; uint64_t m_manifoldAddress;
btPersistentManifold* m_spuManifold; btPersistentManifold* m_spuManifold;
bool m_RequiresWriteBack; bool m_RequiresWriteBack;
bool m_isSwapped;
DoubleBuffer<btPersistentManifold, 1> g_manifoldDmaExport;
DoubleBuffer<btPersistentManifold, 1> g_manifoldDmaExport;
public:
SpuContactResult(); public:
virtual ~SpuContactResult(); SpuContactResult();
virtual ~SpuContactResult();
btPersistentManifold* GetSpuManifold() const
{ btPersistentManifold* GetSpuManifold() const
return m_spuManifold; {
} return m_spuManifold;
}
virtual void setShapeIdentifiers(int partId0,int index0, int partId1,int index1);
virtual void setShapeIdentifiers(int partId0,int index0, int partId1,int index1);
void setContactInfo(btPersistentManifold* spuManifold, uint64_t manifoldAddress,const btTransform& worldTrans0,const btTransform& worldTrans1);
void setContactInfo(btPersistentManifold* spuManifold, uint64_t manifoldAddress,const btTransform& worldTrans0,const btTransform& worldTrans1, bool isSwapped = false);
void writeDoubleBufferedManifold(btPersistentManifold* lsManifold, btPersistentManifold* mmManifold);
void writeDoubleBufferedManifold(btPersistentManifold* lsManifold, btPersistentManifold* mmManifold);
virtual void addContactPoint(const btVector3& normalOnBInWorld,const btPoint3& pointInWorld,float depth);
virtual void addContactPoint(const btVector3& normalOnBInWorld,const btPoint3& pointInWorld,float depth);
void flush();
}; void flush();
};
#endif //SPU_CONTACT_RESULT2_H
#endif //SPU_CONTACT_RESULT2_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;

View File

@@ -26,12 +26,21 @@ subject to the following restrictions:
class btOptimizedBvh; class btOptimizedBvh;
ATTRIBUTE_ALIGNED16(struct) btCompoundShapeChild
{
btTransform m_transform;
btCollisionShape* m_childShape;
int m_childShapeType;
btScalar m_childMargin;
};
/// btCompoundShape allows to store multiple other btCollisionShapes /// btCompoundShape allows to store multiple other btCollisionShapes
/// This allows for concave collision objects. This is more general then the Static Concave btTriangleMeshShape. /// This allows for concave collision objects. This is more general then the Static Concave btTriangleMeshShape.
class btCompoundShape : public btCollisionShape ATTRIBUTE_ALIGNED16(class) btCompoundShape : public btCollisionShape
{ {
btAlignedObjectArray<btTransform> m_childTransforms; //btAlignedObjectArray<btTransform> m_childTransforms;
btAlignedObjectArray<btCollisionShape*> m_childShapes; //btAlignedObjectArray<btCollisionShape*> m_childShapes;
btAlignedObjectArray<btCompoundShapeChild> m_children;
btVector3 m_localAabbMin; btVector3 m_localAabbMin;
btVector3 m_localAabbMax; btVector3 m_localAabbMax;
@@ -46,25 +55,31 @@ public:
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