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-2023 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 PxContactPair
{
    public:
        PX_INLINE   PxContactPair() {}
    PxShape*                shapes[2];
    const PxU8* contactPatches;
    const PxU8* contactPoints;
    const PxReal*           contactImpulses;
    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 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 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