Add PhysicsEffects to Extras. The build is only tested on Windows and Android.
The Android/NEON optimized version of Physics Effects is thanks to Graham Rhodes and Anthony Hamilton, See Issue 587
This commit is contained in:
29
Extras/PhysicsEffects/src/low_level/CMakeLists.txt
Normal file
29
Extras/PhysicsEffects/src/low_level/CMakeLists.txt
Normal file
@@ -0,0 +1,29 @@
|
||||
INCLUDE_DIRECTORIES( ${PHYSICS_EFFECTS_SOURCE_DIR}/include )
|
||||
|
||||
SET(PfxLowLevel_SRCS
|
||||
broadphase/pfx_broadphase_single.cpp
|
||||
collision/pfx_batched_ray_cast_single.cpp
|
||||
collision/pfx_collision_detection_single.cpp
|
||||
collision/pfx_detect_collision_func.cpp
|
||||
collision/pfx_intersect_ray_func.cpp
|
||||
collision/pfx_island_generation.cpp
|
||||
collision/pfx_ray_cast.cpp
|
||||
collision/pfx_refresh_contacts_single.cpp
|
||||
solver/pfx_constraint_solver_single.cpp
|
||||
solver/pfx_joint_constraint_func.cpp
|
||||
solver/pfx_update_rigid_states_single.cpp
|
||||
sort/pfx_parallel_sort_single.cpp
|
||||
)
|
||||
|
||||
SET(PfxLowLevel_HDRS
|
||||
collision/pfx_detect_collision_func.h
|
||||
collision/pfx_intersect_ray_func.h
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
ADD_LIBRARY(PfxLowLevel ${PfxLowLevel_SRCS} ${PfxLowLevel_HDRS})
|
||||
|
||||
SET_TARGET_PROPERTIES(PfxLowLevel PROPERTIES VERSION ${BULLET_VERSION})
|
||||
SET_TARGET_PROPERTIES(PfxLowLevel PROPERTIES SOVERSION ${BULLET_VERSION})
|
||||
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#include "../../../include/physics_effects/base_level/base/pfx_perf_counter.h"
|
||||
#include "../../../include/physics_effects/base_level/sort/pfx_sort.h"
|
||||
#include "../../../include/physics_effects/base_level/broadphase/pfx_update_broadphase_proxy.h"
|
||||
#include "../../../include/physics_effects/low_level/broadphase/pfx_broadphase.h"
|
||||
#include "../../base_level/broadphase/pfx_check_collidable.h"
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
PfxUInt32 pfxGetWorkBytesOfUpdateBroadphaseProxies(PfxUInt32 numRigidBodies)
|
||||
{
|
||||
return 128 + SCE_PFX_ALLOC_BYTES_ALIGN128(sizeof(PfxBroadphaseProxy) * numRigidBodies);
|
||||
}
|
||||
|
||||
PfxUInt32 pfxGetWorkBytesOfUpdateBroadphaseProxies(PfxUInt32 numRigidBodies,PfxUInt32 maxTasks)
|
||||
{
|
||||
(void)maxTasks;
|
||||
return 128 + SCE_PFX_ALLOC_BYTES_ALIGN128(sizeof(PfxBroadphaseProxy) * numRigidBodies) * 6;
|
||||
}
|
||||
|
||||
PfxUInt32 pfxGetWorkBytesOfFindPairs(PfxUInt32 maxPairs,PfxUInt32 maxTasks)
|
||||
{
|
||||
return 128 + SCE_PFX_ALLOC_BYTES_ALIGN128(sizeof(PfxBroadphasePair) * maxPairs) * maxTasks;
|
||||
}
|
||||
|
||||
PfxUInt32 pfxGetPairBytesOfFindPairs(PfxUInt32 maxPairs)
|
||||
{
|
||||
return SCE_PFX_ALLOC_BYTES_ALIGN128(sizeof(PfxBroadphasePair) * maxPairs);
|
||||
}
|
||||
|
||||
PfxUInt32 pfxGetWorkBytesOfDecomposePairs(PfxUInt32 numPreviousPairs,PfxUInt32 numCurrentPairs,int maxTasks)
|
||||
{
|
||||
return 128 +
|
||||
SCE_PFX_ALLOC_BYTES_ALIGN128(sizeof(PfxBroadphasePair)*numPreviousPairs) +
|
||||
SCE_PFX_ALLOC_BYTES_ALIGN128(sizeof(PfxBroadphasePair)*numPreviousPairs) * maxTasks +
|
||||
SCE_PFX_ALLOC_BYTES_ALIGN128(sizeof(PfxBroadphasePair)*numCurrentPairs) * maxTasks;
|
||||
}
|
||||
|
||||
PfxInt32 pfxCheckParamOfUpdateBroadphaseProxies(const PfxUpdateBroadphaseProxiesParam ¶m)
|
||||
{
|
||||
if(!param.workBuff ||
|
||||
!param.proxiesX || !param.proxiesY || !param.proxiesZ ||
|
||||
!param.proxiesXb || !param.proxiesYb || !param.proxiesZb ||
|
||||
!param.offsetRigidStates || !param.offsetCollidables ) return SCE_PFX_ERR_INVALID_VALUE;
|
||||
if(!SCE_PFX_PTR_IS_ALIGNED16(param.proxiesX) || !SCE_PFX_PTR_IS_ALIGNED16(param.proxiesY) || !SCE_PFX_PTR_IS_ALIGNED16(param.proxiesZ) ||
|
||||
!SCE_PFX_PTR_IS_ALIGNED16(param.proxiesXb) || !SCE_PFX_PTR_IS_ALIGNED16(param.proxiesYb) || !SCE_PFX_PTR_IS_ALIGNED16(param.proxiesZb) ) return SCE_PFX_ERR_INVALID_ALIGN;
|
||||
if(SCE_PFX_AVAILABLE_BYTES_ALIGN16(param.workBuff,param.workBytes) < pfxGetWorkBytesOfUpdateBroadphaseProxies(param.numRigidBodies) ) return SCE_PFX_ERR_OUT_OF_BUFFER;
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
PfxInt32 pfxCheckParamOfFindPairs(const PfxFindPairsParam ¶m,int maxTasks)
|
||||
{
|
||||
if(!param.workBuff || !param.pairBuff || !param.proxies || param.axis > 2 || param.axis < 0) return SCE_PFX_ERR_INVALID_VALUE;
|
||||
if(!SCE_PFX_PTR_IS_ALIGNED16(param.proxies) || !SCE_PFX_PTR_IS_ALIGNED16(param.pairBuff)) return SCE_PFX_ERR_INVALID_ALIGN;
|
||||
if(SCE_PFX_AVAILABLE_BYTES_ALIGN16(param.workBuff,param.workBytes) < pfxGetWorkBytesOfFindPairs(param.maxPairs,maxTasks) ) return SCE_PFX_ERR_OUT_OF_BUFFER;
|
||||
if(SCE_PFX_AVAILABLE_BYTES_ALIGN16(param.pairBuff,param.pairBytes) < pfxGetPairBytesOfFindPairs(param.maxPairs) ) return SCE_PFX_ERR_OUT_OF_BUFFER;
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
PfxUInt32 pfxGetPairBytesOfDecomposePairs(PfxUInt32 numPreviousPairs,PfxUInt32 numCurrentPairs)
|
||||
{
|
||||
return sizeof(PfxBroadphasePair)*(numPreviousPairs*2+numCurrentPairs);
|
||||
}
|
||||
|
||||
PfxInt32 pfxCheckParamOfDecomposePairs(const PfxDecomposePairsParam ¶m,int maxTasks)
|
||||
{
|
||||
if(!param.workBuff || !param.pairBuff || !param.previousPairs || !param.currentPairs) return SCE_PFX_ERR_INVALID_VALUE;
|
||||
if(!SCE_PFX_PTR_IS_ALIGNED16(param.previousPairs) || !SCE_PFX_PTR_IS_ALIGNED16(param.currentPairs) || !SCE_PFX_PTR_IS_ALIGNED16(param.pairBuff) ) return SCE_PFX_ERR_INVALID_ALIGN;
|
||||
if(SCE_PFX_AVAILABLE_BYTES_ALIGN16(param.workBuff,param.workBytes) < pfxGetWorkBytesOfDecomposePairs(param.numPreviousPairs,param.numCurrentPairs,maxTasks)) return SCE_PFX_ERR_OUT_OF_BUFFER;
|
||||
if(SCE_PFX_AVAILABLE_BYTES_ALIGN16(param.pairBuff,param.pairBytes) < pfxGetPairBytesOfDecomposePairs(param.numPreviousPairs,param.numCurrentPairs)) return SCE_PFX_ERR_OUT_OF_BUFFER;
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SINGLE THREAD
|
||||
|
||||
PfxInt32 pfxUpdateBroadphaseProxies(PfxUpdateBroadphaseProxiesParam ¶m,PfxUpdateBroadphaseProxiesResult &result)
|
||||
{
|
||||
PfxInt32 ret = pfxCheckParamOfUpdateBroadphaseProxies(param);
|
||||
if(ret != SCE_PFX_OK) return ret;
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxUpdateBroadphaseProxies")
|
||||
|
||||
result.numOutOfWorldProxies = 0;
|
||||
|
||||
for(int i=0;i<(int)param.numRigidBodies;i++) {
|
||||
PfxInt32 chk = pfxUpdateBroadphaseProxy(
|
||||
param.proxiesX[i],
|
||||
param.proxiesY[i],
|
||||
param.proxiesZ[i],
|
||||
param.proxiesXb[i],
|
||||
param.proxiesYb[i],
|
||||
param.proxiesZb[i],
|
||||
param.offsetRigidStates[i],
|
||||
param.offsetCollidables[i],
|
||||
param.worldCenter,
|
||||
param.worldExtent);
|
||||
|
||||
if(chk == SCE_PFX_ERR_OUT_OF_WORLD) {
|
||||
result.numOutOfWorldProxies++;
|
||||
|
||||
if(param.outOfWorldBehavior & SCE_PFX_OUT_OF_WORLD_BEHAVIOR_FIX_MOTION) {
|
||||
PfxRigidState &state = param.offsetRigidStates[i];
|
||||
state.setMotionType(kPfxMotionTypeFixed);
|
||||
pfxSetMotionMask(param.proxiesX[i],state.getMotionMask());
|
||||
pfxSetMotionMask(param.proxiesY[i],state.getMotionMask());
|
||||
pfxSetMotionMask(param.proxiesZ[i],state.getMotionMask());
|
||||
pfxSetMotionMask(param.proxiesXb[i],state.getMotionMask());
|
||||
pfxSetMotionMask(param.proxiesYb[i],state.getMotionMask());
|
||||
pfxSetMotionMask(param.proxiesZb[i],state.getMotionMask());
|
||||
}
|
||||
|
||||
if(param.outOfWorldBehavior & SCE_PFX_OUT_OF_WORLD_BEHAVIOR_REMOVE_PROXY) {
|
||||
pfxSetKey(param.proxiesX[i],SCE_PFX_SENTINEL_KEY);
|
||||
pfxSetKey(param.proxiesY[i],SCE_PFX_SENTINEL_KEY);
|
||||
pfxSetKey(param.proxiesZ[i],SCE_PFX_SENTINEL_KEY);
|
||||
pfxSetKey(param.proxiesXb[i],SCE_PFX_SENTINEL_KEY);
|
||||
pfxSetKey(param.proxiesYb[i],SCE_PFX_SENTINEL_KEY);
|
||||
pfxSetKey(param.proxiesZb[i],SCE_PFX_SENTINEL_KEY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PfxHeapManager pool((unsigned char*)param.workBuff,param.workBytes);
|
||||
PfxBroadphaseProxy *workProxies = (PfxBroadphaseProxy*)pool.allocate(sizeof(PfxBroadphaseProxy)*param.numRigidBodies,PfxHeapManager::ALIGN128);
|
||||
|
||||
pfxSort(param.proxiesX,workProxies,param.numRigidBodies);
|
||||
pfxSort(param.proxiesY,workProxies,param.numRigidBodies);
|
||||
pfxSort(param.proxiesZ,workProxies,param.numRigidBodies);
|
||||
pfxSort(param.proxiesXb,workProxies,param.numRigidBodies);
|
||||
pfxSort(param.proxiesYb,workProxies,param.numRigidBodies);
|
||||
pfxSort(param.proxiesZb,workProxies,param.numRigidBodies);
|
||||
|
||||
pool.deallocate(workProxies);
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
PfxInt32 pfxFindPairs(PfxFindPairsParam ¶m,PfxFindPairsResult &result)
|
||||
{
|
||||
PfxInt32 ret = pfxCheckParamOfFindPairs(param,0);
|
||||
if(ret != SCE_PFX_OK) return ret;
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxFindPairs")
|
||||
|
||||
void *workBuff = param.workBuff;
|
||||
PfxUInt32 workBytes = param.workBytes;
|
||||
PfxBroadphaseProxy *proxies = param.proxies;
|
||||
PfxUInt32 numProxies = param.numProxies;
|
||||
PfxUInt32 maxPairs = param.maxPairs;
|
||||
int axis = param.axis;
|
||||
|
||||
(void) workBytes;
|
||||
|
||||
PfxBroadphasePair *pairs = (PfxBroadphasePair*)SCE_PFX_PTR_ALIGN16(param.pairBuff);
|
||||
PfxUInt32 numPairs = 0;
|
||||
|
||||
for(PfxUInt32 i=0;i<numProxies;i++) {
|
||||
for(PfxUInt32 j=i+1;j<numProxies;j++) {
|
||||
PfxBroadphaseProxy proxyA,proxyB;
|
||||
if(pfxGetObjectId(proxies[i]) < pfxGetObjectId(proxies[j])) {
|
||||
proxyA = proxies[i];
|
||||
proxyB = proxies[j];
|
||||
}
|
||||
else {
|
||||
proxyA = proxies[j];
|
||||
proxyB = proxies[i];
|
||||
}
|
||||
|
||||
if(pfxGetXYZMax(proxyA,axis) < pfxGetXYZMin(proxyB,axis)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if( pfxCheckCollidableInBroadphase(proxyA,proxyB) ) {
|
||||
if(numPairs >= maxPairs)
|
||||
return SCE_PFX_ERR_OUT_OF_MAX_PAIRS;
|
||||
|
||||
PfxBroadphasePair &pair = pairs[numPairs++];
|
||||
pfxSetActive(pair,true);
|
||||
pfxSetObjectIdA(pair,pfxGetObjectId(proxyA));
|
||||
pfxSetObjectIdB(pair,pfxGetObjectId(proxyB));
|
||||
pfxSetMotionMaskA(pair,pfxGetMotionMask(proxyA));
|
||||
pfxSetMotionMaskB(pair,pfxGetMotionMask(proxyB));
|
||||
|
||||
pfxSetKey(pair,pfxCreateUniqueKey(pfxGetObjectId(proxyA),pfxGetObjectId(proxyB)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pfxSort(pairs,(PfxBroadphasePair*)workBuff,numPairs);
|
||||
|
||||
result.pairs = pairs;
|
||||
result.numPairs = numPairs;
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
PfxInt32 pfxDecomposePairs(PfxDecomposePairsParam ¶m,PfxDecomposePairsResult &result)
|
||||
{
|
||||
PfxInt32 ret = pfxCheckParamOfDecomposePairs(param,0);
|
||||
if(ret != SCE_PFX_OK) return ret;
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxDecomposePairs")
|
||||
|
||||
PfxBroadphasePair *previousPairs = param.previousPairs;
|
||||
PfxUInt32 numPreviousPairs = param.numPreviousPairs;
|
||||
PfxBroadphasePair *currentPairs = param.currentPairs;
|
||||
PfxUInt32 numCurrentPairs = param.numCurrentPairs;
|
||||
|
||||
PfxBroadphasePair *outNewPairs = (PfxBroadphasePair*)SCE_PFX_PTR_ALIGN16(param.pairBuff);
|
||||
PfxBroadphasePair *outKeepPairs = outNewPairs + numCurrentPairs;
|
||||
PfxBroadphasePair *outRemovePairs = outKeepPairs + numPreviousPairs;
|
||||
|
||||
PfxUInt32 nNew = 0;
|
||||
PfxUInt32 nKeep = 0;
|
||||
PfxUInt32 nRemove = 0;
|
||||
|
||||
PfxUInt32 oldId = 0,newId = 0;
|
||||
|
||||
while(oldId<numPreviousPairs&&newId<numCurrentPairs) {
|
||||
if(pfxGetKey(currentPairs[newId]) > pfxGetKey(previousPairs[oldId])) {
|
||||
// remove
|
||||
SCE_PFX_ASSERT(nRemove<=numPreviousPairs);
|
||||
outRemovePairs[nRemove] = previousPairs[oldId];
|
||||
nRemove++;
|
||||
oldId++;
|
||||
}
|
||||
else if(pfxGetKey(currentPairs[newId]) == pfxGetKey(previousPairs[oldId])) {
|
||||
// keep
|
||||
SCE_PFX_ASSERT(nKeep<=numPreviousPairs);
|
||||
outKeepPairs[nKeep] = currentPairs[newId];
|
||||
pfxSetContactId(outKeepPairs[nKeep],pfxGetContactId(previousPairs[oldId]));
|
||||
nKeep++;
|
||||
oldId++;
|
||||
newId++;
|
||||
}
|
||||
else {
|
||||
// new
|
||||
SCE_PFX_ASSERT(nNew<=numCurrentPairs);
|
||||
outNewPairs[nNew] = currentPairs[newId];
|
||||
nNew++;
|
||||
newId++;
|
||||
}
|
||||
};
|
||||
|
||||
if(newId<numCurrentPairs) {
|
||||
// all new
|
||||
for(;newId<numCurrentPairs;newId++,nNew++) {
|
||||
SCE_PFX_ASSERT(nNew<=numCurrentPairs);
|
||||
outNewPairs[nNew] = currentPairs[newId];
|
||||
}
|
||||
}
|
||||
else if(oldId<numPreviousPairs) {
|
||||
// all remove
|
||||
for(;oldId<numPreviousPairs;oldId++,nRemove++) {
|
||||
SCE_PFX_ASSERT(nRemove<=numPreviousPairs);
|
||||
outRemovePairs[nRemove] = previousPairs[oldId];
|
||||
}
|
||||
}
|
||||
|
||||
result.outNewPairs = outNewPairs;
|
||||
result.outKeepPairs = outKeepPairs;
|
||||
result.outRemovePairs = outRemovePairs;
|
||||
result.numOutNewPairs = nNew;
|
||||
result.numOutKeepPairs = nKeep;
|
||||
result.numOutRemovePairs = nRemove;
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Applied Research Associates Inc. (c)2011
|
||||
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#include "../../../include/physics_effects/low_level/collision/pfx_batched_ray_cast.h"
|
||||
#include "../../../include/physics_effects/base_level/base/pfx_perf_counter.h"
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MULTIPLE THREADS
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// pfxCastRaysStartTaskEntry
|
||||
//
|
||||
/// The thread PfxTaskEntry function used to cast rays in parallel.
|
||||
//----------------------------------------------------------------------------
|
||||
void pfxCastRaysStartTaskEntry(PfxTaskArg *arg)
|
||||
{
|
||||
PfxRayCastParam ¶m = *((PfxRayCastParam*)arg->io);
|
||||
|
||||
PfxRayInput *rayInputs = (PfxRayInput*)arg->data[0];
|
||||
PfxRayOutput *rayOutputs = (PfxRayOutput*)arg->data[1];
|
||||
PfxUInt32 iFirstRay = arg->data[2];
|
||||
PfxUInt32 iEndRay = arg->data[3];
|
||||
|
||||
for(PfxUInt32 i = iFirstRay; i < iEndRay; i++)
|
||||
{
|
||||
pfxCastSingleRay(rayInputs[i], rayOutputs[i], param);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// pfxCastRays
|
||||
//
|
||||
/// Perform cast rays in parallel using a task manager.
|
||||
///
|
||||
/// @param rayInputs [in] Array of rays to cast
|
||||
/// @param rayOutputs [out] On return contains output of ray casts
|
||||
/// @param param Information about ray cast
|
||||
/// @param taskManager Pointer to the thread task manager to use
|
||||
//----------------------------------------------------------------------------
|
||||
void pfxCastRays(PfxRayInput *rayInputs,PfxRayOutput *rayOutputs,int numRays,
|
||||
PfxRayCastParam ¶m,PfxTaskManager *taskManager)
|
||||
{
|
||||
SCE_PFX_ALWAYS_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.proxiesX));
|
||||
SCE_PFX_ALWAYS_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.proxiesY));
|
||||
SCE_PFX_ALWAYS_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.proxiesZ));
|
||||
SCE_PFX_ALWAYS_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.proxiesXb));
|
||||
SCE_PFX_ALWAYS_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.proxiesYb));
|
||||
SCE_PFX_ALWAYS_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.proxiesZb));
|
||||
SCE_PFX_ALWAYS_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.offsetRigidStates));
|
||||
SCE_PFX_ALWAYS_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.offsetCollidables));
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxCastRays");
|
||||
|
||||
PfxUInt32 maxBatchSize = numRays / (PfxUInt32)(taskManager->getNumTasks());
|
||||
PfxUInt32 iEnd = maxBatchSize, iStart = 0;
|
||||
int task = 0;
|
||||
taskManager->setTaskEntry((void*)pfxCastRaysStartTaskEntry);
|
||||
|
||||
for (task = 0; task < taskManager->getNumTasks() - 1; task++, iStart += maxBatchSize, iEnd += maxBatchSize)
|
||||
{
|
||||
taskManager->startTask(task, static_cast<void*>(¶m), (PfxUInt32)rayInputs, (PfxUInt32)rayOutputs, iStart, iEnd);
|
||||
}
|
||||
|
||||
// send final task
|
||||
iEnd = numRays;
|
||||
taskManager->startTask(taskManager->getNumTasks() - 1, static_cast<void*>(¶m), iStart, iEnd, 0, 0);
|
||||
|
||||
// wait for tasks to complete
|
||||
PfxUInt32 data1, data2, data3, data4;
|
||||
for (PfxUInt32 i = 0; i < taskManager->getNumTasks(); i++)
|
||||
taskManager->waitTask(task, data1, data2, data3, data4);
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
}
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#include "../../../include/physics_effects/low_level/collision/pfx_batched_ray_cast.h"
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SINGLE THREAD
|
||||
|
||||
void pfxCastRaysStart(PfxRayInput *rayInputs,PfxRayOutput *rayOutputs,int numRays,PfxRayCastParam ¶m)
|
||||
{
|
||||
for(int i=0;i<numRays;i++) {
|
||||
pfxCastSingleRay(rayInputs[i],rayOutputs[i],param);
|
||||
}
|
||||
}
|
||||
|
||||
void pfxCastRays(PfxRayInput *rayInputs,PfxRayOutput *rayOutputs,int numRays,PfxRayCastParam ¶m)
|
||||
{
|
||||
SCE_PFX_ALWAYS_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.proxiesX));
|
||||
SCE_PFX_ALWAYS_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.proxiesY));
|
||||
SCE_PFX_ALWAYS_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.proxiesZ));
|
||||
SCE_PFX_ALWAYS_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.proxiesXb));
|
||||
SCE_PFX_ALWAYS_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.proxiesYb));
|
||||
SCE_PFX_ALWAYS_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.proxiesZb));
|
||||
SCE_PFX_ALWAYS_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.offsetRigidStates));
|
||||
SCE_PFX_ALWAYS_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.offsetCollidables));
|
||||
|
||||
pfxCastRaysStart(rayInputs,rayOutputs,numRays,param);
|
||||
}
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
Applied Research Associates Inc. (c)2011
|
||||
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#include "../../../include/physics_effects/base_level/base/pfx_perf_counter.h"
|
||||
#include "../../../include/physics_effects/base_level/collision/pfx_shape_iterator.h"
|
||||
#include "../../../include/physics_effects/low_level/collision/pfx_collision_detection.h"
|
||||
#include "../../base_level/broadphase/pfx_check_collidable.h"
|
||||
#include "../../base_level/collision/pfx_contact_cache.h"
|
||||
#include "pfx_detect_collision_func.h"
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// This function is implemented in pfx_collision_detection_single.cpp
|
||||
extern int pfxCheckParamOfDetectCollision(PfxDetectCollisionParam ¶m);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MULTIPLE THREADS
|
||||
|
||||
#define SCE_PFX_CONTACT_THRESHOLD 0.0f
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// pfxDetectCollisionTaskEntry
|
||||
//
|
||||
/// The thread PfxTaskEntry function used to perform narrow phase collision
|
||||
/// detection in parallel.
|
||||
//----------------------------------------------------------------------------
|
||||
void pfxDetectCollisionTaskEntry(PfxTaskArg *arg)
|
||||
{
|
||||
PfxDetectCollisionParam ¶m = *((PfxDetectCollisionParam*)arg->io);
|
||||
|
||||
PfxUInt32 iFirstContactPair = arg->data[0];
|
||||
PfxUInt32 iEndContactPair = arg->data[1];
|
||||
|
||||
PfxConstraintPair *contactPairs = param.contactPairs;
|
||||
PfxContactManifold *offsetContactManifolds = param.offsetContactManifolds;
|
||||
PfxRigidState *offsetRigidStates = param.offsetRigidStates;
|
||||
PfxCollidable *offsetCollidables = param.offsetCollidables;
|
||||
PfxUInt32 numRigidBodies = param.numRigidBodies;
|
||||
|
||||
for(PfxUInt32 i = iFirstContactPair; i < iEndContactPair; i++)
|
||||
{
|
||||
const PfxBroadphasePair &pair = contactPairs[i];
|
||||
if(!pfxCheckCollidableInCollision(pair))
|
||||
continue;
|
||||
|
||||
PfxUInt32 iContact = pfxGetContactId(pair);
|
||||
PfxUInt32 iA = pfxGetObjectIdA(pair);
|
||||
PfxUInt32 iB = pfxGetObjectIdB(pair);
|
||||
|
||||
PfxContactManifold &contact = offsetContactManifolds[iContact];
|
||||
|
||||
SCE_PFX_ALWAYS_ASSERT(iA==contact.getRigidBodyIdA());
|
||||
SCE_PFX_ALWAYS_ASSERT(iB==contact.getRigidBodyIdB());
|
||||
|
||||
PfxRigidState &stateA = offsetRigidStates[iA];
|
||||
PfxRigidState &stateB = offsetRigidStates[iB];
|
||||
PfxCollidable &collA = offsetCollidables[iA];
|
||||
PfxCollidable &collB = offsetCollidables[iB];
|
||||
PfxTransform3 tA0(stateA.getOrientation(), stateA.getPosition());
|
||||
PfxTransform3 tB0(stateB.getOrientation(), stateB.getPosition());
|
||||
|
||||
PfxContactCache contactCache;
|
||||
|
||||
PfxShapeIterator itrShapeA(collA);
|
||||
for(PfxUInt32 j=0;j<collA.getNumShapes();j++,++itrShapeA)
|
||||
{
|
||||
const PfxShape &shapeA = *itrShapeA;
|
||||
PfxTransform3 offsetTrA = shapeA.getOffsetTransform();
|
||||
PfxTransform3 worldTrA = tA0 * offsetTrA;
|
||||
|
||||
PfxShapeIterator itrShapeB(collB);
|
||||
for(PfxUInt32 k=0;k<collB.getNumShapes();k++,++itrShapeB)
|
||||
{
|
||||
const PfxShape &shapeB = *itrShapeB;
|
||||
PfxTransform3 offsetTrB = shapeB.getOffsetTransform();
|
||||
PfxTransform3 worldTrB = tB0 * offsetTrB;
|
||||
|
||||
if( (shapeA.getContactFilterSelf()&shapeB.getContactFilterTarget()) &&
|
||||
(shapeA.getContactFilterTarget()&shapeB.getContactFilterSelf()) )
|
||||
{
|
||||
pfxGetDetectCollisionFunc(shapeA.getType(),shapeB.getType())(
|
||||
contactCache,
|
||||
shapeA,offsetTrA,worldTrA,j,
|
||||
shapeB,offsetTrB,worldTrB,k,
|
||||
SCE_PFX_CONTACT_THRESHOLD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int j=0;j<contactCache.getNumContacts();j++)
|
||||
{
|
||||
const PfxCachedContactPoint &cp = contactCache.getContactPoint(j);
|
||||
|
||||
contact.addContactPoint(
|
||||
cp.m_distance,
|
||||
cp.m_normal,
|
||||
cp.m_localPointA,
|
||||
cp.m_localPointB,
|
||||
cp.m_subData
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// pfxDetectCollision
|
||||
//
|
||||
/// Perform narrow phase collision detection in parallel using a task
|
||||
/// manager.
|
||||
///
|
||||
/// @param param Information about pairs that may be colliding
|
||||
/// @param taskManager Pointer to the thread task manager to use
|
||||
///
|
||||
/// @return SCE_PFX_OK if successful, otherwise, returns an error code.
|
||||
//----------------------------------------------------------------------------
|
||||
PfxInt32 pfxDetectCollision(PfxDetectCollisionParam ¶m, PfxTaskManager *taskManager)
|
||||
{
|
||||
PfxInt32 ret = pfxCheckParamOfDetectCollision(param);
|
||||
if(ret != SCE_PFX_OK)
|
||||
return ret;
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxDetectCollision");
|
||||
|
||||
PfxUInt32 maxBatchSize = param.numContactPairs / (PfxUInt32)(taskManager->getNumTasks());
|
||||
PfxUInt32 iEnd = maxBatchSize, iStart = 0;
|
||||
int task = 0;
|
||||
taskManager->setTaskEntry((void*)pfxDetectCollisionTaskEntry);
|
||||
|
||||
for (task = 0; task < taskManager->getNumTasks() - 1; task++, iStart += maxBatchSize, iEnd += maxBatchSize)
|
||||
{
|
||||
taskManager->startTask(task, static_cast<void*>(¶m), iStart, iEnd, 0, 0);
|
||||
}
|
||||
|
||||
// send final task
|
||||
iEnd = param.numContactPairs;
|
||||
taskManager->startTask(taskManager->getNumTasks() - 1, static_cast<void*>(¶m), iStart, iEnd, 0, 0);
|
||||
|
||||
// wait for tasks to complete
|
||||
PfxUInt32 data1, data2, data3, data4;
|
||||
for (PfxUInt32 i = 0; i < taskManager->getNumTasks(); i++)
|
||||
taskManager->waitTask(task, data1, data2, data3, data4);
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#include "../../../include/physics_effects/base_level/base/pfx_perf_counter.h"
|
||||
#include "../../../include/physics_effects/base_level/collision/pfx_shape_iterator.h"
|
||||
#include "../../../include/physics_effects/low_level/collision/pfx_collision_detection.h"
|
||||
#include "../../base_level/broadphase/pfx_check_collidable.h"
|
||||
#include "../../base_level/collision/pfx_contact_cache.h"
|
||||
#include "pfx_detect_collision_func.h"
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int pfxCheckParamOfDetectCollision(PfxDetectCollisionParam ¶m)
|
||||
{
|
||||
if(!param.contactPairs || !param.offsetContactManifolds || !param.offsetRigidStates|| !param.offsetCollidables ) return SCE_PFX_ERR_INVALID_VALUE;
|
||||
if(!SCE_PFX_PTR_IS_ALIGNED16(param.contactPairs) || !SCE_PFX_PTR_IS_ALIGNED16(param.offsetContactManifolds) ||
|
||||
!SCE_PFX_PTR_IS_ALIGNED16(param.offsetRigidStates) || !SCE_PFX_PTR_IS_ALIGNED16(param.offsetCollidables)) return SCE_PFX_ERR_INVALID_ALIGN;
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SINGLE THREAD
|
||||
|
||||
#define SCE_PFX_CONTACT_THRESHOLD 0.0f
|
||||
|
||||
PfxInt32 pfxDetectCollision(PfxDetectCollisionParam ¶m)
|
||||
{
|
||||
PfxInt32 ret = pfxCheckParamOfDetectCollision(param);
|
||||
if(ret != SCE_PFX_OK)
|
||||
return ret;
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxDetectCollision");
|
||||
|
||||
PfxConstraintPair *contactPairs = param.contactPairs;
|
||||
PfxUInt32 numContactPairs = param.numContactPairs;
|
||||
PfxContactManifold *offsetContactManifolds = param.offsetContactManifolds;
|
||||
PfxRigidState *offsetRigidStates = param.offsetRigidStates;
|
||||
PfxCollidable *offsetCollidables = param.offsetCollidables;
|
||||
PfxUInt32 numRigidBodies = param.numRigidBodies;
|
||||
|
||||
for(PfxUInt32 i=0;i<numContactPairs;i++) {
|
||||
const PfxBroadphasePair &pair = contactPairs[i];
|
||||
if(!pfxCheckCollidableInCollision(pair)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PfxUInt32 iContact = pfxGetContactId(pair);
|
||||
PfxUInt32 iA = pfxGetObjectIdA(pair);
|
||||
PfxUInt32 iB = pfxGetObjectIdB(pair);
|
||||
|
||||
PfxContactManifold &contact = offsetContactManifolds[iContact];
|
||||
|
||||
SCE_PFX_ALWAYS_ASSERT(iA==contact.getRigidBodyIdA());
|
||||
SCE_PFX_ALWAYS_ASSERT(iB==contact.getRigidBodyIdB());
|
||||
|
||||
PfxRigidState &stateA = offsetRigidStates[iA];
|
||||
PfxRigidState &stateB = offsetRigidStates[iB];
|
||||
PfxCollidable &collA = offsetCollidables[iA];
|
||||
PfxCollidable &collB = offsetCollidables[iB];
|
||||
PfxTransform3 tA0(stateA.getOrientation(), stateA.getPosition());
|
||||
PfxTransform3 tB0(stateB.getOrientation(), stateB.getPosition());
|
||||
|
||||
PfxContactCache contactCache;
|
||||
|
||||
PfxShapeIterator itrShapeA(collA);
|
||||
for(PfxUInt32 j=0;j<collA.getNumShapes();j++,++itrShapeA) {
|
||||
const PfxShape &shapeA = *itrShapeA;
|
||||
PfxTransform3 offsetTrA = shapeA.getOffsetTransform();
|
||||
PfxTransform3 worldTrA = tA0 * offsetTrA;
|
||||
|
||||
PfxShapeIterator itrShapeB(collB);
|
||||
for(PfxUInt32 k=0;k<collB.getNumShapes();k++,++itrShapeB) {
|
||||
const PfxShape &shapeB = *itrShapeB;
|
||||
PfxTransform3 offsetTrB = shapeB.getOffsetTransform();
|
||||
PfxTransform3 worldTrB = tB0 * offsetTrB;
|
||||
|
||||
if( (shapeA.getContactFilterSelf()&shapeB.getContactFilterTarget()) &&
|
||||
(shapeA.getContactFilterTarget()&shapeB.getContactFilterSelf()) ) {
|
||||
pfxGetDetectCollisionFunc(shapeA.getType(),shapeB.getType())(
|
||||
contactCache,
|
||||
shapeA,offsetTrA,worldTrA,j,
|
||||
shapeB,offsetTrB,worldTrB,k,
|
||||
SCE_PFX_CONTACT_THRESHOLD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int j=0;j<contactCache.getNumContacts();j++) {
|
||||
const PfxCachedContactPoint &cp = contactCache.getContactPoint(j);
|
||||
|
||||
contact.addContactPoint(
|
||||
cp.m_distance,
|
||||
cp.m_normal,
|
||||
cp.m_localPointA,
|
||||
cp.m_localPointB,
|
||||
cp.m_subData
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
|
||||
(void) numRigidBodies;
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
@@ -0,0 +1,449 @@
|
||||
/*
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#include "../../../include/physics_effects/base_level/collision/pfx_shape.h"
|
||||
#include "../../base_level/collision/pfx_contact_box_box.h"
|
||||
#include "../../base_level/collision/pfx_contact_box_capsule.h"
|
||||
#include "../../base_level/collision/pfx_contact_box_sphere.h"
|
||||
#include "../../base_level/collision/pfx_contact_capsule_capsule.h"
|
||||
#include "../../base_level/collision/pfx_contact_capsule_sphere.h"
|
||||
#include "../../base_level/collision/pfx_contact_sphere_sphere.h"
|
||||
#include "../../base_level/collision/pfx_gjk_solver.h"
|
||||
#include "../../base_level/collision/pfx_contact_large_tri_mesh.h"
|
||||
#include "../../base_level/collision/pfx_gjk_support_func.h"
|
||||
#include "pfx_detect_collision_func.h"
|
||||
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Collision Detection Function
|
||||
|
||||
void detectCollisionDummy(
|
||||
PfxContactCache &contacts,
|
||||
const PfxShape &shapeA,const PfxTransform3 &offsetTransformA,const PfxTransform3 &worldTransformA,int shapeIdA,
|
||||
const PfxShape &shapeB,const PfxTransform3 &offsetTransformB,const PfxTransform3 &worldTransformB,int shapeIdB,
|
||||
float contactThreshold)
|
||||
{
|
||||
(void)contacts;
|
||||
(void)shapeA,(void)offsetTransformA,(void)worldTransformA,(void)shapeIdA;
|
||||
(void)shapeB,(void)offsetTransformB,(void)worldTransformB,(void)shapeIdB;
|
||||
(void)contactThreshold;
|
||||
}
|
||||
|
||||
void detectCollisionBoxBox(
|
||||
PfxContactCache &contacts,
|
||||
const PfxShape &shapeA,const PfxTransform3 &offsetTransformA,const PfxTransform3 &worldTransformA,int shapeIdA,
|
||||
const PfxShape &shapeB,const PfxTransform3 &offsetTransformB,const PfxTransform3 &worldTransformB,int shapeIdB,
|
||||
float contactThreshold)
|
||||
{
|
||||
(void)shapeIdA,(void)shapeIdB;
|
||||
PfxBox boxA = shapeA.getBox();
|
||||
PfxBox boxB = shapeB.getBox();
|
||||
|
||||
PfxVector3 nml;
|
||||
PfxPoint3 pA,pB;
|
||||
|
||||
PfxFloat d = pfxContactBoxBox(nml,pA,pB,&boxA,worldTransformA,&boxB,worldTransformB);
|
||||
|
||||
if(d < contactThreshold) {
|
||||
contacts.addContactPoint(d,-nml,offsetTransformA*pA,offsetTransformB*pB,PfxSubData());
|
||||
}
|
||||
}
|
||||
|
||||
void detectCollisionBoxCapsule(
|
||||
PfxContactCache &contacts,
|
||||
const PfxShape &shapeA,const PfxTransform3 &offsetTransformA,const PfxTransform3 &worldTransformA,int shapeIdA,
|
||||
const PfxShape &shapeB,const PfxTransform3 &offsetTransformB,const PfxTransform3 &worldTransformB,int shapeIdB,
|
||||
float contactThreshold)
|
||||
{
|
||||
(void)shapeIdA,(void)shapeIdB;
|
||||
PfxBox boxA = shapeA.getBox();
|
||||
PfxCapsule capsuleB = shapeB.getCapsule();
|
||||
|
||||
PfxVector3 nml;
|
||||
PfxPoint3 pA,pB;
|
||||
|
||||
PfxFloat d = pfxContactBoxCapsule(nml,pA,pB,&boxA,worldTransformA,&capsuleB,worldTransformB);
|
||||
|
||||
if(d < contactThreshold) {
|
||||
contacts.addContactPoint(d,-nml,offsetTransformA*pA,offsetTransformB*pB,PfxSubData());
|
||||
}
|
||||
}
|
||||
|
||||
void detectCollisionBoxSphere(
|
||||
PfxContactCache &contacts,
|
||||
const PfxShape &shapeA,const PfxTransform3 &offsetTransformA,const PfxTransform3 &worldTransformA,int shapeIdA,
|
||||
const PfxShape &shapeB,const PfxTransform3 &offsetTransformB,const PfxTransform3 &worldTransformB,int shapeIdB,
|
||||
float contactThreshold)
|
||||
{
|
||||
(void)shapeIdA,(void)shapeIdB;
|
||||
PfxBox boxA = shapeA.getBox();
|
||||
PfxSphere sphereB = shapeB.getSphere();
|
||||
|
||||
PfxVector3 nml;
|
||||
PfxPoint3 pA,pB;
|
||||
|
||||
PfxFloat d = pfxContactBoxSphere(nml,pA,pB,&boxA,worldTransformA,&sphereB,worldTransformB);
|
||||
|
||||
if(d < contactThreshold) {
|
||||
contacts.addContactPoint(d,-nml,offsetTransformA*pA,offsetTransformB*pB,PfxSubData());
|
||||
}
|
||||
}
|
||||
|
||||
void detectCollisionCapsuleBox(
|
||||
PfxContactCache &contacts,
|
||||
const PfxShape &shapeA,const PfxTransform3 &offsetTransformA,const PfxTransform3 &worldTransformA,int shapeIdA,
|
||||
const PfxShape &shapeB,const PfxTransform3 &offsetTransformB,const PfxTransform3 &worldTransformB,int shapeIdB,
|
||||
float contactThreshold)
|
||||
{
|
||||
(void)shapeIdA,(void)shapeIdB;
|
||||
PfxCapsule capsuleA = shapeA.getCapsule();
|
||||
PfxBox boxB = shapeB.getBox();
|
||||
|
||||
PfxVector3 nml;
|
||||
PfxPoint3 pA,pB;
|
||||
|
||||
PfxFloat d = pfxContactBoxCapsule(nml,pB,pA,&boxB,worldTransformB,&capsuleA,worldTransformA);
|
||||
|
||||
if(d < contactThreshold) {
|
||||
contacts.addContactPoint(d,nml,offsetTransformA*pA,offsetTransformB*pB,PfxSubData());
|
||||
}
|
||||
}
|
||||
|
||||
void detectCollisionCapsuleCapsule(
|
||||
PfxContactCache &contacts,
|
||||
const PfxShape &shapeA,const PfxTransform3 &offsetTransformA,const PfxTransform3 &worldTransformA,int shapeIdA,
|
||||
const PfxShape &shapeB,const PfxTransform3 &offsetTransformB,const PfxTransform3 &worldTransformB,int shapeIdB,
|
||||
float contactThreshold)
|
||||
{
|
||||
(void)shapeIdA,(void)shapeIdB;
|
||||
PfxCapsule capsuleA = shapeA.getCapsule();
|
||||
PfxCapsule capsuleB = shapeB.getCapsule();
|
||||
|
||||
PfxVector3 nml;
|
||||
PfxPoint3 pA,pB;
|
||||
|
||||
PfxFloat d = pfxContactCapsuleCapsule(nml,pA,pB,&capsuleA,worldTransformA,&capsuleB,worldTransformB);
|
||||
|
||||
if(d < contactThreshold) {
|
||||
contacts.addContactPoint(d,-nml,offsetTransformA*pA,offsetTransformB*pB,PfxSubData());
|
||||
}
|
||||
}
|
||||
|
||||
void detectCollisionCapsuleSphere(
|
||||
PfxContactCache &contacts,
|
||||
const PfxShape &shapeA,const PfxTransform3 &offsetTransformA,const PfxTransform3 &worldTransformA,int shapeIdA,
|
||||
const PfxShape &shapeB,const PfxTransform3 &offsetTransformB,const PfxTransform3 &worldTransformB,int shapeIdB,
|
||||
float contactThreshold)
|
||||
{
|
||||
(void)shapeIdA,(void)shapeIdB;
|
||||
PfxCapsule capsuleA = shapeA.getCapsule();
|
||||
PfxSphere sphereB = shapeB.getSphere();
|
||||
|
||||
PfxVector3 nml;
|
||||
PfxPoint3 pA,pB;
|
||||
|
||||
PfxFloat d = pfxContactCapsuleSphere(nml,pA,pB,&capsuleA,worldTransformA,&sphereB,worldTransformB);
|
||||
|
||||
if(d < contactThreshold) {
|
||||
contacts.addContactPoint(d,-nml,offsetTransformA*pA,offsetTransformB*pB,PfxSubData());
|
||||
}
|
||||
}
|
||||
|
||||
void detectCollisionSphereBox(
|
||||
PfxContactCache &contacts,
|
||||
const PfxShape &shapeA,const PfxTransform3 &offsetTransformA,const PfxTransform3 &worldTransformA,int shapeIdA,
|
||||
const PfxShape &shapeB,const PfxTransform3 &offsetTransformB,const PfxTransform3 &worldTransformB,int shapeIdB,
|
||||
float contactThreshold)
|
||||
{
|
||||
(void)shapeIdA,(void)shapeIdB;
|
||||
PfxSphere sphereA = shapeA.getSphere();
|
||||
PfxBox boxB = shapeB.getBox();
|
||||
|
||||
PfxVector3 nml;
|
||||
PfxPoint3 pA,pB;
|
||||
|
||||
PfxFloat d = pfxContactBoxSphere(nml,pB,pA,&boxB,worldTransformB,&sphereA,worldTransformA);
|
||||
|
||||
if(d < contactThreshold) {
|
||||
contacts.addContactPoint(d,nml,offsetTransformA*pA,offsetTransformB*pB,PfxSubData());
|
||||
}
|
||||
}
|
||||
|
||||
void detectCollisionSphereCapsule(
|
||||
PfxContactCache &contacts,
|
||||
const PfxShape &shapeA,const PfxTransform3 &offsetTransformA,const PfxTransform3 &worldTransformA,int shapeIdA,
|
||||
const PfxShape &shapeB,const PfxTransform3 &offsetTransformB,const PfxTransform3 &worldTransformB,int shapeIdB,
|
||||
float contactThreshold)
|
||||
{
|
||||
(void)shapeIdA,(void)shapeIdB;
|
||||
PfxSphere sphereA = shapeA.getSphere();
|
||||
PfxCapsule capsuleB = shapeB.getCapsule();
|
||||
|
||||
PfxVector3 nml;
|
||||
PfxPoint3 pA,pB;
|
||||
|
||||
PfxFloat d = pfxContactCapsuleSphere(nml,pB,pA,&capsuleB,worldTransformB,&sphereA,worldTransformA);
|
||||
|
||||
if(d < contactThreshold) {
|
||||
contacts.addContactPoint(d,nml,offsetTransformA*pA,offsetTransformB*pB,PfxSubData());
|
||||
}
|
||||
}
|
||||
|
||||
void detectCollisionSphereSphere(
|
||||
PfxContactCache &contacts,
|
||||
const PfxShape &shapeA,const PfxTransform3 &offsetTransformA,const PfxTransform3 &worldTransformA,int shapeIdA,
|
||||
const PfxShape &shapeB,const PfxTransform3 &offsetTransformB,const PfxTransform3 &worldTransformB,int shapeIdB,
|
||||
float contactThreshold)
|
||||
{
|
||||
(void)shapeIdA,(void)shapeIdB;
|
||||
PfxSphere sphereA = shapeA.getSphere();
|
||||
PfxSphere sphereB = shapeB.getSphere();
|
||||
|
||||
PfxVector3 nml;
|
||||
PfxPoint3 pA,pB;
|
||||
|
||||
PfxFloat d = pfxContactSphereSphere(nml,pA,pB,&sphereA,worldTransformA,&sphereB,worldTransformB);
|
||||
|
||||
if(d < contactThreshold) {
|
||||
contacts.addContactPoint(d,-nml,offsetTransformA*pA,offsetTransformB*pB,PfxSubData());
|
||||
}
|
||||
}
|
||||
|
||||
void detectCollisionGjk(
|
||||
PfxContactCache &contacts,
|
||||
const PfxShape &shapeA,const PfxTransform3 &offsetTransformA,const PfxTransform3 &worldTransformA,int shapeIdA,
|
||||
const PfxShape &shapeB,const PfxTransform3 &offsetTransformB,const PfxTransform3 &worldTransformB,int shapeIdB,
|
||||
float contactThreshold)
|
||||
{
|
||||
(void)shapeIdA,(void)shapeIdB;
|
||||
PfxFloat d = SCE_PFX_FLT_MAX;
|
||||
PfxVector3 nml;
|
||||
PfxPoint3 pA,pB;
|
||||
PfxGjkSolver gjk;
|
||||
|
||||
if(shapeA.getType() == kPfxShapeCylinder) {
|
||||
PfxCylinder cylinderA = shapeA.getCylinder();
|
||||
|
||||
if(shapeB.getType() == kPfxShapeSphere) {
|
||||
PfxSphere sphereB = shapeB.getSphere();
|
||||
gjk.setup((void*)&cylinderA,(void*)&sphereB,pfxGetSupportVertexCylinder,pfxGetSupportVertexSphere);
|
||||
d = gjk.collide(nml,pA,pB,worldTransformA,worldTransformB,SCE_PFX_FLT_MAX);
|
||||
}
|
||||
else if(shapeB.getType() == kPfxShapeBox) {
|
||||
PfxBox boxB = shapeB.getBox();
|
||||
gjk.setup((void*)&cylinderA,(void*)&boxB,pfxGetSupportVertexCylinder,pfxGetSupportVertexBox);
|
||||
d = gjk.collide(nml,pA,pB,worldTransformA,worldTransformB,SCE_PFX_FLT_MAX);
|
||||
}
|
||||
else if(shapeB.getType() == kPfxShapeCapsule) {
|
||||
PfxCapsule capsuleB = shapeB.getCapsule();
|
||||
gjk.setup((void*)&cylinderA,(void*)&capsuleB,pfxGetSupportVertexCylinder,pfxGetSupportVertexCapsule);
|
||||
d = gjk.collide(nml,pA,pB,worldTransformA,worldTransformB,SCE_PFX_FLT_MAX);
|
||||
}
|
||||
else if(shapeB.getType() == kPfxShapeCylinder) {
|
||||
PfxCylinder cylinderB = shapeB.getCylinder();
|
||||
gjk.setup((void*)&cylinderA,(void*)&cylinderB,pfxGetSupportVertexCylinder,pfxGetSupportVertexCylinder);
|
||||
d = gjk.collide(nml,pA,pB,worldTransformA,worldTransformB,SCE_PFX_FLT_MAX);
|
||||
}
|
||||
else if(shapeB.getType() == kPfxShapeConvexMesh) {
|
||||
const PfxConvexMesh *convexB = shapeB.getConvexMesh();
|
||||
|
||||
gjk.setup((void*)&cylinderA,(void*)convexB,pfxGetSupportVertexCylinder,pfxGetSupportVertexConvex);
|
||||
d = gjk.collide(nml,pA,pB,worldTransformA,worldTransformB,SCE_PFX_FLT_MAX);
|
||||
|
||||
}
|
||||
}
|
||||
else if(shapeB.getType() == kPfxShapeCylinder) {
|
||||
PfxCylinder cylinderB = shapeB.getCylinder();
|
||||
|
||||
if(shapeA.getType() == kPfxShapeSphere) {
|
||||
PfxSphere sphereA = shapeA.getSphere();
|
||||
gjk.setup((void*)&sphereA,(void*)&cylinderB,pfxGetSupportVertexSphere,pfxGetSupportVertexCylinder);
|
||||
d = gjk.collide(nml,pA,pB,worldTransformA,worldTransformB,SCE_PFX_FLT_MAX);
|
||||
}
|
||||
else if(shapeA.getType() == kPfxShapeBox) {
|
||||
PfxBox boxA = shapeA.getBox();
|
||||
gjk.setup((void*)&boxA,(void*)&cylinderB,pfxGetSupportVertexBox,pfxGetSupportVertexCylinder);
|
||||
d = gjk.collide(nml,pA,pB,worldTransformA,worldTransformB,SCE_PFX_FLT_MAX);
|
||||
}
|
||||
else if(shapeA.getType() == kPfxShapeCapsule) {
|
||||
PfxCapsule capsuleA = shapeA.getCapsule();
|
||||
gjk.setup((void*)&capsuleA,(void*)&cylinderB,pfxGetSupportVertexCapsule,pfxGetSupportVertexCylinder);
|
||||
d = gjk.collide(nml,pA,pB,worldTransformA,worldTransformB,SCE_PFX_FLT_MAX);
|
||||
}
|
||||
else if(shapeA.getType() == kPfxShapeConvexMesh) {
|
||||
const PfxConvexMesh *convexA = shapeA.getConvexMesh();
|
||||
|
||||
gjk.setup((void*)convexA,(void*)&cylinderB,pfxGetSupportVertexConvex,pfxGetSupportVertexCylinder);
|
||||
d = gjk.collide(nml,pA,pB,worldTransformA,worldTransformB,SCE_PFX_FLT_MAX);
|
||||
|
||||
}
|
||||
}
|
||||
else if(shapeA.getType() == kPfxShapeConvexMesh) {
|
||||
const PfxConvexMesh *convexA = shapeA.getConvexMesh();
|
||||
|
||||
if(shapeB.getType() == kPfxShapeSphere) {
|
||||
PfxSphere sphereB = shapeB.getSphere();
|
||||
gjk.setup((void*)convexA,(void*)&sphereB,pfxGetSupportVertexConvex,pfxGetSupportVertexSphere);
|
||||
d = gjk.collide(nml,pA,pB,worldTransformA,worldTransformB,SCE_PFX_FLT_MAX);
|
||||
}
|
||||
else if(shapeB.getType() == kPfxShapeBox) {
|
||||
PfxBox boxB = shapeB.getBox();
|
||||
gjk.setup((void*)convexA,(void*)&boxB,pfxGetSupportVertexConvex,pfxGetSupportVertexBox);
|
||||
d = gjk.collide(nml,pA,pB,worldTransformA,worldTransformB,SCE_PFX_FLT_MAX);
|
||||
}
|
||||
else if(shapeB.getType() == kPfxShapeCapsule) {
|
||||
PfxCapsule capsuleB = shapeB.getCapsule();
|
||||
gjk.setup((void*)convexA,(void*)&capsuleB,pfxGetSupportVertexConvex,pfxGetSupportVertexCapsule);
|
||||
d = gjk.collide(nml,pA,pB,worldTransformA,worldTransformB,SCE_PFX_FLT_MAX);
|
||||
}
|
||||
else if(shapeB.getType() == kPfxShapeCylinder) {
|
||||
PfxCylinder cylinderB = shapeB.getCylinder();
|
||||
gjk.setup((void*)convexA,(void*)&cylinderB,pfxGetSupportVertexConvex,pfxGetSupportVertexCylinder);
|
||||
d = gjk.collide(nml,pA,pB,worldTransformA,worldTransformB,SCE_PFX_FLT_MAX);
|
||||
}
|
||||
else if(shapeB.getType() == kPfxShapeConvexMesh) {
|
||||
const PfxConvexMesh *convexB = shapeB.getConvexMesh();
|
||||
|
||||
gjk.setup((void*)convexA,(void*)convexB,pfxGetSupportVertexConvex,pfxGetSupportVertexConvex);
|
||||
d = gjk.collide(nml,pA,pB,worldTransformA,worldTransformB,SCE_PFX_FLT_MAX);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else if(shapeB.getType() == kPfxShapeConvexMesh) {
|
||||
const PfxConvexMesh *convexB = shapeB.getConvexMesh();
|
||||
|
||||
if(shapeA.getType() == kPfxShapeSphere) {
|
||||
PfxSphere sphereA = shapeA.getSphere();
|
||||
gjk.setup((void*)&sphereA,(void*)convexB,pfxGetSupportVertexSphere,pfxGetSupportVertexConvex);
|
||||
d = gjk.collide(nml,pA,pB,worldTransformA,worldTransformB,SCE_PFX_FLT_MAX);
|
||||
}
|
||||
else if(shapeA.getType() == kPfxShapeBox) {
|
||||
PfxBox boxA = shapeA.getBox();
|
||||
gjk.setup((void*)&boxA,(void*)convexB,pfxGetSupportVertexBox,pfxGetSupportVertexConvex);
|
||||
d = gjk.collide(nml,pA,pB,worldTransformA,worldTransformB,SCE_PFX_FLT_MAX);
|
||||
}
|
||||
else if(shapeA.getType() == kPfxShapeCapsule) {
|
||||
PfxCapsule capsuleA = shapeA.getCapsule();
|
||||
gjk.setup((void*)&capsuleA,(void*)convexB,pfxGetSupportVertexCapsule,pfxGetSupportVertexConvex);
|
||||
d = gjk.collide(nml,pA,pB,worldTransformA,worldTransformB,SCE_PFX_FLT_MAX);
|
||||
}
|
||||
else if(shapeA.getType() == kPfxShapeConvexMesh) {
|
||||
const PfxConvexMesh *convexA = shapeA.getConvexMesh();
|
||||
|
||||
gjk.setup((void*)convexA,(void*)convexB,pfxGetSupportVertexConvex,pfxGetSupportVertexConvex);
|
||||
d = gjk.collide(nml,pA,pB,worldTransformA,worldTransformB,SCE_PFX_FLT_MAX);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(d < contactThreshold) {
|
||||
contacts.addContactPoint(d,nml,offsetTransformA*pA,offsetTransformB*pB,PfxSubData());
|
||||
}
|
||||
}
|
||||
|
||||
void detectCollisionLargeTriMesh(
|
||||
PfxContactCache &contacts,
|
||||
const PfxShape &shapeA,const PfxTransform3 &offsetTransformA,const PfxTransform3 &worldTransformA,int shapeIdA,
|
||||
const PfxShape &shapeB,const PfxTransform3 &offsetTransformB,const PfxTransform3 &worldTransformB,int shapeIdB,
|
||||
float contactThreshold)
|
||||
{
|
||||
(void)shapeIdA,(void)shapeIdB;
|
||||
if(shapeA.getType() == kPfxShapeLargeTriMesh) {
|
||||
const PfxLargeTriMesh *lmeshA = shapeA.getLargeTriMesh();
|
||||
|
||||
PfxContactCache localContacts;
|
||||
pfxContactLargeTriMesh(localContacts,
|
||||
lmeshA,worldTransformA,
|
||||
shapeB,worldTransformB,
|
||||
contactThreshold);
|
||||
|
||||
|
||||
for(int i=0;i<localContacts.getNumContacts();i++) {
|
||||
contacts.addContactPoint(
|
||||
localContacts.getDistance(i),
|
||||
localContacts.getNormal(i),
|
||||
offsetTransformA * localContacts.getLocalPointA(i),
|
||||
offsetTransformB * localContacts.getLocalPointB(i),
|
||||
localContacts.getSubData(i));
|
||||
}
|
||||
}
|
||||
else if(shapeB.getType() == kPfxShapeLargeTriMesh) {
|
||||
const PfxLargeTriMesh *lmeshB = shapeB.getLargeTriMesh();
|
||||
|
||||
PfxContactCache localContacts;
|
||||
pfxContactLargeTriMesh(localContacts,
|
||||
lmeshB,worldTransformB,
|
||||
shapeA,worldTransformA,
|
||||
contactThreshold);
|
||||
|
||||
|
||||
for(int i=0;i<localContacts.getNumContacts();i++) {
|
||||
contacts.addContactPoint(
|
||||
localContacts.getDistance(i),
|
||||
-localContacts.getNormal(i),
|
||||
offsetTransformA * localContacts.getLocalPointB(i),
|
||||
offsetTransformB * localContacts.getLocalPointA(i),
|
||||
localContacts.getSubData(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Collision Detection Function Table
|
||||
|
||||
pfx_detect_collision_func funcTbl_detectCollision[kPfxShapeCount][kPfxShapeCount] = {
|
||||
{detectCollisionSphereSphere ,detectCollisionSphereBox ,detectCollisionSphereCapsule ,detectCollisionGjk ,detectCollisionGjk ,detectCollisionLargeTriMesh, detectCollisionDummy,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy, detectCollisionDummy},
|
||||
{detectCollisionBoxSphere ,detectCollisionBoxBox ,detectCollisionBoxCapsule ,detectCollisionGjk ,detectCollisionGjk ,detectCollisionLargeTriMesh, detectCollisionDummy,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy, detectCollisionDummy},
|
||||
{detectCollisionCapsuleSphere ,detectCollisionCapsuleBox ,detectCollisionCapsuleCapsule ,detectCollisionGjk ,detectCollisionGjk ,detectCollisionLargeTriMesh, detectCollisionDummy,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy, detectCollisionDummy},
|
||||
{detectCollisionGjk ,detectCollisionGjk ,detectCollisionGjk ,detectCollisionGjk ,detectCollisionGjk ,detectCollisionLargeTriMesh, detectCollisionDummy,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy, detectCollisionDummy},
|
||||
{detectCollisionGjk ,detectCollisionGjk ,detectCollisionGjk ,detectCollisionGjk ,detectCollisionGjk ,detectCollisionLargeTriMesh, detectCollisionDummy,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy, detectCollisionDummy},
|
||||
{detectCollisionLargeTriMesh ,detectCollisionLargeTriMesh,detectCollisionLargeTriMesh ,detectCollisionLargeTriMesh,detectCollisionLargeTriMesh ,detectCollisionDummy, detectCollisionDummy,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy, detectCollisionDummy},
|
||||
{detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy, detectCollisionDummy,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy, detectCollisionDummy},
|
||||
{detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy, detectCollisionDummy,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy, detectCollisionDummy},
|
||||
{detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy, detectCollisionDummy,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy, detectCollisionDummy},
|
||||
{detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy, detectCollisionDummy,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy, detectCollisionDummy},
|
||||
{detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy, detectCollisionDummy,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy, detectCollisionDummy},
|
||||
{detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy, detectCollisionDummy,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy ,detectCollisionDummy, detectCollisionDummy},
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Collision Detection Function Table Interface
|
||||
|
||||
pfx_detect_collision_func pfxGetDetectCollisionFunc(PfxUInt8 shapeTypeA,PfxUInt8 shapeTypeB)
|
||||
{
|
||||
SCE_PFX_ASSERT(shapeTypeA<kPfxShapeCount);
|
||||
SCE_PFX_ASSERT(shapeTypeB<kPfxShapeCount);
|
||||
return funcTbl_detectCollision[shapeTypeA][shapeTypeB];
|
||||
}
|
||||
|
||||
int pfxSetDetectCollisionFunc(PfxUInt8 shapeTypeA,PfxUInt8 shapeTypeB,pfx_detect_collision_func func)
|
||||
{
|
||||
if(shapeTypeA >= kPfxShapeCount || shapeTypeB >= kPfxShapeCount) {
|
||||
return SCE_PFX_ERR_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
funcTbl_detectCollision[shapeTypeA][shapeTypeB] = func;
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#ifndef _SCE_PFX_DETECT_COLLISION_FUNC_H
|
||||
#define _SCE_PFX_DETECT_COLLISION_FUNC_H
|
||||
|
||||
#include "../../base_level/collision/pfx_contact_cache.h"
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
typedef void (*pfx_detect_collision_func)(
|
||||
PfxContactCache &contacts,
|
||||
const PfxShape & shapeA,const PfxTransform3 &offsetTransformA,const PfxTransform3 &worldTransformA,int shapeIdA,
|
||||
const PfxShape & shapeB,const PfxTransform3 &offsetTransformB,const PfxTransform3 &worldTransformB,int shapeIdB,
|
||||
float contactThreshold);
|
||||
|
||||
pfx_detect_collision_func pfxGetDetectCollisionFunc(PfxUInt8 shapeTypeA,PfxUInt8 shapeTypeB);
|
||||
|
||||
int pfxSetDetectCollisionFunc(PfxUInt8 shapeTypeA,PfxUInt8 shapeTypeB,pfx_detect_collision_func func);
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
#endif // _SCE_PFX_DETECT_COLLISION_FUNC_H
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#include "../../../include/physics_effects/base_level/collision/pfx_shape.h"
|
||||
#include "../../base_level/collision/pfx_intersect_ray_box.h"
|
||||
#include "../../base_level/collision/pfx_intersect_ray_sphere.h"
|
||||
#include "../../base_level/collision/pfx_intersect_ray_capsule.h"
|
||||
#include "../../base_level/collision/pfx_intersect_ray_cylinder.h"
|
||||
#include "../../base_level/collision/pfx_intersect_ray_convex.h"
|
||||
#include "../../base_level/collision/pfx_intersect_ray_large_tri_mesh.h"
|
||||
#include "pfx_intersect_ray_func.h"
|
||||
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Ray Intersection Function Table
|
||||
|
||||
PfxBool intersectRayFuncDummy(
|
||||
const PfxRayInput &ray,PfxRayOutput &out,
|
||||
const PfxShape &shape,const PfxTransform3 &transform)
|
||||
{
|
||||
(void)ray,(void)out,(void)shape,(void)transform;
|
||||
return false;
|
||||
}
|
||||
|
||||
PfxBool intersectRayFuncBox(
|
||||
const PfxRayInput &ray,PfxRayOutput &out,
|
||||
const PfxShape &shape,const PfxTransform3 &transform)
|
||||
{
|
||||
return pfxIntersectRayBox(ray,out,shape.getBox(),transform);
|
||||
}
|
||||
|
||||
PfxBool intersectRayFuncSphere(
|
||||
const PfxRayInput &ray,PfxRayOutput &out,
|
||||
const PfxShape &shape,const PfxTransform3 &transform)
|
||||
{
|
||||
return pfxIntersectRaySphere(ray,out,shape.getSphere(),transform);
|
||||
}
|
||||
|
||||
PfxBool intersectRayFuncCapsule(
|
||||
const PfxRayInput &ray,PfxRayOutput &out,
|
||||
const PfxShape &shape,const PfxTransform3 &transform)
|
||||
{
|
||||
return pfxIntersectRayCapsule(ray,out,shape.getCapsule(),transform);
|
||||
}
|
||||
|
||||
PfxBool intersectRayFuncCylinder(
|
||||
const PfxRayInput &ray,PfxRayOutput &out,
|
||||
const PfxShape &shape,const PfxTransform3 &transform)
|
||||
{
|
||||
return pfxIntersectRayCylinder(ray,out,shape.getCylinder(),transform);
|
||||
}
|
||||
|
||||
PfxBool intersectRayFuncConvex(
|
||||
const PfxRayInput &ray,PfxRayOutput &out,
|
||||
const PfxShape &shape,const PfxTransform3 &transform)
|
||||
{
|
||||
const PfxConvexMesh *convex = shape.getConvexMesh();
|
||||
|
||||
PfxBool ret = pfxIntersectRayConvex(ray,out,(const void*)convex,transform);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
PfxBool intersectRayFuncLargeTriMesh(
|
||||
const PfxRayInput &ray,PfxRayOutput &out,
|
||||
const PfxShape &shape,const PfxTransform3 &transform)
|
||||
{
|
||||
const PfxLargeTriMesh *lmesh = shape.getLargeTriMesh();
|
||||
|
||||
PfxBool ret = pfxIntersectRayLargeTriMesh(ray,out,(const void*)lmesh,transform);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
PfxIntersectRayFunc funcTbl_intersectRay[kPfxShapeCount] = {
|
||||
intersectRayFuncSphere,
|
||||
intersectRayFuncBox,
|
||||
intersectRayFuncCapsule,
|
||||
intersectRayFuncCylinder,
|
||||
intersectRayFuncConvex,
|
||||
intersectRayFuncLargeTriMesh,
|
||||
intersectRayFuncDummy,
|
||||
intersectRayFuncDummy,
|
||||
intersectRayFuncDummy,
|
||||
intersectRayFuncDummy,
|
||||
intersectRayFuncDummy,
|
||||
intersectRayFuncDummy,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Ray Intersection Function Table Interface
|
||||
|
||||
PfxIntersectRayFunc pfxGetIntersectRayFunc(PfxUInt8 shapeType)
|
||||
{
|
||||
return funcTbl_intersectRay[shapeType];
|
||||
}
|
||||
|
||||
PfxInt32 pfxSetIntersectRayFunc(PfxUInt8 shapeType,PfxIntersectRayFunc func)
|
||||
{
|
||||
if(shapeType >= kPfxShapeCount) {
|
||||
return SCE_PFX_ERR_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
funcTbl_intersectRay[shapeType] = func;
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#ifndef _SCE_PFX_INTERSECT_RAY_FUNC_H
|
||||
#define _SCE_PFX_INTERSECT_RAY_FUNC_H
|
||||
|
||||
#include "../../../include/physics_effects/base_level/collision/pfx_ray.h"
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
typedef PfxBool (*PfxIntersectRayFunc)(
|
||||
const PfxRayInput &ray,PfxRayOutput &out,
|
||||
const PfxShape &shape,const PfxTransform3 &transform);
|
||||
|
||||
PfxIntersectRayFunc pfxGetIntersectRayFunc(PfxUInt8 shapeType);
|
||||
|
||||
PfxInt32 pfxSetIntersectRayFunc(PfxUInt8 shapeType,PfxIntersectRayFunc func);
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
|
||||
#endif /* _SCE_PFX_INTERSECT_RAY_FUNC_H */
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#include "../../../include/physics_effects/base_level/rigidbody/pfx_rigid_state.h"
|
||||
#include "../../../include/physics_effects/low_level/collision/pfx_island_generation.h"
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
struct PfxIslandNode {
|
||||
PfxUInt32 rootId;
|
||||
PfxUInt32 rank;
|
||||
PfxUInt32 islandId;
|
||||
PfxUInt32 isRoot;
|
||||
};
|
||||
|
||||
struct PfxIslandUnit
|
||||
{
|
||||
PfxUInt32 id;
|
||||
PfxIslandUnit *next;
|
||||
};
|
||||
|
||||
struct PfxIsland
|
||||
{
|
||||
PfxUInt32 numNodes;
|
||||
PfxUInt32 numIslands;
|
||||
PfxIslandNode *nodes;
|
||||
PfxIslandUnit *islandsUnits;
|
||||
PfxIslandUnit **islandsHeads;
|
||||
};
|
||||
|
||||
PfxUInt32 pfxIslandNodeFind(PfxUInt32 i,PfxIsland *island)
|
||||
{
|
||||
if( i != island->nodes[i].rootId ) {
|
||||
island->nodes[i].rootId = pfxIslandNodeFind(island->nodes[i].rootId,island);
|
||||
}
|
||||
return island->nodes[i].rootId;
|
||||
}
|
||||
|
||||
void pfxIslandNodeLink(PfxUInt32 iA,PfxUInt32 iB,PfxIsland *island)
|
||||
{
|
||||
if(island->nodes[iA].rank > island->nodes[iB].rank) {
|
||||
island->nodes[iB].rootId = iA;
|
||||
}
|
||||
else if(island->nodes[iA].rank == island->nodes[iB].rank) {
|
||||
island->nodes[iA].rootId = iB;
|
||||
island->nodes[iB].rank++;
|
||||
}
|
||||
else {
|
||||
island->nodes[iA].rootId = iB;
|
||||
}
|
||||
}
|
||||
|
||||
void pfxIslandNodeUnion(PfxUInt32 iA,PfxUInt32 iB,PfxIsland *island)
|
||||
{
|
||||
SCE_PFX_ALWAYS_ASSERT(iA<island->numNodes);
|
||||
SCE_PFX_ALWAYS_ASSERT(iB<island->numNodes);
|
||||
|
||||
pfxIslandNodeLink(pfxIslandNodeFind(iA,island),pfxIslandNodeFind(iB,island),island);
|
||||
}
|
||||
|
||||
PfxUInt32 pfxGetIslandBytesOfGenerateIsland(PfxUInt32 numObjects)
|
||||
{
|
||||
return 16 +
|
||||
SCE_PFX_ALLOC_BYTES_ALIGN16(sizeof(PfxIsland)) +
|
||||
SCE_PFX_ALLOC_BYTES_ALIGN16(sizeof(PfxIslandNode)*numObjects) +
|
||||
SCE_PFX_ALLOC_BYTES_ALIGN16(sizeof(PfxIslandUnit*)*numObjects) +
|
||||
SCE_PFX_ALLOC_BYTES_ALIGN16(sizeof(PfxIslandUnit)*numObjects);
|
||||
}
|
||||
|
||||
SCE_PFX_FORCE_INLINE int pfxCheckParamOfGenerateIsland(const PfxGenerateIslandParam ¶m)
|
||||
{
|
||||
if(!param.islandBuff || !param.pairs) return SCE_PFX_ERR_INVALID_VALUE;
|
||||
if(!SCE_PFX_PTR_IS_ALIGNED16(param.pairs)) return SCE_PFX_ERR_INVALID_ALIGN;
|
||||
if(SCE_PFX_AVAILABLE_BYTES_ALIGN16(param.islandBuff,param.islandBytes) < pfxGetIslandBytesOfGenerateIsland(param.numObjects) ) return SCE_PFX_ERR_OUT_OF_BUFFER;
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
PfxInt32 pfxGenerateIsland(PfxGenerateIslandParam ¶m,PfxGenerateIslandResult &result)
|
||||
{
|
||||
int ret = pfxCheckParamOfGenerateIsland(param);
|
||||
if(ret != SCE_PFX_OK) return ret;
|
||||
|
||||
PfxConstraintPair *pairs = param.pairs;
|
||||
PfxUInt32 numPairs = param.numPairs;
|
||||
PfxUInt32 numUnits = param.numObjects;
|
||||
|
||||
memset(param.islandBuff,0,param.islandBytes);
|
||||
|
||||
PfxHeapManager pool((unsigned char*)param.islandBuff,param.islandBytes);
|
||||
|
||||
PfxIsland *island = (PfxIsland*)pool.allocate(sizeof(PfxIsland));
|
||||
island->numIslands = 0;
|
||||
island->numNodes = numUnits;
|
||||
island->nodes = (PfxIslandNode*)pool.allocate(sizeof(PfxIslandNode)*numUnits);
|
||||
island->islandsHeads = (PfxIslandUnit**)pool.allocate(sizeof(PfxIslandUnit*)*numUnits);
|
||||
island->islandsUnits = (PfxIslandUnit*)pool.allocate(sizeof(PfxIslandUnit)*numUnits);
|
||||
|
||||
result.island = island;
|
||||
|
||||
// 初期化
|
||||
for(PfxUInt32 i=0;i<island->numNodes;i++) {
|
||||
island->nodes[i].rootId = i;
|
||||
island->nodes[i].rank = 0;
|
||||
}
|
||||
|
||||
return pfxAppendPairs(island,pairs,numPairs);
|
||||
}
|
||||
|
||||
PfxUInt32 pfxGetNumIslands(const PfxIsland *islands)
|
||||
{
|
||||
SCE_PFX_ALWAYS_ASSERT(islands);
|
||||
return islands->numIslands;
|
||||
}
|
||||
|
||||
PfxIslandUnit *pfxGetFirstUnitInIsland(const PfxIsland *islands,PfxUInt32 islandId)
|
||||
{
|
||||
SCE_PFX_ALWAYS_ASSERT(islands);
|
||||
SCE_PFX_ALWAYS_ASSERT(islandId < islands->numIslands);
|
||||
return islands->islandsHeads[islandId];
|
||||
}
|
||||
|
||||
PfxIslandUnit *pfxGetNextUnitInIsland(const PfxIslandUnit *islandUnit)
|
||||
{
|
||||
SCE_PFX_ALWAYS_ASSERT(islandUnit);
|
||||
return islandUnit->next;
|
||||
}
|
||||
|
||||
PfxUInt32 pfxGetUnitId(const PfxIslandUnit *islandUnit)
|
||||
{
|
||||
SCE_PFX_ALWAYS_ASSERT(islandUnit);
|
||||
return islandUnit->id;
|
||||
}
|
||||
|
||||
PfxUInt32 pfxGetIslandId(const PfxIsland *islands,PfxUInt32 unitId)
|
||||
{
|
||||
SCE_PFX_ALWAYS_ASSERT(islands&&unitId<islands->numNodes);
|
||||
return islands->nodes[unitId].islandId;
|
||||
}
|
||||
|
||||
PfxInt32 pfxAppendPairs(PfxIsland *island,PfxConstraintPair *pairs,PfxUInt32 numPairs)
|
||||
{
|
||||
if(numPairs == 0) {
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
if(!island || !pairs) return SCE_PFX_ERR_INVALID_VALUE;
|
||||
if(!SCE_PFX_PTR_IS_ALIGNED16(island) || !SCE_PFX_PTR_IS_ALIGNED16(pairs)) return SCE_PFX_ERR_INVALID_ALIGN;
|
||||
|
||||
// 統合
|
||||
for(PfxUInt32 i=0;i<numPairs;i++) {
|
||||
PfxConstraintPair &pair = pairs[i];
|
||||
if(pfxGetActive(pair)) {
|
||||
PfxUInt32 iA = pfxGetObjectIdA(pair);
|
||||
PfxUInt32 iB = pfxGetObjectIdB(pair);
|
||||
|
||||
SCE_PFX_ALWAYS_ASSERT(iA<island->numNodes);
|
||||
SCE_PFX_ALWAYS_ASSERT(iB<island->numNodes);
|
||||
|
||||
if( (SCE_PFX_MOTION_MASK_DYNAMIC(pfxGetMotionMaskA(pair)&SCE_PFX_MOTION_MASK_TYPE)) &&
|
||||
(SCE_PFX_MOTION_MASK_DYNAMIC(pfxGetMotionMaskB(pair)&SCE_PFX_MOTION_MASK_TYPE)) ) {
|
||||
pfxIslandNodeUnion(iA,iB,island);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// アイランド生成のための初期化
|
||||
for(PfxUInt32 i=0;i<island->numNodes;i++) {
|
||||
island->nodes[i].islandId = 0;
|
||||
island->nodes[i].isRoot = 0;
|
||||
island->islandsHeads[i] = NULL;
|
||||
}
|
||||
|
||||
// 親へ直結
|
||||
PfxUInt32 id = 0;
|
||||
for(PfxUInt32 i=0;i<island->numNodes;i++) {
|
||||
PfxUInt32 rootId = pfxIslandNodeFind(i,island);
|
||||
if( island->nodes[rootId].isRoot == 0 ) {
|
||||
island->nodes[rootId].islandId = id++;
|
||||
island->nodes[rootId].isRoot = 1;
|
||||
}
|
||||
island->nodes[i].islandId = island->nodes[rootId].islandId;
|
||||
}
|
||||
|
||||
// アイランド作成
|
||||
PfxUInt32 n = 0;
|
||||
for(PfxUInt32 i=0;i<island->numNodes;i++) {
|
||||
PfxUInt32 islandId = island->nodes[i].islandId;
|
||||
PfxIslandUnit *newUnit = &island->islandsUnits[n++];
|
||||
newUnit->id = i;
|
||||
|
||||
if(!island->islandsHeads[islandId]) {
|
||||
island->islandsHeads[islandId] = newUnit;
|
||||
continue;
|
||||
}
|
||||
|
||||
PfxIslandUnit *unit=island->islandsHeads[islandId];
|
||||
island->islandsHeads[islandId] = newUnit;
|
||||
newUnit->next = unit;
|
||||
}
|
||||
|
||||
island->numIslands = id;
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
void pfxResetIsland(PfxIsland *island)
|
||||
{
|
||||
SCE_PFX_ALWAYS_ASSERT(island);
|
||||
island->numIslands = 0;
|
||||
for(PfxUInt32 i=0;i<island->numNodes;i++) {
|
||||
island->nodes[i].rootId = i;
|
||||
island->nodes[i].rank = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
228
Extras/PhysicsEffects/src/low_level/collision/pfx_ray_cast.cpp
Normal file
228
Extras/PhysicsEffects/src/low_level/collision/pfx_ray_cast.cpp
Normal file
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#include "../../../include/physics_effects/base_level/base/pfx_vec_utils.h"
|
||||
#include "../../../include/physics_effects/low_level/collision/pfx_ray_cast.h"
|
||||
#include "../../../include/physics_effects/base_level/collision/pfx_shape_iterator.h"
|
||||
#include "pfx_intersect_ray_func.h"
|
||||
#include "../../base_level/collision/pfx_intersect_common.h"
|
||||
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
|
||||
void pfxRayTraverseForward(
|
||||
const PfxRayInput &ray,PfxRayOutput &out,const PfxAabb16 &rayAABB,
|
||||
PfxBroadphaseProxy *proxies,int numProxies,
|
||||
PfxRigidState *offsetRigidStates,
|
||||
PfxCollidable *offsetCollidables,
|
||||
int axis,const PfxVector3 ¢er,const PfxVector3 &half)
|
||||
{
|
||||
#ifdef SCE_PFX_USE_GEOMETRY
|
||||
PfxGeomSegment segment((PfxPoint3)ray.m_startPosition,ray.m_direction);
|
||||
#endif
|
||||
|
||||
for(int i=0;i<numProxies;i++) {
|
||||
PfxBroadphaseProxy &proxy = proxies[i];
|
||||
|
||||
// 終了条件のチェック
|
||||
if(pfxGetXYZMax(rayAABB,axis) < pfxGetXYZMin(proxy,axis)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PfxVector3 boundOnRay = ray.m_startPosition + out.m_variable * ray.m_direction;
|
||||
PfxVector3 AABBmin = pfxConvertCoordLocalToWorld(PfxVecInt3((PfxInt32)pfxGetXMin(proxy),(PfxInt32)pfxGetYMin(proxy),(PfxInt32)pfxGetZMin(proxy)),center,half);
|
||||
PfxVector3 AABBmax = pfxConvertCoordLocalToWorld(PfxVecInt3((PfxInt32)pfxGetXMax(proxy),(PfxInt32)pfxGetYMax(proxy),(PfxInt32)pfxGetZMax(proxy)),center,half);
|
||||
|
||||
if(boundOnRay[axis] < AABBmin[axis]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// スキップ
|
||||
if(pfxGetXYZMax(proxy,axis) < pfxGetXYZMin(rayAABB,axis)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PfxUInt16 rigidbodyId = pfxGetObjectId(proxy);
|
||||
PfxUInt32 contactFilterSelf = pfxGetSelf(proxy);
|
||||
PfxUInt32 contactFilterTarget = pfxGetTarget(proxy);
|
||||
|
||||
#ifdef SCE_PFX_USE_GEOMETRY
|
||||
PfxFloatInVec t_(1.0f);
|
||||
PfxGeomAabb aabb((PfxPoint3)AABBmin,(PfxPoint3)AABBmax);
|
||||
if( (ray.m_contactFilterSelf&contactFilterTarget) && (ray.m_contactFilterTarget&contactFilterSelf) && pfxTestAabb(rayAABB,proxy) &&
|
||||
intersectionPoint(segment,aabb,&t_) && t_ < out.m_variable ) {
|
||||
#else
|
||||
float t_=1.0f;
|
||||
if( (ray.m_contactFilterSelf&contactFilterTarget) && (ray.m_contactFilterTarget&contactFilterSelf) && pfxTestAabb(rayAABB,proxy) &&
|
||||
pfxIntersectRayAABBFast(ray.m_startPosition,ray.m_direction,(AABBmax+AABBmin)*0.5f,(AABBmax-AABBmin)*0.5f,t_) && t_ < out.m_variable ) {
|
||||
#endif
|
||||
|
||||
PfxRigidState &state = offsetRigidStates[rigidbodyId];
|
||||
PfxCollidable &coll = offsetCollidables[rigidbodyId];
|
||||
PfxTransform3 transform(state.getOrientation(), state.getPosition());
|
||||
|
||||
PfxRayOutput tout = out;
|
||||
|
||||
PfxShapeIterator itrShape(coll);
|
||||
for(PfxUInt32 j=0;j<coll.getNumShapes();j++,++itrShape) {
|
||||
const PfxShape &shape = *itrShape;
|
||||
PfxTransform3 shapeTr = transform * shape.getOffsetTransform();
|
||||
|
||||
if(pfxGetIntersectRayFunc(shape.getType())(ray,tout,shape,shapeTr) && tout.m_variable < out.m_variable) {
|
||||
out = tout;
|
||||
out.m_shapeId = j;
|
||||
out.m_objectId = rigidbodyId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pfxRayTraverseBackward(
|
||||
const PfxRayInput &ray,PfxRayOutput &out,const PfxAabb16 &rayAABB,
|
||||
PfxBroadphaseProxy *proxies,int numProxies,
|
||||
PfxRigidState *offsetRigidStates,
|
||||
PfxCollidable *offsetCollidables,
|
||||
int axis,const PfxVector3 ¢er,const PfxVector3 &half)
|
||||
{
|
||||
#ifdef SCE_PFX_USE_GEOMETRY
|
||||
PfxGeomSegment segment((PfxPoint3)ray.m_startPosition,ray.m_direction);
|
||||
#endif
|
||||
|
||||
for(int i=numProxies-1;i>=0;i--) {
|
||||
PfxBroadphaseProxy &proxy = proxies[i];
|
||||
|
||||
// 終了条件のチェック
|
||||
if(pfxGetXYZMax(proxy,axis) < pfxGetXYZMin(rayAABB,axis)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PfxVector3 boundOnRay = ray.m_startPosition + out.m_variable * ray.m_direction;
|
||||
PfxVector3 AABBmin = pfxConvertCoordLocalToWorld(PfxVecInt3((PfxInt32)pfxGetXMin(proxy),(PfxInt32)pfxGetYMin(proxy),(PfxInt32)pfxGetZMin(proxy)),center,half);
|
||||
PfxVector3 AABBmax = pfxConvertCoordLocalToWorld(PfxVecInt3((PfxInt32)pfxGetXMax(proxy),(PfxInt32)pfxGetYMax(proxy),(PfxInt32)pfxGetZMax(proxy)),center,half);
|
||||
|
||||
if(AABBmax[axis] < boundOnRay[axis]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// スキップ
|
||||
if(pfxGetXYZMax(rayAABB,axis) < pfxGetXYZMin(proxy,axis)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PfxUInt16 rigidbodyId = pfxGetObjectId(proxy);
|
||||
PfxUInt32 contactFilterSelf = pfxGetSelf(proxy);
|
||||
PfxUInt32 contactFilterTarget = pfxGetTarget(proxy);
|
||||
|
||||
#ifdef SCE_PFX_USE_GEOMETRY
|
||||
PfxFloatInVec t_(1.0f);
|
||||
PfxGeomAabb aabb((PfxPoint3)AABBmin,(PfxPoint3)AABBmax);
|
||||
if( (ray.m_contactFilterSelf&contactFilterTarget) && (ray.m_contactFilterTarget&contactFilterSelf) && pfxTestAabb(rayAABB,proxy) &&
|
||||
intersectionPoint(segment,aabb,&t_) && t_ < out.m_variable ) {
|
||||
#else
|
||||
float t_=1.0f;
|
||||
if( (ray.m_contactFilterSelf&contactFilterTarget) && (ray.m_contactFilterTarget&contactFilterSelf) && pfxTestAabb(rayAABB,proxy) &&
|
||||
pfxIntersectRayAABBFast(ray.m_startPosition,ray.m_direction,(AABBmax+AABBmin)*0.5f,(AABBmax-AABBmin)*0.5f,t_) && t_ < out.m_variable ) {
|
||||
#endif
|
||||
|
||||
PfxRigidState &state = offsetRigidStates[rigidbodyId];
|
||||
PfxCollidable &coll = offsetCollidables[rigidbodyId];
|
||||
PfxTransform3 transform(state.getOrientation(), state.getPosition());
|
||||
|
||||
PfxRayOutput tout = out;
|
||||
|
||||
PfxShapeIterator itrShape(coll);
|
||||
for(PfxUInt32 j=0;j<coll.getNumShapes();j++,++itrShape) {
|
||||
const PfxShape &shape = *itrShape;
|
||||
PfxTransform3 shapeTr = transform * shape.getOffsetTransform();
|
||||
|
||||
if(pfxGetIntersectRayFunc(shape.getType())(ray,tout,shape,shapeTr) && tout.m_variable < out.m_variable) {
|
||||
out = tout;
|
||||
out.m_shapeId = j;
|
||||
out.m_objectId = rigidbodyId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void pfxCastSingleRay(const PfxRayInput &ray,PfxRayOutput &out,const PfxRayCastParam ¶m)
|
||||
{
|
||||
SCE_PFX_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.proxiesX));
|
||||
SCE_PFX_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.proxiesY));
|
||||
SCE_PFX_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.proxiesZ));
|
||||
SCE_PFX_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.proxiesXb));
|
||||
SCE_PFX_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.proxiesYb));
|
||||
SCE_PFX_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.proxiesZb));
|
||||
SCE_PFX_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.offsetRigidStates));
|
||||
SCE_PFX_ASSERT(SCE_PFX_PTR_IS_ALIGNED16(param.offsetCollidables));
|
||||
|
||||
PfxBroadphaseProxy *proxies[] = {
|
||||
param.proxiesX,
|
||||
param.proxiesY,
|
||||
param.proxiesZ,
|
||||
param.proxiesXb,
|
||||
param.proxiesYb,
|
||||
param.proxiesZb,
|
||||
};
|
||||
|
||||
out.m_variable = 1.0f;
|
||||
out.m_contactFlag = false;
|
||||
|
||||
// 探索軸
|
||||
PfxVector3 chkAxisVec = absPerElem(ray.m_direction);
|
||||
int axis = 0;
|
||||
if(chkAxisVec[1] < chkAxisVec[0]) axis = 1;
|
||||
if(chkAxisVec[2] < chkAxisVec[axis]) axis = 2;
|
||||
|
||||
// レイのAABB作成
|
||||
PfxVector3 p1 = ray.m_startPosition;
|
||||
PfxVector3 p2 = ray.m_startPosition + ray.m_direction;
|
||||
PfxVecInt3 rayMin,rayMax;
|
||||
pfxConvertCoordWorldToLocal(param.rangeCenter,param.rangeExtent,minPerElem(p1,p2),maxPerElem(p1,p2),rayMin,rayMax);
|
||||
|
||||
PfxAabb16 rayAABB;
|
||||
pfxSetXMin(rayAABB,rayMin.getX());
|
||||
pfxSetXMax(rayAABB,rayMax.getX());
|
||||
pfxSetYMin(rayAABB,rayMin.getY());
|
||||
pfxSetYMax(rayAABB,rayMax.getY());
|
||||
pfxSetZMin(rayAABB,rayMin.getZ());
|
||||
pfxSetZMax(rayAABB,rayMax.getZ());
|
||||
|
||||
// AABB探索開始
|
||||
int sign = ray.m_direction[axis] < 0.0f ? -1 : 1; // 探索方向
|
||||
|
||||
if(sign > 0) {
|
||||
pfxRayTraverseForward(
|
||||
ray,out,rayAABB,
|
||||
proxies[axis],param.numProxies,
|
||||
param.offsetRigidStates,param.offsetCollidables,
|
||||
axis,param.rangeCenter,param.rangeExtent);
|
||||
}
|
||||
else {
|
||||
pfxRayTraverseBackward(
|
||||
ray,out,rayAABB,
|
||||
proxies[axis+3],param.numProxies,
|
||||
param.offsetRigidStates,param.offsetCollidables,
|
||||
axis,param.rangeCenter,param.rangeExtent);
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
Applied Research Associates Inc. (c)2011
|
||||
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#include "../../../include/physics_effects/base_level/base/pfx_perf_counter.h"
|
||||
#include "../../../include/physics_effects/base_level/sort/pfx_sort.h"
|
||||
#include "../../../include/physics_effects/low_level/collision/pfx_refresh_contacts.h"
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// This function is implemented in pfx_refresh_contacts_single.cpp
|
||||
extern int pfxCheckParamOfRefreshContacts(PfxRefreshContactsParam ¶m);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MULTIPLE THREADS
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// pfxRefreshContactsTaskEntry
|
||||
//
|
||||
/// The thread PfxTaskEntry function used to perform refresh contacts in
|
||||
/// parallel
|
||||
//----------------------------------------------------------------------------
|
||||
void pfxRefreshContactsTaskEntry(PfxTaskArg *arg)
|
||||
{
|
||||
PfxRefreshContactsParam ¶m = *((PfxRefreshContactsParam*)arg->io);
|
||||
|
||||
PfxUInt32 iFirstContactPair = arg->data[0];
|
||||
PfxUInt32 iEndContactPair = arg->data[1];
|
||||
|
||||
PfxConstraintPair *contactPairs = param.contactPairs;
|
||||
PfxContactManifold *offsetContactManifolds = param.offsetContactManifolds;
|
||||
PfxRigidState *offsetRigidStates = param.offsetRigidStates;
|
||||
PfxUInt32 numRigidBodies = param.numRigidBodies;
|
||||
|
||||
for(PfxUInt32 i = iFirstContactPair; i < iEndContactPair; i++)
|
||||
{
|
||||
PfxBroadphasePair &pair = contactPairs[i];
|
||||
|
||||
PfxUInt32 iContact = pfxGetContactId(pair);
|
||||
PfxUInt32 iA = pfxGetObjectIdA(pair);
|
||||
PfxUInt32 iB = pfxGetObjectIdB(pair);
|
||||
|
||||
PfxContactManifold &contact = offsetContactManifolds[iContact];
|
||||
|
||||
SCE_PFX_ALWAYS_ASSERT(iA==contact.getRigidBodyIdA());
|
||||
SCE_PFX_ALWAYS_ASSERT(iB==contact.getRigidBodyIdB());
|
||||
|
||||
PfxRigidState &instA = offsetRigidStates[iA];
|
||||
PfxRigidState &instB = offsetRigidStates[iB];
|
||||
|
||||
contact.refresh(
|
||||
instA.getPosition(),instA.getOrientation(),
|
||||
instB.getPosition(),instB.getOrientation() );
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// pfxRefreshContacts
|
||||
//
|
||||
/// Perform refresh contacts in parallel using a task manager.
|
||||
///
|
||||
/// @param param Information about contact pairs
|
||||
/// @param taskManager Pointer to the thread task manager to use
|
||||
///
|
||||
/// @return SCE_PFX_OK if successful, otherwise, returns an error code.
|
||||
//----------------------------------------------------------------------------
|
||||
PfxInt32 pfxRefreshContacts(PfxRefreshContactsParam ¶m, PfxTaskManager *taskManager)
|
||||
{
|
||||
PfxInt32 ret = pfxCheckParamOfRefreshContacts(param);
|
||||
if(ret != SCE_PFX_OK) return ret;
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxRefreshContacts");
|
||||
|
||||
PfxUInt32 maxBatchSize = param.numContactPairs / (PfxUInt32)(taskManager->getNumTasks());
|
||||
PfxUInt32 iEnd = maxBatchSize, iStart = 0;
|
||||
int task = 0;
|
||||
taskManager->setTaskEntry((void*)pfxRefreshContactsTaskEntry);
|
||||
|
||||
for (task = 0; task < taskManager->getNumTasks() - 1; task++, iStart += maxBatchSize, iEnd += maxBatchSize)
|
||||
{
|
||||
taskManager->startTask(task, static_cast<void*>(¶m), iStart, iEnd, 0, 0);
|
||||
}
|
||||
|
||||
// send final task
|
||||
iEnd = param.numContactPairs;
|
||||
taskManager->startTask(taskManager->getNumTasks() - 1, static_cast<void*>(¶m), iStart, iEnd, 0, 0);
|
||||
|
||||
// wait for tasks to complete
|
||||
PfxUInt32 data1, data2, data3, data4;
|
||||
for (PfxUInt32 i = 0; i < taskManager->getNumTasks(); i++)
|
||||
taskManager->waitTask(task, data1, data2, data3, data4);
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#include "../../../include/physics_effects/base_level/base/pfx_perf_counter.h"
|
||||
#include "../../../include/physics_effects/base_level/sort/pfx_sort.h"
|
||||
#include "../../../include/physics_effects/low_level/collision/pfx_refresh_contacts.h"
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
int pfxCheckParamOfRefreshContacts(PfxRefreshContactsParam ¶m)
|
||||
{
|
||||
if(!param.contactPairs || !param.offsetContactManifolds || !param.offsetRigidStates ) return SCE_PFX_ERR_INVALID_VALUE;
|
||||
if(!SCE_PFX_PTR_IS_ALIGNED16(param.contactPairs) || !SCE_PFX_PTR_IS_ALIGNED16(param.offsetContactManifolds) ||
|
||||
!SCE_PFX_PTR_IS_ALIGNED16(param.offsetRigidStates)) return SCE_PFX_ERR_INVALID_ALIGN;
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SINGLE THREAD
|
||||
|
||||
PfxInt32 pfxRefreshContacts(PfxRefreshContactsParam ¶m)
|
||||
{
|
||||
PfxInt32 ret = pfxCheckParamOfRefreshContacts(param);
|
||||
if(ret != SCE_PFX_OK) return ret;
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxRefreshContacts");
|
||||
|
||||
PfxConstraintPair *contactPairs = param.contactPairs;
|
||||
PfxUInt32 numContactPairs = param.numContactPairs;
|
||||
PfxContactManifold *offsetContactManifolds = param.offsetContactManifolds;
|
||||
PfxRigidState *offsetRigidStates = param.offsetRigidStates;
|
||||
PfxUInt32 numRigidBodies = param.numRigidBodies;
|
||||
|
||||
for(PfxUInt32 i=0;i<numContactPairs;i++) {
|
||||
PfxBroadphasePair &pair = contactPairs[i];
|
||||
|
||||
PfxUInt32 iContact = pfxGetContactId(pair);
|
||||
PfxUInt32 iA = pfxGetObjectIdA(pair);
|
||||
PfxUInt32 iB = pfxGetObjectIdB(pair);
|
||||
|
||||
PfxContactManifold &contact = offsetContactManifolds[iContact];
|
||||
|
||||
SCE_PFX_ALWAYS_ASSERT(iA==contact.getRigidBodyIdA());
|
||||
SCE_PFX_ALWAYS_ASSERT(iB==contact.getRigidBodyIdB());
|
||||
|
||||
PfxRigidState &instA = offsetRigidStates[iA];
|
||||
PfxRigidState &instB = offsetRigidStates[iB];
|
||||
|
||||
contact.refresh(
|
||||
instA.getPosition(),instA.getOrientation(),
|
||||
instB.getPosition(),instB.getOrientation() );
|
||||
}
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
|
||||
(void) numRigidBodies;
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
12
Extras/PhysicsEffects/src/low_level/premake4.lua
Normal file
12
Extras/PhysicsEffects/src/low_level/premake4.lua
Normal file
@@ -0,0 +1,12 @@
|
||||
project "physicseffects2_lowlevel"
|
||||
|
||||
kind "StaticLib"
|
||||
targetdir "../../build/lib"
|
||||
includedirs {
|
||||
".",
|
||||
}
|
||||
files {
|
||||
"**.cpp",
|
||||
"../../include/physics_effects/low_level/**.h"
|
||||
|
||||
}
|
||||
@@ -0,0 +1,795 @@
|
||||
/*
|
||||
Applied Research Associates Inc. (c)2011
|
||||
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#include "../../../include/physics_effects/base_level/base/pfx_perf_counter.h"
|
||||
#include "../../../include/physics_effects/base_level/solver/pfx_contact_constraint.h"
|
||||
#include "../../../include/physics_effects/low_level/solver/pfx_joint_constraint_func.h"
|
||||
#include "../../../include/physics_effects/low_level/solver/pfx_constraint_solver.h"
|
||||
#include "../../base_level/solver/pfx_check_solver.h"
|
||||
#include "pfx_parallel_group.h"
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// These functions are implemented in pfx_constraint_solver_single.cpp
|
||||
extern PfxUInt32 pfxGetWorkBytesOfSolveConstraints(PfxUInt32 numRigidBodies,PfxUInt32 numContactPairs,PfxUInt32 numJointPairs,PfxUInt32 maxTasks);
|
||||
extern PfxInt32 pfxCheckParamOfSetupSolverBodies(const PfxSetupSolverBodiesParam ¶m);
|
||||
extern PfxInt32 pfxCheckParamOfSetupContactConstraints(const PfxSetupContactConstraintsParam ¶m);
|
||||
extern PfxInt32 pfxCheckParamOfSetupJointConstraints(const PfxSetupJointConstraintsParam ¶m);
|
||||
extern PfxInt32 pfxCheckParamOfSolveConstraints(const PfxSolveConstraintsParam ¶m);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// pfxCheckParamOfSolveConstraints
|
||||
//
|
||||
/// This function verifies that the input parameter for solving constraints
|
||||
/// in parallel is good.
|
||||
//----------------------------------------------------------------------------
|
||||
PfxInt32 pfxCheckParamOfSolveConstraints(const PfxSolveConstraintsParam ¶m,
|
||||
PfxTaskManager *taskManager)
|
||||
{
|
||||
if((param.numContactPairs>0&&(!param.contactPairs||!param.offsetContactManifolds)) ||
|
||||
(param.numJointPairs>0&&(!param.jointPairs||!param.offsetJoints)) || !param.offsetRigidStates || !param.offsetSolverBodies) return SCE_PFX_ERR_INVALID_VALUE;
|
||||
if(!SCE_PFX_PTR_IS_ALIGNED16(param.contactPairs) || !SCE_PFX_PTR_IS_ALIGNED16(param.offsetContactManifolds) ||
|
||||
!SCE_PFX_PTR_IS_ALIGNED16(param.jointPairs) || !SCE_PFX_PTR_IS_ALIGNED16(param.offsetJoints) || !SCE_PFX_PTR_IS_ALIGNED16(param.offsetRigidStates) ||
|
||||
!SCE_PFX_PTR_IS_ALIGNED16(param.offsetSolverBodies)) return SCE_PFX_ERR_INVALID_ALIGN;
|
||||
if(SCE_PFX_AVAILABLE_BYTES_ALIGN16(param.workBuff,param.workBytes) < pfxGetWorkBytesOfSolveConstraints(param.numRigidBodies,param.numContactPairs,param.numJointPairs, taskManager->getNumTasks()) ) return SCE_PFX_ERR_OUT_OF_BUFFER;
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MULTIPLE THREADS
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// pfxSetupSolverBodiesTaskEntry
|
||||
//
|
||||
/// The thread PfxTaskEntry function used to setup solver bodies in parallel.
|
||||
//----------------------------------------------------------------------------
|
||||
void pfxSetupSolverBodiesTaskEntry(PfxTaskArg *arg)
|
||||
{
|
||||
PfxSetupSolverBodiesParam ¶m = *((PfxSetupSolverBodiesParam*)arg->io);
|
||||
|
||||
PfxUInt32 iFirstBody = arg->data[0];
|
||||
PfxUInt32 iEndBody = arg->data[1];
|
||||
|
||||
PfxRigidState *states = param.states;
|
||||
PfxRigidBody *bodies = param.bodies;
|
||||
PfxSolverBody *solverBodies = param.solverBodies;
|
||||
|
||||
for(PfxUInt32 i = iFirstBody; i < iEndBody; i++)
|
||||
{
|
||||
PfxRigidState &state = states[i];
|
||||
PfxRigidBody &body = bodies[i];
|
||||
PfxSolverBody &solverBody = solverBodies[i];
|
||||
|
||||
solverBody.m_orientation = state.getOrientation();
|
||||
solverBody.m_deltaLinearVelocity = PfxVector3(0.0f);
|
||||
solverBody.m_deltaAngularVelocity = PfxVector3(0.0f);
|
||||
solverBody.m_motionType = state.getMotionMask();
|
||||
|
||||
if(SCE_PFX_MOTION_MASK_DYNAMIC(state.getMotionType())) {
|
||||
PfxMatrix3 ori(solverBody.m_orientation);
|
||||
solverBody.m_massInv = body.getMassInv();
|
||||
solverBody.m_inertiaInv = ori * body.getInertiaInv() * transpose(ori);
|
||||
}
|
||||
else {
|
||||
solverBody.m_massInv = 0.0f;
|
||||
solverBody.m_inertiaInv = PfxMatrix3(0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// pfxSetupSolverBodies
|
||||
//
|
||||
/// Perform setup solver bodies in parallel using a task manager.
|
||||
///
|
||||
/// @param param Information about rigid bodies
|
||||
/// @param taskManager Pointer to the thread task manager to use
|
||||
///
|
||||
/// @return SCE_PFX_OK if successful, otherwise, returns an error code.
|
||||
//----------------------------------------------------------------------------
|
||||
PfxInt32 pfxSetupSolverBodies(PfxSetupSolverBodiesParam ¶m,
|
||||
PfxTaskManager *taskManager)
|
||||
{
|
||||
PfxInt32 ret = pfxCheckParamOfSetupSolverBodies(param);
|
||||
if(ret != SCE_PFX_OK) return ret;
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxSetupSolverBodies");
|
||||
|
||||
PfxUInt32 maxBatchSize = param.numRigidBodies / (PfxUInt32)(taskManager->getNumTasks());
|
||||
PfxUInt32 iEnd = maxBatchSize, iStart = 0;
|
||||
int task = 0;
|
||||
taskManager->setTaskEntry((void*)pfxSetupSolverBodiesTaskEntry);
|
||||
|
||||
for (task = 0; task < taskManager->getNumTasks() - 1; task++, iStart += maxBatchSize, iEnd += maxBatchSize)
|
||||
{
|
||||
taskManager->startTask(task, static_cast<void*>(¶m), iStart, iEnd, 0, 0);
|
||||
}
|
||||
|
||||
// send final task
|
||||
iEnd = param.numRigidBodies;
|
||||
taskManager->startTask(taskManager->getNumTasks() - 1, static_cast<void*>(¶m), iStart, iEnd, 0, 0);
|
||||
|
||||
// wait for tasks to complete
|
||||
PfxUInt32 data1, data2, data3, data4;
|
||||
for (PfxUInt32 i = 0; i < taskManager->getNumTasks(); i++)
|
||||
taskManager->waitTask(task, data1, data2, data3, data4);
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// pfxSetupContactConstraintsTaskEntry
|
||||
//
|
||||
/// The thread PfxTaskEntry function used to setup contact constraints in
|
||||
/// parallel.
|
||||
//----------------------------------------------------------------------------
|
||||
void pfxSetupContactConstraintsTaskEntry(PfxTaskArg *arg)
|
||||
{
|
||||
PfxSetupContactConstraintsParam ¶m = *((PfxSetupContactConstraintsParam*)arg->io);
|
||||
|
||||
PfxUInt32 iFirstContactPair = arg->data[0];
|
||||
PfxUInt32 iEndContactPair = arg->data[1];
|
||||
|
||||
PfxConstraintPair *contactPairs = param.contactPairs;
|
||||
PfxUInt32 numContactPairs = param.numContactPairs;
|
||||
PfxContactManifold *offsetContactManifolds = param.offsetContactManifolds;
|
||||
PfxRigidState *offsetRigidStates = param.offsetRigidStates;
|
||||
PfxRigidBody *offsetRigidBodies = param.offsetRigidBodies;
|
||||
PfxSolverBody *offsetSolverBodies = param.offsetSolverBodies;
|
||||
|
||||
for(PfxUInt32 i = iFirstContactPair; i < iEndContactPair; i++)
|
||||
{
|
||||
PfxConstraintPair &pair = contactPairs[i];
|
||||
if(!pfxCheckSolver(pair))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
PfxUInt16 iA = pfxGetObjectIdA(pair);
|
||||
PfxUInt16 iB = pfxGetObjectIdB(pair);
|
||||
PfxUInt32 iConstraint = pfxGetConstraintId(pair);
|
||||
|
||||
PfxContactManifold &contact = offsetContactManifolds[iConstraint];
|
||||
|
||||
SCE_PFX_ALWAYS_ASSERT(iA==contact.getRigidBodyIdA());
|
||||
SCE_PFX_ALWAYS_ASSERT(iB==contact.getRigidBodyIdB());
|
||||
|
||||
PfxRigidState &stateA = offsetRigidStates[iA];
|
||||
PfxRigidBody &bodyA = offsetRigidBodies[iA];
|
||||
PfxSolverBody &solverBodyA = offsetSolverBodies[iA];
|
||||
|
||||
PfxRigidState &stateB = offsetRigidStates[iB];
|
||||
PfxRigidBody &bodyB = offsetRigidBodies[iB];
|
||||
PfxSolverBody &solverBodyB = offsetSolverBodies[iB];
|
||||
|
||||
contact.setInternalFlag(0);
|
||||
|
||||
PfxFloat restitution = 0.5f * (bodyA.getRestitution() + bodyB.getRestitution());
|
||||
if(contact.getDuration() > 1) restitution = 0.0f;
|
||||
|
||||
PfxFloat friction = sqrtf(bodyA.getFriction() * bodyB.getFriction());
|
||||
|
||||
for(int j=0;j<contact.getNumContacts();j++)
|
||||
{
|
||||
PfxContactPoint &cp = contact.getContactPoint(j);
|
||||
|
||||
pfxSetupContactConstraint(
|
||||
cp.m_constraintRow[0],
|
||||
cp.m_constraintRow[1],
|
||||
cp.m_constraintRow[2],
|
||||
cp.m_distance,
|
||||
restitution,
|
||||
friction,
|
||||
pfxReadVector3(cp.m_constraintRow[0].m_normal),
|
||||
pfxReadVector3(cp.m_localPointA),
|
||||
pfxReadVector3(cp.m_localPointB),
|
||||
stateA,
|
||||
stateB,
|
||||
solverBodyA,
|
||||
solverBodyB,
|
||||
param.separateBias,
|
||||
param.timeStep
|
||||
);
|
||||
}
|
||||
|
||||
contact.setCompositeFriction(friction);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// pfxSetupContactConstraints
|
||||
//
|
||||
/// Perform setup contact constraints in parallel using a task manager.
|
||||
///
|
||||
/// @param param Information about contact constraints
|
||||
/// @param taskManager Pointer to the thread task manager to use
|
||||
///
|
||||
/// @return SCE_PFX_OK if successful, otherwise, returns an error code.
|
||||
//----------------------------------------------------------------------------
|
||||
PfxInt32 pfxSetupContactConstraints(PfxSetupContactConstraintsParam ¶m,
|
||||
PfxTaskManager *taskManager)
|
||||
{
|
||||
PfxInt32 ret = pfxCheckParamOfSetupContactConstraints(param);
|
||||
if(ret != SCE_PFX_OK) return ret;
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxSetupContactConstraints");
|
||||
|
||||
PfxUInt32 maxBatchSize = param.numContactPairs / (PfxUInt32)(taskManager->getNumTasks());
|
||||
PfxUInt32 iEnd = maxBatchSize, iStart = 0;
|
||||
int task = 0;
|
||||
taskManager->setTaskEntry((void*)pfxSetupContactConstraintsTaskEntry);
|
||||
|
||||
for (task = 0; task < taskManager->getNumTasks() - 1; task++, iStart += maxBatchSize, iEnd += maxBatchSize)
|
||||
{
|
||||
taskManager->startTask(task, static_cast<void*>(¶m), iStart, iEnd, 0, 0);
|
||||
}
|
||||
|
||||
// send final task
|
||||
iEnd = param.numContactPairs;
|
||||
taskManager->startTask(taskManager->getNumTasks() - 1, static_cast<void*>(¶m), iStart, iEnd, 0, 0);
|
||||
|
||||
// wait for tasks to complete
|
||||
PfxUInt32 data1, data2, data3, data4;
|
||||
for (PfxUInt32 i = 0; i < taskManager->getNumTasks(); i++)
|
||||
taskManager->waitTask(task, data1, data2, data3, data4);
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// pfxSetupJointConstraintsTaskEntry
|
||||
//
|
||||
/// The thread PfxTaskEntry function used to setup joint constraints in
|
||||
/// parallel.
|
||||
//----------------------------------------------------------------------------
|
||||
void pfxSetupJointConstraintsTaskEntry(PfxTaskArg *arg)
|
||||
{
|
||||
PfxSetupJointConstraintsParam ¶m = *((PfxSetupJointConstraintsParam*)arg->io);
|
||||
|
||||
PfxUInt32 iFirstJointPair = arg->data[0];
|
||||
PfxUInt32 iEndJointPair = arg->data[1];
|
||||
|
||||
PfxConstraintPair *jointPairs = param.jointPairs;
|
||||
PfxUInt32 numJointPairs = param.numJointPairs;
|
||||
PfxJoint *offsetJoints = param.offsetJoints;
|
||||
PfxRigidState *offsetRigidStates = param.offsetRigidStates;
|
||||
PfxSolverBody *offsetSolverBodies = param.offsetSolverBodies;
|
||||
|
||||
for(PfxUInt32 i = iFirstJointPair; i < iEndJointPair; i++)
|
||||
{
|
||||
PfxConstraintPair &pair = jointPairs[i];
|
||||
if(!pfxCheckSolver(pair))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
PfxUInt16 iA = pfxGetObjectIdA(pair);
|
||||
PfxUInt16 iB = pfxGetObjectIdB(pair);
|
||||
PfxUInt32 iConstraint = pfxGetConstraintId(pair);
|
||||
|
||||
PfxJoint &joint = offsetJoints[iConstraint];
|
||||
|
||||
SCE_PFX_ALWAYS_ASSERT(iA==joint.m_rigidBodyIdA);
|
||||
SCE_PFX_ALWAYS_ASSERT(iB==joint.m_rigidBodyIdB);
|
||||
|
||||
PfxRigidState &stateA = offsetRigidStates[iA];
|
||||
PfxSolverBody &solverBodyA = offsetSolverBodies[iA];
|
||||
|
||||
PfxRigidState &stateB = offsetRigidStates[iB];
|
||||
PfxSolverBody &solverBodyB = offsetSolverBodies[iB];
|
||||
|
||||
pfxGetSetupJointConstraintFunc(joint.m_type)(
|
||||
joint,
|
||||
stateA,
|
||||
stateB,
|
||||
solverBodyA,
|
||||
solverBodyB,
|
||||
param.timeStep);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// pfxSetupJointConstraints
|
||||
//
|
||||
/// Perform setup joint constraints in parallel using a task manager.
|
||||
///
|
||||
/// @param param Information about joint constraints
|
||||
/// @param taskManager Pointer to the thread task manager to use
|
||||
///
|
||||
/// @return SCE_PFX_OK if successful, otherwise, returns an error code.
|
||||
//----------------------------------------------------------------------------
|
||||
PfxInt32 pfxSetupJointConstraints(PfxSetupJointConstraintsParam ¶m,
|
||||
PfxTaskManager *taskManager)
|
||||
{
|
||||
PfxInt32 ret = pfxCheckParamOfSetupJointConstraints(param);
|
||||
if(ret != SCE_PFX_OK) return ret;
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxSetupJointConstraints");
|
||||
|
||||
PfxUInt32 maxBatchSize = param.numJointPairs / (PfxUInt32)(taskManager->getNumTasks());
|
||||
PfxUInt32 iEnd = maxBatchSize, iStart = 0;
|
||||
int task = 0;
|
||||
taskManager->setTaskEntry((void*)pfxSetupJointConstraintsTaskEntry);
|
||||
|
||||
for (task = 0; task < taskManager->getNumTasks() - 1; task++, iStart += maxBatchSize, iEnd += maxBatchSize)
|
||||
{
|
||||
taskManager->startTask(task, static_cast<void*>(¶m), iStart, iEnd, 0, 0);
|
||||
}
|
||||
|
||||
// send final task
|
||||
iEnd = param.numJointPairs;
|
||||
taskManager->startTask(taskManager->getNumTasks() - 1, static_cast<void*>(¶m), iStart, iEnd, 0, 0);
|
||||
|
||||
// wait for tasks to complete
|
||||
PfxUInt32 data1, data2, data3, data4;
|
||||
for (PfxUInt32 i = 0; i < taskManager->getNumTasks(); i++)
|
||||
taskManager->waitTask(task, data1, data2, data3, data4);
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// pfxSplitConstraints
|
||||
//
|
||||
/// Given a set of constraints to be solved, split the constraints into
|
||||
/// a collection of phases, with each phase having one or more independent
|
||||
/// batches that can be solved in parallel. The phases must be solved
|
||||
/// sequentially.
|
||||
///
|
||||
/// @param numRigidBodies [in] Total number of rigid bodies referenced
|
||||
/// in the given set of constraints
|
||||
/// @param constraintpairs [in] Pointer to array of constraints to split.
|
||||
/// For clarity, note that the pairs always stay
|
||||
/// together. Some pairs are split to be solved
|
||||
/// in parallel with other pairs.
|
||||
/// @param numConstraints [in] Number of constraints to split
|
||||
/// @param taskManager [in] Pointer to the thread task manager that will
|
||||
/// eventually be used to solve the constraints.
|
||||
/// @param group [out] On return, contains information about
|
||||
/// the phases and batches that define the splitting
|
||||
/// @param batches [out] Caller should pass a pointer to a pre-
|
||||
/// allocated array of SCE_PFX_MAX_SOLVER_BATCHES
|
||||
/// PfxParallelBatch objects. On output, these will
|
||||
/// be populated with the correct number of pairs
|
||||
/// for each batch.
|
||||
|
||||
///
|
||||
/// @return SCE_PFX_OK if successful, otherwise, returns an error code.
|
||||
//----------------------------------------------------------------------------
|
||||
void pfxSplitConstraints(PfxUInt32 numRigidBodies, PfxConstraintPair *constraintPairs,
|
||||
PfxUInt32 numConstraints, PfxTaskManager *taskManager, PfxParallelGroup *group,
|
||||
PfxParallelBatch *batches)
|
||||
{
|
||||
SCE_PFX_PUSH_MARKER("pfxSplitConstraints");
|
||||
|
||||
// allocate a table that will be used to indicate, for a given phase being
|
||||
// populated, which batch a given body belongs to.
|
||||
PfxInt32 bufSize = sizeof(PfxUInt8) * numRigidBodies;
|
||||
bufSize = ((bufSize + 127) >> 7) << 7; // 128 bytes alignment
|
||||
PfxUInt8 *bodyTable = (PfxUInt8*)taskManager->allocate(bufSize);
|
||||
|
||||
// allocate a table that will be used to indicate, for a given phase being
|
||||
// populated, which batch a given pair of bodies belongs to.
|
||||
PfxUInt32 *pairTable;
|
||||
size_t allocSize = sizeof(PfxUInt32)*((numConstraints + 31) / 32);
|
||||
pairTable = (PfxUInt32*)taskManager->allocate(allocSize);
|
||||
memset(pairTable, 0, allocSize);
|
||||
|
||||
//
|
||||
PfxUInt32 numTasks = taskManager->getNumTasks();
|
||||
PfxUInt32 targetCount = SCE_PFX_MAX(PfxUInt32(SCE_PFX_MIN_SOLVER_PAIRS),
|
||||
SCE_PFX_MIN(numConstraints / (numTasks * 2), PfxUInt32(SCE_PFX_MAX_SOLVER_PAIRS)));
|
||||
PfxUInt32 startIndex = 0;
|
||||
|
||||
PfxUInt32 phaseId;
|
||||
PfxUInt32 batchId;
|
||||
PfxUInt32 totalCount = 0;
|
||||
|
||||
PfxUInt32 maxBatches = SCE_PFX_MIN(numTasks, PfxUInt32(SCE_PFX_MAX_SOLVER_BATCHES));
|
||||
|
||||
// accumulate phases and batches until group resources are exhausted or all incoming
|
||||
// pairs are accounted for.
|
||||
for (phaseId = 0; phaseId < SCE_PFX_MAX_SOLVER_PHASES && totalCount < numConstraints; phaseId++)
|
||||
{
|
||||
bool startIndexCheck = true;
|
||||
|
||||
group->numBatches[phaseId] = 0;
|
||||
|
||||
PfxUInt32 i = startIndex;
|
||||
// Initialize body table such that no body is assigned to any batch. (0xff is explicitly assumed to
|
||||
// mean no batch assigned)
|
||||
memset(bodyTable, 0xff, bufSize);
|
||||
|
||||
// accumulate batches within the current phase. This code creates batches that are
|
||||
// independent, e.g., no batch on this phase will touch the same bodies as any other
|
||||
// batch on the phase. Batches within a phase can be solved in parallel on shared memory
|
||||
// multiprocessor hardware.
|
||||
for (batchId = 0; i < numConstraints && totalCount < numConstraints && batchId < maxBatches; batchId++)
|
||||
{
|
||||
PfxUInt32 pairCount=0;
|
||||
PfxParallelBatch &batch = batches[(phaseId * SCE_PFX_MAX_SOLVER_BATCHES) + batchId];
|
||||
PfxUInt32 pairId = 0;
|
||||
|
||||
// iterate through pairs, and assigns the pairs to batches
|
||||
for (; i < numConstraints && pairCount < targetCount; i++)
|
||||
{
|
||||
PfxUInt32 idxP = i >> 5;
|
||||
PfxUInt32 maskP = 1L << (i & 31);
|
||||
|
||||
if(pairTable[idxP] & maskP) // pair is already assigned to a phase/batch
|
||||
continue;
|
||||
|
||||
PfxUInt16 idxA = pfxGetObjectIdA(constraintPairs[i]);
|
||||
PfxUInt16 idxB = pfxGetObjectIdB(constraintPairs[i]);
|
||||
|
||||
// It is possible an incoming constraint pair can be skipped. For example, if the pair is inactive,
|
||||
// or if both its objects are static, unmoving objects and therefore would be unaffected by constraints.
|
||||
// This conditional statement addresses constraints to be skipped.
|
||||
if (!pfxGetActive(constraintPairs[i]) ||
|
||||
(SCE_PFX_MOTION_MASK_STATIC(pfxGetMotionMaskA(constraintPairs[i])&SCE_PFX_MOTION_MASK_TYPE) &&
|
||||
SCE_PFX_MOTION_MASK_STATIC(pfxGetMotionMaskB(constraintPairs[i])&SCE_PFX_MOTION_MASK_TYPE)) )
|
||||
{
|
||||
if (startIndexCheck)
|
||||
startIndex++;
|
||||
|
||||
//assign pair -> skip it because it has no constraints
|
||||
pairTable[idxP] |= maskP;
|
||||
totalCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If either body of the current pair belongs to another batch already, we cannot add the current
|
||||
// pair to the current batch. Must defer to another phase
|
||||
if( (bodyTable[idxA] != batchId && bodyTable[idxA] != 0xff) ||
|
||||
(bodyTable[idxB] != batchId && bodyTable[idxB] != 0xff) )
|
||||
{
|
||||
startIndexCheck = false; // so we will revisit this during allocation of next phase
|
||||
continue;
|
||||
}
|
||||
|
||||
// Dynamic bodies for current pair are assigned to the current batch in this phase.
|
||||
// Static bodies are not assigned. Since they never move, and their corresponding solver
|
||||
// bodies are therefore never touched, they can actually be used by any batch.
|
||||
if (SCE_PFX_MOTION_MASK_DYNAMIC(pfxGetMotionMaskA(constraintPairs[i])&SCE_PFX_MOTION_MASK_TYPE))
|
||||
bodyTable[idxA] = batchId;
|
||||
|
||||
if (SCE_PFX_MOTION_MASK_DYNAMIC(pfxGetMotionMaskB(constraintPairs[i])&SCE_PFX_MOTION_MASK_TYPE))
|
||||
bodyTable[idxB] = batchId;
|
||||
|
||||
if(startIndexCheck)
|
||||
startIndex++;
|
||||
|
||||
pairTable[idxP] |= maskP; // pair has been handled
|
||||
|
||||
//add the pair 'i' to the current batch
|
||||
batch.pairIndices[pairId++] = i;
|
||||
pairCount++;
|
||||
}
|
||||
|
||||
group->numPairs[(phaseId * SCE_PFX_MAX_SOLVER_BATCHES) + batchId] = (PfxUInt16)pairId;
|
||||
totalCount += pairCount;
|
||||
}
|
||||
group->numBatches[phaseId] = batchId;
|
||||
}
|
||||
|
||||
group->numPhases = phaseId;
|
||||
|
||||
taskManager->deallocate(bodyTable);
|
||||
taskManager->deallocate(pairTable);
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// pfxSolveConstraintsTaskEntry
|
||||
//
|
||||
/// The thread PfxTaskEntry function used to solve constraints in parallel.
|
||||
//----------------------------------------------------------------------------
|
||||
void pfxSolveConstraintsTaskEntry(PfxTaskArg *arg)
|
||||
{
|
||||
PfxSolveConstraintsParam ¶m = *((PfxSolveConstraintsParam*)arg->io);
|
||||
|
||||
PfxConstraintPair *contactPairs = param.contactPairs;
|
||||
PfxContactManifold *offsetContactManifolds = param.offsetContactManifolds;
|
||||
PfxConstraintPair *jointPairs = param.jointPairs;
|
||||
PfxJoint *offsetJoints = param.offsetJoints;
|
||||
PfxRigidState *offsetRigidStates = param.offsetRigidStates;
|
||||
PfxSolverBody *offsetSolverBodies = param.offsetSolverBodies;
|
||||
|
||||
PfxParallelGroup *jointgroup = (PfxParallelGroup*)arg->data[0];
|
||||
PfxParallelBatch *jointbatches = (PfxParallelBatch*)arg->data[1];
|
||||
PfxParallelGroup *contactgroup = (PfxParallelGroup*)arg->data[2];
|
||||
PfxParallelBatch *contactbatches = (PfxParallelBatch*)arg->data[3];
|
||||
|
||||
// Warm Starting
|
||||
{
|
||||
// Joints
|
||||
for (PfxUInt16 phase = 0; phase < jointgroup->numPhases; phase++)
|
||||
{
|
||||
for (PfxUInt16 batchId = 0; batchId < jointgroup->numBatches[phase]; batchId++)
|
||||
{
|
||||
PfxUInt16 numJointPairs = jointgroup->numPairs[(phase * SCE_PFX_MAX_SOLVER_BATCHES) + batchId];
|
||||
if ((arg->taskId == (batchId % arg->maxTasks)) && numJointPairs > 0) // only spend time on batches meant for this task
|
||||
{
|
||||
const PfxParallelBatch &batch = jointbatches[(phase * SCE_PFX_MAX_SOLVER_BATCHES) + batchId];
|
||||
for (PfxUInt16 i = 0; i < numJointPairs; i++)
|
||||
{
|
||||
PfxConstraintPair &pair = jointPairs[batch.pairIndices[i]];
|
||||
if(!pfxCheckSolver(pair))
|
||||
continue;
|
||||
|
||||
PfxUInt16 iA = pfxGetObjectIdA(pair);
|
||||
PfxUInt16 iB = pfxGetObjectIdB(pair);
|
||||
|
||||
PfxJoint &joint = offsetJoints[pfxGetConstraintId(pair)];
|
||||
|
||||
SCE_PFX_ASSERT(iA==joint.m_rigidBodyIdA);
|
||||
SCE_PFX_ASSERT(iB==joint.m_rigidBodyIdB);
|
||||
|
||||
PfxSolverBody &solverBodyA = offsetSolverBodies[iA];
|
||||
PfxSolverBody &solverBodyB = offsetSolverBodies[iB];
|
||||
|
||||
pfxGetWarmStartJointConstraintFunc(joint.m_type)(
|
||||
joint,
|
||||
solverBodyA,
|
||||
solverBodyB);
|
||||
}
|
||||
}
|
||||
|
||||
arg->barrier->sync(); // block until all threads are ready to go to next phase
|
||||
}
|
||||
}
|
||||
|
||||
// Contacts
|
||||
for (PfxUInt16 phase = 0; phase < contactgroup->numPhases; phase++)
|
||||
{
|
||||
for (PfxUInt16 batchId = 0; batchId < contactgroup->numBatches[phase]; batchId++)
|
||||
{
|
||||
PfxUInt16 numContactPairs = contactgroup->numPairs[(phase * SCE_PFX_MAX_SOLVER_BATCHES) + batchId];
|
||||
if ((arg->taskId == (batchId % arg->maxTasks)) && numContactPairs > 0) // only spend time on batches meant for this task
|
||||
{
|
||||
const PfxParallelBatch &batch = contactbatches[(phase * SCE_PFX_MAX_SOLVER_BATCHES) + batchId];
|
||||
for (PfxUInt16 i = 0; i < numContactPairs; i++)
|
||||
{
|
||||
PfxConstraintPair &pair = contactPairs[batch.pairIndices[i]];
|
||||
if(!pfxCheckSolver(pair))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
PfxUInt16 iA = pfxGetObjectIdA(pair);
|
||||
PfxUInt16 iB = pfxGetObjectIdB(pair);
|
||||
|
||||
PfxContactManifold &contact = offsetContactManifolds[pfxGetConstraintId(pair)];
|
||||
|
||||
SCE_PFX_ASSERT(iA==contact.getRigidBodyIdA());
|
||||
SCE_PFX_ASSERT(iB==contact.getRigidBodyIdB());
|
||||
|
||||
PfxSolverBody &solverBodyA = offsetSolverBodies[iA];
|
||||
PfxSolverBody &solverBodyB = offsetSolverBodies[iB];
|
||||
|
||||
PfxFloat massInvA = solverBodyA.m_massInv;
|
||||
PfxFloat massInvB = solverBodyB.m_massInv;
|
||||
PfxMatrix3 inertiaInvA = solverBodyA.m_inertiaInv;
|
||||
PfxMatrix3 inertiaInvB = solverBodyB.m_inertiaInv;
|
||||
|
||||
if(solverBodyA.m_motionType == kPfxMotionTypeOneWay)
|
||||
{
|
||||
massInvB = 0.0f;
|
||||
inertiaInvB = PfxMatrix3(0.0f);
|
||||
}
|
||||
|
||||
if(solverBodyB.m_motionType == kPfxMotionTypeOneWay)
|
||||
{
|
||||
massInvA = 0.0f;
|
||||
inertiaInvA = PfxMatrix3(0.0f);
|
||||
}
|
||||
|
||||
for(int j = 0; j < contact.getNumContacts(); j++)
|
||||
{
|
||||
PfxContactPoint &cp = contact.getContactPoint(j);
|
||||
|
||||
PfxVector3 rA = rotate(solverBodyA.m_orientation,pfxReadVector3(cp.m_localPointA));
|
||||
PfxVector3 rB = rotate(solverBodyB.m_orientation,pfxReadVector3(cp.m_localPointB));
|
||||
|
||||
for(int k = 0; k < 3; k++)
|
||||
{
|
||||
PfxVector3 normal = pfxReadVector3(cp.m_constraintRow[k].m_normal);
|
||||
PfxFloat deltaImpulse = cp.m_constraintRow[k].m_accumImpulse;
|
||||
solverBodyA.m_deltaLinearVelocity += deltaImpulse * massInvA * normal;
|
||||
solverBodyA.m_deltaAngularVelocity += deltaImpulse * inertiaInvA * cross(rA,normal);
|
||||
solverBodyB.m_deltaLinearVelocity -= deltaImpulse * massInvB * normal;
|
||||
solverBodyB.m_deltaAngularVelocity -= deltaImpulse * inertiaInvB * cross(rB,normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arg->barrier->sync(); // block until all threads are ready to go to next phase
|
||||
}
|
||||
}
|
||||
|
||||
// Solver
|
||||
for(PfxUInt32 iteration = 0; iteration < param.iteration; iteration++)
|
||||
{
|
||||
// Joints
|
||||
for (PfxUInt16 phase = 0; phase < jointgroup->numPhases; phase++)
|
||||
{
|
||||
for (PfxUInt16 batchId = 0; batchId < jointgroup->numBatches[phase]; batchId++)
|
||||
{
|
||||
PfxUInt16 numJointPairs = jointgroup->numPairs[(phase * SCE_PFX_MAX_SOLVER_BATCHES) + batchId];
|
||||
if ((arg->taskId == (batchId % arg->maxTasks)) && numJointPairs > 0) // only spend time on batches meant for this task
|
||||
{
|
||||
const PfxParallelBatch &batch = jointbatches[(phase * SCE_PFX_MAX_SOLVER_BATCHES) + batchId];
|
||||
for(PfxUInt16 i = 0; i < numJointPairs; i++)
|
||||
{
|
||||
PfxConstraintPair &pair = jointPairs[batch.pairIndices[i]];
|
||||
if(!pfxCheckSolver(pair))
|
||||
continue;
|
||||
|
||||
PfxUInt16 iA = pfxGetObjectIdA(pair);
|
||||
PfxUInt16 iB = pfxGetObjectIdB(pair);
|
||||
|
||||
PfxJoint &joint = offsetJoints[pfxGetConstraintId(pair)];
|
||||
|
||||
SCE_PFX_ASSERT(iA==joint.m_rigidBodyIdA);
|
||||
SCE_PFX_ASSERT(iB==joint.m_rigidBodyIdB);
|
||||
|
||||
PfxSolverBody &solverBodyA = offsetSolverBodies[iA];
|
||||
PfxSolverBody &solverBodyB = offsetSolverBodies[iB];
|
||||
|
||||
pfxGetSolveJointConstraintFunc(joint.m_type)(
|
||||
joint,
|
||||
solverBodyA,
|
||||
solverBodyB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arg->barrier->sync(); // block until all threads are ready to go to next phase
|
||||
}
|
||||
|
||||
// Contacts
|
||||
for (PfxUInt32 phase = 0; phase < contactgroup->numPhases; phase++)
|
||||
{
|
||||
for (PfxUInt32 batchId = 0; batchId < contactgroup->numBatches[phase]; batchId++)
|
||||
{
|
||||
PfxUInt32 numContactPairs = contactgroup->numPairs[(phase * SCE_PFX_MAX_SOLVER_BATCHES) + batchId];
|
||||
if ((arg->taskId == (batchId % arg->maxTasks)) && numContactPairs > 0) // only spend time on batches meant for this task
|
||||
{
|
||||
const PfxParallelBatch &batch = contactbatches[(phase * SCE_PFX_MAX_SOLVER_BATCHES) + batchId];
|
||||
for(PfxUInt32 i = 0; i < numContactPairs; i++)
|
||||
{
|
||||
PfxConstraintPair &pair = contactPairs[batch.pairIndices[i]];
|
||||
if(!pfxCheckSolver(pair))
|
||||
continue;
|
||||
|
||||
PfxUInt16 iA = pfxGetObjectIdA(pair);
|
||||
PfxUInt16 iB = pfxGetObjectIdB(pair);
|
||||
|
||||
PfxContactManifold &contact = offsetContactManifolds[pfxGetConstraintId(pair)];
|
||||
|
||||
SCE_PFX_ASSERT(iA==contact.getRigidBodyIdA());
|
||||
SCE_PFX_ASSERT(iB==contact.getRigidBodyIdB());
|
||||
|
||||
PfxSolverBody &solverBodyA = offsetSolverBodies[iA];
|
||||
PfxSolverBody &solverBodyB = offsetSolverBodies[iB];
|
||||
|
||||
for(int j = 0; j < contact.getNumContacts(); j++)
|
||||
{
|
||||
PfxContactPoint &cp = contact.getContactPoint(j);
|
||||
|
||||
pfxSolveContactConstraint(
|
||||
cp.m_constraintRow[0],
|
||||
cp.m_constraintRow[1],
|
||||
cp.m_constraintRow[2],
|
||||
pfxReadVector3(cp.m_localPointA),
|
||||
pfxReadVector3(cp.m_localPointB),
|
||||
solverBodyA,
|
||||
solverBodyB,
|
||||
contact.getCompositeFriction()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arg->barrier->sync(); // block until all threads are ready to go to next phase
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// pfxSolveConstraints
|
||||
//
|
||||
/// Perform setup joint constraints in parallel using a task manager.
|
||||
///
|
||||
/// @param param Information about constraints
|
||||
/// @param taskManager Pointer to the thread task manager to use
|
||||
///
|
||||
/// @return SCE_PFX_OK if successful, otherwise, returns an error code.
|
||||
//----------------------------------------------------------------------------
|
||||
PfxInt32 pfxSolveConstraints(PfxSolveConstraintsParam ¶m,
|
||||
PfxTaskManager *taskManager)
|
||||
{
|
||||
PfxInt32 ret = pfxCheckParamOfSolveConstraints(param);
|
||||
if(ret != SCE_PFX_OK) return ret;
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxSolveConstraints");
|
||||
|
||||
PfxParallelGroup *contactgroup = (PfxParallelGroup*)taskManager->allocate(sizeof(PfxParallelGroup));
|
||||
PfxParallelBatch *contactbatches = (PfxParallelBatch*)taskManager->allocate(sizeof(PfxParallelBatch) * (SCE_PFX_MAX_SOLVER_PHASES * SCE_PFX_MAX_SOLVER_BATCHES));
|
||||
PfxParallelGroup *jointgroup = (PfxParallelGroup*)taskManager->allocate(sizeof(PfxParallelGroup));
|
||||
PfxParallelBatch *jointbatches = (PfxParallelBatch*)taskManager->allocate(sizeof(PfxParallelBatch) * (SCE_PFX_MAX_SOLVER_PHASES * SCE_PFX_MAX_SOLVER_BATCHES));
|
||||
|
||||
// split constraints into independent phases and batches. Phases allow
|
||||
// a set of non-independent constraints to be solved in parallel. One
|
||||
// phase may have dependencies within another phase, but the phases are
|
||||
// solved sequentially. Within a phases, there are multiple batches, and
|
||||
// the batches are independent. Since they are independent, they can be
|
||||
// distributed to different processors and solved in parallel.
|
||||
pfxSplitConstraints(param.numRigidBodies, param.contactPairs, param.numContactPairs,
|
||||
taskManager, contactgroup, contactbatches);
|
||||
pfxSplitConstraints(param.numRigidBodies, param.jointPairs, param.numJointPairs,
|
||||
taskManager, jointgroup, jointbatches);
|
||||
|
||||
// parallel solve
|
||||
taskManager->setTaskEntry((void*)pfxSolveConstraintsTaskEntry);
|
||||
int task = 0;
|
||||
for (; task < taskManager->getNumTasks(); task++)
|
||||
{
|
||||
taskManager->startTask(task, static_cast<void*>(¶m), (PfxUInt32)jointgroup, (PfxUInt32)jointbatches,
|
||||
(PfxUInt32)contactgroup, (PfxUInt32)contactbatches);
|
||||
}
|
||||
|
||||
// wait for tasks to complete
|
||||
PfxUInt32 data1, data2, data3, data4;
|
||||
for (PfxUInt32 i = 0; i < taskManager->getNumTasks(); i++)
|
||||
taskManager->waitTask(task, data1, data2, data3, data4);
|
||||
|
||||
// post solve
|
||||
PfxRigidState *offsetRigidStates = param.offsetRigidStates;
|
||||
PfxSolverBody *offsetSolverBodies = param.offsetSolverBodies;
|
||||
for (PfxUInt32 i = 0; i < param.numRigidBodies; i++)
|
||||
{
|
||||
param.offsetRigidStates[i].setLinearVelocity(param.offsetRigidStates[i].getLinearVelocity() +
|
||||
param.offsetSolverBodies[i].m_deltaLinearVelocity);
|
||||
param.offsetRigidStates[i].setAngularVelocity(param.offsetRigidStates[i].getAngularVelocity() +
|
||||
param.offsetSolverBodies[i].m_deltaAngularVelocity);
|
||||
}
|
||||
|
||||
taskManager->clearPool();
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#include "../../../include/physics_effects/base_level/base/pfx_perf_counter.h"
|
||||
#include "../../../include/physics_effects/base_level/solver/pfx_contact_constraint.h"
|
||||
#include "../../../include/physics_effects/low_level/solver/pfx_joint_constraint_func.h"
|
||||
#include "../../../include/physics_effects/low_level/solver/pfx_constraint_solver.h"
|
||||
#include "../../base_level/solver/pfx_check_solver.h"
|
||||
#include "pfx_parallel_group.h"
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
PfxUInt32 pfxGetWorkBytesOfSolveConstraints(PfxUInt32 numRigidBodies,PfxUInt32 numContactPairs,PfxUInt32 numJointPairs,PfxUInt32 maxTasks)
|
||||
{
|
||||
(void)maxTasks;
|
||||
PfxUInt32 workBytes = SCE_PFX_ALLOC_BYTES_ALIGN16(sizeof(PfxUInt8) * numRigidBodies) +
|
||||
SCE_PFX_ALLOC_BYTES_ALIGN16(sizeof(PfxUInt32)*((SCE_PFX_MAX(numContactPairs,numJointPairs)+31)/32));
|
||||
|
||||
workBytes += 128 + (SCE_PFX_ALLOC_BYTES_ALIGN16(sizeof(PfxParallelGroup)) +
|
||||
SCE_PFX_ALLOC_BYTES_ALIGN128(sizeof(PfxParallelBatch)*(SCE_PFX_MAX_SOLVER_PHASES*SCE_PFX_MAX_SOLVER_BATCHES))) * 2;
|
||||
|
||||
return workBytes;
|
||||
}
|
||||
|
||||
PfxInt32 pfxCheckParamOfSetupSolverBodies(const PfxSetupSolverBodiesParam ¶m)
|
||||
{
|
||||
if(!param.states || !param.bodies || !param.solverBodies ) return SCE_PFX_ERR_INVALID_VALUE;
|
||||
if(!SCE_PFX_PTR_IS_ALIGNED16(param.states) || !SCE_PFX_PTR_IS_ALIGNED16(param.bodies) || !SCE_PFX_PTR_IS_ALIGNED16(param.solverBodies)) return SCE_PFX_ERR_INVALID_ALIGN;
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
PfxInt32 pfxCheckParamOfSetupContactConstraints(const PfxSetupContactConstraintsParam ¶m)
|
||||
{
|
||||
if((param.numContactPairs>0&&(!param.contactPairs||!param.offsetContactManifolds)) || !param.offsetRigidStates ||
|
||||
!param.offsetRigidBodies || !param.offsetSolverBodies || param.timeStep <= 0.0f) return SCE_PFX_ERR_INVALID_VALUE;
|
||||
if(!SCE_PFX_PTR_IS_ALIGNED16(param.contactPairs) || !SCE_PFX_PTR_IS_ALIGNED16(param.offsetContactManifolds) || !SCE_PFX_PTR_IS_ALIGNED16(param.offsetRigidStates) ||
|
||||
!SCE_PFX_PTR_IS_ALIGNED16(param.offsetRigidBodies) || !SCE_PFX_PTR_IS_ALIGNED16(param.offsetSolverBodies)) return SCE_PFX_ERR_INVALID_ALIGN;
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
PfxInt32 pfxCheckParamOfSetupJointConstraints(const PfxSetupJointConstraintsParam ¶m)
|
||||
{
|
||||
if((param.numJointPairs>0&&(!param.jointPairs||!param.offsetJoints)) || !param.offsetRigidStates ||
|
||||
!param.offsetRigidBodies || !param.offsetSolverBodies || param.timeStep <= 0.0f) return SCE_PFX_ERR_INVALID_VALUE;
|
||||
if(!SCE_PFX_PTR_IS_ALIGNED16(param.jointPairs) || !SCE_PFX_PTR_IS_ALIGNED16(param.offsetJoints) || !SCE_PFX_PTR_IS_ALIGNED16(param.offsetRigidStates) ||
|
||||
!SCE_PFX_PTR_IS_ALIGNED16(param.offsetRigidBodies) || !SCE_PFX_PTR_IS_ALIGNED16(param.offsetSolverBodies)) return SCE_PFX_ERR_INVALID_ALIGN;
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
PfxInt32 pfxCheckParamOfSolveConstraints(const PfxSolveConstraintsParam ¶m)
|
||||
{
|
||||
if((param.numContactPairs>0&&(!param.contactPairs||!param.offsetContactManifolds)) ||
|
||||
(param.numJointPairs>0&&(!param.jointPairs||!param.offsetJoints)) || !param.offsetRigidStates || !param.offsetSolverBodies) return SCE_PFX_ERR_INVALID_VALUE;
|
||||
if(!SCE_PFX_PTR_IS_ALIGNED16(param.contactPairs) || !SCE_PFX_PTR_IS_ALIGNED16(param.offsetContactManifolds) ||
|
||||
!SCE_PFX_PTR_IS_ALIGNED16(param.jointPairs) || !SCE_PFX_PTR_IS_ALIGNED16(param.offsetJoints) || !SCE_PFX_PTR_IS_ALIGNED16(param.offsetRigidStates) ||
|
||||
!SCE_PFX_PTR_IS_ALIGNED16(param.offsetSolverBodies)) return SCE_PFX_ERR_INVALID_ALIGN;
|
||||
if(SCE_PFX_AVAILABLE_BYTES_ALIGN16(param.workBuff,param.workBytes) < pfxGetWorkBytesOfSolveConstraints(param.numRigidBodies,param.numContactPairs,param.numJointPairs) ) return SCE_PFX_ERR_OUT_OF_BUFFER;
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SINGLE THREAD
|
||||
|
||||
PfxInt32 pfxSetupSolverBodies(PfxSetupSolverBodiesParam ¶m)
|
||||
{
|
||||
PfxInt32 ret = pfxCheckParamOfSetupSolverBodies(param);
|
||||
if(ret != SCE_PFX_OK) return ret;
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxSetupSolverBodies");
|
||||
|
||||
PfxRigidState *states = param.states;
|
||||
PfxRigidBody *bodies = param.bodies;
|
||||
PfxSolverBody *solverBodies = param.solverBodies;
|
||||
PfxUInt32 numRigidBodies = param.numRigidBodies;
|
||||
|
||||
for(PfxUInt32 i=0;i<numRigidBodies;i++) {
|
||||
PfxRigidState &state = states[i];
|
||||
PfxRigidBody &body = bodies[i];
|
||||
PfxSolverBody &solverBody = solverBodies[i];
|
||||
|
||||
solverBody.m_orientation = state.getOrientation();
|
||||
solverBody.m_deltaLinearVelocity = PfxVector3(0.0f);
|
||||
solverBody.m_deltaAngularVelocity = PfxVector3(0.0f);
|
||||
solverBody.m_motionType = state.getMotionMask();
|
||||
|
||||
if(SCE_PFX_MOTION_MASK_DYNAMIC(state.getMotionType())) {
|
||||
PfxMatrix3 ori(solverBody.m_orientation);
|
||||
solverBody.m_massInv = body.getMassInv();
|
||||
solverBody.m_inertiaInv = ori * body.getInertiaInv() * transpose(ori);
|
||||
}
|
||||
else {
|
||||
solverBody.m_massInv = 0.0f;
|
||||
solverBody.m_inertiaInv = PfxMatrix3(0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
PfxInt32 pfxSetupContactConstraints(PfxSetupContactConstraintsParam ¶m)
|
||||
{
|
||||
PfxInt32 ret = pfxCheckParamOfSetupContactConstraints(param);
|
||||
if(ret != SCE_PFX_OK) return ret;
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxSetupContactConstraints");
|
||||
|
||||
PfxConstraintPair *contactPairs = param.contactPairs;
|
||||
PfxUInt32 numContactPairs = param.numContactPairs;
|
||||
PfxContactManifold *offsetContactManifolds = param.offsetContactManifolds;
|
||||
PfxRigidState *offsetRigidStates = param.offsetRigidStates;
|
||||
PfxRigidBody *offsetRigidBodies = param.offsetRigidBodies;
|
||||
PfxSolverBody *offsetSolverBodies = param.offsetSolverBodies;
|
||||
|
||||
for(PfxUInt32 i=0;i<numContactPairs;i++) {
|
||||
PfxConstraintPair &pair = contactPairs[i];
|
||||
if(!pfxCheckSolver(pair)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PfxUInt16 iA = pfxGetObjectIdA(pair);
|
||||
PfxUInt16 iB = pfxGetObjectIdB(pair);
|
||||
PfxUInt32 iConstraint = pfxGetConstraintId(pair);
|
||||
|
||||
PfxContactManifold &contact = offsetContactManifolds[iConstraint];
|
||||
|
||||
SCE_PFX_ALWAYS_ASSERT(iA==contact.getRigidBodyIdA());
|
||||
SCE_PFX_ALWAYS_ASSERT(iB==contact.getRigidBodyIdB());
|
||||
|
||||
PfxRigidState &stateA = offsetRigidStates[iA];
|
||||
PfxRigidBody &bodyA = offsetRigidBodies[iA];
|
||||
PfxSolverBody &solverBodyA = offsetSolverBodies[iA];
|
||||
|
||||
PfxRigidState &stateB = offsetRigidStates[iB];
|
||||
PfxRigidBody &bodyB = offsetRigidBodies[iB];
|
||||
PfxSolverBody &solverBodyB = offsetSolverBodies[iB];
|
||||
|
||||
contact.setInternalFlag(0);
|
||||
|
||||
PfxFloat restitution = 0.5f * (bodyA.getRestitution() + bodyB.getRestitution());
|
||||
if(contact.getDuration() > 1) restitution = 0.0f;
|
||||
|
||||
PfxFloat friction = sqrtf(bodyA.getFriction() * bodyB.getFriction());
|
||||
|
||||
for(int j=0;j<contact.getNumContacts();j++) {
|
||||
PfxContactPoint &cp = contact.getContactPoint(j);
|
||||
|
||||
pfxSetupContactConstraint(
|
||||
cp.m_constraintRow[0],
|
||||
cp.m_constraintRow[1],
|
||||
cp.m_constraintRow[2],
|
||||
cp.m_distance,
|
||||
restitution,
|
||||
friction,
|
||||
pfxReadVector3(cp.m_constraintRow[0].m_normal),
|
||||
pfxReadVector3(cp.m_localPointA),
|
||||
pfxReadVector3(cp.m_localPointB),
|
||||
stateA,
|
||||
stateB,
|
||||
solverBodyA,
|
||||
solverBodyB,
|
||||
param.separateBias,
|
||||
param.timeStep
|
||||
);
|
||||
}
|
||||
|
||||
contact.setCompositeFriction(friction);
|
||||
}
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
PfxInt32 pfxSetupJointConstraints(PfxSetupJointConstraintsParam ¶m)
|
||||
{
|
||||
PfxInt32 ret = pfxCheckParamOfSetupJointConstraints(param);
|
||||
if(ret != SCE_PFX_OK) return ret;
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxSetupJointConstraints");
|
||||
|
||||
PfxConstraintPair *jointPairs = param.jointPairs;
|
||||
PfxUInt32 numJointPairs = param.numJointPairs;
|
||||
PfxJoint *offsetJoints = param.offsetJoints;
|
||||
PfxRigidState *offsetRigidStates = param.offsetRigidStates;
|
||||
PfxSolverBody *offsetSolverBodies = param.offsetSolverBodies;
|
||||
|
||||
for(PfxUInt32 i=0;i<numJointPairs;i++) {
|
||||
PfxConstraintPair &pair = jointPairs[i];
|
||||
if(!pfxCheckSolver(pair)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PfxUInt16 iA = pfxGetObjectIdA(pair);
|
||||
PfxUInt16 iB = pfxGetObjectIdB(pair);
|
||||
PfxUInt32 iConstraint = pfxGetConstraintId(pair);
|
||||
|
||||
PfxJoint &joint = offsetJoints[iConstraint];
|
||||
|
||||
SCE_PFX_ALWAYS_ASSERT(iA==joint.m_rigidBodyIdA);
|
||||
SCE_PFX_ALWAYS_ASSERT(iB==joint.m_rigidBodyIdB);
|
||||
|
||||
PfxRigidState &stateA = offsetRigidStates[iA];
|
||||
PfxSolverBody &solverBodyA = offsetSolverBodies[iA];
|
||||
|
||||
PfxRigidState &stateB = offsetRigidStates[iB];
|
||||
PfxSolverBody &solverBodyB = offsetSolverBodies[iB];
|
||||
|
||||
pfxGetSetupJointConstraintFunc(joint.m_type)(
|
||||
joint,
|
||||
stateA,
|
||||
stateB,
|
||||
solverBodyA,
|
||||
solverBodyB,
|
||||
param.timeStep);
|
||||
}
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
PfxInt32 pfxSolveConstraints(PfxSolveConstraintsParam ¶m)
|
||||
{
|
||||
PfxInt32 ret = pfxCheckParamOfSolveConstraints(param);
|
||||
if(ret != SCE_PFX_OK) return ret;
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxSolveConstraints");
|
||||
|
||||
PfxConstraintPair *contactPairs = param.contactPairs;
|
||||
PfxUInt32 numContactPairs = param.numContactPairs;
|
||||
PfxContactManifold *offsetContactManifolds = param.offsetContactManifolds;
|
||||
PfxConstraintPair *jointPairs = param.jointPairs;
|
||||
PfxUInt32 numJointPairs = param.numJointPairs;
|
||||
PfxJoint *offsetJoints = param.offsetJoints;
|
||||
PfxRigidState *offsetRigidStates = param.offsetRigidStates;
|
||||
PfxSolverBody *offsetSolverBodies = param.offsetSolverBodies;
|
||||
PfxUInt32 numRigidBodies = param.numRigidBodies;
|
||||
|
||||
// Warm Starting
|
||||
{
|
||||
for(PfxUInt32 i=0;i<numJointPairs;i++) {
|
||||
PfxConstraintPair &pair = jointPairs[i];
|
||||
if(!pfxCheckSolver(pair)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PfxUInt16 iA = pfxGetObjectIdA(pair);
|
||||
PfxUInt16 iB = pfxGetObjectIdB(pair);
|
||||
|
||||
PfxJoint &joint = offsetJoints[pfxGetConstraintId(pair)];
|
||||
|
||||
SCE_PFX_ASSERT(iA==joint.m_rigidBodyIdA);
|
||||
SCE_PFX_ASSERT(iB==joint.m_rigidBodyIdB);
|
||||
|
||||
PfxSolverBody &solverBodyA = offsetSolverBodies[iA];
|
||||
PfxSolverBody &solverBodyB = offsetSolverBodies[iB];
|
||||
|
||||
pfxGetWarmStartJointConstraintFunc(joint.m_type)(
|
||||
joint,
|
||||
solverBodyA,
|
||||
solverBodyB);
|
||||
}
|
||||
for(PfxUInt32 i=0;i<numContactPairs;i++) {
|
||||
PfxConstraintPair &pair = contactPairs[i];
|
||||
if(!pfxCheckSolver(pair)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PfxUInt16 iA = pfxGetObjectIdA(pair);
|
||||
PfxUInt16 iB = pfxGetObjectIdB(pair);
|
||||
|
||||
PfxContactManifold &contact = offsetContactManifolds[pfxGetConstraintId(pair)];
|
||||
|
||||
SCE_PFX_ASSERT(iA==contact.getRigidBodyIdA());
|
||||
SCE_PFX_ASSERT(iB==contact.getRigidBodyIdB());
|
||||
|
||||
PfxSolverBody &solverBodyA = offsetSolverBodies[iA];
|
||||
PfxSolverBody &solverBodyB = offsetSolverBodies[iB];
|
||||
|
||||
PfxFloat massInvA = solverBodyA.m_massInv;
|
||||
PfxFloat massInvB = solverBodyB.m_massInv;
|
||||
PfxMatrix3 inertiaInvA = solverBodyA.m_inertiaInv;
|
||||
PfxMatrix3 inertiaInvB = solverBodyB.m_inertiaInv;
|
||||
|
||||
if(solverBodyA.m_motionType == kPfxMotionTypeOneWay) {
|
||||
massInvB = 0.0f;
|
||||
inertiaInvB = PfxMatrix3(0.0f);
|
||||
}
|
||||
if(solverBodyB.m_motionType == kPfxMotionTypeOneWay) {
|
||||
massInvA = 0.0f;
|
||||
inertiaInvA = PfxMatrix3(0.0f);
|
||||
}
|
||||
|
||||
for(int j=0;j<contact.getNumContacts();j++) {
|
||||
PfxContactPoint &cp = contact.getContactPoint(j);
|
||||
|
||||
PfxVector3 rA = rotate(solverBodyA.m_orientation,pfxReadVector3(cp.m_localPointA));
|
||||
PfxVector3 rB = rotate(solverBodyB.m_orientation,pfxReadVector3(cp.m_localPointB));
|
||||
|
||||
for(int k=0;k<3;k++) {
|
||||
PfxVector3 normal = pfxReadVector3(cp.m_constraintRow[k].m_normal);
|
||||
PfxFloat deltaImpulse = cp.m_constraintRow[k].m_accumImpulse;
|
||||
solverBodyA.m_deltaLinearVelocity += deltaImpulse * massInvA * normal;
|
||||
solverBodyA.m_deltaAngularVelocity += deltaImpulse * inertiaInvA * cross(rA,normal);
|
||||
solverBodyB.m_deltaLinearVelocity -= deltaImpulse * massInvB * normal;
|
||||
solverBodyB.m_deltaAngularVelocity -= deltaImpulse * inertiaInvB * cross(rB,normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Solver
|
||||
for(PfxUInt32 iteration=0;iteration<param.iteration;iteration++) {
|
||||
for(PfxUInt32 i=0;i<numJointPairs;i++) {
|
||||
PfxConstraintPair &pair = jointPairs[i];
|
||||
if(!pfxCheckSolver(pair)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PfxUInt16 iA = pfxGetObjectIdA(pair);
|
||||
PfxUInt16 iB = pfxGetObjectIdB(pair);
|
||||
|
||||
PfxJoint &joint = offsetJoints[pfxGetConstraintId(pair)];
|
||||
|
||||
SCE_PFX_ASSERT(iA==joint.m_rigidBodyIdA);
|
||||
SCE_PFX_ASSERT(iB==joint.m_rigidBodyIdB);
|
||||
|
||||
PfxSolverBody &solverBodyA = offsetSolverBodies[iA];
|
||||
PfxSolverBody &solverBodyB = offsetSolverBodies[iB];
|
||||
|
||||
pfxGetSolveJointConstraintFunc(joint.m_type)(
|
||||
joint,
|
||||
solverBodyA,
|
||||
solverBodyB);
|
||||
}
|
||||
for(PfxUInt32 i=0;i<numContactPairs;i++) {
|
||||
PfxConstraintPair &pair = contactPairs[i];
|
||||
if(!pfxCheckSolver(pair)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PfxUInt16 iA = pfxGetObjectIdA(pair);
|
||||
PfxUInt16 iB = pfxGetObjectIdB(pair);
|
||||
|
||||
PfxContactManifold &contact = offsetContactManifolds[pfxGetConstraintId(pair)];
|
||||
|
||||
SCE_PFX_ASSERT(iA==contact.getRigidBodyIdA());
|
||||
SCE_PFX_ASSERT(iB==contact.getRigidBodyIdB());
|
||||
|
||||
PfxSolverBody &solverBodyA = offsetSolverBodies[iA];
|
||||
PfxSolverBody &solverBodyB = offsetSolverBodies[iB];
|
||||
|
||||
for(int j=0;j<contact.getNumContacts();j++) {
|
||||
PfxContactPoint &cp = contact.getContactPoint(j);
|
||||
|
||||
pfxSolveContactConstraint(
|
||||
cp.m_constraintRow[0],
|
||||
cp.m_constraintRow[1],
|
||||
cp.m_constraintRow[2],
|
||||
pfxReadVector3(cp.m_localPointA),
|
||||
pfxReadVector3(cp.m_localPointB),
|
||||
solverBodyA,
|
||||
solverBodyB,
|
||||
contact.getCompositeFriction()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(PfxUInt32 i=0;i<numRigidBodies;i++) {
|
||||
offsetRigidStates[i].setLinearVelocity(
|
||||
offsetRigidStates[i].getLinearVelocity()+offsetSolverBodies[i].m_deltaLinearVelocity);
|
||||
offsetRigidStates[i].setAngularVelocity(
|
||||
offsetRigidStates[i].getAngularVelocity()+offsetSolverBodies[i].m_deltaAngularVelocity);
|
||||
}
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#include "../../../include/physics_effects/base_level/solver/pfx_joint.h"
|
||||
#include "../../../include/physics_effects/low_level/solver/pfx_joint_constraint_func.h"
|
||||
|
||||
#include "../../../include/physics_effects/base_level/solver/pfx_joint_ball.h"
|
||||
#include "../../../include/physics_effects/base_level/solver/pfx_joint_swing_twist.h"
|
||||
#include "../../../include/physics_effects/base_level/solver/pfx_joint_hinge.h"
|
||||
#include "../../../include/physics_effects/base_level/solver/pfx_joint_slider.h"
|
||||
#include "../../../include/physics_effects/base_level/solver/pfx_joint_fix.h"
|
||||
#include "../../../include/physics_effects/base_level/solver/pfx_joint_universal.h"
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Setup Joint Constraint Function Table
|
||||
|
||||
void setupJointConstraintDummy(
|
||||
PfxJoint &joint,
|
||||
const PfxRigidState &stateA,
|
||||
const PfxRigidState &stateB,
|
||||
PfxSolverBody &solverBodyA,
|
||||
PfxSolverBody &solverBodyB,
|
||||
PfxFloat timeStep)
|
||||
{
|
||||
(void)joint,(void)stateA,(void)stateB,(void)solverBodyA,(void)solverBodyB,(void)timeStep;
|
||||
}
|
||||
|
||||
PfxSetupJointConstraintFunc funcTbl_setupJointConstraint[kPfxJointCount] = {
|
||||
pfxSetupBallJoint,
|
||||
pfxSetupSwingTwistJoint,
|
||||
pfxSetupSwingTwistJoint,
|
||||
pfxSetupSwingTwistJoint,
|
||||
pfxSetupSwingTwistJoint,
|
||||
pfxSetupUniversalJoint,
|
||||
setupJointConstraintDummy,
|
||||
setupJointConstraintDummy,
|
||||
setupJointConstraintDummy,
|
||||
setupJointConstraintDummy,
|
||||
setupJointConstraintDummy,
|
||||
setupJointConstraintDummy,
|
||||
setupJointConstraintDummy,
|
||||
setupJointConstraintDummy,
|
||||
setupJointConstraintDummy,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Setup Joint Constraint Function Table Interface
|
||||
|
||||
PfxSetupJointConstraintFunc pfxGetSetupJointConstraintFunc(PfxUInt8 jointType)
|
||||
{
|
||||
SCE_PFX_ASSERT(jointType<kPfxJointCount);
|
||||
return funcTbl_setupJointConstraint[jointType];
|
||||
}
|
||||
|
||||
int pfxSetSetupJointConstraintFunc(PfxUInt8 jointType,PfxSetupJointConstraintFunc func)
|
||||
{
|
||||
if(jointType >= kPfxJointCount) {
|
||||
return SCE_PFX_ERR_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
funcTbl_setupJointConstraint[jointType] = func;
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Warm Start Joint Constraint Function Table
|
||||
|
||||
void warmStartJointConstraintDummy(
|
||||
PfxJoint &joint,
|
||||
PfxSolverBody &solverBodyA,
|
||||
PfxSolverBody &solverBodyB)
|
||||
{
|
||||
(void)joint,(void)solverBodyA,(void)solverBodyB;
|
||||
}
|
||||
|
||||
PfxWarmStartJointConstraintFunc funcTbl_warmStartJointConstraint[kPfxJointCount] = {
|
||||
pfxWarmStartBallJoint,
|
||||
pfxWarmStartSwingTwistJoint,
|
||||
pfxWarmStartSwingTwistJoint,
|
||||
pfxWarmStartSwingTwistJoint,
|
||||
pfxWarmStartSwingTwistJoint,
|
||||
pfxWarmStartSwingTwistJoint,
|
||||
warmStartJointConstraintDummy,
|
||||
warmStartJointConstraintDummy,
|
||||
warmStartJointConstraintDummy,
|
||||
warmStartJointConstraintDummy,
|
||||
warmStartJointConstraintDummy,
|
||||
warmStartJointConstraintDummy,
|
||||
warmStartJointConstraintDummy,
|
||||
warmStartJointConstraintDummy,
|
||||
warmStartJointConstraintDummy,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Warm Start Joint Constraint Function Table Interface
|
||||
|
||||
PfxWarmStartJointConstraintFunc pfxGetWarmStartJointConstraintFunc(PfxUInt8 jointType)
|
||||
{
|
||||
SCE_PFX_ASSERT(jointType<kPfxJointCount);
|
||||
return funcTbl_warmStartJointConstraint[jointType];
|
||||
}
|
||||
|
||||
int pfxSetWarmStartJointConstraintFunc(PfxUInt8 jointType,PfxWarmStartJointConstraintFunc func)
|
||||
{
|
||||
if(jointType >= kPfxJointCount) {
|
||||
return SCE_PFX_ERR_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
funcTbl_warmStartJointConstraint[jointType] = func;
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Solve Joint Constraint Function Table
|
||||
|
||||
void solveJointConstraintDummy(
|
||||
PfxJoint &joint,
|
||||
PfxSolverBody &solverBodyA,
|
||||
PfxSolverBody &solverBodyB)
|
||||
{
|
||||
(void)joint,(void)solverBodyA,(void)solverBodyB;
|
||||
}
|
||||
|
||||
PfxSolveJointConstraintFunc funcTbl_solveJointConstraint[kPfxJointCount] = {
|
||||
pfxSolveBallJoint,
|
||||
pfxSolveSwingTwistJoint,
|
||||
pfxSolveSwingTwistJoint,
|
||||
pfxSolveSwingTwistJoint,
|
||||
pfxSolveSwingTwistJoint,
|
||||
pfxSolveSwingTwistJoint,
|
||||
solveJointConstraintDummy,
|
||||
solveJointConstraintDummy,
|
||||
solveJointConstraintDummy,
|
||||
solveJointConstraintDummy,
|
||||
solveJointConstraintDummy,
|
||||
solveJointConstraintDummy,
|
||||
solveJointConstraintDummy,
|
||||
solveJointConstraintDummy,
|
||||
solveJointConstraintDummy,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Solve Joint Constraint Function Table Interface
|
||||
|
||||
PfxSolveJointConstraintFunc pfxGetSolveJointConstraintFunc(PfxUInt8 jointType)
|
||||
{
|
||||
SCE_PFX_ASSERT(jointType<kPfxJointCount);
|
||||
return funcTbl_solveJointConstraint[jointType];
|
||||
}
|
||||
|
||||
int pfxSetSolveJointConstraintFunc(PfxUInt8 jointType,PfxSolveJointConstraintFunc func)
|
||||
{
|
||||
if(jointType >= kPfxJointCount) {
|
||||
return SCE_PFX_ERR_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
funcTbl_solveJointConstraint[jointType] = func;
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#ifndef _SCE_PFX_PARALLEL_GROUP_H
|
||||
#define _SCE_PFX_PARALLEL_GROUP_H
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Parallel Group
|
||||
|
||||
#define SCE_PFX_MAX_SOLVER_PHASES 64 // 最大フェーズ数
|
||||
#define SCE_PFX_MAX_SOLVER_BATCHES 32 // 1フェーズに含まれる最大並列処理バッチ
|
||||
#define SCE_PFX_MAX_SOLVER_PAIRS 64 // 1バッチに含まれる最大ペア数
|
||||
#define SCE_PFX_MIN_SOLVER_PAIRS 16 // 1バッチに含まれる最小ペア数
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
struct SCE_PFX_ALIGNED(128) PfxParallelBatch {
|
||||
PfxUInt16 pairIndices[SCE_PFX_MAX_SOLVER_PAIRS];
|
||||
};
|
||||
|
||||
struct SCE_PFX_ALIGNED(128) PfxParallelGroup {
|
||||
PfxUInt16 numPhases;
|
||||
PfxUInt16 numBatches[SCE_PFX_MAX_SOLVER_PHASES]; // 各フェーズの保持する並列実行可能なバッチの数
|
||||
PfxUInt16 numPairs[SCE_PFX_MAX_SOLVER_PHASES*SCE_PFX_MAX_SOLVER_BATCHES]; // 各バッチの保持するペアの数
|
||||
SCE_PFX_PADDING(1,126)
|
||||
};
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
#endif // _SCE_PFX_PARALLEL_GROUP_H
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
Applied Research Associates Inc. (c)2011
|
||||
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#include "../../../include/physics_effects/base_level/base/pfx_perf_counter.h"
|
||||
#include "../../../include/physics_effects/base_level/solver/pfx_integrate.h"
|
||||
#include "../../../include/physics_effects/low_level/solver/pfx_update_rigid_states.h"
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// This function is implemented in pfx_update_rigid_states_single.cpp
|
||||
extern PfxInt32 pfxCheckParamOfUpdateRigidStates(const PfxUpdateRigidStatesParam ¶m);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MULTIPLE THREADS
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// pfxUpdateRigidStatesTaskEntry
|
||||
//
|
||||
/// The thread PfxTaskEntry function used to update rigid body states in
|
||||
/// parallel.
|
||||
//----------------------------------------------------------------------------
|
||||
void pfxUpdateRigidStatesTaskEntry(PfxTaskArg *arg)
|
||||
{
|
||||
PfxUpdateRigidStatesParam ¶m = *((PfxUpdateRigidStatesParam*)arg->io);
|
||||
|
||||
PfxUInt32 iFirstBody = arg->data[0];
|
||||
PfxUInt32 iEndBody = arg->data[1];
|
||||
|
||||
for(PfxUInt32 i = iFirstBody; i < iEndBody; i++)
|
||||
{
|
||||
pfxIntegrate(param.states[i],param.bodies[i],param.timeStep);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// pfxUpdateRigidStates
|
||||
//
|
||||
/// Perform update rigid states in parallel using a task manager.
|
||||
///
|
||||
/// @param param Information about rigid bodies
|
||||
/// @param taskManager Pointer to the thread task manager to use
|
||||
///
|
||||
/// @return SCE_PFX_OK if successful, otherwise, returns an error code.
|
||||
//----------------------------------------------------------------------------
|
||||
PfxInt32 pfxUpdateRigidStates(PfxUpdateRigidStatesParam ¶m, PfxTaskManager *taskManager)
|
||||
{
|
||||
PfxInt32 ret = pfxCheckParamOfUpdateRigidStates(param);
|
||||
if(ret != SCE_PFX_OK) return ret;
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxUpdateRigidStates");
|
||||
|
||||
PfxUInt32 maxBatchSize = param.numRigidBodies / (PfxUInt32)(taskManager->getNumTasks());
|
||||
PfxUInt32 iEnd = maxBatchSize, iStart = 0;
|
||||
int task = 0;
|
||||
taskManager->setTaskEntry((void*)pfxUpdateRigidStatesTaskEntry);
|
||||
|
||||
for (task = 0; task < taskManager->getNumTasks() - 1; task++, iStart += maxBatchSize, iEnd += maxBatchSize)
|
||||
{
|
||||
taskManager->startTask(task, static_cast<void*>(¶m), iStart, iEnd, 0, 0);
|
||||
}
|
||||
|
||||
// send final task
|
||||
iEnd = param.numRigidBodies;
|
||||
taskManager->startTask(taskManager->getNumTasks() - 1, static_cast<void*>(¶m), iStart, iEnd, 0, 0);
|
||||
|
||||
// wait for tasks to complete
|
||||
PfxUInt32 data1, data2, data3, data4;
|
||||
for (PfxUInt32 i = 0; i < taskManager->getNumTasks(); i++)
|
||||
taskManager->waitTask(task, data1, data2, data3, data4);
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#include "../../../include/physics_effects/base_level/base/pfx_perf_counter.h"
|
||||
#include "../../../include/physics_effects/base_level/solver/pfx_integrate.h"
|
||||
#include "../../../include/physics_effects/low_level/solver/pfx_update_rigid_states.h"
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
PfxInt32 pfxCheckParamOfUpdateRigidStates(const PfxUpdateRigidStatesParam ¶m)
|
||||
{
|
||||
if(!param.states || !param.bodies || param.timeStep <= 0.0f) return SCE_PFX_ERR_INVALID_VALUE;
|
||||
if(!SCE_PFX_PTR_IS_ALIGNED16(param.states) || !SCE_PFX_PTR_IS_ALIGNED16(param.bodies)) return SCE_PFX_ERR_INVALID_ALIGN;
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SINGLE THREAD
|
||||
|
||||
PfxInt32 pfxUpdateRigidStates(PfxUpdateRigidStatesParam ¶m)
|
||||
{
|
||||
PfxInt32 ret = pfxCheckParamOfUpdateRigidStates(param);
|
||||
if(ret != SCE_PFX_OK) return ret;
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxUpdateRigidStates");
|
||||
|
||||
for(PfxUInt32 i=0;i<param.numRigidBodies;i++) {
|
||||
pfxIntegrate(param.states[i],param.bodies[i],param.timeStep);
|
||||
}
|
||||
|
||||
SCE_PFX_POP_MARKER();
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
|
||||
All rights reserved.
|
||||
|
||||
Physics Effects is open software; you can redistribute it and/or
|
||||
modify it under the terms of the BSD License.
|
||||
|
||||
Physics Effects is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the BSD License for more details.
|
||||
|
||||
A copy of the BSD License is distributed with
|
||||
Physics Effects under the filename: physics_effects_license.txt
|
||||
*/
|
||||
|
||||
#include "../../../include/physics_effects/base_level/base/pfx_perf_counter.h"
|
||||
#include "../../../include/physics_effects/low_level/sort/pfx_parallel_sort.h"
|
||||
#include "../../../include/physics_effects/base_level/sort/pfx_sort.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SINGLE THREAD
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
PfxInt32 pfxParallelSort(
|
||||
PfxSortData16 *data,PfxUInt32 numData,
|
||||
void *workBuff,PfxUInt32 workBytes)
|
||||
{
|
||||
if(!SCE_PFX_PTR_IS_ALIGNED16(workBuff)) return SCE_PFX_ERR_INVALID_ALIGN;
|
||||
if(SCE_PFX_AVAILABLE_BYTES_ALIGN16(workBuff,workBytes) < sizeof(PfxSortData16) * numData) return SCE_PFX_ERR_OUT_OF_BUFFER;
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxParallelSort");
|
||||
pfxSort(data,(PfxSortData16*)workBuff,numData);
|
||||
SCE_PFX_POP_MARKER();
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
PfxInt32 pfxParallelSort(
|
||||
PfxSortData32 *data,PfxUInt32 numData,
|
||||
void *workBuff,PfxUInt32 workBytes)
|
||||
{
|
||||
if(!SCE_PFX_PTR_IS_ALIGNED16(workBuff)) return SCE_PFX_ERR_INVALID_ALIGN;
|
||||
if(SCE_PFX_AVAILABLE_BYTES_ALIGN16(workBuff,workBytes) < sizeof(PfxSortData32) * numData) return SCE_PFX_ERR_OUT_OF_BUFFER;
|
||||
|
||||
SCE_PFX_PUSH_MARKER("pfxParallelSort");
|
||||
pfxSort(data,(PfxSortData32*)workBuff,numData);
|
||||
SCE_PFX_POP_MARKER();
|
||||
|
||||
return SCE_PFX_OK;
|
||||
}
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
Applied Research Associates Inc. (c)2011
|
||||
|
||||
Redistribution and use in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Applied Research Associates Inc nor the names
|
||||
of its contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifdef __ANDROID__
|
||||
|
||||
#include "../../../include/physics_effects/base_level/base/pfx_common.h"
|
||||
#include "../../../include/physics_effects/low_level/task/pfx_pthreads.h"
|
||||
#include "../../../include/physics_effects/low_level/task/pfx_sync_components.h"
|
||||
#include "pfx_sync_components_pthreads.h"
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsBarrier::PfxPthreadsBarrier
|
||||
//
|
||||
/// Default constructor
|
||||
//----------------------------------------------------------------------------
|
||||
PfxPthreadsBarrier::PfxPthreadsBarrier() :
|
||||
m_maxThreads(0), m_called(0)
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsBarrier::~PfxPthreadsBarrier
|
||||
//
|
||||
/// Destructor
|
||||
//----------------------------------------------------------------------------
|
||||
PfxPthreadsBarrier::~PfxPthreadsBarrier()
|
||||
{
|
||||
if (m_maxThreads > 0)
|
||||
{
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(pthread_mutex_destroy(&m_mutex));
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(pthread_cond_destroy(&m_cond));
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsBarrier::sync
|
||||
//
|
||||
/// This function is used to sync m_numThreads worker threads. Each worker
|
||||
/// should call sync() when it finishes a task. All workers will block until
|
||||
/// the last worker also calls sync().
|
||||
//----------------------------------------------------------------------------
|
||||
void PfxPthreadsBarrier::sync()
|
||||
{
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(pthread_mutex_lock(&m_mutex));
|
||||
|
||||
m_called++;
|
||||
|
||||
if (m_called == m_maxThreads)
|
||||
{
|
||||
// last thread to join broadcasts a condition that will release
|
||||
// all the threads waiting at the barrier. The barrier is reset
|
||||
// to be ready for the next sync point.
|
||||
m_called = 0;
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(pthread_cond_broadcast(&m_cond));
|
||||
}
|
||||
else
|
||||
{
|
||||
// First m_numThreads - 1 worker threads block on the condition.
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(pthread_cond_wait(&m_cond, &m_mutex));
|
||||
}
|
||||
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(pthread_mutex_unlock(&m_mutex));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsBarrier::setMaxCount
|
||||
//
|
||||
/// Set the number of threads that the barrier should wait for. This also
|
||||
/// initializes a mutex and condition variable that are used to implement
|
||||
/// the barrier.
|
||||
///
|
||||
/// @param n Number of threads that should wait at the barrier.
|
||||
//----------------------------------------------------------------------------
|
||||
void PfxPthreadsBarrier::setMaxCount(int n)
|
||||
{
|
||||
if (m_maxThreads > 0)
|
||||
{
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(pthread_mutex_destroy(&m_mutex));
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(pthread_cond_destroy(&m_cond));
|
||||
}
|
||||
|
||||
m_called = 0;
|
||||
|
||||
if (0 < n)
|
||||
{
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(pthread_mutex_init(&m_mutex,NULL));
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(pthread_cond_init(&m_cond,NULL));
|
||||
}
|
||||
|
||||
m_maxThreads = n;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsBarrier::getMaxCount
|
||||
//
|
||||
/// Get the number of threads that the barrier will wait for.
|
||||
///
|
||||
/// @return The number of threads the barrier waits for
|
||||
//----------------------------------------------------------------------------
|
||||
int PfxPthreadsBarrier::getMaxCount()
|
||||
{
|
||||
return m_maxThreads;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsCriticalSection::PfxPthreadsCriticalSection
|
||||
//
|
||||
/// Default constructor
|
||||
//----------------------------------------------------------------------------
|
||||
PfxPthreadsCriticalSection::PfxPthreadsCriticalSection()
|
||||
{
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(pthread_mutex_init(&m_mutex,NULL));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsCriticalSection::~PfxPthreadsCriticalSection
|
||||
//
|
||||
/// Destructor
|
||||
//----------------------------------------------------------------------------
|
||||
PfxPthreadsCriticalSection::~PfxPthreadsCriticalSection()
|
||||
{
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(pthread_mutex_destroy(&m_mutex));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsCriticalSection::getSharedParam
|
||||
//
|
||||
/// Get the value of a shared parameter. Note that user must lock the
|
||||
/// critical section before performing this action.
|
||||
///
|
||||
/// @param i index of shared parameter to retrieve. Must have value
|
||||
/// between 0 and 31
|
||||
///
|
||||
/// @return Shared parameter value
|
||||
//----------------------------------------------------------------------------
|
||||
PfxUInt32 PfxPthreadsCriticalSection::getSharedParam(int i)
|
||||
{
|
||||
return(m_commonBuff[i]);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsCriticalSection::setSharedParam
|
||||
//
|
||||
/// Set the value of a shared parameter. Note that user must lock the
|
||||
/// critical section before performing this action.
|
||||
///
|
||||
/// @param i index of shared parameter to set. Must have value
|
||||
/// between 0 and 31
|
||||
/// @param p Value to assign to shared parameter
|
||||
//----------------------------------------------------------------------------
|
||||
void PfxPthreadsCriticalSection::setSharedParam(int i,PfxUInt32 p)
|
||||
{
|
||||
m_commonBuff[i] = p;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsCriticalSection::lock
|
||||
//
|
||||
/// Lock the critical section
|
||||
//----------------------------------------------------------------------------
|
||||
void PfxPthreadsCriticalSection::lock()
|
||||
{
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(pthread_mutex_lock(&m_mutex));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsCriticalSection::lock
|
||||
//
|
||||
/// Unlock the critical section
|
||||
//----------------------------------------------------------------------------
|
||||
void PfxPthreadsCriticalSection::unlock()
|
||||
{
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(pthread_mutex_unlock(&m_mutex));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Factory functions
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxCreateBarrierPthreads
|
||||
//
|
||||
/// Factory function to create a pthreads-based barrier
|
||||
///
|
||||
/// @param n Max number of tasks
|
||||
//----------------------------------------------------------------------------
|
||||
PfxBarrier *PfxCreateBarrierPthreads(int n)
|
||||
{
|
||||
PfxPthreadsBarrier *barrier = new PfxPthreadsBarrier;
|
||||
barrier->setMaxCount(n);
|
||||
return(barrier);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxCreateCriticalSectionPthreads
|
||||
//
|
||||
/// Factory function to create a pthreads-based critical section
|
||||
//----------------------------------------------------------------------------
|
||||
PfxCriticalSection *PfxCreateCriticalSectionPthreads()
|
||||
{
|
||||
PfxPthreadsCriticalSection *cs = new PfxPthreadsCriticalSection;
|
||||
return(cs);
|
||||
}
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
|
||||
#endif //__ANDROID__
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
Applied Research Associates Inc. (c)2011
|
||||
|
||||
Redistribution and use in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Applied Research Associates Inc nor the names
|
||||
of its contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SCE_PFX_SYNC_COMPONENTS_PTHREADS_H
|
||||
#define _SCE_PFX_SYNC_COMPONENTS_PTHREADS_H
|
||||
|
||||
#include "../../../include/physics_effects/base_level/base/pfx_common.h"
|
||||
#include "../../../include/physics_effects/low_level/task/pfx_pthreads.h"
|
||||
#include "../../../include/physics_effects/low_level/task/pfx_sync_components.h"
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsBarrier
|
||||
//
|
||||
/// Implementation of a barrier using pthreads. This version uses a mutex
|
||||
/// and condition variable rather than using native pthreads barrier, which
|
||||
/// enables it to be used on platforms that don't support pthreads barriers
|
||||
/// (such as Android 2.3x)
|
||||
//----------------------------------------------------------------------------
|
||||
class PfxPthreadsBarrier : public PfxBarrier
|
||||
{
|
||||
public:
|
||||
PfxPthreadsBarrier();
|
||||
virtual ~PfxPthreadsBarrier();
|
||||
|
||||
// from PfxBarrier
|
||||
virtual void sync();
|
||||
virtual void setMaxCount(int n);
|
||||
virtual int getMaxCount();
|
||||
|
||||
private:
|
||||
pthread_mutex_t m_mutex; ///< Mutex used to block worker threads
|
||||
pthread_cond_t m_cond; ///< Condition variable
|
||||
|
||||
int m_maxThreads; ///< Maximum number of worker threads
|
||||
int m_called; ///< Number of worker threads waiting at barrier
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsBarrier
|
||||
//
|
||||
/// Implementation of a critical section using pthreads.
|
||||
//----------------------------------------------------------------------------
|
||||
class PfxPthreadsCriticalSection : public PfxCriticalSection
|
||||
{
|
||||
public:
|
||||
PfxPthreadsCriticalSection();
|
||||
virtual ~PfxPthreadsCriticalSection();
|
||||
|
||||
// from PfxCriticalSection
|
||||
virtual PfxUInt32 getSharedParam(int i);
|
||||
virtual void setSharedParam(int i,PfxUInt32 p);
|
||||
|
||||
virtual void lock();
|
||||
virtual void unlock();
|
||||
|
||||
private:
|
||||
pthread_mutex_t m_mutex; ///< Mutex used to implement lock
|
||||
};
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
|
||||
#endif // _SCE_PFX_SYNC_COMPONENTS_PTHREADS_H
|
||||
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
Applied Research Associates Inc. (c)2011
|
||||
|
||||
Redistribution and use in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Applied Research Associates Inc nor the names
|
||||
of its contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef __ANDROID__
|
||||
|
||||
#include "../../../include/physics_effects/base_level/base/pfx_common.h"
|
||||
#include "../../../include/physics_effects/low_level/task/pfx_pthreads.h"
|
||||
#include "../../../include/physics_effects/low_level/task/pfx_task_manager.h"
|
||||
#include "../../../include/physics_effects/low_level/task/pfx_sync_components.h"
|
||||
#include "pfx_sync_components_pthreads.h"
|
||||
|
||||
namespace sce {
|
||||
namespace PhysicsEffects {
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Standalone functions and structs
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsThreadData
|
||||
//
|
||||
/// Struct to store information needed by worker threads
|
||||
//----------------------------------------------------------------------------
|
||||
struct PfxPthreadsThreadData
|
||||
{
|
||||
// task runner information
|
||||
PfxTaskArg *taskargument; ///< Pointer to argument for the task entry function
|
||||
PfxTaskEntry taskEntry; ///< Pointer to current task entry function
|
||||
|
||||
// pthreads synchronization and thread info
|
||||
pthread_t thread; ///< Current thread
|
||||
sem_t semaphore; ///< Semaphore used to wake the thread
|
||||
sem_t *taskmanagersemaphore; ///< Semaphore used to notify parent thread
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsThreadFunction
|
||||
//
|
||||
/// The thread function used for threads created and managed using a
|
||||
/// PfxPthreadsThreadPool
|
||||
//----------------------------------------------------------------------------
|
||||
void *PfxPthreadsThreadFunction(void *argument)
|
||||
{
|
||||
PfxPthreadsThreadData *threaddata = (PfxPthreadsThreadData*)argument;
|
||||
|
||||
while (1)
|
||||
{
|
||||
// wait until a task is available
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(sem_wait(&threaddata->semaphore));
|
||||
|
||||
// do work
|
||||
if (threaddata->taskEntry)
|
||||
threaddata->taskEntry(threaddata->taskargument);
|
||||
|
||||
// notify threadpool that task is done
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(sem_post(threaddata->taskmanagersemaphore));
|
||||
|
||||
// If no task, then exit
|
||||
if (!threaddata->taskEntry)
|
||||
pthread_exit(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Class definitions
|
||||
//----------------------------------------------------------------------------
|
||||
class PfxPthreadsTaskManager : public PfxTaskManager
|
||||
{
|
||||
public:
|
||||
PfxPthreadsTaskManager(PfxUInt32 numTasks, PfxUInt32 maxTasks, void *workBuff, PfxUInt32 workBytes) :
|
||||
PfxTaskManager(numTasks, maxTasks, workBuff, workBytes),
|
||||
m_threads(NULL) {}
|
||||
|
||||
// from PfxTaskManager
|
||||
virtual PfxUInt32 getSharedParam(int i);
|
||||
virtual void setSharedParam(int i, PfxUInt32 p);
|
||||
virtual void startTask(int taskId, void *io, PfxUInt32 data1, PfxUInt32 data2,
|
||||
PfxUInt32 data3, PfxUInt32 data4);
|
||||
virtual void waitTask(int &taskId, PfxUInt32 &data1, PfxUInt32 &data2,
|
||||
PfxUInt32 &data3, PfxUInt32 &data4);
|
||||
|
||||
virtual void initialize();
|
||||
virtual void finalize();
|
||||
|
||||
protected:
|
||||
PfxPthreadsTaskManager() : PfxTaskManager(), m_threads(NULL) {}
|
||||
|
||||
private:
|
||||
PfxPthreadsThreadData *m_threads; ///< Pointer to array of running threads (count is m_numThreads);
|
||||
PfxPthreadsBarrier m_barrier; ///< Barrier used to sync task groups
|
||||
PfxPthreadsCriticalSection m_cs; ///< Critical section used to manage shared parameters
|
||||
sem_t m_taskmanagersemaphore; ///< Synchronization semaphore for task manager
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsTaskManager
|
||||
//
|
||||
/// Implementation of a task manager using pthreads.
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsTaskManager::initialize
|
||||
//
|
||||
/// Initialize the task manager
|
||||
//----------------------------------------------------------------------------
|
||||
void PfxPthreadsTaskManager::initialize()
|
||||
{
|
||||
if (0 == m_maxTasks)
|
||||
return;
|
||||
|
||||
if (m_threads) // already started
|
||||
{
|
||||
SCE_PFX_PRINTF("PfxPthreadsThreadPool attempt to start threads when they are already started, line %i, file %s\n", __LINE__, __FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
m_threads = (PfxPthreadsThreadData*)m_pool.allocate(sizeof(PfxPthreadsThreadData)*m_maxTasks);
|
||||
if (!m_threads)
|
||||
{
|
||||
SCE_PFX_PRINTF("PfxPthreadsThreadPool unable to allocate threads at line %i in file %s\n", __LINE__, __FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
m_barrier.setMaxCount(m_maxTasks);
|
||||
|
||||
// Initialize sync semaphore
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(sem_init(&m_taskmanagersemaphore, 0, 0));
|
||||
|
||||
// Allocate and start the threads
|
||||
for (unsigned int i = 0; i < m_maxTasks; i++)
|
||||
{
|
||||
// Prepare argument data structure for task entry functions. Mostly, this is
|
||||
// setting parameters that are fixed until the simulation ends
|
||||
m_taskArg[i].taskId = i;
|
||||
m_taskArg[i].maxTasks = m_maxTasks;
|
||||
m_taskArg[i].barrier = &m_barrier;
|
||||
m_taskArg[i].criticalSection = &m_cs;
|
||||
m_taskArg[i].io = NULL;
|
||||
|
||||
// Prepare other per-thread data
|
||||
m_threads[i].taskEntry = NULL;
|
||||
m_threads[i].taskargument = &m_taskArg[i];
|
||||
m_threads[i].taskmanagersemaphore = &m_taskmanagersemaphore;
|
||||
|
||||
// Now create the thread's semaphore, then start the thread
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(sem_init(&m_threads[i].semaphore, 0, 0));
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(pthread_create(&m_threads[i].thread, NULL, PfxPthreadsThreadFunction, (void*)&m_threads[i]));
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsTaskManager::finalize
|
||||
//
|
||||
/// Finalize the task manager
|
||||
//----------------------------------------------------------------------------
|
||||
void PfxPthreadsTaskManager::finalize()
|
||||
{
|
||||
// stop the threads
|
||||
for (unsigned int i = 0; i < m_maxTasks; i++)
|
||||
{
|
||||
m_threads[i].taskEntry = NULL; // NULL task tells thread to exit
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(sem_post(&m_threads[i].semaphore));
|
||||
}
|
||||
|
||||
// wait for them all to exit
|
||||
for (unsigned int i = 0; i < m_maxTasks; i++)
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(sem_wait(&m_taskmanagersemaphore));
|
||||
|
||||
// destroy per-thread semaphores
|
||||
for (unsigned int i = 0; i < m_maxTasks; i++)
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(sem_destroy(&m_threads[i].semaphore));
|
||||
|
||||
// delete thread pool
|
||||
delete [] m_threads;
|
||||
m_threads = NULL;
|
||||
|
||||
// destroy task manager semaphore and reset barrier
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(sem_destroy(&m_taskmanagersemaphore));
|
||||
|
||||
m_barrier.setMaxCount(0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsTaskManager::startTask
|
||||
//
|
||||
/// Start a task
|
||||
///
|
||||
/// @param taskId [in] task thread identifier/index
|
||||
/// @param io [in, out] task input and output buffer
|
||||
/// @param data1 [in] first of four user parameter data values for the task
|
||||
/// @param data2 [in] second of four user parameter data values for the task
|
||||
/// @param data3 [in] third of four user parameter data values for the task
|
||||
/// @param data4 [in] fourth of four user parameter data values for the task
|
||||
//----------------------------------------------------------------------------
|
||||
void PfxPthreadsTaskManager::startTask(int taskId,void *io,PfxUInt32 data1,
|
||||
PfxUInt32 data2,PfxUInt32 data3,PfxUInt32 data4)
|
||||
{
|
||||
m_threads[taskId].taskEntry = m_taskEntry;
|
||||
m_taskArg[taskId].io = io;
|
||||
m_taskArg[taskId].data[0] = data1;
|
||||
m_taskArg[taskId].data[1] = data2;
|
||||
m_taskArg[taskId].data[2] = data3;
|
||||
m_taskArg[taskId].data[3] = data4;
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(sem_post(&m_threads[taskId].semaphore));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsTaskManager::waitTask
|
||||
//
|
||||
/// Wait for a task to finish
|
||||
///
|
||||
/// @param taskId [out] task thread identifier/index
|
||||
/// @param data1 [out] first of four data values from the task
|
||||
/// @param data2 [out] second of four data values from the task
|
||||
/// @param data3 [out] third of four data values from the task
|
||||
/// @param data4 [out] fourth of four data values from the task
|
||||
//----------------------------------------------------------------------------
|
||||
void PfxPthreadsTaskManager::waitTask(int &taskId,PfxUInt32 &data1,PfxUInt32 &data2,
|
||||
PfxUInt32 &data3,PfxUInt32 &data4)
|
||||
{
|
||||
SCE_PFX_CHECK_PTHREADS_OUTCOME(sem_wait(&m_taskmanagersemaphore));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsTaskManager::getSharedParam
|
||||
//
|
||||
/// Get the value of a shared parameter
|
||||
///
|
||||
/// @param i index of shared parameter to retrieve. Must have value
|
||||
/// between 0 and 31
|
||||
///
|
||||
/// @return Shared parameter value
|
||||
//----------------------------------------------------------------------------
|
||||
PfxUInt32 PfxPthreadsTaskManager::getSharedParam(int i)
|
||||
{
|
||||
m_cs.lock();
|
||||
PfxUInt32 paramval = m_cs.getSharedParam(i);
|
||||
m_cs.unlock();
|
||||
return(paramval);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxPthreadsTaskManager::setSharedParam
|
||||
//
|
||||
/// Set the value of a shared parameter
|
||||
///
|
||||
/// @param i index of shared parameter to set. Must have value
|
||||
/// between 0 and 31
|
||||
/// @param p Value to assign to shared parameter
|
||||
//----------------------------------------------------------------------------
|
||||
void PfxPthreadsTaskManager::setSharedParam(int i, PfxUInt32 p)
|
||||
{
|
||||
m_cs.lock();
|
||||
PfxUInt32 paramval = m_cs.getSharedParam(i);
|
||||
m_cs.setSharedParam(i, p);
|
||||
m_cs.unlock();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Factory functions
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PfxCreateTaskManagerPthreads
|
||||
//
|
||||
/// Factory function to create a pthreads-based task manager
|
||||
///
|
||||
/// @param numTasks number of tasks
|
||||
/// @param maxTasks max number of tasks
|
||||
/// @param workBuff work buffer
|
||||
/// @param workBytes size of work buffer, in bytes
|
||||
//----------------------------------------------------------------------------
|
||||
PfxTaskManager *PfxCreateTaskManagerPthreads(PfxUInt32 numTasks,PfxUInt32 maxTasks,
|
||||
void *workBuff,PfxUInt32 workBytes)
|
||||
{
|
||||
PfxTaskManager *taskmanager = new PfxPthreadsTaskManager(numTasks, maxTasks,
|
||||
workBuff, workBytes);
|
||||
return(taskmanager);
|
||||
}
|
||||
|
||||
} //namespace PhysicsEffects
|
||||
} //namespace sce
|
||||
|
||||
#endif //__ANDROID__
|
||||
Reference in New Issue
Block a user