Skip to content

Commit

Permalink
Contact events and access (#82)
Browse files Browse the repository at this point in the history
- weeble sample
- contact events
- contact access
- contact event sample
- forces and impulses
- shape geometry access
  • Loading branch information
erincatto authored Dec 17, 2023
1 parent b5994ad commit fc6c279
Show file tree
Hide file tree
Showing 41 changed files with 1,642 additions and 551 deletions.
16 changes: 6 additions & 10 deletions include/box2d/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,15 @@ typedef void b2FreeFcn(void* mem);
// Return 0 to
typedef int b2AssertFcn(const char* condition, const char* fileName, int lineNumber);

#ifdef __cplusplus
extern "C"
{
#endif

/// Default allocation functions
void b2SetAllocator(b2AllocFcn* allocFcn, b2FreeFcn* freeFcn);
BOX2D_API void b2SetAllocator(b2AllocFcn* allocFcn, b2FreeFcn* freeFcn);

/// Total bytes allocated by Box2D
uint32_t b2GetByteCount(void);

extern b2AssertFcn* Box2DAssertCallback;
BOX2D_API uint32_t b2GetByteCount(void);

#ifdef __cplusplus
}
extern "C" b2AssertFcn* Box2DAssertCallback;
#else
extern b2AssertFcn* Box2DAssertCallback;
#endif

98 changes: 77 additions & 21 deletions include/box2d/box2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,19 @@ BOX2D_API b2BodyId b2World_CreateBody(b2WorldId worldId, const b2BodyDef* def);
/// @warning This function is locked during callbacks.
BOX2D_API void b2World_DestroyBody(b2BodyId bodyId);

/// Get sensor events for the current time step. Do not store a reference to this data.
BOX2D_API b2SensorEvents b2World_GetSensorEvents(b2WorldId worldId);
BOX2D_API b2ContactEvents b2World_GetContactEvents(b2WorldId worldId);

BOX2D_API b2BodyType b2Body_GetType(b2BodyId bodyId);
BOX2D_API void b2Body_SetType(b2BodyId bodyId, b2BodyType type);

/// Get the user data stored in a body
BOX2D_API void* b2Body_GetUserData(b2BodyId bodyId);

BOX2D_API b2Vec2 b2Body_GetPosition(b2BodyId bodyId);
BOX2D_API float b2Body_GetAngle(b2BodyId bodyId);
BOX2D_API b2Transform b2Body_GetTransform(b2BodyId bodyId);
BOX2D_API void b2Body_SetTransform(b2BodyId bodyId, b2Vec2 position, float angle);

BOX2D_API b2Vec2 b2Body_GetLocalPoint(b2BodyId bodyId, b2Vec2 globalPoint);
Expand All @@ -57,11 +68,42 @@ BOX2D_API float b2Body_GetAngularVelocity(b2BodyId bodyId);
BOX2D_API void b2Body_SetLinearVelocity(b2BodyId bodyId, b2Vec2 linearVelocity);
BOX2D_API void b2Body_SetAngularVelocity(b2BodyId bodyId, float angularVelocity);

BOX2D_API b2BodyType b2Body_GetType(b2BodyId bodyId);
BOX2D_API void b2Body_SetType(b2BodyId bodyId, b2BodyType type);

/// Get the user data stored in a body
BOX2D_API void* b2Body_GetUserData(b2BodyId bodyId);
/// 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 wakes up the body.
/// @param force the world force vector, usually in Newtons (N).
/// @param point the world position of the point of application.
/// @param wake also wake up the body
BOX2D_API void b2Body_ApplyForce(b2BodyId bodyId, b2Vec2 force, b2Vec2 point, bool wake);

/// Apply a force to the center of mass. This wakes up the body.
/// @param force the world force vector, usually in Newtons (N).
/// @param wake also wake up the body
BOX2D_API void b2Body_ApplyForceToCenter(b2BodyId bodyId, b2Vec2 force, bool wake);

/// Apply a torque. This affects the angular velocity
/// without affecting the linear velocity of the center of mass.
/// @param torque about the z-axis (out of the screen), usually in N-m.
/// @param wake also wake up the body
BOX2D_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 wakes up the body.
/// @param impulse the world impulse vector, usually in N-seconds or kg-m/s.
/// @param point the world position of the point of application.
/// @param wake also wake up the body
BOX2D_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.
/// @param impulse the world impulse vector, usually in N-seconds or kg-m/s.
/// @param wake also wake up the body
BOX2D_API void b2Body_ApplyLinearImpulseToCenter(b2BodyId bodyId, b2Vec2 impulse, bool wake);

/// Apply an angular impulse.
/// @param impulse the angular impulse in units of kg*m*m/s
/// @param wake also wake up the body
BOX2D_API void b2Body_ApplyAngularImpulse(b2BodyId bodyId, float impulse, bool wake);

/// Get the mass of the body (kilograms)
BOX2D_API float b2Body_GetMass(b2BodyId bodyId);
Expand All @@ -78,10 +120,10 @@ BOX2D_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.
BOX2D_API void b2Body_SetMassData(b2MassData massData);
BOX2D_API void b2Body_SetMassData(b2BodyId bodyId, b2MassData massData);

/// Is this body awake?
BOX2D_API void b2Body_IsAwake(b2BodyId bodyId);
BOX2D_API bool b2Body_IsAwake(b2BodyId bodyId);

/// Wake a body from sleep. This wakes the entire island the body is touching.
BOX2D_API void b2Body_Wake(b2BodyId bodyId);
Expand All @@ -103,17 +145,43 @@ BOX2D_API b2ShapeId b2Body_CreateCapsule(b2BodyId bodyId, const b2ShapeDef* def,
BOX2D_API b2ShapeId b2Body_CreatePolygon(b2BodyId bodyId, const b2ShapeDef* def, const b2Polygon* polygon);
BOX2D_API void b2Body_DestroyShape(b2ShapeId shapeId);

BOX2D_API b2ChainId b2Body_CreateChain(b2BodyId bodyId, const b2ChainDef* def);
BOX2D_API void b2Body_DestroyChain(b2ChainId chainId);

/// Iterate over shapes on a body
BOX2D_API b2ShapeId b2Body_GetFirstShape(b2BodyId bodyId);
BOX2D_API b2ShapeId b2Body_GetNextShape(b2ShapeId shapeId);

BOX2D_API b2BodyId b2Shape_GetBody(b2ShapeId shapeId);
BOX2D_API void* b2Shape_GetUserData(b2ShapeId shapeId);
BOX2D_API bool b2Shape_TestPoint(b2ShapeId shapeId, b2Vec2 point);
BOX2D_API void b2Shape_SetFriction(b2ShapeId shapeId, float friction);
BOX2D_API void b2Shape_SetRestitution(b2ShapeId shapeId, float restitution);

BOX2D_API b2ChainId b2Body_CreateChain(b2BodyId bodyId, const b2ChainDef* def);
BOX2D_API void b2Body_DestroyChain(b2ChainId chainId);
BOX2D_API b2ShapeType b2Shape_GetType(b2ShapeId shapeId);
BOX2D_API const b2Circle* b2Shape_GetCircle(b2ShapeId shapeId);
BOX2D_API const b2Segment* b2Shape_GetSegment(b2ShapeId shapeId);
BOX2D_API const b2Polygon* b2Shape_GetSmoothSegment(b2ShapeId shapeId);
BOX2D_API const b2Capsule* b2Shape_GetCapsule(b2ShapeId shapeId);
BOX2D_API const b2Polygon* b2Shape_GetPolygon(b2ShapeId shapeId);

BOX2D_API void b2Chain_SetFriction(b2ChainId chainId, float friction);
BOX2D_API void b2Chain_SetRestitution(b2ChainId chainId, float restitution);

/// Contacts

/// Get the number of touching contacts on a body
BOX2D_API int32_t b2Body_GetContactCount(b2BodyId bodyId);

/// Get the touching contact data for a body
BOX2D_API int32_t b2Body_GetContactData(b2BodyId bodyId, b2ContactData* contactData, int32_t capacity);

/// Get the number of touching contacts on a shape. For efficiency, this may be larger than the actual number.
BOX2D_API int32_t b2Shape_GetContactCount(b2ShapeId shapeId);

/// Get the touching contact data for a shape. The provided shapeId will be either shapeIdA or shapeIdB on the contact data.
BOX2D_API int32_t b2Shape_GetContactData(b2ShapeId shapeId, b2ContactData* contactData, int32_t capacity);

/// Create a joint
BOX2D_API b2JointId b2World_CreateDistanceJoint(b2WorldId worldId, const b2DistanceJointDef* def);
BOX2D_API b2JointId b2World_CreateMouseJoint(b2WorldId worldId, const b2MouseJointDef* def);
Expand Down Expand Up @@ -180,18 +248,6 @@ BOX2D_API void b2World_CapsuleCast(b2WorldId worldId, const b2Capsule* capsule,
BOX2D_API void b2World_PolygonCast(b2WorldId worldId, const b2Polygon* polygon, b2Transform originTransform, b2Vec2 translation,
b2QueryFilter filter, b2RayResultFcn* fcn, void* context);

/// World events

/// Get sensor events for the current time step. Do not store a reference to this data.
BOX2D_API b2SensorEvents b2World_GetSensorEvents(b2WorldId worldId);

/// Id validation. These allow validation for up 64K allocations.
BOX2D_API bool b2World_IsValid(b2WorldId id);
BOX2D_API bool b2Body_IsValid(b2BodyId id);
BOX2D_API bool b2Shape_IsValid(b2ShapeId id);
BOX2D_API bool b2Chain_IsValid(b2ChainId id);
BOX2D_API bool b2Joint_IsValid(b2JointId id);

/// Advanced API for testing and special cases

/// Enable/disable sleep.
Expand Down
4 changes: 4 additions & 0 deletions include/box2d/debug_draw.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ typedef struct b2DebugDraw
bool drawJoints;
bool drawAABBs;
bool drawMass;
bool drawContacts;
bool drawGraphColors;
bool drawContactNormals;
bool drawContactImpulses;
bool drawFrictionImpulses;
void* context;
} b2DebugDraw;
36 changes: 36 additions & 0 deletions include/box2d/event_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#pragma once

#include "box2d/id.h"
#include "box2d/manifold.h"

#include <stdbool.h>
#include <stddef.h>
Expand All @@ -25,10 +26,45 @@ typedef struct 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
{
b2SensorBeginTouchEvent* beginEvents;
b2SensorEndTouchEvent* endEvents;
int beginCount;
int endCount;
} b2SensorEvents;

/// A begin touch event is generated when two shapes begin touching.
typedef struct b2ContactBeginTouchEvent
{
b2ShapeId shapeIdA;
b2ShapeId shapeIdB;
b2Manifold manifold;
} b2ContactBeginTouchEvent;

/// An end touch event is generated when two shapes stop touching.
typedef struct b2ContactEndTouchEvent
{
b2ShapeId shapeIdA;
b2ShapeId shapeIdB;
} b2ContactEndTouchEvent;

/// 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
{
b2ContactBeginTouchEvent* beginEvents;
b2ContactEndTouchEvent* endEvents;
int beginCount;
int endCount;
} b2ContactEvents;

/// This is the data you can access using a b2ContactId.
typedef struct b2ContactData
{
b2ShapeId shapeIdA;
b2ShapeId shapeIdB;
b2Manifold manifold;
} b2ContactData;
2 changes: 2 additions & 0 deletions include/box2d/geometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ BOX2D_API b2Polygon b2MakeRoundedBox(float hx, float hy, float radius);
BOX2D_API b2Polygon b2MakeOffsetBox(float hx, float hy, b2Vec2 center, float angle);
BOX2D_API b2Polygon b2MakeCapsule(b2Vec2 p1, b2Vec2 p2, float radius);

BOX2D_API b2Polygon b2TransformPolygon(b2Transform transform, const b2Polygon* polygon);

/// Compute mass properties
BOX2D_API b2MassData b2ComputeCircleMass(const b2Circle* shape, float density);
BOX2D_API b2MassData b2ComputeCapsuleMass(const b2Capsule* shape, float density);
Expand Down
27 changes: 25 additions & 2 deletions include/box2d/id.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

#pragma once

#include "api.h"

#include <stdbool.h>
#include <stdint.h>

/// These ids serve as handles to internal Box2D objects. These should be considered opaque data and passed by value.
Expand Down Expand Up @@ -31,6 +34,14 @@ typedef struct b2ShapeId
uint16_t revision;
} b2ShapeId;

/// References a contact instance
typedef struct b2ContactId
{
int32_t index;
int16_t world;
uint16_t revision;
} b2ContactId;

/// References a joint instance
typedef struct b2JointId
{
Expand All @@ -39,6 +50,7 @@ typedef struct b2JointId
uint16_t revision;
} b2JointId;

/// References a chain instances
typedef struct b2ChainId
{
int32_t index;
Expand All @@ -49,8 +61,19 @@ typedef struct b2ChainId
static const b2WorldId b2_nullWorldId = {-1, 0};
static const b2BodyId b2_nullBodyId = {-1, -1, 0};
static const b2ShapeId b2_nullShapeId = {-1, -1, 0};
static const b2ContactId b2_nullContactId = {-1, -1, 0};
static const b2JointId b2_nullJointId = {-1, -1, 0};
static const b2ChainId b2_nullChainId = {-1, -1, 0};

#define B2_IS_NULL(ID) (ID.index == -1)
#define B2_NON_NULL(ID) (ID.index != -1)
#define B2_IS_NULL(id) (id.index == -1)
#define B2_NON_NULL(id) (id.index != -1)

// Compare two ids for equality. Doesn't work for b2WorldId./
#define B2_ID_EQUALS(id1, id2) (id1.index == id2.index && id1.world == id2.world && id1.revision == id2.revision)

/// Id validation. These allow validation for up 64K allocations.
BOX2D_API bool b2World_IsValid(b2WorldId id);
BOX2D_API bool b2Body_IsValid(b2BodyId id);
BOX2D_API bool b2Shape_IsValid(b2ShapeId id);
BOX2D_API bool b2Chain_IsValid(b2ChainId id);
BOX2D_API bool b2Joint_IsValid(b2JointId id);
4 changes: 1 addition & 3 deletions include/box2d/manifold.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ typedef struct b2Polygon b2Polygon;
typedef struct b2Segment b2Segment;
typedef struct b2SmoothSegment b2SmoothSegment;

#define B2_MAKE_ID(A, B) ((uint8_t)(A) << 8 | (uint8_t)(B))

/// 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.
Expand All @@ -24,7 +22,7 @@ typedef struct b2ManifoldPoint
/// world coordinates of contact point
b2Vec2 point;

/// Body anchors used by solver
/// body anchors used by solver internally
b2Vec2 anchorA, anchorB;

/// the separation of the contact point, negative if penetrating
Expand Down
23 changes: 12 additions & 11 deletions include/box2d/math.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include "api.h"
#include "types.h"

#include <math.h>
Expand All @@ -24,9 +25,6 @@ static const b2Transform b2Transform_identity = {{0.0f, 0.0f}, {0.0f, 1.0f}};
static const b2Mat22 b2Mat22_zero = {{0.0f, 0.0f}, {0.0f, 0.0f}};
static const b2Mat33 b2Mat33_zero = {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}};

bool b2IsValid(float a);
bool b2IsValidVec2(b2Vec2 v);

/// Make a vector
static inline b2Vec2 b2MakeVec2(float x, float y)
{
Expand Down Expand Up @@ -167,14 +165,6 @@ static inline b2Vec2 b2Clamp(b2Vec2 v, b2Vec2 a, b2Vec2 b)
return c;
}

/// Convert this vector into a unit vector
b2Vec2 b2Normalize(b2Vec2 v);

/// This asserts of the vector is too short
b2Vec2 b2NormalizeChecked(b2Vec2 v);

b2Vec2 b2GetLengthAndNormalize(float* length, b2Vec2 v);

/// Get the length of this vector (the norm).
static inline float b2Length(b2Vec2 v)
{
Expand Down Expand Up @@ -417,3 +407,14 @@ static inline b2Vec3 b2Solve33(b2Mat33 A, b2Vec3 b)
#ifdef __cplusplus
}
#endif

BOX2D_API bool b2IsValid(float a);
BOX2D_API bool b2IsValidVec2(b2Vec2 v);

/// Convert this vector into a unit vector
BOX2D_API b2Vec2 b2Normalize(b2Vec2 v);

/// This asserts of the vector is too short
BOX2D_API b2Vec2 b2NormalizeChecked(b2Vec2 v);

BOX2D_API b2Vec2 b2GetLengthAndNormalize(float* length, b2Vec2 v);
Loading

0 comments on commit fc6c279

Please sign in to comment.