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