Skip to content

Commit

Permalink
body movement events
Browse files Browse the repository at this point in the history
remove unneeded solver arrays
  • Loading branch information
erincatto committed Feb 25, 2024
1 parent 0076e58 commit ce351a3
Show file tree
Hide file tree
Showing 18 changed files with 164 additions and 111 deletions.
3 changes: 3 additions & 0 deletions include/box2d/box2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ B2_API void b2World_Step(b2WorldId worldId, float timeStep, int32_t subStepCount
/// Call this to draw shapes and other debug draw data. This is intentionally non-const.
B2_API void b2World_Draw(b2WorldId worldId, b2DebugDraw* debugDraw);

/// 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);

Expand Down
22 changes: 22 additions & 0 deletions include/box2d/event_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,25 @@ typedef struct b2ContactData
b2ShapeId shapeIdB;
b2Manifold manifold;
} b2ContactData;

/// Triggered when a body moves from 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.
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 date becomes invalid if bodies are destroyed
typedef struct b2BodyEvents
{
b2BodyMoveEvent* moveEvents;
int moveCount;
} b2BodyEvents;
38 changes: 31 additions & 7 deletions src/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,28 @@

#include <string.h>

void* b2CreateArray(int32_t elementSize, int32_t capacity)
void* b2CreateArray(int elementSize, int capacity)
{
void* result = (b2ArrayHeader*)b2Alloc(sizeof(b2ArrayHeader) + elementSize * capacity) + 1;
b2Array(result).count = 0;
b2Array(result).capacity = capacity;
return result;
}

void b2DestroyArray(void* a, int32_t elementSize)
void b2DestroyArray(void* a, int elementSize)
{
int32_t capacity = b2Array(a).capacity;
int32_t size = sizeof(b2ArrayHeader) + elementSize * capacity;
int capacity = b2Array(a).capacity;
int size = sizeof(b2ArrayHeader) + elementSize * capacity;
b2Free(((b2ArrayHeader*)a) - 1, size);
}

void b2Array_Grow(void** a, int32_t elementSize)
void b2Array_Grow(void** a, int elementSize)
{
int32_t capacity = b2Array(*a).capacity;
int capacity = b2Array(*a).capacity;
B2_ASSERT(capacity == b2Array(*a).count);

// grow by 50%
int32_t newCapacity = capacity + (capacity >> 1);
int newCapacity = capacity + (capacity >> 1);
newCapacity = newCapacity >= 2 ? newCapacity : 2;
void* tmp = *a;
*a = (b2ArrayHeader*)b2Alloc(sizeof(b2ArrayHeader) + elementSize * newCapacity) + 1;
Expand All @@ -38,3 +38,27 @@ void b2Array_Grow(void** a, int32_t elementSize)
memcpy(*a, tmp, capacity * elementSize);
b2DestroyArray(tmp, elementSize);
}

void b2Array_Resize(void** a, int elementSize, int count)
{
int capacity = b2Array(*a).capacity;
if (capacity >= count)
{
b2Array(*a).count = count;
return;
}

int originalCount = b2Array(*a).count;

// grow by 50%
int newCapacity = count + (count >> 1);
newCapacity = newCapacity >= 2 ? newCapacity : 2;
void* tmp = *a;
*a = (b2ArrayHeader*)b2Alloc(sizeof(b2ArrayHeader) + elementSize * newCapacity) + 1;
b2Array(*a).capacity = newCapacity;
b2Array(*a).count = count;

// copy existing elements
memcpy(*a, tmp, originalCount * elementSize);
b2DestroyArray(tmp, elementSize);
}
13 changes: 6 additions & 7 deletions src/array.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,18 @@

#include "core.h"

#include <stdint.h>

typedef struct b2ArrayHeader
{
int32_t count;
int32_t capacity;
int count;
int capacity;
} b2ArrayHeader;

#define b2Array(a) ((b2ArrayHeader*)(a))[-1]

void* b2CreateArray(int32_t elementSize, int32_t capacity);
void b2DestroyArray(void* a, int32_t elementSize);
void b2Array_Grow(void** a, int32_t elementSize);
void* b2CreateArray(int elementSize, int capacity);
void b2DestroyArray(void* a, int elementSize);
void b2Array_Grow(void** a, int elementSize);
void b2Array_Resize(void** a, int elementSize, int count);

#define b2Array_Check(a, index) B2_ASSERT(0 <= index && index < b2Array(a).count)

Expand Down
1 change: 1 addition & 0 deletions src/body.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ b2BodyId b2CreateBody(b2WorldId worldId, const b2BodyDef* def)
body->islandIndex = B2_NULL_INDEX;
body->islandPrev = B2_NULL_INDEX;
body->islandNext = B2_NULL_INDEX;
body->solverIndex = B2_NULL_INDEX;

if (body->isEnabled)
{
Expand Down
2 changes: 2 additions & 0 deletions src/body.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ typedef struct b2Body
int32_t islandPrev;
int32_t islandNext;

int32_t solverIndex;

float mass, invMass;

// Rotational inertia about the center of mass.
Expand Down
92 changes: 41 additions & 51 deletions src/contact_solver.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,13 @@ void b2PrepareOverflowContacts(b2StepContext* context)
b2World* world = context->world;
b2ConstraintGraph* graph = context->graph;
b2Contact* contacts = world->contacts;
const int32_t* bodyMap = context->bodyToSolverMap;
const b2BodyParam* params = context->bodyParams;
b2BodyState* states = context->bodyStates;
b2Body* bodies = world->bodies;
int32_t bodyCapacity = world->bodyPool.capacity;

b2ContactConstraint* constraints = graph->overflow.contactConstraints;
int32_t* contactIndices = graph->overflow.contactArray;
int32_t contactCount = b2Array(graph->overflow.contactArray).count;

// This is a dummy body to represent a static body because static bodies don't have a solver body.
b2BodyState dummyState = b2_identityBodyState;
b2BodyParam dummyParam = {0};

b2Softness contactSoftness = context->contactSoftness;
b2Softness staticSoftness = context->staticSoftness;

Expand All @@ -52,34 +47,34 @@ void b2PrepareOverflowContacts(b2StepContext* context)

B2_ASSERT(0 < pointCount && pointCount <= 2);

// resolve solver body indices
int32_t indexA = bodyMap[contact->edges[0].bodyIndex];
int32_t indexB = bodyMap[contact->edges[1].bodyIndex];
int32_t indexA = contact->edges[0].bodyIndex;
int32_t indexB = contact->edges[1].bodyIndex;
B2_ASSERT(0 <= indexA && indexA < bodyCapacity);
B2_ASSERT(0 <= indexB && indexB < bodyCapacity);

b2Body* bodyA = context->bodies + indexA;
b2Body* bodyB = context->bodies + indexB;
B2_ASSERT(bodyA->object.index == bodyA->object.next);
B2_ASSERT(bodyB->object.index == bodyB->object.next);

b2ContactConstraint* constraint = constraints + i;
constraint->contact = contact;
constraint->indexA = indexA;
constraint->indexB = indexB;
constraint->indexA = bodyA->solverIndex;
constraint->indexB = bodyB->solverIndex;
constraint->normal = manifold->normal;
constraint->friction = contact->friction;
constraint->restitution = contact->restitution;
constraint->pointCount = pointCount;

b2BodyState* stateA = indexA == B2_NULL_INDEX ? &dummyState : states + indexA;
const b2BodyParam* paramA = indexA == B2_NULL_INDEX ? &dummyParam : params + indexA;

b2BodyState* stateB = indexB == B2_NULL_INDEX ? &dummyState : states + indexB;
const b2BodyParam* paramB = indexB == B2_NULL_INDEX ? &dummyParam : params + indexB;

b2Vec2 vA = stateA->linearVelocity;
float wA = stateA->angularVelocity;
float mA = paramA->invMass;
float iA = paramA->invI;
b2Vec2 vA = bodyA->linearVelocity;
float wA = bodyA->angularVelocity;
float mA = bodyA->invMass;
float iA = bodyA->invI;

b2Vec2 vB = stateB->linearVelocity;
float wB = stateB->angularVelocity;
float mB = paramB->invMass;
float iB = paramB->invI;
b2Vec2 vB = bodyB->linearVelocity;
float wB = bodyB->angularVelocity;
float mB = bodyB->invMass;
float iB = bodyB->invI;

// Stiffer for static contacts to avoid bodies getting pushed through the ground
if (indexA == B2_NULL_INDEX || indexB == B2_NULL_INDEX)
Expand Down Expand Up @@ -568,19 +563,13 @@ static void b2ScatterBodies(b2BodyState* restrict bodies, int32_t* restrict indi
void b2PrepareContactsTask(int32_t startIndex, int32_t endIndex, b2StepContext* context)
{
b2TracyCZoneNC(prepare_contact, "Prepare Contact", b2_colorYellow, true);

b2World* world = context->world;
b2Contact* contacts = world->contacts;
const int32_t* bodyMap = context->bodyToSolverMap;
b2BodyState* states = context->bodyStates;
const b2BodyParam* params = context->bodyParams;
b2Body* bodies = world->bodies;
int32_t bodyCapacity = world->bodyPool.capacity;
b2ContactConstraintSIMD* constraints = context->contactConstraints;
const int32_t* contactIndices = context->contactIndices;

// dummy body to represent a static body
b2BodyState dummyState = b2_identityBodyState;
b2BodyParam dummyParam = {0};

b2Softness contactSoftness = context->contactSoftness;
b2Softness staticSoftness = context->staticSoftness;

Expand All @@ -600,28 +589,29 @@ void b2PrepareContactsTask(int32_t startIndex, int32_t endIndex, b2StepContext*
b2Contact* contact = contacts + contactIndex;

const b2Manifold* manifold = &contact->manifold;
int32_t indexA = bodyMap[contact->edges[0].bodyIndex];
int32_t indexB = bodyMap[contact->edges[1].bodyIndex];

constraint->indexA[j] = indexA;
constraint->indexB[j] = indexB;
int32_t indexA = contact->edges[0].bodyIndex;
int32_t indexB = contact->edges[1].bodyIndex;
B2_ASSERT(0 <= indexA && indexA < bodyCapacity);
B2_ASSERT(0 <= indexB && indexB < bodyCapacity);

b2BodyState* stateA = indexA == B2_NULL_INDEX ? &dummyState : states + indexA;
const b2BodyParam* paramA = indexA == B2_NULL_INDEX ? &dummyParam : params + indexA;
b2Body* bodyA = context->bodies + indexA;
b2Body* bodyB = context->bodies + indexB;
B2_ASSERT(bodyA->object.index == bodyA->object.next);
B2_ASSERT(bodyB->object.index == bodyB->object.next);

b2BodyState* stateB = indexB == B2_NULL_INDEX ? &dummyState : states + indexB;
const b2BodyParam* paramB = indexB == B2_NULL_INDEX ? &dummyParam : params + indexB;
constraint->indexA[j] = bodyA->solverIndex;
constraint->indexB[j] = bodyB->solverIndex;

b2Vec2 vA = stateA->linearVelocity;
float wA = stateA->angularVelocity;
b2Vec2 vA = bodyA->linearVelocity;
float wA = bodyA->angularVelocity;

b2Vec2 vB = stateB->linearVelocity;
float wB = stateB->angularVelocity;
b2Vec2 vB = bodyB->linearVelocity;
float wB = bodyB->angularVelocity;

float mA = paramA->invMass;
float iA = paramA->invI;
float mB = paramB->invMass;
float iB = paramB->invI;
float mA = bodyA->invMass;
float iA = bodyA->invI;
float mB = bodyB->invMass;
float iB = bodyB->invI;

((float*)&constraint->invMassA)[j] = mA;
((float*)&constraint->invMassB)[j] = mB;
Expand Down
4 changes: 2 additions & 2 deletions src/distance_joint.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ void b2PrepareDistanceJoint(b2Joint* base, b2StepContext* context)

b2DistanceJoint* joint = &base->distanceJoint;

joint->indexA = context->bodyToSolverMap[indexA];
joint->indexB = context->bodyToSolverMap[indexB];
joint->indexA = bodyA->solverIndex;
joint->indexB = bodyB->solverIndex;

// initial anchors in world space
joint->anchorA = b2RotateVector(bodyA->rotation, b2Sub(base->localOriginAnchorA, bodyA->localCenter));
Expand Down
4 changes: 2 additions & 2 deletions src/motor_joint.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ void b2PrepareMotorJoint(b2Joint* base, b2StepContext* context)
base->invIB = iB;

b2MotorJoint* joint = &base->motorJoint;
joint->indexA = context->bodyToSolverMap[indexA];
joint->indexB = context->bodyToSolverMap[indexB];
joint->indexA = bodyA->solverIndex;
joint->indexB = bodyB->solverIndex;

joint->anchorA = b2RotateVector(bodyA->rotation, b2Sub(base->localOriginAnchorA, bodyA->localCenter));
joint->anchorB = b2RotateVector(bodyB->rotation, b2Sub(base->localOriginAnchorB, bodyB->localCenter));
Expand Down
2 changes: 1 addition & 1 deletion src/mouse_joint.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ void b2PrepareMouseJoint(b2Joint* base, b2StepContext* context)
base->invIB = bodyB->invI;

b2MouseJoint* joint = &base->mouseJoint;
joint->indexB = context->bodyToSolverMap[indexB];
joint->indexB = bodyB->solverIndex;
joint->anchorB = b2RotateVector(bodyB->rotation, b2Sub(base->localOriginAnchorB, bodyB->localCenter));

joint->linearSoftness = b2MakeSoft(joint->hertz, joint->dampingRatio, context->h);
Expand Down
4 changes: 2 additions & 2 deletions src/prismatic_joint.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ void b2PreparePrismaticJoint(b2Joint* base, b2StepContext* context)

b2PrismaticJoint* joint = &base->prismaticJoint;

joint->indexA = context->bodyToSolverMap[indexA];
joint->indexB = context->bodyToSolverMap[indexB];
joint->indexA = bodyA->solverIndex;
joint->indexB = bodyB->solverIndex;

joint->anchorA = b2RotateVector(bodyA->rotation, b2Sub(base->localOriginAnchorA, bodyA->localCenter));
joint->anchorB = b2RotateVector(bodyB->rotation, b2Sub(base->localOriginAnchorB, bodyB->localCenter));
Expand Down
4 changes: 2 additions & 2 deletions src/revolute_joint.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ void b2PrepareRevoluteJoint(b2Joint* base, b2StepContext* context)

b2RevoluteJoint* joint = &base->revoluteJoint;

joint->indexA = context->bodyToSolverMap[indexA];
joint->indexB = context->bodyToSolverMap[indexB];
joint->indexA = bodyA->solverIndex;
joint->indexB = bodyB->solverIndex;

// initial anchors in world space
joint->anchorA = b2RotateVector(bodyA->rotation, b2Sub(base->localOriginAnchorA, bodyA->localCenter));
Expand Down
Loading

0 comments on commit ce351a3

Please sign in to comment.