Skip to content

Commit

Permalink
Cross platform determinism (#773)
Browse files Browse the repository at this point in the history
Cross platform determinism by implementing custom trigonometry functions
64-bit filter category and mask
Fixed island bug
Added `b2DefaultDebugDraw()`
  • Loading branch information
erincatto authored Aug 29, 2024
1 parent 0e333ff commit 9314f30
Show file tree
Hide file tree
Showing 48 changed files with 1,012 additions and 326 deletions.
5 changes: 2 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,8 @@ jobs:
- uses: actions/checkout@v4

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

- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ include(FetchContent)
include(CMakeDependentOption)

project(box2d
VERSION 3.0.1
VERSION 3.1.0
DESCRIPTION "A 2D physics engine for games"
HOMEPAGE_URL "https://box2d.org"
LANGUAGES C CXX
Expand Down
2 changes: 1 addition & 1 deletion benchmark/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ int main( int argc, char** argv )

b2WorldDef worldDef = b2DefaultWorldDef();
worldDef.enableSleep = false;
worldDef.enableContinous = enableContinuous;
worldDef.enableContinuous = enableContinuous;
worldDef.enqueueTask = EnqueueTask;
worldDef.finishTask = FinishTask;
worldDef.workerCount = threadCount;
Expand Down
8 changes: 4 additions & 4 deletions benchmark/tumbler.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ b2WorldId Tumbler( b2WorldDef* worldDef )
shapeDef.density = 50.0f;

b2Polygon polygon;
polygon = b2MakeOffsetBox( 0.5f, 10.0f, ( b2Vec2 ){ 10.0f, 0.0f }, 0.0 );
polygon = b2MakeOffsetBox( 0.5f, 10.0f, ( b2Vec2 ){ 10.0f, 0.0f }, b2Rot_identity );
b2CreatePolygonShape( bodyId, &shapeDef, &polygon );
polygon = b2MakeOffsetBox( 0.5f, 10.0f, ( b2Vec2 ){ -10.0f, 0.0f }, 0.0 );
polygon = b2MakeOffsetBox( 0.5f, 10.0f, ( b2Vec2 ){ -10.0f, 0.0f }, b2Rot_identity );
b2CreatePolygonShape( bodyId, &shapeDef, &polygon );
polygon = b2MakeOffsetBox( 10.0f, 0.5f, ( b2Vec2 ){ 0.0f, 10.0f }, 0.0 );
polygon = b2MakeOffsetBox( 10.0f, 0.5f, ( b2Vec2 ){ 0.0f, 10.0f }, b2Rot_identity );
b2CreatePolygonShape( bodyId, &shapeDef, &polygon );
polygon = b2MakeOffsetBox( 10.0f, 0.5f, ( b2Vec2 ){ 0.0f, -10.0f }, 0.0 );
polygon = b2MakeOffsetBox( 10.0f, 0.5f, ( b2Vec2 ){ 0.0f, -10.0f }, b2Rot_identity );
b2CreatePolygonShape( bodyId, &shapeDef, &polygon );

float motorSpeed = 25.0f;
Expand Down
9 changes: 4 additions & 5 deletions docs/simulation.md
Original file line number Diff line number Diff line change
Expand Up @@ -455,8 +455,8 @@ scenarios that require altering the mass.
b2MassData myMassData;
myMassData.mass = 10.0f;
myMassData.center = (b2Vec2){0.0f, 0.0f};
myMassData.I = 100.0f;
b2Body_SetMassData(myBodyId, &myMassData);
myMassData.rotationalInertia = 100.0f;
b2Body_SetMassData(myBodyId, myMassData);
```

After setting a body's mass directly, you may wish to revert to the
Expand All @@ -470,7 +470,7 @@ The body's mass data is available through the following functions:
```c
float mass = b2Body_GetMass(myBodyId);
float inertia = b2Body_GetInertiaTensor(myBodyId);
float inertia = b2Body_GetRotationalInertia(myBodyId);
b2Vec2 localCenter b2Body_GetLocalCenterOfMass(myBodyId);
b2MassData massData = b2Body_GetMassData(myBodyId);
```
Expand Down Expand Up @@ -1448,8 +1448,7 @@ joint limit and a friction motor:
```c
b2Vec2 worldPivot = {10.0f, -4.0f};
b2Vec2 worldAxis = {1.0f, 0.0f};
b2PrismaticJointDef jointDef;
b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef();
b2PrismaticJointDef jointDef = b2DefaultPrismaticJointDef();
jointDef.bodyIdA = myBodyIdA;
jointDef.bodyIdB = myBodyIdB;
jointDef.localAnchorA = b2Body_GetLocalPoint(myBodyIdA, worldPivot);
Expand Down
14 changes: 10 additions & 4 deletions include/box2d/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,24 @@

#include <stdint.h>

// clang-format off
//
// Shared library macros
#if defined( _MSC_VER ) && defined( box2d_EXPORTS )
// build the Windows DLL
#define BOX2D_EXPORT __declspec( dllexport )
#elif defined( _MSC_VER ) && defined( BOX2D_DLL )
// using the Windows DLL
// using the Windows DLL
#define BOX2D_EXPORT __declspec( dllimport )
#elif defined( box2d_EXPORTS )
// building or using the Box2D shared library
// building or using the Box2D shared library
#define BOX2D_EXPORT __attribute__( ( visibility( "default" ) ) )
#else
// static library
// static library
#define BOX2D_EXPORT
#endif

// C++ macros
// clang-format off
#ifdef __cplusplus
#define B2_API extern "C" BOX2D_EXPORT
#define B2_INLINE inline
Expand Down Expand Up @@ -104,4 +105,9 @@ B2_API float b2GetMilliseconds( const b2Timer* timer );
B2_API float b2GetMillisecondsAndReset( b2Timer* timer );
B2_API void b2SleepMilliseconds( int milliseconds );
B2_API void b2Yield( void );

// Simple djb2 hash function for determinism testing
#define B2_HASH_INIT 5381
B2_API uint32_t b2Hash( uint32_t hash, const uint8_t* data, int count );

//! @endcond
13 changes: 8 additions & 5 deletions include/box2d/box2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,8 @@ B2_API void b2Body_ApplyAngularImpulse( b2BodyId bodyId, float impulse, bool wak
/// Get the mass of the body, typically in kilograms
B2_API float b2Body_GetMass( b2BodyId bodyId );

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

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

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

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

/// Get the spring Hertz
B2_API float b2DistanceJoint_GetHertz( b2JointId jointId );
B2_API float b2DistanceJoint_GetSpringHertz( b2JointId jointId );

/// Get the spring damping ratio
B2_API float b2DistanceJoint_GetDampingRatio( b2JointId jointId );
B2_API float b2DistanceJoint_GetSpringDampingRatio( b2JointId jointId );

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

/// It the revolute angular spring enabled?
B2_API bool b2RevoluteJoint_IsSpringEnabled( b2JointId jointId );

/// Set the revolute joint spring stiffness in Hertz
B2_API void b2RevoluteJoint_SetSpringHertz( b2JointId jointId, float hertz );

Expand Down
22 changes: 10 additions & 12 deletions include/box2d/collision.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ B2_API b2Polygon b2MakeBox( float hx, float hy );
B2_API b2Polygon b2MakeRoundedBox( float hx, float hy, float radius );

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

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

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

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

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

/// Category bits for collision filtering
uint32_t categoryBits; // 4
uint64_t categoryBits; // 8

union
{
Expand Down Expand Up @@ -631,7 +630,7 @@ typedef struct b2TreeNode
bool enlarged; // 1

/// Padding for clarity
char pad[9];
char pad[5];
} b2TreeNode;

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

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

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

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

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

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

/// Validate this tree. For testing.
Expand Down
Loading

0 comments on commit 9314f30

Please sign in to comment.