Skip to content

Commit 9314f30

Browse files
authored
Cross platform determinism (#773)
Cross platform determinism by implementing custom trigonometry functions 64-bit filter category and mask Fixed island bug Added `b2DefaultDebugDraw()`
1 parent 0e333ff commit 9314f30

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1012
-326
lines changed

.github/workflows/build.yml

+2-3
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,8 @@ jobs:
5252
- uses: actions/checkout@v4
5353

5454
- name: Configure CMake
55-
# some problem with simde
56-
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBOX2D_SAMPLES=OFF -DBOX2D_SANITIZE=ON -DBUILD_SHARED_LIBS=OFF
57-
# run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBOX2D_SAMPLES=OFF -DBUILD_SHARED_LIBS=OFF
55+
# run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBOX2D_SAMPLES=OFF -DBOX2D_SANITIZE=ON -DBUILD_SHARED_LIBS=OFF
56+
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBOX2D_SAMPLES=OFF -DBUILD_SHARED_LIBS=OFF
5857

5958
- name: Build
6059
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}

CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ include(FetchContent)
33
include(CMakeDependentOption)
44

55
project(box2d
6-
VERSION 3.0.1
6+
VERSION 3.1.0
77
DESCRIPTION "A 2D physics engine for games"
88
HOMEPAGE_URL "https://box2d.org"
99
LANGUAGES C CXX

benchmark/main.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ int main( int argc, char** argv )
183183

184184
b2WorldDef worldDef = b2DefaultWorldDef();
185185
worldDef.enableSleep = false;
186-
worldDef.enableContinous = enableContinuous;
186+
worldDef.enableContinuous = enableContinuous;
187187
worldDef.enqueueTask = EnqueueTask;
188188
worldDef.finishTask = FinishTask;
189189
worldDef.workerCount = threadCount;

benchmark/tumbler.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ b2WorldId Tumbler( b2WorldDef* worldDef )
2424
shapeDef.density = 50.0f;
2525

2626
b2Polygon polygon;
27-
polygon = b2MakeOffsetBox( 0.5f, 10.0f, ( b2Vec2 ){ 10.0f, 0.0f }, 0.0 );
27+
polygon = b2MakeOffsetBox( 0.5f, 10.0f, ( b2Vec2 ){ 10.0f, 0.0f }, b2Rot_identity );
2828
b2CreatePolygonShape( bodyId, &shapeDef, &polygon );
29-
polygon = b2MakeOffsetBox( 0.5f, 10.0f, ( b2Vec2 ){ -10.0f, 0.0f }, 0.0 );
29+
polygon = b2MakeOffsetBox( 0.5f, 10.0f, ( b2Vec2 ){ -10.0f, 0.0f }, b2Rot_identity );
3030
b2CreatePolygonShape( bodyId, &shapeDef, &polygon );
31-
polygon = b2MakeOffsetBox( 10.0f, 0.5f, ( b2Vec2 ){ 0.0f, 10.0f }, 0.0 );
31+
polygon = b2MakeOffsetBox( 10.0f, 0.5f, ( b2Vec2 ){ 0.0f, 10.0f }, b2Rot_identity );
3232
b2CreatePolygonShape( bodyId, &shapeDef, &polygon );
33-
polygon = b2MakeOffsetBox( 10.0f, 0.5f, ( b2Vec2 ){ 0.0f, -10.0f }, 0.0 );
33+
polygon = b2MakeOffsetBox( 10.0f, 0.5f, ( b2Vec2 ){ 0.0f, -10.0f }, b2Rot_identity );
3434
b2CreatePolygonShape( bodyId, &shapeDef, &polygon );
3535

3636
float motorSpeed = 25.0f;

docs/simulation.md

+4-5
Original file line numberDiff line numberDiff line change
@@ -455,8 +455,8 @@ scenarios that require altering the mass.
455455
b2MassData myMassData;
456456
myMassData.mass = 10.0f;
457457
myMassData.center = (b2Vec2){0.0f, 0.0f};
458-
myMassData.I = 100.0f;
459-
b2Body_SetMassData(myBodyId, &myMassData);
458+
myMassData.rotationalInertia = 100.0f;
459+
b2Body_SetMassData(myBodyId, myMassData);
460460
```
461461

462462
After setting a body's mass directly, you may wish to revert to the
@@ -470,7 +470,7 @@ The body's mass data is available through the following functions:
470470
471471
```c
472472
float mass = b2Body_GetMass(myBodyId);
473-
float inertia = b2Body_GetInertiaTensor(myBodyId);
473+
float inertia = b2Body_GetRotationalInertia(myBodyId);
474474
b2Vec2 localCenter b2Body_GetLocalCenterOfMass(myBodyId);
475475
b2MassData massData = b2Body_GetMassData(myBodyId);
476476
```
@@ -1448,8 +1448,7 @@ joint limit and a friction motor:
14481448
```c
14491449
b2Vec2 worldPivot = {10.0f, -4.0f};
14501450
b2Vec2 worldAxis = {1.0f, 0.0f};
1451-
b2PrismaticJointDef jointDef;
1452-
b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef();
1451+
b2PrismaticJointDef jointDef = b2DefaultPrismaticJointDef();
14531452
jointDef.bodyIdA = myBodyIdA;
14541453
jointDef.bodyIdB = myBodyIdB;
14551454
jointDef.localAnchorA = b2Body_GetLocalPoint(myBodyIdA, worldPivot);

include/box2d/base.h

+10-4
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,24 @@
55

66
#include <stdint.h>
77

8+
// clang-format off
9+
//
810
// Shared library macros
911
#if defined( _MSC_VER ) && defined( box2d_EXPORTS )
1012
// build the Windows DLL
1113
#define BOX2D_EXPORT __declspec( dllexport )
1214
#elif defined( _MSC_VER ) && defined( BOX2D_DLL )
13-
// using the Windows DLL
15+
// using the Windows DLL
1416
#define BOX2D_EXPORT __declspec( dllimport )
1517
#elif defined( box2d_EXPORTS )
16-
// building or using the Box2D shared library
18+
// building or using the Box2D shared library
1719
#define BOX2D_EXPORT __attribute__( ( visibility( "default" ) ) )
1820
#else
19-
// static library
21+
// static library
2022
#define BOX2D_EXPORT
2123
#endif
2224

2325
// C++ macros
24-
// clang-format off
2526
#ifdef __cplusplus
2627
#define B2_API extern "C" BOX2D_EXPORT
2728
#define B2_INLINE inline
@@ -104,4 +105,9 @@ B2_API float b2GetMilliseconds( const b2Timer* timer );
104105
B2_API float b2GetMillisecondsAndReset( b2Timer* timer );
105106
B2_API void b2SleepMilliseconds( int milliseconds );
106107
B2_API void b2Yield( void );
108+
109+
// Simple djb2 hash function for determinism testing
110+
#define B2_HASH_INIT 5381
111+
B2_API uint32_t b2Hash( uint32_t hash, const uint8_t* data, int count );
112+
107113
//! @endcond

include/box2d/box2d.h

+8-5
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,8 @@ B2_API void b2Body_ApplyAngularImpulse( b2BodyId bodyId, float impulse, bool wak
288288
/// Get the mass of the body, typically in kilograms
289289
B2_API float b2Body_GetMass( b2BodyId bodyId );
290290

291-
/// Get the inertia tensor of the body, typically in kg*m^2
292-
B2_API float b2Body_GetInertiaTensor( b2BodyId bodyId );
291+
/// Get the rotational inertia of the body, typically in kg*m^2
292+
B2_API float b2Body_GetRotationalInertia( b2BodyId bodyId );
293293

294294
/// Get the center of mass position of the body in local space
295295
B2_API b2Vec2 b2Body_GetLocalCenterOfMass( b2BodyId bodyId );
@@ -353,7 +353,7 @@ B2_API void b2Body_EnableSleep( b2BodyId bodyId, bool enableSleep );
353353
B2_API bool b2Body_IsSleepEnabled( b2BodyId bodyId );
354354

355355
/// Set the sleep threshold, typically in meters per second
356-
B2_API void b2Body_SetSleepThreshold( b2BodyId bodyId, float sleepVelocity );
356+
B2_API void b2Body_SetSleepThreshold( b2BodyId bodyId, float sleepThreshold );
357357

358358
/// Get the sleep threshold, typically in meters per second.
359359
B2_API float b2Body_GetSleepThreshold( b2BodyId bodyId );
@@ -674,10 +674,10 @@ B2_API void b2DistanceJoint_SetSpringHertz( b2JointId jointId, float hertz );
674674
B2_API void b2DistanceJoint_SetSpringDampingRatio( b2JointId jointId, float dampingRatio );
675675

676676
/// Get the spring Hertz
677-
B2_API float b2DistanceJoint_GetHertz( b2JointId jointId );
677+
B2_API float b2DistanceJoint_GetSpringHertz( b2JointId jointId );
678678

679679
/// Get the spring damping ratio
680-
B2_API float b2DistanceJoint_GetDampingRatio( b2JointId jointId );
680+
B2_API float b2DistanceJoint_GetSpringDampingRatio( b2JointId jointId );
681681

682682
/// Enable joint limit. The limit only works if the joint spring is enabled. Otherwise the joint is rigid
683683
/// and the limit has no effect.
@@ -893,6 +893,9 @@ B2_API b2JointId b2CreateRevoluteJoint( b2WorldId worldId, const b2RevoluteJoint
893893
/// Enable/disable the revolute joint spring
894894
B2_API void b2RevoluteJoint_EnableSpring( b2JointId jointId, bool enableSpring );
895895

896+
/// It the revolute angular spring enabled?
897+
B2_API bool b2RevoluteJoint_IsSpringEnabled( b2JointId jointId );
898+
896899
/// Set the revolute joint spring stiffness in Hertz
897900
B2_API void b2RevoluteJoint_SetSpringHertz( b2JointId jointId, float hertz );
898901

include/box2d/collision.h

+10-12
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ B2_API b2Polygon b2MakeBox( float hx, float hy );
192192
B2_API b2Polygon b2MakeRoundedBox( float hx, float hy, float radius );
193193

194194
/// Make an offset box, bypassing the need for a convex hull.
195-
B2_API b2Polygon b2MakeOffsetBox( float hx, float hy, b2Vec2 center, float angle );
195+
B2_API b2Polygon b2MakeOffsetBox( float hx, float hy, b2Vec2 center, b2Rot rotation );
196196

197197
/// Transform a polygon. This is useful for transferring a shape from one body to another.
198198
B2_API b2Polygon b2TransformPolygon( b2Transform transform, const b2Polygon* polygon );
@@ -589,21 +589,20 @@ B2_API b2Manifold b2CollideSmoothSegmentAndPolygon( const b2SmoothSegment* smoot
589589
*/
590590

591591
/// The default category bit for a tree proxy. Used for collision filtering.
592-
#define b2_defaultCategoryBits ( 0x00000001 )
592+
#define b2_defaultCategoryBits ( 1 )
593593

594594
/// Convenience mask bits to use when you don't need collision filtering and just want
595595
/// all results.
596-
#define b2_defaultMaskBits ( 0xFFFFFFFF )
596+
#define b2_defaultMaskBits ( UINT64_MAX )
597597

598598
/// A node in the dynamic tree. This is private data placed here for performance reasons.
599-
/// 16 + 16 + 8 + pad(8)
600599
typedef struct b2TreeNode
601600
{
602601
/// The node bounding box
603602
b2AABB aabb; // 16
604603

605604
/// Category bits for collision filtering
606-
uint32_t categoryBits; // 4
605+
uint64_t categoryBits; // 8
607606

608607
union
609608
{
@@ -631,7 +630,7 @@ typedef struct b2TreeNode
631630
bool enlarged; // 1
632631

633632
/// Padding for clarity
634-
char pad[9];
633+
char pad[5];
635634
} b2TreeNode;
636635

637636
/// The dynamic tree structure. This should be considered private data.
@@ -679,7 +678,7 @@ B2_API b2DynamicTree b2DynamicTree_Create( void );
679678
B2_API void b2DynamicTree_Destroy( b2DynamicTree* tree );
680679

681680
/// Create a proxy. Provide an AABB and a userData value.
682-
B2_API int32_t b2DynamicTree_CreateProxy( b2DynamicTree* tree, b2AABB aabb, uint32_t categoryBits, int32_t userData );
681+
B2_API int32_t b2DynamicTree_CreateProxy( b2DynamicTree* tree, b2AABB aabb, uint64_t categoryBits, int32_t userData );
683682

684683
/// Destroy a proxy. This asserts if the id is invalid.
685684
B2_API void b2DynamicTree_DestroyProxy( b2DynamicTree* tree, int32_t proxyId );
@@ -694,9 +693,8 @@ B2_API void b2DynamicTree_EnlargeProxy( b2DynamicTree* tree, int32_t proxyId, b2
694693
/// @return true if the query should continue
695694
typedef bool b2TreeQueryCallbackFcn( int32_t proxyId, int32_t userData, void* context );
696695

697-
/// Query an AABB for overlapping proxies. The callback class
698-
/// is called for each proxy that overlaps the supplied AABB.
699-
B2_API void b2DynamicTree_Query( const b2DynamicTree* tree, b2AABB aabb, uint32_t maskBits, b2TreeQueryCallbackFcn* callback,
696+
/// Query an AABB for overlapping proxies. The callback class is called for each proxy that overlaps the supplied AABB.
697+
B2_API void b2DynamicTree_Query( const b2DynamicTree* tree, b2AABB aabb, uint64_t maskBits, b2TreeQueryCallbackFcn* callback,
700698
void* context );
701699

702700
/// This function receives clipped raycast input for a proxy. The function
@@ -717,7 +715,7 @@ typedef float b2TreeRayCastCallbackFcn( const b2RayCastInput* input, int32_t pro
717715
/// @param maskBits filter bits: `bool accept = (maskBits & node->categoryBits) != 0;`
718716
/// @param callback a callback class that is called for each proxy that is hit by the ray
719717
/// @param context user context that is passed to the callback
720-
B2_API void b2DynamicTree_RayCast( const b2DynamicTree* tree, const b2RayCastInput* input, uint32_t maskBits,
718+
B2_API void b2DynamicTree_RayCast( const b2DynamicTree* tree, const b2RayCastInput* input, uint64_t maskBits,
721719
b2TreeRayCastCallbackFcn* callback, void* context );
722720

723721
/// This function receives clipped ray-cast input for a proxy. The function
@@ -737,7 +735,7 @@ typedef float b2TreeShapeCastCallbackFcn( const b2ShapeCastInput* input, int32_t
737735
/// @param maskBits filter bits: `bool accept = (maskBits & node->categoryBits) != 0;`
738736
/// @param callback a callback class that is called for each proxy that is hit by the shape
739737
/// @param context user context that is passed to the callback
740-
B2_API void b2DynamicTree_ShapeCast( const b2DynamicTree* tree, const b2ShapeCastInput* input, uint32_t maskBits,
738+
B2_API void b2DynamicTree_ShapeCast( const b2DynamicTree* tree, const b2ShapeCastInput* input, uint64_t maskBits,
741739
b2TreeShapeCastCallbackFcn* callback, void* context );
742740

743741
/// Validate this tree. For testing.

0 commit comments

Comments
 (0)