From c1f8317ffb887492d437cdd6e01b0861b9cb51d6 Mon Sep 17 00:00:00 2001 From: Erin Catto Date: Fri, 20 Sep 2024 21:16:04 -0700 Subject: [PATCH] more conversions --- src/array.h | 70 +++++++++++++++++++--------- src/broad_phase.c | 18 ++++---- src/broad_phase.h | 4 +- src/shape.c | 3 ++ src/shape.h | 3 ++ src/solver.c | 31 +++++++------ src/solver_set.c | 10 ++-- src/solver_set.h | 2 + src/stack_allocator.c | 15 +++--- src/stack_allocator.h | 6 ++- src/world.c | 105 +++++++++++++++++++++++------------------- src/world.h | 22 ++++++--- 12 files changed, 175 insertions(+), 114 deletions(-) diff --git a/src/array.h b/src/array.h index da2e25d79..c2664ebf0 100644 --- a/src/array.h +++ b/src/array.h @@ -49,15 +49,19 @@ void b2Array_Resize( void** a, int elementSize, int count ); // Macro based dynamic arrays // Pros // - type safe -// - debuggable (visible count and capacity) +// - array data debuggable (visible count and capacity) // - bounds checking // - forward declaration -// - simple +// - simple implementation +// - generates functions (like C++ templates) +// - functions have https://en.wikipedia.org/wiki/Sequence_point +// - avoids stretchy buffer dropped pointer update bugs // Cons -// - macros suck, however all array functions are real, type-safe functions +// - cannot debug +// - breaks code navigation // Array declaration that doesn't need the type T to be defined -#define B2_DECLARE_ARRAY( T, PREFIX ) \ +#define B2_ARRAY_DECLARE( T, PREFIX ) \ typedef struct \ { \ struct T* data; \ @@ -82,12 +86,19 @@ void b2Array_Resize( void** a, int elementSize, int count ); // Inline array functions that need the type T to be defined #define B2_ARRAY_INLINE( T, PREFIX ) \ + /* Resize */ \ + static inline void PREFIX##Array_Resize( PREFIX##Array* a, int count ) \ + { \ + PREFIX##Array_Reserve( a, count ); \ + a->count = count; \ + } \ + /* Get */ \ static inline T* PREFIX##Array_Get( PREFIX##Array* a, int index ) \ { \ B2_ASSERT( 0 <= index && index < a->count ); \ return a->data + index; \ } \ - \ + /* Add */ \ static inline T* PREFIX##Array_Add( PREFIX##Array* a ) \ { \ if ( a->count == a->capacity ) \ @@ -98,7 +109,7 @@ void b2Array_Resize( void** a, int elementSize, int count ); a->count += 1; \ return a->data + ( a->count - 1 ); \ } \ - \ + /* Push */ \ static inline void PREFIX##Array_Push( PREFIX##Array* a, T value ) \ { \ if ( a->count == a->capacity ) \ @@ -109,13 +120,13 @@ void b2Array_Resize( void** a, int elementSize, int count ); a->data[a->count] = value; \ a->count += 1; \ } \ - \ + /* Set */ \ static inline void PREFIX##Array_Set( PREFIX##Array* a, int index, T value ) \ { \ B2_ASSERT( 0 <= index && index < a->count ); \ a->data[index] = value; \ } \ - \ + /* RemoveSwap */ \ static inline int PREFIX##Array_RemoveSwap( PREFIX##Array* a, int index ) \ { \ B2_ASSERT( 0 <= index && index < a->count ); \ @@ -128,7 +139,7 @@ void b2Array_Resize( void** a, int elementSize, int count ); a->count -= 1; \ return movedIndex; \ } \ - \ + /* Pop */ \ static inline T PREFIX##Array_Pop( PREFIX##Array* a ) \ { \ B2_ASSERT( a->count > 0 ); \ @@ -136,7 +147,12 @@ void b2Array_Resize( void** a, int elementSize, int count ); a->count -= 1; \ return value; \ } \ - \ + /* Clear */ \ + static inline void PREFIX##Array_Clear( PREFIX##Array* a ) \ + { \ + a->count = 0; \ + } \ + /* ByteCount */ \ static inline int PREFIX##Array_ByteCount( PREFIX##Array* a ) \ { \ return (int)( a->capacity * sizeof( T ) ); \ @@ -144,6 +160,7 @@ void b2Array_Resize( void** a, int elementSize, int count ); // Array implementations to be instantiated in a source file where the type T is known #define B2_ARRAY_SOURCE( T, PREFIX ) \ + /* Create */ \ PREFIX##Array PREFIX##Array_Create( int capacity ) \ { \ PREFIX##Array a; \ @@ -152,7 +169,7 @@ void b2Array_Resize( void** a, int elementSize, int count ); a.capacity = capacity; \ return a; \ } \ - \ + /* Reserve */ \ void PREFIX##Array_Reserve( PREFIX##Array* a, int newCapacity ) \ { \ if ( newCapacity <= a->capacity ) \ @@ -162,7 +179,7 @@ void b2Array_Resize( void** a, int elementSize, int count ); a->data = b2GrowAlloc( a->data, a->capacity * sizeof( T ), newCapacity * sizeof( T ) ); \ a->capacity = newCapacity; \ } \ - \ + /* Destroy */ \ void PREFIX##Array_Destroy( PREFIX##Array* a ) \ { \ b2Free( a->data, a->capacity * sizeof( T ) ); \ @@ -174,12 +191,23 @@ void b2Array_Resize( void** a, int elementSize, int count ); B2_DECLARE_ARRAY_NATIVE( int, b2Int ); B2_ARRAY_INLINE( int, b2Int ); -B2_DECLARE_ARRAY( b2Body, b2Body ); -B2_DECLARE_ARRAY( b2BodySim, b2BodySim ); -B2_DECLARE_ARRAY( b2BodyState, b2BodyState ); -B2_DECLARE_ARRAY( b2Contact, b2Contact ); -B2_DECLARE_ARRAY( b2ContactSim, b2ContactSim ); -B2_DECLARE_ARRAY( b2Joint, b2Joint ); -B2_DECLARE_ARRAY( b2JointSim, b2JointSim ); -B2_DECLARE_ARRAY( b2Island, b2Island ); -B2_DECLARE_ARRAY( b2IslandSim, b2IslandSim ); +// Declare all the arrays +B2_ARRAY_DECLARE( b2Body, b2Body ); +B2_ARRAY_DECLARE( b2BodyMoveEvent, b2BodyMoveEvent ); +B2_ARRAY_DECLARE( b2BodySim, b2BodySim ); +B2_ARRAY_DECLARE( b2BodyState, b2BodyState ); +B2_ARRAY_DECLARE( b2ChainShape, b2ChainShape ); +B2_ARRAY_DECLARE( b2Contact, b2Contact ); +B2_ARRAY_DECLARE( b2ContactBeginTouchEvent, b2ContactBeginTouchEvent ); +B2_ARRAY_DECLARE( b2ContactEndTouchEvent, b2ContactEndTouchEvent ); +B2_ARRAY_DECLARE( b2ContactHitEvent, b2ContactHitEvent ); +B2_ARRAY_DECLARE( b2ContactSim, b2ContactSim ); +B2_ARRAY_DECLARE( b2Island, b2Island ); +B2_ARRAY_DECLARE( b2IslandSim, b2IslandSim ); +B2_ARRAY_DECLARE( b2Joint, b2Joint ); +B2_ARRAY_DECLARE( b2JointSim, b2JointSim ); +B2_ARRAY_DECLARE( b2SensorBeginTouchEvent, b2SensorBeginTouchEvent ); +B2_ARRAY_DECLARE( b2SensorEndTouchEvent, b2SensorEndTouchEvent ); +B2_ARRAY_DECLARE( b2Shape, b2Shape ); +B2_ARRAY_DECLARE( b2SolverSet, b2SolverSet ); +B2_ARRAY_DECLARE( b2TaskContext, b2TaskContext ); diff --git a/src/broad_phase.c b/src/broad_phase.c index fbbb09900..d9f32529c 100644 --- a/src/broad_phase.c +++ b/src/broad_phase.c @@ -34,7 +34,7 @@ void b2CreateBroadPhase( b2BroadPhase* bp ) bp->proxyCount = 0; bp->moveSet = b2CreateSet( 16 ); - bp->moveArray = b2CreateArray( sizeof( int ), 16 ); + bp->moveArray = b2IntArray_Create( 16 ); bp->moveResults = NULL; bp->movePairs = NULL; bp->movePairCapacity = 0; @@ -55,7 +55,7 @@ void b2DestroyBroadPhase( b2BroadPhase* bp ) } b2DestroySet( &bp->moveSet ); - b2DestroyArray( bp->moveArray, sizeof( int ) ); + b2IntArray_Destroy( &bp->moveArray ); b2DestroySet( &bp->pairSet ); memset( bp, 0, sizeof( b2BroadPhase ) ); @@ -75,12 +75,12 @@ static inline void b2UnBufferMove( b2BroadPhase* bp, int proxyKey ) { // Purge from move buffer. Linear search. // todo if I can iterate the move set then I don't need the moveArray - int count = b2Array( bp->moveArray ).count; + int count = bp->moveArray.count; for ( int i = 0; i < count; ++i ) { - if ( bp->moveArray[i] == proxyKey ) + if ( bp->moveArray.data[i] == proxyKey ) { - b2Array_RemoveSwap( bp->moveArray, i ); + b2IntArray_RemoveSwap( &bp->moveArray, i ); break; } } @@ -102,7 +102,7 @@ int b2BroadPhase_CreateProxy( b2BroadPhase* bp, b2BodyType proxyType, b2AABB aab void b2BroadPhase_DestroyProxy( b2BroadPhase* bp, int proxyKey ) { - B2_ASSERT( b2Array( bp->moveArray ).count == (int)bp->moveSet.count ); + B2_ASSERT( bp->moveArray.count == (int)bp->moveSet.count ); b2UnBufferMove( bp, proxyKey ); --bp->proxyCount; @@ -292,7 +292,7 @@ void b2FindPairsTask( int startIndex, int endIndex, uint32_t threadIndex, void* queryContext.moveResult = bp->moveResults + i; queryContext.moveResult->pairList = NULL; - int proxyKey = bp->moveArray[i]; + int proxyKey = bp->moveArray.data[i]; if ( proxyKey == B2_NULL_INDEX ) { // proxy was destroyed after it moved @@ -336,7 +336,7 @@ void b2UpdateBroadPhasePairs( b2World* world ) { b2BroadPhase* bp = &world->broadPhase; - int moveCount = b2Array( bp->moveArray ).count; + int moveCount = bp->moveArray.count; B2_ASSERT( moveCount == (int)bp->moveSet.count ); if ( moveCount == 0 ) @@ -422,7 +422,7 @@ void b2UpdateBroadPhasePairs( b2World* world ) // } // Reset move buffer - b2Array_Clear( bp->moveArray ); + b2IntArray_Clear( &bp->moveArray ); b2ClearSet( &bp->moveSet ); b2FreeStackItem( alloc, bp->movePairs ); diff --git a/src/broad_phase.h b/src/broad_phase.h index 07284ab26..ad53ef12d 100644 --- a/src/broad_phase.h +++ b/src/broad_phase.h @@ -34,7 +34,7 @@ typedef struct b2BroadPhase // todo implement a 32bit hash set for faster lookup // todo moveSet can grow quite large on the first time step and remain large b2HashSet moveSet; - int* moveArray; + b2IntArray moveArray; // These are the results from the pair query and are used to create new contacts // in deterministic order. @@ -78,6 +78,6 @@ static inline void b2BufferMove( b2BroadPhase* bp, int queryProxy ) bool alreadyAdded = b2AddKey( &bp->moveSet, queryProxy + 1 ); if ( alreadyAdded == false ) { - b2Array_Push( bp->moveArray, queryProxy ); + b2IntArray_Push( &bp->moveArray, queryProxy ); } } diff --git a/src/shape.c b/src/shape.c index 58426c719..7ee63d369 100644 --- a/src/shape.c +++ b/src/shape.c @@ -13,6 +13,9 @@ #include +B2_ARRAY_SOURCE( b2ChainShape, b2ChainShape ); +B2_ARRAY_SOURCE( b2Shape, b2Shape ); + static b2Shape* b2GetShape( b2World* world, b2ShapeId shapeId ) { int id = shapeId.index1 - 1; diff --git a/src/shape.h b/src/shape.h index fd8e398b7..e5efe65e4 100644 --- a/src/shape.h +++ b/src/shape.h @@ -80,3 +80,6 @@ b2CastOutput b2RayCastShape( const b2RayCastInput* input, const b2Shape* shape, b2CastOutput b2ShapeCastShape( const b2ShapeCastInput* input, const b2Shape* shape, b2Transform transform ); b2Transform b2GetOwnerTransform( b2World* world, b2Shape* shape ); + +B2_ARRAY_INLINE( b2ChainShape, b2ChainShape ); +B2_ARRAY_INLINE( b2Shape, b2Shape ); diff --git a/src/solver.c b/src/solver.c index 845cea31a..9c25a64b7 100644 --- a/src/solver.c +++ b/src/solver.c @@ -193,13 +193,16 @@ static void b2FinalizeBodiesTask( int startIndex, int endIndex, uint32_t threadI float invTimeStep = stepContext->inv_dt; uint16_t worldId = world->worldId; - b2BodyMoveEvent* moveEvents = world->bodyMoveEventArray; + + // The body move event array has should already have the correct size + B2_ASSERT( endIndex <= world->bodyMoveEventArray.count ); + b2BodyMoveEvent* moveEvents = world->bodyMoveEventArray.data; b2Island* islands = world->islandArray; - b2BitSet* enlargedSimBitSet = &world->taskContextArray[threadIndex].enlargedSimBitSet; - b2BitSet* awakeIslandBitSet = &world->taskContextArray[threadIndex].awakeIslandBitSet; - b2TaskContext* taskContext = world->taskContextArray + threadIndex; + b2BitSet* enlargedSimBitSet = &world->taskContextArray.data[threadIndex].enlargedSimBitSet; + b2BitSet* awakeIslandBitSet = &world->taskContextArray.data[threadIndex].awakeIslandBitSet; + b2TaskContext* taskContext = world->taskContextArray.data + threadIndex; bool enableContinuous = world->enableContinuous; @@ -1185,9 +1188,7 @@ void b2Solve( b2World* world, b2StepContext* stepContext ) // Deal with void** { - void* bodyMoveEventArray = world->bodyMoveEventArray; - b2Array_Resize( &bodyMoveEventArray, sizeof( b2BodyMoveEvent ), awakeBodyCount ); - world->bodyMoveEventArray = bodyMoveEventArray; + b2BodyMoveEventArray_Resize( &world->bodyMoveEventArray, awakeBodyCount ); } // Each worker receives at most M blocks of work. The workers may receive less than there is not sufficient work. @@ -1655,7 +1656,7 @@ void b2Solve( b2World* world, b2StepContext* stepContext ) int awakeIslandCount = awakeSet->islandsNew.count; for ( int i = 0; i < world->workerCount; ++i ) { - b2TaskContext* taskContext = world->taskContextArray + i; + b2TaskContext* taskContext = world->taskContextArray.data + i; b2SetBitCountAndClear( &taskContext->enlargedSimBitSet, awakeBodyCount ); b2SetBitCountAndClear( &taskContext->awakeIslandBitSet, awakeIslandCount ); taskContext->splitIslandId = B2_NULL_INDEX; @@ -1692,7 +1693,7 @@ void b2Solve( b2World* world, b2StepContext* stepContext ) { b2TracyCZoneNC( hit_events, "Hit", b2_colorVioletRed, true ); - B2_ASSERT( b2Array( world->contactHitArray ).count == 0 ); + B2_ASSERT( world->contactHitArray.count == 0 ); float threshold = world->hitEventThreshold; b2GraphColor* colors = world->constraintGraph.colors; @@ -1738,7 +1739,7 @@ void b2Solve( b2World* world, b2StepContext* stepContext ) event.shapeIdA = ( b2ShapeId ){ shapeA->id + 1, world->worldId, shapeA->revision }; event.shapeIdB = ( b2ShapeId ){ shapeB->id + 1, world->worldId, shapeB->revision }; - b2Array_Push( world->contactHitArray, event ); + b2ContactHitEventArray_Push( &world->contactHitArray, event ); } } } @@ -1763,10 +1764,10 @@ void b2Solve( b2World* world, b2StepContext* stepContext ) b2TracyCZoneNC( enlarge_proxies, "Enlarge Proxies", b2_colorDarkTurquoise, true ); // Gather bits for all sim bodies that have enlarged AABBs - b2BitSet* simBitSet = &world->taskContextArray[0].enlargedSimBitSet; + b2BitSet* simBitSet = &world->taskContextArray.data[0].enlargedSimBitSet; for ( int i = 1; i < world->workerCount; ++i ) { - b2InPlaceUnion( simBitSet, &world->taskContextArray[i].enlargedSimBitSet ); + b2InPlaceUnion( simBitSet, &world->taskContextArray.data[i].enlargedSimBitSet ); } // Enlarge broad-phase proxies and build move array @@ -1986,7 +1987,7 @@ void b2Solve( b2World* world, b2StepContext* stepContext ) float splitSleepTimer = 0.0f; for ( int i = 0; i < world->workerCount; ++i ) { - b2TaskContext* taskContext = world->taskContextArray + i; + b2TaskContext* taskContext = world->taskContextArray.data + i; if ( taskContext->splitIslandId != B2_NULL_INDEX && taskContext->splitSleepTime >= splitSleepTimer ) { B2_ASSERT( taskContext->splitSleepTime > 0.0f ); @@ -2002,10 +2003,10 @@ void b2Solve( b2World* world, b2StepContext* stepContext ) } } - b2BitSet* awakeIslandBitSet = &world->taskContextArray[0].awakeIslandBitSet; + b2BitSet* awakeIslandBitSet = &world->taskContextArray.data[0].awakeIslandBitSet; for ( int i = 1; i < world->workerCount; ++i ) { - b2InPlaceUnion( awakeIslandBitSet, &world->taskContextArray[i].awakeIslandBitSet ); + b2InPlaceUnion( awakeIslandBitSet, &world->taskContextArray.data[i].awakeIslandBitSet ); } // Need to process in reverse because this moves islands to sleeping solver sets. diff --git a/src/solver_set.c b/src/solver_set.c index 1c4ebf192..b38035f85 100644 --- a/src/solver_set.c +++ b/src/solver_set.c @@ -170,8 +170,6 @@ void b2TrySleepIsland( b2World* world, int islandId ) return; } - b2BodyMoveEvent* moveEvents = world->bodyMoveEventArray; - // island is sleeping // - create new sleeping solver set // - move island to sleeping solver set @@ -214,10 +212,10 @@ void b2TrySleepIsland( b2World* world, int islandId ) // It could happen the body is forced asleep before it ever moves. if ( body->bodyMoveIndex != B2_NULL_INDEX ) { - b2CheckIndex( moveEvents, body->bodyMoveIndex ); - B2_ASSERT( moveEvents[body->bodyMoveIndex].bodyId.index1 - 1 == bodyId ); - B2_ASSERT( moveEvents[body->bodyMoveIndex].bodyId.revision == body->revision ); - moveEvents[body->bodyMoveIndex].fellAsleep = true; + b2BodyMoveEvent* moveEvent = b2BodyMoveEventArray_Get( &world->bodyMoveEventArray, body->bodyMoveIndex ); + B2_ASSERT( moveEvent->bodyId.index1 - 1 == bodyId ); + B2_ASSERT( moveEvent->bodyId.revision == body->revision ); + moveEvent->fellAsleep = true; body->bodyMoveIndex = B2_NULL_INDEX; } diff --git a/src/solver_set.h b/src/solver_set.h index 76761b8d5..4a4626d7b 100644 --- a/src/solver_set.h +++ b/src/solver_set.h @@ -53,3 +53,5 @@ void b2MergeSolverSets( b2World* world, int setIndex1, int setIndex2 ); void b2TransferBody( b2World* world, b2SolverSet* targetSet, b2SolverSet* sourceSet, b2Body* body ); void b2TransferJoint( b2World* world, b2SolverSet* targetSet, b2SolverSet* sourceSet, b2Joint* joint ); + +B2_ARRAY_INLINE( b2SolverSet, b2SolverSet ); diff --git a/src/stack_allocator.c b/src/stack_allocator.c index be71cd235..bd255b404 100644 --- a/src/stack_allocator.c +++ b/src/stack_allocator.c @@ -16,6 +16,9 @@ typedef struct b2StackEntry bool usedMalloc; } b2StackEntry; +B2_ARRAY_INLINE( b2StackEntry, b2StackEntry ); +B2_ARRAY_SOURCE( b2StackEntry, b2StackEntry ); + b2StackAllocator b2CreateStackAllocator( int capacity ) { B2_ASSERT( capacity >= 0 ); @@ -25,13 +28,13 @@ b2StackAllocator b2CreateStackAllocator( int capacity ) allocator.allocation = 0; allocator.maxAllocation = 0; allocator.index = 0; - allocator.entries = b2CreateArray( sizeof( b2StackEntry ), 32 ); + allocator.entries = b2StackEntryArray_Create( 32 ); return allocator; } void b2DestroyStackAllocator( b2StackAllocator* allocator ) { - b2DestroyArray( allocator->entries, sizeof( b2StackEntry ) ); + b2StackEntryArray_Destroy( &allocator->entries ); b2Free( allocator->data, allocator->capacity ); } @@ -66,15 +69,15 @@ void* b2AllocateStackItem( b2StackAllocator* alloc, int size, const char* name ) alloc->maxAllocation = alloc->allocation; } - b2Array_Push( alloc->entries, entry ); + b2StackEntryArray_Push( &alloc->entries, entry ); return entry.data; } void b2FreeStackItem( b2StackAllocator* alloc, void* mem ) { - int entryCount = b2Array( alloc->entries ).count; + int entryCount = alloc->entries.count; B2_ASSERT( entryCount > 0 ); - b2StackEntry* entry = alloc->entries + ( entryCount - 1 ); + b2StackEntry* entry = alloc->entries.data + ( entryCount - 1 ); B2_ASSERT( mem == entry->data ); if ( entry->usedMalloc ) { @@ -85,7 +88,7 @@ void b2FreeStackItem( b2StackAllocator* alloc, void* mem ) alloc->index -= entry->size; } alloc->allocation -= entry->size; - b2Array_Pop( alloc->entries ); + b2StackEntryArray_Pop( &alloc->entries ); } void b2GrowStack( b2StackAllocator* alloc ) diff --git a/src/stack_allocator.h b/src/stack_allocator.h index 7d4fb05f7..e6d6149a2 100644 --- a/src/stack_allocator.h +++ b/src/stack_allocator.h @@ -3,6 +3,10 @@ #pragma once +#include "array.h" + +B2_ARRAY_DECLARE( b2StackEntry, b2StackEntry ); + // This is a stack-like arena allocator used for fast per step allocations. // You must nest allocate/free pairs. The code will B2_ASSERT // if you try to interleave multiple allocate/free pairs. @@ -17,7 +21,7 @@ typedef struct b2StackAllocator int allocation; int maxAllocation; - struct b2StackEntry* entries; + b2StackEntryArray entries; } b2StackAllocator; b2StackAllocator b2CreateStackAllocator( int capacity ); diff --git a/src/world.c b/src/world.c index bdd43d139..727ab1660 100644 --- a/src/world.c +++ b/src/world.c @@ -30,6 +30,14 @@ _Static_assert( b2_maxWorlds > 0, "must be 1 or more" ); b2World b2_worlds[b2_maxWorlds]; +B2_ARRAY_SOURCE( b2BodyMoveEvent, b2BodyMoveEvent ); +B2_ARRAY_SOURCE( b2ContactBeginTouchEvent, b2ContactBeginTouchEvent ); +B2_ARRAY_SOURCE( b2ContactEndTouchEvent, b2ContactEndTouchEvent ); +B2_ARRAY_SOURCE( b2ContactHitEvent, b2ContactHitEvent ); +B2_ARRAY_SOURCE( b2SensorBeginTouchEvent, b2SensorBeginTouchEvent ); +B2_ARRAY_SOURCE( b2SensorEndTouchEvent, b2SensorEndTouchEvent ); +B2_ARRAY_SOURCE( b2TaskContext, b2TaskContext ); + b2World* b2GetWorldFromId( b2WorldId id ) { B2_ASSERT( 1 <= id.index1 && id.index1 <= b2_maxWorlds ); @@ -149,12 +157,12 @@ b2WorldId b2CreateWorld( const b2WorldDef* def ) world->islandIdPool = b2CreateIdPool(); world->islandArray = b2CreateArray( sizeof( b2Island ), 8 ); - world->bodyMoveEventArray = b2CreateArray( sizeof( b2BodyMoveEvent ), 4 ); - world->sensorBeginEventArray = b2CreateArray( sizeof( b2SensorBeginTouchEvent ), 4 ); - world->sensorEndEventArray = b2CreateArray( sizeof( b2SensorEndTouchEvent ), 4 ); - world->contactBeginArray = b2CreateArray( sizeof( b2ContactBeginTouchEvent ), 4 ); - world->contactEndArray = b2CreateArray( sizeof( b2ContactEndTouchEvent ), 4 ); - world->contactHitArray = b2CreateArray( sizeof( b2ContactHitEvent ), 4 ); + world->bodyMoveEventArray = b2BodyMoveEventArray_Create( 4 ); + world->sensorBeginEventArray = b2SensorBeginTouchEventArray_Create( 4 ); + world->sensorEndEventArray = b2SensorEndTouchEventArray_Create( 4 ); + world->contactBeginArray = b2ContactBeginTouchEventArray_Create( 4 ); + world->contactEndArray = b2ContactEndTouchEventArray_Create( 4 ); + world->contactHitArray = b2ContactHitEventArray_Create( 4 ); world->stepIndex = 0; world->splitIslandId = B2_NULL_INDEX; @@ -190,12 +198,14 @@ b2WorldId b2CreateWorld( const b2WorldDef* def ) world->userTaskContext = NULL; } - world->taskContextArray = b2CreateArray( sizeof( b2TaskContext ), world->workerCount ); + world->taskContextArray = b2TaskContextArray_Create( world->workerCount ); + b2TaskContextArray_Resize( &world->taskContextArray, world->workerCount ); + for ( int i = 0; i < world->workerCount; ++i ) { - world->taskContextArray[i].contactStateBitSet = b2CreateBitSet( 1024 ); - world->taskContextArray[i].enlargedSimBitSet = b2CreateBitSet( 256 ); - world->taskContextArray[i].awakeIslandBitSet = b2CreateBitSet( 256 ); + world->taskContextArray.data[i].contactStateBitSet = b2CreateBitSet( 1024 ); + world->taskContextArray.data[i].enlargedSimBitSet = b2CreateBitSet( 256 ); + world->taskContextArray.data[i].awakeIslandBitSet = b2CreateBitSet( 256 ); } world->debugBodySet = b2CreateBitSet( 256 ); @@ -216,19 +226,19 @@ void b2DestroyWorld( b2WorldId worldId ) for ( int i = 0; i < world->workerCount; ++i ) { - b2DestroyBitSet( &world->taskContextArray[i].contactStateBitSet ); - b2DestroyBitSet( &world->taskContextArray[i].enlargedSimBitSet ); - b2DestroyBitSet( &world->taskContextArray[i].awakeIslandBitSet ); + b2DestroyBitSet( &world->taskContextArray.data[i].contactStateBitSet ); + b2DestroyBitSet( &world->taskContextArray.data[i].enlargedSimBitSet ); + b2DestroyBitSet( &world->taskContextArray.data[i].awakeIslandBitSet ); } - b2DestroyArray( world->taskContextArray, sizeof( b2TaskContext ) ); + b2TaskContextArray_Destroy( &world->taskContextArray ); - b2DestroyArray( world->bodyMoveEventArray, sizeof( b2BodyMoveEvent ) ); - b2DestroyArray( world->sensorBeginEventArray, sizeof( b2SensorBeginTouchEvent ) ); - b2DestroyArray( world->sensorEndEventArray, sizeof( b2SensorEndTouchEvent ) ); - b2DestroyArray( world->contactBeginArray, sizeof( b2ContactBeginTouchEvent ) ); - b2DestroyArray( world->contactEndArray, sizeof( b2ContactEndTouchEvent ) ); - b2DestroyArray( world->contactHitArray, sizeof( b2ContactHitEvent ) ); + b2BodyMoveEventArray_Destroy( &world->bodyMoveEventArray ); + b2SensorBeginTouchEventArray_Destroy( &world->sensorBeginEventArray ); + b2SensorEndTouchEventArray_Destroy( &world->sensorEndEventArray ); + b2ContactBeginTouchEventArray_Destroy( &world->contactBeginArray ); + b2ContactEndTouchEventArray_Destroy( &world->contactEndArray ); + b2ContactHitEventArray_Destroy( &world->contactHitArray ); int chainCapacity = b2Array( world->chainArray ).count; for ( int i = 0; i < chainCapacity; ++i ) @@ -293,7 +303,7 @@ static void b2CollideTask( int startIndex, int endIndex, uint32_t threadIndex, v b2StepContext* stepContext = context; b2World* world = stepContext->world; B2_ASSERT( threadIndex < world->workerCount ); - b2TaskContext* taskContext = world->taskContextArray + threadIndex; + b2TaskContext* taskContext = world->taskContextArray.data + threadIndex; b2ContactSim** contactSims = stepContext->contacts; b2Shape* shapes = world->shapeArray; b2Body* bodies = world->bodyArrayNew.data; @@ -469,7 +479,7 @@ static void b2Collide( b2StepContext* context ) int contactIdCapacity = b2GetIdCapacity( &world->contactIdPool ); for ( int i = 0; i < world->workerCount; ++i ) { - b2SetBitCountAndClear( &world->taskContextArray[i].contactStateBitSet, contactIdCapacity ); + b2SetBitCountAndClear( &world->taskContextArray.data[i].contactStateBitSet, contactIdCapacity ); } // Task should take at least 40us on a 4GHz CPU (10K cycles) @@ -489,10 +499,10 @@ static void b2Collide( b2StepContext* context ) b2TracyCZoneNC( contact_state, "Contact State", b2_colorCoral, true ); // Bitwise OR all contact bits - b2BitSet* bitSet = &world->taskContextArray[0].contactStateBitSet; + b2BitSet* bitSet = &world->taskContextArray.data[0].contactStateBitSet; for ( int i = 1; i < world->workerCount; ++i ) { - b2InPlaceUnion( bitSet, &world->taskContextArray[i].contactStateBitSet ); + b2InPlaceUnion( bitSet, &world->taskContextArray.data[i].contactStateBitSet ); } b2Contact* contacts = world->contactArray; @@ -544,7 +554,7 @@ static void b2Collide( b2StepContext* context ) if ( ( flags & b2_contactTouchingFlag ) != 0 && ( flags & b2_contactEnableContactEvents ) != 0 ) { b2ContactEndTouchEvent event = { shapeIdA, shapeIdB }; - b2Array_Push( world->contactEndArray, event ); + b2ContactEndTouchEventArray_Push( &world->contactEndArray, event ); } // Bounding boxes no longer overlap @@ -564,13 +574,13 @@ static void b2Collide( b2StepContext* context ) if ( shapeA->isSensor ) { b2SensorBeginTouchEvent event = { shapeIdA, shapeIdB }; - b2Array_Push( world->sensorBeginEventArray, event ); + b2SensorBeginTouchEventArray_Push( &world->sensorBeginEventArray, event ); } if ( shapeB->isSensor ) { b2SensorBeginTouchEvent event = { shapeIdB, shapeIdA }; - b2Array_Push( world->sensorBeginEventArray, event ); + b2SensorBeginTouchEventArray_Push( &world->sensorBeginEventArray, event ); } } @@ -583,7 +593,7 @@ static void b2Collide( b2StepContext* context ) if ( flags & b2_contactEnableContactEvents ) { b2ContactBeginTouchEvent event = { shapeIdA, shapeIdB }; - b2Array_Push( world->contactBeginArray, event ); + b2ContactBeginTouchEventArray_Push( &world->contactBeginArray, event ); } B2_ASSERT( contactSim->manifold.pointCount > 0 ); @@ -623,13 +633,13 @@ static void b2Collide( b2StepContext* context ) if ( shapeA->isSensor ) { b2SensorEndTouchEvent event = { shapeIdA, shapeIdB }; - b2Array_Push( world->sensorEndEventArray, event ); + b2SensorEndTouchEventArray_Push( &world->sensorEndEventArray, event ); } if ( shapeB->isSensor ) { b2SensorEndTouchEvent event = { shapeIdB, shapeIdA }; - b2Array_Push( world->sensorEndEventArray, event ); + b2SensorEndTouchEventArray_Push( &world->sensorEndEventArray, event ); } } } @@ -641,7 +651,7 @@ static void b2Collide( b2StepContext* context ) if ( contact->flags & b2_contactEnableContactEvents ) { b2ContactEndTouchEvent event = { shapeIdA, shapeIdB }; - b2Array_Push( world->contactEndArray, event ); + b2ContactEndTouchEventArray_Push( &world->contactEndArray, event ); } B2_ASSERT( contactSim->manifold.pointCount == 0 ); @@ -680,12 +690,12 @@ void b2World_Step( b2WorldId worldId, float timeStep, int subStepCount ) // Prepare to capture events // Ensure user does not access stale data if there is an early return - b2Array_Clear( world->bodyMoveEventArray ); - b2Array_Clear( world->sensorBeginEventArray ); - b2Array_Clear( world->sensorEndEventArray ); - b2Array_Clear( world->contactBeginArray ); - b2Array_Clear( world->contactEndArray ); - b2Array_Clear( world->contactHitArray ); + b2BodyMoveEventArray_Clear( &world->bodyMoveEventArray ); + b2SensorBeginTouchEventArray_Clear( &world->sensorBeginEventArray ); + b2SensorEndTouchEventArray_Clear( &world->sensorEndEventArray ); + b2ContactBeginTouchEventArray_Clear( &world->contactBeginArray ); + b2ContactEndTouchEventArray_Clear( &world->contactEndArray ); + b2ContactHitEventArray_Clear( &world->contactHitArray ); world->profile = ( b2Profile ){ 0 }; @@ -1363,8 +1373,8 @@ b2BodyEvents b2World_GetBodyEvents( b2WorldId worldId ) return ( b2BodyEvents ){ 0 }; } - int count = b2Array( world->bodyMoveEventArray ).count; - b2BodyEvents events = { world->bodyMoveEventArray, count }; + int count = world->bodyMoveEventArray.count; + b2BodyEvents events = { world->bodyMoveEventArray.data, count }; return events; } @@ -1377,10 +1387,10 @@ b2SensorEvents b2World_GetSensorEvents( b2WorldId worldId ) return ( b2SensorEvents ){ 0 }; } - int beginCount = b2Array( world->sensorBeginEventArray ).count; - int endCount = b2Array( world->sensorEndEventArray ).count; + int beginCount = world->sensorBeginEventArray.count; + int endCount = world->sensorEndEventArray.count; - b2SensorEvents events = { world->sensorBeginEventArray, world->sensorEndEventArray, beginCount, endCount }; + b2SensorEvents events = { world->sensorBeginEventArray.data, world->sensorEndEventArray.data, beginCount, endCount }; return events; } @@ -1393,12 +1403,13 @@ b2ContactEvents b2World_GetContactEvents( b2WorldId worldId ) return ( b2ContactEvents ){ 0 }; } - int beginCount = b2Array( world->contactBeginArray ).count; - int endCount = b2Array( world->contactEndArray ).count; - int hitCount = b2Array( world->contactHitArray ).count; + int beginCount = world->contactBeginArray.count; + int endCount = world->contactEndArray.count; + int hitCount = world->contactHitArray.count; b2ContactEvents events = { - world->contactBeginArray, world->contactEndArray, world->contactHitArray, beginCount, endCount, hitCount }; + world->contactBeginArray.data, world->contactEndArray.data, world->contactHitArray.data, beginCount, endCount, hitCount, + }; return events; } @@ -1751,7 +1762,7 @@ void b2World_DumpMemoryStats( b2WorldId worldId ) fprintf( file, "dynamic tree: %d\n", b2DynamicTree_GetByteCount( world->broadPhase.trees + b2_dynamicBody ) ); b2HashSet* moveSet = &world->broadPhase.moveSet; fprintf( file, "moveSet: %d (%d, %d)\n", b2GetHashSetBytes( moveSet ), moveSet->count, moveSet->capacity ); - fprintf( file, "moveArray: %d\n", b2GetArrayBytes( world->broadPhase.moveArray, sizeof( int ) ) ); + fprintf( file, "moveArray: %d\n", b2IntArray_ByteCount( &world->broadPhase.moveArray ) ); b2HashSet* pairSet = &world->broadPhase.pairSet; fprintf( file, "pairSet: %d (%d, %d)\n", b2GetHashSetBytes( pairSet ), pairSet->count, pairSet->capacity ); fprintf( file, "\n" ); diff --git a/src/world.h b/src/world.h index 6f972eeff..d5de73f4b 100644 --- a/src/world.h +++ b/src/world.h @@ -96,14 +96,14 @@ typedef struct b2World struct b2ChainShape* chainArray; // Per thread storage - b2TaskContext* taskContextArray; + b2TaskContextArray taskContextArray; - struct b2BodyMoveEvent* bodyMoveEventArray; - struct b2SensorBeginTouchEvent* sensorBeginEventArray; - struct b2SensorEndTouchEvent* sensorEndEventArray; - struct b2ContactBeginTouchEvent* contactBeginArray; - struct b2ContactEndTouchEvent* contactEndArray; - struct b2ContactHitEvent* contactHitArray; + b2BodyMoveEventArray bodyMoveEventArray; + b2SensorBeginTouchEventArray sensorBeginEventArray; + b2SensorEndTouchEventArray sensorEndEventArray; + b2ContactBeginTouchEventArray contactBeginArray; + b2ContactEndTouchEventArray contactEndArray; + b2ContactHitEventArray contactHitArray; // Used to track debug draw b2BitSet debugBodySet; @@ -170,3 +170,11 @@ b2World* b2GetWorldLocked( int index ); void b2ValidateConnectivity( b2World* world ); void b2ValidateSolverSets( b2World* world ); void b2ValidateContacts( b2World* world ); + +B2_ARRAY_INLINE( b2BodyMoveEvent, b2BodyMoveEvent ); +B2_ARRAY_INLINE( b2ContactBeginTouchEvent, b2ContactBeginTouchEvent ); +B2_ARRAY_INLINE( b2ContactEndTouchEvent, b2ContactEndTouchEvent ); +B2_ARRAY_INLINE( b2ContactHitEvent, b2ContactHitEvent ); +B2_ARRAY_INLINE( b2SensorBeginTouchEvent, b2SensorBeginTouchEvent ); +B2_ARRAY_INLINE( b2SensorEndTouchEvent, b2SensorEndTouchEvent ); +B2_ARRAY_INLINE( b2TaskContext, b2TaskContext );