diff --git a/.gitignore b/.gitignore index 23af8b4..66cd22d 100644 --- a/.gitignore +++ b/.gitignore @@ -77,7 +77,6 @@ CMakeUserPresets.json *.dSYM/ *.su *.idb -*.pdb # Kernel Module Compile Results *.mod* diff --git a/TSE_Core/include/box2d.lib b/TSE_Core/include/box2d.lib new file mode 100644 index 0000000..bdb6ad6 Binary files /dev/null and b/TSE_Core/include/box2d.lib differ diff --git a/TSE_Core/include/box2d/base.h b/TSE_Core/include/box2d/base.h new file mode 100644 index 0000000..14943f1 --- /dev/null +++ b/TSE_Core/include/box2d/base.h @@ -0,0 +1,131 @@ +// SPDX-FileCopyrightText: 2023 Erin Catto +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +// clang-format off +// +// Shared library macros +#if defined( _MSC_VER ) && defined( box2d_EXPORTS ) + // build the Windows DLL + #define BOX2D_EXPORT __declspec( dllexport ) +#elif defined( _MSC_VER ) && defined( BOX2D_DLL ) + // using the Windows DLL + #define BOX2D_EXPORT __declspec( dllimport ) +#elif defined( box2d_EXPORTS ) + // building or using the shared library + #define BOX2D_EXPORT __attribute__( ( visibility( "default" ) ) ) +#else + // static library + #define BOX2D_EXPORT +#endif + +// C++ macros +#ifdef __cplusplus + #define B2_API extern "C" BOX2D_EXPORT + #define B2_INLINE inline + #define B2_LITERAL(T) T + #define B2_ZERO_INIT {} +#else + #define B2_API BOX2D_EXPORT + #define B2_INLINE static inline + /// Used for C literals like (b2Vec2){1.0f, 2.0f} where C++ requires b2Vec2{1.0f, 2.0f} + #define B2_LITERAL(T) (T) + #define B2_ZERO_INIT {0} +#endif +// clang-format on + +/** + * @defgroup base Base + * Base functionality + * @{ + */ + +/// Prototype for user allocation function +/// @param size the allocation size in bytes +/// @param alignment the required alignment, guaranteed to be a power of 2 +typedef void* b2AllocFcn( unsigned int size, int alignment ); + +/// Prototype for user free function +/// @param mem the memory previously allocated through `b2AllocFcn` +typedef void b2FreeFcn( void* mem ); + +/// Prototype for the user assert callback. Return 0 to skip the debugger break. +typedef int b2AssertFcn( const char* condition, const char* fileName, int lineNumber ); + +/// This allows the user to override the allocation functions. These should be +/// set during application startup. +B2_API void b2SetAllocator( b2AllocFcn* allocFcn, b2FreeFcn* freeFcn ); + +/// @return the total bytes allocated by Box2D +B2_API int b2GetByteCount( void ); + +/// Override the default assert callback +/// @param assertFcn a non-null assert callback +B2_API void b2SetAssertFcn( b2AssertFcn* assertFcn ); + +/// Version numbering scheme. +/// See https://semver.org/ +typedef struct b2Version +{ + /// Significant changes + int major; + + /// Incremental changes + int minor; + + /// Bug fixes + int revision; +} b2Version; + +/// Get the current version of Box2D +B2_API b2Version b2GetVersion( void ); + +/**@}*/ + +//! @cond + +// see https://github.com/scottt/debugbreak +#if defined( _MSC_VER ) +#define B2_BREAKPOINT __debugbreak() +#elif defined( __GNUC__ ) || defined( __clang__ ) +#define B2_BREAKPOINT __builtin_trap() +#else +// Unknown compiler +#include +#define B2_BREAKPOINT assert( 0 ) +#endif + +#if !defined( NDEBUG ) || defined( B2_ENABLE_ASSERT ) +B2_API int b2InternalAssertFcn( const char* condition, const char* fileName, int lineNumber ); +#define B2_ASSERT( condition ) \ + do \ + { \ + if ( !( condition ) && b2InternalAssertFcn( #condition, __FILE__, (int)__LINE__ ) ) \ + B2_BREAKPOINT; \ + } \ + while ( 0 ) +#else +#define B2_ASSERT( ... ) ( (void)0 ) +#endif + +/// Get the absolute number of system ticks. The value is platform specific. +B2_API uint64_t b2GetTicks( void ); + +/// Get the milliseconds passed from an initial tick value. +B2_API float b2GetMilliseconds( uint64_t ticks ); + +/// Get the milliseconds passed from an initial tick value. Resets the passed in +/// value to the current tick value. +B2_API float b2GetMillisecondsAndReset( uint64_t* ticks ); + +/// Yield to be used in a busy loop. +B2_API void b2Yield( void ); + +/// Simple djb2 hash function for determinism testing +#define B2_HASH_INIT 5381 +B2_API uint32_t b2Hash( uint32_t hash, const uint8_t* data, int count ); + +//! @endcond diff --git a/TSE_Core/include/box2d/box2d.h b/TSE_Core/include/box2d/box2d.h new file mode 100644 index 0000000..ac2b765 --- /dev/null +++ b/TSE_Core/include/box2d/box2d.h @@ -0,0 +1,1261 @@ +// SPDX-FileCopyrightText: 2023 Erin Catto +// SPDX-License-Identifier: MIT + +#pragma once + +#include "base.h" +#include "collision.h" +#include "id.h" +#include "types.h" + +#include + +/** + * @defgroup world World + * These functions allow you to create a simulation world. + * + * You can add rigid bodies and joint constraints to the world and run the simulation. You can get contact + * information to get contact points and normals as well as events. You can query to world, checking for overlaps and casting rays + * or shapes. There is also debugging information such as debug draw, timing information, and counters. You can find documentation + * here: https://box2d.org/ + * @{ + */ + +/// Create a world for rigid body simulation. A world contains bodies, shapes, and constraints. You make create +/// up to 128 worlds. Each world is completely independent and may be simulated in parallel. +/// @return the world id. +B2_API b2WorldId b2CreateWorld( const b2WorldDef* def ); + +/// Destroy a world +B2_API void b2DestroyWorld( b2WorldId worldId ); + +/// World id validation. Provides validation for up to 64K allocations. +B2_API bool b2World_IsValid( b2WorldId id ); + +/// Simulate a world for one time step. This performs collision detection, integration, and constraint solution. +/// @param worldId The world to simulate +/// @param timeStep The amount of time to simulate, this should be a fixed number. Usually 1/60. +/// @param subStepCount The number of sub-steps, increasing the sub-step count can increase accuracy. Usually 4. +B2_API void b2World_Step( b2WorldId worldId, float timeStep, int subStepCount ); + +/// Call this to draw shapes and other debug draw data +B2_API void b2World_Draw( b2WorldId worldId, b2DebugDraw* draw ); + +/// Get the body events for the current time step. The event data is transient. Do not store a reference to this data. +B2_API b2BodyEvents b2World_GetBodyEvents( b2WorldId worldId ); + +/// Get sensor events for the current time step. The event data is transient. Do not store a reference to this data. +B2_API b2SensorEvents b2World_GetSensorEvents( b2WorldId worldId ); + +/// Get contact events for this current time step. The event data is transient. Do not store a reference to this data. +B2_API b2ContactEvents b2World_GetContactEvents( b2WorldId worldId ); + +/// Overlap test for all shapes that *potentially* overlap the provided AABB +B2_API b2TreeStats b2World_OverlapAABB( b2WorldId worldId, b2AABB aabb, b2QueryFilter filter, b2OverlapResultFcn* fcn, + void* context ); + +/// Overlap test for all shapes that overlap the provided shape proxy. +B2_API b2TreeStats b2World_OverlapShape( b2WorldId worldId, const b2ShapeProxy* proxy, b2QueryFilter filter, + b2OverlapResultFcn* fcn, void* context ); + +/// Cast a ray into the world to collect shapes in the path of the ray. +/// Your callback function controls whether you get the closest point, any point, or n-points. +/// @note The callback function may receive shapes in any order +/// @param worldId The world to cast the ray against +/// @param origin The start point of the ray +/// @param translation The translation of the ray from the start point to the end point +/// @param filter Contains bit flags to filter unwanted shapes from the results +/// @param fcn A user implemented callback function +/// @param context A user context that is passed along to the callback function +/// @return traversal performance counters +B2_API b2TreeStats b2World_CastRay( b2WorldId worldId, b2Vec2 origin, b2Vec2 translation, b2QueryFilter filter, + b2CastResultFcn* fcn, void* context ); + +/// Cast a ray into the world to collect the closest hit. This is a convenience function. Ignores initial overlap. +/// This is less general than b2World_CastRay() and does not allow for custom filtering. +B2_API b2RayResult b2World_CastRayClosest( b2WorldId worldId, b2Vec2 origin, b2Vec2 translation, b2QueryFilter filter ); + +/// Cast a shape through the world. Similar to a cast ray except that a shape is cast instead of a point. +/// @see b2World_CastRay +B2_API b2TreeStats b2World_CastShape( b2WorldId worldId, const b2ShapeProxy* proxy, b2Vec2 translation, b2QueryFilter filter, + b2CastResultFcn* fcn, void* context ); + +/// Cast a capsule mover through the world. This is a special shape cast that handles sliding along other shapes while reducing +/// clipping. +B2_API float b2World_CastMover( b2WorldId worldId, const b2Capsule* mover, b2Vec2 translation, b2QueryFilter filter ); + +/// Collide a capsule mover with the world, gathering collision planes that can be fed to b2SolvePlanes. Useful for +/// kinematic character movement. +B2_API void b2World_CollideMover( b2WorldId worldId, const b2Capsule* mover, b2QueryFilter filter, b2PlaneResultFcn* fcn, + void* context ); + +/// Enable/disable sleep. If your application does not need sleeping, you can gain some performance +/// by disabling sleep completely at the world level. +/// @see b2WorldDef +B2_API void b2World_EnableSleeping( b2WorldId worldId, bool flag ); + +/// Is body sleeping enabled? +B2_API bool b2World_IsSleepingEnabled( b2WorldId worldId ); + +/// Enable/disable continuous collision between dynamic and static bodies. Generally you should keep continuous +/// collision enabled to prevent fast moving objects from going through static objects. The performance gain from +/// disabling continuous collision is minor. +/// @see b2WorldDef +B2_API void b2World_EnableContinuous( b2WorldId worldId, bool flag ); + +/// Is continuous collision enabled? +B2_API bool b2World_IsContinuousEnabled( b2WorldId worldId ); + +/// Adjust the restitution threshold. It is recommended not to make this value very small +/// because it will prevent bodies from sleeping. Usually in meters per second. +/// @see b2WorldDef +B2_API void b2World_SetRestitutionThreshold( b2WorldId worldId, float value ); + +/// Get the the restitution speed threshold. Usually in meters per second. +B2_API float b2World_GetRestitutionThreshold( b2WorldId worldId ); + +/// Adjust the hit event threshold. This controls the collision speed needed to generate a b2ContactHitEvent. +/// Usually in meters per second. +/// @see b2WorldDef::hitEventThreshold +B2_API void b2World_SetHitEventThreshold( b2WorldId worldId, float value ); + +/// Get the the hit event speed threshold. Usually in meters per second. +B2_API float b2World_GetHitEventThreshold( b2WorldId worldId ); + +/// Register the custom filter callback. This is optional. +B2_API void b2World_SetCustomFilterCallback( b2WorldId worldId, b2CustomFilterFcn* fcn, void* context ); + +/// Register the pre-solve callback. This is optional. +B2_API void b2World_SetPreSolveCallback( b2WorldId worldId, b2PreSolveFcn* fcn, void* context ); + +/// Set the gravity vector for the entire world. Box2D has no concept of an up direction and this +/// is left as a decision for the application. Usually in m/s^2. +/// @see b2WorldDef +B2_API void b2World_SetGravity( b2WorldId worldId, b2Vec2 gravity ); + +/// Get the gravity vector +B2_API b2Vec2 b2World_GetGravity( b2WorldId worldId ); + +/// Apply a radial explosion +/// @param worldId The world id +/// @param explosionDef The explosion definition +B2_API void b2World_Explode( b2WorldId worldId, const b2ExplosionDef* explosionDef ); + +/// Adjust contact tuning parameters +/// @param worldId The world id +/// @param hertz The contact stiffness (cycles per second) +/// @param dampingRatio The contact bounciness with 1 being critical damping (non-dimensional) +/// @param pushSpeed The maximum contact constraint push out speed (meters per second) +/// @note Advanced feature +B2_API void b2World_SetContactTuning( b2WorldId worldId, float hertz, float dampingRatio, float pushSpeed ); + +/// Set the maximum linear speed. Usually in m/s. +B2_API void b2World_SetMaximumLinearSpeed( b2WorldId worldId, float maximumLinearSpeed ); + +/// Get the maximum linear speed. Usually in m/s. +B2_API float b2World_GetMaximumLinearSpeed( b2WorldId worldId ); + +/// Enable/disable constraint warm starting. Advanced feature for testing. Disabling +/// warm starting greatly reduces stability and provides no performance gain. +B2_API void b2World_EnableWarmStarting( b2WorldId worldId, bool flag ); + +/// Is constraint warm starting enabled? +B2_API bool b2World_IsWarmStartingEnabled( b2WorldId worldId ); + +/// Get the number of awake bodies. +B2_API int b2World_GetAwakeBodyCount( b2WorldId worldId ); + +/// Get the current world performance profile +B2_API b2Profile b2World_GetProfile( b2WorldId worldId ); + +/// Get world counters and sizes +B2_API b2Counters b2World_GetCounters( b2WorldId worldId ); + +/// Set the user data pointer. +B2_API void b2World_SetUserData( b2WorldId worldId, void* userData ); + +/// Get the user data pointer. +B2_API void* b2World_GetUserData( b2WorldId worldId ); + +/// Set the friction callback. Passing NULL resets to default. +B2_API void b2World_SetFrictionCallback( b2WorldId worldId, b2FrictionCallback* callback ); + +/// Set the restitution callback. Passing NULL resets to default. +B2_API void b2World_SetRestitutionCallback( b2WorldId worldId, b2RestitutionCallback* callback ); + +/// Dump memory stats to box2d_memory.txt +B2_API void b2World_DumpMemoryStats( b2WorldId worldId ); + +/// This is for internal testing +B2_API void b2World_RebuildStaticTree( b2WorldId worldId ); + +/// This is for internal testing +B2_API void b2World_EnableSpeculative( b2WorldId worldId, bool flag ); + +/** @} */ + +/** + * @defgroup body Body + * This is the body API. + * @{ + */ + +/// Create a rigid body given a definition. No reference to the definition is retained. So you can create the definition +/// on the stack and pass it as a pointer. +/// @code{.c} +/// b2BodyDef bodyDef = b2DefaultBodyDef(); +/// b2BodyId myBodyId = b2CreateBody(myWorldId, &bodyDef); +/// @endcode +/// @warning This function is locked during callbacks. +B2_API b2BodyId b2CreateBody( b2WorldId worldId, const b2BodyDef* def ); + +/// Destroy a rigid body given an id. This destroys all shapes and joints attached to the body. +/// Do not keep references to the associated shapes and joints. +B2_API void b2DestroyBody( b2BodyId bodyId ); + +/// Body identifier validation. Can be used to detect orphaned ids. Provides validation for up to 64K allocations. +B2_API bool b2Body_IsValid( b2BodyId id ); + +/// Get the body type: static, kinematic, or dynamic +B2_API b2BodyType b2Body_GetType( b2BodyId bodyId ); + +/// Change the body type. This is an expensive operation. This automatically updates the mass +/// properties regardless of the automatic mass setting. +B2_API void b2Body_SetType( b2BodyId bodyId, b2BodyType type ); + +/// Set the body name. Up to 31 characters excluding 0 termination. +B2_API void b2Body_SetName( b2BodyId bodyId, const char* name ); + +/// Get the body name. May be null. +B2_API const char* b2Body_GetName( b2BodyId bodyId ); + +/// Set the user data for a body +B2_API void b2Body_SetUserData( b2BodyId bodyId, void* userData ); + +/// Get the user data stored in a body +B2_API void* b2Body_GetUserData( b2BodyId bodyId ); + +/// Get the world position of a body. This is the location of the body origin. +B2_API b2Vec2 b2Body_GetPosition( b2BodyId bodyId ); + +/// Get the world rotation of a body as a cosine/sine pair (complex number) +B2_API b2Rot b2Body_GetRotation( b2BodyId bodyId ); + +/// Get the world transform of a body. +B2_API b2Transform b2Body_GetTransform( b2BodyId bodyId ); + +/// Set the world transform of a body. This acts as a teleport and is fairly expensive. +/// @note Generally you should create a body with then intended transform. +/// @see b2BodyDef::position and b2BodyDef::angle +B2_API void b2Body_SetTransform( b2BodyId bodyId, b2Vec2 position, b2Rot rotation ); + +/// Get a local point on a body given a world point +B2_API b2Vec2 b2Body_GetLocalPoint( b2BodyId bodyId, b2Vec2 worldPoint ); + +/// Get a world point on a body given a local point +B2_API b2Vec2 b2Body_GetWorldPoint( b2BodyId bodyId, b2Vec2 localPoint ); + +/// Get a local vector on a body given a world vector +B2_API b2Vec2 b2Body_GetLocalVector( b2BodyId bodyId, b2Vec2 worldVector ); + +/// Get a world vector on a body given a local vector +B2_API b2Vec2 b2Body_GetWorldVector( b2BodyId bodyId, b2Vec2 localVector ); + +/// Get the linear velocity of a body's center of mass. Usually in meters per second. +B2_API b2Vec2 b2Body_GetLinearVelocity( b2BodyId bodyId ); + +/// Get the angular velocity of a body in radians per second +B2_API float b2Body_GetAngularVelocity( b2BodyId bodyId ); + +/// Set the linear velocity of a body. Usually in meters per second. +B2_API void b2Body_SetLinearVelocity( b2BodyId bodyId, b2Vec2 linearVelocity ); + +/// Set the angular velocity of a body in radians per second +B2_API void b2Body_SetAngularVelocity( b2BodyId bodyId, float angularVelocity ); + +/// Set the velocity to reach the given transform after a given time step. +/// The result will be close but maybe not exact. This is meant for kinematic bodies. +/// The target is not applied if the velocity would be below the sleep threshold. +/// This will automatically wake the body if asleep. +B2_API void b2Body_SetTargetTransform( b2BodyId bodyId, b2Transform target, float timeStep ); + +/// Get the linear velocity of a local point attached to a body. Usually in meters per second. +B2_API b2Vec2 b2Body_GetLocalPointVelocity( b2BodyId bodyId, b2Vec2 localPoint ); + +/// Get the linear velocity of a world point attached to a body. Usually in meters per second. +B2_API b2Vec2 b2Body_GetWorldPointVelocity( b2BodyId bodyId, b2Vec2 worldPoint ); + +/// Apply a force at a world point. If the force is not applied at the center of mass, +/// it will generate a torque and affect the angular velocity. This optionally wakes up the body. +/// The force is ignored if the body is not awake. +/// @param bodyId The body id +/// @param force The world force vector, usually in newtons (N) +/// @param point The world position of the point of application +/// @param wake Option to wake up the body +B2_API void b2Body_ApplyForce( b2BodyId bodyId, b2Vec2 force, b2Vec2 point, bool wake ); + +/// Apply a force to the center of mass. This optionally wakes up the body. +/// The force is ignored if the body is not awake. +/// @param bodyId The body id +/// @param force the world force vector, usually in newtons (N). +/// @param wake also wake up the body +B2_API void b2Body_ApplyForceToCenter( b2BodyId bodyId, b2Vec2 force, bool wake ); + +/// Apply a torque. This affects the angular velocity without affecting the linear velocity. +/// This optionally wakes the body. The torque is ignored if the body is not awake. +/// @param bodyId The body id +/// @param torque about the z-axis (out of the screen), usually in N*m. +/// @param wake also wake up the body +B2_API void b2Body_ApplyTorque( b2BodyId bodyId, float torque, bool wake ); + +/// Apply an impulse at a point. This immediately modifies the velocity. +/// It also modifies the angular velocity if the point of application +/// is not at the center of mass. This optionally wakes the body. +/// The impulse is ignored if the body is not awake. +/// @param bodyId The body id +/// @param impulse the world impulse vector, usually in N*s or kg*m/s. +/// @param point the world position of the point of application. +/// @param wake also wake up the body +/// @warning This should be used for one-shot impulses. If you need a steady force, +/// use a force instead, which will work better with the sub-stepping solver. +B2_API void b2Body_ApplyLinearImpulse( b2BodyId bodyId, b2Vec2 impulse, b2Vec2 point, bool wake ); + +/// Apply an impulse to the center of mass. This immediately modifies the velocity. +/// The impulse is ignored if the body is not awake. This optionally wakes the body. +/// @param bodyId The body id +/// @param impulse the world impulse vector, usually in N*s or kg*m/s. +/// @param wake also wake up the body +/// @warning This should be used for one-shot impulses. If you need a steady force, +/// use a force instead, which will work better with the sub-stepping solver. +B2_API void b2Body_ApplyLinearImpulseToCenter( b2BodyId bodyId, b2Vec2 impulse, bool wake ); + +/// Apply an angular impulse. The impulse is ignored if the body is not awake. +/// This optionally wakes the body. +/// @param bodyId The body id +/// @param impulse the angular impulse, usually in units of kg*m*m/s +/// @param wake also wake up the body +/// @warning This should be used for one-shot impulses. If you need a steady force, +/// use a force instead, which will work better with the sub-stepping solver. +B2_API void b2Body_ApplyAngularImpulse( b2BodyId bodyId, float impulse, bool wake ); + +/// Get the mass of the body, usually in kilograms +B2_API float b2Body_GetMass( b2BodyId bodyId ); + +/// Get the rotational inertia of the body, usually in kg*m^2 +B2_API float b2Body_GetRotationalInertia( b2BodyId bodyId ); + +/// Get the center of mass position of the body in local space +B2_API b2Vec2 b2Body_GetLocalCenterOfMass( b2BodyId bodyId ); + +/// Get the center of mass position of the body in world space +B2_API b2Vec2 b2Body_GetWorldCenterOfMass( b2BodyId bodyId ); + +/// Override the body's mass properties. Normally this is computed automatically using the +/// shape geometry and density. This information is lost if a shape is added or removed or if the +/// body type changes. +B2_API void b2Body_SetMassData( b2BodyId bodyId, b2MassData massData ); + +/// Get the mass data for a body +B2_API b2MassData b2Body_GetMassData( b2BodyId bodyId ); + +/// This update the mass properties to the sum of the mass properties of the shapes. +/// This normally does not need to be called unless you called SetMassData to override +/// the mass and you later want to reset the mass. +/// You may also use this when automatic mass computation has been disabled. +/// You should call this regardless of body type. +/// Note that sensor shapes may have mass. +B2_API void b2Body_ApplyMassFromShapes( b2BodyId bodyId ); + +/// Adjust the linear damping. Normally this is set in b2BodyDef before creation. +B2_API void b2Body_SetLinearDamping( b2BodyId bodyId, float linearDamping ); + +/// Get the current linear damping. +B2_API float b2Body_GetLinearDamping( b2BodyId bodyId ); + +/// Adjust the angular damping. Normally this is set in b2BodyDef before creation. +B2_API void b2Body_SetAngularDamping( b2BodyId bodyId, float angularDamping ); + +/// Get the current angular damping. +B2_API float b2Body_GetAngularDamping( b2BodyId bodyId ); + +/// Adjust the gravity scale. Normally this is set in b2BodyDef before creation. +/// @see b2BodyDef::gravityScale +B2_API void b2Body_SetGravityScale( b2BodyId bodyId, float gravityScale ); + +/// Get the current gravity scale +B2_API float b2Body_GetGravityScale( b2BodyId bodyId ); + +/// @return true if this body is awake +B2_API bool b2Body_IsAwake( b2BodyId bodyId ); + +/// Wake a body from sleep. This wakes the entire island the body is touching. +/// @warning Putting a body to sleep will put the entire island of bodies touching this body to sleep, +/// which can be expensive and possibly unintuitive. +B2_API void b2Body_SetAwake( b2BodyId bodyId, bool awake ); + +/// Enable or disable sleeping for this body. If sleeping is disabled the body will wake. +B2_API void b2Body_EnableSleep( b2BodyId bodyId, bool enableSleep ); + +/// Returns true if sleeping is enabled for this body +B2_API bool b2Body_IsSleepEnabled( b2BodyId bodyId ); + +/// Set the sleep threshold, usually in meters per second +B2_API void b2Body_SetSleepThreshold( b2BodyId bodyId, float sleepThreshold ); + +/// Get the sleep threshold, usually in meters per second. +B2_API float b2Body_GetSleepThreshold( b2BodyId bodyId ); + +/// Returns true if this body is enabled +B2_API bool b2Body_IsEnabled( b2BodyId bodyId ); + +/// Disable a body by removing it completely from the simulation. This is expensive. +B2_API void b2Body_Disable( b2BodyId bodyId ); + +/// Enable a body by adding it to the simulation. This is expensive. +B2_API void b2Body_Enable( b2BodyId bodyId ); + +/// Set this body to have fixed rotation. This causes the mass to be reset in all cases. +B2_API void b2Body_SetFixedRotation( b2BodyId bodyId, bool flag ); + +/// Does this body have fixed rotation? +B2_API bool b2Body_IsFixedRotation( b2BodyId bodyId ); + +/// Set this body to be a bullet. A bullet does continuous collision detection +/// against dynamic bodies (but not other bullets). +B2_API void b2Body_SetBullet( b2BodyId bodyId, bool flag ); + +/// Is this body a bullet? +B2_API bool b2Body_IsBullet( b2BodyId bodyId ); + +/// Enable/disable contact events on all shapes. +/// @see b2ShapeDef::enableContactEvents +/// @warning changing this at runtime may cause mismatched begin/end touch events +B2_API void b2Body_EnableContactEvents( b2BodyId bodyId, bool flag ); + +/// Enable/disable hit events on all shapes +/// @see b2ShapeDef::enableHitEvents +B2_API void b2Body_EnableHitEvents( b2BodyId bodyId, bool flag ); + +/// Get the world that owns this body +B2_API b2WorldId b2Body_GetWorld( b2BodyId bodyId ); + +/// Get the number of shapes on this body +B2_API int b2Body_GetShapeCount( b2BodyId bodyId ); + +/// Get the shape ids for all shapes on this body, up to the provided capacity. +/// @returns the number of shape ids stored in the user array +B2_API int b2Body_GetShapes( b2BodyId bodyId, b2ShapeId* shapeArray, int capacity ); + +/// Get the number of joints on this body +B2_API int b2Body_GetJointCount( b2BodyId bodyId ); + +/// Get the joint ids for all joints on this body, up to the provided capacity +/// @returns the number of joint ids stored in the user array +B2_API int b2Body_GetJoints( b2BodyId bodyId, b2JointId* jointArray, int capacity ); + +/// Get the maximum capacity required for retrieving all the touching contacts on a body +B2_API int b2Body_GetContactCapacity( b2BodyId bodyId ); + +/// Get the touching contact data for a body. +/// @note Box2D uses speculative collision so some contact points may be separated. +/// @returns the number of elements filled in the provided array +/// @warning do not ignore the return value, it specifies the valid number of elements +B2_API int b2Body_GetContactData( b2BodyId bodyId, b2ContactData* contactData, int capacity ); + +/// Get the current world AABB that contains all the attached shapes. Note that this may not encompass the body origin. +/// If there are no shapes attached then the returned AABB is empty and centered on the body origin. +B2_API b2AABB b2Body_ComputeAABB( b2BodyId bodyId ); + +/** @} */ + +/** + * @defgroup shape Shape + * Functions to create, destroy, and access. + * Shapes bind raw geometry to bodies and hold material properties including friction and restitution. + * @{ + */ + +/// Create a circle shape and attach it to a body. The shape definition and geometry are fully cloned. +/// Contacts are not created until the next time step. +/// @return the shape id for accessing the shape +B2_API b2ShapeId b2CreateCircleShape( b2BodyId bodyId, const b2ShapeDef* def, const b2Circle* circle ); + +/// Create a line segment shape and attach it to a body. The shape definition and geometry are fully cloned. +/// Contacts are not created until the next time step. +/// @return the shape id for accessing the shape +B2_API b2ShapeId b2CreateSegmentShape( b2BodyId bodyId, const b2ShapeDef* def, const b2Segment* segment ); + +/// Create a capsule shape and attach it to a body. The shape definition and geometry are fully cloned. +/// Contacts are not created until the next time step. +/// @return the shape id for accessing the shape +B2_API b2ShapeId b2CreateCapsuleShape( b2BodyId bodyId, const b2ShapeDef* def, const b2Capsule* capsule ); + +/// Create a polygon shape and attach it to a body. The shape definition and geometry are fully cloned. +/// Contacts are not created until the next time step. +/// @return the shape id for accessing the shape +B2_API b2ShapeId b2CreatePolygonShape( b2BodyId bodyId, const b2ShapeDef* def, const b2Polygon* polygon ); + +/// Destroy a shape. You may defer the body mass update which can improve performance if several shapes on a +/// body are destroyed at once. +/// @see b2Body_ApplyMassFromShapes +B2_API void b2DestroyShape( b2ShapeId shapeId, bool updateBodyMass ); + +/// Shape identifier validation. Provides validation for up to 64K allocations. +B2_API bool b2Shape_IsValid( b2ShapeId id ); + +/// Get the type of a shape +B2_API b2ShapeType b2Shape_GetType( b2ShapeId shapeId ); + +/// Get the id of the body that a shape is attached to +B2_API b2BodyId b2Shape_GetBody( b2ShapeId shapeId ); + +/// Get the world that owns this shape +B2_API b2WorldId b2Shape_GetWorld( b2ShapeId shapeId ); + +/// Returns true if the shape is a sensor. It is not possible to change a shape +/// from sensor to solid dynamically because this breaks the contract for +/// sensor events. +B2_API bool b2Shape_IsSensor( b2ShapeId shapeId ); + +/// Set the user data for a shape +B2_API void b2Shape_SetUserData( b2ShapeId shapeId, void* userData ); + +/// Get the user data for a shape. This is useful when you get a shape id +/// from an event or query. +B2_API void* b2Shape_GetUserData( b2ShapeId shapeId ); + +/// Set the mass density of a shape, usually in kg/m^2. +/// This will optionally update the mass properties on the parent body. +/// @see b2ShapeDef::density, b2Body_ApplyMassFromShapes +B2_API void b2Shape_SetDensity( b2ShapeId shapeId, float density, bool updateBodyMass ); + +/// Get the density of a shape, usually in kg/m^2 +B2_API float b2Shape_GetDensity( b2ShapeId shapeId ); + +/// Set the friction on a shape +/// @see b2ShapeDef::friction +B2_API void b2Shape_SetFriction( b2ShapeId shapeId, float friction ); + +/// Get the friction of a shape +B2_API float b2Shape_GetFriction( b2ShapeId shapeId ); + +/// Set the shape restitution (bounciness) +/// @see b2ShapeDef::restitution +B2_API void b2Shape_SetRestitution( b2ShapeId shapeId, float restitution ); + +/// Get the shape restitution +B2_API float b2Shape_GetRestitution( b2ShapeId shapeId ); + +/// Set the shape material identifier +/// @see b2ShapeDef::material +B2_API void b2Shape_SetMaterial( b2ShapeId shapeId, int material ); + +/// Get the shape material identifier +B2_API int b2Shape_GetMaterial( b2ShapeId shapeId ); + +/// Set the shape surface material +B2_API void b2Shape_SetSurfaceMaterial( b2ShapeId shapeId, b2SurfaceMaterial surfaceMaterial ); + +/// Get the shape surface material +B2_API b2SurfaceMaterial b2Shape_GetSurfaceMaterial( b2ShapeId shapeId ); + +/// Get the shape filter +B2_API b2Filter b2Shape_GetFilter( b2ShapeId shapeId ); + +/// Set the current filter. This is almost as expensive as recreating the shape. This may cause +/// contacts to be immediately destroyed. However contacts are not created until the next world step. +/// Sensor overlap state is also not updated until the next world step. +/// @see b2ShapeDef::filter +B2_API void b2Shape_SetFilter( b2ShapeId shapeId, b2Filter filter ); + +/// Enable sensor events for this shape. +/// @see b2ShapeDef::enableSensorEvents +B2_API void b2Shape_EnableSensorEvents( b2ShapeId shapeId, bool flag ); + +/// Returns true if sensor events are enabled. +B2_API bool b2Shape_AreSensorEventsEnabled( b2ShapeId shapeId ); + +/// Enable contact events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors. +/// @see b2ShapeDef::enableContactEvents +/// @warning changing this at run-time may lead to lost begin/end events +B2_API void b2Shape_EnableContactEvents( b2ShapeId shapeId, bool flag ); + +/// Returns true if contact events are enabled +B2_API bool b2Shape_AreContactEventsEnabled( b2ShapeId shapeId ); + +/// Enable pre-solve contact events for this shape. Only applies to dynamic bodies. These are expensive +/// and must be carefully handled due to multithreading. Ignored for sensors. +/// @see b2PreSolveFcn +B2_API void b2Shape_EnablePreSolveEvents( b2ShapeId shapeId, bool flag ); + +/// Returns true if pre-solve events are enabled +B2_API bool b2Shape_ArePreSolveEventsEnabled( b2ShapeId shapeId ); + +/// Enable contact hit events for this shape. Ignored for sensors. +/// @see b2WorldDef.hitEventThreshold +B2_API void b2Shape_EnableHitEvents( b2ShapeId shapeId, bool flag ); + +/// Returns true if hit events are enabled +B2_API bool b2Shape_AreHitEventsEnabled( b2ShapeId shapeId ); + +/// Test a point for overlap with a shape +B2_API bool b2Shape_TestPoint( b2ShapeId shapeId, b2Vec2 point ); + +/// Ray cast a shape directly +B2_API b2CastOutput b2Shape_RayCast( b2ShapeId shapeId, const b2RayCastInput* input ); + +/// Get a copy of the shape's circle. Asserts the type is correct. +B2_API b2Circle b2Shape_GetCircle( b2ShapeId shapeId ); + +/// Get a copy of the shape's line segment. Asserts the type is correct. +B2_API b2Segment b2Shape_GetSegment( b2ShapeId shapeId ); + +/// Get a copy of the shape's chain segment. These come from chain shapes. +/// Asserts the type is correct. +B2_API b2ChainSegment b2Shape_GetChainSegment( b2ShapeId shapeId ); + +/// Get a copy of the shape's capsule. Asserts the type is correct. +B2_API b2Capsule b2Shape_GetCapsule( b2ShapeId shapeId ); + +/// Get a copy of the shape's convex polygon. Asserts the type is correct. +B2_API b2Polygon b2Shape_GetPolygon( b2ShapeId shapeId ); + +/// Allows you to change a shape to be a circle or update the current circle. +/// This does not modify the mass properties. +/// @see b2Body_ApplyMassFromShapes +B2_API void b2Shape_SetCircle( b2ShapeId shapeId, const b2Circle* circle ); + +/// Allows you to change a shape to be a capsule or update the current capsule. +/// This does not modify the mass properties. +/// @see b2Body_ApplyMassFromShapes +B2_API void b2Shape_SetCapsule( b2ShapeId shapeId, const b2Capsule* capsule ); + +/// Allows you to change a shape to be a segment or update the current segment. +B2_API void b2Shape_SetSegment( b2ShapeId shapeId, const b2Segment* segment ); + +/// Allows you to change a shape to be a polygon or update the current polygon. +/// This does not modify the mass properties. +/// @see b2Body_ApplyMassFromShapes +B2_API void b2Shape_SetPolygon( b2ShapeId shapeId, const b2Polygon* polygon ); + +/// Get the parent chain id if the shape type is a chain segment, otherwise +/// returns b2_nullChainId. +B2_API b2ChainId b2Shape_GetParentChain( b2ShapeId shapeId ); + +/// Get the maximum capacity required for retrieving all the touching contacts on a shape +B2_API int b2Shape_GetContactCapacity( b2ShapeId shapeId ); + +/// Get the touching contact data for a shape. The provided shapeId will be either shapeIdA or shapeIdB on the contact data. +/// @note Box2D uses speculative collision so some contact points may be separated. +/// @returns the number of elements filled in the provided array +/// @warning do not ignore the return value, it specifies the valid number of elements +B2_API int b2Shape_GetContactData( b2ShapeId shapeId, b2ContactData* contactData, int capacity ); + +/// Get the maximum capacity required for retrieving all the overlapped shapes on a sensor shape. +/// This returns 0 if the provided shape is not a sensor. +/// @param shapeId the id of a sensor shape +/// @returns the required capacity to get all the overlaps in b2Shape_GetSensorOverlaps +B2_API int b2Shape_GetSensorCapacity( b2ShapeId shapeId ); + +/// Get the overlapped shapes for a sensor shape. +/// @param shapeId the id of a sensor shape +/// @param overlaps a user allocated array that is filled with the overlapping shapes +/// @param capacity the capacity of overlappedShapes +/// @returns the number of elements filled in the provided array +/// @warning do not ignore the return value, it specifies the valid number of elements +/// @warning overlaps may contain destroyed shapes so use b2Shape_IsValid to confirm each overlap +B2_API int b2Shape_GetSensorOverlaps( b2ShapeId shapeId, b2ShapeId* overlaps, int capacity ); + +/// Get the current world AABB +B2_API b2AABB b2Shape_GetAABB( b2ShapeId shapeId ); + +/// Get the mass data for a shape +B2_API b2MassData b2Shape_GetMassData( b2ShapeId shapeId ); + +/// Get the closest point on a shape to a target point. Target and result are in world space. +/// todo need sample +B2_API b2Vec2 b2Shape_GetClosestPoint( b2ShapeId shapeId, b2Vec2 target ); + +/// Chain Shape + +/// Create a chain shape +/// @see b2ChainDef for details +B2_API b2ChainId b2CreateChain( b2BodyId bodyId, const b2ChainDef* def ); + +/// Destroy a chain shape +B2_API void b2DestroyChain( b2ChainId chainId ); + +/// Get the world that owns this chain shape +B2_API b2WorldId b2Chain_GetWorld( b2ChainId chainId ); + +/// Get the number of segments on this chain +B2_API int b2Chain_GetSegmentCount( b2ChainId chainId ); + +/// Fill a user array with chain segment shape ids up to the specified capacity. Returns +/// the actual number of segments returned. +B2_API int b2Chain_GetSegments( b2ChainId chainId, b2ShapeId* segmentArray, int capacity ); + +/// Set the chain friction +/// @see b2ChainDef::friction +B2_API void b2Chain_SetFriction( b2ChainId chainId, float friction ); + +/// Get the chain friction +B2_API float b2Chain_GetFriction( b2ChainId chainId ); + +/// Set the chain restitution (bounciness) +/// @see b2ChainDef::restitution +B2_API void b2Chain_SetRestitution( b2ChainId chainId, float restitution ); + +/// Get the chain restitution +B2_API float b2Chain_GetRestitution( b2ChainId chainId ); + +/// Set the chain material +/// @see b2ChainDef::material +B2_API void b2Chain_SetMaterial( b2ChainId chainId, int material ); + +/// Get the chain material +B2_API int b2Chain_GetMaterial( b2ChainId chainId ); + +/// Chain identifier validation. Provides validation for up to 64K allocations. +B2_API bool b2Chain_IsValid( b2ChainId id ); + +/** @} */ + +/** + * @defgroup joint Joint + * @brief Joints allow you to connect rigid bodies together while allowing various forms of relative motions. + * @{ + */ + +/// Destroy a joint +B2_API void b2DestroyJoint( b2JointId jointId ); + +/// Joint identifier validation. Provides validation for up to 64K allocations. +B2_API bool b2Joint_IsValid( b2JointId id ); + +/// Get the joint type +B2_API b2JointType b2Joint_GetType( b2JointId jointId ); + +/// Get body A id on a joint +B2_API b2BodyId b2Joint_GetBodyA( b2JointId jointId ); + +/// Get body B id on a joint +B2_API b2BodyId b2Joint_GetBodyB( b2JointId jointId ); + +/// Get the world that owns this joint +B2_API b2WorldId b2Joint_GetWorld( b2JointId jointId ); + +/// Set the local anchor on bodyA +B2_API void b2Joint_SetLocalAnchorA( b2JointId jointId, b2Vec2 localAnchor ); + +/// Get the local anchor on bodyA +B2_API b2Vec2 b2Joint_GetLocalAnchorA( b2JointId jointId ); + +/// Set the local anchor on bodyB +B2_API void b2Joint_SetLocalAnchorB( b2JointId jointId, b2Vec2 localAnchor ); + +/// Get the local anchor on bodyB +B2_API b2Vec2 b2Joint_GetLocalAnchorB( b2JointId jointId ); + +/// Get the joint reference angle in radians (revolute, prismatic, and weld) +B2_API float b2Joint_GetReferenceAngle( b2JointId jointId ); + +/// Set the joint reference angle in radians, must be in [-pi,pi]. (revolute, prismatic, and weld) +B2_API void b2Joint_SetReferenceAngle( b2JointId jointId, float angleInRadians ); + +/// Set the local axis on bodyA (prismatic and wheel) +B2_API void b2Joint_SetLocalAxisA( b2JointId jointId, b2Vec2 localAxis ); + +/// Get the local axis on bodyA (prismatic and wheel) +B2_API b2Vec2 b2Joint_GetLocalAxisA( b2JointId jointId ); + +/// Toggle collision between connected bodies +B2_API void b2Joint_SetCollideConnected( b2JointId jointId, bool shouldCollide ); + +/// Is collision allowed between connected bodies? +B2_API bool b2Joint_GetCollideConnected( b2JointId jointId ); + +/// Set the user data on a joint +B2_API void b2Joint_SetUserData( b2JointId jointId, void* userData ); + +/// Get the user data on a joint +B2_API void* b2Joint_GetUserData( b2JointId jointId ); + +/// Wake the bodies connect to this joint +B2_API void b2Joint_WakeBodies( b2JointId jointId ); + +/// Get the current constraint force for this joint. Usually in Newtons. +B2_API b2Vec2 b2Joint_GetConstraintForce( b2JointId jointId ); + +/// Get the current constraint torque for this joint. Usually in Newton * meters. +B2_API float b2Joint_GetConstraintTorque( b2JointId jointId ); + +/// Get the current linear separation error for this joint. Does not consider admissible movement. Usually in meters. +B2_API float b2Joint_GetLinearSeparation( b2JointId jointId ); + +/// Get the current angular separation error for this joint. Does not consider admissible movement. Usually in meters. +B2_API float b2Joint_GetAngularSeparation( b2JointId jointId ); + +/// Get the joint constraint tuning. Advanced feature. +B2_API void b2Joint_GetConstraintTuning( b2JointId jointId, float* hertz, float* dampingRatio ); + +/// Set the joint constraint tuning. Advanced feature. +/// @param jointId the joint +/// @param hertz the stiffness in Hertz (cycles per second) +/// @param dampingRatio the non-dimensional damping ratio (one for critical damping) +B2_API void b2Joint_SetConstraintTuning( b2JointId jointId, float hertz, float dampingRatio ); + +/** + * @defgroup distance_joint Distance Joint + * @brief Functions for the distance joint. + * @{ + */ + +/// Create a distance joint +/// @see b2DistanceJointDef for details +B2_API b2JointId b2CreateDistanceJoint( b2WorldId worldId, const b2DistanceJointDef* def ); + +/// Set the rest length of a distance joint +/// @param jointId The id for a distance joint +/// @param length The new distance joint length +B2_API void b2DistanceJoint_SetLength( b2JointId jointId, float length ); + +/// Get the rest length of a distance joint +B2_API float b2DistanceJoint_GetLength( b2JointId jointId ); + +/// Enable/disable the distance joint spring. When disabled the distance joint is rigid. +B2_API void b2DistanceJoint_EnableSpring( b2JointId jointId, bool enableSpring ); + +/// Is the distance joint spring enabled? +B2_API bool b2DistanceJoint_IsSpringEnabled( b2JointId jointId ); + +/// Set the spring stiffness in Hertz +B2_API void b2DistanceJoint_SetSpringHertz( b2JointId jointId, float hertz ); + +/// Set the spring damping ratio, non-dimensional +B2_API void b2DistanceJoint_SetSpringDampingRatio( b2JointId jointId, float dampingRatio ); + +/// Get the spring Hertz +B2_API float b2DistanceJoint_GetSpringHertz( b2JointId jointId ); + +/// Get the spring damping ratio +B2_API float b2DistanceJoint_GetSpringDampingRatio( b2JointId jointId ); + +/// Enable joint limit. The limit only works if the joint spring is enabled. Otherwise the joint is rigid +/// and the limit has no effect. +B2_API void b2DistanceJoint_EnableLimit( b2JointId jointId, bool enableLimit ); + +/// Is the distance joint limit enabled? +B2_API bool b2DistanceJoint_IsLimitEnabled( b2JointId jointId ); + +/// Set the minimum and maximum length parameters of a distance joint +B2_API void b2DistanceJoint_SetLengthRange( b2JointId jointId, float minLength, float maxLength ); + +/// Get the distance joint minimum length +B2_API float b2DistanceJoint_GetMinLength( b2JointId jointId ); + +/// Get the distance joint maximum length +B2_API float b2DistanceJoint_GetMaxLength( b2JointId jointId ); + +/// Get the current length of a distance joint +B2_API float b2DistanceJoint_GetCurrentLength( b2JointId jointId ); + +/// Enable/disable the distance joint motor +B2_API void b2DistanceJoint_EnableMotor( b2JointId jointId, bool enableMotor ); + +/// Is the distance joint motor enabled? +B2_API bool b2DistanceJoint_IsMotorEnabled( b2JointId jointId ); + +/// Set the distance joint motor speed, usually in meters per second +B2_API void b2DistanceJoint_SetMotorSpeed( b2JointId jointId, float motorSpeed ); + +/// Get the distance joint motor speed, usually in meters per second +B2_API float b2DistanceJoint_GetMotorSpeed( b2JointId jointId ); + +/// Set the distance joint maximum motor force, usually in newtons +B2_API void b2DistanceJoint_SetMaxMotorForce( b2JointId jointId, float force ); + +/// Get the distance joint maximum motor force, usually in newtons +B2_API float b2DistanceJoint_GetMaxMotorForce( b2JointId jointId ); + +/// Get the distance joint current motor force, usually in newtons +B2_API float b2DistanceJoint_GetMotorForce( b2JointId jointId ); + +/** @} */ + +/** + * @defgroup motor_joint Motor Joint + * @brief Functions for the motor joint. + * + * The motor joint is used to drive the relative transform between two bodies. It takes + * a relative position and rotation and applies the forces and torques needed to achieve + * that relative transform over time. + * @{ + */ + +/// Create a motor joint +/// @see b2MotorJointDef for details +B2_API b2JointId b2CreateMotorJoint( b2WorldId worldId, const b2MotorJointDef* def ); + +/// Set the motor joint linear offset target +B2_API void b2MotorJoint_SetLinearOffset( b2JointId jointId, b2Vec2 linearOffset ); + +/// Get the motor joint linear offset target +B2_API b2Vec2 b2MotorJoint_GetLinearOffset( b2JointId jointId ); + +/// Set the motor joint angular offset target in radians. This angle will be unwound +/// so the motor will drive along the shortest arc. +B2_API void b2MotorJoint_SetAngularOffset( b2JointId jointId, float angularOffset ); + +/// Get the motor joint angular offset target in radians +B2_API float b2MotorJoint_GetAngularOffset( b2JointId jointId ); + +/// Set the motor joint maximum force, usually in newtons +B2_API void b2MotorJoint_SetMaxForce( b2JointId jointId, float maxForce ); + +/// Get the motor joint maximum force, usually in newtons +B2_API float b2MotorJoint_GetMaxForce( b2JointId jointId ); + +/// Set the motor joint maximum torque, usually in newton-meters +B2_API void b2MotorJoint_SetMaxTorque( b2JointId jointId, float maxTorque ); + +/// Get the motor joint maximum torque, usually in newton-meters +B2_API float b2MotorJoint_GetMaxTorque( b2JointId jointId ); + +/// Set the motor joint correction factor, usually in [0, 1] +B2_API void b2MotorJoint_SetCorrectionFactor( b2JointId jointId, float correctionFactor ); + +/// Get the motor joint correction factor, usually in [0, 1] +B2_API float b2MotorJoint_GetCorrectionFactor( b2JointId jointId ); + +/**@}*/ + +/** + * @defgroup mouse_joint Mouse Joint + * @brief Functions for the mouse joint. + * + * The mouse joint is designed for use in the samples application, but you may find it useful in applications where + * the user moves a rigid body with a cursor. + * @{ + */ + +/// Create a mouse joint +/// @see b2MouseJointDef for details +B2_API b2JointId b2CreateMouseJoint( b2WorldId worldId, const b2MouseJointDef* def ); + +/// Set the mouse joint target +B2_API void b2MouseJoint_SetTarget( b2JointId jointId, b2Vec2 target ); + +/// Get the mouse joint target +B2_API b2Vec2 b2MouseJoint_GetTarget( b2JointId jointId ); + +/// Set the mouse joint spring stiffness in Hertz +B2_API void b2MouseJoint_SetSpringHertz( b2JointId jointId, float hertz ); + +/// Get the mouse joint spring stiffness in Hertz +B2_API float b2MouseJoint_GetSpringHertz( b2JointId jointId ); + +/// Set the mouse joint spring damping ratio, non-dimensional +B2_API void b2MouseJoint_SetSpringDampingRatio( b2JointId jointId, float dampingRatio ); + +/// Get the mouse joint damping ratio, non-dimensional +B2_API float b2MouseJoint_GetSpringDampingRatio( b2JointId jointId ); + +/// Set the mouse joint maximum force, usually in newtons +B2_API void b2MouseJoint_SetMaxForce( b2JointId jointId, float maxForce ); + +/// Get the mouse joint maximum force, usually in newtons +B2_API float b2MouseJoint_GetMaxForce( b2JointId jointId ); + +/**@}*/ + +/** + * @defgroup filter_joint Filter Joint + * @brief Functions for the filter joint. + * + * The filter joint is used to disable collision between two bodies. As a side effect of being a joint, it also + * keeps the two bodies in the same simulation island. + * @{ + */ + +/// Create a filter joint. +/// @see b2FilterJointDef for details +B2_API b2JointId b2CreateFilterJoint( b2WorldId worldId, const b2FilterJointDef* def ); + +/**@}*/ + +/** + * @defgroup prismatic_joint Prismatic Joint + * @brief A prismatic joint allows for translation along a single axis with no rotation. + * + * The prismatic joint is useful for things like pistons and moving platforms, where you want a body to translate + * along an axis and have no rotation. Also called a *slider* joint. + * @{ + */ + +/// Create a prismatic (slider) joint. +/// @see b2PrismaticJointDef for details +B2_API b2JointId b2CreatePrismaticJoint( b2WorldId worldId, const b2PrismaticJointDef* def ); + +/// Enable/disable the joint spring. +B2_API void b2PrismaticJoint_EnableSpring( b2JointId jointId, bool enableSpring ); + +/// Is the prismatic joint spring enabled or not? +B2_API bool b2PrismaticJoint_IsSpringEnabled( b2JointId jointId ); + +/// Set the prismatic joint stiffness in Hertz. +/// This should usually be less than a quarter of the simulation rate. For example, if the simulation +/// runs at 60Hz then the joint stiffness should be 15Hz or less. +B2_API void b2PrismaticJoint_SetSpringHertz( b2JointId jointId, float hertz ); + +/// Get the prismatic joint stiffness in Hertz +B2_API float b2PrismaticJoint_GetSpringHertz( b2JointId jointId ); + +/// Set the prismatic joint damping ratio (non-dimensional) +B2_API void b2PrismaticJoint_SetSpringDampingRatio( b2JointId jointId, float dampingRatio ); + +/// Get the prismatic spring damping ratio (non-dimensional) +B2_API float b2PrismaticJoint_GetSpringDampingRatio( b2JointId jointId ); + +/// Set the prismatic joint spring target angle, usually in meters +B2_API void b2PrismaticJoint_SetTargetTranslation( b2JointId jointId, float translation ); + +/// Get the prismatic joint spring target translation, usually in meters +B2_API float b2PrismaticJoint_GetTargetTranslation( b2JointId jointId ); + +/// Enable/disable a prismatic joint limit +B2_API void b2PrismaticJoint_EnableLimit( b2JointId jointId, bool enableLimit ); + +/// Is the prismatic joint limit enabled? +B2_API bool b2PrismaticJoint_IsLimitEnabled( b2JointId jointId ); + +/// Get the prismatic joint lower limit +B2_API float b2PrismaticJoint_GetLowerLimit( b2JointId jointId ); + +/// Get the prismatic joint upper limit +B2_API float b2PrismaticJoint_GetUpperLimit( b2JointId jointId ); + +/// Set the prismatic joint limits +B2_API void b2PrismaticJoint_SetLimits( b2JointId jointId, float lower, float upper ); + +/// Enable/disable a prismatic joint motor +B2_API void b2PrismaticJoint_EnableMotor( b2JointId jointId, bool enableMotor ); + +/// Is the prismatic joint motor enabled? +B2_API bool b2PrismaticJoint_IsMotorEnabled( b2JointId jointId ); + +/// Set the prismatic joint motor speed, usually in meters per second +B2_API void b2PrismaticJoint_SetMotorSpeed( b2JointId jointId, float motorSpeed ); + +/// Get the prismatic joint motor speed, usually in meters per second +B2_API float b2PrismaticJoint_GetMotorSpeed( b2JointId jointId ); + +/// Set the prismatic joint maximum motor force, usually in newtons +B2_API void b2PrismaticJoint_SetMaxMotorForce( b2JointId jointId, float force ); + +/// Get the prismatic joint maximum motor force, usually in newtons +B2_API float b2PrismaticJoint_GetMaxMotorForce( b2JointId jointId ); + +/// Get the prismatic joint current motor force, usually in newtons +B2_API float b2PrismaticJoint_GetMotorForce( b2JointId jointId ); + +/// Get the current joint translation, usually in meters. +B2_API float b2PrismaticJoint_GetTranslation( b2JointId jointId ); + +/// Get the current joint translation speed, usually in meters per second. +B2_API float b2PrismaticJoint_GetSpeed( b2JointId jointId ); + +/** @} */ + +/** + * @defgroup revolute_joint Revolute Joint + * @brief A revolute joint allows for relative rotation in the 2D plane with no relative translation. + * + * The revolute joint is probably the most common joint. It can be used for ragdolls and chains. + * Also called a *hinge* or *pin* joint. + * @{ + */ + +/// Create a revolute joint +/// @see b2RevoluteJointDef for details +B2_API b2JointId b2CreateRevoluteJoint( b2WorldId worldId, const b2RevoluteJointDef* def ); + +/// Enable/disable the revolute joint spring +B2_API void b2RevoluteJoint_EnableSpring( b2JointId jointId, bool enableSpring ); + +/// It the revolute angular spring enabled? +B2_API bool b2RevoluteJoint_IsSpringEnabled( b2JointId jointId ); + +/// Set the revolute joint spring stiffness in Hertz +B2_API void b2RevoluteJoint_SetSpringHertz( b2JointId jointId, float hertz ); + +/// Get the revolute joint spring stiffness in Hertz +B2_API float b2RevoluteJoint_GetSpringHertz( b2JointId jointId ); + +/// Set the revolute joint spring damping ratio, non-dimensional +B2_API void b2RevoluteJoint_SetSpringDampingRatio( b2JointId jointId, float dampingRatio ); + +/// Get the revolute joint spring damping ratio, non-dimensional +B2_API float b2RevoluteJoint_GetSpringDampingRatio( b2JointId jointId ); + +/// Set the revolute joint spring target angle, radians +B2_API void b2RevoluteJoint_SetTargetAngle( b2JointId jointId, float angle ); + +/// Get the revolute joint spring target angle, radians +B2_API float b2RevoluteJoint_GetTargetAngle( b2JointId jointId ); + +/// Get the revolute joint current angle in radians relative to the reference angle +/// @see b2RevoluteJointDef::referenceAngle +B2_API float b2RevoluteJoint_GetAngle( b2JointId jointId ); + +/// Enable/disable the revolute joint limit +B2_API void b2RevoluteJoint_EnableLimit( b2JointId jointId, bool enableLimit ); + +/// Is the revolute joint limit enabled? +B2_API bool b2RevoluteJoint_IsLimitEnabled( b2JointId jointId ); + +/// Get the revolute joint lower limit in radians +B2_API float b2RevoluteJoint_GetLowerLimit( b2JointId jointId ); + +/// Get the revolute joint upper limit in radians +B2_API float b2RevoluteJoint_GetUpperLimit( b2JointId jointId ); + +/// Set the revolute joint limits in radians. It is expected that lower <= upper +/// and that -0.99 * B2_PI <= lower && upper <= -0.99 * B2_PI. +B2_API void b2RevoluteJoint_SetLimits( b2JointId jointId, float lower, float upper ); + +/// Enable/disable a revolute joint motor +B2_API void b2RevoluteJoint_EnableMotor( b2JointId jointId, bool enableMotor ); + +/// Is the revolute joint motor enabled? +B2_API bool b2RevoluteJoint_IsMotorEnabled( b2JointId jointId ); + +/// Set the revolute joint motor speed in radians per second +B2_API void b2RevoluteJoint_SetMotorSpeed( b2JointId jointId, float motorSpeed ); + +/// Get the revolute joint motor speed in radians per second +B2_API float b2RevoluteJoint_GetMotorSpeed( b2JointId jointId ); + +/// Get the revolute joint current motor torque, usually in newton-meters +B2_API float b2RevoluteJoint_GetMotorTorque( b2JointId jointId ); + +/// Set the revolute joint maximum motor torque, usually in newton-meters +B2_API void b2RevoluteJoint_SetMaxMotorTorque( b2JointId jointId, float torque ); + +/// Get the revolute joint maximum motor torque, usually in newton-meters +B2_API float b2RevoluteJoint_GetMaxMotorTorque( b2JointId jointId ); + +/**@}*/ + +/** + * @defgroup weld_joint Weld Joint + * @brief A weld joint fully constrains the relative transform between two bodies while allowing for springiness + * + * A weld joint constrains the relative rotation and translation between two bodies. Both rotation and translation + * can have damped springs. + * + * @note The accuracy of weld joint is limited by the accuracy of the solver. Long chains of weld joints may flex. + * @{ + */ + +/// Create a weld joint +/// @see b2WeldJointDef for details +B2_API b2JointId b2CreateWeldJoint( b2WorldId worldId, const b2WeldJointDef* def ); + +/// Set the weld joint linear stiffness in Hertz. 0 is rigid. +B2_API void b2WeldJoint_SetLinearHertz( b2JointId jointId, float hertz ); + +/// Get the weld joint linear stiffness in Hertz +B2_API float b2WeldJoint_GetLinearHertz( b2JointId jointId ); + +/// Set the weld joint linear damping ratio (non-dimensional) +B2_API void b2WeldJoint_SetLinearDampingRatio( b2JointId jointId, float dampingRatio ); + +/// Get the weld joint linear damping ratio (non-dimensional) +B2_API float b2WeldJoint_GetLinearDampingRatio( b2JointId jointId ); + +/// Set the weld joint angular stiffness in Hertz. 0 is rigid. +B2_API void b2WeldJoint_SetAngularHertz( b2JointId jointId, float hertz ); + +/// Get the weld joint angular stiffness in Hertz +B2_API float b2WeldJoint_GetAngularHertz( b2JointId jointId ); + +/// Set weld joint angular damping ratio, non-dimensional +B2_API void b2WeldJoint_SetAngularDampingRatio( b2JointId jointId, float dampingRatio ); + +/// Get the weld joint angular damping ratio, non-dimensional +B2_API float b2WeldJoint_GetAngularDampingRatio( b2JointId jointId ); + +/** @} */ + +/** + * @defgroup wheel_joint Wheel Joint + * The wheel joint can be used to simulate wheels on vehicles. + * + * The wheel joint restricts body B to move along a local axis in body A. Body B is free to + * rotate. Supports a linear spring, linear limits, and a rotational motor. + * + * @{ + */ + +/// Create a wheel joint +/// @see b2WheelJointDef for details +B2_API b2JointId b2CreateWheelJoint( b2WorldId worldId, const b2WheelJointDef* def ); + +/// Enable/disable the wheel joint spring +B2_API void b2WheelJoint_EnableSpring( b2JointId jointId, bool enableSpring ); + +/// Is the wheel joint spring enabled? +B2_API bool b2WheelJoint_IsSpringEnabled( b2JointId jointId ); + +/// Set the wheel joint stiffness in Hertz +B2_API void b2WheelJoint_SetSpringHertz( b2JointId jointId, float hertz ); + +/// Get the wheel joint stiffness in Hertz +B2_API float b2WheelJoint_GetSpringHertz( b2JointId jointId ); + +/// Set the wheel joint damping ratio, non-dimensional +B2_API void b2WheelJoint_SetSpringDampingRatio( b2JointId jointId, float dampingRatio ); + +/// Get the wheel joint damping ratio, non-dimensional +B2_API float b2WheelJoint_GetSpringDampingRatio( b2JointId jointId ); + +/// Enable/disable the wheel joint limit +B2_API void b2WheelJoint_EnableLimit( b2JointId jointId, bool enableLimit ); + +/// Is the wheel joint limit enabled? +B2_API bool b2WheelJoint_IsLimitEnabled( b2JointId jointId ); + +/// Get the wheel joint lower limit +B2_API float b2WheelJoint_GetLowerLimit( b2JointId jointId ); + +/// Get the wheel joint upper limit +B2_API float b2WheelJoint_GetUpperLimit( b2JointId jointId ); + +/// Set the wheel joint limits +B2_API void b2WheelJoint_SetLimits( b2JointId jointId, float lower, float upper ); + +/// Enable/disable the wheel joint motor +B2_API void b2WheelJoint_EnableMotor( b2JointId jointId, bool enableMotor ); + +/// Is the wheel joint motor enabled? +B2_API bool b2WheelJoint_IsMotorEnabled( b2JointId jointId ); + +/// Set the wheel joint motor speed in radians per second +B2_API void b2WheelJoint_SetMotorSpeed( b2JointId jointId, float motorSpeed ); + +/// Get the wheel joint motor speed in radians per second +B2_API float b2WheelJoint_GetMotorSpeed( b2JointId jointId ); + +/// Set the wheel joint maximum motor torque, usually in newton-meters +B2_API void b2WheelJoint_SetMaxMotorTorque( b2JointId jointId, float torque ); + +/// Get the wheel joint maximum motor torque, usually in newton-meters +B2_API float b2WheelJoint_GetMaxMotorTorque( b2JointId jointId ); + +/// Get the wheel joint current motor torque, usually in newton-meters +B2_API float b2WheelJoint_GetMotorTorque( b2JointId jointId ); + +/**@}*/ + +/**@}*/ diff --git a/TSE_Core/include/box2d/collision.h b/TSE_Core/include/box2d/collision.h new file mode 100644 index 0000000..df93583 --- /dev/null +++ b/TSE_Core/include/box2d/collision.h @@ -0,0 +1,833 @@ +// SPDX-FileCopyrightText: 2023 Erin Catto +// SPDX-License-Identifier: MIT + +#pragma once + +#include "base.h" +#include "math_functions.h" + +#include + +typedef struct b2SimplexCache b2SimplexCache; +typedef struct b2Hull b2Hull; + +/** + * @defgroup geometry Geometry + * @brief Geometry types and algorithms + * + * Definitions of circles, capsules, segments, and polygons. Various algorithms to compute hulls, mass properties, and so on. + * @{ + */ + +/// The maximum number of vertices on a convex polygon. Changing this affects performance even if you +/// don't use more vertices. +#define B2_MAX_POLYGON_VERTICES 8 + +/// Low level ray cast input data +typedef struct b2RayCastInput +{ + /// Start point of the ray cast + b2Vec2 origin; + + /// Translation of the ray cast + b2Vec2 translation; + + /// The maximum fraction of the translation to consider, typically 1 + float maxFraction; +} b2RayCastInput; + +/// A distance proxy is used by the GJK algorithm. It encapsulates any shape. +/// You can provide between 1 and B2_MAX_POLYGON_VERTICES and a radius. +typedef struct b2ShapeProxy +{ + /// The point cloud + b2Vec2 points[B2_MAX_POLYGON_VERTICES]; + + /// The number of points. Must be greater than 0. + int count; + + /// The external radius of the point cloud. May be zero. + float radius; +} b2ShapeProxy; + +/// Low level shape cast input in generic form. This allows casting an arbitrary point +/// cloud wrap with a radius. For example, a circle is a single point with a non-zero radius. +/// A capsule is two points with a non-zero radius. A box is four points with a zero radius. +typedef struct b2ShapeCastInput +{ + /// A generic shape + b2ShapeProxy proxy; + + /// The translation of the shape cast + b2Vec2 translation; + + /// The maximum fraction of the translation to consider, typically 1 + float maxFraction; + + /// Allow shape cast to encroach when initially touching. This only works if the radius is greater than zero. + bool canEncroach; +} b2ShapeCastInput; + +/// Low level ray cast or shape-cast output data. Returns a zero fraction and normal in the case of initial overlap. +typedef struct b2CastOutput +{ + /// The surface normal at the hit point + b2Vec2 normal; + + /// The surface hit point + b2Vec2 point; + + /// The fraction of the input translation at collision + float fraction; + + /// The number of iterations used + int iterations; + + /// Did the cast hit? + bool hit; +} b2CastOutput; + +/// This holds the mass data computed for a shape. +typedef struct b2MassData +{ + /// The mass of the shape, usually in kilograms. + float mass; + + /// The position of the shape's centroid relative to the shape's origin. + b2Vec2 center; + + /// The rotational inertia of the shape about the local origin. + float rotationalInertia; +} b2MassData; + +/// A solid circle +typedef struct b2Circle +{ + /// The local center + b2Vec2 center; + + /// The radius + float radius; +} b2Circle; + +/// A solid capsule can be viewed as two semicircles connected +/// by a rectangle. +typedef struct b2Capsule +{ + /// Local center of the first semicircle + b2Vec2 center1; + + /// Local center of the second semicircle + b2Vec2 center2; + + /// The radius of the semicircles + float radius; +} b2Capsule; + +/// A solid convex polygon. It is assumed that the interior of the polygon is to +/// the left of each edge. +/// Polygons have a maximum number of vertices equal to B2_MAX_POLYGON_VERTICES. +/// In most cases you should not need many vertices for a convex polygon. +/// @warning DO NOT fill this out manually, instead use a helper function like +/// b2MakePolygon or b2MakeBox. +typedef struct b2Polygon +{ + /// The polygon vertices + b2Vec2 vertices[B2_MAX_POLYGON_VERTICES]; + + /// The outward normal vectors of the polygon sides + b2Vec2 normals[B2_MAX_POLYGON_VERTICES]; + + /// The centroid of the polygon + b2Vec2 centroid; + + /// The external radius for rounded polygons + float radius; + + /// The number of polygon vertices + int count; +} b2Polygon; + +/// A line segment with two-sided collision. +typedef struct b2Segment +{ + /// The first point + b2Vec2 point1; + + /// The second point + b2Vec2 point2; +} b2Segment; + +/// A line segment with one-sided collision. Only collides on the right side. +/// Several of these are generated for a chain shape. +/// ghost1 -> point1 -> point2 -> ghost2 +typedef struct b2ChainSegment +{ + /// The tail ghost vertex + b2Vec2 ghost1; + + /// The line segment + b2Segment segment; + + /// The head ghost vertex + b2Vec2 ghost2; + + /// The owning chain shape index (internal usage only) + int chainId; +} b2ChainSegment; + +/// Validate ray cast input data (NaN, etc) +B2_API bool b2IsValidRay( const b2RayCastInput* input ); + +/// Make a convex polygon from a convex hull. This will assert if the hull is not valid. +/// @warning Do not manually fill in the hull data, it must come directly from b2ComputeHull +B2_API b2Polygon b2MakePolygon( const b2Hull* hull, float radius ); + +/// Make an offset convex polygon from a convex hull. This will assert if the hull is not valid. +/// @warning Do not manually fill in the hull data, it must come directly from b2ComputeHull +B2_API b2Polygon b2MakeOffsetPolygon( const b2Hull* hull, b2Vec2 position, b2Rot rotation ); + +/// Make an offset convex polygon from a convex hull. This will assert if the hull is not valid. +/// @warning Do not manually fill in the hull data, it must come directly from b2ComputeHull +B2_API b2Polygon b2MakeOffsetRoundedPolygon( const b2Hull* hull, b2Vec2 position, b2Rot rotation, float radius ); + +/// Make a square polygon, bypassing the need for a convex hull. +/// @param halfWidth the half-width +B2_API b2Polygon b2MakeSquare( float halfWidth ); + +/// Make a box (rectangle) polygon, bypassing the need for a convex hull. +/// @param halfWidth the half-width (x-axis) +/// @param halfHeight the half-height (y-axis) +B2_API b2Polygon b2MakeBox( float halfWidth, float halfHeight ); + +/// Make a rounded box, bypassing the need for a convex hull. +/// @param halfWidth the half-width (x-axis) +/// @param halfHeight the half-height (y-axis) +/// @param radius the radius of the rounded extension +B2_API b2Polygon b2MakeRoundedBox( float halfWidth, float halfHeight, float radius ); + +/// Make an offset box, bypassing the need for a convex hull. +/// @param halfWidth the half-width (x-axis) +/// @param halfHeight the half-height (y-axis) +/// @param center the local center of the box +/// @param rotation the local rotation of the box +B2_API b2Polygon b2MakeOffsetBox( float halfWidth, float halfHeight, b2Vec2 center, b2Rot rotation ); + +/// Make an offset rounded box, bypassing the need for a convex hull. +/// @param halfWidth the half-width (x-axis) +/// @param halfHeight the half-height (y-axis) +/// @param center the local center of the box +/// @param rotation the local rotation of the box +/// @param radius the radius of the rounded extension +B2_API b2Polygon b2MakeOffsetRoundedBox( float halfWidth, float halfHeight, b2Vec2 center, b2Rot rotation, float radius ); + +/// Transform a polygon. This is useful for transferring a shape from one body to another. +B2_API b2Polygon b2TransformPolygon( b2Transform transform, const b2Polygon* polygon ); + +/// Compute mass properties of a circle +B2_API b2MassData b2ComputeCircleMass( const b2Circle* shape, float density ); + +/// Compute mass properties of a capsule +B2_API b2MassData b2ComputeCapsuleMass( const b2Capsule* shape, float density ); + +/// Compute mass properties of a polygon +B2_API b2MassData b2ComputePolygonMass( const b2Polygon* shape, float density ); + +/// Compute the bounding box of a transformed circle +B2_API b2AABB b2ComputeCircleAABB( const b2Circle* shape, b2Transform transform ); + +/// Compute the bounding box of a transformed capsule +B2_API b2AABB b2ComputeCapsuleAABB( const b2Capsule* shape, b2Transform transform ); + +/// Compute the bounding box of a transformed polygon +B2_API b2AABB b2ComputePolygonAABB( const b2Polygon* shape, b2Transform transform ); + +/// Compute the bounding box of a transformed line segment +B2_API b2AABB b2ComputeSegmentAABB( const b2Segment* shape, b2Transform transform ); + +/// Test a point for overlap with a circle in local space +B2_API bool b2PointInCircle( b2Vec2 point, const b2Circle* shape ); + +/// Test a point for overlap with a capsule in local space +B2_API bool b2PointInCapsule( b2Vec2 point, const b2Capsule* shape ); + +/// Test a point for overlap with a convex polygon in local space +B2_API bool b2PointInPolygon( b2Vec2 point, const b2Polygon* shape ); + +/// Ray cast versus circle shape in local space. Initial overlap is treated as a miss. +B2_API b2CastOutput b2RayCastCircle( const b2RayCastInput* input, const b2Circle* shape ); + +/// Ray cast versus capsule shape in local space. Initial overlap is treated as a miss. +B2_API b2CastOutput b2RayCastCapsule( const b2RayCastInput* input, const b2Capsule* shape ); + +/// Ray cast versus segment shape in local space. Optionally treat the segment as one-sided with hits from +/// the left side being treated as a miss. +B2_API b2CastOutput b2RayCastSegment( const b2RayCastInput* input, const b2Segment* shape, bool oneSided ); + +/// Ray cast versus polygon shape in local space. Initial overlap is treated as a miss. +B2_API b2CastOutput b2RayCastPolygon( const b2RayCastInput* input, const b2Polygon* shape ); + +/// Shape cast versus a circle. Initial overlap is treated as a miss. +B2_API b2CastOutput b2ShapeCastCircle( const b2ShapeCastInput* input, const b2Circle* shape ); + +/// Shape cast versus a capsule. Initial overlap is treated as a miss. +B2_API b2CastOutput b2ShapeCastCapsule( const b2ShapeCastInput* input, const b2Capsule* shape ); + +/// Shape cast versus a line segment. Initial overlap is treated as a miss. +B2_API b2CastOutput b2ShapeCastSegment( const b2ShapeCastInput* input, const b2Segment* shape ); + +/// Shape cast versus a convex polygon. Initial overlap is treated as a miss. +B2_API b2CastOutput b2ShapeCastPolygon( const b2ShapeCastInput* input, const b2Polygon* shape ); + +/// A convex hull. Used to create convex polygons. +/// @warning Do not modify these values directly, instead use b2ComputeHull() +typedef struct b2Hull +{ + /// The final points of the hull + b2Vec2 points[B2_MAX_POLYGON_VERTICES]; + + /// The number of points + int count; +} b2Hull; + +/// Compute the convex hull of a set of points. Returns an empty hull if it fails. +/// Some failure cases: +/// - all points very close together +/// - all points on a line +/// - less than 3 points +/// - more than B2_MAX_POLYGON_VERTICES points +/// This welds close points and removes collinear points. +/// @warning Do not modify a hull once it has been computed +B2_API b2Hull b2ComputeHull( const b2Vec2* points, int count ); + +/// This determines if a hull is valid. Checks for: +/// - convexity +/// - collinear points +/// This is expensive and should not be called at runtime. +B2_API bool b2ValidateHull( const b2Hull* hull ); + +/**@}*/ + +/** + * @defgroup distance Distance + * Functions for computing the distance between shapes. + * + * These are advanced functions you can use to perform distance calculations. There + * are functions for computing the closest points between shapes, doing linear shape casts, + * and doing rotational shape casts. The latter is called time of impact (TOI). + * @{ + */ + +/// Result of computing the distance between two line segments +typedef struct b2SegmentDistanceResult +{ + /// The closest point on the first segment + b2Vec2 closest1; + + /// The closest point on the second segment + b2Vec2 closest2; + + /// The barycentric coordinate on the first segment + float fraction1; + + /// The barycentric coordinate on the second segment + float fraction2; + + /// The squared distance between the closest points + float distanceSquared; +} b2SegmentDistanceResult; + +/// Compute the distance between two line segments, clamping at the end points if needed. +B2_API b2SegmentDistanceResult b2SegmentDistance( b2Vec2 p1, b2Vec2 q1, b2Vec2 p2, b2Vec2 q2 ); + +/// Used to warm start the GJK simplex. If you call this function multiple times with nearby +/// transforms this might improve performance. Otherwise you can zero initialize this. +/// The distance cache must be initialized to zero on the first call. +/// Users should generally just zero initialize this structure for each call. +typedef struct b2SimplexCache +{ + /// The number of stored simplex points + uint16_t count; + + /// The cached simplex indices on shape A + uint8_t indexA[3]; + + /// The cached simplex indices on shape B + uint8_t indexB[3]; +} b2SimplexCache; + +static const b2SimplexCache b2_emptySimplexCache = B2_ZERO_INIT; + +/// Input for b2ShapeDistance +typedef struct b2DistanceInput +{ + /// The proxy for shape A + b2ShapeProxy proxyA; + + /// The proxy for shape B + b2ShapeProxy proxyB; + + /// The world transform for shape A + b2Transform transformA; + + /// The world transform for shape B + b2Transform transformB; + + /// Should the proxy radius be considered? + bool useRadii; +} b2DistanceInput; + +/// Output for b2ShapeDistance +typedef struct b2DistanceOutput +{ + b2Vec2 pointA; ///< Closest point on shapeA + b2Vec2 pointB; ///< Closest point on shapeB + b2Vec2 normal; ///< Normal vector that points from A to B. Invalid if distance is zero. + float distance; ///< The final distance, zero if overlapped + int iterations; ///< Number of GJK iterations used + int simplexCount; ///< The number of simplexes stored in the simplex array +} b2DistanceOutput; + +/// Simplex vertex for debugging the GJK algorithm +typedef struct b2SimplexVertex +{ + b2Vec2 wA; ///< support point in proxyA + b2Vec2 wB; ///< support point in proxyB + b2Vec2 w; ///< wB - wA + float a; ///< barycentric coordinate for closest point + int indexA; ///< wA index + int indexB; ///< wB index +} b2SimplexVertex; + +/// Simplex from the GJK algorithm +typedef struct b2Simplex +{ + b2SimplexVertex v1, v2, v3; ///< vertices + int count; ///< number of valid vertices +} b2Simplex; + +/// Compute the closest points between two shapes represented as point clouds. +/// b2SimplexCache cache is input/output. On the first call set b2SimplexCache.count to zero. +/// The underlying GJK algorithm may be debugged by passing in debug simplexes and capacity. You may pass in NULL and 0 for these. +B2_API b2DistanceOutput b2ShapeDistance( const b2DistanceInput* input, b2SimplexCache* cache, b2Simplex* simplexes, + int simplexCapacity ); + +/// Input parameters for b2ShapeCast +typedef struct b2ShapeCastPairInput +{ + b2ShapeProxy proxyA; ///< The proxy for shape A + b2ShapeProxy proxyB; ///< The proxy for shape B + b2Transform transformA; ///< The world transform for shape A + b2Transform transformB; ///< The world transform for shape B + b2Vec2 translationB; ///< The translation of shape B + float maxFraction; ///< The fraction of the translation to consider, typically 1 + bool canEncroach; ///< Allows shapes with a radius to move slightly closer if already touching +} b2ShapeCastPairInput; + +/// Perform a linear shape cast of shape B moving and shape A fixed. Determines the hit point, normal, and translation fraction. +/// Initially touching shapes are treated as a miss. +B2_API b2CastOutput b2ShapeCast( const b2ShapeCastPairInput* input ); + +/// Make a proxy for use in overlap, shape cast, and related functions. This is a deep copy of the points. +B2_API b2ShapeProxy b2MakeProxy( const b2Vec2* points, int count, float radius ); + +/// Make a proxy with a transform. This is a deep copy of the points. +B2_API b2ShapeProxy b2MakeOffsetProxy( const b2Vec2* points, int count, float radius, b2Vec2 position, b2Rot rotation ); + +/// This describes the motion of a body/shape for TOI computation. Shapes are defined with respect to the body origin, +/// which may not coincide with the center of mass. However, to support dynamics we must interpolate the center of mass +/// position. +typedef struct b2Sweep +{ + b2Vec2 localCenter; ///< Local center of mass position + b2Vec2 c1; ///< Starting center of mass world position + b2Vec2 c2; ///< Ending center of mass world position + b2Rot q1; ///< Starting world rotation + b2Rot q2; ///< Ending world rotation +} b2Sweep; + +/// Evaluate the transform sweep at a specific time. +B2_API b2Transform b2GetSweepTransform( const b2Sweep* sweep, float time ); + +/// Input parameters for b2TimeOfImpact +typedef struct b2TOIInput +{ + b2ShapeProxy proxyA; ///< The proxy for shape A + b2ShapeProxy proxyB; ///< The proxy for shape B + b2Sweep sweepA; ///< The movement of shape A + b2Sweep sweepB; ///< The movement of shape B + float maxFraction; ///< Defines the sweep interval [0, maxFraction] +} b2TOIInput; + +/// Describes the TOI output +typedef enum b2TOIState +{ + b2_toiStateUnknown, + b2_toiStateFailed, + b2_toiStateOverlapped, + b2_toiStateHit, + b2_toiStateSeparated +} b2TOIState; + +/// Output parameters for b2TimeOfImpact. +typedef struct b2TOIOutput +{ + b2TOIState state; ///< The type of result + float fraction; ///< The sweep time of the collision +} b2TOIOutput; + +/// Compute the upper bound on time before two shapes penetrate. Time is represented as +/// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate, +/// non-tunneling collisions. If you change the time interval, you should call this function +/// again. +B2_API b2TOIOutput b2TimeOfImpact( const b2TOIInput* input ); + +/**@}*/ + +/** + * @defgroup collision Collision + * @brief Functions for colliding pairs of shapes + * @{ + */ + +/// A manifold point is a contact point belonging to a contact manifold. +/// It holds details related to the geometry and dynamics of the contact points. +/// Box2D uses speculative collision so some contact points may be separated. +/// You may use the totalNormalImpulse to determine if there was an interaction during +/// the time step. +typedef struct b2ManifoldPoint +{ + /// Location of the contact point in world space. Subject to precision loss at large coordinates. + /// @note Should only be used for debugging. + b2Vec2 point; + + /// Location of the contact point relative to shapeA's origin in world space + /// @note When used internally to the Box2D solver, this is relative to the body center of mass. + b2Vec2 anchorA; + + /// Location of the contact point relative to shapeB's origin in world space + /// @note When used internally to the Box2D solver, this is relative to the body center of mass. + b2Vec2 anchorB; + + /// The separation of the contact point, negative if penetrating + float separation; + + /// The impulse along the manifold normal vector. + float normalImpulse; + + /// The friction impulse + float tangentImpulse; + + /// The total normal impulse applied across sub-stepping and restitution. This is important + /// to identify speculative contact points that had an interaction in the time step. + float totalNormalImpulse; + + /// Relative normal velocity pre-solve. Used for hit events. If the normal impulse is + /// zero then there was no hit. Negative means shapes are approaching. + float normalVelocity; + + /// Uniquely identifies a contact point between two shapes + uint16_t id; + + /// Did this contact point exist the previous step? + bool persisted; +} b2ManifoldPoint; + +/// A contact manifold describes the contact points between colliding shapes. +/// @note Box2D uses speculative collision so some contact points may be separated. +typedef struct b2Manifold +{ + /// The unit normal vector in world space, points from shape A to bodyB + b2Vec2 normal; + + /// Angular impulse applied for rolling resistance. N * m * s = kg * m^2 / s + float rollingImpulse; + + /// The manifold points, up to two are possible in 2D + b2ManifoldPoint points[2]; + + /// The number of contacts points, will be 0, 1, or 2 + int pointCount; + +} b2Manifold; + +/// Compute the contact manifold between two circles +B2_API b2Manifold b2CollideCircles( const b2Circle* circleA, b2Transform xfA, const b2Circle* circleB, b2Transform xfB ); + +/// Compute the contact manifold between a capsule and circle +B2_API b2Manifold b2CollideCapsuleAndCircle( const b2Capsule* capsuleA, b2Transform xfA, const b2Circle* circleB, + b2Transform xfB ); + +/// Compute the contact manifold between an segment and a circle +B2_API b2Manifold b2CollideSegmentAndCircle( const b2Segment* segmentA, b2Transform xfA, const b2Circle* circleB, + b2Transform xfB ); + +/// Compute the contact manifold between a polygon and a circle +B2_API b2Manifold b2CollidePolygonAndCircle( const b2Polygon* polygonA, b2Transform xfA, const b2Circle* circleB, + b2Transform xfB ); + +/// Compute the contact manifold between a capsule and circle +B2_API b2Manifold b2CollideCapsules( const b2Capsule* capsuleA, b2Transform xfA, const b2Capsule* capsuleB, b2Transform xfB ); + +/// Compute the contact manifold between an segment and a capsule +B2_API b2Manifold b2CollideSegmentAndCapsule( const b2Segment* segmentA, b2Transform xfA, const b2Capsule* capsuleB, + b2Transform xfB ); + +/// Compute the contact manifold between a polygon and capsule +B2_API b2Manifold b2CollidePolygonAndCapsule( const b2Polygon* polygonA, b2Transform xfA, const b2Capsule* capsuleB, + b2Transform xfB ); + +/// Compute the contact manifold between two polygons +B2_API b2Manifold b2CollidePolygons( const b2Polygon* polygonA, b2Transform xfA, const b2Polygon* polygonB, b2Transform xfB ); + +/// Compute the contact manifold between an segment and a polygon +B2_API b2Manifold b2CollideSegmentAndPolygon( const b2Segment* segmentA, b2Transform xfA, const b2Polygon* polygonB, + b2Transform xfB ); + +/// Compute the contact manifold between a chain segment and a circle +B2_API b2Manifold b2CollideChainSegmentAndCircle( const b2ChainSegment* segmentA, b2Transform xfA, const b2Circle* circleB, + b2Transform xfB ); + +/// Compute the contact manifold between a chain segment and a capsule +B2_API b2Manifold b2CollideChainSegmentAndCapsule( const b2ChainSegment* segmentA, b2Transform xfA, const b2Capsule* capsuleB, + b2Transform xfB, b2SimplexCache* cache ); + +/// Compute the contact manifold between a chain segment and a rounded polygon +B2_API b2Manifold b2CollideChainSegmentAndPolygon( const b2ChainSegment* segmentA, b2Transform xfA, const b2Polygon* polygonB, + b2Transform xfB, b2SimplexCache* cache ); + +/**@}*/ + +/** + * @defgroup tree Dynamic Tree + * The dynamic tree is a binary AABB tree to organize and query large numbers of geometric objects + * + * Box2D uses the dynamic tree internally to sort collision shapes into a binary bounding volume hierarchy. + * This data structure may have uses in games for organizing other geometry data and may be used independently + * of Box2D rigid body simulation. + * + * A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt. + * A dynamic tree arranges data in a binary tree to accelerate + * queries such as AABB queries and ray casts. Leaf nodes are proxies + * with an AABB. These are used to hold a user collision object. + * Nodes are pooled and relocatable, so I use node indices rather than pointers. + * The dynamic tree is made available for advanced users that would like to use it to organize + * spatial game data besides rigid bodies. + * @{ + */ + +/// The dynamic tree structure. This should be considered private data. +/// It is placed here for performance reasons. +typedef struct b2DynamicTree +{ + /// The tree nodes + struct b2TreeNode* nodes; + + /// The root index + int root; + + /// The number of nodes + int nodeCount; + + /// The allocated node space + int nodeCapacity; + + /// Node free list + int freeList; + + /// Number of proxies created + int proxyCount; + + /// Leaf indices for rebuild + int* leafIndices; + + /// Leaf bounding boxes for rebuild + b2AABB* leafBoxes; + + /// Leaf bounding box centers for rebuild + b2Vec2* leafCenters; + + /// Bins for sorting during rebuild + int* binIndices; + + /// Allocated space for rebuilding + int rebuildCapacity; +} b2DynamicTree; + +/// These are performance results returned by dynamic tree queries. +typedef struct b2TreeStats +{ + /// Number of internal nodes visited during the query + int nodeVisits; + + /// Number of leaf nodes visited during the query + int leafVisits; +} b2TreeStats; + +/// Constructing the tree initializes the node pool. +B2_API b2DynamicTree b2DynamicTree_Create( void ); + +/// Destroy the tree, freeing the node pool. +B2_API void b2DynamicTree_Destroy( b2DynamicTree* tree ); + +/// Create a proxy. Provide an AABB and a userData value. +B2_API int b2DynamicTree_CreateProxy( b2DynamicTree* tree, b2AABB aabb, uint64_t categoryBits, uint64_t userData ); + +/// Destroy a proxy. This asserts if the id is invalid. +B2_API void b2DynamicTree_DestroyProxy( b2DynamicTree* tree, int proxyId ); + +/// Move a proxy to a new AABB by removing and reinserting into the tree. +B2_API void b2DynamicTree_MoveProxy( b2DynamicTree* tree, int proxyId, b2AABB aabb ); + +/// Enlarge a proxy and enlarge ancestors as necessary. +B2_API void b2DynamicTree_EnlargeProxy( b2DynamicTree* tree, int proxyId, b2AABB aabb ); + +/// Modify the category bits on a proxy. This is an expensive operation. +B2_API void b2DynamicTree_SetCategoryBits( b2DynamicTree* tree, int proxyId, uint64_t categoryBits ); + +/// Get the category bits on a proxy. +B2_API uint64_t b2DynamicTree_GetCategoryBits( b2DynamicTree* tree, int proxyId ); + +/// This function receives proxies found in the AABB query. +/// @return true if the query should continue +typedef bool b2TreeQueryCallbackFcn( int proxyId, uint64_t userData, void* context ); + +/// Query an AABB for overlapping proxies. The callback class is called for each proxy that overlaps the supplied AABB. +/// @return performance data +B2_API b2TreeStats b2DynamicTree_Query( const b2DynamicTree* tree, b2AABB aabb, uint64_t maskBits, + b2TreeQueryCallbackFcn* callback, void* context ); + +/// This function receives clipped ray cast input for a proxy. The function +/// returns the new ray fraction. +/// - return a value of 0 to terminate the ray cast +/// - return a value less than input->maxFraction to clip the ray +/// - return a value of input->maxFraction to continue the ray cast without clipping +typedef float b2TreeRayCastCallbackFcn( const b2RayCastInput* input, int proxyId, uint64_t userData, void* context ); + +/// Ray cast against the proxies in the tree. This relies on the callback +/// to perform a exact ray cast in the case were the proxy contains a shape. +/// The callback also performs the any collision filtering. This has performance +/// roughly equal to k * log(n), where k is the number of collisions and n is the +/// number of proxies in the tree. +/// Bit-wise filtering using mask bits can greatly improve performance in some scenarios. +/// However, this filtering may be approximate, so the user should still apply filtering to results. +/// @param tree the dynamic tree to ray cast +/// @param input the ray cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1) +/// @param maskBits mask bit hint: `bool accept = (maskBits & node->categoryBits) != 0;` +/// @param callback a callback class that is called for each proxy that is hit by the ray +/// @param context user context that is passed to the callback +/// @return performance data +B2_API b2TreeStats b2DynamicTree_RayCast( const b2DynamicTree* tree, const b2RayCastInput* input, uint64_t maskBits, + b2TreeRayCastCallbackFcn* callback, void* context ); + +/// This function receives clipped ray cast input for a proxy. The function +/// returns the new ray fraction. +/// - return a value of 0 to terminate the ray cast +/// - return a value less than input->maxFraction to clip the ray +/// - return a value of input->maxFraction to continue the ray cast without clipping +typedef float b2TreeShapeCastCallbackFcn( const b2ShapeCastInput* input, int proxyId, uint64_t userData, void* context ); + +/// Ray cast against the proxies in the tree. This relies on the callback +/// to perform a exact ray cast in the case were the proxy contains a shape. +/// The callback also performs the any collision filtering. This has performance +/// roughly equal to k * log(n), where k is the number of collisions and n is the +/// number of proxies in the tree. +/// @param tree the dynamic tree to ray cast +/// @param input the ray cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). +/// @param maskBits filter bits: `bool accept = (maskBits & node->categoryBits) != 0;` +/// @param callback a callback class that is called for each proxy that is hit by the shape +/// @param context user context that is passed to the callback +/// @return performance data +B2_API b2TreeStats b2DynamicTree_ShapeCast( const b2DynamicTree* tree, const b2ShapeCastInput* input, uint64_t maskBits, + b2TreeShapeCastCallbackFcn* callback, void* context ); + +/// Get the height of the binary tree. +B2_API int b2DynamicTree_GetHeight( const b2DynamicTree* tree ); + +/// Get the ratio of the sum of the node areas to the root area. +B2_API float b2DynamicTree_GetAreaRatio( const b2DynamicTree* tree ); + +/// Get the bounding box that contains the entire tree +B2_API b2AABB b2DynamicTree_GetRootBounds( const b2DynamicTree* tree ); + +/// Get the number of proxies created +B2_API int b2DynamicTree_GetProxyCount( const b2DynamicTree* tree ); + +/// Rebuild the tree while retaining subtrees that haven't changed. Returns the number of boxes sorted. +B2_API int b2DynamicTree_Rebuild( b2DynamicTree* tree, bool fullBuild ); + +/// Get the number of bytes used by this tree +B2_API int b2DynamicTree_GetByteCount( const b2DynamicTree* tree ); + +/// Get proxy user data +B2_API uint64_t b2DynamicTree_GetUserData( const b2DynamicTree* tree, int proxyId ); + +/// Get the AABB of a proxy +B2_API b2AABB b2DynamicTree_GetAABB( const b2DynamicTree* tree, int proxyId ); + +/// Validate this tree. For testing. +B2_API void b2DynamicTree_Validate( const b2DynamicTree* tree ); + +/// Validate this tree has no enlarged AABBs. For testing. +B2_API void b2DynamicTree_ValidateNoEnlarged( const b2DynamicTree* tree ); + +/**@}*/ + +/** + * @defgroup character Character mover + * Character movement solver + * @{ + */ + +/// These are the collision planes returned from b2World_CollideMover +typedef struct b2PlaneResult +{ + /// The collision plane between the mover and a convex shape + b2Plane plane; + + // The collision point on the shape. + b2Vec2 point; + + /// Did the collision register a hit? If not this plane should be ignored. + bool hit; +} b2PlaneResult; + +/// These are collision planes that can be fed to b2SolvePlanes. Normally +/// this is assembled by the user from plane results in b2PlaneResult +typedef struct b2CollisionPlane +{ + /// The collision plane between the mover and some shape + b2Plane plane; + + /// Setting this to FLT_MAX makes the plane as rigid as possible. Lower values can + /// make the plane collision soft. Usually in meters. + float pushLimit; + + /// The push on the mover determined by b2SolvePlanes. Usually in meters. + float push; + + /// Indicates if b2ClipVector should clip against this plane. Should be false for soft collision. + bool clipVelocity; +} b2CollisionPlane; + +/// Result returned by b2SolvePlanes +typedef struct b2PlaneSolverResult +{ + /// The translation of the mover + b2Vec2 translation; + + /// The number of iterations used by the plane solver. For diagnostics. + int iterationCount; +} b2PlaneSolverResult; + +/// Solves the position of a mover that satisfies the given collision planes. +/// @param targetDelta the desired movement from the position used to generate the collision planes +/// @param planes the collision planes +/// @param count the number of collision planes +B2_API b2PlaneSolverResult b2SolvePlanes( b2Vec2 targetDelta, b2CollisionPlane* planes, int count ); + +/// Clips the velocity against the given collision planes. Planes with zero push or clipVelocity +/// set to false are skipped. +B2_API b2Vec2 b2ClipVector( b2Vec2 vector, const b2CollisionPlane* planes, int count ); + +/**@}*/ diff --git a/TSE_Core/include/box2d/id.h b/TSE_Core/include/box2d/id.h new file mode 100644 index 0000000..d7aaea0 --- /dev/null +++ b/TSE_Core/include/box2d/id.h @@ -0,0 +1,157 @@ +// SPDX-FileCopyrightText: 2023 Erin Catto +// SPDX-License-Identifier: MIT + +#pragma once + +#include "base.h" + +#include + +/** + * @defgroup id Ids + * These ids serve as handles to internal Box2D objects. + * These should be considered opaque data and passed by value. + * Include this header if you need the id types and not the whole Box2D API. + * All ids are considered null if initialized to zero. + * + * For example in C++: + * + * @code{.cxx} + * b2WorldId worldId = {}; + * @endcode + * + * Or in C: + * + * @code{.c} + * b2WorldId worldId = {0}; + * @endcode + * + * These are both considered null. + * + * @warning Do not use the internals of these ids. They are subject to change. Ids should be treated as opaque objects. + * @warning You should use ids to access objects in Box2D. Do not access files within the src folder. Such usage is unsupported. + * @{ + */ + +/// World id references a world instance. This should be treated as an opaque handle. +typedef struct b2WorldId +{ + uint16_t index1; + uint16_t generation; +} b2WorldId; + +/// Body id references a body instance. This should be treated as an opaque handle. +typedef struct b2BodyId +{ + int32_t index1; + uint16_t world0; + uint16_t generation; +} b2BodyId; + +/// Shape id references a shape instance. This should be treated as an opaque handle. +typedef struct b2ShapeId +{ + int32_t index1; + uint16_t world0; + uint16_t generation; +} b2ShapeId; + +/// Chain id references a chain instances. This should be treated as an opaque handle. +typedef struct b2ChainId +{ + int32_t index1; + uint16_t world0; + uint16_t generation; +} b2ChainId; + +/// Joint id references a joint instance. This should be treated as an opaque handle. +typedef struct b2JointId +{ + int32_t index1; + uint16_t world0; + uint16_t generation; +} b2JointId; + +/// Use these to make your identifiers null. +/// You may also use zero initialization to get null. +static const b2WorldId b2_nullWorldId = B2_ZERO_INIT; +static const b2BodyId b2_nullBodyId = B2_ZERO_INIT; +static const b2ShapeId b2_nullShapeId = B2_ZERO_INIT; +static const b2ChainId b2_nullChainId = B2_ZERO_INIT; +static const b2JointId b2_nullJointId = B2_ZERO_INIT; + +/// Macro to determine if any id is null. +#define B2_IS_NULL( id ) ( id.index1 == 0 ) + +/// Macro to determine if any id is non-null. +#define B2_IS_NON_NULL( id ) ( id.index1 != 0 ) + +/// Compare two ids for equality. Doesn't work for b2WorldId. +#define B2_ID_EQUALS( id1, id2 ) ( id1.index1 == id2.index1 && id1.world0 == id2.world0 && id1.generation == id2.generation ) + +/// Store a world id into a uint32_t. +B2_INLINE uint32_t b2StoreWorldId( b2WorldId id ) +{ + return ( (uint32_t)id.index1 << 16 ) | (uint32_t)id.generation; +} + +/// Load a uint32_t into a world id. +B2_INLINE b2WorldId b2LoadWorldId( uint32_t x ) +{ + b2WorldId id = { (uint16_t)( x >> 16 ), (uint16_t)( x ) }; + return id; +} + +/// Store a body id into a uint64_t. +B2_INLINE uint64_t b2StoreBodyId( b2BodyId id ) +{ + return ( (uint64_t)id.index1 << 32 ) | ( (uint64_t)id.world0 ) << 16 | (uint64_t)id.generation; +} + +/// Load a uint64_t into a body id. +B2_INLINE b2BodyId b2LoadBodyId( uint64_t x ) +{ + b2BodyId id = { (int32_t)( x >> 32 ), (uint16_t)( x >> 16 ), (uint16_t)( x ) }; + return id; +} + +/// Store a shape id into a uint64_t. +B2_INLINE uint64_t b2StoreShapeId( b2ShapeId id ) +{ + return ( (uint64_t)id.index1 << 32 ) | ( (uint64_t)id.world0 ) << 16 | (uint64_t)id.generation; +} + +/// Load a uint64_t into a shape id. +B2_INLINE b2ShapeId b2LoadShapeId( uint64_t x ) +{ + b2ShapeId id = { (int32_t)( x >> 32 ), (uint16_t)( x >> 16 ), (uint16_t)( x ) }; + return id; +} + +/// Store a chain id into a uint64_t. +B2_INLINE uint64_t b2StoreChainId( b2ChainId id ) +{ + return ( (uint64_t)id.index1 << 32 ) | ( (uint64_t)id.world0 ) << 16 | (uint64_t)id.generation; +} + +/// Load a uint64_t into a chain id. +B2_INLINE b2ChainId b2LoadChainId( uint64_t x ) +{ + b2ChainId id = { (int32_t)( x >> 32 ), (uint16_t)( x >> 16 ), (uint16_t)( x ) }; + return id; +} + +/// Store a joint id into a uint64_t. +B2_INLINE uint64_t b2StoreJointId( b2JointId id ) +{ + return ( (uint64_t)id.index1 << 32 ) | ( (uint64_t)id.world0 ) << 16 | (uint64_t)id.generation; +} + +/// Load a uint64_t into a joint id. +B2_INLINE b2JointId b2LoadJointId( uint64_t x ) +{ + b2JointId id = { (int32_t)( x >> 32 ), (uint16_t)( x >> 16 ), (uint16_t)( x ) }; + return id; +} + +/**@}*/ diff --git a/TSE_Core/include/box2d/math_functions.h b/TSE_Core/include/box2d/math_functions.h new file mode 100644 index 0000000..25dea3c --- /dev/null +++ b/TSE_Core/include/box2d/math_functions.h @@ -0,0 +1,756 @@ +// SPDX-FileCopyrightText: 2023 Erin Catto +// SPDX-License-Identifier: MIT + +#pragma once + +#include "base.h" + +#include +#include +#include + +/** + * @defgroup math Math + * @brief Vector math types and functions + * @{ + */ + +/// 2D vector +/// This can be used to represent a point or free vector +typedef struct b2Vec2 +{ + /// coordinates + float x, y; +} b2Vec2; + +/// Cosine and sine pair +/// This uses a custom implementation designed for cross-platform determinism +typedef struct b2CosSin +{ + /// cosine and sine + float cosine; + float sine; +} b2CosSin; + +/// 2D rotation +/// This is similar to using a complex number for rotation +typedef struct b2Rot +{ + /// cosine and sine + float c, s; +} b2Rot; + +/// A 2D rigid transform +typedef struct b2Transform +{ + b2Vec2 p; + b2Rot q; +} b2Transform; + +/// A 2-by-2 Matrix +typedef struct b2Mat22 +{ + /// columns + b2Vec2 cx, cy; +} b2Mat22; + +/// Axis-aligned bounding box +typedef struct b2AABB +{ + b2Vec2 lowerBound; + b2Vec2 upperBound; +} b2AABB; + +/// separation = dot(normal, point) - offset +typedef struct b2Plane +{ + b2Vec2 normal; + float offset; +} b2Plane; + +/**@}*/ + +/** + * @addtogroup math + * @{ + */ + +/// https://en.wikipedia.org/wiki/Pi +#define B2_PI 3.14159265359f + +static const b2Vec2 b2Vec2_zero = { 0.0f, 0.0f }; +static const b2Rot b2Rot_identity = { 1.0f, 0.0f }; +static const b2Transform b2Transform_identity = { { 0.0f, 0.0f }, { 1.0f, 0.0f } }; +static const b2Mat22 b2Mat22_zero = { { 0.0f, 0.0f }, { 0.0f, 0.0f } }; + +/// Is this a valid number? Not NaN or infinity. +B2_API bool b2IsValidFloat( float a ); + +/// Is this a valid vector? Not NaN or infinity. +B2_API bool b2IsValidVec2( b2Vec2 v ); + +/// Is this a valid rotation? Not NaN or infinity. Is normalized. +B2_API bool b2IsValidRotation( b2Rot q ); + +/// Is this a valid bounding box? Not Nan or infinity. Upper bound greater than or equal to lower bound. +B2_API bool b2IsValidAABB( b2AABB aabb ); + +/// Is this a valid plane? Normal is a unit vector. Not Nan or infinity. +B2_API bool b2IsValidPlane( b2Plane a ); + +/// @return the minimum of two integers +B2_INLINE int b2MinInt( int a, int b ) +{ + return a < b ? a : b; +} + +/// @return the maximum of two integers +B2_INLINE int b2MaxInt( int a, int b ) +{ + return a > b ? a : b; +} + +/// @return the absolute value of an integer +B2_INLINE int b2AbsInt( int a ) +{ + return a < 0 ? -a : a; +} + +/// @return an integer clamped between a lower and upper bound +B2_INLINE int b2ClampInt( int a, int lower, int upper ) +{ + return a < lower ? lower : ( a > upper ? upper : a ); +} + +/// @return the minimum of two floats +B2_INLINE float b2MinFloat( float a, float b ) +{ + return a < b ? a : b; +} + +/// @return the maximum of two floats +B2_INLINE float b2MaxFloat( float a, float b ) +{ + return a > b ? a : b; +} + +/// @return the absolute value of a float +B2_INLINE float b2AbsFloat( float a ) +{ + return a < 0 ? -a : a; +} + +/// @return a float clamped between a lower and upper bound +B2_INLINE float b2ClampFloat( float a, float lower, float upper ) +{ + return a < lower ? lower : ( a > upper ? upper : a ); +} + +/// Compute an approximate arctangent in the range [-pi, pi] +/// This is hand coded for cross-platform determinism. The atan2f +/// function in the standard library is not cross-platform deterministic. +/// Accurate to around 0.0023 degrees +B2_API float b2Atan2( float y, float x ); + +/// Compute the cosine and sine of an angle in radians. Implemented +/// for cross-platform determinism. +B2_API b2CosSin b2ComputeCosSin( float radians ); + +/// Vector dot product +B2_INLINE float b2Dot( b2Vec2 a, b2Vec2 b ) +{ + return a.x * b.x + a.y * b.y; +} + +/// Vector cross product. In 2D this yields a scalar. +B2_INLINE float b2Cross( b2Vec2 a, b2Vec2 b ) +{ + return a.x * b.y - a.y * b.x; +} + +/// Perform the cross product on a vector and a scalar. In 2D this produces a vector. +B2_INLINE b2Vec2 b2CrossVS( b2Vec2 v, float s ) +{ + return B2_LITERAL( b2Vec2 ){ s * v.y, -s * v.x }; +} + +/// Perform the cross product on a scalar and a vector. In 2D this produces a vector. +B2_INLINE b2Vec2 b2CrossSV( float s, b2Vec2 v ) +{ + return B2_LITERAL( b2Vec2 ){ -s * v.y, s * v.x }; +} + +/// Get a left pointing perpendicular vector. Equivalent to b2CrossSV(1.0f, v) +B2_INLINE b2Vec2 b2LeftPerp( b2Vec2 v ) +{ + return B2_LITERAL( b2Vec2 ){ -v.y, v.x }; +} + +/// Get a right pointing perpendicular vector. Equivalent to b2CrossVS(v, 1.0f) +B2_INLINE b2Vec2 b2RightPerp( b2Vec2 v ) +{ + return B2_LITERAL( b2Vec2 ){ v.y, -v.x }; +} + +/// Vector addition +B2_INLINE b2Vec2 b2Add( b2Vec2 a, b2Vec2 b ) +{ + return B2_LITERAL( b2Vec2 ){ a.x + b.x, a.y + b.y }; +} + +/// Vector subtraction +B2_INLINE b2Vec2 b2Sub( b2Vec2 a, b2Vec2 b ) +{ + return B2_LITERAL( b2Vec2 ){ a.x - b.x, a.y - b.y }; +} + +/// Vector negation +B2_INLINE b2Vec2 b2Neg( b2Vec2 a ) +{ + return B2_LITERAL( b2Vec2 ){ -a.x, -a.y }; +} + +/// Vector linear interpolation +/// https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/ +B2_INLINE b2Vec2 b2Lerp( b2Vec2 a, b2Vec2 b, float t ) +{ + return B2_LITERAL( b2Vec2 ){ ( 1.0f - t ) * a.x + t * b.x, ( 1.0f - t ) * a.y + t * b.y }; +} + +/// Component-wise multiplication +B2_INLINE b2Vec2 b2Mul( b2Vec2 a, b2Vec2 b ) +{ + return B2_LITERAL( b2Vec2 ){ a.x * b.x, a.y * b.y }; +} + +/// Multiply a scalar and vector +B2_INLINE b2Vec2 b2MulSV( float s, b2Vec2 v ) +{ + return B2_LITERAL( b2Vec2 ){ s * v.x, s * v.y }; +} + +/// a + s * b +B2_INLINE b2Vec2 b2MulAdd( b2Vec2 a, float s, b2Vec2 b ) +{ + return B2_LITERAL( b2Vec2 ){ a.x + s * b.x, a.y + s * b.y }; +} + +/// a - s * b +B2_INLINE b2Vec2 b2MulSub( b2Vec2 a, float s, b2Vec2 b ) +{ + return B2_LITERAL( b2Vec2 ){ a.x - s * b.x, a.y - s * b.y }; +} + +/// Component-wise absolute vector +B2_INLINE b2Vec2 b2Abs( b2Vec2 a ) +{ + b2Vec2 b; + b.x = b2AbsFloat( a.x ); + b.y = b2AbsFloat( a.y ); + return b; +} + +/// Component-wise minimum vector +B2_INLINE b2Vec2 b2Min( b2Vec2 a, b2Vec2 b ) +{ + b2Vec2 c; + c.x = b2MinFloat( a.x, b.x ); + c.y = b2MinFloat( a.y, b.y ); + return c; +} + +/// Component-wise maximum vector +B2_INLINE b2Vec2 b2Max( b2Vec2 a, b2Vec2 b ) +{ + b2Vec2 c; + c.x = b2MaxFloat( a.x, b.x ); + c.y = b2MaxFloat( a.y, b.y ); + return c; +} + +/// Component-wise clamp vector v into the range [a, b] +B2_INLINE b2Vec2 b2Clamp( b2Vec2 v, b2Vec2 a, b2Vec2 b ) +{ + b2Vec2 c; + c.x = b2ClampFloat( v.x, a.x, b.x ); + c.y = b2ClampFloat( v.y, a.y, b.y ); + return c; +} + +/// Get the length of this vector (the norm) +B2_INLINE float b2Length( b2Vec2 v ) +{ + return sqrtf( v.x * v.x + v.y * v.y ); +} + +/// Get the distance between two points +B2_INLINE float b2Distance( b2Vec2 a, b2Vec2 b ) +{ + float dx = b.x - a.x; + float dy = b.y - a.y; + return sqrtf( dx * dx + dy * dy ); +} + +/// Convert a vector into a unit vector if possible, otherwise returns the zero vector. +/// todo MSVC is not inlining this function in several places per warning 4710 +B2_INLINE b2Vec2 b2Normalize( b2Vec2 v ) +{ + float length = sqrtf( v.x * v.x + v.y * v.y ); + if ( length < FLT_EPSILON ) + { + return B2_LITERAL( b2Vec2 ){ 0.0f, 0.0f }; + } + + float invLength = 1.0f / length; + b2Vec2 n = { invLength * v.x, invLength * v.y }; + return n; +} + +/// Determines if the provided vector is normalized (norm(a) == 1). +B2_INLINE bool b2IsNormalized( b2Vec2 a ) +{ + float aa = b2Dot( a, a ); + return b2AbsFloat( 1.0f - aa ) < 100.0f * FLT_EPSILON; +} + +/// Convert a vector into a unit vector if possible, otherwise returns the zero vector. Also +/// outputs the length. +B2_INLINE b2Vec2 b2GetLengthAndNormalize( float* length, b2Vec2 v ) +{ + *length = sqrtf( v.x * v.x + v.y * v.y ); + if ( *length < FLT_EPSILON ) + { + return B2_LITERAL( b2Vec2 ){ 0.0f, 0.0f }; + } + + float invLength = 1.0f / *length; + b2Vec2 n = { invLength * v.x, invLength * v.y }; + return n; +} + +/// Normalize rotation +B2_INLINE b2Rot b2NormalizeRot( b2Rot q ) +{ + float mag = sqrtf( q.s * q.s + q.c * q.c ); + float invMag = mag > 0.0 ? 1.0f / mag : 0.0f; + b2Rot qn = { q.c * invMag, q.s * invMag }; + return qn; +} + +/// Integrate rotation from angular velocity +/// @param q1 initial rotation +/// @param deltaAngle the angular displacement in radians +B2_INLINE b2Rot b2IntegrateRotation( b2Rot q1, float deltaAngle ) +{ + // dc/dt = -omega * sin(t) + // ds/dt = omega * cos(t) + // c2 = c1 - omega * h * s1 + // s2 = s1 + omega * h * c1 + b2Rot q2 = { q1.c - deltaAngle * q1.s, q1.s + deltaAngle * q1.c }; + float mag = sqrtf( q2.s * q2.s + q2.c * q2.c ); + float invMag = mag > 0.0 ? 1.0f / mag : 0.0f; + b2Rot qn = { q2.c * invMag, q2.s * invMag }; + return qn; +} + +/// Get the length squared of this vector +B2_INLINE float b2LengthSquared( b2Vec2 v ) +{ + return v.x * v.x + v.y * v.y; +} + +/// Get the distance squared between points +B2_INLINE float b2DistanceSquared( b2Vec2 a, b2Vec2 b ) +{ + b2Vec2 c = { b.x - a.x, b.y - a.y }; + return c.x * c.x + c.y * c.y; +} + +/// Make a rotation using an angle in radians +B2_INLINE b2Rot b2MakeRot( float radians ) +{ + b2CosSin cs = b2ComputeCosSin( radians ); + return B2_LITERAL( b2Rot ){ cs.cosine, cs.sine }; +} + +/// Compute the rotation between two unit vectors +B2_API b2Rot b2ComputeRotationBetweenUnitVectors( b2Vec2 v1, b2Vec2 v2 ); + +/// Is this rotation normalized? +B2_INLINE bool b2IsNormalizedRot( b2Rot q ) +{ + // larger tolerance due to failure on mingw 32-bit + float qq = q.s * q.s + q.c * q.c; + return 1.0f - 0.0006f < qq && qq < 1.0f + 0.0006f; +} + +/// Normalized linear interpolation +/// https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/ +/// https://web.archive.org/web/20170825184056/http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/ +B2_INLINE b2Rot b2NLerp( b2Rot q1, b2Rot q2, float t ) +{ + float omt = 1.0f - t; + b2Rot q = { + omt * q1.c + t * q2.c, + omt * q1.s + t * q2.s, + }; + + float mag = sqrtf( q.s * q.s + q.c * q.c ); + float invMag = mag > 0.0 ? 1.0f / mag : 0.0f; + b2Rot qn = { q.c * invMag, q.s * invMag }; + return qn; +} + +/// Compute the angular velocity necessary to rotate between two rotations over a give time +/// @param q1 initial rotation +/// @param q2 final rotation +/// @param inv_h inverse time step +B2_INLINE float b2ComputeAngularVelocity( b2Rot q1, b2Rot q2, float inv_h ) +{ + // ds/dt = omega * cos(t) + // dc/dt = -omega * sin(t) + // s2 = s1 + omega * h * c1 + // c2 = c1 - omega * h * s1 + + // omega * h * s1 = c1 - c2 + // omega * h * c1 = s2 - s1 + // omega * h = (c1 - c2) * s1 + (s2 - s1) * c1; + // omega * h = s1 * c1 - c2 * s1 + s2 * c1 - s1 * c1 + // omega * h = s2 * c1 - c2 * s1 = sin(a2 - a1) ~= a2 - a1 for small delta + float omega = inv_h * ( q2.s * q1.c - q2.c * q1.s ); + return omega; +} + +/// Get the angle in radians in the range [-pi, pi] +B2_INLINE float b2Rot_GetAngle( b2Rot q ) +{ + return b2Atan2( q.s, q.c ); +} + +/// Get the x-axis +B2_INLINE b2Vec2 b2Rot_GetXAxis( b2Rot q ) +{ + b2Vec2 v = { q.c, q.s }; + return v; +} + +/// Get the y-axis +B2_INLINE b2Vec2 b2Rot_GetYAxis( b2Rot q ) +{ + b2Vec2 v = { -q.s, q.c }; + return v; +} + +/// Multiply two rotations: q * r +B2_INLINE b2Rot b2MulRot( b2Rot q, b2Rot r ) +{ + // [qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc] + // [qs qc] [rs rc] [qs*rc+qc*rs -qs*rs+qc*rc] + // s(q + r) = qs * rc + qc * rs + // c(q + r) = qc * rc - qs * rs + b2Rot qr; + qr.s = q.s * r.c + q.c * r.s; + qr.c = q.c * r.c - q.s * r.s; + return qr; +} + +/// Transpose multiply two rotations: qT * r +B2_INLINE b2Rot b2InvMulRot( b2Rot q, b2Rot r ) +{ + // [ qc qs] * [rc -rs] = [qc*rc+qs*rs -qc*rs+qs*rc] + // [-qs qc] [rs rc] [-qs*rc+qc*rs qs*rs+qc*rc] + // s(q - r) = qc * rs - qs * rc + // c(q - r) = qc * rc + qs * rs + b2Rot qr; + qr.s = q.c * r.s - q.s * r.c; + qr.c = q.c * r.c + q.s * r.s; + return qr; +} + +/// relative angle between b and a (rot_b * inv(rot_a)) +B2_INLINE float b2RelativeAngle( b2Rot b, b2Rot a ) +{ + // sin(b - a) = bs * ac - bc * as + // cos(b - a) = bc * ac + bs * as + float s = b.s * a.c - b.c * a.s; + float c = b.c * a.c + b.s * a.s; + return b2Atan2( s, c ); +} + +/// Convert any angle into the range [-pi, pi] +B2_INLINE float b2UnwindAngle( float radians ) +{ + // Assuming this is deterministic + return remainderf( radians, 2.0f * B2_PI ); +} + +/// Rotate a vector +B2_INLINE b2Vec2 b2RotateVector( b2Rot q, b2Vec2 v ) +{ + return B2_LITERAL( b2Vec2 ){ q.c * v.x - q.s * v.y, q.s * v.x + q.c * v.y }; +} + +/// Inverse rotate a vector +B2_INLINE b2Vec2 b2InvRotateVector( b2Rot q, b2Vec2 v ) +{ + return B2_LITERAL( b2Vec2 ){ q.c * v.x + q.s * v.y, -q.s * v.x + q.c * v.y }; +} + +/// Transform a point (e.g. local space to world space) +B2_INLINE b2Vec2 b2TransformPoint( b2Transform t, const b2Vec2 p ) +{ + float x = ( t.q.c * p.x - t.q.s * p.y ) + t.p.x; + float y = ( t.q.s * p.x + t.q.c * p.y ) + t.p.y; + + return B2_LITERAL( b2Vec2 ){ x, y }; +} + +/// Inverse transform a point (e.g. world space to local space) +B2_INLINE b2Vec2 b2InvTransformPoint( b2Transform t, const b2Vec2 p ) +{ + float vx = p.x - t.p.x; + float vy = p.y - t.p.y; + return B2_LITERAL( b2Vec2 ){ t.q.c * vx + t.q.s * vy, -t.q.s * vx + t.q.c * vy }; +} + +/// Multiply two transforms. If the result is applied to a point p local to frame B, +/// the transform would first convert p to a point local to frame A, then into a point +/// in the world frame. +/// v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p +/// = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p +B2_INLINE b2Transform b2MulTransforms( b2Transform A, b2Transform B ) +{ + b2Transform C; + C.q = b2MulRot( A.q, B.q ); + C.p = b2Add( b2RotateVector( A.q, B.p ), A.p ); + return C; +} + +/// Creates a transform that converts a local point in frame B to a local point in frame A. +/// v2 = A.q' * (B.q * v1 + B.p - A.p) +/// = A.q' * B.q * v1 + A.q' * (B.p - A.p) +B2_INLINE b2Transform b2InvMulTransforms( b2Transform A, b2Transform B ) +{ + b2Transform C; + C.q = b2InvMulRot( A.q, B.q ); + C.p = b2InvRotateVector( A.q, b2Sub( B.p, A.p ) ); + return C; +} + +/// Multiply a 2-by-2 matrix times a 2D vector +B2_INLINE b2Vec2 b2MulMV( b2Mat22 A, b2Vec2 v ) +{ + b2Vec2 u = { + A.cx.x * v.x + A.cy.x * v.y, + A.cx.y * v.x + A.cy.y * v.y, + }; + return u; +} + +/// Get the inverse of a 2-by-2 matrix +B2_INLINE b2Mat22 b2GetInverse22( b2Mat22 A ) +{ + float a = A.cx.x, b = A.cy.x, c = A.cx.y, d = A.cy.y; + float det = a * d - b * c; + if ( det != 0.0f ) + { + det = 1.0f / det; + } + + b2Mat22 B = { + { det * d, -det * c }, + { -det * b, det * a }, + }; + return B; +} + +/// Solve A * x = b, where b is a column vector. This is more efficient +/// than computing the inverse in one-shot cases. +B2_INLINE b2Vec2 b2Solve22( b2Mat22 A, b2Vec2 b ) +{ + float a11 = A.cx.x, a12 = A.cy.x, a21 = A.cx.y, a22 = A.cy.y; + float det = a11 * a22 - a12 * a21; + if ( det != 0.0f ) + { + det = 1.0f / det; + } + b2Vec2 x = { det * ( a22 * b.x - a12 * b.y ), det * ( a11 * b.y - a21 * b.x ) }; + return x; +} + +/// Does a fully contain b +B2_INLINE bool b2AABB_Contains( b2AABB a, b2AABB b ) +{ + bool s = true; + s = s && a.lowerBound.x <= b.lowerBound.x; + s = s && a.lowerBound.y <= b.lowerBound.y; + s = s && b.upperBound.x <= a.upperBound.x; + s = s && b.upperBound.y <= a.upperBound.y; + return s; +} + +/// Get the center of the AABB. +B2_INLINE b2Vec2 b2AABB_Center( b2AABB a ) +{ + b2Vec2 b = { 0.5f * ( a.lowerBound.x + a.upperBound.x ), 0.5f * ( a.lowerBound.y + a.upperBound.y ) }; + return b; +} + +/// Get the extents of the AABB (half-widths). +B2_INLINE b2Vec2 b2AABB_Extents( b2AABB a ) +{ + b2Vec2 b = { 0.5f * ( a.upperBound.x - a.lowerBound.x ), 0.5f * ( a.upperBound.y - a.lowerBound.y ) }; + return b; +} + +/// Union of two AABBs +B2_INLINE b2AABB b2AABB_Union( b2AABB a, b2AABB b ) +{ + b2AABB c; + c.lowerBound.x = b2MinFloat( a.lowerBound.x, b.lowerBound.x ); + c.lowerBound.y = b2MinFloat( a.lowerBound.y, b.lowerBound.y ); + c.upperBound.x = b2MaxFloat( a.upperBound.x, b.upperBound.x ); + c.upperBound.y = b2MaxFloat( a.upperBound.y, b.upperBound.y ); + return c; +} + +/// Do a and b overlap +B2_INLINE bool b2AABB_Overlaps( b2AABB a, b2AABB b ) +{ + return !( b.lowerBound.x > a.upperBound.x || b.lowerBound.y > a.upperBound.y || a.lowerBound.x > b.upperBound.x || + a.lowerBound.y > b.upperBound.y ); +} + +/// Compute the bounding box of an array of circles +B2_INLINE b2AABB b2MakeAABB( const b2Vec2* points, int count, float radius ) +{ + B2_ASSERT( count > 0 ); + b2AABB a = { points[0], points[0] }; + for ( int i = 1; i < count; ++i ) + { + a.lowerBound = b2Min( a.lowerBound, points[i] ); + a.upperBound = b2Max( a.upperBound, points[i] ); + } + + b2Vec2 r = { radius, radius }; + a.lowerBound = b2Sub( a.lowerBound, r ); + a.upperBound = b2Add( a.upperBound, r ); + + return a; +} + +/// Signed separation of a point from a plane +B2_INLINE float b2PlaneSeparation( b2Plane plane, b2Vec2 point ) +{ + return b2Dot( plane.normal, point ) - plane.offset; +} + +/// One-dimensional mass-spring-damper simulation. Returns the new velocity given the position and time step. +/// You can then compute the new position using: +/// position += timeStep * newVelocity +/// This drives towards a zero position. By using implicit integration we get a stable solution +/// that doesn't require transcendental functions. +B2_INLINE float b2SpringDamper( float hertz, float dampingRatio, float position, float velocity, float timeStep ) +{ + float omega = 2.0f * B2_PI * hertz; + float omegaH = omega * timeStep; + return ( velocity - omega * omegaH * position ) / ( 1.0f + 2.0f * dampingRatio * omegaH + omegaH * omegaH ); +} + +/// Box2D bases all length units on meters, but you may need different units for your game. +/// You can set this value to use different units. This should be done at application startup +/// and only modified once. Default value is 1. +/// For example, if your game uses pixels for units you can use pixels for all length values +/// sent to Box2D. There should be no extra cost. However, Box2D has some internal tolerances +/// and thresholds that have been tuned for meters. By calling this function, Box2D is able +/// to adjust those tolerances and thresholds to improve accuracy. +/// A good rule of thumb is to pass the height of your player character to this function. So +/// if your player character is 32 pixels high, then pass 32 to this function. Then you may +/// confidently use pixels for all the length values sent to Box2D. All length values returned +/// from Box2D will also be pixels because Box2D does not do any scaling internally. +/// However, you are now on the hook for coming up with good values for gravity, density, and +/// forces. +/// @warning This must be modified before any calls to Box2D +B2_API void b2SetLengthUnitsPerMeter( float lengthUnits ); + +/// Get the current length units per meter. +B2_API float b2GetLengthUnitsPerMeter( void ); + +/**@}*/ + +/** + * @defgroup math_cpp C++ Math + * @brief Math operator overloads for C++ + * + * See math_functions.h for details. + * @{ + */ + +#ifdef __cplusplus + +/// Unary add one vector to another +inline void operator+=( b2Vec2& a, b2Vec2 b ) +{ + a.x += b.x; + a.y += b.y; +} + +/// Unary subtract one vector from another +inline void operator-=( b2Vec2& a, b2Vec2 b ) +{ + a.x -= b.x; + a.y -= b.y; +} + +/// Unary multiply a vector by a scalar +inline void operator*=( b2Vec2& a, float b ) +{ + a.x *= b; + a.y *= b; +} + +/// Unary negate a vector +inline b2Vec2 operator-( b2Vec2 a ) +{ + return { -a.x, -a.y }; +} + +/// Binary vector addition +inline b2Vec2 operator+( b2Vec2 a, b2Vec2 b ) +{ + return { a.x + b.x, a.y + b.y }; +} + +/// Binary vector subtraction +inline b2Vec2 operator-( b2Vec2 a, b2Vec2 b ) +{ + return { a.x - b.x, a.y - b.y }; +} + +/// Binary scalar and vector multiplication +inline b2Vec2 operator*( float a, b2Vec2 b ) +{ + return { a * b.x, a * b.y }; +} + +/// Binary scalar and vector multiplication +inline b2Vec2 operator*( b2Vec2 a, float b ) +{ + return { a.x * b, a.y * b }; +} + +/// Binary vector equality +inline bool operator==( b2Vec2 a, b2Vec2 b ) +{ + return a.x == b.x && a.y == b.y; +} + +/// Binary vector inequality +inline bool operator!=( b2Vec2 a, b2Vec2 b ) +{ + return a.x != b.x || a.y != b.y; +} + +#endif + +/**@}*/ diff --git a/TSE_Core/include/box2d/types.h b/TSE_Core/include/box2d/types.h new file mode 100644 index 0000000..a09cb96 --- /dev/null +++ b/TSE_Core/include/box2d/types.h @@ -0,0 +1,1464 @@ +// SPDX-FileCopyrightText: 2023 Erin Catto +// SPDX-License-Identifier: MIT + +#pragma once + +#include "base.h" +#include "collision.h" +#include "id.h" +#include "math_functions.h" + +#include +#include + +#define B2_DEFAULT_CATEGORY_BITS 1 +#define B2_DEFAULT_MASK_BITS UINT64_MAX + +/// Task interface +/// This is prototype for a Box2D task. Your task system is expected to invoke the Box2D task with these arguments. +/// The task spans a range of the parallel-for: [startIndex, endIndex) +/// The worker index must correctly identify each worker in the user thread pool, expected in [0, workerCount). +/// A worker must only exist on only one thread at a time and is analogous to the thread index. +/// The task context is the context pointer sent from Box2D when it is enqueued. +/// The startIndex and endIndex are expected in the range [0, itemCount) where itemCount is the argument to b2EnqueueTaskCallback +/// below. Box2D expects startIndex < endIndex and will execute a loop like this: +/// +/// @code{.c} +/// for (int i = startIndex; i < endIndex; ++i) +/// { +/// DoWork(); +/// } +/// @endcode +/// @ingroup world +typedef void b2TaskCallback( int startIndex, int endIndex, uint32_t workerIndex, void* taskContext ); + +/// These functions can be provided to Box2D to invoke a task system. These are designed to work well with enkiTS. +/// Returns a pointer to the user's task object. May be nullptr. A nullptr indicates to Box2D that the work was executed +/// serially within the callback and there is no need to call b2FinishTaskCallback. +/// The itemCount is the number of Box2D work items that are to be partitioned among workers by the user's task system. +/// This is essentially a parallel-for. The minRange parameter is a suggestion of the minimum number of items to assign +/// per worker to reduce overhead. For example, suppose the task is small and that itemCount is 16. A minRange of 8 suggests +/// that your task system should split the work items among just two workers, even if you have more available. +/// In general the range [startIndex, endIndex) send to b2TaskCallback should obey: +/// endIndex - startIndex >= minRange +/// The exception of course is when itemCount < minRange. +/// @ingroup world +typedef void* b2EnqueueTaskCallback( b2TaskCallback* task, int itemCount, int minRange, void* taskContext, void* userContext ); + +/// Finishes a user task object that wraps a Box2D task. +/// @ingroup world +typedef void b2FinishTaskCallback( void* userTask, void* userContext ); + +/// Optional friction mixing callback. This intentionally provides no context objects because this is called +/// from a worker thread. +/// @warning This function should not attempt to modify Box2D state or user application state. +/// @ingroup world +typedef float b2FrictionCallback( float frictionA, int userMaterialIdA, float frictionB, int userMaterialIdB ); + +/// Optional restitution mixing callback. This intentionally provides no context objects because this is called +/// from a worker thread. +/// @warning This function should not attempt to modify Box2D state or user application state. +/// @ingroup world +typedef float b2RestitutionCallback( float restitutionA, int userMaterialIdA, float restitutionB, int userMaterialIdB ); + +/// Result from b2World_RayCastClosest +/// If there is initial overlap the fraction and normal will be zero while the point is an arbitrary point in the overlap region. +/// @ingroup world +typedef struct b2RayResult +{ + b2ShapeId shapeId; + b2Vec2 point; + b2Vec2 normal; + float fraction; + int nodeVisits; + int leafVisits; + bool hit; +} b2RayResult; + +/// World definition used to create a simulation world. +/// Must be initialized using b2DefaultWorldDef(). +/// @ingroup world +typedef struct b2WorldDef +{ + /// Gravity vector. Box2D has no up-vector defined. + b2Vec2 gravity; + + /// Restitution speed threshold, usually in m/s. Collisions above this + /// speed have restitution applied (will bounce). + float restitutionThreshold; + + /// Threshold speed for hit events. Usually meters per second. + float hitEventThreshold; + + /// Contact stiffness. Cycles per second. Increasing this increases the speed of overlap recovery, but can introduce jitter. + float contactHertz; + + /// Contact bounciness. Non-dimensional. You can speed up overlap recovery by decreasing this with + /// the trade-off that overlap resolution becomes more energetic. + float contactDampingRatio; + + /// This parameter controls how fast overlap is resolved and usually has units of meters per second. This only + /// puts a cap on the resolution speed. The resolution speed is increased by increasing the hertz and/or + /// decreasing the damping ratio. + float maxContactPushSpeed; + + /// Maximum linear speed. Usually meters per second. + float maximumLinearSpeed; + + /// Optional mixing callback for friction. The default uses sqrt(frictionA * frictionB). + b2FrictionCallback* frictionCallback; + + /// Optional mixing callback for restitution. The default uses max(restitutionA, restitutionB). + b2RestitutionCallback* restitutionCallback; + + /// Can bodies go to sleep to improve performance + bool enableSleep; + + /// Enable continuous collision + bool enableContinuous; + + /// Number of workers to use with the provided task system. Box2D performs best when using only + /// performance cores and accessing a single L2 cache. Efficiency cores and hyper-threading provide + /// little benefit and may even harm performance. + /// @note Box2D does not create threads. This is the number of threads your applications has created + /// that you are allocating to b2World_Step. + /// @warning Do not modify the default value unless you are also providing a task system and providing + /// task callbacks (enqueueTask and finishTask). + int workerCount; + + /// Function to spawn tasks + b2EnqueueTaskCallback* enqueueTask; + + /// Function to finish a task + b2FinishTaskCallback* finishTask; + + /// User context that is provided to enqueueTask and finishTask + void* userTaskContext; + + /// User data + void* userData; + + /// Used internally to detect a valid definition. DO NOT SET. + int internalValue; +} b2WorldDef; + +/// Use this to initialize your world definition +/// @ingroup world +B2_API b2WorldDef b2DefaultWorldDef( void ); + +/// The body simulation type. +/// Each body is one of these three types. The type determines how the body behaves in the simulation. +/// @ingroup body +typedef enum b2BodyType +{ + /// zero mass, zero velocity, may be manually moved + b2_staticBody = 0, + + /// zero mass, velocity set by user, moved by solver + b2_kinematicBody = 1, + + /// positive mass, velocity determined by forces, moved by solver + b2_dynamicBody = 2, + + /// number of body types + b2_bodyTypeCount, +} b2BodyType; + +/// A body definition holds all the data needed to construct a rigid body. +/// You can safely re-use body definitions. Shapes are added to a body after construction. +/// Body definitions are temporary objects used to bundle creation parameters. +/// Must be initialized using b2DefaultBodyDef(). +/// @ingroup body +typedef struct b2BodyDef +{ + /// The body type: static, kinematic, or dynamic. + b2BodyType type; + + /// The initial world position of the body. Bodies should be created with the desired position. + /// @note Creating bodies at the origin and then moving them nearly doubles the cost of body creation, especially + /// if the body is moved after shapes have been added. + b2Vec2 position; + + /// The initial world rotation of the body. Use b2MakeRot() if you have an angle. + b2Rot rotation; + + /// The initial linear velocity of the body's origin. Usually in meters per second. + b2Vec2 linearVelocity; + + /// The initial angular velocity of the body. Radians per second. + float angularVelocity; + + /// Linear damping is used to reduce the linear velocity. The damping parameter + /// can be larger than 1 but the damping effect becomes sensitive to the + /// time step when the damping parameter is large. + /// Generally linear damping is undesirable because it makes objects move slowly + /// as if they are floating. + float linearDamping; + + /// Angular damping is used to reduce the angular velocity. The damping parameter + /// can be larger than 1.0f but the damping effect becomes sensitive to the + /// time step when the damping parameter is large. + /// Angular damping can be use slow down rotating bodies. + float angularDamping; + + /// Scale the gravity applied to this body. Non-dimensional. + float gravityScale; + + /// Sleep speed threshold, default is 0.05 meters per second + float sleepThreshold; + + /// Optional body name for debugging. Up to 31 characters (excluding null termination) + const char* name; + + /// Use this to store application specific body data. + void* userData; + + /// Set this flag to false if this body should never fall asleep. + bool enableSleep; + + /// Is this body initially awake or sleeping? + bool isAwake; + + /// Should this body be prevented from rotating? Useful for characters. + bool fixedRotation; + + /// Treat this body as high speed object that performs continuous collision detection + /// against dynamic and kinematic bodies, but not other bullet bodies. + /// @warning Bullets should be used sparingly. They are not a solution for general dynamic-versus-dynamic + /// continuous collision. They may interfere with joint constraints. + bool isBullet; + + /// Used to disable a body. A disabled body does not move or collide. + bool isEnabled; + + /// This allows this body to bypass rotational speed limits. Should only be used + /// for circular objects, like wheels. + bool allowFastRotation; + + /// Used internally to detect a valid definition. DO NOT SET. + int internalValue; +} b2BodyDef; + +/// Use this to initialize your body definition +/// @ingroup body +B2_API b2BodyDef b2DefaultBodyDef( void ); + +/// This is used to filter collision on shapes. It affects shape-vs-shape collision +/// and shape-versus-query collision (such as b2World_CastRay). +/// @ingroup shape +typedef struct b2Filter +{ + /// The collision category bits. Normally you would just set one bit. The category bits should + /// represent your application object types. For example: + /// @code{.cpp} + /// enum MyCategories + /// { + /// Static = 0x00000001, + /// Dynamic = 0x00000002, + /// Debris = 0x00000004, + /// Player = 0x00000008, + /// // etc + /// }; + /// @endcode + uint64_t categoryBits; + + /// The collision mask bits. This states the categories that this + /// shape would accept for collision. + /// For example, you may want your player to only collide with static objects + /// and other players. + /// @code{.c} + /// maskBits = Static | Player; + /// @endcode + uint64_t maskBits; + + /// Collision groups allow a certain group of objects to never collide (negative) + /// or always collide (positive). A group index of zero has no effect. Non-zero group filtering + /// always wins against the mask bits. + /// For example, you may want ragdolls to collide with other ragdolls but you don't want + /// ragdoll self-collision. In this case you would give each ragdoll a unique negative group index + /// and apply that group index to all shapes on the ragdoll. + int groupIndex; +} b2Filter; + +/// Use this to initialize your filter +/// @ingroup shape +B2_API b2Filter b2DefaultFilter( void ); + +/// The query filter is used to filter collisions between queries and shapes. For example, +/// you may want a ray-cast representing a projectile to hit players and the static environment +/// but not debris. +/// @ingroup shape +typedef struct b2QueryFilter +{ + /// The collision category bits of this query. Normally you would just set one bit. + uint64_t categoryBits; + + /// The collision mask bits. This states the shape categories that this + /// query would accept for collision. + uint64_t maskBits; +} b2QueryFilter; + +/// Use this to initialize your query filter +/// @ingroup shape +B2_API b2QueryFilter b2DefaultQueryFilter( void ); + +/// Shape type +/// @ingroup shape +typedef enum b2ShapeType +{ + /// A circle with an offset + b2_circleShape, + + /// A capsule is an extruded circle + b2_capsuleShape, + + /// A line segment + b2_segmentShape, + + /// A convex polygon + b2_polygonShape, + + /// A line segment owned by a chain shape + b2_chainSegmentShape, + + /// The number of shape types + b2_shapeTypeCount +} b2ShapeType; + +/// Surface materials allow chain shapes to have per segment surface properties. +/// @ingroup shape +typedef struct b2SurfaceMaterial +{ + /// The Coulomb (dry) friction coefficient, usually in the range [0,1]. + float friction; + + /// The coefficient of restitution (bounce) usually in the range [0,1]. + /// https://en.wikipedia.org/wiki/Coefficient_of_restitution + float restitution; + + /// The rolling resistance usually in the range [0,1]. + float rollingResistance; + + /// The tangent speed for conveyor belts + float tangentSpeed; + + /// User material identifier. This is passed with query results and to friction and restitution + /// combining functions. It is not used internally. + int userMaterialId; + + /// Custom debug draw color. + uint32_t customColor; +} b2SurfaceMaterial; + +/// Use this to initialize your surface material +/// @ingroup shape +B2_API b2SurfaceMaterial b2DefaultSurfaceMaterial( void ); + +/// Used to create a shape. +/// This is a temporary object used to bundle shape creation parameters. You may use +/// the same shape definition to create multiple shapes. +/// Must be initialized using b2DefaultShapeDef(). +/// @ingroup shape +typedef struct b2ShapeDef +{ + /// Use this to store application specific shape data. + void* userData; + + /// The surface material for this shape. + b2SurfaceMaterial material; + + /// The density, usually in kg/m^2. + /// This is not part of the surface material because this is for the interior, which may have + /// other considerations, such as being hollow. For example a wood barrel may be hollow or full of water. + float density; + + /// Collision filtering data. + b2Filter filter; + + /// A sensor shape generates overlap events but never generates a collision response. + /// Sensors do not have continuous collision. Instead, use a ray or shape cast for those scenarios. + /// Sensors still contribute to the body mass if they have non-zero density. + /// @note Sensor events are disabled by default. + /// @see enableSensorEvents + bool isSensor; + + /// Enable sensor events for this shape. This applies to sensors and non-sensors. False by default, even for sensors. + bool enableSensorEvents; + + /// Enable contact events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors. False by default. + bool enableContactEvents; + + /// Enable hit events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors. False by default. + bool enableHitEvents; + + /// Enable pre-solve contact events for this shape. Only applies to dynamic bodies. These are expensive + /// and must be carefully handled due to threading. Ignored for sensors. + bool enablePreSolveEvents; + + /// When shapes are created they will scan the environment for collision the next time step. This can significantly slow down + /// static body creation when there are many static shapes. + /// This is flag is ignored for dynamic and kinematic shapes which always invoke contact creation. + bool invokeContactCreation; + + /// Should the body update the mass properties when this shape is created. Default is true. + bool updateBodyMass; + + /// Used internally to detect a valid definition. DO NOT SET. + int internalValue; +} b2ShapeDef; + +/// Use this to initialize your shape definition +/// @ingroup shape +B2_API b2ShapeDef b2DefaultShapeDef( void ); + +/// Used to create a chain of line segments. This is designed to eliminate ghost collisions with some limitations. +/// - chains are one-sided +/// - chains have no mass and should be used on static bodies +/// - chains have a counter-clockwise winding order (normal points right of segment direction) +/// - chains are either a loop or open +/// - a chain must have at least 4 points +/// - the distance between any two points must be greater than B2_LINEAR_SLOP +/// - a chain shape should not self intersect (this is not validated) +/// - an open chain shape has NO COLLISION on the first and final edge +/// - you may overlap two open chains on their first three and/or last three points to get smooth collision +/// - a chain shape creates multiple line segment shapes on the body +/// https://en.wikipedia.org/wiki/Polygonal_chain +/// Must be initialized using b2DefaultChainDef(). +/// @warning Do not use chain shapes unless you understand the limitations. This is an advanced feature. +/// @ingroup shape +typedef struct b2ChainDef +{ + /// Use this to store application specific shape data. + void* userData; + + /// An array of at least 4 points. These are cloned and may be temporary. + const b2Vec2* points; + + /// The point count, must be 4 or more. + int count; + + /// Surface materials for each segment. These are cloned. + const b2SurfaceMaterial* materials; + + /// The material count. Must be 1 or count. This allows you to provide one + /// material for all segments or a unique material per segment. + int materialCount; + + /// Contact filtering data. + b2Filter filter; + + /// Indicates a closed chain formed by connecting the first and last points + bool isLoop; + + /// Enable sensors to detect this chain. False by default. + bool enableSensorEvents; + + /// Used internally to detect a valid definition. DO NOT SET. + int internalValue; +} b2ChainDef; + +/// Use this to initialize your chain definition +/// @ingroup shape +B2_API b2ChainDef b2DefaultChainDef( void ); + +//! @cond +/// Profiling data. Times are in milliseconds. +typedef struct b2Profile +{ + float step; + float pairs; + float collide; + float solve; + float mergeIslands; + float prepareStages; + float solveConstraints; + float prepareConstraints; + float integrateVelocities; + float warmStart; + float solveImpulses; + float integratePositions; + float relaxImpulses; + float applyRestitution; + float storeImpulses; + float splitIslands; + float transforms; + float hitEvents; + float refit; + float bullets; + float sleepIslands; + float sensors; +} b2Profile; + +/// Counters that give details of the simulation size. +typedef struct b2Counters +{ + int bodyCount; + int shapeCount; + int contactCount; + int jointCount; + int islandCount; + int stackUsed; + int staticTreeHeight; + int treeHeight; + int byteCount; + int taskCount; + int colorCounts[12]; +} b2Counters; +//! @endcond + +/// Joint type enumeration +/// +/// This is useful because all joint types use b2JointId and sometimes you +/// want to get the type of a joint. +/// @ingroup joint +typedef enum b2JointType +{ + b2_distanceJoint, + b2_filterJoint, + b2_motorJoint, + b2_mouseJoint, + b2_prismaticJoint, + b2_revoluteJoint, + b2_weldJoint, + b2_wheelJoint, +} b2JointType; + +/// Distance joint definition +/// +/// This requires defining an anchor point on both +/// bodies and the non-zero distance of the distance joint. The definition uses +/// local anchor points so that the initial configuration can violate the +/// constraint slightly. This helps when saving and loading a game. +/// @ingroup distance_joint +typedef struct b2DistanceJointDef +{ + /// The first attached body + b2BodyId bodyIdA; + + /// The second attached body + b2BodyId bodyIdB; + + /// The local anchor point relative to bodyA's origin + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin + b2Vec2 localAnchorB; + + /// The rest length of this joint. Clamped to a stable minimum value. + float length; + + /// Enable the distance constraint to behave like a spring. If false + /// then the distance joint will be rigid, overriding the limit and motor. + bool enableSpring; + + /// The spring linear stiffness Hertz, cycles per second + float hertz; + + /// The spring linear damping ratio, non-dimensional + float dampingRatio; + + /// Enable/disable the joint limit + bool enableLimit; + + /// Minimum length. Clamped to a stable minimum value. + float minLength; + + /// Maximum length. Must be greater than or equal to the minimum length. + float maxLength; + + /// Enable/disable the joint motor + bool enableMotor; + + /// The maximum motor force, usually in newtons + float maxMotorForce; + + /// The desired motor speed, usually in meters per second + float motorSpeed; + + /// Set this flag to true if the attached bodies should collide + bool collideConnected; + + /// User data pointer + void* userData; + + /// Used internally to detect a valid definition. DO NOT SET. + int internalValue; +} b2DistanceJointDef; + +/// Use this to initialize your joint definition +/// @ingroup distance_joint +B2_API b2DistanceJointDef b2DefaultDistanceJointDef( void ); + +/// A motor joint is used to control the relative motion between two bodies +/// +/// A typical usage is to control the movement of a dynamic body with respect to the ground. +/// @ingroup motor_joint +typedef struct b2MotorJointDef +{ + /// The first attached body + b2BodyId bodyIdA; + + /// The second attached body + b2BodyId bodyIdB; + + /// Position of bodyB minus the position of bodyA, in bodyA's frame + b2Vec2 linearOffset; + + /// The bodyB angle minus bodyA angle in radians + float angularOffset; + + /// The maximum motor force in newtons + float maxForce; + + /// The maximum motor torque in newton-meters + float maxTorque; + + /// Position correction factor in the range [0,1] + float correctionFactor; + + /// Set this flag to true if the attached bodies should collide + bool collideConnected; + + /// User data pointer + void* userData; + + /// Used internally to detect a valid definition. DO NOT SET. + int internalValue; +} b2MotorJointDef; + +/// Use this to initialize your joint definition +/// @ingroup motor_joint +B2_API b2MotorJointDef b2DefaultMotorJointDef( void ); + +/// A mouse joint is used to make a point on a body track a specified world point. +/// +/// This a soft constraint and allows the constraint to stretch without +/// applying huge forces. This also applies rotation constraint heuristic to improve control. +/// @ingroup mouse_joint +typedef struct b2MouseJointDef +{ + /// The first attached body. This is assumed to be static. + b2BodyId bodyIdA; + + /// The second attached body. + b2BodyId bodyIdB; + + /// The initial target point in world space + b2Vec2 target; + + /// Stiffness in hertz + float hertz; + + /// Damping ratio, non-dimensional + float dampingRatio; + + /// Maximum force, typically in newtons + float maxForce; + + /// Set this flag to true if the attached bodies should collide. + bool collideConnected; + + /// User data pointer + void* userData; + + /// Used internally to detect a valid definition. DO NOT SET. + int internalValue; +} b2MouseJointDef; + +/// Use this to initialize your joint definition +/// @ingroup mouse_joint +B2_API b2MouseJointDef b2DefaultMouseJointDef( void ); + +/// A filter joint is used to disable collision between two specific bodies. +/// +/// @ingroup filter_joint +typedef struct b2FilterJointDef +{ + /// The first attached body. + b2BodyId bodyIdA; + + /// The second attached body. + b2BodyId bodyIdB; + + /// User data pointer + void* userData; + + /// Used internally to detect a valid definition. DO NOT SET. + int internalValue; +} b2FilterJointDef; + +/// Use this to initialize your joint definition +/// @ingroup filter_joint +B2_API b2FilterJointDef b2DefaultFilterJointDef( void ); + +/// Prismatic joint definition +/// +/// This requires defining a line of motion using an axis and an anchor point. +/// The definition uses local anchor points and a local axis so that the initial +/// configuration can violate the constraint slightly. The joint translation is zero +/// when the local anchor points coincide in world space. +/// @ingroup prismatic_joint +typedef struct b2PrismaticJointDef +{ + /// The first attached body + b2BodyId bodyIdA; + + /// The second attached body + b2BodyId bodyIdB; + + /// The local anchor point relative to bodyA's origin + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin + b2Vec2 localAnchorB; + + /// The local translation unit axis in bodyA + b2Vec2 localAxisA; + + /// The constrained angle between the bodies: bodyB_angle - bodyA_angle + float referenceAngle; + + /// The target translation for the joint in meters. The spring-damper will drive + /// to this translation. + float targetTranslation; + + /// Enable a linear spring along the prismatic joint axis + bool enableSpring; + + /// The spring stiffness Hertz, cycles per second + float hertz; + + /// The spring damping ratio, non-dimensional + float dampingRatio; + + /// Enable/disable the joint limit + bool enableLimit; + + /// The lower translation limit + float lowerTranslation; + + /// The upper translation limit + float upperTranslation; + + /// Enable/disable the joint motor + bool enableMotor; + + /// The maximum motor force, typically in newtons + float maxMotorForce; + + /// The desired motor speed, typically in meters per second + float motorSpeed; + + /// Set this flag to true if the attached bodies should collide + bool collideConnected; + + /// User data pointer + void* userData; + + /// Used internally to detect a valid definition. DO NOT SET. + int internalValue; +} b2PrismaticJointDef; + +/// Use this to initialize your joint definition +/// @ingroupd prismatic_joint +B2_API b2PrismaticJointDef b2DefaultPrismaticJointDef( void ); + +/// Revolute joint definition +/// +/// This requires defining an anchor point where the bodies are joined. +/// The definition uses local anchor points so that the +/// initial configuration can violate the constraint slightly. You also need to +/// specify the initial relative angle for joint limits. This helps when saving +/// and loading a game. +/// The local anchor points are measured from the body's origin +/// rather than the center of mass because: +/// 1. you might not know where the center of mass will be +/// 2. if you add/remove shapes from a body and recompute the mass, the joints will be broken +/// @ingroup revolute_joint +typedef struct b2RevoluteJointDef +{ + /// The first attached body + b2BodyId bodyIdA; + + /// The second attached body + b2BodyId bodyIdB; + + /// The local anchor point relative to bodyA's origin + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin + b2Vec2 localAnchorB; + + /// The bodyB angle minus bodyA angle in the reference state (radians). + /// This defines the zero angle for the joint limit. + float referenceAngle; + + /// The target angle for the joint in radians. The spring-damper will drive + /// to this angle. + float targetAngle; + + /// Enable a rotational spring on the revolute hinge axis + bool enableSpring; + + /// The spring stiffness Hertz, cycles per second + float hertz; + + /// The spring damping ratio, non-dimensional + float dampingRatio; + + /// A flag to enable joint limits + bool enableLimit; + + /// The lower angle for the joint limit in radians. Minimum of -0.99*pi radians. + float lowerAngle; + + /// The upper angle for the joint limit in radians. Maximum of 0.99*pi radians. + float upperAngle; + + /// A flag to enable the joint motor + bool enableMotor; + + /// The maximum motor torque, typically in newton-meters + float maxMotorTorque; + + /// The desired motor speed in radians per second + float motorSpeed; + + /// Scale the debug draw + float drawSize; + + /// Set this flag to true if the attached bodies should collide + bool collideConnected; + + /// User data pointer + void* userData; + + /// Used internally to detect a valid definition. DO NOT SET. + int internalValue; +} b2RevoluteJointDef; + +/// Use this to initialize your joint definition. +/// @ingroup revolute_joint +B2_API b2RevoluteJointDef b2DefaultRevoluteJointDef( void ); + +/// Weld joint definition +/// +/// A weld joint connect to bodies together rigidly. This constraint provides springs to mimic +/// soft-body simulation. +/// @note The approximate solver in Box2D cannot hold many bodies together rigidly +/// @ingroup weld_joint +typedef struct b2WeldJointDef +{ + /// The first attached body + b2BodyId bodyIdA; + + /// The second attached body + b2BodyId bodyIdB; + + /// The local anchor point relative to bodyA's origin + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin + b2Vec2 localAnchorB; + + /// The bodyB angle minus bodyA angle in the reference state (radians) + /// todo maybe make this a b2Rot + float referenceAngle; + + /// Linear stiffness expressed as Hertz (cycles per second). Use zero for maximum stiffness. + float linearHertz; + + /// Angular stiffness as Hertz (cycles per second). Use zero for maximum stiffness. + float angularHertz; + + /// Linear damping ratio, non-dimensional. Use 1 for critical damping. + float linearDampingRatio; + + /// Linear damping ratio, non-dimensional. Use 1 for critical damping. + float angularDampingRatio; + + /// Set this flag to true if the attached bodies should collide + bool collideConnected; + + /// User data pointer + void* userData; + + /// Used internally to detect a valid definition. DO NOT SET. + int internalValue; +} b2WeldJointDef; + +/// Use this to initialize your joint definition +/// @ingroup weld_joint +B2_API b2WeldJointDef b2DefaultWeldJointDef( void ); + +/// Wheel joint definition +/// +/// This requires defining a line of motion using an axis and an anchor point. +/// The definition uses local anchor points and a local axis so that the initial +/// configuration can violate the constraint slightly. The joint translation is zero +/// when the local anchor points coincide in world space. +/// @ingroup wheel_joint +typedef struct b2WheelJointDef +{ + /// The first attached body + b2BodyId bodyIdA; + + /// The second attached body + b2BodyId bodyIdB; + + /// The local anchor point relative to bodyA's origin + b2Vec2 localAnchorA; + + /// The local anchor point relative to bodyB's origin + b2Vec2 localAnchorB; + + /// The local translation unit axis in bodyA + b2Vec2 localAxisA; + + /// Enable a linear spring along the local axis + bool enableSpring; + + /// Spring stiffness in Hertz + float hertz; + + /// Spring damping ratio, non-dimensional + float dampingRatio; + + /// Enable/disable the joint linear limit + bool enableLimit; + + /// The lower translation limit + float lowerTranslation; + + /// The upper translation limit + float upperTranslation; + + /// Enable/disable the joint rotational motor + bool enableMotor; + + /// The maximum motor torque, typically in newton-meters + float maxMotorTorque; + + /// The desired motor speed in radians per second + float motorSpeed; + + /// Set this flag to true if the attached bodies should collide + bool collideConnected; + + /// User data pointer + void* userData; + + /// Used internally to detect a valid definition. DO NOT SET. + int internalValue; +} b2WheelJointDef; + +/// Use this to initialize your joint definition +/// @ingroup wheel_joint +B2_API b2WheelJointDef b2DefaultWheelJointDef( void ); + +/// The explosion definition is used to configure options for explosions. Explosions +/// consider shape geometry when computing the impulse. +/// @ingroup world +typedef struct b2ExplosionDef +{ + /// Mask bits to filter shapes + uint64_t maskBits; + + /// The center of the explosion in world space + b2Vec2 position; + + /// The radius of the explosion + float radius; + + /// The falloff distance beyond the radius. Impulse is reduced to zero at this distance. + float falloff; + + /// Impulse per unit length. This applies an impulse according to the shape perimeter that + /// is facing the explosion. Explosions only apply to circles, capsules, and polygons. This + /// may be negative for implosions. + float impulsePerLength; +} b2ExplosionDef; + +/// Use this to initialize your explosion definition +/// @ingroup world +B2_API b2ExplosionDef b2DefaultExplosionDef( void ); + +/** + * @defgroup events Events + * World event types. + * + * Events are used to collect events that occur during the world time step. These events + * are then available to query after the time step is complete. This is preferable to callbacks + * because Box2D uses multithreaded simulation. + * + * Also when events occur in the simulation step it may be problematic to modify the world, which is + * often what applications want to do when events occur. + * + * With event arrays, you can scan the events in a loop and modify the world. However, you need to be careful + * that some event data may become invalid. There are several samples that show how to do this safely. + * + * @{ + */ + +/// A begin touch event is generated when a shape starts to overlap a sensor shape. +typedef struct b2SensorBeginTouchEvent +{ + /// The id of the sensor shape + b2ShapeId sensorShapeId; + + /// The id of the dynamic shape that began touching the sensor shape + b2ShapeId visitorShapeId; +} b2SensorBeginTouchEvent; + +/// An end touch event is generated when a shape stops overlapping a sensor shape. +/// These include things like setting the transform, destroying a body or shape, or changing +/// a filter. You will also get an end event if the sensor or visitor are destroyed. +/// Therefore you should always confirm the shape id is valid using b2Shape_IsValid. +typedef struct b2SensorEndTouchEvent +{ + /// The id of the sensor shape + /// @warning this shape may have been destroyed + /// @see b2Shape_IsValid + b2ShapeId sensorShapeId; + + /// The id of the dynamic shape that stopped touching the sensor shape + /// @warning this shape may have been destroyed + /// @see b2Shape_IsValid + b2ShapeId visitorShapeId; + +} b2SensorEndTouchEvent; + +/// Sensor events are buffered in the Box2D world and are available +/// as begin/end overlap event arrays after the time step is complete. +/// Note: these may become invalid if bodies and/or shapes are destroyed +typedef struct b2SensorEvents +{ + /// Array of sensor begin touch events + b2SensorBeginTouchEvent* beginEvents; + + /// Array of sensor end touch events + b2SensorEndTouchEvent* endEvents; + + /// The number of begin touch events + int beginCount; + + /// The number of end touch events + int endCount; +} b2SensorEvents; + +/// A begin touch event is generated when two shapes begin touching. +typedef struct b2ContactBeginTouchEvent +{ + /// Id of the first shape + b2ShapeId shapeIdA; + + /// Id of the second shape + b2ShapeId shapeIdB; + + /// The initial contact manifold. This is recorded before the solver is called, + /// so all the impulses will be zero. + b2Manifold manifold; +} b2ContactBeginTouchEvent; + +/// An end touch event is generated when two shapes stop touching. +/// You will get an end event if you do anything that destroys contacts previous to the last +/// world step. These include things like setting the transform, destroying a body +/// or shape, or changing a filter or body type. +typedef struct b2ContactEndTouchEvent +{ + /// Id of the first shape + /// @warning this shape may have been destroyed + /// @see b2Shape_IsValid + b2ShapeId shapeIdA; + + /// Id of the second shape + /// @warning this shape may have been destroyed + /// @see b2Shape_IsValid + b2ShapeId shapeIdB; +} b2ContactEndTouchEvent; + +/// A hit touch event is generated when two shapes collide with a speed faster than the hit speed threshold. +/// This may be reported for speculative contacts that have a confirmed impulse. +typedef struct b2ContactHitEvent +{ + /// Id of the first shape + b2ShapeId shapeIdA; + + /// Id of the second shape + b2ShapeId shapeIdB; + + /// Point where the shapes hit at the beginning of the time step. + /// This is a mid-point between the two surfaces. It could be at speculative + /// point where the two shapes were not touching at the beginning of the time step. + b2Vec2 point; + + /// Normal vector pointing from shape A to shape B + b2Vec2 normal; + + /// The speed the shapes are approaching. Always positive. Typically in meters per second. + float approachSpeed; +} b2ContactHitEvent; + +/// Contact events are buffered in the Box2D world and are available +/// as event arrays after the time step is complete. +/// Note: these may become invalid if bodies and/or shapes are destroyed +typedef struct b2ContactEvents +{ + /// Array of begin touch events + b2ContactBeginTouchEvent* beginEvents; + + /// Array of end touch events + b2ContactEndTouchEvent* endEvents; + + /// Array of hit events + b2ContactHitEvent* hitEvents; + + /// Number of begin touch events + int beginCount; + + /// Number of end touch events + int endCount; + + /// Number of hit events + int hitCount; +} b2ContactEvents; + +/// Body move events triggered when a body moves. +/// Triggered when a body moves due to simulation. Not reported for bodies moved by the user. +/// This also has a flag to indicate that the body went to sleep so the application can also +/// sleep that actor/entity/object associated with the body. +/// On the other hand if the flag does not indicate the body went to sleep then the application +/// can treat the actor/entity/object associated with the body as awake. +/// This is an efficient way for an application to update game object transforms rather than +/// calling functions such as b2Body_GetTransform() because this data is delivered as a contiguous array +/// and it is only populated with bodies that have moved. +/// @note If sleeping is disabled all dynamic and kinematic bodies will trigger move events. +typedef struct b2BodyMoveEvent +{ + b2Transform transform; + b2BodyId bodyId; + void* userData; + bool fellAsleep; +} b2BodyMoveEvent; + +/// Body events are buffered in the Box2D world and are available +/// as event arrays after the time step is complete. +/// Note: this data becomes invalid if bodies are destroyed +typedef struct b2BodyEvents +{ + /// Array of move events + b2BodyMoveEvent* moveEvents; + + /// Number of move events + int moveCount; +} b2BodyEvents; + +/// The contact data for two shapes. By convention the manifold normal points +/// from shape A to shape B. +/// @see b2Shape_GetContactData() and b2Body_GetContactData() +typedef struct b2ContactData +{ + b2ShapeId shapeIdA; + b2ShapeId shapeIdB; + b2Manifold manifold; +} b2ContactData; + +/**@}*/ + +/// Prototype for a contact filter callback. +/// This is called when a contact pair is considered for collision. This allows you to +/// perform custom logic to prevent collision between shapes. This is only called if +/// one of the two shapes has custom filtering enabled. +/// Notes: +/// - this function must be thread-safe +/// - this is only called if one of the two shapes has enabled custom filtering +/// - this is called only for awake dynamic bodies +/// Return false if you want to disable the collision +/// @see b2ShapeDef +/// @warning Do not attempt to modify the world inside this callback +/// @ingroup world +typedef bool b2CustomFilterFcn( b2ShapeId shapeIdA, b2ShapeId shapeIdB, void* context ); + +/// Prototype for a pre-solve callback. +/// This is called after a contact is updated. This allows you to inspect a +/// contact before it goes to the solver. If you are careful, you can modify the +/// contact manifold (e.g. modify the normal). +/// Notes: +/// - this function must be thread-safe +/// - this is only called if the shape has enabled pre-solve events +/// - this is called only for awake dynamic bodies +/// - this is not called for sensors +/// - the supplied manifold has impulse values from the previous step +/// Return false if you want to disable the contact this step +/// @warning Do not attempt to modify the world inside this callback +/// @ingroup world +typedef bool b2PreSolveFcn( b2ShapeId shapeIdA, b2ShapeId shapeIdB, b2Manifold* manifold, void* context ); + +/// Prototype callback for overlap queries. +/// Called for each shape found in the query. +/// @see b2World_OverlapABB +/// @return false to terminate the query. +/// @ingroup world +typedef bool b2OverlapResultFcn( b2ShapeId shapeId, void* context ); + +/// Prototype callback for ray and shape casts. +/// Called for each shape found in the query. You control how the ray cast +/// proceeds by returning a float: +/// return -1: ignore this shape and continue +/// return 0: terminate the ray cast +/// return fraction: clip the ray to this point +/// return 1: don't clip the ray and continue +/// A cast with initial overlap will return a zero fraction and a zero normal. +/// @param shapeId the shape hit by the ray +/// @param point the point of initial intersection +/// @param normal the normal vector at the point of intersection, zero for a shape cast with initial overlap +/// @param fraction the fraction along the ray at the point of intersection, zero for a shape cast with initial overlap +/// @param context the user context +/// @return -1 to filter, 0 to terminate, fraction to clip the ray for closest hit, 1 to continue +/// @see b2World_CastRay +/// @ingroup world +typedef float b2CastResultFcn( b2ShapeId shapeId, b2Vec2 point, b2Vec2 normal, float fraction, void* context ); + +// Used to collect collision planes for character movers. +// Return true to continue gathering planes. +typedef bool b2PlaneResultFcn( b2ShapeId shapeId, const b2PlaneResult* plane, void* context ); + +/// These colors are used for debug draw and mostly match the named SVG colors. +/// See https://www.rapidtables.com/web/color/index.html +/// https://johndecember.com/html/spec/colorsvg.html +/// https://upload.wikimedia.org/wikipedia/commons/2/2b/SVG_Recognized_color_keyword_names.svg +typedef enum b2HexColor +{ + b2_colorAliceBlue = 0xF0F8FF, + b2_colorAntiqueWhite = 0xFAEBD7, + b2_colorAqua = 0x00FFFF, + b2_colorAquamarine = 0x7FFFD4, + b2_colorAzure = 0xF0FFFF, + b2_colorBeige = 0xF5F5DC, + b2_colorBisque = 0xFFE4C4, + b2_colorBlack = 0x000000, + b2_colorBlanchedAlmond = 0xFFEBCD, + b2_colorBlue = 0x0000FF, + b2_colorBlueViolet = 0x8A2BE2, + b2_colorBrown = 0xA52A2A, + b2_colorBurlywood = 0xDEB887, + b2_colorCadetBlue = 0x5F9EA0, + b2_colorChartreuse = 0x7FFF00, + b2_colorChocolate = 0xD2691E, + b2_colorCoral = 0xFF7F50, + b2_colorCornflowerBlue = 0x6495ED, + b2_colorCornsilk = 0xFFF8DC, + b2_colorCrimson = 0xDC143C, + b2_colorCyan = 0x00FFFF, + b2_colorDarkBlue = 0x00008B, + b2_colorDarkCyan = 0x008B8B, + b2_colorDarkGoldenRod = 0xB8860B, + b2_colorDarkGray = 0xA9A9A9, + b2_colorDarkGreen = 0x006400, + b2_colorDarkKhaki = 0xBDB76B, + b2_colorDarkMagenta = 0x8B008B, + b2_colorDarkOliveGreen = 0x556B2F, + b2_colorDarkOrange = 0xFF8C00, + b2_colorDarkOrchid = 0x9932CC, + b2_colorDarkRed = 0x8B0000, + b2_colorDarkSalmon = 0xE9967A, + b2_colorDarkSeaGreen = 0x8FBC8F, + b2_colorDarkSlateBlue = 0x483D8B, + b2_colorDarkSlateGray = 0x2F4F4F, + b2_colorDarkTurquoise = 0x00CED1, + b2_colorDarkViolet = 0x9400D3, + b2_colorDeepPink = 0xFF1493, + b2_colorDeepSkyBlue = 0x00BFFF, + b2_colorDimGray = 0x696969, + b2_colorDodgerBlue = 0x1E90FF, + b2_colorFireBrick = 0xB22222, + b2_colorFloralWhite = 0xFFFAF0, + b2_colorForestGreen = 0x228B22, + b2_colorFuchsia = 0xFF00FF, + b2_colorGainsboro = 0xDCDCDC, + b2_colorGhostWhite = 0xF8F8FF, + b2_colorGold = 0xFFD700, + b2_colorGoldenRod = 0xDAA520, + b2_colorGray = 0x808080, + b2_colorGreen = 0x008000, + b2_colorGreenYellow = 0xADFF2F, + b2_colorHoneyDew = 0xF0FFF0, + b2_colorHotPink = 0xFF69B4, + b2_colorIndianRed = 0xCD5C5C, + b2_colorIndigo = 0x4B0082, + b2_colorIvory = 0xFFFFF0, + b2_colorKhaki = 0xF0E68C, + b2_colorLavender = 0xE6E6FA, + b2_colorLavenderBlush = 0xFFF0F5, + b2_colorLawnGreen = 0x7CFC00, + b2_colorLemonChiffon = 0xFFFACD, + b2_colorLightBlue = 0xADD8E6, + b2_colorLightCoral = 0xF08080, + b2_colorLightCyan = 0xE0FFFF, + b2_colorLightGoldenRodYellow = 0xFAFAD2, + b2_colorLightGray = 0xD3D3D3, + b2_colorLightGreen = 0x90EE90, + b2_colorLightPink = 0xFFB6C1, + b2_colorLightSalmon = 0xFFA07A, + b2_colorLightSeaGreen = 0x20B2AA, + b2_colorLightSkyBlue = 0x87CEFA, + b2_colorLightSlateGray = 0x778899, + b2_colorLightSteelBlue = 0xB0C4DE, + b2_colorLightYellow = 0xFFFFE0, + b2_colorLime = 0x00FF00, + b2_colorLimeGreen = 0x32CD32, + b2_colorLinen = 0xFAF0E6, + b2_colorMagenta = 0xFF00FF, + b2_colorMaroon = 0x800000, + b2_colorMediumAquaMarine = 0x66CDAA, + b2_colorMediumBlue = 0x0000CD, + b2_colorMediumOrchid = 0xBA55D3, + b2_colorMediumPurple = 0x9370DB, + b2_colorMediumSeaGreen = 0x3CB371, + b2_colorMediumSlateBlue = 0x7B68EE, + b2_colorMediumSpringGreen = 0x00FA9A, + b2_colorMediumTurquoise = 0x48D1CC, + b2_colorMediumVioletRed = 0xC71585, + b2_colorMidnightBlue = 0x191970, + b2_colorMintCream = 0xF5FFFA, + b2_colorMistyRose = 0xFFE4E1, + b2_colorMoccasin = 0xFFE4B5, + b2_colorNavajoWhite = 0xFFDEAD, + b2_colorNavy = 0x000080, + b2_colorOldLace = 0xFDF5E6, + b2_colorOlive = 0x808000, + b2_colorOliveDrab = 0x6B8E23, + b2_colorOrange = 0xFFA500, + b2_colorOrangeRed = 0xFF4500, + b2_colorOrchid = 0xDA70D6, + b2_colorPaleGoldenRod = 0xEEE8AA, + b2_colorPaleGreen = 0x98FB98, + b2_colorPaleTurquoise = 0xAFEEEE, + b2_colorPaleVioletRed = 0xDB7093, + b2_colorPapayaWhip = 0xFFEFD5, + b2_colorPeachPuff = 0xFFDAB9, + b2_colorPeru = 0xCD853F, + b2_colorPink = 0xFFC0CB, + b2_colorPlum = 0xDDA0DD, + b2_colorPowderBlue = 0xB0E0E6, + b2_colorPurple = 0x800080, + b2_colorRebeccaPurple = 0x663399, + b2_colorRed = 0xFF0000, + b2_colorRosyBrown = 0xBC8F8F, + b2_colorRoyalBlue = 0x4169E1, + b2_colorSaddleBrown = 0x8B4513, + b2_colorSalmon = 0xFA8072, + b2_colorSandyBrown = 0xF4A460, + b2_colorSeaGreen = 0x2E8B57, + b2_colorSeaShell = 0xFFF5EE, + b2_colorSienna = 0xA0522D, + b2_colorSilver = 0xC0C0C0, + b2_colorSkyBlue = 0x87CEEB, + b2_colorSlateBlue = 0x6A5ACD, + b2_colorSlateGray = 0x708090, + b2_colorSnow = 0xFFFAFA, + b2_colorSpringGreen = 0x00FF7F, + b2_colorSteelBlue = 0x4682B4, + b2_colorTan = 0xD2B48C, + b2_colorTeal = 0x008080, + b2_colorThistle = 0xD8BFD8, + b2_colorTomato = 0xFF6347, + b2_colorTurquoise = 0x40E0D0, + b2_colorViolet = 0xEE82EE, + b2_colorWheat = 0xF5DEB3, + b2_colorWhite = 0xFFFFFF, + b2_colorWhiteSmoke = 0xF5F5F5, + b2_colorYellow = 0xFFFF00, + b2_colorYellowGreen = 0x9ACD32, + + b2_colorBox2DRed = 0xDC3132, + b2_colorBox2DBlue = 0x30AEBF, + b2_colorBox2DGreen = 0x8CC924, + b2_colorBox2DYellow = 0xFFEE8C +} b2HexColor; + +/// This struct holds callbacks you can implement to draw a Box2D world. +/// This structure should be zero initialized. +/// @ingroup world +typedef struct b2DebugDraw +{ + /// Draw a closed polygon provided in CCW order. + void ( *DrawPolygonFcn )( const b2Vec2* vertices, int vertexCount, b2HexColor color, void* context ); + + /// Draw a solid closed polygon provided in CCW order. + void ( *DrawSolidPolygonFcn )( b2Transform transform, const b2Vec2* vertices, int vertexCount, float radius, b2HexColor color, + void* context ); + + /// Draw a circle. + void ( *DrawCircleFcn )( b2Vec2 center, float radius, b2HexColor color, void* context ); + + /// Draw a solid circle. + void ( *DrawSolidCircleFcn )( b2Transform transform, float radius, b2HexColor color, void* context ); + + /// Draw a solid capsule. + void ( *DrawSolidCapsuleFcn )( b2Vec2 p1, b2Vec2 p2, float radius, b2HexColor color, void* context ); + + /// Draw a line segment. + void ( *DrawSegmentFcn )( b2Vec2 p1, b2Vec2 p2, b2HexColor color, void* context ); + + /// Draw a transform. Choose your own length scale. + void ( *DrawTransformFcn )( b2Transform transform, void* context ); + + /// Draw a point. + void ( *DrawPointFcn )( b2Vec2 p, float size, b2HexColor color, void* context ); + + /// Draw a string in world space + void ( *DrawStringFcn )( b2Vec2 p, const char* s, b2HexColor color, void* context ); + + /// Bounds to use if restricting drawing to a rectangular region + b2AABB drawingBounds; + + /// Option to restrict drawing to a rectangular region. May suffer from unstable depth sorting. + bool useDrawingBounds; + + /// Option to draw shapes + bool drawShapes; + + /// Option to draw joints + bool drawJoints; + + /// Option to draw additional information for joints + bool drawJointExtras; + + /// Option to draw the bounding boxes for shapes + bool drawBounds; + + /// Option to draw the mass and center of mass of dynamic bodies + bool drawMass; + + /// Option to draw body names + bool drawBodyNames; + + /// Option to draw contact points + bool drawContacts; + + /// Option to visualize the graph coloring used for contacts and joints + bool drawGraphColors; + + /// Option to draw contact normals + bool drawContactNormals; + + /// Option to draw contact normal impulses + bool drawContactImpulses; + + /// Option to draw contact feature ids + bool drawContactFeatures; + + /// Option to draw contact friction impulses + bool drawFrictionImpulses; + + /// Option to draw islands as bounding boxes + bool drawIslands; + + /// User context that is passed as an argument to drawing callback functions + void* context; +} b2DebugDraw; + +/// Use this to initialize your drawing interface. This allows you to implement a sub-set +/// of the drawing functions. +B2_API b2DebugDraw b2DefaultDebugDraw( void ); diff --git a/TSE_Core/include/box2dd.lib b/TSE_Core/include/box2dd.lib new file mode 100644 index 0000000..3c1e3eb Binary files /dev/null and b/TSE_Core/include/box2dd.lib differ diff --git a/TSE_Core/include/box2dd.pdb b/TSE_Core/include/box2dd.pdb new file mode 100644 index 0000000..4ccc79e Binary files /dev/null and b/TSE_Core/include/box2dd.pdb differ diff --git a/TSE_Core/include/libbox2d.a b/TSE_Core/include/libbox2d.a new file mode 100644 index 0000000..d394d13 Binary files /dev/null and b/TSE_Core/include/libbox2d.a differ diff --git a/TSE_Core/src/BehaviourScripts/PhysicsObject.cpp b/TSE_Core/src/BehaviourScripts/PhysicsObject.cpp new file mode 100644 index 0000000..85d0725 --- /dev/null +++ b/TSE_Core/src/BehaviourScripts/PhysicsObject.cpp @@ -0,0 +1,117 @@ +#include "PhysicsObject.hpp" +#include "MathF.hpp" +#include "elements/Transformable.hpp" +#include "elements/PhysicsEngine.hpp" + +TSE::PhysicsObject::PhysicsObject(BodyType t, ColliderShape s, float d, float f, Vector3 cs) +{ + type = t; + shape = s; + density = d; + friction = f; + collidersize = cs; +} + +TSE::PhysicsObject::~PhysicsObject() +{ + PhysicsEngine::UnRegisterPhysicsObject(this); + if(b2Body_IsValid(bodyId)) + b2DestroyBody(bodyId); +} + +void TSE::PhysicsObject::UpdatePosition() +{ + b2Vec2 b2newPos = b2Body_GetPosition(bodyId); + if(lastPos.x != b2newPos.x || lastPos.y != b2newPos.y) + { + Vector3 newPos(b2newPos.x, b2newPos.y, lastPos.z); + lastPos = newPos; + Vector3 delta = baseObject->GlobalToLocalPosition(newPos); + baseObject->position = baseObject->position + delta; + } + float newRot = b2Rot_GetAngle(b2Body_GetRotation(bodyId)); + if(newRot != lastRot) + { + lastRot = newRot; + Vector3 euler = baseObject->GetEuler(); + euler.z = Rad2Deg(newRot); + } +} + +void TSE::PhysicsObject::OnUpdate() +{ + Vector3 globalPos = baseObject->GetGlobalPosition(); + float rot = Deg2Rad(baseObject->GetEuler().z); + if(globalPos != lastPos || rot != lastRot) + { + lastPos = globalPos; + lastRot = rot; + b2Vec2 pos; + pos.x = globalPos.x; + pos.y = globalPos.y; + b2Body_SetTransform(bodyId, pos, b2MakeRot(rot)); + b2Body_SetAwake(bodyId, true); + } +} + +void TSE::PhysicsObject::Start() +{ + b2WorldId& wid = PhysicsEngine::GetWorldId(); + + b2BodyDef def = b2DefaultBodyDef(); + b2Vec2 pos; + Vector3 globalPos = baseObject->GetGlobalPosition(); + pos.x = globalPos.x; + pos.y = globalPos.y; + def.position = pos; + lastPos = globalPos; + float rot = Deg2Rad(baseObject->GetEuler().z); + def.rotation = b2MakeRot(rot); + lastRot = rot; + b2BodyType b2type; + switch(type) + { + case BodyType::Dynamic: + b2type = b2_dynamicBody; + break; + case BodyType::Static: + b2type = b2_staticBody; + break; + } + def.type = b2type; + + bodyId = b2CreateBody(wid, &def); + + b2ShapeDef shapeDef = b2DefaultShapeDef(); + shapeDef.density = density; + shapeDef.material.friction = friction; + + b2Polygon b2shape; + b2Circle b2circle; + b2Capsule b2capsule; + + switch (shape) + { + case ColliderShape::Box: + b2shape = b2MakeBox(collidersize.x * 0.5f, collidersize.y * 0.5f); + b2CreatePolygonShape(bodyId, &shapeDef, &b2shape); + break; + case ColliderShape::RoundedBox: + b2shape = b2MakeRoundedBox(collidersize.x * 0.5f, collidersize.y * 0.5f, collidersize.z); + b2CreatePolygonShape(bodyId, &shapeDef, &b2shape); + break; + case ColliderShape::Circle: + b2circle.radius = collidersize.x; + b2CreateCircleShape(bodyId, &shapeDef, &b2circle); + break; + case ColliderShape::Capsule: + b2capsule.radius = collidersize.x; + b2capsule.center1 = {0, collidersize.y * 0.5f}; + b2capsule.center1 = {0, collidersize.y * -0.5f}; + b2CreateCapsuleShape(bodyId, &shapeDef, &b2capsule); + break; + + } + + PhysicsEngine::RegisterPhysicsObject(this); +} diff --git a/TSE_Core/src/BehaviourScripts/PhysicsObject.hpp b/TSE_Core/src/BehaviourScripts/PhysicsObject.hpp new file mode 100644 index 0000000..77052fc --- /dev/null +++ b/TSE_Core/src/BehaviourScripts/PhysicsObject.hpp @@ -0,0 +1,41 @@ +#pragma once + +#define PHYSICSOBJECT typeid(PhysicsObject).name() + +#include "box2d/box2d.h" +#include "enums/PhysicsEnums.hpp" +#include "elements/BehaviourScript.hpp" +#include "Vector3.hpp" + +namespace TSE +{ + class PhysicsObject: public BehaviourScript + { + private: + BodyType type; + ColliderShape shape; + float density; + float friction; + + //in case of box: x = x, y = y, z = unused + //in case of circle: x = radius, y = unused, z = unused + //in case of capsule: x = radius, y = height, z = unused + //in case of RoundedBox: x = x, y = y, z = radius + Vector3 collidersize; + + b2BodyId bodyId; + Vector3 lastPos; + float lastRot; + public: + PhysicsObject(BodyType type, ColliderShape shape, float density, float friction, Vector3 colliderSize); + ~PhysicsObject(); + + void UpdatePosition(); + void OnUpdate() override; + void Start() override; + inline const char* GetName() override + { + return "Physics Object"; + } + }; +} // namespace TSE diff --git a/TSE_Core/src/elements/PhysicsEngine.cpp b/TSE_Core/src/elements/PhysicsEngine.cpp new file mode 100644 index 0000000..93baa44 --- /dev/null +++ b/TSE_Core/src/elements/PhysicsEngine.cpp @@ -0,0 +1,57 @@ +#include "PhysicsEngine.hpp" +#include "utils/Time.hpp" + +void TSE::PhysicsEngine::InitPhysics(Vector2 gravity) +{ + b2WorldDef def = b2DefaultWorldDef(); + def.enableSleep = true; + b2Vec2 grav; + grav.x = gravity.x; + grav.y = gravity.y; + def.gravity = grav; + worldId = b2CreateWorld(&def); +} + +void TSE::PhysicsEngine::UpdatePhysics() +{ + if(elapsedTime >= timestep) + { + elapsedTime = 0; + b2World_Step(worldId, timestep, iterations); + //update physics objects + } + elapsedTime += Time::deltaTime(); + + for(auto obj : registeredObjects) + { + obj->UpdatePosition(); + } +} + +void TSE::PhysicsEngine::DeletePhysics() +{ + b2DestroyWorld(worldId); +} + +void TSE::PhysicsEngine::RegisterPhysicsObject(PhysicsObject *obj) +{ + registeredObjects.push_back(obj); +} + +void TSE::PhysicsEngine::UnRegisterPhysicsObject(PhysicsObject *obj) +{ + auto it = registeredObjects.begin(); + for (; it != registeredObjects.end(); it++) + { + if(*it == obj) + { + registeredObjects.erase(it); + return; + } + } +} + +b2WorldId &TSE::PhysicsEngine::GetWorldId() +{ + return worldId; +} diff --git a/TSE_Core/src/elements/PhysicsEngine.hpp b/TSE_Core/src/elements/PhysicsEngine.hpp new file mode 100644 index 0000000..816b68f --- /dev/null +++ b/TSE_Core/src/elements/PhysicsEngine.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "BehaviourScripts/PhysicsObject.hpp" +#include "box2d/box2d.h" +#include +#include "Vector2.hpp" + +namespace TSE +{ + class PhysicsEngine + { + private: + inline static std::vector registeredObjects = std::vector(); + inline static b2WorldId worldId = b2WorldId(); + inline static constexpr float timestep = 1.0f / 60.0f; + inline static const int iterations = 4; + inline static float elapsedTime = 0; + + public: + static void InitPhysics(Vector2 gravity); + static void UpdatePhysics(); + static void DeletePhysics(); + static void RegisterPhysicsObject(PhysicsObject* obj); + static void UnRegisterPhysicsObject(PhysicsObject* obj); + + static b2WorldId& GetWorldId(); + }; +} // namespace TSE diff --git a/TSE_Core/src/enums/PhysicsEnums.hpp b/TSE_Core/src/enums/PhysicsEnums.hpp new file mode 100644 index 0000000..3513f1a --- /dev/null +++ b/TSE_Core/src/enums/PhysicsEnums.hpp @@ -0,0 +1,16 @@ +#pragma once + +namespace TSE +{ + enum BodyType { + Static, + Dynamic, + }; + enum ColliderShape { + Box, + RoundedBox, + Circle, + Capsule, + }; + +} // namespace TSE