Revision control
++ // Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
++ // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
++ // SPDX-FileCopyrightText: Copyright (c) 2008-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
++ // SPDX-License-Identifier: Apache-2.0
++
++ #ifndef PXC_NP_WORK_UNIT_H
++ #define PXC_NP_WORK_UNIT_H
++
++ #include "PxConstraintDesc.h"
++ #include "PxvGeometry.h"
++
++ // PT: the shapeCore structs are 16-bytes aligned by design so the low 4 bits of their pointers are available.
++ // We can store the geom types there since they fit. An alternative would be simply to read the types from
++ // shapeCore->mGeometry.getType() but that is one more indirection/cache miss. We might be using other shapeCore
++ // data everywhere we need the type so that might be irrelevant and could be revisited.
++ PX_COMPILE_TIME_ASSERT(physx::PxGeometryType::eGEOMETRY_COUNT<16);
++
++ namespace physx
++ {
++ struct PxsRigidCore;
++ struct PxsShapeCore;
++
++ namespace IG
++ {
++ typedef PxU32 EdgeIndex;
++ }
++
++ struct PxcNpWorkUnitFlag
++ {
++ enum Enum
++ {
++ eOUTPUT_CONTACTS = 1 << 0,
++ eOUTPUT_CONSTRAINTS = 1 << 1,
++ eDISABLE_STRONG_FRICTION = 1 << 2,
++ eARTICULATION_BODY0 = 1 << 3,
++ eARTICULATION_BODY1 = 1 << 4,
++ eDYNAMIC_BODY0 = 1 << 5,
++ eDYNAMIC_BODY1 = 1 << 6,
++ eSOFT_BODY = 1 << 7,
++ eMODIFIABLE_CONTACT = 1 << 8,
++ eFORCE_THRESHOLD = 1 << 9,
++ eDETECT_DISCRETE_CONTACT = 1 << 10,
++ eHAS_KINEMATIC_ACTOR = 1 << 11,
++ eDISABLE_RESPONSE = 1 << 12,
++ eDETECT_CCD_CONTACTS = 1 << 13,
++ eDOMINANCE_0 = 1 << 14,
++ eDOMINANCE_1 = 1 << 15,
++ };
++ };
++
++ 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)
++ };
++ };
++
++ struct PxcNpWorkUnit
++ {
++ const PxsRigidCore* mRigidCore0; // INPUT //8
++ const PxsRigidCore* mRigidCore1; // INPUT //16
++
++ private:
++ const void* mShapeCoreAndType0; // INPUT //24
++ const void* mShapeCoreAndType1; // INPUT //32
++ public:
++
++ PxU8* mCCDContacts; // OUTPUT //40
++ PxU8* mFrictionDataPtr; // INOUT //48
++
++ PxU16 mFlags; // INPUT //50
++ PxU8 mFrictionPatchCount; // INOUT //51
++ PxU8 mStatusFlags; // OUTPUT (see PxcNpWorkUnitStatusFlag) //52
++
++ PxReal mRestDistance; // INPUT //56
++
++ PxU32 mTransformCache0; // //60
++ PxU32 mTransformCache1; // //64
++
++ IG::EdgeIndex mEdgeIndex; //inout the island gen edge index //68
++ PxU32 mNpIndex; //INPUT //72
++
++ PxReal mTorsionalPatchRadius; //76
++ PxReal mMinTorsionalPatchRadius; //80
++ PxReal mOffsetSlop; //84
++ //88 pading
++
++ ///////////////////////////////////////////////////////////////////////////
++
++ PX_FORCE_INLINE const void* encode(const PxsShapeCore* shapeCore)
++ {
++ const PxU64 type = PxU64(shapeCore->mGeometry.getType());
++ PxU64 data = PxU64(shapeCore);
++ PX_ASSERT(!(data & 15));
++ data |= type;
++ return reinterpret_cast<const void*>(data);
++ }
++
++ PX_FORCE_INLINE void setShapeCore0(const PxsShapeCore* shapeCore)
++ {
++ mShapeCoreAndType0 = encode(shapeCore);
++ }
++
++ PX_FORCE_INLINE void setShapeCore1(const PxsShapeCore* shapeCore)
++ {
++ mShapeCoreAndType1 = encode(shapeCore);
++ }
++
++ PX_FORCE_INLINE const PxsShapeCore* getShapeCore0() const
++ {
++ return reinterpret_cast<const PxsShapeCore*>(PxU64(mShapeCoreAndType0) & ~15);
++ }
++
++ PX_FORCE_INLINE const PxsShapeCore* getShapeCore1() const
++ {
++ return reinterpret_cast<const PxsShapeCore*>(PxU64(mShapeCoreAndType1) & ~15);
++ }
++
++ PX_FORCE_INLINE PxGeometryType::Enum getGeomType0() const
++ {
++ return PxGeometryType::Enum(PxU64(mShapeCoreAndType0) & 15);
++ }
++
++ PX_FORCE_INLINE PxGeometryType::Enum getGeomType1() const
++ {
++ return PxGeometryType::Enum(PxU64(mShapeCoreAndType1) & 15);
++ }
++
++ ///////////////////////////////////////////////////////////////////////////
++
++ PX_FORCE_INLINE PxU8 getDominance0() const
++ {
++ return (mFlags & PxcNpWorkUnitFlag::eDOMINANCE_0) ? 0 : 1;
++ }
++
++ PX_FORCE_INLINE void setDominance0(PxU8 v)
++ {
++ if(v==0)
++ mFlags |= PxcNpWorkUnitFlag::eDOMINANCE_0;
++ else
++ mFlags &= ~PxcNpWorkUnitFlag::eDOMINANCE_0;
++ }
++
++ PX_FORCE_INLINE PxU8 getDominance1() const
++ {
++ return (mFlags & PxcNpWorkUnitFlag::eDOMINANCE_1) ? 0 : 1;
++ }
++
++ PX_FORCE_INLINE void setDominance1(PxU8 v)
++ {
++ if(v==0)
++ mFlags |= PxcNpWorkUnitFlag::eDOMINANCE_1;
++ else
++ mFlags &= ~PxcNpWorkUnitFlag::eDOMINANCE_1;
++ }
++
++ PX_FORCE_INLINE void setInvMassScaleFromDominance(PxConstraintInvMassScale& invMassScales) const
++ {
++ const PxReal dominance0 = getDominance0() ? 1.0f : 0.0f;
++ const PxReal dominance1 = getDominance1() ? 1.0f : 0.0f;
++
++ invMassScales.linear0 = invMassScales.angular0 = dominance0;
++ invMassScales.linear1 = invMassScales.angular1 = dominance1;
++ }
++
++ ///////////////////////////////////////////////////////////////////////////
++
++ PX_FORCE_INLINE void clearCachedState()
++ {
++ mFrictionDataPtr = NULL;
++ mFrictionPatchCount = 0;
++ mCCDContacts = NULL;
++ }
++ };
++
++ }
++
++ #endif