aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/LowLevel
diff options
context:
space:
mode:
Diffstat (limited to 'PhysX_3.4/Source/LowLevel')
-rw-r--r--PhysX_3.4/Source/LowLevel/API/include/PxsMaterialCore.h166
-rw-r--r--PhysX_3.4/Source/LowLevel/API/include/PxsMaterialManager.h149
-rw-r--r--PhysX_3.4/Source/LowLevel/API/include/PxvConfig.h47
-rw-r--r--PhysX_3.4/Source/LowLevel/API/include/PxvContext.h73
-rw-r--r--PhysX_3.4/Source/LowLevel/API/include/PxvDynamics.h157
-rw-r--r--PhysX_3.4/Source/LowLevel/API/include/PxvGeometry.h94
-rw-r--r--PhysX_3.4/Source/LowLevel/API/include/PxvGlobals.h118
-rw-r--r--PhysX_3.4/Source/LowLevel/API/include/PxvManager.h239
-rw-r--r--PhysX_3.4/Source/LowLevel/API/include/PxvSimStats.h114
-rw-r--r--PhysX_3.4/Source/LowLevel/API/src/px_globals.cpp135
-rw-r--r--PhysX_3.4/Source/LowLevel/common/include/collision/PxcContactMethodImpl.h98
-rw-r--r--PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcCCDStateStreamPair.h29
-rw-r--r--PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcConstraintBlockStream.h166
-rw-r--r--PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcContactCache.h64
-rw-r--r--PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcMaterialMethodImpl.h69
-rw-r--r--PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpBatch.h65
-rw-r--r--PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpCache.h154
-rw-r--r--PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpCacheStreamPair.h63
-rw-r--r--PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpContactPrepShared.h59
-rw-r--r--PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpMemBlockPool.h119
-rw-r--r--PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpThreadContext.h216
-rw-r--r--PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpWorkUnit.h162
-rw-r--r--PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcRigidBody.h117
-rw-r--r--PhysX_3.4/Source/LowLevel/common/include/utils/PxcScratchAllocator.h138
-rw-r--r--PhysX_3.4/Source/LowLevel/common/include/utils/PxcThreadCoherentCache.h150
-rw-r--r--PhysX_3.4/Source/LowLevel/common/src/collision/PxcContact.cpp289
-rw-r--r--PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcContactCache.cpp393
-rw-r--r--PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcContactMethodImpl.cpp279
-rw-r--r--PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialHeightField.cpp116
-rw-r--r--PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialMesh.cpp107
-rw-r--r--PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialMethodImpl.cpp140
-rw-r--r--PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialShape.cpp62
-rw-r--r--PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpBatch.cpp413
-rw-r--r--PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpCacheStreamPair.cpp75
-rw-r--r--PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpContactPrepShared.cpp623
-rw-r--r--PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpMemBlockPool.cpp351
-rw-r--r--PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpThreadContext.cpp93
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxsBodySim.h52
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxsCCD.h617
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxsContactManager.h178
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxsContactManagerState.h95
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxsContext.h369
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxsDefaultMemoryManager.h98
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxsHeapMemoryAllocator.h68
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxsIncrementalConstraintPartitioning.h40
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxsIslandManagerTypes.h372
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxsIslandSim.h965
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxsKernelWrangler.h50
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxsMaterialCombiner.h143
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxsMemoryManager.h62
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxsNphaseImplementationContext.h142
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxsRigidBody.h168
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxsShapeSim.h52
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxsSimpleIslandManager.h207
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxsSimulationController.h135
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxsTransformCache.h144
-rw-r--r--PhysX_3.4/Source/LowLevel/software/include/PxvNphaseImplementationContext.h220
-rw-r--r--PhysX_3.4/Source/LowLevel/software/src/PxsCCD.cpp2020
-rw-r--r--PhysX_3.4/Source/LowLevel/software/src/PxsContactManager.cpp87
-rw-r--r--PhysX_3.4/Source/LowLevel/software/src/PxsContext.cpp641
-rw-r--r--PhysX_3.4/Source/LowLevel/software/src/PxsDefaultMemoryManager.cpp74
-rw-r--r--PhysX_3.4/Source/LowLevel/software/src/PxsIslandSim.cpp2299
-rw-r--r--PhysX_3.4/Source/LowLevel/software/src/PxsMaterialCombiner.cpp102
-rw-r--r--PhysX_3.4/Source/LowLevel/software/src/PxsNphaseImplementationContext.cpp952
-rw-r--r--PhysX_3.4/Source/LowLevel/software/src/PxsSimpleIslandManager.cpp369
65 files changed, 16623 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/LowLevel/API/include/PxsMaterialCore.h b/PhysX_3.4/Source/LowLevel/API/include/PxsMaterialCore.h
new file mode 100644
index 00000000..20562783
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/API/include/PxsMaterialCore.h
@@ -0,0 +1,166 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXS_MATERIAL_H
+#define PXS_MATERIAL_H
+
+#include "foundation/PxVec3.h"
+#include "PxMaterial.h"
+#include "PsUserAllocated.h"
+#include "CmPhysXCommon.h"
+#include "PxMetaData.h"
+#include "PsUtilities.h"
+
+namespace physx
+{
+
+#define MATERIAL_INVALID_HANDLE 0xffffffff
+
+ //PX_ALIGN_PREFIX(16) struct PxsMaterialData
+ //{
+ // PxReal dynamicFriction;
+ // PxReal staticFriction;
+ // PxReal restitution;
+ // PxReal dynamicFrictionV;
+ // PxReal staticFrictionV;
+ // PxVec3 dirOfAnisotropy;//might need to get rid of this
+ // PxCombineMode::Enum frictionCombineMode;
+ // PxCombineMode::Enum restitutionCombineMode;
+
+ // PxMaterialFlags flags;
+ // PxU8 paddingFromFlags[2];
+ // PxU32 pads;
+
+ // PxsMaterialData()
+ // : dynamicFriction(0.0)
+ // , staticFriction(0.0f)
+ // , restitution(0.0f)
+ // , dynamicFrictionV(0.0f)
+ // , staticFrictionV(0.0f)
+ // , dirOfAnisotropy(1,0,0)
+ // , frictionCombineMode(PxCombineMode::eAVERAGE)
+ // , restitutionCombineMode(PxCombineMode::eAVERAGE)
+ // {}
+
+ // PX_FORCE_INLINE PxCombineMode::Enum getFrictionCombineMode() const
+ // {
+ // return frictionCombineMode;
+ // }
+
+ //
+ // PX_FORCE_INLINE PxCombineMode::Enum getRestitutionCombineMode() const
+ // {
+ // return restitutionCombineMode;
+ // }
+
+ // PX_FORCE_INLINE void setFrictionCombineMode(PxCombineMode::Enum frictionFlags)
+ // {
+ // frictionCombineMode = frictionFlags;
+ // }
+
+ // PX_FORCE_INLINE void setRestitutionCombineMode(PxCombineMode::Enum restitutionFlags)
+ // {
+ // restitutionCombineMode = restitutionFlags;
+ // }
+
+ //}PX_ALIGN_SUFFIX(16);
+
+ PX_ALIGN_PREFIX(16) struct PxsMaterialData
+ {
+ PxReal dynamicFriction; //4
+ PxReal staticFriction; //8
+ PxReal restitution; //12
+ PxMaterialFlags flags; //14
+ PxU8 fricRestCombineMode; //15
+ PxU8 padding; //16
+
+ PxsMaterialData()
+ : dynamicFriction(0.0)
+ , staticFriction(0.0f)
+ , restitution(0.0f)
+ , fricRestCombineMode((PxCombineMode::eAVERAGE << 4) | PxCombineMode::eAVERAGE)
+ {}
+
+ PxsMaterialData(const PxEMPTY) {}
+
+ PX_CUDA_CALLABLE PX_FORCE_INLINE PxCombineMode::Enum getFrictionCombineMode() const
+ {
+ return PxCombineMode::Enum(fricRestCombineMode >> 4);
+ }
+
+ PX_CUDA_CALLABLE PX_FORCE_INLINE PxCombineMode::Enum getRestitutionCombineMode() const
+ {
+ return PxCombineMode::Enum(fricRestCombineMode & 0xf);
+ }
+
+ PX_FORCE_INLINE void setFrictionCombineMode(PxCombineMode::Enum frictionFlags)
+ {
+ fricRestCombineMode = Ps::to8((fricRestCombineMode & 0xf) | (frictionFlags << 4));
+ }
+
+ PX_FORCE_INLINE void setRestitutionCombineMode(PxCombineMode::Enum restitutionFlags)
+ {
+ fricRestCombineMode = Ps::to8((fricRestCombineMode & 0xf0) | (restitutionFlags));
+ }
+
+ }PX_ALIGN_SUFFIX(16);
+
+
+ class PxsMaterialCore : public PxsMaterialData, public Ps::UserAllocated
+ {
+ public:
+
+ PxsMaterialCore(const PxsMaterialData& desc): PxsMaterialData(desc), mNxMaterial(0), mMaterialIndex(MATERIAL_INVALID_HANDLE)
+ {
+ }
+
+ PxsMaterialCore(): mNxMaterial(0), mMaterialIndex(MATERIAL_INVALID_HANDLE)
+ {
+ }
+
+ PxsMaterialCore(const PxEMPTY) : PxsMaterialData(PxEmpty) {}
+
+ ~PxsMaterialCore()
+ {
+ }
+
+ PX_FORCE_INLINE void setNxMaterial(PxMaterial* m) { mNxMaterial = m; }
+ PX_FORCE_INLINE PxMaterial* getNxMaterial() const { return mNxMaterial; }
+ PX_FORCE_INLINE void setMaterialIndex(const PxU32 materialIndex) { mMaterialIndex = materialIndex; }
+ PX_FORCE_INLINE PxU32 getMaterialIndex() const { return mMaterialIndex; }
+
+ protected:
+ PxMaterial* mNxMaterial;
+ PxU32 mMaterialIndex; //handle assign by the handle manager
+ };
+
+} //namespace phyxs
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/API/include/PxsMaterialManager.h b/PhysX_3.4/Source/LowLevel/API/include/PxsMaterialManager.h
new file mode 100644
index 00000000..c3e6bd9e
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/API/include/PxsMaterialManager.h
@@ -0,0 +1,149 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXS_MATERIALMANAGER
+#define PXS_MATERIALMANAGER
+
+#include "PxsMaterialCore.h"
+#include "PsAlignedMalloc.h"
+
+namespace physx
+{
+ struct PxsMaterialInfo
+ {
+ PxU16 mMaterialIndex0;
+ PxU16 mMaterialIndex1;
+ };
+
+ class PxsMaterialManager
+ {
+ public:
+ PxsMaterialManager()
+ {
+ const PxU32 matCount = 128;
+ materials = reinterpret_cast<PxsMaterialCore*>(physx::shdfnd::AlignedAllocator<16>().allocate(sizeof(PxsMaterialCore)*matCount, __FILE__, __LINE__));
+ maxMaterials = matCount;
+ for(PxU32 i=0; i<matCount; ++i)
+ {
+ materials[i].setMaterialIndex(MATERIAL_INVALID_HANDLE);
+ }
+ }
+
+ ~PxsMaterialManager()
+ {
+ physx::shdfnd::AlignedAllocator<16>().deallocate(materials);
+ }
+
+ void setMaterial(PxsMaterialCore* mat)
+ {
+ const PxU32 materialIndex = mat->getMaterialIndex();
+ resize(materialIndex+1);
+ materials[materialIndex] = *mat;
+ }
+
+ void updateMaterial(PxsMaterialCore* mat)
+ {
+ materials[mat->getMaterialIndex()] =*mat;
+ }
+
+ void removeMaterial(PxsMaterialCore* mat)
+ {
+ mat->setMaterialIndex(MATERIAL_INVALID_HANDLE);
+ }
+
+ PX_FORCE_INLINE PxsMaterialCore* getMaterial(const PxU32 index)const
+ {
+ PX_ASSERT(index < maxMaterials);
+ return &materials[index];
+ }
+
+ PxU32 getMaxSize()const
+ {
+ return maxMaterials;
+ }
+
+ void resize(PxU32 minValueForMax)
+ {
+ if(maxMaterials>=minValueForMax)
+ return;
+
+ const PxU32 numMaterials = maxMaterials;
+
+ maxMaterials = (minValueForMax+31)&~31;
+ PxsMaterialCore* mat = reinterpret_cast<PxsMaterialCore*>(physx::shdfnd::AlignedAllocator<16>().allocate(sizeof(PxsMaterialCore)*maxMaterials, __FILE__, __LINE__));
+ for(PxU32 i=0; i<numMaterials; ++i)
+ {
+ mat[i] = materials[i];
+ }
+ for(PxU32 i = numMaterials; i < maxMaterials; ++i)
+ {
+ mat[i].setMaterialIndex(MATERIAL_INVALID_HANDLE);
+ }
+
+ physx::shdfnd::AlignedAllocator<16>().deallocate(materials);
+
+ materials = mat;
+ }
+
+ PxsMaterialCore* materials;//make sure materials's start address is 16 bytes align
+ PxU32 maxMaterials;
+ PxU32 mPad[2];
+ };
+
+ class PxsMaterialManagerIterator
+ {
+
+ public:
+ PxsMaterialManagerIterator(PxsMaterialManager& manager) : mManager(manager), mIndex(0)
+ {
+ }
+
+ bool getNextMaterial(PxsMaterialCore*& materialCore)
+ {
+ const PxU32 maxSize = mManager.getMaxSize();
+ PxU32 index = mIndex;
+ while(index < maxSize && mManager.getMaterial(index)->getMaterialIndex() == MATERIAL_INVALID_HANDLE)
+ index++;
+ materialCore = NULL;
+ if(index < maxSize)
+ materialCore = mManager.getMaterial(index++);
+ mIndex = index;
+ return materialCore!=NULL;
+ }
+
+ private:
+ PxsMaterialManagerIterator& operator=(const PxsMaterialManagerIterator&);
+ PxsMaterialManager& mManager;
+ PxU32 mIndex;
+ };
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/API/include/PxvConfig.h b/PhysX_3.4/Source/LowLevel/API/include/PxvConfig.h
new file mode 100644
index 00000000..cbac7a7c
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/API/include/PxvConfig.h
@@ -0,0 +1,47 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXD_CONFIG_H
+#define PXD_CONFIG_H
+
+/*! \file internal top level include file for lowlevel. */
+
+#include "CmPhysXCommon.h"
+#include "PxPhysXConfig.h"
+
+/************************************************************************/
+/* Compiler workarounds */
+/************************************************************************/
+#if PX_VC
+#pragma warning(disable: 4355 ) // "this" used in base member initializer list
+#pragma warning(disable: 4146 ) // unary minus operator applied to unsigned type.
+#endif
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/API/include/PxvContext.h b/PhysX_3.4/Source/LowLevel/API/include/PxvContext.h
new file mode 100644
index 00000000..b37dbaf3
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/API/include/PxvContext.h
@@ -0,0 +1,73 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXV_CONTEXT_H
+#define PXV_CONTEXT_H
+
+#include "task/PxTask.h"
+#include "PxvGlobals.h"
+#include "PxvSimStats.h"
+
+namespace physx
+{
+
+class PxsContext;
+
+class PxContactModifyCallback;
+class PxsRigidBody;
+struct PxsBodyCore;
+class PxvParticleSystemSim;
+class BroadPhase;
+
+class PxsContactManager;
+struct PxvManagerDescRigidRigid;
+struct PxvContactManagerTouchEvent;
+
+/*!
+\file
+Context handling
+*/
+
+/************************************************************************/
+/* Context handling, types */
+/************************************************************************/
+
+enum PxvContextProperty
+{
+ /**
+ Float value for sweep epsilon distance. Default is 0. (not a good idea to leave unchanged)
+ */
+ PXD_CONTEXT_SWEEP_EPSILON_DISTANCE
+
+};
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/API/include/PxvDynamics.h b/PhysX_3.4/Source/LowLevel/API/include/PxvDynamics.h
new file mode 100644
index 00000000..a5085994
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/API/include/PxvDynamics.h
@@ -0,0 +1,157 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXV_DYNAMICS_H
+#define PXV_DYNAMICS_H
+
+#include "foundation/PxVec3.h"
+#include "foundation/PxQuat.h"
+#include "foundation/PxTransform.h"
+#include "foundation/PxSimpleTypes.h"
+#include "PsIntrinsics.h"
+#include "PxRigidDynamic.h"
+
+namespace physx
+{
+
+/*!
+\file
+Dynamics interface.
+*/
+
+/************************************************************************/
+/* Atoms */
+/************************************************************************/
+
+class PxsContext;
+class PxsRigidBody;
+class PxShape;
+class PxGeometry;
+struct PxsShapeCore;
+
+
+struct PxsRigidCore
+{
+//= ATTENTION! =====================================================================================
+// Changing the data layout of this class breaks the binary serialization format. See comments for
+// PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData
+// function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION
+// accordingly.
+//==================================================================================================
+
+ PxsRigidCore() : mFlags(0), mIdtBody2Actor(0) {}
+ PxsRigidCore(const PxEMPTY) : mFlags(PxEmpty) {}
+
+ PX_ALIGN_PREFIX(16)
+ PxTransform body2World PX_ALIGN_SUFFIX(16);
+ PxRigidBodyFlags mFlags; // API body flags
+ PxU8 mIdtBody2Actor; // PT: true if PxsBodyCore::body2Actor is identity
+ PxU16 solverIterationCounts; //vel iters are in low word and pos iters in high word.
+
+ PX_FORCE_INLINE PxU32 isKinematic() const
+ {
+ return mFlags & PxRigidBodyFlag::eKINEMATIC;
+ }
+
+ PX_FORCE_INLINE PxU32 hasCCD() const
+ {
+ return mFlags & PxRigidBodyFlag::eENABLE_CCD;
+ }
+
+ PX_FORCE_INLINE PxU32 hasCCDFriction() const
+ {
+ return mFlags & PxRigidBodyFlag::eENABLE_CCD_FRICTION;
+ }
+};
+PX_COMPILE_TIME_ASSERT(sizeof(PxsRigidCore) == 32);
+
+
+struct PxsBodyCore: public PxsRigidCore
+{
+//= ATTENTION! =====================================================================================
+// Changing the data layout of this class breaks the binary serialization format. See comments for
+// PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData
+// function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION
+// accordingly.
+//==================================================================================================
+
+ PxsBodyCore() : PxsRigidCore() {}
+ PxsBodyCore(const PxEMPTY) : PxsRigidCore(PxEmpty) {}
+
+ PX_FORCE_INLINE const PxTransform& getBody2Actor() const { return body2Actor; }
+ PX_FORCE_INLINE void setBody2Actor(const PxTransform& t)
+ {
+ mIdtBody2Actor = PxU8(t.p.isZero() && t.q.isIdentity());
+
+ body2Actor = t;
+ }
+ protected:
+ PxTransform body2Actor;
+ public:
+ PxReal ccdAdvanceCoefficient; //64
+
+ PxVec3 linearVelocity;
+ PxReal maxPenBias;
+
+ PxVec3 angularVelocity;
+ PxReal contactReportThreshold; //96
+
+ PxReal maxAngularVelocitySq;
+ PxReal maxLinearVelocitySq;
+ PxReal linearDamping;
+ PxReal angularDamping; //112
+
+ PxVec3 inverseInertia;
+ PxReal inverseMass; //128
+
+ PxReal maxContactImpulse;
+ PxReal sleepThreshold;
+ PxReal freezeThreshold;
+ PxReal wakeCounter; //144 this is authoritative wakeCounter
+
+ PxReal solverWakeCounter; //this is calculated by the solver when it performs sleepCheck. It is committed to wakeCounter in ScAfterIntegrationTask if the body is still awake.
+ PxU32 numCountedInteractions;
+ PxU32 numBodyInteractions; //Used by adaptive force to keep track of the total number of body interactions
+ PxU16 isFastMoving; //This could be a single bit but it's a u32 at the moment for simplicity's sake
+ PxRigidDynamicLockFlags lockFlags; //160 This could be a u8 but it is a u32 for simplicity's sake. All fits into 16 byte alignment
+
+ PX_FORCE_INLINE bool shouldCreateContactReports() const
+ {
+ const PxU32* binary = reinterpret_cast<const PxU32*>(&contactReportThreshold);
+ return *binary != 0x7f7fffff; // PX_MAX_REAL
+ }
+};
+
+PX_COMPILE_TIME_ASSERT(sizeof(PxsBodyCore) == 160);
+
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/API/include/PxvGeometry.h b/PhysX_3.4/Source/LowLevel/API/include/PxvGeometry.h
new file mode 100644
index 00000000..5ddf3ab8
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/API/include/PxvGeometry.h
@@ -0,0 +1,94 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXV_GEOMETRY_H
+#define PXV_GEOMETRY_H
+
+#include "foundation/PxTransform.h"
+#include "PxvConfig.h"
+
+namespace physx
+{
+
+class PxsRigidBody;
+class PxvParticleSystem;
+
+namespace Gu
+{
+ struct ConvexHullData;
+ class TriangleMesh;
+ struct HeightFieldData;
+}
+
+}
+
+/*!
+\file
+Geometry interface
+*/
+
+/************************************************************************/
+/* Shapes */
+/************************************************************************/
+
+// moved to
+#include "GuGeometryUnion.h"
+
+namespace physx
+{
+
+struct PxsShapeCore
+{
+//= ATTENTION! =====================================================================================
+// Changing the data layout of this class breaks the binary serialization format. See comments for
+// PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData
+// function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION
+// accordingly.
+//==================================================================================================
+
+// PX_SERIALIZATION
+ PxsShapeCore() {}
+ PxsShapeCore(const PxEMPTY) : geometry(PxEmpty) {}
+//~PX_SERIALIZATION
+
+ PX_ALIGN_PREFIX(16)
+ PxTransform transform PX_ALIGN_SUFFIX(16);
+ PxReal contactOffset;
+ PxU8 mShapeFlags; // !< API shape flags // PT: TODO: use PxShapeFlags here. Needs to move flags to separate file.
+ PxU8 mOwnsMaterialIdxMemory; // PT: for de-serialization to avoid deallocating material index list. Moved there from Sc::ShapeCore (since one byte was free).
+ PxU16 materialIndex;
+ Gu::GeometryUnion geometry;
+};
+
+PX_COMPILE_TIME_ASSERT( (sizeof(PxsShapeCore)&0xf) == 0);
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/API/include/PxvGlobals.h b/PhysX_3.4/Source/LowLevel/API/include/PxvGlobals.h
new file mode 100644
index 00000000..43353965
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/API/include/PxvGlobals.h
@@ -0,0 +1,118 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXD_INIT_H
+#define PXD_INIT_H
+
+#include "PxvConfig.h"
+#include "PsBasicTemplates.h"
+
+namespace physx
+{
+
+/*!
+\file
+PhysX Low-level, Memory management
+*/
+
+/************************************************************************/
+/* Error Handling */
+/************************************************************************/
+
+
+enum PxvErrorCode
+{
+ PXD_ERROR_NO_ERROR = 0,
+ PXD_ERROR_INVALID_PARAMETER,
+ PXD_ERROR_INVALID_PARAMETER_SIZE,
+ PXD_ERROR_INTERNAL_ERROR,
+ PXD_ERROR_NOT_IMPLEMENTED,
+ PXD_ERROR_NO_CONTEXT,
+ PXD_ERROR_NO_TASK_MANAGER,
+ PXD_ERROR_WARNING
+};
+
+class PxShape;
+class PxRigidActor;
+struct PxsShapeCore;
+struct PxsRigidCore;
+
+struct PxvOffsetTable
+{
+ PX_FORCE_INLINE PxvOffsetTable() {}
+
+ PX_FORCE_INLINE const PxShape* convertPxsShape2Px(const PxsShapeCore* pxs) const
+ {
+ return shdfnd::pointerOffset<const PxShape*>(pxs, pxsShapeCore2PxShape);
+ }
+
+ PX_FORCE_INLINE const PxRigidActor* convertPxsRigidCore2PxRigidBody(const PxsRigidCore* pxs) const
+ {
+ return shdfnd::pointerOffset<const PxRigidActor*>(pxs, pxsRigidCore2PxRigidBody);
+ }
+
+ PX_FORCE_INLINE const PxRigidActor* convertPxsRigidCore2PxRigidStatic(const PxsRigidCore* pxs) const
+ {
+ return shdfnd::pointerOffset<const PxRigidActor*>(pxs, pxsRigidCore2PxRigidStatic);
+ }
+
+ ptrdiff_t pxsShapeCore2PxShape;
+ ptrdiff_t pxsRigidCore2PxRigidBody;
+ ptrdiff_t pxsRigidCore2PxRigidStatic;
+};
+extern PxvOffsetTable gPxvOffsetTable;
+
+/*!
+Initialize low-level implementation.
+*/
+
+void PxvInit(const PxvOffsetTable& offsetTable);
+
+
+/*!
+Shut down low-level implementation.
+*/
+void PxvTerm();
+
+/*!
+Initialize low-level implementation.
+*/
+
+void PxvRegisterHeightFields();
+
+void PxvRegisterLegacyHeightFields();
+
+#if PX_SUPPORT_GPU_PHYSX
+class PxPhysXGpu* PxvGetPhysXGpu(bool createIfNeeded);
+#endif
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/API/include/PxvManager.h b/PhysX_3.4/Source/LowLevel/API/include/PxvManager.h
new file mode 100644
index 00000000..da8750be
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/API/include/PxvManager.h
@@ -0,0 +1,239 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXV_MANAGER_H
+#define PXV_MANAGER_H
+
+#include "foundation/PxVec3.h"
+#include "foundation/PxQuat.h"
+#include "foundation/PxTransform.h"
+#include "foundation/PxMemory.h"
+#include "PxvConfig.h"
+#include "PxvGeometry.h"
+
+namespace physx
+{
+
+class PxvContact;
+
+/*!
+\file
+Manager interface
+*/
+
+/************************************************************************/
+/* Managers */
+/************************************************************************/
+
+class PxsContactManager;
+class PxsContext;
+
+struct PxsRigidCore;
+struct PxsShapeCore;
+
+
+
+/*!
+Type of PXD_MANAGER_CCD_MODE property
+*/
+enum PxvContactManagerCCDMode
+{
+ PXD_MANAGER_CCD_NONE,
+ PXD_MANAGER_CCD_LINEAR
+};
+
+
+/*!
+Manager descriptor
+*/
+struct PxvManagerDescRigidRigid
+{
+ /*!
+ Manager user data
+
+ \sa PXD_MANAGER_USER_DATA
+ */
+ //void* userData;
+
+ /*!
+ Dominance setting for one way interactions.
+ A dominance of 0 means the corresp. body will
+ not be pushable by the other body in the constraint.
+ \sa PXD_MANAGER_DOMINANCE0
+ */
+ PxU8 dominance0;
+
+ /*!
+ Dominance setting for one way interactions.
+ A dominance of 0 means the corresp. body will
+ not be pushable by the other body in the constraint.
+ \sa PXD_MANAGER_DOMINANCE1
+ */
+ PxU8 dominance1;
+
+ /*!
+ PxsRigidBodies
+ */
+ PxsRigidBody* rigidBody0;
+ PxsRigidBody* rigidBody1;
+
+ /*!
+ Shape Core structures
+ */
+
+ const PxsShapeCore* shapeCore0;
+ const PxsShapeCore* shapeCore1;
+
+ /*!
+ Body Core structures
+ */
+
+ PxsRigidCore* rigidCore0;
+ PxsRigidCore* rigidCore1;
+
+ /*!
+ Enable contact information reporting.
+
+ */
+ int reportContactInfo;
+
+ /*!
+ Enable contact impulse threshold reporting.
+
+ */
+ int hasForceThreshold;
+
+ /*!
+ Enable generated contacts to be changeable
+
+ */
+ int contactChangeable;
+
+ /*!
+ Disable strong friction
+
+ */
+ //int disableStrongFriction;
+
+ /*!
+ Contact resolution rest distance.
+
+ */
+ PxReal restDistance;
+
+ /*!
+ Disable contact response
+
+ */
+ int disableResponse;
+
+ /*!
+ Disable discrete contact generation
+
+ */
+ int disableDiscreteContact;
+
+ /*!
+ Disable CCD contact generation
+
+ */
+ int disableCCDContact;
+
+ /*!
+ Is connected to an articulation (1 - first body, 2 - second body)
+
+ */
+ int hasArticulations;
+
+ /*!
+ is connected to a dynamic (1 - first body, 2 - second body)
+ */
+ int hasDynamics;
+
+ /*!
+ Is the pair touching? Use when re-creating the manager with prior knowledge about touch status.
+
+ positive: pair is touching
+ 0: touch state unknown (this is a new pair)
+ negative: pair is not touching
+
+ Default is 0
+ */
+ int hasTouch;
+
+ /*!
+ Identifies whether body 1 is kinematic. We can treat kinematics as statics and embed velocity into constraint
+ because kinematic bodies' velocities will not change
+ */
+ bool body1Kinematic;
+
+ /*
+ Index entries into the transform cache for shape 0
+ */
+
+ PxU32 transformCache0;
+
+ /*
+ Index entries into the transform cache for shape 1
+ */
+
+ PxU32 transformCache1;
+
+
+ PxvManagerDescRigidRigid()
+ {
+ PxMemSet(this, 0, sizeof(PxvManagerDescRigidRigid));
+
+ dominance0 = 1u;
+ dominance1 = 1u;
+ }
+};
+
+
+/*!
+Report struct for contact manager touch reports
+*/
+struct PxvContactManagerTouchEvent
+{
+ /*!
+ Manager handle
+ */
+ PxsContactManager* manager;
+
+ /*!
+ Manager userdata
+ */
+ void* userData;
+};
+
+}
+
+#endif
+
diff --git a/PhysX_3.4/Source/LowLevel/API/include/PxvSimStats.h b/PhysX_3.4/Source/LowLevel/API/include/PxvSimStats.h
new file mode 100644
index 00000000..4fba92f1
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/API/include/PxvSimStats.h
@@ -0,0 +1,114 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXV_SIM_STATS_H
+#define PXV_SIM_STATS_H
+
+#include "foundation/PxAssert.h"
+#include "foundation/PxMemory.h"
+#include "CmPhysXCommon.h"
+#include "PxGeometry.h"
+
+namespace physx
+{
+
+/*!
+\file
+Context handling
+*/
+
+/************************************************************************/
+/* Context handling, types */
+/************************************************************************/
+
+/*!
+Description: contains statistics for the simulation.
+*/
+struct PxvSimStats
+{
+ PxvSimStats() { clearAll(); }
+ void clearAll() { PxMemZero(this, sizeof(PxvSimStats)); } // set counters to zero
+
+ PX_FORCE_INLINE void incCCDPairs(PxGeometryType::Enum g0, PxGeometryType::Enum g1)
+ {
+ PX_ASSERT(g0 <= g1); // That's how they should be sorted
+ mNbCCDPairs[g0][g1]++;
+ }
+
+ PX_FORCE_INLINE void decCCDPairs(PxGeometryType::Enum g0, PxGeometryType::Enum g1)
+ {
+ PX_ASSERT(g0 <= g1); // That's how they should be sorted
+ PX_ASSERT(mNbCCDPairs[g0][g1]);
+ mNbCCDPairs[g0][g1]--;
+ }
+
+ PX_FORCE_INLINE void incModifiedContactPairs(PxGeometryType::Enum g0, PxGeometryType::Enum g1)
+ {
+ PX_ASSERT(g0 <= g1); // That's how they should be sorted
+ mNbModifiedContactPairs[g0][g1]++;
+ }
+
+ PX_FORCE_INLINE void decModifiedContactPairs(PxGeometryType::Enum g0, PxGeometryType::Enum g1)
+ {
+ PX_ASSERT(g0 <= g1); // That's how they should be sorted
+ PX_ASSERT(mNbModifiedContactPairs[g0][g1]);
+ mNbModifiedContactPairs[g0][g1]--;
+ }
+
+ // PT: those guys are now persistent and shouldn't be cleared each frame
+ PxU32 mNbDiscreteContactPairs [PxGeometryType::eGEOMETRY_COUNT][PxGeometryType::eGEOMETRY_COUNT];
+ PxU32 mNbCCDPairs [PxGeometryType::eGEOMETRY_COUNT][PxGeometryType::eGEOMETRY_COUNT];
+
+ PxU32 mNbModifiedContactPairs [PxGeometryType::eGEOMETRY_COUNT][PxGeometryType::eGEOMETRY_COUNT];
+
+ PxU32 mNbDiscreteContactPairsTotal; // PT: sum of mNbDiscreteContactPairs, i.e. number of pairs reaching narrow phase
+ PxU32 mNbDiscreteContactPairsWithCacheHits;
+ PxU32 mNbDiscreteContactPairsWithContacts;
+ PxU32 mNbActiveConstraints;
+ PxU32 mNbActiveDynamicBodies;
+ PxU32 mNbActiveKinematicBodies;
+
+ PxU32 mNbAxisSolverConstraints;
+ PxU32 mTotalCompressedContactSize;
+ PxU32 mTotalConstraintSize;
+ PxU32 mPeakConstraintBlockAllocations;
+
+ PxU32 mNbNewPairs;
+ PxU32 mNbLostPairs;
+
+ PxU32 mNbNewTouches;
+ PxU32 mNbLostTouches;
+
+ PxU32 mNbPartitions;
+};
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/API/src/px_globals.cpp b/PhysX_3.4/Source/LowLevel/API/src/px_globals.cpp
new file mode 100644
index 00000000..43809179
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/API/src/px_globals.cpp
@@ -0,0 +1,135 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PxvGlobals.h"
+#include "PxsContext.h"
+#include "PxcContactMethodImpl.h"
+#include "GuContactMethodImpl.h"
+
+
+#if PX_SUPPORT_GPU_PHYSX
+#include "PxPhysXGpu.h"
+
+physx::PxPhysXGpu* gPxPhysXGpu;
+#endif
+
+namespace physx
+{
+
+PxvOffsetTable gPxvOffsetTable;
+
+bool PxcLegacyContactSphereHeightField (GU_CONTACT_METHOD_ARGS);
+bool PxcLegacyContactCapsuleHeightField (GU_CONTACT_METHOD_ARGS);
+bool PxcLegacyContactBoxHeightField (GU_CONTACT_METHOD_ARGS);
+bool PxcLegacyContactConvexHeightField (GU_CONTACT_METHOD_ARGS);
+
+bool PxcPCMContactSphereHeightField (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactCapsuleHeightField (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactBoxHeightField (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactConvexHeightField (GU_CONTACT_METHOD_ARGS);
+
+bool PxcContactSphereHeightField (GU_CONTACT_METHOD_ARGS);
+bool PxcContactCapsuleHeightField (GU_CONTACT_METHOD_ARGS);
+bool PxcContactBoxHeightField (GU_CONTACT_METHOD_ARGS);
+bool PxcContactConvexHeightField (GU_CONTACT_METHOD_ARGS);
+
+bool gUnifiedHeightfieldCollision = false;
+
+void PxvRegisterHeightFields()
+{
+ g_ContactMethodTable[PxGeometryType::eSPHERE][PxGeometryType::eHEIGHTFIELD] = PxcContactSphereHeightField;
+ g_ContactMethodTable[PxGeometryType::eCAPSULE][PxGeometryType::eHEIGHTFIELD] = PxcContactCapsuleHeightField;
+ g_ContactMethodTable[PxGeometryType::eBOX][PxGeometryType::eHEIGHTFIELD] = PxcContactBoxHeightField;
+ g_ContactMethodTable[PxGeometryType::eCONVEXMESH][PxGeometryType::eHEIGHTFIELD] = PxcContactConvexHeightField;
+
+ g_PCMContactMethodTable[PxGeometryType::eSPHERE][PxGeometryType::eHEIGHTFIELD] = PxcPCMContactSphereHeightField;
+ g_PCMContactMethodTable[PxGeometryType::eCAPSULE][PxGeometryType::eHEIGHTFIELD] = PxcPCMContactCapsuleHeightField;
+ g_PCMContactMethodTable[PxGeometryType::eBOX][PxGeometryType::eHEIGHTFIELD] = PxcPCMContactBoxHeightField;
+ g_PCMContactMethodTable[PxGeometryType::eCONVEXMESH][PxGeometryType::eHEIGHTFIELD] = PxcPCMContactConvexHeightField;
+ gUnifiedHeightfieldCollision = true;
+}
+
+void PxvRegisterLegacyHeightFields()
+{
+ g_ContactMethodTable[PxGeometryType::eSPHERE][PxGeometryType::eHEIGHTFIELD] = PxcLegacyContactSphereHeightField;
+ g_ContactMethodTable[PxGeometryType::eCAPSULE][PxGeometryType::eHEIGHTFIELD] = PxcLegacyContactCapsuleHeightField;
+ g_ContactMethodTable[PxGeometryType::eBOX][PxGeometryType::eHEIGHTFIELD] = PxcLegacyContactBoxHeightField;
+ g_ContactMethodTable[PxGeometryType::eCONVEXMESH][PxGeometryType::eHEIGHTFIELD] = PxcLegacyContactConvexHeightField;
+
+ g_PCMContactMethodTable[PxGeometryType::eSPHERE][PxGeometryType::eHEIGHTFIELD] = PxcLegacyContactSphereHeightField;
+ g_PCMContactMethodTable[PxGeometryType::eCAPSULE][PxGeometryType::eHEIGHTFIELD] = PxcLegacyContactCapsuleHeightField;
+ g_PCMContactMethodTable[PxGeometryType::eBOX][PxGeometryType::eHEIGHTFIELD] = PxcLegacyContactBoxHeightField;
+ g_PCMContactMethodTable[PxGeometryType::eCONVEXMESH][PxGeometryType::eHEIGHTFIELD] = PxcLegacyContactConvexHeightField;
+ gUnifiedHeightfieldCollision = false;
+}
+
+void PxvInit(const PxvOffsetTable& offsetTable)
+{
+#if PX_SUPPORT_GPU_PHYSX
+ gPxPhysXGpu = NULL;
+#endif
+ gPxvOffsetTable = offsetTable;
+}
+
+void PxvTerm()
+{
+#if PX_SUPPORT_GPU_PHYSX
+ if (gPxPhysXGpu)
+ {
+ gPxPhysXGpu->release();
+ gPxPhysXGpu = NULL;
+ }
+#endif
+}
+
+}
+
+#if PX_SUPPORT_GPU_PHYSX
+namespace physx
+{
+ //forward declare stuff from PxPhysXGpuModuleLoader.cpp
+ void PxLoadPhysxGPUModule(const char* appGUID);
+ typedef physx::PxPhysXGpu* (PxCreatePhysXGpu_FUNC)();
+ extern PxCreatePhysXGpu_FUNC* g_PxCreatePhysXGpu_Func;
+
+ PxPhysXGpu* PxvGetPhysXGpu(bool createIfNeeded)
+ {
+ if (!gPxPhysXGpu && createIfNeeded)
+ {
+ PxLoadPhysxGPUModule(NULL);
+ if (g_PxCreatePhysXGpu_Func)
+ {
+ gPxPhysXGpu = g_PxCreatePhysXGpu_Func();
+ }
+ }
+
+ return gPxPhysXGpu;
+ }
+}
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/common/include/collision/PxcContactMethodImpl.h b/PhysX_3.4/Source/LowLevel/common/include/collision/PxcContactMethodImpl.h
new file mode 100644
index 00000000..193b20a5
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/include/collision/PxcContactMethodImpl.h
@@ -0,0 +1,98 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXC_CONTACTMETHODIMPL_H
+#define PXC_CONTACTMETHODIMPL_H
+
+#include "GuGeometryUnion.h"
+#include "CmPhysXCommon.h"
+#include "GuContactMethodImpl.h"
+
+namespace physx
+{
+namespace Cm
+{
+ class RenderOutput;
+}
+
+namespace Gu
+{
+ class ContactBuffer;
+ struct Cache;
+ struct NarrowPhaseParams;
+}
+
+struct PxcNpCache;
+class PxcNpThreadContext;
+class PxsContext;
+class PxcConvexTriangles;
+class PxsRigidBody;
+struct PxsCCDShape;
+
+namespace Cm
+{
+ class FastVertex2ShapeScaling;
+}
+
+/*!\file
+This file contains forward declarations of all implemented contact methods.
+*/
+
+
+/*! Parameter list without names to avoid unused parameter warnings
+*/
+#define CONTACT_METHOD_ARGS_UNUSED \
+ const Gu::GeometryUnion&, \
+ const Gu::GeometryUnion&, \
+ const PxTransform&, \
+ const PxTransform&, \
+ const Gu::NarrowPhaseParams&, \
+ Gu::Cache&, \
+ Gu::ContactBuffer&, \
+ Cm::RenderOutput*
+
+
+/*!
+Method prototype for contact generation routines
+*/
+typedef bool (*PxcContactMethod) (GU_CONTACT_METHOD_ARGS);
+
+
+// Matrix of types
+extern PxcContactMethod g_ContactMethodTable[][PxGeometryType::eGEOMETRY_COUNT];
+extern const bool g_CanUseContactCache[][PxGeometryType::eGEOMETRY_COUNT];
+extern PxcContactMethod g_PCMContactMethodTable[][PxGeometryType::eGEOMETRY_COUNT];
+
+extern bool gEnablePCMCaching[][PxGeometryType::eGEOMETRY_COUNT];
+
+extern bool gUnifiedHeightfieldCollision;
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcCCDStateStreamPair.h b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcCCDStateStreamPair.h
new file mode 100644
index 00000000..cf29bad0
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcCCDStateStreamPair.h
@@ -0,0 +1,29 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
diff --git a/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcConstraintBlockStream.h b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcConstraintBlockStream.h
new file mode 100644
index 00000000..37c0ba8e
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcConstraintBlockStream.h
@@ -0,0 +1,166 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+
+#ifndef PXC_CONSTRAINTBLOCKPOOL_H
+#define PXC_CONSTRAINTBLOCKPOOL_H
+
+#include "PxvConfig.h"
+#include "PsArray.h"
+#include "PsMutex.h"
+#include "PxcNpMemBlockPool.h"
+
+namespace physx
+{
+
+class PxsConstraintBlockManager
+{
+public:
+ PxsConstraintBlockManager(PxcNpMemBlockPool & blockPool):
+ mBlockPool(blockPool)
+ {
+ }
+
+
+ PX_FORCE_INLINE void reset()
+ {
+ mBlockPool.releaseConstraintBlocks(mTrackingArray);
+ }
+
+
+ PxcNpMemBlockArray mTrackingArray;
+ PxcNpMemBlockPool& mBlockPool;
+
+private:
+ PxsConstraintBlockManager& operator=(const PxsConstraintBlockManager&);
+};
+
+class PxcConstraintBlockStream
+{
+ PX_NOCOPY(PxcConstraintBlockStream)
+public:
+ PxcConstraintBlockStream(PxcNpMemBlockPool & blockPool):
+ mBlockPool(blockPool),
+ mBlock(NULL),
+ mUsed(0)
+ {
+ }
+
+ PX_FORCE_INLINE PxU8* reserve(PxU32 size, PxsConstraintBlockManager& manager)
+ {
+ size = (size+15)&~15;
+ if(size>PxcNpMemBlock::SIZE)
+ return mBlockPool.acquireExceptionalConstraintMemory(size);
+
+ if(mBlock == NULL || size+mUsed>PxcNpMemBlock::SIZE)
+ {
+ mBlock = mBlockPool.acquireConstraintBlock(manager.mTrackingArray);
+ PX_ASSERT(0==mBlock || mBlock->data == reinterpret_cast<PxU8*>(mBlock));
+ mUsed = size;
+ return reinterpret_cast<PxU8*>(mBlock);
+ }
+ PX_ASSERT(mBlock && mBlock->data == reinterpret_cast<PxU8*>(mBlock));
+ PxU8* PX_RESTRICT result = mBlock->data+mUsed;
+ mUsed += size;
+ return result;
+ }
+
+ PX_FORCE_INLINE void reset()
+ {
+ mBlock = NULL;
+ mUsed = 0;
+ }
+
+ PX_FORCE_INLINE PxcNpMemBlockPool& getMemBlockPool()
+ {
+ return mBlockPool;
+ }
+
+private:
+ PxcNpMemBlockPool& mBlockPool;
+ PxcNpMemBlock* mBlock; // current constraint block
+ PxU32 mUsed; // number of bytes used in constraint block
+ //Tracking peak allocations
+ PxU32 mPeakUsed;
+};
+
+class PxcContactBlockStream
+{
+ PX_NOCOPY(PxcContactBlockStream)
+public:
+ PxcContactBlockStream(PxcNpMemBlockPool & blockPool):
+ mBlockPool(blockPool),
+ mBlock(NULL),
+ mUsed(0)
+ {
+ }
+
+ PX_FORCE_INLINE PxU8* reserve(PxU32 size)
+ {
+ size = (size+15)&~15;
+
+ if(size>PxcNpMemBlock::SIZE)
+ return mBlockPool.acquireExceptionalConstraintMemory(size);
+
+ PX_ASSERT(size <= PxcNpMemBlock::SIZE);
+
+ if(mBlock == NULL || size+mUsed>PxcNpMemBlock::SIZE)
+ {
+ mBlock = mBlockPool.acquireContactBlock();
+ PX_ASSERT(0==mBlock || mBlock->data == reinterpret_cast<PxU8*>(mBlock));
+ mUsed = size;
+ return reinterpret_cast<PxU8*>(mBlock);
+ }
+ PX_ASSERT(mBlock && mBlock->data == reinterpret_cast<PxU8*>(mBlock));
+ PxU8* PX_RESTRICT result = mBlock->data+mUsed;
+ mUsed += size;
+ return result;
+ }
+
+ PX_FORCE_INLINE void reset()
+ {
+ mBlock = NULL;
+ mUsed = 0;
+ }
+
+ PX_FORCE_INLINE PxcNpMemBlockPool& getMemBlockPool()
+ {
+ return mBlockPool;
+ }
+
+private:
+ PxcNpMemBlockPool& mBlockPool;
+ PxcNpMemBlock* mBlock; // current constraint block
+ PxU32 mUsed; // number of bytes used in constraint block
+};
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcContactCache.h b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcContactCache.h
new file mode 100644
index 00000000..34174b35
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcContactCache.h
@@ -0,0 +1,64 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef PXC_CONTACT_CACHE_H
+#define PXC_CONTACT_CACHE_H
+
+#include "foundation/PxTransform.h"
+#include "PxvConfig.h"
+#include "PxcContactMethodImpl.h"
+
+namespace physx
+{
+ bool PxcCacheLocalContacts( PxcNpThreadContext& context, Gu::Cache& pairContactCache,
+ const PxTransform& tm0, const PxTransform& tm1,
+ const PxcContactMethod conMethod,
+ const Gu::GeometryUnion& shape0, const Gu::GeometryUnion& shape1);
+
+ struct PxcLocalContactsCache
+ {
+ PxTransform mTransform0;
+ PxTransform mTransform1;
+ PxU16 mNbCachedContacts;
+ bool mUseFaceIndices;
+ bool mSameNormal;
+
+ PX_FORCE_INLINE void operator = (const PxcLocalContactsCache& other)
+ {
+ mTransform0 = other.mTransform0;
+ mTransform1 = other.mTransform1;
+ mNbCachedContacts = other.mNbCachedContacts;
+ mUseFaceIndices = other.mUseFaceIndices;
+ mSameNormal = other.mSameNormal;
+ }
+ };
+
+}
+
+#endif // PXC_CONTACT_CACHE_H
diff --git a/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcMaterialMethodImpl.h b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcMaterialMethodImpl.h
new file mode 100644
index 00000000..b7260aa4
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcMaterialMethodImpl.h
@@ -0,0 +1,69 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef PXC_MATERIALMETHOD_H
+#define PXC_MATERIALMETHOD_H
+
+#include "CmPhysXCommon.h"
+#include "PxGeometry.h"
+
+namespace physx
+{
+
+struct PxsShapeCore;
+struct PxsMaterialInfo;
+class PxcNpThreadContext;
+
+#define MATERIAL_METHOD_ARGS \
+ const PxsShapeCore* shape0, \
+ const PxsShapeCore* shape1, \
+ PxcNpThreadContext& pairContext, \
+ PxsMaterialInfo* materialInfo
+
+
+#define SINGLE_MATERIAL_METHOD_ARGS \
+ const PxsShapeCore* shape, \
+ const PxU32 index, \
+ PxcNpThreadContext& pairContext, \
+ PxsMaterialInfo* materialInfo
+
+/*!
+Method prototype for fetch material routines
+*/
+typedef bool (*PxcGetMaterialMethod) (MATERIAL_METHOD_ARGS);
+
+typedef bool (*PxcGetSingleMaterialMethod) (SINGLE_MATERIAL_METHOD_ARGS);
+
+extern PxcGetMaterialMethod g_GetMaterialMethodTable[][PxGeometryType::eGEOMETRY_COUNT];
+
+extern PxcGetSingleMaterialMethod g_GetSingleMaterialMethodTable[PxGeometryType::eGEOMETRY_COUNT];
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpBatch.h b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpBatch.h
new file mode 100644
index 00000000..fe243aed
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpBatch.h
@@ -0,0 +1,65 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef PXC_NP_BATCH_H
+#define PXC_NP_BATCH_H
+
+#include "PxvConfig.h"
+
+namespace physx
+{
+ struct PxcNpWorkUnit;
+ class PxcNpThreadContext;
+
+struct PxcNpWorkUnit;
+class PxsContactManager;
+struct PxsContactManagerOutput;
+
+namespace Gu
+{
+ struct Cache;
+}
+
+namespace Cm
+{
+ class FlushPool;
+}
+
+class PxLightCpuTask;
+
+namespace Gu
+{
+ class PxgGpuNarrowphaseCoreInterface;
+}
+
+void PxcDiscreteNarrowPhase(PxcNpThreadContext& context, PxcNpWorkUnit& cmInput, Gu::Cache& cache, PxsContactManagerOutput& output);
+void PxcDiscreteNarrowPhasePCM(PxcNpThreadContext& context, PxcNpWorkUnit& cmInput, Gu::Cache& cache, PxsContactManagerOutput& output);
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpCache.h b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpCache.h
new file mode 100644
index 00000000..2ac7dde8
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpCache.h
@@ -0,0 +1,154 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef PXC_NPCACHE_H
+#define PXC_NPCACHE_H
+
+#include "foundation/PxMemory.h"
+
+#include "PsIntrinsics.h"
+#include "PxcNpCacheStreamPair.h"
+
+#include "PsPool.h"
+#include "PsFoundation.h"
+#include "GuContactMethodImpl.h"
+#include "PsUtilities.h"
+
+namespace physx
+{
+
+template <typename T>
+void PxcNpCacheWrite(PxcNpCacheStreamPair& streams,
+ Gu::Cache& cache,
+ const T& payload,
+ PxU32 bytes,
+ const PxU8* data)
+{
+ const PxU32 payloadSize = (sizeof(payload)+3)&~3;
+ cache.mCachedSize = Ps::to16((payloadSize + 4 + bytes + 0xF)&~0xF);
+
+ PxU8* ls = streams.reserve(cache.mCachedSize);
+ cache.mCachedData = ls;
+ if(ls==NULL || (reinterpret_cast<PxU8*>(-1))==ls)
+ {
+ if(ls==NULL)
+ {
+ PX_WARN_ONCE(
+ "Reached limit set by PxSceneDesc::maxNbContactDataBlocks - ran out of buffer space for narrow phase. "
+ "Either accept dropped contacts or increase buffer size allocated for narrow phase by increasing PxSceneDesc::maxNbContactDataBlocks.");
+ return;
+ }
+ else
+ {
+ PX_WARN_ONCE(
+ "Attempting to allocate more than 16K of contact data for a single contact pair in narrowphase. "
+ "Either accept dropped contacts or simplify collision geometry.");
+ cache.mCachedData = NULL;
+ ls = NULL;
+ return;
+ }
+ }
+
+ *reinterpret_cast<T*>(ls) = payload;
+ *reinterpret_cast<PxU32*>(ls+payloadSize) = bytes;
+ if(data)
+ PxMemCopy(ls+payloadSize+sizeof(PxU32), data, bytes);
+}
+
+
+template <typename T>
+PxU8* PxcNpCacheWriteInitiate(PxcNpCacheStreamPair& streams, Gu::Cache& cache, const T& payload, PxU32 bytes)
+{
+ PX_UNUSED(payload);
+
+ const PxU32 payloadSize = (sizeof(payload)+3)&~3;
+ cache.mCachedSize = Ps::to16((payloadSize + 4 + bytes + 0xF)&~0xF);
+
+ PxU8* ls = streams.reserve(cache.mCachedSize);
+ cache.mCachedData = ls;
+ if(NULL==ls || reinterpret_cast<PxU8*>(-1)==ls)
+ {
+ if(NULL==ls)
+ {
+ PX_WARN_ONCE(
+ "Reached limit set by PxSceneDesc::maxNbContactDataBlocks - ran out of buffer space for narrow phase. "
+ "Either accept dropped contacts or increase buffer size allocated for narrow phase by increasing PxSceneDesc::maxNbContactDataBlocks.");
+ }
+ else
+ {
+ PX_WARN_ONCE(
+ "Attempting to allocate more than 16K of contact data for a single contact pair in narrowphase. "
+ "Either accept dropped contacts or simplify collision geometry.");
+ cache.mCachedData = NULL;
+ ls = NULL;
+ }
+ }
+ return ls;
+}
+
+template <typename T>
+PX_FORCE_INLINE void PxcNpCacheWriteFinalize(PxU8* ls, const T& payload, PxU32 bytes, const PxU8* data)
+{
+ const PxU32 payloadSize = (sizeof(payload)+3)&~3;
+ *reinterpret_cast<T*>(ls) = payload;
+ *reinterpret_cast<PxU32*>(ls+payloadSize) = bytes;
+ if(data)
+ PxMemCopy(ls+payloadSize+sizeof(PxU32), data, bytes);
+}
+
+
+template <typename T>
+PX_FORCE_INLINE PxU8* PxcNpCacheRead(Gu::Cache& cache, T*& payload)
+{
+ PxU8* ls = cache.mCachedData;
+ payload = reinterpret_cast<T*>(ls);
+ const PxU32 payloadSize = (sizeof(T)+3)&~3;
+ return reinterpret_cast<PxU8*>(ls+payloadSize+sizeof(PxU32));
+}
+
+template <typename T>
+const PxU8* PxcNpCacheRead2(Gu::Cache& cache, T& payload, PxU32& bytes)
+{
+ const PxU8* ls = cache.mCachedData;
+ if(ls==NULL)
+ {
+ bytes = 0;
+ return NULL;
+ }
+
+ const PxU32 payloadSize = (sizeof(payload)+3)&~3;
+ payload = *reinterpret_cast<const T*>(ls);
+ bytes = *reinterpret_cast<const PxU32*>(ls+payloadSize);
+ PX_ASSERT(cache.mCachedSize == ((payloadSize + 4 + bytes+0xF)&~0xF));
+ return reinterpret_cast<const PxU8*>(ls+payloadSize+sizeof(PxU32));
+}
+
+}
+
+#endif // #ifndef PXC_NPCACHE_H
diff --git a/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpCacheStreamPair.h b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpCacheStreamPair.h
new file mode 100644
index 00000000..08757b8c
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpCacheStreamPair.h
@@ -0,0 +1,63 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+
+#ifndef PXC_NPCACHESTREAMPAIR_H
+#define PXC_NPCACHESTREAMPAIR_H
+
+#include "foundation/PxSimpleTypes.h"
+#include "PxvConfig.h"
+#include "PxcNpMemBlockPool.h"
+
+namespace physx
+{
+
+static const PxU32 PXC_NPCACHE_BLOCK_SIZE = 16384;
+
+
+struct PxcNpCacheStreamPair
+{
+public:
+ PxcNpCacheStreamPair(PxcNpMemBlockPool& blockPool);
+
+ // reserve can fail and return null.
+ PxU8* reserve(PxU32 byteCount);
+ void reset();
+private:
+ PxcNpMemBlockPool& mBlockPool;
+ PxcNpMemBlock* mBlock;
+ PxU32 mUsed;
+private:
+ PxcNpCacheStreamPair& operator=(const PxcNpCacheStreamPair&);
+};
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpContactPrepShared.h b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpContactPrepShared.h
new file mode 100644
index 00000000..4fc9c122
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpContactPrepShared.h
@@ -0,0 +1,59 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef PXC_NPCONTACTPREPSHARED_H
+#define PXC_NPCONTACTPREPSHARED_H
+
+namespace physx
+{
+class PxcNpThreadContext;
+struct PxsMaterialInfo;
+class PxsMaterialManager;
+class PxsConstraintBlockManager;
+class PxcConstraintBlockStream;
+struct PxsContactManagerOutput;
+
+namespace Gu
+{
+ struct ContactPoint;
+}
+
+static const PxReal PXC_SAME_NORMAL = 0.999f; //Around 6 degrees
+
+bool finishContacts(PxcNpWorkUnit& input, PxsContactManagerOutput& npOutput, PxcNpThreadContext& threadContext, PxsMaterialInfo* pMaterialInfo, const bool isMeshType);
+
+PxU32 writeCompressedContact(const Gu::ContactPoint* const PX_RESTRICT contactPoints, const PxU32 numContactPoints, PxcNpThreadContext* threadContext,
+ PxU8& writtenContactCount, PxU8*& outContactPatches, PxU8*& outContactPoints, PxU16& compressedContactSize, PxReal*& contactForces, PxU32 contactForceByteSize,
+ const PxsMaterialManager* materialManager, bool hasModifiableContacts, bool forceNoResponse, PxsMaterialInfo* PX_RESTRICT pMaterial, PxU8& numPatches,
+ PxU32 additionalHeaderSize = 0, PxsConstraintBlockManager* manager = NULL, PxcConstraintBlockStream* blockStream = NULL, bool insertAveragePoint = false,
+ PxcDataStreamPool* pool = NULL, PxcDataStreamPool* patchStreamPool = NULL, PxcDataStreamPool* forcePool = NULL, const bool isMeshType = false);
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpMemBlockPool.h b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpMemBlockPool.h
new file mode 100644
index 00000000..8374cfa9
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpMemBlockPool.h
@@ -0,0 +1,119 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+
+#ifndef PXC_NP_MEM_BLOCK_POOL_H
+#define PXC_NP_MEM_BLOCK_POOL_H
+
+#include "PxvConfig.h"
+#include "PsArray.h"
+#include "PxcScratchAllocator.h"
+
+namespace physx
+{
+struct PxcNpMemBlock
+{
+ enum
+ {
+ SIZE = 16384
+ };
+ PxU8 data[SIZE];
+};
+
+typedef Ps::Array<PxcNpMemBlock*> PxcNpMemBlockArray;
+
+class PxcNpMemBlockPool
+{
+ PX_NOCOPY(PxcNpMemBlockPool)
+public:
+ PxcNpMemBlockPool(PxcScratchAllocator& allocator);
+ ~PxcNpMemBlockPool();
+
+ void init(PxU32 initial16KDataBlocks, PxU32 maxBlocks);
+ void flush();
+ void setBlockCount(PxU32 count);
+ PxU32 getUsedBlockCount() const;
+ PxU32 getMaxUsedBlockCount() const;
+ PxU32 getPeakConstraintBlockCount() const;
+ void releaseUnusedBlocks();
+
+ PxcNpMemBlock* acquireConstraintBlock();
+ PxcNpMemBlock* acquireConstraintBlock(PxcNpMemBlockArray& memBlocks);
+ PxcNpMemBlock* acquireContactBlock();
+ PxcNpMemBlock* acquireFrictionBlock();
+ PxcNpMemBlock* acquireNpCacheBlock();
+
+ PxU8* acquireExceptionalConstraintMemory(PxU32 size);
+
+ void acquireConstraintMemory();
+ void releaseConstraintMemory();
+ void releaseConstraintBlocks(PxcNpMemBlockArray& memBlocks);
+ void releaseContacts();
+ void swapFrictionStreams();
+ void swapNpCacheStreams();
+
+ void flushUnused();
+
+private:
+
+
+ Ps::Mutex mLock;
+ PxcNpMemBlockArray mConstraints;
+ PxcNpMemBlockArray mContacts[2];
+ PxcNpMemBlockArray mFriction[2];
+ PxcNpMemBlockArray mNpCache[2];
+ PxcNpMemBlockArray mScratchBlocks;
+ Ps::Array<PxU8*> mExceptionalConstraints;
+
+ PxcNpMemBlockArray mUnused;
+
+ PxU32 mNpCacheActiveStream;
+ PxU32 mFrictionActiveStream;
+ PxU32 mCCDCacheActiveStream;
+ PxU32 mContactIndex;
+ PxU32 mAllocatedBlocks;
+ PxU32 mMaxBlocks;
+ PxU32 mInitialBlocks;
+ PxU32 mUsedBlocks;
+ PxU32 mMaxUsedBlocks;
+ PxcNpMemBlock* mScratchBlockAddr;
+ PxU32 mNbScratchBlocks;
+ PxcScratchAllocator& mScratchAllocator;
+
+ PxU32 mPeakConstraintAllocations;
+ PxU32 mConstraintAllocations;
+
+ PxcNpMemBlock* acquire(PxcNpMemBlockArray& trackingArray, PxU32* allocationCount = NULL, PxU32* peakAllocationCount = NULL, bool isScratchAllocation = false);
+ void release(PxcNpMemBlockArray& deadArray, PxU32* allocationCount = NULL);
+};
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpThreadContext.h b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpThreadContext.h
new file mode 100644
index 00000000..ef731066
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpThreadContext.h
@@ -0,0 +1,216 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXC_NPTHREADCONTEXT_H
+#define PXC_NPTHREADCONTEXT_H
+
+#include "PxvConfig.h"
+#include "CmScaling.h"
+#include "CmRenderOutput.h"
+#include "PxcNpCacheStreamPair.h"
+#include "PxcConstraintBlockStream.h"
+#include "GuContactBuffer.h"
+#include "PxvContext.h"
+#include "PxcThreadCoherentCache.h"
+#include "CmBitMap.h"
+#include "../pcm/GuPersistentContactManifold.h"
+
+namespace physx
+{
+
+class PxsTransformCache;
+class PxsMaterialManager;
+
+namespace Bp
+{
+ class AABBManagerImpl;
+}
+
+namespace Sc
+{
+ class BodySim;
+}
+
+/*!
+Per-thread context used by contact generation routines.
+*/
+
+struct PxcDataStreamPool
+{
+ PxU8* mDataStream;
+ PxI32 mSharedDataIndex;
+ PxU32 mDataStreamSize;
+ PxU32 mSharedDataIndexGPU;
+
+ bool isOverflown() const
+ {
+ //FD: my expectaton is that reading those variables is atomic, shared indices are non-decreasing,
+ //so we can only get a false overflow alert because of concurrency issues, which is not a big deal as it means
+ //it did overflow a bit later
+ return mSharedDataIndex + mSharedDataIndexGPU >= mDataStreamSize;
+ }
+};
+
+struct PxcNpContext
+{
+ private:
+ PX_NOCOPY(PxcNpContext)
+ public:
+
+ PxcNpContext() :
+ mNpMemBlockPool (mScratchAllocator),
+ mMeshContactMargin (0.0f),
+ mToleranceLength (0.0f),
+ mCreateContactStream (false),
+ mContactStreamPool (NULL),
+ mPatchStreamPool (NULL),
+ mForceAndIndiceStreamPool(NULL),
+ mMaterialManager (NULL)
+ {
+ }
+
+ PxcScratchAllocator mScratchAllocator;
+ PxcNpMemBlockPool mNpMemBlockPool;
+ PxReal mMeshContactMargin;
+ PxReal mToleranceLength;
+ Cm::RenderBuffer mRenderBuffer;
+ bool mCreateContactStream; // flag to enforce that contacts are stored persistently per workunit. Used for PVD.
+ PxcDataStreamPool* mContactStreamPool;
+ PxcDataStreamPool* mPatchStreamPool;
+ PxcDataStreamPool* mForceAndIndiceStreamPool;
+ PxcDataStreamPool* mConstraintWriteBackStreamPool;
+ PxsMaterialManager* mMaterialManager;
+
+ PX_FORCE_INLINE PxReal getToleranceLength() const { return mToleranceLength; }
+ PX_FORCE_INLINE void setToleranceLength(PxReal x) { mToleranceLength = x; }
+ PX_FORCE_INLINE PxReal getMeshContactMargin() const { return mMeshContactMargin; }
+ PX_FORCE_INLINE void setMeshContactMargin(PxReal x) { mMeshContactMargin = x; }
+ PX_FORCE_INLINE bool getCreateContactStream() { return mCreateContactStream; }
+
+ PX_FORCE_INLINE PxcNpMemBlockPool& getNpMemBlockPool() { return mNpMemBlockPool; }
+ PX_FORCE_INLINE const PxcNpMemBlockPool& getNpMemBlockPool() const { return mNpMemBlockPool; }
+ PX_FORCE_INLINE void setMaterialManager(PxsMaterialManager* m){ mMaterialManager = m; }
+ PX_FORCE_INLINE PxsMaterialManager* getMaterialManager() const { return mMaterialManager; }
+
+ Cm::RenderOutput getRenderOutput() { return Cm::RenderOutput(mRenderBuffer); }
+};
+
+class PxcNpThreadContext : public PxcThreadCoherentCache<PxcNpThreadContext, PxcNpContext>::EntryBase
+{
+ PX_NOCOPY(PxcNpThreadContext)
+public:
+ PxcNpThreadContext(PxcNpContext* params);
+ ~PxcNpThreadContext();
+
+#if PX_ENABLE_SIM_STATS
+ void clearStats();
+#endif
+
+ PX_FORCE_INLINE void setCreateContactStream(bool to) { mCreateContactStream = to; }
+
+ PX_FORCE_INLINE void addLocalNewTouchCount(PxU32 newTouchCMCount) { mLocalNewTouchCount += newTouchCMCount; }
+ PX_FORCE_INLINE void addLocalLostTouchCount(PxU32 lostTouchCMCount) { mLocalLostTouchCount += lostTouchCMCount; }
+ PX_FORCE_INLINE PxU32 getLocalNewTouchCount() const { return mLocalNewTouchCount; }
+ PX_FORCE_INLINE PxU32 getLocalLostTouchCount() const { return mLocalLostTouchCount; }
+
+ PX_FORCE_INLINE void addLocalFoundPatchCount(PxU32 foundPatchCount) { mLocalFoundPatchCount += foundPatchCount; }
+ PX_FORCE_INLINE void addLocalLostPatchCount(PxU32 lostPatchCount) { mLocalLostPatchCount += lostPatchCount; }
+ PX_FORCE_INLINE PxU32 getLocalFoundPatchCount() const { return mLocalFoundPatchCount; }
+ PX_FORCE_INLINE PxU32 getLocalLostPatchCount() const { return mLocalLostPatchCount; }
+
+ PX_FORCE_INLINE Cm::BitMap& getLocalChangeTouch() { return mLocalChangeTouch; }
+
+ PX_FORCE_INLINE Cm::BitMap& getLocalPatchChangeMap() { return mLocalPatchCountChange; }
+
+ void reset(PxU32 cmCount);
+ // debugging
+ Cm::RenderOutput mRenderOutput;
+
+ // dsequeira: Need to think about this block pool allocation a bit more. Ideally we'd be
+ // taking blocks from a single pool, except that we want to be able to selectively reclaim
+ // blocks if the user needs to defragment, depending on which artifacts they're willing
+ // to tolerate, such that the blocks we don't reclaim are contiguous.
+#if PX_ENABLE_SIM_STATS
+ PxU32 mDiscreteContactPairs [PxGeometryType::eGEOMETRY_COUNT][PxGeometryType::eGEOMETRY_COUNT];
+ PxU32 mModifiedContactPairs [PxGeometryType::eGEOMETRY_COUNT][PxGeometryType::eGEOMETRY_COUNT];
+#endif
+ PxcContactBlockStream mContactBlockStream; // constraint block pool
+ PxcNpCacheStreamPair mNpCacheStreamPair; // narrow phase pairwise data cache
+
+ // Everything below here is scratch state. Most of it can even overlap.
+
+ // temporary contact buffer
+ Gu::ContactBuffer mContactBuffer;
+
+ PX_ALIGN(16, Gu::MultiplePersistentContactManifold mTempManifold);
+
+ Gu::NarrowPhaseParams mNarrowPhaseParams;
+
+ // DS: this stuff got moved here from the PxcNpPairContext. As Pierre says:
+ ////////// PT: those members shouldn't be there in the end, it's not necessary
+ Ps::Array<Sc::BodySim*> mBodySimPool;
+ PxsTransformCache* mTransformCache;
+ PxReal* mContactDistance;
+ bool mPCM;
+ bool mContactCache;
+ bool mCreateContactStream; // flag to enforce that contacts are stored persistently per workunit. Used for PVD.
+ bool mCreateAveragePoint; // flag to enforce whether we create average points
+#if PX_ENABLE_SIM_STATS
+ PxU32 mCompressedCacheSize;
+ PxU32 mNbDiscreteContactPairsWithCacheHits;
+ PxU32 mNbDiscreteContactPairsWithContacts;
+#endif
+ PxReal mDt; // AP: still needed for ccd
+ PxU32 mCCDPass;
+ PxU32 mCCDFaceIndex;
+
+ PxU32 mMaxPatches;
+ //PxU32 mTotalContactCount;
+ PxU32 mTotalCompressedCacheSize;
+ //PxU32 mTotalPatchCount;
+
+ PxcDataStreamPool* mContactStreamPool;
+ PxcDataStreamPool* mPatchStreamPool;
+ PxcDataStreamPool* mForceAndIndiceStreamPool; //this stream is used to store the force buffer and triangle index if we are performing mesh/heightfield contact gen
+ PxcDataStreamPool* mConstraintWriteBackStreamPool;
+ PxsMaterialManager* mMaterialManager;
+private:
+ // change touch handling.
+ Cm::BitMap mLocalChangeTouch;
+ Cm::BitMap mLocalPatchCountChange;
+ PxU32 mLocalNewTouchCount;
+ PxU32 mLocalLostTouchCount;
+ PxU32 mLocalFoundPatchCount;
+ PxU32 mLocalLostPatchCount;
+};
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpWorkUnit.h b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpWorkUnit.h
new file mode 100644
index 00000000..bfc4f0da
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcNpWorkUnit.h
@@ -0,0 +1,162 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+
+#ifndef PXC_NPWORKUNIT_H
+#define PXC_NPWORKUNIT_H
+
+#include "PxcNpThreadContext.h"
+#include "PxcMaterialMethodImpl.h"
+#include "PxcNpCache.h"
+
+namespace physx
+{
+
+class PxvContact;
+
+struct PxsRigidCore;
+struct PxsShapeCore;
+
+class PxsMaterialManager;
+
+struct PxcNpWorkUnitFlag
+{
+ enum Enum
+ {
+ eOUTPUT_CONTACTS = 1,
+ eOUTPUT_CONSTRAINTS = 2,
+ eDISABLE_STRONG_FRICTION = 4,
+ eARTICULATION_BODY0 = 8,
+ eARTICULATION_BODY1 = 16,
+ eDYNAMIC_BODY0 = 32,
+ eDYNAMIC_BODY1 = 64,
+ eMODIFIABLE_CONTACT = 128,
+ eFORCE_THRESHOLD = 256,
+ eDETECT_DISCRETE_CONTACT = 512,
+ eHAS_KINEMATIC_ACTOR = 1024,
+ eDISABLE_RESPONSE = 2048,
+ eDETECT_CCD_CONTACTS = 4096
+ };
+};
+
+struct PxcNpWorkUnitStatusFlag
+{
+ enum Enum
+ {
+ eHAS_NO_TOUCH = (1 << 0),
+ eHAS_TOUCH = (1 << 1),
+ //eHAS_SOLVER_CONSTRAINTS = (1 << 2),
+ eREQUEST_CONSTRAINTS = (1 << 3),
+ eHAS_CCD_RETOUCH = (1 << 4), // Marks pairs that are touching at a CCD pass and were touching at discrete collision or at a previous CCD pass already
+ // but we can not tell whether they lost contact in a pass before. We send them as pure eNOTIFY_TOUCH_CCD events to the
+ // contact report callback if requested.
+ eDIRTY_MANAGER = (1 << 5),
+ eREFRESHED_WITH_TOUCH = (1 << 6),
+ eTOUCH_KNOWN = eHAS_NO_TOUCH | eHAS_TOUCH // The touch status is known (if narrowphase never ran for a pair then no flag will be set)
+ };
+};
+
+/*
+ * A struct to record the number of work units a particular constraint pointer references.
+ * This is created at the beginning of the constriant data and is used to bypass constraint preparation when the
+ * bodies are not moving a lot. In this case, we can recycle the constraints and save ourselves some cycles.
+*/
+struct PxcNpWorkUnit;
+struct PxcNpWorkUnitBatch
+{
+ PxcNpWorkUnit* mUnits[4];
+ PxU32 mSize;
+};
+
+struct PxcNpWorkUnit
+{
+
+ const PxsRigidCore* rigidCore0; // INPUT //4 //8
+ const PxsRigidCore* rigidCore1; // INPUT //8 //16
+
+ const PxsShapeCore* shapeCore0; // INPUT //12 //24
+ const PxsShapeCore* shapeCore1; // INPUT //16 //32
+
+ PxU8* ccdContacts; // OUTPUT //20 //40
+
+ PxU8* frictionDataPtr; // INOUT //24 //48
+
+ PxU16 flags; // INPUT //26 //50
+ PxU8 frictionPatchCount; // INOUT //27 //51
+ PxU8 statusFlags; // OUTPUT (see PxcNpWorkUnitStatusFlag) //28 //52
+
+ PxU8 dominance0; // INPUT //29 //53
+ PxU8 dominance1; // INPUT //30 //54
+ PxU8 geomType0; // INPUT //31 //55
+ PxU8 geomType1; // INPUT //32 //56
+
+ PxU32 index; // INPUT //36 //60
+
+ PxReal restDistance; // INPUT //40 //64
+
+ PxU32 mTransformCache0; // //44 //68
+ PxU32 mTransformCache1; // //48 //72
+
+ PxU32 mEdgeIndex; //inout the island gen edge index //52 //76
+ PxU32 mNpIndex; //INPUT //56 //80
+
+};
+
+//#if !defined(PX_P64)
+//PX_COMPILE_TIME_ASSERT(0 == (sizeof(PxcNpWorkUnit) & 0x0f));
+//#endif
+
+PX_FORCE_INLINE void PxcNpWorkUnitClearContactState(PxcNpWorkUnit& n)
+{
+ n.ccdContacts = NULL;
+}
+
+
+PX_FORCE_INLINE void PxcNpWorkUnitClearCachedState(PxcNpWorkUnit& n)
+{
+ n.frictionDataPtr = 0;
+ n.frictionPatchCount = 0;
+ n.ccdContacts = NULL;
+}
+
+PX_FORCE_INLINE void PxcNpWorkUnitClearFrictionCachedState(PxcNpWorkUnit& n)
+{
+ n.frictionDataPtr = 0;
+ n.frictionPatchCount = 0;
+ n.ccdContacts = NULL;
+}
+
+#if !defined(PX_P64)
+//PX_COMPILE_TIME_ASSERT(sizeof(PxcNpWorkUnit)==128);
+#endif
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcRigidBody.h b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcRigidBody.h
new file mode 100644
index 00000000..03870e4f
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/include/pipeline/PxcRigidBody.h
@@ -0,0 +1,117 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXC_RIGIDBODY_H
+#define PXC_RIGIDBODY_H
+
+#include "foundation/PxVec3.h"
+#include "foundation/PxTransform.h"
+#include "PxvDynamics.h"
+#include "CmSpatialVector.h"
+
+namespace physx
+{
+
+class PxsContactManager;
+struct PxsCCDPair;
+struct PxsCCDBody;
+
+#define PX_INTERNAL_LOCK_FLAG_START 7
+
+PX_ALIGN_PREFIX(16)
+class PxcRigidBody
+{
+public:
+
+ enum PxcRigidBodyFlag
+ {
+ eFROZEN = 1 << 0, //This flag indicates that the stabilization is enabled and the body is
+ //"frozen". By "frozen", we mean that the body's transform is unchanged
+ //from the previous frame. This permits various optimizations.
+ eFREEZE_THIS_FRAME = 1 << 1,
+ eUNFREEZE_THIS_FRAME = 1 << 2,
+ eACTIVATE_THIS_FRAME = 1 << 3,
+ eDEACTIVATE_THIS_FRAME = 1 << 4,
+ eDISABLE_GRAVITY = 1 << 5,
+ eSPECULATIVE_CCD = 1 << 6,
+ //KS - copied here for GPU simulation to avoid needing to pass another set of flags around.
+ eLOCK_LINEAR_X = 1 << (PX_INTERNAL_LOCK_FLAG_START),
+ eLOCK_LINEAR_Y = 1 << (PX_INTERNAL_LOCK_FLAG_START + 1),
+ eLOCK_LINEAR_Z = 1 << (PX_INTERNAL_LOCK_FLAG_START + 2),
+ eLOCK_ANGULAR_X = 1 << (PX_INTERNAL_LOCK_FLAG_START + 3),
+ eLOCK_ANGULAR_Y = 1 << (PX_INTERNAL_LOCK_FLAG_START + 4),
+ eLOCK_ANGULAR_Z = 1 << (PX_INTERNAL_LOCK_FLAG_START + 5)
+
+ };
+
+ PX_FORCE_INLINE PxcRigidBody(PxsBodyCore* core)
+ : mLastTransform(core->body2World),
+ mCCD(NULL),
+ mCore(core)
+ {
+ }
+
+ void adjustCCDLastTransform();
+
+protected:
+
+ ~PxcRigidBody()
+ {
+ }
+
+public:
+
+ PxTransform mLastTransform; //28 (28)
+
+ PxU16 mInternalFlags; //30 (30)
+ PxU16 solverIterationCounts; //32 (32)
+
+ PxsCCDBody* mCCD; //36 (40) // only valid during CCD
+
+ PxsBodyCore* mCore; //40 (48)
+
+#if !PX_P64_FAMILY
+ PxU32 alignmentPad[2]; //48 (48)
+#endif
+
+ PxVec3 sleepLinVelAcc; //60 (60)
+ PxReal freezeCount; //64 (64)
+
+ PxVec3 sleepAngVelAcc; //76 (76)
+ PxReal accelScale; //80 (80)
+
+
+}
+PX_ALIGN_SUFFIX(16);
+PX_COMPILE_TIME_ASSERT(0 == (sizeof(PxcRigidBody) & 0x0f));
+
+}
+
+#endif //PXC_RIGIDBODY_H
diff --git a/PhysX_3.4/Source/LowLevel/common/include/utils/PxcScratchAllocator.h b/PhysX_3.4/Source/LowLevel/common/include/utils/PxcScratchAllocator.h
new file mode 100644
index 00000000..aaf43626
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/include/utils/PxcScratchAllocator.h
@@ -0,0 +1,138 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXC_SCRATCHALLOCATOR_H
+#define PXC_SCRATCHALLOCATOR_H
+
+#include "foundation/PxAssert.h"
+#include "PxvConfig.h"
+#include "PsMutex.h"
+#include "PsArray.h"
+#include "PsAllocator.h"
+
+namespace physx
+{
+class PxcScratchAllocator
+{
+ PX_NOCOPY(PxcScratchAllocator)
+public:
+ PxcScratchAllocator() : mStack(PX_DEBUG_EXP("PxcScratchAllocator")), mStart(NULL), mSize(0)
+ {
+ mStack.reserve(64);
+ mStack.pushBack(0);
+ }
+
+ void setBlock(void* addr, PxU32 size)
+ {
+ // if the stack is not empty then some scratch memory was not freed on the previous frame. That's
+ // likely indicative of a problem, because when the scratch block is too small the memory will have
+ // come from the heap
+
+ PX_ASSERT(mStack.size()==1);
+ mStack.popBack();
+
+ mStart = reinterpret_cast<PxU8*>(addr);
+ mSize = size;
+ mStack.pushBack(mStart + size);
+ }
+
+ void* allocAll(PxU32& size)
+ {
+ Ps::Mutex::ScopedLock lock(mLock);
+ PX_ASSERT(mStack.size()>0);
+ size = PxU32(mStack.back()-mStart);
+
+ if(size==0)
+ return NULL;
+
+ mStack.pushBack(mStart);
+ return mStart;
+ }
+
+
+ void* alloc(PxU32 requestedSize, bool fallBackToHeap = false)
+ {
+ requestedSize = (requestedSize+15)&~15;
+
+ Ps::Mutex::ScopedLock lock(mLock);
+ PX_ASSERT(mStack.size()>=1);
+
+ PxU8* top = mStack.back();
+
+ if(top - mStart >= ptrdiff_t(requestedSize))
+ {
+ PxU8* addr = top - requestedSize;
+ mStack.pushBack(addr);
+ return addr;
+ }
+
+ if(!fallBackToHeap)
+ return NULL;
+
+ return PX_ALLOC(requestedSize, "Scratch Block Fallback");
+ }
+
+ void free(void* addr)
+ {
+ PX_ASSERT(addr!=NULL);
+ if(!isScratchAddr(addr))
+ {
+ PX_FREE(addr);
+ return;
+ }
+
+ Ps::Mutex::ScopedLock lock(mLock);
+ PX_ASSERT(mStack.size()>1);
+
+ PxU32 i=mStack.size()-1;
+ while(mStack[i]<addr)
+ i--;
+
+ PX_ASSERT(mStack[i]==addr);
+ mStack.remove(i);
+ }
+
+
+ bool isScratchAddr(void* addr) const
+ {
+ PxU8* a = reinterpret_cast<PxU8*>(addr);
+ return a>= mStart && a<mStart+mSize;
+ }
+
+private:
+ Ps::Mutex mLock;
+ Ps::Array<PxU8*> mStack;
+ PxU8* mStart;
+ PxU32 mSize;
+};
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/common/include/utils/PxcThreadCoherentCache.h b/PhysX_3.4/Source/LowLevel/common/include/utils/PxcThreadCoherentCache.h
new file mode 100644
index 00000000..ed8a37a5
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/include/utils/PxcThreadCoherentCache.h
@@ -0,0 +1,150 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXC_THREADCOHERENTCACHE_H
+#define PXC_THREADCOHERENTCACHE_H
+
+#include "PsMutex.h"
+#include "PsAllocator.h"
+#include "PsSList.h"
+
+namespace physx
+{
+
+class PxsContext;
+/*!
+Controls a pool of large objects which must be thread safe.
+Tries to return the object most recently used by the thread(for better cache coherancy).
+Assumes the object has a default contructor.
+
+(Note the semantics are different to a pool because we dont want to construct/destroy each time
+an object is requested, which may be expensive).
+
+TODO: add thread coherancy.
+*/
+template<class T, class Params>
+class PxcThreadCoherentCache : public Ps::AlignedAllocator<16, Ps::ReflectionAllocator<T> >
+{
+ typedef Ps::AlignedAllocator<16, Ps::ReflectionAllocator<T> > Allocator;
+ PX_NOCOPY(PxcThreadCoherentCache)
+public:
+
+ typedef Ps::SListEntry EntryBase;
+
+ PX_INLINE PxcThreadCoherentCache(Params* params, const Allocator& alloc = Allocator()) : Allocator(alloc), mParams(params)
+ {
+ }
+
+ PX_INLINE ~PxcThreadCoherentCache()
+ {
+ T* np = static_cast<T*>(root.pop());
+
+ while(np!=NULL)
+ {
+ np->~T();
+ Allocator::deallocate(np);
+ np = static_cast<T*>(root.pop());
+ }
+ }
+
+ PX_INLINE T* get()
+ {
+ T* rv = static_cast<T*>(root.pop());
+ if(rv==NULL)
+ {
+ rv = reinterpret_cast<T*>(Allocator::allocate(sizeof(T), __FILE__, __LINE__));
+ new (rv) T(mParams);
+ }
+
+ return rv;
+ }
+
+ PX_INLINE void put(T* item)
+ {
+ root.push(*item);
+ }
+
+
+private:
+ Ps::SList root;
+ Params* mParams;
+
+ template<class T2, class P2>
+ friend class PxcThreadCoherentCacheIterator;
+};
+
+/*!
+Used to iterate over all objects controlled by the cache.
+
+Note: The iterator flushes the cache(extracts all items on construction and adds them back on
+destruction so we can iterate the list in a safe manner).
+*/
+template<class T, class Params>
+class PxcThreadCoherentCacheIterator
+{
+public:
+ PxcThreadCoherentCacheIterator(PxcThreadCoherentCache<T, Params>& cache) : mCache(cache)
+ {
+ mNext = cache.root.flush();
+ mFirst = mNext;
+ }
+ ~PxcThreadCoherentCacheIterator()
+ {
+ Ps::SListEntry* np = mFirst;
+ while(np != NULL)
+ {
+ Ps::SListEntry* npNext = np->next();
+ mCache.root.push(*np);
+ np = npNext;
+ }
+ }
+
+ PX_INLINE T* getNext()
+ {
+ if(mNext == NULL)
+ return NULL;
+
+ T* rv = static_cast<T*>(mNext);
+ mNext = mNext->next();
+
+ return rv;
+ }
+private:
+
+ PxcThreadCoherentCacheIterator<T, Params>& operator=(const PxcThreadCoherentCacheIterator<T, Params>&);
+ PxcThreadCoherentCache<T, Params> &mCache;
+ Ps::SListEntry* mNext;
+ Ps::SListEntry* mFirst;
+
+};
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/common/src/collision/PxcContact.cpp b/PhysX_3.4/Source/LowLevel/common/src/collision/PxcContact.cpp
new file mode 100644
index 00000000..c37b3af7
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/src/collision/PxcContact.cpp
@@ -0,0 +1,289 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PxcContactMethodImpl.h"
+
+namespace physx
+{
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////
+//non-pcm sphere function
+bool PxcContactSphereSphere(GU_CONTACT_METHOD_ARGS)
+{
+ return contactSphereSphere(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcContactSphereCapsule(GU_CONTACT_METHOD_ARGS)
+{
+ return contactSphereCapsule(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcContactSphereBox(GU_CONTACT_METHOD_ARGS)
+{
+ return contactSphereBox(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcContactSpherePlane(GU_CONTACT_METHOD_ARGS)
+{
+ return contactSpherePlane(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcContactSphereConvex(GU_CONTACT_METHOD_ARGS)
+{
+ return contactCapsuleConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcContactSphereHeightField(GU_CONTACT_METHOD_ARGS)
+{
+ return contactSphereHeightfield(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcContactSphereMesh(GU_CONTACT_METHOD_ARGS)
+{
+ return contactSphereMesh(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+//non-pcm plane functions
+bool PxcContactPlaneBox(GU_CONTACT_METHOD_ARGS)
+{
+ return contactPlaneBox(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcContactPlaneCapsule(GU_CONTACT_METHOD_ARGS)
+{
+ return contactPlaneCapsule(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcContactPlaneConvex(GU_CONTACT_METHOD_ARGS)
+{
+ return contactPlaneConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+//non-pcm capsule funtions
+bool PxcContactCapsuleCapsule(GU_CONTACT_METHOD_ARGS)
+{
+ return contactCapsuleCapsule(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcContactCapsuleBox(GU_CONTACT_METHOD_ARGS)
+{
+ return contactCapsuleBox(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcContactCapsuleConvex(GU_CONTACT_METHOD_ARGS)
+{
+ return contactCapsuleConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcContactCapsuleHeightField(GU_CONTACT_METHOD_ARGS)
+{
+ return contactCapsuleHeightfield(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcContactCapsuleMesh(GU_CONTACT_METHOD_ARGS)
+{
+ return contactCapsuleMesh(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+//non-pcm box functions
+bool PxcContactBoxBox(GU_CONTACT_METHOD_ARGS)
+{
+ return contactBoxBox(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcContactBoxConvex(GU_CONTACT_METHOD_ARGS)
+{
+ return contactBoxConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcContactBoxHeightField(GU_CONTACT_METHOD_ARGS)
+{
+ return contactBoxHeightfield(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcContactBoxMesh(GU_CONTACT_METHOD_ARGS)
+{
+ return contactBoxMesh(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+//non-pcm convex functions
+bool PxcContactConvexConvex(GU_CONTACT_METHOD_ARGS)
+{
+ return contactConvexConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcContactConvexHeightField(GU_CONTACT_METHOD_ARGS)
+{
+ return contactConvexHeightfield(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcContactConvexMesh(GU_CONTACT_METHOD_ARGS)
+{
+ return contactConvexMesh(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+//legacy height field functions
+bool PxcLegacyContactSphereHeightField(GU_CONTACT_METHOD_ARGS)
+{
+ return legacyContactSphereHeightfield(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcLegacyContactCapsuleHeightField(GU_CONTACT_METHOD_ARGS)
+{
+ return legacyContactCapsuleHeightfield(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcLegacyContactBoxHeightField(GU_CONTACT_METHOD_ARGS)
+{
+ return legacyContactBoxHeightfield(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcLegacyContactConvexHeightField(GU_CONTACT_METHOD_ARGS)
+{
+ return legacyContactConvexHeightfield(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+//pcm sphere functions
+bool PxcPCMContactSphereSphere(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactSphereSphere(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcPCMContactSpherePlane(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactSpherePlane(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcPCMContactSphereCapsule(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactSphereCapsule(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcPCMContactSphereBox(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactSphereBox(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcPCMContactSphereConvex(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactSphereConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcPCMContactSphereHeightField(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactSphereHeightField(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcPCMContactSphereMesh(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactSphereMesh(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+//pcm plane functions
+bool PxcPCMContactPlaneBox(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactPlaneBox(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcPCMContactPlaneCapsule(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactPlaneCapsule(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcPCMContactPlaneConvex(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactPlaneConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+//pcm capsule functions
+bool PxcPCMContactCapsuleCapsule(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactCapsuleCapsule(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcPCMContactCapsuleBox(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactCapsuleBox(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcPCMContactCapsuleConvex(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactCapsuleConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcPCMContactCapsuleHeightField(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactCapsuleHeightField(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcPCMContactCapsuleMesh(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactCapsuleMesh(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+//pcm box functions
+bool PxcPCMContactBoxBox(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactBoxBox(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcPCMContactBoxConvex(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactBoxConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcPCMContactBoxHeightField(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactBoxHeightField(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcPCMContactBoxMesh(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactBoxMesh(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+//pcm convex functions
+bool PxcPCMContactConvexConvex(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactConvexConvex(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcPCMContactConvexHeightField(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactConvexHeightField(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+bool PxcPCMContactConvexMesh(GU_CONTACT_METHOD_ARGS)
+{
+ return pcmContactConvexMesh(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput);
+}
+
+}
diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcContactCache.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcContactCache.cpp
new file mode 100644
index 00000000..26ea90a5
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcContactCache.cpp
@@ -0,0 +1,393 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PxcContactCache.h"
+#include "PxsContactManager.h"
+#include "PsUtilities.h"
+#include "PxcNpCache.h"
+
+using namespace physx;
+using namespace Gu;
+
+//#define ENABLE_CONTACT_CACHE_STATS
+
+#ifdef ENABLE_CONTACT_CACHE_STATS
+ static PxU32 gNbCalls;
+ static PxU32 gNbHits;
+#endif
+
+void PxcClearContactCacheStats()
+{
+#ifdef ENABLE_CONTACT_CACHE_STATS
+ gNbCalls = 0;
+ gNbHits = 0;
+#endif
+}
+
+void PxcDisplayContactCacheStats()
+{
+#ifdef ENABLE_CONTACT_CACHE_STATS
+ pxPrintf("%d|%d (%f)\n", gNbHits, gNbCalls, gNbCalls ? float(gNbHits)/float(gNbCalls) : 0.0f);
+#endif
+}
+
+namespace physx
+{
+ const bool g_CanUseContactCache[][PxGeometryType::eGEOMETRY_COUNT] =
+ {
+ //PxGeometryType::eSPHERE
+ {
+ false, //PxcContactSphereSphere
+ false, //PxcContactSpherePlane
+ true, //PxcContactSphereCapsule
+ false, //PxcContactSphereBox
+ true, //PxcContactSphereConvex
+ true, //PxcContactSphereMesh
+ true, //PxcContactSphereHeightField
+ },
+
+ //PxGeometryType::ePLANE
+ {
+ false, //-
+ false, //PxcInvalidContactPair
+ true, //PxcContactPlaneCapsule
+ true, //PxcContactPlaneBox
+ true, //PxcContactPlaneConvex
+ false, //PxcInvalidContactPair
+ false, //PxcInvalidContactPair
+ },
+
+ //PxGeometryType::eCAPSULE
+ {
+ false, //-
+ false, //-
+ true, //PxcContactCapsuleCapsule
+ true, //PxcContactCapsuleBox
+ true, //PxcContactCapsuleConvex
+ true, //PxcContactCapsuleMesh
+ true, //PxcContactCapsuleHeightField
+ },
+
+ //PxGeometryType::eBOX
+ {
+ false, //-
+ false, //-
+ false, //-
+ true, //PxcContactBoxBox
+ true, //PxcContactBoxConvex
+ true, //PxcContactBoxMesh
+ true, //PxcContactBoxHeightField
+ },
+
+ //PxGeometryType::eCONVEXMESH
+ {
+ false, //-
+ false, //-
+ false, //-
+ false, //-
+ true, //PxcContactConvexConvex
+ true, //PxcContactConvexMesh2
+ true, //PxcContactConvexHeightField
+ },
+
+ //PxGeometryType::eTRIANGLEMESH
+ {
+ false, //-
+ false, //-
+ false, //-
+ false, //-
+ false, //-
+ false, //PxcInvalidContactPair
+ false, //PxcInvalidContactPair
+ },
+
+ //PxGeometryType::eHEIGHTFIELD
+ {
+ false, //-
+ false, //-
+ false, //-
+ false, //-
+ false, //-
+ false, //-
+ false, //PxcInvalidContactPair
+ },
+ };
+}
+
+static PX_FORCE_INLINE void updateContact( Gu::ContactPoint& dst, const PxcLocalContactsCache& contactsData,
+ const Cm::Matrix34& world0, const Cm::Matrix34& world1,
+ const PxVec3& point, const PxVec3& normal, float separation)
+{
+ const PxVec3 tmp0 = contactsData.mTransform0.transformInv(point);
+ const PxVec3 worldpt0 = world0.transform(tmp0);
+
+ const PxVec3 tmp1 = contactsData.mTransform1.transformInv(point);
+ const PxVec3 worldpt1 = world1.transform(tmp1);
+
+ const PxVec3 motion = worldpt0 - worldpt1;
+ dst.normal = normal;
+ dst.point = (worldpt0 + worldpt1)*0.5f;
+ //dst.point = point;
+ dst.separation = separation + motion.dot(normal);
+}
+
+static PX_FORCE_INLINE void prefetchData128(PxU8* PX_RESTRICT ptr, PxU32 size)
+{
+ // PT: always prefetch the cache line containing our address (which unfortunately won't be aligned to 128 most of the time)
+ Ps::prefetchLine(ptr, 0);
+ // PT: compute start offset of our data within its cache line
+ const PxU32 startOffset = PxU32(size_t(ptr)&127);
+ // PT: prefetch next cache line if needed
+ if(startOffset+size>128)
+ Ps::prefetchLine(ptr+128, 0);
+}
+
+static PX_FORCE_INLINE PxU8* outputToCache(PxU8* PX_RESTRICT bytes, const PxVec3& v)
+{
+ *reinterpret_cast<PxVec3*>(bytes) = v;
+ return bytes + sizeof(PxVec3);
+}
+
+static PX_FORCE_INLINE PxU8* outputToCache(PxU8* PX_RESTRICT bytes, PxReal v)
+{
+ *reinterpret_cast<PxReal*>(bytes) = v;
+ return bytes + sizeof(PxReal);
+}
+
+static PX_FORCE_INLINE PxU8* outputToCache(PxU8* PX_RESTRICT bytes, PxU32 v)
+{
+ *reinterpret_cast<PxU32*>(bytes) = v;
+ return bytes + sizeof(PxU32);
+}
+
+//PxU32 gContactCache_NbCalls = 0;
+//PxU32 gContactCache_NbHits = 0;
+
+static PX_FORCE_INLINE PxReal maxComponentDeltaPos(const PxTransform& t0, const PxTransform& t1)
+{
+ PxReal delta = PxAbs(t0.p.x - t1.p.x);
+ delta = PxMax(delta, PxAbs(t0.p.y - t1.p.y));
+ delta = PxMax(delta, PxAbs(t0.p.z - t1.p.z));
+ return delta;
+}
+
+static PX_FORCE_INLINE PxReal maxComponentDeltaRot(const PxTransform& t0, const PxTransform& t1)
+{
+ PxReal delta = PxAbs(t0.q.x - t1.q.x);
+ delta = PxMax(delta, PxAbs(t0.q.y - t1.q.y));
+ delta = PxMax(delta, PxAbs(t0.q.z - t1.q.z));
+ delta = PxMax(delta, PxAbs(t0.q.w - t1.q.w));
+ return delta;
+}
+
+bool physx::PxcCacheLocalContacts( PxcNpThreadContext& context, Gu::Cache& pairContactCache,
+ const PxTransform& tm0, const PxTransform& tm1,
+ const PxcContactMethod conMethod,
+ const Gu::GeometryUnion& shape0, const Gu::GeometryUnion& shape1)
+{
+ const Gu::NarrowPhaseParams& params = context.mNarrowPhaseParams;
+
+// gContactCache_NbCalls++;
+
+ if(pairContactCache.mCachedData)
+ prefetchData128(pairContactCache.mCachedData, pairContactCache.mCachedSize);
+
+ ContactBuffer& contactBuffer = context.mContactBuffer;
+ contactBuffer.reset();
+
+ PxcLocalContactsCache contactsData;
+ PxU32 nbCachedBytes;
+ const PxU8* cachedBytes = PxcNpCacheRead2(pairContactCache, contactsData, nbCachedBytes);
+
+ pairContactCache.mCachedData = NULL;
+ pairContactCache.mCachedSize = 0;
+
+#ifdef ENABLE_CONTACT_CACHE_STATS
+ gNbCalls++;
+#endif
+
+ const PxU32 payloadSize = (sizeof(PxcLocalContactsCache)+3)&~3;
+
+ if(cachedBytes)
+ {
+ // PT: we used to store the relative TM but it's better to save memory and recompute it
+ const PxTransform t0to1 = tm1.transformInv(tm0);
+ const PxTransform relTM = contactsData.mTransform1.transformInv(contactsData.mTransform0);
+
+ const PxReal epsilon = 0.01f;
+ if( maxComponentDeltaPos(t0to1, relTM)<epsilon*params.mToleranceLength
+ && maxComponentDeltaRot(t0to1, relTM)<epsilon)
+ {
+// gContactCache_NbHits++;
+ const PxU32 nbContacts = contactsData.mNbCachedContacts;
+
+ PxU8* ls = PxcNpCacheWriteInitiate(context.mNpCacheStreamPair, pairContactCache, contactsData, nbCachedBytes);
+ prefetchData128(ls, (payloadSize + 4 + nbCachedBytes + 0xF)&~0xF);
+
+ contactBuffer.count = nbContacts;
+ if(nbContacts)
+ {
+ Gu::ContactPoint* PX_RESTRICT dst = contactBuffer.contacts;
+
+ const Cm::Matrix34 world1(tm1);
+ const Cm::Matrix34 world0(tm0);
+
+ const bool sameNormal = contactsData.mSameNormal;
+
+ const PxU8* contacts = reinterpret_cast<const PxU8*>(cachedBytes);
+ const PxVec3* normal0 = NULL;
+ for(PxU32 i=0;i<nbContacts;i++)
+ {
+ if(i!=nbContacts-1)
+ Ps::prefetchLine(contacts, 128);
+
+ const PxVec3* cachedNormal;
+ if(!i || !sameNormal)
+ {
+ cachedNormal = reinterpret_cast<const PxVec3*>(contacts); contacts += sizeof(PxVec3);
+ normal0 = cachedNormal;
+ }
+ else
+ {
+ cachedNormal = normal0;
+ }
+
+ const PxVec3* cachedPoint = reinterpret_cast<const PxVec3*>(contacts); contacts += sizeof(PxVec3);
+ const PxReal* cachedPD = reinterpret_cast<const PxReal*>(contacts); contacts += sizeof(PxReal);
+
+ updateContact(*dst, contactsData, world0, world1, *cachedPoint, *cachedNormal, *cachedPD);
+
+ if(contactsData.mUseFaceIndices)
+ {
+ const PxU32* cachedIndex1 = reinterpret_cast<const PxU32*>(contacts); contacts += sizeof(PxU32);
+
+ dst->internalFaceIndex1 = *cachedIndex1;
+ }
+ else
+ {
+ dst->internalFaceIndex1 = PXC_CONTACT_NO_FACE_INDEX;
+ }
+ dst++;
+ }
+ }
+ if(ls)
+ PxcNpCacheWriteFinalize(ls, contactsData, nbCachedBytes, cachedBytes);
+#ifdef ENABLE_CONTACT_CACHE_STATS
+ gNbHits++;
+#endif
+ return true;
+ }
+ else
+ {
+ // PT: if we reach this point we cached the contacts but we couldn't use them next frame
+ // => waste of time and memory
+ }
+ }
+
+ conMethod(shape0, shape1, tm0, tm1, params, pairContactCache, context.mContactBuffer, &context.mRenderOutput);
+
+ //if(contactBuffer.count)
+ {
+ contactsData.mTransform0 = tm0;
+ contactsData.mTransform1 = tm1;
+
+ PxU32 nbBytes = 0;
+ const PxU8* bytes = NULL;
+ const PxU32 count = contactBuffer.count;
+ if(count)
+ {
+ const bool useFaceIndices = contactBuffer.contacts[0].internalFaceIndex1!=PXC_CONTACT_NO_FACE_INDEX;
+ contactsData.mNbCachedContacts = Ps::to16(count);
+ contactsData.mUseFaceIndices = useFaceIndices;
+
+ const Gu::ContactPoint* PX_RESTRICT srcContacts = contactBuffer.contacts;
+ // PT: this loop should not be here. We should output the contacts directly compressed, as we used to.
+ bool sameNormal = true;
+ {
+ const PxVec3 normal0 = srcContacts->normal;
+ for(PxU32 i=1;i<count;i++)
+ {
+ if(srcContacts[i].normal!=normal0)
+ {
+ sameNormal = false;
+ break;
+ }
+ }
+ }
+ contactsData.mSameNormal = sameNormal;
+
+ if(!sameNormal)
+ {
+ const PxU32 sizeof_CachedContactPoint = sizeof(PxVec3) + sizeof(PxVec3) + sizeof(PxReal);
+ const PxU32 sizeof_CachedContactPointAndFaceIndices = sizeof_CachedContactPoint + sizeof(PxU32);
+ const PxU32 sizeOfItem = useFaceIndices ? sizeof_CachedContactPointAndFaceIndices : sizeof_CachedContactPoint;
+ nbBytes = count * sizeOfItem;
+ }
+ else
+ {
+ const PxU32 sizeof_CachedContactPoint = sizeof(PxVec3) + sizeof(PxReal);
+ const PxU32 sizeof_CachedContactPointAndFaceIndices = sizeof_CachedContactPoint + sizeof(PxU32);
+ const PxU32 sizeOfItem = useFaceIndices ? sizeof_CachedContactPointAndFaceIndices : sizeof_CachedContactPoint;
+ nbBytes = sizeof(PxVec3) + count * sizeOfItem;
+ }
+ PxU8* ls = PxcNpCacheWriteInitiate(context.mNpCacheStreamPair, pairContactCache, contactsData, nbBytes);
+ if(ls)
+ {
+ *reinterpret_cast<PxcLocalContactsCache*>(ls) = contactsData;
+ *reinterpret_cast<PxU32*>(ls+payloadSize) = nbBytes;
+ bytes = ls+payloadSize+sizeof(PxU32);
+ PxU8* dest = const_cast<PxU8*>(bytes);
+ for(PxU32 i=0;i<count;i++)
+ {
+ if(!i || !sameNormal)
+ dest = outputToCache(dest, srcContacts[i].normal);
+ dest = outputToCache(dest, srcContacts[i].point);
+ dest = outputToCache(dest, srcContacts[i].separation);
+ if(useFaceIndices)
+ {
+ dest = outputToCache(dest, srcContacts[i].internalFaceIndex1);
+ }
+ }
+ PX_ASSERT(size_t(dest) - size_t(bytes)==nbBytes);
+ }
+ else
+ {
+ contactsData.mNbCachedContacts = 0;
+ PxcNpCacheWrite(context.mNpCacheStreamPair, pairContactCache, contactsData, 0, bytes);
+ }
+ }
+ else
+ {
+ contactsData.mNbCachedContacts = 0;
+ contactsData.mUseFaceIndices = false;
+ PxcNpCacheWrite(context.mNpCacheStreamPair, pairContactCache, contactsData, nbBytes, bytes);
+ }
+ }
+ return false;
+}
diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcContactMethodImpl.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcContactMethodImpl.cpp
new file mode 100644
index 00000000..53eb5d88
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcContactMethodImpl.cpp
@@ -0,0 +1,279 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#include "PxGeometry.h"
+#include "PxcContactMethodImpl.h"
+
+namespace physx
+{
+
+// PT: those prototypes shouldn't be public. Keep them here.
+
+// Sphere - other
+bool PxcContactSphereSphere (GU_CONTACT_METHOD_ARGS);
+bool PxcContactSpherePlane (GU_CONTACT_METHOD_ARGS);
+bool PxcContactSphereCapsule (GU_CONTACT_METHOD_ARGS);
+bool PxcContactSphereBox (GU_CONTACT_METHOD_ARGS);
+bool PxcContactSphereConvex (GU_CONTACT_METHOD_ARGS);
+bool PxcContactSphereMesh (GU_CONTACT_METHOD_ARGS);
+bool PxcContactSphereHeightField (GU_CONTACT_METHOD_ARGS);
+
+// Plane - other
+bool PxcContactPlaneCapsule (GU_CONTACT_METHOD_ARGS);
+bool PxcContactPlaneBox (GU_CONTACT_METHOD_ARGS);
+bool PxcContactPlaneConvex (GU_CONTACT_METHOD_ARGS);
+
+// Capsule - other
+bool PxcContactCapsuleCapsule (GU_CONTACT_METHOD_ARGS);
+bool PxcContactCapsuleBox (GU_CONTACT_METHOD_ARGS);
+bool PxcContactCapsuleConvex (GU_CONTACT_METHOD_ARGS);
+bool PxcContactCapsuleMesh (GU_CONTACT_METHOD_ARGS);
+bool PxcContactCapsuleHeightField (GU_CONTACT_METHOD_ARGS);
+
+// Box - other
+bool PxcContactBoxBox (GU_CONTACT_METHOD_ARGS);
+bool PxcContactBoxConvex (GU_CONTACT_METHOD_ARGS);
+bool PxcContactBoxMesh (GU_CONTACT_METHOD_ARGS);
+bool PxcContactBoxHeightField (GU_CONTACT_METHOD_ARGS);
+
+// Convex - other
+bool PxcContactConvexConvex (GU_CONTACT_METHOD_ARGS);
+bool PxcContactConvexMesh (GU_CONTACT_METHOD_ARGS);
+bool PxcContactConvexHeightField (GU_CONTACT_METHOD_ARGS);
+
+
+static bool PxcInvalidContactPair (CONTACT_METHOD_ARGS_UNUSED)
+{
+ return false;
+}
+
+//PCM Sphere - other
+bool PxcPCMContactSphereSphere (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactSpherePlane (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactSphereBox (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactSphereCapsule (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactSphereConvex (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactSphereMesh (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactSphereHeightField (GU_CONTACT_METHOD_ARGS);
+
+// Plane - other
+bool PxcPCMContactPlaneCapsule (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactPlaneBox (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactPlaneConvex (GU_CONTACT_METHOD_ARGS);
+
+//PCM Capsule - other
+bool PxcPCMContactCapsuleCapsule (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactCapsuleBox (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactCapsuleConvex (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactCapsuleMesh (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactCapsuleHeightField (GU_CONTACT_METHOD_ARGS);
+
+//PCM Box - other
+bool PxcPCMContactBoxBox (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactBoxConvex (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactBoxMesh (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactBoxHeightField (GU_CONTACT_METHOD_ARGS);
+
+//PCM Convex
+bool PxcPCMContactConvexConvex (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactConvexMesh (GU_CONTACT_METHOD_ARGS);
+bool PxcPCMContactConvexHeightField (GU_CONTACT_METHOD_ARGS);
+
+
+#define DYNAMIC_CONTACT_REGISTRATION(x) PxcInvalidContactPair
+//#define DYNAMIC_CONTACT_REGISTRATION(x) x
+
+//Table of contact methods for different shape-type combinations
+PxcContactMethod g_ContactMethodTable[][PxGeometryType::eGEOMETRY_COUNT] =
+{
+ //PxGeometryType::eSPHERE
+ {
+ PxcContactSphereSphere, //PxGeometryType::eSPHERE
+ PxcContactSpherePlane, //PxGeometryType::ePLANE
+ PxcContactSphereCapsule, //PxGeometryType::eCAPSULE
+ PxcContactSphereBox, //PxGeometryType::eBOX
+ PxcContactSphereConvex, //PxGeometryType::eCONVEXMESH
+ PxcContactSphereMesh, //PxGeometryType::eTRIANGLEMESH
+ DYNAMIC_CONTACT_REGISTRATION(PxcContactSphereHeightField), //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
+
+ },
+
+ //PxGeometryType::ePLANE
+ {
+ 0, //PxGeometryType::eSPHERE
+ PxcInvalidContactPair, //PxGeometryType::ePLANE
+ PxcContactPlaneCapsule, //PxGeometryType::eCAPSULE
+ PxcContactPlaneBox, //PxGeometryType::eBOX
+ PxcContactPlaneConvex, //PxGeometryType::eCONVEXMESH
+ PxcInvalidContactPair, //PxGeometryType::eTRIANGLEMESH
+ PxcInvalidContactPair, //PxGeometryType::eHEIGHTFIELD
+ },
+
+ //PxGeometryType::eCAPSULE
+ {
+ 0, //PxGeometryType::eSPHERE
+ 0, //PxGeometryType::ePLANE
+ PxcContactCapsuleCapsule, //PxGeometryType::eCAPSULE
+ PxcContactCapsuleBox, //PxGeometryType::eBOX
+ PxcContactCapsuleConvex, //PxGeometryType::eCONVEXMESH
+ PxcContactCapsuleMesh, //PxGeometryType::eTRIANGLEMESH
+ DYNAMIC_CONTACT_REGISTRATION(PxcContactCapsuleHeightField), //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
+ },
+
+ //PxGeometryType::eBOX
+ {
+ 0, //PxGeometryType::eSPHERE
+ 0, //PxGeometryType::ePLANE
+ 0, //PxGeometryType::eCAPSULE
+ PxcContactBoxBox, //PxGeometryType::eBOX
+ PxcContactBoxConvex, //PxGeometryType::eCONVEXMESH
+ PxcContactBoxMesh, //PxGeometryType::eTRIANGLEMESH
+ DYNAMIC_CONTACT_REGISTRATION(PxcContactBoxHeightField), //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
+ },
+
+ //PxGeometryType::eCONVEXMESH
+ {
+ 0, //PxGeometryType::eSPHERE
+ 0, //PxGeometryType::ePLANE
+ 0, //PxGeometryType::eCAPSULE
+ 0, //PxGeometryType::eBOX
+ PxcContactConvexConvex, //PxGeometryType::eCONVEXMESH
+ PxcContactConvexMesh, //PxGeometryType::eTRIANGLEMESH
+ DYNAMIC_CONTACT_REGISTRATION(PxcContactConvexHeightField), //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
+ },
+
+ //PxGeometryType::eTRIANGLEMESH
+ {
+ 0, //PxGeometryType::eSPHERE
+ 0, //PxGeometryType::ePLANE
+ 0, //PxGeometryType::eCAPSULE
+ 0, //PxGeometryType::eBOX
+ 0, //PxGeometryType::eCONVEXMESH
+ PxcInvalidContactPair, //PxGeometryType::eTRIANGLEMESH
+ PxcInvalidContactPair, //PxGeometryType::eHEIGHTFIELD
+ },
+
+ //PxGeometryType::eHEIGHTFIELD
+ {
+ 0, //PxGeometryType::eSPHERE
+ 0, //PxGeometryType::ePLANE
+ 0, //PxGeometryType::eCAPSULE
+ 0, //PxGeometryType::eBOX
+ 0, //PxGeometryType::eCONVEXMESH
+ 0, //PxGeometryType::eTRIANGLEMESH
+ PxcInvalidContactPair, //PxGeometryType::eHEIGHTFIELD
+ },
+};
+
+
+//#if PERSISTENT_CONTACT_MANIFOLD
+//Table of contact methods for different shape-type combinations
+PxcContactMethod g_PCMContactMethodTable[][PxGeometryType::eGEOMETRY_COUNT] =
+{
+ //PxGeometryType::eSPHERE
+ {
+ PxcPCMContactSphereSphere, //PxGeometryType::eSPHERE
+ PxcPCMContactSpherePlane, //PxGeometryType::ePLANE
+ PxcPCMContactSphereCapsule, //PxGeometryType::eCAPSULE
+ PxcPCMContactSphereBox, //PxGeometryType::eBOX
+ PxcPCMContactSphereConvex, //PxGeometryType::eCONVEXMESH
+ PxcPCMContactSphereMesh, //PxGeometryType::eTRIANGLEMESH
+ DYNAMIC_CONTACT_REGISTRATION(PxcPCMContactSphereHeightField), //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
+ },
+
+ //PxGeometryType::ePLANE
+ {
+ 0, //PxGeometryType::eSPHERE
+ PxcInvalidContactPair, //PxGeometryType::ePLANE
+ PxcPCMContactPlaneCapsule, //PxGeometryType::eCAPSULE
+ PxcPCMContactPlaneBox, //PxGeometryType::eBOX
+ PxcPCMContactPlaneConvex, //PxGeometryType::eCONVEXMESH
+ PxcInvalidContactPair, //PxGeometryType::eTRIANGLEMESH
+ PxcInvalidContactPair, //PxGeometryType::eHEIGHTFIELD
+ },
+
+ //PxGeometryType::eCAPSULE
+ {
+ 0, //PxGeometryType::eSPHERE
+ 0, //PxGeometryType::ePLANE
+ PxcPCMContactCapsuleCapsule, //PxGeometryType::eCAPSULE
+ PxcPCMContactCapsuleBox, //PxGeometryType::eBOX
+ PxcPCMContactCapsuleConvex, //PxGeometryType::eCONVEXMESH
+ PxcPCMContactCapsuleMesh, //PxGeometryType::eTRIANGLEMESH
+ DYNAMIC_CONTACT_REGISTRATION(PxcPCMContactCapsuleHeightField), //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
+ },
+
+ //PxGeometryType::eBOX
+ {
+ 0, //PxGeometryType::eSPHERE
+ 0, //PxGeometryType::ePLANE
+ 0, //PxGeometryType::eCAPSULE
+ PxcPCMContactBoxBox, //PxGeometryType::eBOX
+ PxcPCMContactBoxConvex, //PxGeometryType::eCONVEXMESH
+ PxcPCMContactBoxMesh, //PxGeometryType::eTRIANGLEMESH
+ DYNAMIC_CONTACT_REGISTRATION(PxcPCMContactBoxHeightField), //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
+
+ },
+
+ //PxGeometryType::eCONVEXMESH
+ {
+ 0, //PxGeometryType::eSPHERE
+ 0, //PxGeometryType::ePLANE
+ 0, //PxGeometryType::eCAPSULE
+ 0, //PxGeometryType::eBOX
+ PxcPCMContactConvexConvex, //PxGeometryType::eCONVEXMESH
+ PxcPCMContactConvexMesh, //PxGeometryType::eTRIANGLEMESH
+ DYNAMIC_CONTACT_REGISTRATION(PxcPCMContactConvexHeightField), //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
+ },
+
+ //PxGeometryType::eTRIANGLEMESH
+ {
+ 0, //PxGeometryType::eSPHERE
+ 0, //PxGeometryType::ePLANE
+ 0, //PxGeometryType::eCAPSULE
+ 0, //PxGeometryType::eBOX
+ 0, //PxGeometryType::eCONVEXMESH
+ PxcInvalidContactPair, //PxGeometryType::eTRIANGLEMESH
+ PxcInvalidContactPair, //PxGeometryType::eHEIGHTFIELD
+ },
+
+ //PxGeometryType::eHEIGHTFIELD
+ {
+ 0, //PxGeometryType::eSPHERE
+ 0, //PxGeometryType::ePLANE
+ 0, //PxGeometryType::eCAPSULE
+ 0, //PxGeometryType::eBOX
+ 0, //PxGeometryType::eCONVEXMESH
+ 0, //PxGeometryType::eTRIANGLEMESH
+ PxcInvalidContactPair, //PxGeometryType::eHEIGHTFIELD
+ },
+
+};
+}
diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialHeightField.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialHeightField.cpp
new file mode 100644
index 00000000..89b347c2
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialHeightField.cpp
@@ -0,0 +1,116 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PxTriangleMesh.h"
+#include "PxvGeometry.h"
+#include "PxsMaterialManager.h"
+#include "PxcNpThreadContext.h"
+#include "GuHeightField.h"
+
+using namespace physx;
+using namespace Gu;
+
+namespace physx
+{
+ bool PxcGetMaterialShapeHeightField(const PxsShapeCore* shape0, const PxsShapeCore* shape1, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo);
+ bool PxcGetMaterialHeightField(const PxsShapeCore* shape, const PxU32 index, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo);
+ PxU32 GetMaterialIndex(const Gu::HeightFieldData* hfData, PxU32 triangleIndex);
+}
+
+physx::PxU32 physx::GetMaterialIndex(const Gu::HeightFieldData* hfData, PxU32 triangleIndex)
+{
+ const PxU32 sampleIndex = triangleIndex >> 1;
+ const bool isFirstTriangle = (triangleIndex & 0x1) == 0;
+
+ //get sample
+ const PxHeightFieldSample* hf = &hfData->samples[sampleIndex];
+ return isFirstTriangle ? hf->materialIndex0 : hf->materialIndex1;
+}
+
+bool physx::PxcGetMaterialHeightField(const PxsShapeCore* shape, const PxU32 index, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo)
+{
+ PX_ASSERT(index == 1);
+ PX_UNUSED(index);
+ const ContactBuffer& contactBuffer = context.mContactBuffer;
+ const PxHeightFieldGeometryLL& hfGeom = shape->geometry.get<const PxHeightFieldGeometryLL>();
+ if(hfGeom.materials.numIndices <= 1)
+ {
+ for(PxU32 i=0; i< contactBuffer.count; ++i)
+ {
+ (&materialInfo[i].mMaterialIndex0)[index] = shape->materialIndex;
+ }
+ }
+ else
+ {
+ const PxU16* materialIndices = hfGeom.materials.indices;
+
+ const Gu::HeightFieldData* hf = hfGeom.heightFieldData;
+
+ for(PxU32 i=0; i< contactBuffer.count; ++i)
+ {
+ const Gu::ContactPoint& contact = contactBuffer.contacts[i];
+ const PxU32 localMaterialIndex = GetMaterialIndex(hf, contact.internalFaceIndex1);
+ (&materialInfo[i].mMaterialIndex0)[index] = materialIndices[localMaterialIndex];
+ }
+ }
+ return true;
+}
+
+bool physx::PxcGetMaterialShapeHeightField(const PxsShapeCore* shape0, const PxsShapeCore* shape1, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo)
+{
+ const ContactBuffer& contactBuffer = context.mContactBuffer;
+ const PxHeightFieldGeometryLL& hfGeom = shape1->geometry.get<const PxHeightFieldGeometryLL>();
+ if(hfGeom.materials.numIndices <= 1)
+ {
+ for(PxU32 i=0; i< contactBuffer.count; ++i)
+ {
+ materialInfo[i].mMaterialIndex0 = shape0->materialIndex;
+ materialInfo[i].mMaterialIndex1 = shape1->materialIndex;
+ }
+ }
+ else
+ {
+ const PxU16* materialIndices = hfGeom.materials.indices;
+
+ const Gu::HeightFieldData* hf = hfGeom.heightFieldData;
+
+ for(PxU32 i=0; i< contactBuffer.count; ++i)
+ {
+ const Gu::ContactPoint& contact = contactBuffer.contacts[i];
+ materialInfo[i].mMaterialIndex0 = shape0->materialIndex;
+ //contact.featureIndex0 = shape0->materialIndex;
+ const PxU32 localMaterialIndex = GetMaterialIndex(hf, contact.internalFaceIndex1);
+ //contact.featureIndex1 = materialIndices[localMaterialIndex];
+ PX_ASSERT(localMaterialIndex<hfGeom.materials.numIndices);
+ materialInfo[i].mMaterialIndex1 = materialIndices[localMaterialIndex];
+ }
+ }
+ return true;
+}
+
diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialMesh.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialMesh.cpp
new file mode 100644
index 00000000..17b16712
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialMesh.cpp
@@ -0,0 +1,107 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PxTriangleMesh.h"
+#include "PxvGeometry.h"
+#include "PxsMaterialManager.h"
+#include "PxcNpThreadContext.h"
+#include "GuHeightField.h"
+#include "GuTriangleMesh.h"
+
+using namespace physx;
+using namespace Gu;
+
+namespace physx
+{
+ bool PxcGetMaterialShapeMesh(const PxsShapeCore* shape0, const PxsShapeCore* shape1, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo);
+ bool PxcGetMaterialMesh(const PxsShapeCore* shape, const PxU32 index, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo);
+}
+
+bool physx::PxcGetMaterialMesh(const PxsShapeCore* shape, const PxU32 index, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo)
+{
+ PX_ASSERT(index == 1);
+ PX_UNUSED(index);
+ ContactBuffer& contactBuffer = context.mContactBuffer;
+ const PxTriangleMeshGeometryLL& shapeMesh = shape->geometry.get<const PxTriangleMeshGeometryLL>();
+ if(shapeMesh.materials.numIndices <= 1)
+ {
+ for(PxU32 i=0; i< contactBuffer.count; ++i)
+ {
+ (&materialInfo[i].mMaterialIndex0)[index] = shape->materialIndex;
+ }
+ }
+ else
+ {
+ for(PxU32 i=0; i< contactBuffer.count; ++i)
+ {
+
+ Gu::ContactPoint& contact = contactBuffer.contacts[i];
+ const PxU16* eaMaterialIndices = shapeMesh.materialIndices;
+
+ const PxU32 localMaterialIndex = eaMaterialIndices[contact.internalFaceIndex1];//shapeMesh.triangleMesh->getTriangleMaterialIndex(contact.featureIndex1);
+ (&materialInfo[i].mMaterialIndex0)[index] = shapeMesh.materials.indices[localMaterialIndex];
+ }
+ }
+ return true;
+}
+
+bool physx::PxcGetMaterialShapeMesh(const PxsShapeCore* shape0, const PxsShapeCore* shape1, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo)
+{
+
+ ContactBuffer& contactBuffer = context.mContactBuffer;
+ const PxTriangleMeshGeometryLL& shapeMesh = shape1->geometry.get<const PxTriangleMeshGeometryLL>();
+// const Gu::TriangleMesh* meshData = shapeMesh.meshData;
+ if(shapeMesh.materials.numIndices <= 1)
+ {
+ for(PxU32 i=0; i< contactBuffer.count; ++i)
+ {
+ materialInfo[i].mMaterialIndex0 = shape0->materialIndex;
+ materialInfo[i].mMaterialIndex1 = shape1->materialIndex;
+ }
+ }
+ else
+ {
+
+ for(PxU32 i=0; i< contactBuffer.count; ++i)
+ {
+
+ Gu::ContactPoint& contact = contactBuffer.contacts[i];
+ //contact.featureIndex0 = shape0->materialIndex;
+ materialInfo[i].mMaterialIndex0 = shape0->materialIndex;
+ const PxU16* eaMaterialIndices = shapeMesh.materialIndices;
+
+ const PxU32 localMaterialIndex = eaMaterialIndices[contact.internalFaceIndex1];//shapeMesh.triangleMesh->getTriangleMaterialIndex(contact.featureIndex1);
+ //contact.featureIndex1 = shapeMesh.materials.indices[localMaterialIndex];
+ materialInfo[i].mMaterialIndex1 = shapeMesh.materials.indices[localMaterialIndex];
+
+ }
+ }
+
+ return true;
+}
diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialMethodImpl.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialMethodImpl.cpp
new file mode 100644
index 00000000..61195bf0
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialMethodImpl.cpp
@@ -0,0 +1,140 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#include "PxGeometry.h"
+#include "PxcMaterialMethodImpl.h"
+
+namespace physx
+{
+bool PxcGetMaterialShapeShape (MATERIAL_METHOD_ARGS);
+bool PxcGetMaterialShapeMesh (MATERIAL_METHOD_ARGS);
+bool PxcGetMaterialShapeHeightField (MATERIAL_METHOD_ARGS);
+bool PxcGetMaterialShape (SINGLE_MATERIAL_METHOD_ARGS);
+bool PxcGetMaterialMesh (SINGLE_MATERIAL_METHOD_ARGS);
+bool PxcGetMaterialHeightField (SINGLE_MATERIAL_METHOD_ARGS);
+
+
+PxcGetSingleMaterialMethod g_GetSingleMaterialMethodTable[PxGeometryType::eGEOMETRY_COUNT] =
+{
+ PxcGetMaterialShape, //PxGeometryType::eSPHERE
+ PxcGetMaterialShape, //PxGeometryType::ePLANE
+ PxcGetMaterialShape, //PxGeometryType::eCAPSULE
+ PxcGetMaterialShape, //PxGeometryType::eBOX
+ PxcGetMaterialShape, //PxGeometryType::eCONVEXMESH
+ PxcGetMaterialMesh, //PxGeometryType::eTRIANGLEMESH //not used: mesh always uses swept method for midphase.
+ PxcGetMaterialHeightField, //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
+
+};
+
+//Table of contact methods for different shape-type combinations
+PxcGetMaterialMethod g_GetMaterialMethodTable[][PxGeometryType::eGEOMETRY_COUNT] =
+{
+
+ //PxGeometryType::eSPHERE
+ {
+ PxcGetMaterialShapeShape, //PxGeometryType::eSPHERE
+ PxcGetMaterialShapeShape, //PxGeometryType::ePLANE
+ PxcGetMaterialShapeShape, //PxGeometryType::eCAPSULE
+ PxcGetMaterialShapeShape, //PxGeometryType::eBOX
+ PxcGetMaterialShapeShape, //PxGeometryType::eCONVEXMESH
+ PxcGetMaterialShapeMesh, //PxGeometryType::eTRIANGLEMESH //not used: mesh always uses swept method for midphase.
+ PxcGetMaterialShapeHeightField, //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
+
+ },
+
+ //PxGeometryType::ePLANE
+ {
+ 0, //PxGeometryType::eSPHERE
+ 0, //PxGeometryType::ePLANE
+ PxcGetMaterialShapeShape, //PxGeometryType::eCAPSULE
+ PxcGetMaterialShapeShape, //PxGeometryType::eBOX
+ PxcGetMaterialShapeShape, //PxGeometryType::eCONVEXMESH
+ 0, //PxGeometryType::eTRIANGLEMESH
+ 0, //PxGeometryType::eHEIGHTFIELD
+ },
+
+ //PxGeometryType::eCAPSULE
+ {
+ 0, //PxGeometryType::eSPHERE
+ 0, //PxGeometryType::ePLANE
+ PxcGetMaterialShapeShape, //PxGeometryType::eCAPSULE
+ PxcGetMaterialShapeShape, //PxGeometryType::eBOX
+ PxcGetMaterialShapeShape, //PxGeometryType::eCONVEXMESH
+ PxcGetMaterialShapeMesh, //PxGeometryType::eTRIANGLEMESH //not used: mesh always uses swept method for midphase.
+ PxcGetMaterialShapeHeightField, //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
+ },
+
+ //PxGeometryType::eBOX
+ {
+ 0, //PxGeometryType::eSPHERE
+ 0, //PxGeometryType::ePLANE
+ 0, //PxGeometryType::eCAPSULE
+ PxcGetMaterialShapeShape, //PxGeometryType::eBOX
+ PxcGetMaterialShapeShape, //PxGeometryType::eCONVEXMESH
+ PxcGetMaterialShapeMesh, //PxGeometryType::eTRIANGLEMESH //not used: mesh always uses swept method for midphase.
+ PxcGetMaterialShapeHeightField, //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
+ },
+
+ //PxGeometryType::eCONVEXMESH
+ {
+ 0, //PxGeometryType::eSPHERE
+ 0, //PxGeometryType::ePLANE
+ 0, //PxGeometryType::eCAPSULE
+ 0, //PxGeometryType::eBOX
+ PxcGetMaterialShapeShape, //PxGeometryType::eCONVEXMESH
+ PxcGetMaterialShapeMesh, //PxGeometryType::eTRIANGLEMESH //not used: mesh always uses swept method for midphase.
+ PxcGetMaterialShapeHeightField, //PxGeometryType::eHEIGHTFIELD //TODO: make HF midphase that will mask this
+ },
+
+ //PxGeometryType::eTRIANGLEMESH
+ {
+ 0, //PxGeometryType::eSPHERE
+ 0, //PxGeometryType::ePLANE
+ 0, //PxGeometryType::eCAPSULE
+ 0, //PxGeometryType::eBOX
+ 0, //PxGeometryType::eCONVEXMESH
+ 0, //PxGeometryType::eTRIANGLEMESH
+ 0, //PxGeometryType::eHEIGHTFIELD
+ },
+
+ //PxGeometryType::eHEIGHTFIELD
+ {
+ 0, //PxGeometryType::eSPHERE
+ 0, //PxGeometryType::ePLANE
+ 0, //PxGeometryType::eCAPSULE
+ 0, //PxGeometryType::eBOX
+ 0, //PxGeometryType::eCONVEXMESH
+ 0, //PxGeometryType::eTRIANGLEMESH
+ 0, //PxGeometryType::eHEIGHTFIELD
+ },
+
+};
+
+}
diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialShape.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialShape.cpp
new file mode 100644
index 00000000..1c8c3849
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcMaterialShape.cpp
@@ -0,0 +1,62 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PxTriangleMesh.h"
+#include "PxvGeometry.h"
+#include "PxsMaterialManager.h"
+#include "PxcNpThreadContext.h"
+#include "GuHeightField.h"
+
+using namespace physx;
+using namespace Gu;
+
+namespace physx
+{
+bool PxcGetMaterialShape(const PxsShapeCore* shape, const PxU32 index, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo)
+{
+ ContactBuffer& contactBuffer = context.mContactBuffer;
+ for(PxU32 i=0; i< contactBuffer.count; ++i)
+ {
+ (&materialInfo[i].mMaterialIndex0)[index] = shape->materialIndex;
+ }
+ return true;
+}
+
+bool PxcGetMaterialShapeShape(const PxsShapeCore* shape0, const PxsShapeCore* shape1, PxcNpThreadContext& context, PxsMaterialInfo* materialInfo)
+{
+ ContactBuffer& contactBuffer = context.mContactBuffer;
+ for(PxU32 i=0; i< contactBuffer.count; ++i)
+ {
+ materialInfo[i].mMaterialIndex0 = shape0->materialIndex;
+ materialInfo[i].mMaterialIndex1 = shape1->materialIndex;
+ }
+ return true;
+}
+}
+
diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpBatch.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpBatch.cpp
new file mode 100644
index 00000000..7ed87b05
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpBatch.cpp
@@ -0,0 +1,413 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#include "PxcNpBatch.h"
+#include "PxcNpWorkUnit.h"
+#include "PxsContactManager.h"
+#include "GuGeometryUnion.h"
+#include "PxcContactCache.h"
+#include "PxcMaterialMethodImpl.h"
+#include "PxcNpContactPrepShared.h"
+#include "PxvDynamics.h" // for PxsBodyCore
+#include "PxvGeometry.h" // for PxsShapeCore
+#include "CmFlushPool.h"
+#include "CmTask.h"
+#include "PxTriangleMesh.h"
+#include "PxsMaterialManager.h"
+#include "PxsTransformCache.h"
+#include "GuPersistentContactManifold.h"
+#include "PxsContactManagerState.h"
+#include "PsFoundation.h"
+
+using namespace physx;
+using namespace Gu;
+
+
+static void startContacts(PxsContactManagerOutput& output, PxcNpThreadContext& context)
+{
+ context.mContactBuffer.reset();
+
+ output.contactForces = NULL;
+ output.contactPatches = NULL;
+ output.contactPoints = NULL;
+ output.nbContacts = 0;
+ output.nbPatches = 0;
+ output.statusFlag = 0;
+}
+
+static void flipContacts(PxcNpThreadContext& threadContext, PxsMaterialInfo* PX_RESTRICT materialInfo)
+{
+ ContactBuffer& buffer = threadContext.mContactBuffer;
+ for(PxU32 i=0; i<buffer.count; ++i)
+ {
+ Gu::ContactPoint& contactPoint = buffer.contacts[i];
+ contactPoint.normal = -contactPoint.normal;
+ Ps::swap(materialInfo[i].mMaterialIndex0, materialInfo[i].mMaterialIndex1);
+ }
+}
+
+static PX_FORCE_INLINE void updateDiscreteContactStats(PxcNpThreadContext& context, PxGeometryType::Enum type0, PxGeometryType::Enum type1)
+{
+#if PX_ENABLE_SIM_STATS
+ PX_ASSERT(type0<=type1);
+ context.mDiscreteContactPairs[type0][type1]++;
+#endif
+}
+
+static bool copyBuffers(PxsContactManagerOutput& cmOutput, Gu::Cache& cache, PxcNpThreadContext& context, const bool useContactCache, const bool isMeshType)
+{
+ bool ret = false;
+ //Copy the contact stream from previous buffer to current buffer...
+ PxU32 oldSize = sizeof(PxContact) * cmOutput.nbContacts + sizeof(PxContactPatch)*cmOutput.nbPatches;
+ if(oldSize)
+ {
+ ret = true;
+ PxU8* oldPatches = cmOutput.contactPatches;
+ PxU8* oldContacts = cmOutput.contactPoints;
+
+ PxU32 forceSize = cmOutput.nbContacts * sizeof(PxReal);
+
+ PxU8* PX_RESTRICT contactPatches = NULL;
+ PxU8* PX_RESTRICT contactPoints = NULL;
+
+ PxReal* forceBuffer = NULL;
+
+ bool isOverflown = false;
+
+ //ML: if we are using contactStreamPool, which means we are running the GPU codepath
+ if(context.mContactStreamPool)
+ {
+ const PxU32 patchSize = cmOutput.nbPatches * sizeof(PxContactPatch);
+ const PxU32 contactSize = cmOutput.nbContacts * sizeof(PxContact);
+
+ PxU32 index = PxU32(Ps::atomicAdd(&context.mContactStreamPool->mSharedDataIndex, PxI32(contactSize)));
+
+ if(context.mContactStreamPool->isOverflown())
+ {
+ PX_WARN_ONCE("Contact buffer overflow detected, please increase its size in the scene desc!\n");
+ isOverflown = true;
+ }
+ contactPoints = context.mContactStreamPool->mDataStream + context.mContactStreamPool->mDataStreamSize - index;
+
+ const PxU32 patchIndex = PxU32(Ps::atomicAdd(&context.mPatchStreamPool->mSharedDataIndex, PxI32(patchSize)));
+
+ if(context.mPatchStreamPool->isOverflown())
+ {
+ PX_WARN_ONCE("Patch buffer overflow detected, please increase its size in the scene desc!\n");
+ isOverflown = true;
+ }
+ contactPatches = context.mPatchStreamPool->mDataStream + context.mPatchStreamPool->mDataStreamSize - patchIndex;
+
+ if(forceSize)
+ {
+ forceSize = isMeshType ? (forceSize * 2) : forceSize;
+
+ index = PxU32(Ps::atomicAdd(&context.mForceAndIndiceStreamPool->mSharedDataIndex, PxI32(forceSize)));
+
+ if(context.mForceAndIndiceStreamPool->isOverflown())
+ {
+ PX_WARN_ONCE("Force buffer overflow detected, please increase its size in the scene desc!\n");
+ isOverflown = true;
+ }
+ forceBuffer = reinterpret_cast<PxReal*>(context.mForceAndIndiceStreamPool->mDataStream + context.mForceAndIndiceStreamPool->mDataStreamSize - index);
+ }
+
+ if(isOverflown)
+ {
+ contactPatches = NULL;
+ contactPoints = NULL;
+ forceBuffer = NULL;
+ cmOutput.nbContacts = cmOutput.nbPatches = 0;
+ }
+ else
+ {
+ PxMemCopy(contactPatches, oldPatches, patchSize);
+ PxMemCopy(contactPoints, oldContacts, contactSize);
+ }
+ }
+ else
+ {
+ const PxU32 alignedOldSize = (oldSize + 0xf) & 0xfffffff0;
+
+ PxU8* data = context.mContactBlockStream.reserve(alignedOldSize + forceSize);
+ if(forceSize)
+ forceBuffer = reinterpret_cast<PxReal*>(data + alignedOldSize);
+
+ contactPatches = data;
+ contactPoints = data + cmOutput.nbPatches * sizeof(PxContactPatch);
+
+ PxMemCopy(data, oldPatches, oldSize);
+ }
+
+ if(forceSize)
+ {
+ PxMemZero(forceBuffer, forceSize);
+ }
+
+ cmOutput.contactPatches= contactPatches;
+ cmOutput.contactPoints = contactPoints;
+ cmOutput.contactForces = forceBuffer;
+ }
+
+ if(cache.mCachedSize)
+ {
+ if(cache.isMultiManifold())
+ {
+ PX_ASSERT((cache.mCachedSize & 0xF) == 0);
+ PxU8* newData = context.mNpCacheStreamPair.reserve(cache.mCachedSize);
+ PX_ASSERT((reinterpret_cast<uintptr_t>(newData)& 0xF) == 0);
+ PxMemCopy(newData, & cache.getMultipleManifold(), cache.mCachedSize);
+ cache.setMultiManifold(newData);
+ }
+ else if(useContactCache)
+ {
+ //Copy cache information as well...
+ const PxU8* cachedData = cache.mCachedData;
+ PxU8* newData = context.mNpCacheStreamPair.reserve(PxU32(cache.mCachedSize + 0xf) & 0xfff0);
+ PxMemCopy(newData, cachedData, cache.mCachedSize);
+ cache.mCachedData = newData;
+ }
+ }
+ return ret;
+}
+
+void physx::PxcDiscreteNarrowPhase(PxcNpThreadContext& context, PxcNpWorkUnit& input, Gu::Cache& cache, PxsContactManagerOutput& output)
+{
+ //ML : if user doesn't raise the eDETECT_DISCRETE_CONTACT, we should not generate contacts
+ if(!(input.flags & PxcNpWorkUnitFlag::eDETECT_DISCRETE_CONTACT))
+ return;
+
+ PxGeometryType::Enum type0 = static_cast<PxGeometryType::Enum>(input.geomType0);
+ PxGeometryType::Enum type1 = static_cast<PxGeometryType::Enum>(input.geomType1);
+
+ const bool flip = (type1<type0);
+
+ const PxsCachedTransform* cachedTransform0 = &context.mTransformCache->getTransformCache(input.mTransformCache0);
+ const PxsCachedTransform* cachedTransform1 = &context.mTransformCache->getTransformCache(input.mTransformCache1);
+
+ if(!(output.statusFlag & PxcNpWorkUnitStatusFlag::eDIRTY_MANAGER) && !(input.flags & PxcNpWorkUnitFlag::eMODIFIABLE_CONTACT))
+ {
+ const PxU32 body0Dynamic = PxU32(input.flags & PxcNpWorkUnitFlag::eDYNAMIC_BODY0);
+ const PxU32 body1Dynamic = PxU32(input.flags & PxcNpWorkUnitFlag::eDYNAMIC_BODY1);
+
+ const PxU32 active0 = PxU32(body0Dynamic && !cachedTransform0->isFrozen());
+ const PxU32 active1 = PxU32(body1Dynamic && !cachedTransform1->isFrozen());
+
+ if(!(active0 || active1))
+ {
+ if(flip)
+ Ps::swap(type0, type1);
+
+ const bool useContactCache = context.mContactCache && g_CanUseContactCache[type0][type1];
+
+#if PX_ENABLE_SIM_STATS
+ if(output.nbContacts)
+ context.mNbDiscreteContactPairsWithContacts++;
+#endif
+ const bool isMeshType = type1 > PxGeometryType::eCONVEXMESH;
+ copyBuffers(output, cache, context, useContactCache, isMeshType);
+ return;
+ }
+ }
+
+ output.statusFlag &= (~PxcNpWorkUnitStatusFlag::eDIRTY_MANAGER);
+
+ PxsShapeCore* shape0 = const_cast<PxsShapeCore*>(input.shapeCore0);
+ PxsShapeCore* shape1 = const_cast<PxsShapeCore*>(input.shapeCore1);
+
+ if(flip)
+ {
+ Ps::swap(type0, type1);
+ Ps::swap(shape0, shape1);
+ Ps::swap(cachedTransform0, cachedTransform1);
+ }
+
+ // PT: many cache misses here...
+ // PT: TODO: refactor this change with runNpBatchPPU
+
+ Ps::prefetchLine(shape1, 0); // PT: at least get rid of L2s for shape1
+
+ const PxTransform* tm0 = &cachedTransform0->transform;
+ const PxTransform* tm1 = &cachedTransform1->transform;
+ PX_ASSERT(tm0->isSane() && tm1->isSane());
+
+ updateDiscreteContactStats(context, type0, type1);
+
+ const PxReal contactDist0 = context.mContactDistance[input.mTransformCache0];
+ const PxReal contactDist1 = context.mContactDistance[input.mTransformCache1];
+ //context.mNarrowPhaseParams.mContactDistance = shape0->contactOffset + shape1->contactOffset;
+ context.mNarrowPhaseParams.mContactDistance = contactDist0 + contactDist1;
+
+ startContacts(output, context);
+
+ const PxcContactMethod conMethod = g_ContactMethodTable[type0][type1];
+ PX_ASSERT(conMethod);
+
+ const bool useContactCache = context.mContactCache && g_CanUseContactCache[type0][type1];
+ if(useContactCache)
+ {
+#if PX_ENABLE_SIM_STATS
+ if(PxcCacheLocalContacts(context, cache, *tm0, *tm1, conMethod, shape0->geometry, shape1->geometry))
+ context.mNbDiscreteContactPairsWithCacheHits++;
+#else
+ PxcCacheLocalContacts(context, n.pairCache, *tm0, *tm1, conMethod, shape0->geometry, shape1->geometry);
+#endif
+ }
+ else
+ {
+ conMethod(shape0->geometry, shape1->geometry, *tm0, *tm1, context.mNarrowPhaseParams, cache, context.mContactBuffer, &context.mRenderOutput);
+ }
+
+ PxsMaterialInfo materialInfo[ContactBuffer::MAX_CONTACTS];
+
+ const PxcGetMaterialMethod materialMethod = g_GetMaterialMethodTable[type0][type1];
+ PX_ASSERT(materialMethod);
+
+ materialMethod(shape0, shape1, context, materialInfo);
+
+ if(flip)
+ flipContacts(context, materialInfo);
+
+ const bool isMeshType = type1 > PxGeometryType::eCONVEXMESH;
+ finishContacts(input, output, context, materialInfo, isMeshType);
+}
+
+void physx::PxcDiscreteNarrowPhasePCM(PxcNpThreadContext& context, PxcNpWorkUnit& cmInput, Gu::Cache& cache, PxsContactManagerOutput& output)
+{
+ //ML : if user doesn't raise the eDETECT_DISCRETE_CONTACT, we should not generate contacts
+ if(!(cmInput.flags & PxcNpWorkUnitFlag::eDETECT_DISCRETE_CONTACT))
+ return;
+
+ PxGeometryType::Enum type0 = static_cast<PxGeometryType::Enum>(cmInput.geomType0);
+ PxGeometryType::Enum type1 = static_cast<PxGeometryType::Enum>(cmInput.geomType1);
+
+ const bool flip = type1<type0;
+
+ const PxsCachedTransform* tm0 = &context.mTransformCache->getTransformCache(cmInput.mTransformCache0);
+ const PxsCachedTransform* tm1 = &context.mTransformCache->getTransformCache(cmInput.mTransformCache1);
+
+ if(!(output.statusFlag & PxcNpWorkUnitStatusFlag::eDIRTY_MANAGER) && !(cmInput.flags & PxcNpWorkUnitFlag::eMODIFIABLE_CONTACT))
+ {
+ const PxU32 body0Dynamic = PxU32(cmInput.flags & PxcNpWorkUnitFlag::eDYNAMIC_BODY0);
+ const PxU32 body1Dynamic = PxU32(cmInput.flags & PxcNpWorkUnitFlag::eDYNAMIC_BODY1);
+
+ const PxU32 active0 = PxU32(body0Dynamic && !(tm0->isFrozen()));
+ const PxU32 active1 = PxU32(body1Dynamic && !(tm1->isFrozen()));
+
+ if(!(active0 || active1))
+ {
+ if(flip)
+ Ps::swap(type0, type1);
+
+#if PX_ENABLE_SIM_STATS
+ if(output.nbContacts)
+ context.mNbDiscreteContactPairsWithContacts++;
+#endif
+ const bool isMeshType = type1 > PxGeometryType::eCONVEXMESH;
+ copyBuffers(output, cache, context, false, isMeshType);
+ return;
+ }
+ }
+
+ output.statusFlag &= (~PxcNpWorkUnitStatusFlag::eDIRTY_MANAGER);
+
+ Gu::MultiplePersistentContactManifold& manifold = context.mTempManifold;
+ bool isMultiManifold = false;
+
+ if(cache.isMultiManifold())
+ {
+ //We are using a multi-manifold. This is cached in a reduced npCache...
+ isMultiManifold = true;
+ uintptr_t address = uintptr_t(&cache.getMultipleManifold());
+ manifold.fromBuffer(reinterpret_cast<PxU8*>(address));
+ cache.setMultiManifold(&manifold);
+ }
+ else if(cache.isManifold())
+ {
+ void* address = reinterpret_cast<void*>(&cache.getManifold());
+ Ps::prefetch(address);
+ Ps::prefetch(address, 128);
+ Ps::prefetch(address, 256);
+ }
+
+ PxsShapeCore* shape0 = const_cast<PxsShapeCore*>(cmInput.shapeCore0);
+ PxsShapeCore* shape1 = const_cast<PxsShapeCore*>(cmInput.shapeCore1);
+
+ if(flip)
+ {
+ Ps::swap(tm0, tm1);
+ Ps::swap(shape0, shape1);
+ Ps::swap(type0, type1);
+ }
+
+ const PxReal contactDist0 = context.mContactDistance[cmInput.mTransformCache0];
+ const PxReal contactDist1 = context.mContactDistance[cmInput.mTransformCache1];
+// context.mNarrowPhaseParams.mContactDistance = shape0->contactOffset + shape1->contactOffset;
+ context.mNarrowPhaseParams.mContactDistance = contactDist0 + contactDist1;
+
+ PX_ASSERT(tm0->transform.isSane() && tm1->transform.isSane());
+
+ updateDiscreteContactStats(context, type0, type1);
+
+ const PxcContactMethod conMethod = g_PCMContactMethodTable[type0][type1];
+ PX_ASSERT(conMethod);
+
+ startContacts(output, context);
+
+ conMethod(shape0->geometry, shape1->geometry, tm0->transform, tm1->transform, context.mNarrowPhaseParams, cache, context.mContactBuffer, &context.mRenderOutput);
+
+ PxsMaterialInfo materialInfo[ContactBuffer::MAX_CONTACTS];
+
+ const PxcGetMaterialMethod materialMethod = g_GetMaterialMethodTable[type0][type1];
+ PX_ASSERT(materialMethod);
+
+ materialMethod(shape0, shape1, context, materialInfo);
+
+ if(flip)
+ flipContacts(context, materialInfo);
+
+ if(isMultiManifold)
+ {
+ //Store the manifold back...
+ const PxU32 size = (sizeof(MultiPersistentManifoldHeader) +
+ manifold.mNumManifolds * sizeof(SingleManifoldHeader) +
+ manifold.mNumTotalContacts * sizeof(Gu::CachedMeshPersistentContact));
+
+ PxU8* buffer = context.mNpCacheStreamPair.reserve(size);
+
+ PX_ASSERT((reinterpret_cast<uintptr_t>(buffer)& 0xf) == 0);
+ manifold.toBuffer(buffer);
+ cache.setMultiManifold(buffer);
+ cache.mCachedSize = Ps::to16(size);
+ }
+
+ const bool isMeshType = type1 > PxGeometryType::eCONVEXMESH;
+ finishContacts(cmInput, output, context, materialInfo, isMeshType);
+}
diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpCacheStreamPair.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpCacheStreamPair.cpp
new file mode 100644
index 00000000..54096677
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpCacheStreamPair.cpp
@@ -0,0 +1,75 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#include "PxcNpCacheStreamPair.h"
+#include "PsUserAllocated.h"
+#include "PxcNpMemBlockPool.h"
+
+using namespace physx;
+
+void PxcNpCacheStreamPair::reset()
+{
+ mBlock = NULL;
+ mUsed = 0;
+}
+
+PxcNpCacheStreamPair::PxcNpCacheStreamPair(PxcNpMemBlockPool& blockPool):
+ mBlockPool(blockPool), mBlock(NULL), mUsed(0)
+{
+}
+
+// reserve can fail and return null. Read should never fail
+PxU8* PxcNpCacheStreamPair::reserve(PxU32 size)
+{
+ size = (size+15)&~15;
+
+ if(size>PxcNpMemBlock::SIZE)
+ {
+ return reinterpret_cast<PxU8*>(-1);
+ }
+
+ if(mBlock == NULL || mUsed + size > PxcNpMemBlock::SIZE)
+ {
+ mBlock = mBlockPool.acquireNpCacheBlock();
+ mUsed = 0;
+ }
+
+ PxU8* ptr;
+ if(mBlock == NULL)
+ ptr = 0;
+ else
+ {
+ ptr = mBlock->data+mUsed;
+ mUsed += size;
+ }
+
+ return ptr;
+}
+
diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpContactPrepShared.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpContactPrepShared.cpp
new file mode 100644
index 00000000..e0fa6262
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpContactPrepShared.cpp
@@ -0,0 +1,623 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#include "foundation/PxPreprocessor.h"
+#include "PsMathUtils.h"
+#include "PxcNpWorkUnit.h"
+#include "PxvDynamics.h"
+
+using namespace physx;
+using namespace Gu;
+
+#include "PxsMaterialManager.h"
+#include "PxsMaterialCombiner.h"
+
+#include "PxcNpContactPrepShared.h"
+#include "PsAtomic.h"
+#include "PxsContactManagerState.h"
+
+#include "PsVecMath.h"
+using namespace physx;
+using namespace Ps::aos;
+
+static PX_FORCE_INLINE void copyContactPoint(PxContact* PX_RESTRICT point, const Gu::ContactPoint* PX_RESTRICT cp)
+{
+ // PT: TODO: consider moving "separation" right after "point" in both structures, to copy both at the same time.
+// point->contact = cp->point;
+ const Vec4V contactV = V4LoadA(&cp->point.x); // PT: V4LoadA safe because 'point' is aligned.
+ V4StoreU(contactV, &point->contact.x);
+
+ point->separation = cp->separation;
+}
+
+struct StridePatch
+{
+ PxU8 startIndex;
+ PxU8 endIndex;
+ PxU8 nextIndex;
+ PxU8 totalCount;
+ bool isRoot;
+};
+
+PxU32 physx::writeCompressedContact(const Gu::ContactPoint* const PX_RESTRICT contactPoints, const PxU32 numContactPoints, PxcNpThreadContext* threadContext,
+ PxU8& writtenContactCount, PxU8*& outContactPatches, PxU8*& outContactPoints, PxU16& compressedContactSize, PxReal*& outContactForces, PxU32 contactForceByteSize,
+ const PxsMaterialManager* materialManager, bool hasModifiableContacts, bool forceNoResponse, PxsMaterialInfo* PX_RESTRICT pMaterial, PxU8& numPatches,
+ PxU32 additionalHeaderSize, PxsConstraintBlockManager* manager, PxcConstraintBlockStream* blockStream, bool insertAveragePoint,
+ PxcDataStreamPool* contactStreamPool, PxcDataStreamPool* patchStreamPool, PxcDataStreamPool* forceStreamPool, const bool isMeshType)
+{
+ if(numContactPoints == 0)
+ {
+ writtenContactCount = 0;
+ outContactPatches = NULL;
+ outContactPoints = NULL;
+ outContactForces = NULL;
+ compressedContactSize = 0;
+ numPatches = 0;
+ return 0;
+ }
+
+ //Calculate the size of the contact buffer...
+ PX_ALLOCA(strPatches, StridePatch, numContactPoints);
+
+ StridePatch* stridePatches = &strPatches[0];
+
+ PxU32 numStrideHeaders = 1;
+
+ /*const bool hasInternalFaceIndex = contactPoints[0].internalFaceIndex0 != PXC_CONTACT_NO_FACE_INDEX ||
+ contactPoints[0].internalFaceIndex1 != PXC_CONTACT_NO_FACE_INDEX;*/
+ const bool isModifiable = !forceNoResponse && hasModifiableContacts;
+
+ PxU32 totalUniquePatches = 1;
+
+ PxU32 totalContactPoints = numContactPoints;
+
+ PxU32 strideStart = 0;
+ bool root = true;
+ StridePatch* parentRootPatch = NULL;
+ {
+ const PxReal closeNormalThresh = PXC_SAME_NORMAL;
+ //Go through and tag how many patches we have...
+ PxVec3 normal = contactPoints[0].normal;
+ PxU16 mat0 = pMaterial[0].mMaterialIndex0;
+ PxU16 mat1 = pMaterial[0].mMaterialIndex1;
+
+ for(PxU32 a = 1; a < numContactPoints; ++a)
+ {
+ if(normal.dot(contactPoints[a].normal) < closeNormalThresh ||
+ pMaterial[a].mMaterialIndex0 != mat0 || pMaterial[a].mMaterialIndex1 != mat1)
+ {
+ StridePatch& patch = stridePatches[numStrideHeaders-1];
+
+ patch.startIndex = PxU8(strideStart);
+ patch.endIndex = PxU8(a);
+ patch.nextIndex = 0xFF;
+ patch.totalCount = PxU8(a - strideStart);
+ patch.isRoot = root;
+ if(parentRootPatch)
+ parentRootPatch->totalCount += PxU8(a - strideStart);
+
+ root = true;
+ parentRootPatch = NULL;
+ for(PxU32 b = 1; b < numStrideHeaders; ++b)
+ {
+ StridePatch& thisPatch = stridePatches[b-1];
+ if(thisPatch.isRoot)
+ {
+ PxU32 ind = thisPatch.startIndex;
+ PxReal dp2 = contactPoints[a].normal.dot(contactPoints[ind].normal);
+ if(dp2 >= closeNormalThresh && pMaterial[a].mMaterialIndex0 == pMaterial[ind].mMaterialIndex0 &&
+ pMaterial[a].mMaterialIndex1 == pMaterial[ind].mMaterialIndex1)
+ {
+ PxU32 nextInd = b-1;
+ while(stridePatches[nextInd].nextIndex != 0xFF)
+ nextInd = stridePatches[nextInd].nextIndex;
+ stridePatches[nextInd].nextIndex = PxU8(numStrideHeaders);
+ root = false;
+ parentRootPatch = &stridePatches[b-1];
+ break;
+ }
+ }
+ }
+
+ normal = contactPoints[a].normal;
+
+ mat0 = pMaterial[a].mMaterialIndex0;
+ mat1 = pMaterial[a].mMaterialIndex1;
+ totalContactPoints = insertAveragePoint && (a - strideStart) > 1 ? totalContactPoints + 1 : totalContactPoints;
+ strideStart = a;
+ numStrideHeaders++;
+ if(root)
+ totalUniquePatches++;
+ }
+ }
+ totalContactPoints = insertAveragePoint &&(numContactPoints - strideStart) > 1 ? totalContactPoints + 1 : totalContactPoints;
+ contactForceByteSize = insertAveragePoint && contactForceByteSize != 0 ? contactForceByteSize + sizeof(PxF32) * (totalContactPoints - numContactPoints) : contactForceByteSize;
+ }
+ {
+ StridePatch& patch = stridePatches[numStrideHeaders-1];
+ patch.startIndex = PxU8(strideStart);
+ patch.endIndex = PxU8(numContactPoints);
+ patch.nextIndex = 0xFF;
+ patch.totalCount = PxU8(numContactPoints - strideStart);
+ patch.isRoot = root;
+ if(parentRootPatch)
+ parentRootPatch->totalCount += PxU8(numContactPoints - strideStart);
+ }
+
+ numPatches = PxU8(totalUniquePatches);
+
+ //Calculate the number of patches/points required
+
+ const PxU32 patchHeaderSize = sizeof(PxContactPatch) * (isModifiable ? totalContactPoints : totalUniquePatches) + additionalHeaderSize;
+ const PxU32 pointSize = totalContactPoints * (isModifiable ? sizeof(PxModifiableContact) : sizeof(PxContact));
+
+ PxU32 requiredContactSize = pointSize;
+ PxU32 requiredPatchSize = patchHeaderSize;
+ PxU32 totalRequiredSize;
+
+ PxU8* PX_RESTRICT contactData = NULL;
+ PxU8* PX_RESTRICT patchData = NULL;
+ PxReal* PX_RESTRICT forceData = NULL;
+ PxU32* PX_RESTRICT triangleIndice = NULL;
+
+ if(contactStreamPool && !isModifiable && additionalHeaderSize == 0) //If the contacts are modifiable, we **DON'T** allocate them in GPU pinned memory. This will be handled later when they're modified
+ {
+ bool isOverflown = false;
+
+ PxU32 contactIndex = PxU32(Ps::atomicAdd(&contactStreamPool->mSharedDataIndex, PxI32(requiredContactSize)));
+
+ if (contactStreamPool->isOverflown())
+ {
+ PX_WARN_ONCE("Contact buffer overflow detected, please increase its size in the scene desc!\n");
+ isOverflown = true;
+ }
+
+ contactData = contactStreamPool->mDataStream + contactStreamPool->mDataStreamSize - contactIndex;
+
+ PxU32 patchIndex = PxU32(Ps::atomicAdd(&patchStreamPool->mSharedDataIndex, PxI32(requiredPatchSize)));
+
+ if (patchStreamPool->isOverflown())
+ {
+ PX_WARN_ONCE("Patch buffer overflow detected, please increase its size in the scene desc!\n");
+ isOverflown = true;
+ }
+
+ patchData = patchStreamPool->mDataStream + patchStreamPool->mDataStreamSize - patchIndex;
+
+ if(contactForceByteSize)
+ {
+ contactForceByteSize = isMeshType ? contactForceByteSize * 2 : contactForceByteSize;
+ contactIndex = PxU32(Ps::atomicAdd(&forceStreamPool->mSharedDataIndex, PxI32(contactForceByteSize)));
+
+ if (forceStreamPool->isOverflown())
+ {
+ PX_WARN_ONCE("Force buffer overflow detected, please increase its size in the scene desc!\n");
+ isOverflown = true;
+ }
+ forceData = reinterpret_cast<PxReal*>(forceStreamPool->mDataStream + forceStreamPool->mDataStreamSize - contactIndex);
+ if (isMeshType)
+ triangleIndice = reinterpret_cast<PxU32*>(forceData + numContactPoints);
+ }
+
+ totalRequiredSize = requiredContactSize + requiredPatchSize;
+
+ if (isOverflown)
+ {
+ patchData = NULL;
+ contactData = NULL;
+ forceData = NULL;
+ triangleIndice = NULL;
+ }
+ }
+ else
+ {
+ PxU32 alignedRequiredSize = (requiredContactSize + requiredPatchSize + 0xf) & 0xfffffff0;
+ contactForceByteSize = (isMeshType ? contactForceByteSize * 2 : contactForceByteSize);
+ PxU32 totalSize = alignedRequiredSize + contactForceByteSize;
+ PxU8* data = manager ? blockStream->reserve(totalSize, *manager) : threadContext->mContactBlockStream.reserve(totalSize);
+
+ patchData = data;
+ contactData = patchData + requiredPatchSize;
+
+ if(contactForceByteSize)
+ {
+ forceData = reinterpret_cast<PxReal*>((data + alignedRequiredSize));
+
+ if (isMeshType)
+ triangleIndice = reinterpret_cast<PxU32*>(forceData + numContactPoints);
+
+ if(data)
+ {
+ PxMemZero(forceData, contactForceByteSize);
+ }
+ }
+
+ totalRequiredSize = alignedRequiredSize;
+
+ }
+
+ Ps::prefetchLine(patchData);
+ Ps::prefetchLine(contactData);
+
+ if(patchData == NULL)
+ {
+ writtenContactCount = 0;
+ outContactPatches = NULL;
+ outContactPoints = NULL;
+ outContactForces = NULL;
+ compressedContactSize = 0;
+ numPatches = 0;
+ return 0;
+ }
+
+#if PX_ENABLE_SIM_STATS
+ if(threadContext)
+ {
+ threadContext->mCompressedCacheSize += totalRequiredSize;
+ threadContext->mTotalCompressedCacheSize += totalRequiredSize;
+ }
+#endif
+ compressedContactSize = Ps::to16(totalRequiredSize);
+
+
+
+ //PxU32 startIndex = 0;
+
+ //Extract first material
+ PxU16 origMatIndex0 = pMaterial[0].mMaterialIndex0;
+ PxU16 origMatIndex1 = pMaterial[0].mMaterialIndex1;
+
+ PxReal staticFriction, dynamicFriction, combinedRestitution;
+ PxU32 materialFlags;
+ {
+ const PxsMaterialData& data0 = *materialManager->getMaterial(origMatIndex0);
+ const PxsMaterialData& data1 = *materialManager->getMaterial(origMatIndex1);
+
+ combinedRestitution = PxsMaterialCombiner::combineRestitution(data0, data1);
+ PxsMaterialCombiner combiner(1.0f, 1.0f);
+ PxsMaterialCombiner::PxsCombinedMaterial combinedMat = combiner.combineIsotropicFriction(data0, data1);
+ staticFriction = combinedMat.staFriction;
+ dynamicFriction = combinedMat.dynFriction;
+ materialFlags = combinedMat.flags;
+ }
+
+
+ PxU8* PX_RESTRICT dataPlusOffset = patchData + additionalHeaderSize;
+ PxContactPatch* PX_RESTRICT patches = reinterpret_cast<PxContactPatch*>(dataPlusOffset);
+ PxU32* PX_RESTRICT faceIndice = triangleIndice;
+
+ outContactPatches = patchData;
+ outContactPoints = contactData;
+ outContactForces = forceData;
+
+ if(isModifiable)
+ {
+
+ PxU32 flags = PxU32(isModifiable ? PxContactPatch::eMODIFIABLE : 0) |
+ (forceNoResponse ? PxContactPatch::eFORCE_NO_RESPONSE : 0) |
+ (isMeshType ? PxContactPatch::eHAS_FACE_INDICES : 0);
+
+ PxU32 currentIndex = 0;
+
+ PxModifiableContact* PX_RESTRICT point = reinterpret_cast<PxModifiableContact*>(contactData);
+
+ for(PxU32 a = 0; a < numStrideHeaders; ++a)
+ {
+ StridePatch& rootPatch = stridePatches[a];
+ if(rootPatch.isRoot)
+ {
+ PxContactPatch* PX_RESTRICT patch = patches++;
+
+ PxU32 startIndex = rootPatch.startIndex;
+
+ const PxU16 matIndex0 = pMaterial[startIndex].mMaterialIndex0;
+ const PxU16 matIndex1 = pMaterial[startIndex].mMaterialIndex1;
+ if(matIndex0 != origMatIndex0 || matIndex1 != origMatIndex1)
+ {
+ const PxsMaterialData& data0 = *materialManager->getMaterial(matIndex0);
+ const PxsMaterialData& data1 = *materialManager->getMaterial(matIndex1);
+
+ combinedRestitution = PxsMaterialCombiner::combineRestitution(data0, data1);
+ PxsMaterialCombiner combiner(1.0f, 1.0f);
+ PxsMaterialCombiner::PxsCombinedMaterial combinedMat = combiner.combineIsotropicFriction(data0, data1);
+ staticFriction = combinedMat.staFriction;
+ dynamicFriction = combinedMat.dynFriction;
+ materialFlags = combinedMat.flags;
+ origMatIndex0 = matIndex0;
+ origMatIndex1 = matIndex1;
+ }
+
+ patch->nbContacts = rootPatch.totalCount;
+
+ patch->startContactIndex = Ps::to8(currentIndex);
+ patch->materialFlags = PxU8(materialFlags);
+ patch->staticFriction = staticFriction;
+ patch->dynamicFriction = dynamicFriction;
+ patch->restitution = combinedRestitution;
+ patch->materialIndex0 = matIndex0;
+ patch->materialIndex1 = matIndex1;
+ patch->normal = contactPoints[0].normal;
+ patch->mMassModification.mInvMassScale0 = 1.0f;
+ patch->mMassModification.mInvMassScale1 = 1.0f;
+ patch->mMassModification.mInvInertiaScale0 = 1.0f;
+ patch->mMassModification.mInvInertiaScale1 = 1.0f;
+ patch->internalFlags = PxU8(flags);
+
+ //const PxU32 endIndex = strideHeader[a];
+ const PxU32 totalCountThisPatch = rootPatch.totalCount;
+ if(insertAveragePoint && totalCountThisPatch > 1)
+ {
+ PxVec3 avgPt(0.0f);
+ PxF32 avgPen(0.0f);
+ PxF32 recipCount = 1.0f/(PxF32(rootPatch.totalCount));
+
+ PxU32 index = a;
+ while(index != 0xFF)
+ {
+ StridePatch& p = stridePatches[index];
+ for(PxU32 b = p.startIndex; b < p.endIndex; ++b)
+ {
+ avgPt += contactPoints[b].point;
+ avgPen += contactPoints[b].separation;
+ }
+ index = p.nextIndex;
+ }
+
+ if (faceIndice)
+ {
+ StridePatch& p = stridePatches[index];
+ *faceIndice = contactPoints[p.startIndex].internalFaceIndex1;
+ faceIndice++;
+ }
+
+ patch->nbContacts++;
+ point->contact = avgPt * recipCount;
+ point->separation = avgPen * recipCount;
+ point->normal = contactPoints[0].normal;
+ point->maxImpulse = PX_MAX_REAL;
+ point->targetVelocity = PxVec3(0.0f);
+ point->staticFriction = staticFriction;
+ point->dynamicFriction = dynamicFriction;
+ point->restitution = combinedRestitution;
+ point->materialFlags = materialFlags;
+ point->materialIndex0 = matIndex0;
+ point->materialIndex1 = matIndex1;
+ point++;
+ currentIndex++;
+ Ps::prefetchLine(point, 128);
+ }
+
+ PxU32 index = a;
+ while(index != 0xFF)
+ {
+ StridePatch& p = stridePatches[index];
+
+ for(PxU32 b = p.startIndex; b < p.endIndex; ++b)
+ {
+ copyContactPoint(point, &contactPoints[b]);
+ point->normal = contactPoints[b].normal;
+ point->maxImpulse = PX_MAX_REAL;
+ point->targetVelocity = PxVec3(0.0f);
+ point->staticFriction = staticFriction;
+ point->dynamicFriction = dynamicFriction;
+ point->restitution = combinedRestitution;
+ point->materialFlags = materialFlags;
+ point->materialIndex0 = matIndex0;
+ point->materialIndex1 = matIndex1;
+ if (faceIndice)
+ {
+ *faceIndice = contactPoints[b].internalFaceIndex1;
+ faceIndice++;
+ }
+ point++;
+ currentIndex++;
+ Ps::prefetchLine(point, 128);
+ }
+ index = p.nextIndex;
+ }
+ }
+ }
+ }
+ else
+ {
+ PxU32 flags = PxU32(isMeshType ? PxContactPatch::eHAS_FACE_INDICES : 0);
+
+ PxContact* PX_RESTRICT point = reinterpret_cast<PxContact*>(contactData);
+
+ PxU32 currentIndex = 0;
+ {
+ for(PxU32 a = 0; a < numStrideHeaders; ++a)
+ {
+ StridePatch& rootPatch = stridePatches[a];
+
+ if(rootPatch.isRoot)
+ {
+ const PxU16 matIndex0 = pMaterial[rootPatch.startIndex].mMaterialIndex0;
+ const PxU16 matIndex1 = pMaterial[rootPatch.startIndex].mMaterialIndex1;
+ if(matIndex0 != origMatIndex0 || matIndex1 != origMatIndex1)
+ {
+ const PxsMaterialData& data0 = *materialManager->getMaterial(matIndex0);
+ const PxsMaterialData& data1 = *materialManager->getMaterial(matIndex1);
+
+ combinedRestitution = PxsMaterialCombiner::combineRestitution(data0, data1);
+ PxsMaterialCombiner combiner(1.0f, 1.0f);
+ PxsMaterialCombiner::PxsCombinedMaterial combinedMat = combiner.combineIsotropicFriction(data0, data1);
+ staticFriction = combinedMat.staFriction;
+ dynamicFriction = combinedMat.dynFriction;
+ materialFlags = combinedMat.flags;
+ origMatIndex0 = matIndex0;
+ origMatIndex1 = matIndex1;
+ }
+
+ PxContactPatch* PX_RESTRICT patch = patches++;
+ patch->normal = contactPoints[rootPatch.startIndex].normal;
+ patch->nbContacts = rootPatch.totalCount;
+ patch->startContactIndex = Ps::to8(currentIndex);
+ //KS - we could probably compress this further into the header but the complexity might not be worth it
+ patch->staticFriction = staticFriction;
+ patch->dynamicFriction = dynamicFriction;
+ patch->restitution = combinedRestitution;
+ patch->materialIndex0 = matIndex0;
+ patch->materialIndex1 = matIndex1;
+ patch->materialFlags = PxU8(materialFlags);
+ patch->internalFlags = PxU8(flags);
+ patch->mMassModification.mInvMassScale0 = 1.0f;
+ patch->mMassModification.mInvMassScale1 = 1.0f;
+ patch->mMassModification.mInvInertiaScale0 = 1.0f;
+ patch->mMassModification.mInvInertiaScale1 = 1.0f;
+ if(insertAveragePoint && (rootPatch.totalCount) > 1)
+ {
+ patch->nbContacts++;
+ PxVec3 avgPt(0.0f);
+ PxF32 avgPen(0.0f);
+ PxF32 recipCount = 1.0f/(PxF32(rootPatch.totalCount));
+ PxU32 index = a;
+
+ while(index != 0xFF)
+ {
+ StridePatch& p = stridePatches[index];
+ for(PxU32 b = p.startIndex; b < p.endIndex; ++b)
+ {
+ avgPt += contactPoints[b].point;
+ avgPen += contactPoints[b].separation;
+ }
+ index = stridePatches[index].nextIndex;
+ }
+
+ if (faceIndice)
+ {
+ StridePatch& p = stridePatches[index];
+ *faceIndice = contactPoints[p.startIndex].internalFaceIndex1;
+ faceIndice++;
+ }
+ point->contact = avgPt * recipCount;
+ point->separation = avgPen * recipCount;
+
+ point++;
+ currentIndex++;
+ Ps::prefetchLine(point, 128);
+ }
+
+ PxU32 index = a;
+ while(index != 0xFF)
+ {
+ StridePatch& p = stridePatches[index];
+ for(PxU32 b = p.startIndex; b < p.endIndex; ++b)
+ {
+ copyContactPoint(point, &contactPoints[b]);
+ if (faceIndice)
+ {
+ *faceIndice = contactPoints[b].internalFaceIndex1;
+ faceIndice++;
+ }
+ point++;
+ currentIndex++;
+ Ps::prefetchLine(point, 128);
+ }
+ index = stridePatches[index].nextIndex;
+ }
+ }
+ }
+ }
+ }
+
+ writtenContactCount = Ps::to8(totalContactPoints);
+
+ return totalRequiredSize;
+}
+
+//ML: isMeshType is used in the GPU codepath. If the collision pair is mesh/heightfield vs primitives, we need to allocate enough memory for the mForceAndIndiceStreamPool in the threadContext.
+bool physx::finishContacts(PxcNpWorkUnit& input, PxsContactManagerOutput& npOutput, PxcNpThreadContext& threadContext, PxsMaterialInfo* PX_RESTRICT pMaterials, const bool isMeshType)
+{
+ ContactBuffer& buffer = threadContext.mContactBuffer;
+
+ PX_ASSERT((npOutput.statusFlag & PxsContactManagerStatusFlag::eTOUCH_KNOWN) != PxsContactManagerStatusFlag::eTOUCH_KNOWN);
+ PxU8 statusFlags = PxU16(npOutput.statusFlag & (~PxsContactManagerStatusFlag::eTOUCH_KNOWN));
+ if (buffer.count != 0)
+ statusFlags |= PxsContactManagerStatusFlag::eHAS_TOUCH;
+ else
+ statusFlags |= PxsContactManagerStatusFlag::eHAS_NO_TOUCH;
+
+ npOutput.nbContacts = Ps::to8(buffer.count);
+
+ if(buffer.count==0)
+ {
+ npOutput.statusFlag = statusFlags;
+ npOutput.nbContacts = 0;
+ npOutput.nbPatches = 0;
+ return true;
+ }
+
+
+#if PX_ENABLE_SIM_STATS
+ if(buffer.count)
+ threadContext.mNbDiscreteContactPairsWithContacts++;
+#endif
+
+ npOutput.statusFlag = statusFlags;
+
+ PxU32 contactForceByteSize = buffer.count * sizeof(PxReal);
+
+ //Regardless of the flags, we need to now record the compressed contact stream
+
+ PxU16 compressedContactSize;
+
+ const bool createReports =
+ input.flags & PxcNpWorkUnitFlag::eOUTPUT_CONTACTS
+ || threadContext.mCreateContactStream
+ || (input.flags & PxcNpWorkUnitFlag::eFORCE_THRESHOLD);
+
+ if (!buffer.count || (!isMeshType && !createReports))
+ {
+ contactForceByteSize = 0;
+ }
+
+ bool res = (writeCompressedContact(buffer.contacts, buffer.count, &threadContext, npOutput.nbContacts, npOutput.contactPatches, npOutput.contactPoints, compressedContactSize,
+ reinterpret_cast<PxReal*&>(npOutput.contactForces), contactForceByteSize, threadContext.mMaterialManager, ((input.flags & PxcNpWorkUnitFlag::eMODIFIABLE_CONTACT) != 0),
+ false, pMaterials, npOutput.nbPatches, 0, NULL, NULL, threadContext.mCreateAveragePoint, threadContext.mContactStreamPool,
+ threadContext.mPatchStreamPool, threadContext.mForceAndIndiceStreamPool, isMeshType) != 0) || (buffer.count == 0);
+
+ //handle buffer overflow
+ if (buffer.count && !npOutput.nbContacts)
+ {
+ PxU8 thisStatusFlags = PxU16(npOutput.statusFlag & (~PxsContactManagerStatusFlag::eTOUCH_KNOWN));
+ thisStatusFlags |= PxsContactManagerStatusFlag::eHAS_NO_TOUCH;
+
+ npOutput.statusFlag = thisStatusFlags;
+ npOutput.nbContacts = 0;
+ npOutput.nbPatches = 0;
+#if PX_ENABLE_SIM_STATS
+ if(buffer.count)
+ threadContext.mNbDiscreteContactPairsWithContacts--;
+#endif
+ }
+
+ return res;
+}
diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpMemBlockPool.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpMemBlockPool.cpp
new file mode 100644
index 00000000..51eb0110
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpMemBlockPool.cpp
@@ -0,0 +1,351 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "foundation/PxPreprocessor.h"
+#include "foundation/PxMath.h"
+#include "PxcNpMemBlockPool.h"
+#include "PsUserAllocated.h"
+#include "PsInlineArray.h"
+#include "PsFoundation.h"
+
+using namespace physx;
+
+PxcNpMemBlockPool::PxcNpMemBlockPool(PxcScratchAllocator& allocator):
+ mConstraints(PX_DEBUG_EXP("PxcNpMemBlockPool::mConstraints")),
+ mExceptionalConstraints(PX_DEBUG_EXP("PxcNpMemBlockPool::mExceptionalConstraints")),
+ mNpCacheActiveStream(0),
+ mFrictionActiveStream(0),
+ mCCDCacheActiveStream(0),
+ mContactIndex(0),
+ mAllocatedBlocks(0),
+ mMaxBlocks(0),
+ mUsedBlocks(0),
+ mMaxUsedBlocks(0),
+ mScratchBlockAddr(0),
+ mNbScratchBlocks(0),
+ mScratchAllocator(allocator),
+ mPeakConstraintAllocations(0),
+ mConstraintAllocations(0)
+{
+}
+
+void PxcNpMemBlockPool::init(PxU32 initialBlockCount, PxU32 maxBlocks)
+{
+ mMaxBlocks = maxBlocks;
+ mInitialBlocks = initialBlockCount;
+
+ PxU32 reserve = PxMax<PxU32>(initialBlockCount, 64);
+
+ mConstraints.reserve(reserve);
+ mExceptionalConstraints.reserve(16);
+
+ mFriction[0].reserve(reserve);
+ mFriction[1].reserve(reserve);
+ mNpCache[0].reserve(reserve);
+ mNpCache[1].reserve(reserve);
+ mUnused.reserve(reserve);
+
+ setBlockCount(initialBlockCount);
+}
+
+PxU32 PxcNpMemBlockPool::getUsedBlockCount() const
+{
+ return mUsedBlocks;
+}
+
+PxU32 PxcNpMemBlockPool::getMaxUsedBlockCount() const
+{
+ return mMaxUsedBlocks;
+}
+
+PxU32 PxcNpMemBlockPool::getPeakConstraintBlockCount() const
+{
+ return mPeakConstraintAllocations;
+}
+
+
+void PxcNpMemBlockPool::setBlockCount(PxU32 blockCount)
+{
+ Ps::Mutex::ScopedLock lock(mLock);
+ PxU32 current = getUsedBlockCount();
+ for(PxU32 i=current;i<blockCount;i++)
+ {
+ mUnused.pushBack(reinterpret_cast<PxcNpMemBlock *>(PX_ALLOC(PxcNpMemBlock::SIZE, "PxcNpMemBlock")));
+ mAllocatedBlocks++;
+ }
+}
+
+void PxcNpMemBlockPool::releaseUnusedBlocks()
+{
+ Ps::Mutex::ScopedLock lock(mLock);
+ while(mUnused.size())
+ {
+ PX_FREE(mUnused.popBack());
+ mAllocatedBlocks--;
+ }
+}
+
+
+PxcNpMemBlockPool::~PxcNpMemBlockPool()
+{
+ // swapping twice guarantees all blocks are released from the stream pairs
+ swapFrictionStreams();
+ swapFrictionStreams();
+
+ swapNpCacheStreams();
+ swapNpCacheStreams();
+
+ releaseConstraintMemory();
+ releaseContacts();
+ releaseContacts();
+
+ PX_ASSERT(mUsedBlocks == 0);
+
+ flushUnused();
+}
+
+void PxcNpMemBlockPool::acquireConstraintMemory()
+{
+ PxU32 size;
+ void* addr = mScratchAllocator.allocAll(size);
+ size = size&~(PxcNpMemBlock::SIZE-1);
+
+ PX_ASSERT(mScratchBlocks.size()==0);
+ mScratchBlockAddr = reinterpret_cast<PxcNpMemBlock*>(addr);
+ mNbScratchBlocks = size/PxcNpMemBlock::SIZE;
+
+ mScratchBlocks.resize(mNbScratchBlocks);
+ for(PxU32 i=0;i<mNbScratchBlocks;i++)
+ mScratchBlocks[i] = mScratchBlockAddr+i;
+}
+
+void PxcNpMemBlockPool::releaseConstraintMemory()
+{
+ Ps::Mutex::ScopedLock lock(mLock);
+
+ mPeakConstraintAllocations = mConstraintAllocations = 0;
+
+ while(mConstraints.size())
+ {
+ PxcNpMemBlock* block = mConstraints.popBack();
+ if(mScratchAllocator.isScratchAddr(block))
+ mScratchBlocks.pushBack(block);
+ else
+ {
+ mUnused.pushBack(block);
+ PX_ASSERT(mUsedBlocks>0);
+ mUsedBlocks--;
+ }
+ }
+
+ for(PxU32 i=0;i<mExceptionalConstraints.size();i++)
+ PX_FREE(mExceptionalConstraints[i]);
+ mExceptionalConstraints.clear();
+
+ PX_ASSERT(mScratchBlocks.size()==mNbScratchBlocks); // check we released them all
+ mScratchBlocks.clear();
+
+ if(mScratchBlockAddr)
+ {
+ mScratchAllocator.free(mScratchBlockAddr);
+ mScratchBlockAddr = 0;
+ mNbScratchBlocks = 0;
+ }
+}
+
+
+PxcNpMemBlock* PxcNpMemBlockPool::acquire(PxcNpMemBlockArray& trackingArray, PxU32* allocationCount, PxU32* peakAllocationCount, bool isScratchAllocation)
+{
+ Ps::Mutex::ScopedLock lock(mLock);
+ if(allocationCount && peakAllocationCount)
+ {
+ *peakAllocationCount = PxMax(*allocationCount + 1, *peakAllocationCount);
+ (*allocationCount)++;
+ }
+
+ // this is a bit of hack - the logic would be better placed in acquireConstraintBlock, but then we'd have to grab the mutex
+ // once there to check the scratch block array and once here if we fail - or, we'd need a larger refactor to separate out
+ // locking and acquisition.
+
+ if(isScratchAllocation && mScratchBlocks.size()>0)
+ {
+ PxcNpMemBlock* block = mScratchBlocks.popBack();
+ trackingArray.pushBack(block);
+ return block;
+ }
+
+
+ if(mUnused.size())
+ {
+ PxcNpMemBlock* block = mUnused.popBack();
+ trackingArray.pushBack(block);
+ mMaxUsedBlocks = PxMax<PxU32>(mUsedBlocks+1, mMaxUsedBlocks);
+ mUsedBlocks++;
+ return block;
+ }
+
+
+ if(mAllocatedBlocks == mMaxBlocks)
+ {
+#if PX_CHECKED
+ Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__,
+ "Reached maximum number of allocated blocks so 16k block allocation will fail!");
+#endif
+ return NULL;
+ }
+
+#if PX_CHECKED
+ if(mInitialBlocks)
+ {
+ Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__,
+ "Number of required 16k memory blocks has exceeded the initial number of blocks. Allocator is being called. Consider increasing the number of pre-allocated 16k blocks.");
+ }
+#endif
+
+ // increment here so that if we hit the limit in separate threads we won't overallocated
+ mAllocatedBlocks++;
+
+ PxcNpMemBlock* block = reinterpret_cast<PxcNpMemBlock*>(PX_ALLOC(sizeof(PxcNpMemBlock), "PxcNpMemBlock"));
+
+ if(block)
+ {
+ trackingArray.pushBack(block);
+ mMaxUsedBlocks = PxMax<PxU32>(mUsedBlocks+1, mMaxUsedBlocks);
+ mUsedBlocks++;
+ }
+ else
+ mAllocatedBlocks--;
+
+ return block;
+}
+
+PxU8* PxcNpMemBlockPool::acquireExceptionalConstraintMemory(PxU32 size)
+{
+ PxU8* memory = reinterpret_cast<PxU8*>(PX_ALLOC(size, "PxcNpExceptionalMemory"));
+ if(memory)
+ {
+ Ps::Mutex::ScopedLock lock(mLock);
+ mExceptionalConstraints.pushBack(memory);
+ }
+ return memory;
+}
+
+void PxcNpMemBlockPool::release(PxcNpMemBlockArray& deadArray, PxU32* allocationCount)
+{
+ Ps::Mutex::ScopedLock lock(mLock);
+ PX_ASSERT(mUsedBlocks >= deadArray.size());
+ mUsedBlocks -= deadArray.size();
+ if(allocationCount)
+ {
+ *allocationCount -= deadArray.size();
+ }
+ while(deadArray.size())
+ {
+ PxcNpMemBlock* block = deadArray.popBack();
+ for(PxU32 a = 0; a < mUnused.size(); ++a)
+ {
+ PX_ASSERT(mUnused[a] != block);
+ }
+ mUnused.pushBack(block);
+ }
+}
+
+void PxcNpMemBlockPool::flushUnused()
+{
+ while(mUnused.size())
+ PX_FREE(mUnused.popBack());
+}
+
+
+PxcNpMemBlock* PxcNpMemBlockPool::acquireConstraintBlock()
+{
+ // we track the scratch blocks in the constraint block array, because the code in acquireMultipleConstraintBlocks
+ // assumes that acquired blocks are listed there.
+
+ return acquire(mConstraints);
+}
+
+PxcNpMemBlock* PxcNpMemBlockPool::acquireConstraintBlock(PxcNpMemBlockArray& memBlocks)
+{
+ return acquire(memBlocks, &mConstraintAllocations, &mPeakConstraintAllocations, true);
+}
+
+PxcNpMemBlock* PxcNpMemBlockPool::acquireContactBlock()
+{
+ return acquire(mContacts[mContactIndex], NULL, NULL, true);
+}
+
+
+void PxcNpMemBlockPool::releaseConstraintBlocks(PxcNpMemBlockArray& memBlocks)
+{
+ Ps::Mutex::ScopedLock lock(mLock);
+
+ while(memBlocks.size())
+ {
+ PxcNpMemBlock* block = memBlocks.popBack();
+ if(mScratchAllocator.isScratchAddr(block))
+ mScratchBlocks.pushBack(block);
+ else
+ {
+ mUnused.pushBack(block);
+ PX_ASSERT(mUsedBlocks>0);
+ mUsedBlocks--;
+ }
+ }
+}
+
+void PxcNpMemBlockPool::releaseContacts()
+{
+ //releaseConstraintBlocks(mContacts);
+ release(mContacts[1-mContactIndex]);
+ mContactIndex = 1-mContactIndex;
+}
+
+PxcNpMemBlock* PxcNpMemBlockPool::acquireFrictionBlock()
+{
+ return acquire(mFriction[mFrictionActiveStream]);
+}
+
+void PxcNpMemBlockPool::swapFrictionStreams()
+{
+ release(mFriction[1-mFrictionActiveStream]);
+ mFrictionActiveStream = 1-mFrictionActiveStream;
+}
+
+PxcNpMemBlock* PxcNpMemBlockPool::acquireNpCacheBlock()
+{
+ return acquire(mNpCache[mNpCacheActiveStream]);
+}
+
+void PxcNpMemBlockPool::swapNpCacheStreams()
+{
+ release(mNpCache[1-mNpCacheActiveStream]);
+ mNpCacheActiveStream = 1-mNpCacheActiveStream;
+}
+
diff --git a/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpThreadContext.cpp b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpThreadContext.cpp
new file mode 100644
index 00000000..9738e5da
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/common/src/pipeline/PxcNpThreadContext.cpp
@@ -0,0 +1,93 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PxcConstraintBlockStream.h"
+#include "PxcNpThreadContext.h"
+
+using namespace physx;
+
+PxcNpThreadContext::PxcNpThreadContext(PxcNpContext* params) :
+ mRenderOutput (params->mRenderBuffer),
+ mContactBlockStream (params->mNpMemBlockPool),
+ mNpCacheStreamPair (params->mNpMemBlockPool),
+ mNarrowPhaseParams (0.0f, params->mMeshContactMargin, params->mToleranceLength),
+ mPCM (false),
+ mContactCache (false),
+ mCreateContactStream (params->mCreateContactStream),
+ mCreateAveragePoint (false),
+#if PX_ENABLE_SIM_STATS
+ mCompressedCacheSize (0),
+ mNbDiscreteContactPairsWithCacheHits(0),
+ mNbDiscreteContactPairsWithContacts (0),
+#endif
+ mMaxPatches (0),
+ mTotalCompressedCacheSize (0),
+ mContactStreamPool (params->mContactStreamPool),
+ mPatchStreamPool (params->mPatchStreamPool),
+ mForceAndIndiceStreamPool (params->mForceAndIndiceStreamPool),
+ mMaterialManager(params->mMaterialManager),
+ mLocalNewTouchCount (0),
+ mLocalLostTouchCount (0),
+ mLocalFoundPatchCount (0),
+ mLocalLostPatchCount (0)
+{
+#if PX_ENABLE_SIM_STATS
+ clearStats();
+#endif
+}
+
+PxcNpThreadContext::~PxcNpThreadContext()
+{
+}
+
+#if PX_ENABLE_SIM_STATS
+void PxcNpThreadContext::clearStats()
+{
+ PxMemSet(mDiscreteContactPairs, 0, sizeof(mDiscreteContactPairs));
+ PxMemSet(mModifiedContactPairs, 0, sizeof(mModifiedContactPairs));
+ mCompressedCacheSize = 0;
+ mNbDiscreteContactPairsWithCacheHits = 0;
+ mNbDiscreteContactPairsWithContacts = 0;
+}
+#endif
+
+void PxcNpThreadContext::reset(PxU32 cmCount)
+{
+ mContactBlockStream.reset();
+ mNpCacheStreamPair.reset();
+
+ mLocalChangeTouch.clear();
+ mLocalChangeTouch.resize(cmCount);
+ mLocalPatchCountChange.clear();
+ mLocalPatchCountChange.resize(cmCount);
+ mLocalNewTouchCount = 0;
+ mLocalLostTouchCount = 0;
+ mLocalFoundPatchCount = 0;
+ mLocalLostPatchCount = 0;
+}
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxsBodySim.h b/PhysX_3.4/Source/LowLevel/software/include/PxsBodySim.h
new file mode 100644
index 00000000..93aafc41
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxsBodySim.h
@@ -0,0 +1,52 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef PXS_BODYSIM_H
+#define PXS_BODYSIM_H
+
+#include "PxsRigidBody.h"
+
+namespace physx
+{
+
+struct PxsBodySim
+{
+public:
+ PxsBodySim() : mRigidBody(NULL), mBodySimIndex(0xffffffff), mUpdated(0)
+ {
+ }
+
+ PxsRigidBody* mRigidBody; //4 or 8
+ PxU32 mBodySimIndex; //8 or 12
+ PxU32 mUpdated; //12 or 16
+};
+
+}//physx
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxsCCD.h b/PhysX_3.4/Source/LowLevel/software/include/PxsCCD.h
new file mode 100644
index 00000000..32ec53d3
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxsCCD.h
@@ -0,0 +1,617 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "Ps.h"
+#include "PxGeometry.h"
+#include "GuCCDSweepConvexMesh.h"
+#include "PsHashMap.h"
+
+#ifndef PXS_CCD_H
+#define PXS_CCD_H
+
+#define CCD_DEBUG_PRINTS 0
+#define CCD_POST_DEPENETRATE_DIST 0.001f
+#define CCD_ROTATION_LOCKING 0
+#define CCD_MIN_TIME_LEFT 0.01f
+#define CCD_ANGULAR_IMPULSE 0
+
+#define DEBUG_RENDER_CCD 0
+
+#if CCD_DEBUG_PRINTS
+namespace physx {
+ extern void printCCDDebug(const char* msg, const PxsRigidBody* atom0, PxGeometryType::Enum g0, bool printPtr = true);
+ extern void printShape(PxsRigidBody* atom0, PxGeometryType::Enum g0, const char* annotation, PxReal dt, PxU32 pass, bool printPtr = true);
+}
+#define PRINTCCDSHAPE(x) printShape x
+#define PRINTCCDDEBUG(x) printCCDDebug x
+#else
+#define PRINTCCDSHAPE(x)
+#define PRINTCCDDEBUG(x)
+#endif
+
+namespace physx
+{
+
+// ------------------------------------------------------------------------------------------------------------
+// a fraction of objects will be CCD active so this is dynamic, not a member of PsxRigidBody
+// CCD code builds a temporary array of PxsCCDPair objects (allocated in blocks)
+// this is done to gather scattered data from memory and also to reduce PxsRidigBody permanent memory footprint
+// we have to do it every pass since new CMs can become fast moving after each pass (and sometimes cease to be)
+//
+struct PxsCCDBody;
+class PxsRigidBody;
+struct PxsShapeCore;
+struct PxsRigidCore;
+class PxsContactManager;
+class PxsContext;
+class PxCCDContactModifyCallback;
+class PxcNpThreadContext;
+
+class PxvNphaseImplementationContext;
+
+namespace Dy
+{
+ class ThresholdStream;
+}
+
+
+/**
+\brief structure to represent interactions between a given body and another body.
+*/
+struct PxsCCDOverlap
+{
+ //The body the interaction relates to
+ PxsCCDBody* mBody;
+ //The next interaction in the list
+ PxsCCDOverlap* mNext;
+};
+
+/**
+\brief Temporary CCD representation for a shape.
+
+Stores data about a shape that may be frequently used in CCD. It also stores update counters per-shape that can be compared with the body's update
+counter to determine if the shape needs its transforms re-calculated. This avoids us needing to store a list of shapes in a CCD body.
+*/
+struct PxsCCDShape : Gu::CCDShape
+{
+public:
+ const PxsShapeCore* mShapeCore; //Shape core (can be shared)
+ const PxsRigidCore* mRigidCore; //Rigid body core
+
+ /**
+ \brief Returns the world-space pose for this shape
+ \param[in] atom The rigid body that this CCD shape is associated with
+ */
+ PxTransform getAbsPose(const PxsRigidBody* atom) const;
+ /**
+ \brief Returns the world-space previous pose for this shape
+ \param[in] atom The rigid body that this CCD shape is associated with
+ */
+ PxTransform getLastCCDAbsPose(const PxsRigidBody* atom) const;
+};
+
+/**
+\brief Structure to represent a body in the CCD system.
+*/
+struct PxsCCDBody
+{
+ Cm::SpatialVector mPreSolverVelocity;
+ PxU16 mIndex; //The CCD body's index
+ bool mPassDone; //Whether it has been processed in the current CCD pass
+ bool mHasAnyPassDone; //Whether this body was influenced by any passes
+ PxReal mTimeLeft; //CCD time left to elapse (normalized in range 0-1)
+ PxsRigidBody* mBody; //The rigid body
+ PxsCCDOverlap* mOverlappingObjects; //A list of overlapping bodies for island update
+ PxU32 mUpdateCount; //How many times this body has eben updated in the CCD. This is correlated with CCD shapes' update counts.
+
+
+
+ /**
+ \brief Returns the CCD body's index.
+ \return The CCD body's index.
+ */
+ PX_FORCE_INLINE PxU32 getIndex() const { return mIndex; }
+
+ /**
+ \brief Tests whether this body has already registered an overlap with a given body.
+ \param[in] body The body to test against.
+ \return Whether this body has already registered an overlap with a given body.
+ */
+ bool overlaps(PxsCCDBody* body) const
+ {
+ PxsCCDOverlap* overlaps = mOverlappingObjects;
+
+ while(overlaps)
+ {
+ if(overlaps->mBody == body)
+ return true;
+ overlaps = overlaps->mNext;
+ }
+ return false;
+ }
+
+ /**
+ \brief Registers an overlap with a given body
+ \param[in] overlap The CCD overlap to register.
+ */
+ void addOverlap(PxsCCDOverlap* overlap)
+ {
+ overlap->mNext = mOverlappingObjects;
+ mOverlappingObjects = overlap;
+ }
+
+};
+
+/**
+\brief a container class used in the CCD that minimizes frequency of hitting the allocator.
+
+This class stores a set of blocks of memory. It is effectively an array that resizes more efficiently because it doesn't need to
+reallocate an entire buffer and copy data.
+*/
+template<typename T, int BLOCK_SIZE>
+struct PxsCCDBlockArray
+{
+ /**
+ \brief A block of data
+ */
+ struct Block : Ps::UserAllocated { T items[BLOCK_SIZE]; };
+ /**
+ \brief A header for a block of data.
+ */
+ struct BlockInfo
+ {
+ Block* block;
+ PxU32 count; // number of elements in this block
+ BlockInfo(Block* aBlock, PxU32 aCount) : block(aBlock), count(aCount) {}
+ };
+ /*
+ \brief An array of block headers
+ */
+ Ps::Array<BlockInfo> blocks;
+ /**
+ \brief The current block.
+ */
+ PxU32 currentBlock;
+
+ /**
+ \brief Constructor
+ */
+ PxsCCDBlockArray() : currentBlock(0)
+ {
+ blocks.pushBack(BlockInfo(PX_NEW(Block), 0));
+ }
+
+ /**
+ \brief Destructor
+ */
+ ~PxsCCDBlockArray()
+ {
+ for (PxU32 i = 0; i < blocks.size(); i++)
+ {
+ PX_DELETE(blocks[i].block);
+ }
+ currentBlock = 0;
+ }
+
+ /**
+ \brief Clears this block array.
+ \note This clear function also deletes all additional blocks
+ */
+ void clear()
+ {
+ for (PxU32 i = 0; i < blocks.size(); i++)
+ {
+ PX_DELETE(blocks[i].block);
+ }
+ blocks.clear();
+ blocks.pushBack(BlockInfo(PX_NEW(Block), 0)); // at least one block is expected to always be present in the array
+ currentBlock = 0;
+ }
+
+ /**
+ \brief Clears this block array but does not release the memory.
+ */
+ void clear_NoDelete()
+ {
+ currentBlock = 0;
+ blocks[0].count = 0;
+ }
+
+ /**
+ \brief Push a new element onto the back of the block array
+ \return The new element
+ */
+ T& pushBack()
+ {
+ PxU32 numBlocks = blocks.size();
+ if (blocks[currentBlock].count == BLOCK_SIZE)
+ {
+ if((currentBlock + 1) == numBlocks)
+ {
+ blocks.pushBack(BlockInfo(PX_NEW(Block), 0));
+ numBlocks ++;
+ }
+ currentBlock++;
+ blocks[currentBlock].count = 0;
+ }
+ const PxU32 count = blocks[currentBlock].count ++;
+
+ return blocks[currentBlock].block->items[count];
+ }
+
+ /**
+ \brief Pushes a new element onto the back of this array, intitializing it to match the data
+ \param data The data to initialize the new element to
+ \return The new element
+ */
+ T& pushBack(T& data)
+ {
+ PxU32 numBlocks = blocks.size();
+ if (blocks[currentBlock].count == BLOCK_SIZE)
+ {
+ if((currentBlock + 1) == numBlocks)
+ {
+ blocks.pushBack(BlockInfo(PX_NEW(Block), 0));
+ numBlocks ++;
+ }
+ currentBlock++;
+ blocks[currentBlock].count = 0;
+ }
+ const PxU32 count = blocks[currentBlock].count ++;
+ blocks[currentBlock].block->items[count] = data;
+ return blocks[currentBlock].block->items[count];
+ }
+
+ /**
+ \brief Pops the last element from the list.
+ */
+ void popBack()
+ {
+ PX_ASSERT(blocks[currentBlock].count > 0);
+ if (blocks[currentBlock].count > 1)
+ blocks[currentBlock].count --;
+ else
+ {
+ PX_DELETE(blocks[currentBlock].block);
+ blocks.popBack();
+ currentBlock--;
+ }
+ }
+
+ /**
+ \brief Returns the current size of the array.
+ \return The current size of the array.
+ */
+ PxU32 size() const
+ {
+ return (currentBlock)*BLOCK_SIZE + blocks[currentBlock].count;
+ }
+
+ /**
+ \brief Returns the element at a given index in the array
+ \param[in] index The index of the element in the array
+ \return The element at a given index in the array.
+ */
+ T& operator[] (PxU32 index) const
+ {
+ PX_ASSERT(index/BLOCK_SIZE < blocks.size());
+ PX_ASSERT(index%BLOCK_SIZE < blocks[index/BLOCK_SIZE].count);
+ return blocks[index/BLOCK_SIZE].block->items[index%BLOCK_SIZE];
+ }
+};
+
+/**
+\brief A structure to represent a potential CCD interaction between a pair of shapes
+*/
+struct PxsCCDPair
+{
+ /**
+ \brief Defines whether this is an estimated TOI or an accurate TOI.
+
+ We store pairs in a priority queue based on the TOIs. We use cheap estimates to cull away work and lazily evaluate TOIs. This means that an element in the
+ priority queue may either be an estimate or a precise result.
+ */
+ enum E_TOIType
+ {
+ eEstimate,
+ ePrecise
+ };
+ PxsRigidBody* mBa0; // Body A. Can be NULL for statics
+ PxsRigidBody* mBa1; // Body B. Can be NULL for statics
+ PxsCCDShape* mCCDShape0; // Shape A
+ PxsCCDShape* mCCDShape1; // Shape B
+ PxVec3 mMinToiNormal; // The contact normal. Only valid for precise results. On the surface of body/shape A
+ PxReal mMinToi; // Min TOI. Valid for both precise and estimated results but estimates may be too early (i.e. conservative).
+ PxReal mPenetrationPostStep; // Valid only for precise sweeps. Only used for initial intersections (i.e. at TOI = 0).
+ PxVec3 mMinToiPoint; // The contact point. Only valid for precise sweep results.
+ PxReal mPenetration; // The penetration. Only valid for precise sweep results.
+ PxsContactManager* mCm; // The contact manager.
+ PxU32 mIslandId; // The index of the island this pair is in
+ PxGeometryType::Enum mG0, mG1; // The geometry types for shapes 0 and 1
+ bool mIsEarliestToiHit; // Indicates this was the earliest hit for one of the bodies in the pair
+ bool mIsModifiable; // Indicates whether this contact is modifiable
+ PxU32 mFaceIndex; // The face index. Only valid for precise sweeps involving meshes or heightfields.
+ PxU16 mMaterialIndex0; // The material index for shape 0
+ PxU16 mMaterialIndex1; // The material index for shape 1
+ PxReal mDynamicFriction; // The dynamic friction coefficient
+ PxReal mStaticFriction; // The static friction coefficient
+ PxReal mRestitution; // The restitution coefficient
+ PxU32 mEstimatePass; // The current estimation pass. Used after a sweep hit was found to determine if the pair needs re-estimating.
+ PxReal mAppliedForce; // The applied force for this pair. Only valid if the pair has been responded to.
+
+ E_TOIType mToiType; // The TOI type (estimate, precise).
+ bool mHasFriction; // Whether we want to simulate CCD friction for this pair
+
+ /**
+ \brief Perform a precise sweep for this pair
+ \param[in] threadContext The per-thread context
+ \param[in] dt The time-step
+ \param[in] pass The current CCD pass
+ \return The normalized TOI. <=1.0 indicates a hit. Otherwise PX_MAX_REAL.
+ */
+ PxReal sweepFindToi(PxcNpThreadContext& threadContext, PxReal dt, PxU32 pass);
+ /**
+ \brief Performs a sweep estimation for this pair
+ \return The normalized TOI. <= 1.0 indicates a potential hit, otherwise PX_MAX_REAL.
+ */
+ PxReal sweepEstimateToi();
+ /**
+ \brief Advances this pair to the TOI
+ \param[in] dt The time-step
+ \param[in] clipTrajectoryToToi Indicates whether we clip the body's trajectory to the end pose. Only done in the final pass
+ \return Whether the advance was successful. An advance will be unsuccessful if body bodies were already updated.
+ */
+ bool sweepAdvanceToToi(PxReal dt, bool clipTrajectoryToToi);
+ /**
+ \brief Updates the transforms of the shapes involved in this pair.
+ */
+ void updateShapes();
+
+};
+
+/**
+\brief Block array of CCD bodies
+*/
+typedef PxsCCDBlockArray<PxsCCDBody, 128> PxsCCDBodyArray;
+/**
+\brief Block array of CCD pairs
+*/
+typedef PxsCCDBlockArray<PxsCCDPair, 128> PxsCCDPairArray;
+/**
+\brief Block array of CCD overlaps
+*/
+typedef PxsCCDBlockArray<PxsCCDOverlap, 128> PxsCCDOverlapArray;
+/**
+\brief Block array of CCD shapes
+*/
+typedef PxsCCDBlockArray<PxsCCDShape, 128> PxsCCDShapeArray;
+
+/**
+\brief Pair structure to be able to look-up a rigid body-shape pair in a map
+*/
+typedef Ps::Pair<const PxsRigidCore*, const PxsShapeCore*> PxsRigidShapePair;
+
+
+/**
+\brief CCD context object.
+*/
+class PxsCCDContext
+{
+public:
+
+ /**
+ \brief Creates this PxsCCDContext
+ */
+ static PxsCCDContext* create(PxsContext* context, Dy::ThresholdStream& dynamicsContext, PxvNphaseImplementationContext& nPhaseContext);
+
+ /**
+ \brief Destroys this PxsCCDContext
+ */
+ void destroy();
+
+ /**
+ \brief Returns the CCD contact modification callback
+ \return The CCD contact modification callback
+ */
+ PX_FORCE_INLINE PxCCDContactModifyCallback* getCCDContactModifyCallback() const { return mCCDContactModifyCallback; }
+ /**
+ \brief Sets the CCD contact modification callback
+ \param[in] c The CCD contact modification callback
+ */
+ PX_FORCE_INLINE void setCCDContactModifyCallback(PxCCDContactModifyCallback* c) { mCCDContactModifyCallback = c; }
+ /**
+ \brief Returns the maximum number of CCD passes
+ \return The maximum number of CCD passes
+ */
+ PX_FORCE_INLINE PxU32 getCCDMaxPasses() const { return mCCDMaxPasses; }
+ /**
+ \brief Sets the maximum number of CCD passes
+ \param[in] ccdMaxPasses The maximum number of CCD passes
+ */
+ PX_FORCE_INLINE void setCCDMaxPasses(PxU32 ccdMaxPasses) { mCCDMaxPasses = ccdMaxPasses; }
+ /**
+ \brief Returns the current CCD pass
+ \return The current CCD pass
+ */
+ PX_FORCE_INLINE PxU32 getCurrentCCDPass() const { return miCCDPass; }
+ /**
+ \brief Returns The number of swept hits reported
+ \return The number of swept hits reported
+ */
+ PX_FORCE_INLINE PxI32 getNumSweepHits() const { return mSweepTotalHits; }
+ /**
+ \brief Returns The number of updated bodies
+ \return The number of updated bodies in this CCD pass
+ */
+ PX_FORCE_INLINE PxU32 getNumUpdatedBodies() const { return mUpdatedCCDBodies.size(); }
+ /**
+ \brief Returns The update bodies array
+ \return The updated bodies array from this CCD pass
+ */
+ PX_FORCE_INLINE PxsRigidBody*const* getUpdatedBodies() const { return mUpdatedCCDBodies.begin(); }
+
+ /**
+ \brief Returns Clears the updated bodies array
+ */
+ PX_FORCE_INLINE void clearUpdatedBodies() { mUpdatedCCDBodies.forceSize_Unsafe(0); }
+
+ /**
+ \brief Runs the CCD contact modification.
+ \param[in] contacts The list of modifiable contacts
+ \param[in] contactCount The number of contacts
+ \param[in] shapeCore0 The first shape core
+ \param[in] shapeCore1 The second shape core
+ \param[in] rigidCore0 The first rigid core
+ \param[in] rigidCore1 The second rigid core
+ \param[in] rigid0 The first rigid body
+ \param[in] rigid1 The second rigid body
+ */
+ void runCCDModifiableContact(PxModifiableContact* PX_RESTRICT contacts, PxU32 contactCount, const PxsShapeCore* PX_RESTRICT shapeCore0,
+ const PxsShapeCore* PX_RESTRICT shapeCore1, const PxsRigidCore* PX_RESTRICT rigidCore0, const PxsRigidCore* PX_RESTRICT rigidCore1,
+ const PxsRigidBody* PX_RESTRICT rigid0, const PxsRigidBody* PX_RESTRICT rigid1);
+
+ /**
+ \brief Performs a single CCD update
+ This occurs after broad phase and is responsible for creating islands, finding the TOI of collisions, filtering contacts, issuing modification callbacks and responding to
+ collisions. At the end of this phase all bodies will have stepper to their first TOI if they were involved in a CCD collision this frame.
+ \param[in] dt The timestep to simulate
+ \param[in] continuation The continuation task
+ \param[in] disableResweep If this is true, we perform a reduced-fidelity CCD approach
+ */
+ void updateCCD(PxReal dt, PxBaseTask* continuation, bool disableResweep, PxI32 numFastMovingShapes);
+
+ /**
+ \brief Signals the beginning of a CCD multi-pass update
+ */
+ void updateCCDBegin();
+
+ /**
+ \brief Resets the CCD contact state in any contact managers that previously had a reported CCD touch. This must be called if CCD update is bypassed for a frame
+ */
+ void resetContactManagers();
+
+
+
+
+protected:
+
+ /**
+ \brief Constructor for PxsCCDContext
+ \param[in] context The PxsContext that is associated with this PxsCCDContext.
+ */
+ PxsCCDContext(PxsContext* context, Dy::ThresholdStream& thresholdStream, PxvNphaseImplementationContext& nPhaseContext);
+ /**
+ \brief Destructor for PxsCCDContext
+ */
+ ~PxsCCDContext();
+
+private:
+
+
+ /**
+ \brief Verifies the consistency of the CCD context at the beginning
+ */
+ void verifyCCDBegin();
+
+ /**
+ \brief Cleans up after the CCD update has completed
+ */
+ void updateCCDEnd();
+
+ /**
+ \brief Spawns the update island tasks after the initial sweep estimates have been performed
+ \param[in] continuation The continuation task
+ */
+ void postCCDSweep(PxBaseTask* continuation);
+ /**
+ \brief Creates contact buffers for CCD contacts. These will be sent to the user in the contact notification.
+ \param[in] continuation The continuation task
+ */
+ void postCCDAdvance(PxBaseTask* continuation);
+ /**
+ \brief The final phase of the CCD task chain. Cleans up after the parallel update/postCCDAdvance stages.
+ \param[in] continuation The continuation task
+ */
+ void postCCDDepenetrate(PxBaseTask* continuation);
+
+ typedef Cm::DelegateTask<PxsCCDContext, &PxsCCDContext::postCCDSweep> PostCCDSweepTask;
+ typedef Cm::DelegateTask<PxsCCDContext, &PxsCCDContext::postCCDAdvance> PostCCDAdvanceTask;
+ typedef Cm::DelegateTask<PxsCCDContext, &PxsCCDContext::postCCDDepenetrate> PostCCDDepenetrateTask;
+
+ PostCCDSweepTask mPostCCDSweepTask;
+ PostCCDAdvanceTask mPostCCDAdvanceTask;
+ PostCCDDepenetrateTask mPostCCDDepenetrateTask;
+
+ PxCCDContactModifyCallback* mCCDContactModifyCallback;
+
+ // CCD global data
+ bool mDisableCCDResweep;
+ PxU32 miCCDPass;
+ PxI32 mSweepTotalHits;
+
+ // a fraction of objects will be CCD active so PxsCCDBody is dynamic, not a member of PxsRigidBody
+ PxsCCDBodyArray mCCDBodies;
+ PxsCCDOverlapArray mCCDOverlaps;
+ PxsCCDShapeArray mCCDShapes;
+ Ps::Array<PxsCCDBody*> mIslandBodies;
+ Ps::Array<PxU16> mIslandSizes;
+ Ps::Array<PxsRigidBody*> mUpdatedCCDBodies;
+ Ps::HashMap<PxsRigidShapePair, PxsCCDShape*> mMap;
+
+ // temporary array updated during CCD update
+ //Array<PxsCCDPair> mCCDPairs;
+ PxsCCDPairArray mCCDPairs;
+ Ps::Array<PxsCCDPair*> mCCDPtrPairs;
+ // number of pairs per island
+ Ps::Array<PxU32> mCCDIslandHistogram;
+ // thread context valid during CCD update
+ PxcNpThreadContext* mCCDThreadContext;
+ // number of pairs to process per thread
+ PxU32 mCCDPairsPerBatch;
+ PxU32 mCCDMaxPasses;
+
+ PxsContext* mContext;
+ Dy::ThresholdStream& mThresholdStream;
+
+ PxvNphaseImplementationContext& mNphaseContext;
+
+ Ps::Mutex mMutex;
+
+private:
+
+ PX_NOCOPY(PxsCCDContext)
+};
+
+
+}
+
+
+
+#endif
+
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxsContactManager.h b/PhysX_3.4/Source/LowLevel/software/include/PxsContactManager.h
new file mode 100644
index 00000000..197b4afa
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxsContactManager.h
@@ -0,0 +1,178 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXS_CONTACTMANAGER_H
+#define PXS_CONTACTMANAGER_H
+
+#include "PxvConfig.h"
+#include "PxcNpWorkUnit.h"
+
+namespace physx
+{
+
+class PxsContext;
+class PxsRigidBody;
+struct PxsCCDBody;
+class PxsMaterialManager;
+struct PxsCCDShape;
+
+namespace Dy
+{
+ class DynamicsContext;
+}
+
+namespace Sc
+{
+ class ShapeInteraction;
+}
+
+enum PxsPairVisColor
+{
+
+ eVIS_COLOR_SWEPTINTEGRATE_OFF = 0x000000,
+ eVIS_COLOR_SWEPTINTEGRATE_SLOW = 0x404040,
+ eVIS_COLOR_SWEPTINTEGRATE_CLEAR = 0x007f00,
+ eVIS_COLOR_SWEPTINTEGRATE_IMPACT = 0x1680ff,
+ eVIS_COLOR_SWEPTINTEGRATE_FAIL = 0x0000ff
+
+};
+
+
+/**
+\brief Additional header structure for CCD contact data stream.
+*/
+struct PxsCCDContactHeader
+{
+ /**
+ \brief Stream for next collision. The same pair can collide multiple times during multiple CCD passes.
+ */
+ PxsCCDContactHeader* nextStream; //4 //8
+ /**
+ \brief Size (in bytes) of the CCD contact stream (not including force buffer)
+ */
+ PxU16 contactStreamSize; //6 //10
+ /**
+ \brief Defines whether the stream is from a previous pass.
+
+ It could happen that the stream can not get allocated because we run out of memory. In that case the current event should not use the stream
+ from an event of the previous pass.
+ */
+ PxU16 isFromPreviousPass; //8 //12
+
+ PxU8 pad[12 - sizeof(PxsCCDContactHeader*)]; //16
+};
+
+PX_COMPILE_TIME_ASSERT((sizeof(PxsCCDContactHeader) & 0xF) == 0);
+
+
+class PxsContactManager
+{
+public:
+ PxsContactManager(PxsContext* context, PxU32 index);
+ ~PxsContactManager();
+
+
+ PX_FORCE_INLINE void setDisableStrongFriction(PxU32 d) { (!d) ? mNpUnit.flags &= ~PxcNpWorkUnitFlag::eDISABLE_STRONG_FRICTION
+ : mNpUnit.flags |= PxcNpWorkUnitFlag::eDISABLE_STRONG_FRICTION; }
+
+ PX_FORCE_INLINE PxReal getRestDistance() const { return mNpUnit.restDistance; }
+ PX_FORCE_INLINE void setRestDistance(PxReal v) { mNpUnit.restDistance = v; }
+
+ void destroy();
+
+ PX_FORCE_INLINE PxU8 getDominance0() const { return mNpUnit.dominance0; }
+ PX_FORCE_INLINE void setDominance0(PxU8 v) { mNpUnit.dominance0 = v; }
+
+ PX_FORCE_INLINE PxU8 getDominance1() const { return mNpUnit.dominance1; }
+ PX_FORCE_INLINE void setDominance1(PxU8 v) { mNpUnit.dominance1 = v; }
+
+ PX_FORCE_INLINE PxU16 getTouchStatus() const { return PxU16(mNpUnit.statusFlags & PxcNpWorkUnitStatusFlag::eHAS_TOUCH); }
+ PX_FORCE_INLINE PxU16 touchStatusKnown() const { return PxU16(mNpUnit.statusFlags & PxcNpWorkUnitStatusFlag::eTOUCH_KNOWN); }
+ PX_FORCE_INLINE PxI32 getTouchIdx() const { return (mNpUnit.statusFlags& PxcNpWorkUnitStatusFlag::eHAS_TOUCH) ? 1 : (mNpUnit.statusFlags& PxcNpWorkUnitStatusFlag::eHAS_NO_TOUCH ? -1 : 0); }
+
+ PX_FORCE_INLINE PxU32 getIndex() const { return mNpUnit.index; }
+
+ PX_FORCE_INLINE PxU16 getHasCCDRetouch() const { return PxU16(mNpUnit.statusFlags & PxcNpWorkUnitStatusFlag::eHAS_CCD_RETOUCH); }
+ PX_FORCE_INLINE void clearCCDRetouch() { mNpUnit.statusFlags &= ~PxcNpWorkUnitStatusFlag::eHAS_CCD_RETOUCH; }
+ PX_FORCE_INLINE void raiseCCDRetouch() { mNpUnit.statusFlags |= PxcNpWorkUnitStatusFlag::eHAS_CCD_RETOUCH; }
+
+
+
+ // flags stuff - needs to be refactored
+
+ PX_FORCE_INLINE Ps::IntBool isChangeable() const { return Ps::IntBool(mFlags & PXS_CM_CHANGEABLE); }
+ PX_FORCE_INLINE Ps::IntBool getCCD() const { return Ps::IntBool((mFlags & PXS_CM_CCD_LINEAR) && (mNpUnit.flags & PxcNpWorkUnitFlag::eDETECT_CCD_CONTACTS)); }
+ PX_FORCE_INLINE Ps::IntBool getHadCCDContact() const { return Ps::IntBool(mFlags & PXS_CM_CCD_CONTACT); }
+ PX_FORCE_INLINE void setHadCCDContact() { mFlags |= PXS_CM_CCD_CONTACT; }
+ void setCCD(bool enable);
+ PX_FORCE_INLINE void clearCCDContactInfo() { mFlags &= ~PXS_CM_CCD_CONTACT; mNpUnit.ccdContacts = NULL; }
+
+ PX_FORCE_INLINE PxcNpWorkUnit& getWorkUnit() { return mNpUnit; }
+ PX_FORCE_INLINE const PxcNpWorkUnit& getWorkUnit() const { return mNpUnit; }
+
+ PX_FORCE_INLINE void* getUserData() const { return mShapeInteraction; }
+
+ // Setup solver-constraints
+ void resetCachedState();
+ void resetFrictionCachedState();
+
+ Sc::ShapeInteraction* getShapeInteraction() const { return mShapeInteraction; }
+
+private:
+ //KS - moving this up - we want to get at flags
+
+ PxsRigidBody* mRigidBody0; //4 //8
+ PxsRigidBody* mRigidBody1; //8 //16
+ PxU32 mFlags; //20 //36
+ Sc::ShapeInteraction* mShapeInteraction; //16 //32
+
+
+
+ friend class PxsContext;
+ // everything required for narrow phase to run
+ PxcNpWorkUnit mNpUnit;
+
+ enum
+ {
+ PXS_CM_CHANGEABLE = (1<<0),
+ PXS_CM_CCD_LINEAR = (1<<1),
+ PXS_CM_CCD_CONTACT = (1 << 2)
+ };
+
+ friend class Dy::DynamicsContext;
+ friend struct PxsCCDPair;
+ friend class PxsIslandManager;
+ friend class PxsCCDContext;
+ friend class Sc::ShapeInteraction;
+};
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxsContactManagerState.h b/PhysX_3.4/Source/LowLevel/software/include/PxsContactManagerState.h
new file mode 100644
index 00000000..a06a2063
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxsContactManagerState.h
@@ -0,0 +1,95 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef PXS_CONTACT_MANAGER_STATE_H
+#define PXS_CONTACT_MANAGER_STATE_H
+
+#include "foundation/PxSimpleTypes.h"
+
+namespace physx
+{
+
+ struct PxsShapeCore;
+
+ /**
+ There is an implicit 1:1 mapping between PxgContactManagerInput and PxsContactManagerOutput. The structures are split because PxgNpContactManagerInput contains constant
+ data that is produced by the CPU code and PxgNpContactManagerOutput contains per-frame contact information produced by the NP.
+
+ There is also a 1:1 mapping between the PxgNpContactManager and PxsContactManager. This mapping is handled within the PxgNPhaseCore.
+
+ The previous contact states are implicitly cached in PxsContactManager and will be propagated to the solver. Friction correlation is also done implicitly using cached
+ information in PxsContactManager.
+ The NP will produce a list of pairs that found/lost patches for the solver along with updating the PxgNpContactManagerOutput for all pairs.
+ */
+
+ struct PxsContactManagerStatusFlag
+ {
+ enum Enum
+ {
+ eHAS_NO_TOUCH = (1 << 0),
+ eHAS_TOUCH = (1 << 1),
+ //eHAS_SOLVER_CONSTRAINTS = (1 << 2),
+ eREQUEST_CONSTRAINTS = (1 << 3),
+ eHAS_CCD_RETOUCH = (1 << 4), // Marks pairs that are touching at a CCD pass and were touching at discrete collision or at a previous CCD pass already
+ // but we can not tell whether they lost contact in a pass before. We send them as pure eNOTIFY_TOUCH_CCD events to the
+ // contact report callback if requested.
+ eDIRTY_MANAGER = (1 << 5),
+ eTOUCH_KNOWN = eHAS_NO_TOUCH | eHAS_TOUCH // The touch status is known (if narrowphase never ran for a pair then no flag will be set)
+ };
+ };
+
+
+ struct PX_ALIGN_PREFIX(16) PxsContactManagerOutput
+ {
+ PxU8* contactPatches; //Start index/ptr for contact patches
+ PxU8* contactPoints; //Start index/ptr for contact points
+ PxReal* contactForces; //Start index/ptr for contact forces
+ PxU8 nbContacts; //Num contacts
+ PxU8 nbPatches; //Num patches
+ PxU8 statusFlag; //Status flag (has touch etc.)
+ PxU8 prevPatches; //Previous number of patches
+
+ PX_FORCE_INLINE PxU32* getInternalFaceIndice()
+ {
+ return reinterpret_cast<PxU32*>(contactForces + nbContacts);
+ }
+ }
+ PX_ALIGN_SUFFIX(16);
+
+ struct /*PX_ALIGN_PREFIX(16)*/ PxsContactManagerPersistency
+ {
+ PxU8 mPrevPatches;
+ PxU8 mNbFrictionPatches;
+ PxU8 mNbPrevFrictionPatches;
+ }
+ /*PX_ALIGN_SUFFIX(16)*/;
+
+}
+
+#endif //PXG_CONTACT_MANAGER_H
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxsContext.h b/PhysX_3.4/Source/LowLevel/software/include/PxsContext.h
new file mode 100644
index 00000000..d50cff15
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxsContext.h
@@ -0,0 +1,369 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXS_CONTEXT_H
+#define PXS_CONTEXT_H
+
+#include "PxVisualizationParameter.h"
+#include "PxSceneDesc.h"
+
+#include "CmPool.h"
+
+#include "PxvContext.h"
+#include "PxvNphaseImplementationContext.h"
+#include "PxsContactManager.h"
+#include "PxcNpBatch.h"
+#include "PxcConstraintBlockStream.h"
+#include "PxcNpCacheStreamPair.h"
+#include "PxcNpMemBlockPool.h"
+#include "CmRenderOutput.h"
+#include "CmUtils.h"
+#include "CmTask.h"
+
+#include "PxContactModifyCallback.h"
+
+#include "PxsTransformCache.h"
+#include "GuPersistentContactManifold.h"
+#include "DyArticulation.h"
+
+#if PX_SUPPORT_GPU_PHYSX
+namespace physx
+{
+ class PxCudaContextManager;
+}
+#endif
+
+namespace physx
+{
+
+class PxsRigidBody;
+struct PxcConstraintBlock;
+class PxsMaterialManager;
+class PxsCCDContext;
+struct PxsContactManagerOutput;
+
+namespace Cm
+{
+ class FlushPool;
+}
+
+namespace Bp
+{
+ class AABBManagerImpl;
+}
+
+namespace IG
+{
+ class SimpleIslandManager;
+ typedef PxU32 EdgeIndex;
+}
+
+enum PxsTouchEventCount
+{
+ PXS_LOST_TOUCH_COUNT = 0,
+ PXS_NEW_TOUCH_COUNT = 1,
+ PXS_CCD_RETOUCH_COUNT = 2, // pairs that are touching at a CCD pass and were touching at discrete collision or at a previous CCD pass already
+ // (but they could have lost touch in between)
+ PXS_PATCH_FOUND_COUNT = 3,
+ PXS_PATCH_LOST_COUNT = 4,
+ PXS_TOUCH_EVENT_COUNT = 5
+};
+
+
+
+class PxsCMUpdateTask : public Cm::Task
+{
+public:
+
+ static const PxU32 BATCH_SIZE = 128;
+
+ PxsCMUpdateTask(PxsContext* context, PxReal dt, PxsContactManager** cmArray, PxsContactManagerOutput* cmOutputs, Gu::Cache* caches, PxU32 cmCount,
+ PxContactModifyCallback* callback):
+ mCmArray(cmArray), mCmOutputs(cmOutputs), mCaches(caches), mCmCount(cmCount), mDt(dt), mContext(context), mCallback(callback)
+ {
+ }
+
+ virtual void release();
+
+ /*PX_FORCE_INLINE void insert(PxsContactManager* cm)
+ {
+ PX_ASSERT(mCmCount < BATCH_SIZE);
+ mCmArray[mCmCount++]=cm;
+ }*/
+
+protected:
+ //PxsContactManager* mCmArray[BATCH_SIZE];
+ PxsContactManager** mCmArray;
+ PxsContactManagerOutput* mCmOutputs;
+ Gu::Cache* mCaches;
+ PxU32 mCmCount;
+ PxReal mDt; //we could probably retrieve from context to save space?
+ PxsContext* mContext;
+ PxContactModifyCallback* mCallback;
+};
+
+class PxsContext : public Ps::UserAllocated, public PxcNpContext
+{
+ PX_NOCOPY(PxsContext)
+public:
+ PxsContext( const PxSceneDesc& desc, PxTaskManager*, Cm::FlushPool&, PxU64 contextID);
+ ~PxsContext();
+
+ void removeRigidBody(PxsRigidBody&);
+
+ Dy::Articulation* createArticulation();
+ void destroyArticulation(Dy::Articulation&);
+
+ void createTransformCache(Ps::VirtualAllocatorCallback& allocatorCallback);
+
+ PxsContactManager* createContactManager(PxsContactManager* contactManager, const bool useCCD);
+ void createCache(Gu::Cache& cache, PxsContactManager* cm, PxU8 geomType0, PxU8 geomType1);
+ void destroyCache(Gu::Cache& cache);
+ void destroyContactManager(PxsContactManager* cm);
+
+
+ PX_FORCE_INLINE PxU64 getContextId() const { return mContextID; }
+
+ // Collision properties
+ PX_FORCE_INLINE PxContactModifyCallback* getContactModifyCallback() const { return mContactModifyCallback; }
+ PX_FORCE_INLINE void setContactModifyCallback(PxContactModifyCallback* c) { mContactModifyCallback = c; mNpImplementationContext->setContactModifyCallback(c);}
+
+
+ // resource-related
+ void setScratchBlock(void* addr, PxU32 size);
+
+ void setContactDistance(Ps::Array<PxReal, Ps::VirtualAllocator>* contactDistance);
+
+ // Task-related
+ void updateContactManager(PxReal dt, bool hasBoundsArrayChanged, bool hasContactDistanceChanged, PxBaseTask* continuation, PxBaseTask* firstPassContinuation);
+ void secondPassUpdateContactManager(PxReal dt, PxBaseTask* continuation);
+ void fetchUpdateContactManager();
+ void swapStreams();
+
+ void resetThreadContexts();
+
+ // Manager status change
+ bool getManagerTouchEventCount(int* newTouch, int* lostTouch, int* ccdTouch) const;
+ bool fillManagerTouchEvents(
+ PxvContactManagerTouchEvent* newTouch, PxI32& newTouchCount,
+ PxvContactManagerTouchEvent* lostTouch, PxI32& lostTouchCount,
+ PxvContactManagerTouchEvent* ccdTouch, PxI32& ccdTouchCount);
+
+ PX_FORCE_INLINE void getManagerPatchEventCount(PxU32& foundPatch, PxU32& lostPatch) const { foundPatch = mCMTouchEventCount[PXS_PATCH_FOUND_COUNT]; lostPatch = mCMTouchEventCount[PXS_PATCH_LOST_COUNT]; }
+ bool fillManagerPatchChangedEvents(
+ PxsContactManager** foundPatch, PxU32& foundPatchCount,
+ PxsContactManager** lostPatch, PxU32& lostPatchCount);
+
+ void beginUpdate();
+
+ // PX_ENABLE_SIM_STATS
+ PX_FORCE_INLINE PxvSimStats& getSimStats() { return mSimStats; }
+ PX_FORCE_INLINE const PxvSimStats& getSimStats() const { return mSimStats; }
+
+ PX_FORCE_INLINE Cm::FlushPool& getTaskPool() const { return mTaskPool; }
+ PX_FORCE_INLINE Cm::RenderBuffer& getRenderBuffer() { return mRenderBuffer; }
+
+ PxReal getVisualizationParameter(PxVisualizationParameter::Enum param) const;
+ void setVisualizationParameter(PxVisualizationParameter::Enum param, PxReal value);
+
+ PX_FORCE_INLINE void setVisualizationCullingBox(const PxBounds3& box) { mVisualizationCullingBox = box; }
+ PX_FORCE_INLINE const PxBounds3& getVisualizationCullingBox()const { return mVisualizationCullingBox; }
+
+ PX_FORCE_INLINE PxReal getRenderScale() const { return mVisualizationParams[PxVisualizationParameter::eSCALE]; }
+ Cm::RenderOutput getRenderOutput() { return Cm::RenderOutput(mRenderBuffer); }
+ PX_FORCE_INLINE bool getPCM() const { return mPCM; }
+ PX_FORCE_INLINE bool getContactCacheFlag() const { return mContactCache; }
+ PX_FORCE_INLINE bool getCreateAveragePoint() const { return mCreateAveragePoint; }
+
+ // general stuff
+ void shiftOrigin(const PxVec3& shift);
+
+ void setCreateContactStream(bool to);
+ PX_FORCE_INLINE void setPCM(bool enabled) { mPCM = enabled; }
+ PX_FORCE_INLINE void setContactCache(bool enabled) { mContactCache = enabled; }
+
+ PX_FORCE_INLINE PxcScratchAllocator& getScratchAllocator() { return mScratchAllocator; }
+ PX_FORCE_INLINE PxsTransformCache& getTransformCache() { return *mTransformCache; }
+ PX_FORCE_INLINE PxReal* getContactDistance() { return mContactDistance->begin(); }
+
+ PX_FORCE_INLINE PxvNphaseImplementationContext* getNphaseImplementationContext() const
+ {
+ return mNpImplementationContext;
+ }
+
+ PX_FORCE_INLINE void setNphaseImplementationContext(PxvNphaseImplementationContext* ctx)
+ {
+ mNpImplementationContext = ctx;
+ }
+
+ PX_FORCE_INLINE PxvNphaseImplementationContext* getNphaseFallbackImplementationContext() const
+ {
+ return mNpFallbackImplementationContext;
+ }
+
+ PX_FORCE_INLINE void setNphaseFallbackImplementationContext(PxvNphaseImplementationContext* ctx)
+ {
+ mNpFallbackImplementationContext = ctx;
+ }
+
+ PxU32 getTotalCompressedContactSize() const { return mTotalCompressedCacheSize; }
+ PxU32 getMaxPatchCount() const { return mMaxPatches; }
+
+ PX_FORCE_INLINE PxcThreadCoherentCache<PxcNpThreadContext, PxcNpContext>& getNpThreadContextPool()
+ {
+ return mNpThreadContextPool;
+ }
+
+ PX_FORCE_INLINE PxcNpThreadContext* getNpThreadContext()
+ {
+ // We may want to conditional compile to exclude this on single threaded implementations
+ // if it is determined to be a performance hit.
+ return mNpThreadContextPool.get();
+ }
+
+ PX_FORCE_INLINE void putNpThreadContext(PxcNpThreadContext* threadContext)
+ { mNpThreadContextPool.put(threadContext); }
+ PX_FORCE_INLINE Ps::Mutex& getLock() { return mLock; }
+
+ PX_FORCE_INLINE PxTaskManager& getTaskManager()
+ {
+ PX_ASSERT(mTaskManager);
+ return *mTaskManager;
+ }
+
+ PX_FORCE_INLINE void clearManagerTouchEvents();
+
+ PX_FORCE_INLINE Cm::PoolList<PxsContactManager, PxsContext>& getContactManagerPool()
+ {
+ return this->mContactManagerPool;
+ }
+
+ PX_FORCE_INLINE void setActiveContactManager(const PxsContactManager* manager)
+ {
+ const PxU32 index = manager->getIndex();
+ if (index >= mActiveContactManager.size())
+ {
+ PxU32 newSize = (2 * index + 256)&~255;
+ mActiveContactManager.resize(newSize);
+ }
+ mActiveContactManager.set(index);
+
+ //Record any pairs that have CCD enabled!
+ if (manager->getCCD())
+ {
+ if (index >= mActiveContactManagersWithCCD.size())
+ {
+ PxU32 newSize = (2 * index + 256)&~255;
+ mActiveContactManagersWithCCD.resize(newSize);
+ }
+ mActiveContactManagersWithCCD.set(index);
+ }
+ }
+
+
+private:
+ void mergeCMDiscreteUpdateResults(PxBaseTask* continuation);
+
+ PxU32 mIndex;
+
+ // Threading
+ PxcThreadCoherentCache<PxcNpThreadContext, PxcNpContext>
+ mNpThreadContextPool;
+
+ // Contact managers
+ Cm::PoolList<PxsContactManager, PxsContext> mContactManagerPool;
+ Ps::Pool<Gu::LargePersistentContactManifold> mManifoldPool;
+ Ps::Pool<Gu::SpherePersistentContactManifold> mSphereManifoldPool;
+
+ Cm::BitMap mActiveContactManager;
+ Cm::BitMap mActiveContactManagersWithCCD; //KS - adding to filter any pairs that had a touch
+ Cm::BitMap mContactManagersWithCCDTouch; //KS - adding to filter any pairs that had a touch
+ Cm::BitMap mContactManagerTouchEvent;
+ Cm::BitMap mContactManagerPatchChangeEvent;
+ PxU32 mCMTouchEventCount[PXS_TOUCH_EVENT_COUNT];
+
+ Ps::Mutex mLock;
+
+
+
+ PxContactModifyCallback* mContactModifyCallback;
+
+ // narrowphase platform-dependent implementations support
+ PxvNphaseImplementationContext* mNpImplementationContext;
+ PxvNphaseImplementationContext* mNpFallbackImplementationContext;
+
+
+ // debug rendering (CS TODO: MS would like to have these wrapped into a class)
+ PxReal mVisualizationParams[PxVisualizationParameter::eNUM_VALUES];
+
+ PxBounds3 mVisualizationCullingBox;
+
+ PxTaskManager* mTaskManager;
+ Cm::FlushPool& mTaskPool;
+
+
+ // PxU32 mTouchesLost;
+ // PxU32 mTouchesFound;
+
+ // PX_ENABLE_SIM_STATS
+ PxvSimStats mSimStats;
+ bool mPCM;
+ bool mContactCache;
+ bool mCreateAveragePoint;
+
+ PxsTransformCache* mTransformCache;
+ Ps::Array<PxReal, Ps::VirtualAllocator>* mContactDistance;
+
+
+ PxU32 mMaxPatches;
+ PxU32 mTotalCompressedCacheSize;
+
+ PxU64 mContextID;
+
+ friend class PxsCCDContext;
+ friend class PxsNphaseImplementationContext;
+ friend class PxgNphaseImplementationContext; //FDTODO ideally it shouldn't be here..
+};
+
+
+PX_FORCE_INLINE void PxsContext::clearManagerTouchEvents()
+{
+ mContactManagerTouchEvent.clear();
+ mContactManagerPatchChangeEvent.clear();
+ for(PxU32 i = 0; i < PXS_TOUCH_EVENT_COUNT; ++i)
+ {
+ mCMTouchEventCount[i] = 0;
+ }
+}
+
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxsDefaultMemoryManager.h b/PhysX_3.4/Source/LowLevel/software/include/PxsDefaultMemoryManager.h
new file mode 100644
index 00000000..baabbd86
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxsDefaultMemoryManager.h
@@ -0,0 +1,98 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXS_DEFAULT_MEMORY_MANAGER_H
+#define PXS_DEFAULT_MEMORY_MANAGER_H
+
+#include "PxsMemoryManager.h"
+#include "PsAllocator.h"
+#include "PsArray.h"
+
+namespace physx
+{
+
+ class PxsDefaultMemoryAllocator : public Ps::VirtualAllocatorCallback
+ {
+ public:
+
+ PxsDefaultMemoryAllocator(const char* name = NULL)
+ {
+ PX_UNUSED(name);
+#if 0 //PX_USE_NAMED_ALLOCATOR
+ if (name)
+ strcpy(mName, name);
+ else
+ strcpy(mName, "");
+#endif
+ }
+
+ virtual ~PxsDefaultMemoryAllocator()
+ {
+ }
+
+ virtual void* allocate(const size_t newByteSize, const char* filename, const int line)
+ {
+ PX_UNUSED(line);
+ PX_UNUSED(filename);
+#if 0 //PX_USE_NAMED_ALLOCATOR
+ return PX_ALLOC(newByteSize, mName);
+#else
+ return PX_ALLOC(newByteSize, filename);
+#endif
+ }
+
+ virtual void deallocate(void* ptr)
+ {
+ if (ptr)
+ PX_FREE(ptr);
+ }
+
+#if 0 //PX_USE_NAMED_ALLOCATOR
+ char mName[32];
+#endif
+ };
+
+
+ class PxsDefaultMemoryManager : public PxsMemoryManager
+ {
+ public:
+ virtual ~PxsDefaultMemoryManager();
+ virtual Ps::VirtualAllocatorCallback* createHostMemoryAllocator(const PxU32 gpuComputeVersion = 0);
+ virtual Ps::VirtualAllocatorCallback* createDeviceMemoryAllocator(const PxU32 gpuComputeVersion = 0);
+
+ virtual void destroyMemoryAllocator();
+
+ Ps::Array<Ps::VirtualAllocatorCallback*> mAllocators;
+
+ };
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxsHeapMemoryAllocator.h b/PhysX_3.4/Source/LowLevel/software/include/PxsHeapMemoryAllocator.h
new file mode 100644
index 00000000..61d600dc
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxsHeapMemoryAllocator.h
@@ -0,0 +1,68 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXS_HEAP_MEMORY_ALLOCATOR_H
+#define PXS_HEAP_MEMORY_ALLOCATOR_H
+
+
+#include "DyGpuAPI.h"
+#include "foundation/PxSimpleTypes.h"
+
+namespace physx
+{
+ namespace shdfnd
+ {
+ class VirtualAllocatorCallback;
+ }
+
+ class PxErrorCallback;
+ class PxsHostMemoryAllocator;
+
+ class PxsHeapMemoryAllocator : public Ps::VirtualAllocatorCallback
+ {
+ public:
+ virtual ~PxsHeapMemoryAllocator(){}
+ virtual void* allocate(const size_t size, const char* file, const int line) = 0;
+ virtual void deallocate(void* ptr) = 0;
+
+ };
+
+ class PxsHeapMemoryAllocatorManager
+ {
+ public:
+ virtual ~PxsHeapMemoryAllocatorManager()
+ {
+
+ }
+ PxsHeapMemoryAllocator* mMappedMemoryAllocators;
+ };
+}
+
+#endif \ No newline at end of file
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxsIncrementalConstraintPartitioning.h b/PhysX_3.4/Source/LowLevel/software/include/PxsIncrementalConstraintPartitioning.h
new file mode 100644
index 00000000..279e3666
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxsIncrementalConstraintPartitioning.h
@@ -0,0 +1,40 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef PXS_INCREMENTAL_CONSTRAINT_PARTITIONING_H
+#define PXS_INCREMENTAL_CONSTRAINT_PARTITIONING_H
+
+#include "PxsSimpleIslandManager.h"
+
+namespace physx
+{
+
+}
+
+#endif \ No newline at end of file
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxsIslandManagerTypes.h b/PhysX_3.4/Source/LowLevel/software/include/PxsIslandManagerTypes.h
new file mode 100644
index 00000000..01f7b4ee
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxsIslandManagerTypes.h
@@ -0,0 +1,372 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXS_ISLAND_MANAGER_TYPES_H
+#define PXS_ISLAND_MANAGER_TYPES_H
+
+#include "CmPhysXCommon.h"
+
+namespace physx
+{
+
+class PxsContactManager;
+class PxsRigidBody;
+namespace Dy
+{
+ struct Constraint;
+ class Articulation;
+}
+
+#if PX_USE_16_BIT_HANDLES
+typedef PxU16 NodeType;
+typedef PxU16 EdgeType;
+typedef PxU16 IslandType;
+#define INVALID_NODE 0xffff
+#define INVALID_EDGE 0xffff
+#define INVALID_ISLAND 0xffff
+#else
+typedef PxU32 NodeType;
+typedef PxU32 EdgeType;
+typedef PxU32 IslandType;
+#define INVALID_NODE 0xffffffff
+#define INVALID_EDGE 0xffffffff
+#define INVALID_ISLAND 0xffffffff
+#endif
+
+namespace Dy
+{
+ typedef size_t ArticulationLinkHandle;
+}
+
+//----------------------------------------------------------------------------//
+
+template <class T, T INVLD> class PxsIslandManagerHook
+{
+ friend class PxsIslandManager;
+ T index;
+
+public:
+
+ static const T INVALID = INVLD;
+
+ PX_FORCE_INLINE PxsIslandManagerHook(): index(INVLD) {}
+ PX_FORCE_INLINE PxsIslandManagerHook(const T id): index(id) {}
+ PX_FORCE_INLINE PxsIslandManagerHook(const PxsIslandManagerHook<T,INVLD>& src) : index(src.index) {}
+ PX_FORCE_INLINE ~PxsIslandManagerHook(){}
+
+ PX_FORCE_INLINE bool isManaged() const { return index!=INVLD; }
+
+private:
+};
+
+typedef PxsIslandManagerHook<NodeType,INVALID_NODE> PxsIslandManagerNodeHook;
+typedef PxsIslandManagerHook<EdgeType,INVALID_EDGE> PxsIslandManagerEdgeHook;
+typedef PxsIslandManagerHook<IslandType,INVALID_ISLAND> PxsIslandManagerIslandHook;
+
+//----------------------------------------------------------------------------//
+
+/**
+\brief PxsIslandObjects contains arrays of all rigid bodies, articulations, contact managers, and constraints that
+belong to all awake islands. The per array indices denoting the ownership per island are stored in PxsIslandIndices.
+
+@see PxsIslandManager::getIslandObjects
+*/
+struct PxsIslandObjects
+{
+ /**
+ \brief Array of all rigid bodies in all awake islands.
+
+ \note Each rigid body corresponds to the void* passed to PxsIslandManager::addBody. The PxsRigidBody ptr is computed
+ by adding the rigid body offset value (passed to PxsIslandManager::create) to the void* pointer
+ ie [(PxsRigidBody*)((PxU8*)owner + rigidBodyOffset)]
+
+ @see PxsIslandManager::addBody, PxsIslandManager::create
+ */
+ PxsRigidBody*const* bodies;
+
+ /**
+ \brief Array of all articulation roots in all awake islands.
+
+ \note Each Articulation* corresponds to Dy::getArticulation(articLinkHandle) where
+ articLinkHandle is the handle passed to PxsIslandManager::setArticulationRootLinkHandle.
+
+ @see PxsIslandManager::setArticulationRootLinkHandle, Dy::getArticulation
+ */
+ Dy::Articulation*const* articulations;
+
+ /**
+ \brief Array of all articulation roots in all awake islands.
+
+ \note Each void* corresponds to the void* passed to PxsIslandManager::setArticulationRootLinkHandle
+
+ @see PxsIslandManager::setArticulationRootLinkHandle
+ */
+ void*const* articulationOwners;
+
+ /**
+ \brief Array of all contact managers in all awake islands.
+
+ @see PxsIslandManager::setEdgeRigidCM
+ */
+ struct PxsIndexedContactManager* contactManagers;
+
+ /**
+ \brief Array of all constraints in all awake islands.
+
+ @see PxsIslandManager::setEdgeConstraint
+ */
+ struct PxsIndexedConstraint* constraints;
+
+
+ PxsIslandObjects() : bodies(NULL), articulations(NULL), articulationOwners(NULL), contactManagers(NULL), constraints(NULL)
+ {
+ }
+};
+
+
+//----------------------------------------------------------------------------//
+
+/**
+\brief An array of PxsIslandIndices describes the rigid bodies, articulations, contacts and constraints that
+belong to each island.
+
+\note Given an array of PxsIslandIndices, the rigid bodies of the ith island span the inclusive range:
+ (PxsIslandObjects::bodies[PxsIslandIndices[i]], PxsIslandObjects::bodies[PxsIslandIndices[i+1]-1])
+
+\note Given an array of PxsIslandIndices, the constraints of the ith island span the inclusive range:
+ (PxsIslandObjects::constraints[PxsIslandIndices[i]], PxsIslandObjects::constraints[PxsIslandIndices[i+1]-1])
+
+@see PxsIslandObjects::getIslandIndices, PxsIslandObjects::getIslandCount
+*/
+class PxsIslandIndices
+{
+public:
+
+ PxsIslandIndices(){}
+ ~PxsIslandIndices(){}
+
+ /**
+ \brief Return true if the corresponding island has a contact with a static rigid body.
+ */
+ PX_FORCE_INLINE bool getHasStaticContact() const
+ {
+ return (1 & hasStaticContact) ? true : false;
+ }
+
+ /**
+ \brief The starting index of island rigid bodies in the array PxsIslandObjects::bodies
+ */
+ NodeType bodies;
+
+ /**
+ \brief The starting index of island articulations in the arrays PxsIslandObjects::articulations and PxsIslandObjects::articulationOwners
+
+ \note The total number of articulations is clamped at 32767 on any platform that uses 16-bit handles.
+ */
+ NodeType articulations : 8*sizeof(NodeType)-1;
+
+private:
+
+ NodeType hasStaticContact : 1;
+
+public:
+
+ /**
+ \brief The starting index of island contact managers in the array PxsIslandObjects::contactManagers.
+ */
+ EdgeType contactManagers;
+
+ /**
+ \brief The starting index of island constraints in the array PxsIslandObjects::constraints.
+
+ \note islandId is for internal use only and is used for tracking islands that need a second pass.
+ */
+ union
+ {
+ EdgeType constraints;
+ IslandType islandId;
+ };
+
+//private:
+
+ /**
+ \brief Internal use only.
+ */
+ PX_FORCE_INLINE void setHasStaticContact(const bool b)
+ {
+ hasStaticContact = NodeType(b ? 1 : 0);
+ }
+};
+PX_COMPILE_TIME_ASSERT(0==(0x07 & sizeof(PxsIslandIndices)));
+
+
+//----------------------------------------------------------------------------//
+
+typedef Dy::ArticulationLinkHandle PxsNodeType;
+
+
+/**
+\brief Each contact manager or constraint references two separate bodies, where
+a body can be a dynamic rigid body, a kinematic rigid body, an articulation or a static.
+The struct PxsIndexedInteraction describes the bodies that make up the pair.
+*/
+struct PxsIndexedInteraction
+{
+ /**
+ \brief An enumerated list of all possible body types.
+ A body type is stored for each body in the pair.
+ */
+ enum Enum
+ {
+ eBODY = 0,
+ eKINEMATIC = 1,
+ eARTICULATION = 2,
+ eWORLD = 3
+ };
+
+ /**
+ \brief An index describing how to access body0
+
+ \note If body0 is a dynamic (eBODY) rigid body then solverBody0 is an index into PxsIslandObjects::bodies.
+ \note If body0 is a kinematic (eKINEMATIC) rigid body then solverBody0 is an index into PxsIslandManager::getActiveKinematics.
+
+ \note If body0 is a static (eWORLD) then solverBody0 is PX_MAX_U32 or PX_MAX_U64, depending on the platform being 32- or 64-bit.
+
+ \note If body0 is an articulation then the articulation is found directly from Dy::getArticulation(articulation0)
+ */
+ union
+ {
+ PxsNodeType solverBody0;
+ Dy::ArticulationLinkHandle articulation0;
+ };
+
+ /**
+ \brief An index describing how to access body1
+
+ \note If body1 is a dynamic (eBODY) rigid body then solverBody1 is an index into PxsIslandObjects::bodies.
+ \note If body1 is a kinematic (eKINEMATIC) rigid body then solverBody1 is an index into PxsIslandManager::getActiveKinematics.
+
+ \note If body1 is a static (eWORLD) then solverBody1 is PX_MAX_U32 or PX_MAX_U64, depending on the platform being 32- or 64-bit.
+
+ \note If body1 is an articulation then the articulation is found directly from Dy::getArticulation(articulation1)
+ */
+ union
+ {
+ PxsNodeType solverBody1;
+ Dy::ArticulationLinkHandle articulation1;
+ };
+
+ /**
+ \brief The type (eBODY, eKINEMATIC etc) of body0
+ */
+ PxU8 indexType0;
+
+ /**
+ \brief The type (eBODY, eKINEMATIC etc) of body1
+ */
+ PxU8 indexType1;
+
+ PxU8 pad[2];
+};
+
+/**
+@see PxsIslandObjects, PxsIndexedInteraction
+*/
+struct PxsIndexedContactManager : public PxsIndexedInteraction
+{
+ /**
+ \brief The contact manager corresponds to the value set in PxsIslandManager::setEdgeRigidCM
+ */
+ PxsContactManager* contactManager;
+
+ PxsIndexedContactManager(PxsContactManager* cm) : contactManager(cm) {}
+};
+#if !PX_X64
+PX_COMPILE_TIME_ASSERT(0==(sizeof(PxsIndexedContactManager) & 0x0f));
+#endif
+
+/**
+@see PxsIslandObjects, PxsIndexedInteraction
+*/
+struct PxsIndexedConstraint : public PxsIndexedInteraction
+{
+ /**
+ \brief The constraint corresponds to the value set in PxsIslandManager::setEdgeConstraint
+ */
+ Dy::Constraint* constraint;
+
+ PxsIndexedConstraint(Dy::Constraint* c) : constraint(c) {}
+};
+#if !PX_P64_FAMILY
+PX_COMPILE_TIME_ASSERT(0==(sizeof(PxsIndexedConstraint) & 0x0f));
+#endif
+
+//----------------------------------------------------------------------------//
+
+/**
+\brief Any sleeping contact pair that finds itself in an awake island after 1st pass island gen
+must participate in 2nd pass narrowphase so that contacts can be generated.
+
+\note Contact managers in sleeping pairs are NULL until PxsIslandManager::setWokenPairContactManagers is complete.
+
+@see PxsIslandManager::getNarrowPhaseSecondPassContactManagers, PxsIslandManager::getNumNarrowPhaseSecondPassContactManagers,
+PxsIslandManager::setWokenPairContactManagers
+*/
+struct PxsNarrowPhaseSecondPassContactManager
+{
+ /**
+ \brief The contact manager that is to participate in 2nd pass narrowphase.
+
+ \note This pointer is NULL after 1st pass island gen and remains NULL until PxsIslandManager::setWokenPairContactManagers
+ completes.
+ */
+ PxsContactManager* mCM;
+
+ /**
+ \brief The corresponding entry in PxsIslandObjects::contactManagers.
+
+ \note All sleeping pairs have a null contact manager during 1st pass island gen. After 1st pass island gen completes,
+ the bodies to be woken are externally processed. Waking up bodies generates contact managers and passes the pointer to the
+ corresponding edge. So that the contact manager can be efficiently passed to PxsIslandObjects we store mEdgeId and mSolverCMId.
+ The contact manager pointers are set in PxsIslandManager::setWokenPairContactManagers
+ */
+ EdgeType mSolverCMId; //Keeps a track of which entries in the solver islands temporarily have a null contact manager
+
+ /**
+ \brief The internal id of the corresponding edge.
+ */
+ EdgeType mEdgeId;
+};
+
+
+} //namespace physx
+
+
+#endif //PXS_ISLAND_MANAGER_TYPES_H
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxsIslandSim.h b/PhysX_3.4/Source/LowLevel/software/include/PxsIslandSim.h
new file mode 100644
index 00000000..48cfc7d2
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxsIslandSim.h
@@ -0,0 +1,965 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef PXS_ISLAND_SIM_H
+#define PXS_ISLAND_SIM_H
+
+#include "CmPhysXCommon.h"
+#include "foundation/PxAssert.h"
+#include "PsArray.h"
+#include "CmBitMap.h"
+#include "CmPriorityQueue.h"
+
+namespace physx
+{
+
+namespace Dy
+{
+ struct Constraint;
+ class Articulation;
+}
+
+namespace Sc
+{
+ class ArticulationSim;
+}
+
+class PxsContactManager;
+class PxsRigidBody;
+
+struct PartitionEdge;
+
+namespace IG
+{
+
+//This index is
+#define IG_INVALID_ISLAND 0xFFFFFFFFu
+#define IG_INVALID_EDGE 0xFFFFFFFFu
+#define IG_INVALID_NODE 0x3FFFFFFu
+#define IG_INVALID_LINK 0xFFu
+
+typedef PxU32 IslandId;
+typedef PxU32 EdgeIndex;
+typedef PxU32 EdgeInstanceIndex;
+
+class IslandSim;
+
+
+
+class NodeIndex
+{
+private:
+ PxU32 ind;
+
+public:
+
+ explicit PX_FORCE_INLINE NodeIndex(PxU32 id = IG_INVALID_NODE, PxU32 articId = 0) : ind((id<<6) | articId)
+ {
+ }
+
+ PxU32 index() const { return ind>>6; }
+ PxU32 articulationLinkId() const { return (ind & 63); }
+
+ bool isStaticBody() const { return (ind>>6) == IG_INVALID_NODE; }
+
+ bool isValid() const { return (ind>>6) != IG_INVALID_NODE; }
+
+ void setIndices(PxU32 index, PxU32 articId) { ind = ((index<<6) | articId); }
+};
+
+union ConstraintOrContactManager
+{
+ PxsContactManager* mCm;
+ Dy::Constraint* mConstraint;
+};
+
+
+struct Edge
+{
+ //Edge instances can be implicitly calculated based on this edge index, which is an offset into the array of edges.
+ //From that, the child edge index is simply the
+ //The constraint or contact referenced by this edge
+
+ enum EdgeType
+ {
+ eCONTACT_MANAGER,
+ eCONSTRAINT,
+ eEDGE_TYPE_COUNT
+ };
+
+
+ enum EdgeState
+ {
+ eINSERTED =1<<0,
+ ePENDING_DESTROYED =1<<1,
+ eACTIVE =1<<2,
+ eIN_DIRTY_LIST =1<<3,
+ eDESTROYED =1<<4,
+ eREPORT_ONLY_DESTROY=1<<5,
+ eACTIVATING =1<<6
+ };
+
+
+ //NodeIndex mNode1, mNode2;
+ EdgeType mEdgeType;
+ PxU16 mEdgeState;
+
+ EdgeIndex mNextIslandEdge, mPrevIslandEdge;
+
+
+
+ PX_FORCE_INLINE void setInserted() { mEdgeState |= (eINSERTED); }
+
+ PX_FORCE_INLINE void clearInserted() { mEdgeState &= (~eINSERTED); }
+
+ PX_FORCE_INLINE void clearDestroyed() { mEdgeState &=(~eDESTROYED);}
+ PX_FORCE_INLINE void setPendingDestroyed() { mEdgeState |= ePENDING_DESTROYED; }
+ PX_FORCE_INLINE void clearPendingDestroyed() { mEdgeState &= (~ePENDING_DESTROYED); }
+ PX_FORCE_INLINE void activateEdge() { mEdgeState |= eACTIVE; }
+ PX_FORCE_INLINE void deactivateEdge() { mEdgeState &= (~eACTIVE); }
+ PX_FORCE_INLINE void markInDirtyList() { mEdgeState |= (eIN_DIRTY_LIST); }
+ PX_FORCE_INLINE void clearInDirtyList() { mEdgeState &= (~eIN_DIRTY_LIST); }
+ PX_FORCE_INLINE void setReportOnlyDestroy() { mEdgeState |= (eREPORT_ONLY_DESTROY); }
+ PX_FORCE_INLINE void clearReportOnlyDestroy() { mEdgeState &= (~eREPORT_ONLY_DESTROY); }
+public:
+ Edge() : mEdgeType(Edge::eCONTACT_MANAGER), mEdgeState(eDESTROYED),
+ mNextIslandEdge(IG_INVALID_EDGE), mPrevIslandEdge(IG_INVALID_EDGE)
+ {
+ }
+ PX_FORCE_INLINE bool isInserted() const { return !!(mEdgeState & eINSERTED);}
+ PX_FORCE_INLINE bool isDestroyed() const { return !!(mEdgeState & eDESTROYED); }
+ PX_FORCE_INLINE bool isPendingDestroyed() const { return !!(mEdgeState & ePENDING_DESTROYED); }
+ PX_FORCE_INLINE bool isActive() const { return !!(mEdgeState & eACTIVE); }
+ PX_FORCE_INLINE bool isInDirtyList() const { return !!(mEdgeState & eIN_DIRTY_LIST); }
+ PX_FORCE_INLINE EdgeType getEdgeType() const { return mEdgeType; }
+ //PX_FORCE_INLINE const NodeIndex getIndex1() const { return mNode1; }
+ //PX_FORCE_INLINE const NodeIndex getIndex2() const { return mNode2; }
+ PX_FORCE_INLINE bool isReportOnlyDestroy() { return !!(mEdgeState & eREPORT_ONLY_DESTROY); }
+};
+
+struct EdgeInstance
+{
+ EdgeInstanceIndex mNextEdge, mPrevEdge; //The next edge instance in this node's list of edge instances
+
+ EdgeInstance() : mNextEdge(IG_INVALID_EDGE), mPrevEdge(IG_INVALID_EDGE)
+ {
+ }
+};
+
+template<typename Handle>
+class HandleManager
+{
+ Ps::Array<Handle> mFreeHandles;
+ Handle mCurrentHandle;
+
+public:
+
+ HandleManager() : mFreeHandles(PX_DEBUG_EXP("FreeHandles")), mCurrentHandle(0)
+ {
+ }
+
+ ~HandleManager(){}
+
+ Handle getHandle()
+ {
+ if(mFreeHandles.size())
+ {
+ Handle handle = mFreeHandles.popBack();
+ PX_ASSERT(isValidHandle(handle));
+ return handle;
+ }
+ return mCurrentHandle++;
+ }
+
+ bool isNotFreeHandle(Handle handle)
+ {
+ for(PxU32 a = 0; a < mFreeHandles.size(); ++a)
+ {
+ if(mFreeHandles[a] == handle)
+ return false;
+ }
+ return true;
+ }
+
+ void freeHandle(Handle handle)
+ {
+ PX_ASSERT(isValidHandle(handle));
+ PX_ASSERT(isNotFreeHandle(handle));
+ if(handle == mCurrentHandle)
+ mCurrentHandle--;
+ else
+ mFreeHandles.pushBack(handle);
+ }
+
+ bool isValidHandle(Handle handle)
+ {
+ return handle < mCurrentHandle;
+ }
+
+ PX_FORCE_INLINE PxU32 getTotalHandles() const { return mCurrentHandle; }
+};
+
+class Node
+{
+
+public:
+ enum NodeType
+ {
+ eRIGID_BODY_TYPE,
+ eARTICULATION_TYPE,
+ eTYPE_COUNT
+ };
+ enum State
+ {
+ eREADY_FOR_SLEEPING = 1u << 0, //! Ready to go to sleep
+ eACTIVE = 1u << 1, //! Active
+ eKINEMATIC = 1u << 2, //! Kinematic
+ eDELETED = 1u << 3, //! Is pending deletion
+ eDIRTY = 1u << 4, //! Is dirty (i.e. lost a connection)
+ eACTIVATING = 1u << 5, //! Is in the activating list
+ eDEACTIVATING = 1u << 6 //! It is being forced to deactivate this frame
+ };
+ EdgeInstanceIndex mFirstEdgeIndex;
+
+ PxU8 mFlags;
+ PxU8 mType;
+ PxU16 mStaticTouchCount;
+ //PxU32 mActiveNodeIndex; //! Look-up for this node in the active nodes list, activating list or deactivating list...
+
+ NodeIndex mNextNode, mPrevNode;
+
+ //A counter for the number of active references to this body. Whenever an edge is activated, this is incremented.
+ //Whenver an edge is deactivated, this is decremented. This is used for kinematic bodies to determine if they need
+ //to be in the active kinematics list
+ PxU32 mActiveRefCount;
+
+
+ //A node can correspond with either a rigid body or an articulation.
+ union
+ {
+ PxsRigidBody* mRigidBody;
+ Dy::Articulation* mLLArticulation;
+ };
+
+
+
+ PX_FORCE_INLINE Node() : mFirstEdgeIndex(IG_INVALID_EDGE), mFlags(eDELETED), mType(eRIGID_BODY_TYPE),
+ mStaticTouchCount(0), mActiveRefCount(0), mRigidBody(NULL)
+ {
+ }
+
+ PX_FORCE_INLINE ~Node() {}
+
+ PX_FORCE_INLINE void reset()
+ {
+ mFirstEdgeIndex = IG_INVALID_EDGE;
+ mFlags = eDELETED;
+ mRigidBody = NULL;
+ mActiveRefCount = 0;
+ mStaticTouchCount = 0;
+ }
+
+ PX_FORCE_INLINE void setRigidBody(PxsRigidBody* body) { mRigidBody = body; }
+
+ PX_FORCE_INLINE PxsRigidBody* getRigidBody() const { return mRigidBody; }
+
+ PX_FORCE_INLINE Dy::Articulation* getArticulation() const { return mLLArticulation; }
+
+
+ PX_FORCE_INLINE void setActive() { mFlags |= eACTIVE; }
+ PX_FORCE_INLINE void clearActive() { mFlags &= ~eACTIVE; }
+
+ PX_FORCE_INLINE void setActivating() { mFlags |= eACTIVATING; }
+ PX_FORCE_INLINE void clearActivating() { mFlags &= ~eACTIVATING; }
+
+ PX_FORCE_INLINE void setDeactivating() { mFlags |= eDEACTIVATING; }
+ PX_FORCE_INLINE void clearDeactivating() { mFlags &= (~eDEACTIVATING); }
+
+
+ //Activates a body/node.
+ PX_FORCE_INLINE void setIsReadyForSleeping() { mFlags |= eREADY_FOR_SLEEPING; }
+
+ PX_FORCE_INLINE void clearIsReadyForSleeping(){ mFlags &= (~eREADY_FOR_SLEEPING);}
+
+ PX_FORCE_INLINE void setIsDeleted(){mFlags |= eDELETED; }
+
+ PX_FORCE_INLINE void setKinematicFlag() {PX_ASSERT(!isKinematic()); mFlags |= eKINEMATIC;}
+
+ PX_FORCE_INLINE void clearKinematicFlag(){ PX_ASSERT(isKinematic()); mFlags &= (~eKINEMATIC);}
+
+ PX_FORCE_INLINE void markDirty(){mFlags |= eDIRTY;}
+
+ PX_FORCE_INLINE void clearDirty(){mFlags &= (~eDIRTY);}
+
+public:
+
+ PX_FORCE_INLINE bool isActive() const { return !!(mFlags & eACTIVE); }
+
+ PX_FORCE_INLINE bool isActivating() const { return !!(mFlags & eACTIVATING); }
+
+ PX_FORCE_INLINE bool isDeactivating() const { return !!(mFlags & eDEACTIVATING); }
+
+ PX_FORCE_INLINE bool isKinematic() const { return !!(mFlags & eKINEMATIC); }
+
+ PX_FORCE_INLINE bool isDeleted() const { return !!(mFlags & eDELETED); }
+
+ PX_FORCE_INLINE bool isDirty() const { return !!(mFlags & eDIRTY); }
+
+ PX_FORCE_INLINE bool isReadyForSleeping() const { return !!(mFlags & eREADY_FOR_SLEEPING); }
+
+ PX_FORCE_INLINE NodeType getNodeType() const { return NodeType(mType); }
+
+ friend class SimpleIslandManager;
+
+};
+
+struct Island
+{
+ NodeIndex mRootNode;
+ NodeIndex mLastNode;
+ PxU32 mSize[Node::eTYPE_COUNT];
+ PxU32 mActiveIndex;
+
+ EdgeIndex mFirstEdge[Edge::eEDGE_TYPE_COUNT], mLastEdge[Edge::eEDGE_TYPE_COUNT];
+ PxU32 mEdgeCount[Edge::eEDGE_TYPE_COUNT];
+
+ Island() : mActiveIndex(IG_INVALID_ISLAND)
+ {
+ for(PxU32 a = 0; a < Edge::eEDGE_TYPE_COUNT; ++a)
+ {
+ mFirstEdge[a] = IG_INVALID_EDGE;
+ mLastEdge[a] = IG_INVALID_EDGE;
+ mEdgeCount[a] = 0;
+ }
+
+ for(PxU32 a = 0; a < Node::eTYPE_COUNT; ++a)
+ {
+ mSize[a] = 0;
+ }
+ }
+};
+
+struct TraversalState
+{
+ NodeIndex mNodeIndex;
+ PxU32 mCurrentIndex;
+ PxU32 mPrevIndex;
+ PxU32 mDepth;
+
+ TraversalState()
+ {
+ }
+
+ TraversalState(NodeIndex nodeIndex, PxU32 currentIndex, PxU32 prevIndex, PxU32 depth) :
+ mNodeIndex(nodeIndex), mCurrentIndex(currentIndex), mPrevIndex(prevIndex), mDepth(depth)
+ {
+ }
+};
+
+struct QueueElement
+{
+ TraversalState* mState;
+ PxU32 mHopCount;
+
+ QueueElement()
+ {
+ }
+
+ QueueElement(TraversalState* state, PxU32 hopCount) : mState(state), mHopCount(hopCount)
+ {
+ }
+};
+
+struct NodeComparator
+{
+ NodeComparator()
+ {
+ }
+
+ bool operator() (const QueueElement& node0, const QueueElement& node1) const
+ {
+ return node0.mHopCount < node1.mHopCount;
+ }
+private:
+ NodeComparator& operator = (const NodeComparator&);
+};
+
+
+class IslandSim
+{
+ HandleManager<IslandId> mIslandHandles; //! Handle manager for islands
+
+ Ps::Array<Node> mNodes; //! The nodes used in the constraint graph
+ Ps::Array<PxU32> mActiveNodeIndex; //! The active node index for each node
+ Ps::Array<Edge> mEdges; //! Edges used to represent contacts or constraints
+ //Ps::Array<ConstraintOrContactManager> mConstraintOrCm; //! Pointers to either the constraint or Cm for this pair
+ Ps::Array<EdgeInstance> mEdgeInstances; //! Edges used to connect nodes in the constraint graph
+ Ps::Array<Island> mIslands; //! The array of islands
+ Ps::Array<PxU32> mIslandStaticTouchCount; //! Array of static touch counts per-island
+
+
+ Ps::Array<NodeIndex> mActiveNodes[Node::eTYPE_COUNT]; //! An array of active nodes
+ Ps::Array<NodeIndex> mActiveKinematicNodes; //! An array of active or referenced kinematic nodes
+ //Ps::Array<EdgeIndex> mActiveEdges[Edge::eEDGE_TYPE_COUNT]; //! An array of active edges
+ Ps::Array<EdgeIndex> mActivatedEdges[Edge::eEDGE_TYPE_COUNT]; //! An array of active edges
+
+ PxU32 mActiveEdgeCount[Edge::eEDGE_TYPE_COUNT];
+
+ Ps::Array<PxU32> mHopCounts; //! The observed number of "hops" from a given node to its root node. May be inaccurate but used to accelerate searches.
+ Ps::Array<NodeIndex> mFastRoute; //! The observed last route from a given node to the root node. We try the fast route (unless its broken) before trying others.
+
+ Ps::Array<IslandId> mIslandIds; //! The array of per-node island ids
+
+ Cm::BitMap mIslandAwake; //! Indicates whether an island is awake or not
+
+ Cm::BitMap mActiveContactEdges;
+
+ //An array of active islands
+ Ps::Array<IslandId> mActiveIslands;
+
+ //PxU32 mInitialActiveEdgeCount[Edge::eEDGE_TYPE_COUNT];
+ PxU32 mInitialActiveNodeCount[Edge::eEDGE_TYPE_COUNT];
+
+ Ps::Array<NodeIndex> mNodesToPutToSleep[Node::eTYPE_COUNT];
+
+ //Input to this frame's island management (changed nodes/edges)
+
+ //Input list of changes observed this frame. If there no changes, no work to be done.
+ Ps::Array<EdgeIndex> mDirtyEdges[Edge::eEDGE_TYPE_COUNT];
+ //Dirty nodes. These nodes lost at least one connection so we need to recompute islands from these nodes
+ //Ps::Array<NodeIndex> mDirtyNodes;
+ Cm::BitMap mDirtyMap;
+ PxU32 mLastMapIndex;
+
+ //An array of nodes to activate
+ Ps::Array<NodeIndex> mActivatingNodes;
+ Ps::Array<EdgeIndex> mDestroyedEdges;
+ Ps::Array<IslandId> mTempIslandIds;
+
+
+ //Temporary, transient data used for traversals. TODO - move to PxsSimpleIslandManager. Or if we keep it here, we can
+ //process multiple island simulations in parallel
+ Cm::PriorityQueue<QueueElement, NodeComparator>
+ mPriorityQueue; //! Priority queue used for graph traversal
+ Ps::Array<TraversalState> mVisitedNodes; //! The list of nodes visited in the current traversal
+ Cm::BitMap mVisitedState; //! Indicates whether a node has been visited
+ Ps::Array<EdgeIndex> mIslandSplitEdges[Edge::eEDGE_TYPE_COUNT];
+
+ Ps::Array<EdgeIndex> mDeactivatingEdges[Edge::eEDGE_TYPE_COUNT];
+
+ Ps::Array<PartitionEdge*>* mFirstPartitionEdges;
+ Ps::Array<NodeIndex>& mEdgeNodeIndices;
+ Ps::Array<physx::PartitionEdge*>* mDestroyedPartitionEdges;
+
+ PxU32* mNpIndexPtr;
+
+ PxU64 mContextId;
+
+public:
+
+ IslandSim(Ps::Array<PartitionEdge*>* firstPartitionEdges, Ps::Array<NodeIndex>& edgeNodeIndices, Ps::Array<PartitionEdge*>* destroyedPartitionEdges, PxU64 contextID);
+ ~IslandSim() {}
+
+ void resize(const PxU32 nbNodes, const PxU32 nbContactManagers, const PxU32 nbConstraints);
+
+ void addRigidBody(PxsRigidBody* body, bool isKinematic, bool isActive, NodeIndex nodeIndex);
+
+ void addArticulation(Sc::ArticulationSim* articulation, Dy::Articulation* llArtic, bool isActive, NodeIndex nodeIndex);
+
+ void addContactManager(PxsContactManager* manager, NodeIndex nodeHandle1, NodeIndex nodeHandle2, EdgeIndex handle);
+
+ void addConstraint(Dy::Constraint* constraint, NodeIndex nodeHandle1, NodeIndex nodeHandle2, EdgeIndex handle);
+
+ void activateNode(NodeIndex index);
+ void deactivateNode(NodeIndex index);
+ void putNodeToSleep(NodeIndex index);
+
+ void removeConnection(EdgeIndex edgeIndex);
+
+ PX_FORCE_INLINE PxU32 getNbNodes() const { return mNodes.size(); }
+
+ PX_FORCE_INLINE PxU32 getNbActiveNodes(Node::NodeType type) const { return mActiveNodes[type].size(); }
+
+ PX_FORCE_INLINE const NodeIndex* getActiveNodes(Node::NodeType type) const { return mActiveNodes[type].begin(); }
+
+ PX_FORCE_INLINE PxU32 getNbActiveKinematics() const { return mActiveKinematicNodes.size(); }
+
+ PX_FORCE_INLINE const NodeIndex* getActiveKinematics() const { return mActiveKinematicNodes.begin(); }
+
+ PX_FORCE_INLINE PxU32 getNbNodesToActivate(Node::NodeType type) const { return mActiveNodes[type].size() - mInitialActiveNodeCount[type]; }
+
+ PX_FORCE_INLINE const NodeIndex* getNodesToActivate(Node::NodeType type) const { return mActiveNodes[type].begin() + mInitialActiveNodeCount[type]; }
+
+ PX_FORCE_INLINE PxU32 getNbNodesToDeactivate(Node::NodeType type) const { return mNodesToPutToSleep[type].size(); }
+
+ PX_FORCE_INLINE const NodeIndex* getNodesToDeactivate(Node::NodeType type) const { return mNodesToPutToSleep[type].begin(); }
+
+ PX_FORCE_INLINE PxU32 getNbActivatedEdges(Edge::EdgeType type) const { return mActivatedEdges[type].size(); }
+
+ PX_FORCE_INLINE const EdgeIndex* getActivatedEdges(Edge::EdgeType type) const { return mActivatedEdges[type].begin(); }
+
+ PX_FORCE_INLINE PxU32 getNbActiveEdges(Edge::EdgeType type) const { return mActiveEdgeCount[type]; }
+
+ PX_FORCE_INLINE PartitionEdge* getFirstPartitionEdge(IG::EdgeIndex edgeIndex) const { return (*mFirstPartitionEdges)[edgeIndex]; }
+ PX_FORCE_INLINE void setFirstPartitionEdge(IG::EdgeIndex edgeIndex, PartitionEdge* partitionEdge) { (*mFirstPartitionEdges)[edgeIndex] = partitionEdge; }
+
+ //PX_FORCE_INLINE const EdgeIndex* getActiveEdges(Edge::EdgeType type) const { return mActiveEdges[type].begin(); }
+
+ PX_FORCE_INLINE PxsRigidBody* getRigidBody(NodeIndex nodeIndex) const
+ {
+ const Node& node = mNodes[nodeIndex.index()];
+ PX_ASSERT(node.mType == Node::eRIGID_BODY_TYPE);
+ return node.mRigidBody;
+ }
+
+ PX_FORCE_INLINE Dy::Articulation* getLLArticulation(NodeIndex nodeIndex) const
+ {
+ const Node& node = mNodes[nodeIndex.index()];
+ PX_ASSERT(node.mType == Node::eARTICULATION_TYPE);
+ return node.mLLArticulation;
+ }
+
+ PX_FORCE_INLINE void clearDeactivations()
+ {
+ mNodesToPutToSleep[0].forceSize_Unsafe(0);
+ mNodesToPutToSleep[1].forceSize_Unsafe(0);
+
+ mDeactivatingEdges[0].forceSize_Unsafe(0);
+ mDeactivatingEdges[1].forceSize_Unsafe(0);
+ }
+
+ PX_FORCE_INLINE const Island& getIsland(IG::IslandId islandIndex) const { return mIslands[islandIndex]; }
+
+ PX_FORCE_INLINE PxU32 getNbActiveIslands() const { return mActiveIslands.size(); }
+ PX_FORCE_INLINE const IslandId* getActiveIslands() const { return mActiveIslands.begin(); }
+
+ PX_FORCE_INLINE PxU32 getNbDeactivatingEdges(const IG::Edge::EdgeType edgeType) const { return mDeactivatingEdges[edgeType].size(); }
+ PX_FORCE_INLINE const EdgeIndex* getDeactivatingEdges(const IG::Edge::EdgeType edgeType) const { return mDeactivatingEdges[edgeType].begin(); }
+
+ PX_FORCE_INLINE PxU32 getNbDestroyedEdges() const { return mDestroyedEdges.size(); }
+ PX_FORCE_INLINE const EdgeIndex* getDestroyedEdges() const { return mDestroyedEdges.begin(); }
+
+ PX_FORCE_INLINE PxU32 getNbDestroyedPartitionEdges() const { return mDestroyedPartitionEdges->size(); }
+ PX_FORCE_INLINE const PartitionEdge*const * getDestroyedPartitionEdges() const { return mDestroyedPartitionEdges->begin(); }
+ PX_FORCE_INLINE PartitionEdge** getDestroyedPartitionEdges() { return mDestroyedPartitionEdges->begin(); }
+
+ PX_FORCE_INLINE PxU32 getNbDirtyEdges(IG::Edge::EdgeType type) const { return mDirtyEdges[type].size(); }
+ PX_FORCE_INLINE const EdgeIndex* getDirtyEdges(IG::Edge::EdgeType type) const { return mDirtyEdges[type].begin(); }
+
+ PX_FORCE_INLINE const Edge& getEdge(const EdgeIndex edgeIndex) const { return mEdges[edgeIndex]; }
+
+ PX_FORCE_INLINE Edge& getEdge(const EdgeIndex edgeIndex) { return mEdges[edgeIndex]; }
+
+ PX_FORCE_INLINE const Node& getNode(const NodeIndex& nodeIndex) const { return mNodes[nodeIndex.index()]; }
+
+ PX_FORCE_INLINE const Island& getIsland(const NodeIndex& nodeIndex) const { PX_ASSERT(mIslandIds[nodeIndex.index()] != IG_INVALID_ISLAND); return mIslands[mIslandIds[nodeIndex.index()]]; }
+
+ PX_FORCE_INLINE PxU32 getIslandStaticTouchCount(const NodeIndex& nodeIndex) const { PX_ASSERT(mIslandIds[nodeIndex.index()] != IG_INVALID_ISLAND); return mIslandStaticTouchCount[mIslandIds[nodeIndex.index()]]; }
+
+ PX_FORCE_INLINE const Cm::BitMap& getActiveContactManagerBitmap() const { return mActiveContactEdges; }
+
+ PX_FORCE_INLINE PxU32 getActiveNodeIndex(const NodeIndex& nodeIndex) const { PxU32 activeNodeIndex = mActiveNodeIndex[nodeIndex.index()]; return activeNodeIndex;}
+
+ PX_FORCE_INLINE const PxU32* getActiveNodeIndex() const { return mActiveNodeIndex.begin(); }
+
+ PX_FORCE_INLINE PxU32 getNbActiveNodeIndex() const { return mActiveNodeIndex.size(); }
+
+ void setKinematic(IG::NodeIndex nodeIndex);
+
+ void setDynamic(IG::NodeIndex nodeIndex);
+
+ PX_FORCE_INLINE void setEdgeNodeIndexPtr(PxU32* ptr) { mNpIndexPtr = ptr; }
+
+ PX_FORCE_INLINE NodeIndex getNodeIndex1(IG::EdgeIndex index) const { return mEdgeNodeIndices[2 * index]; }
+ PX_FORCE_INLINE NodeIndex getNodeIndex2(IG::EdgeIndex index) const { return mEdgeNodeIndices[2 * index + 1]; }
+
+ PX_FORCE_INLINE PxU32* getEdgeNodeIndexPtr() const { return mNpIndexPtr; }
+ PX_FORCE_INLINE PxU64 getContextId() const { return mContextId; }
+
+ PxU32 getNbIslands() const { return mIslandStaticTouchCount.size(); }
+
+ const PxU32* getIslandStaticTouchCount() const { return mIslandStaticTouchCount.begin(); }
+
+ const PxU32* getIslandIds() const { return mIslandIds.begin(); }
+
+ bool checkInternalConsistency();
+
+private:
+
+ void insertNewEdges();
+ void removeDestroyedEdges();
+ void wakeIslands();
+ void wakeIslands2();
+ void processNewEdges();
+ void processLostEdges(Ps::Array<NodeIndex>& destroyedNodes, bool allowDeactivation, bool permitKinematicDeactivation, PxU32 dirtyNodeLimit);
+
+ void removeConnectionInternal(EdgeIndex edgeIndex);
+
+ void addConnection(NodeIndex nodeHandle1, NodeIndex nodeHandle2, Edge::EdgeType edgeType, EdgeIndex handle);
+
+ void addConnectionToGraph(EdgeIndex index);
+ void removeConnectionFromGraph(EdgeIndex edgeIndex);
+ void connectEdge(EdgeInstance& instance, EdgeInstanceIndex edgeIndex, Node& source, NodeIndex destination);
+ void disconnectEdge(EdgeInstance& instance, EdgeInstanceIndex edgeIndex, Node& node);
+
+ //Merges 2 islands together. The returned id is the id of the merged island
+ IslandId mergeIslands(IslandId island0, IslandId island1, NodeIndex node0, NodeIndex node1);
+
+ void mergeIslandsInternal(Island& island0, Island& island1, IslandId islandId0, IslandId islandId1, NodeIndex node0, NodeIndex node1);
+
+
+ IslandSim& operator = (const IslandSim&);
+ IslandSim(const IslandSim&);
+
+ void unwindRoute(PxU32 traversalIndex, NodeIndex lastNode, PxU32 hopCount, IslandId id);
+
+ void activateIsland(IslandId island);
+
+ void deactivateIsland(IslandId island);
+
+ bool canFindRoot(NodeIndex startNode, NodeIndex targetNode, Ps::Array<NodeIndex>* visitedNodes);
+
+ bool tryFastPath(NodeIndex startNode, NodeIndex targetNode, IslandId islandId);
+
+ bool findRoute(NodeIndex startNode, NodeIndex targetNode, IslandId islandId);
+
+ bool isPathTo(NodeIndex startNode, NodeIndex targetNode);
+
+ void addNode(bool isActive, bool isKinematic, Node::NodeType type, NodeIndex nodeIndex);
+
+ void activateNodeInternal(NodeIndex index);
+ void deactivateNodeInternal(NodeIndex index);
+
+ PX_FORCE_INLINE void notifyReadyForSleeping(const NodeIndex nodeIndex)
+ {
+ Node& node = mNodes[nodeIndex.index()];
+ //PX_ASSERT(node.isActive());
+ node.setIsReadyForSleeping();
+ }
+
+ PX_FORCE_INLINE void notifyNotReadyForSleeping(const NodeIndex nodeIndex)
+ {
+ Node& node = mNodes[nodeIndex.index()];
+ PX_ASSERT(node.isActive() || node.isActivating());
+ node.clearIsReadyForSleeping();
+ }
+
+ PX_FORCE_INLINE void markIslandActive(IslandId islandId)
+ {
+ Island& island = mIslands[islandId];
+ PX_ASSERT(!mIslandAwake.test(islandId));
+ PX_ASSERT(island.mActiveIndex == IG_INVALID_ISLAND);
+
+ mIslandAwake.set(islandId);
+ island.mActiveIndex = mActiveIslands.size();
+ mActiveIslands.pushBack(islandId);
+ }
+
+ PX_FORCE_INLINE void markIslandInactive(IslandId islandId)
+ {
+ Island& island = mIslands[islandId];
+ PX_ASSERT(mIslandAwake.test(islandId));
+ PX_ASSERT(island.mActiveIndex != IG_INVALID_ISLAND);
+ PX_ASSERT(mActiveIslands[island.mActiveIndex] == islandId);
+ IslandId replaceId = mActiveIslands[mActiveIslands.size()-1];
+ PX_ASSERT(mIslandAwake.test(replaceId));
+ Island& replaceIsland = mIslands[replaceId];
+ replaceIsland.mActiveIndex = island.mActiveIndex;
+ mActiveIslands[island.mActiveIndex] = replaceId;
+ mActiveIslands.forceSize_Unsafe(mActiveIslands.size()-1);
+ island.mActiveIndex = IG_INVALID_ISLAND;
+ mIslandAwake.reset(islandId);
+ }
+
+ PX_FORCE_INLINE void markKinematicActive(NodeIndex index)
+ {
+ Node& node = mNodes[index.index()];
+ PX_ASSERT(node.isKinematic());
+ if(node.mActiveRefCount == 0 && mActiveNodeIndex[index.index()] == IG_INVALID_NODE)
+ {
+ //PX_ASSERT(mActiveNodeIndex[index.index()] == IG_INVALID_NODE);
+ //node.mActiveNodeIndex = mActiveKinematicNodes.size();
+ mActiveNodeIndex[index.index()] = mActiveKinematicNodes.size();
+ mActiveKinematicNodes.pushBack(index);
+ }
+ }
+
+ PX_FORCE_INLINE void markKinematicInactive(NodeIndex index)
+ {
+ Node& node = mNodes[index.index()];
+ PX_ASSERT(node.isKinematic());
+ PX_ASSERT(mActiveNodeIndex[index.index()] != IG_INVALID_NODE);
+ PX_ASSERT(mActiveKinematicNodes[mActiveNodeIndex[index.index()]].index() == index.index());
+
+ if(node.mActiveRefCount == 0)
+ {
+ //Only remove from active kinematic list if it has no active contacts referencing it *and* it is asleep
+ if(mActiveNodeIndex[index.index()] != IG_INVALID_NODE)
+ {
+ //Need to verify active node index because there is an edge case where a node could be woken, then put to
+ //sleep in the same frame. This would mean that it would not have an active index at this stage.
+ NodeIndex replaceIndex = mActiveKinematicNodes.back();
+ PX_ASSERT(mActiveNodeIndex[replaceIndex.index()] == mActiveKinematicNodes.size()-1);
+ mActiveNodeIndex[replaceIndex.index()] = mActiveNodeIndex[index.index()];
+ mActiveKinematicNodes[mActiveNodeIndex[index.index()]] = replaceIndex;
+ mActiveKinematicNodes.forceSize_Unsafe(mActiveKinematicNodes.size()-1);
+ mActiveNodeIndex[index.index()] = IG_INVALID_NODE;
+ }
+ }
+ }
+
+ PX_FORCE_INLINE void markActive(NodeIndex index)
+ {
+ Node& node = mNodes[index.index()];
+ PX_ASSERT(!node.isKinematic());
+ PX_ASSERT(mActiveNodeIndex[index.index()] == IG_INVALID_NODE);
+ mActiveNodeIndex[index.index()] = mActiveNodes[node.mType].size();
+ mActiveNodes[node.mType].pushBack(index);
+ }
+
+ PX_FORCE_INLINE void markInactive(NodeIndex index)
+ {
+ Node& node = mNodes[index.index()];
+
+ PX_ASSERT(!node.isKinematic());
+ PX_ASSERT(mActiveNodeIndex[index.index()] != IG_INVALID_NODE);
+
+ Ps::Array<NodeIndex>& activeNodes = mActiveNodes[node.mType];
+
+ PX_ASSERT(activeNodes[mActiveNodeIndex[index.index()]].index() == index.index());
+ const PxU32 initialActiveNodeCount = mInitialActiveNodeCount[node.mType];
+
+ if(mActiveNodeIndex[index.index()] < initialActiveNodeCount)
+ {
+ //It's in the initial active node set. We retain a list of active nodes, where the existing active nodes
+ //are at the beginning of the array and the newly activated nodes are at the end of the array...
+ //The solution is to move the node to the end of the initial active node list in this case
+ PxU32 activeNodeIndex = mActiveNodeIndex[index.index()];
+ NodeIndex replaceIndex = activeNodes[initialActiveNodeCount-1];
+ PX_ASSERT(mActiveNodeIndex[replaceIndex.index()] == initialActiveNodeCount-1);
+ mActiveNodeIndex[index.index()] = mActiveNodeIndex[replaceIndex.index()];
+ mActiveNodeIndex[replaceIndex.index()] = activeNodeIndex;
+ activeNodes[activeNodeIndex] = replaceIndex;
+ activeNodes[mActiveNodeIndex[index.index()]] = index;
+ mInitialActiveNodeCount[node.mType]--;
+ }
+
+ PX_ASSERT(!node.isKinematic());
+ PX_ASSERT(mActiveNodeIndex[index.index()] != IG_INVALID_NODE);
+ PX_ASSERT(activeNodes[mActiveNodeIndex[index.index()]].index() == index.index());
+
+ NodeIndex replaceIndex = activeNodes.back();
+ PX_ASSERT(mActiveNodeIndex[replaceIndex.index()] == activeNodes.size()-1);
+ mActiveNodeIndex[replaceIndex.index()] = mActiveNodeIndex[index.index()];
+ activeNodes[mActiveNodeIndex[index.index()]] = replaceIndex;
+ activeNodes.forceSize_Unsafe(activeNodes.size()-1);
+ mActiveNodeIndex[index.index()] = IG_INVALID_NODE;
+ }
+
+ PX_FORCE_INLINE void markEdgeActive(EdgeIndex index)
+ {
+ Edge& edge = mEdges[index];
+
+ PX_ASSERT((edge.mEdgeState & Edge::eACTIVATING) == 0);
+
+ edge.mEdgeState |= Edge::eACTIVATING;
+
+ mActivatedEdges[edge.mEdgeType].pushBack(index);
+
+ mActiveEdgeCount[edge.mEdgeType]++;
+
+ //Set the active bit...
+ if(edge.mEdgeType == Edge::eCONTACT_MANAGER)
+ mActiveContactEdges.set(index);
+
+ NodeIndex nodeIndex1 = mEdgeNodeIndices[2 * index];
+ NodeIndex nodeIndex2 = mEdgeNodeIndices[2 * index + 1];
+
+ if (nodeIndex1.index() != IG_INVALID_NODE && nodeIndex2.index() != IG_INVALID_NODE)
+ {
+ PX_ASSERT((!mNodes[nodeIndex1.index()].isKinematic()) || (!mNodes[nodeIndex2.index()].isKinematic()) || edge.getEdgeType() == IG::Edge::eCONTACT_MANAGER);
+ {
+ Node& node = mNodes[nodeIndex1.index()];
+
+ if(node.mActiveRefCount == 0 && node.isKinematic() && !(node.isActive() || node.isActivating()))
+ {
+ //Add to active kinematic list
+ markKinematicActive(nodeIndex1);
+ }
+ node.mActiveRefCount++;
+ }
+
+ {
+ Node& node = mNodes[nodeIndex2.index()];
+ if(node.mActiveRefCount == 0 && node.isKinematic() && !(node.isActive() || node.isActivating()))
+ {
+ //Add to active kinematic list
+ markKinematicActive(nodeIndex2);
+ }
+ node.mActiveRefCount++;
+ }
+ }
+
+ }
+
+ void removeEdgeFromActivatingList(EdgeIndex index);
+
+ PX_FORCE_INLINE void removeEdgeFromIsland(Island& island, EdgeIndex edgeIndex)
+ {
+ Edge& edge = mEdges[edgeIndex];
+ if(edge.mNextIslandEdge != IG_INVALID_EDGE)
+ {
+ PX_ASSERT(mEdges[edge.mNextIslandEdge].mPrevIslandEdge == edgeIndex);
+ mEdges[edge.mNextIslandEdge].mPrevIslandEdge = edge.mPrevIslandEdge;
+ }
+ else
+ {
+ PX_ASSERT(island.mLastEdge[edge.mEdgeType] == edgeIndex);
+ island.mLastEdge[edge.mEdgeType] = edge.mPrevIslandEdge;
+ }
+
+ if(edge.mPrevIslandEdge != IG_INVALID_EDGE)
+ {
+ PX_ASSERT(mEdges[edge.mPrevIslandEdge].mNextIslandEdge == edgeIndex);
+ mEdges[edge.mPrevIslandEdge].mNextIslandEdge = edge.mNextIslandEdge;
+ }
+ else
+ {
+ PX_ASSERT(island.mFirstEdge[edge.mEdgeType] == edgeIndex);
+ island.mFirstEdge[edge.mEdgeType] = edge.mNextIslandEdge;
+ }
+
+ island.mEdgeCount[edge.mEdgeType]--;
+ edge.mNextIslandEdge = edge.mPrevIslandEdge = IG_INVALID_EDGE;
+ }
+
+ PX_FORCE_INLINE void addEdgeToIsland(Island& island, EdgeIndex edgeIndex)
+ {
+ Edge& edge = mEdges[edgeIndex];
+ PX_ASSERT(edge.mNextIslandEdge == IG_INVALID_EDGE && edge.mPrevIslandEdge == IG_INVALID_EDGE);
+
+ if(island.mLastEdge[edge.mEdgeType] != IG_INVALID_EDGE)
+ {
+ PX_ASSERT(mEdges[island.mLastEdge[edge.mEdgeType]].mNextIslandEdge == IG_INVALID_EDGE);
+ mEdges[island.mLastEdge[edge.mEdgeType]].mNextIslandEdge = edgeIndex;
+ }
+ else
+ {
+ PX_ASSERT(island.mFirstEdge[edge.mEdgeType] == IG_INVALID_EDGE);
+ island.mFirstEdge[edge.mEdgeType] = edgeIndex;
+ }
+
+ edge.mPrevIslandEdge = island.mLastEdge[edge.mEdgeType];
+ island.mLastEdge[edge.mEdgeType] = edgeIndex;
+ island.mEdgeCount[edge.mEdgeType]++;
+ }
+
+ PX_FORCE_INLINE void removeNodeFromIsland(Island& island, NodeIndex nodeIndex)
+ {
+ Node& node = mNodes[nodeIndex.index()];
+ if(node.mNextNode.isValid())
+ {
+ PX_ASSERT(mNodes[node.mNextNode.index()].mPrevNode.index() == nodeIndex.index());
+ mNodes[node.mNextNode.index()].mPrevNode = node.mPrevNode;
+ }
+ else
+ {
+ PX_ASSERT(island.mLastNode.index() == nodeIndex.index());
+ island.mLastNode = node.mPrevNode;
+ }
+
+ if(node.mPrevNode.isValid())
+ {
+ PX_ASSERT(mNodes[node.mPrevNode.index()].mNextNode.index() == nodeIndex.index());
+ mNodes[node.mPrevNode.index()].mNextNode = node.mNextNode;
+ }
+ else
+ {
+ PX_ASSERT(island.mRootNode.index() == nodeIndex.index());
+ island.mRootNode = node.mNextNode;
+ }
+
+ island.mSize[node.mType]--;
+
+ node.mNextNode = NodeIndex(); node.mPrevNode = NodeIndex();
+ }
+
+ //void setEdgeConnectedInternal(EdgeIndex edgeIndex);
+
+ //void setEdgeDisconnectedInternal(EdgeIndex edgeIndex);
+
+ friend class SimpleIslandManager;
+ friend class ThirdPassTask;
+
+};
+
+
+}
+
+
+struct PartitionIndexData
+{
+ PxU16 mPartitionIndex; //! The current partition this edge is in. Used to find the edge efficiently. PxU8 is probably too small (256 partitions max) but PxU16 should be more than enough
+ PxU8 mPatchIndex; //! The patch index for this partition edge. There may be multiple entries for a given edge if there are multiple patches.
+ PxU8 mType; //! The type of constraint this is
+ PxU32 mPartitionEntryIndex; //! index of partition edges for this partition
+};
+
+struct PartitionNodeData
+{
+ PxU32 mNodeIndex0;
+ PxU32 mNodeIndex1;
+ PxU32 mNextIndex0;
+ PxU32 mNextIndex1;
+};
+
+
+#define INVALID_PARTITION_INDEX 0xFFFF
+
+struct PartitionEdge
+{
+ IG::EdgeIndex mEdgeIndex; //! The edge index into the island manager. Used to identify the contact manager/constraint
+ IG::NodeIndex mNode0; //! The node index for node 0. Can be obtained from the edge index alternatively
+ IG::NodeIndex mNode1; //! The node idnex for node 1. Can be obtained from the edge index alternatively
+ bool mInfiniteMass0; //! Whether body 0 is kinematic
+ bool mInfiniteMass1; //! Whether body 1 is kinematic
+
+ PartitionEdge* mNextPatch; //! for the contact manager has more than 1 patch, we have next patch's edge and previous patch's edge to connect to this edge
+
+ PxU32 mUniqueIndex; //! a unique ID for this edge
+
+ PartitionEdge() : mEdgeIndex(IG_INVALID_EDGE), mInfiniteMass0(false),
+ mInfiniteMass1(false), mNextPatch(NULL)
+ {
+ }
+};
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxsKernelWrangler.h b/PhysX_3.4/Source/LowLevel/software/include/PxsKernelWrangler.h
new file mode 100644
index 00000000..494ab4f7
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxsKernelWrangler.h
@@ -0,0 +1,50 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXS_KERNEL_WRANGLER_H
+#define PXS_KERNEL_WRANGLER_H
+
+#include "DyGpuAPI.h"
+#include "foundation/PxSimpleTypes.h"
+
+namespace physx
+{
+ class KernelWrangler;
+ class PxGpuDispatcher;
+ class PxErrorCallback;
+
+ class PxsKernelWranglerManager
+ {
+ public:
+ virtual ~PxsKernelWranglerManager(){}
+ virtual KernelWrangler* getKernelWrangler() = 0;
+ };
+}
+#endif \ No newline at end of file
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxsMaterialCombiner.h b/PhysX_3.4/Source/LowLevel/software/include/PxsMaterialCombiner.h
new file mode 100644
index 00000000..4f6a3dfc
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxsMaterialCombiner.h
@@ -0,0 +1,143 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXS_MATERIALCOMBINER_H
+#define PXS_MATERIALCOMBINER_H
+
+#include "PxsMaterialCore.h"
+
+namespace physx
+{
+
+ class PxsMaterialCombiner
+ {
+ public:
+
+ class PxsCombinedMaterial
+ {
+ public:
+ PxReal staFriction;
+ PxReal dynFriction;
+ PxU32 flags; //PxMaterialFlag::eDISABLE_FRICTION, PxMaterialFlag::eDISABLE_STRONG_FRICTION.
+ };
+
+ static PxReal combineRestitution(const PxsMaterialData& material0, const PxsMaterialData& material1);
+
+ PxsMaterialCombiner(PxReal staticFrictionScaling, PxReal dynamicFrictionScaling);
+
+ PxsCombinedMaterial combineIsotropicFriction(const PxsMaterialData& material0, const PxsMaterialData& material1);
+
+ //ML:: move this function to header file to avoid LHS in Xbox
+ PX_FORCE_INLINE void combineIsotropicFriction(const PxsMaterialData& mat0, const PxsMaterialData& mat1, PxReal& dynamicFriction, PxReal& staticFriction, PxU32& flags)
+ {
+
+ const PxU32 combineFlags= (mat0.flags | mat1.flags); //& (PxMaterialFlag::eDISABLE_STRONG_FRICTION|PxMaterialFlag::eDISABLE_FRICTION); //eventually set DisStrongFric flag, lower all others.
+
+ if (!(combineFlags & PxMaterialFlag::eDISABLE_FRICTION))
+ {
+ const PxI32 fictionCombineMode = PxMax(mat0.getFrictionCombineMode(), mat1.getFrictionCombineMode());
+ PxReal dynFriction = 0.f;
+ PxReal staFriction = 0.f;
+
+
+ switch (fictionCombineMode)
+ {
+ case PxCombineMode::eAVERAGE:
+ dynFriction = 0.5f * (mat0.dynamicFriction + mat1.dynamicFriction);
+ staFriction = 0.5f * (mat0.staticFriction + mat1.staticFriction);
+ break;
+ case PxCombineMode::eMIN:
+ dynFriction = PxMin(mat0.dynamicFriction, mat1.dynamicFriction);
+ staFriction = PxMin(mat0.staticFriction, mat1.staticFriction);
+ break;
+ case PxCombineMode::eMULTIPLY:
+ dynFriction = (mat0.dynamicFriction * mat1.dynamicFriction);
+ staFriction = (mat0.staticFriction * mat1.staticFriction);
+ break;
+ case PxCombineMode::eMAX:
+ dynFriction = PxMax(mat0.dynamicFriction, mat1.dynamicFriction);
+ staFriction = PxMax(mat0.staticFriction, mat1.staticFriction);
+ break;
+ }
+
+ dynFriction*=mDynamicFrictionScaling;
+ staFriction*=mStaticFrictionScaling;
+ //isotropic case
+ const PxReal fDynFriction = PxMax(dynFriction, 0.f);
+
+ const PxReal fStaFriction = physx::intrinsics::fsel(staFriction - fDynFriction, staFriction*mStaticFrictionScaling, fDynFriction);
+ /*dest.dynFriction = fDynFriction;
+ dest.staFriction = fStaFriction;*/
+
+ dynamicFriction = fDynFriction;
+ staticFriction = fStaFriction;
+ flags = combineFlags;
+ }
+ else
+ {
+ /* dest.flags |= PxMaterialFlag::eDISABLE_STRONG_FRICTION;
+ dest.staFriction = 0.0f;
+ dest.dynFriction = 0.0f;*/
+ flags = (combineFlags | PxMaterialFlag::eDISABLE_STRONG_FRICTION);
+ dynamicFriction = 0.f;
+ staticFriction = 0.f;
+ }
+
+ }
+
+
+ //private:
+ protected:
+ static PX_FORCE_INLINE PxReal combineScalars(PxReal a, PxReal b, PxI32 nxCombineMode)
+ {
+ switch (nxCombineMode)
+ {
+ case PxCombineMode::eAVERAGE:
+ return 0.5f * (a + b);
+ case PxCombineMode::eMIN:
+ return PxMin(a,b);
+ case PxCombineMode::eMULTIPLY:
+ return a * b;
+ case PxCombineMode::eMAX:
+ return PxMax(a,b);
+ default:
+ /* Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__,
+ "Sc::MaterialCombiner::combineScalars(): unknown combine mode");*/
+ return PxReal(0);
+ }
+ }
+
+ PxReal mStaticFrictionScaling, mDynamicFrictionScaling;
+
+ };
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxsMemoryManager.h b/PhysX_3.4/Source/LowLevel/software/include/PxsMemoryManager.h
new file mode 100644
index 00000000..1f5193dd
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxsMemoryManager.h
@@ -0,0 +1,62 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXS_MEMORY_MANAGER_H
+#define PXS_MEMORY_MANAGER_H
+
+#include "foundation/PxPreprocessor.h"
+#include "foundation/PxSimpleTypes.h"
+#include "DyGpuAPI.h"
+#include "CmPhysXCommon.h"
+
+namespace physx
+{
+ namespace shdfnd
+ {
+ class VirtualAllocatorCallback;
+ }
+
+ class PxGpuDispatcher;
+
+ class PxsMemoryManager
+ {
+ public:
+ virtual ~PxsMemoryManager(){}
+ virtual Ps::VirtualAllocatorCallback* createHostMemoryAllocator(const PxU32 gpuComputeVersion = 0) = 0;
+ virtual Ps::VirtualAllocatorCallback* createDeviceMemoryAllocator(const PxU32 gpuComputeVersion = 0) = 0;
+
+ virtual void destroyMemoryAllocator() = 0;
+
+ };
+
+ PxsMemoryManager* createMemoryManager();
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxsNphaseImplementationContext.h b/PhysX_3.4/Source/LowLevel/software/include/PxsNphaseImplementationContext.h
new file mode 100644
index 00000000..e6d9b8e9
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxsNphaseImplementationContext.h
@@ -0,0 +1,142 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXS_NPHASE_IMPLEMENTATION_CONTEXT_H
+#define PXS_NPHASE_IMPLEMENTATION_CONTEXT_H
+
+#include "PxvNphaseImplementationContext.h"
+#include "PxsContactManagerState.h"
+#include "PxcNpCache.h"
+
+namespace physx
+{
+
+struct PxsContactManagers : PxsContactManagerBase
+{
+ Ps::Array<PxsContactManagerOutput> mOutputContactManagers;
+ Ps::Array<PxsContactManager*> mContactManagerMapping;
+ Ps::Array<Gu::Cache> mCaches;
+
+
+ PxsContactManagers(const PxU32 bucketId) : PxsContactManagerBase(bucketId),
+ mOutputContactManagers(PX_DEBUG_EXP("mOutputContactManagers")),
+ mContactManagerMapping(PX_DEBUG_EXP("mContactManagerMapping")),
+ mCaches(PX_DEBUG_EXP("mCaches"))
+ {
+ }
+
+ void clear()
+ {
+ mOutputContactManagers.forceSize_Unsafe(0);
+ mContactManagerMapping.forceSize_Unsafe(0);
+ mCaches.forceSize_Unsafe(0);
+
+ }
+private:
+ PX_NOCOPY(PxsContactManagers)
+};
+
+
+class PxsNphaseImplementationContext: public PxvNphaseImplementationContextUsableAsFallback
+{
+public:
+ static PxsNphaseImplementationContext* create(PxsContext& context, IG::IslandSim* islandSim);
+
+ PxsNphaseImplementationContext(PxsContext& context, IG::IslandSim* islandSim, PxU32 index = 0): PxvNphaseImplementationContextUsableAsFallback(context), mNarrowPhasePairs(index), mNewNarrowPhasePairs(index),
+ mModifyCallback(NULL), mIslandSim(islandSim) {}
+ virtual void destroy();
+ virtual void updateContactManager(PxReal dt, bool hasBoundsArrayChanged, bool hasContactDistanceChanged, PxBaseTask* continuation, PxBaseTask* firstPassContinuation);
+ virtual void secondPassUpdateContactManager(PxReal dt, PxBaseTask* continuation);
+
+ virtual void registerContactManager(PxsContactManager* cm, PxI32 touching, PxU32 numPatches);
+ virtual void registerContactManagers(PxsContactManager** cm, PxU32 nbContactManagers, PxU32 maxContactManagerId);
+ virtual void unregisterContactManager(PxsContactManager* cm);
+ virtual void unregisterContactManagerFallback(PxsContactManager* cm, PxsContactManagerOutput* cmOutputs);
+
+
+ virtual void refreshContactManager(PxsContactManager* cm);
+ virtual void refreshContactManagerFallback(PxsContactManager* cm, PxsContactManagerOutput* cmOutputs);
+
+ virtual void registerShape(const PxsShapeCore& shapeCore);
+
+ virtual void updateShapeMaterial(const PxsShapeCore& shapeCore);
+ virtual void updateShapeContactOffset(const PxsShapeCore& shapeCore);
+
+ virtual void unregisterShape(const PxsShapeCore& shapeCore);
+
+ virtual void registerMaterial(const PxsMaterialCore& materialCore);
+ virtual void updateMaterial(const PxsMaterialCore& materialCore);
+ virtual void unregisterMaterial(const PxsMaterialCore& materialCore);
+
+ virtual void appendContactManagers();
+ virtual void appendContactManagersFallback(PxsContactManagerOutput* cmOutputs);
+
+ virtual void removeContactManagersFallback(PxsContactManagerOutput* cmOutputs);
+
+ virtual void setContactModifyCallback(PxContactModifyCallback* callback) { mModifyCallback = callback; }
+
+ virtual PxsContactManagerOutputIterator getContactManagerOutputs();
+
+ virtual PxsContactManagerOutput& getNewContactManagerOutput(PxU32 npIndex);
+
+ virtual PxsContactManagerOutput* getGPUContactManagerOutputBase() { return NULL; }
+
+ virtual void acquireContext(){}
+ virtual void releaseContext(){}
+ virtual void preallocateNewBuffers(PxU32 /*nbNewPairs*/, PxU32 /*maxIndex*/) { /*TODO - implement if it's useful to do so*/}
+
+ void processContactManager(PxReal dt, PxsContactManagerOutput* cmOutputs, PxBaseTask* continuation);
+ void processContactManagerSecondPass(PxReal dt, PxBaseTask* continuation);
+ void fetchUpdateContactManager() {}
+
+
+
+ void startNarrowPhaseTasks() {}
+
+
+
+ Ps::Array<PxU32> mRemovedContactManagers;
+ PxsContactManagers mNarrowPhasePairs;
+ PxsContactManagers mNewNarrowPhasePairs;
+
+ PxContactModifyCallback* mModifyCallback;
+
+ IG::IslandSim* mIslandSim;
+
+private:
+
+ void unregisterContactManagerInternal(PxU32 npIndex, PxsContactManagers& managers, PxsContactManagerOutput* cmOutputs);
+
+ PX_NOCOPY(PxsNphaseImplementationContext)
+};
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxsRigidBody.h b/PhysX_3.4/Source/LowLevel/software/include/PxsRigidBody.h
new file mode 100644
index 00000000..0bbfc8ec
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxsRigidBody.h
@@ -0,0 +1,168 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXS_BODYATOM_H
+#define PXS_BODYATOM_H
+
+#include "PxcRigidBody.h"
+#include "PxvDynamics.h"
+
+namespace physx
+{
+
+class PxsRigidBody : public PxcRigidBody
+{
+ public:
+ PX_FORCE_INLINE PxsRigidBody(PxsBodyCore* core) : PxcRigidBody(core) { }
+ PX_FORCE_INLINE ~PxsRigidBody() {}
+
+ PX_FORCE_INLINE const PxTransform& getPose() const { PX_ASSERT(mCore->body2World.isSane()); return mCore->body2World; }
+
+ //PX_FORCE_INLINE const Cm::SpatialVector& getAccelerationV() const { return mAcceleration; }
+ //PX_FORCE_INLINE void setAccelerationV(const Cm::SpatialVector& v) { mAcceleration = v; }
+
+ PX_FORCE_INLINE const PxVec3& getLinearVelocity() const { PX_ASSERT(mCore->linearVelocity.isFinite()); return mCore->linearVelocity; }
+ PX_FORCE_INLINE const PxVec3& getAngularVelocity() const { PX_ASSERT(mCore->angularVelocity.isFinite()); return mCore->angularVelocity; }
+
+ PX_FORCE_INLINE void setVelocity(const PxVec3& linear,
+ const PxVec3& angular) { PX_ASSERT(linear.isFinite()); PX_ASSERT(angular.isFinite());
+ mCore->linearVelocity = linear;
+ mCore->angularVelocity = angular; }
+ PX_FORCE_INLINE void setLinearVelocity(const PxVec3& linear) { PX_ASSERT(linear.isFinite()); mCore->linearVelocity = linear; }
+ PX_FORCE_INLINE void setAngularVelocity(const PxVec3& angular) { PX_ASSERT(angular.isFinite()); mCore->angularVelocity = angular; }
+
+ PX_FORCE_INLINE void constrainLinearVelocity();
+ PX_FORCE_INLINE void constrainAngularVelocity();
+
+ PX_FORCE_INLINE PxU32 getIterationCounts() { return mCore->solverIterationCounts; }
+
+ PX_FORCE_INLINE PxReal getReportThreshold() const { return mCore->contactReportThreshold; }
+
+ // AP newccd todo: merge into get both velocities, compute inverse transform once, precompute mLastTransform.getInverse()
+ PX_FORCE_INLINE PxVec3 getLinearMotionVelocity(PxReal invDt) const {
+ // delta(t0(x))=t1(x)
+ // delta(t0(t0`(x)))=t1(t0`(x))
+ // delta(x)=t1(t0`(x))
+ PxVec3 deltaP = mCore->body2World.p - getLastCCDTransform().p;
+ return deltaP * invDt;
+ }
+ PX_FORCE_INLINE PxVec3 getAngularMotionVelocity(PxReal invDt) const {
+ PxQuat deltaQ = mCore->body2World.q * getLastCCDTransform().q.getConjugate();
+ PxVec3 axis;
+ PxReal angle;
+ deltaQ.toRadiansAndUnitAxis(angle, axis);
+ return axis * angle * invDt;
+ }
+ PX_FORCE_INLINE PxVec3 getLinearMotionVelocity(PxReal dt, const PxsBodyCore* PX_RESTRICT bodyCore) const {
+ // delta(t0(x))=t1(x)
+ // delta(t0(t0`(x)))=t1(t0`(x))
+ // delta(x)=t1(t0`(x))
+ PxVec3 deltaP = bodyCore->body2World.p - getLastCCDTransform().p;
+ return deltaP * 1.0f / dt;
+ }
+ PX_FORCE_INLINE PxVec3 getAngularMotionVelocity(PxReal dt, const PxsBodyCore* PX_RESTRICT bodyCore) const {
+ PxQuat deltaQ = bodyCore->body2World.q * getLastCCDTransform().q.getConjugate();
+ PxVec3 axis;
+ PxReal angle;
+ deltaQ.toRadiansAndUnitAxis(angle, axis);
+ return axis * angle * 1.0f/dt;
+ }
+
+ PX_FORCE_INLINE PxTransform getLastCCDTransform() const { return mLastTransform; }
+ PX_FORCE_INLINE void saveLastCCDTransform() { mLastTransform = mCore->body2World; }
+
+ PX_FORCE_INLINE bool isKinematic() const { return (mCore->inverseMass == 0.0f); }
+
+ PX_FORCE_INLINE void setPose(const PxTransform& pose) { mCore->body2World = pose; }
+ PX_FORCE_INLINE void setPosition(const PxVec3& position) { mCore->body2World.p = position; }
+ PX_FORCE_INLINE PxReal getInvMass() const { return mCore->inverseMass; }
+ PX_FORCE_INLINE PxVec3 getInvInertia() const { return mCore->inverseInertia; }
+ PX_FORCE_INLINE PxReal getMass() const { return 1.0f/mCore->inverseMass; }
+ PX_FORCE_INLINE PxVec3 getInertia() const { return PxVec3(1.0f/mCore->inverseInertia.x,
+ 1.0f/mCore->inverseInertia.y,
+ 1.0f/mCore->inverseInertia.z); }
+ PX_FORCE_INLINE PxsBodyCore& getCore() { return *mCore; }
+ PX_FORCE_INLINE const PxsBodyCore& getCore() const { return *mCore; }
+
+ PX_FORCE_INLINE PxU32 isActivateThisFrame() const { return PxU32(mInternalFlags & eACTIVATE_THIS_FRAME); }
+
+ PX_FORCE_INLINE PxU32 isDeactivateThisFrame() const { return PxU32(mInternalFlags & eDEACTIVATE_THIS_FRAME); }
+
+ PX_FORCE_INLINE PxU32 isFreezeThisFrame() const { return PxU32(mInternalFlags & eFREEZE_THIS_FRAME); }
+
+ PX_FORCE_INLINE PxU32 isUnfreezeThisFrame() const { return PxU32(mInternalFlags & eUNFREEZE_THIS_FRAME); }
+
+ PX_FORCE_INLINE void clearFreezeFlag() { mInternalFlags &= ~eFREEZE_THIS_FRAME; }
+
+ PX_FORCE_INLINE void clearUnfreezeFlag() { mInternalFlags &= ~eUNFREEZE_THIS_FRAME; }
+
+ PX_FORCE_INLINE void clearAllFrameFlags() { mInternalFlags &= (eFROZEN | eDISABLE_GRAVITY); }
+
+ void advanceToToi(PxReal toi, PxReal dt, bool clip);
+ void advancePrevPoseToToi(PxReal toi);
+ PxTransform getAdvancedTransform(PxReal toi) const;
+ Cm::SpatialVector getPreSolverVelocities() const;
+
+
+};
+
+void PxsRigidBody::constrainLinearVelocity()
+{
+ const PxU32 lockFlags = mCore->lockFlags;
+
+ if (lockFlags)
+ {
+ if (lockFlags & PxRigidDynamicLockFlag::eLOCK_LINEAR_X)
+ mCore->linearVelocity.x = 0.f;
+ if (lockFlags & PxRigidDynamicLockFlag::eLOCK_LINEAR_Y)
+ mCore->linearVelocity.y = 0.f;
+ if (lockFlags & PxRigidDynamicLockFlag::eLOCK_LINEAR_Z)
+ mCore->linearVelocity.z = 0.f;
+ }
+}
+
+void PxsRigidBody::constrainAngularVelocity()
+{
+ const PxU32 lockFlags = mCore->lockFlags;
+
+ if (lockFlags)
+ {
+ if (lockFlags & PxRigidDynamicLockFlag::eLOCK_ANGULAR_X)
+ mCore->angularVelocity.x = 0.f;
+ if (lockFlags & PxRigidDynamicLockFlag::eLOCK_ANGULAR_Y)
+ mCore->angularVelocity.y = 0.f;
+ if (lockFlags & PxRigidDynamicLockFlag::eLOCK_ANGULAR_Z)
+ mCore->angularVelocity.z = 0.f;
+ }
+}
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxsShapeSim.h b/PhysX_3.4/Source/LowLevel/software/include/PxsShapeSim.h
new file mode 100644
index 00000000..0bf63f2e
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxsShapeSim.h
@@ -0,0 +1,52 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef PXS_SHAPESIM_H
+#define PXS_SHAPESIM_H
+
+#include "PxsBodySim.h"
+
+namespace physx
+{
+
+//PxsBodySim is 12 or 16 bytes
+struct PxsShapeSim// : public PxsBodySim
+{
+ PxsShapeCore* mShapeCore; // 4 or 8
+ PxU32 mBodySimIndex; // 8 or 12
+ PxU32 mElementIndex; // 12 or 16 transform cache and bound index
+ PxU32 mShapeIndex; // 16 or 20
+#if PX_P64_FAMILY
+ PxU32 mPad[3];
+#endif
+};
+
+}//physx
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxsSimpleIslandManager.h b/PhysX_3.4/Source/LowLevel/software/include/PxsSimpleIslandManager.h
new file mode 100644
index 00000000..50291b8f
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxsSimpleIslandManager.h
@@ -0,0 +1,207 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef PXS_SIMPLE_ISLAND_GEN_H
+#define PXS_SIMPLE_ISLAND_GEN_H
+
+#include "PxsIslandSim.h"
+#include "CmTask.h"
+
+namespace physx
+{
+
+namespace Sc
+{
+ class Interaction;
+}
+namespace IG
+{
+
+ class SimpleIslandManager;
+
+class ThirdPassTask : public Cm::Task
+{
+ SimpleIslandManager& mIslandManager;
+ IslandSim& mIslandSim;
+
+public:
+
+ ThirdPassTask(SimpleIslandManager& islandManager, IslandSim& islandSim) : mIslandManager(islandManager), mIslandSim(islandSim)
+ {
+ }
+
+ virtual void runInternal();
+
+ virtual const char* getName() const
+ {
+ return "ThirdPassIslandGenTask";
+ }
+
+private:
+ PX_NOCOPY(ThirdPassTask)
+};
+
+class PostThirdPassTask : public Cm::Task
+{
+ SimpleIslandManager& mIslandManager;
+
+public:
+
+ PostThirdPassTask(SimpleIslandManager& islandManager) : mIslandManager(islandManager)
+ {
+ }
+
+ virtual void runInternal();
+
+ virtual const char* getName() const
+ {
+ return "PostThirdPassTask";
+ }
+private:
+ PX_NOCOPY(PostThirdPassTask)
+};
+
+class SimpleIslandManager
+{
+
+ HandleManager<PxU32> mNodeHandles; //! Handle manager for nodes
+ HandleManager<EdgeIndex> mEdgeHandles; //! Handle manager for edges
+
+ //An array of destroyed nodes
+ Ps::Array<NodeIndex> mDestroyedNodes;
+ Ps::Array<Sc::Interaction*> mInteractions;
+
+
+ //Edges destroyed this frame
+ Ps::Array<EdgeIndex> mDestroyedEdges;
+ Ps::Array<PartitionEdge*> mFirstPartitionEdges;
+ Ps::Array<PartitionEdge*> mDestroyedPartitionEdges;
+ //KS - stores node indices for a given edge. Node index 0 is at 2* edgeId and NodeIndex1 is at 2*edgeId + 1
+ //can also be used for edgeInstance indexing so there's no need to figure out outboundNode ID either!
+ Ps::Array<NodeIndex> mEdgeNodeIndices;
+
+ Ps::Array<ConstraintOrContactManager> mConstraintOrCm; //! Pointers to either the constraint or Cm for this pair
+
+ Cm::BitMap mConnectedMap;
+
+ IslandSim mIslandManager;
+ IslandSim mSpeculativeIslandManager;
+
+ ThirdPassTask mSpeculativeThirdPassTask;
+ ThirdPassTask mAccurateThirdPassTask;
+
+ PostThirdPassTask mPostThirdPassTask;
+ PxU32 mMaxDirtyNodesPerFrame;
+
+ PxU64 mContextID;
+public:
+
+ SimpleIslandManager(bool useEnhancedDeterminism, PxU64 contextID);
+
+ ~SimpleIslandManager();
+
+ NodeIndex addRigidBody(PxsRigidBody* body, bool isKinematic, bool isActive);
+
+ void removeNode(const NodeIndex index);
+
+ NodeIndex addArticulation(Sc::ArticulationSim* articulation, Dy::Articulation* llArtic, bool isActive);
+
+ EdgeIndex addContactManager(PxsContactManager* manager, NodeIndex nodeHandle1, NodeIndex nodeHandle2, Sc::Interaction* interaction);
+
+ EdgeIndex addConstraint(Dy::Constraint* constraint, NodeIndex nodeHandle1, NodeIndex nodeHandle2, Sc::Interaction* interaction);
+
+ bool isConnected(EdgeIndex edgeIndex) const { return !!mConnectedMap.test(edgeIndex); }
+
+ PX_FORCE_INLINE NodeIndex getEdgeIndex(EdgeInstanceIndex edgeIndex) const { return mEdgeNodeIndices[edgeIndex]; }
+
+ void activateNode(NodeIndex index);
+ void deactivateNode(NodeIndex index);
+ void putNodeToSleep(NodeIndex index);
+
+ void removeConnection(EdgeIndex edgeIndex);
+
+ void firstPassIslandGen();
+ void additionalSpeculativeActivation();
+ void secondPassIslandGen();
+ void thirdPassIslandGen(PxBaseTask* continuation);
+
+ void clearDestroyedEdges();
+
+ void setEdgeConnected(EdgeIndex edgeIndex);
+ void setEdgeDisconnected(EdgeIndex edgeIndex);
+
+ bool getIsEdgeConnected(EdgeIndex edgeIndex);
+
+ void setEdgeRigidCM(const EdgeIndex edgeIndex, PxsContactManager* cm);
+
+ void clearEdgeRigidCM(const EdgeIndex edgeIndex);
+
+ void setKinematic(IG::NodeIndex nodeIndex);
+
+ void setDynamic(IG::NodeIndex nodeIndex);
+
+ const IslandSim& getSpeculativeIslandSim() const { return mSpeculativeIslandManager; }
+ const IslandSim& getAccurateIslandSim() const { return mIslandManager; }
+
+ IslandSim& getAccurateIslandSim() { return mIslandManager; }
+
+ PX_FORCE_INLINE PxU32 getNbEdgeHandles() const { return mEdgeHandles.getTotalHandles(); }
+
+ PX_FORCE_INLINE PxU32 getNbNodeHandles() const { return mNodeHandles.getTotalHandles(); }
+
+ void deactivateEdge(const EdgeIndex edge);
+
+ PX_FORCE_INLINE PxsContactManager* getContactManager(IG::EdgeIndex edgeId) const { return mConstraintOrCm[edgeId].mCm; }
+ PX_FORCE_INLINE PxsContactManager* getContactManagerUnsafe(IG::EdgeIndex edgeId) const { return mConstraintOrCm[edgeId].mCm; }
+ PX_FORCE_INLINE Dy::Constraint* getConstraint(IG::EdgeIndex edgeId) const { return mConstraintOrCm[edgeId].mConstraint; }
+ PX_FORCE_INLINE Dy::Constraint* getConstraintUnsafe(IG::EdgeIndex edgeId) const { return mConstraintOrCm[edgeId].mConstraint; }
+
+ PX_FORCE_INLINE Sc::Interaction* getInteraction(IG::EdgeIndex edgeId) const { return mInteractions[edgeId]; }
+
+ PX_FORCE_INLINE PxU64 getContextId() const { return mContextID; }
+
+ bool checkInternalConsistency();
+
+
+private:
+
+ friend class ThirdPassTask;
+ friend class PostThirdPassTask;
+
+ bool validateDeactivations() const;
+
+ PX_NOCOPY(SimpleIslandManager)
+};
+
+
+
+}
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxsSimulationController.h b/PhysX_3.4/Source/LowLevel/software/include/PxsSimulationController.h
new file mode 100644
index 00000000..8d6c2612
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxsSimulationController.h
@@ -0,0 +1,135 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXS_SIMULATION_CONTROLLER_H
+#define PXS_SIMULATION_CONTROLLER_H
+
+#include "foundation/PxSimpleTypes.h"
+#include "foundation/PxPreprocessor.h"
+#include "foundation/PxTransform.h"
+#include "DyGpuAPI.h"
+#include "CmBitMap.h"
+#include "PsArray.h"
+
+
+namespace physx
+{
+ namespace Dy
+ {
+ class Context;
+ struct Constraint;
+ }
+
+ namespace Cm
+ {
+ class EventProfiler;
+ }
+
+ namespace Bp
+ {
+ class BoundsArray;
+ class BroadPhase;
+ }
+
+ namespace IG
+ {
+ class SimpleIslandManager;
+ class IslandSim;
+ }
+
+ class PxGpuDispatcher;
+ class PxsTransformCache;
+ class PxvNphaseImplementationContext;
+ class PxBaseTask;
+
+ struct PxsBodySim;
+ struct PxsShapeSim;
+ class PxsRigidBody;
+ class PxsKernelWranglerManager;
+ class PxsHeapMemoryAllocatorManager;
+
+ template<typename T> class PxgIterator;
+ struct PxgSolverConstraintManagerConstants;
+
+
+ class PxsSimulationControllerCallback
+ {
+ public:
+ virtual void updateScBodyAndShapeSim(PxBaseTask* continuation) = 0;
+ virtual PxU32 getNbCcdBodies() = 0;
+
+ virtual ~PxsSimulationControllerCallback() {}
+ };
+
+
+ class PxsSimulationController
+ {
+ public:
+ PxsSimulationController(PxsSimulationControllerCallback* callback): mCallback(callback){}
+ virtual ~PxsSimulationController(){}
+
+ virtual void addJoint(const PxU32 edgeIndex, Dy::Constraint* constraint, IG::IslandSim& islandSim, Ps::Array<PxU32, Ps::VirtualAllocator>& jointIndices,
+ Ps::Array<PxgSolverConstraintManagerConstants, Ps::VirtualAllocator>& managerIter, PxU32 uniqueId) = 0;
+ virtual void removeJoint(const PxU32 edgeIndex, Dy::Constraint* constraint, Ps::Array<PxU32, Ps::VirtualAllocator>& jointIndices, IG::IslandSim& islandSim) = 0;
+ virtual void addShape(PxsShapeSim* shapeSim, const PxU32 index) = 0;
+ virtual void removeShape(const PxU32 index) = 0;
+ virtual void addDynamic(PxsRigidBody* rigidBody, const PxU32 nodeIndex) = 0;
+ virtual void addDynamics(PxsRigidBody** rigidBody, const PxU32* nodeIndex, PxU32 nbToProcess) = 0;
+ virtual void updateJoint(const PxU32 edgeIndex, Dy::Constraint* constraint) = 0;
+ virtual void updateBodies(PxsRigidBody** rigidBodies, PxU32* nodeIndices, const PxU32 nbBodies) = 0;
+ virtual void updateBody(PxsRigidBody* rigidBodies, const PxU32 nodeIndex) = 0;
+ virtual void updateBodiesAndShapes(PxBaseTask* continuation, bool extrudeHeightfields) = 0;
+ virtual void update(const PxU32 bitMapWordCounts) = 0;
+ virtual void gpuDmabackData(PxsTransformCache& cache, Bp::BoundsArray& boundArray, Cm::BitMapPinned& changedAABBMgrHandles) = 0;
+ virtual void udpateScBodyAndShapeSim(PxsTransformCache& cache, Bp::BoundsArray& boundArray, PxBaseTask* continuation) = 0;
+ virtual PxU32* getActiveBodies() = 0;
+ virtual PxU32* getDeactiveBodies() = 0;
+ virtual PxsBodySim* getBodySims() = 0;
+ virtual PxU32 getNbBodies() = 0;
+
+ virtual PxU32* getUnfrozenShapes() = 0;
+ virtual PxU32* getFrozenShapes() = 0;
+ virtual PxsShapeSim** getShapeSims() = 0;
+ virtual PxU32 getNbFrozenShapes() = 0;
+ virtual PxU32 getNbUnfrozenShapes() = 0;
+
+ virtual void clear() = 0;
+ virtual void setBounds(Bp::BoundsArray* boundArray) = 0;
+ virtual void reserve(const PxU32 nbBodies) = 0;
+
+ protected:
+ PxsSimulationControllerCallback* mCallback;
+
+ };
+
+ PxsSimulationController* createSimulationController(PxsSimulationControllerCallback* callback);
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxsTransformCache.h b/PhysX_3.4/Source/LowLevel/software/include/PxsTransformCache.h
new file mode 100644
index 00000000..b9d69022
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxsTransformCache.h
@@ -0,0 +1,144 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef PXS_TRANSFORM_CACHE_H
+#define PXS_TRANSFORM_CACHE_H
+
+#include "CmPhysXCommon.h"
+#include "CmIDPool.h"
+#include "CmBitMap.h"
+#include "PsUserAllocated.h"
+#include "PsAllocator.h"
+
+#define PX_DEFAULT_CACHE_SIZE 512
+
+namespace physx
+{
+ struct PxsTransformFlag
+ {
+ enum Flags
+ {
+ eFROZEN = (1 << 0)
+ };
+ };
+
+ struct PX_ALIGN_PREFIX(16) PxsCachedTransform
+ {
+ PxTransform transform;
+ PxU32 flags;
+
+ PX_FORCE_INLINE PxU32 isFrozen() const { return flags & PxsTransformFlag::eFROZEN; }
+ }
+ PX_ALIGN_SUFFIX(16);
+
+
+ class PxsTransformCache : public Ps::UserAllocated
+ {
+ typedef PxU32 RefCountType;
+
+ public:
+ PxsTransformCache(Ps::VirtualAllocatorCallback& allocatorCallback) : mTransformCache(Ps::VirtualAllocator(&allocatorCallback)), mHasAnythingChanged(true)
+ {
+ /*mTransformCache.reserve(PX_DEFAULT_CACHE_SIZE);
+ mTransformCache.forceSize_Unsafe(PX_DEFAULT_CACHE_SIZE);*/
+ mUsedSize = 0;
+ }
+
+ void initEntry(PxU32 index)
+ {
+ PxU32 oldCapacity = mTransformCache.capacity();
+ if (index >= oldCapacity)
+ {
+ PxU32 newCapacity = Ps::nextPowerOfTwo(index);
+ mTransformCache.reserve(newCapacity);
+ mTransformCache.forceSize_Unsafe(newCapacity);
+ }
+ mUsedSize = PxMax(mUsedSize, index + 1u);
+ }
+
+
+ PX_FORCE_INLINE void setTransformCache(const PxTransform& transform, const PxU32 flags, const PxU32 index)
+ {
+ mTransformCache[index].transform = transform;
+ mTransformCache[index].flags = flags;
+ mHasAnythingChanged = true;
+ }
+
+ PX_FORCE_INLINE const PxsCachedTransform& getTransformCache(const PxU32 index) const
+ {
+ return mTransformCache[index];
+ }
+
+
+ PX_FORCE_INLINE PxsCachedTransform& getTransformCache(const PxU32 index)
+ {
+ return mTransformCache[index];
+ }
+
+ PX_FORCE_INLINE void shiftTransforms(const PxVec3& shift)
+ {
+ for (PxU32 i = 0; i < mTransformCache.capacity(); i++)
+ {
+ mTransformCache[i].transform.p += shift;
+ }
+ mHasAnythingChanged = true;
+ }
+
+ PX_FORCE_INLINE PxU32 getTotalSize() const
+ {
+ return mUsedSize;
+ }
+
+ PX_FORCE_INLINE const PxsCachedTransform* getTransforms() const
+ {
+ return mTransformCache.begin();
+ }
+
+ PX_FORCE_INLINE PxsCachedTransform* getTransforms()
+ {
+ return mTransformCache.begin();
+ }
+
+ PX_FORCE_INLINE Ps::Array<PxsCachedTransform, Ps::VirtualAllocator>* getCachedTransformArray()
+ {
+ return &mTransformCache;
+ }
+
+ PX_FORCE_INLINE void resetChangedState() { mHasAnythingChanged = false; }
+ PX_FORCE_INLINE void setChangedState() { mHasAnythingChanged = true; }
+ PX_FORCE_INLINE bool hasChanged() const { return mHasAnythingChanged; }
+
+ private:
+ Ps::Array<PxsCachedTransform, Ps::VirtualAllocator> mTransformCache;
+ PxU32 mUsedSize;
+ bool mHasAnythingChanged;
+ };
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/software/include/PxvNphaseImplementationContext.h b/PhysX_3.4/Source/LowLevel/software/include/PxvNphaseImplementationContext.h
new file mode 100644
index 00000000..84eddbca
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/include/PxvNphaseImplementationContext.h
@@ -0,0 +1,220 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef PXV_NPHASE_IMPLEMENTATION_CONTEXT_H
+#define PXV_NPHASE_IMPLEMENTATION_CONTEXT_H
+
+#include "PxSceneDesc.h"
+#include "PxsContactManagerState.h"
+#include "PsArray.h"
+
+#if PX_SUPPORT_GPU_PHYSX
+#include "Pxg.h"
+#endif
+
+namespace physx
+{
+
+namespace IG
+{
+ class SimpleIslandManager;
+ class IslandSim;
+ typedef PxU32 EdgeIndex;
+}
+
+namespace Dy
+{
+ class Context;
+}
+
+class PxBaseTask;
+class PxsContext;
+struct PxsShapeCore;
+class PxsMaterialCore;
+struct PxgDynamicsMemoryConfig;
+class PxsContactManager;
+struct PxsContactManagerOutput;
+class PxsKernelWranglerManager;
+class PxsHeapMemoryAllocatorManager;
+
+
+struct PxsContactManagerBase
+{
+ static const PxU32 NEW_CONTACT_MANAGER_MASK = 0x80000000;
+ static const PxU32 GPU_NP_OFFSET = 0x4;
+
+ static const PxU32 MaxBucketBits = 3;
+
+ const PxU32 mBucketId;
+
+ PxsContactManagerBase(const PxU32 bucketId) : mBucketId(bucketId)
+ {
+ PX_ASSERT(bucketId < (1<<MaxBucketBits));
+ }
+
+
+ PX_FORCE_INLINE PxU32 computeId(const PxU32 index) const { PX_ASSERT(index < PxU32(1 << (32 - (MaxBucketBits-1)))); return (index << MaxBucketBits) | (mBucketId); }
+ static PX_FORCE_INLINE PxU32 computeIndexFromId(const PxU32 id) { return id >> MaxBucketBits; }
+ static PX_FORCE_INLINE PxU32 computeBucketIndexFromId(const PxU32 id) { return id & ((1<<MaxBucketBits)-1); }
+
+private:
+ PX_NOCOPY(PxsContactManagerBase)
+};
+
+class PxsContactManagerOutputIterator
+{
+ PxU32 mOffsets[1<<PxsContactManagerBase::MaxBucketBits];
+ PxsContactManagerOutput* mOutputs;
+
+public:
+
+ PxsContactManagerOutputIterator() : mOutputs(NULL)
+ {
+ }
+
+ PxsContactManagerOutputIterator(PxU32* offsets, PxU32 nbOffsets, PxsContactManagerOutput* outputs) : mOutputs(outputs)
+ {
+ PX_ASSERT(nbOffsets <= (1<<PxsContactManagerBase::MaxBucketBits));
+
+ for(PxU32 a = 0; a < nbOffsets; ++a)
+ {
+ mOffsets[a] = offsets[a];
+ }
+ }
+
+ PX_FORCE_INLINE PxsContactManagerOutput& getContactManager(PxU32 id)
+ {
+ PX_ASSERT((id & PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK) == 0);
+ PxU32 bucketId = PxsContactManagerBase::computeBucketIndexFromId(id);
+ PxU32 cmOutId = PxsContactManagerBase::computeIndexFromId(id);
+ return mOutputs[mOffsets[bucketId] + cmOutId];
+ }
+
+ PxU32 getIndex(PxU32 id)
+ {
+ PX_ASSERT((id & PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK) == 0);
+ PxU32 bucketId = PxsContactManagerBase::computeBucketIndexFromId(id);
+ PxU32 cmOutId = PxsContactManagerBase::computeIndexFromId(id);
+ return mOffsets[bucketId] + cmOutId;
+ }
+};
+
+
+class PxvNphaseImplementationContext
+{
+ private:
+ PX_NOCOPY(PxvNphaseImplementationContext)
+public:
+
+ PxvNphaseImplementationContext(PxsContext& context): mContext(context) {}
+ virtual ~PxvNphaseImplementationContext() {}
+ virtual void destroy() = 0;
+ virtual void updateContactManager(PxReal dt, bool hasBoundsArrayChanged, bool hasContactDistanceChanged, PxBaseTask* continuation, PxBaseTask* firstPassContinuation) = 0;
+ virtual void secondPassUpdateContactManager(PxReal dt, PxBaseTask* continuation) = 0;
+ virtual void fetchUpdateContactManager() = 0;
+
+ virtual void registerContactManager(PxsContactManager* cm, PxI32 touching, PxU32 patchCount) = 0;
+ virtual void registerContactManagers(PxsContactManager** cm, PxU32 nbContactManagers, PxU32 maxContactManagerId) = 0;
+ virtual void unregisterContactManager(PxsContactManager* cm) = 0;
+ virtual void refreshContactManager(PxsContactManager* cm) = 0;
+
+ virtual void registerShape(const PxsShapeCore& shapeCore) = 0;
+ virtual void unregisterShape(const PxsShapeCore& shapeCore) = 0;
+
+ virtual void registerMaterial(const PxsMaterialCore& materialCore) = 0;
+ virtual void updateMaterial(const PxsMaterialCore& materialCore) = 0;
+ virtual void unregisterMaterial(const PxsMaterialCore& materialCore) = 0;
+
+ virtual void updateShapeMaterial(const PxsShapeCore& shapeCore) = 0;
+
+ virtual PxsContactManagerOutput* getGPUContactManagerOutputBase() = 0;
+
+ virtual void startNarrowPhaseTasks() = 0;
+
+ virtual void appendContactManagers() = 0;
+
+ virtual PxsContactManagerOutput& getNewContactManagerOutput(PxU32 index) = 0;
+
+ virtual PxsContactManagerOutputIterator getContactManagerOutputs() = 0;
+
+ virtual void setContactModifyCallback(PxContactModifyCallback* callback) = 0;
+
+ virtual void acquireContext() = 0;
+ virtual void releaseContext() = 0;
+ virtual void preallocateNewBuffers(PxU32 nbNewPairs, PxU32 maxIndex) = 0;
+
+
+
+
+protected:
+
+ PxsContext& mContext;
+};
+
+class PxvNphaseImplementationFallback
+{
+ private:
+ PX_NOCOPY(PxvNphaseImplementationFallback)
+public:
+
+ PxvNphaseImplementationFallback() {}
+ virtual ~PxvNphaseImplementationFallback() {}
+ virtual void processContactManager(PxReal dt, PxsContactManagerOutput* cmOutputs, PxBaseTask* continuation) = 0;
+ virtual void processContactManagerSecondPass(PxReal dt, PxBaseTask* continuation) = 0;
+
+ virtual void registerContactManager(PxsContactManager* cm, PxI32 touching, PxU32 numPatches) = 0;
+ virtual void unregisterContactManagerFallback(PxsContactManager* cm, PxsContactManagerOutput* cmOutputs) = 0;
+
+ virtual void refreshContactManagerFallback(PxsContactManager* cm, PxsContactManagerOutput* cmOutputs) = 0;
+
+ virtual PxsContactManagerOutput& getNewContactManagerOutput(PxU32 npId) = 0;
+
+ virtual void appendContactManagersFallback(PxsContactManagerOutput* outputs) = 0;
+
+ virtual void setContactModifyCallback(PxContactModifyCallback* callback) = 0;
+
+ virtual void removeContactManagersFallback(PxsContactManagerOutput* cmOutputs) = 0;
+
+};
+
+class PxvNphaseImplementationContextUsableAsFallback: public PxvNphaseImplementationContext, public PxvNphaseImplementationFallback
+{
+ private:
+ PX_NOCOPY(PxvNphaseImplementationContextUsableAsFallback)
+public:
+ PxvNphaseImplementationContextUsableAsFallback(PxsContext& context): PxvNphaseImplementationContext(context) {}
+ virtual ~PxvNphaseImplementationContextUsableAsFallback() {}
+};
+
+PxvNphaseImplementationContextUsableAsFallback* createNphaseImplementationContext(PxsContext& context, IG::IslandSim* islandSim);
+
+}
+
+#endif
diff --git a/PhysX_3.4/Source/LowLevel/software/src/PxsCCD.cpp b/PhysX_3.4/Source/LowLevel/software/src/PxsCCD.cpp
new file mode 100644
index 00000000..4dd7d182
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/src/PxsCCD.cpp
@@ -0,0 +1,2020 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "foundation/PxProfiler.h"
+#include "PxsContactManager.h"
+#include "PxsContext.h"
+#include "PxsRigidBody.h"
+#include "PxcContactMethodImpl.h"
+#include "GuContactPoint.h"
+#include "PxsCCD.h"
+#include "PsSort.h"
+#include "PsAtomic.h"
+#include "CmFlushPool.h"
+#include "PxsMaterialManager.h"
+#include "PxcMaterialMethodImpl.h"
+#include "PxsMaterialManager.h"
+#include "PxsMaterialCombiner.h"
+#include "PxcNpContactPrepShared.h"
+#include "PxvGeometry.h"
+#include "DyThresholdTable.h"
+#include "GuCCDSweepConvexMesh.h"
+#include "PsUtilities.h"
+#include "foundation/PxProfiler.h"
+#include "GuBounds.h"
+
+#if DEBUG_RENDER_CCD
+#include "CmRenderOutput.h"
+#include "CmRenderBuffer.h"
+#include "PxPhysics.h"
+#include "PxScene.h"
+#endif
+
+#define DEBUG_RENDER_CCD_FIRST_PASS_ONLY 1
+#define DEBUG_RENDER_CCD_ATOM_PTR 0
+#define DEBUG_RENDER_CCD_NORMAL 1
+
+
+using namespace physx;
+using namespace physx::shdfnd;
+using namespace physx::Dy;
+using namespace Gu;
+
+
+static PX_FORCE_INLINE void verifyCCDPair(const PxsCCDPair& /*pair*/)
+{
+#if 0
+ if (pair.mBa0)
+ pair.mBa0->getPose();
+ if (pair.mBa1)
+ pair.mBa1->getPose();
+#endif
+}
+
+#if CCD_DEBUG_PRINTS
+namespace physx {
+
+static const char* gGeomTypes[PxGeometryType::eGEOMETRY_COUNT+1] = {
+ "sphere", "plane", "capsule", "box", "convex", "trimesh", "heightfield", "*"
+};
+
+FILE* gCCDLog = NULL;
+
+static inline void openCCDLog()
+{
+ if (gCCDLog)
+ {
+ fclose(gCCDLog);
+ gCCDLog = NULL;
+ }
+ gCCDLog = fopen("c:\\ccd.txt", "wt");
+ fprintf(gCCDLog, ">>>>>>>>>>>>>>>>>>>>>>>>>>> CCD START FRAME <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
+}
+
+static inline void printSeparator(
+ const char* prefix, PxU32 pass, PxsRigidBody* atom0, PxGeometryType::Enum g0, PxsRigidBody* atom1, PxGeometryType::Enum g1)
+{
+ fprintf(gCCDLog, "------- %s pass %d (%s %x) vs (%s %x)\n", prefix, pass, gGeomTypes[g0], atom0, gGeomTypes[g1], atom1);
+ fflush(gCCDLog);
+}
+
+static inline void printCCDToi(
+ const char* header, PxF32 t, const PxVec3& v,
+ PxsRigidBody* atom0, PxGeometryType::Enum g0, PxsRigidBody* atom1, PxGeometryType::Enum g1
+)
+{
+ fprintf(gCCDLog, "%s (%s %x vs %s %x): %.5f, (%.2f, %.2f, %.2f)\n", header, gGeomTypes[g0], atom0, gGeomTypes[g1], atom1, t, v.x, v.y, v.z);
+ fflush(gCCDLog);
+}
+
+static inline void printCCDPair(const char* header, PxsCCDPair& pair)
+{
+ printCCDToi(header, pair.mMinToi, pair.mMinToiNormal, pair.mBa0, pair.mG0, pair.mBa1, pair.mG1);
+}
+
+// also used in PxcSweepConvexMesh.cpp
+void printCCDDebug(const char* msg, const PxsRigidBody* atom0, PxGeometryType::Enum g0, bool printPtr)
+{
+ fprintf(gCCDLog, " %s (%s %x)\n", msg, gGeomTypes[g0], printPtr ? atom0 : 0);
+ fflush(gCCDLog);
+}
+
+// also used in PxcSweepConvexMesh.cpp
+void printShape(
+ PxsRigidBody* atom0, PxGeometryType::Enum g0, const char* annotation, PxReal dt, PxU32 pass, bool printPtr)
+{
+ fprintf(gCCDLog, "%s (%s %x) atom=(%.2f, %.2f, %.2f)>(%.2f, %.2f, %.2f) v=(%.1f, %.1f, %.1f), mv=(%.1f, %.1f, %.1f)\n",
+ annotation, gGeomTypes[g0], printPtr ? atom0 : 0,
+ atom0->getLastCCDTransform().p.x, atom0->getLastCCDTransform().p.y, atom0->getLastCCDTransform().p.z,
+ atom0->getPose().p.x, atom0->getPose().p.y, atom0->getPose().p.z,
+ atom0->getLinearVelocity().x, atom0->getLinearVelocity().y, atom0->getLinearVelocity().z,
+ atom0->getLinearMotionVelocity(dt).x, atom0->getLinearMotionVelocity(dt).y, atom0->getLinearMotionVelocity(dt).z );
+ fflush(gCCDLog);
+ #if DEBUG_RENDER_CCD && DEBUG_RENDER_CCD_ATOM_PTR
+ if (!DEBUG_RENDER_CCD_FIRST_PASS_ONLY || pass == 0)
+ {
+ PxScene *s; PxGetPhysics()->getScenes(&s, 1, 0);
+ Cm::RenderOutput((Cm::RenderBuffer&)s->getRenderBuffer())
+ << Cm::DebugText(atom0->getPose().p, 0.05f, "%x", atom0);
+ }
+ #endif
+}
+
+static inline void flushCCDLog()
+{
+ fflush(gCCDLog);
+}
+
+} // namespace physx
+
+#else
+
+namespace physx
+{
+
+void printShape(PxsRigidBody* /*atom0*/, PxGeometryType::Enum /*g0*/, const char* /*annotation*/, PxReal /*dt*/, PxU32 /*pass*/, bool printPtr = true)
+{PX_UNUSED(printPtr);}
+
+static inline void openCCDLog() {}
+
+static inline void flushCCDLog() {}
+
+void printCCDDebug(const char* /*msg*/, const PxsRigidBody* /*atom0*/, PxGeometryType::Enum /*g0*/, bool printPtr = true) {PX_UNUSED(printPtr);}
+
+static inline void printSeparator(
+ const char* /*prefix*/, PxU32 /*pass*/, PxsRigidBody* /*atom0*/, PxGeometryType::Enum /*g0*/,
+ PxsRigidBody* /*atom1*/, PxGeometryType::Enum /*g1*/) {}
+} // namespace physx
+#endif
+
+namespace
+{
+ // PT: TODO: refactor with ShapeSim version (SIMD)
+ PX_INLINE PxTransform getShapeAbsPose(const PxsShapeCore* shapeCore, const PxsRigidCore* rigidCore, PxU32 isDynamic)
+ {
+ if(isDynamic)
+ {
+ const PxsBodyCore* PX_RESTRICT bodyCore = static_cast<const PxsBodyCore*>(rigidCore);
+ return bodyCore->body2World * bodyCore->getBody2Actor().getInverse() *shapeCore->transform;
+ }
+ else
+ {
+ return rigidCore->body2World * shapeCore->transform;
+ }
+ }
+}
+
+namespace physx
+{
+
+ PxsCCDContext::PxsCCDContext(PxsContext* context, Dy::ThresholdStream& thresholdStream, PxvNphaseImplementationContext& nPhaseContext) :
+ mPostCCDSweepTask (this, "PxsContext.postCCDSweep"),
+ mPostCCDAdvanceTask (this, "PxsContext.postCCDAdvance"),
+ mPostCCDDepenetrateTask (this, "PxsContext.postCCDDepenetrate"),
+ mDisableCCDResweep (false),
+ miCCDPass (0),
+ mSweepTotalHits (0),
+ mCCDThreadContext (NULL),
+ mCCDPairsPerBatch (0),
+ mCCDMaxPasses (1),
+ mContext (context),
+ mThresholdStream (thresholdStream),
+ mNphaseContext(nPhaseContext)
+{
+}
+
+PxsCCDContext::~PxsCCDContext()
+{
+}
+
+PxsCCDContext* PxsCCDContext::create(PxsContext* context, Dy::ThresholdStream& thresholdStream, PxvNphaseImplementationContext& nPhaseContext)
+{
+ PxsCCDContext* dc = reinterpret_cast<PxsCCDContext*>(
+ PX_ALLOC(sizeof(PxsCCDContext), "PxsCCDContext"));
+
+ if(dc)
+ {
+ new(dc) PxsCCDContext(context, thresholdStream, nPhaseContext);
+ }
+ return dc;
+}
+
+void PxsCCDContext::destroy()
+{
+ this->~PxsCCDContext();
+ PX_FREE(this);
+}
+
+PxTransform PxsCCDShape::getAbsPose(const PxsRigidBody* atom) const
+{
+ // PT: TODO: refactor with ShapeSim version (SIMD) - or with redundant getShapeAbsPose() above in this same file!
+ if(atom)
+ return atom->getPose() * atom->getCore().getBody2Actor().getInverse() * mShapeCore->transform;
+ else
+ return mRigidCore->body2World * mShapeCore->transform;
+}
+
+PxTransform PxsCCDShape::getLastCCDAbsPose(const PxsRigidBody* atom) const
+{
+ // PT: TODO: refactor with ShapeSim version (SIMD)
+ return atom->getLastCCDTransform() * atom->getCore().getBody2Actor().getInverse() * mShapeCore->transform;
+}
+
+PxReal PxsCCDPair::sweepFindToi(PxcNpThreadContext& context, PxReal dt, PxU32 pass)
+{
+ printSeparator("findToi", pass, mBa0, mG0, NULL, PxGeometryType::eGEOMETRY_COUNT);
+ //Update shape transforms if necessary
+ updateShapes();
+
+ //Extract the bodies
+ PxsRigidBody* atom0 = mBa0;
+ PxsRigidBody* atom1 = mBa1;
+ PxsCCDShape* ccdShape0 = mCCDShape0;
+ PxsCCDShape* ccdShape1 = mCCDShape1;
+ PxGeometryType::Enum g0 = mG0, g1 = mG1;
+
+ //If necessary, flip the bodies to make sure that g0 <= g1
+ if(mG1 < mG0)
+ {
+ g0 = mG1;
+ g1 = mG0;
+ ccdShape0 = mCCDShape1;
+ ccdShape1 = mCCDShape0;
+ atom0 = mBa1;
+ atom1 = mBa0;
+ }
+
+ PX_ALIGN(16, PxTransform tm0);
+ PX_ALIGN(16, PxTransform tm1);
+ PX_ALIGN(16, PxTransform lastTm0);
+ PX_ALIGN(16, PxTransform lastTm1);
+
+ tm0 = ccdShape0->mCurrentTransform;
+ lastTm0 = ccdShape0->mPrevTransform;
+
+ tm1 = ccdShape1->mCurrentTransform;
+ lastTm1 = ccdShape1->mPrevTransform;
+
+ const PxVec3 trA = tm0.p - lastTm0.p;
+ const PxVec3 trB = tm1.p - lastTm1.p;
+ const PxVec3 relTr = trA - trB;
+
+ // Do the sweep
+ PxVec3 sweepNormal(0.0f);
+ PxVec3 sweepPoint(0.0f);
+
+ PxReal restDistance = PxMax(mCm->getWorkUnit().restDistance, 0.f);
+
+ context.mDt = dt;
+ context.mCCDFaceIndex = PXC_CONTACT_NO_FACE_INDEX;
+
+ //Cull the sweep hit based on the relative velocity along the normal
+ const PxReal fastMovingThresh0 = ccdShape0->mFastMovingThreshold;
+ const PxReal fastMovingThresh1 = ccdShape1->mFastMovingThreshold;
+
+ const PxReal sumFastMovingThresh = (fastMovingThresh0 + fastMovingThresh1);
+
+
+ PxReal toi = Gu::SweepShapeShape(*ccdShape0, *ccdShape1, tm0, tm1, lastTm0, lastTm1, restDistance,
+ sweepNormal, sweepPoint, mMinToi, context.mCCDFaceIndex, sumFastMovingThresh);
+
+ //If toi is after the end of TOI, return no hit
+ if (toi >= 1.0f)
+ {
+ mToiType = PxsCCDPair::ePrecise;
+ mPenetration = 0.f;
+ mPenetrationPostStep = 0.f;
+ mMinToi = PX_MAX_REAL; // needs to be reset in case of resweep
+ return toi;
+ }
+
+ PX_ASSERT(PxIsFinite(toi));
+ PX_ASSERT(sweepNormal.isFinite());
+ mFaceIndex = context.mCCDFaceIndex;
+
+ //Work out linear motion (used to cull the sweep hit)
+ const PxReal linearMotion = relTr.dot(-sweepNormal);
+
+ //If we swapped the shapes, swap them back
+ if(mG1 >= mG0)
+ sweepNormal = -sweepNormal;
+
+
+ mToiType = PxsCCDPair::ePrecise;
+
+ PxReal penetration = 0.f;
+ PxReal penetrationPostStep = 0.f;
+
+ //If linear motion along normal < the CCD threshold, set toi to no-hit.
+ if((linearMotion) < sumFastMovingThresh)
+ {
+ mMinToi = PX_MAX_REAL; // needs to be reset in case of resweep
+ return PX_MAX_REAL;
+ }
+ else if(toi <= 0.f)
+ {
+ //If the toi <= 0.f, this implies an initial overlap. If the value < 0.f, it implies penetration
+ PxReal stepRatio0 = atom0 ? atom0->mCCD->mTimeLeft : 1.f;
+ PxReal stepRatio1 = atom1 ? atom1->mCCD->mTimeLeft : 1.f;
+
+ PxReal stepRatio = PxMin(stepRatio0, stepRatio1);
+ penetration = -toi;
+
+ toi = 0.f;
+
+ if(stepRatio == 1.f)
+ {
+ //If stepRatio == 1.f (i.e. neither body has stepped forwards any time at all)
+ //we extract the advance coefficients from the bodies and permit the bodies to step forwards a small amount
+ //to ensure that they won't remain jammed because TOI = 0.0
+ const PxReal advance0 = atom0 ? atom0->mCore->ccdAdvanceCoefficient : 1.f;
+ const PxReal advance1 = atom1 ? atom1->mCore->ccdAdvanceCoefficient : 1.f;
+ const PxReal advance = PxMin(advance0, advance1);
+
+ PxReal fastMoving = PxMin(fastMovingThresh0, atom1 ? fastMovingThresh1 : PX_MAX_REAL);
+ PxReal advanceCoeff = advance * fastMoving;
+ penetrationPostStep = advanceCoeff/linearMotion;
+
+ }
+ PX_ASSERT(PxIsFinite(toi));
+ }
+
+ //Store TOI, penetration and post-step (how much to step forward in initial overlap conditions)
+ mMinToi = toi;
+ mPenetration = penetration;
+ mPenetrationPostStep = penetrationPostStep;
+
+ mMinToiPoint = sweepPoint;
+
+ mMinToiNormal = sweepNormal;
+
+
+ //Work out the materials for the contact (restitution, friction etc.)
+ context.mContactBuffer.count = 0;
+ context.mContactBuffer.contact(mMinToiPoint, mMinToiNormal, 0.f, g1 == PxGeometryType::eTRIANGLEMESH || g1 == PxGeometryType::eHEIGHTFIELD? mFaceIndex : PXC_CONTACT_NO_FACE_INDEX);
+
+ PxsMaterialInfo materialInfo;
+
+ g_GetSingleMaterialMethodTable[g0](ccdShape0->mShapeCore, 0, context, &materialInfo);
+ g_GetSingleMaterialMethodTable[g1](ccdShape1->mShapeCore, 1, context, &materialInfo);
+
+ const PxsMaterialData& data0 = *context.mMaterialManager->getMaterial(materialInfo.mMaterialIndex0);
+ const PxsMaterialData& data1 = *context.mMaterialManager->getMaterial(materialInfo.mMaterialIndex1);
+
+ const PxReal restitution = PxsMaterialCombiner::combineRestitution(data0, data1);
+ PxsMaterialCombiner combiner(1.0f, 1.0f);
+ PxsMaterialCombiner::PxsCombinedMaterial combinedMat = combiner.combineIsotropicFriction(data0, data1);
+ const PxReal sFriction = combinedMat.staFriction;
+ const PxReal dFriction = combinedMat.dynFriction;
+
+ mMaterialIndex0 = materialInfo.mMaterialIndex0;
+ mMaterialIndex1 = materialInfo.mMaterialIndex1;
+ mDynamicFriction = dFriction;
+ mStaticFriction = sFriction;
+ mRestitution = restitution;
+
+ return toi;
+}
+
+void PxsCCDPair::updateShapes()
+{
+ if(mBa0)
+ {
+ //If the CCD shape's update count doesn't match the body's update count, this shape needs its transforms and bounds re-calculated
+ if(mBa0->mCCD->mUpdateCount != mCCDShape0->mUpdateCount)
+ {
+ const PxTransform tm0 = mCCDShape0->getAbsPose(mBa0);
+ const PxTransform lastTm0 = mCCDShape0->getLastCCDAbsPose(mBa0);
+
+ const PxVec3 trA = tm0.p - lastTm0.p;
+
+ Gu::Vec3p origin, extents;
+ Gu::computeBoundsWithCCDThreshold(origin, extents, mCCDShape0->mShapeCore->geometry.getGeometry(), tm0, NULL);
+
+ mCCDShape0->mCenter = origin - trA;
+ mCCDShape0->mExtents = extents;
+ mCCDShape0->mPrevTransform = lastTm0;
+ mCCDShape0->mCurrentTransform = tm0;
+ mCCDShape0->mUpdateCount = mBa0->mCCD->mUpdateCount;
+ }
+ }
+
+ if(mBa1)
+ {
+ //If the CCD shape's update count doesn't match the body's update count, this shape needs its transforms and bounds re-calculated
+ if(mBa1->mCCD->mUpdateCount != mCCDShape1->mUpdateCount)
+ {
+ const PxTransform tm1 = mCCDShape1->getAbsPose(mBa1);
+ const PxTransform lastTm1 = mCCDShape1->getLastCCDAbsPose(mBa1);
+
+ const PxVec3 trB = tm1.p - lastTm1.p;
+
+ Vec3p origin, extents;
+ computeBoundsWithCCDThreshold(origin, extents, mCCDShape1->mShapeCore->geometry.getGeometry(), tm1, NULL);
+
+ mCCDShape1->mCenter = origin - trB;
+ mCCDShape1->mExtents = extents;
+ mCCDShape1->mPrevTransform = lastTm1;
+ mCCDShape1->mCurrentTransform = tm1;
+ mCCDShape1->mUpdateCount = mBa1->mCCD->mUpdateCount;
+ }
+ }
+}
+
+PxReal PxsCCDPair::sweepEstimateToi()
+{
+ //Update shape transforms if necessary
+ updateShapes();
+
+ //PxsRigidBody* atom1 = mBa1;
+ //PxsRigidBody* atom0 = mBa0;
+ PxsCCDShape* ccdShape0 = mCCDShape0;
+ PxsCCDShape* ccdShape1 = mCCDShape1;
+ PxGeometryType::Enum g0 = mG0, g1 = mG1;
+ PX_UNUSED(g0);
+
+
+ //Flip shapes if necessary
+ if(mG1 < mG0)
+ {
+ g0 = mG1;
+ g1 = mG0;
+ /*atom0 = mBa1;
+ atom1 = mBa0;*/
+ ccdShape0 = mCCDShape1;
+ ccdShape1 = mCCDShape0;
+ }
+
+ //Extract previous/current transforms, translations etc.
+ PxTransform tm0, lastTm0, tm1, lastTm1;
+
+ PxVec3 trA(0.f);
+ PxVec3 trB(0.f);
+ tm0 = ccdShape0->mCurrentTransform;
+ lastTm0 = ccdShape0->mPrevTransform;
+ trA = tm0.p - lastTm0.p;
+
+ tm1 = ccdShape1->mCurrentTransform;
+ lastTm1 = ccdShape1->mPrevTransform;
+ trB = tm1.p - lastTm1.p;
+
+ PxReal restDistance = PxMax(mCm->getWorkUnit().restDistance, 0.f);
+
+ const PxVec3 relTr = trA - trB;
+
+ //Work out the sum of the fast moving thresholds scaled by the step ratio
+ const PxReal fastMovingThresh0 = ccdShape0->mFastMovingThreshold;
+ const PxReal fastMovingThresh1 = ccdShape1->mFastMovingThreshold;
+ const PxReal sumFastMovingThresh = (fastMovingThresh0 + fastMovingThresh1);
+
+ mToiType = eEstimate;
+
+ //If the objects are not moving fast-enough relative to each-other to warrant CCD, set estimated time as PX_MAX_REAL
+ if((relTr.magnitudeSquared()) <= (sumFastMovingThresh * sumFastMovingThresh))
+ {
+ mToiType = eEstimate;
+ mMinToi = PX_MAX_REAL;
+ return PX_MAX_REAL;
+ }
+
+ //Otherwise, the objects *are* moving fast-enough so perform estimation pass
+ if(g1 == PxGeometryType::eTRIANGLEMESH)
+ {
+ //Special-case estimation code for meshes
+ PxF32 toi = Gu::SweepEstimateAnyShapeMesh(*ccdShape0, *ccdShape1, tm0, tm1, lastTm0, lastTm1, restDistance, sumFastMovingThresh);
+
+ mMinToi = toi;
+ return toi;
+ }
+ else if (g1 == PxGeometryType::eHEIGHTFIELD)
+ {
+ //Special-case estimation code for heightfields
+ PxF32 toi = Gu::SweepEstimateAnyShapeHeightfield(*ccdShape0, *ccdShape1, tm0, tm1, lastTm0, lastTm1, restDistance, sumFastMovingThresh);
+
+ mMinToi = toi;
+ return toi;
+ }
+
+ //Generic estimation code for prim-prim sweeps
+ PxVec3 centreA, extentsA;
+ PxVec3 centreB, extentsB;
+ centreA = ccdShape0->mCenter;
+ extentsA = ccdShape0->mExtents + PxVec3(restDistance);
+
+ centreB = ccdShape1->mCenter;
+ extentsB = ccdShape1->mExtents;
+
+ PxF32 toi = Gu::sweepAABBAABB(centreA, extentsA * 1.1f, centreB, extentsB * 1.1f, trA, trB);
+ mMinToi = toi;
+ return toi;
+}
+
+bool PxsCCDPair::sweepAdvanceToToi(PxReal dt, bool clipTrajectoryToToi)
+{
+ PxsCCDShape* ccds0 = mCCDShape0;
+ PxsRigidBody* atom0 = mBa0;
+ PxsCCDShape* ccds1 = mCCDShape1;
+ PxsRigidBody* atom1 = mBa1;
+
+ const PxsCCDPair* thisPair = this;
+
+ //Both already had a pass so don't do anything
+ if ((atom0 == NULL || atom0->mCCD->mPassDone) && (atom1 == NULL || atom1->mCCD->mPassDone))
+ return false;
+
+ //Test to validate that they're both infinite mass objects. If so, there can be no response so terminate on a notification-only
+ if((atom0 == NULL || atom0->mCore->inverseMass == 0.f) && (atom1 == NULL || atom1->mCore->inverseMass == 0.f))
+ return false;
+
+ //If the TOI < 1.f. If not, this hit happens after this frame or at the very end of the frame. Either way, next frame can handle it
+ if (thisPair->mMinToi < 1.0f)
+ {
+ if(thisPair->mCm->getWorkUnit().flags & PxcNpWorkUnitFlag::eDISABLE_RESPONSE)
+ {
+ //This is a contact which has response disabled. We just step the bodies and return true but don't respond.
+ if(atom0)
+ {
+ atom0->advancePrevPoseToToi(thisPair->mMinToi);
+ atom0->advanceToToi(thisPair->mMinToi, dt, false);
+ }
+ if(atom1)
+ {
+ atom1->advancePrevPoseToToi(thisPair->mMinToi);
+ atom1->advanceToToi(thisPair->mMinToi, dt, false);
+ }
+ //Don't mark pass as done on either body
+ return true;
+ }
+
+
+ PxReal minToi = thisPair->mMinToi;
+
+ PxF32 penetration = -mPenetration * 10.f;
+
+ PxVec3 minToiNormal = thisPair->mMinToiNormal;
+
+ if (!minToiNormal.isNormalized())
+ {
+ // somehow we got zero normal. This can happen for instance if two identical objects spawn exactly on top of one another
+ // abort ccd and clip to current toi
+ if (atom0 && !atom0->mCCD->mPassDone)
+ {
+ atom0->advancePrevPoseToToi(minToi);
+ atom0->advanceToToi(minToi, dt, true);
+ atom0->mCCD->mUpdateCount++;
+ }
+ return true;
+ }
+
+
+
+ //Get the material indices...
+ const PxReal restitution = mRestitution;
+ const PxReal sFriction = mStaticFriction;
+ const PxReal dFriction = mDynamicFriction;
+
+
+ PxVec3 v0(0.f), v1(0.f);
+
+ PxReal invMass0(0.f), invMass1(0.f);
+#if CCD_ANGULAR_IMPULSE
+ PxMat33 invInertia0(PxVec3(0.f), PxVec3(0.f), PxVec3(0.f)), invInertia1(PxVec3(0.f), PxVec3(0.f), PxVec3(0.f));
+ PxVec3 localPoint0(0.f), localPoint1(0.f);
+#endif
+
+ PxReal dom0 = mCm->getDominance0();
+ PxReal dom1 = mCm->getDominance1();
+
+ //Work out velocity and invMass for body 0
+ if(atom0)
+ {
+ //Put contact point in local space, then find how much point is moving using point velocity...
+
+#if CCD_ANGULAR_IMPULSE
+ localPoint0 = mMinToiPoint - trA.p;
+ v0 = atom0->mCore->linearVelocity + atom0->mCore->angularVelocity.cross(localPoint0);
+
+ physx::Cm::transformInertiaTensor(atom0->mCore->inverseInertia, PxMat33(trA.q),invInertia0);
+ invInertia0 *= dom0;
+#else
+ v0 = atom0->mCore->linearVelocity + atom0->mCore->angularVelocity.cross(ccds0->mShapeCore->transform.p);
+#endif
+ invMass0 = atom0->getInvMass() * dom0;
+
+ }
+
+ //Work out velocity and invMass for body 1
+ if(atom1)
+ {
+ //Put contact point in local space, then find how much point is moving using point velocity...
+#if CCD_ANGULAR_IMPULSE
+ localPoint1 = mMinToiPoint - trB.p;
+ v1 = atom1->mCore->linearVelocity + atom1->mCore->angularVelocity.cross(localPoint1);
+ physx::Cm::transformInertiaTensor(atom1->mCore->inverseInertia, PxMat33(trB.q),invInertia1);
+ invInertia1 *= dom1;
+#else
+ v1 = atom1->mCore->linearVelocity + atom1->mCore->angularVelocity.cross(ccds1->mShapeCore->transform.p);
+#endif
+ invMass1 = atom1->getInvMass() * dom1;
+ }
+
+ PX_ASSERT(v0.isFinite() && v1.isFinite());
+
+ //Work out relative velocity
+ PxVec3 vRel = v1 - v0;
+
+ //Project relative velocity onto contact normal and bias with penetration
+ PxReal relNorVel = vRel.dot(minToiNormal);
+ PxReal relNorVelPlusPen = relNorVel + penetration;
+
+#if CCD_ANGULAR_IMPULSE
+ if(relNorVelPlusPen >= -1e-6f)
+ {
+ //we fall back on linear only parts...
+ localPoint0 = PxVec3(0.f);
+ localPoint1 = PxVec3(0.f);
+ v0 = atom0 ? atom0->getLinearVelocity() : PxVec3(0.f);
+ v1 = atom1 ? atom1->getLinearVelocity() : PxVec3(0.f);
+ vRel = v1 - v0;
+ relNorVel = vRel.dot(minToiNormal);
+ relNorVelPlusPen = relNorVel + penetration;
+ }
+#endif
+
+
+ //If the relative motion is moving towards each-other, respond
+ if(relNorVelPlusPen < -1e-6f)
+ {
+ PxReal sumRecipMass = invMass0 + invMass1;
+
+ const PxReal jLin = relNorVelPlusPen;
+ const PxReal normalResponse = (1.f + restitution) * jLin;
+
+#if CCD_ANGULAR_IMPULSE
+ const PxVec3 angularMom0 = invInertia0 * (localPoint0.cross(mMinToiNormal));
+ const PxVec3 angularMom1 = invInertia1 * (localPoint1.cross(mMinToiNormal));
+
+ const PxReal jAng = minToiNormal.dot(angularMom0.cross(localPoint0) + angularMom1.cross(localPoint1));
+ const PxReal impulseDivisor = sumRecipMass + jAng;
+
+#else
+ const PxReal impulseDivisor = sumRecipMass;
+#endif
+ const PxReal jImp = normalResponse/impulseDivisor;
+
+ PxVec3 j(0.f);
+
+ //If the user requested CCD friction, calculate friction forces.
+ //Note, CCD is *linear* so friction is also linear. The net result is that CCD friction can stop bodies' lateral motion so its better to have it disabled
+ //unless there's a real need for it.
+ if(mHasFriction)
+ {
+
+ PxVec3 vPerp = vRel - relNorVel * minToiNormal;
+ PxVec3 tDir = vPerp;
+ PxReal length = tDir.normalize();
+ PxReal vPerpImp = length/impulseDivisor;
+ PxF32 fricResponse = 0.f;
+ PxF32 staticResponse = (jImp*sFriction);
+ PxF32 dynamicResponse = (jImp*dFriction);
+
+
+ if (PxAbs(staticResponse) >= vPerpImp)
+ fricResponse = vPerpImp;
+ else
+ {
+ fricResponse = -dynamicResponse /* times m0 */;
+ }
+
+
+ //const PxVec3 fricJ = -vPerp.getNormalized() * (fricResponse/impulseDivisor);
+ const PxVec3 fricJ = tDir * (fricResponse);
+ j = jImp * mMinToiNormal + fricJ;
+ }
+ else
+ {
+ j = jImp * mMinToiNormal;
+ }
+
+ verifyCCDPair(*this);
+ //If we have a negative impulse value, then we need to apply it. If not, the bodies are separating (no impulse to apply).
+ if(jImp < 0.f)
+ {
+ mAppliedForce = -jImp;
+
+ //Adjust velocities
+ if((atom0 != NULL && atom0->mCCD->mPassDone) ||
+ (atom1 != NULL && atom1->mCCD->mPassDone))
+ {
+ mPenetrationPostStep = 0.f;
+ }
+ else
+ {
+ if (atom0)
+ {
+ //atom0->mAcceleration.linear = atom0->getLinearVelocity(); // to provide pre-"solver" velocity in contact reports
+
+ atom0->setLinearVelocity(atom0->getLinearVelocity() + j * invMass0);
+ atom0->constrainLinearVelocity();
+ #if CCD_ANGULAR_IMPULSE
+ atom0->mAcceleration.angular = atom0->getAngularVelocity(); // to provide pre-"solver" velocity in contact reports
+ atom0->setAngularVelocity(atom0->getAngularVelocity() + invInertia0 * localPoint0.cross(j));
+ atom0->constrainAngularVelocity();
+ #endif
+ }
+ if (atom1)
+ {
+ //atom1->mAcceleration.linear = atom1->getLinearVelocity(); // to provide pre-"solver" velocity in contact reports
+ atom1->setLinearVelocity(atom1->getLinearVelocity() - j * invMass1);
+ atom1->constrainLinearVelocity();
+ #if CCD_ANGULAR_IMPULSE
+ atom1->mAcceleration.angular = atom1->getAngularVelocity(); // to provide pre-"solver" velocity in contact reports
+ atom1->setAngularVelocity(atom1->getAngularVelocity() - invInertia1 * localPoint1.cross(j));
+ atom1->constrainAngularVelocity();
+ #endif
+ }
+ }
+ }
+ }
+
+ //Update poses
+ if (atom0 && !atom0->mCCD->mPassDone)
+ {
+ atom0->advancePrevPoseToToi(minToi);
+ atom0->advanceToToi(minToi, dt, clipTrajectoryToToi && mPenetrationPostStep == 0.f);
+ atom0->mCCD->mUpdateCount++;
+ }
+ if (atom1 && !atom1->mCCD->mPassDone)
+ {
+ atom1->advancePrevPoseToToi(minToi);
+ atom1->advanceToToi(minToi, dt, clipTrajectoryToToi && mPenetrationPostStep == 0.f);
+ atom1->mCCD->mUpdateCount++;
+ }
+
+ //If we had a penetration post-step (i.e. an initial overlap), step forwards slightly after collision response
+ if(mPenetrationPostStep > 0.f)
+ {
+ if (atom0 && !atom0->mCCD->mPassDone)
+ {
+ atom0->advancePrevPoseToToi(mPenetrationPostStep);
+ if(clipTrajectoryToToi)
+ atom0->advanceToToi(mPenetrationPostStep, dt, clipTrajectoryToToi);
+ }
+ if (atom1 && !atom1->mCCD->mPassDone)
+ {
+ atom1->advancePrevPoseToToi(mPenetrationPostStep);
+ if(clipTrajectoryToToi)
+ atom1->advanceToToi(mPenetrationPostStep, dt, clipTrajectoryToToi);
+ }
+ }
+ //Mark passes as done
+ if (atom0)
+ {
+ atom0->mCCD->mPassDone = true;
+ atom0->mCCD->mHasAnyPassDone = true;
+ }
+ if (atom1)
+ {
+ atom1->mCCD->mPassDone = true;
+ atom1->mCCD->mHasAnyPassDone = true;
+ }
+
+ return true;
+
+ //return false;
+ }
+ else
+ {
+ printCCDDebug("advToi: clean sweep", atom0, mG0);
+ }
+
+ return false;
+}
+
+struct IslandCompare
+{
+ bool operator()(PxsCCDPair& a, PxsCCDPair& b) const { return a.mIslandId < b.mIslandId; }
+};
+
+struct IslandPtrCompare
+{
+ bool operator()(PxsCCDPair*& a, PxsCCDPair*& b) const { return a->mIslandId < b->mIslandId; }
+};
+
+struct ToiCompare
+{
+ bool operator()(PxsCCDPair& a, PxsCCDPair& b) const
+ {
+ return (a.mMinToi < b.mMinToi) ||
+ ((a.mMinToi == b.mMinToi) && (a.mBa1 != NULL && b.mBa1 == NULL));
+ }
+};
+
+struct ToiPtrCompare
+{
+ bool operator()(PxsCCDPair*& a, PxsCCDPair*& b) const
+ {
+ return (a->mMinToi < b->mMinToi) ||
+ ((a->mMinToi == b->mMinToi) && (a->mBa1 != NULL && b->mBa1 == NULL));
+ }
+};
+
+
+// --------------------------------------------------------------
+/**
+\brief Class to perform a set of sweep estimate tasks
+*/
+class PxsCCDSweepTask : public Cm::Task
+{
+ PxsCCDPair** mPairs;
+ PxU32 mNumPairs;
+public:
+ PxsCCDSweepTask(PxsCCDPair** pairs, PxU32 nPairs)
+ : mPairs(pairs), mNumPairs(nPairs)
+ {
+ }
+
+ virtual void runInternal()
+ {
+ for (PxU32 j = 0; j < mNumPairs; j++)
+ {
+ PxsCCDPair& pair = *mPairs[j];
+ pair.sweepEstimateToi();
+ pair.mEstimatePass = 0;
+ }
+ }
+
+ virtual const char *getName() const
+ {
+ return "PxsContext.CCDSweep";
+ }
+
+private:
+ PxsCCDSweepTask& operator=(const PxsCCDSweepTask&);
+};
+
+#define ENABLE_RESWEEP 1
+
+// --------------------------------------------------------------
+/**
+\brief Class to advance a set of islands
+*/
+class PxsCCDAdvanceTask : public Cm::Task
+{
+ PxsCCDPair** mCCDPairs;
+ PxU32 mNumPairs;
+ PxsContext* mContext;
+ PxsCCDContext* mCCDContext;
+ PxReal mDt;
+ PxU32 mCCDPass;
+ const PxsCCDBodyArray& mCCDBodies;
+
+ PxU32 mFirstThreadIsland;
+ PxU32 mIslandsPerThread;
+ PxU32 mTotalIslandCount;
+ PxU32 mFirstIslandPair; // pairs are sorted by island
+ PxsCCDBody** mIslandBodies;
+ PxU16* mNumIslandBodies;
+ PxI32* mSweepTotalHits;
+ bool mClipTrajectory;
+ bool mDisableResweep;
+
+ PxsCCDAdvanceTask& operator=(const PxsCCDAdvanceTask&);
+public:
+ PxsCCDAdvanceTask(PxsCCDPair** pairs, PxU32 nPairs, const PxsCCDBodyArray& ccdBodies,
+ PxsContext* context, PxsCCDContext* ccdContext, PxReal dt, PxU32 ccdPass,
+ PxU32 firstIslandPair, PxU32 firstThreadIsland, PxU32 islandsPerThread, PxU32 totalIslands,
+ PxsCCDBody** islandBodies, PxU16* numIslandBodies, bool clipTrajectory, bool disableResweep,
+ PxI32* sweepTotalHits)
+ : mCCDPairs(pairs), mNumPairs(nPairs), mContext(context), mCCDContext(ccdContext), mDt(dt),
+ mCCDPass(ccdPass), mCCDBodies(ccdBodies), mFirstThreadIsland(firstThreadIsland),
+ mIslandsPerThread(islandsPerThread), mTotalIslandCount(totalIslands), mFirstIslandPair(firstIslandPair),
+ mIslandBodies(islandBodies), mNumIslandBodies(numIslandBodies), mSweepTotalHits(sweepTotalHits),
+ mClipTrajectory(clipTrajectory), mDisableResweep(disableResweep)
+
+ {
+ PX_ASSERT(mFirstIslandPair < mNumPairs);
+ }
+
+ virtual void runInternal()
+ {
+
+ PxI32 sweepTotalHits = 0;
+
+ PxcNpThreadContext* threadContext = mContext->getNpThreadContext();
+
+ // --------------------------------------------------------------------------------------
+ // loop over island labels assigned to this thread
+ PxU32 islandStart = mFirstIslandPair;
+ PxU32 lastIsland = PxMin(mFirstThreadIsland + mIslandsPerThread, mTotalIslandCount);
+ for (PxU32 iIsland = mFirstThreadIsland; iIsland < lastIsland; iIsland++)
+ {
+ if (islandStart >= mNumPairs)
+ // this is possible when for instance there are two islands with 0 pairs in the second
+ // since islands are initially segmented using bodies, not pairs, it can happen
+ break;
+
+ // --------------------------------------------------------------------------------------
+ // sort all pairs within current island by toi
+ PxU32 islandEnd = islandStart+1;
+ while (islandEnd < mNumPairs && mCCDPairs[islandEnd]->mIslandId == iIsland) // find first index past the current island id
+ islandEnd++;
+
+ if (islandEnd > islandStart+1)
+ shdfnd::sort(mCCDPairs+islandStart, islandEnd-islandStart, ToiPtrCompare());
+
+ PX_ASSERT(islandEnd <= mNumPairs);
+
+ // --------------------------------------------------------------------------------------
+ // advance all affected pairs within each island to min toi
+ // for each pair (A,B) in toi order, find any later-toi pairs that collide against A or B
+ // and resweep against changed trajectories of either A or B (excluding statics and kinematics)
+ PxReal islandMinToi = PX_MAX_REAL;
+ PxU32 estimatePass = 1;
+
+ PxReal dt = mDt;
+
+ for (PxU32 iFront = islandStart; iFront < islandEnd; iFront++)
+ {
+ PxsCCDPair& pair = *mCCDPairs[iFront];
+
+ verifyCCDPair(pair);
+
+ //If we have reached a pair with a TOI after 1.0, we can terminate this island
+ if(pair.mMinToi > 1.f)
+ break;
+
+ bool needSweep0 = (pair.mBa0 && pair.mBa0->mCCD->mPassDone == false);
+ bool needSweep1 = (pair.mBa1 && pair.mBa1->mCCD->mPassDone == false);
+
+ //If both bodies have been updated (or one has been updated and the other is static), we can skip to the next pair
+ if(!(needSweep0 || needSweep1))
+ continue;
+
+ {
+ //If the pair was an estimate, we must perform an accurate sweep now
+ if(pair.mToiType == PxsCCDPair::eEstimate)
+ {
+ pair.sweepFindToi(*threadContext, dt, mCCDPass);
+
+ //Test to see if the pair is still the earliest pair.
+ if((iFront + 1) < islandEnd && mCCDPairs[iFront+1]->mMinToi < pair.mMinToi)
+ {
+ //If there is an earlier pair, we push this pair into its correct place in the list and return to the start
+ //of this update loop
+ PxsCCDPair* tmp = &pair;
+ PxU32 index = iFront;
+ while((index + 1) < islandEnd && mCCDPairs[index+1]->mMinToi < pair.mMinToi)
+ {
+ mCCDPairs[index] = mCCDPairs[index+1];
+ ++index;
+ }
+
+ mCCDPairs[index] = tmp;
+
+ --iFront;
+ continue;
+ }
+ }
+
+ //We now have the earliest contact pair for this island and one/both of the bodies have not been updated. We now perform
+ //contact modification to find out if the user still wants to respond to the collision
+ if(pair.mMinToi <= islandMinToi &&
+ pair.mIsModifiable &&
+ mCCDContext->getCCDContactModifyCallback())
+ {
+ //create a modifiable contact and then
+ PxModifiableContact point;
+ point.contact = pair.mMinToiPoint;
+ point.normal = pair.mMinToiNormal;
+
+ //KS - todo - reintroduce face indices!!!!
+ //point.internalFaceIndex0 = PXC_CONTACT_NO_FACE_INDEX;
+ //point.internalFaceIndex1 = pair.mFaceIndex;
+ point.materialIndex0 = pair.mMaterialIndex0;
+ point.materialIndex1 = pair.mMaterialIndex1;
+ point.dynamicFriction = pair.mDynamicFriction;
+ point.staticFriction = pair.mStaticFriction;
+ point.restitution = pair.mRestitution;
+ point.separation = 0.f;
+ point.maxImpulse = PX_MAX_REAL;
+ point.materialFlags= 0;
+ point.targetVelocity = PxVec3(0.f);
+
+ mCCDContext->runCCDModifiableContact(&point, 1, pair.mCCDShape0->mShapeCore, pair.mCCDShape1->mShapeCore,
+ pair.mCCDShape0->mRigidCore, pair.mCCDShape1->mRigidCore, pair.mBa0, pair.mBa1);
+
+ //If the maxImpulse is 0, we return to the beginning of the loop, knowing that the application did not want an interaction
+ //between the pair.
+ if(point.maxImpulse == 0.f)
+ {
+ pair.mMinToi = PX_MAX_REAL;
+ continue;
+ }
+ pair.mDynamicFriction = point.dynamicFriction;
+ pair.mStaticFriction = point.staticFriction;
+ pair.mRestitution = point.restitution;
+ pair.mMinToiPoint = point.contact;
+ pair.mMinToiNormal = point.normal;
+
+ }
+
+ }
+
+ // pair.mIsEarliestToiHit is used for contact notification.
+ // only mark as such if this is the first impact for both atoms of this pair (the impacts are sorted)
+ // and there was an actual impact for this pair
+ bool atom0FirstSweep = (pair.mBa0 && pair.mBa0->mCCD->mPassDone == false) || pair.mBa0 == NULL;
+ bool atom1FirstSweep = (pair.mBa1 && pair.mBa1->mCCD->mPassDone == false) || pair.mBa1 == NULL;
+ if (pair.mMinToi <= 1.0f && atom0FirstSweep && atom1FirstSweep)
+ pair.mIsEarliestToiHit = true;
+
+ // sweepAdvanceToToi sets mCCD->mPassDone flags on both atoms, doesn't advance atoms with flag already set
+ // can advance one atom if the other already has the flag set
+ bool advanced = pair.sweepAdvanceToToi( dt, mClipTrajectory);
+ if(pair.mMinToi < 0.f)
+ pair.mMinToi = 0.f;
+ verifyCCDPair(pair);
+
+ if (advanced && pair.mMinToi <= 1.0f)
+ {
+ sweepTotalHits++;
+ PxU32 islandStartIndex = iIsland == 0 ? 0 : PxU32(mNumIslandBodies[iIsland - 1]);
+ PxU32 islandEndIndex = mNumIslandBodies[iIsland];
+
+ if(pair.mMinToi > 0.f)
+ {
+ for(PxU32 a = islandStartIndex; a < islandEndIndex; ++a)
+ {
+ if(!mIslandBodies[a]->mPassDone)
+ {
+ //If the body has not updated, we advance it to the current time-step that the island has reached.
+ PxsRigidBody* atom = mIslandBodies[a]->mBody;
+ atom->advancePrevPoseToToi(pair.mMinToi);
+ atom->mCCD->mTimeLeft = PxMax(atom->mCCD->mTimeLeft * (1.0f - pair.mMinToi), CCD_MIN_TIME_LEFT);
+ atom->mCCD->mUpdateCount++;
+ }
+ }
+
+ //Adjust remaining dt for the island
+ dt -= dt * pair.mMinToi;
+
+ const PxReal recipOneMinusToi = 1.f/(1.f - pair.mMinToi);
+ for(PxU32 k = iFront+1; k < islandEnd; ++k)
+ {
+ PxsCCDPair& pair1 = *mCCDPairs[k];
+ pair1.mMinToi = (pair1.mMinToi - pair.mMinToi)*recipOneMinusToi;
+ }
+
+ }
+
+ //If we disabled response, we don't need to resweep at all
+ if(!mDisableResweep && !(pair.mCm->getWorkUnit().flags & PxcNpWorkUnitFlag::eDISABLE_RESPONSE))
+ {
+ void* a0 = pair.mBa0 == NULL ? NULL : reinterpret_cast<void*>(pair.mBa0);
+ void* a1 = pair.mBa1 == NULL ? NULL : reinterpret_cast<void*>(pair.mBa1);
+
+ for(PxU32 k = iFront+1; k < islandEnd; ++k)
+ {
+ PxsCCDPair& pair1 = *mCCDPairs[k];
+
+ void* b0 = pair1.mBa0 == NULL ? reinterpret_cast<void*>(pair1.mCCDShape0) : reinterpret_cast<void*>(pair1.mBa0);
+ void* b1 = pair1.mBa1 == NULL ? reinterpret_cast<void*>(pair1.mCCDShape1) : reinterpret_cast<void*>(pair1.mBa1);
+
+ bool containsStatic = pair1.mBa0 == NULL || pair1.mBa1 == NULL;
+
+ PX_ASSERT(b0 != NULL && b1 != NULL);
+
+ if ((!containsStatic) &&
+ ((b0 == a0 && b1 != a1) || (b1 == a0 && b0 != a1) ||
+ (b0 == a1 && b1 != a0) || (b1 == a1 && b0 != a0))
+ )
+ {
+ if(estimatePass != pair1.mEstimatePass)
+ {
+ pair1.mEstimatePass = estimatePass;
+ // resweep pair1 since either b0 or b1 trajectory has changed
+ PxReal oldToi = pair1.mMinToi;
+ verifyCCDPair(pair1);
+ PxReal toi1 = pair1.sweepEstimateToi();
+ PX_ASSERT(pair1.mBa0); // this is because mMinToiNormal is the impact point here
+ if (toi1 < oldToi)
+ {
+ // if toi decreased, resort the array backwards
+ PxU32 kk = k;
+ PX_ASSERT(kk > 0);
+
+ while (kk-1 > iFront && mCCDPairs[kk-1]->mMinToi > toi1)
+ {
+ PxsCCDPair* temp = mCCDPairs[kk-1];
+ mCCDPairs[kk-1] = mCCDPairs[kk];
+ mCCDPairs[kk] = temp;
+ kk--;
+ }
+
+ }
+ else if (toi1 > oldToi)
+ {
+ // if toi increased, resort the array forwards
+ PxU32 kk = k;
+ PX_ASSERT(kk > 0);
+ PxU32 stepped = 0;
+ while (kk+1 < islandEnd && mCCDPairs[kk+1]->mMinToi < toi1)
+ {
+ stepped = 1;
+ PxsCCDPair* temp = mCCDPairs[kk+1];
+ mCCDPairs[kk+1] = mCCDPairs[kk];
+ mCCDPairs[kk] = temp;
+ kk++;
+ }
+ k -= stepped;
+ }
+ }
+ }
+ }
+ }
+ estimatePass++;
+ } // if pair.minToi <= 1.0f
+ } // for iFront
+
+ islandStart = islandEnd;
+ } // for (PxU32 iIsland = mFirstThreadIsland; iIsland < lastIsland; iIsland++)
+
+ Ps::atomicAdd(mSweepTotalHits, sweepTotalHits);
+ mContext->putNpThreadContext(threadContext);
+ }
+
+ virtual const char *getName() const
+ {
+ return "PxsContext.CCDAdvance";
+ }
+};
+
+// --------------------------------------------------------------
+// CCD main function
+// Overall structure:
+/*
+for nPasses (passes are now handled in void Sc::Scene::updateCCDMultiPass)
+
+ update CCD broadphase, generate a list of CMs
+
+ foreach CM
+ create CCDPairs, CCDBodies from CM
+ add shapes, overlappingShapes to CCDBodies
+
+ foreach CCDBody
+ assign island labels per body
+ uses overlappingShapes
+
+ foreach CCDPair
+ assign island label to pair
+
+ sort all pairs by islandId
+
+ foreach CCDPair
+ sweep/find toi
+ compute normal:
+
+ foreach island
+ sort within island by toi
+ foreach pair within island
+ advanceToToi
+ from curPairInIsland to lastPairInIsland
+ resweep if needed
+
+*/
+// --------------------------------------------------------------
+void PxsCCDContext::updateCCDBegin()
+{
+ openCCDLog();
+
+ miCCDPass = 0;
+ mSweepTotalHits = 0;
+}
+
+// --------------------------------------------------------------
+void PxsCCDContext::updateCCDEnd()
+{
+ if (miCCDPass == mCCDMaxPasses - 1 || mSweepTotalHits == 0)
+ {
+ // --------------------------------------------------------------------------------------
+ // At last CCD pass we need to reset mBody pointers back to NULL
+ // so that the next frame we know which ones need to be newly paired with PxsCCDBody objects
+ // also free the CCDBody memory blocks
+
+ mMutex.lock();
+ for (PxU32 j = 0, n = mCCDBodies.size(); j < n; j++)
+ {
+ if (mCCDBodies[j].mBody->mCCD && mCCDBodies[j].mBody->mCCD->mHasAnyPassDone)
+ {
+ //Record this body in the list of bodies that were updated
+ mUpdatedCCDBodies.pushBack(mCCDBodies[j].mBody);
+ }
+ mCCDBodies[j].mBody->mCCD = NULL;
+ mCCDBodies[j].mBody->getCore().isFastMoving = false; //Clear the "isFastMoving" bool
+ }
+ mMutex.unlock();
+
+ mCCDBodies.clear_NoDelete();
+
+ }
+
+ mCCDShapes.clear_NoDelete();
+
+ mMap.clear();
+
+ miCCDPass++;
+}
+
+// --------------------------------------------------------------
+void PxsCCDContext::verifyCCDBegin()
+{
+ #if 0
+ // validate that all bodies have a NULL mCCD pointer
+ if (miCCDPass == 0)
+ {
+ Cm::BitMap::Iterator it(mActiveContactManager);
+ for (PxU32 index = it.getNext(); index != Cm::BitMap::Iterator::DONE; index = it.getNext())
+ {
+ PxsContactManager* cm = mContactManagerPool.findByIndexFast(index);
+ PxsRigidBody* b0 = cm->mBodyShape0->getBodyAtom(), *b1 = cm->mBodyShape1->getBodyAtom();
+ PX_ASSERT(b0 == NULL || b0->mCCD == NULL);
+ PX_ASSERT(b1 == NULL || b1->mCCD == NULL);
+ }
+ }
+ #endif
+}
+
+void PxsCCDContext::resetContactManagers()
+{
+ Cm::BitMap::Iterator it(mContext->mContactManagersWithCCDTouch);
+
+ for (PxU32 index = it.getNext(); index != Cm::BitMap::Iterator::DONE; index = it.getNext())
+ {
+ PxsContactManager* cm = mContext->mContactManagerPool.findByIndexFast(index);
+ cm->clearCCDContactInfo();
+ }
+
+ mContext->mContactManagersWithCCDTouch.clear();
+}
+
+// --------------------------------------------------------------
+void PxsCCDContext::updateCCD(PxReal dt, PxBaseTask* continuation, bool disableResweep, PxI32 numFastMovingShapes)
+{
+ //Flag to run a slightly less-accurate version of CCD that will ensure that objects don't tunnel through the static world but is not as reliable for dynamic-dynamic collisions
+ mDisableCCDResweep = disableResweep;
+ mThresholdStream.clear(); // clear force threshold report stream
+
+ mContext->clearManagerTouchEvents();
+
+ if (miCCDPass == 0)
+ {
+ resetContactManagers();
+ }
+
+
+ // If we're not in the first pass and the previous pass had no sweeps or the BP didn't generate any fast-moving shapes, we can skip CCD entirely
+ if ((miCCDPass > 0 && mSweepTotalHits == 0) || (numFastMovingShapes == 0))
+ {
+ mSweepTotalHits = 0;
+ updateCCDEnd();
+ return;
+ }
+ mSweepTotalHits = 0;
+
+ PX_ASSERT(continuation);
+ PX_ASSERT(continuation->getReference() > 0);
+
+ //printf("CCD 1\n");
+
+ mCCDThreadContext = mContext->getNpThreadContext();
+ mCCDThreadContext->mDt = dt; // doesn't get set anywhere else since it's only used for CCD now
+
+ verifyCCDBegin();
+
+ // --------------------------------------------------------------------------------------
+ // From a list of active CMs, build a temporary array of PxsCCDPair objects (allocated in blocks)
+ // this is done to gather scattered data from memory and also to reduce PxsRidigBody permanent memory footprint
+ // we have to do it every pass since new CMs can become fast moving after each pass (and sometimes cease to be)
+ mCCDPairs.clear_NoDelete();
+ mCCDPtrPairs.forceSize_Unsafe(0);
+
+ mUpdatedCCDBodies.forceSize_Unsafe(0);
+
+ mCCDOverlaps.clear_NoDelete();
+
+
+ bool needsSweep = false;
+
+ {
+ PX_PROFILE_ZONE("Sim.ccdPair", mContext->mContextID);
+
+ Cm::BitMap::Iterator it(mContext->mActiveContactManagersWithCCD);
+ for (PxU32 index = it.getNext(); index != Cm::BitMap::Iterator::DONE; index = it.getNext())
+ {
+ PxsContactManager* cm = mContext->mContactManagerPool.findByIndexFast(index);
+
+ // skip disabled pairs
+ if(!cm->getCCD())
+ continue;
+
+ bool isJoint0 = (cm->mNpUnit.flags & PxcNpWorkUnitFlag::eARTICULATION_BODY0) == PxcNpWorkUnitFlag::eARTICULATION_BODY0;
+ bool isJoint1 = (cm->mNpUnit.flags & PxcNpWorkUnitFlag::eARTICULATION_BODY1) == PxcNpWorkUnitFlag::eARTICULATION_BODY1;
+ // skip articulation vs articulation ccd
+ //Actually. This is fundamentally wrong also :(. We only want to skip links in the same articulation - not all articulations!!!
+ if (isJoint0 && isJoint1)
+ continue;
+
+ bool isFastMoving0 = static_cast<const PxsBodyCore*>(cm->mNpUnit.rigidCore0)->isFastMoving != 0;
+
+ bool isFastMoving1 = (cm->mNpUnit.flags & (PxcNpWorkUnitFlag::eARTICULATION_BODY1 | PxcNpWorkUnitFlag::eDYNAMIC_BODY1)) ? static_cast<const PxsBodyCore*>(cm->mNpUnit.rigidCore1)->isFastMoving != 0: false;
+
+ if (!(isFastMoving0 || isFastMoving1))
+ continue;
+
+ PxcNpWorkUnit& unit = cm->getWorkUnit();
+ const PxsRigidCore* rc0 = unit.rigidCore0;
+ const PxsRigidCore* rc1 = unit.rigidCore1;
+
+ {
+ const PxsShapeCore* sc0 = unit.shapeCore0;
+ const PxsShapeCore* sc1 = unit.shapeCore1;
+
+ PxsRigidBody* ba0 = cm->mRigidBody0;
+ PxsRigidBody* ba1 = cm->mRigidBody1;
+
+ //Look up the body/shape pair in our CCDShape map
+ const Ps::Pair<const PxsRigidShapePair, PxsCCDShape*>* ccdShapePair0 = mMap.find(PxsRigidShapePair(rc0, sc0));
+ const Ps::Pair<const PxsRigidShapePair, PxsCCDShape*>* ccdShapePair1 = mMap.find(PxsRigidShapePair(rc1, sc1));
+
+ //If the CCD shapes exist, extract them from the map
+ PxsCCDShape* ccdShape0 = ccdShapePair0 ? ccdShapePair0->second : NULL;
+ PxsCCDShape* ccdShape1 = ccdShapePair1 ? ccdShapePair1->second : NULL;
+
+ PxReal threshold0 = 0.f;
+ PxReal threshold1 = 0.f;
+
+ PxVec3 trA(0.f);
+ PxVec3 trB(0.f);
+
+ if(ccdShape0 == NULL)
+ {
+ //If we hadn't already created ccdShape, create one
+ ccdShape0 = &mCCDShapes.pushBack();
+ mMap.insert(PxsRigidShapePair(rc0, sc0), ccdShape0);
+
+ ccdShape0->mRigidCore = rc0;
+ ccdShape0->mShapeCore = sc0;
+ ccdShape0->mGeometry = &sc0->geometry;
+
+ const PxTransform tm0 = ccdShape0->getAbsPose(ba0);
+ const PxTransform oldTm0 = ba0 ? ccdShape0->getLastCCDAbsPose(ba0) : tm0;
+
+ trA = tm0.p - oldTm0.p;
+
+ Vec3p origin, extents;
+
+ //Compute the shape's bounds and CCD threshold
+ threshold0 = computeBoundsWithCCDThreshold(origin, extents, sc0->geometry.getGeometry(), tm0, NULL);
+
+ //Set up the CCD shape
+ ccdShape0->mCenter = origin - trA;
+ ccdShape0->mExtents = extents;
+ ccdShape0->mFastMovingThreshold = threshold0;
+ ccdShape0->mPrevTransform = oldTm0;
+ ccdShape0->mCurrentTransform = tm0;
+ ccdShape0->mUpdateCount = 0;
+ }
+ else
+ {
+ //We had already created the shape, so extract the threshold and translation components
+ threshold0 = ccdShape0->mFastMovingThreshold;
+ trA = ccdShape0->mCurrentTransform.p - ccdShape0->mPrevTransform.p;
+ }
+
+ if(ccdShape1 == NULL)
+ {
+ //If the CCD shape was not already constructed, create it
+ ccdShape1 = &mCCDShapes.pushBack();
+ ccdShape1->mRigidCore = rc1;
+ ccdShape1->mShapeCore = sc1;
+ ccdShape1->mGeometry = &sc1->geometry;
+
+ mMap.insert(PxsRigidShapePair(rc1, sc1), ccdShape1);
+
+ const PxTransform tm1 = ccdShape1->getAbsPose(ba1);
+ const PxTransform oldTm1 = ba1 ? ccdShape1->getLastCCDAbsPose(ba1) : tm1;
+
+ trB = tm1.p - oldTm1.p;
+
+ Vec3p origin, extents;
+ //Compute the shape's bounds and CCD threshold
+ threshold1 = computeBoundsWithCCDThreshold(origin, extents, sc1->geometry.getGeometry(), tm1, NULL);
+
+ //Set up the CCD shape
+ ccdShape1->mCenter = origin - trB;
+ ccdShape1->mExtents = extents;
+ ccdShape1->mFastMovingThreshold = threshold1;
+ ccdShape1->mPrevTransform = oldTm1;
+ ccdShape1->mCurrentTransform = tm1;
+ ccdShape1->mUpdateCount = 0;
+ }
+ else
+ {
+ //CCD shape already constructed so just extract thresholds and trB components
+ threshold1 = ccdShape1->mFastMovingThreshold;
+ trB = ccdShape1->mCurrentTransform.p - ccdShape1->mPrevTransform.p;
+ }
+
+ {
+ //Initialize the CCD bodies
+ PxsRigidBody* atoms[2] = {ba0, ba1};
+ for (int k = 0; k < 2; k++)
+ {
+ PxsRigidBody* b = atoms[k];
+ //If there isn't a body (i.e. it's a static), no need to create a CCD body
+ if (!b)
+ continue;
+ if (b->mCCD == NULL)
+ {
+ // this rigid body has no CCD body created for it yet. Create and initialize one.
+ PxsCCDBody& newB = mCCDBodies.pushBack();
+ b->mCCD = &newB;
+ b->mCCD->mIndex = Ps::to16(mCCDBodies.size()-1);
+ b->mCCD->mBody = b;
+ b->mCCD->mTimeLeft = 1.0f;
+ b->mCCD->mOverlappingObjects = NULL;
+ b->mCCD->mUpdateCount = 0;
+ b->mCCD->mHasAnyPassDone = false;
+
+ }
+ b->mCCD->mPassDone = 0;
+ }
+ if(ba0 && ba1)
+ {
+ //If both bodies exist (i.e. this is dynamic-dynamic collision), we create an
+ //overlap between the 2 bodies used for island detection.
+ if(!(ba0->isKinematic() || ba1->isKinematic()))
+ {
+ if(!ba0->mCCD->overlaps(ba1->mCCD))
+ {
+ PxsCCDOverlap* overlapA = &mCCDOverlaps.pushBack();
+ PxsCCDOverlap* overlapB = &mCCDOverlaps.pushBack();
+
+ overlapA->mBody = ba1->mCCD;
+ overlapB->mBody = ba0->mCCD;
+
+ ba0->mCCD->addOverlap(overlapA);
+ ba1->mCCD->addOverlap(overlapB);
+ }
+ }
+ }
+ }
+
+ //We now create the CCD pair. These are used in the CCD sweep and update phases
+ {
+ PxsCCDPair& p = mCCDPairs.pushBack();
+ p.mBa0 = ba0;
+ p.mBa1 = ba1;
+ p.mCCDShape0 = ccdShape0;
+ p.mCCDShape1 = ccdShape1;
+ p.mHasFriction = rc0->hasCCDFriction() || rc1->hasCCDFriction();
+ p.mMinToi = PX_MAX_REAL;
+ p.mG0 = cm->mNpUnit.shapeCore0->geometry.getType();
+ p.mG1 = cm->mNpUnit.shapeCore1->geometry.getType();
+ p.mCm = cm;
+ p.mIslandId = 0xFFFFffff;
+ p.mIsEarliestToiHit = false;
+ p.mFaceIndex = PXC_CONTACT_NO_FACE_INDEX;
+ p.mIsModifiable = cm->isChangeable() != 0;
+ p.mAppliedForce = 0.f;
+
+#if PX_ENABLE_SIM_STATS
+ mContext->mSimStats.mNbCCDPairs[PxMin(p.mG0, p.mG1)][PxMax(p.mG0, p.mG1)] ++;
+#endif
+
+ //Calculate the sum of the thresholds and work out if we need to perform a sweep.
+
+ const PxReal thresh = threshold0 + threshold1;
+ //If no shape pairs in the entire scene are fast-moving, we can bypass the entire of the CCD.
+ needsSweep = needsSweep || (trA - trB).magnitudeSquared() >= (thresh * thresh);
+ }
+
+ }
+ }
+ //There are no fast-moving pairs in this scene, so we can terminate right now without proceeding any further
+ if(!needsSweep)
+ {
+ updateCCDEnd();
+ mContext->putNpThreadContext(mCCDThreadContext);
+ return;
+ }
+ }
+
+ //Create the pair pointer buffer. This is a flattened array of pointers to pairs. It is used to sort the pairs
+ //into islands and is also used to prioritize the pairs into their TOIs
+ {
+ const PxU32 size = mCCDPairs.size();
+ mCCDPtrPairs.reserve(size);
+ for(PxU32 a = 0; a < size; ++a)
+ {
+ mCCDPtrPairs.pushBack(&mCCDPairs[a]);
+ }
+
+ mThresholdStream.reserve(Ps::nextPowerOfTwo(size));
+
+ for (PxU32 a = 0; a < mCCDBodies.size(); ++a)
+ {
+ mCCDBodies[a].mPreSolverVelocity.linear = mCCDBodies[a].mBody->getLinearVelocity();
+ mCCDBodies[a].mPreSolverVelocity.angular = mCCDBodies[a].mBody->getAngularVelocity();
+ }
+ }
+
+
+ PxU32 ccdBodyCount = mCCDBodies.size();
+
+ // --------------------------------------------------------------------------------------
+ // assign island labels
+ const PxU16 noLabelYet = 0xFFFF;
+
+ //Temporary array allocations. Ideally, we should use the scratch pad for there
+ Array<PxU16> islandLabels;
+ islandLabels.resize(ccdBodyCount);
+ Array<const PxsCCDBody*> stack;
+ stack.reserve(ccdBodyCount);
+ stack.forceSize_Unsafe(ccdBodyCount);
+
+
+ //Initialize all islands labels (for each body) to be unitialized
+ mIslandSizes.forceSize_Unsafe(0);
+ mIslandSizes.reserve(ccdBodyCount + 1);
+ mIslandSizes.forceSize_Unsafe(ccdBodyCount + 1);
+ for (PxU32 j = 0; j < ccdBodyCount; j++)
+ islandLabels[j] = noLabelYet;
+
+ PxU16 islandCount = 0;
+ PxU32 stackSize = 0;
+ const PxsCCDBody* top = NULL;
+
+ for (PxU32 j = 0; j < ccdBodyCount; j++)
+ {
+ //If the body has already been labelled, continue
+ if (islandLabels[j] != noLabelYet)
+ continue;
+
+ top = &mCCDBodies[j];
+ //Otherwise push it back into the queue and proceed
+ islandLabels[j] = islandCount;
+
+ stack[stackSize++] = top;
+ // assign new label to unlabeled atom
+ // assign the same label to all connected nodes using stack traversal
+ PxU16 islandSize = 0;
+ while (stackSize > 0)
+ {
+ --stackSize;
+ const PxsCCDBody* ccdb = top;
+ top = stack[PxMax(1u, stackSize)-1];
+
+ PxsCCDOverlap* overlaps = ccdb->mOverlappingObjects;
+ while(overlaps)
+ {
+ if (islandLabels[overlaps->mBody->mIndex] == noLabelYet) // non-static & unlabeled?
+ {
+ islandLabels[overlaps->mBody->mIndex] = islandCount;
+ stack[stackSize++] = overlaps->mBody; // push adjacent node to the top of the stack
+ top = overlaps->mBody;
+ islandSize++;
+ }
+ overlaps = overlaps->mNext;
+ }
+ }
+ //Record island size
+ mIslandSizes[islandCount] = PxU16(islandSize + 1);
+ islandCount++;
+ }
+
+ // --------------------------------------------------------------------------------------
+ // label pairs with island ids
+ // (need an extra loop since we don't maintain a mapping from atom to all of it's pairs)
+ mCCDIslandHistogram.clear(); // number of pairs per island
+ mCCDIslandHistogram.resize(islandCount);
+
+ PxU32 totalActivePairs = 0;
+ for (PxU32 j = 0, n = mCCDPtrPairs.size(); j < n; j++)
+ {
+ const PxU32 staticLabel = 0xFFFFffff;
+ PxsCCDPair& p = *mCCDPtrPairs[j];
+ PxU32 id0 = p.mBa0 && !p.mBa0->isKinematic()? islandLabels[p.mBa0->mCCD->getIndex()] : staticLabel;
+ PxU32 id1 = p.mBa1 && !p.mBa1->isKinematic()? islandLabels[p.mBa1->mCCD->getIndex()] : staticLabel;
+ PX_ASSERT(id0 != 0xFFFF || id1 != 0xFFFF);
+
+ PX_ASSERT(id0 == staticLabel || id1 == staticLabel || (id0 == id1));
+
+ p.mIslandId = PxMin(id0, id1);
+ mCCDIslandHistogram[p.mIslandId] ++;
+ PX_ASSERT(p.mIslandId != staticLabel);
+ totalActivePairs++;
+ }
+
+ PxU16 count = 0;
+ for(PxU16 a = 0; a < islandCount+1; ++a)
+ {
+ PxU16 islandSize = mIslandSizes[a];
+ mIslandSizes[a] = count;
+ count += islandSize;
+ }
+
+ mIslandBodies.forceSize_Unsafe(0);
+ mIslandBodies.reserve(ccdBodyCount);
+ mIslandBodies.forceSize_Unsafe(ccdBodyCount);
+ for(PxU32 a = 0; a < mCCDBodies.size(); ++a)
+ {
+ const PxU32 island = islandLabels[mCCDBodies[a].mIndex];
+ PxU16 writeIndex = mIslandSizes[island];
+ mIslandSizes[island] = PxU16(writeIndex + 1);
+ mIslandBodies[writeIndex] = &mCCDBodies[a];
+ }
+
+ // --------------------------------------------------------------------------------------
+ // setup tasks
+ mPostCCDDepenetrateTask.setContinuation(continuation);
+ mPostCCDAdvanceTask.setContinuation(&mPostCCDDepenetrateTask);
+ mPostCCDSweepTask.setContinuation(&mPostCCDAdvanceTask);
+
+ // --------------------------------------------------------------------------------------
+ // sort all pairs by islands
+ shdfnd::sort(mCCDPtrPairs.begin(), mCCDPtrPairs.size(), IslandPtrCompare());
+
+ // --------------------------------------------------------------------------------------
+ // sweep all CCD pairs
+ const PxU32 nPairs = mCCDPtrPairs.size();
+ const PxU32 numThreads = PxMax(1u, mContext->mTaskManager->getCpuDispatcher()->getWorkerCount()); PX_ASSERT(numThreads > 0);
+ mCCDPairsPerBatch = PxMax<PxU32>((nPairs)/numThreads, 1);
+
+ for (PxU32 batchBegin = 0; batchBegin < nPairs; batchBegin += mCCDPairsPerBatch)
+ {
+ void* ptr = mContext->mTaskPool.allocate(sizeof(PxsCCDSweepTask));
+ PX_ASSERT_WITH_MESSAGE(ptr, "Failed to allocate PxsCCDSweepTask");
+ const PxU32 batchEnd = PxMin(nPairs, batchBegin + mCCDPairsPerBatch);
+ PX_ASSERT(batchEnd >= batchBegin);
+ PxsCCDSweepTask* task = PX_PLACEMENT_NEW(ptr, PxsCCDSweepTask)(
+ mCCDPtrPairs.begin() + batchBegin, batchEnd - batchBegin);
+ task->setContinuation(*mContext->mTaskManager, &mPostCCDSweepTask);
+ task->removeReference();
+ }
+
+ mPostCCDSweepTask.removeReference();
+ mPostCCDAdvanceTask.removeReference();
+ mPostCCDDepenetrateTask.removeReference();
+}
+
+void PxsCCDContext::postCCDSweep(PxBaseTask* continuation)
+{
+ // --------------------------------------------------------------------------------------
+ // batch up the islands and send them over to worker threads
+ PxU32 firstIslandPair = 0;
+ PxU32 islandCount = mCCDIslandHistogram.size();
+ for (PxU32 firstIslandInBatch = 0; firstIslandInBatch < islandCount;)
+ {
+ PxU32 pairSum = 0;
+ PxU32 lastIslandInBatch = firstIslandInBatch+1;
+ PxU32 j;
+ // add up the numbers in the histogram until we reach target pairsPerBatch
+ for (j = firstIslandInBatch; j < islandCount; j++)
+ {
+ pairSum += mCCDIslandHistogram[j];
+ if (pairSum > mCCDPairsPerBatch)
+ {
+ lastIslandInBatch = j+1;
+ break;
+ }
+ }
+ if (j == islandCount) // j is islandCount if not enough pairs were left to fill up to pairsPerBatch
+ {
+ if (pairSum == 0)
+ break; // we are done and there are no islands in this batch
+ lastIslandInBatch = islandCount;
+ }
+
+ void* ptr = mContext->mTaskPool.allocate(sizeof(PxsCCDAdvanceTask));
+ PX_ASSERT_WITH_MESSAGE(ptr , "Failed to allocate PxsCCDSweepTask");
+ bool clipTrajectory = (miCCDPass == mCCDMaxPasses-1);
+ PxsCCDAdvanceTask* task = PX_PLACEMENT_NEW(ptr, PxsCCDAdvanceTask) (
+ mCCDPtrPairs.begin(), mCCDPtrPairs.size(), mCCDBodies, mContext, this, mCCDThreadContext->mDt, miCCDPass,
+ firstIslandPair, firstIslandInBatch, lastIslandInBatch-firstIslandInBatch, islandCount,
+ mIslandBodies.begin(), mIslandSizes.begin(), clipTrajectory, mDisableCCDResweep,
+ &mSweepTotalHits);
+ firstIslandInBatch = lastIslandInBatch;
+ firstIslandPair += pairSum;
+ task->setContinuation(*mContext->mTaskManager, continuation);
+ task->removeReference();
+ } // for iIsland
+}
+
+void PxsCCDContext::postCCDAdvance(PxBaseTask* /*continuation*/)
+{
+ // --------------------------------------------------------------------------------------
+ // contact notifications: update touch status (multi-threading this section would probably slow it down but might be worth a try)
+ PxU32 countLost = 0, countFound = 0, countRetouch = 0;
+
+ PxU32 islandCount = mCCDIslandHistogram.size();
+ PxU32 index = 0;
+
+ for (PxU32 island = 0; island < islandCount; ++island)
+ {
+ PxU32 islandEnd = mCCDIslandHistogram[island] + index;
+ for(PxU32 j = index; j < islandEnd; ++j)
+ {
+ PxsCCDPair& p = *mCCDPtrPairs[j];
+ //The CCD pairs are ordered by TOI. If we reach a TOI > 1, we can terminate
+ if(p.mMinToi > 1.f)
+ break;
+
+ //If this was the earliest touch for the pair of bodies, we can notify the user about it. If not, it's a future collision that we haven't stepped to yet
+ if(p.mIsEarliestToiHit)
+ {
+ //Flag that we had a CCD contact
+ p.mCm->setHadCCDContact();
+
+ //Test/set the changed touch map
+ PxU16 oldTouch = p.mCm->getTouchStatus();
+ if (!oldTouch)
+ {
+ mContext->mContactManagerTouchEvent.growAndSet(p.mCm->getIndex());
+ p.mCm->mNpUnit.statusFlags = PxU16((p.mCm->mNpUnit.statusFlags & (~PxcNpWorkUnitStatusFlag::eHAS_NO_TOUCH)) | PxcNpWorkUnitStatusFlag::eHAS_TOUCH);
+ //Also need to write it in the CmOutput structure!!!!!
+
+ //The achieve this, we need to unregister the CM from the Nphase, then re-register it with the status set. This is the only way to force a push to the GPU
+ mNphaseContext.unregisterContactManager(p.mCm);
+ mNphaseContext.registerContactManager(p.mCm, 1, 0);
+ countFound++;
+ }
+ else
+ {
+ mContext->mContactManagerTouchEvent.growAndSet(p.mCm->getIndex());
+ p.mCm->raiseCCDRetouch();
+ countRetouch++;
+ }
+
+ //Do we want to create reports?
+ const bool createReports =
+ p.mCm->mNpUnit.flags & PxcNpWorkUnitFlag::eOUTPUT_CONTACTS
+ || (p.mCm->mNpUnit.flags & PxcNpWorkUnitFlag::eFORCE_THRESHOLD
+ && ((p.mCm->mNpUnit.flags & PxcNpWorkUnitFlag::eDYNAMIC_BODY0 && static_cast<const PxsBodyCore*>(p.mCm->mNpUnit.rigidCore0)->shouldCreateContactReports())
+ || (p.mCm->mNpUnit.flags & PxcNpWorkUnitFlag::eDYNAMIC_BODY1 && static_cast<const PxsBodyCore*>(p.mCm->mNpUnit.rigidCore1)->shouldCreateContactReports())));
+
+ if(createReports)
+ {
+ mContext->mContactManagersWithCCDTouch.growAndSet(p.mCm->getIndex());
+
+ const PxU32 numContacts = 1;
+ PxsMaterialInfo matInfo;
+ Gu::ContactBuffer& buffer = mCCDThreadContext->mContactBuffer;
+
+ Gu::ContactPoint& cp = buffer.contacts[0];
+ cp.point = p.mMinToiPoint;
+ cp.normal = -p.mMinToiNormal; //KS - discrete contact gen produces contacts pointing in the opposite direction to CCD sweeps
+ cp.internalFaceIndex1 = p.mFaceIndex;
+ cp.separation = 0.0f;
+ cp.restitution = p.mRestitution;
+ cp.dynamicFriction = p.mDynamicFriction;
+ cp.staticFriction = p.mStaticFriction;
+ cp.targetVel = PxVec3(0.f);
+ cp.maxImpulse = PX_MAX_REAL;
+
+ matInfo.mMaterialIndex0 = p.mMaterialIndex0;
+ matInfo.mMaterialIndex1 = p.mMaterialIndex1;
+
+ //Write contact stream for the contact. This will allocate memory for the contacts and forces
+ PxReal* contactForces;
+ //PxU8* contactStream;
+ PxU8* contactPatches;
+ PxU8* contactPoints;
+ PxU16 contactStreamSize;
+ PxU8 contactCount;
+ PxU8 nbPatches;
+ PxsCCDContactHeader* ccdHeader = reinterpret_cast<PxsCCDContactHeader*>(p.mCm->mNpUnit.ccdContacts);
+ if (writeCompressedContact(buffer.contacts, numContacts, mCCDThreadContext, contactCount, contactPatches,
+ contactPoints, contactStreamSize, contactForces, numContacts*sizeof(PxReal), mCCDThreadContext->mMaterialManager,
+ ((p.mCm->mNpUnit.flags & PxcNpWorkUnitFlag::eMODIFIABLE_CONTACT) != 0), true, &matInfo, nbPatches, sizeof(PxsCCDContactHeader),NULL, NULL,
+ false, NULL, NULL, NULL, p.mFaceIndex != PXC_CONTACT_NO_FACE_INDEX))
+ {
+ PxsCCDContactHeader* newCCDHeader = reinterpret_cast<PxsCCDContactHeader*>(contactPatches);
+ newCCDHeader->contactStreamSize = Ps::to16(contactStreamSize);
+ newCCDHeader->isFromPreviousPass = 0;
+
+ p.mCm->mNpUnit.ccdContacts = contactPatches; // put the latest stream at the head of the linked list since it needs to get accessed every CCD pass
+ // to prepare the reports
+
+ if (!ccdHeader)
+ newCCDHeader->nextStream = NULL;
+ else
+ {
+ newCCDHeader->nextStream = ccdHeader;
+ ccdHeader->isFromPreviousPass = 1;
+ }
+
+ //And write the force and contact count
+ PX_ASSERT(contactForces != NULL);
+ contactForces[0] = p.mAppliedForce;
+ }
+ else if (!ccdHeader)
+ {
+ p.mCm->mNpUnit.ccdContacts = NULL;
+ // we do not set the status flag on failure because the pair might have written
+ // a contact stream sucessfully during discrete collision this frame.
+ }
+ else
+ ccdHeader->isFromPreviousPass = 1;
+
+ //If the touch event already existed, the solver would have already configured the threshold stream
+ if((p.mCm->mNpUnit.flags & (PxcNpWorkUnitFlag::eARTICULATION_BODY0 | PxcNpWorkUnitFlag::eARTICULATION_BODY1)) == 0 && p.mAppliedForce)
+ {
+#if 0
+ ThresholdStreamElement elt;
+ elt.normalForce = p.mAppliedForce;
+ elt.threshold = PxMin<float>(p.mBa0 == NULL ? PX_MAX_REAL : p.mBa0->mCore->contactReportThreshold, p.mBa1 == NULL ? PX_MAX_REAL :
+ p.mBa1->mCore->contactReportThreshold);
+ elt.body0 = p.mBa0;
+ elt.body1 = p.mBa1;
+ Ps::order(elt.body0,elt.body1);
+ PX_ASSERT(elt.body0 < elt.body1);
+ mThresholdStream.pushBack(elt);
+#endif
+ }
+ }
+ }
+ }
+ index = islandEnd;
+ }
+
+ mContext->mCMTouchEventCount[PXS_LOST_TOUCH_COUNT] += countLost;
+ mContext->mCMTouchEventCount[PXS_NEW_TOUCH_COUNT] += countFound;
+ mContext->mCMTouchEventCount[PXS_CCD_RETOUCH_COUNT] += countRetouch;
+}
+
+void PxsCCDContext::postCCDDepenetrate(PxBaseTask* /*continuation*/)
+{
+ // --------------------------------------------------------------------------------------
+ // reset mOverlappingShapes array for all bodies
+ // we do it each pass because this set can change due to movement as well as new objects
+ // becoming fast moving due to intra-frame impacts
+
+ for (PxU32 j = 0; j < mCCDBodies.size(); j ++)
+ {
+ mCCDBodies[j].mOverlappingObjects = NULL;
+ }
+
+ mCCDOverlaps.clear_NoDelete();
+
+ updateCCDEnd();
+
+ mContext->putNpThreadContext(mCCDThreadContext);
+
+ flushCCDLog();
+}
+
+Cm::SpatialVector PxsRigidBody::getPreSolverVelocities() const
+{
+ if (mCCD)
+ return mCCD->mPreSolverVelocity;
+ return Cm::SpatialVector(PxVec3(0.f), PxVec3(0.f));
+}
+
+
+PxTransform PxsRigidBody::getAdvancedTransform(PxReal toi) const
+{
+ //If it is kinematic, just return identity. We don't fully support kinematics yet
+ if (isKinematic())
+ return PxTransform(PxIdentity);
+
+ //Otherwise we interpolate the pose between the current and previous pose and return that pose
+ PxVec3 newLastP = mLastTransform.p*(1.0f-toi) + mCore->body2World.p*toi; // advance mLastTransform position to toi
+ PxQuat newLastQ = slerp(toi, getLastCCDTransform().q, mCore->body2World.q); // advance mLastTransform rotation to toi
+ return PxTransform(newLastP, newLastQ);
+}
+
+void PxsRigidBody::advancePrevPoseToToi(PxReal toi)
+{
+ //If this is kinematic, just return
+ if (isKinematic())
+ return;
+
+ //update latest pose
+ PxVec3 newLastP = mLastTransform.p*(1.0f-toi) + mCore->body2World.p*toi; // advance mLastTransform position to toi
+ mLastTransform.p = newLastP;
+#if CCD_ROTATION_LOCKING
+ mCore->body2World.q = getLastCCDTransform().q;
+#else
+ // slerp from last transform to current transform with ratio of toi
+ PxQuat newLastQ = slerp(toi, getLastCCDTransform().q, mCore->body2World.q); // advance mLastTransform rotation to toi
+ mLastTransform.q = newLastQ;
+#endif
+
+
+
+}
+
+
+void PxsRigidBody::advanceToToi(PxReal toi, PxReal dt, bool clip)
+{
+ if (isKinematic())
+ return;
+
+
+ if (clip)
+ {
+ //If clip is true, we set the previous and current pose to be the same. This basically makes the object appear stationary in the CCD
+ mCore->body2World.p = getLastCCDTransform().p;
+#if !CCD_ROTATION_LOCKING
+ mCore->body2World.q = getLastCCDTransform().q;
+#endif
+ }
+ else
+ {
+ // advance new CCD target after impact to remaining toi using post-impact velocities
+ mCore->body2World.p = getLastCCDTransform().p + getLinearVelocity() * dt * (1.0f - toi);
+#if !CCD_ROTATION_LOCKING
+ PxVec3 angularDelta = getAngularVelocity() * dt * (1.0f - toi);
+ PxReal deltaMag = angularDelta.magnitude();
+ PxVec3 deltaAng = deltaMag > 1e-20f ? angularDelta / deltaMag : PxVec3(1.0f, 0.0f, 0.0f);
+ PxQuat angularQuat(deltaMag, deltaAng);
+ mCore->body2World.q = getLastCCDTransform().q * angularQuat;
+#endif
+ PX_ASSERT(mCore->body2World.isSane());
+ }
+
+ // rescale total time left to elapse this frame
+ mCCD->mTimeLeft = PxMax(mCCD->mTimeLeft * (1.0f - toi), CCD_MIN_TIME_LEFT);
+}
+
+
+void PxsCCDContext::runCCDModifiableContact(PxModifiableContact* PX_RESTRICT contacts, PxU32 contactCount, const PxsShapeCore* PX_RESTRICT shapeCore0,
+ const PxsShapeCore* PX_RESTRICT shapeCore1, const PxsRigidCore* PX_RESTRICT rigidCore0, const PxsRigidCore* PX_RESTRICT rigidCore1,
+ const PxsRigidBody* PX_RESTRICT rigid0, const PxsRigidBody* PX_RESTRICT rigid1)
+{
+ if(!mCCDContactModifyCallback)
+ return;
+
+ class PxcContactSet: public PxContactSet
+ {
+ public:
+ PxcContactSet(PxU32 count, PxModifiableContact* contacts_)
+ {
+ mContacts = contacts_;
+ mCount = count;
+ }
+ };
+ {
+ PxContactModifyPair p;
+
+ p.shape[0] = gPxvOffsetTable.convertPxsShape2Px(shapeCore0);
+ p.shape[1] = gPxvOffsetTable.convertPxsShape2Px(shapeCore1);
+
+ p.actor[0] = rigid0 != NULL ? gPxvOffsetTable.convertPxsRigidCore2PxRigidBody(rigidCore0)
+ : gPxvOffsetTable.convertPxsRigidCore2PxRigidStatic(rigidCore0);
+
+ p.actor[1] = rigid1 != NULL ? gPxvOffsetTable.convertPxsRigidCore2PxRigidBody(rigidCore1)
+ : gPxvOffsetTable.convertPxsRigidCore2PxRigidStatic(rigidCore1);
+
+ p.transform[0] = getShapeAbsPose(shapeCore0, rigidCore0, PxU32(rigid0 != NULL));
+ p.transform[1] = getShapeAbsPose(shapeCore1, rigidCore1, PxU32(rigid1 != NULL));
+
+ static_cast<PxcContactSet&>(p.contacts) =
+ PxcContactSet(contactCount, contacts);
+
+ mCCDContactModifyCallback->onCCDContactModify(&p, 1);
+ }
+}
+
+
+} //namespace physx
+
+
diff --git a/PhysX_3.4/Source/LowLevel/software/src/PxsContactManager.cpp b/PhysX_3.4/Source/LowLevel/software/src/PxsContactManager.cpp
new file mode 100644
index 00000000..97e9fe85
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/src/PxsContactManager.cpp
@@ -0,0 +1,87 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#include "PxsContactManager.h"
+#include "PxsRigidBody.h"
+#include "PxcContactMethodImpl.h"
+#include "PxvManager.h"
+#include "PxsIslandSim.h"
+
+using namespace physx;
+
+PxsContactManager::PxsContactManager(PxsContext*, PxU32 index) /*:
+ mUserData (NULL)*/
+{
+ mFlags = 0;
+
+ // PT: TODO: any reason why we don't initialize all members here, e.g. shapeCore pointers?
+ mNpUnit.index = index;
+ mNpUnit.rigidCore0 = NULL;
+ mNpUnit.rigidCore1 = NULL;
+ mNpUnit.restDistance = 0;
+ mNpUnit.dominance0 = 1u;
+ mNpUnit.dominance1 = 1u;
+ mNpUnit.frictionDataPtr = NULL;
+ mNpUnit.frictionPatchCount = 0;
+}
+
+PxsContactManager::~PxsContactManager()
+{
+}
+
+
+void PxsContactManager::setCCD(bool enable)
+{
+ PxU32 flags = mFlags & (~PXS_CM_CCD_CONTACT);
+ if (enable)
+ flags |= PXS_CM_CCD_LINEAR;
+ else
+ flags &= ~PXS_CM_CCD_LINEAR;
+
+ mFlags = flags;
+}
+
+
+
+void PxsContactManager::resetCachedState()
+{
+ // happens when the body transform or shape relative transform changes.
+
+ PxcNpWorkUnitClearCachedState(mNpUnit);
+}
+
+void PxsContactManager::resetFrictionCachedState()
+{
+ // happens when the body transform or shape relative transform changes.
+
+ PxcNpWorkUnitClearFrictionCachedState(mNpUnit);
+}
+
+
diff --git a/PhysX_3.4/Source/LowLevel/software/src/PxsContext.cpp b/PhysX_3.4/Source/LowLevel/software/src/PxsContext.cpp
new file mode 100644
index 00000000..0e18355b
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/src/PxsContext.cpp
@@ -0,0 +1,641 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "foundation/PxProfiler.h"
+#include "PxvConfig.h"
+#include "PxcContactCache.h"
+#include "PxsRigidBody.h"
+#include "PxsContactManager.h"
+#include "PxsContext.h"
+#include "PxPhysXConfig.h"
+
+#include "CmBitMap.h"
+#include "CmFlushPool.h"
+
+#include "PxsMaterialManager.h"
+#include "PxSceneDesc.h"
+#include "PxsCCD.h"
+#include "PxvGeometry.h"
+#include "PxvManager.h"
+#include "PxsSimpleIslandManager.h"
+
+#if PX_SUPPORT_GPU_PHYSX
+#include "task/PxGpuDispatcher.h"
+#include "PxPhysXGpu.h"
+#endif
+
+#include "PxcNpContactPrepShared.h"
+#include "PxcNpCache.h"
+
+
+using namespace physx;
+using namespace physx::shdfnd;
+
+#define PXS_CONTACTMANAGER_SLABSIZE 1024
+#define PXS_MAX_CONTACTMANAGER_SLABS 64
+
+#define PXS_BODYSHAPE_SLABSIZE 1024
+#define PXS_MAX_BODYSHAPE_SLABS 16
+
+
+void PxsCMUpdateTask::release()
+{
+ // We used to do Task::release(); here before fixing DE1106 (xbox pure virtual crash)
+ // Release in turn causes the dependent tasks to start running
+ // The problem was that between the time release was called and by the time we got to the destructor
+ // The task chain would get all the way to scene finalization code which would reset the allocation pool
+ // And a new task would get allocated at the same address, then we would invoke the destructor on that freshly created task
+ // This could potentially cause any number of other problems, it is suprising that it only manifested itself
+ // as a pure virtual crash
+ PxBaseTask* saveContinuation = mCont;
+ this->~PxsCMUpdateTask();
+ if (saveContinuation)
+ saveContinuation->removeReference();
+}
+
+
+
+PxsContext::PxsContext(const PxSceneDesc& desc, PxTaskManager* taskManager, Cm::FlushPool& taskPool, PxU64 contextID) :
+ mNpThreadContextPool (this),
+ mContactManagerPool ("mContactManagerPool", this, 256, 8192),
+ mManifoldPool ("mManifoldPool", 256),
+ mSphereManifoldPool ("mSphereManifoldPool", 256),
+ mContactModifyCallback (NULL),
+ mNpImplementationContext (NULL),
+ mNpFallbackImplementationContext(NULL),
+ mTaskManager (taskManager),
+ mTaskPool (taskPool),
+ mPCM (desc.flags & PxSceneFlag::eENABLE_PCM),
+ mContactCache (false),
+ mCreateAveragePoint (desc.flags & PxSceneFlag::eENABLE_AVERAGE_POINT),
+ mContextID (contextID)
+{
+ clearManagerTouchEvents();
+ mVisualizationCullingBox.setMaximal();
+
+ PxMemZero(mVisualizationParams, sizeof(PxReal) * PxVisualizationParameter::eNUM_VALUES);
+
+ mNpMemBlockPool.init(desc.nbContactDataBlocks, desc.maxNbContactDataBlocks);
+}
+
+PxsContext::~PxsContext()
+{
+ if(mTransformCache)
+ {
+ mTransformCache->~PxsTransformCache();
+ PX_FREE(mTransformCache);
+ }
+ mTransformCache = NULL;
+
+ mContactManagerPool.destroy(); //manually destroy the contact manager pool, otherwise pool deletion order is random and we can get into trouble with references into other pools needed during destruction.
+}
+
+// =========================== Create methods
+namespace physx
+{
+ bool gEnablePCMCaching[PxGeometryType::eGEOMETRY_COUNT][PxGeometryType::eGEOMETRY_COUNT] =
+ {
+ //eSPHERE,
+ {
+ false, //eSPHERE
+ false, //ePLANE
+ false, //eCAPSULE
+ false, //eBOX
+ true, //eCONVEXMESH
+ true, //eTRIANGLEMESH
+ true //eHEIGHTFIELD
+ },
+
+ //ePLANE
+ {
+ false, //eSPHERE
+ false, //ePLANE
+ true, //eCAPSULE
+ true, //eBOX
+ true, //eCONVEXMESH
+ false, //eTRIANGLEMESH
+ false //eHEIGHTFIELD
+ },
+
+ //eCAPSULE,
+ {
+ false, //eSPHERE
+ true, //ePLANE
+ false, //eCAPSULE
+ true, //eBOX
+ true, //eCONVEXMESH
+ true, //eTRIANGLEMESH
+ true //eHEIGHTFIELD
+ },
+
+ //eBOX,
+ {
+ false, //eSPHERE
+ true, //ePLANE
+ true, //eCAPSULE
+ true, //eBOX
+ true, //eCONVEXMESH
+ true, //eTRIANGLEMESH
+ true //eHEIGHTFIELD
+ },
+
+ //eCONVEXMESH,
+ {
+ true, //eSPHERE
+ true, //ePLANE
+ true, //eCAPSULE
+ true, //eBOX
+ true, //eCONVEXMESH
+ true, //eTRIANGLEMESH
+ true //eHEIGHTFIELD
+ },
+ //eTRIANGLEMESH,
+ {
+ true, //eSPHERE
+ false, //ePLANE
+ true, //eCAPSULE
+ true, //eBOX
+ true, //eCONVEXMESH
+ false, //eTRIANGLEMESH
+ false //eHEIGHTFIELD
+ },
+
+ //eHEIGHTFIELD,
+ {
+ true, //eSPHERE
+ false, //ePLANE
+ true, //eCAPSULE
+ true, //eBOX
+ true, //eCONVEXMESH
+ false, //eTRIANGLEMESH
+ false //eHEIGHTFIELD
+ }
+ };
+}
+
+void PxsContext::createTransformCache(Ps::VirtualAllocatorCallback& allocatorCallback)
+{
+ mTransformCache = PX_PLACEMENT_NEW(PX_ALLOC(sizeof(PxsTransformCache), PX_DEBUG_EXP("PxsTransformCache")), PxsTransformCache(allocatorCallback));
+}
+
+PxsContactManager* PxsContext::createContactManager(PxsContactManager* contactManager, const bool useCCD)
+{
+ PxsContactManager* cm = contactManager? contactManager : mContactManagerPool.get();
+
+ if(cm)
+ {
+ PxcNpWorkUnitClearContactState(cm->getWorkUnit());
+ PxcNpWorkUnitClearCachedState(cm->getWorkUnit());
+
+ if (contactManager == NULL)
+ {
+ if (cm->getIndex() >= mActiveContactManager.size())
+ {
+ PxU32 newSize = (2 * cm->getIndex() + 256)&~255;
+ mActiveContactManager.resize(newSize);
+ }
+ mActiveContactManager.set(cm->getIndex());
+
+ if (useCCD)
+ {
+ if (cm->getIndex() >= mActiveContactManagersWithCCD.size())
+ {
+ PxU32 newSize = (2 * cm->getIndex() + 256)&~255;
+ mActiveContactManagersWithCCD.resize(newSize);
+ }
+ mActiveContactManagersWithCCD.set(cm->getIndex());
+ }
+ }
+ }
+ else
+ {
+ PX_WARN_ONCE("Reached limit of contact pairs.");
+ }
+
+ return cm;
+}
+
+void PxsContext::createCache(Gu::Cache& cache, PxsContactManager* cm, PxU8 geomType0, PxU8 geomType1)
+{
+ if(cm)
+ {
+ if(mPCM)
+ {
+ if(gEnablePCMCaching[geomType0][geomType1])
+ {
+ if(geomType0 <= PxGeometryType::eCONVEXMESH &&
+ geomType1 <= PxGeometryType::eCONVEXMESH)
+ {
+ if(geomType0 == PxGeometryType::eSPHERE || geomType1 == PxGeometryType::eSPHERE)
+ {
+ Gu::PersistentContactManifold* manifold = mSphereManifoldPool.allocate();
+ new(manifold) Gu::SpherePersistentContactManifold();
+ cache.setManifold(manifold);
+ }
+ else
+ {
+ Gu::PersistentContactManifold* manifold = mManifoldPool.allocate();
+ new(manifold) Gu::LargePersistentContactManifold();
+ cache.setManifold(manifold);
+
+ }
+ cache.getManifold().clearManifold();
+
+ }
+ else
+ {
+ //ML: raised 1 to indicate the manifold is multiManifold which is for contact gen in mesh/height field
+ //cache.manifold = 1;
+ cache.setMultiManifold(NULL);
+ }
+ }
+ else
+ {
+ //cache.manifold = 0;
+ cache.mCachedData = NULL;
+ cache.mManifoldFlags = 0;
+ }
+ }
+ }
+}
+
+void PxsContext::destroyContactManager(PxsContactManager* cm)
+{
+ const PxU32 idx = cm->getIndex();
+ if (cm->getCCD())
+ mActiveContactManagersWithCCD.growAndReset(idx);
+ mActiveContactManager.growAndReset(idx);
+ mContactManagerTouchEvent.growAndReset(idx);
+ mContactManagerPatchChangeEvent.growAndReset(idx);
+ mContactManagerPool.put(cm);
+}
+
+void PxsContext::destroyCache(Gu::Cache& cache)
+{
+ if(cache.isManifold())
+ {
+ if(!cache.isMultiManifold())
+ {
+ Gu::PersistentContactManifold& manifold = cache.getManifold();
+ if (manifold.mCapacity == GU_SPHERE_MANIFOLD_CACHE_SIZE)
+ {
+ mSphereManifoldPool.deallocate(static_cast<Gu::SpherePersistentContactManifold*>(&manifold));
+ }
+ else
+ {
+ mManifoldPool.deallocate(static_cast<Gu::LargePersistentContactManifold*>(&manifold));
+ }
+ }
+ cache.mCachedData = NULL;
+ cache.mManifoldFlags = 0;
+ }
+}
+
+void PxsContext::setScratchBlock(void* addr, PxU32 size)
+{
+ mScratchAllocator.setBlock(addr, size);
+}
+
+void PxsContext::setContactDistance(Ps::Array<PxReal, Ps::VirtualAllocator>* contactDistance)
+{
+ mContactDistance = contactDistance;
+}
+
+
+void PxsContext::shiftOrigin(const PxVec3& shift)
+{
+ // transform cache
+ mTransformCache->shiftTransforms(-shift);
+
+#if 0
+ if (getContactCacheFlag())
+ {
+ //Iterate all active contact managers
+ Cm::BitMap::Iterator it(mActiveContactManager);
+ PxU32 index = it.getNext();
+ while(index != Cm::BitMap::Iterator::DONE)
+ {
+ PxsContactManager* cm = mContactManagerPool.findByIndexFast(index);
+
+ PxcNpWorkUnit& npwUnit = cm->getWorkUnit();
+
+ // contact cache
+ if(!npwUnit.pairCache.isManifold())
+ {
+ PxU8* contactCachePtr = npwUnit.pairCache.mCachedData;
+ if (contactCachePtr)
+ {
+ PxcLocalContactsCache* lcc;
+ PxU8* contacts = PxcNpCacheRead(npwUnit.pairCache, lcc);
+#ifdef _DEBUG
+ PxcLocalContactsCache testCache;
+ PxU32 testBytes;
+ const PxU8* testPtr = PxcNpCacheRead2(npwUnit.pairCache, testCache, testBytes);
+#endif
+ lcc->mTransform0.p -= shift;
+ lcc->mTransform1.p -= shift;
+
+ const PxU32 nbContacts = lcc->mNbCachedContacts;
+ const bool sameNormal = lcc->mSameNormal;
+ const bool useFaceIndices = lcc->mUseFaceIndices;
+
+ for(PxU32 i=0; i < nbContacts; i++)
+ {
+ if (i != nbContacts-1)
+ Ps::prefetchLine(contacts, 128);
+
+ if(!i || !sameNormal)
+ contacts += sizeof(PxVec3);
+
+ PxVec3* cachedPoint = reinterpret_cast<PxVec3*>(contacts);
+ *cachedPoint -= shift;
+ contacts += sizeof(PxVec3);
+ contacts += sizeof(PxReal);
+
+ if(useFaceIndices)
+ contacts += 2 * sizeof(PxU32);
+ }
+#ifdef _DEBUG
+ PX_ASSERT(contacts == (testPtr + testBytes));
+#endif
+ }
+ }
+
+ index = it.getNext();
+ }
+
+ }
+#endif
+
+ //
+ // adjust visualization culling box
+ //
+ PxBounds3 maximalBounds;
+ maximalBounds.setMaximal();
+ if ((mVisualizationCullingBox.minimum != maximalBounds.minimum) || (mVisualizationCullingBox.maximum != maximalBounds.maximum))
+ {
+ mVisualizationCullingBox.minimum -= shift;
+ mVisualizationCullingBox.maximum -= shift;
+ }
+}
+
+void PxsContext::swapStreams()
+{
+ mNpMemBlockPool.swapNpCacheStreams();
+}
+
+void PxsContext::mergeCMDiscreteUpdateResults(PxBaseTask* /*continuation*/)
+{
+ PX_PROFILE_ZONE("Sim.narrowPhaseMerge", mContextID);
+
+ this->mNpImplementationContext->appendContactManagers();
+
+ //Note: the iterator extracts all the items and returns them to the cache on destruction(for thread safety).
+ PxcThreadCoherentCacheIterator<PxcNpThreadContext, PxcNpContext> threadContextIt(mNpThreadContextPool);
+
+ for(PxcNpThreadContext* threadContext = threadContextIt.getNext(); threadContext; threadContext = threadContextIt.getNext())
+ {
+ mCMTouchEventCount[PXS_LOST_TOUCH_COUNT] += threadContext->getLocalLostTouchCount();
+ mCMTouchEventCount[PXS_NEW_TOUCH_COUNT] += threadContext->getLocalNewTouchCount();
+ mCMTouchEventCount[PXS_PATCH_FOUND_COUNT] += threadContext->getLocalFoundPatchCount();
+ mCMTouchEventCount[PXS_PATCH_LOST_COUNT] += threadContext->getLocalLostPatchCount();
+
+#if PX_ENABLE_SIM_STATS
+ for(PxU32 i=0;i<PxGeometryType::eGEOMETRY_COUNT;i++)
+ {
+ #if PX_DEBUG
+ for(PxU32 j=0; j<i; j++)
+ PX_ASSERT(!threadContext->mDiscreteContactPairs[i][j]);
+ #endif
+ for(PxU32 j=i; j<PxGeometryType::eGEOMETRY_COUNT; j++)
+ {
+ const PxU32 nb = threadContext->mDiscreteContactPairs[i][j];
+ const PxU32 nbModified = threadContext->mModifiedContactPairs[i][j];
+ mSimStats.mNbDiscreteContactPairs[i][j] += nb;
+ mSimStats.mNbModifiedContactPairs[i][j] += nbModified;
+ mSimStats.mNbDiscreteContactPairsTotal += nb;
+ }
+ }
+
+ mSimStats.mNbDiscreteContactPairsWithCacheHits += threadContext->mNbDiscreteContactPairsWithCacheHits;
+ mSimStats.mNbDiscreteContactPairsWithContacts += threadContext->mNbDiscreteContactPairsWithContacts;
+
+ mSimStats.mTotalCompressedContactSize += threadContext->mCompressedCacheSize;
+ //KS - this data is not available yet
+ //mSimStats.mTotalConstraintSize += threadContext->mConstraintSize;
+ threadContext->clearStats();
+#endif
+ mContactManagerTouchEvent.combineInPlace<Cm::BitMap::OR>(threadContext->getLocalChangeTouch());
+ mContactManagerPatchChangeEvent.combineInPlace<Cm::BitMap::OR>(threadContext->getLocalPatchChangeMap());
+ mTotalCompressedCacheSize += threadContext->mTotalCompressedCacheSize;
+ mMaxPatches = PxMax(mMaxPatches, threadContext->mMaxPatches);
+
+ threadContext->mTotalCompressedCacheSize = threadContext->mMaxPatches = 0;
+ }
+}
+
+void PxsContext::setCreateContactStream(bool to)
+{
+ mCreateContactStream = to;
+ PxcThreadCoherentCacheIterator<PxcNpThreadContext, PxcNpContext> threadContextIt(mNpThreadContextPool);
+ for(PxcNpThreadContext* threadContext = threadContextIt.getNext(); threadContext; threadContext = threadContextIt.getNext())
+ {
+ threadContext->setCreateContactStream(to);
+ }
+}
+
+void PxsContext::updateContactManager(PxReal dt, bool hasBoundsArrayChanged, bool hasContactDistanceChanged, PxBaseTask* continuation, PxBaseTask* firstPassContinuation)
+{
+ PX_ASSERT(mNpImplementationContext);
+ mNpImplementationContext->updateContactManager(dt, hasBoundsArrayChanged, hasContactDistanceChanged, continuation, firstPassContinuation);
+}
+
+void PxsContext::secondPassUpdateContactManager(PxReal dt, PxBaseTask* continuation)
+{
+ PX_ASSERT(mNpImplementationContext);
+ mNpImplementationContext->secondPassUpdateContactManager(dt, continuation);
+}
+
+void PxsContext::fetchUpdateContactManager()
+{
+ PX_ASSERT(mNpImplementationContext);
+ mNpImplementationContext->fetchUpdateContactManager();
+ mergeCMDiscreteUpdateResults(NULL);
+}
+
+void PxsContext::resetThreadContexts()
+{
+ //Note: the iterator extracts all the items and returns them to the cache on destruction(for thread safety).
+ PxcThreadCoherentCacheIterator<PxcNpThreadContext, PxcNpContext> threadContextIt(mNpThreadContextPool);
+ PxcNpThreadContext* threadContext = threadContextIt.getNext();
+
+ while(threadContext != NULL)
+ {
+ threadContext->reset(mContactManagerTouchEvent.size());
+ threadContext = threadContextIt.getNext();
+ }
+}
+
+bool PxsContext::getManagerTouchEventCount(int* newTouch, int* lostTouch, int* ccdTouch) const
+{
+ if(newTouch)
+ *newTouch = int(mCMTouchEventCount[PXS_NEW_TOUCH_COUNT]);
+
+ if(lostTouch)
+ *lostTouch = int(mCMTouchEventCount[PXS_LOST_TOUCH_COUNT]);
+
+ if(ccdTouch)
+ *ccdTouch = int(mCMTouchEventCount[PXS_CCD_RETOUCH_COUNT]);
+
+ return true;
+}
+
+bool PxsContext::fillManagerTouchEvents(PxvContactManagerTouchEvent* newTouch, PxI32& newTouchCount, PxvContactManagerTouchEvent* lostTouch, PxI32& lostTouchCount,
+ PxvContactManagerTouchEvent* ccdTouch, PxI32& ccdTouchCount)
+{
+ PxU32 index;
+
+ const PxvContactManagerTouchEvent* newTouchStart = newTouch;
+ const PxvContactManagerTouchEvent* lostTouchStart = lostTouch;
+ const PxvContactManagerTouchEvent* ccdTouchStart = ccdTouch;
+
+ const PxvContactManagerTouchEvent* newTouchEnd = newTouch + newTouchCount;
+ const PxvContactManagerTouchEvent* lostTouchEnd = lostTouch + lostTouchCount;
+ const PxvContactManagerTouchEvent* ccdTouchEnd = ccdTouch + ccdTouchCount;
+
+ PX_UNUSED(newTouchEnd);
+ PX_UNUSED(lostTouchEnd);
+ PX_UNUSED(ccdTouchEnd);
+
+ Cm::BitMap::Iterator it(mContactManagerTouchEvent);
+
+ while((index = it.getNext()) != Cm::BitMap::Iterator::DONE)
+ {
+ PxsContactManager* cm = mContactManagerPool.findByIndexFast(index);
+
+ if(cm->getTouchStatus())
+ {
+ if (!cm->getHasCCDRetouch())
+ {
+ PX_ASSERT(newTouch < newTouchEnd);
+ newTouch->manager = cm;
+ newTouch->userData = cm->getUserData();
+ newTouch++;
+ }
+ else
+ {
+ PX_ASSERT(ccdTouch);
+ PX_ASSERT(ccdTouch < ccdTouchEnd);
+ ccdTouch->manager = cm;
+ ccdTouch->userData = cm->getUserData();
+ cm->clearCCDRetouch();
+ ccdTouch++;
+ }
+ }
+ else
+ {
+ PX_ASSERT(lostTouch < lostTouchEnd);
+ lostTouch->manager = cm;
+ lostTouch->userData = cm->getUserData();
+ lostTouch++;
+ }
+ }
+ newTouchCount = PxI32(newTouch - newTouchStart);
+ lostTouchCount = PxI32(lostTouch - lostTouchStart);
+ ccdTouchCount = PxI32(ccdTouch - ccdTouchStart);
+ return true;
+}
+
+
+
+bool PxsContext::fillManagerPatchChangedEvents(PxsContactManager** foundPatch, PxU32& foundPatchCount,
+ PxsContactManager** lostPatch, PxU32& lostPatchCount)
+{
+ Cm::BitMap::Iterator it(mContactManagerPatchChangeEvent);
+
+ PxsContactManagerOutputIterator outputs = mNpImplementationContext->getContactManagerOutputs();
+
+ PxU32 index;
+ PxsContactManager** currFoundPatch = foundPatch;
+ PxsContactManager** currLostPatch = lostPatch;
+ while((index = it.getNext()) != Cm::BitMap::Iterator::DONE)
+ {
+ PxsContactManager* cm = mContactManagerPool.findByIndexFast(index);
+ PxcNpWorkUnit& workUnit = cm->getWorkUnit();
+ PxsContactManagerOutput& output = outputs.getContactManager(workUnit.mNpIndex);
+ if(output.nbPatches > output.prevPatches)
+ {
+ PX_ASSERT(PxU32(currFoundPatch - foundPatch) < foundPatchCount);
+ *currFoundPatch = cm;
+ currFoundPatch++;
+ }
+ else if(output.nbPatches < output.prevPatches)
+ {
+ PX_ASSERT(PxU32(currLostPatch - lostPatch) < lostPatchCount);
+ *currLostPatch = cm;
+ currLostPatch++;
+ }
+ }
+
+ foundPatchCount = PxU32(currFoundPatch - foundPatch);
+ lostPatchCount = PxU32(currLostPatch - lostPatch);
+ return true;
+}
+
+
+void PxsContext::beginUpdate()
+{
+#if PX_ENABLE_SIM_STATS
+ mSimStats.clearAll();
+#endif
+}
+
+
+// Contact manager related
+
+PxReal PxsContext::getVisualizationParameter(PxVisualizationParameter::Enum param) const
+{
+ PX_ASSERT(param < PxVisualizationParameter::eNUM_VALUES);
+
+ return mVisualizationParams[param];
+}
+
+void PxsContext::setVisualizationParameter(PxVisualizationParameter::Enum param, PxReal value)
+{
+ PX_ASSERT(param < PxVisualizationParameter::eNUM_VALUES);
+ PX_ASSERT(value >= 0.0f);
+
+ mVisualizationParams[param] = value;
+}
+
+
+
+
+
+
diff --git a/PhysX_3.4/Source/LowLevel/software/src/PxsDefaultMemoryManager.cpp b/PhysX_3.4/Source/LowLevel/software/src/PxsDefaultMemoryManager.cpp
new file mode 100644
index 00000000..f84efdd5
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/src/PxsDefaultMemoryManager.cpp
@@ -0,0 +1,74 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PxsDefaultMemoryManager.h"
+
+namespace physx
+{
+
+ PxsDefaultMemoryManager::~PxsDefaultMemoryManager()
+ {
+ for (PxU32 i = 0; i < mAllocators.size(); ++i)
+ {
+ mAllocators[i]->~VirtualAllocatorCallback();
+ PX_FREE(mAllocators[i]);
+ }
+ }
+
+ Ps::VirtualAllocatorCallback* PxsDefaultMemoryManager::createHostMemoryAllocator(const PxU32 gpuComputeVersion)
+ {
+ PX_UNUSED(gpuComputeVersion);
+ Ps::VirtualAllocatorCallback* allocator = PX_PLACEMENT_NEW(PX_ALLOC(sizeof(PxsDefaultMemoryAllocator), "PxsDefaultMemoryAllocator"), PxsDefaultMemoryAllocator());
+ mAllocators.pushBack(allocator);
+ return allocator;
+ }
+
+ //this is an empty stub
+ Ps::VirtualAllocatorCallback* PxsDefaultMemoryManager::createDeviceMemoryAllocator(const PxU32 gpuComputeVersion)
+ {
+ PX_UNUSED(gpuComputeVersion);
+ return NULL;
+ }
+
+ void PxsDefaultMemoryManager::destroyMemoryAllocator()
+ {
+ for (PxU32 i = 0; i < mAllocators.size(); ++i)
+ {
+ mAllocators[i]->~VirtualAllocatorCallback();
+ PX_FREE(mAllocators[i]);
+ }
+ }
+
+
+ PxsMemoryManager* createMemoryManager()
+ {
+ return PX_PLACEMENT_NEW(PX_ALLOC(sizeof(PxsDefaultMemoryManager), PX_DEBUG_EXP("PxsDefaultMemoryManager")), PxsDefaultMemoryManager());
+ }
+
+}
diff --git a/PhysX_3.4/Source/LowLevel/software/src/PxsIslandSim.cpp b/PhysX_3.4/Source/LowLevel/software/src/PxsIslandSim.cpp
new file mode 100644
index 00000000..867e291f
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/src/PxsIslandSim.cpp
@@ -0,0 +1,2299 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PxsIslandSim.h"
+#include "PsSort.h"
+#include "PsUtilities.h"
+#include "foundation/PxProfiler.h"
+
+#define IG_SANITY_CHECKS 0
+
+namespace physx
+{
+namespace IG
+{
+
+ IslandSim::IslandSim(Ps::Array<PartitionEdge*>* firstPartitionEdges, Ps::Array<NodeIndex>& edgeNodeIndices,
+ Ps::Array<PartitionEdge*>* destroyedPartitionEdges, PxU64 contextID) :
+ mNodes(PX_DEBUG_EXP("IslandSim::mNodes")),
+ mActiveNodeIndex(PX_DEBUG_EXP("IslandSim::mActiveNodeIndex")),
+ mEdges(PX_DEBUG_EXP("IslandSim::mEdges")),
+ mEdgeInstances(PX_DEBUG_EXP("IslandSim::mEdgeInstances")),
+ mIslands(PX_DEBUG_EXP("IslandSim::mIslands")),
+ mIslandStaticTouchCount(PX_DEBUG_EXP("IslandSim.activeStaticTouchCount")),
+ mActiveKinematicNodes(PX_DEBUG_EXP("IslandSim::mActiveKinematicNodes")),
+ //Ps::Array<EdgeIndex> mActiveEdges[Edge::eEDGE_TYPE_COUNT]; //! An array of active edges
+ mHopCounts(PX_DEBUG_EXP("IslandSim::mHopCounts")),
+ mFastRoute(PX_DEBUG_EXP("IslandSim::,FastRoute")),
+ mIslandIds(PX_DEBUG_EXP("IslandSim::mIslandIds")),
+ //mIslandAwake(PX_DEBUG_EXP("IslandSim::mIslandAwake")),
+ //mActiveContactEdges(PX_DEBUG_EXP("IslandSim::mActiveContactEdges")),
+ mActiveIslands(PX_DEBUG_EXP("IslandSim::mActiveIslands")),
+ mLastMapIndex(0),
+ mActivatingNodes(PX_DEBUG_EXP("IslandSim::mActivatingNodes")),
+ mDestroyedEdges(PX_DEBUG_EXP("IslandSim::mDestroyedEdges")),
+ mTempIslandIds(PX_DEBUG_EXP("IslandSim::mTempIslandIds")),
+ //mPriorityQueue(PX_DEBUG_EXP("IslandSim::mPriorityQueue")),
+ mVisitedNodes(PX_DEBUG_EXP("IslandSim::mVisitedNodes")),
+ //mVisitedState(PX_DEBUG_EXP("IslandSim::mVisitedState"))
+ mFirstPartitionEdges(firstPartitionEdges),
+ mEdgeNodeIndices(edgeNodeIndices),
+ mDestroyedPartitionEdges(destroyedPartitionEdges),
+ mContextId(contextID)
+ {
+ mInitialActiveNodeCount[0] = 0; mInitialActiveNodeCount[1] = 0; mNpIndexPtr = NULL;
+ mActiveEdgeCount[0] = mActiveEdgeCount[1] = 0;
+ }
+
+template <typename Thing>
+static bool contains(Ps::Array<Thing>& arr, const Thing& thing)
+{
+ for(PxU32 a = 0; a < arr.size(); ++a)
+ {
+ if(thing == arr[a])
+ return true;
+ }
+ return false;
+}
+
+void IslandSim::resize(const PxU32 nbNodes, const PxU32 nbContactManagers, const PxU32 nbConstraints)
+{
+ PxU32 totalEdges = nbContactManagers + nbConstraints;
+ mNodes.reserve(nbNodes);
+ mIslandIds.reserve(nbNodes);
+ mEdges.reserve(totalEdges);
+ mActiveContactEdges.resize(totalEdges);
+ mEdgeInstances.reserve(totalEdges*2);
+}
+
+void IslandSim::addNode(bool isActive, bool isKinematic, Node::NodeType type, NodeIndex nodeIndex)
+{
+ PxU32 handle = nodeIndex.index();
+ if(handle == mNodes.capacity())
+ {
+ const PxU32 newCapacity = PxMax(2*mNodes.capacity(), 256u);
+ mNodes.reserve(newCapacity);
+ mIslandIds.reserve(newCapacity);
+ mFastRoute.reserve(newCapacity);
+ mHopCounts.reserve(newCapacity);
+ mActiveNodeIndex.reserve(newCapacity);
+ }
+
+ const PxU32 newSize = PxMax(handle+1, mNodes.size());
+ mNodes.resize(newSize);
+ mIslandIds.resize(newSize);
+ mFastRoute.resize(newSize);
+ mHopCounts.resize(newSize);
+ mActiveNodeIndex.resize(newSize);
+
+ mActiveNodeIndex[handle] = IG_INVALID_NODE;
+
+
+ Node& node = mNodes[handle];
+ node.mType = Ps::to8(type);
+ //Ensure that the node is not currently being used.
+ PX_ASSERT(node.isDeleted());
+
+ PxU8 flags = PxU16(isActive ? 0 : Node::eREADY_FOR_SLEEPING);
+ if(isKinematic)
+ flags |= Node::eKINEMATIC;
+ node.mFlags = flags;
+ mIslandIds[handle] = IG_INVALID_ISLAND;
+ mFastRoute[handle].setIndices(IG_INVALID_NODE, 0);
+ mHopCounts[handle] = 0;
+
+ if(!isKinematic)
+ {
+ IslandId islandHandle = mIslandHandles.getHandle();
+
+ if(islandHandle == mIslands.capacity())
+ {
+ const PxU32 newCapacity = PxMax(2*mIslands.capacity(), 256u);
+ mIslands.reserve(newCapacity);
+ mIslandAwake.resize(newCapacity);
+ mIslandStaticTouchCount.reserve(newCapacity);
+ }
+ mIslands.resize(PxMax(islandHandle+1, mIslands.size()));
+ mIslandStaticTouchCount.resize(PxMax(islandHandle+1, mIslands.size()));
+ mIslandAwake.growAndReset(PxMax(islandHandle+1, mIslands.size()));
+ Island& island = mIslands[islandHandle];
+ island.mLastNode = island.mRootNode = nodeIndex;
+ island.mSize[type] = 1;
+ mIslandIds[handle] = islandHandle;
+ mIslandStaticTouchCount[islandHandle] = 0;
+ }
+
+ if(isActive)
+ {
+ activateNode(nodeIndex);
+ }
+}
+
+void IslandSim::addRigidBody(PxsRigidBody* body, bool isKinematic, bool isActive, NodeIndex nodeIndex)
+{
+ addNode(isActive, isKinematic, Node::eRIGID_BODY_TYPE, nodeIndex);
+ Node& node = mNodes[nodeIndex.index()];
+ node.mRigidBody = body;
+}
+
+void IslandSim::addArticulation(Sc::ArticulationSim* /*articulation*/, Dy::Articulation* llArtic, bool isActive, NodeIndex nodeIndex)
+{
+ addNode(isActive, false, Node::eARTICULATION_TYPE, nodeIndex);
+ Node& node = mNodes[nodeIndex.index()];
+ node.mLLArticulation = llArtic;
+}
+
+void IslandSim::connectEdge(EdgeInstance& instance, EdgeInstanceIndex edgeIndex, Node& source, NodeIndex /*destination*/)
+{
+ PX_ASSERT(instance.mNextEdge == IG_INVALID_EDGE);
+ PX_ASSERT(instance.mPrevEdge == IG_INVALID_EDGE);
+
+ instance.mNextEdge = source.mFirstEdgeIndex;
+ if(source.mFirstEdgeIndex != IG_INVALID_EDGE)
+ {
+ EdgeInstance& firstEdge = mEdgeInstances[source.mFirstEdgeIndex];
+ firstEdge.mPrevEdge = edgeIndex;
+ }
+
+ source.mFirstEdgeIndex = edgeIndex;
+ instance.mPrevEdge = IG_INVALID_EDGE;
+}
+
+void IslandSim::addConnection(NodeIndex nodeHandle1, NodeIndex nodeHandle2, Edge::EdgeType edgeType, EdgeIndex handle)
+{
+ PX_UNUSED(nodeHandle1);
+ PX_UNUSED(nodeHandle2);
+ if(handle >= mEdges.capacity())
+ {
+ const PxU32 newSize = PxMax(2*(handle+1), 256u);
+ mEdges.reserve(newSize);
+ mActiveContactEdges.resize(newSize);
+ }
+ mEdges.resize(PxMax(mEdges.size(), handle+1));
+ mActiveContactEdges.reset(handle);
+
+ Edge& edge = mEdges[handle];
+
+ if(edge.isPendingDestroyed())
+ {
+ //If it's in this state, then the edge has been tagged for destruction but actually is now not needed to be destroyed
+ edge.clearPendingDestroyed();
+ return;
+ }
+
+ if(edge.isInDirtyList())
+ {
+ PX_ASSERT(mEdgeNodeIndices[handle * 2].index() == nodeHandle1.index());
+ PX_ASSERT(mEdgeNodeIndices[handle * 2 + 1].index() == nodeHandle2.index());
+ PX_ASSERT(edge.mEdgeType == edgeType);
+ return;
+ }
+
+ PX_ASSERT(!edge.isInserted());
+
+ PX_ASSERT(edge.isDestroyed());
+ edge.clearDestroyed();
+
+ PX_ASSERT(edge.mNextIslandEdge == IG_INVALID_ISLAND);
+ PX_ASSERT(edge.mPrevIslandEdge == IG_INVALID_ISLAND);
+
+ PX_ASSERT(mEdgeInstances.size() <= 2*handle || mEdgeInstances[2*handle].mNextEdge == IG_INVALID_EDGE);
+ PX_ASSERT(mEdgeInstances.size() <= 2*handle || mEdgeInstances[2*handle+1].mNextEdge == IG_INVALID_EDGE);
+ PX_ASSERT(mEdgeInstances.size() <= 2*handle || mEdgeInstances[2*handle].mPrevEdge == IG_INVALID_EDGE);
+ PX_ASSERT(mEdgeInstances.size() <= 2*handle || mEdgeInstances[2*handle+1].mPrevEdge == IG_INVALID_EDGE);
+
+ edge.mEdgeType = edgeType;
+
+ PX_ASSERT(handle*2 >= mEdgeInstances.size() || mEdgeInstances[handle*2].mNextEdge == IG_INVALID_EDGE);
+ PX_ASSERT(handle*2+1 >= mEdgeInstances.size() || mEdgeInstances[handle*2+1].mNextEdge == IG_INVALID_EDGE);
+ PX_ASSERT(handle*2 >= mEdgeInstances.size() || mEdgeInstances[handle*2].mPrevEdge == IG_INVALID_EDGE);
+ PX_ASSERT(handle*2+1 >= mEdgeInstances.size() || mEdgeInstances[handle*2+1].mPrevEdge == IG_INVALID_EDGE);
+
+ //Add the new handle
+ if(!edge.isInDirtyList())
+ {
+ PX_ASSERT(!contains(mDirtyEdges[edgeType], handle));
+ mDirtyEdges[edgeType].pushBack(handle);
+ edge.markInDirtyList();
+ }
+ edge.mEdgeState &= ~(Edge::eACTIVATING);
+}
+
+void IslandSim::addConnectionToGraph(EdgeIndex handle)
+{
+ EdgeInstanceIndex instanceHandle = 2*handle;
+ PX_ASSERT(instanceHandle < mEdgeInstances.capacity());
+ /*if(instanceHandle == mEdgeInstances.capacity())
+ {
+ mEdgeInstances.reserve(2*mEdgeInstances.capacity() + 2);
+ }*/
+ mEdgeInstances.resize(PxMax(instanceHandle+2, mEdgeInstances.size()));
+
+ Edge& edge = mEdges[handle];
+
+ bool activeEdge = false;
+ bool kinematicKinematicEdge = true;
+
+ NodeIndex nodeIndex1 = mEdgeNodeIndices[instanceHandle];
+ NodeIndex nodeIndex2 = mEdgeNodeIndices[instanceHandle+1];
+
+ if(nodeIndex1.index() != IG_INVALID_NODE)
+ {
+ Node& node = mNodes[nodeIndex1.index()];
+ connectEdge(mEdgeInstances[instanceHandle], instanceHandle, node, nodeIndex2);
+ activeEdge = node.isActive() || node.isActivating();
+ kinematicKinematicEdge = node.isKinematic();
+ }
+
+ if (nodeIndex1.index() != nodeIndex2.index() && nodeIndex2.index() != IG_INVALID_NODE)
+ {
+ Node& node = mNodes[nodeIndex2.index()];
+ connectEdge(mEdgeInstances[instanceHandle + 1], instanceHandle + 1, node, nodeIndex1);
+ activeEdge = activeEdge || node.isActive() || node.isActivating();
+ kinematicKinematicEdge = kinematicKinematicEdge && node.isKinematic();
+ }
+
+ if(activeEdge && (!kinematicKinematicEdge || edge.getEdgeType() == IG::Edge::eCONTACT_MANAGER))
+ {
+ markEdgeActive(handle);
+ edge.activateEdge();
+ }
+}
+
+void IslandSim::removeConnectionFromGraph(EdgeIndex edgeIndex)
+{
+ NodeIndex nodeIndex1 = mEdgeNodeIndices[2 * edgeIndex];
+ NodeIndex nodeIndex2 = mEdgeNodeIndices[2 * edgeIndex+1];
+ if (nodeIndex1.index() != IG_INVALID_NODE)
+ {
+ Node& node = mNodes[nodeIndex1.index()];
+ if (nodeIndex2.index() == mFastRoute[nodeIndex1.index()].index())
+ mFastRoute[nodeIndex1.index()].setIndices(IG_INVALID_NODE, 0);
+ if(!node.isDirty())
+ {
+ //mDirtyNodes.pushBack(nodeIndex1);
+ mDirtyMap.growAndSet(nodeIndex1.index());
+ node.markDirty();
+ }
+ }
+
+ if (nodeIndex2.index() != IG_INVALID_NODE)
+ {
+ Node& node = mNodes[nodeIndex2.index()];
+ if (nodeIndex1.index() == mFastRoute[nodeIndex2.index()].index())
+ mFastRoute[nodeIndex2.index()].setIndices(IG_INVALID_NODE, 0);
+ if(!node.isDirty())
+ {
+ mDirtyMap.growAndSet(nodeIndex2.index());
+ node.markDirty();
+ }
+ }
+}
+
+void IslandSim::disconnectEdge(EdgeInstance& instance, EdgeInstanceIndex edgeIndex, Node& node)
+{
+
+ PX_ASSERT(instance.mNextEdge == IG_INVALID_EDGE || mEdgeInstances[instance.mNextEdge].mPrevEdge == edgeIndex);
+ PX_ASSERT(instance.mPrevEdge == IG_INVALID_EDGE || mEdgeInstances[instance.mPrevEdge].mNextEdge == edgeIndex);
+
+ if(node.mFirstEdgeIndex == edgeIndex)
+ {
+ PX_ASSERT(instance.mPrevEdge == IG_INVALID_EDGE);
+ node.mFirstEdgeIndex = instance.mNextEdge;
+ }
+ else
+ {
+ EdgeInstance& prev = mEdgeInstances[instance.mPrevEdge];
+ PX_ASSERT(prev.mNextEdge == edgeIndex);
+ prev.mNextEdge = instance.mNextEdge;
+ }
+
+ if(instance.mNextEdge != IG_INVALID_EDGE)
+ {
+ EdgeInstance& next = mEdgeInstances[instance.mNextEdge];
+ PX_ASSERT(next.mPrevEdge == edgeIndex);
+ next.mPrevEdge = instance.mPrevEdge;
+ }
+
+ PX_ASSERT(instance.mNextEdge == IG_INVALID_EDGE || mEdgeInstances[instance.mNextEdge].mPrevEdge == instance.mPrevEdge);
+ PX_ASSERT(instance.mPrevEdge == IG_INVALID_EDGE || mEdgeInstances[instance.mPrevEdge].mNextEdge == instance.mNextEdge);
+
+ instance.mNextEdge = IG_INVALID_EDGE;
+ instance.mPrevEdge = IG_INVALID_EDGE;
+}
+
+void IslandSim::removeConnection(EdgeIndex edgeIndex)
+{
+ Edge& edge = mEdges[edgeIndex];
+ if(!edge.isPendingDestroyed())// && edge.isInserted())
+ {
+ mDestroyedEdges.pushBack(edgeIndex);
+ /*if(!edge.isInserted())
+ edge.setReportOnlyDestroy();*/
+ }
+ edge.setPendingDestroyed();
+}
+
+void IslandSim::removeConnectionInternal(EdgeIndex edgeIndex)
+{
+ PX_ASSERT(edgeIndex != IG_INVALID_EDGE);
+ EdgeInstanceIndex edgeInstanceBase = edgeIndex*2;
+
+
+ NodeIndex nodeIndex1 = mEdgeNodeIndices[edgeIndex * 2];
+
+ if (nodeIndex1.index() != IG_INVALID_NODE)
+ {
+ Node& node = mNodes[nodeIndex1.index()];
+ disconnectEdge(mEdgeInstances[edgeInstanceBase], edgeInstanceBase, node);
+ }
+
+ NodeIndex nodeIndex2 = mEdgeNodeIndices[edgeIndex * 2 + 1];
+
+ if (nodeIndex2.index() != IG_INVALID_NODE && nodeIndex1.index() != nodeIndex2.index())
+ {
+ Node& node = mNodes[nodeIndex2.index()];
+ disconnectEdge(mEdgeInstances[edgeInstanceBase+1], edgeInstanceBase+1, node);
+ }
+}
+
+
+void IslandSim::addContactManager(PxsContactManager* /*manager*/, NodeIndex nodeHandle1, NodeIndex nodeHandle2, EdgeIndex handle)
+{
+ addConnection(nodeHandle1, nodeHandle2, Edge::eCONTACT_MANAGER, handle);
+}
+
+void IslandSim::addConstraint(Dy::Constraint* /*constraint*/, NodeIndex nodeHandle1, NodeIndex nodeHandle2, EdgeIndex handle)
+{
+ addConnection(nodeHandle1, nodeHandle2, Edge::eCONSTRAINT, handle);
+}
+
+void IslandSim::activateNode(NodeIndex nodeIndex)
+{
+ if(nodeIndex.index() != IG_INVALID_NODE)
+ {
+ Node& node = mNodes[nodeIndex.index()];
+
+ if(!(node.isActive() ||
+ node.isActivating()))
+ {
+
+ //If the node is kinematic and already in the active node list, then we need to remove it
+ //from the active kinematic node list, then re-add it after the wake-up. It's a bit stupid
+ //but it means that we don't need another index
+
+ if(node.isKinematic() && mActiveNodeIndex[nodeIndex.index()] != IG_INVALID_NODE)
+ {
+ //node.setActive();
+ //node.clearIsReadyForSleeping(); //Clear the "isReadyForSleeping" flag. Just in case it was set
+ //return;
+
+ PxU32 activeRefCount = node.mActiveRefCount;
+ node.mActiveRefCount = 0;
+ node.clearActive();
+ markKinematicInactive(nodeIndex);
+ node.mActiveRefCount = activeRefCount;
+ }
+
+ node.setActivating(); //Tag it as activating
+ PX_ASSERT(mActiveNodeIndex[nodeIndex.index()] == IG_INVALID_NODE);
+ mActiveNodeIndex[nodeIndex.index()] = mActivatingNodes.size();
+ //Add to waking list
+ mActivatingNodes.pushBack(nodeIndex);
+ }
+ node.clearIsReadyForSleeping(); //Clear the "isReadyForSleeping" flag. Just in case it was set
+ node.clearDeactivating();
+ }
+}
+
+void IslandSim::deactivateNode(NodeIndex nodeIndex)
+{
+ if(nodeIndex.index() != IG_INVALID_NODE)
+ {
+ Node& node = mNodes[nodeIndex.index()];
+
+ //If the node is activating, clear its activating state and remove it from the activating list.
+ //If it wasn't already activating, then it's probably already in the active list
+
+ bool wasActivating = node.isActivating();
+
+ if(wasActivating)
+ {
+ //Already activating, so remove it from the activating list
+ node.clearActivating();
+ PX_ASSERT(mActivatingNodes[mActiveNodeIndex[nodeIndex.index()]].index() == nodeIndex.index());
+ NodeIndex replaceIndex = mActivatingNodes[mActivatingNodes.size()-1];
+ mActiveNodeIndex[replaceIndex.index()] = mActiveNodeIndex[nodeIndex.index()];
+ mActivatingNodes[mActiveNodeIndex[nodeIndex.index()]] = replaceIndex;
+ mActivatingNodes.forceSize_Unsafe(mActivatingNodes.size()-1);
+ mActiveNodeIndex[nodeIndex.index()] = IG_INVALID_NODE;
+
+ if(node.isKinematic())
+ {
+ //If we were temporarily removed from the active kinematic list to be put in the waking kinematic list
+ //then add the node back in before deactivating the node. This is a bit counter-intuitive but the active
+ //kinematic list contains all active kinematics and all kinematics that are referenced by an active constraint
+ PX_ASSERT(mActiveNodeIndex[nodeIndex.index()] == IG_INVALID_NODE);
+ mActiveNodeIndex[nodeIndex.index()] = mActiveKinematicNodes.size();
+ mActiveKinematicNodes.pushBack(nodeIndex);
+ }
+ }
+
+ //Raise the "ready for sleeping" flag so that island gen can put this node to sleep
+ node.setIsReadyForSleeping();
+ }
+}
+
+void IslandSim::putNodeToSleep(NodeIndex nodeIndex)
+{
+ if(nodeIndex.index() != IG_INVALID_NODE)
+ {
+ deactivateNode(nodeIndex);
+ }
+}
+
+
+void IslandSim::activateNodeInternal(NodeIndex nodeIndex)
+{
+ //This method should activate the node, then activate all the connections involving this node
+ Node& node = mNodes[nodeIndex.index()];
+
+ if(!node.isActive())
+ {
+ PX_ASSERT(mActiveNodeIndex[nodeIndex.index()] == IG_INVALID_NODE);
+
+ //Activate all the edges + nodes...
+
+ EdgeInstanceIndex index = node.mFirstEdgeIndex;
+
+ while(index != IG_INVALID_EDGE)
+ {
+ EdgeIndex idx = index/2;
+ Edge& edge = mEdges[idx]; //InstanceIndex/2 = edgeIndex
+ if(!edge.isActive())
+ {
+ //Make the edge active...
+ PX_ASSERT(mEdgeNodeIndices[idx * 2].index() == IG_INVALID_NODE || !mNodes[mEdgeNodeIndices[idx * 2].index()].isActive() || mNodes[mEdgeNodeIndices[idx * 2].index()].isKinematic());
+ PX_ASSERT(mEdgeNodeIndices[idx * 2 + 1].index() == IG_INVALID_NODE || !mNodes[mEdgeNodeIndices[idx * 2 + 1].index()].isActive() || mNodes[mEdgeNodeIndices[idx * 2 + 1].index()].isKinematic());
+
+ markEdgeActive(idx);
+ edge.activateEdge();
+
+ }
+ index = mEdgeInstances[index].mNextEdge;
+ }
+
+ if(node.isKinematic())
+ {
+ markKinematicActive(nodeIndex);
+ }
+ else
+ {
+ markActive(nodeIndex);
+ }
+ node.setActive();
+ }
+
+}
+
+void IslandSim::deactivateNodeInternal(NodeIndex nodeIndex)
+{
+ //We deactivate a node, we need to loop through all the edges and deactivate them *if* both bodies are asleep
+
+ Node& node = mNodes[nodeIndex.index()];
+
+ if(node.isActive())
+ {
+ if(node.isKinematic())
+ {
+ markKinematicInactive(nodeIndex);
+ }
+ else
+ {
+ markInactive(nodeIndex);
+ }
+
+ //Clear the active status flag
+ node.clearActive();
+ node.clearActivating();
+
+ EdgeInstanceIndex index = node.mFirstEdgeIndex;
+
+ while(index != IG_INVALID_EDGE)
+ {
+ EdgeInstance& instance = mEdgeInstances[index];
+
+
+ NodeIndex outboundNode = mEdgeNodeIndices[index ^ 1];
+ if(outboundNode.index() == IG_INVALID_NODE ||
+ !mNodes[outboundNode.index()].isActive())
+ {
+ EdgeIndex idx = index/2;
+ Edge& edge = mEdges[idx]; //InstanceIndex/2 = edgeIndex
+ //PX_ASSERT(edge.isActive()); //The edge must currently be inactive because the node was active
+ //Deactivate the edge if both nodes connected are inactive OR if one node is static/kinematic and the other is inactive...
+ PX_ASSERT(mEdgeNodeIndices[index & (~1)].index() == IG_INVALID_NODE || !mNodes[mEdgeNodeIndices[index & (~1)].index()].isActive());
+ PX_ASSERT(mEdgeNodeIndices[index | 1].index() == IG_INVALID_NODE || !mNodes[mEdgeNodeIndices[index | 1].index()].isActive());
+ if(edge.isActive())
+ {
+ edge.deactivateEdge();
+ mActiveEdgeCount[edge.mEdgeType]--;
+ removeEdgeFromActivatingList(idx);
+ mDeactivatingEdges[edge.mEdgeType].pushBack(idx);
+ }
+ }
+ index = instance.mNextEdge;
+ }
+ }
+
+}
+
+bool IslandSim::canFindRoot(NodeIndex startNode, NodeIndex targetNode, Ps::Array<NodeIndex>* visitedNodes)
+{
+ if(visitedNodes)
+ visitedNodes->pushBack(startNode);
+ if(startNode.index() == targetNode.index())
+ return true;
+ Cm::BitMap visitedState;
+ visitedState.resizeAndClear(mNodes.size());
+
+ Ps::Array<NodeIndex> stack;
+
+ stack.pushBack(startNode);
+
+ visitedState.set(startNode.index());
+
+ do
+ {
+ NodeIndex currentIndex = stack.popBack();
+ Node& currentNode = mNodes[currentIndex.index()];
+
+ EdgeInstanceIndex currentEdge = currentNode.mFirstEdgeIndex;
+
+ while(currentEdge != IG_INVALID_EDGE)
+ {
+ EdgeInstance& edge = mEdgeInstances[currentEdge];
+ NodeIndex outboundNode = mEdgeNodeIndices[currentEdge ^ 1];
+ if(outboundNode.index() != IG_INVALID_NODE && !mNodes[outboundNode.index()].isKinematic() && !visitedState.test(outboundNode.index()))
+ {
+ if(outboundNode.index() == targetNode.index())
+ {
+ return true;
+ }
+
+ visitedState.set(outboundNode.index());
+ stack.pushBack(outboundNode);
+ if(visitedNodes)
+ visitedNodes->pushBack(outboundNode);
+ }
+
+ currentEdge = edge.mNextEdge;
+ }
+
+ }
+ while(stack.size());
+
+ return false;
+
+}
+
+
+
+void IslandSim::unwindRoute(PxU32 traversalIndex, NodeIndex lastNode, PxU32 hopCount, IslandId id)
+{
+ //We have found either a witness *or* the root node with this traversal. In the event of finding the root node, hopCount will be 0. In the event of finding
+ //a witness, hopCount will be the hopCount that witness reported as being the distance to the root.
+
+ PxU32 currIndex = traversalIndex;
+ PxU32 hc = hopCount+1; //Add on 1 for the hop to the witness/root node.
+ do
+ {
+ TraversalState& state = mVisitedNodes[currIndex];
+ mHopCounts[state.mNodeIndex.index()] = hc++;
+ mIslandIds[state.mNodeIndex.index()] = id;
+ mFastRoute[state.mNodeIndex.index()] = lastNode;
+ currIndex = state.mPrevIndex;
+ lastNode = state.mNodeIndex;
+ }
+ while(currIndex != IG_INVALID_NODE);
+}
+
+void IslandSim::activateIsland(IslandId islandId)
+{
+ Island& island = mIslands[islandId];
+ PX_ASSERT(!mIslandAwake.test(islandId));
+ PX_ASSERT(island.mActiveIndex == IG_INVALID_ISLAND);
+
+ NodeIndex currentNode = island.mRootNode;
+ while(currentNode.index() != IG_INVALID_NODE)
+ {
+ activateNodeInternal(currentNode);
+ currentNode = mNodes[currentNode.index()].mNextNode;
+ }
+ markIslandActive(islandId);
+}
+
+void IslandSim::deactivateIsland(IslandId islandId)
+{
+ PX_ASSERT(mIslandAwake.test(islandId));
+ Island& island = mIslands[islandId];
+
+ NodeIndex currentNode = island.mRootNode;
+ while(currentNode.index() != IG_INVALID_NODE)
+ {
+ Node& node = mNodes[currentNode.index()];
+ //if(mActiveNodeIndex[currentNode.index()] < mInitialActiveNodeCount[node.mType])
+ mNodesToPutToSleep[node.mType].pushBack(currentNode); //If this node was previously active, then push it to the list of nodes to deactivate
+ deactivateNodeInternal(currentNode);
+ currentNode = node.mNextNode;
+ }
+ markIslandInactive(islandId);
+}
+
+
+void IslandSim::wakeIslands()
+{
+ PX_PROFILE_ZONE("Basic.wakeIslands", getContextId());
+
+ //(1) Iterate over activating nodes and activate them
+
+
+ PxU32 originalActiveIslands = mActiveIslands.size();
+
+ for (PxU32 a = 0; a < Edge::eEDGE_TYPE_COUNT; ++a)
+ {
+ for (PxU32 i = 0, count = mActivatedEdges[a].size(); i < count; ++i)
+ {
+ IG::Edge& edge = mEdges[mActivatedEdges[a][i]];
+ edge.mEdgeState &= (~Edge::eACTIVATING);
+ }
+
+ }
+
+ mActivatedEdges[0].forceSize_Unsafe(0);
+ mActivatedEdges[1].forceSize_Unsafe(0);
+ /*mInitialActiveEdgeCount[0] = mActiveEdges[0].size();
+ mInitialActiveEdgeCount[1] = mActiveEdges[1].size();*/
+
+ for(PxU32 a = 0; a < mActivatingNodes.size(); ++a)
+ {
+ NodeIndex wakeNode = mActivatingNodes[a];
+
+ IslandId islandId = mIslandIds[wakeNode.index()];
+
+ Node& node = mNodes[wakeNode.index()];
+ node.clearActivating();
+ if(islandId != IG_INVALID_ISLAND)
+ {
+ if(!mIslandAwake.test(islandId))
+ {
+ markIslandActive(islandId);
+ }
+ mActiveNodeIndex[wakeNode.index()] = IG_INVALID_NODE; //Mark active node as invalid.
+ activateNodeInternal(wakeNode);
+ }
+ else
+ {
+ PX_ASSERT(node.isKinematic());
+ node.setActive();
+ PX_ASSERT(mActiveNodeIndex[wakeNode.index()] == a);
+ mActiveNodeIndex[wakeNode.index()] = mActiveKinematicNodes.size();
+ mActiveKinematicNodes.pushBack(wakeNode);
+
+ //Wake up the islands connected to this waking kinematic!
+ EdgeInstanceIndex index = node.mFirstEdgeIndex;
+ while(index != IG_INVALID_EDGE)
+ {
+ EdgeInstance& edgeInstance = mEdgeInstances[index];
+
+ NodeIndex outboundNode = mEdgeNodeIndices[index ^ 1];
+ //Edge& edge = mEdges[index/2];
+ //if(edge.isConnected()) //Only wake up if the edge is not connected...
+ NodeIndex nodeIndex = outboundNode;
+
+ if (nodeIndex.isStaticBody() || mIslandIds[nodeIndex.index()] == IG_INVALID_ISLAND)
+ {
+ //If the edge connects to a static body *or* it connects to a node which is not part of an island (i.e. a kinematic), then activate the edge
+ EdgeIndex idx = index / 2;
+ Edge& edge = mEdges[idx];
+ if (!edge.isActive() && edge.getEdgeType() != IG::Edge::eCONSTRAINT)
+ {
+ //Make the edge active...
+ PX_ASSERT(mEdgeNodeIndices[idx * 2].index() == IG_INVALID_NODE || !mNodes[mEdgeNodeIndices[idx * 2].index()].isActive() || mNodes[mEdgeNodeIndices[idx * 2].index()].isKinematic());
+ PX_ASSERT(mEdgeNodeIndices[idx * 2 + 1].index() == IG_INVALID_NODE || !mNodes[mEdgeNodeIndices[idx * 2 + 1].index()].isActive() || mNodes[mEdgeNodeIndices[idx * 2 + 1].index()].isKinematic());
+
+ markEdgeActive(idx);
+ edge.activateEdge();
+
+ }
+ }
+ else
+ {
+ IslandId connectedIslandId = mIslandIds[nodeIndex.index()];
+ if(!mIslandAwake.test(connectedIslandId))
+ {
+ //Wake up that island
+ markIslandActive(connectedIslandId);
+ }
+ }
+
+ index = edgeInstance.mNextEdge;
+ }
+ }
+ }
+
+ mInitialActiveNodeCount[0] = mActiveNodes[0].size();
+ mInitialActiveNodeCount[1] = mActiveNodes[1].size();
+
+ mActivatingNodes.forceSize_Unsafe(0);
+
+ for(PxU32 a = originalActiveIslands; a < mActiveIslands.size(); ++a)
+ {
+ Island& island = mIslands[mActiveIslands[a]];
+
+ NodeIndex currentNode = island.mRootNode;
+ while(currentNode.index() != IG_INVALID_NODE)
+ {
+ activateNodeInternal(currentNode);
+ currentNode = mNodes[currentNode.index()].mNextNode;
+ }
+ }
+}
+
+void IslandSim::wakeIslands2()
+{
+ PxU32 originalActiveIslands = mActiveIslands.size();
+
+ for (PxU32 a = 0; a < mActivatingNodes.size(); ++a)
+ {
+ NodeIndex wakeNode = mActivatingNodes[a];
+
+ IslandId islandId = mIslandIds[wakeNode.index()];
+
+ Node& node = mNodes[wakeNode.index()];
+ node.clearActivating();
+ if (islandId != IG_INVALID_ISLAND)
+ {
+ if (!mIslandAwake.test(islandId))
+ {
+ markIslandActive(islandId);
+ }
+ mActiveNodeIndex[wakeNode.index()] = IG_INVALID_NODE; //Mark active node as invalid.
+ activateNodeInternal(wakeNode);
+ }
+ else
+ {
+ PX_ASSERT(node.isKinematic());
+ node.setActive();
+ PX_ASSERT(mActiveNodeIndex[wakeNode.index()] == a);
+ mActiveNodeIndex[wakeNode.index()] = mActiveKinematicNodes.size();
+ mActiveKinematicNodes.pushBack(wakeNode);
+
+ //Wake up the islands connected to this waking kinematic!
+ EdgeInstanceIndex index = node.mFirstEdgeIndex;
+ while (index != IG_INVALID_EDGE)
+ {
+ EdgeInstance& edgeInstance = mEdgeInstances[index];
+
+ NodeIndex outboundNode = mEdgeNodeIndices[index ^ 1];
+ //Edge& edge = mEdges[index/2];
+ //if(edge.isConnected()) //Only wake up if the edge is not connected...
+ NodeIndex nodeIndex = outboundNode;
+
+ if (nodeIndex.isStaticBody() || mIslandIds[nodeIndex.index()] == IG_INVALID_ISLAND)
+ {
+ //If the edge connects to a static body *or* it connects to a node which is not part of an island (i.e. a kinematic), then activate the edge
+ EdgeIndex idx = index / 2;
+ Edge& edge = mEdges[idx];
+ if (!edge.isActive() && edge.getEdgeType() != IG::Edge::eCONSTRAINT)
+ {
+ //Make the edge active...
+ PX_ASSERT(mEdgeNodeIndices[idx * 2].index() == IG_INVALID_NODE || !mNodes[mEdgeNodeIndices[idx * 2].index()].isActive() || mNodes[mEdgeNodeIndices[idx * 2].index()].isKinematic());
+ PX_ASSERT(mEdgeNodeIndices[idx * 2 + 1].index() == IG_INVALID_NODE || !mNodes[mEdgeNodeIndices[idx * 2 + 1].index()].isActive() || mNodes[mEdgeNodeIndices[idx * 2 + 1].index()].isKinematic());
+
+ markEdgeActive(idx);
+ edge.activateEdge();
+
+ }
+ }
+ else
+ {
+ IslandId connectedIslandId = mIslandIds[nodeIndex.index()];
+ if (!mIslandAwake.test(connectedIslandId))
+ {
+ //Wake up that island
+ markIslandActive(connectedIslandId);
+ }
+ }
+
+ index = edgeInstance.mNextEdge;
+ }
+ }
+ }
+
+ mActivatingNodes.forceSize_Unsafe(0);
+
+ for (PxU32 a = originalActiveIslands; a < mActiveIslands.size(); ++a)
+ {
+ Island& island = mIslands[mActiveIslands[a]];
+
+ NodeIndex currentNode = island.mRootNode;
+ while (currentNode.index() != IG_INVALID_NODE)
+ {
+ activateNodeInternal(currentNode);
+ currentNode = mNodes[currentNode.index()].mNextNode;
+ }
+ }
+}
+
+void IslandSim::insertNewEdges()
+{
+ PX_PROFILE_ZONE("Basic.insertNewEdges", getContextId());
+
+ mEdgeInstances.reserve(mEdges.capacity()*2);
+
+ for(PxU32 i = 0; i < Edge::eEDGE_TYPE_COUNT; ++i)
+ {
+ for(PxU32 a = 0; a < mDirtyEdges[i].size(); ++a)
+ {
+ EdgeIndex edgeIndex = mDirtyEdges[i][a];
+
+ Edge& edge = mEdges[edgeIndex];
+
+ if(!edge.isPendingDestroyed())
+ {
+ //PX_ASSERT(!edge.isInserted());
+ if(!edge.isInserted())
+ {
+ addConnectionToGraph(edgeIndex);
+ edge.setInserted();
+ }
+ }
+ }
+ }
+}
+
+void IslandSim::removeDestroyedEdges()
+{
+ PX_PROFILE_ZONE("Basic.removeDestroyedEdges", getContextId());
+
+ for(PxU32 a = 0; a < mDestroyedEdges.size(); ++a)
+ {
+ EdgeIndex edgeIndex = mDestroyedEdges[a];
+
+ Edge& edge = mEdges[edgeIndex];
+
+ if(edge.isPendingDestroyed())
+ {
+ if(!edge.isInDirtyList() && edge.isInserted())
+ {
+ PX_ASSERT(edge.isInserted());
+ removeConnectionInternal(edgeIndex);
+ removeConnectionFromGraph(edgeIndex);
+ //edge.clearInserted();
+ }
+ //edge.clearDestroyed();
+ }
+ }
+}
+
+void IslandSim::processNewEdges()
+{
+ PX_PROFILE_ZONE("Basic.processNewEdges", getContextId());
+ //Stage 1: we process the list of new pairs. To do this, we need to first sort them based on a predicate...
+
+ insertNewEdges();
+
+ mHopCounts.resize(mNodes.size()); //Make sure we have enough space for hop counts for all nodes
+ mFastRoute.resize(mNodes.size());
+
+
+ for(PxU32 i = 0; i < Edge::eEDGE_TYPE_COUNT; ++i)
+ {
+ for(PxU32 a = 0; a < mDirtyEdges[i].size(); ++a)
+ {
+ EdgeIndex edgeIndex = mDirtyEdges[i][a];
+ Edge& edge = mEdges[edgeIndex];
+
+ /*PX_ASSERT(edge.mState != Edge::eDESTROYED || ((edge.mNode1.index() == IG_INVALID_NODE || mNodes[edge.mNode1.index()].isKinematic() || mNodes[edge.mNode1.index()].isActive() == false) &&
+ (edge.mNode2.index() == IG_INVALID_NODE || mNodes[edge.mNode2.index()].isKinematic() || mNodes[edge.mNode2.index()].isActive() == false)));*/
+
+ //edge.clearInDirtyList();
+
+
+ //We do not process either destroyed or disconnected edges
+ if(/*edge.isConnected() && */!edge.isPendingDestroyed())
+ {
+ //Conditions:
+ //(1) Neither body is in an island (static/kinematics are never in islands) so we need to create a new island containing these bodies
+ // or just 1 body if the other is kinematic/static
+ //(2) Both bodies are already in the same island. Update root node hop count estimates for the bodies if a route through the new connection
+ // is shorter for either body
+ //(3) One body is already in an island and the other isn't, so we just add the new body to the existing island.
+ //(4) Both bodies are in different islands. In that case, we merge the islands
+
+ NodeIndex nodeIndex1 = mEdgeNodeIndices[2 * edgeIndex];
+ NodeIndex nodeIndex2 = mEdgeNodeIndices[2 * edgeIndex+1];
+
+ IslandId islandId1 = nodeIndex1.index() == IG_INVALID_NODE ? IG_INVALID_ISLAND : mIslandIds[nodeIndex1.index()];
+ IslandId islandId2 = nodeIndex2.index() == IG_INVALID_NODE ? IG_INVALID_ISLAND : mIslandIds[nodeIndex2.index()];
+
+ //TODO - wake ups!!!!
+ //If one of the nodes is awake and the other is asleep, we need to wake 'em up
+
+ //When a node is activated, the island must also be activated...
+
+ bool active1 = nodeIndex1.index() != IG_INVALID_NODE && mNodes[nodeIndex1.index()].isActive();
+ bool active2 = nodeIndex2.index() != IG_INVALID_NODE && mNodes[nodeIndex2.index()].isActive();
+
+ IslandId islandId = IG_INVALID_ISLAND;
+
+ if(islandId1 == IG_INVALID_ISLAND && islandId2 == IG_INVALID_ISLAND)
+ {
+ //All nodes should be introduced in an island now unless they are static or kinematic. Therefore, if we get here, we have an edge
+ //between 2 kinematic nodes or a kinematic and static node. These should not influence island management so we should just ignore
+ //these edges.
+ }
+ else if(islandId1 == islandId2)
+ {
+ islandId = islandId1;
+ if(active1 || active2)
+ {
+ PX_ASSERT(mIslandAwake.test(islandId1)); //If we got here, where the 2 were already in an island, if 1 node is awake, the whole island must be awake
+ }
+ //Both bodies in the same island. Nothing major to do already but we should see if this creates a shorter path to root for either node
+ PxU32 hopCount1 = mHopCounts[nodeIndex1.index()];
+ PxU32 hopCount2 = mHopCounts[nodeIndex2.index()];
+ if((hopCount1+1) < hopCount2)
+ {
+ //It would be faster for node 2 to go through node 1
+ mHopCounts[nodeIndex2.index()] = hopCount1 + 1;
+ mFastRoute[nodeIndex2.index()] = nodeIndex1;
+ }
+ else if((hopCount2+1) < hopCount1)
+ {
+ //It would be faster for node 1 to go through node 2
+ mHopCounts[nodeIndex1.index()] = hopCount2 + 1;
+ mFastRoute[nodeIndex1.index()] = nodeIndex2;
+ }
+
+ //No need to activate/deactivate the island. Its state won't have changed
+
+ }
+ else if(islandId1 == IG_INVALID_ISLAND)
+ {
+ islandId = islandId2;
+ if (nodeIndex1.index() != IG_INVALID_NODE)
+ {
+ if (!mNodes[nodeIndex1.index()].isKinematic())
+ {
+ PX_ASSERT(islandId2 != IG_INVALID_ISLAND);
+ //We need to add node 1 to island2
+ PX_ASSERT(mNodes[nodeIndex1.index()].mNextNode.index() == IG_INVALID_NODE); //Ensure that this node is not in any other island
+ PX_ASSERT(mNodes[nodeIndex1.index()].mPrevNode.index() == IG_INVALID_NODE); //Ensure that this node is not in any other island
+
+ Island& island = mIslands[islandId2];
+
+ Node& lastNode = mNodes[island.mLastNode.index()];
+
+ PX_ASSERT(lastNode.mNextNode.index() == IG_INVALID_NODE);
+
+ Node& node = mNodes[nodeIndex1.index()];
+ lastNode.mNextNode = nodeIndex1;
+ node.mPrevNode = island.mLastNode;
+ island.mLastNode = nodeIndex1;
+ island.mSize[node.mType]++;
+ mIslandIds[nodeIndex1.index()] = islandId2;
+ mHopCounts[nodeIndex1.index()] = mHopCounts[nodeIndex2.index()] + 1;
+ mFastRoute[nodeIndex1.index()] = nodeIndex2;
+
+ if(active1 || active2)
+ {
+ if(!mIslandAwake.test(islandId2))
+ {
+ //This island wasn't already awake, so need to wake the whole island up
+ activateIsland(islandId2);
+ }
+ if(!active1)
+ {
+ //Wake up this node...
+ activateNodeInternal(nodeIndex1);
+ }
+ }
+ }
+ else if(active1 && !active2)
+ {
+ //Active kinematic object -> wake island!
+ activateIsland(islandId2);
+ }
+ }
+ else
+ {
+ //A new touch with a static body...
+ Node& node = mNodes[nodeIndex2.index()];
+ node.mStaticTouchCount++; //Increment static touch counter on the body
+ //Island& island = mIslands[islandId2];
+ //island.mStaticTouchCount++; //Increment static touch counter on the island
+ mIslandStaticTouchCount[islandId2]++;
+
+ }
+ }
+ else if (islandId2 == IG_INVALID_ISLAND)
+ {
+ islandId = islandId1;
+ if (nodeIndex2.index() != IG_INVALID_NODE)
+ {
+ if (!mNodes[nodeIndex2.index()].isKinematic())
+ {
+ PX_ASSERT(islandId1 != IG_INVALID_NODE);
+ //We need to add node 1 to island2
+ PX_ASSERT(mNodes[nodeIndex2.index()].mNextNode.index() == IG_INVALID_NODE); //Ensure that this node is not in any other island
+ PX_ASSERT(mNodes[nodeIndex2.index()].mPrevNode.index() == IG_INVALID_NODE); //Ensure that this node is not in any other island
+
+ Island& island = mIslands[islandId1];
+
+ Node& lastNode = mNodes[island.mLastNode.index()];
+ PX_ASSERT(lastNode.mNextNode.index() == IG_INVALID_NODE);
+ Node& node = mNodes[nodeIndex2.index()];
+ lastNode.mNextNode = nodeIndex2;
+ node.mPrevNode = island.mLastNode;
+ island.mLastNode = nodeIndex2;
+ island.mSize[node.mType]++;
+ mIslandIds[nodeIndex2.index()] = islandId1;
+ mHopCounts[nodeIndex2.index()] = mHopCounts[nodeIndex1.index()] + 1;
+ mFastRoute[nodeIndex2.index()] = nodeIndex1;
+
+ if(active1 || active2)
+ {
+ if(!mIslandAwake.test(islandId1))
+ {
+ //This island wasn't already awake, so need to wake the whole island up
+ activateIsland(islandId1);
+ }
+ if(!active1)
+ {
+ //Wake up this node...
+ activateNodeInternal(nodeIndex2);
+ }
+ }
+ }
+ else if(active2 && !active1)
+ {
+ //Active kinematic object -> wake island!
+ activateIsland(islandId1);
+ }
+ }
+ else
+ {
+ //New static touch
+ //A new touch with a static body...
+ Node& node = mNodes[nodeIndex1.index()];
+ node.mStaticTouchCount++; //Increment static touch counter on the body
+ //Island& island = mIslands[islandId1];
+ mIslandStaticTouchCount[islandId1]++;
+ //island.mStaticTouchCount++; //Increment static touch counter on the island
+ }
+
+ }
+ else
+ {
+ PX_ASSERT(islandId1 != islandId2);
+ PX_ASSERT(islandId1 != IG_INVALID_ISLAND && islandId2 != IG_INVALID_ISLAND);
+
+ if(active1 || active2)
+ {
+ //One of the 2 islands was awake, so need to wake the other one! We do this now, before we merge the islands, to ensure that all
+ //the bodies are activated
+ if(!mIslandAwake.test(islandId1))
+ {
+ //This island wasn't already awake, so need to wake the whole island up
+ activateIsland(islandId1);
+ }
+ if(!mIslandAwake.test(islandId2))
+ {
+ //This island wasn't already awake, so need to wake the whole island up
+ activateIsland(islandId2);
+ }
+ }
+
+ //OK. We need to merge these islands together...
+ islandId = mergeIslands(islandId1, islandId2, nodeIndex1, nodeIndex2);
+ }
+
+ if(islandId != IG_INVALID_ISLAND)
+ {
+ //Add new edge to existing island
+ Island& island = mIslands[islandId];
+ addEdgeToIsland(island, edgeIndex);
+ }
+ }
+ }
+
+ }
+
+}
+
+bool IslandSim::isPathTo(NodeIndex startNode, NodeIndex targetNode)
+{
+ Node& node = mNodes[startNode.index()];
+
+ EdgeInstanceIndex index = node.mFirstEdgeIndex;
+ while(index != IG_INVALID_EDGE)
+ {
+ EdgeInstance& instance = mEdgeInstances[index];
+ if(/*mEdges[index/2].isConnected() &&*/ mEdgeNodeIndices[index^1].index() == targetNode.index())
+ return true;
+ index = instance.mNextEdge;
+ }
+ return false;
+}
+
+bool IslandSim::tryFastPath(NodeIndex startNode, NodeIndex targetNode, IslandId islandId)
+{
+ PX_UNUSED(startNode);
+ PX_UNUSED(targetNode);
+
+ NodeIndex currentNode = startNode;
+
+ PxU32 currentVisitedNodes = mVisitedNodes.size();
+
+ PxU32 depth = 0;
+
+ bool found = false;
+ do
+ {
+ //Get the fast path from this node...
+
+ if(mVisitedState.test(currentNode.index()))
+ {
+ found = mIslandIds[currentNode.index()] != IG_INVALID_ISLAND; //Already visited and not tagged with invalid island == a witness!
+ break;
+ }
+ if( currentNode.index() == targetNode.index())
+ {
+ found = true;
+ break;
+ }
+
+ mVisitedNodes.pushBack(TraversalState(currentNode, mVisitedNodes.size(), mVisitedNodes.size()-1, depth++));
+
+ PX_ASSERT(mFastRoute[currentNode.index()].index() == IG_INVALID_NODE || isPathTo(currentNode, mFastRoute[currentNode.index()]));
+
+ mIslandIds[currentNode.index()] = IG_INVALID_ISLAND;
+ mVisitedState.set(currentNode.index());
+
+ currentNode = mFastRoute[currentNode.index()];
+ }
+ while(currentNode.index() != IG_INVALID_NODE);
+
+ for(PxU32 a = currentVisitedNodes; a < mVisitedNodes.size(); ++a)
+ {
+ TraversalState& state = mVisitedNodes[a];
+ mIslandIds[state.mNodeIndex.index()] = islandId;
+ }
+
+ if(!found)
+ {
+ for(PxU32 a = currentVisitedNodes; a < mVisitedNodes.size(); ++a)
+ {
+ TraversalState& state = mVisitedNodes[a];
+ mVisitedState.reset(state.mNodeIndex.index());
+ }
+
+ mVisitedNodes.forceSize_Unsafe(currentVisitedNodes);
+ }
+ return found;
+
+}
+
+bool IslandSim::findRoute(NodeIndex startNode, NodeIndex targetNode, IslandId islandId)
+{
+
+ //Firstly, traverse the fast path and tag up witnesses. TryFastPath can fail. In that case, no witnesses are left but this node is permitted to report
+ //that it is still part of the island. Whichever node lost its fast path will be tagged as dirty and will be responsible for recovering the fast path
+ //and tagging up the visited nodes
+ if(mFastRoute[startNode.index()].index() != IG_INVALID_NODE)
+ {
+ if(tryFastPath(startNode, targetNode, islandId))
+ return true;
+
+ //Try fast path can either be successful or not. If it was successful, then we had a valid fast path cached and all nodes on that fast path were tagged
+ //as witness nodes (visited and with a valid island ID). If the fast path was not successful, then no nodes were tagged as witnesses.
+ //Technically, we need to find a route to the root node but, as an optimization, we can simply return true from here with no witnesses added.
+ //Whichever node actually broke the "fast path" will also be on the list of dirty nodes and will be processed later.
+ //If that broken edge triggered an island separation, this node will be re-visited and added to that island, otherwise
+ //the path to the root node will be re-established. The end result is the same - the island state is computed - this just saves us some work.
+ //return true;
+ }
+
+ {
+ //If we got here, there was no fast path. Therefore, we need to fall back on searching for the root node. This is optimized by using "hop counts".
+ //These are per-node counts that indicate the expected number of hops from this node to the root node. These are lazily evaluated and updated
+ //as new edges are formed or when traversals occur to re-establish islands. As a result, they may be inaccurate but they still serve the purpose
+ //of guiding our search to minimize the chances of us doing an exhaustive search to find the root node.
+ mIslandIds[startNode.index()] = IG_INVALID_ISLAND;
+ TraversalState* startTraversal = &mVisitedNodes.pushBack(TraversalState(startNode, mVisitedNodes.size(), IG_INVALID_NODE, 0));
+ mVisitedState.set(startNode.index());
+ QueueElement element(startTraversal, mHopCounts[startNode.index()]);
+ mPriorityQueue.push(element);
+
+ do
+ {
+ QueueElement currentQE = mPriorityQueue.pop();
+
+ TraversalState& currentState = *currentQE.mState;
+
+ Node& currentNode = mNodes[currentState.mNodeIndex.index()];
+
+ EdgeInstanceIndex edge = currentNode.mFirstEdgeIndex;
+
+ while(edge != IG_INVALID_EDGE)
+ {
+ EdgeInstance& instance = mEdgeInstances[edge];
+ {
+ NodeIndex nextIndex = mEdgeNodeIndices[edge ^ 1];
+
+ //Static or kinematic nodes don't connect islands.
+ if(nextIndex.index() != IG_INVALID_NODE && !mNodes[nextIndex.index()].isKinematic())
+ {
+ if(nextIndex.index() == targetNode.index())
+ {
+ unwindRoute(currentState.mCurrentIndex, nextIndex, 0, islandId);
+ return true;
+ }
+
+ if(mVisitedState.test(nextIndex.index()))
+ {
+ //We already visited this node. This means that it's either in the priority queue already or we
+ //visited in on a previous pass. If it was visited on a previous pass, then it already knows what island it's in.
+ //We now need to test the island id to find out if this node knows the root.
+ //If it has a valid root id, that id *is* our new root. We can guesstimate our hop count based on the node's properties
+
+ IslandId visitedIslandId = mIslandIds[nextIndex.index()];
+ if(visitedIslandId != IG_INVALID_ISLAND)
+ {
+ //If we get here, we must have found a node that knows a route to our root node. It must not be a different island
+ //because that would caused me to have been visited already because totally separate islands trigger a full traversal on
+ //the orphaned side.
+ PX_ASSERT(visitedIslandId == islandId);
+ unwindRoute(currentState.mCurrentIndex, nextIndex, mHopCounts[nextIndex.index()], islandId);
+ return true;
+ }
+ }
+ else
+ {
+ //This node has not been visited yet, so we need to push it into the stack and continue traversing
+ TraversalState* state = &mVisitedNodes.pushBack(TraversalState(nextIndex, mVisitedNodes.size(), currentState.mCurrentIndex, currentState.mDepth+1));
+ QueueElement qe(state, mHopCounts[nextIndex.index()]);
+ mPriorityQueue.push(qe);
+ mVisitedState.set(nextIndex.index());
+ PX_ASSERT(mIslandIds[nextIndex.index()] == islandId);
+ mIslandIds[nextIndex.index()] = IG_INVALID_ISLAND; //Flag as invalid island until we know whether we can find root or an island id.
+ }
+ }
+ }
+
+ edge = instance.mNextEdge;
+ }
+ }
+ while(mPriorityQueue.size());
+
+ return false;
+ }
+}
+
+
+void IslandSim::processLostEdges(Ps::Array<NodeIndex>& destroyedNodes, bool allowDeactivation, bool permitKinematicDeactivation,
+ PxU32 dirtyNodeLimit)
+{
+ PX_PROFILE_ZONE("Basic.processLostEdges", getContextId());
+ //At this point, all nodes and edges are activated.
+
+ //Bit map for visited
+ mVisitedState.resizeAndClear(mNodes.size());
+
+ //Reserve space on priority queue for at least 1024 nodes. It will resize if more memory is required during traversal.
+ mPriorityQueue.reserve(1024);
+
+ mIslandSplitEdges[0].reserve(1024);
+ mIslandSplitEdges[1].reserve(1024);
+
+ mVisitedNodes.reserve(mNodes.size()); //Make sure we have enough space for all nodes!
+
+ const PxU32 nbDestroyedEdges = mDestroyedEdges.size();
+ PX_UNUSED(nbDestroyedEdges);
+ {
+ PX_PROFILE_ZONE("Basic.removeEdgesFromIslands", getContextId());
+ for(PxU32 a = 0; a < mDestroyedEdges.size(); ++a)
+ {
+ EdgeIndex lostIndex = mDestroyedEdges[a];
+ Edge& lostEdge = mEdges[lostIndex];
+
+ if(lostEdge.isPendingDestroyed() && !lostEdge.isInDirtyList() )
+ {
+ //Process this edge...
+ if(!lostEdge.isReportOnlyDestroy() && lostEdge.isInserted())
+ {
+ PxU32 index1 = mEdgeNodeIndices[mDestroyedEdges[a] * 2].index();
+ PxU32 index2 = mEdgeNodeIndices[mDestroyedEdges[a] * 2 + 1].index();
+
+ IslandId islandId = IG_INVALID_ISLAND;
+ if(index1 != IG_INVALID_NODE && index2 != IG_INVALID_NODE)
+ {
+ PX_ASSERT(mIslandIds[index1] == IG_INVALID_ISLAND || mIslandIds[index2] == IG_INVALID_ISLAND ||
+ mIslandIds[index1] == mIslandIds[index2]);
+ islandId = mIslandIds[index1] != IG_INVALID_ISLAND ? mIslandIds[index1] : mIslandIds[index2];
+ }
+ else if(index1 != IG_INVALID_NODE)
+ {
+ PX_ASSERT(index2 == IG_INVALID_NODE);
+ Node& node = mNodes[index1];
+ if(!node.isKinematic())
+ {
+ islandId = mIslandIds[index1];
+ node.mStaticTouchCount--;
+ //Island& island = mIslands[islandId];
+ mIslandStaticTouchCount[islandId]--;
+ //island.mStaticTouchCount--;
+ }
+ }
+ else if(index2 != IG_INVALID_NODE)
+ {
+ PX_ASSERT(index1 == IG_INVALID_NODE);
+ Node& node = mNodes[index2];
+ if(!node.isKinematic())
+ {
+ islandId = mIslandIds[index2];
+ node.mStaticTouchCount--;
+ //Island& island = mIslands[islandId];
+ mIslandStaticTouchCount[islandId]--;
+ //island.mStaticTouchCount--;
+ }
+ }
+
+ if(islandId != IG_INVALID_ISLAND)
+ {
+ //We need to remove this edge from the island
+ Island& island = mIslands[islandId];
+ removeEdgeFromIsland(island, lostIndex);
+ }
+ }
+
+ lostEdge.clearInserted();
+
+ }
+ }
+ }
+
+ if (allowDeactivation)
+ {
+ PX_PROFILE_ZONE("Basic.findPathsAndBreakIslands", getContextId());
+ Cm::BitMap::CircularIterator iter(mDirtyMap, mLastMapIndex);
+
+ //KS - process only this many dirty nodes, deferring future dirty nodes to subsequent frames.
+ //This means that it may take several frames for broken edges to trigger islands to completely break but this is better
+ //than triggering large performance spikes.
+ const PxU32 MaxCount = dirtyNodeLimit;
+
+ PxU32 count = 0;
+ PxU32 dirtyIdx;
+ while ((dirtyIdx = iter.getNext()) != Cm::BitMap::CircularIterator::DONE && (count++ < MaxCount))
+ {
+ mLastMapIndex = dirtyIdx + 1;
+ //Process dirty nodes. Figure out if we can make our way from the dirty node to the root.
+
+ mPriorityQueue.clear(); //Clear the queue used for traversal
+ mVisitedNodes.forceSize_Unsafe(0); //Clear the list of nodes in this island
+ NodeIndex dirtyNodeIndex(dirtyIdx);
+ Node& dirtyNode = mNodes[dirtyNodeIndex.index()];
+
+ //Check whether this node has already been touched. If it has been touched this frame, then its island state is reliable
+ //and we can just unclear the dirty flag on the body. If we were already visited, then the state should have already been confirmed in a
+ //previous pass.
+ if(!dirtyNode.isKinematic() && !dirtyNode.isDeleted() && !mVisitedState.test(dirtyNodeIndex.index()))
+ {
+ //We haven't visited this node in our island repair passes yet, so we still need to process until we've hit a visited node or found
+ //our root node. Note that, as soon as we hit a visited node that has already been processed in a previous pass, we know that we can rely
+ //on its island information although the hop counts may not be optimal. It also indicates that this island was not broken immediately because
+ //otherwise, the entire new sub-island would already have been visited and this node would have already had its new island state assigned.
+
+ //Indicate that I've been visited
+
+ IslandId islandId = mIslandIds[dirtyNodeIndex.index()];
+ Island& findIsland = mIslands[islandId];
+
+ NodeIndex searchNode = findIsland.mRootNode;//The node that we're searching for!
+
+ if(searchNode.index() != dirtyNodeIndex.index()) //If we are the root node, we don't need to do anything!
+ {
+ if(findRoute(dirtyNodeIndex, searchNode, islandId))
+ {
+ //We found the root node so let's let every visited node know that we found its root
+ //and we can also update our hop counts because we recorded how many hops it took to reach this
+ //node
+
+ //We already filled in the path to the root/witness with accurate hop counts. Now we just need to fill in the estimates
+ //for the remaining nodes and re-define their islandIds. We approximate their path to the root by just routing them through
+ //the route we already found.
+
+ //This loop works because mVisitedNodes are recorded in the order they were visited and we already filled in the critical path
+ //so the remainder of the paths will just fork from that path.
+
+ //Verify state (that we can see the root from this node)...
+
+ #if IG_SANITY_CHECKS
+ PX_ASSERT(canFindRoot(dirtyNode, searchNode, NULL)); //Verify that we found the connection
+ #endif
+
+ for(PxU32 b = 0; b < mVisitedNodes.size(); ++b)
+ {
+ TraversalState& state = mVisitedNodes[b];
+ if(mIslandIds[state.mNodeIndex.index()] == IG_INVALID_ISLAND)
+ {
+ mHopCounts[state.mNodeIndex.index()] = mHopCounts[mVisitedNodes[state.mPrevIndex].mNodeIndex.index()]+1;
+ mFastRoute[state.mNodeIndex.index()] = mVisitedNodes[state.mPrevIndex].mNodeIndex;
+ mIslandIds[state.mNodeIndex.index()] = islandId;
+ }
+ }
+ }
+ else
+ {
+ //If I traversed and could not find the root node, then I have established a new island. In this island, I am the root node
+ //and I will point all my nodes towards me. Furthermore, I have established how many steps it took to reach all nodes in my island
+
+ //OK. We need to separate the islands. We have a list of nodes that are part of the new island (mVisitedNodes) and we know that the
+ //first node in that list is the root node.
+
+
+ //OK, we need to remove all these actors from their current island, then add them to the new island...
+
+ Island& oldIsland = mIslands[islandId];
+ //We can just unpick these nodes from the island because they do not contain the root node (if they did, then we wouldn't be
+ //removing this node from the island at all). The only challenge is if we need to remove the last node. In that case
+ //we need to re-establish the new last node in the island but perhaps the simplest way to do that would be to traverse
+ //the island to establish the last node again
+
+ #if IG_SANITY_CHECKS
+ PX_ASSERT(!canFindRoot(dirtyNode, searchNode, NULL));
+ #endif
+
+ PxU32 totalStaticTouchCount = 0;
+ mIslandSplitEdges[0].forceSize_Unsafe(0);
+ mIslandSplitEdges[1].forceSize_Unsafe(0);
+ PxU32 size[2] = {0,0};
+
+ //NodeIndex lastIndex = oldIsland.mLastNode;
+
+ //size[node.mType] = 1;
+
+ for(PxU32 a = 0; a < mVisitedNodes.size(); ++a)
+ {
+ NodeIndex index = mVisitedNodes[a].mNodeIndex;
+ Node& node = mNodes[index.index()];
+
+ if(node.mNextNode.index() != IG_INVALID_NODE)
+ mNodes[node.mNextNode.index()].mPrevNode = node.mPrevNode;
+ else
+ oldIsland.mLastNode = node.mPrevNode;
+ if(node.mPrevNode.index() != IG_INVALID_NODE)
+ mNodes[node.mPrevNode.index()].mNextNode = node.mNextNode;
+
+ size[node.mType]++;
+
+ node.mNextNode.setIndices(IG_INVALID_NODE, 0);
+ node.mPrevNode.setIndices(IG_INVALID_NODE, 0);
+
+ PX_ASSERT(mNodes[oldIsland.mLastNode.index()].mNextNode.index() == IG_INVALID_NODE);
+
+ totalStaticTouchCount += node.mStaticTouchCount;
+
+ EdgeInstanceIndex idx = node.mFirstEdgeIndex;
+
+ while(idx != IG_INVALID_EDGE)
+ {
+ EdgeInstance& instance = mEdgeInstances[idx];
+ const EdgeIndex edgeIndex = idx/2;
+ Edge& edge = mEdges[edgeIndex];
+
+ //Only split the island if we're processing the first node or if the first node is infinte-mass
+ if (!(idx & 1) || (mEdgeNodeIndices[idx & (~1)].index() == IG_INVALID_NODE || mNodes[mEdgeNodeIndices[idx & (~1)].index()].isKinematic()))
+ {
+ //We will remove this edge from the island...
+ mIslandSplitEdges[edge.mEdgeType].pushBack(edgeIndex);
+
+ removeEdgeFromIsland(oldIsland, edgeIndex);
+
+ }
+ idx = instance.mNextEdge;
+ }
+
+ }
+
+ //oldIsland.mStaticTouchCount -= totalStaticTouchCount;
+ mIslandStaticTouchCount[islandId] -= totalStaticTouchCount;
+
+ oldIsland.mSize[0] -= size[0];
+ oldIsland.mSize[1] -= size[1];
+
+ //Now add all these nodes to the new island
+
+ //(1) Create the new island...
+ IslandId newIslandHandle = mIslandHandles.getHandle();
+ /*if(newIslandHandle == mIslands.capacity())
+ {
+ mIslands.reserve(2*mIslands.capacity() + 1);
+ }*/
+ mIslands.resize(PxMax(newIslandHandle+1, mIslands.size()));
+ mIslandStaticTouchCount.resize(PxMax(newIslandHandle+1, mIslandStaticTouchCount.size()));
+ Island& newIsland = mIslands[newIslandHandle];
+
+ if(mIslandAwake.test(islandId))
+ {
+ newIsland.mActiveIndex = mActiveIslands.size();
+ mActiveIslands.pushBack(newIslandHandle);
+ mIslandAwake.growAndSet(newIslandHandle); //Separated island, so it should be awake
+ }
+ else
+ {
+ mIslandAwake.growAndReset(newIslandHandle);
+ }
+
+ newIsland.mRootNode = dirtyNodeIndex;
+ mHopCounts[dirtyNodeIndex.index()] = 0;
+ mIslandIds[dirtyNodeIndex.index()] = newIslandHandle;
+ //newIsland.mTotalSize = mVisitedNodes.size();
+
+ mNodes[dirtyNodeIndex.index()].mPrevNode.setIndices(IG_INVALID_NODE, 0); //First node so doesn't have a preceding node
+ mFastRoute[dirtyNodeIndex.index()].setIndices(IG_INVALID_NODE, 0);
+
+ size[0] = 0; size[1] = 0;
+
+ size[dirtyNode.mType] = 1;
+
+ for(PxU32 a = 1; a < mVisitedNodes.size(); ++a)
+ {
+ NodeIndex index = mVisitedNodes[a].mNodeIndex;
+ Node& thisNode = mNodes[index.index()];
+ NodeIndex prevNodeIndex = mVisitedNodes[a-1].mNodeIndex;
+ thisNode.mPrevNode = prevNodeIndex;
+ mNodes[prevNodeIndex.index()].mNextNode = index;
+ size[thisNode.mType]++;
+ mIslandIds[index.index()] = newIslandHandle;
+ mHopCounts[index.index()] = mVisitedNodes[a].mDepth; //How many hops to root
+ mFastRoute[index.index()] = mVisitedNodes[mVisitedNodes[a].mPrevIndex].mNodeIndex;
+ }
+
+ newIsland.mSize[0] = size[0];
+ newIsland.mSize[1] = size[1];
+ //Last node in the island
+ NodeIndex lastIndex = mVisitedNodes[mVisitedNodes.size()-1].mNodeIndex;
+ mNodes[lastIndex.index()].mNextNode.setIndices(IG_INVALID_NODE, 0);
+ newIsland.mLastNode = lastIndex;
+ //newIsland.mStaticTouchCount = totalStaticTouchCount;
+ mIslandStaticTouchCount[newIslandHandle] = totalStaticTouchCount;
+ newIsland.mSize[0] = size[0];
+ newIsland.mSize[1] = size[1];
+
+ PX_ASSERT(mNodes[newIsland.mLastNode.index()].mNextNode.index() == IG_INVALID_NODE);
+
+ for(PxU32 j = 0; j < 2; ++j)
+ {
+ Ps::Array<EdgeIndex>& splitEdges = mIslandSplitEdges[j];
+ const PxU32 splitEdgeSize = splitEdges.size();
+ if(splitEdgeSize)
+ {
+ splitEdges.pushBack(IG_INVALID_EDGE); //Push in a dummy invalid edge to complete the connectivity
+ mEdges[splitEdges[0]].mNextIslandEdge = splitEdges[1];
+ for(PxU32 a = 1; a < splitEdgeSize; ++a)
+ {
+ EdgeIndex edgeIndex = splitEdges[a];
+ Edge& edge = mEdges[edgeIndex];
+ edge.mNextIslandEdge = splitEdges[a+1];
+ edge.mPrevIslandEdge = splitEdges[a-1];
+ }
+
+ newIsland.mFirstEdge[j] = splitEdges[0];
+ newIsland.mLastEdge[j] = splitEdges[splitEdgeSize-1];
+ newIsland.mEdgeCount[j] = splitEdgeSize;
+ }
+ }
+
+ }
+ }
+
+ }
+
+ dirtyNode.clearDirty();
+ mDirtyMap.reset(dirtyIdx);
+ }
+
+ if (count < MaxCount)
+ mLastMapIndex = 0;
+ //mDirtyNodes.forceSize_Unsafe(0);
+ }
+
+
+ {
+ PX_PROFILE_ZONE("Basic.clearDestroyedEdges", getContextId());
+ //Now process the lost edges...
+ for (PxU32 a = 0; a < mDestroyedEdges.size(); ++a)
+ {
+ //Process these destroyed edges. Recompute island information. Update the islands and hop counters accordingly
+ EdgeIndex index = mDestroyedEdges[a];
+
+ Edge& edge = mEdges[index];
+ if (edge.isPendingDestroyed())
+ {
+ //if(edge.mFirstPartitionEdge)
+ PartitionEdge* pEdge = mFirstPartitionEdges ? (*mFirstPartitionEdges)[index] : NULL;
+ if (pEdge)
+ {
+ mDestroyedPartitionEdges->pushBack(pEdge);
+ (*mFirstPartitionEdges)[index] = NULL; //Force first partition edge to NULL to ensure we don't have a clash
+ }
+ if (edge.isActive())
+ {
+ removeEdgeFromActivatingList(index); //TODO - can we remove this call? Can we handle this elsewhere, e.g. when destroying the nodes...
+ mActiveEdgeCount[edge.mEdgeType]--;
+ }
+
+ edge = Edge(); //Reset edge
+ mActiveContactEdges.growAndReset(index);
+ }
+ }
+
+ mDestroyedEdges.forceSize_Unsafe(0);
+ }
+
+ {
+ PX_PROFILE_ZONE("Basic.clearDestroyedNodes", getContextId());
+
+ for(PxU32 a = 0; a < destroyedNodes.size(); ++a)
+ {
+ NodeIndex nodeIndex = destroyedNodes[a];
+ IslandId islandId = mIslandIds[nodeIndex.index()];
+ Node& node = mNodes[nodeIndex.index()];
+ if(islandId != IG_INVALID_ISLAND)
+ {
+ Island& island = mIslands[islandId];
+
+ removeNodeFromIsland(island, nodeIndex);
+
+ mIslandIds[nodeIndex.index()] = IG_INVALID_ISLAND;
+
+ if((island.mSize[0] + island.mSize[1]) == 0)
+ {
+ mIslandHandles.freeHandle(islandId);
+ if(island.mActiveIndex != IG_INVALID_ISLAND)
+ {
+ IslandId replaceId = mActiveIslands[mActiveIslands.size()-1];
+ Island& replaceIsland = mIslands[replaceId];
+ replaceIsland.mActiveIndex = island.mActiveIndex;
+ mActiveIslands[island.mActiveIndex] = replaceId;
+ mActiveIslands.forceSize_Unsafe(mActiveIslands.size()-1);
+ island.mActiveIndex = IG_INVALID_ISLAND;
+ //island.mStaticTouchCount -= node.mStaticTouchCount; //Remove the static touch count from the island
+ mIslandStaticTouchCount[islandId] -= node.mStaticTouchCount;
+ }
+ mIslandAwake.reset(islandId);
+ island.mLastNode.setIndices(IG_INVALID_NODE, 0);
+ island.mRootNode.setIndices(IG_INVALID_NODE, 0);
+ island.mActiveIndex = IG_INVALID_ISLAND;
+ }
+ }
+
+ if(node.isKinematic())
+ {
+ if(mActiveNodeIndex[nodeIndex.index()] != IG_INVALID_NODE)
+ {
+ //Remove from the active kinematics list...
+ markKinematicInactive(nodeIndex);
+ }
+ }
+ else
+ {
+ if(mActiveNodeIndex[nodeIndex.index()] != IG_INVALID_NODE)
+ {
+ markInactive(nodeIndex);
+ }
+ }
+
+ node.reset();
+ }
+ }
+ //Now we need to produce the list of active edges and nodes!!!
+
+ //If we get here, we have a list of active islands. From this, we need to iterate over all active islands and establish if that island
+ //can, in fact, go to sleep. In order to become deactivated, all nodes in the island must be ready for sleeping...
+
+ if(allowDeactivation)
+ {
+ PX_PROFILE_ZONE("Basic.deactivation", getContextId());
+ for(PxU32 a = 0; a < mActiveIslands.size(); a++)
+ {
+ IslandId islandId = mActiveIslands[a];
+
+ mIslandAwake.reset(islandId);
+ }
+
+ //Loop over the active kinematic nodes and tag all islands touched by active kinematics as awake
+ for(PxU32 a = mActiveKinematicNodes.size(); a > 0; --a)
+ {
+ NodeIndex kinematicIndex = mActiveKinematicNodes[a-1];
+
+ Node& kinematicNode = mNodes[kinematicIndex.index()];
+
+ if(kinematicNode.isReadyForSleeping())
+ {
+ if(permitKinematicDeactivation)
+ {
+ kinematicNode.clearActive();
+ markKinematicInactive(kinematicIndex);
+ }
+ }
+ else //if(!kinematicNode.isReadyForSleeping())
+ {
+ //KS - if kinematic is active, then wake up all islands the kinematic is touching
+ EdgeInstanceIndex edgeId = kinematicNode.mFirstEdgeIndex;
+ while(edgeId != IG_INVALID_EDGE)
+ {
+ EdgeInstance& instance = mEdgeInstances[edgeId];
+ //Edge& edge = mEdges[edgeId/2];
+ //Only wake up islands if a connection was present
+ //if(edge.isConnected())
+ {
+ NodeIndex outNode = mEdgeNodeIndices[edgeId^1];
+ if(outNode.index() != IG_INVALID_NODE)
+ {
+ IslandId islandId = mIslandIds[outNode.index()];
+ if(islandId != IG_INVALID_ISLAND)
+ {
+ mIslandAwake.set(islandId);
+ PX_ASSERT(mIslands[islandId].mActiveIndex != IG_INVALID_ISLAND);
+ }
+ }
+ }
+ edgeId = instance.mNextEdge;
+ }
+ }
+ }
+
+ for(PxU32 a = mActiveIslands.size(); a > 0; --a)
+ {
+ IslandId islandId = mActiveIslands[a-1];
+
+ Island& island = mIslands[islandId];
+
+ bool canDeactivate = !mIslandAwake.test(islandId);
+ mIslandAwake.set(islandId);
+
+ //If it was touched by an active kinematic in the above loop, we can't deactivate it.
+ //Therefore, no point in testing the nodes in the island. They must remain awake
+ if(canDeactivate)
+ {
+ NodeIndex nodeId = island.mRootNode;
+ while(nodeId.index() != IG_INVALID_NODE)
+ {
+ Node& node = mNodes[nodeId.index()];
+ if(!node.isReadyForSleeping())
+ {
+ canDeactivate = false;
+ break;
+ }
+ nodeId = node.mNextNode;
+ }
+ if(canDeactivate)
+ {
+ //If all nodes in this island are ready for sleeping and there were no active
+ //kinematics interacting with the any bodies in the island, we can deactivate the island.
+ deactivateIsland(islandId);
+ }
+ }
+ }
+ }
+
+ {
+ PX_PROFILE_ZONE("Basic.resetDirtyEdges", getContextId());
+ for (PxU32 i = 0; i < Edge::eEDGE_TYPE_COUNT; ++i)
+ {
+ for (PxU32 a = 0; a < mDirtyEdges[i].size(); ++a)
+ {
+ Edge& edge = mEdges[mDirtyEdges[i][a]];
+ edge.clearInDirtyList();
+ }
+ mDirtyEdges[i].clear(); //All new edges processed
+ }
+ }
+
+}
+
+
+IslandId IslandSim::mergeIslands(IslandId island0, IslandId island1, NodeIndex node0, NodeIndex node1)
+{
+ Island& is0 = mIslands[island0];
+ Island& is1 = mIslands[island1];
+
+ //We defer this process and do it later instead. That way, if we have some pathalogical
+ //case where multiple islands get merged repeatedly, we don't end up repeatedly remapping all the nodes in those islands
+ //to their new island. Instead, we just choose the largest island and remap the smaller island to that.
+
+ PxU32 totalSize0 = is0.mSize[0] + is0.mSize[1];
+ PxU32 totalSize1 = is1.mSize[0] + is1.mSize[1];
+ if(totalSize0 > totalSize1)
+ {
+ mergeIslandsInternal(is0, is1, island0, island1, node0, node1);
+ mIslandAwake.reset(island1);
+ mIslandHandles.freeHandle(island1);
+ mFastRoute[node1.index()] = node0;
+ return island0;
+ }
+ else
+ {
+ mergeIslandsInternal(is1, is0, island1, island0, node1, node0);
+ mIslandAwake.reset(island0);
+ mIslandHandles.freeHandle(island0);
+ mFastRoute[node0.index()] = node1;
+ return island1;
+ }
+}
+
+bool IslandSim::checkInternalConsistency()
+{
+ //Loop over islands, confirming that the island data is consistent...
+ //Really expensive. Turn off unless investigating some random issue...
+#if 0
+ for (PxU32 a = 0; a < mIslands.size(); ++a)
+ {
+ Island& island = mIslands[a];
+
+ PxU32 expectedSize = island.mSize[0] + island.mSize[1];
+ bool metLastNode = expectedSize == 0;
+
+ NodeIndex nodeId = island.mRootNode;
+
+ while (nodeId.index() != IG_INVALID_NODE)
+ {
+
+ PX_ASSERT(mIslandIds[nodeId.index()] == a);
+
+ if (nodeId.index() == island.mLastNode.index())
+ {
+ metLastNode = true;
+ PX_ASSERT(mNodes[nodeId.index()].mNextNode.index() == IG_INVALID_NODE);
+ }
+
+ --expectedSize;
+
+ nodeId = mNodes[nodeId.index()].mNextNode;
+ }
+
+ PX_ASSERT(expectedSize == 0);
+ PX_ASSERT(metLastNode);
+ }
+#endif
+
+ return true;
+
+}
+
+void IslandSim::mergeIslandsInternal(Island& island0, Island& island1, IslandId islandId0, IslandId islandId1, NodeIndex nodeIndex0, NodeIndex nodeIndex1)
+{
+ PX_ASSERT((island0.mSize[0] + island0.mSize[1]) >= (island1.mSize[0] + island1.mSize[1])); //We only ever merge the smaller island to the larger island
+ //Stage 1 - we need to move all the nodes across to the new island ID (i.e. write all their new island indices, move them to the
+ //island and then also update their estimated hop counts to the root. As we don't want to do a full traversal at this point,
+ //instead, we estimate based on the route from the node to their previous root and then from that root to the new connection
+ //between the 2 islands. This is probably a very indirect route but it will be refined later.
+
+ //In this case, island1 is subsumed by island0
+
+ //It takes mHopCounts[nodeIndex1] to get from node1 to its old root. It takes mHopCounts[nodeIndex0] to get from nodeIndex0 to the new root
+ //and it takes 1 extra hop to go from node1 to node0. Therefore, a sub-optimal route can be planned going via the old root node that should take
+ //mHopCounts[nodeIndex0] + mHopCounts[nodeIndex1] + 1 + mHopCounts[nodeIndex] to travel from any arbitrary node (nodeIndex) in island1 to the root
+ //of island2.
+
+
+ PxU32 extraPath = mHopCounts[nodeIndex0.index()] + mHopCounts[nodeIndex1.index()] + 1;
+
+ NodeIndex islandNode = island1.mRootNode;
+ while(islandNode.index() != IG_INVALID_NODE)
+ {
+ mHopCounts[islandNode.index()] += extraPath;
+ mIslandIds[islandNode.index()] = islandId0;
+
+ //mFastRoute[islandNode] = IG_INVALID_NODE;
+
+ Node& node = mNodes[islandNode.index()];
+ islandNode = node.mNextNode;
+ }
+
+ //Now fill in the hop count for node1, which is directly connected to node0.
+ mHopCounts[nodeIndex1.index()] = mHopCounts[nodeIndex0.index()] + 1;
+ Node& lastNode = mNodes[island0.mLastNode.index()];
+ Node& firstNode = mNodes[island1.mRootNode.index()];
+ PX_ASSERT(lastNode.mNextNode.index() == IG_INVALID_NODE);
+ PX_ASSERT(firstNode.mPrevNode.index() == IG_INVALID_NODE);
+ PX_ASSERT(island1.mRootNode.index() != island0.mLastNode.index());
+
+ PX_ASSERT(mNodes[island0.mLastNode.index()].mNextNode.index() == IG_INVALID_NODE);
+ PX_ASSERT(mNodes[island1.mLastNode.index()].mNextNode.index() == IG_INVALID_NODE);
+
+ PX_ASSERT(mIslandIds[island0.mLastNode.index()] == islandId0);
+
+
+
+ lastNode.mNextNode = island1.mRootNode;
+ firstNode.mPrevNode = island0.mLastNode;
+
+
+
+ island0.mLastNode = island1.mLastNode;
+ island0.mSize[0] += island1.mSize[0];
+ island0.mSize[1] += island1.mSize[1];
+ //island0.mStaticTouchCount += island1.mStaticTouchCount;
+ mIslandStaticTouchCount[islandId0] += mIslandStaticTouchCount[islandId1];
+
+ //Merge the edge list for the islands...
+ for(PxU32 a = 0; a < 2; ++a)
+ {
+ if(island0.mLastEdge[a] != IG_INVALID_EDGE)
+ {
+ PX_ASSERT(mEdges[island0.mLastEdge[a]].mNextIslandEdge == IG_INVALID_EDGE);
+ mEdges[island0.mLastEdge[a]].mNextIslandEdge = island1.mFirstEdge[a];
+ }
+ else
+ {
+ PX_ASSERT(island0.mFirstEdge[a] == IG_INVALID_EDGE);
+ island0.mFirstEdge[a] = island1.mFirstEdge[a];
+ }
+ if(island1.mFirstEdge[a] != IG_INVALID_EDGE)
+ {
+ PX_ASSERT(mEdges[island1.mFirstEdge[a]].mPrevIslandEdge == IG_INVALID_EDGE);
+ mEdges[island1.mFirstEdge[a]].mPrevIslandEdge = island0.mLastEdge[a];
+ island0.mLastEdge[a] = island1.mLastEdge[a];
+ }
+
+ island0.mEdgeCount[a] += island1.mEdgeCount[a];
+ island1.mFirstEdge[a] = IG_INVALID_EDGE;
+ island1.mLastEdge[a] = IG_INVALID_EDGE;
+ island1.mEdgeCount[a] = 0;
+ }
+
+
+ island1.mLastNode.setIndices(IG_INVALID_NODE, 0);
+ island1.mRootNode.setIndices(IG_INVALID_NODE, 0);
+ island1.mSize[0] = 0;
+ island1.mSize[1] = 0;
+ mIslandStaticTouchCount[islandId1] = 0;
+ //island1.mStaticTouchCount = 0;
+
+ //Remove from active island list
+ if(island1.mActiveIndex != IG_INVALID_ISLAND)
+ {
+ markIslandInactive(islandId1);
+ }
+
+}
+
+void IslandSim::removeEdgeFromActivatingList(EdgeIndex index)
+{
+ Edge& edge = mEdges[index];
+
+ if (edge.mEdgeState & Edge::eACTIVATING)
+ {
+ for (PxU32 a = 0, count = mActivatedEdges[edge.mEdgeType].size(); a < count; a++)
+ {
+ if (mActivatedEdges[edge.mEdgeType][a] == index)
+ {
+ mActivatedEdges[edge.mEdgeType].replaceWithLast(a);
+ break;
+ }
+ }
+
+ edge.mEdgeState &= (~Edge::eACTIVATING);
+ }
+
+
+ NodeIndex nodeIndex1 = mEdgeNodeIndices[index * 2];
+ NodeIndex nodeIndex2 = mEdgeNodeIndices[index * 2 + 1];
+
+ if (nodeIndex1.isValid() && nodeIndex2.isValid())
+ {
+ {
+ Node& node = mNodes[nodeIndex1.index()];
+ node.mActiveRefCount--;
+ }
+ {
+ Node& node = mNodes[nodeIndex2.index()];
+ node.mActiveRefCount--;
+ }
+ }
+
+ if(edge.mEdgeType == Edge::eCONTACT_MANAGER)
+ mActiveContactEdges.reset(index);
+
+}
+
+void IslandSim::setKinematic(IG::NodeIndex nodeIndex)
+{
+
+ Node& node = mNodes[nodeIndex.index()];
+
+ if(!node.isKinematic())
+ {
+
+ //Transition from dynamic to kinematic:
+ //(1) Remove this node from the island
+ //(2) Remove this node from the active node list
+ //(3) If active or referenced, add it to the active kinematic list
+ //(4) Tag the node as kinematic
+ //External code will re-filter interactions and lost touches will be reported
+
+ IslandId islandId = mIslandIds[nodeIndex.index()];
+ PX_ASSERT(islandId != IG_INVALID_ISLAND);
+
+ Island& island = mIslands[islandId];
+
+ mIslandIds[nodeIndex.index()] = IG_INVALID_ISLAND;
+
+ removeNodeFromIsland(island, nodeIndex);
+
+ bool isActive = node.isActive();
+
+ if (isActive)
+ {
+ //Remove from active list...
+ markInactive(nodeIndex);
+ }
+ else if (node.isActivating())
+ {
+ //Remove from activating list...
+ node.clearActivating();
+ PX_ASSERT(mActivatingNodes[mActiveNodeIndex[nodeIndex.index()]].index() == nodeIndex.index());
+
+ NodeIndex replaceIndex = mActivatingNodes[mActivatingNodes.size() - 1];
+ mActiveNodeIndex[replaceIndex.index()] = mActiveNodeIndex[nodeIndex.index()];
+ mActivatingNodes[mActiveNodeIndex[nodeIndex.index()]] = replaceIndex;
+ mActivatingNodes.forceSize_Unsafe(mActivatingNodes.size() - 1);
+ mActiveNodeIndex[nodeIndex.index()] = IG_INVALID_NODE;
+ }
+
+ node.setKinematicFlag();
+
+ node.clearActive();
+
+ if (/*isActive || */node.mActiveRefCount != 0)
+ {
+ //Add to active kinematic list...
+ PX_ASSERT(mActiveNodeIndex[nodeIndex.index()] == IG_INVALID_NODE);
+
+ mActiveNodeIndex[nodeIndex.index()] = mActivatingNodes.size();
+ mActivatingNodes.pushBack(nodeIndex);
+ node.setActivating();
+ }
+
+ PxU32 newSize = island.mSize[0] + island.mSize[1];
+
+ {
+ //This node was in an island with other bodies. We need to force an island recomputation in case the
+ //islands became broken due to losing this connection. Same rules as losing a contact, we just
+ //tag the nodes directly connected to the lost edge as "dirty" and force an island recomputation if
+ //it resulted in lost connections
+ EdgeInstanceIndex edgeId = node.mFirstEdgeIndex;
+ while(edgeId != IG_INVALID_EDGE)
+ {
+ EdgeInstance& instance = mEdgeInstances[edgeId];
+ EdgeInstanceIndex nextId = instance.mNextEdge;
+
+ PxU32 idx = edgeId/2;
+ IG::Edge& edge = mEdges[edgeId/2];
+
+ removeEdgeFromIsland(island, idx);
+
+ removeConnectionInternal(idx);
+ removeConnectionFromGraph(idx);
+
+ edge.clearInserted();
+
+ if (edge.isActive())
+ {
+ removeEdgeFromActivatingList(idx);
+ edge.deactivateEdge();
+ mActiveEdgeCount[edge.mEdgeType]--;
+ }
+
+ if(!edge.isPendingDestroyed())
+ {
+ if(!edge.isInDirtyList())
+ {
+ PX_ASSERT(!contains(mDirtyEdges[edge.mEdgeType], idx));
+ mDirtyEdges[edge.mEdgeType].pushBack(idx);
+ edge.markInDirtyList();
+ }
+ }
+ else
+ {
+ edge.setReportOnlyDestroy();
+ }
+
+ edgeId = nextId;
+ }
+ }
+
+ if(newSize == 0)
+ {
+ //This node was in an island by itself, so no need to mess with any connections
+ for(PxU32 a = 0; a < Edge::eEDGE_TYPE_COUNT; ++a)
+ {
+ island.mFirstEdge[a] = island.mLastEdge[a] = IG_INVALID_EDGE;
+ island.mEdgeCount[a] = 0;
+ mIslandStaticTouchCount[islandId] = 0;
+ //island.mStaticTouchCount = 0;
+ }
+
+ if(island.mActiveIndex != IG_INVALID_ISLAND)
+ {
+ markIslandInactive(islandId);
+ }
+
+ mIslandAwake.reset(islandId);
+ mIslandHandles.freeHandle(islandId);
+ }
+ }
+}
+
+void IslandSim::setDynamic(IG::NodeIndex nodeIndex)
+{
+ //(1) Remove all edges involving this node from all islands they may be in
+ //(2) Mark all edges as "new" edges - let island gen re-process them!
+ //(3) Remove this node from the active kinematic list
+ //(4) Add this node to the active dynamic list (if it is active)
+ //(5) Mark node as dynamic
+
+
+ Node& node = mNodes[nodeIndex.index()];
+
+ if(node.isKinematic())
+ {
+ //EdgeInstanceIndex edgeIndex = node.mFirstEdgeIndex;
+
+ EdgeInstanceIndex edgeId = node.mFirstEdgeIndex;
+ while(edgeId != IG_INVALID_EDGE)
+ {
+ EdgeInstance& instance = mEdgeInstances[edgeId];
+ EdgeInstanceIndex nextId = instance.mNextEdge;
+
+ NodeIndex otherNode = mEdgeNodeIndices[edgeId^1];
+
+ PxU32 idx = edgeId/2;
+ IG::Edge& edge = mEdges[edgeId/2];
+
+ if(!otherNode.isStaticBody())
+ {
+ IslandId islandId = mIslandIds[otherNode.index()];
+ if(islandId != IG_INVALID_ISLAND)
+ removeEdgeFromIsland(mIslands[islandId], idx);
+ }
+
+ removeConnectionInternal(idx);
+ removeConnectionFromGraph(idx);
+
+ edge.clearInserted();
+ if (edge.isActive())
+ {
+ edge.deactivateEdge();
+ removeEdgeFromActivatingList(idx);
+ mActiveEdgeCount[edge.mEdgeType]--;
+ }
+
+ if(!edge.isPendingDestroyed())
+ {
+ if(!edge.isInDirtyList())
+ {
+ PX_ASSERT(!contains(mDirtyEdges[edge.mEdgeType], idx));
+ mDirtyEdges[edge.mEdgeType].pushBack(idx);
+ edge.markInDirtyList();
+ }
+ }
+ else
+ {
+ edge.setReportOnlyDestroy();
+ }
+
+ edgeId = nextId;
+ }
+
+
+ if(!node.isActivating() && mActiveNodeIndex[nodeIndex.index()] != IG_INVALID_NODE)
+ {
+ //Remove from active kinematic list, add to active dynamic list
+ PxU32 oldRefCount = node.mActiveRefCount;
+ node.mActiveRefCount = 0;
+ markKinematicInactive(nodeIndex);
+ node.mActiveRefCount = oldRefCount;
+ }
+
+ node.clearKinematicFlag();
+
+
+
+ //Create an island for this node. If there are any edges affecting this node, they will have been marked as
+ //"new" and will be processed next island update.
+ {
+ IslandId islandHandle = mIslandHandles.getHandle();
+
+ if(islandHandle == mIslands.capacity())
+ {
+ const PxU32 newCapacity = 2*mIslands.capacity()+1;
+ mIslands.reserve(newCapacity);
+ mIslandAwake.resize(newCapacity);
+ mIslandStaticTouchCount.resize(newCapacity);
+ }
+ mIslandAwake.reset(islandHandle);
+ mIslands.resize(PxMax(islandHandle+1, mIslands.size()));
+ mIslandStaticTouchCount.resize(PxMax(islandHandle + 1, mIslands.size()));
+ Island& island = mIslands[islandHandle];
+ island.mLastNode = island.mRootNode = nodeIndex;
+ PX_ASSERT(mNodes[nodeIndex.index()].mNextNode.index() == IG_INVALID_NODE);
+ island.mSize[node.mType] = 1;
+ mIslandIds[nodeIndex.index()] = islandHandle;
+ mIslandStaticTouchCount[islandHandle] = 0;
+
+
+ if(node.isActive())
+ {
+ node.clearActive();
+
+ activateNode(nodeIndex);
+ }
+ }
+ }
+}
+
+}
+}
diff --git a/PhysX_3.4/Source/LowLevel/software/src/PxsMaterialCombiner.cpp b/PhysX_3.4/Source/LowLevel/software/src/PxsMaterialCombiner.cpp
new file mode 100644
index 00000000..9c06336b
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/src/PxsMaterialCombiner.cpp
@@ -0,0 +1,102 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#include "PxsMaterialCombiner.h"
+#include "PsMathUtils.h"
+#include "CmPhysXCommon.h"
+#include "PsFoundation.h"
+
+namespace physx
+{
+
+
+PxsMaterialCombiner::PxsMaterialCombiner(PxReal staticFrictionScaling, PxReal dynamicFrictionScaling)
+: mStaticFrictionScaling(staticFrictionScaling), mDynamicFrictionScaling(dynamicFrictionScaling)
+{}
+
+
+PxReal PxsMaterialCombiner::combineRestitution(const PxsMaterialData& mat0, const PxsMaterialData& mat1)
+{
+ /*return combineScalars(mat0.restitution, mat1.restitution, PxMax(mat0.restitutionCombineMode, mat1.restitutionCombineMode));*/
+ return combineScalars(mat0.restitution, mat1.restitution, PxMax(mat0.getRestitutionCombineMode(), mat1.getRestitutionCombineMode()));
+}
+
+PxsMaterialCombiner::PxsCombinedMaterial PxsMaterialCombiner::combineIsotropicFriction(const PxsMaterialData& mat0, const PxsMaterialData& mat1)
+{
+ PxsCombinedMaterial dest;
+
+ dest.flags = (mat0.flags | mat1.flags); //& (PxMaterialFlag::eDISABLE_STRONG_FRICTION|PxMaterialFlag::eDISABLE_FRICTION); //eventually set DisStrongFric flag, lower all others.
+
+ if (!(dest.flags & PxMaterialFlag::eDISABLE_FRICTION))
+ {
+ const PxI32 fictionCombineMode = PxMax(mat0.getFrictionCombineMode(), mat1.getFrictionCombineMode());
+ PxReal dynFriction = 0.f;
+ PxReal staFriction = 0.f;
+
+
+ switch (fictionCombineMode)
+ {
+ case PxCombineMode::eAVERAGE:
+ dynFriction = 0.5f * (mat0.dynamicFriction + mat1.dynamicFriction);
+ staFriction = 0.5f * (mat0.staticFriction + mat1.staticFriction);
+ break;
+ case PxCombineMode::eMIN:
+ dynFriction = PxMin(mat0.dynamicFriction, mat1.dynamicFriction);
+ staFriction = PxMin(mat0.staticFriction, mat1.staticFriction);
+ break;
+ case PxCombineMode::eMULTIPLY:
+ dynFriction = (mat0.dynamicFriction * mat1.dynamicFriction);
+ staFriction = (mat0.staticFriction * mat1.staticFriction);
+ break;
+ case PxCombineMode::eMAX:
+ dynFriction = PxMax(mat0.dynamicFriction, mat1.dynamicFriction);
+ staFriction = PxMax(mat0.staticFriction, mat1.staticFriction);
+ break;
+ }
+
+ dynFriction*=mDynamicFrictionScaling;
+ staFriction*=mStaticFrictionScaling;
+ //isotropic case
+ const PxReal fDynFriction = PxMax(dynFriction, 0.f);
+
+ const PxReal fStaFriction = physx::intrinsics::fsel(staFriction - fDynFriction, staFriction, fDynFriction);
+ dest.dynFriction = fDynFriction;
+ dest.staFriction = fStaFriction;
+ }
+ else
+ {
+ dest.flags |= PxMaterialFlag::eDISABLE_STRONG_FRICTION;
+ dest.staFriction = 0.0f;
+ dest.dynFriction = 0.0f;
+ }
+
+ return dest;
+}
+}
diff --git a/PhysX_3.4/Source/LowLevel/software/src/PxsNphaseImplementationContext.cpp b/PhysX_3.4/Source/LowLevel/software/src/PxsNphaseImplementationContext.cpp
new file mode 100644
index 00000000..e7bcd737
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/src/PxsNphaseImplementationContext.cpp
@@ -0,0 +1,952 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#include "PxsContext.h"
+#include "CmFlushPool.h"
+#include "PxsSimpleIslandManager.h"
+
+//Enable tuner profiling.
+#ifdef PX_PS3
+#include "CellTimerMarker.h"
+#endif
+
+#if PX_SUPPORT_GPU_PHYSX
+#include "PxPhysXGpu.h"
+#include "task/PxGpuDispatcher.h"
+#endif
+
+#include "PxsContactManagerState.h"
+
+#include "PxsNphaseImplementationContext.h"
+#include "PxvGeometry.h"
+#include "PxvDynamics.h"
+
+#include "PxcNpContactPrepShared.h"
+
+using namespace physx;
+using namespace physx::shdfnd;
+
+
+class PxsCMDiscreteUpdateTask : public PxsCMUpdateTask
+{
+public:
+ PxsCMDiscreteUpdateTask(PxsContext* context, PxReal dt, PxsContactManager** cms, PxsContactManagerOutput* cmOutputs, Gu::Cache* caches, PxU32 nbCms,
+ PxContactModifyCallback* callback):
+ PxsCMUpdateTask(context, dt, cms, cmOutputs, caches, nbCms, callback)
+ {}
+
+ virtual ~PxsCMDiscreteUpdateTask()
+ {}
+
+ void runModifiableContactManagers(PxU32* modifiableIndices, PxU32 nbModifiableManagers, PxcNpThreadContext& threadContext, PxU32& foundPatchCount_, PxU32& lostPatchCount_,
+ PxU32& maxPatches_)
+ {
+ PX_ASSERT(nbModifiableManagers != 0);
+
+ PxU32 foundPatchCount = foundPatchCount_;
+ PxU32 lostPatchCount = lostPatchCount_;
+ PxU32 maxPatches = maxPatches_;
+
+ Cm::BitMap& localPatchChangedMap = threadContext.getLocalPatchChangeMap();
+
+ class PxcContactSet: public PxContactSet
+ {
+ public:
+ PxcContactSet(PxU32 count, PxModifiableContact *contacts)
+ {
+ mContacts = contacts;
+ mCount = count;
+ }
+ PxModifiableContact* getContacts() { return mContacts; }
+ PxU32 getCount() { return mCount; }
+
+ };
+
+
+
+ if(mCallback)
+ {
+ PX_ALLOCA(mModifiablePairArray, PxContactModifyPair, nbModifiableManagers);
+
+
+ PxsTransformCache& transformCache = mContext->getTransformCache();
+
+ for(PxU32 i = 0; i < nbModifiableManagers; ++i)
+ {
+ PxU32 index = modifiableIndices[i];
+ PxsContactManager& cm = *mCmArray[index];
+
+ PxsContactManagerOutput& output = mCmOutputs[index];
+
+ PxU32 count = output.nbContacts;
+
+ if(count)
+ {
+ PxContactModifyPair& p = mModifiablePairArray[i];
+ PxcNpWorkUnit &unit = cm.getWorkUnit();
+
+ p.shape[0] = gPxvOffsetTable.convertPxsShape2Px(unit.shapeCore0);
+ p.shape[1] = gPxvOffsetTable.convertPxsShape2Px(unit.shapeCore1);
+
+ p.actor[0] = unit.flags & PxcNpWorkUnitFlag::eDYNAMIC_BODY0 ? gPxvOffsetTable.convertPxsRigidCore2PxRigidBody(unit.rigidCore0)
+ : gPxvOffsetTable.convertPxsRigidCore2PxRigidStatic(unit.rigidCore0);
+
+ p.actor[1] = unit.flags & PxcNpWorkUnitFlag::eDYNAMIC_BODY1 ? gPxvOffsetTable.convertPxsRigidCore2PxRigidBody(unit.rigidCore1)
+ : gPxvOffsetTable.convertPxsRigidCore2PxRigidStatic(unit.rigidCore1);
+
+ p.transform[0] = transformCache.getTransformCache(unit.mTransformCache0).transform;
+ p.transform[1] = transformCache.getTransformCache(unit.mTransformCache1).transform;
+
+ PxModifiableContact* contacts = reinterpret_cast<PxModifiableContact*>(output.contactPoints);
+ static_cast<PxcContactSet&>(p.contacts) = PxcContactSet(count, contacts);
+
+ PxReal mi0 = unit.flags & PxcNpWorkUnitFlag::eDYNAMIC_BODY0 ? static_cast<const PxsBodyCore*>(unit.rigidCore0)->maxContactImpulse : PX_MAX_F32;
+ PxReal mi1 = unit.flags & PxcNpWorkUnitFlag::eDYNAMIC_BODY1 ? static_cast<const PxsBodyCore*>(unit.rigidCore1)->maxContactImpulse : PX_MAX_F32;
+ PxReal maxImpulse = PxMin(mi0, mi1);
+ for (PxU32 j = 0; j < count; j++)
+ contacts[j].maxImpulse = maxImpulse;
+
+ #if PX_ENABLE_SIM_STATS
+ PxU8 gt0 = Ps::to8(unit.geomType0), gt1 = Ps::to8(unit.geomType1);
+ threadContext.mModifiedContactPairs[PxMin(gt0, gt1)][PxMax(gt0, gt1)]++;
+ #endif
+ }
+ }
+
+ mCallback->onContactModify(mModifiablePairArray, nbModifiableManagers);
+ }
+
+ for(PxU32 i = 0; i < nbModifiableManagers; ++i)
+ {
+ PxU32 index = modifiableIndices[i];
+ PxsContactManager& cm = *mCmArray[index];
+
+ //Loop through the contacts in the contact stream and update contact count!
+
+ PxU32 numContacts = 0;
+ PxcNpWorkUnit& unit = cm.getWorkUnit();
+ PxsContactManagerOutput& output = mCmOutputs[index];
+
+
+ PxU32 numPatches = output.nbPatches;
+
+ if (output.nbContacts)
+ {
+ //PxU8* compressedContacts = cm.getWorkUnit().compressedContacts;
+ //PxModifyContactHeader* header = reinterpret_cast<PxModifyContactHeader*>(compressedContacts);
+ PxContactPatch* patches = reinterpret_cast<PxContactPatch*>(output.contactPatches);
+ PxModifiableContact* points = reinterpret_cast<PxModifiableContact*>(output.contactPoints);
+
+ if (patches->internalFlags & PxContactPatch::eREGENERATE_PATCHES)
+ {
+ //Some data was modified that must trigger patch re-generation...
+ for (PxU8 k = 0; k < numPatches; ++k)
+ {
+ PxU32 startIndex = patches[k].startContactIndex;
+
+ patches[k].normal = points[startIndex].normal;
+ patches[k].dynamicFriction = points[startIndex].dynamicFriction;
+ patches[k].staticFriction = points[startIndex].staticFriction;
+ patches[k].restitution = points[startIndex].restitution;
+ patches[k].materialIndex0 = points[startIndex].materialIndex0;
+ patches[k].materialIndex1 = points[startIndex].materialIndex1;
+
+ for (PxU32 j = 1; j < patches[k].nbContacts; ++j)
+ {
+ if (points[startIndex].normal.dot(points[j + startIndex].normal) < PXC_SAME_NORMAL
+ && points[startIndex].maxImpulse > 0.f) //TODO - this needs extending for material indices but we don't support modifying those yet
+ {
+ //The points are now in a separate friction patch...
+ for (PxU32 c = numPatches - 1; c > k; --c)
+ {
+ patches[c + 1] = patches[c];
+ }
+ numPatches++;
+ patches[k + 1].materialFlags = patches[k].materialFlags;
+ patches[k + 1].internalFlags = patches[k].internalFlags;
+ patches[k + 1].startContactIndex = Ps::to8(j + startIndex);
+ patches[k + 1].nbContacts = Ps::to8(patches[k].nbContacts - j);
+ //Fill in patch information now that final patches are available
+ patches[k].nbContacts = PxU8(j);
+ break;
+ }
+ }
+ }
+ }
+
+ if (output.prevPatches < numPatches)
+ {
+ foundPatchCount++;
+ localPatchChangedMap.growAndSet(unit.index);
+ }
+
+ maxPatches = PxMax(maxPatches, PxU32(numPatches));
+
+ output.nbPatches = PxU8(numPatches);
+
+ for (PxU32 a = 0; a < output.nbContacts; ++a)
+ {
+ numContacts += points[a].maxImpulse != 0.f;
+ }
+ }
+
+ if(output.nbPatches < output.prevPatches)
+ {
+ lostPatchCount++;
+ //Trigger a lost patch event...required to let the solver
+ localPatchChangedMap.growAndSet(unit.index);
+ }
+
+ if(!numContacts)
+ {
+ //KS - we still need to retain the patch count from the previous frame to detect found/lost events...
+ PxcNpWorkUnitClearFrictionCachedState(unit);
+ output.nbPatches = 0;
+ output.nbContacts = 0;
+
+ if(output.prevPatches)
+ {
+ lostPatchCount++;
+ //Trigger a lost patch event...required to let the solver
+ localPatchChangedMap.growAndSet(unit.index);
+ }
+
+ continue;
+ }
+
+ if(threadContext.mContactStreamPool)
+ {
+ //We need to allocate a new structure inside the contact stream pool
+
+ PxU32 patchSize = output.nbPatches * sizeof(PxContactPatch);
+ PxU32 contactSize = output.nbContacts * sizeof(PxExtendedContact);
+
+ /*PxI32 increment = (PxI32)(patchSize + contactSize);
+ PxI32 index = Ps::atomicAdd(&mContactStreamPool->mSharedContactIndex, increment) - increment;
+ PxU8* address = mContactStreamPool->mContactStream + index;*/
+ bool isOverflown = false;
+
+ PxI32 contactIncrement = PxI32(contactSize);
+ PxI32 contactIndex = Ps::atomicAdd(&threadContext.mContactStreamPool->mSharedDataIndex, contactIncrement);
+
+ if (threadContext.mContactStreamPool->isOverflown())
+ {
+ PX_WARN_ONCE("Contact buffer overflow detected, please increase its size in the scene desc!\n");
+ isOverflown = true;
+ }
+
+ PxU8* contactAddress = threadContext.mContactStreamPool->mDataStream + threadContext.mContactStreamPool->mDataStreamSize - contactIndex;
+
+ PxI32 patchIncrement = PxI32(patchSize);
+ PxI32 patchIndex = Ps::atomicAdd(&threadContext.mPatchStreamPool->mSharedDataIndex, patchIncrement);
+
+ if (threadContext.mPatchStreamPool->isOverflown())
+ {
+ PX_WARN_ONCE("Patch buffer overflow detected, please increase its size in the scene desc!\n");
+ isOverflown = true;
+ }
+
+ PxU8* patchAddress = threadContext.mPatchStreamPool->mDataStream + threadContext.mPatchStreamPool->mDataStreamSize - patchIndex;
+
+
+ PxU32 internalFlags = reinterpret_cast<PxContactPatch*>(output.contactPatches)->internalFlags;
+
+ PxI32 increment2 = PxI32(output.nbContacts * sizeof(PxReal));
+ PxI32 index2 = Ps::atomicAdd(&threadContext.mForceAndIndiceStreamPool->mSharedDataIndex, increment2);
+
+ if (threadContext.mForceAndIndiceStreamPool->isOverflown())
+ {
+ PX_WARN_ONCE("Force buffer overflow detected, please increase its size in the scene desc!\n");
+ isOverflown = true;
+ }
+
+ if (isOverflown)
+ {
+ output.contactPoints = NULL;
+ output.contactPatches = NULL;
+ output.contactForces = NULL;
+
+ output.nbContacts = output.nbPatches = 0;
+ }
+ else
+ {
+ output.contactForces = reinterpret_cast<PxReal*>(threadContext.mForceAndIndiceStreamPool->mDataStream + threadContext.mForceAndIndiceStreamPool->mDataStreamSize - index2);
+
+ PxMemZero(output.contactForces, sizeof(PxReal) * output.nbContacts);
+
+ PxExtendedContact* contacts = reinterpret_cast<PxExtendedContact*>(contactAddress);
+ PxMemCopy(patchAddress, output.contactPatches, sizeof(PxContactPatch) * output.nbPatches);
+
+ PxContactPatch* newPatches = reinterpret_cast<PxContactPatch*>(patchAddress);
+
+ internalFlags |= PxContactPatch::eCOMPRESSED_MODIFIED_CONTACT;
+
+ for(PxU32 a = 0; a < output.nbPatches; ++a)
+ {
+ newPatches[a].internalFlags = PxU8(internalFlags);
+ }
+
+ //KS - only the first patch will have mass modification properties set. For the GPU solver, this must be propagated to the remaining patches
+ for(PxU32 a = 1; a < output.nbPatches; ++a)
+ {
+ newPatches[a].mMassModification = newPatches->mMassModification;
+ }
+
+ PxModifiableContact* sourceContacts = reinterpret_cast<PxModifiableContact*>(output.contactPoints);
+
+ for(PxU32 a = 0; a < output.nbContacts; ++a)
+ {
+ PxExtendedContact& contact = contacts[a];
+ PxModifiableContact& srcContact = sourceContacts[a];
+ contact.contact = srcContact.contact;
+ contact.separation = srcContact.separation;
+ contact.targetVelocity = srcContact.targetVelocity;
+ contact.maxImpulse = srcContact.maxImpulse;
+ }
+
+ output.contactPatches = patchAddress;
+ output.contactPoints = reinterpret_cast<PxU8*>(contacts);
+ }
+ }
+ }
+
+ foundPatchCount_ = foundPatchCount;
+ lostPatchCount_ = lostPatchCount;
+ maxPatches_ = maxPatches;
+ }
+
+
+ template < void (*NarrowPhase)(PxcNpThreadContext&, PxcNpWorkUnit&, Gu::Cache&, PxsContactManagerOutput&)>
+ void processCms(PxcNpThreadContext* threadContext)
+ {
+ // PT: use local variables to avoid reading class members N times, if possible
+ const PxU32 nb = mCmCount;
+ PxsContactManager** PX_RESTRICT cmArray = mCmArray;
+
+ PxU32 lostPatchCount = 0, foundPatchCount = 0;
+
+ PxU32 maxPatches = threadContext->mMaxPatches;
+
+ PxU32 newTouchCMCount = 0, lostTouchCMCount = 0;
+ Cm::BitMap& localChangeTouchCM = threadContext->getLocalChangeTouch();
+ Cm::BitMap& localPatchChangedMap = threadContext->getLocalPatchChangeMap();
+
+ PX_ALLOCA(modifiableIndices, PxU32, nb);
+ PxU32 modifiableCount = 0;
+
+ for(PxU32 i=0;i<nb;i++)
+ {
+ const PxU32 prefetch1 = PxMin(i + 1, nb - 1);
+ const PxU32 prefetch2 = PxMin(i + 2, nb - 1);
+
+ Ps::prefetchLine(cmArray[prefetch2]);
+ Ps::prefetchLine(&mCmOutputs[prefetch2]);
+ Ps::prefetchLine(cmArray[prefetch1]->getWorkUnit().shapeCore0);
+ Ps::prefetchLine(cmArray[prefetch1]->getWorkUnit().shapeCore1);
+ Ps::prefetchLine(&threadContext->mTransformCache->getTransformCache(cmArray[prefetch1]->getWorkUnit().mTransformCache0));
+ Ps::prefetchLine(&threadContext->mTransformCache->getTransformCache(cmArray[prefetch1]->getWorkUnit().mTransformCache1));
+
+ PxsContactManager* cm = cmArray[i];
+
+ if(cm)
+ {
+ PxsContactManagerOutput& output = mCmOutputs[i];
+ PxcNpWorkUnit& unit = cm->getWorkUnit();
+
+ output.prevPatches = output.nbPatches;
+
+
+ PxU8 oldStatusFlag = output.statusFlag;
+
+ PxU8 oldTouch = Ps::to8(oldStatusFlag & PxsContactManagerStatusFlag::eHAS_TOUCH);
+
+ Gu::Cache& cache = mCaches[i];
+
+ NarrowPhase(*threadContext, unit, cache, output);
+
+ PxU16 newTouch = Ps::to8(output.statusFlag & PxsContactManagerStatusFlag::eHAS_TOUCH);
+
+
+ bool modifiable = output.nbPatches != 0 && unit.flags & PxcNpWorkUnitFlag::eMODIFIABLE_CONTACT;
+
+ if(modifiable)
+ {
+ modifiableIndices[modifiableCount++] = i;
+ }
+ else
+ {
+ maxPatches = PxMax(maxPatches, Ps::to32(output.nbPatches));
+
+ if(output.prevPatches != output.nbPatches)
+ {
+ localPatchChangedMap.growAndSet(cmArray[i]->getIndex());
+ if(output.prevPatches < output.nbPatches)
+ foundPatchCount++;
+ else
+ lostPatchCount++;
+ }
+ }
+
+ if (newTouch ^ oldTouch)
+ {
+ cm->getWorkUnit().statusFlags = PxU8(output.statusFlag | (unit.statusFlags & PxcNpWorkUnitStatusFlag::eREFRESHED_WITH_TOUCH)); //KS - todo - remove the need to access the work unit at all!
+ localChangeTouchCM.growAndSet(cmArray[i]->getIndex());
+ if(newTouch)
+ newTouchCMCount++;
+ else
+ lostTouchCMCount++;
+ }
+ else if (!(oldStatusFlag&PxsContactManagerStatusFlag::eTOUCH_KNOWN))
+ {
+ cm->getWorkUnit().statusFlags = PxU8(output.statusFlag | (unit.statusFlags & PxcNpWorkUnitStatusFlag::eREFRESHED_WITH_TOUCH)); //KS - todo - remove the need to access the work unit at all!
+ }
+ }
+ }
+
+ if(modifiableCount)
+ {
+ runModifiableContactManagers(modifiableIndices, modifiableCount, *threadContext, foundPatchCount, lostPatchCount, maxPatches);
+ }
+
+
+ threadContext->addLocalNewTouchCount(newTouchCMCount);
+ threadContext->addLocalLostTouchCount(lostTouchCMCount);
+
+ threadContext->addLocalFoundPatchCount(foundPatchCount);
+ threadContext->addLocalLostPatchCount(lostPatchCount);
+
+ threadContext->mMaxPatches = maxPatches;
+ }
+
+ virtual void runInternal()
+ {
+ PX_PROFILE_ZONE("Sim.narrowPhase", mContext->getContextId());
+
+ PxcNpThreadContext* PX_RESTRICT threadContext = mContext->getNpThreadContext();
+
+ threadContext->mDt = mDt;
+
+ const bool pcm = mContext->getPCM();
+ threadContext->mPCM = pcm;
+ threadContext->mCreateAveragePoint = mContext->getCreateAveragePoint();
+ threadContext->mContactCache = mContext->getContactCacheFlag();
+ threadContext->mTransformCache = &mContext->getTransformCache();
+ threadContext->mContactDistance = mContext->getContactDistance();
+
+ if(pcm)
+ {
+ processCms<PxcDiscreteNarrowPhasePCM>(threadContext);
+ }
+ else
+ {
+ processCms<PxcDiscreteNarrowPhase>(threadContext);
+ }
+
+ mContext->putNpThreadContext(threadContext);
+ }
+
+ virtual const char* getName() const
+ {
+ return "PxsContext.contactManagerDiscreteUpdate";
+ }
+};
+
+void PxsNphaseImplementationContext::processContactManager(PxReal dt, PxsContactManagerOutput* cmOutputs, PxBaseTask* continuation)
+{
+ //Iterate all active contact managers
+ mContext.mTaskPool.lock();
+ const PxU32 nbCmsToProcess = mNarrowPhasePairs.mContactManagerMapping.size();
+
+ for(PxU32 a = 0; a < nbCmsToProcess;)
+ {
+ void* ptr = mContext.mTaskPool.allocateNotThreadSafe(sizeof(PxsCMDiscreteUpdateTask));
+ PxU32 nbToProcess = PxMin(nbCmsToProcess - a, PxsCMUpdateTask::BATCH_SIZE);
+ PxsCMDiscreteUpdateTask* task = PX_PLACEMENT_NEW(ptr, PxsCMDiscreteUpdateTask)(&mContext, dt, mNarrowPhasePairs.mContactManagerMapping.begin() + a,
+ cmOutputs + a, mNarrowPhasePairs.mCaches.begin() + a, nbToProcess, mModifyCallback);
+
+ a += nbToProcess;
+
+ task->setContinuation(continuation);
+ task->removeReference();
+ }
+ mContext.mTaskPool.unlock();
+}
+
+void PxsNphaseImplementationContext::processContactManagerSecondPass(PxReal dt, PxBaseTask* continuation)
+{
+ //Iterate all active contact managers
+ mContext.mTaskPool.lock();
+
+ const PxU32 nbCmsToProcess = mNewNarrowPhasePairs.mContactManagerMapping.size();
+
+ for(PxU32 a = 0; a < nbCmsToProcess;)
+ {
+ void* ptr = mContext.mTaskPool.allocateNotThreadSafe(sizeof(PxsCMDiscreteUpdateTask));
+ PxU32 nbToProcess = PxMin(nbCmsToProcess - a, PxsCMUpdateTask::BATCH_SIZE);
+ PxsCMDiscreteUpdateTask* task = PX_PLACEMENT_NEW(ptr, PxsCMDiscreteUpdateTask)(&mContext, dt, mNewNarrowPhasePairs.mContactManagerMapping.begin() + a,
+ mNewNarrowPhasePairs.mOutputContactManagers.begin() + a, mNewNarrowPhasePairs.mCaches.begin() + a, nbToProcess,
+ mModifyCallback);
+
+ a += nbToProcess;
+
+ task->setContinuation(continuation);
+ task->removeReference();
+ }
+ mContext.mTaskPool.unlock();
+}
+
+void PxsNphaseImplementationContext::updateContactManager(PxReal dt, bool /*hasBoundsArrayChanged*/, bool /*hasContactDistanceChanged*/, PxBaseTask* continuation, PxBaseTask* firstPassNpContinuation)
+{
+ PX_PROFILE_ZONE("Sim.queueNarrowPhase", mContext.mContextID);
+
+ firstPassNpContinuation->removeReference();
+
+ mContext.clearManagerTouchEvents();
+
+#if PX_ENABLE_SIM_STATS
+ mContext.mSimStats.mNbDiscreteContactPairsTotal = 0;
+ mContext.mSimStats.mNbDiscreteContactPairsWithCacheHits = 0;
+ mContext.mSimStats.mNbDiscreteContactPairsWithContacts = 0;
+#endif
+
+
+ //KS - temporarily put this here. TODO - move somewhere better
+ mContext.mTotalCompressedCacheSize = 0;
+ mContext.mMaxPatches = 0;
+
+ processContactManager(dt, mNarrowPhasePairs.mOutputContactManagers.begin(), continuation);
+
+}
+
+void PxsNphaseImplementationContext::secondPassUpdateContactManager(PxReal dt, PxBaseTask* continuation)
+{
+ PX_PROFILE_ZONE("Sim.queueNarrowPhase", mContext.mContextID);
+
+ processContactManagerSecondPass(dt, continuation);
+}
+
+PxsNphaseImplementationContext* PxsNphaseImplementationContext::create(PxsContext& context, IG::IslandSim* islandSim)
+{
+ PxsNphaseImplementationContext* npImplContext = reinterpret_cast<PxsNphaseImplementationContext*>(
+ PX_ALLOC(sizeof(PxsNphaseImplementationContext), "PxsNphaseImplementationContext"));
+
+ if (npImplContext)
+ {
+ new(npImplContext) PxsNphaseImplementationContext(context, islandSim);
+ }
+
+ return npImplContext;
+}
+
+void PxsNphaseImplementationContext::destroy()
+{
+ this->~PxsNphaseImplementationContext();
+ PX_FREE(this);
+}
+
+void PxsNphaseImplementationContext::registerContactManagers(PxsContactManager** cms, PxU32 nbContactManagers, PxU32 maxContactManagerId)
+{
+ PX_UNUSED(maxContactManagerId);
+ for (PxU32 a = 0; a < nbContactManagers; ++a)
+ {
+ registerContactManager(cms[a], 0, 0);
+ }
+}
+
+void PxsNphaseImplementationContext::registerContactManager(PxsContactManager* cm, PxI32 touching, PxU32 patchCount)
+{
+ PxcNpWorkUnit& workUnit = cm->getWorkUnit();
+ PxsContactManagerOutput output;
+
+ PxU8 geomType0 = PxU8(workUnit.geomType0);
+ PxU8 geomType1 = PxU8(workUnit.geomType1);
+
+ Gu::Cache cache;
+
+ mContext.createCache(cache, cm, geomType0, geomType1);
+
+ PxMemZero(&output, sizeof(output));
+ output.nbPatches = Ps::to8(patchCount);
+
+ if(workUnit.flags & PxcNpWorkUnitFlag::eOUTPUT_CONSTRAINTS)
+ output.statusFlag |= PxsContactManagerStatusFlag::eREQUEST_CONSTRAINTS;
+
+ if (touching > 0)
+ {
+ output.statusFlag |= PxsContactManagerStatusFlag::eHAS_TOUCH;
+ }
+ else if (touching < 0)
+ {
+ output.statusFlag |= PxsContactManagerStatusFlag::eHAS_NO_TOUCH;
+ }
+
+ output.statusFlag |= PxsContactManagerStatusFlag::eDIRTY_MANAGER;
+
+ if (cm->getWorkUnit().statusFlags & PxcNpWorkUnitStatusFlag::eHAS_TOUCH)
+ cm->getWorkUnit().statusFlags |= PxcNpWorkUnitStatusFlag::eREFRESHED_WITH_TOUCH;
+
+ mNewNarrowPhasePairs.mOutputContactManagers.pushBack(output);
+ mNewNarrowPhasePairs.mCaches.pushBack(cache);
+ mNewNarrowPhasePairs.mContactManagerMapping.pushBack(cm);
+ PxU32 newSz = mNewNarrowPhasePairs.mOutputContactManagers.size();
+ cm->getWorkUnit().mNpIndex = mNewNarrowPhasePairs.computeId(newSz - 1) | PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK;
+}
+
+void PxsNphaseImplementationContext::removeContactManagersFallback(PxsContactManagerOutput* cmOutputs)
+{
+ if (mRemovedContactManagers.size())
+ {
+ Ps::sort(mRemovedContactManagers.begin(), mRemovedContactManagers.size(), Ps::Greater<PxU32>());
+
+ for (PxU32 a = 0; a < mRemovedContactManagers.size(); ++a)
+ {
+#if PX_DEBUG
+ if (a > 0)
+ PX_ASSERT(mRemovedContactManagers[a] < mRemovedContactManagers[a - 1]);
+#endif
+ unregisterContactManagerInternal(mRemovedContactManagers[a], mNarrowPhasePairs, cmOutputs);
+ }
+
+ mRemovedContactManagers.forceSize_Unsafe(0);
+ }
+}
+
+void PxsNphaseImplementationContext::unregisterContactManager(PxsContactManager* cm)
+{
+ PxcNpWorkUnit& unit = cm->getWorkUnit();
+ PxU32 index = unit.mNpIndex;
+ PX_ASSERT(index != 0xFFffFFff);
+
+ if (!(index & PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK))
+ {
+ unregisterContactManagerInternal(index, mNarrowPhasePairs, mNarrowPhasePairs.mOutputContactManagers.begin());
+ mNarrowPhasePairs.mOutputContactManagers.forceSize_Unsafe(mNarrowPhasePairs.mOutputContactManagers.size()-1);
+ }
+ else
+ {
+ //KS - the index in the "new" list will be the index
+ unregisterContactManagerInternal(index, mNewNarrowPhasePairs, mNewNarrowPhasePairs.mOutputContactManagers.begin());
+ mNewNarrowPhasePairs.mOutputContactManagers.forceSize_Unsafe(mNewNarrowPhasePairs.mOutputContactManagers.size()-1);
+ }
+}
+
+void PxsNphaseImplementationContext::refreshContactManager(PxsContactManager* cm)
+{
+ PxcNpWorkUnit& unit = cm->getWorkUnit();
+ PxU32 index = unit.mNpIndex;
+ PX_ASSERT(index != 0xFFffFFff);
+ PxsContactManagerOutput output;
+ if (!(index & PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK))
+ {
+ output = mNarrowPhasePairs.mOutputContactManagers[PxsContactManagerBase::computeIndexFromId(index)];
+ unregisterContactManagerInternal(index, mNarrowPhasePairs, mNarrowPhasePairs.mOutputContactManagers.begin());
+ mNarrowPhasePairs.mOutputContactManagers.forceSize_Unsafe(mNarrowPhasePairs.mOutputContactManagers.size()-1);
+ }
+ else
+ {
+ output = mNewNarrowPhasePairs.mOutputContactManagers[PxsContactManagerBase::computeIndexFromId(index & (~PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK))];
+ //KS - the index in the "new" list will be the index
+ unregisterContactManagerInternal(index, mNewNarrowPhasePairs, mNewNarrowPhasePairs.mOutputContactManagers.begin());
+ mNewNarrowPhasePairs.mOutputContactManagers.forceSize_Unsafe(mNewNarrowPhasePairs.mOutputContactManagers.size()-1);
+ }
+ PxI32 touching = 0;
+ if(output.statusFlag & PxsContactManagerStatusFlag::eHAS_TOUCH)
+ touching = 1;
+ else if (output.statusFlag & PxsContactManagerStatusFlag::eHAS_NO_TOUCH)
+ touching = -1;
+ registerContactManager(cm, touching, output.nbPatches);
+}
+
+void PxsNphaseImplementationContext::unregisterContactManagerFallback(PxsContactManager* cm, PxsContactManagerOutput* /*cmOutputs*/)
+{
+ PxcNpWorkUnit& unit = cm->getWorkUnit();
+ PxU32 index = unit.mNpIndex;
+ PX_ASSERT(index != 0xFFffFFff);
+
+ if (!(index & PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK))
+ {
+ mRemovedContactManagers.pushBack(index);
+ }
+ else
+ {
+ //KS - the index in the "new" list will be the index
+ unregisterContactManagerInternal(index, mNewNarrowPhasePairs, mNewNarrowPhasePairs.mOutputContactManagers.begin());
+ mNewNarrowPhasePairs.mOutputContactManagers.forceSize_Unsafe(mNewNarrowPhasePairs.mOutputContactManagers.size()-1);
+ }
+}
+
+void PxsNphaseImplementationContext::refreshContactManagerFallback(PxsContactManager* cm, PxsContactManagerOutput* cmOutputs)
+{
+ PxcNpWorkUnit& unit = cm->getWorkUnit();
+ PxU32 index = unit.mNpIndex;
+ PX_ASSERT(index != 0xFFffFFff);
+
+ PxsContactManagerOutput output;
+ if (!(index & PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK))
+ {
+ output = cmOutputs[PxsContactManagerBase::computeIndexFromId(index)];
+ //unregisterContactManagerInternal(index, mNarrowPhasePairs, cmOutputs);
+ unregisterContactManagerFallback(cm, cmOutputs);
+ }
+ else
+ {
+ //KS - the index in the "new" list will be the index
+ output = mNewNarrowPhasePairs.mOutputContactManagers[PxsContactManagerBase::computeIndexFromId(index & (~PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK))];
+ unregisterContactManagerInternal(index, mNewNarrowPhasePairs, mNewNarrowPhasePairs.mOutputContactManagers.begin());
+ mNewNarrowPhasePairs.mOutputContactManagers.forceSize_Unsafe(mNewNarrowPhasePairs.mOutputContactManagers.size()-1);
+ }
+
+ PxI32 touching = 0;
+ if(output.statusFlag & PxsContactManagerStatusFlag::eHAS_TOUCH)
+ {
+ touching = 1;
+ cm->getWorkUnit().statusFlags |= PxcNpWorkUnitStatusFlag::eREFRESHED_WITH_TOUCH;
+ }
+ else if (output.statusFlag & PxsContactManagerStatusFlag::eHAS_NO_TOUCH)
+ touching = -1;
+ registerContactManager(cm, touching, output.nbPatches);
+
+
+}
+
+void PxsNphaseImplementationContext::appendContactManagers()
+{
+ //Copy new pairs to end of old pairs. Clear new flag, update npIndex on CM and clear the new pair buffer
+ const PxU32 existingSize = mNarrowPhasePairs.mContactManagerMapping.size();
+ const PxU32 nbToAdd = mNewNarrowPhasePairs.mContactManagerMapping.size();
+ const PxU32 newSize =existingSize + nbToAdd;
+
+ if(newSize > mNarrowPhasePairs.mContactManagerMapping.capacity())
+ {
+ PxU32 newSz = PxMax(256u, PxMax(mNarrowPhasePairs.mContactManagerMapping.capacity()*2, newSize));
+
+ mNarrowPhasePairs.mContactManagerMapping.reserve(newSz);
+ mNarrowPhasePairs.mOutputContactManagers.reserve(newSz);
+ mNarrowPhasePairs.mCaches.reserve(newSz);
+ }
+
+ mNarrowPhasePairs.mContactManagerMapping.forceSize_Unsafe(newSize);
+ mNarrowPhasePairs.mOutputContactManagers.forceSize_Unsafe(newSize);
+ mNarrowPhasePairs.mCaches.forceSize_Unsafe(newSize);
+
+ PxMemCopy(mNarrowPhasePairs.mContactManagerMapping.begin() + existingSize, mNewNarrowPhasePairs.mContactManagerMapping.begin(), sizeof(PxsContactManager*)*nbToAdd);
+ PxMemCopy(mNarrowPhasePairs.mOutputContactManagers.begin() + existingSize, mNewNarrowPhasePairs.mOutputContactManagers.begin(), sizeof(PxsContactManagerOutput)*nbToAdd);
+ PxMemCopy(mNarrowPhasePairs.mCaches.begin() + existingSize, mNewNarrowPhasePairs.mCaches.begin(), sizeof(Gu::Cache)*nbToAdd);
+
+ PxU32* edgeNodeIndices = mIslandSim->getEdgeNodeIndexPtr();
+
+ for(PxU32 a = 0; a < mNewNarrowPhasePairs.mContactManagerMapping.size(); ++a)
+ {
+ PxsContactManager* cm = mNewNarrowPhasePairs.mContactManagerMapping[a];
+ PxcNpWorkUnit& unit = cm->getWorkUnit();
+ unit.mNpIndex = mNarrowPhasePairs.computeId(existingSize + a);
+
+ if(unit.statusFlags & PxcNpWorkUnitStatusFlag::eREFRESHED_WITH_TOUCH)
+ {
+ unit.statusFlags &= (~PxcNpWorkUnitStatusFlag::eREFRESHED_WITH_TOUCH);
+ if(!(unit.flags & PxcNpWorkUnitFlag::eDISABLE_RESPONSE))
+ {
+ PartitionEdge* partitionEdge = mIslandSim->getFirstPartitionEdge(unit.mEdgeIndex);
+
+ while(partitionEdge)
+ {
+ edgeNodeIndices[partitionEdge->mUniqueIndex] = unit.mNpIndex;
+ partitionEdge = partitionEdge->mNextPatch;
+ }
+ }
+ }
+ }
+
+ mNewNarrowPhasePairs.clear();
+}
+
+void PxsNphaseImplementationContext::appendContactManagersFallback(PxsContactManagerOutput* cmOutputs)
+{
+ PX_PROFILE_ZONE("PxsNphaseImplementationContext.appendContactManagersFallback", mContext.mContextID);
+ //Copy new pairs to end of old pairs. Clear new flag, update npIndex on CM and clear the new pair buffer
+ //Copy new pairs to end of old pairs. Clear new flag, update npIndex on CM and clear the new pair buffer
+ const PxU32 existingSize = mNarrowPhasePairs.mContactManagerMapping.size();
+ const PxU32 nbToAdd = mNewNarrowPhasePairs.mContactManagerMapping.size();
+ const PxU32 newSize =existingSize + nbToAdd;
+
+ if(newSize > mNarrowPhasePairs.mContactManagerMapping.capacity())
+ {
+ PxU32 newSz = PxMax(mNarrowPhasePairs.mContactManagerMapping.capacity()*2, newSize);
+
+ mNarrowPhasePairs.mContactManagerMapping.reserve(newSz);
+ mNarrowPhasePairs.mCaches.reserve(newSz);
+ /*mNarrowPhasePairs.mLostFoundPairsCms.reserve(2 * newSz);
+ mNarrowPhasePairs.mLostFoundPairsOutputData.reserve(2*newSz);*/
+ }
+
+ mNarrowPhasePairs.mContactManagerMapping.forceSize_Unsafe(newSize);
+ mNarrowPhasePairs.mCaches.forceSize_Unsafe(newSize);
+
+ PxMemCopy(mNarrowPhasePairs.mContactManagerMapping.begin() + existingSize, mNewNarrowPhasePairs.mContactManagerMapping.begin(), sizeof(PxsContactManager*)*nbToAdd);
+ PxMemCopy(cmOutputs + existingSize, mNewNarrowPhasePairs.mOutputContactManagers.begin(), sizeof(PxsContactManagerOutput)*nbToAdd);
+ PxMemCopy(mNarrowPhasePairs.mCaches.begin() + existingSize, mNewNarrowPhasePairs.mCaches.begin(), sizeof(Gu::Cache)*nbToAdd);
+
+ PxU32* edgeNodeIndices = mIslandSim->getEdgeNodeIndexPtr();
+
+ for(PxU32 a = 0; a < mNewNarrowPhasePairs.mContactManagerMapping.size(); ++a)
+ {
+ PxsContactManager* cm = mNewNarrowPhasePairs.mContactManagerMapping[a];
+ PxcNpWorkUnit& unit = cm->getWorkUnit();
+ unit.mNpIndex = mNarrowPhasePairs.computeId(existingSize + a);
+
+ if(unit.statusFlags & PxcNpWorkUnitStatusFlag::eREFRESHED_WITH_TOUCH)
+ {
+ unit.statusFlags &= (~PxcNpWorkUnitStatusFlag::eREFRESHED_WITH_TOUCH);
+ if(!(unit.flags & PxcNpWorkUnitFlag::eDISABLE_RESPONSE))
+ {
+ PartitionEdge* partitionEdge = mIslandSim->getFirstPartitionEdge(unit.mEdgeIndex);
+
+ while(partitionEdge)
+ {
+ edgeNodeIndices[partitionEdge->mUniqueIndex] = unit.mNpIndex;
+ partitionEdge = partitionEdge->mNextPatch;
+ }
+ }
+ }
+ }
+
+ //const PxU32 existingLostFoundPairs = mNarrowPhasePairs.mLostFoundPairsCms.size();
+ //const PxU32 newLostFoundPairs = mNewNarrowPhasePairs.mLostFoundPairsCms.size();
+ //const PxU32 newLostFoundSize = existingLostFoundPairs + newLostFoundPairs;
+
+ //if (mNarrowPhasePairs.mLostFoundPairsCms.capacity() < newLostFoundSize)
+ //{
+ // const PxU32 newSz = PxMax(newLostFoundSize, 2 * mNarrowPhasePairs.mLostFoundPairsCms.capacity());
+ // mNarrowPhasePairs.mLostFoundPairsCms.reserve(newSz);
+ // mNarrowPhasePairs.mLostFoundPairsOutputData.reserve(newSz);
+ //}
+
+ //mNarrowPhasePairs.mLostFoundPairsCms.forceSize_Unsafe(newLostFoundSize);
+ //mNarrowPhasePairs.mLostFoundPairsOutputData.forceSize_Unsafe(newLostFoundSize);
+
+ //PxMemCopy(mNarrowPhasePairs.mLostFoundPairsCms.begin() + existingLostFoundPairs, mNewNarrowPhasePairs.mLostFoundPairsCms.begin(), sizeof(PxsContactManager*)* newLostFoundPairs);
+ //PxMemCopy(mNarrowPhasePairs.mLostFoundPairsOutputData.begin() + existingLostFoundPairs, mNewNarrowPhasePairs.mLostFoundPairsOutputData.begin(), sizeof(PxsContactManagerOutput) * newLostFoundPairs);
+
+ mNewNarrowPhasePairs.clear();
+}
+
+
+
+void PxsNphaseImplementationContext::unregisterContactManagerInternal(PxU32 npIndex, PxsContactManagers& managers, PxsContactManagerOutput* cmOutputs)
+{
+ //TODO - remove this element from the list.
+ PxU32 index = PxsContactManagerBase::computeIndexFromId((npIndex & (~PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK)));
+
+ //Now we replace-with-last and remove the elements...
+
+ PxU32 replaceIndex = managers.mContactManagerMapping.size()-1;
+
+ PxsContactManager* replaceManager = managers.mContactManagerMapping[replaceIndex];
+
+ mContext.destroyCache(managers.mCaches[index]);
+
+ managers.mContactManagerMapping[index] = replaceManager;
+ managers.mCaches[index] = managers.mCaches[replaceIndex];
+ cmOutputs[index] = cmOutputs[replaceIndex];
+
+ PxU32* edgeNodeIndices = mIslandSim->getEdgeNodeIndexPtr();
+
+ PxcNpWorkUnit& replaceUnit = replaceManager->getWorkUnit();
+ replaceUnit.mNpIndex = npIndex;
+ if(replaceUnit.statusFlags & PxcNpWorkUnitStatusFlag::eHAS_TOUCH)
+ {
+ if(!(replaceUnit.flags & PxcNpWorkUnitFlag::eDISABLE_RESPONSE))
+ {
+ PartitionEdge* partitionEdge = mIslandSim->getFirstPartitionEdge(replaceUnit.mEdgeIndex);
+ while(partitionEdge)
+ {
+ edgeNodeIndices[partitionEdge->mUniqueIndex] = replaceUnit.mNpIndex;
+ partitionEdge = partitionEdge->mNextPatch;
+ }
+ }
+ }
+
+ managers.mContactManagerMapping.forceSize_Unsafe(replaceIndex);
+ managers.mCaches.forceSize_Unsafe(replaceIndex);
+}
+
+PxsContactManagerOutput& PxsNphaseImplementationContext::getNewContactManagerOutput(PxU32 npId)
+{
+ PX_ASSERT(npId & PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK);
+ return this->mNewNarrowPhasePairs.mOutputContactManagers[PxsContactManagerBase::computeIndexFromId(npId & (~PxsContactManagerBase::NEW_CONTACT_MANAGER_MASK))];
+}
+
+void PxsNphaseImplementationContext::registerShape(const PxsShapeCore& shapeCore)
+{
+ PX_UNUSED(shapeCore);
+}
+
+void PxsNphaseImplementationContext::updateShapeMaterial(const PxsShapeCore& shapeCore)
+{
+ PX_UNUSED(shapeCore);
+}
+
+void PxsNphaseImplementationContext::updateShapeContactOffset(const PxsShapeCore& shapeCore)
+{
+ PX_UNUSED(shapeCore);
+}
+
+void PxsNphaseImplementationContext::unregisterShape(const PxsShapeCore& shapeCore)
+{
+ PX_UNUSED(shapeCore);
+}
+
+void PxsNphaseImplementationContext::registerMaterial(const PxsMaterialCore& materialCore)
+{
+ PX_UNUSED(materialCore);
+}
+
+void PxsNphaseImplementationContext::updateMaterial(const PxsMaterialCore& materialCore)
+{
+ PX_UNUSED(materialCore);
+}
+
+void PxsNphaseImplementationContext::unregisterMaterial(const PxsMaterialCore& materialCore)
+{
+ PX_UNUSED(materialCore);
+}
+
+PxsContactManagerOutputIterator PxsNphaseImplementationContext::getContactManagerOutputs()
+{
+ PxU32 offsets[1] = {0};
+ return PxsContactManagerOutputIterator(offsets, 1, this->mNarrowPhasePairs.mOutputContactManagers.begin());
+}
+
+
+PxvNphaseImplementationContextUsableAsFallback* physx::createNphaseImplementationContext(PxsContext& context, IG::IslandSim* islandSim)
+{
+ return PxsNphaseImplementationContext::create(context, islandSim);
+}
+
diff --git a/PhysX_3.4/Source/LowLevel/software/src/PxsSimpleIslandManager.cpp b/PhysX_3.4/Source/LowLevel/software/src/PxsSimpleIslandManager.cpp
new file mode 100644
index 00000000..b01eefb0
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevel/software/src/PxsSimpleIslandManager.cpp
@@ -0,0 +1,369 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "foundation/PxProfiler.h"
+#include "PxsSimpleIslandManager.h"
+#include "PsSort.h"
+#include "PxsContactManager.h"
+#include "CmTask.h"
+
+#define IG_SANITY_CHECKS 0
+
+namespace physx
+{
+namespace IG
+{
+
+ SimpleIslandManager::SimpleIslandManager(bool useEnhancedDeterminism, PxU64 contextID) :
+ mDestroyedNodes(PX_DEBUG_EXP("mDestroyedNodes")),
+ mInteractions(PX_DEBUG_EXP("mInteractions")),
+ mDestroyedEdges(PX_DEBUG_EXP("mDestroyedEdges")),
+ mFirstPartitionEdges(PX_DEBUG_EXP("mFirstPartitionEdges")),
+ mDestroyedPartitionEdges(PX_DEBUG_EXP("IslandSim::mDestroyedPartitionEdges")),
+ mEdgeNodeIndices(PX_DEBUG_EXP("mEdgeNodeIndices")),
+ mConstraintOrCm(PX_DEBUG_EXP("mConstraintOrCm")),
+ mIslandManager(&mFirstPartitionEdges, mEdgeNodeIndices, &mDestroyedPartitionEdges, contextID),
+ mSpeculativeIslandManager(NULL, mEdgeNodeIndices, NULL, contextID),
+ mSpeculativeThirdPassTask(*this, mSpeculativeIslandManager),
+ mAccurateThirdPassTask(*this, mIslandManager),
+ mPostThirdPassTask(*this),
+ mContextID(contextID)
+{
+ mFirstPartitionEdges.resize(1024);
+ mMaxDirtyNodesPerFrame = useEnhancedDeterminism ? 0xFFFFFFFF : 1000u;
+}
+
+SimpleIslandManager::~SimpleIslandManager()
+{
+}
+
+NodeIndex SimpleIslandManager::addRigidBody(PxsRigidBody* body, bool isKinematic, bool isActive)
+{
+ PxU32 handle = mNodeHandles.getHandle();
+ NodeIndex nodeIndex(handle);
+ mIslandManager.addRigidBody(body, isKinematic, isActive, nodeIndex);
+ mSpeculativeIslandManager.addRigidBody(body, isKinematic, isActive, nodeIndex);
+ return nodeIndex;
+}
+
+void SimpleIslandManager::removeNode(const NodeIndex index)
+{
+ PX_ASSERT(mNodeHandles.isValidHandle(index.index()));
+ mDestroyedNodes.pushBack(index);
+}
+
+NodeIndex SimpleIslandManager::addArticulation(Sc::ArticulationSim* articulation, Dy::Articulation* llArtic, bool isActive)
+{
+ PxU32 handle = mNodeHandles.getHandle();
+ NodeIndex nodeIndex(handle);
+ mIslandManager.addArticulation(articulation, llArtic, isActive, nodeIndex);
+ mSpeculativeIslandManager.addArticulation(articulation, llArtic, isActive, nodeIndex);
+ return nodeIndex;
+}
+
+EdgeIndex SimpleIslandManager::addContactManager(PxsContactManager* manager, NodeIndex nodeHandle1, NodeIndex nodeHandle2, Sc::Interaction* interaction)
+{
+ EdgeIndex handle = mEdgeHandles.getHandle();
+
+ PxU32 nodeIds = 2 * handle;
+ if (mEdgeNodeIndices.size() == nodeIds)
+ {
+ mEdgeNodeIndices.resize(2 * (nodeIds + 2));
+ mConstraintOrCm.resize(2 * (handle + 1));
+ mInteractions.resize(2 * (handle + 1));
+ }
+
+ mEdgeNodeIndices[nodeIds] = nodeHandle1;
+ mEdgeNodeIndices[nodeIds+1] = nodeHandle2;
+ mConstraintOrCm[handle].mCm = manager;
+ mInteractions[handle] = interaction;
+
+ mSpeculativeIslandManager.addContactManager(manager, nodeHandle1, nodeHandle2, handle);
+
+ if (manager)
+ manager->getWorkUnit().mEdgeIndex = handle;
+
+ if(mConnectedMap.size() == handle)
+ {
+ mConnectedMap.resize(2 * (handle + 1));
+ }
+ if (mFirstPartitionEdges.capacity() == handle)
+ {
+ mFirstPartitionEdges.resize(2 * (handle + 1));
+ }
+ mConnectedMap.reset(handle);
+ return handle;
+}
+
+EdgeIndex SimpleIslandManager::addConstraint(Dy::Constraint* constraint, NodeIndex nodeHandle1, NodeIndex nodeHandle2, Sc::Interaction* interaction)
+{
+ EdgeIndex handle = mEdgeHandles.getHandle();
+
+ PxU32 nodeIds = 2 * handle;
+ if (mEdgeNodeIndices.size() == nodeIds)
+ {
+ mEdgeNodeIndices.resize(2 * (mEdgeNodeIndices.size() + 2));
+ mConstraintOrCm.resize(2 * (handle + 1));
+ mInteractions.resize(2 * (handle + 1));
+ }
+
+ mEdgeNodeIndices[nodeIds] = nodeHandle1;
+ mEdgeNodeIndices[nodeIds + 1] = nodeHandle2;
+
+ mConstraintOrCm[handle].mConstraint = constraint;
+
+ mInteractions[handle] = interaction;
+
+ mIslandManager.addConstraint(constraint, nodeHandle1, nodeHandle2, handle);
+ mSpeculativeIslandManager.addConstraint(constraint, nodeHandle1, nodeHandle2, handle);
+ if(mConnectedMap.size() == handle)
+ {
+ mConnectedMap.resize(2*(mConnectedMap.size()+1));
+ }
+
+ if (mFirstPartitionEdges.capacity() == handle)
+ {
+ mFirstPartitionEdges.resize(2 * (mFirstPartitionEdges.capacity() + 1));
+ }
+ mConnectedMap.set(handle);
+ return handle;
+}
+
+void SimpleIslandManager::activateNode(NodeIndex index)
+{
+ mIslandManager.activateNode(index);
+ mSpeculativeIslandManager.activateNode(index);
+}
+
+void SimpleIslandManager::deactivateNode(NodeIndex index)
+{
+ mIslandManager.deactivateNode(index);
+ mSpeculativeIslandManager.deactivateNode(index);
+}
+
+void SimpleIslandManager::putNodeToSleep(NodeIndex index)
+{
+ mIslandManager.putNodeToSleep(index);
+ mSpeculativeIslandManager.putNodeToSleep(index);
+}
+
+void SimpleIslandManager::removeConnection(EdgeIndex edgeIndex)
+{
+ if(edgeIndex == IG_INVALID_EDGE)
+ return;
+ mDestroyedEdges.pushBack(edgeIndex);
+ mSpeculativeIslandManager.removeConnection(edgeIndex);
+ if(mConnectedMap.test(edgeIndex))
+ {
+ mIslandManager.removeConnection(edgeIndex);
+ mConnectedMap.reset(edgeIndex);
+ }
+
+ mConstraintOrCm[edgeIndex].mCm = NULL;
+ mInteractions[edgeIndex] = NULL;
+}
+
+void SimpleIslandManager::firstPassIslandGen()
+{
+ PX_PROFILE_ZONE("Basic.firstPassIslandGen", getContextId());
+ mSpeculativeIslandManager.clearDeactivations();
+ mSpeculativeIslandManager.wakeIslands();
+ mSpeculativeIslandManager.processNewEdges();
+ mSpeculativeIslandManager.removeDestroyedEdges();
+ mSpeculativeIslandManager.processLostEdges(mDestroyedNodes, false, false, mMaxDirtyNodesPerFrame);
+}
+
+void SimpleIslandManager::additionalSpeculativeActivation()
+{
+ mSpeculativeIslandManager.wakeIslands2();
+}
+
+void SimpleIslandManager::secondPassIslandGen()
+{
+ PX_PROFILE_ZONE("Basic.secondPassIslandGen", getContextId());
+
+ mIslandManager.wakeIslands();
+ mIslandManager.processNewEdges();
+
+ mIslandManager.removeDestroyedEdges();
+ mIslandManager.processLostEdges(mDestroyedNodes, false, false, mMaxDirtyNodesPerFrame);
+
+ for(PxU32 a = 0; a < mDestroyedNodes.size(); ++a)
+ {
+ mNodeHandles.freeHandle(mDestroyedNodes[a].index());
+ }
+ mDestroyedNodes.clear();
+ mDestroyedEdges.clear();
+}
+
+bool SimpleIslandManager::validateDeactivations() const
+{
+ //This method sanity checks the deactivations produced by third-pass island gen. Specifically, it ensures that any bodies that
+ //the speculative IG wants to deactivate are also candidates for deactivation in the accurate island gen. In practice, both should be the case. If this fails, something went wrong...
+
+ const NodeIndex* const nodeIndices = mSpeculativeIslandManager.getNodesToDeactivate(Node::eRIGID_BODY_TYPE);
+ const PxU32 nbNodesToDeactivate = mSpeculativeIslandManager.getNbNodesToDeactivate(Node::eRIGID_BODY_TYPE);
+
+ for(PxU32 i = 0; i < nbNodesToDeactivate; ++i)
+ {
+ //Node is active in accurate sim => mismatch between accurate and inaccurate sim!
+ const Node& node = mIslandManager.getNode(nodeIndices[i]);
+ const Node& speculativeNode = mSpeculativeIslandManager.getNode(nodeIndices[i]);
+ //KS - we need to verify that the bodies in the "deactivating" list are still candidates for deactivation. There are cases where they may not no longer be candidates, e.g. if the application
+ //put bodies to sleep and activated them
+ if(node.isActive() && !speculativeNode.isActive())
+ return false;
+ }
+ return true;
+}
+
+void ThirdPassTask::runInternal()
+{
+ PX_PROFILE_ZONE("Basic.thirdPassIslandGen", mIslandSim.getContextId());
+ mIslandSim.removeDestroyedEdges();
+ mIslandSim.processLostEdges(mIslandManager.mDestroyedNodes, true, true, mIslandManager.mMaxDirtyNodesPerFrame);
+}
+
+void PostThirdPassTask::runInternal()
+{
+ for (PxU32 a = 0; a < mIslandManager.mDestroyedNodes.size(); ++a)
+ {
+ mIslandManager.mNodeHandles.freeHandle(mIslandManager.mDestroyedNodes[a].index());
+ }
+ mIslandManager.mDestroyedNodes.clear();
+
+ for (PxU32 a = 0; a < mIslandManager.mDestroyedEdges.size(); ++a)
+ {
+ mIslandManager.mEdgeHandles.freeHandle(mIslandManager.mDestroyedEdges[a]);
+ }
+ mIslandManager.mDestroyedEdges.clear();
+
+ PX_ASSERT(mIslandManager.validateDeactivations());
+}
+
+void SimpleIslandManager::thirdPassIslandGen(PxBaseTask* continuation)
+{
+
+ mIslandManager.clearDeactivations();
+
+ mPostThirdPassTask.setContinuation(continuation);
+
+ mSpeculativeThirdPassTask.setContinuation(&mPostThirdPassTask);
+ mAccurateThirdPassTask.setContinuation(&mPostThirdPassTask);
+
+ mSpeculativeThirdPassTask.removeReference();
+ mAccurateThirdPassTask.removeReference();
+
+ mPostThirdPassTask.removeReference();
+
+ //PX_PROFILE_ZONE("Basic.thirdPassIslandGen", getContextId());
+ //mSpeculativeIslandManager.removeDestroyedEdges();
+ //mSpeculativeIslandManager.processLostEdges(mDestroyedNodes, true, true);
+
+ //mIslandManager.removeDestroyedEdges();
+ //mIslandManager.processLostEdges(mDestroyedNodes, true, true);
+
+
+}
+
+bool SimpleIslandManager::checkInternalConsistency()
+{
+ return mIslandManager.checkInternalConsistency() && mSpeculativeIslandManager.checkInternalConsistency();
+}
+
+void SimpleIslandManager::clearDestroyedEdges()
+{
+ mDestroyedPartitionEdges.forceSize_Unsafe(0);
+}
+
+void SimpleIslandManager::setEdgeConnected(EdgeIndex edgeIndex)
+{
+ if(!mConnectedMap.test(edgeIndex))
+ {
+ mIslandManager.addContactManager(mConstraintOrCm[edgeIndex].mCm, mEdgeNodeIndices[edgeIndex*2], mEdgeNodeIndices[edgeIndex*2+1], edgeIndex);
+ mConnectedMap.set(edgeIndex);
+ }
+}
+
+bool SimpleIslandManager::getIsEdgeConnected(EdgeIndex edgeIndex)
+{
+ return !!mConnectedMap.test(edgeIndex);
+}
+
+void SimpleIslandManager::deactivateEdge(const EdgeIndex edgeIndex)
+{
+ if (mFirstPartitionEdges[edgeIndex])
+ {
+ mDestroyedPartitionEdges.pushBack(mFirstPartitionEdges[edgeIndex]);
+ mFirstPartitionEdges[edgeIndex] = NULL;
+ }
+}
+
+void SimpleIslandManager::setEdgeDisconnected(EdgeIndex edgeIndex)
+{
+ if(mConnectedMap.test(edgeIndex))
+ {
+ //PX_ASSERT(!mIslandManager.getEdge(edgeIndex).isInDirtyList());
+ mIslandManager.removeConnection(edgeIndex);
+ mConnectedMap.reset(edgeIndex);
+ }
+}
+
+void SimpleIslandManager::setEdgeRigidCM(const EdgeIndex edgeIndex, PxsContactManager* cm)
+{
+ mConstraintOrCm[edgeIndex].mCm = cm;
+ cm->getWorkUnit().mEdgeIndex = edgeIndex;
+}
+
+void SimpleIslandManager::clearEdgeRigidCM(const EdgeIndex edgeIndex)
+{
+ mConstraintOrCm[edgeIndex].mCm = NULL;
+ if (mFirstPartitionEdges[edgeIndex])
+ {
+ //this is the partition edges created/updated by the gpu solver
+ mDestroyedPartitionEdges.pushBack(mFirstPartitionEdges[edgeIndex]);
+ mFirstPartitionEdges[edgeIndex] = NULL;
+ }
+}
+
+void SimpleIslandManager::setKinematic(IG::NodeIndex nodeIndex)
+{
+ mIslandManager.setKinematic(nodeIndex);
+ mSpeculativeIslandManager.setKinematic(nodeIndex);
+}
+
+void SimpleIslandManager::setDynamic(IG::NodeIndex nodeIndex)
+{
+ mIslandManager.setDynamic(nodeIndex);
+ mSpeculativeIslandManager.setDynamic(nodeIndex);
+}
+
+}
+}
+