include/PxContact.h

File members: include/PxContact.h

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//  * Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//  * Neither the name of NVIDIA CORPORATION nor the names of its
//    contributors may be used to endorse or promote products derived
//    from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2024 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 PX_CONTACT_H
#define PX_CONTACT_H

#include "foundation/PxVec3.h"
#include "foundation/PxAssert.h"
#include "PxConstraintDesc.h"
#include "PxNodeIndex.h"
#include "PxMaterial.h"

#if !PX_DOXYGEN
namespace physx
{
#endif

#if PX_VC
#pragma warning(push)
#pragma warning(disable: 4324)  // Padding was added at the end of a structure because of a __declspec(align) value.
#endif

#define PXC_CONTACT_NO_FACE_INDEX 0xffffffff

class PxActor;

PX_ALIGN_PREFIX(16)
struct PxContactPatch
{
    enum PxContactPatchFlags
    {
        eHAS_FACE_INDICES = 1,
        eMODIFIABLE = 2,
        eFORCE_NO_RESPONSE = 4,
        eHAS_MODIFIED_MASS_RATIOS = 8,
        eHAS_TARGET_VELOCITY = 16,
        eHAS_MAX_IMPULSE = 32,
        eREGENERATE_PATCHES = 64,
        eCOMPRESSED_MODIFIED_CONTACT = 128
    };

    PX_ALIGN(16, PxConstraintInvMassScale mMassModification);

    PX_ALIGN(16, PxVec3 normal);

    PxReal  restitution;

    PxReal  dynamicFriction;

    PxReal  staticFriction;

    PxReal  damping;

    PxU16   startContactIndex;

    PxU8    nbContacts;

    PxU8    materialFlags;

    PxU16   internalFlags;

    PxU16   materialIndex0;

    PxU16   materialIndex1;

    PxU16   pad[5];
}
PX_ALIGN_SUFFIX(16);

PX_ALIGN_PREFIX(16)
struct PxContact
{
    PxVec3  contact;
    PxReal  separation;
}
PX_ALIGN_SUFFIX(16);

PX_ALIGN_PREFIX(16)
struct PxExtendedContact : public PxContact
{
    PX_ALIGN(16, PxVec3 targetVelocity);
    PxReal  maxImpulse;
}
PX_ALIGN_SUFFIX(16);

PX_ALIGN_PREFIX(16)
struct PxModifiableContact : public PxExtendedContact
{
    PX_ALIGN(16, PxVec3 normal);
    PxReal  restitution;

    PxU32   materialFlags;

    PxU16   materialIndex0;
    PxU16   materialIndex1;
    PxReal  staticFriction;
    PxReal dynamicFriction;
}
PX_ALIGN_SUFFIX(16);

struct PxContactStreamIterator
{
    enum StreamFormat
    {
        eSIMPLE_STREAM,
        eMODIFIABLE_STREAM,
        eCOMPRESSED_MODIFIABLE_STREAM
    };
    PxVec3 zero;

    const PxContactPatch* patch;

    const PxContact* contact;

    const PxU32* faceIndice;

    PxU32 totalPatches;

    PxU32 totalContacts;

    PxU32 nextContactIndex;

    PxU32 nextPatchIndex;

    PxU32 contactPatchHeaderSize;

    PxU32 contactPointSize;

    StreamFormat mStreamFormat;

    PxU32 forceNoResponse;

    bool pointStepped;

    PxU32 hasFaceIndices;

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxContactStreamIterator(const PxU8* contactPatches, const PxU8* contactPoints, const PxU32* contactFaceIndices, PxU32 nbPatches, PxU32 nbContacts)
        : zero(0.f)
    {
        bool modify = false;
        bool compressedModify = false;
        bool response = false;
        bool indices = false;

        PxU32 pointSize = 0;
        PxU32 patchHeaderSize = sizeof(PxContactPatch);

        const PxContactPatch* patches = reinterpret_cast<const PxContactPatch*>(contactPatches);

        if(patches)
        {
            modify = (patches->internalFlags & PxContactPatch::eMODIFIABLE) != 0;
            compressedModify = (patches->internalFlags & PxContactPatch::eCOMPRESSED_MODIFIED_CONTACT) != 0;
            indices = (patches->internalFlags & PxContactPatch::eHAS_FACE_INDICES) != 0;

            patch = patches;

            contact = reinterpret_cast<const PxContact*>(contactPoints);

            faceIndice = contactFaceIndices;

            pointSize = compressedModify ?  sizeof(PxExtendedContact) : modify ? sizeof(PxModifiableContact) : sizeof(PxContact);

            response = (patch->internalFlags & PxContactPatch::eFORCE_NO_RESPONSE) == 0;
        }

        mStreamFormat = compressedModify ? eCOMPRESSED_MODIFIABLE_STREAM : modify ? eMODIFIABLE_STREAM : eSIMPLE_STREAM;
        hasFaceIndices = PxU32(indices);
        forceNoResponse = PxU32(!response);

        contactPatchHeaderSize = patchHeaderSize;
        contactPointSize = pointSize;
        nextPatchIndex = 0;
        nextContactIndex = 0;
        totalContacts = nbContacts;
        totalPatches = nbPatches;

        pointStepped = false;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE bool hasNextPatch() const
    {
        return nextPatchIndex < totalPatches;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getTotalContactCount() const
    {
        return totalContacts;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getTotalPatchCount() const
    {
        return totalPatches;
    }

    PX_CUDA_CALLABLE PX_INLINE void nextPatch()
    {
        PX_ASSERT(nextPatchIndex < totalPatches);
        if(nextPatchIndex)
        {
            if(nextContactIndex < patch->nbContacts)
            {
                PxU32 nbToStep = patch->nbContacts - this->nextContactIndex;
                contact = reinterpret_cast<const PxContact*>(reinterpret_cast<const PxU8*>(contact) + contactPointSize * nbToStep);
            }
            patch = reinterpret_cast<const PxContactPatch*>(reinterpret_cast<const PxU8*>(patch) + contactPatchHeaderSize);
        }
        nextPatchIndex++;
        nextContactIndex = 0;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE bool hasNextContact() const
    {
        return nextContactIndex < (patch->nbContacts);
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE void nextContact()
    {
        PX_ASSERT(nextContactIndex < patch->nbContacts);
        if(pointStepped)
        {
            contact = reinterpret_cast<const PxContact*>(reinterpret_cast<const PxU8*>(contact) + contactPointSize);
            faceIndice++;
        }
        nextContactIndex++;
        pointStepped = true;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE const PxVec3& getContactNormal() const
    {
        return getContactPatch().normal;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getInvMassScale0() const
    {
        return patch->mMassModification.linear0;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getInvMassScale1() const
    {
        return patch->mMassModification.linear1;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getInvInertiaScale0() const
    {
        return patch->mMassModification.angular0;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getInvInertiaScale1() const
    {
        return patch->mMassModification.angular1;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getMaxImpulse() const
    {
        return mStreamFormat != eSIMPLE_STREAM ? getExtendedContact().maxImpulse : PX_MAX_REAL;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE const PxVec3& getTargetVel() const
    {
        return mStreamFormat != eSIMPLE_STREAM ? getExtendedContact().targetVelocity : zero;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE const PxVec3& getContactPoint() const
    {
        return contact->contact;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getSeparation() const
    {
        return contact->separation;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getFaceIndex0() const
    {
        return PXC_CONTACT_NO_FACE_INDEX;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getFaceIndex1() const
    {
        return hasFaceIndices ? *faceIndice : PXC_CONTACT_NO_FACE_INDEX;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getStaticFriction() const
    {
        return getContactPatch().staticFriction;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getDynamicFriction() const
    {
        return getContactPatch().dynamicFriction;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getRestitution() const
    {
        return getContactPatch().restitution;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getDamping() const
    {
        return getContactPatch().damping;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getMaterialFlags() const
    {
        return getContactPatch().materialFlags;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxU16 getMaterialIndex0() const
    {
        return PxU16(getContactPatch().materialIndex0);
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxU16 getMaterialIndex1() const
    {
        return PxU16(getContactPatch().materialIndex1);
    }

    bool advanceToIndex(const PxU32 initialIndex)
    {
        PX_ASSERT(this->nextPatchIndex == 0 && this->nextContactIndex == 0);

        PxU32 numToAdvance = initialIndex;

        if(numToAdvance == 0)
        {
            PX_ASSERT(hasNextPatch());
            nextPatch();
            return true;
        }

        while(numToAdvance)
        {
            while(hasNextPatch())
            {
                nextPatch();
                PxU32 patchSize = patch->nbContacts;
                if(numToAdvance <= patchSize)
                {
                    contact = reinterpret_cast<const PxContact*>(reinterpret_cast<const PxU8*>(contact) + contactPointSize * numToAdvance);
                    nextContactIndex += numToAdvance;
                    return true;
                }
                else
                {
                    numToAdvance -= patchSize;
                }
            }
        }
        return false;
    }

private:

    PX_CUDA_CALLABLE PX_FORCE_INLINE const PxContactPatch& getContactPatch() const
    {
        return *static_cast<const PxContactPatch*>(patch);
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE const PxExtendedContact& getExtendedContact() const
    {
        PX_ASSERT(mStreamFormat == eMODIFIABLE_STREAM || mStreamFormat == eCOMPRESSED_MODIFIABLE_STREAM);
        return *static_cast<const PxExtendedContact*>(contact);
    }

};

struct PxFrictionPatch
{
    static const PxU32 MAX_ANCHOR_COUNT = 2;

    PxVec3 anchorPositions[MAX_ANCHOR_COUNT];

    PxVec3 anchorImpulses[MAX_ANCHOR_COUNT];

    PxU32 anchorCount;
};

class PxFrictionAnchorStreamIterator
{
public:
    PX_CUDA_CALLABLE PX_FORCE_INLINE PxFrictionAnchorStreamIterator(const PxU8* contactPatches, const PxU8* frictionPatches, PxU32 patchCount)
        :
        mContactPatches(reinterpret_cast<const PxContactPatch*>(contactPatches)),
        mFrictionPatches(reinterpret_cast<const PxFrictionPatch*>(frictionPatches)),
        mPatchCount(patchCount),
        mFrictionAnchorIndex(-1),
        mPatchIndex(-1)
    {}

    PX_CUDA_CALLABLE PX_FORCE_INLINE bool hasNextPatch() const
    {
        return isValid() && mPatchIndex < PxI32(mPatchCount) - 1;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE void nextPatch()
    {
        PX_ASSERT(hasNextPatch());
        ++mPatchIndex;
        mFrictionAnchorIndex = -1;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE bool hasNextFrictionAnchor() const
    {
        return patchIsValid() && mFrictionAnchorIndex < PxI32(mFrictionPatches[mPatchIndex].anchorCount) - 1;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE void nextFrictionAnchor()
    {
        PX_ASSERT(hasNextFrictionAnchor());
        mFrictionAnchorIndex++;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE const PxVec3& getPosition() const
    {
        PX_ASSERT(frictionAnchorIsValid());
        return mFrictionPatches[mPatchIndex].anchorPositions[mFrictionAnchorIndex];
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE const PxVec3& getImpulse() const
    {
        PX_ASSERT(frictionAnchorIsValid());
        return mFrictionPatches[mPatchIndex].anchorImpulses[mFrictionAnchorIndex];
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE const PxVec3& getNormal() const
    {
        PX_ASSERT(patchIsValid());
        return mContactPatches[mPatchIndex].normal;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getStaticFriction() const
    {
        PX_ASSERT(patchIsValid());
        return mContactPatches[mPatchIndex].staticFriction;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getDynamicFriction() const
    {
        PX_ASSERT(patchIsValid());
        return mContactPatches[mPatchIndex].dynamicFriction;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxMaterialFlags getMaterialFlags() const
    {
        PX_ASSERT(patchIsValid());
        return PxMaterialFlags(mContactPatches[mPatchIndex].materialFlags);
    }

private:

    PX_CUDA_CALLABLE PX_FORCE_INLINE PxFrictionAnchorStreamIterator();

    PX_CUDA_CALLABLE PX_FORCE_INLINE bool isValid() const
    {
        return mContactPatches && mFrictionPatches;
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE bool patchIsValid() const
    {
        return isValid() && mPatchIndex >= 0 && mPatchIndex < PxI32(mPatchCount);
    }

    PX_CUDA_CALLABLE PX_FORCE_INLINE bool frictionAnchorIsValid() const
    {
        return patchIsValid() && mFrictionAnchorIndex >= 0 && mFrictionAnchorIndex < PxI32(mFrictionPatches[mPatchIndex].anchorCount);
    }

    const PxContactPatch* mContactPatches;
    const PxFrictionPatch* mFrictionPatches;
    PxU32 mPatchCount;
    PxI32 mFrictionAnchorIndex;
    PxI32 mPatchIndex;
};

struct PxGpuContactPair
{
    PxU8* contactPatches;
    PxU8* contactPoints;
    PxReal* contactForces;
    PxU8* frictionPatches;
    PxU32 transformCacheRef0;
    PxU32 transformCacheRef1;
    PxNodeIndex nodeIndex0;
    PxNodeIndex nodeIndex1;
    PxActor* actor0;
    PxActor* actor1;

    PxU16 nbContacts;
    PxU16 nbPatches;
};

#if PX_VC
#pragma warning(pop)
#endif

#if !PX_DOXYGEN
} // namespace physx
#endif

#endif