include/PxSimulationEventCallback.h

File members: include/PxSimulationEventCallback.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_SIMULATION_EVENT_CALLBACK_H
#define PX_SIMULATION_EVENT_CALLBACK_H

#include "foundation/PxVec3.h"
#include "foundation/PxTransform.h"
#include "foundation/PxMemory.h"
#include "PxPhysXConfig.h"
#include "PxFiltering.h"
#include "PxContact.h"

#if !PX_DOXYGEN
namespace physx
{
#endif

class PxShape;
class PxActor;
class PxRigidActor;
class PxRigidBody;
class PxConstraint;

struct PxContactPairExtraDataType
{
    enum Enum
    {
        ePRE_SOLVER_VELOCITY,
        ePOST_SOLVER_VELOCITY,
        eCONTACT_EVENT_POSE,
        eCONTACT_PAIR_INDEX
    };
};

struct PxContactPairExtraDataItem
{
public:
    PX_FORCE_INLINE PxContactPairExtraDataItem() {}

    PxU8 type;
};

struct PxContactPairVelocity : public PxContactPairExtraDataItem
{
public:
    PX_FORCE_INLINE PxContactPairVelocity() {}

    PxVec3 linearVelocity[2];

    PxVec3 angularVelocity[2];
};

struct PxContactPairPose : public PxContactPairExtraDataItem
{
public:
    PX_FORCE_INLINE PxContactPairPose() {}

    PxTransform globalPose[2];
};

struct PxContactPairIndex : public PxContactPairExtraDataItem
{
public:
    PX_FORCE_INLINE PxContactPairIndex() {}

    PxU16 index;
};

struct PxContactPairExtraDataIterator
{
    PX_FORCE_INLINE PxContactPairExtraDataIterator(const PxU8* stream, PxU32 size)
        : currPtr(stream), endPtr(stream + size), contactPairIndex(0)
    {
        clearDataPtrs();
    }

    PX_INLINE bool nextItemSet()
    {
        clearDataPtrs();

        bool foundEntry = false;
        bool endOfItemSet = false;
        while ((currPtr < endPtr) && (!endOfItemSet))
        {
            const PxContactPairExtraDataItem* edItem = reinterpret_cast<const PxContactPairExtraDataItem*>(currPtr);
            PxU8 type = edItem->type;

            switch(type)
            {
                case PxContactPairExtraDataType::ePRE_SOLVER_VELOCITY:
                {
                    PX_ASSERT(!preSolverVelocity);
                    preSolverVelocity = static_cast<const PxContactPairVelocity*>(edItem);
                    currPtr += sizeof(PxContactPairVelocity);
                    foundEntry = true;
                }
                break;

                case PxContactPairExtraDataType::ePOST_SOLVER_VELOCITY:
                {
                    postSolverVelocity = static_cast<const PxContactPairVelocity*>(edItem);
                    currPtr += sizeof(PxContactPairVelocity);
                    foundEntry = true;
                }
                break;

                case PxContactPairExtraDataType::eCONTACT_EVENT_POSE:
                {
                    eventPose = static_cast<const PxContactPairPose*>(edItem);
                    currPtr += sizeof(PxContactPairPose);
                    foundEntry = true;
                }
                break;

                case PxContactPairExtraDataType::eCONTACT_PAIR_INDEX:
                {
                    if (!foundEntry)
                    {
                        contactPairIndex = static_cast<const PxContactPairIndex*>(edItem)->index;
                        currPtr += sizeof(PxContactPairIndex);
                        foundEntry = true;
                    }
                    else
                        endOfItemSet = true;
                }
                break;

                default:
                    return foundEntry;
            }
        }

        return foundEntry;
    }

private:
    PX_FORCE_INLINE void clearDataPtrs()
    {
        preSolverVelocity = NULL;
        postSolverVelocity = NULL;
        eventPose = NULL;
    }

public:
    const PxU8* currPtr;

    const PxU8* endPtr;

    const PxContactPairVelocity* preSolverVelocity;

    const PxContactPairVelocity* postSolverVelocity;

    const PxContactPairPose* eventPose;

    PxU32 contactPairIndex;
};

struct PxContactPairHeaderFlag
{
    enum Enum
    {
        eREMOVED_ACTOR_0                = (1<<0),
        eREMOVED_ACTOR_1                = (1<<1)
    };
};

typedef PxFlags<PxContactPairHeaderFlag::Enum, PxU16> PxContactPairHeaderFlags;
PX_FLAGS_OPERATORS(PxContactPairHeaderFlag::Enum, PxU16)

struct PxContactPairHeader
{
    public:
        PX_INLINE   PxContactPairHeader() {}

    PxActor*                actors[2];

    const PxU8*                 extraDataStream;

    PxU16                       extraDataStreamSize;

    PxContactPairHeaderFlags    flags;

    const struct PxContactPair* pairs;

    PxU32                       nbPairs;
};

struct PxContactPairFlag
{
    enum Enum
    {
        eREMOVED_SHAPE_0                = (1<<0),

        eREMOVED_SHAPE_1                = (1<<1),

        eACTOR_PAIR_HAS_FIRST_TOUCH     = (1<<2),

        eACTOR_PAIR_LOST_TOUCH          = (1<<3),

        eINTERNAL_HAS_IMPULSES          = (1<<4),

        eINTERNAL_CONTACTS_ARE_FLIPPED  = (1<<5)
    };
};

typedef PxFlags<PxContactPairFlag::Enum, PxU16> PxContactPairFlags;
PX_FLAGS_OPERATORS(PxContactPairFlag::Enum, PxU16)

struct PxContactPairPoint
{
    PxVec3  position;

    PxReal  separation;

    PxVec3  normal;

    PxU32   internalFaceIndex0;

    PxVec3  impulse;

    PxU32   internalFaceIndex1;
};

struct PxContactPairFrictionAnchor
{
    PxVec3  position;

    PxVec3  impulse;
};

struct PxContactPair
{
    public:
        PX_INLINE   PxContactPair() {}

    PxShape*                shapes[2];

    const PxU8* contactPatches;

    const PxU8* contactPoints;

    const PxReal*           contactImpulses;

    const PxU8*             frictionPatches;

    PxU32                   requiredBufferSize;

    PxU8                    contactCount;

    PxU8                    patchCount;

    PxU16                   contactStreamSize;

    PxContactPairFlags      flags;

    PxPairFlags             events;

    PxU32                   internalData[2];    // For internal use only

    PX_INLINE PxU32         extractContacts(PxContactPairPoint* userBuffer, PxU32 bufferSize) const;

    PX_INLINE PxU32         extractFrictionAnchors(PxContactPairFrictionAnchor* userBuffer, PxU32 bufferSize) const;

    PX_INLINE void              bufferContacts(PxContactPair* newPair, PxU8* bufferMemory) const;

    PX_INLINE const PxU32*      getInternalFaceIndices() const;
};

PX_INLINE PxU32 PxContactPair::extractContacts(PxContactPairPoint* userBuffer, PxU32 bufferSize) const
{
    PxU32 nbContacts = 0;

    if(contactCount && bufferSize)
    {
        PxContactStreamIterator iter(contactPatches, contactPoints, getInternalFaceIndices(), patchCount, contactCount);

        const PxReal* impulses = contactImpulses;

        const PxU32 flippedContacts = (flags & PxContactPairFlag::eINTERNAL_CONTACTS_ARE_FLIPPED);
        const PxU32 hasImpulses = (flags & PxContactPairFlag::eINTERNAL_HAS_IMPULSES);

        while(iter.hasNextPatch())
        {
            iter.nextPatch();
            while(iter.hasNextContact())
            {
                iter.nextContact();
                PxContactPairPoint& dst = userBuffer[nbContacts];
                dst.position = iter.getContactPoint();
                dst.separation = iter.getSeparation();
                dst.normal = iter.getContactNormal();
                if(!flippedContacts)
                {
                    dst.internalFaceIndex0 = iter.getFaceIndex0();
                    dst.internalFaceIndex1 = iter.getFaceIndex1();
                }
                else
                {
                    dst.internalFaceIndex0 = iter.getFaceIndex1();
                    dst.internalFaceIndex1 = iter.getFaceIndex0();
                }

                if(hasImpulses)
                {
                    const PxReal impulse = impulses[nbContacts];
                    dst.impulse = dst.normal * impulse;
                }
                else
                    dst.impulse = PxVec3(0.0f);
                ++nbContacts;
                if(nbContacts == bufferSize)
                    return nbContacts;
            }
        }
    }

    return nbContacts;
}

PX_INLINE PxU32 PxContactPair::extractFrictionAnchors(PxContactPairFrictionAnchor* userBuffer, PxU32 bufferSize) const
{
    PxU32 nbAnchors = 0;

    if(bufferSize)
    {
        PxFrictionAnchorStreamIterator iter(contactPatches, frictionPatches, patchCount);

        while(iter.hasNextPatch())
        {
            iter.nextPatch();
            while(iter.hasNextFrictionAnchor())
            {
                iter.nextFrictionAnchor();
                PxContactPairFrictionAnchor& dst = userBuffer[nbAnchors];

                dst.position = iter.getPosition();
                dst.impulse = iter.getImpulse();

                ++nbAnchors;
                if(nbAnchors == bufferSize)
                    return nbAnchors;
            }
        }
    }

    return nbAnchors;
}

PX_INLINE void PxContactPair::bufferContacts(PxContactPair* newPair, PxU8* bufferMemory) const
{
    PxU8* patches = bufferMemory;
    PxU8* contacts = NULL;
    if(patches)
    {
        contacts = bufferMemory + patchCount * sizeof(PxContactPatch);
        PxMemCopy(patches, contactPatches, sizeof(PxContactPatch)*patchCount);
        PxMemCopy(contacts, contactPoints, contactStreamSize - (sizeof(PxContactPatch)*patchCount));
    }

    if(contactImpulses)
    {
        PxMemCopy(bufferMemory + ((contactStreamSize + 15) & (~15)), contactImpulses, sizeof(PxReal) * contactCount);
    }

    if (newPair)
    {
        *newPair = *this;
        newPair->contactPatches = patches;
        newPair->contactPoints = contacts;
    }
}

PX_INLINE const PxU32* PxContactPair::getInternalFaceIndices() const
{
    return reinterpret_cast<const PxU32*>(contactImpulses + contactCount);
}

struct PxTriggerPairFlag
{
    enum Enum
    {
        eREMOVED_SHAPE_TRIGGER                  = (1<<0),
        eREMOVED_SHAPE_OTHER                    = (1<<1),
        eNEXT_FREE                              = (1<<2)
    };
};

typedef PxFlags<PxTriggerPairFlag::Enum, PxU8> PxTriggerPairFlags;
PX_FLAGS_OPERATORS(PxTriggerPairFlag::Enum, PxU8)

struct PxTriggerPair
{
    PX_INLINE PxTriggerPair() {}

    PxShape*                triggerShape;
    PxActor*                triggerActor;
    PxShape*                otherShape;
    PxActor*                otherActor;
    PxPairFlag::Enum        status;
    PxTriggerPairFlags      flags;
};

struct PxConstraintInfo
{
    PX_INLINE PxConstraintInfo() {}
    PX_INLINE PxConstraintInfo(PxConstraint* c, void* extRef, PxU32 t) : constraint(c), externalReference(extRef), type(t) {}

    PxConstraint*   constraint;
    void*           externalReference;
    PxU32           type;
};

class PxSimulationEventCallback
    {
    public:
    virtual void onConstraintBreak(PxConstraintInfo* constraints, PxU32 count) = 0;

    virtual void onWake(PxActor** actors, PxU32 count) = 0;

    virtual void onSleep(PxActor** actors, PxU32 count) = 0;

    virtual void onContact(const PxContactPairHeader& pairHeader, const PxContactPair* pairs, PxU32 nbPairs) = 0;

    virtual void onTrigger(PxTriggerPair* pairs, PxU32 count) = 0;

    virtual void onAdvance(const PxRigidBody*const* bodyBuffer, const PxTransform* poseBuffer, const PxU32 count) = 0;

    virtual ~PxSimulationEventCallback() {}
    };

#if !PX_DOXYGEN
} // namespace physx
#endif

#endif