Box2D-0.1.0.0: upstream/src/physics_world.h
// SPDX-FileCopyrightText: 2023 Erin Catto
// SPDX-License-Identifier: MIT
#pragma once
typedef struct b2Recording b2Recording;
#include "arena_allocator.h"
#include "bitset.h"
#include "broad_phase.h"
#include "constraint_graph.h"
#include "container.h"
#include "id_pool.h"
#include "sensor.h"
#include "shape.h"
#include "solver_set.h"
#include "box2d/types.h"
b2DeclareArray( b2BodyMoveEvent );
b2DeclareArray( b2ContactBeginTouchEvent );
b2DeclareArray( b2ContactEndTouchEvent );
b2DeclareArray( b2ContactHitEvent );
b2DeclareArray( b2JointEvent );
b2DeclareArray( b2SensorBeginTouchEvent );
b2DeclareArray( b2SensorEndTouchEvent );
b2DeclareArray( b2TaskContext );
// Per thread task storage
typedef struct b2TaskContext
{
// Collect per thread sensor continuous hit events.
b2Array( b2SensorHit ) sensorHits;
// Broad-phase pairs.
b2Array( uint64_t ) pairKeys;
// These bits align with the contact id capacity and signal a change in contact status
b2BitSet contactStateBitSet;
// These bits align with the contact id capacity and signal a hit event.
b2BitSet hitEventBitSet;
// Fast-path flag: true when this worker set at least one bit in hitEventBitSet this step.
bool hasHitEvents;
// These bits align with the joint id capacity and signal a change in contact status
b2BitSet jointStateBitSet;
// Used to track bodies with shapes that have enlarged AABBs. This avoids having a bit array
// that is very large when there are many static shapes.
b2BitSet enlargedSimBitSet;
// Used to put islands to sleep
b2BitSet awakeIslandBitSet;
// Per worker split island candidate
float splitSleepTime;
int splitIslandId;
// Number of contacts recycled this step (collide pass).
int recycledContactCount;
} b2TaskContext;
// The world struct manages all physics entities, dynamic simulation, and asynchronous queries.
// The world also contains efficient memory management facilities.
typedef struct b2World
{
b2Stack stack;
b2BroadPhase broadPhase;
b2ConstraintGraph constraintGraph;
// The body id pool is used to allocate and recycle body ids. Body ids
// provide a stable identifier for users, but incur caches misses when used
// to access body data. Aligns with b2Body.
b2IdPool bodyIdPool;
// This is a sparse array that maps body ids to the body data
// stored in solver sets. As sims move within a set or across set.
// Indices come from id pool.
b2Array( b2Body ) bodies;
// Provides free list for solver sets.
b2IdPool solverSetIdPool;
// Solvers sets allow sims to be stored in contiguous arrays. The first
// set is all static sims. The second set is active sims. The third set is disabled
// sims. The remaining sets are sleeping islands.
b2Array( b2SolverSet ) solverSets;
// Used to create stable ids for joints
b2IdPool jointIdPool;
// This is a sparse array that maps joint ids to the joint data stored in the constraint graph
// or in the solver sets.
b2Array( b2Joint ) joints;
// Used to create stable ids for contacts
b2IdPool contactIdPool;
// This is a sparse array that maps contact ids to the contact data stored in the constraint graph
// or in the solver sets.
b2Array( b2Contact ) contacts;
// Used to create stable ids for islands
b2IdPool islandIdPool;
// Persistent islands
b2Array( b2Island ) islands;
b2IdPool shapeIdPool;
b2IdPool chainIdPool;
// These are sparse arrays that point into the pools above
b2Array( b2Shape ) shapes;
// Shape enlarged bounds (hot data split).
b2Array( b2AABB ) fatAABBs;
b2Array( b2ChainShape ) chainShapes;
// This is a dense array of sensor data.
b2Array( b2Sensor ) sensors;
// Per thread storage
b2Array( b2TaskContext ) taskContexts;
b2Array( b2SensorTaskContext ) sensorTaskContexts;
b2Array( b2BodyMoveEvent ) bodyMoveEvents;
b2Array( b2SensorBeginTouchEvent ) sensorBeginEvents;
b2Array( b2ContactBeginTouchEvent ) contactBeginEvents;
// End events are double buffered so that the user doesn't need to flush events
b2Array( b2SensorEndTouchEvent ) sensorEndEvents[2];
b2Array( b2ContactEndTouchEvent ) contactEndEvents[2];
int endEventArrayIndex;
b2Array( b2ContactHitEvent ) contactHitEvents;
b2Array( b2JointEvent ) jointEvents;
// todo consider deferred waking and impulses to make it possible
// to apply forces and impulses from multiple threads
// impulses must be deferred because sleeping bodies have no velocity state
// Problems:
// - multiple forces applied to the same body from multiple threads
// Used to track debug draw
b2BitSet debugBodySet;
b2BitSet debugJointSet;
b2BitSet debugContactSet;
b2BitSet debugIslandSet;
// Id that is incremented every time step
uint64_t stepIndex;
// Identify islands for splitting as follows:
// - I want to split islands so smaller islands can sleep
// - when a body comes to rest and its sleep timer trips, I can look at the island and flag it for splitting
// if it has removed constraints
// - islands that have removed constraints must be put split first because I don't want to wake bodies incorrectly
// - otherwise I can use the awake islands that have bodies wanting to sleep as the splitting candidates
// - if no bodies want to sleep then there is no reason to perform island splitting
int splitIslandId;
b2Vec2 gravity;
float hitEventThreshold;
float restitutionThreshold;
int restitutionIterations;
bool enableRestitutionPropagation;
float maxLinearSpeed;
float contactSpeed;
float contactHertz;
float contactDampingRatio;
float contactRecycleDistance;
b2FrictionCallbackFcn* frictionCallback;
b2RestitutionCallbackFcn* restitutionCallback;
uint16_t generation;
b2Profile profile;
b2Capacity maxCapacity;
b2PreSolveCallbackFcn* preSolveFcn;
b2PreContinuousCallbackFcn* preContinuousFcn;
void* preSolveContext;
b2CustomFilterCallbackFcn* customFilterFcn;
void* customFilterContext;
int workerCount;
int simdWidth;
b2EnqueueTaskCallbackFcn* enqueueTaskFcn;
b2FinishTaskCallbackFcn* finishTaskFcn;
void* userTaskContext;
void* userTreeTask;
struct b2Scheduler* scheduler;
void* userData;
b2Recording* recording; // NULL unless b2World_StartRecording is active, owned by the host
// Remember type step used for reporting forces and torques
// inverse sub-step
float inv_h;
// inverse full-step
float inv_dt;
int activeTaskCount;
int taskCount;
uint16_t worldId;
bool enableSleep;
bool locked;
bool enableWarmStarting;
bool enableContinuous;
bool inUse;
} b2World;
b2World* b2GetWorldFromId( b2WorldId id );
b2World* b2GetWorld( int index );
b2World* b2GetWorldLocked( int index );
// Union of the broad-phase root bounds across all body types. Returns false when no tree holds a
// proxy, so callers don't fold an empty world's origin into a running bounds.
bool b2ComputeWorldBounds( b2World* world, b2AABB* bounds );
void b2ValidateConnectivity( b2World* world );
void b2ValidateSolverSets( b2World* world );
void b2ValidateContacts( b2World* world );