Added multi-threaded collision detection. Original code is written for Cell SPU, but wrappers are provided to run on multi-core using Win32 Threads.

SpuLibspe2Support is on the todo list, so it can run on Cell Blade & PS3 Linux.
This commit is contained in:
ejcoumans
2007-06-13 01:04:43 +00:00
parent a0c6adf5d6
commit 6f26aa1591
34 changed files with 5508 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
#ifndef TYPE_DEFINITIONS_H
#define TYPE_DEFINITIONS_H
#include <LinearMath/btScalar.h>
///This file provides some platform/compiler checks for common definitions
#ifdef WIN32
#if defined(__MINGW32__) || defined(__CYGWIN__) || (defined (_MSC_VER) && _MSC_VER < 1300)
#else
#endif //__MINGW32__
typedef unsigned char uint8_t;
typedef unsigned long int uint64_t;
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;
#include <malloc.h>
#define memalign(alignment, size) malloc(size);
#include <string.h> //memcpy
#define USE_WIN32_THREADING 1
#else
#if defined (__CELLOS_LV2__)
///Playstation 3 Cell SDK
#else
//non-windows systems
#define USE_PTHREADS 1
#endif //__CELLOS_LV2__
#include <stdint.h>
#include <stdlib.h>
#endif
#endif //TYPE_DEFINITIONS_H

View File

@@ -0,0 +1,309 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 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.
*/
//#define __CELLOS_LV2__ 1
//#define DEBUG_SPU_TASK_SCHEDULING 1
#include "SpuLibspe2Support.h"
#include "Win32ThreadSupport.h"
//#include "SPUAssert.h"
#include <string.h>
//class OptimizedBvhNode;
#include "SpuCollisionTaskProcess.h"
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
#include "BulletCollision/CollisionShapes/btCollisionShape.h"
#include "BulletCollision/CollisionShapes/btConvexShape.h"
#include "SpuLibspe2Support.h"
#include "SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h" // for definitions processCollisionTask and createCollisionLocalStoreMemory
#include <stdio.h>
//#ifdef __CELLOS_LV2__???
#ifdef USE_WIN32_THREADING
Win32ThreadSupport gMidphaseSPU(Win32ThreadSupport::Win32ThreadConstructionInfo("collision",
processCollisionTask,
createCollisionLocalStoreMemory,
MIDPHASE_NUM_WORKUNIT_TASKS));
#elif defined(USE_LIBSPE2)
SpuLibspe2Support gMidphaseSPU(SPU_ELF_COLLISION_DETECTION,MIDPHASE_NUM_WORKUNIT_TASKS);
#endif
#ifdef __CELLOS_LV2__
#endif
SpuGatherAndProcessPairsTaskDesc g_spuGatherTaskDesc[MIDPHASE_NUM_WORKUNIT_TASKS];
SpuCollisionTaskProcess::SpuCollisionTaskProcess()
{
m_workUnitTaskBuffers = (unsigned char *)0;
for (int i = 0; i < MIDPHASE_NUM_WORKUNIT_TASKS; i++)
{
m_taskBusy[i] = false;
}
m_numBusyTasks = 0;
m_currentTask = 0;
m_currentPage = 0;
m_currentPageEntry = 0;
#ifdef DEBUG_SpuCollisionTaskProcess
m_initialized = false;
#endif
#ifdef __CELLOS_LV2__
// adding SPURS support.
gMidphaseSPU.startSPU();
#endif
//printf("sizeof vec_float4: %d\n", sizeof(vec_float4));
printf("sizeof SpuGatherAndProcessWorkUnitInput: %d\n", sizeof(SpuGatherAndProcessWorkUnitInput));
}
SpuCollisionTaskProcess::~SpuCollisionTaskProcess()
{
if (m_workUnitTaskBuffers != 0)
{
free(m_workUnitTaskBuffers);
m_workUnitTaskBuffers = 0;
}
#ifdef __CELLOS_LV2__
// Consolidating SPU code
gMidphaseSPU.stopSPU();
#endif
}
void
SpuCollisionTaskProcess::initialize2()
{
#ifdef DEBUG_SPU_TASK_SCHEDULING
printf("SpuCollisionTaskProcess::initialize()\n");
#endif //DEBUG_SPU_TASK_SCHEDULING
if (!m_workUnitTaskBuffers)
{
m_workUnitTaskBuffers = (unsigned char *)memalign(128, MIDPHASE_WORKUNIT_TASK_SIZE*MIDPHASE_NUM_WORKUNIT_TASKS);
}
for (int i = 0; i < MIDPHASE_NUM_WORKUNIT_TASKS; i++)
{
m_taskBusy[i] = false;
}
m_numBusyTasks = 0;
m_currentTask = 0;
m_currentPage = 0;
m_currentPageEntry = 0;
#ifdef DEBUG_SpuCollisionTaskProcess
m_initialized = true;
assert(MIDPHASE_NUM_WORKUNITS_PER_TASK*sizeof(SpuGatherAndProcessWorkUnitInput) <= MIDPHASE_WORKUNIT_TASK_SIZE);
#endif
}
void SpuCollisionTaskProcess::issueTask2()
{
#ifdef DEBUG_SPU_TASK_SCHEDULING
printf("SpuCollisionTaskProcess::issueTask (m_currentTask= %d\)n", m_currentTask);
#endif //DEBUG_SPU_TASK_SCHEDULING
m_taskBusy[m_currentTask] = true;
m_numBusyTasks++;
SpuGatherAndProcessPairsTaskDesc& taskDesc = g_spuGatherTaskDesc[m_currentTask];
{
// send task description in event message
// no error checking here...
// but, currently, event queue can be no larger than NUM_WORKUNIT_TASKS.
taskDesc.inPtr = reinterpret_cast<uint64_t>(MIDPHASE_TASK_PTR(m_currentTask));
taskDesc.taskId = m_currentTask;
taskDesc.numPages = m_currentPage+1;
taskDesc.numOnLastPage = m_currentPageEntry;
}
gMidphaseSPU.sendRequest(CMD_GATHER_AND_PROCESS_PAIRLIST, (uint32_t) &taskDesc,m_currentTask);
// if all tasks busy, wait for spu event to clear the task.
if (m_numBusyTasks >= MIDPHASE_NUM_WORKUNIT_TASKS)
{
unsigned int taskId;
unsigned int outputSize;
gMidphaseSPU.waitForResponse(&taskId, &outputSize);
//printf("PPU: after issue, received event: %u %d\n", taskId, outputSize);
//postProcess(taskId, outputSize);
m_taskBusy[taskId] = false;
m_numBusyTasks--;
}
}
void SpuCollisionTaskProcess::addWorkToTask(void* pairArrayPtr,int startIndex,int endIndex)
{
#ifdef DEBUG_SPU_TASK_SCHEDULING
printf("#");
#endif //DEBUG_SPU_TASK_SCHEDULING
#ifdef DEBUG_SpuCollisionTaskProcess
assert(m_initialized);
assert(m_workUnitTaskBuffers);
#endif
bool batch = true;
if (batch)
{
if (m_currentPageEntry == MIDPHASE_NUM_WORKUNITS_PER_PAGE)
{
if (m_currentPage == MIDPHASE_NUM_WORKUNIT_PAGES-1)
{
// task buffer is full, issue current task.
// if all task buffers busy, this waits until SPU is done.
issueTask2();
// find new task buffer
for (unsigned int i = 0; i < MIDPHASE_NUM_WORKUNIT_TASKS; i++)
{
if (!m_taskBusy[i])
{
m_currentTask = i;
//init the task data
break;
}
}
m_currentPage = 0;
}
else
{
m_currentPage++;
}
m_currentPageEntry = 0;
}
}
{
SpuGatherAndProcessWorkUnitInput &wuInput =
*(reinterpret_cast<SpuGatherAndProcessWorkUnitInput*>
(MIDPHASE_ENTRY_PTR(m_currentTask, m_currentPage, m_currentPageEntry)));
wuInput.m_pairArrayPtr = reinterpret_cast<uint64_t>(pairArrayPtr);
wuInput.m_startIndex = startIndex;
wuInput.m_endIndex = endIndex;
m_currentPageEntry++;
if (!batch)
{
issueTask2();
// find new task buffer
for (unsigned int i = 0; i < MIDPHASE_NUM_WORKUNIT_TASKS; i++)
{
if (!m_taskBusy[i])
{
m_currentTask = i;
//init the task data
break;
}
}
m_currentPage = 0;
m_currentPageEntry =0;
}
}
}
void
SpuCollisionTaskProcess::flush2()
{
#ifdef DEBUG_SPU_TASK_SCHEDULING
printf("\nSpuCollisionTaskProcess::flush()\n");
#endif //DEBUG_SPU_TASK_SCHEDULING
// if there's a partially filled task buffer, submit that task
if (m_currentPage > 0 || m_currentPageEntry > 0)
{
issueTask2();
}
// all tasks are issued, wait for all tasks to be complete
while(m_numBusyTasks > 0)
{
// Consolidating SPU code
unsigned int taskId;
unsigned int outputSize;
{
// SPURS support.
gMidphaseSPU.waitForResponse(&taskId, &outputSize);
}
//printf("PPU: flushing, received event: %u %d\n", taskId, outputSize);
//postProcess(taskId, outputSize);
m_taskBusy[taskId] = false;
m_numBusyTasks--;
}
}

View File

@@ -0,0 +1,131 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 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.
*/
#ifndef SPU_COLLISION_TASK_PROCESS_H
#define SPU_COLLISION_TASK_PROCESS_H
#include <assert.h>
#include <LinearMath/btScalar.h>
#include "PlatformDefinitions.h"
#define DEBUG_SpuCollisionTaskProcess 1
//#define MIDPHASE_NUM_WORKUNIT_TASKS 4 //attempt for multi-core
#define MIDPHASE_NUM_WORKUNIT_TASKS 12 //attempt for multi-core
//#define MIDPHASE_NUM_WORKUNIT_TASKS 6 //for SPUs
#define CMD_GATHER_AND_PROCESS_PAIRLIST 1
class btCollisionObject;
class btPersistentManifold;
class btDispatcher;
///Task Description for SPU collision detection
struct SpuGatherAndProcessPairsTaskDesc
{
uint64_t inPtr;//m_pairArrayPtr;
//mutex variable
uint32_t m_someMutexVariableInMainMemory;
uint64_t m_dispatcher;
uint32_t numOnLastPage;
uint16_t numPages;
uint16_t taskId;
struct CollisionTask_LocalStoreMemory* m_lsMemory;
}
#ifdef __CELLOS_LV2__
__attribute__ ((aligned (16)))
#endif
;
///MidphaseWorkUnitInput stores individual primitive versus mesh collision detection input, to be processed by the SPU.
struct SpuGatherAndProcessWorkUnitInput
{
uint64_t m_pairArrayPtr;
int m_startIndex;
int m_endIndex;
};
/// SpuCollisionTaskProcess handles SPU processing of collision pairs.
/// Maintains a set of task buffers.
/// When the task is full, the task is issued for SPUs to process. Contact output goes into btPersistentManifold
/// associated with each task.
/// When PPU issues a task, it will look for completed task buffers
/// PPU will do postprocessing, dependent on workunit output (not likely)
class SpuCollisionTaskProcess
{
unsigned char *m_workUnitTaskBuffers;
// track task buffers that are being used, and total busy tasks
bool m_taskBusy[MIDPHASE_NUM_WORKUNIT_TASKS];
unsigned int m_numBusyTasks;
// the current task and the current entry to insert a new work unit
unsigned int m_currentTask;
unsigned int m_currentPage;
unsigned int m_currentPageEntry;
#ifdef DEBUG_SpuCollisionTaskProcess
bool m_initialized;
#endif
void issueTask2();
//void postProcess(unsigned int taskId, int outputSize);
public:
SpuCollisionTaskProcess();
~SpuCollisionTaskProcess();
///call initialize in the beginning of the frame, before addCollisionPairToTask
void initialize2();
///batch up additional work to a current task for SPU processing. When batch is full, it issues the task.
void addWorkToTask(void* pairArrayPtr,int startIndex,int endIndex);
///call flush to submit potential outstanding work to SPUs and wait for all involved SPUs to be finished
void flush2();
};
#define MIDPHASE_TASK_PTR(task) (&m_workUnitTaskBuffers[0] + MIDPHASE_WORKUNIT_TASK_SIZE*task)
#define MIDPHASE_ENTRY_PTR(task,page,entry) (MIDPHASE_TASK_PTR(task) + MIDPHASE_WORKUNIT_PAGE_SIZE*page + sizeof(SpuGatherAndProcessWorkUnitInput)*entry)
#define MIDPHASE_OUTPUT_PTR(task) (&m_contactOutputBuffers[0] + MIDPHASE_MAX_CONTACT_BUFFER_SIZE*task)
#define MIDPHASE_TREENODES_PTR(task) (&m_complexShapeBuffers[0] + MIDPHASE_COMPLEX_SHAPE_BUFFER_SIZE*task)
#define MIDPHASE_WORKUNIT_PAGE_SIZE (16)
#define MIDPHASE_NUM_WORKUNIT_PAGES 1
#define MIDPHASE_WORKUNIT_TASK_SIZE (MIDPHASE_WORKUNIT_PAGE_SIZE*MIDPHASE_NUM_WORKUNIT_PAGES)
#define MIDPHASE_NUM_WORKUNITS_PER_PAGE (MIDPHASE_WORKUNIT_PAGE_SIZE / sizeof(SpuGatherAndProcessWorkUnitInput))
#define MIDPHASE_NUM_WORKUNITS_PER_TASK (MIDPHASE_NUM_WORKUNITS_PER_PAGE*MIDPHASE_NUM_WORKUNIT_PAGES)
#endif // SPU_COLLISION_TASK_PROCESS_H

View File

@@ -0,0 +1,58 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 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 "SpuContactManifoldCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
#include "BulletCollision/CollisionShapes/btCollisionShape.h"
SpuContactManifoldCollisionAlgorithm::SpuContactManifoldCollisionAlgorithm()
:m_manifoldPtr(0)
{
}
void SpuContactManifoldCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)
{
btAssert(0);
}
float SpuContactManifoldCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)
{
btAssert(0);
return 1.f;
}
#ifndef __SPU__
SpuContactManifoldCollisionAlgorithm::SpuContactManifoldCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1)
:btCollisionAlgorithm(ci)
{
m_manifoldPtr = m_dispatcher->getNewManifold(body0,body1);
m_shapeType0 = body0->getCollisionShape()->getShapeType();
m_shapeType1 = body1->getCollisionShape()->getShapeType();
m_collisionMargin0 = body0->getCollisionShape()->getMargin();
m_collisionMargin1 = body1->getCollisionShape()->getMargin();
}
#endif //__SPU__
SpuContactManifoldCollisionAlgorithm::~SpuContactManifoldCollisionAlgorithm()
{
if (m_manifoldPtr)
m_dispatcher->releaseManifold(m_manifoldPtr);
}

View File

@@ -0,0 +1,80 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 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.
*/
#ifndef SPU_CONTACTMANIFOLD_COLLISION_ALGORITHM_H
#define SPU_CONTACTMANIFOLD_COLLISION_ALGORITHM_H
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
#include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h"
class btPersistentManifold;
/// SpuContactManifoldCollisionAlgorithm provides contact manifold and should be processed on SPU.
ATTRIBUTE_ALIGNED16(class) SpuContactManifoldCollisionAlgorithm : public btCollisionAlgorithm
{
btPersistentManifold* m_manifoldPtr;
int m_shapeType0;
int m_shapeType1;
float m_collisionMargin0;
float m_collisionMargin1;
public:
virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut);
virtual float calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut);
SpuContactManifoldCollisionAlgorithm();
SpuContactManifoldCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1);
virtual ~SpuContactManifoldCollisionAlgorithm();
btPersistentManifold* getContactManifoldPtr()
{
return m_manifoldPtr;
}
int getShapeType0() const
{
return m_shapeType0;
}
int getShapeType1() const
{
return m_shapeType1;
}
float getCollisionMargin0() const
{
return m_collisionMargin0;
}
float getCollisionMargin1() const
{
return m_collisionMargin1;
}
struct CreateFunc :public btCollisionAlgorithmCreateFunc
{
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1)
{
return new SpuContactManifoldCollisionAlgorithm(ci,body0,body1);
}
};
};
#endif //SPU_CONTACTMANIFOLD_COLLISION_ALGORITHM_H

View File

@@ -0,0 +1,105 @@
#ifndef DOUBLE_BUFFER_H
#define DOUBLE_BUFFER_H
#ifdef __CELLOS_LV2__
#include <cell/dma.h>
#include <stdint.h>
#else
#include "SpuFakeDma.h"
#endif //
///DoubleBuffer
template<class T, int size>
class DoubleBuffer
{
#ifdef __CELLOS_LV2__
T m_buffer0[size] __attribute__ ((aligned (128)));
T m_buffer1[size] __attribute__ ((aligned (128)));
#else
T m_buffer0[size];
T m_buffer1[size];
#endif
T *m_frontBuffer;
T *m_backBuffer;
unsigned int m_dmaTag;
bool m_dmaPending;
public:
bool isPending() const { return m_dmaPending;}
DoubleBuffer();
// dma get and put commands
void backBufferDmaGet(uint64_t ea, unsigned int numBytes, unsigned int tag);
void backBufferDmaPut(uint64_t ea, unsigned int numBytes, unsigned int tag);
// gets pointer to a buffer
T *getFront();
T *getBack();
// if back buffer dma was started, wait for it to complete
// then move back to front and vice versa
T *swapBuffers();
};
template<class T, int size>
DoubleBuffer<T,size>::DoubleBuffer()
{
m_dmaPending = false;
m_frontBuffer = &m_buffer0[0];
m_backBuffer = &m_buffer1[0];
}
template<class T, int size>
void
DoubleBuffer<T,size>::backBufferDmaGet(uint64_t ea, unsigned int numBytes, unsigned int tag)
{
m_dmaPending = true;
m_dmaTag = tag;
cellDmaLargeGet(m_backBuffer, ea, numBytes, tag, 0, 0);
}
template<class T, int size>
void
DoubleBuffer<T,size>::backBufferDmaPut(uint64_t ea, unsigned int numBytes, unsigned int tag)
{
m_dmaPending = true;
m_dmaTag = tag;
cellDmaLargePut(m_backBuffer, ea, numBytes, tag, 0, 0);
}
template<class T, int size>
T *
DoubleBuffer<T,size>::getFront()
{
return m_frontBuffer;
}
template<class T, int size>
T *
DoubleBuffer<T,size>::getBack()
{
return m_backBuffer;
}
template<class T, int size>
T *
DoubleBuffer<T,size>::swapBuffers()
{
if (m_dmaPending)
{
cellDmaWaitTagStatusAll(1<<m_dmaTag);
m_dmaPending = false;
}
T *tmp = m_backBuffer;
m_backBuffer = m_frontBuffer;
m_frontBuffer = tmp;
return m_frontBuffer;
}
#endif

View File

@@ -0,0 +1,30 @@
#include "SpuFakeDma.h"
int cellDmaLargeGet(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid)
{
void* targetMainMem = (void*)ea;
memcpy(ls,targetMainMem,size);
return 0;
}
int cellDmaGet(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid)
{
void* targetMainMem = (void*)ea;
memcpy(ls,targetMainMem,size);
return 0;
}
int cellDmaLargePut(const void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid)
{
void* targetMainMem = (void*)ea;
memcpy(targetMainMem,ls,size);
return 0;
}
void cellDmaWaitTagStatusAll(int ignore)
{
}

View File

@@ -0,0 +1,21 @@
#ifndef FAKE_DMA_H
#define FAKE_DMA_H
#include "PlatformDefinitions.h"
#include <LinearMath/btScalar.h> //for definition of uint64_t,uint32_t
#define DMA_TAG(a) (a)
#define DMA_MASK(a) (a)
/// cellDmaLargeGet Win32 replacements for Cell DMA to allow simulating most of the SPU code (just memcpy)
int cellDmaLargeGet(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid);
int cellDmaGet(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid);
/// cellDmaLargePut Win32 replacements for Cell DMA to allow simulating most of the SPU code (just memcpy)
int cellDmaLargePut(const void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid);
/// cellDmaWaitTagStatusAll Win32 replacements for Cell DMA to allow simulating most of the SPU code (just memcpy)
void cellDmaWaitTagStatusAll(int ignore);
#endif //FAKE_DMA_H

View File

@@ -0,0 +1,210 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 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 "SpuGatheringCollisionDispatcher.h"
#include "SpuCollisionTaskProcess.h"
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
#include "BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h"
#include "SpuContactManifoldCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
#include "BulletCollision/CollisionShapes/btCollisionShape.h"
SpuGatheringCollisionDispatcher::SpuGatheringCollisionDispatcher()
:m_spuCollisionTaskProcess(0)
{
}
bool SpuGatheringCollisionDispatcher::supportsDispatchPairOnSpu(int proxyType0,int proxyType1)
{
bool supported0 = (
(proxyType0 == BOX_SHAPE_PROXYTYPE) ||
(proxyType0 == TRIANGLE_SHAPE_PROXYTYPE) ||
(proxyType0 == SPHERE_SHAPE_PROXYTYPE) ||
(proxyType0 == CAPSULE_SHAPE_PROXYTYPE) ||
(proxyType0 == CYLINDER_SHAPE_PROXYTYPE) ||
// (proxyType0 == CONE_SHAPE_PROXYTYPE) ||
(proxyType0 == TRIANGLE_MESH_SHAPE_PROXYTYPE) ||
(proxyType0 == CONVEX_HULL_SHAPE_PROXYTYPE)
);
bool supported1 = (
(proxyType1 == BOX_SHAPE_PROXYTYPE) ||
(proxyType1 == TRIANGLE_SHAPE_PROXYTYPE) ||
(proxyType1 == SPHERE_SHAPE_PROXYTYPE) ||
(proxyType1 == CAPSULE_SHAPE_PROXYTYPE) ||
(proxyType1 == CYLINDER_SHAPE_PROXYTYPE) ||
// (proxyType1 == CONE_SHAPE_PROXYTYPE) ||
(proxyType1 == TRIANGLE_MESH_SHAPE_PROXYTYPE) ||
(proxyType1 == CONVEX_HULL_SHAPE_PROXYTYPE)
);
return supported0 && supported1;
}
SpuGatheringCollisionDispatcher::~SpuGatheringCollisionDispatcher()
{
if (m_spuCollisionTaskProcess)
delete m_spuCollisionTaskProcess;
}
#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
{
btDispatcherInfo& m_dispatchInfo;
SpuGatheringCollisionDispatcher* m_dispatcher;
public:
btSpuCollisionPairCallback(btDispatcherInfo& dispatchInfo,SpuGatheringCollisionDispatcher* dispatcher)
:m_dispatchInfo(dispatchInfo),
m_dispatcher(dispatcher)
{
}
virtual bool processOverlap(btBroadphasePair& collisionPair)
{
//PPU version
//(*m_dispatcher->getNearCallback())(collisionPair,*m_dispatcher,m_dispatchInfo);
//only support discrete collision detection for now, we could fallback on PPU/unoptimized version for TOI/CCD
btAssert(m_dispatchInfo.m_dispatchFunc == btDispatcherInfo::DISPATCH_DISCRETE);
//by default, Bullet will use this near callback
{
///userInfo is used to determine if the SPU has to handle this case or not (skip PPU tasks)
if (!collisionPair.m_userInfo)
{
collisionPair.m_userInfo = (void*) 1;
}
if (!collisionPair.m_algorithm)
{
btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject;
btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject;
btCollisionAlgorithmConstructionInfo ci;
ci.m_dispatcher = m_dispatcher;
ci.m_manifold = 0;
if (m_dispatcher->needsCollision(colObj0,colObj1))
{
int proxyType0 = colObj0->getCollisionShape()->getShapeType();
int proxyType1 = colObj1->getCollisionShape()->getShapeType();
if (m_dispatcher->supportsDispatchPairOnSpu(proxyType0,proxyType1))
{
collisionPair.m_algorithm = new SpuContactManifoldCollisionAlgorithm(ci,colObj0,colObj1);
collisionPair.m_userInfo = (void*) 2;
} else
{
collisionPair.m_algorithm = m_dispatcher->findAlgorithm(colObj0,colObj1);
collisionPair.m_userInfo = (void*)3;
}
} else
{
//create an empty algorithm
collisionPair.m_algorithm = new btEmptyAlgorithm(ci);
}
}
}
return false;
}
};
void SpuGatheringCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,btDispatcherInfo& dispatchInfo)
{
//cellPerfInsertCBEpmBookmark(1);
if (dispatchInfo.m_enableSPU)
{
if (!m_spuCollisionTaskProcess)
m_spuCollisionTaskProcess = new SpuCollisionTaskProcess();
m_spuCollisionTaskProcess->initialize2();
///modified version of btCollisionDispatcher::dispatchAllCollisionPairs:
{
btSpuCollisionPairCallback collisionCallback(dispatchInfo,this);
pairCache->processAllOverlappingPairs(&collisionCallback);
}
//send one big batch
int numTotalPairs = pairCache->getNumOverlappingPairs();
btBroadphasePair* pairPtr = pairCache->getOverlappingPairArrayPtr();
int i;
for (i=0;i<numTotalPairs;)
{
//Performance Hint: tweak this number during benchmarking
static const int pairRange = SPU_BATCHSIZE_BROADPHASE_PAIRS;
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++)
{
btBroadphasePair& collisionPair = pairPtr[i];
if (collisionPair.m_userInfo == (void*)3)
{
if (collisionPair.m_algorithm)
{
btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject;
btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject;
btManifoldResult contactPointResult(colObj0,colObj1);
if (dispatchInfo.m_dispatchFunc == btDispatcherInfo::DISPATCH_DISCRETE)
{
//discrete collision detection query
collisionPair.m_algorithm->processCollision(colObj0,colObj1,dispatchInfo,&contactPointResult);
} else
{
//continuous collision detection query, time of impact (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();
} else
{
///PPU fallback
///!Need to make sure to clear all 'algorithms' when switching between SPU and PPU
btCollisionDispatcher::dispatchAllCollisionPairs(pairCache,dispatchInfo);
}
}

View File

@@ -0,0 +1,58 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 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.
*/
#ifndef SPU_GATHERING_COLLISION__DISPATCHER_H
#define SPU_GATHERING_COLLISION__DISPATCHER_H
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
///Tuning value to optimized SPU utilization
///Too small value means Task overhead is large compared to computation (too fine granularity)
///Too big value might render some SPUs are idle, while a few other SPUs are doing all work.
//#define SPU_BATCHSIZE_BROADPHASE_PAIRS 16
#define SPU_BATCHSIZE_BROADPHASE_PAIRS 256
class SpuCollisionTaskProcess;
///SpuGatheringCollisionDispatcher can use SPU to gather and calculate collision detection
///Time of Impact, Closest Points and Penetration Depth.
class SpuGatheringCollisionDispatcher : public btCollisionDispatcher
{
SpuCollisionTaskProcess* m_spuCollisionTaskProcess;
public:
//can be used by SPU collision algorithms
SpuCollisionTaskProcess* getSpuCollisionTaskProcess()
{
return m_spuCollisionTaskProcess;
}
SpuGatheringCollisionDispatcher ();
virtual ~SpuGatheringCollisionDispatcher();
bool supportsDispatchPairOnSpu(int proxyType0,int proxyType1);
virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,btDispatcherInfo& dispatchInfo);
};
#endif //SPU_GATHERING_COLLISION__DISPATCHER_H

View File

@@ -0,0 +1 @@
Empty placeholder for future Libspe2 SPU task

View File

@@ -0,0 +1,224 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 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.
*/
#ifdef USE_LIBSPE2
#include "SpuLibspe2Support.h"
#include "SpuCollisionTaskProcess.h"
#include "SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h"
#include <Windows.h>
///SpuLibspe2Support helps to initialize/shutdown libspe2, start/stop SPU tasks and communication
///Setup and initialize SPU/CELL/Libspe2
SpuLibspe2Support::SpuLibspe2Support(SpuLibspe2ElfId_t elfId,int numThreads)
{
startSPUs(numThreads);
}
///cleanup/shutdown Libspe2
SpuLibspe2Support::~SpuLibspe2Support()
{
stopSPUs();
}
#include <stdio.h>
DWORD WINAPI Thread_no_1( LPVOID lpParam )
{
btSpuStatus* status = (btSpuStatus*)lpParam;
while (1)
{
WaitForSingleObject(status->m_eventStartHandle,INFINITE);
btAssert(status->m_status);
SpuGatherAndProcessPairsTaskDesc* taskDesc = status->m_taskDesc;
if (taskDesc)
{
processCollisionTask(*taskDesc);
SetEvent(status->m_eventCompletetHandle);
} else
{
//exit Thread
break;
}
}
return 0;
}
///send messages to SPUs
void SpuLibspe2Support::sendRequest(uint32_t uiCommand, uint32_t uiArgument0, uint32_t uiArgument1)
{
/// gMidphaseSPU.sendRequest(CMD_GATHER_AND_PROCESS_PAIRLIST, (uint32_t) &taskDesc);
///we should spawn an SPU task here, and in 'waitForResponse' it should wait for response of the (one of) the first tasks that finished
switch (uiCommand)
{
case CMD_GATHER_AND_PROCESS_PAIRLIST:
{
SpuGatherAndProcessPairsTaskDesc* taskDesc = (SpuGatherAndProcessPairsTaskDesc*) uiArgument0 ;
//#define SINGLE_THREADED 1
#ifdef SINGLE_THREADED
btSpuStatus& spuStatus = m_activeSpuStatus[0];
taskDesc->m_lsMemory = (CollisionTask_LocalStoreMemory*)spuStatus.m_lsMemory;
processCollisionTask(*taskDesc);
HANDLE handle =0;
#else
btAssert(taskDesc->taskId>=0);
btAssert(taskDesc->taskId<m_activeSpuStatus.size());
btSpuStatus& spuStatus = m_activeSpuStatus[taskDesc->taskId];
spuStatus.m_commandId = uiCommand;
spuStatus.m_status = 1;
spuStatus.m_taskDesc = taskDesc;
taskDesc->m_lsMemory = (CollisionTask_LocalStoreMemory*)spuStatus.m_lsMemory;
///fire event to start new task
SetEvent(spuStatus.m_eventStartHandle);
#endif //CollisionTask_LocalStoreMemory
break;
}
default:
{
///not implemented
btAssert(0);
}
};
}
///check for messages from SPUs
void SpuLibspe2Support::waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1)
{
///We should wait for (one of) the first tasks to finish (or other SPU messages), and report its response
///A possible response can be 'yes, SPU handled it', or 'no, please do a PPU fallback'
btAssert(m_activeSpuStatus.size());
int last = -1;
//find an active spu/thread
for (int i=0;i<m_activeSpuStatus.size();i++)
{
if (m_activeSpuStatus[i].m_status)
{
last = i;
break;
}
}
#ifndef SINGLE_THREADED
btAssert(spuStatus.m_threadHandle);
btAssert(spuStatus.m_eventCompletetHandle);
btSpuStatus& spuStatus = m_activeSpuStatus[last];
WaitForSingleObject(spuStatus.m_eventCompletetHandle, INFINITE);
spuStatus.m_status = 0;
///need to find an active spu
btAssert(last>=0);
#else
last=0;
btSpuStatus& spuStatus = m_activeSpuStatus[last];
#endif //SINGLE_THREADED
*puiArgument0 = spuStatus.m_taskId;
*puiArgument1 = spuStatus.m_status;
}
///start the spus group (can be called at the beginning of each frame, to make sure that the right SPU program is loaded)
void SpuLibspe2Support::startSPUs(int numThreads)
{
m_activeSpuStatus.resize(numThreads);
for (int i=0;i<numThreads;i++)
{
printf("starting thread %d\n",i);
btSpuStatus& spuStatus = m_activeSpuStatus[i];
LPSECURITY_ATTRIBUTES lpThreadAttributes=NULL;
SIZE_T dwStackSize=65535;
LPTHREAD_START_ROUTINE lpStartAddress=&Thread_no_1;
LPVOID lpParameter=&spuStatus;
DWORD dwCreationFlags=0;
LPDWORD lpThreadId=0;
spuStatus.m_taskDesc = 0;
sprintf(spuStatus.m_eventStartHandleName,"eventStart%d",i);
spuStatus.m_eventStartHandle = CreateEvent(0,false,false,spuStatus.m_eventStartHandleName);
sprintf(spuStatus.m_eventCompletetHandleName,"eventComplete%d",i);
spuStatus.m_eventCompletetHandle = CreateEvent(0,false,false,spuStatus.m_eventCompletetHandleName);
HANDLE handle = CreateThread(lpThreadAttributes,dwStackSize,lpStartAddress,lpParameter, dwCreationFlags,lpThreadId);
SetThreadPriority(handle,THREAD_PRIORITY_TIME_CRITICAL);
spuStatus.m_taskId = i;
spuStatus.m_commandId = 0;
spuStatus.m_status = 0;
spuStatus.m_threadHandle = handle;
spuStatus.m_lsMemory = createLocalStoreMemory();
printf("started thread %d with threadHandle %d\n",i,handle);
}
}
///tell the task scheduler we are done with the SPU tasks
void SpuLibspe2Support::stopSPUs()
{
// m_activeSpuStatus.pop_back();
// WaitForSingleObject(spuStatus.bla, INFINITE);
// CloseHandle(spuStatus.m_threadHandle);
}
#endif// USE_LIBSPE2

View File

@@ -0,0 +1,102 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 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.
*/
///USE_LIBSPE2: this define should be in the build system, or in <LinearMath/btScalar.h>
//#define USE_LIBSPE2 1
#ifdef USE_LIBSPE2
#ifndef SPU_LIBSPE2_SUPPORT_H
#define SPU_LIBSPE2_SUPPORT_H
#include "LinearMath/btAlignedObjectArray.h"
/**
* Note:
* The order of elements in this enum are important, that's why each one is explicitly
* given a value. They will correspond to the .elf names/addresses that will be
* loaded into Libspe2.
* Mixing up these values will cause the wrong code to execute, for instance, the
* solver may be asked to do a collision detection job.
*/
typedef enum {
SPU_ELF_COLLISION_DETECTION=0,
SPU_ELF_SAMPLE,
//SPU_ELF_INTEGRATION,
//SPU_ELF_SOLVER,
SPU_ELF_LAST,
} SpuLibspe2ElfId_t;
#ifdef WIN32
#include <malloc.h>
#define memalign(alignment, size) malloc(size);
#else
#include <stdlib.h>
#endif // WIN32
#include <LinearMath/btScalar.h> //for uint32_t etc.
///placeholder, until libspe2 support is there
struct btSpuStatus
{
uint32_t m_taskId;
uint32_t m_commandId;
uint32_t m_status;
struct SpuGatherAndProcessPairsTaskDesc* m_taskDesc;
void* m_threadHandle;
void* m_lsMemory;
void* m_eventStartHandle;
char m_eventStartHandleName[32];
void* m_eventCompletetHandle;
char m_eventCompletetHandleName[32];
};
///SpuLibspe2Support helps to initialize/shutdown libspe2, start/stop SPU tasks and communication
class SpuLibspe2Support {
btAlignedObjectArray<btSpuStatus> m_activeSpuStatus;
public:
///Setup and initialize SPU/CELL/Libspe2
SpuLibspe2Support(SpuLibspe2ElfId_t elfId,int numThreads);
///cleanup/shutdown Libspe2
~SpuLibspe2Support();
///send messages to SPUs
void sendRequest(uint32_t uiCommand, uint32_t uiArgument0, uint32_t uiArgument1=0);
///check for messages from SPUs
void waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1);
///start the spus (can be called at the beginning of each frame, to make sure that the right SPU program is loaded)
void startSPUs(int numThreads);
///tell the task scheduler we are done with the SPU tasks
void stopSPUs();
};
#endif //SPU_LIBSPE2_SUPPORT_H
#endif //USE_LIBSPE2

View File

@@ -0,0 +1,162 @@
/* [SCE CONFIDENTIAL DOCUMENT]
* PLAYSTATION(R)3 SPU Optimized Bullet Physics Library (http://bulletphysics.com)
* Copyright (C) 2007 Sony Computer Entertainment Inc.
* All Rights Reserved.
*/
#include "SpuContactResult.h"
//#define DEBUG_SPU_COLLISION_DETECTION 1
#include "SpuContactResult.h"
SpuContactResult::SpuContactResult()
{
m_manifoldAddress = 0;
m_spuManifold = NULL;
m_RequiresWriteBack = false;
}
SpuContactResult::~SpuContactResult()
{
g_manifoldDmaExport.swapBuffers();
}
void SpuContactResult::setContactInfo(btPersistentManifold* spuManifold, uint64_t manifoldAddress,const btTransform& worldTrans0,const btTransform& worldTrans1)
{
// spu_printf("SpuContactResult::setContactInfo\n");
m_rootWorldTransform0 = worldTrans0;
m_rootWorldTransform1 = worldTrans1;
m_manifoldAddress = manifoldAddress;
m_spuManifold = spuManifold;
}
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,
const btVector3& pointInWorld,
float depth,
btPersistentManifold* manifoldPtr,
btTransform& transA,
btTransform& transB
)
{
float contactTreshold = manifoldPtr->getContactBreakingThreshold();
//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);
#endif //DEBUG_SPU_COLLISION_DETECTION
if (depth > manifoldPtr->getContactBreakingThreshold())
return false;
//provide inverses or just calculate?
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 localB = transBInv(pointInWorld);
btManifoldPoint newPt(localA,localB,normalOnBInWorld,depth);
int insertIndex = manifoldPtr->getCacheEntry(newPt);
if (insertIndex >= 0)
{
// manifoldPtr->replaceContactPoint(newPt,insertIndex);
// return true;
#ifdef DEBUG_SPU_COLLISION_DETECTION
spu_printf("SPU: same contact detected, nothing done\n");
#endif //DEBUG_SPU_COLLISION_DETECTION
// This is not needed, just use the old info! saves a DMA transfer as well
} else
{
newPt.m_combinedFriction = 0.25f;//calculateCombinedFriction(m_body0,m_body1);
newPt.m_combinedRestitution = 0.0f;//calculateCombinedRestitution(m_body0,m_body1);
/*
//potential TODO: SPU callbacks, either immediate (local on the SPU), or deferred
//User can override friction and/or restitution
if (gContactAddedCallback &&
//and if either of the two bodies requires custom material
((m_body0->m_collisionFlags & btCollisionObject::customMaterialCallback) ||
(m_body1->m_collisionFlags & btCollisionObject::customMaterialCallback)))
{
//experimental feature info, for per-triangle material etc.
(*gContactAddedCallback)(newPt,m_body0,m_partId0,m_index0,m_body1,m_partId1,m_index1);
}
*/
manifoldPtr->AddManifoldPoint(newPt);
return true;
}
return false;
}
void SpuContactResult::writeDoubleBufferedManifold(btPersistentManifold* lsManifold, btPersistentManifold* mmManifold)
{
memcpy(g_manifoldDmaExport.getFront(),lsManifold,sizeof(btPersistentManifold));
g_manifoldDmaExport.swapBuffers();
g_manifoldDmaExport.backBufferDmaPut((uint64_t)mmManifold, sizeof(btPersistentManifold), DMA_TAG(9));
// 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
}
void SpuContactResult::addContactPoint(const btVector3& normalOnBInWorld,const btPoint3& pointInWorld,float depth)
{
// spu_printf("*** SpuContactResult::addContactPoint: depth = %f\n",depth);
#ifdef DEBUG_SPU_COLLISION_DETECTION
// int sman = sizeof(rage::phManifold);
// spu_printf("sizeof_manifold = %i\n",sman);
#endif //DEBUG_SPU_COLLISION_DETECTION
btPersistentManifold* localManifold = m_spuManifold;
btVector3 normalB(normalOnBInWorld.getX(),normalOnBInWorld.getY(),normalOnBInWorld.getZ());
btVector3 pointWrld(pointInWorld.getX(),pointInWorld.getY(),pointInWorld.getZ());
//process the contact point
const bool retVal = ManifoldResultAddContactPoint(normalB,
pointWrld,
depth,
localManifold,
m_rootWorldTransform0,
m_rootWorldTransform1
);
m_RequiresWriteBack = m_RequiresWriteBack || retVal;
}
void SpuContactResult::flush()
{
if (m_RequiresWriteBack)
{
#ifdef DEBUG_SPU_COLLISION_DETECTION
spu_printf("SPU: Start rage::phManifold Write (Put) DMA\n");
#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

@@ -0,0 +1,101 @@
#ifndef SPU_CONTACT_RESULT2_H
#define SPU_CONTACT_RESULT2_H
#ifndef WIN32
#include <stdint.h>
#endif
#ifdef WIN32
#include "SpuDoubleBuffer.h"
#else
#include "SPU_Common/SpuDefines.h"
#include "SPU_Common/SpuDoubleBuffer.h"
#include <spu_printf.h>
#endif //WIN32
#include "LinearMath/btTransform.h"
#include "LinearMath/btPoint3.h"
#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
struct SpuCollisionPairInput
{
uint64_t m_collisionShapes[2];
void* m_spuCollisionShapes[2];
uint64_t m_persistentManifoldPtr;
btVector3 m_primitiveDimensions0;
btVector3 m_primitiveDimensions1;
int m_shapeType0;
int m_shapeType1;
float m_collisionMargin0;
float m_collisionMargin1;
btTransform m_worldTransform0;
btTransform m_worldTransform1;
bool m_isSwapped;
};
struct SpuClosestPointInput
{
SpuClosestPointInput()
:m_maximumDistanceSquared(float(1e30)),
m_stackAlloc(0)
{
}
btTransform m_transformA;
btTransform m_transformB;
float m_maximumDistanceSquared;
class btStackAlloc* m_stackAlloc;
struct SpuConvexPolyhedronVertexData* m_convexVertexData;
};
///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.
class SpuContactResult
{
btTransform m_rootWorldTransform0;
btTransform m_rootWorldTransform1;
uint64_t m_manifoldAddress;
btPersistentManifold* m_spuManifold;
bool m_RequiresWriteBack;
DoubleBuffer<btPersistentManifold, 1> g_manifoldDmaExport;
public:
SpuContactResult();
virtual ~SpuContactResult();
btPersistentManifold* GetSpuManifold() const
{
return m_spuManifold;
}
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 writeDoubleBufferedManifold(btPersistentManifold* lsManifold, btPersistentManifold* mmManifold);
virtual void addContactPoint(const btVector3& normalOnBInWorld,const btPoint3& pointInWorld,float depth);
void flush();
};
#endif //SPU_CONTACT_RESULT2_H

View File

@@ -0,0 +1,56 @@
/* [SCE CONFIDENTIAL DOCUMENT]
* PLAYSTATION(R)3 SPU Optimized Bullet Physics Library (http://bulletphysics.com)
* Copyright (C) 2007 Sony Computer Entertainment Inc.
* All Rights Reserved.
*/
/*
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_PENETRATION_DEPTH_H
#define CONVEX_PENETRATION_DEPTH_H
class btStackAlloc;
class btIDebugDraw;
class SpuVoronoiSimplexSolver;
#include <LinearMath/btTransform.h>
#include <LinearMath/btPoint3.h>
///ConvexPenetrationDepthSolver provides an interface for penetration depth calculation.
class SpuConvexPenetrationDepthSolver
{
public:
virtual ~SpuConvexPenetrationDepthSolver() {};
virtual bool calcPenDepth( SpuVoronoiSimplexSolver& simplexSolver,
void* convexA,void* convexB,int shapeTypeA, int shapeTypeB, float marginA, float marginB,
btTransform& transA,const btTransform& transB,
btVector3& v, btPoint3& pa, btPoint3& pb,
class btIDebugDraw* debugDraw,btStackAlloc* stackAlloc,
struct SpuConvexPolyhedronVertexData* convexVertexData
) const = 0;
};
#endif //CONVEX_PENETRATION_DEPTH_H

View File

@@ -0,0 +1,399 @@
#include "SpuGatheringCollisionTask.h"
#include "SpuDoubleBuffer.h"
#include "../SpuCollisionTaskProcess.h"
#include "../SpuGatheringCollisionDispatcher.h" //for SPU_BATCHSIZE_BROADPHASE_PAIRS
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
#include "SpuContactManifoldCollisionAlgorithm.h"
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
#include "SpuContactResult.h"
#include "BulletCollision/CollisionShapes/btOptimizedBvh.h"
#include "BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h"
#include "BulletCollision/CollisionShapes/btConvexShape.h"
#include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h"
#include "SpuMinkowskiPenetrationDepthSolver.h"
#include "SpuGjkPairDetector.h"
#include "SpuVoronoiSimplexSolver.h"
#include "SpuLocalSupport.h" //definition of SpuConvexPolyhedronVertexData
#ifdef WIN32
#define spu_printf printf
#include <stdio.h>
#endif
//int gNumConvexPoints0=0;
///Make sure no destructors are called on this memory
struct CollisionTask_LocalStoreMemory
{
DoubleBuffer<unsigned char, MIDPHASE_WORKUNIT_PAGE_SIZE> g_workUnitTaskBuffers;
btBroadphasePair gBroadphasePairs[SPU_BATCHSIZE_BROADPHASE_PAIRS];
//SpuContactManifoldCollisionAlgorithm gSpuContactManifoldAlgo;
ATTRIBUTE_ALIGNED16(char gSpuContactManifoldAlgo[sizeof(SpuContactManifoldCollisionAlgorithm)+128]);
SpuContactManifoldCollisionAlgorithm* getlocalCollisionAlgorithm()
{
return (SpuContactManifoldCollisionAlgorithm*)&gSpuContactManifoldAlgo;
}
btPersistentManifold gPersistentManifold;
btBroadphaseProxy gProxy0;
btBroadphaseProxy gProxy1;
btCollisionObject gColObj0;
btCollisionObject gColObj1;
static const int maxShapeSize = 256;//todo: make some compile-time assert that this is value is larger then sizeof(btCollisionShape)
ATTRIBUTE_ALIGNED16(char gCollisionShape0[maxShapeSize]);
ATTRIBUTE_ALIGNED16(char gCollisionShape1[maxShapeSize]);
ATTRIBUTE_ALIGNED16(btScalar spuUnscaledVertex[4]);
ATTRIBUTE_ALIGNED16(int spuIndices[16]);
ATTRIBUTE_ALIGNED16(btOptimizedBvh gOptimizedBvh);
ATTRIBUTE_ALIGNED16(btTriangleIndexVertexArray gTriangleMeshInterface);
///only a single mesh part for now, we can add support for multiple parts, but quantized trees don't support this at the moment
ATTRIBUTE_ALIGNED16(btIndexedMesh gIndexMesh);
#define MAX_SPU_SUBTREE_HEADERS 32
//1024
ATTRIBUTE_ALIGNED16(btBvhSubtreeInfo gSubtreeHeaders[MAX_SPU_SUBTREE_HEADERS]);
ATTRIBUTE_ALIGNED16(btQuantizedBvhNode gSubtreeNodes[MAX_SUBTREE_SIZE_IN_BYTES/sizeof(btQuantizedBvhNode)]);
SpuConvexPolyhedronVertexData* convexVertexData;
};
void* createCollisionLocalStoreMemory()
{
return new CollisionTask_LocalStoreMemory;
};
void ProcessSpuConvexConvexCollision(SpuCollisionPairInput* wuInput, CollisionTask_LocalStoreMemory* lsMemPtr, SpuContactResult& spuContacts)
{
#ifdef DEBUG_SPU_COLLISION_DETECTION
//spu_printf("SPU: ProcessSpuConvexConvexCollision\n");
#endif //DEBUG_SPU_COLLISION_DETECTION
//CollisionShape* shape0 = (CollisionShape*)wuInput->m_collisionShapes[0];
//CollisionShape* shape1 = (CollisionShape*)wuInput->m_collisionShapes[1];
btPersistentManifold* manifold = (btPersistentManifold*)wuInput->m_persistentManifoldPtr;
bool genericGjk = true;
if (genericGjk)
{
//try generic GJK
SpuVoronoiSimplexSolver vsSolver;
SpuMinkowskiPenetrationDepthSolver penetrationSolver;
void* shape0Ptr = wuInput->m_spuCollisionShapes[0];
void* shape1Ptr = wuInput->m_spuCollisionShapes[1];
int shapeType0 = wuInput->m_shapeType0;
int shapeType1 = wuInput->m_shapeType1;
float marginA = wuInput->m_collisionMargin0;
float marginB = wuInput->m_collisionMargin1;
SpuClosestPointInput cpInput;
cpInput.m_convexVertexData = lsMemPtr->convexVertexData;
cpInput.m_transformA = wuInput->m_worldTransform0;
cpInput.m_transformB = wuInput->m_worldTransform1;
float sumMargin = (marginA+marginB);
cpInput.m_maximumDistanceSquared = sumMargin * sumMargin;
uint64_t manifoldAddress = (uint64_t)manifold;
btPersistentManifold* spuManifold=&lsMemPtr->gPersistentManifold;
spuContacts.setContactInfo(spuManifold,manifoldAddress,wuInput->m_worldTransform0,wuInput->m_worldTransform1);
SpuGjkPairDetector gjk(shape0Ptr,shape1Ptr,shapeType0,shapeType1,marginA,marginB,&vsSolver,&penetrationSolver);
gjk.getClosestPoints(cpInput,spuContacts);//,debugDraw);
}
}
void processCollisionTask(void* userPtr, void* lsMemPtr)
{
SpuGatherAndProcessPairsTaskDesc* taskDescPtr = (SpuGatherAndProcessPairsTaskDesc*)userPtr;
SpuGatherAndProcessPairsTaskDesc& taskDesc = *taskDescPtr;
CollisionTask_LocalStoreMemory* colMemPtr = (CollisionTask_LocalStoreMemory*)lsMemPtr;
CollisionTask_LocalStoreMemory& lsMem = *(colMemPtr);
SpuContactResult spuContacts;
uint64_t dmaInPtr = taskDesc.inPtr;
unsigned int numPages = taskDesc.numPages;
unsigned int numOnLastPage = taskDesc.numOnLastPage;
// prefetch first set of inputs and wait
unsigned int nextNumOnPage = (numPages > 1)? MIDPHASE_NUM_WORKUNITS_PER_PAGE : numOnLastPage;
lsMem.g_workUnitTaskBuffers.backBufferDmaGet(dmaInPtr, nextNumOnPage*sizeof(SpuGatherAndProcessWorkUnitInput), DMA_TAG(3));
dmaInPtr += MIDPHASE_WORKUNIT_PAGE_SIZE;
for (unsigned int i = 0; i < numPages; i++)
{
// wait for back buffer dma and swap buffers
unsigned char *inputPtr = lsMem.g_workUnitTaskBuffers.swapBuffers();
// number on current page is number prefetched last iteration
unsigned int numOnPage = nextNumOnPage;
unsigned int j;
// prefetch next set of inputs
if (i < numPages-1)
{
nextNumOnPage = (i == numPages-2)? numOnLastPage : MIDPHASE_NUM_WORKUNITS_PER_PAGE;
lsMem.g_workUnitTaskBuffers.backBufferDmaGet(dmaInPtr, nextNumOnPage*sizeof(SpuGatherAndProcessWorkUnitInput), DMA_TAG(3));
dmaInPtr += MIDPHASE_WORKUNIT_PAGE_SIZE;
}
SpuGatherAndProcessWorkUnitInput* wuInputs = reinterpret_cast<SpuGatherAndProcessWorkUnitInput *>(inputPtr);
for (j = 0; j < numOnPage; j++)
{
#ifdef DEBUG_SPU_COLLISION_DETECTION
printMidphaseInput(&wuInputs[j]);
#endif //DEBUG_SPU_COLLISION_DETECTION
int numPairs = wuInputs[j].m_endIndex - wuInputs[j].m_startIndex;
// printf("startIndex=%d, endIndex = %d\n",wuInputs[j].m_startIndex,wuInputs[j].m_endIndex);
if (numPairs)
{
{
int dmaSize = numPairs*sizeof(SpuGatherAndProcessPairsTaskDesc);
uint64_t dmaPpuAddress = wuInputs[j].m_pairArrayPtr+wuInputs[j].m_startIndex * sizeof(btBroadphasePair);
cellDmaGet(&lsMem.gBroadphasePairs, dmaPpuAddress , dmaSize, DMA_TAG(1), 0, 0);
cellDmaWaitTagStatusAll(DMA_MASK(1));
}
for (int p=0;p<numPairs;p++)
{
//for each broadphase pair, do something
btBroadphasePair& pair = lsMem.gBroadphasePairs[p];
int userInfo = int(pair.m_userInfo);
if (userInfo == 2 && pair.m_algorithm && pair.m_pProxy0 && pair.m_pProxy1)
{
{
int dmaSize = sizeof(SpuContactManifoldCollisionAlgorithm);
uint64_t dmaPpuAddress2 = (uint64_t)pair.m_algorithm;
cellDmaGet(&lsMem.gSpuContactManifoldAlgo, dmaPpuAddress2 , dmaSize, DMA_TAG(1), 0, 0);
cellDmaWaitTagStatusAll(DMA_MASK(1));
}
SpuCollisionPairInput collisionPairInput;
collisionPairInput.m_persistentManifoldPtr = (uint64_t) lsMem.getlocalCollisionAlgorithm()->getContactManifoldPtr();
#ifdef DEBUG_SPU_COLLISION_DETECTION
spu_printf("SPU: manifoldPtr: %llx",collisionPairInput->m_persistentManifoldPtr);
#endif //DEBUG_SPU_COLLISION_DETECTION
{
int dmaSize = sizeof(btBroadphaseProxy);
uint64_t dmaPpuAddress2 = (uint64_t)pair.m_pProxy0;
cellDmaGet(&lsMem.gProxy0, dmaPpuAddress2 , dmaSize, DMA_TAG(1), 0, 0);
cellDmaWaitTagStatusAll(DMA_MASK(1));
}
{
int dmaSize = sizeof(btBroadphaseProxy);
uint64_t dmaPpuAddress2 = (uint64_t)pair.m_pProxy1;
cellDmaGet(&lsMem.gProxy1, dmaPpuAddress2 , dmaSize, DMA_TAG(2), 0, 0);
cellDmaWaitTagStatusAll(DMA_MASK(2));
}
//btCollisionObject* colObj0 = (btCollisionObject*)gProxy0.m_clientObject;
//btCollisionObject* colObj1 = (btCollisionObject*)gProxy1.m_clientObject;
{
int dmaSize = sizeof(btCollisionObject);
uint64_t dmaPpuAddress2 = (uint64_t)lsMem.gProxy0.m_clientObject;
cellDmaGet(&lsMem.gColObj0, dmaPpuAddress2 , dmaSize, DMA_TAG(1), 0, 0);
cellDmaWaitTagStatusAll(DMA_MASK(1));
}
{
int dmaSize = sizeof(btCollisionObject);
uint64_t dmaPpuAddress2 = (uint64_t)lsMem.gProxy1.m_clientObject;
cellDmaGet(&lsMem.gColObj1, dmaPpuAddress2 , dmaSize, DMA_TAG(2), 0, 0);
cellDmaWaitTagStatusAll(DMA_MASK(2));
}
///can wait on the combined DMA_MASK, or dma on the same tag
collisionPairInput.m_shapeType0 = lsMem.getlocalCollisionAlgorithm()->getShapeType0();
collisionPairInput.m_shapeType1 = lsMem.getlocalCollisionAlgorithm()->getShapeType1();
collisionPairInput.m_collisionMargin0 = lsMem.getlocalCollisionAlgorithm()->getCollisionMargin0();
collisionPairInput.m_collisionMargin1 = lsMem.getlocalCollisionAlgorithm()->getCollisionMargin1();
#ifdef DEBUG_SPU_COLLISION_DETECTION
spu_printf("SPU collisionPairInput->m_shapeType0 = %d\n",collisionPairInput->m_shapeType0);
spu_printf("SPU collisionPairInput->m_shapeType1 = %d\n",collisionPairInput->m_shapeType1);
#endif //DEBUG_SPU_COLLISION_DETECTION
if (1)
{
collisionPairInput.m_worldTransform0 = lsMem.gColObj0.getWorldTransform();
collisionPairInput.m_worldTransform1 = lsMem.gColObj1.getWorldTransform();
#ifdef DEBUG_SPU_COLLISION_DETECTION
spu_printf("SPU worldTrans0.origin = (%f,%f,%f)\n",
collisionPairInput->m_worldTransform0.getOrigin().getX(),
collisionPairInput->m_worldTransform0.getOrigin().getY(),
collisionPairInput->m_worldTransform0.getOrigin().getZ());
spu_printf("SPU worldTrans1.origin = (%f,%f,%f)\n",
collisionPairInput->m_worldTransform1.getOrigin().getX(),
collisionPairInput->m_worldTransform1.getOrigin().getY(),
collisionPairInput->m_worldTransform1.getOrigin().getZ());
#endif //DEBUG_SPU_COLLISION_DETECTION
{
int dmaSize = sizeof(btPersistentManifold);
uint64_t dmaPpuAddress2 = collisionPairInput.m_persistentManifoldPtr;
cellDmaGet(&lsMem.gPersistentManifold, dmaPpuAddress2 , dmaSize, DMA_TAG(1), 0, 0);
cellDmaWaitTagStatusAll(DMA_MASK(1));
}
if (btBroadphaseProxy::isConvex(collisionPairInput.m_shapeType0)
&& btBroadphaseProxy::isConvex(collisionPairInput.m_shapeType1))
{
{
int dmaSize = lsMem.maxShapeSize;
uint64_t dmaPpuAddress2 = (uint64_t)lsMem.gColObj0.getCollisionShape();
cellDmaGet(lsMem.gCollisionShape0, dmaPpuAddress2 , dmaSize, DMA_TAG(1), 0, 0);
cellDmaWaitTagStatusAll(DMA_MASK(1));
}
{
int dmaSize = lsMem.maxShapeSize;
uint64_t dmaPpuAddress2 = (uint64_t)lsMem.gColObj1.getCollisionShape();
cellDmaGet(lsMem.gCollisionShape1, dmaPpuAddress2 , dmaSize, DMA_TAG(2), 0, 0);
cellDmaWaitTagStatusAll(DMA_MASK(2));
}
btConvexShape* spuConvexShape0 = (btConvexShape*)lsMem.gCollisionShape0;
btConvexShape* spuConvexShape1 = (btConvexShape*)lsMem.gCollisionShape1;
btVector3 dim0 = spuConvexShape0->getImplicitShapeDimensions();
btVector3 dim1 = spuConvexShape1->getImplicitShapeDimensions();
collisionPairInput.m_primitiveDimensions0 = dim0;
collisionPairInput.m_primitiveDimensions1 = dim1;
collisionPairInput.m_collisionShapes[0] = (uint64_t)lsMem.gColObj0.getCollisionShape();
collisionPairInput.m_collisionShapes[1] = (uint64_t)lsMem.gColObj1.getCollisionShape();
collisionPairInput.m_spuCollisionShapes[0] = spuConvexShape0;
collisionPairInput.m_spuCollisionShapes[1] = spuConvexShape1;
ProcessSpuConvexConvexCollision(&collisionPairInput,&lsMem, spuContacts);
} else
{
//a non-convex shape is involved
bool isSwapped = false;
bool handleConvexConcave = false;
if (btBroadphaseProxy::isConcave(collisionPairInput.m_shapeType0) &&
btBroadphaseProxy::isConvex(collisionPairInput.m_shapeType1))
{
isSwapped = true;
spu_printf("SPU convex/concave swapped, unsupported!\n");
handleConvexConcave = true;
}
if (btBroadphaseProxy::isConvex(collisionPairInput.m_shapeType0)&&
btBroadphaseProxy::isConcave(collisionPairInput.m_shapeType1))
{
handleConvexConcave = true;
}
if (handleConvexConcave && !isSwapped)
{
// spu_printf("SPU: non-convex detected\n");
{
// uint64_t dmaPpuAddress2 = (uint64_t)gProxy1.m_clientObject;
// spu_printf("SPU: gColObj1 trimesh = %llx\n",dmaPpuAddress2);
}
///dma and initialize the convex object
{
int dmaSize = lsMem.maxShapeSize;
uint64_t dmaPpuAddress2 = (uint64_t)lsMem.gColObj0.getCollisionShape();
cellDmaGet(lsMem.gCollisionShape0, dmaPpuAddress2 , dmaSize, DMA_TAG(1), 0, 0);
cellDmaWaitTagStatusAll(DMA_MASK(1));
}
///dma and initialize the convex object
{
int dmaSize = lsMem.maxShapeSize;
uint64_t dmaPpuAddress2 = (uint64_t)lsMem.gColObj1.getCollisionShape();
// spu_printf("SPU: trimesh = %llx\n",dmaPpuAddress2);
cellDmaGet(lsMem.gCollisionShape1, dmaPpuAddress2 , dmaSize, DMA_TAG(2), 0, 0);
cellDmaWaitTagStatusAll(DMA_MASK(2));
}
btConvexShape* spuConvexShape0 = (btConvexShape*)lsMem.gCollisionShape0;
btBvhTriangleMeshShape* trimeshShape = (btBvhTriangleMeshShape*)lsMem.gCollisionShape1;
btVector3 dim0 = spuConvexShape0->getImplicitShapeDimensions();
collisionPairInput.m_primitiveDimensions0 = dim0;
collisionPairInput.m_collisionShapes[0] = (uint64_t)lsMem.gColObj0.getCollisionShape();
collisionPairInput.m_collisionShapes[1] = (uint64_t)lsMem.gColObj1.getCollisionShape();
collisionPairInput.m_spuCollisionShapes[0] = spuConvexShape0;
collisionPairInput.m_spuCollisionShapes[1] = trimeshShape;
btAssert(0);
//ProcessConvexConcaveSpuCollision(&collisionPairInput,spuContacts);
}
}
spuContacts.flush();
}
}
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
#ifndef SPU_GATHERING_COLLISION_TASK_H
#define SPU_GATHERING_COLLISION_TASK_H
struct SpuGatherAndProcessPairsTaskDesc;
void processCollisionTask(void* userPtr, void* lsMemory);
void* createCollisionLocalStoreMemory();
#endif //SPU_GATHERING_COLLISION_TASK_H

View File

@@ -0,0 +1,310 @@
/*
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 "SpuGjkPairDetector.h"
#include "SpuConvexPenetrationDepthSolver.h"
#include "SpuLocalSupport.h"
#if defined(DEBUG) || defined (_DEBUG)
#include <stdio.h> //for debug printf
#ifdef __SPU__
#include <spu_printf.h>
#define printf spu_printf
#endif //__SPU__
#endif
//must be above the machine epsilon
#define REL_ERROR2 btScalar(1.0e-6)
//temp globals, to improve GJK/EPA/penetration calculations
int gSpuNumDeepPenetrationChecks = 0;
int gSpuNumGjkChecks = 0;
SpuGjkPairDetector::SpuGjkPairDetector(void* objectA,void* objectB,int shapeTypeA, int shapeTypeB, float marginA,float marginB,SpuVoronoiSimplexSolver* simplexSolver, const SpuConvexPenetrationDepthSolver* penetrationDepthSolver)
:m_cachedSeparatingAxis(float(0.),float(0.),float(1.)),
m_penetrationDepthSolver(penetrationDepthSolver),
m_simplexSolver(simplexSolver),
m_minkowskiA(objectA),
m_minkowskiB(objectB),
m_shapeTypeA(shapeTypeA),
m_shapeTypeB(shapeTypeB),
m_marginA(marginA),
m_marginB(marginB),
m_ignoreMargin(false),
m_lastUsedMethod(-1),
m_catchDegeneracies(1)
{
}
void SpuGjkPairDetector::getClosestPoints(const SpuClosestPointInput& input,SpuContactResult& output)
{
btScalar distance=btScalar(0.);
btVector3 normalInB(btScalar(0.),btScalar(0.),btScalar(0.));
btVector3 pointOnA,pointOnB;
btTransform localTransA = input.m_transformA;
btTransform localTransB = input.m_transformB;
btVector3 positionOffset = (localTransA.getOrigin() + localTransB.getOrigin()) * btScalar(0.5);
localTransA.getOrigin() -= positionOffset;
localTransB.getOrigin() -= positionOffset;
btScalar marginA = m_marginA;
btScalar marginB = m_marginB;
gSpuNumGjkChecks++;
//for CCD we don't use margins
if (m_ignoreMargin)
{
marginA = btScalar(0.);
marginB = btScalar(0.);
}
m_curIter = 0;
int gGjkMaxIter = 1000;//this is to catch invalid input, perhaps check for #NaN?
m_cachedSeparatingAxis.setValue(0,1,0);
bool isValid = false;
bool checkSimplex = false;
bool checkPenetration = true;
m_degenerateSimplex = 0;
m_lastUsedMethod = -1;
{
btScalar squaredDistance = SIMD_INFINITY;
btScalar delta = btScalar(0.);
btScalar margin = marginA + marginB;
m_simplexSolver->reset();
for ( ; ; )
//while (true)
{
btVector3 seperatingAxisInA = (-m_cachedSeparatingAxis)* input.m_transformA.getBasis();
btVector3 seperatingAxisInB = m_cachedSeparatingAxis* input.m_transformB.getBasis();
// btVector3 pInA = m_minkowskiA->localGetSupportingVertexWithoutMargin(seperatingAxisInA);
// btVector3 qInB = m_minkowskiB->localGetSupportingVertexWithoutMargin(seperatingAxisInB);
btVector3 pInA = localGetSupportingVertexWithoutMargin(m_shapeTypeA, m_minkowskiA, seperatingAxisInA,input.m_convexVertexData);//, &featureIndexA);
btVector3 qInB = localGetSupportingVertexWithoutMargin(m_shapeTypeB, m_minkowskiB, seperatingAxisInB,input.m_convexVertexData);//, &featureIndexB);
btPoint3 pWorld = localTransA(pInA);
btPoint3 qWorld = localTransB(qInB);
btVector3 w = pWorld - qWorld;
delta = m_cachedSeparatingAxis.dot(w);
// potential exit, they don't overlap
if ((delta > btScalar(0.0)) && (delta * delta > squaredDistance * input.m_maximumDistanceSquared))
{
checkPenetration = false;
break;
}
//exit 0: the new point is already in the simplex, or we didn't come any closer
if (m_simplexSolver->inSimplex(w))
{
m_degenerateSimplex = 1;
checkSimplex = true;
break;
}
// are we getting any closer ?
btScalar f0 = squaredDistance - delta;
btScalar f1 = squaredDistance * REL_ERROR2;
if (f0 <= f1)
{
if (f0 <= btScalar(0.))
{
m_degenerateSimplex = 2;
}
checkSimplex = true;
break;
}
//add current vertex to simplex
m_simplexSolver->addVertex(w, pWorld, qWorld);
//calculate the closest point to the origin (update vector v)
if (!m_simplexSolver->closest(m_cachedSeparatingAxis))
{
m_degenerateSimplex = 3;
checkSimplex = true;
break;
}
btScalar previousSquaredDistance = squaredDistance;
squaredDistance = m_cachedSeparatingAxis.length2();
//redundant m_simplexSolver->compute_points(pointOnA, pointOnB);
//are we getting any closer ?
if (previousSquaredDistance - squaredDistance <= SIMD_EPSILON * previousSquaredDistance)
{
m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
checkSimplex = true;
break;
}
//degeneracy, this is typically due to invalid/uninitialized worldtransforms for a btCollisionObject
if (m_curIter++ > gGjkMaxIter)
{
#if defined(DEBUG) || defined (_DEBUG)
printf("SpuGjkPairDetector maxIter exceeded:%i\n",m_curIter);
printf("sepAxis=(%f,%f,%f), squaredDistance = %f, shapeTypeA=%i,shapeTypeB=%i\n",
m_cachedSeparatingAxis.getX(),
m_cachedSeparatingAxis.getY(),
m_cachedSeparatingAxis.getZ(),
squaredDistance,
m_shapeTypeA,
m_shapeTypeB);
#endif
break;
}
bool check = (!m_simplexSolver->fullSimplex());
//bool check = (!m_simplexSolver->fullSimplex() && squaredDistance > SIMD_EPSILON * m_simplexSolver->maxVertex());
if (!check)
{
//do we need this backup_closest here ?
m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
break;
}
}
if (checkSimplex)
{
m_simplexSolver->compute_points(pointOnA, pointOnB);
normalInB = pointOnA-pointOnB;
btScalar lenSqr = m_cachedSeparatingAxis.length2();
//valid normal
if (lenSqr < 0.0001)
{
m_degenerateSimplex = 5;
}
if (lenSqr > SIMD_EPSILON*SIMD_EPSILON)
{
btScalar rlen = btScalar(1.) / btSqrt(lenSqr );
normalInB *= rlen; //normalize
btScalar s = btSqrt(squaredDistance);
btAssert(s > btScalar(0.0));
pointOnA -= m_cachedSeparatingAxis * (marginA / s);
pointOnB += m_cachedSeparatingAxis * (marginB / s);
distance = ((btScalar(1.)/rlen) - margin);
isValid = true;
m_lastUsedMethod = 1;
} else
{
m_lastUsedMethod = 2;
}
}
bool catchDegeneratePenetrationCase =
(m_catchDegeneracies && m_penetrationDepthSolver && m_degenerateSimplex && ((distance+margin) < 0.01));
//if (checkPenetration && !isValid)
if (checkPenetration && (!isValid || catchDegeneratePenetrationCase ))
{
//penetration case
//if there is no way to handle penetrations, bail out
if (m_penetrationDepthSolver)
{
// Penetration depth case.
btVector3 tmpPointOnA,tmpPointOnB;
gSpuNumDeepPenetrationChecks++;
bool isValid2 = m_penetrationDepthSolver->calcPenDepth(
*m_simplexSolver,
m_minkowskiA,m_minkowskiB,
m_shapeTypeA, m_shapeTypeB,
marginA, marginB,
localTransA,localTransB,
m_cachedSeparatingAxis, tmpPointOnA, tmpPointOnB,
0,input.m_stackAlloc,input.m_convexVertexData
);
if (isValid2)
{
btVector3 tmpNormalInB = tmpPointOnB-tmpPointOnA;
btScalar lenSqr = tmpNormalInB.length2();
if (lenSqr > (SIMD_EPSILON*SIMD_EPSILON))
{
tmpNormalInB /= btSqrt(lenSqr);
btScalar distance2 = -(tmpPointOnA-tmpPointOnB).length();
//only replace valid penetrations when the result is deeper (check)
if (!isValid || (distance2 < distance))
{
distance = distance2;
pointOnA = tmpPointOnA;
pointOnB = tmpPointOnB;
normalInB = tmpNormalInB;
isValid = true;
m_lastUsedMethod = 3;
} else
{
}
} else
{
//isValid = false;
m_lastUsedMethod = 4;
}
} else
{
m_lastUsedMethod = 5;
}
}
}
}
if (isValid)
{
#ifdef __SPU__
//spu_printf("distance\n");
#endif //__CELLOS_LV2__
output.addContactPoint(
normalInB,
pointOnB+positionOffset,
distance);
//printf("gjk add:%f",distance);
}
}

View File

@@ -0,0 +1,98 @@
/* [SCE CONFIDENTIAL DOCUMENT]
* PLAYSTATION(R)3 SPU Optimized Bullet Physics Library (http://bulletphysics.com)
* Copyright (C) 2007 Sony Computer Entertainment Inc.
* All Rights Reserved.
*/
/*
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 SPU_GJK_PAIR_DETECTOR_H
#define SPU_GJK_PAIR_DETECTOR_H
#include "SpuContactResult.h"
#include "SpuVoronoiSimplexSolver.h"
class SpuConvexPenetrationDepthSolver;
/// btGjkPairDetector uses GJK to implement the btDiscreteCollisionDetectorInterface
class SpuGjkPairDetector
{
btVector3 m_cachedSeparatingAxis;
const SpuConvexPenetrationDepthSolver* m_penetrationDepthSolver;
SpuVoronoiSimplexSolver* m_simplexSolver;
void* m_minkowskiA;
void* m_minkowskiB;
int m_shapeTypeA;
int m_shapeTypeB;
float m_marginA;
float m_marginB;
bool m_ignoreMargin;
public:
//some debugging to fix degeneracy problems
int m_lastUsedMethod;
int m_curIter;
int m_degenerateSimplex;
int m_catchDegeneracies;
SpuGjkPairDetector(void* objectA,void* objectB,int m_shapeTypeA, int m_shapeTypeB, float marginA, float marginB, SpuVoronoiSimplexSolver* simplexSolver, const SpuConvexPenetrationDepthSolver* penetrationDepthSolver);
virtual ~SpuGjkPairDetector() {};
virtual void getClosestPoints(const SpuClosestPointInput& input,SpuContactResult& output);
void setMinkowskiA(void* minkA)
{
m_minkowskiA = minkA;
}
void setMinkowskiB(void* minkB)
{
m_minkowskiB = minkB;
}
void setCachedSeperatingAxis(const btVector3& seperatingAxis)
{
m_cachedSeparatingAxis = seperatingAxis;
}
void setPenetrationDepthSolver(SpuConvexPenetrationDepthSolver* penetrationDepthSolver)
{
m_penetrationDepthSolver = penetrationDepthSolver;
}
///don't use setIgnoreMargin, it's for Bullet's internal use
void setIgnoreMargin(bool ignoreMargin)
{
m_ignoreMargin = ignoreMargin;
}
};
#endif //SPU_GJK_PAIR_DETECTOR_H

View File

@@ -0,0 +1,332 @@
/*
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 "SpuGjkPairDetector.h"
#include "SpuConvexPenetrationDepthSolver.h"
#include "SpuLocalSupport.h"
//#include "BulletCollision/CollisionShapes/btConvexShape.h"
#if defined(DEBUG) || defined (_DEBUG)
#include <stdio.h> //for debug printf
#ifdef __SPU__
#include <spu_printf.h>
#define printf spu_printf
#endif //__SPU__
#endif
//must be above the machine epsilon
#define REL_ERROR2 float(1.0e-6)
//temp globals, to improve GJK/EPA/penetration calculations
int gSpuNumDeepPenetrationChecks = 0;
int gSpuNumGjkChecks = 0;
SpuGjkPairDetector::SpuGjkPairDetector(void* objectA,void* objectB,int shapeTypeA, int shapeTypeB, float marginA,float marginB,SpuVoronoiSimplexSolver* simplexSolver, const SpuConvexPenetrationDepthSolver* penetrationDepthSolver)
:m_cachedSeparatingAxis(float(0.),float(0.),float(1.)),
m_penetrationDepthSolver(penetrationDepthSolver),
m_simplexSolver(simplexSolver),
m_minkowskiA(objectA),
m_minkowskiB(objectB),
m_shapeTypeA(shapeTypeA),
m_shapeTypeB(shapeTypeB),
m_marginA(marginA),
m_marginB(marginB),
m_ignoreMargin(false),
m_lastUsedMethod(-1),
m_catchDegeneracies(1)
{
}
void SpuGjkPairDetector::getClosestPoints(const SpuClosestPointInput& input,SpuContactResult& output)
{
float distance=float(0.);
Vectormath::Aos::Vector3 normalInB(float(0.),float(0.),float(0.));
Vectormath::Aos::Point3 pointOnA,pointOnB;
Vectormath::Aos::Transform3 localTransA = input.m_transformA;
Vectormath::Aos::Transform3 localTransB = input.m_transformB;
// World space coordinate
Vectormath::Aos::Vector3 localOriginA = localTransA.getTranslation();
Vectormath::Aos::Vector3 localOriginB = localTransB.getTranslation();
// Average instance position.
Vectormath::Aos::Vector3 positionOffset = (localOriginA + localOriginB) * float(0.5);
// Adjust the instance positions so that they're equidistant from the origin.
localTransA.setTranslation(localOriginA - positionOffset);
localTransB.setTranslation(localOriginB - positionOffset);
float marginA = m_marginA;
float marginB = m_marginB;
gSpuNumGjkChecks++;
//for CCD we don't use margins
if (m_ignoreMargin)
{
marginA = float(0.);
marginB = float(0.);
}
m_curIter = 0;
int gGjkMaxIter = 1000;//this is to catch invalid input, perhaps check for #NaN?
m_cachedSeparatingAxis = Vectormath::Aos::Vector3(0.f,1.f,0.f);
bool isValid = false;
bool checkSimplex = false;
bool checkPenetration = true;
m_degenerateSimplex = 0;
m_lastUsedMethod = -1;
{
float squaredDistance = 1e30f;
// There's no reason to have this delta declared out here, it's set in the loop before it's used and it's not used outside of the loop.
float delta = float(0.);
float margin = marginA + marginB;
m_simplexSolver->reset();
while (true)
{
// Get the separating axes into each bound's local space.
Vectormath::Aos::Vector3 seperatingAxisInA = orthoInverse(input.m_transformA) * (-m_cachedSeparatingAxis);
Vectormath::Aos::Vector3 seperatingAxisInB = orthoInverse(input.m_transformB) * m_cachedSeparatingAxis;
int shapeTypeA = m_shapeTypeA;
int shapeTypeB = m_shapeTypeB;
// int featureIndexA = 0, featureIndexB = 0; // Feature index basically means vertex index.
Vectormath::Aos::Point3 pInA = localGetSupportingVertexWithoutMargin(shapeTypeA, m_minkowskiA, seperatingAxisInA);//, &featureIndexA);
Vectormath::Aos::Point3 qInB = localGetSupportingVertexWithoutMargin(shapeTypeB, m_minkowskiB, seperatingAxisInB);//, &featureIndexB);
// These are in a 'translated' world space where the origin of that world space corresponds to 'positionOffset' in the 'real' world space.
Vectormath::Aos::Point3 pWorld = localTransA * pInA;
Vectormath::Aos::Point3 qWorld = localTransB * qInB;
//spu_printf("support point A: %f %f %f\n", pWorld.getX(), pWorld.getY(), pWorld.getZ());
//spu_printf("support point B: %f %f %f\n", qWorld.getX(), qWorld.getY(), qWorld.getZ());
// delta is sort of the distance between the current 'closest points' ...
// This seems kind of weird to me since m_cachedSeparatingAxis isn't a unit vector, so I'm not really sure what this signifies.
Vectormath::Aos::Vector3 w = pWorld - qWorld;
delta = dot(m_cachedSeparatingAxis, w);
// potential exit, they don't overlap
if ((delta > float(0.0)) && (delta * delta > squaredDistance * input.m_maximumDistanceSquared))
{
checkPenetration = false;
break;
}
//exit 0: the new point is already in the simplex, or we didn't come any closer
if (m_simplexSolver->inSimplex(w))
{
m_degenerateSimplex = 1;
checkSimplex = true;
break;
}
// are we getting any closer ?
float f0 = squaredDistance - delta;
float f1 = squaredDistance * REL_ERROR2;
// Are we close enough
if (f0 <= f1)
{
if (f0 <= float(0.))
{
m_degenerateSimplex = 2;
}
checkSimplex = true;
break;
}
//add current vertex to simplex
m_simplexSolver->addVertex(w, pWorld, qWorld);//, featureIndexA, featureIndexB);
//calculate the closest point to the origin (update vector v)
if (!m_simplexSolver->closest(m_cachedSeparatingAxis))
{
m_degenerateSimplex = 3;
checkSimplex = true;
break;
}
float previousSquaredDistance = squaredDistance;
squaredDistance = lengthSqr(m_cachedSeparatingAxis);
//redundant m_simplexSolver->compute_points(pointOnA, pointOnB);
//are we getting any closer ?
if (previousSquaredDistance - squaredDistance <= FLT_EPSILON * previousSquaredDistance)
{
m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
checkSimplex = true;
break;
}
//degeneracy, this is typically due to invalid/uninitialized worldtransforms for a btCollisionObject
if (m_curIter++ > gGjkMaxIter)
{
#if defined(DEBUG) || defined (_DEBUG)
printf("SpuGjkPairDetector maxIter exceeded:%i\n",m_curIter);
printf("sepAxis=(%f,%f,%f), squaredDistance = %f, shapeTypeA=%i,shapeTypeB=%i\n",
m_cachedSeparatingAxis.getX(),
m_cachedSeparatingAxis.getY(),
m_cachedSeparatingAxis.getZ(),
squaredDistance,
shapeTypeA,
shapeTypeB);
#endif
break;
}
bool check = (!m_simplexSolver->fullSimplex());
//bool check = (!m_simplexSolver->fullSimplex() && squaredDistance > FLT_EPSILON * m_simplexSolver->maxVertex());
if (!check)
{
//do we need this backup_closest here ?
m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
break;
}
}
if (checkSimplex)
{
m_simplexSolver->compute_points(pointOnA, pointOnB);
normalInB = pointOnA-pointOnB;
float lenSqr = lengthSqr(m_cachedSeparatingAxis);
//valid normal
if (lenSqr < 0.0001)
{
m_degenerateSimplex = 5;
}
if (lenSqr > FLT_EPSILON*FLT_EPSILON)
{
float rlen = float(1.) / sqrtf(lenSqr );
normalInB *= rlen; //normalize
float s = sqrtf(squaredDistance);
btAssert(s > float(0.0));
pointOnA -= m_cachedSeparatingAxis * (marginA / s);
pointOnB += m_cachedSeparatingAxis * (marginB / s);
distance = ((float(1.)/rlen) - margin);
isValid = true;
m_lastUsedMethod = 1;
} else
{
m_lastUsedMethod = 2;
}
}
bool catchDegeneratePenetrationCase =
(m_catchDegeneracies && m_penetrationDepthSolver && m_degenerateSimplex && ((distance+margin) < 0.01));
//if (checkPenetration && !isValid)
if (checkPenetration && (!isValid || catchDegeneratePenetrationCase ))
{
//penetration case
//if there is no way to handle penetrations, bail out
if (m_penetrationDepthSolver)
{
// Penetration depth case.
Vectormath::Aos::Point3 tmpPointOnA,tmpPointOnB;
// spu_printf("SPU: deep penetration check\n");
gSpuNumDeepPenetrationChecks++;
bool isValid2 = m_penetrationDepthSolver->calcPenDepth(
*m_simplexSolver,
m_minkowskiA,m_minkowskiB,
m_shapeTypeA, m_shapeTypeB,
marginA, marginB,
localTransA,localTransB,
m_cachedSeparatingAxis, tmpPointOnA, tmpPointOnB,
0,input.m_stackAlloc
);
if (isValid2)
{
Vectormath::Aos::Vector3 tmpNormalInB = tmpPointOnB-tmpPointOnA;
float lenSqr = lengthSqr(tmpNormalInB);
if (lenSqr > (FLT_EPSILON*FLT_EPSILON))
{
tmpNormalInB /= sqrtf(lenSqr);
float distance2 = -dist(tmpPointOnA,tmpPointOnB);
//only replace valid penetrations when the result is deeper (check)
if (!isValid || (distance2 < distance))
{
distance = distance2;
pointOnA = tmpPointOnA;
pointOnB = tmpPointOnB;
normalInB = tmpNormalInB;
isValid = true;
m_lastUsedMethod = 3;
} else
{
}
} else
{
//isValid = false;
m_lastUsedMethod = 4;
}
} else
{
m_lastUsedMethod = 5;
}
}
}
}
if (isValid)
{
#ifdef __SPU__
//spu_printf("distance\n");
#endif //__CELLOS_LV2__
Vectormath::Aos::Point3 tmpPtOnB=pointOnB+positionOffset;
Vectormath::Aos::Point3 vmPtOnB(tmpPtOnB.getX(),tmpPtOnB.getY(),tmpPtOnB.getZ());
Vectormath::Aos::Vector3 vmNormalOnB(normalInB.getX(),normalInB.getY(),normalInB.getZ());
output.addContactPoint(
vmNormalOnB,
vmPtOnB,
distance
);
//printf("gjk add:%f",distance);
}
}

View File

@@ -0,0 +1,236 @@
/* [SCE CONFIDENTIAL DOCUMENT]
* PLAYSTATION(R)3 SPU Optimized Bullet Physics Library (http://bulletphysics.com)
* Copyright (C) 2007 Sony Computer Entertainment Inc.
* All Rights Reserved.
*/
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
#include "BulletCollision/CollisionShapes/btConvexShape.h"
#include "BulletCollision/CollisionShapes/btCylinderShape.h"
struct SpuConvexPolyhedronVertexData
{
void* gSpuConvexShapePtr0;
void* gSpuConvexShapePtr1;
btPoint3* gConvexPoints0;
btPoint3* gConvexPoints1;
int gNumConvexPoints0;
int gNumConvexPoints1;
};
inline btPoint3 localGetSupportingVertexWithoutMargin(int shapeType, void* shape, btVector3 localDir,struct SpuConvexPolyhedronVertexData* convexVertexData)//, int *featureIndex)
{
switch (shapeType)
{
case SPHERE_SHAPE_PROXYTYPE:
{
return btPoint3(0,0,0);
}
case BOX_SHAPE_PROXYTYPE:
{
// spu_printf("SPU: getSupport BOX_SHAPE_PROXYTYPE\n");
btConvexShape* convexShape = (btConvexShape*)shape;
btVector3 halfExtents = convexShape->getImplicitShapeDimensions();
float margin = convexShape->getMarginNV();
halfExtents -= btVector3(margin,margin,margin);
return btPoint3(
localDir.getX() < 0.0f ? -halfExtents.x() : halfExtents.x(),
localDir.getY() < 0.0f ? -halfExtents.y() : halfExtents.y(),
localDir.getZ() < 0.0f ? -halfExtents.z() : halfExtents.z());
}
case TRIANGLE_SHAPE_PROXYTYPE:
{
btVector3 dir(localDir.getX(),localDir.getY(),localDir.getZ());
btVector3* vertices = (btVector3*)shape;
btVector3 dots(dir.dot(vertices[0]), dir.dot(vertices[1]), dir.dot(vertices[2]));
btVector3 sup = vertices[dots.maxAxis()];
return btPoint3(sup.getX(),sup.getY(),sup.getZ());
break;
}
case CYLINDER_SHAPE_PROXYTYPE:
{
btCylinderShape* cylShape = (btCylinderShape*)shape;
//mapping of halfextents/dimension onto radius/height depends on how cylinder local orientation is (upAxis)
btVector3 halfExtents = cylShape->getImplicitShapeDimensions();
btVector3 v(localDir.getX(),localDir.getY(),localDir.getZ());
int cylinderUpAxis = cylShape->getUpAxis();
int XX(1),YY(0),ZZ(2);
switch (cylinderUpAxis)
{
case 0:
{
XX = 1;
YY = 0;
ZZ = 2;
break;
}
case 1:
{
XX = 0;
YY = 1;
ZZ = 2;
break;
}
case 2:
{
XX = 0;
YY = 2;
ZZ = 1;
break;
}
default:
btAssert(0);
//printf("SPU:localGetSupportingVertexWithoutMargin unknown Cylinder up-axis\n");
};
btScalar radius = halfExtents[XX];
btScalar halfHeight = halfExtents[cylinderUpAxis];
btVector3 tmp;
btScalar d ;
btScalar s = btSqrt(v[XX] * v[XX] + v[ZZ] * v[ZZ]);
if (s != btScalar(0.0))
{
d = radius / s;
tmp[XX] = v[XX] * d;
tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight;
tmp[ZZ] = v[ZZ] * d;
return btPoint3(tmp.getX(),tmp.getY(),tmp.getZ());
}
else
{
tmp[XX] = radius;
tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight;
tmp[ZZ] = btScalar(0.0);
return btPoint3(tmp.getX(),tmp.getY(),tmp.getZ());
}
}
case CAPSULE_SHAPE_PROXYTYPE:
{
//spu_printf("SPU: todo: getSupport CAPSULE_SHAPE_PROXYTYPE\n");
btVector3 vec0(localDir.getX(),localDir.getY(),localDir.getZ());
btConvexShape* cnvxShape = (btConvexShape*)shape;
btVector3 halfExtents = cnvxShape->getImplicitShapeDimensions();
btScalar halfHeight = halfExtents.getY();
btScalar radius = halfExtents.getX();
btVector3 supVec(0,0,0);
btScalar maxDot(btScalar(-1e30));
btVector3 vec = vec0;
btScalar lenSqr = vec.length2();
if (lenSqr < btScalar(0.0001))
{
vec.setValue(1,0,0);
} else
{
btScalar rlen = btScalar(1.) / btSqrt(lenSqr );
vec *= rlen;
}
btVector3 vtx;
btScalar newDot;
{
btVector3 pos(0,halfHeight,0);
vtx = pos +vec*(radius);
newDot = vec.dot(vtx);
if (newDot > maxDot)
{
maxDot = newDot;
supVec = vtx;
}
}
{
btVector3 pos(0,-halfHeight,0);
vtx = pos +vec*(radius);
newDot = vec.dot(vtx);
if (newDot > maxDot)
{
maxDot = newDot;
supVec = vtx;
}
}
return btPoint3(supVec.getX(),supVec.getY(),supVec.getZ());
break;
};
case CONVEX_HULL_SHAPE_PROXYTYPE:
{
//spu_printf("SPU: todo: getSupport CONVEX_HULL_SHAPE_PROXYTYPE\n");
btPoint3* points = 0;
int numPoints = 0;
if (shape==convexVertexData->gSpuConvexShapePtr0)
{
points = convexVertexData->gConvexPoints0;
numPoints = convexVertexData->gNumConvexPoints0;
}
if (shape == convexVertexData->gSpuConvexShapePtr1)
{
points = convexVertexData->gConvexPoints1;
numPoints = convexVertexData->gNumConvexPoints1;
}
// spu_printf("numPoints = %d\n",numPoints);
btVector3 supVec(btScalar(0.),btScalar(0.),btScalar(0.));
btScalar newDot,maxDot = btScalar(-1e30);
btVector3 vec0(localDir.getX(),localDir.getY(),localDir.getZ());
btVector3 vec = vec0;
btScalar lenSqr = vec.length2();
if (lenSqr < btScalar(0.0001))
{
vec.setValue(1,0,0);
} else
{
btScalar rlen = btScalar(1.) / btSqrt(lenSqr );
vec *= rlen;
}
for (int i=0;i<numPoints;i++)
{
btPoint3 vtx = points[i];// * m_localScaling;
newDot = vec.dot(vtx);
if (newDot > maxDot)
{
maxDot = newDot;
supVec = vtx;
}
}
return btPoint3(supVec.getX(),supVec.getY(),supVec.getZ());
break;
};
default:
//spu_printf("SPU:(type %i) missing support function\n",shapeType);
#if __ASSERT
spu_printf("localGetSupportingVertexWithoutMargin() - Unsupported bound type: %d.\n", shapeType);
#endif // __ASSERT
return btPoint3(0.f, 0.f, 0.f);
}
}

View File

@@ -0,0 +1,339 @@
/*
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 "SpuMinkowskiPenetrationDepthSolver.h"
#include "SpuVoronoiSimplexSolver.h"
#include "SpuGjkPairDetector.h"
#include "SpuContactResult.h"
#include "SpuLocalSupport.h"
#define NUM_UNITSPHERE_POINTS 42
static btVector3 sPenetrationDirections[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))
};
bool SpuMinkowskiPenetrationDepthSolver::calcPenDepth( SpuVoronoiSimplexSolver& simplexSolver,
void* convexA,void* convexB,int shapeTypeA, int shapeTypeB, float marginA, float marginB,
btTransform& transA,const btTransform& transB,
btVector3& v, btPoint3& pa, btPoint3& pb,
class btIDebugDraw* debugDraw,btStackAlloc* stackAlloc,
struct SpuConvexPolyhedronVertexData* convexVertexData
) const
{
(void)stackAlloc;
(void)v;
struct btIntermediateResult : public SpuContactResult
{
btIntermediateResult():m_hasResult(false)
{
}
btVector3 m_normalOnBInWorld;
btVector3 m_pointInWorld;
btScalar m_depth;
bool m_hasResult;
virtual void setShapeIdentifiers(int partId0,int index0, int partId1,int index1)
{
(void)partId0;
(void)index0;
(void)partId1;
(void)index1;
}
void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth)
{
m_normalOnBInWorld = normalOnBInWorld;
m_pointInWorld = pointInWorld;
m_depth = depth;
m_hasResult = true;
}
};
//just take fixed number of orientation, and sample the penetration depth in that direction
btScalar minProj = btScalar(1e30);
btVector3 minNorm;
btVector3 minVertex;
btVector3 minA,minB;
btVector3 seperatingAxisInA,seperatingAxisInB;
btVector3 pInA,qInB,pWorld,qWorld,w;
//#define USE_BATCHED_SUPPORT 1
#ifdef USE_BATCHED_SUPPORT
btVector3 supportVerticesABatch[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2];
btVector3 supportVerticesBBatch[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2];
btVector3 seperatingAxisInABatch[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2];
btVector3 seperatingAxisInBBatch[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2];
int i;
int numSampleDirections = NUM_UNITSPHERE_POINTS;
for (i=0;i<numSampleDirections;i++)
{
const btVector3& norm = sPenetrationDirections[i];
seperatingAxisInABatch[i] = (-norm) * transA.getBasis() ;
seperatingAxisInBBatch[i] = norm * transB.getBasis() ;
}
{
int numPDA = convexA->getNumPreferredPenetrationDirections();
if (numPDA)
{
for (int i=0;i<numPDA;i++)
{
btVector3 norm;
convexA->getPreferredPenetrationDirection(i,norm);
norm = transA.getBasis() * norm;
sPenetrationDirections[numSampleDirections] = norm;
seperatingAxisInABatch[numSampleDirections] = (-norm) * transA.getBasis();
seperatingAxisInBBatch[numSampleDirections] = norm * transB.getBasis();
numSampleDirections++;
}
}
}
{
int numPDB = convexB->getNumPreferredPenetrationDirections();
if (numPDB)
{
for (int i=0;i<numPDB;i++)
{
btVector3 norm;
convexB->getPreferredPenetrationDirection(i,norm);
norm = transB.getBasis() * norm;
sPenetrationDirections[numSampleDirections] = norm;
seperatingAxisInABatch[numSampleDirections] = (-norm) * transA.getBasis();
seperatingAxisInBBatch[numSampleDirections] = norm * transB.getBasis();
numSampleDirections++;
}
}
}
convexA->batchedUnitVectorGetSupportingVertexWithoutMargin(seperatingAxisInABatch,supportVerticesABatch,numSampleDirections);
convexB->batchedUnitVectorGetSupportingVertexWithoutMargin(seperatingAxisInBBatch,supportVerticesBBatch,numSampleDirections);
for (i=0;i<numSampleDirections;i++)
{
const btVector3& norm = sPenetrationDirections[i];
seperatingAxisInA = seperatingAxisInABatch[i];
seperatingAxisInB = seperatingAxisInBBatch[i];
pInA = supportVerticesABatch[i];
qInB = supportVerticesBBatch[i];
pWorld = transA(pInA);
qWorld = transB(qInB);
w = qWorld - pWorld;
btScalar delta = norm.dot(w);
//find smallest delta
if (delta < minProj)
{
minProj = delta;
minNorm = norm;
minA = pWorld;
minB = qWorld;
}
}
#else
int numSampleDirections = NUM_UNITSPHERE_POINTS;
#ifdef DO_PREFERRED_DIRECTIONS
{
int numPDA = convexA->getNumPreferredPenetrationDirections();
if (numPDA)
{
for (int i=0;i<numPDA;i++)
{
btVector3 norm;
convexA->getPreferredPenetrationDirection(i,norm);
norm = transA.getBasis() * norm;
sPenetrationDirections[numSampleDirections] = norm;
numSampleDirections++;
}
}
}
{
int numPDB = convexB->getNumPreferredPenetrationDirections();
if (numPDB)
{
for (int i=0;i<numPDB;i++)
{
btVector3 norm;
convexB->getPreferredPenetrationDirection(i,norm);
norm = transB.getBasis() * norm;
sPenetrationDirections[numSampleDirections] = norm;
numSampleDirections++;
}
}
}
#endif //DO_PREFERRED_DIRECTIONS
for (int i=0;i<numSampleDirections;i++)
{
const btVector3& norm = sPenetrationDirections[i];
seperatingAxisInA = (-norm)* transA.getBasis();
seperatingAxisInB = norm* transB.getBasis();
pInA = localGetSupportingVertexWithoutMargin(shapeTypeA, convexA, seperatingAxisInA,convexVertexData);//, NULL);
qInB = localGetSupportingVertexWithoutMargin(shapeTypeB, convexB, seperatingAxisInB,convexVertexData);//, NULL);
// pInA = convexA->localGetSupportingVertexWithoutMargin(seperatingAxisInA);
// qInB = convexB->localGetSupportingVertexWithoutMargin(seperatingAxisInB);
pWorld = transA(pInA);
qWorld = transB(qInB);
w = qWorld - pWorld;
btScalar delta = norm.dot(w);
//find smallest delta
if (delta < minProj)
{
minProj = delta;
minNorm = norm;
minA = pWorld;
minB = qWorld;
}
}
#endif //USE_BATCHED_SUPPORT
//add the margins
minA += minNorm*marginA;
minB -= minNorm*marginB;
//no penetration
if (minProj < btScalar(0.))
return false;
minProj += (marginA + marginB);
//#define DEBUG_DRAW 1
#ifdef DEBUG_DRAW
if (debugDraw)
{
btVector3 color(0,1,0);
debugDraw->drawLine(minA,minB,color);
color = btVector3 (1,1,1);
btVector3 vec = minB-minA;
btScalar prj2 = minNorm.dot(vec);
debugDraw->drawLine(minA,minA+(minNorm*minProj),color);
}
#endif //DEBUG_DRAW
SpuGjkPairDetector gjkdet(convexA,convexB,shapeTypeA,shapeTypeB,marginA,marginB,&simplexSolver,0);
btScalar offsetDist = minProj;
btVector3 offset = minNorm * offsetDist;
SpuClosestPointInput input;
btVector3 newOrg = transA.getOrigin() + offset;
btTransform displacedTrans = transA;
displacedTrans.setOrigin(newOrg);
input.m_transformA = displacedTrans;
input.m_transformB = transB;
input.m_maximumDistanceSquared = btScalar(1e30);//minProj;
btIntermediateResult res;
gjkdet.getClosestPoints(input,res);
btScalar correctedMinNorm = minProj - res.m_depth;
//the penetration depth is over-estimated, relax it
btScalar penetration_relaxation= btScalar(1.);
minNorm*=penetration_relaxation;
if (res.m_hasResult)
{
pa = res.m_pointInWorld - minNorm * correctedMinNorm;
pb = res.m_pointInWorld;
#ifdef DEBUG_DRAW
if (debugDraw)
{
btVector3 color(1,0,0);
debugDraw->drawLine(pa,pb,color);
}
#endif//DEBUG_DRAW
}
return res.m_hasResult;
}

View File

@@ -0,0 +1,51 @@
/* [SCE CONFIDENTIAL DOCUMENT]
* PLAYSTATION(R)3 SPU Optimized Bullet Physics Library (http://bulletphysics.com)
* Copyright (C) 2007 Sony Computer Entertainment Inc.
* All Rights Reserved.
*/
/*
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 MINKOWSKI_PENETRATION_DEPTH_SOLVER_H
#define MINKOWSKI_PENETRATION_DEPTH_SOLVER_H
#include "SpuConvexPenetrationDepthSolver.h"
class btStackAlloc;
class btIDebugDraw;
class SpuVoronoiSimplexSolver;
///MinkowskiPenetrationDepthSolver implements bruteforce penetration depth estimation.
///Implementation is based on sampling the depth using support mapping, and using GJK step to get the witness points.
class SpuMinkowskiPenetrationDepthSolver : public SpuConvexPenetrationDepthSolver
{
public:
virtual bool calcPenDepth( SpuVoronoiSimplexSolver& simplexSolver,
void* convexA,void* convexB,int shapeTypeA, int shapeTypeB, float marginA, float marginB,
btTransform& transA,const btTransform& transB,
btVector3& v, btPoint3& pa, btPoint3& pb,
class btIDebugDraw* debugDraw,btStackAlloc* stackAlloc,
struct SpuConvexPolyhedronVertexData* convexVertexData
) const;
};
#endif //MINKOWSKI_PENETRATION_DEPTH_SOLVER_H

View File

@@ -0,0 +1,606 @@
/*
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.
Elsevier CDROM license agreements grants nonexclusive license to use the software
for any purpose, commercial or non-commercial as long as the following credit is included
identifying the original source of the software:
Parts of the source are "from the book Real-Time Collision Detection by
Christer Ericson, published by Morgan Kaufmann Publishers,
(c) 2005 Elsevier Inc."
*/
#include "SpuVoronoiSimplexSolver.h"
#include <assert.h>
#include <stdio.h>
#define VERTA 0
#define VERTB 1
#define VERTC 2
#define VERTD 3
#define CATCH_DEGENERATE_TETRAHEDRON 1
void SpuVoronoiSimplexSolver::removeVertex(int index)
{
assert(m_numVertices>0);
m_numVertices--;
m_simplexVectorW[index] = m_simplexVectorW[m_numVertices];
m_simplexPointsP[index] = m_simplexPointsP[m_numVertices];
m_simplexPointsQ[index] = m_simplexPointsQ[m_numVertices];
}
void SpuVoronoiSimplexSolver::reduceVertices (const SpuUsageBitfield& usedVerts)
{
if ((numVertices() >= 4) && (!usedVerts.usedVertexD))
removeVertex(3);
if ((numVertices() >= 3) && (!usedVerts.usedVertexC))
removeVertex(2);
if ((numVertices() >= 2) && (!usedVerts.usedVertexB))
removeVertex(1);
if ((numVertices() >= 1) && (!usedVerts.usedVertexA))
removeVertex(0);
}
//clear the simplex, remove all the vertices
void SpuVoronoiSimplexSolver::reset()
{
m_cachedValidClosest = false;
m_numVertices = 0;
m_needsUpdate = true;
m_lastW = btVector3(btScalar(1e30),btScalar(1e30),btScalar(1e30));
m_cachedBC.reset();
}
//add a vertex
void SpuVoronoiSimplexSolver::addVertex(const btVector3& w, const btPoint3& p, const btPoint3& q)
{
m_lastW = w;
m_needsUpdate = true;
m_simplexVectorW[m_numVertices] = w;
m_simplexPointsP[m_numVertices] = p;
m_simplexPointsQ[m_numVertices] = q;
m_numVertices++;
}
bool SpuVoronoiSimplexSolver::updateClosestVectorAndPoints()
{
if (m_needsUpdate)
{
m_cachedBC.reset();
m_needsUpdate = false;
switch (numVertices())
{
case 0:
m_cachedValidClosest = false;
break;
case 1:
{
m_cachedP1 = m_simplexPointsP[0];
m_cachedP2 = m_simplexPointsQ[0];
m_cachedV = m_cachedP1-m_cachedP2; //== m_simplexVectorW[0]
m_cachedBC.reset();
m_cachedBC.setBarycentricCoordinates(btScalar(1.),btScalar(0.),btScalar(0.),btScalar(0.));
m_cachedValidClosest = m_cachedBC.isValid();
break;
};
case 2:
{
//closest point origin from line segment
const btVector3& from = m_simplexVectorW[0];
const btVector3& to = m_simplexVectorW[1];
btVector3 nearest;
btVector3 p (btScalar(0.),btScalar(0.),btScalar(0.));
btVector3 diff = p - from;
btVector3 v = to - from;
btScalar t = v.dot(diff);
if (t > 0) {
btScalar dotVV = v.dot(v);
if (t < dotVV) {
t /= dotVV;
diff -= t*v;
m_cachedBC.m_usedVertices.usedVertexA = true;
m_cachedBC.m_usedVertices.usedVertexB = true;
} else {
t = 1;
diff -= v;
//reduce to 1 point
m_cachedBC.m_usedVertices.usedVertexB = true;
}
} else
{
t = 0;
//reduce to 1 point
m_cachedBC.m_usedVertices.usedVertexA = true;
}
m_cachedBC.setBarycentricCoordinates(1-t,t);
nearest = from + t*v;
m_cachedP1 = m_simplexPointsP[0] + t * (m_simplexPointsP[1] - m_simplexPointsP[0]);
m_cachedP2 = m_simplexPointsQ[0] + t * (m_simplexPointsQ[1] - m_simplexPointsQ[0]);
m_cachedV = m_cachedP1 - m_cachedP2;
reduceVertices(m_cachedBC.m_usedVertices);
m_cachedValidClosest = m_cachedBC.isValid();
break;
}
case 3:
{
//closest point origin from triangle
btVector3 p (btScalar(0.),btScalar(0.),btScalar(0.));
const btVector3& a = m_simplexVectorW[0];
const btVector3& b = m_simplexVectorW[1];
const btVector3& c = m_simplexVectorW[2];
closestPtPointTriangle(p,a,b,c,m_cachedBC);
m_cachedP1 = m_simplexPointsP[0] * m_cachedBC.m_barycentricCoords[0] +
m_simplexPointsP[1] * m_cachedBC.m_barycentricCoords[1] +
m_simplexPointsP[2] * m_cachedBC.m_barycentricCoords[2] +
m_simplexPointsP[3] * m_cachedBC.m_barycentricCoords[3];
m_cachedP2 = m_simplexPointsQ[0] * m_cachedBC.m_barycentricCoords[0] +
m_simplexPointsQ[1] * m_cachedBC.m_barycentricCoords[1] +
m_simplexPointsQ[2] * m_cachedBC.m_barycentricCoords[2] +
m_simplexPointsQ[3] * m_cachedBC.m_barycentricCoords[3];
m_cachedV = m_cachedP1-m_cachedP2;
reduceVertices (m_cachedBC.m_usedVertices);
m_cachedValidClosest = m_cachedBC.isValid();
break;
}
case 4:
{
btVector3 p (btScalar(0.),btScalar(0.),btScalar(0.));
const btVector3& a = m_simplexVectorW[0];
const btVector3& b = m_simplexVectorW[1];
const btVector3& c = m_simplexVectorW[2];
const btVector3& d = m_simplexVectorW[3];
bool hasSeperation = closestPtPointTetrahedron(p,a,b,c,d,m_cachedBC);
if (hasSeperation)
{
m_cachedP1 = m_simplexPointsP[0] * m_cachedBC.m_barycentricCoords[0] +
m_simplexPointsP[1] * m_cachedBC.m_barycentricCoords[1] +
m_simplexPointsP[2] * m_cachedBC.m_barycentricCoords[2] +
m_simplexPointsP[3] * m_cachedBC.m_barycentricCoords[3];
m_cachedP2 = m_simplexPointsQ[0] * m_cachedBC.m_barycentricCoords[0] +
m_simplexPointsQ[1] * m_cachedBC.m_barycentricCoords[1] +
m_simplexPointsQ[2] * m_cachedBC.m_barycentricCoords[2] +
m_simplexPointsQ[3] * m_cachedBC.m_barycentricCoords[3];
m_cachedV = m_cachedP1-m_cachedP2;
reduceVertices (m_cachedBC.m_usedVertices);
} else
{
// printf("sub distance got penetration\n");
if (m_cachedBC.m_degenerate)
{
m_cachedValidClosest = false;
} else
{
m_cachedValidClosest = true;
//degenerate case == false, penetration = true + zero
m_cachedV.setValue(btScalar(0.),btScalar(0.),btScalar(0.));
}
break;
}
m_cachedValidClosest = m_cachedBC.isValid();
//closest point origin from tetrahedron
break;
}
default:
{
m_cachedValidClosest = false;
}
};
}
return m_cachedValidClosest;
}
//return/calculate the closest vertex
bool SpuVoronoiSimplexSolver::closest(btVector3& v)
{
bool succes = updateClosestVectorAndPoints();
v = m_cachedV;
return succes;
}
btScalar SpuVoronoiSimplexSolver::maxVertex()
{
int i, numverts = numVertices();
btScalar maxV = btScalar(0.);
for (i=0;i<numverts;i++)
{
btScalar curLen2 = m_simplexVectorW[i].length2();
if (maxV < curLen2)
maxV = curLen2;
}
return maxV;
}
//return the current simplex
int SpuVoronoiSimplexSolver::getSimplex(btPoint3 *pBuf, btPoint3 *qBuf, btVector3 *yBuf) const
{
int i;
for (i=0;i<numVertices();i++)
{
yBuf[i] = m_simplexVectorW[i];
pBuf[i] = m_simplexPointsP[i];
qBuf[i] = m_simplexPointsQ[i];
}
return numVertices();
}
bool SpuVoronoiSimplexSolver::inSimplex(const btVector3& w)
{
bool found = false;
int i, numverts = numVertices();
//btScalar maxV = btScalar(0.);
//w is in the current (reduced) simplex
for (i=0;i<numverts;i++)
{
if (m_simplexVectorW[i] == w)
found = true;
}
//check in case lastW is already removed
if (w == m_lastW)
return true;
return found;
}
void SpuVoronoiSimplexSolver::backup_closest(btVector3& v)
{
v = m_cachedV;
}
bool SpuVoronoiSimplexSolver::emptySimplex() const
{
return (numVertices() == 0);
}
void SpuVoronoiSimplexSolver::compute_points(btPoint3& p1, btPoint3& p2)
{
updateClosestVectorAndPoints();
p1 = m_cachedP1;
p2 = m_cachedP2;
}
bool SpuVoronoiSimplexSolver::closestPtPointTriangle(const btPoint3& p, const btPoint3& a, const btPoint3& b, const btPoint3& c,SpuSubSimplexClosestResult& result)
{
result.m_usedVertices.reset();
// Check if P in vertex region outside A
btVector3 ab = b - a;
btVector3 ac = c - a;
btVector3 ap = p - a;
btScalar d1 = ab.dot(ap);
btScalar d2 = ac.dot(ap);
if (d1 <= btScalar(0.0) && d2 <= btScalar(0.0))
{
result.m_closestPointOnSimplex = a;
result.m_usedVertices.usedVertexA = true;
result.setBarycentricCoordinates(1,0,0);
return true;// a; // barycentric coordinates (1,0,0)
}
// Check if P in vertex region outside B
btVector3 bp = p - b;
btScalar d3 = ab.dot(bp);
btScalar d4 = ac.dot(bp);
if (d3 >= btScalar(0.0) && d4 <= d3)
{
result.m_closestPointOnSimplex = b;
result.m_usedVertices.usedVertexB = true;
result.setBarycentricCoordinates(0,1,0);
return true; // b; // barycentric coordinates (0,1,0)
}
// Check if P in edge region of AB, if so return projection of P onto AB
btScalar vc = d1*d4 - d3*d2;
if (vc <= btScalar(0.0) && d1 >= btScalar(0.0) && d3 <= btScalar(0.0)) {
btScalar v = d1 / (d1 - d3);
result.m_closestPointOnSimplex = a + v * ab;
result.m_usedVertices.usedVertexA = true;
result.m_usedVertices.usedVertexB = true;
result.setBarycentricCoordinates(1-v,v,0);
return true;
//return a + v * ab; // barycentric coordinates (1-v,v,0)
}
// Check if P in vertex region outside C
btVector3 cp = p - c;
btScalar d5 = ab.dot(cp);
btScalar d6 = ac.dot(cp);
if (d6 >= btScalar(0.0) && d5 <= d6)
{
result.m_closestPointOnSimplex = c;
result.m_usedVertices.usedVertexC = true;
result.setBarycentricCoordinates(0,0,1);
return true;//c; // barycentric coordinates (0,0,1)
}
// Check if P in edge region of AC, if so return projection of P onto AC
btScalar vb = d5*d2 - d1*d6;
if (vb <= btScalar(0.0) && d2 >= btScalar(0.0) && d6 <= btScalar(0.0)) {
btScalar w = d2 / (d2 - d6);
result.m_closestPointOnSimplex = a + w * ac;
result.m_usedVertices.usedVertexA = true;
result.m_usedVertices.usedVertexC = true;
result.setBarycentricCoordinates(1-w,0,w);
return true;
//return a + w * ac; // barycentric coordinates (1-w,0,w)
}
// Check if P in edge region of BC, if so return projection of P onto BC
btScalar va = d3*d6 - d5*d4;
if (va <= btScalar(0.0) && (d4 - d3) >= btScalar(0.0) && (d5 - d6) >= btScalar(0.0)) {
btScalar w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
result.m_closestPointOnSimplex = b + w * (c - b);
result.m_usedVertices.usedVertexB = true;
result.m_usedVertices.usedVertexC = true;
result.setBarycentricCoordinates(0,1-w,w);
return true;
// return b + w * (c - b); // barycentric coordinates (0,1-w,w)
}
// P inside face region. Compute Q through its barycentric coordinates (u,v,w)
btScalar denom = btScalar(1.0) / (va + vb + vc);
btScalar v = vb * denom;
btScalar w = vc * denom;
result.m_closestPointOnSimplex = a + ab * v + ac * w;
result.m_usedVertices.usedVertexA = true;
result.m_usedVertices.usedVertexB = true;
result.m_usedVertices.usedVertexC = true;
result.setBarycentricCoordinates(1-v-w,v,w);
return true;
// return a + ab * v + ac * w; // = u*a + v*b + w*c, u = va * denom = btScalar(1.0) - v - w
}
/// Test if point p and d lie on opposite sides of plane through abc
int SpuVoronoiSimplexSolver::pointOutsideOfPlane(const btPoint3& p, const btPoint3& a, const btPoint3& b, const btPoint3& c, const btPoint3& d)
{
btVector3 normal = (b-a).cross(c-a);
btScalar signp = (p - a).dot(normal); // [AP AB AC]
btScalar signd = (d - a).dot( normal); // [AD AB AC]
#ifdef CATCH_DEGENERATE_TETRAHEDRON
#ifdef BT_USE_DOUBLE_PRECISION
if (signd * signd < (btScalar(1e-8) * btScalar(1e-8)))
{
return -1;
}
#else
if (signd * signd < (btScalar(1e-4) * btScalar(1e-4)))
{
// printf("affine dependent/degenerate\n");//
return -1;
}
#endif
#endif
// Points on opposite sides if expression signs are opposite
return signp * signd < btScalar(0.);
}
bool SpuVoronoiSimplexSolver::closestPtPointTetrahedron(const btPoint3& p, const btPoint3& a, const btPoint3& b, const btPoint3& c, const btPoint3& d, SpuSubSimplexClosestResult& finalResult)
{
SpuSubSimplexClosestResult tempResult;
// Start out assuming point inside all halfspaces, so closest to itself
finalResult.m_closestPointOnSimplex = p;
finalResult.m_usedVertices.reset();
finalResult.m_usedVertices.usedVertexA = true;
finalResult.m_usedVertices.usedVertexB = true;
finalResult.m_usedVertices.usedVertexC = true;
finalResult.m_usedVertices.usedVertexD = true;
int pointOutsideABC = pointOutsideOfPlane(p, a, b, c, d);
int pointOutsideACD = pointOutsideOfPlane(p, a, c, d, b);
int pointOutsideADB = pointOutsideOfPlane(p, a, d, b, c);
int pointOutsideBDC = pointOutsideOfPlane(p, b, d, c, a);
if (pointOutsideABC < 0 || pointOutsideACD < 0 || pointOutsideADB < 0 || pointOutsideBDC < 0)
{
finalResult.m_degenerate = true;
return false;
}
if (!pointOutsideABC && !pointOutsideACD && !pointOutsideADB && !pointOutsideBDC)
{
return false;
}
btScalar bestSqDist = FLT_MAX;
// If point outside face abc then compute closest point on abc
if (pointOutsideABC)
{
closestPtPointTriangle(p, a, b, c,tempResult);
btPoint3 q = tempResult.m_closestPointOnSimplex;
btScalar sqDist = (q - p).dot( q - p);
// Update best closest point if (squared) distance is less than current best
if (sqDist < bestSqDist) {
bestSqDist = sqDist;
finalResult.m_closestPointOnSimplex = q;
//convert result bitmask!
finalResult.m_usedVertices.reset();
finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA;
finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexB;
finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexC;
finalResult.setBarycentricCoordinates(
tempResult.m_barycentricCoords[VERTA],
tempResult.m_barycentricCoords[VERTB],
tempResult.m_barycentricCoords[VERTC],
0
);
}
}
// Repeat test for face acd
if (pointOutsideACD)
{
closestPtPointTriangle(p, a, c, d,tempResult);
btPoint3 q = tempResult.m_closestPointOnSimplex;
//convert result bitmask!
btScalar sqDist = (q - p).dot( q - p);
if (sqDist < bestSqDist)
{
bestSqDist = sqDist;
finalResult.m_closestPointOnSimplex = q;
finalResult.m_usedVertices.reset();
finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA;
finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexB;
finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexC;
finalResult.setBarycentricCoordinates(
tempResult.m_barycentricCoords[VERTA],
0,
tempResult.m_barycentricCoords[VERTB],
tempResult.m_barycentricCoords[VERTC]
);
}
}
// Repeat test for face adb
if (pointOutsideADB)
{
closestPtPointTriangle(p, a, d, b,tempResult);
btPoint3 q = tempResult.m_closestPointOnSimplex;
//convert result bitmask!
btScalar sqDist = (q - p).dot( q - p);
if (sqDist < bestSqDist)
{
bestSqDist = sqDist;
finalResult.m_closestPointOnSimplex = q;
finalResult.m_usedVertices.reset();
finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA;
finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexB;
finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexC;
finalResult.setBarycentricCoordinates(
tempResult.m_barycentricCoords[VERTA],
tempResult.m_barycentricCoords[VERTC],
0,
tempResult.m_barycentricCoords[VERTB]
);
}
}
// Repeat test for face bdc
if (pointOutsideBDC)
{
closestPtPointTriangle(p, b, d, c,tempResult);
btPoint3 q = tempResult.m_closestPointOnSimplex;
//convert result bitmask!
btScalar sqDist = (q - p).dot( q - p);
if (sqDist < bestSqDist)
{
bestSqDist = sqDist;
finalResult.m_closestPointOnSimplex = q;
finalResult.m_usedVertices.reset();
finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexA;
finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexB;
finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexC;
finalResult.setBarycentricCoordinates(
0,
tempResult.m_barycentricCoords[VERTA],
tempResult.m_barycentricCoords[VERTC],
tempResult.m_barycentricCoords[VERTB]
);
}
}
//help! we ended up full !
if (finalResult.m_usedVertices.usedVertexA &&
finalResult.m_usedVertices.usedVertexB &&
finalResult.m_usedVertices.usedVertexC &&
finalResult.m_usedVertices.usedVertexD)
{
return true;
}
return true;
}

View File

@@ -0,0 +1,161 @@
/* [SCE CONFIDENTIAL DOCUMENT]
* PLAYSTATION(R)3 SPU Optimized Bullet Physics Library (http://bulletphysics.com)
* Copyright (C) 2007 Sony Computer Entertainment Inc.
* All Rights Reserved.
*/
/*
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 SPUVoronoiSimplexSolver_H
#define SPUVoronoiSimplexSolver_H
#include <LinearMath/btTransform.h>
#include <LinearMath/btPoint3.h>
#define VORONOI_SIMPLEX_MAX_VERTS 5
struct SpuUsageBitfield{
SpuUsageBitfield()
{
reset();
}
void reset()
{
usedVertexA = false;
usedVertexB = false;
usedVertexC = false;
usedVertexD = false;
}
unsigned short usedVertexA : 1;
unsigned short usedVertexB : 1;
unsigned short usedVertexC : 1;
unsigned short usedVertexD : 1;
unsigned short unused1 : 1;
unsigned short unused2 : 1;
unsigned short unused3 : 1;
unsigned short unused4 : 1;
};
struct SpuSubSimplexClosestResult
{
btVector3 m_closestPointOnSimplex;
//MASK for m_usedVertices
//stores the simplex vertex-usage, using the MASK,
// if m_usedVertices & MASK then the related vertex is used
SpuUsageBitfield m_usedVertices;
float m_barycentricCoords[4];
bool m_degenerate;
void reset()
{
m_degenerate = false;
setBarycentricCoordinates();
m_usedVertices.reset();
}
bool isValid()
{
bool valid = (m_barycentricCoords[0] >= float(0.)) &&
(m_barycentricCoords[1] >= float(0.)) &&
(m_barycentricCoords[2] >= float(0.)) &&
(m_barycentricCoords[3] >= float(0.));
return valid;
}
void setBarycentricCoordinates(float a=float(0.),float b=float(0.),float c=float(0.),float d=float(0.))
{
m_barycentricCoords[0] = a;
m_barycentricCoords[1] = b;
m_barycentricCoords[2] = c;
m_barycentricCoords[3] = d;
}
};
/// SpuVoronoiSimplexSolver is an implementation of the closest point distance algorithm from a 1-4 points simplex to the origin.
/// Can be used with GJK, as an alternative to Johnson distance algorithm.
class SpuVoronoiSimplexSolver
{
public:
int m_numVertices;
btVector3 m_simplexVectorW[VORONOI_SIMPLEX_MAX_VERTS];
btVector3 m_simplexPointsP[VORONOI_SIMPLEX_MAX_VERTS];
btVector3 m_simplexPointsQ[VORONOI_SIMPLEX_MAX_VERTS];
int m_VertexIndexA[VORONOI_SIMPLEX_MAX_VERTS];
int m_VertexIndexB[VORONOI_SIMPLEX_MAX_VERTS];
btVector3 m_cachedP1;
btVector3 m_cachedP2;
btVector3 m_cachedV;
btVector3 m_lastW;
bool m_cachedValidClosest;
SpuSubSimplexClosestResult m_cachedBC;
bool m_needsUpdate;
void removeVertex(int index);
void reduceVertices (const SpuUsageBitfield& usedVerts);
bool updateClosestVectorAndPoints();
bool closestPtPointTetrahedron(const btVector3& p, const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d, SpuSubSimplexClosestResult& finalResult);
int pointOutsideOfPlane(const btVector3& p, const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d);
bool closestPtPointTriangle(const btVector3& p, const btVector3& a, const btVector3& b, const btVector3& c,SpuSubSimplexClosestResult& result);
int RemoveDegenerateIndices (const int *inArray, int numIndices, int *outArray) const;
public:
void reset();
void addVertex(const btVector3& w, const btPoint3& p, const btPoint3& q);
bool closest(btVector3& v);
float maxVertex();
bool fullSimplex() const
{
return (m_numVertices == 4);
}
int getSimplex(btVector3 *pBuf, btVector3 *qBuf, btVector3 *yBuf) const;
bool inSimplex(const btVector3& w);
void backup_closest(btVector3& v) ;
bool emptySimplex() const ;
void compute_points(btVector3& p1, btVector3& p2) ;
int numVertices() const
{
return m_numVertices;
}
};
#endif //SpuVoronoiSimplexSolver

View File

@@ -0,0 +1,649 @@
/*
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.
Elsevier CDROM license agreements grants nonexclusive license to use the software
for any purpose, commercial or non-commercial as long as the following credit is included
identifying the original source of the software:
Parts of the source are "from the book Real-Time Collision Detection by
Christer Ericson, published by Morgan Kaufmann Publishers,
(c) 2005 Elsevier Inc."
*/
// Needed to be able to DMA.
#ifdef WIN32
#include "SpuFakeDma.h"
#else
#include "SPU_Common/SpuDefines.h"
#include <cell/spurs/common.h>
#include <cell/dma.h>
#endif //WIN32
#include "SpuVoronoiSimplexSolver.h"
#include "LinearMath/btScalar.h"
#include <assert.h>
#include <stdio.h>
#define VERTA 0
#define VERTB 1
#define VERTC 2
#define VERTD 3
#define CATCH_DEGENERATE_TETRAHEDRON 1
void SpuVoronoiSimplexSolver::removeVertex(int index)
{
assert(m_numVertices>0);
m_numVertices--;
m_simplexVectorW[index] = m_simplexVectorW[m_numVertices];
m_simplexPointsP[index] = m_simplexPointsP[m_numVertices];
m_simplexPointsQ[index] = m_simplexPointsQ[m_numVertices];
// m_VertexIndexA[index] = m_VertexIndexA[m_numVertices];
// m_VertexIndexB[index] = m_VertexIndexB[m_numVertices];
}
void SpuVoronoiSimplexSolver::reduceVertices (const SpuUsageBitfield& usedVerts)
{
if ((numVertices() >= 4) && (!usedVerts.usedVertexD))
removeVertex(3);
if ((numVertices() >= 3) && (!usedVerts.usedVertexC))
removeVertex(2);
if ((numVertices() >= 2) && (!usedVerts.usedVertexB))
removeVertex(1);
if ((numVertices() >= 1) && (!usedVerts.usedVertexA))
removeVertex(0);
}
//clear the simplex, remove all the vertices
void SpuVoronoiSimplexSolver::reset()
{
m_cachedValidClosest = false;
m_numVertices = 0;
m_needsUpdate = true;
m_lastW = Vectormath::Aos::Vector3(float(1e30),float(1e30),float(1e30));
m_cachedBC.reset();
}
//add a vertex
void SpuVoronoiSimplexSolver::addVertex(const Vectormath::Aos::Vector3& w, const Vectormath::Aos::Point3& p, const Vectormath::Aos::Point3& q)//, int vertexIndexA, int vertexIndexB)
{
m_lastW = w;
m_needsUpdate = true;
m_simplexVectorW[m_numVertices] = w;
m_simplexPointsP[m_numVertices] = Vectormath::Aos::Vector3(p);
m_simplexPointsQ[m_numVertices] = Vectormath::Aos::Vector3(q);
//m_VertexIndexA[m_numVertices] = vertexIndexA;
//m_VertexIndexB[m_numVertices] = vertexIndexB;
m_numVertices++;
}
bool SpuVoronoiSimplexSolver::updateClosestVectorAndPoints()
{
if (m_needsUpdate)
{
m_cachedBC.reset();
m_needsUpdate = false;
switch (numVertices())
{
case 0:
m_cachedValidClosest = false;
break;
case 1:
{
m_cachedP1 = m_simplexPointsP[0];
m_cachedP2 = m_simplexPointsQ[0];
m_cachedV = m_cachedP1-m_cachedP2; //== m_simplexVectorW[0]
m_cachedBC.reset();
m_cachedBC.setBarycentricCoordinates(float(1.),float(0.),float(0.),float(0.));
m_cachedValidClosest = m_cachedBC.isValid();
break;
};
case 2:
{
//closest point origin from line segment
const Vectormath::Aos::Vector3& from = m_simplexVectorW[0];
const Vectormath::Aos::Vector3& to = m_simplexVectorW[1];
Vectormath::Aos::Vector3 nearest;
Vectormath::Aos::Vector3 p (float(0.),float(0.),float(0.));
Vectormath::Aos::Vector3 diff = p - from;
Vectormath::Aos::Vector3 v = to - from;
float t = dot(v, diff);
if (t > 0) {
float dotVV = dot(v, v);
if (t < dotVV) {
t /= dotVV;
diff -= t*v;
m_cachedBC.m_usedVertices.usedVertexA = true;
m_cachedBC.m_usedVertices.usedVertexB = true;
} else {
t = 1;
diff -= v;
//reduce to 1 point
m_cachedBC.m_usedVertices.usedVertexB = true;
}
} else
{
t = 0;
//reduce to 1 point
m_cachedBC.m_usedVertices.usedVertexA = true;
}
m_cachedBC.setBarycentricCoordinates(1-t,t);
nearest = from + t*v;
m_cachedP1 = m_simplexPointsP[0] + t * (m_simplexPointsP[1] - m_simplexPointsP[0]);
m_cachedP2 = m_simplexPointsQ[0] + t * (m_simplexPointsQ[1] - m_simplexPointsQ[0]);
m_cachedV = m_cachedP1 - m_cachedP2;
reduceVertices(m_cachedBC.m_usedVertices);
m_cachedValidClosest = m_cachedBC.isValid();
break;
}
case 3:
{
//closest point origin from triangle
Vectormath::Aos::Vector3 p (float(0.),float(0.),float(0.));
const Vectormath::Aos::Vector3& a = m_simplexVectorW[0];
const Vectormath::Aos::Vector3& b = m_simplexVectorW[1];
const Vectormath::Aos::Vector3& c = m_simplexVectorW[2];
closestPtPointTriangle(p,a,b,c,m_cachedBC);
m_cachedP1 = m_simplexPointsP[0] * m_cachedBC.m_barycentricCoords[0] +
m_simplexPointsP[1] * m_cachedBC.m_barycentricCoords[1] +
m_simplexPointsP[2] * m_cachedBC.m_barycentricCoords[2];
m_cachedP2 = m_simplexPointsQ[0] * m_cachedBC.m_barycentricCoords[0] +
m_simplexPointsQ[1] * m_cachedBC.m_barycentricCoords[1] +
m_simplexPointsQ[2] * m_cachedBC.m_barycentricCoords[2];
m_cachedV = m_cachedP1-m_cachedP2;
reduceVertices (m_cachedBC.m_usedVertices);
m_cachedValidClosest = m_cachedBC.isValid();
break;
}
case 4:
{
Vectormath::Aos::Vector3 p (float(0.),float(0.),float(0.));
const Vectormath::Aos::Vector3& a = m_simplexVectorW[0];
const Vectormath::Aos::Vector3& b = m_simplexVectorW[1];
const Vectormath::Aos::Vector3& c = m_simplexVectorW[2];
const Vectormath::Aos::Vector3& d = m_simplexVectorW[3];
bool hasSeperation = closestPtPointTetrahedron(p,a,b,c,d,m_cachedBC);
if (hasSeperation)
{
m_cachedP1 = m_simplexPointsP[0] * m_cachedBC.m_barycentricCoords[0] +
m_simplexPointsP[1] * m_cachedBC.m_barycentricCoords[1] +
m_simplexPointsP[2] * m_cachedBC.m_barycentricCoords[2] +
m_simplexPointsP[3] * m_cachedBC.m_barycentricCoords[3];
m_cachedP2 = m_simplexPointsQ[0] * m_cachedBC.m_barycentricCoords[0] +
m_simplexPointsQ[1] * m_cachedBC.m_barycentricCoords[1] +
m_simplexPointsQ[2] * m_cachedBC.m_barycentricCoords[2] +
m_simplexPointsQ[3] * m_cachedBC.m_barycentricCoords[3];
m_cachedV = m_cachedP1-m_cachedP2;
reduceVertices (m_cachedBC.m_usedVertices);
} else
{
// printf("sub distance got penetration\n");
if (m_cachedBC.m_degenerate)
{
m_cachedValidClosest = false;
} else
{
m_cachedValidClosest = true;
//degenerate case == false, penetration = true + zero
m_cachedV = Vectormath::Aos::Vector3(float(0.),float(0.),float(0.));
}
break;
}
m_cachedValidClosest = m_cachedBC.isValid();
//closest point origin from tetrahedron
break;
}
default:
{
m_cachedValidClosest = false;
}
};
}
return m_cachedValidClosest;
}
//return/calculate the closest vertex
bool SpuVoronoiSimplexSolver::closest(Vectormath::Aos::Vector3& v)
{
bool succes = updateClosestVectorAndPoints();
v = m_cachedV;
return succes;
}
float SpuVoronoiSimplexSolver::maxVertex()
{
int i, numverts = numVertices();
float maxV = float(0.);
for (i=0;i<numverts;i++)
{
float curLen2 = lengthSqr(m_simplexVectorW[i]);
if (maxV < curLen2)
maxV = curLen2;
}
return maxV;
}
//return the current simplex
int SpuVoronoiSimplexSolver::getSimplex(Vectormath::Aos::Vector3 *pBuf, Vectormath::Aos::Vector3 *qBuf, Vectormath::Aos::Vector3 *yBuf) const
{
int i;
for (i=0;i<numVertices();i++)
{
yBuf[i] = m_simplexVectorW[i];
pBuf[i] = m_simplexPointsP[i];
qBuf[i] = m_simplexPointsQ[i];
}
return numVertices();
}
bool SpuVoronoiSimplexSolver::inSimplex(const Vectormath::Aos::Vector3& w)
{
bool found = false;
int i, numverts = numVertices();
//float maxV = float(0.);
//w is in the current (reduced) simplex
for (i=0;i<numverts;i++)
{
// TODO: find a better way to determine equality
if (m_simplexVectorW[i].getX() == w.getX() &&
m_simplexVectorW[i].getY() == w.getY() &&
m_simplexVectorW[i].getZ() == w.getZ())
found = true;
}
//check in case lastW is already removed
// TODO: find a better way to determine equality
if (w.getX() == m_lastW.getX() &&
w.getY() == m_lastW.getY() &&
w.getZ() == m_lastW.getZ())
return true;
return found;
}
void SpuVoronoiSimplexSolver::backup_closest(Vectormath::Aos::Vector3& v)
{
v = m_cachedV;
}
bool SpuVoronoiSimplexSolver::emptySimplex() const
{
return (numVertices() == 0);
}
void SpuVoronoiSimplexSolver::compute_points(Vectormath::Aos::Point3& p1, Vectormath::Aos::Point3& p2)
{
updateClosestVectorAndPoints();
p1 = Vectormath::Aos::Point3(m_cachedP1);
p2 = Vectormath::Aos::Point3(m_cachedP2);
}
bool SpuVoronoiSimplexSolver::closestPtPointTriangle(const Vectormath::Aos::Vector3& p, const Vectormath::Aos::Vector3& a, const Vectormath::Aos::Vector3& b, const Vectormath::Aos::Vector3& c,SpuSubSimplexClosestResult& result)
{
result.m_usedVertices.reset();
// Check if P in vertex region outside A
Vectormath::Aos::Vector3 ab = b - a;
Vectormath::Aos::Vector3 ac = c - a;
Vectormath::Aos::Vector3 ap = p - a;
float d1 = dot(ab,ap);
float d2 = dot(ac,ap);
if (d1 <= float(0.0) && d2 <= float(0.0))
{
result.m_closestPointOnSimplex = Vectormath::Aos::Point3(a);
result.m_usedVertices.usedVertexA = true;
result.setBarycentricCoordinates(1,0,0);
return true;// a; // barycentric coordinates (1,0,0)
}
// Check if P in vertex region outside B
Vectormath::Aos::Vector3 bp = p - b;
float d3 = dot(ab,bp);
float d4 = dot(ac,bp);
if (d3 >= float(0.0) && d4 <= d3)
{
result.m_closestPointOnSimplex = Vectormath::Aos::Point3(b);
result.m_usedVertices.usedVertexB = true;
result.setBarycentricCoordinates(0,1,0);
return true; // b; // barycentric coordinates (0,1,0)
}
// Check if P in edge region of AB, if so return projection of P onto AB
float vc = d1*d4 - d3*d2;
if (vc <= float(0.0) && d1 >= float(0.0) && d3 <= float(0.0)) {
float v = d1 / (d1 - d3);
result.m_closestPointOnSimplex = Vectormath::Aos::Point3(a + v * ab);
result.m_usedVertices.usedVertexA = true;
result.m_usedVertices.usedVertexB = true;
result.setBarycentricCoordinates(1-v,v,0);
return true;
//return a + v * ab; // barycentric coordinates (1-v,v,0)
}
// Check if P in vertex region outside C
Vectormath::Aos::Vector3 cp = p - c;
float d5 = dot(ab,cp);
float d6 = dot(ac,cp);
if (d6 >= float(0.0) && d5 <= d6)
{
result.m_closestPointOnSimplex = Vectormath::Aos::Point3(c);
result.m_usedVertices.usedVertexC = true;
result.setBarycentricCoordinates(0,0,1);
return true;//c; // barycentric coordinates (0,0,1)
}
// Check if P in edge region of AC, if so return projection of P onto AC
float vb = d5*d2 - d1*d6;
if (vb <= float(0.0) && d2 >= float(0.0) && d6 <= float(0.0)) {
float w = d2 / (d2 - d6);
result.m_closestPointOnSimplex = Vectormath::Aos::Point3(a + w * ac);
result.m_usedVertices.usedVertexA = true;
result.m_usedVertices.usedVertexC = true;
result.setBarycentricCoordinates(1-w,0,w);
return true;
//return a + w * ac; // barycentric coordinates (1-w,0,w)
}
// Check if P in edge region of BC, if so return projection of P onto BC
float va = d3*d6 - d5*d4;
if (va <= float(0.0) && (d4 - d3) >= float(0.0) && (d5 - d6) >= float(0.0)) {
float w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
result.m_closestPointOnSimplex = Vectormath::Aos::Point3(b + w * (c - b));
result.m_usedVertices.usedVertexB = true;
result.m_usedVertices.usedVertexC = true;
result.setBarycentricCoordinates(0,1-w,w);
return true;
// return b + w * (c - b); // barycentric coordinates (0,1-w,w)
}
// P inside face region. Compute Q through its barycentric coordinates (u,v,w)
float denom = float(1.0) / (va + vb + vc);
float v = vb * denom;
float w = vc * denom;
result.m_closestPointOnSimplex = Vectormath::Aos::Point3(a + ab * v + ac * w);
result.m_usedVertices.usedVertexA = true;
result.m_usedVertices.usedVertexB = true;
result.m_usedVertices.usedVertexC = true;
result.setBarycentricCoordinates(1-v-w,v,w);
return true;
// return a + ab * v + ac * w; // = u*a + v*b + w*c, u = va * denom = float(1.0) - v - w
}
// This is specifically just removing duplicate indices.
int SpuVoronoiSimplexSolver::RemoveDegenerateIndices (const int* inArray, int numIndices, int* outArray) const
{
int outIndex = 0;
for (int firstIndex=0; firstIndex<numIndices; firstIndex++)
{
bool duplicate = false;
for (int secondIndex=0; secondIndex<firstIndex; secondIndex++)
{
if (inArray[secondIndex]==inArray[firstIndex])
{
duplicate = true;
break;
}
}
if (!duplicate)
{
outArray[outIndex++] = inArray[firstIndex];
}
}
return outIndex;
}
/// Test if point p and d lie on opposite sides of plane through abc
int SpuVoronoiSimplexSolver::pointOutsideOfPlane(const Vectormath::Aos::Vector3& p, const Vectormath::Aos::Vector3& a, const Vectormath::Aos::Vector3& b, const Vectormath::Aos::Vector3& c, const Vectormath::Aos::Vector3& d)
{
Vectormath::Aos::Vector3 normal = cross(b-a,c-a);
float signp = dot(p - a, normal); // [AP AB AC]
float signd = dot(d - a, normal); // [AD AB AC]
#ifdef CATCH_DEGENERATE_TETRAHEDRON
if (signd * signd < (float(1e-4) * float(1e-4)))
{
// printf("affine dependent/degenerate\n");//
return -1;
}
#endif
// Points on opposite sides if expression signs are opposite
return signp * signd < float(0.);
}
bool SpuVoronoiSimplexSolver::closestPtPointTetrahedron(const Vectormath::Aos::Vector3& p, const Vectormath::Aos::Vector3& a, const Vectormath::Aos::Vector3& b, const Vectormath::Aos::Vector3& c, const Vectormath::Aos::Vector3& d, SpuSubSimplexClosestResult& finalResult)
{
SpuSubSimplexClosestResult tempResult;
// Start out assuming point inside all halfspaces, so closest to itself
finalResult.m_closestPointOnSimplex = Vectormath::Aos::Point3(p);
finalResult.m_usedVertices.reset();
finalResult.m_usedVertices.usedVertexA = true;
finalResult.m_usedVertices.usedVertexB = true;
finalResult.m_usedVertices.usedVertexC = true;
finalResult.m_usedVertices.usedVertexD = true;
// Check only the tetrahedron faces that are closest to p. We do that by checking each face (which itself is a triangle) to see if the excluded
// vertex (the one vertex that isn't part of that face) is on the other side of that face from the point p.
int pointOutsideABC = pointOutsideOfPlane(p, a, b, c, d);
int pointOutsideACD = pointOutsideOfPlane(p, a, c, d, b);
int pointOutsideADB = pointOutsideOfPlane(p, a, d, b, c);
int pointOutsideBDC = pointOutsideOfPlane(p, b, d, c, a);
if (pointOutsideABC < 0 || pointOutsideACD < 0 || pointOutsideADB < 0 || pointOutsideBDC < 0)
{
finalResult.m_degenerate = true;
return false;
}
if (!pointOutsideABC && !pointOutsideACD && !pointOutsideADB && !pointOutsideBDC)
{
return false;
}
float bestSqDist = 1e30f;//FLT_MAX;
// If point outside face abc then compute closest point on abc
if (pointOutsideABC)
{
closestPtPointTriangle(p, a, b, c,tempResult);
Vectormath::Aos::Vector3 q = Vectormath::Aos::Vector3(tempResult.m_closestPointOnSimplex);
float sqDist = dot(q - p, q - p);
// Update best closest point if (squared) distance is less than current best
//if (sqDist < bestSqDist)
btAssert(sqDist < bestSqDist); // This has to be true; we haven't actually tested any other combinations.
{
bestSqDist = sqDist;
finalResult.m_closestPointOnSimplex = Vectormath::Aos::Point3(q);
//convert result bitmask!
finalResult.m_usedVertices.reset();
finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA;
finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexB;
finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexC;
finalResult.setBarycentricCoordinates(
tempResult.m_barycentricCoords[VERTA],
tempResult.m_barycentricCoords[VERTB],
tempResult.m_barycentricCoords[VERTC],
0
);
}
}
// Repeat test for face acd
if (pointOutsideACD)
{
closestPtPointTriangle(p, a, c, d,tempResult);
Vectormath::Aos::Vector3 q = Vectormath::Aos::Vector3(tempResult.m_closestPointOnSimplex);
//convert result bitmask!
float sqDist = dot(q - p, q - p);
if (sqDist < bestSqDist)
{
bestSqDist = sqDist;
finalResult.m_closestPointOnSimplex = Vectormath::Aos::Point3(q);
finalResult.m_usedVertices.reset();
finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA;
finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexB;
finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexC;
finalResult.setBarycentricCoordinates(
tempResult.m_barycentricCoords[VERTA],
0,
tempResult.m_barycentricCoords[VERTB],
tempResult.m_barycentricCoords[VERTC]
);
}
}
// Repeat test for face adb
if (pointOutsideADB)
{
closestPtPointTriangle(p, a, d, b,tempResult);
Vectormath::Aos::Vector3 q = Vectormath::Aos::Vector3(tempResult.m_closestPointOnSimplex);
//convert result bitmask!
float sqDist = dot(q - p, q - p);
if (sqDist < bestSqDist)
{
bestSqDist = sqDist;
finalResult.m_closestPointOnSimplex = Vectormath::Aos::Point3(q);
finalResult.m_usedVertices.reset();
finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA;
finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexB;
finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexC;
finalResult.setBarycentricCoordinates(
tempResult.m_barycentricCoords[VERTA],
tempResult.m_barycentricCoords[VERTC],
0,
tempResult.m_barycentricCoords[VERTB]
);
}
}
// Repeat test for face bdc
if (pointOutsideBDC)
{
closestPtPointTriangle(p, b, d, c,tempResult);
Vectormath::Aos::Vector3 q = Vectormath::Aos::Vector3(tempResult.m_closestPointOnSimplex);
//convert result bitmask!
float sqDist = dot(q - p, q - p);
if (sqDist < bestSqDist)
{
bestSqDist = sqDist;
finalResult.m_closestPointOnSimplex = Vectormath::Aos::Point3(q);
finalResult.m_usedVertices.reset();
finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexA;
finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexB;
finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexC;
finalResult.setBarycentricCoordinates(
0,
tempResult.m_barycentricCoords[VERTA],
tempResult.m_barycentricCoords[VERTC],
tempResult.m_barycentricCoords[VERTB]
);
}
}
//help! we ended up full !
if (finalResult.m_usedVertices.usedVertexA &&
finalResult.m_usedVertices.usedVertexB &&
finalResult.m_usedVertices.usedVertexC &&
finalResult.m_usedVertices.usedVertexD)
{
return true;
}
return true;
}

View File

@@ -0,0 +1 @@
Empty placeholder for future Libspe2 SPU task

View File

@@ -0,0 +1 @@
Empty placeholder for future Libspe2 SPU task

View File

@@ -0,0 +1,199 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 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.
*/
//#define __CELLOS_LV2__ 1
#include "SpuLibspe2Support.h"
#include "Win32ThreadSupport.h"
//#include "SPUAssert.h"
#include <string.h>
#include "SpuSampleTaskProcess.h"
#include <stdio.h>
void SampleThreadFunc(void* userPtr,void* lsMemory)
{
//do nothing
printf("hello world\n");
}
void* SamplelsMemoryFunc()
{
//don't create local store memory, just return 0
return 0;
}
//SpuLibspe2Support gSampleSPU(SPU_ELF_SAMPLE,SAMPLE_NUM_WORKUNIT_TASKS);
Win32ThreadSupport gSampleSPU(Win32ThreadSupport::Win32ThreadConstructionInfo("sample",
SampleThreadFunc,
SamplelsMemoryFunc,
SAMPLE_NUM_WORKUNIT_TASKS));
extern "C" {
extern char SPU_SAMPLE_ELF_SYMBOL[];
};
SpuSampleTaskDesc g_spuSampleTaskDesc[SAMPLE_NUM_WORKUNIT_TASKS];
SpuSampleTaskProcess::SpuSampleTaskProcess(Win32ThreadSupport::Win32ThreadConstructionInfo& threadConstructionInfo)
{
for (int i = 0; i < threadConstructionInfo.m_numThreads; i++)
{
m_taskBusy[i] = false;
}
m_numBusyTasks = 0;
m_currentTask = 0;
m_initialized = false;
gSampleSPU.startSPUs(threadConstructionInfo);
}
SpuSampleTaskProcess::~SpuSampleTaskProcess()
{
gSampleSPU.stopSPUs();
}
void SpuSampleTaskProcess::initialize()
{
#ifdef DEBUG_SPU_TASK_SCHEDULING
printf("SpuSampleTaskProcess::initialize()\n");
#endif //DEBUG_SPU_TASK_SCHEDULING
for (int i = 0; i < SAMPLE_NUM_WORKUNIT_TASKS; i++)
{
m_taskBusy[i] = false;
}
m_numBusyTasks = 0;
m_currentTask = 0;
m_initialized = true;
}
void SpuSampleTaskProcess::issueTask(void* sampleMainMemPtr,int sampleValue)
{
#ifdef DEBUG_SPU_TASK_SCHEDULING
printf("SpuSampleTaskProcess::issueTask (m_currentTask= %d\)n", m_currentTask);
#endif //DEBUG_SPU_TASK_SCHEDULING
m_taskBusy[m_currentTask] = true;
m_numBusyTasks++;
SpuSampleTaskDesc& taskDesc = g_spuSampleTaskDesc[m_currentTask];
{
// send task description in event message
// no error checking here...
// but, currently, event queue can be no larger than NUM_WORKUNIT_TASKS.
taskDesc.m_mainMemoryPtr = reinterpret_cast<uint64_t>(sampleMainMemPtr);
taskDesc.m_sampleValue = sampleValue;
//some bookkeeping to recognize finished tasks
taskDesc.m_taskId = m_currentTask;
}
gSampleSPU.sendRequest(CMD_SAMPLE_TASK_COMMAND, (uint32_t) &taskDesc, m_currentTask);
// if all tasks busy, wait for spu event to clear the task.
if (m_numBusyTasks >= SAMPLE_NUM_WORKUNIT_TASKS)
{
unsigned int taskId;
unsigned int outputSize;
gSampleSPU.waitForResponse(&taskId, &outputSize);
//printf("PPU: after issue, received event: %u %d\n", taskId, outputSize);
postProcess(taskId, outputSize);
m_taskBusy[taskId] = false;
m_numBusyTasks--;
}
// find new task buffer
for (unsigned int i = 0; i < SAMPLE_NUM_WORKUNIT_TASKS; i++)
{
if (!m_taskBusy[i])
{
m_currentTask = i;
break;
}
}
}
///Optional PPU-size post processing for each task
void SpuSampleTaskProcess::postProcess(int taskId, int outputSize)
{
}
void SpuSampleTaskProcess::flush()
{
#ifdef DEBUG_SPU_TASK_SCHEDULING
printf("\nSpuCollisionTaskProcess::flush()\n");
#endif //DEBUG_SPU_TASK_SCHEDULING
// all tasks are issued, wait for all tasks to be complete
while(m_numBusyTasks > 0)
{
// Consolidating SPU code
unsigned int taskId;
unsigned int outputSize;
{
gSampleSPU.waitForResponse(&taskId, &outputSize);
}
//printf("PPU: flushing, received event: %u %d\n", taskId, outputSize);
postProcess(taskId, outputSize);
m_taskBusy[taskId] = false;
m_numBusyTasks--;
}
}

View File

@@ -0,0 +1,83 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 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.
*/
#ifndef SPU_SAMPLE_TASK_PROCESS_H
#define SPU_SAMPLE_TASK_PROCESS_H
#include <assert.h>
#include <LinearMath/btScalar.h>
#include "PlatformDefinitions.h"
#include <stdlib.h>
///maximum outstanding tasks
#define SAMPLE_NUM_WORKUNIT_TASKS 4
///SpuSampleTaskDesc
struct SpuSampleTaskDesc
{
uint64_t m_mainMemoryPtr;
int m_sampleValue;
uint16_t m_taskId;
}
#ifdef __CELLOS_LV2__
__attribute__ ((aligned (16)))
#endif
;
//just add your commands here, try to keep them globally unique for debugging purposes
#define CMD_SAMPLE_TASK_COMMAND 10
/// SpuSampleTaskProcess handles SPU processing of collision pairs.
/// When PPU issues a task, it will look for completed task buffers
/// PPU will do postprocessing, dependent on workunit output (not likely)
class SpuSampleTaskProcess
{
// track task buffers that are being used, and total busy tasks
bool m_taskBusy[SAMPLE_NUM_WORKUNIT_TASKS];
unsigned int m_numBusyTasks;
// the current task and the current entry to insert a new work unit
unsigned int m_currentTask;
bool m_initialized;
void postProcess(int taskId, int outputSize);
public:
SpuSampleTaskProcess(Win32ThreadSupport::Win32ThreadConstructionInfo& ci);
~SpuSampleTaskProcess();
///call initialize in the beginning of the frame, before addCollisionPairToTask
void initialize();
void issueTask(void* sampleMainMemPtr,int sampleValue);
///call flush to submit potential outstanding work to SPUs and wait for all involved SPUs to be finished
void flush();
};
#endif // SPU_SAMPLE_TASK_PROCESS_H

View File

@@ -0,0 +1 @@
Empty placeholder for future Libspe2 SPU task

View File

@@ -0,0 +1,226 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 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 "Win32ThreadSupport.h"
#ifdef USE_WIN32_THREADING
#include "SpuCollisionTaskProcess.h"
#include "SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h"
#include <Windows.h>
///Win32ThreadSupport helps to initialize/shutdown libspe2, start/stop SPU tasks and communication
///Setup and initialize SPU/CELL/Libspe2
Win32ThreadSupport::Win32ThreadSupport(Win32ThreadConstructionInfo& threadConstructionInfo)
{
startSPUs(threadConstructionInfo);
}
///cleanup/shutdown Libspe2
Win32ThreadSupport::~Win32ThreadSupport()
{
stopSPUs();
}
#include <stdio.h>
DWORD WINAPI Thread_no_1( LPVOID lpParam )
{
btSpuStatus* status = (btSpuStatus*)lpParam;
while (1)
{
WaitForSingleObject(status->m_eventStartHandle,INFINITE);
btAssert(status->m_status);
void* userPtr = status->m_userPtr;
if (userPtr)
{
status->m_userThreadFunc(userPtr,status->m_lsMemory);
SetEvent(status->m_eventCompletetHandle);
} else
{
//exit Thread
break;
}
}
return 0;
}
///send messages to SPUs
void Win32ThreadSupport::sendRequest(uint32_t uiCommand, uint32_t uiArgument0, uint32_t taskId)
{
/// gMidphaseSPU.sendRequest(CMD_GATHER_AND_PROCESS_PAIRLIST, (uint32_t) &taskDesc);
///we should spawn an SPU task here, and in 'waitForResponse' it should wait for response of the (one of) the first tasks that finished
switch (uiCommand)
{
case CMD_GATHER_AND_PROCESS_PAIRLIST:
{
//#define SINGLE_THREADED 1
#ifdef SINGLE_THREADED
btSpuStatus& spuStatus = m_activeSpuStatus[0];
spuStatus.m_userPtr=(void*)uiArgument0;
spuStatus.m_userThreadFunc(spuStatus.m_userPtr,spuStatus.m_lsMemory);
HANDLE handle =0;
#else
btSpuStatus& spuStatus = m_activeSpuStatus[taskId];
btAssert(taskId>=0);
btAssert(taskId<m_activeSpuStatus.size());
spuStatus.m_commandId = uiCommand;
spuStatus.m_status = 1;
spuStatus.m_userPtr = (void*)uiArgument0;
///fire event to start new task
SetEvent(spuStatus.m_eventStartHandle);
#endif //CollisionTask_LocalStoreMemory
break;
}
default:
{
///not implemented
btAssert(0);
}
};
}
///check for messages from SPUs
void Win32ThreadSupport::waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1)
{
///We should wait for (one of) the first tasks to finish (or other SPU messages), and report its response
///A possible response can be 'yes, SPU handled it', or 'no, please do a PPU fallback'
btAssert(m_activeSpuStatus.size());
int last = -1;
//find an active spu/thread
for (int i=0;i<m_activeSpuStatus.size();i++)
{
if (m_activeSpuStatus[i].m_status)
{
last = i;
break;
}
}
#ifndef SINGLE_THREADED
btSpuStatus& spuStatus = m_activeSpuStatus[last];
btAssert(spuStatus.m_threadHandle);
btAssert(spuStatus.m_eventCompletetHandle);
WaitForSingleObject(spuStatus.m_eventCompletetHandle, INFINITE);
spuStatus.m_status = 0;
///need to find an active spu
btAssert(last>=0);
#else
last=0;
btSpuStatus& spuStatus = m_activeSpuStatus[last];
#endif //SINGLE_THREADED
*puiArgument0 = spuStatus.m_taskId;
*puiArgument1 = spuStatus.m_status;
}
///start the spus group (can be called at the beginning of each frame, to make sure that the right SPU program is loaded)
void Win32ThreadSupport::startSPUs(Win32ThreadConstructionInfo& threadConstructionInfo)
{
m_activeSpuStatus.resize(threadConstructionInfo.m_numThreads);
for (int i=0;i<threadConstructionInfo.m_numThreads;i++)
{
printf("starting thread %d\n",i);
btSpuStatus& spuStatus = m_activeSpuStatus[i];
LPSECURITY_ATTRIBUTES lpThreadAttributes=NULL;
SIZE_T dwStackSize=threadConstructionInfo.m_threadStackSize;
LPTHREAD_START_ROUTINE lpStartAddress=&Thread_no_1;
LPVOID lpParameter=&spuStatus;
DWORD dwCreationFlags=0;
LPDWORD lpThreadId=0;
spuStatus.m_userPtr=0;
sprintf(spuStatus.m_eventStartHandleName,"eventStart%s%d",threadConstructionInfo.m_uniqueName,i);
spuStatus.m_eventStartHandle = CreateEvent(0,false,false,spuStatus.m_eventStartHandleName);
sprintf(spuStatus.m_eventCompletetHandleName,"eventComplete%s%d",threadConstructionInfo.m_uniqueName,i);
spuStatus.m_eventCompletetHandle = CreateEvent(0,false,false,spuStatus.m_eventCompletetHandleName);
HANDLE handle = CreateThread(lpThreadAttributes,dwStackSize,lpStartAddress,lpParameter, dwCreationFlags,lpThreadId);
SetThreadPriority(handle,THREAD_PRIORITY_TIME_CRITICAL);
spuStatus.m_taskId = i;
spuStatus.m_commandId = 0;
spuStatus.m_status = 0;
spuStatus.m_threadHandle = handle;
spuStatus.m_lsMemory = threadConstructionInfo.m_lsMemoryFunc();
spuStatus.m_userThreadFunc = threadConstructionInfo.m_userThreadFunc;
printf("started thread %d with threadHandle %d\n",i,handle);
}
}
///tell the task scheduler we are done with the SPU tasks
void Win32ThreadSupport::stopSPUs()
{
// m_activeSpuStatus.pop_back();
// WaitForSingleObject(spuStatus.bla, INFINITE);
// CloseHandle(spuStatus.m_threadHandle);
}
#endif //USE_WIN32_THREADING

View File

@@ -0,0 +1,116 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2007 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 "LinearMath/btScalar.h"
#include "PlatformDefinitions.h"
#ifdef USE_WIN32_THREADING //platform specific defines are defined in PlatformDefinitions.h
#ifndef WIN32_THREAD_SUPPORT_H
#define WIN32_THREAD_SUPPORT_H
#include "LinearMath/btAlignedObjectArray.h"
#include <LinearMath/btScalar.h> //for uint32_t etc.
typedef void (*Win32ThreadFunc)(void* userPtr,void* lsMemory);
typedef void* (*Win32lsMemorySetupFunc)();
///placeholder, until libspe2 support is there
struct btSpuStatus
{
uint32_t m_taskId;
uint32_t m_commandId;
uint32_t m_status;
Win32ThreadFunc m_userThreadFunc;
void* m_userPtr; //for taskDesc etc
void* m_lsMemory; //initialized using Win32LocalStoreMemorySetupFunc
void* m_threadHandle; //this one is calling 'Win32ThreadFunc'
void* m_eventStartHandle;
char m_eventStartHandleName[32];
void* m_eventCompletetHandle;
char m_eventCompletetHandleName[32];
};
///Win32ThreadSupport helps to initialize/shutdown libspe2, start/stop SPU tasks and communication
class Win32ThreadSupport {
btAlignedObjectArray<btSpuStatus> m_activeSpuStatus;
public:
///Setup and initialize SPU/CELL/Libspe2
struct Win32ThreadConstructionInfo
{
Win32ThreadConstructionInfo(char* uniqueName,
Win32ThreadFunc userThreadFunc,
Win32lsMemorySetupFunc lsMemoryFunc,
int numThreads=1,
int threadStackSize=65535
)
:m_uniqueName(uniqueName),
m_userThreadFunc(userThreadFunc),
m_lsMemoryFunc(lsMemoryFunc),
m_numThreads(numThreads),
m_threadStackSize(threadStackSize)
{
}
char* m_uniqueName;
Win32ThreadFunc m_userThreadFunc;
Win32lsMemorySetupFunc m_lsMemoryFunc;
int m_numThreads;
int m_threadStackSize;
};
Win32ThreadSupport(Win32ThreadConstructionInfo& threadConstructionInfo);
///cleanup/shutdown Libspe2
~Win32ThreadSupport();
///send messages to SPUs
void sendRequest(uint32_t uiCommand, uint32_t uiArgument0, uint32_t uiArgument1);
///check for messages from SPUs
void waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1);
///start the spus (can be called at the beginning of each frame, to make sure that the right SPU program is loaded)
void startSPUs(Win32ThreadConstructionInfo& threadConstructionInfo);
///tell the task scheduler we are done with the SPU tasks
void stopSPUs();
};
#endif //WIN32_THREAD_SUPPORT_H
#endif //USE_WIN32_THREADING