diff options
Diffstat (limited to 'PhysX_3.4/Source/LowLevel')
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); +} + +} +} + |