From 077d04a6dd64622554265026c808ec51cfa009ec Mon Sep 17 00:00:00 2001 From: Erin Catto Date: Fri, 29 Dec 2023 16:00:23 -0800 Subject: [PATCH] Fix falling body assert (#92) API to get parent chain id default definitions as constants 128 max worlds removed extents from mass data removed box2d_exports.h and implemented similar switches in api.h user_constants.h optional and off by default added some missing API functions added shape filter sample addresses #93 --- .clang-format | 1 + CMakeLists.txt | 12 +- docs/CMakeLists.txt | 2 +- include/box2d/api.h | 26 ++- include/box2d/box2d.h | 273 +++++++++++++------------ include/box2d/callbacks.h | 2 +- include/box2d/constants.h | 12 +- include/box2d/distance.h | 12 +- include/box2d/dynamic_tree.h | 38 ++-- include/box2d/geometry.h | 63 +++--- include/box2d/hull.h | 4 +- include/box2d/id.h | 16 +- include/box2d/joint_types.h | 203 ++++++++---------- include/box2d/joint_util.h | 4 +- include/box2d/manifold.h | 24 +-- include/box2d/math.h | 10 +- include/box2d/timer.h | 10 +- include/box2d/types.h | 96 ++++++--- samples/collection/benchmark.cpp | 6 +- samples/collection/human.cpp | 20 +- samples/collection/sample_bodies.cpp | 6 +- samples/collection/sample_events.cpp | 2 +- samples/collection/sample_joints.cpp | 36 ++-- samples/collection/sample_manifold.cpp | 20 +- samples/collection/sample_shapes.cpp | 212 +++++++++++++++++++ samples/main.cpp | 2 +- samples/sample.cpp | 6 +- src/CMakeLists.txt | 48 +++-- src/body.c | 36 +++- src/dynamic_tree.c | 14 +- src/geometry.c | 20 -- src/shape.c | 116 ++++++++++- src/shape.h | 7 + src/world.c | 2 +- test/test_determinism.c | 2 +- test/test_world.c | 4 +- 36 files changed, 876 insertions(+), 491 deletions(-) diff --git a/.clang-format b/.clang-format index 73b59dd4..7f08d921 100644 --- a/.clang-format +++ b/.clang-format @@ -33,6 +33,7 @@ IncludeCategories: IndentExternBlock: NoIndent IndentCaseLabels: true +IndentPPDirectives: BeforeHash IndentAccessModifiers: false AccessModifierOffset: -4 diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ec41887..ce5309cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,10 @@ -cmake_minimum_required(VERSION 3.23) +cmake_minimum_required(VERSION 3.22) include(FetchContent) project(box2d VERSION 3.0.0 DESCRIPTION "A 2D physics engine for games" - HOMEPAGE_URL "box2d.org" + HOMEPAGE_URL "https://box2d.org" LANGUAGES C CXX ) @@ -15,8 +15,12 @@ project(box2d # message(STATUS "CMake C++ compiler: ${CMAKE_CXX_COMPILER_ID}") message(STATUS "CMake system name: ${CMAKE_SYSTEM_NAME}") -set(BOX2D_LENGTH_UNIT_PER_METER "1.0" CACHE STRING "Length units per meter") -set(BOX2D_MAX_POLYGON_VERTICES "8" CACHE STRING "Maximum number of polygon vertices (affects performance)") +option(BOX2D_USER_CONSTANTS "Generate user_constants.h" OFF) + +if (BOX2D_USER_CONSTANTS) + set(BOX2D_LENGTH_UNIT_PER_METER "1.0" CACHE STRING "Length units per meter") + set(BOX2D_MAX_POLYGON_VERTICES "8" CACHE STRING "Maximum number of polygon vertices (affects performance)") +endif() # Needed for samples.exe to find box2d.dll # set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin") diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 67c132e0..d281f91e 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -5,7 +5,7 @@ set(DOXYGEN_FILE_PATTERNS *.h) set(DOXYGEN_ENABLE_PREPROCESSING YES) set(DOXYGEN_MACRO_EXPANSION YES) set(DOXYGEN_EXPAND_ONLY_PREDEF YES) -set(DOXYGEN_PREDEFINED BOX2D_API=) +set(DOXYGEN_PREDEFINED B2_API=) set(DOXYGEN_IMAGE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/images") set(DOXYGEN_HTML_EXTRA_STYLESHEET "${CMAKE_CURRENT_SOURCE_DIR}/extra.css") diff --git a/include/box2d/api.h b/include/box2d/api.h index 0fadb4ce..d2008681 100644 --- a/include/box2d/api.h +++ b/include/box2d/api.h @@ -3,14 +3,26 @@ #pragma once -#include "box2d_export.h" - #include +#if defined(_WIN32) && defined(box2d_EXPORTS) + // building the Box2D DLL + #define BOX2D_EXPORT __declspec(dllexport) +#elif defined(_WIN32) && defined(BOX2D_DLL) + // using the Box2D DLL + #define BOX2D_EXPORT __declspec(dllimport) +#elif defined(__GNUC__) && defined(box2d_EXPORTS) + // building the Box2D shared library + #define BOX2D_EXPORT __attribute__((visibility("default"))) +#else + // static library + #define BOX2D_EXPORT +#endif + #ifdef __cplusplus -#define BOX2D_API extern "C" BOX2D_EXPORT + #define B2_API extern "C" BOX2D_EXPORT #else -#define BOX2D_API BOX2D_EXPORT + #define B2_API BOX2D_EXPORT #endif /// Prototype for user allocation function. @@ -24,14 +36,14 @@ typedef void b2FreeFcn(void* mem); /// This allows the user to override the allocation functions. These should be /// set during application startup. -BOX2D_API void b2SetAllocator(b2AllocFcn* allocFcn, b2FreeFcn* freeFcn); +B2_API void b2SetAllocator(b2AllocFcn* allocFcn, b2FreeFcn* freeFcn); /// Total bytes allocated by Box2D -BOX2D_API uint32_t b2GetByteCount(void); +B2_API uint32_t b2GetByteCount(void); /// Prototype for the user assert callback. Return 0 to skip the debugger break. typedef int b2AssertFcn(const char* condition, const char* fileName, int lineNumber); /// Override the default assert callback. /// @param assertFcn a non-null assert callback -BOX2D_API void b2SetAssertFcn(b2AssertFcn* assertFcn); +B2_API void b2SetAssertFcn(b2AssertFcn* assertFcn); diff --git a/include/box2d/box2d.h b/include/box2d/box2d.h index 15c0d013..7cc10514 100644 --- a/include/box2d/box2d.h +++ b/include/box2d/box2d.h @@ -19,7 +19,7 @@ typedef struct b2Segment b2Segment; /** * \defgroup WorldAPI Worlds - * This is the main Box2D API. With this API you can create a simulation world. You can then add bodies and + * These functions allow you to create a simulation world. You can then add bodies and * joints to the world and run the simulation. You can get contact information to get contact points * and normals as well as events. You can query to world, checking for overlaps and casting rays or shapes. * There is also debugging information such as debug draw, timing information, and counters. @@ -27,40 +27,40 @@ typedef struct b2Segment b2Segment; */ /// Create a world for rigid body simulation. This contains all the bodies, shapes, and constraints. -BOX2D_API b2WorldId b2CreateWorld(const b2WorldDef* def); +B2_API b2WorldId b2CreateWorld(const b2WorldDef* def); /// Destroy a world. -BOX2D_API void b2DestroyWorld(b2WorldId worldId); +B2_API void b2DestroyWorld(b2WorldId worldId); /// Take a time step. This performs collision detection, integration, /// and constraint solution. /// @param timeStep the amount of time to simulate, this should not vary. /// @param velocityIterations for the velocity constraint solver. /// @param relaxIterations for reducing constraint bounce solver. -BOX2D_API void b2World_Step(b2WorldId worldId, float timeStep, int32_t velocityIterations, int32_t relaxIterations); +B2_API void b2World_Step(b2WorldId worldId, float timeStep, int32_t velocityIterations, int32_t relaxIterations); /// Call this to draw shapes and other debug draw data. This is intentionally non-const. -BOX2D_API void b2World_Draw(b2WorldId worldId, b2DebugDraw* debugDraw); +B2_API void b2World_Draw(b2WorldId worldId, b2DebugDraw* debugDraw); /// Get sensor events for the current time step. The event data is transient. Do not store a reference to this data. -BOX2D_API b2SensorEvents b2World_GetSensorEvents(b2WorldId worldId); +B2_API b2SensorEvents b2World_GetSensorEvents(b2WorldId worldId); /// Get contact events for this current time step. The event data is transient. Do not store a reference to this data. -BOX2D_API b2ContactEvents b2World_GetContactEvents(b2WorldId worldId); +B2_API b2ContactEvents b2World_GetContactEvents(b2WorldId worldId); /// Query the world for all shapes that potentially overlap the provided AABB. -BOX2D_API void b2World_QueryAABB(b2WorldId worldId, b2QueryResultFcn* fcn, b2AABB aabb, b2QueryFilter filter, void* context); +B2_API void b2World_QueryAABB(b2WorldId worldId, b2QueryResultFcn* fcn, b2AABB aabb, b2QueryFilter filter, void* context); /// Query the world for all shapes that overlap the provided circle. -BOX2D_API void b2World_OverlapCircle(b2WorldId worldId, b2QueryResultFcn* fcn, const b2Circle* circle, b2Transform transform, +B2_API void b2World_OverlapCircle(b2WorldId worldId, b2QueryResultFcn* fcn, const b2Circle* circle, b2Transform transform, b2QueryFilter filter, void* context); /// Query the world for all shapes that overlap the provided capsule. -BOX2D_API void b2World_OverlapCapsule(b2WorldId worldId, b2QueryResultFcn* fcn, const b2Capsule* capsule, b2Transform transform, +B2_API void b2World_OverlapCapsule(b2WorldId worldId, b2QueryResultFcn* fcn, const b2Capsule* capsule, b2Transform transform, b2QueryFilter filter, void* context); /// Query the world for all shapes that overlap the provided polygon. -BOX2D_API void b2World_OverlapPolygon(b2WorldId worldId, b2QueryResultFcn* fcn, const b2Polygon* polygon, b2Transform transform, +B2_API void b2World_OverlapPolygon(b2WorldId worldId, b2QueryResultFcn* fcn, const b2Polygon* polygon, b2Transform transform, b2QueryFilter filter, void* context); /// Ray-cast the world for all shapes in the path of the ray. Your callback @@ -69,48 +69,48 @@ BOX2D_API void b2World_OverlapPolygon(b2WorldId worldId, b2QueryResultFcn* fcn, /// @param callback a user implemented callback class. /// @param point1 the ray starting point /// @param point2 the ray ending point -BOX2D_API void b2World_RayCast(b2WorldId worldId, b2Vec2 origin, b2Vec2 translation, b2QueryFilter filter, b2RayResultFcn* fcn, +B2_API void b2World_RayCast(b2WorldId worldId, b2Vec2 origin, b2Vec2 translation, b2QueryFilter filter, b2RayResultFcn* fcn, void* context); /// Ray-cast closest hit. Convenience function. This is less general than b2World_RayCast and does not allow for custom filtering. -BOX2D_API b2RayResult b2World_RayCastClosest(b2WorldId worldId, b2Vec2 origin, b2Vec2 translation, b2QueryFilter filter); +B2_API b2RayResult b2World_RayCastClosest(b2WorldId worldId, b2Vec2 origin, b2Vec2 translation, b2QueryFilter filter); /// Cast a circle through the world. Similar to a ray-cast except that a circle is cast instead of a point. -BOX2D_API void b2World_CircleCast(b2WorldId worldId, const b2Circle* circle, b2Transform originTransform, b2Vec2 translation, +B2_API void b2World_CircleCast(b2WorldId worldId, const b2Circle* circle, b2Transform originTransform, b2Vec2 translation, b2QueryFilter filter, b2RayResultFcn* fcn, void* context); /// Cast a capsule through the world. Similar to a ray-cast except that a capsule is cast instead of a point. -BOX2D_API void b2World_CapsuleCast(b2WorldId worldId, const b2Capsule* capsule, b2Transform originTransform, b2Vec2 translation, +B2_API void b2World_CapsuleCast(b2WorldId worldId, const b2Capsule* capsule, b2Transform originTransform, b2Vec2 translation, b2QueryFilter filter, b2RayResultFcn* fcn, void* context); /// Cast a capsule through the world. Similar to a ray-cast except that a polygon is cast instead of a point. -BOX2D_API void b2World_PolygonCast(b2WorldId worldId, const b2Polygon* polygon, b2Transform originTransform, b2Vec2 translation, +B2_API void b2World_PolygonCast(b2WorldId worldId, const b2Polygon* polygon, b2Transform originTransform, b2Vec2 translation, b2QueryFilter filter, b2RayResultFcn* fcn, void* context); /// Enable/disable sleep. Advanced feature for testing. -BOX2D_API void b2World_EnableSleeping(b2WorldId worldId, bool flag); +B2_API void b2World_EnableSleeping(b2WorldId worldId, bool flag); /// Enable/disable constraint warm starting. Advanced feature for testing. -BOX2D_API void b2World_EnableWarmStarting(b2WorldId worldId, bool flag); +B2_API void b2World_EnableWarmStarting(b2WorldId worldId, bool flag); /// Enable/disable continuous collision. Advanced feature for testing. -BOX2D_API void b2World_EnableContinuous(b2WorldId worldId, bool flag); +B2_API void b2World_EnableContinuous(b2WorldId worldId, bool flag); /// Adjust the restitution threshold. Advanced feature for testing. -BOX2D_API void b2World_SetRestitutionThreshold(b2WorldId worldId, float value); +B2_API void b2World_SetRestitutionThreshold(b2WorldId worldId, float value); /// Adjust contact tuning parameters: /// - hertz is the contact stiffness (cycles per second) /// - damping ratio is the contact bounciness with 1 being critical damping (non-dimensional) /// - push velocity is the maximum contact constraint push out velocity (meters per second) /// Advanced feature -BOX2D_API void b2World_SetContactTuning(b2WorldId worldId, float hertz, float dampingRatio, float pushVelocity); +B2_API void b2World_SetContactTuning(b2WorldId worldId, float hertz, float dampingRatio, float pushVelocity); /// Get the current profile -BOX2D_API b2Profile b2World_GetProfile(b2WorldId worldId); +B2_API b2Profile b2World_GetProfile(b2WorldId worldId); /// Get counters and sizes -BOX2D_API b2Counters b2World_GetCounters(b2WorldId worldId); +B2_API b2Counters b2World_GetCounters(b2WorldId worldId); /** @} */ @@ -122,56 +122,56 @@ BOX2D_API b2Counters b2World_GetCounters(b2WorldId worldId); /// Create a rigid body given a definition. No reference to the definition is retained. /// @warning This function is locked during callbacks. -BOX2D_API b2BodyId b2CreateBody(b2WorldId worldId, const b2BodyDef* def); +B2_API b2BodyId b2CreateBody(b2WorldId worldId, const b2BodyDef* def); /// Destroy a rigid body given an id. /// @warning This function is locked during callbacks. -BOX2D_API void b2DestroyBody(b2BodyId bodyId); +B2_API void b2DestroyBody(b2BodyId bodyId); /// Get the type of a body -BOX2D_API b2BodyType b2Body_GetType(b2BodyId bodyId); +B2_API b2BodyType b2Body_GetType(b2BodyId bodyId); /// Set the type of a body. This has a similar cost to re-creating the body. -BOX2D_API void b2Body_SetType(b2BodyId bodyId, b2BodyType type); +B2_API void b2Body_SetType(b2BodyId bodyId, b2BodyType type); /// Get the user data stored in a body -BOX2D_API void* b2Body_GetUserData(b2BodyId bodyId); +B2_API void* b2Body_GetUserData(b2BodyId bodyId); /// Get the world position of a body. This is the location of the body origin. -BOX2D_API b2Vec2 b2Body_GetPosition(b2BodyId bodyId); +B2_API b2Vec2 b2Body_GetPosition(b2BodyId bodyId); /// Get the world angle of a body in radians. -BOX2D_API float b2Body_GetAngle(b2BodyId bodyId); +B2_API float b2Body_GetAngle(b2BodyId bodyId); /// Get the world transform of a body. -BOX2D_API b2Transform b2Body_GetTransform(b2BodyId bodyId); +B2_API b2Transform b2Body_GetTransform(b2BodyId bodyId); /// Set the world transform of a body. This acts as a teleport and is fairly expensive. -BOX2D_API void b2Body_SetTransform(b2BodyId bodyId, b2Vec2 position, float angle); +B2_API void b2Body_SetTransform(b2BodyId bodyId, b2Vec2 position, float angle); /// Get a local point on a body given a world point -BOX2D_API b2Vec2 b2Body_GetLocalPoint(b2BodyId bodyId, b2Vec2 worldPoint); +B2_API b2Vec2 b2Body_GetLocalPoint(b2BodyId bodyId, b2Vec2 worldPoint); /// Get a world point on a body given a local point -BOX2D_API b2Vec2 b2Body_GetWorldPoint(b2BodyId bodyId, b2Vec2 localPoint); +B2_API b2Vec2 b2Body_GetWorldPoint(b2BodyId bodyId, b2Vec2 localPoint); /// Get a local vector on a body given a world vector -BOX2D_API b2Vec2 b2Body_GetLocalVector(b2BodyId bodyId, b2Vec2 worldVector); +B2_API b2Vec2 b2Body_GetLocalVector(b2BodyId bodyId, b2Vec2 worldVector); /// Get a world vector on a body given a local vector -BOX2D_API b2Vec2 b2Body_GetWorldVector(b2BodyId bodyId, b2Vec2 localVector); +B2_API b2Vec2 b2Body_GetWorldVector(b2BodyId bodyId, b2Vec2 localVector); /// Get the linear velocity of a body's center of mass -BOX2D_API b2Vec2 b2Body_GetLinearVelocity(b2BodyId bodyId); +B2_API b2Vec2 b2Body_GetLinearVelocity(b2BodyId bodyId); /// Get the angular velocity of a body in radians per second -BOX2D_API float b2Body_GetAngularVelocity(b2BodyId bodyId); +B2_API float b2Body_GetAngularVelocity(b2BodyId bodyId); /// Set the linear velocity of a body -BOX2D_API void b2Body_SetLinearVelocity(b2BodyId bodyId, b2Vec2 linearVelocity); +B2_API void b2Body_SetLinearVelocity(b2BodyId bodyId, b2Vec2 linearVelocity); /// Set the angular velocity of a body in radians per second -BOX2D_API void b2Body_SetAngularVelocity(b2BodyId bodyId, float angularVelocity); +B2_API void b2Body_SetAngularVelocity(b2BodyId bodyId, float angularVelocity); /// Apply a force at a world point. If the force is not /// applied at the center of mass, it will generate a torque and @@ -179,18 +179,18 @@ BOX2D_API void b2Body_SetAngularVelocity(b2BodyId bodyId, float angularVelocity) /// @param force the world force vector, usually in Newtons (N). /// @param point the world position of the point of application. /// @param wake also wake up the body -BOX2D_API void b2Body_ApplyForce(b2BodyId bodyId, b2Vec2 force, b2Vec2 point, bool wake); +B2_API void b2Body_ApplyForce(b2BodyId bodyId, b2Vec2 force, b2Vec2 point, bool wake); /// Apply a force to the center of mass. This wakes up the body. /// @param force the world force vector, usually in Newtons (N). /// @param wake also wake up the body -BOX2D_API void b2Body_ApplyForceToCenter(b2BodyId bodyId, b2Vec2 force, bool wake); +B2_API void b2Body_ApplyForceToCenter(b2BodyId bodyId, b2Vec2 force, bool wake); /// Apply a torque. This affects the angular velocity /// without affecting the linear velocity of the center of mass. /// @param torque about the z-axis (out of the screen), usually in N-m. /// @param wake also wake up the body -BOX2D_API void b2Body_ApplyTorque(b2BodyId bodyId, float torque, bool wake); +B2_API void b2Body_ApplyTorque(b2BodyId bodyId, float torque, bool wake); /// Apply an impulse at a point. This immediately modifies the velocity. /// It also modifies the angular velocity if the point of application @@ -198,59 +198,68 @@ BOX2D_API void b2Body_ApplyTorque(b2BodyId bodyId, float torque, bool wake); /// @param impulse the world impulse vector, usually in N-seconds or kg-m/s. /// @param point the world position of the point of application. /// @param wake also wake up the body -BOX2D_API void b2Body_ApplyLinearImpulse(b2BodyId bodyId, b2Vec2 impulse, b2Vec2 point, bool wake); +B2_API void b2Body_ApplyLinearImpulse(b2BodyId bodyId, b2Vec2 impulse, b2Vec2 point, bool wake); /// Apply an impulse to the center of mass. This immediately modifies the velocity. /// @param impulse the world impulse vector, usually in N-seconds or kg-m/s. /// @param wake also wake up the body -BOX2D_API void b2Body_ApplyLinearImpulseToCenter(b2BodyId bodyId, b2Vec2 impulse, bool wake); +B2_API void b2Body_ApplyLinearImpulseToCenter(b2BodyId bodyId, b2Vec2 impulse, bool wake); /// Apply an angular impulse. /// @param impulse the angular impulse in units of kg*m*m/s /// @param wake also wake up the body -BOX2D_API void b2Body_ApplyAngularImpulse(b2BodyId bodyId, float impulse, bool wake); +B2_API void b2Body_ApplyAngularImpulse(b2BodyId bodyId, float impulse, bool wake); /// Get the mass of the body (kilograms) -BOX2D_API float b2Body_GetMass(b2BodyId bodyId); +B2_API float b2Body_GetMass(b2BodyId bodyId); /// Get the inertia tensor of the body. In 2D this is a single number. (kilograms * meters^2) -BOX2D_API float b2Body_GetInertiaTensor(b2BodyId bodyId); +B2_API float b2Body_GetInertiaTensor(b2BodyId bodyId); /// Get the center of mass position of the body in local space. -BOX2D_API b2Vec2 b2Body_GetLocalCenterOfMass(b2BodyId bodyId); +B2_API b2Vec2 b2Body_GetLocalCenterOfMass(b2BodyId bodyId); /// Get the center of mass position of the body in world space. -BOX2D_API b2Vec2 b2Body_GetWorldCenterOfMass(b2BodyId bodyId); +B2_API b2Vec2 b2Body_GetWorldCenterOfMass(b2BodyId bodyId); /// Override the body's mass properties. Normally this is computed automatically using the /// shape geometry and density. This information is lost if a shape is added or removed or if the /// body type changes. -BOX2D_API void b2Body_SetMassData(b2BodyId bodyId, b2MassData massData); +B2_API void b2Body_SetMassData(b2BodyId bodyId, b2MassData massData); + +/// Adjust the linear damping. Normally this is set in b2BodyDef before creation. +B2_API void b2Body_SetLinearDamping(b2BodyId bodyId, float linearDamping); + +/// Adjust the angular damping. Normally this is set in b2BodyDef before creation. +B2_API void b2Body_SetAngularDamping(b2BodyId bodyId, float angularDamping); + +/// Adjust the gravity scale. Normally this is set in b2BodyDef before creation. +B2_API void b2Body_SetGravityScale(b2BodyId bodyId, float gravityScale); /// Is this body awake? -BOX2D_API bool b2Body_IsAwake(b2BodyId bodyId); +B2_API bool b2Body_IsAwake(b2BodyId bodyId); /// Wake a body from sleep. This wakes the entire island the body is touching. -BOX2D_API void b2Body_Wake(b2BodyId bodyId); +B2_API void b2Body_Wake(b2BodyId bodyId); /// Is this body enabled? -BOX2D_API bool b2Body_IsEnabled(b2BodyId bodyId); +B2_API bool b2Body_IsEnabled(b2BodyId bodyId); /// Disable a body by removing it completely from the simulation -BOX2D_API void b2Body_Disable(b2BodyId bodyId); +B2_API void b2Body_Disable(b2BodyId bodyId); /// Enable a body by adding it to the simulation -BOX2D_API void b2Body_Enable(b2BodyId bodyId); +B2_API void b2Body_Enable(b2BodyId bodyId); /// Iterate over shapes on a body -BOX2D_API b2ShapeId b2Body_GetFirstShape(b2BodyId bodyId); -BOX2D_API b2ShapeId b2Body_GetNextShape(b2ShapeId shapeId); +B2_API b2ShapeId b2Body_GetFirstShape(b2BodyId bodyId); +B2_API b2ShapeId b2Body_GetNextShape(b2ShapeId shapeId); /// Get the maximum capacity required for retrieving all the touching contacts on a body -BOX2D_API int32_t b2Body_GetContactCapacity(b2BodyId bodyId); +B2_API int32_t b2Body_GetContactCapacity(b2BodyId bodyId); /// Get the touching contact data for a body -BOX2D_API int32_t b2Body_GetContactData(b2BodyId bodyId, b2ContactData* contactData, int32_t capacity); +B2_API int32_t b2Body_GetContactData(b2BodyId bodyId, b2ContactData* contactData, int32_t capacity); /** @} */ @@ -263,78 +272,88 @@ BOX2D_API int32_t b2Body_GetContactData(b2BodyId bodyId, b2ContactData* contactD /// Create a circle shape and attach it to a body. The shape defintion and geometry are fully cloned. /// Contacts are not created until the next time step. /// @return the shape id for accessing the shape -BOX2D_API b2ShapeId b2CreateCircleShape(b2BodyId bodyId, const b2ShapeDef* def, const b2Circle* circle); +B2_API b2ShapeId b2CreateCircleShape(b2BodyId bodyId, const b2ShapeDef* def, const b2Circle* circle); /// Create a line segment shape and attach it to a body. The shape defintion and geometry are fully cloned. /// Contacts are not created until the next time step. /// @return the shape id for accessing the shape -BOX2D_API b2ShapeId b2CreateSegmentShape(b2BodyId bodyId, const b2ShapeDef* def, const b2Segment* segment); +B2_API b2ShapeId b2CreateSegmentShape(b2BodyId bodyId, const b2ShapeDef* def, const b2Segment* segment); /// Create a capsule shape and attach it to a body. The shape defintion and geometry are fully cloned. /// Contacts are not created until the next time step. /// @return the shape id for accessing the shape -BOX2D_API b2ShapeId b2CreateCapsuleShape(b2BodyId bodyId, const b2ShapeDef* def, const b2Capsule* capsule); +B2_API b2ShapeId b2CreateCapsuleShape(b2BodyId bodyId, const b2ShapeDef* def, const b2Capsule* capsule); /// Create a polygon shape and attach it to a body. The shape defintion and geometry are fully cloned. /// Contacts are not created until the next time step. /// @return the shape id for accessing the shape -BOX2D_API b2ShapeId b2CreatePolygonShape(b2BodyId bodyId, const b2ShapeDef* def, const b2Polygon* polygon); +B2_API b2ShapeId b2CreatePolygonShape(b2BodyId bodyId, const b2ShapeDef* def, const b2Polygon* polygon); /// Destroy any shape type -BOX2D_API void b2DestroyShape(b2ShapeId shapeId); +B2_API void b2DestroyShape(b2ShapeId shapeId); /// Create a chain shape /// @see b2ChainDef for details -BOX2D_API b2ChainId b2CreateChain(b2BodyId bodyId, const b2ChainDef* def); +B2_API b2ChainId b2CreateChain(b2BodyId bodyId, const b2ChainDef* def); /// Destroy a chain shape -BOX2D_API void b2DestroyChain(b2ChainId chainId); +B2_API void b2DestroyChain(b2ChainId chainId); /// Get the body that a shape is attached to -BOX2D_API b2BodyId b2Shape_GetBody(b2ShapeId shapeId); +B2_API b2BodyId b2Shape_GetBody(b2ShapeId shapeId); /// Get the user data for a shape. This is useful when you get a shape id /// from an event or query -BOX2D_API void* b2Shape_GetUserData(b2ShapeId shapeId); +B2_API void* b2Shape_GetUserData(b2ShapeId shapeId); /// Test a point for overlap with a shape -BOX2D_API bool b2Shape_TestPoint(b2ShapeId shapeId, b2Vec2 point); +B2_API bool b2Shape_TestPoint(b2ShapeId shapeId, b2Vec2 point); /// Set the friction on a shape. Normally this is specified in b2ShapeDef. -BOX2D_API void b2Shape_SetFriction(b2ShapeId shapeId, float friction); +B2_API void b2Shape_SetFriction(b2ShapeId shapeId, float friction); /// Set the restitution (bounciness) on a shape. Normally this is specified in b2ShapeDef. -BOX2D_API void b2Shape_SetRestitution(b2ShapeId shapeId, float restitution); +B2_API void b2Shape_SetRestitution(b2ShapeId shapeId, float restitution); + +/// Get the current filter +B2_API b2Filter b2Shape_GetFilter(b2ShapeId shapeId); + +/// Set the current filter. This is almost as expensive as recreating the shape. +B2_API void b2Shape_SetFilter(b2ShapeId shapeId, b2Filter filter); /// Get the type of a shape. -BOX2D_API b2ShapeType b2Shape_GetType(b2ShapeId shapeId); +B2_API b2ShapeType b2Shape_GetType(b2ShapeId shapeId); /// Access the circle geometry of a shape. -BOX2D_API const b2Circle* b2Shape_GetCircle(b2ShapeId shapeId); +B2_API const b2Circle* b2Shape_GetCircle(b2ShapeId shapeId); /// Access the line segment geometry of a shape. -BOX2D_API const b2Segment* b2Shape_GetSegment(b2ShapeId shapeId); +B2_API const b2Segment* b2Shape_GetSegment(b2ShapeId shapeId); /// Access the smooth line segment geometry of a shape. These come from chain shapes. -BOX2D_API const b2SmoothSegment* b2Shape_GetSmoothSegment(b2ShapeId shapeId); +B2_API const b2SmoothSegment* b2Shape_GetSmoothSegment(b2ShapeId shapeId); /// Access the capsule geometry of a shape. -BOX2D_API const b2Capsule* b2Shape_GetCapsule(b2ShapeId shapeId); +B2_API const b2Capsule* b2Shape_GetCapsule(b2ShapeId shapeId); /// Access the convex polygon geometry of a shape. -BOX2D_API const b2Polygon* b2Shape_GetPolygon(b2ShapeId shapeId); +B2_API const b2Polygon* b2Shape_GetPolygon(b2ShapeId shapeId); + +/// If the type is b2_smoothSegmentShape then you can get the parent chain id. +/// If the shape is not a smooth segment then this will return b2_nullChainId. +B2_API b2ChainId b2Shape_GetParentChain(b2ShapeId shapeId); /// Set the friction of a chain. Normally this is set in b2ChainDef. -BOX2D_API void b2Chain_SetFriction(b2ChainId chainId, float friction); +B2_API void b2Chain_SetFriction(b2ChainId chainId, float friction); /// Set the restitution (bounciness) on a chain. Normally this is specified in b2ChainDef. -BOX2D_API void b2Chain_SetRestitution(b2ChainId chainId, float restitution); +B2_API void b2Chain_SetRestitution(b2ChainId chainId, float restitution); /// Get the maximum capacity required for retrieving all the touching contacts on a shape -BOX2D_API int32_t b2Shape_GetContactCapacity(b2ShapeId shapeId); +B2_API int32_t b2Shape_GetContactCapacity(b2ShapeId shapeId); /// Get the touching contact data for a shape. The provided shapeId will be either shapeIdA or shapeIdB on the contact data. -BOX2D_API int32_t b2Shape_GetContactData(b2ShapeId shapeId, b2ContactData* contactData, int32_t capacity); +B2_API int32_t b2Shape_GetContactData(b2ShapeId shapeId, b2ContactData* contactData, int32_t capacity); /** @} */ @@ -346,146 +365,146 @@ BOX2D_API int32_t b2Shape_GetContactData(b2ShapeId shapeId, b2ContactData* conta /// Create a distance joint /// @see b2DistanceJointDef for details -BOX2D_API b2JointId b2CreateDistanceJoint(b2WorldId worldId, const b2DistanceJointDef* def); +B2_API b2JointId b2CreateDistanceJoint(b2WorldId worldId, const b2DistanceJointDef* def); /// Create a motor joint /// @see b2MotorJointDef for details -BOX2D_API b2JointId b2CreateMotorJoint(b2WorldId worldId, const b2MotorJointDef* def); +B2_API b2JointId b2CreateMotorJoint(b2WorldId worldId, const b2MotorJointDef* def); /// Create a mouse joint /// @see b2MouseJointDef for details -BOX2D_API b2JointId b2CreateMouseJoint(b2WorldId worldId, const b2MouseJointDef* def); +B2_API b2JointId b2CreateMouseJoint(b2WorldId worldId, const b2MouseJointDef* def); /// Create a prismatic (slider) joint /// @see b2PrismaticJointDef for details -BOX2D_API b2JointId b2CreatePrismaticJoint(b2WorldId worldId, const b2PrismaticJointDef* def); +B2_API b2JointId b2CreatePrismaticJoint(b2WorldId worldId, const b2PrismaticJointDef* def); /// Create a revolute (hinge) joint /// @see b2RevoluteJointDef for details -BOX2D_API b2JointId b2CreateRevoluteJoint(b2WorldId worldId, const b2RevoluteJointDef* def); +B2_API b2JointId b2CreateRevoluteJoint(b2WorldId worldId, const b2RevoluteJointDef* def); /// Create a weld joint /// @see b2WeldJointDef for details -BOX2D_API b2JointId b2CreateWeldJoint(b2WorldId worldId, const b2WeldJointDef* def); +B2_API b2JointId b2CreateWeldJoint(b2WorldId worldId, const b2WeldJointDef* def); /// Create a wheel joint /// @see b2WheelJointDef for details -BOX2D_API b2JointId b2CreateWheelJoint(b2WorldId worldId, const b2WheelJointDef* def); +B2_API b2JointId b2CreateWheelJoint(b2WorldId worldId, const b2WheelJointDef* def); /// Destroy any joint type -BOX2D_API void b2DestroyJoint(b2JointId jointId); +B2_API void b2DestroyJoint(b2JointId jointId); /// Get body A on a joint -BOX2D_API b2BodyId b2Joint_GetBodyA(b2JointId jointId); +B2_API b2BodyId b2Joint_GetBodyA(b2JointId jointId); /// Get body B on a joint -BOX2D_API b2BodyId b2Joint_GetBodyB(b2JointId jointId); +B2_API b2BodyId b2Joint_GetBodyB(b2JointId jointId); /// Get the constraint force on a distance joint -BOX2D_API float b2DistanceJoint_GetConstraintForce(b2JointId jointId, float timeStep); +B2_API float b2DistanceJoint_GetConstraintForce(b2JointId jointId, float timeStep); /// Set the length parameters of a distance joint /// @see b2DistanceJointDef for details -BOX2D_API void b2DistanceJoint_SetLength(b2JointId jointId, float length, float minLength, float maxLength); +B2_API void b2DistanceJoint_SetLength(b2JointId jointId, float length, float minLength, float maxLength); /// Get the current length of a distance joint -BOX2D_API float b2DistanceJoint_GetCurrentLength(b2JointId jointId); +B2_API float b2DistanceJoint_GetCurrentLength(b2JointId jointId); /// Adjust the softness of a distance joint /// @see b2DistanceJointDef for details -BOX2D_API void b2DistanceJoint_SetTuning(b2JointId jointId, float hertz, float dampingRatio); +B2_API void b2DistanceJoint_SetTuning(b2JointId jointId, float hertz, float dampingRatio); /// Set the linear offset target for a motor joint -BOX2D_API void b2MotorJoint_SetLinearOffset(b2JointId jointId, b2Vec2 linearOffset); +B2_API void b2MotorJoint_SetLinearOffset(b2JointId jointId, b2Vec2 linearOffset); /// Set the angular offset target for a motor joint in radians -BOX2D_API void b2MotorJoint_SetAngularOffset(b2JointId jointId, float angularOffset); +B2_API void b2MotorJoint_SetAngularOffset(b2JointId jointId, float angularOffset); /// Set the maximum force for a motor joint -BOX2D_API void b2MotorJoint_SetMaxForce(b2JointId jointId, float maxForce); +B2_API void b2MotorJoint_SetMaxForce(b2JointId jointId, float maxForce); /// Set the maximum torque for a motor joint -BOX2D_API void b2MotorJoint_SetMaxTorque(b2JointId jointId, float maxTorque); +B2_API void b2MotorJoint_SetMaxTorque(b2JointId jointId, float maxTorque); /// Set the correction factor for a motor joint -BOX2D_API void b2MotorJoint_SetCorrectionFactor(b2JointId jointId, float correctionFactor); +B2_API void b2MotorJoint_SetCorrectionFactor(b2JointId jointId, float correctionFactor); /// Get the current constraint force for a motor joint -BOX2D_API b2Vec2 b2MotorJoint_GetConstraintForce(b2JointId jointId, float inverseTimeStep); +B2_API b2Vec2 b2MotorJoint_GetConstraintForce(b2JointId jointId, float inverseTimeStep); /// Get the current constraint torque for a motor joint -BOX2D_API float b2MotorJoint_GetConstraintTorque(b2JointId jointId, float inverseTimeStep); +B2_API float b2MotorJoint_GetConstraintTorque(b2JointId jointId, float inverseTimeStep); /// Set the target for a mouse joint -BOX2D_API void b2MouseJoint_SetTarget(b2JointId jointId, b2Vec2 target); +B2_API void b2MouseJoint_SetTarget(b2JointId jointId, b2Vec2 target); /// Enable/disable a prismatic joint limit -BOX2D_API void b2PrismaticJoint_EnableLimit(b2JointId jointId, bool enableLimit); +B2_API void b2PrismaticJoint_EnableLimit(b2JointId jointId, bool enableLimit); /// Enable/disable a prismatic joint motor -BOX2D_API void b2PrismaticJoint_EnableMotor(b2JointId jointId, bool enableMotor); +B2_API void b2PrismaticJoint_EnableMotor(b2JointId jointId, bool enableMotor); /// Set the motor speed for a prismatic joint -BOX2D_API void b2PrismaticJoint_SetMotorSpeed(b2JointId jointId, float motorSpeed); +B2_API void b2PrismaticJoint_SetMotorSpeed(b2JointId jointId, float motorSpeed); /// Get the current motor force for a prismatic joint -BOX2D_API float b2PrismaticJoint_GetMotorForce(b2JointId jointId, float inverseTimeStep); +B2_API float b2PrismaticJoint_GetMotorForce(b2JointId jointId, float inverseTimeStep); /// Set the maximum force for a pristmatic joint motor -BOX2D_API void b2PrismaticJoint_SetMaxMotorForce(b2JointId jointId, float force); +B2_API void b2PrismaticJoint_SetMaxMotorForce(b2JointId jointId, float force); /// Get the current constraint force for a prismatic joint -BOX2D_API b2Vec2 b2PrismaticJoint_GetConstraintForce(b2JointId jointId, float inverseTimeStep); +B2_API b2Vec2 b2PrismaticJoint_GetConstraintForce(b2JointId jointId, float inverseTimeStep); /// Get the current constraint torque for a prismatic joint -BOX2D_API float b2PrismaticJoint_GetConstraintTorque(b2JointId jointId, float inverseTimeStep); +B2_API float b2PrismaticJoint_GetConstraintTorque(b2JointId jointId, float inverseTimeStep); /// Enable/disable a revolute joint limit -BOX2D_API void b2RevoluteJoint_EnableLimit(b2JointId jointId, bool enableLimit); +B2_API void b2RevoluteJoint_EnableLimit(b2JointId jointId, bool enableLimit); /// Enable/disable a revolute joint motor -BOX2D_API void b2RevoluteJoint_EnableMotor(b2JointId jointId, bool enableMotor); +B2_API void b2RevoluteJoint_EnableMotor(b2JointId jointId, bool enableMotor); /// Set the motor speed for a revolute joint in radians per second -BOX2D_API void b2RevoluteJoint_SetMotorSpeed(b2JointId jointId, float motorSpeed); +B2_API void b2RevoluteJoint_SetMotorSpeed(b2JointId jointId, float motorSpeed); /// Get the current motor torque for a revolute joint -BOX2D_API float b2RevoluteJoint_GetMotorTorque(b2JointId jointId, float inverseTimeStep); +B2_API float b2RevoluteJoint_GetMotorTorque(b2JointId jointId, float inverseTimeStep); /// Set the maximum torque for a revolute joint motor -BOX2D_API void b2RevoluteJoint_SetMaxMotorTorque(b2JointId jointId, float torque); +B2_API void b2RevoluteJoint_SetMaxMotorTorque(b2JointId jointId, float torque); /// Get the current constraint force for a revolute joint -BOX2D_API b2Vec2 b2RevoluteJoint_GetConstraintForce(b2JointId jointId, float inverseTimeStep); +B2_API b2Vec2 b2RevoluteJoint_GetConstraintForce(b2JointId jointId, float inverseTimeStep); /// Get the current constraint torque for a revolute joint -BOX2D_API float b2RevoluteJoint_GetConstraintTorque(b2JointId jointId, float inverseTimeStep); +B2_API float b2RevoluteJoint_GetConstraintTorque(b2JointId jointId, float inverseTimeStep); /// Set the wheel joint stiffness -BOX2D_API void b2WheelJoint_SetStiffness(b2JointId jointId, float stiffness); +B2_API void b2WheelJoint_SetStiffness(b2JointId jointId, float stiffness); /// Set the wheel joint damping -BOX2D_API void b2WheelJoint_SetDamping(b2JointId jointId, float damping); +B2_API void b2WheelJoint_SetDamping(b2JointId jointId, float damping); /// Enable/disable the wheel joint limit -BOX2D_API void b2WheelJoint_EnableLimit(b2JointId jointId, bool enableLimit); +B2_API void b2WheelJoint_EnableLimit(b2JointId jointId, bool enableLimit); /// Enable/disable the wheel joint motor -BOX2D_API void b2WheelJoint_EnableMotor(b2JointId jointId, bool enableMotor); +B2_API void b2WheelJoint_EnableMotor(b2JointId jointId, bool enableMotor); /// Set the wheel joint motor speed in radians per second -BOX2D_API void b2WheelJoint_SetMotorSpeed(b2JointId jointId, float motorSpeed); +B2_API void b2WheelJoint_SetMotorSpeed(b2JointId jointId, float motorSpeed); /// Get the wheel joint current motor torque -BOX2D_API float b2WheelJoint_GetMotorTorque(b2JointId jointId, float inverseTimeStep); +B2_API float b2WheelJoint_GetMotorTorque(b2JointId jointId, float inverseTimeStep); /// Set the wheel joint maximum motor torque -BOX2D_API void b2WheelJoint_SetMaxMotorTorque(b2JointId jointId, float torque); +B2_API void b2WheelJoint_SetMaxMotorTorque(b2JointId jointId, float torque); /// Get the current wheel joint constraint force -BOX2D_API b2Vec2 b2WheelJoint_GetConstraintForce(b2JointId jointId, float inverseTimeStep); +B2_API b2Vec2 b2WheelJoint_GetConstraintForce(b2JointId jointId, float inverseTimeStep); /// Get the current wheel joint constraint torque -BOX2D_API float b2WheelJoint_GetConstraintTorque(b2JointId jointId, float inverseTimeStep); +B2_API float b2WheelJoint_GetConstraintTorque(b2JointId jointId, float inverseTimeStep); /** @} */ diff --git a/include/box2d/callbacks.h b/include/box2d/callbacks.h index a9cea917..28b2f85c 100644 --- a/include/box2d/callbacks.h +++ b/include/box2d/callbacks.h @@ -23,7 +23,7 @@ typedef struct b2Manifold b2Manifold; typedef bool b2PreSolveFcn(b2ShapeId shapeIdA, b2ShapeId shapeIdB, b2Manifold* manifold, void* context); /// Register the pre-solve callback. This is optional. -BOX2D_API void b2World_SetPreSolveCallback(b2WorldId worldId, b2PreSolveFcn* fcn, void* context); +B2_API void b2World_SetPreSolveCallback(b2WorldId worldId, b2PreSolveFcn* fcn, void* context); /// Prototype callback for AABB queries. /// See b2World_Query diff --git a/include/box2d/constants.h b/include/box2d/constants.h index f9c495da..7a508f53 100644 --- a/include/box2d/constants.h +++ b/include/box2d/constants.h @@ -12,14 +12,14 @@ /// Although most of these are not user configurable, it can be interesting for a user to see /// these to understand the tuning values Box2D uses. -// todo move constraint hertz/damping here - -#include "user_constants.h" +#ifdef BOX2D_USER_CONSTANTS + #include "user_constants.h" +#endif /// box2d bases all length units on meters, but you may need different units for your game. /// You can override this value to use different units. #ifndef b2_lengthUnitsPerMeter -#define b2_lengthUnitsPerMeter 1.0f + #define b2_lengthUnitsPerMeter 1.0f #endif /// https://en.wikipedia.org/wiki/Pi @@ -44,11 +44,11 @@ /// The maximum number of vertices on a convex polygon. Changing this affects performance even if you /// don't use more vertices. #ifndef b2_maxPolygonVertices -#define b2_maxPolygonVertices 8 + #define b2_maxPolygonVertices 8 #endif /// Maximum number of simultaneous worlds that can be allocated -#define b2_maxWorlds 32 +#define b2_maxWorlds 128 /// The maximum linear translation of a body per step. This limit is very large and is used /// to prevent numerical problems. You shouldn't need to adjust this. Meters. diff --git a/include/box2d/distance.h b/include/box2d/distance.h index 3b72a1d4..e4a4b44e 100644 --- a/include/box2d/distance.h +++ b/include/box2d/distance.h @@ -17,7 +17,7 @@ typedef struct b2SegmentDistanceResult } b2SegmentDistanceResult; /// Compute the distance between two line segments, clamping at the end points if needed. -BOX2D_API b2SegmentDistanceResult b2SegmentDistance(b2Vec2 p1, b2Vec2 q1, b2Vec2 p2, b2Vec2 q2); +B2_API b2SegmentDistanceResult b2SegmentDistance(b2Vec2 p1, b2Vec2 q1, b2Vec2 p2, b2Vec2 q2); /// A distance proxy is used by the GJK algorithm. It encapsulates any shape. typedef struct b2DistanceProxy @@ -63,7 +63,7 @@ typedef struct b2DistanceOutput /// Compute the closest points between two shapes. Supports any combination of: /// b2Circle, b2Polygon, b2EdgeShape. The simplex cache is input/output. /// On the first call set b2SimplexCache.count to zero. -BOX2D_API b2DistanceOutput b2ShapeDistance(b2DistanceCache* cache, const b2DistanceInput* input); +B2_API b2DistanceOutput b2ShapeDistance(b2DistanceCache* cache, const b2DistanceInput* input); /// Input parameters for b2ShapeCast typedef struct b2ShapeCastPairInput @@ -78,10 +78,10 @@ typedef struct b2ShapeCastPairInput /// Perform a linear shape cast of shape B moving and shape A fixed. Determines the hit point, normal, and translation fraction. /// @returns true if hit, false if there is no hit or an initial overlap -BOX2D_API b2RayCastOutput b2ShapeCast(const b2ShapeCastPairInput* input); +B2_API b2RayCastOutput b2ShapeCast(const b2ShapeCastPairInput* input); /// Make a proxy for use in GJK and related functions. -BOX2D_API b2DistanceProxy b2MakeProxy(const b2Vec2* vertices, int32_t count, float radius); +B2_API b2DistanceProxy b2MakeProxy(const b2Vec2* vertices, int32_t count, float radius); /// This describes the motion of a body/shape for TOI computation. Shapes are defined with respect to the body origin, /// which may not coincide with the center of mass. However, to support dynamics we must interpolate the center of mass @@ -98,7 +98,7 @@ typedef struct b2Sweep float a1, a2; } b2Sweep; -BOX2D_API b2Transform b2GetSweepTransform(const b2Sweep* sweep, float time); +B2_API b2Transform b2GetSweepTransform(const b2Sweep* sweep, float time); /// Input parameters for b2TimeOfImpact typedef struct b2TOIInput @@ -133,4 +133,4 @@ typedef struct b2TOIOutput /// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate, /// non-tunneling collisions. If you change the time interval, you should call this function /// again. -BOX2D_API b2TOIOutput b2TimeOfImpact(const b2TOIInput* input); +B2_API b2TOIOutput b2TimeOfImpact(const b2TOIInput* input); diff --git a/include/box2d/dynamic_tree.h b/include/box2d/dynamic_tree.h index 64c60b3c..eb15a731 100644 --- a/include/box2d/dynamic_tree.h +++ b/include/box2d/dynamic_tree.h @@ -64,25 +64,25 @@ typedef struct b2DynamicTree } b2DynamicTree; /// Constructing the tree initializes the node pool. -BOX2D_API b2DynamicTree b2DynamicTree_Create(void); +B2_API b2DynamicTree b2DynamicTree_Create(void); /// Destroy the tree, freeing the node pool. -BOX2D_API void b2DynamicTree_Destroy(b2DynamicTree* tree); +B2_API void b2DynamicTree_Destroy(b2DynamicTree* tree); /// Create a proxy. Provide a tight fitting AABB and a userData value. -BOX2D_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, uint32_t categoryBits, int32_t userData); /// Destroy a proxy. This asserts if the id is invalid. -BOX2D_API void b2DynamicTree_DestroyProxy(b2DynamicTree* tree, int32_t proxyId); +B2_API void b2DynamicTree_DestroyProxy(b2DynamicTree* tree, int32_t proxyId); // Clone one tree to another, reusing storage in the outTree if possible -BOX2D_API void b2DynamicTree_Clone(b2DynamicTree* outTree, const b2DynamicTree* inTree); +B2_API void b2DynamicTree_Clone(b2DynamicTree* outTree, const b2DynamicTree* inTree); /// Move a proxy to a new AABB by removing and reinserting into the tree. -BOX2D_API void b2DynamicTree_MoveProxy(b2DynamicTree* tree, int32_t proxyId, b2AABB aabb); +B2_API void b2DynamicTree_MoveProxy(b2DynamicTree* tree, int32_t proxyId, b2AABB aabb); /// Enlarge a proxy and enlarge ancestors as necessary. -BOX2D_API void b2DynamicTree_EnlargeProxy(b2DynamicTree* tree, int32_t proxyId, b2AABB aabb); +B2_API void b2DynamicTree_EnlargeProxy(b2DynamicTree* tree, int32_t proxyId, b2AABB aabb); /// This function receives proxies found in the AABB query. /// @return true if the query should continue @@ -90,12 +90,12 @@ typedef bool b2TreeQueryCallbackFcn(int32_t proxyId, int32_t userData, void* con /// Query an AABB for overlapping proxies. The callback class /// is called for each proxy that overlaps the supplied AABB. -BOX2D_API void b2DynamicTree_QueryFiltered(const b2DynamicTree* tree, b2AABB aabb, uint32_t maskBits, +B2_API void b2DynamicTree_QueryFiltered(const b2DynamicTree* tree, b2AABB aabb, uint32_t maskBits, b2TreeQueryCallbackFcn* callback, void* context); /// Query an AABB for overlapping proxies. The callback class /// is called for each proxy that overlaps the supplied AABB. -BOX2D_API void b2DynamicTree_Query(const b2DynamicTree* tree, b2AABB aabb, b2TreeQueryCallbackFcn* callback, void* context); +B2_API void b2DynamicTree_Query(const b2DynamicTree* tree, b2AABB aabb, b2TreeQueryCallbackFcn* callback, void* context); /// This function receives clipped raycast input for a proxy. The function /// returns the new ray fraction. @@ -111,7 +111,7 @@ typedef float b2TreeRayCastCallbackFcn(const b2RayCastInput* input, int32_t prox /// number of proxies in the tree. /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). /// @param callback a callback class that is called for each proxy that is hit by the ray. -BOX2D_API void b2DynamicTree_RayCast(const b2DynamicTree* tree, const b2RayCastInput* input, uint32_t maskBits, +B2_API void b2DynamicTree_RayCast(const b2DynamicTree* tree, const b2RayCastInput* input, uint32_t maskBits, b2TreeRayCastCallbackFcn* callback, void* context); /// This function receives clipped raycast input for a proxy. The function @@ -128,35 +128,35 @@ typedef float b2TreeShapeCastCallbackFcn(const b2ShapeCastInput* input, int32_t /// number of proxies in the tree. /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). /// @param callback a callback class that is called for each proxy that is hit by the ray. -BOX2D_API void b2DynamicTree_ShapeCast(const b2DynamicTree* tree, const b2ShapeCastInput* input, uint32_t maskBits, +B2_API void b2DynamicTree_ShapeCast(const b2DynamicTree* tree, const b2ShapeCastInput* input, uint32_t maskBits, b2TreeShapeCastCallbackFcn* callback, void* context); /// Validate this tree. For testing. -BOX2D_API void b2DynamicTree_Validate(const b2DynamicTree* tree); +B2_API void b2DynamicTree_Validate(const b2DynamicTree* tree); /// Compute the height of the binary tree in O(N) time. Should not be /// called often. -BOX2D_API int32_t b2DynamicTree_GetHeight(const b2DynamicTree* tree); +B2_API int32_t b2DynamicTree_GetHeight(const b2DynamicTree* tree); /// Get the maximum balance of the tree. The balance is the difference in height of the two children of a node. -BOX2D_API int32_t b2DynamicTree_GetMaxBalance(const b2DynamicTree* tree); +B2_API int32_t b2DynamicTree_GetMaxBalance(const b2DynamicTree* tree); /// Get the ratio of the sum of the node areas to the root area. -BOX2D_API float b2DynamicTree_GetAreaRatio(const b2DynamicTree* tree); +B2_API float b2DynamicTree_GetAreaRatio(const b2DynamicTree* tree); /// Build an optimal tree. Very expensive. For testing. -BOX2D_API void b2DynamicTree_RebuildBottomUp(b2DynamicTree* tree); +B2_API void b2DynamicTree_RebuildBottomUp(b2DynamicTree* tree); /// Get the number of proxies created -BOX2D_API int32_t b2DynamicTree_GetProxyCount(const b2DynamicTree* tree); +B2_API int32_t b2DynamicTree_GetProxyCount(const b2DynamicTree* tree); /// Rebuild the tree while retaining subtrees that haven't changed. Returns the number of boxes sorted. -BOX2D_API int32_t b2DynamicTree_Rebuild(b2DynamicTree* tree, bool fullBuild); +B2_API int32_t b2DynamicTree_Rebuild(b2DynamicTree* tree, bool fullBuild); /// Shift the world origin. Useful for large worlds. /// The shift formula is: position -= newOrigin /// @param newOrigin the new origin with respect to the old origin -BOX2D_API void b2DynamicTree_ShiftOrigin(b2DynamicTree* tree, b2Vec2 newOrigin); +B2_API void b2DynamicTree_ShiftOrigin(b2DynamicTree* tree, b2Vec2 newOrigin); /// Get proxy user data /// @return the proxy user data or 0 if the id is invalid diff --git a/include/box2d/geometry.h b/include/box2d/geometry.h index 621cfbc3..a39dfe69 100644 --- a/include/box2d/geometry.h +++ b/include/box2d/geometry.h @@ -22,14 +22,6 @@ typedef struct b2MassData /// The rotational inertia of the shape about the local origin. float I; - - /// TODO_ERIN remove geometry info from this - - /// Distance from shape centroid to closest point on perimeter. - float minExtent; - - /// Distance from shape origin to furthest point on perimeter. - float maxExtent; } b2MassData; /// A solid circle @@ -80,83 +72,86 @@ typedef struct b2SmoothSegment /// The head ghost vertex b2Vec2 ghost2; + + /// The owning chain shape index (internal usage only) + int32_t chainIndex; } b2SmoothSegment; /// Validate ray cast input data (NaN, etc) -BOX2D_API bool b2IsValidRay(const b2RayCastInput* input); +B2_API bool b2IsValidRay(const b2RayCastInput* input); /// Make a convex polygon from a convex hull. This will assert if the hull is not valid. -BOX2D_API b2Polygon b2MakePolygon(const b2Hull* hull, float radius); +B2_API b2Polygon b2MakePolygon(const b2Hull* hull, float radius); /// Make an offset convex polygon from a convex hull. This will assert if the hull is not valid. -BOX2D_API b2Polygon b2MakeOffsetPolygon(const b2Hull* hull, float radius, b2Transform transform); +B2_API b2Polygon b2MakeOffsetPolygon(const b2Hull* hull, float radius, b2Transform transform); /// Make a square polygon, bypassing the need for a convex hull. -BOX2D_API b2Polygon b2MakeSquare(float h); +B2_API b2Polygon b2MakeSquare(float h); /// Make a box (rectangle) polygon, bypassing the need for a convex hull. -BOX2D_API b2Polygon b2MakeBox(float hx, float hy); +B2_API b2Polygon b2MakeBox(float hx, float hy); /// Make a rounded box, bypassing the need for a convex hull. -BOX2D_API b2Polygon b2MakeRoundedBox(float hx, float hy, float radius); +B2_API b2Polygon b2MakeRoundedBox(float hx, float hy, float radius); /// Make an offset box, bypassing the need for a convex hull. -BOX2D_API b2Polygon b2MakeOffsetBox(float hx, float hy, b2Vec2 center, float angle); +B2_API b2Polygon b2MakeOffsetBox(float hx, float hy, b2Vec2 center, float angle); /// Transform a polygon. This is useful for transfering a shape from one body to another. -BOX2D_API b2Polygon b2TransformPolygon(b2Transform transform, const b2Polygon* polygon); +B2_API b2Polygon b2TransformPolygon(b2Transform transform, const b2Polygon* polygon); /// Compute mass properties of a circle -BOX2D_API b2MassData b2ComputeCircleMass(const b2Circle* shape, float density); +B2_API b2MassData b2ComputeCircleMass(const b2Circle* shape, float density); /// Compute mass properties of a capsule -BOX2D_API b2MassData b2ComputeCapsuleMass(const b2Capsule* shape, float density); +B2_API b2MassData b2ComputeCapsuleMass(const b2Capsule* shape, float density); /// Compute mass properties of a polygon -BOX2D_API b2MassData b2ComputePolygonMass(const b2Polygon* shape, float density); +B2_API b2MassData b2ComputePolygonMass(const b2Polygon* shape, float density); /// Compute the bounding box of a transformed circle -BOX2D_API b2AABB b2ComputeCircleAABB(const b2Circle* shape, b2Transform transform); +B2_API b2AABB b2ComputeCircleAABB(const b2Circle* shape, b2Transform transform); /// Compute the bounding box of a transformed capsule -BOX2D_API b2AABB b2ComputeCapsuleAABB(const b2Capsule* shape, b2Transform transform); +B2_API b2AABB b2ComputeCapsuleAABB(const b2Capsule* shape, b2Transform transform); /// Compute the bounding box of a transformed polygon -BOX2D_API b2AABB b2ComputePolygonAABB(const b2Polygon* shape, b2Transform transform); +B2_API b2AABB b2ComputePolygonAABB(const b2Polygon* shape, b2Transform transform); /// Compute the bounding box of a transformed line segment -BOX2D_API b2AABB b2ComputeSegmentAABB(const b2Segment* shape, b2Transform transform); +B2_API b2AABB b2ComputeSegmentAABB(const b2Segment* shape, b2Transform transform); /// Test a point for overlap with a circle in local space -BOX2D_API bool b2PointInCircle(b2Vec2 point, const b2Circle* shape); +B2_API bool b2PointInCircle(b2Vec2 point, const b2Circle* shape); /// Test a point for overlap with a capsule in local space -BOX2D_API bool b2PointInCapsule(b2Vec2 point, const b2Capsule* shape); +B2_API bool b2PointInCapsule(b2Vec2 point, const b2Capsule* shape); /// Test a point for overlap with a convex polygon in local space -BOX2D_API bool b2PointInPolygon(b2Vec2 point, const b2Polygon* shape); +B2_API bool b2PointInPolygon(b2Vec2 point, const b2Polygon* shape); /// Ray cast versus circle in shape local space. Initial overlap is treated as a miss. -BOX2D_API b2RayCastOutput b2RayCastCircle(const b2RayCastInput* input, const b2Circle* shape); +B2_API b2RayCastOutput b2RayCastCircle(const b2RayCastInput* input, const b2Circle* shape); /// Ray cast versus capsule in shape local space. Initial overlap is treated as a miss. -BOX2D_API b2RayCastOutput b2RayCastCapsule(const b2RayCastInput* input, const b2Capsule* shape); +B2_API b2RayCastOutput b2RayCastCapsule(const b2RayCastInput* input, const b2Capsule* shape); /// Ray cast versus segment in shape local space. Optionally treat the segment as one-sided with hits from /// the left side being treated as a miss. -BOX2D_API b2RayCastOutput b2RayCastSegment(const b2RayCastInput* input, const b2Segment* shape, bool oneSided); +B2_API b2RayCastOutput b2RayCastSegment(const b2RayCastInput* input, const b2Segment* shape, bool oneSided); /// Ray cast versus polygon in shape local space. Initial overlap is treated as a miss. -BOX2D_API b2RayCastOutput b2RayCastPolygon(const b2RayCastInput* input, const b2Polygon* shape); +B2_API b2RayCastOutput b2RayCastPolygon(const b2RayCastInput* input, const b2Polygon* shape); /// Shape cast versus a circle. Initial overlap is treated as a miss. -BOX2D_API b2RayCastOutput b2ShapeCastCircle(const b2ShapeCastInput* input, const b2Circle* shape); +B2_API b2RayCastOutput b2ShapeCastCircle(const b2ShapeCastInput* input, const b2Circle* shape); /// Shape cast versus a capsule. Initial overlap is treated as a miss. -BOX2D_API b2RayCastOutput b2ShapeCastCapsule(const b2ShapeCastInput* input, const b2Capsule* shape); +B2_API b2RayCastOutput b2ShapeCastCapsule(const b2ShapeCastInput* input, const b2Capsule* shape); /// Shape cast versus a line segment. Initial overlap is treated as a miss. -BOX2D_API b2RayCastOutput b2ShapeCastSegment(const b2ShapeCastInput* input, const b2Segment* shape); +B2_API b2RayCastOutput b2ShapeCastSegment(const b2ShapeCastInput* input, const b2Segment* shape); /// Shape cast versus a convex polygon. Initial overlap is treated as a miss. -BOX2D_API b2RayCastOutput b2ShapeCastPolygon(const b2ShapeCastInput* input, const b2Polygon* shape); +B2_API b2RayCastOutput b2ShapeCastPolygon(const b2ShapeCastInput* input, const b2Polygon* shape); diff --git a/include/box2d/hull.h b/include/box2d/hull.h index 5afbd586..1468dd29 100644 --- a/include/box2d/hull.h +++ b/include/box2d/hull.h @@ -21,10 +21,10 @@ typedef struct b2Hull /// - less than 3 points /// - more than b2_maxPolygonVertices points /// This welds close points and removes collinear points. -BOX2D_API b2Hull b2ComputeHull(const b2Vec2* points, int32_t count); +B2_API b2Hull b2ComputeHull(const b2Vec2* points, int32_t count); /// This determines if a hull is valid. Checks for: /// - convexity /// - collinear points /// This is expensive and should not be called at runtime. -BOX2D_API bool b2ValidateHull(const b2Hull* hull); +B2_API bool b2ValidateHull(const b2Hull* hull); diff --git a/include/box2d/id.h b/include/box2d/id.h index 9bdaea85..260ec848 100644 --- a/include/box2d/id.h +++ b/include/box2d/id.h @@ -50,8 +50,12 @@ typedef struct b2ChainId uint16_t revision; } b2ChainId; +/// Macros is needed for constant definitions +#define B2_NULL_BODY_ID {-1, -1, 0} + +/// Use these to make your identifiers null static const b2WorldId b2_nullWorldId = {-1, 0}; -static const b2BodyId b2_nullBodyId = {-1, -1, 0}; +static const b2BodyId b2_nullBodyId = B2_NULL_BODY_ID; static const b2ShapeId b2_nullShapeId = {-1, -1, 0}; static const b2JointId b2_nullJointId = {-1, -1, 0}; static const b2ChainId b2_nullChainId = {-1, -1, 0}; @@ -66,16 +70,16 @@ static const b2ChainId b2_nullChainId = {-1, -1, 0}; #define B2_ID_EQUALS(id1, id2) (id1.index == id2.index && id1.world == id2.world && id1.revision == id2.revision) /// World identifier validation. Provides validation for up to 64K allocations. -BOX2D_API bool b2World_IsValid(b2WorldId id); +B2_API bool b2World_IsValid(b2WorldId id); /// Body identifier validation. Provides validation for up to 64K allocations. -BOX2D_API bool b2Body_IsValid(b2BodyId id); +B2_API bool b2Body_IsValid(b2BodyId id); /// Shape identifier validation. Provides validation for up to 64K allocations. -BOX2D_API bool b2Shape_IsValid(b2ShapeId id); +B2_API bool b2Shape_IsValid(b2ShapeId id); /// Chain identifier validation. Provides validation for up to 64K allocations. -BOX2D_API bool b2Chain_IsValid(b2ChainId id); +B2_API bool b2Chain_IsValid(b2ChainId id); /// Joint identifier validation. Provides validation for up to 64K allocations. -BOX2D_API bool b2Joint_IsValid(b2JointId id); +B2_API bool b2Joint_IsValid(b2JointId id); diff --git a/include/box2d/joint_types.h b/include/box2d/joint_types.h index e5a05811..8f79f2fd 100644 --- a/include/box2d/joint_types.h +++ b/include/box2d/joint_types.h @@ -44,21 +44,18 @@ typedef struct b2DistanceJointDef } b2DistanceJointDef; /// Use this to initialize your joint definition -static inline b2DistanceJointDef b2DefaultDistanceJointDef(void) -{ - b2DistanceJointDef def = B2_ZERO_INIT; - def.bodyIdA = b2_nullBodyId; - def.bodyIdB = b2_nullBodyId; - def.localAnchorA = B2_LITERAL(b2Vec2){0.0f, 0.0f}; - def.localAnchorB = B2_LITERAL(b2Vec2){0.0f, 0.0f}; - def.length = 1.0f; - def.minLength = 0.0f; - def.maxLength = b2_huge; - def.hertz = 0.0f; - def.dampingRatio = 0.0f; - def.collideConnected = false; - return def; -} +static const b2DistanceJointDef b2_defaultDistanceJointDef = { + B2_NULL_BODY_ID, // bodyIdA + B2_NULL_BODY_ID, // bodyIdB + {0.0f, 0.0f}, // localAnchorA + {0.0f, 0.0f}, // localAnchorB + 1.0f, // length + 0.0f, // minLength + b2_huge, // maxLength + 0.0f, // hertz + 0.0f, // dampingRatio + false, // collideConnected +}; /// A motor joint is used to control the relative motion /// between two bodies. A typical usage is to control the movement @@ -88,18 +85,15 @@ typedef struct b2MotorJointDef } b2MotorJointDef; /// Use this to initialize your joint definition -static inline b2MotorJointDef b2DefaultMotorJointDef(void) -{ - b2MotorJointDef def = B2_ZERO_INIT; - def.bodyIdA = b2_nullBodyId; - def.bodyIdB = b2_nullBodyId; - def.linearOffset = B2_LITERAL(b2Vec2){0.0f, 0.0f}; - def.angularOffset = 0.0f; - def.maxForce = 1.0f; - def.maxTorque = 1.0f; - def.correctionFactor = 0.3f; - return def; -} +static const b2MotorJointDef b2_defaultMotorJointDef = { + B2_NULL_BODY_ID, // bodyIdA + B2_NULL_BODY_ID, // bodyIdB + {0.0f, 0.0f}, // linearOffset + 0.0f, // angularOffset + 1.0f, // maxForce + 1.0f, // maxTorque + 0.3f, // correctionFactor +}; /// A mouse joint is used to make a point on a body track a /// specified world point. This a soft constraint with a maximum @@ -129,17 +123,14 @@ typedef struct b2MouseJointDef } b2MouseJointDef; /// Use this to initialize your joint definition -static inline b2MouseJointDef b2DefaultMouseJointDef(void) -{ - b2MouseJointDef def = B2_ZERO_INIT; - def.bodyIdA = b2_nullBodyId; - def.bodyIdB = b2_nullBodyId; - def.target = B2_LITERAL(b2Vec2){0.0f, 0.0f}; - def.maxForce = 0.0f; - def.stiffness = 0.0f; - def.damping = 0.0f; - return def; -} +static const b2MouseJointDef b2_defaultMouseJointDef = { + B2_NULL_BODY_ID, // bodyIdA + B2_NULL_BODY_ID, // bodyIdB + {0.0f, 0.0f}, // target + 0.0f, // maxForce + 0.0f, // stiffness + 0.0f, // damping +}; /// Prismatic joint definition. This requires defining a line of /// motion using an axis and an anchor point. The definition uses local @@ -189,24 +180,21 @@ typedef struct b2PrismaticJointDef } b2PrismaticJointDef; /// Use this to initialize your joint definition -static inline b2PrismaticJointDef b2DefaultPrismaticJointDef(void) -{ - b2PrismaticJointDef def = B2_ZERO_INIT; - def.bodyIdA = b2_nullBodyId; - def.bodyIdB = b2_nullBodyId; - def.localAnchorA = B2_LITERAL(b2Vec2){0.0f, 0.0f}; - def.localAnchorB = B2_LITERAL(b2Vec2){0.0f, 0.0f}; - def.localAxisA = B2_LITERAL(b2Vec2){1.0f, 0.0f}; - def.referenceAngle = 0.0f; - def.enableLimit = false; - def.lowerTranslation = 0.0f; - def.upperTranslation = 0.0f; - def.enableMotor = false; - def.maxMotorForce = 0.0f; - def.motorSpeed = 0.0f; - def.collideConnected = false; - return def; -} +static const b2PrismaticJointDef b2_defaultPrismaticJointDef = { + B2_NULL_BODY_ID, // bodyIdA + B2_NULL_BODY_ID, // bodyIdB + {0.0f, 0.0f}, // localAnchorA + {0.0f, 0.0f}, // localAnchorB + {1.0f, 0.0f}, // localAxisA + 0.0f, // referenceAngle + false, // enableLimit + 0.0f, // lowerTranslation + 0.0f, // upperTranslation + false, // enableMotor + 0.0f, // maxMotorForce + 0.0f, // motorSpeed + false, // collideConnected +}; /// Revolute joint definition. This requires defining an anchor point where the /// bodies are joined. The definition uses local anchor points so that the @@ -248,13 +236,13 @@ typedef struct b2RevoluteJointDef /// A flag to enable the joint motor. bool enableMotor; - /// The desired motor speed. Usually in radians per second. - float motorSpeed; - /// The maximum motor torque used to achieve the desired motor speed. /// Usually in N-m. float maxMotorTorque; + /// The desired motor speed. Usually in radians per second. + float motorSpeed; + /// Scale the debug draw float drawSize; @@ -263,24 +251,21 @@ typedef struct b2RevoluteJointDef } b2RevoluteJointDef; /// Use this to initialize your joint definition -static inline b2RevoluteJointDef b2DefaultRevoluteJointDef(void) -{ - b2RevoluteJointDef def = B2_ZERO_INIT; - def.bodyIdA = b2_nullBodyId; - def.bodyIdB = b2_nullBodyId; - def.localAnchorA = B2_LITERAL(b2Vec2){0.0f, 0.0f}; - def.localAnchorB = B2_LITERAL(b2Vec2){0.0f, 0.0f}; - def.referenceAngle = 0.0f; - def.lowerAngle = 0.0f; - def.upperAngle = 0.0f; - def.maxMotorTorque = 0.0f; - def.motorSpeed = 0.0f; - def.enableLimit = false; - def.enableMotor = false; - def.drawSize = 0.25f; - def.collideConnected = false; - return def; -} +static const b2RevoluteJointDef b2_defaultRevoluteJointDef = { + B2_NULL_BODY_ID, // bodyIdA + B2_NULL_BODY_ID, // bodyIdB + {0.0f, 0.0f}, // localAnchorA + {0.0f, 0.0f}, // localAnchorB + 0.0f, // referenceAngle + false, // enableLimit + 0.0f, // lowerAngle + 0.0f, // upperAngle + false, // enableMotor + 0.0f, // maxMotorTorque + 0.0f, // motorSpeed + 0.25f, // drawSize + false, // collideConnected +}; /// A weld joint connect to bodies together rigidly. This constraint can be made soft to mimic /// soft-body simulation. @@ -318,27 +303,20 @@ typedef struct b2WeldJointDef bool collideConnected; } b2WeldJointDef; +/// Use this to initialize your joint definition static const b2WeldJointDef b2_defaultWeldJointDef = { - {-1, -1, 0}, {-1, -1, 0}, {0.0f, 0.0f}, {0.0f, 0.0f}, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, false, + B2_NULL_BODY_ID, // bodyIdA + B2_NULL_BODY_ID, // bodyIdB + {0.0f, 0.0f}, // localAnchorA + {0.0f, 0.0f}, // localAnchorB, + 0.0f, // referenceAngle + 0.0f, // linearHertz + 0.0f, // angularHertz + 1.0f, // linearDampingRatio + 1.0f, // angularDampingRatio + false, // collideConnected }; -/// Use this to initialize your joint definition -static inline b2WeldJointDef b2DefaultWeldJointDef(void) -{ - b2WeldJointDef def = B2_ZERO_INIT; - def.bodyIdA = b2_nullBodyId; - def.bodyIdB = b2_nullBodyId; - def.localAnchorA = B2_LITERAL(b2Vec2){0.0f, 0.0f}; - def.localAnchorB = B2_LITERAL(b2Vec2){0.0f, 0.0f}; - def.referenceAngle = 0.0f; - def.linearHertz = 0.0f; - def.angularHertz = 0.0f; - def.linearDampingRatio = 1.0f; - def.angularDampingRatio = 1.0f; - def.collideConnected = false; - return def; -} - /// Wheel joint definition. This requires defining a line of /// motion using an axis and an anchor point. The definition uses local /// anchor points and a local axis so that the initial configuration @@ -391,22 +369,19 @@ typedef struct b2WheelJointDef } b2WheelJointDef; /// Use this to initialize your joint definition -static inline b2WheelJointDef b2DefaultWheelJointDef(void) -{ - b2WheelJointDef def = B2_ZERO_INIT; - def.bodyIdA = b2_nullBodyId; - def.bodyIdB = b2_nullBodyId; - def.localAnchorA = B2_LITERAL(b2Vec2){0.0f, 0.0f}; - def.localAnchorB = B2_LITERAL(b2Vec2){0.0f, 0.0f}; - def.localAxisA = B2_LITERAL(b2Vec2){1.0f, 0.0f}; - def.enableLimit = false; - def.lowerTranslation = 0.0f; - def.upperTranslation = 0.0f; - def.enableMotor = false; - def.maxMotorTorque = 0.0f; - def.motorSpeed = 0.0f; - def.stiffness = 0.0f; - def.damping = 0.0f; - def.collideConnected = false; - return def; -} +static const b2WheelJointDef b2_defaultWheelJointDef = { + B2_NULL_BODY_ID, // bodyIdA + B2_NULL_BODY_ID, // bodyIdB + {0.0f, 0.0f}, // localAnchorA + {0.0f, 0.0f}, // localAnchorB + {1.0f, 0.0f}, // localAxisA + false, // enableLimit + 0.0f, // lowerTranslation + 0.0f, // upperTranslation + false, // enableMotor + 0.0f, // maxMotorTorque + 0.0f, // motorSpeed + 0.0f, // stiffness + 0.0f, // damping + false, // collideConnected +}; diff --git a/include/box2d/joint_util.h b/include/box2d/joint_util.h index 622e0084..0509603d 100644 --- a/include/box2d/joint_util.h +++ b/include/box2d/joint_util.h @@ -7,9 +7,9 @@ #include "id.h" /// Utility to compute linear stiffness values from frequency and damping ratio -BOX2D_API void b2LinearStiffness(float* stiffness, float* damping, float frequencyHertz, float dampingRatio, b2BodyId bodyA, +B2_API void b2LinearStiffness(float* stiffness, float* damping, float frequencyHertz, float dampingRatio, b2BodyId bodyA, b2BodyId bodyB); /// Utility to compute angular stiffness values from frequency and damping ratio -BOX2D_API void b2AngularStiffness(float* stiffness, float* damping, float frequencyHertz, float dampingRatio, b2BodyId bodyA, +B2_API void b2AngularStiffness(float* stiffness, float* damping, float frequencyHertz, float dampingRatio, b2BodyId bodyA, b2BodyId bodyB); diff --git a/include/box2d/manifold.h b/include/box2d/manifold.h index 56926f7c..d8f491db 100644 --- a/include/box2d/manifold.h +++ b/include/box2d/manifold.h @@ -51,48 +51,48 @@ typedef struct b2Manifold static const b2Manifold b2_emptyManifold = B2_ZERO_INIT; /// Compute the collision manifold between two circles. -BOX2D_API b2Manifold b2CollideCircles(const b2Circle* circleA, b2Transform xfA, const b2Circle* circleB, b2Transform xfB); +B2_API b2Manifold b2CollideCircles(const b2Circle* circleA, b2Transform xfA, const b2Circle* circleB, b2Transform xfB); /// Compute the collision manifold between a capsule and circle -BOX2D_API b2Manifold b2CollideCapsuleAndCircle(const b2Capsule* capsuleA, b2Transform xfA, const b2Circle* circleB, +B2_API b2Manifold b2CollideCapsuleAndCircle(const b2Capsule* capsuleA, b2Transform xfA, const b2Circle* circleB, b2Transform xfB); /// Compute the collision manifold between an segment and a circle. -BOX2D_API b2Manifold b2CollideSegmentAndCircle(const b2Segment* segmentA, b2Transform xfA, const b2Circle* circleB, +B2_API b2Manifold b2CollideSegmentAndCircle(const b2Segment* segmentA, b2Transform xfA, const b2Circle* circleB, b2Transform xfB); /// Compute the collision manifold between a polygon and a circle. -BOX2D_API b2Manifold b2CollidePolygonAndCircle(const b2Polygon* polygonA, b2Transform xfA, const b2Circle* circleB, +B2_API b2Manifold b2CollidePolygonAndCircle(const b2Polygon* polygonA, b2Transform xfA, const b2Circle* circleB, b2Transform xfB); /// Compute the collision manifold between a capsule and circle -BOX2D_API b2Manifold b2CollideCapsules(const b2Capsule* capsuleA, b2Transform xfA, const b2Capsule* capsuleB, b2Transform xfB, +B2_API b2Manifold b2CollideCapsules(const b2Capsule* capsuleA, b2Transform xfA, const b2Capsule* capsuleB, b2Transform xfB, b2DistanceCache* cache); /// Compute the collision manifold between an segment and a capsule. -BOX2D_API b2Manifold b2CollideSegmentAndCapsule(const b2Segment* segmentA, b2Transform xfA, const b2Capsule* capsuleB, +B2_API b2Manifold b2CollideSegmentAndCapsule(const b2Segment* segmentA, b2Transform xfA, const b2Capsule* capsuleB, b2Transform xfB, b2DistanceCache* cache); /// Compute the collision manifold between a polygon and capsule -BOX2D_API b2Manifold b2CollidePolygonAndCapsule(const b2Polygon* polygonA, b2Transform xfA, const b2Capsule* capsuleB, +B2_API b2Manifold b2CollidePolygonAndCapsule(const b2Polygon* polygonA, b2Transform xfA, const b2Capsule* capsuleB, b2Transform xfB, b2DistanceCache* cache); /// Compute the collision manifold between two polygons. -BOX2D_API b2Manifold b2CollidePolygons(const b2Polygon* polyA, b2Transform xfA, const b2Polygon* polyB, b2Transform xfB, +B2_API b2Manifold b2CollidePolygons(const b2Polygon* polyA, b2Transform xfA, const b2Polygon* polyB, b2Transform xfB, b2DistanceCache* cache); /// Compute the collision manifold between an segment and a polygon. -BOX2D_API b2Manifold b2CollideSegmentAndPolygon(const b2Segment* segmentA, b2Transform xfA, const b2Polygon* polygonB, +B2_API b2Manifold b2CollideSegmentAndPolygon(const b2Segment* segmentA, b2Transform xfA, const b2Polygon* polygonB, b2Transform xfB, b2DistanceCache* cache); /// Compute the collision manifold between a smooth segment and a circle. -BOX2D_API b2Manifold b2CollideSmoothSegmentAndCircle(const b2SmoothSegment* smoothSegmentA, b2Transform xfA, +B2_API b2Manifold b2CollideSmoothSegmentAndCircle(const b2SmoothSegment* smoothSegmentA, b2Transform xfA, const b2Circle* circleB, b2Transform xfB); /// Compute the collision manifold between an segment and a capsule. -BOX2D_API b2Manifold b2CollideSmoothSegmentAndCapsule(const b2SmoothSegment* segmentA, b2Transform xfA, const b2Capsule* capsuleB, +B2_API b2Manifold b2CollideSmoothSegmentAndCapsule(const b2SmoothSegment* segmentA, b2Transform xfA, const b2Capsule* capsuleB, b2Transform xfB, b2DistanceCache* cache); /// Compute the collision manifold between a smooth segment and a rounded polygon. -BOX2D_API b2Manifold b2CollideSmoothSegmentAndPolygon(const b2SmoothSegment* segmentA, b2Transform xfA, const b2Polygon* polygonB, +B2_API b2Manifold b2CollideSmoothSegmentAndPolygon(const b2SmoothSegment* segmentA, b2Transform xfA, const b2Polygon* polygonB, b2Transform xfB, b2DistanceCache* cache); diff --git a/include/box2d/math.h b/include/box2d/math.h index 37615519..f7938cee 100644 --- a/include/box2d/math.h +++ b/include/box2d/math.h @@ -313,13 +313,13 @@ static inline bool b2AABB_Contains(b2AABB a, b2AABB b) return s; } -BOX2D_API bool b2IsValid(float a); -BOX2D_API bool b2IsValidVec2(b2Vec2 v); +B2_API bool b2IsValid(float a); +B2_API bool b2IsValidVec2(b2Vec2 v); /// Convert this vector into a unit vector -BOX2D_API b2Vec2 b2Normalize(b2Vec2 v); +B2_API b2Vec2 b2Normalize(b2Vec2 v); /// This asserts of the vector is too short -BOX2D_API b2Vec2 b2NormalizeChecked(b2Vec2 v); +B2_API b2Vec2 b2NormalizeChecked(b2Vec2 v); -BOX2D_API b2Vec2 b2GetLengthAndNormalize(float* length, b2Vec2 v); +B2_API b2Vec2 b2GetLengthAndNormalize(float* length, b2Vec2 v); diff --git a/include/box2d/timer.h b/include/box2d/timer.h index 89ed4fea..ff566fb0 100644 --- a/include/box2d/timer.h +++ b/include/box2d/timer.h @@ -18,11 +18,11 @@ typedef struct b2Timer #endif } b2Timer; -BOX2D_API b2Timer b2CreateTimer(void); -BOX2D_API int64_t b2GetTicks(b2Timer* timer); -BOX2D_API float b2GetMilliseconds(const b2Timer* timer); -BOX2D_API float b2GetMillisecondsAndReset(b2Timer* timer); -BOX2D_API void b2SleepMilliseconds(float milliseconds); +B2_API b2Timer b2CreateTimer(void); +B2_API int64_t b2GetTicks(b2Timer* timer); +B2_API float b2GetMilliseconds(const b2Timer* timer); +B2_API float b2GetMillisecondsAndReset(b2Timer* timer); +B2_API void b2SleepMilliseconds(float milliseconds); /// Tracy profiler instrumentation /// https://github.com/wolfpld/tracy diff --git a/include/box2d/types.h b/include/box2d/types.h index e5d3b5fe..bc395026 100644 --- a/include/box2d/types.h +++ b/include/box2d/types.h @@ -19,21 +19,18 @@ #include #include +// clang-format off #ifdef __cplusplus -#define B2_LITERAL(T) T -#define B2_ZERO_INIT \ - { \ - } + #define B2_LITERAL(T) T + #define B2_ZERO_INIT {} #else -/// Used for C literals like (b2Vec2){1.0f, 2.0f} where C++ requires b2Vec2{1.0f, 2.0f} -#define B2_LITERAL(T) (T) - -/// Used for C zero initialization, such as b2Vec2 v = {0} where C++ requires b2Vec2 v = {} -#define B2_ZERO_INIT \ - { \ - 0 \ - } + /// Used for C literals like (b2Vec2){1.0f, 2.0f} where C++ requires b2Vec2{1.0f, 2.0f} + #define B2_LITERAL(T) (T) + + /// Used for C zero initialization, such as b2Vec2 v = {0} where C++ requires b2Vec2 v = {} + #define B2_ZERO_INIT {0} #endif +// clang-format on /// Returns the number of elements of an array #define B2_ARRAY_COUNT(A) (int)(sizeof(A) / sizeof(A[0])) @@ -156,32 +153,39 @@ typedef struct b2WorldDef /// Stack allocator capacity. This controls how much space box2d reserves for per-frame calculations. /// Larger worlds require more space. b2Counters can be used to determine a good capacity for your /// application. - int32_t stackAllocatorCapacity; + int32_t arenaAllocatorCapacity; /// task system hookup uint32_t workerCount; + + /// function to spawn task b2EnqueueTaskCallback* enqueueTask; + + /// function to finish a task b2FinishTaskCallback* finishTask; + + /// User context that is provided to enqueueTask and finishTask void* userTaskContext; } b2WorldDef; /// Use this to initialize your world definition -static inline b2WorldDef b2DefaultWorldDef(void) -{ - b2WorldDef def = B2_ZERO_INIT; - def.gravity = B2_LITERAL(b2Vec2){0.0f, -10.0f}; - def.restitutionThreshold = 1.0f * b2_lengthUnitsPerMeter; - def.contactPushoutVelocity = 3.0f * b2_lengthUnitsPerMeter; - def.contactHertz = 30.0f; - def.contactDampingRatio = 1.0f; - def.enableSleep = true; - def.bodyCapacity = 8; - def.shapeCapacity = 8; - def.contactCapacity = 8; - def.jointCapacity = 8; - def.stackAllocatorCapacity = 1024 * 1024; - return def; -} +static const b2WorldDef b2_defaultWorldDef = { + {0.0f, -10.0f}, // gravity + 1.0f * b2_lengthUnitsPerMeter, // restitutionThreshold + 3.0f * b2_lengthUnitsPerMeter, // contactPushoutVelocity + 30.0, // contactHertz + 1.0f, // contactDampingRatio + true, // enableSleep + 0, // bodyCapacity + 0, // shapeCapacity + 0, // contactCapacity + 0, // jointCapacity + 1024 * 1024, // arenaAllocatorCapacity + 0, // workerCount + NULL, // enqueueTask + NULL, // finishTask + NULL, // userTaskContext +}; /// The body type. /// static: zero mass, zero velocity, may be manually moved @@ -248,7 +252,19 @@ typedef struct b2BodyDef /// Use this to initialize your body definition static const b2BodyDef b2_defaultBodyDef = { - b2_staticBody, {0.0f, 0.0f}, 0.0f, {0.0f, 0.0f}, 0.0f, 0.0f, 0.0f, 1.0f, NULL, true, true, false, true, + b2_staticBody, // bodyType + {0.0f, 0.0f}, // position + 0.0f, // angle + {0.0f, 0.0f}, // linearVelocity + 0.0f, // angularVelocity + 0.0f, // linearDamping + 0.0f, // angularDamping + 1.0f, // gravityScale + NULL, // userData + true, // enableSleep + true, // isAwake + false, // fixedRotation + true, // isEnabled }; /// This holds contact filtering data. @@ -330,7 +346,15 @@ typedef struct b2ShapeDef /// Use this to initialize your shape definition static const b2ShapeDef b2_defaultShapeDef = { - NULL, 0.6f, 0.0f, 1.0f, {0x00000001, 0xFFFFFFFF, 0}, false, true, true, false, + NULL, // userData + 0.6f, // friction + 0.0f, // restitution + 1.0f, // density + {0x00000001, 0xFFFFFFFF, 0}, // filter + false, // isSensor + true, // enableSensorEvents + true, // enableContactEvents + false, // enablePreSolveEvents }; /// Used to create a chain of edges. This is designed to eliminate ghost collisions with some limitations. @@ -370,7 +394,15 @@ typedef struct b2ChainDef } b2ChainDef; /// Use this to initialize your chain definition -static const b2ChainDef b2_defaultChainDef = {NULL, 0, false, NULL, 0.6f, 0.0f, {0x00000001, 0xFFFFFFFF, 0}}; +static const b2ChainDef b2_defaultChainDef = { + NULL, // points + 0, // count + false, // loop + NULL, // userData + 0.6f, // friction + 0.0f, // restitution + {0x00000001, 0xFFFFFFFF, 0} // filter +}; /// Profiling data. Times are in milliseconds. typedef struct b2Profile diff --git a/samples/collection/benchmark.cpp b/samples/collection/benchmark.cpp index 808249b1..25209bad 100644 --- a/samples/collection/benchmark.cpp +++ b/samples/collection/benchmark.cpp @@ -274,7 +274,7 @@ class BenchmarkTumbler : public Sample // m_motorSpeed = 9.0f; m_motorSpeed = 25.0f; - b2RevoluteJointDef jd = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jd = b2_defaultRevoluteJointDef; jd.bodyIdA = groundId; jd.bodyIdB = bodyId; jd.localAnchorA = {0.0f, 10.0f}; @@ -399,7 +399,7 @@ class BenchmarkManyTumblers : public Sample polygon = b2MakeOffsetBox(2.0f, 0.25f, {0.0f, -2.0f}, 0.0); b2CreatePolygonShape(bodyId, &shapeDef, &polygon); - b2RevoluteJointDef jd = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jd = b2_defaultRevoluteJointDef; jd.bodyIdA = m_groundId; jd.bodyIdB = bodyId; jd.localAnchorA = position; @@ -902,7 +902,7 @@ class BenchmarkJointGrid : public Sample b2Circle circle = {0}; circle.radius = rad; - b2RevoluteJointDef jd = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jd = b2_defaultRevoluteJointDef; for (int32_t k = 0; k < numk; ++k) { diff --git a/samples/collection/human.cpp b/samples/collection/human.cpp index eeecd7f3..97b4b7e5 100644 --- a/samples/collection/human.cpp +++ b/samples/collection/human.cpp @@ -71,7 +71,7 @@ void Human::Spawn(b2WorldId worldId, b2Vec2 position, float scale, int groupInde b2CreateCapsuleShape(bone->bodyId, &shapeDef, &capsule); b2Vec2 pivot = b2Add({0.0f, 1.0f * s}, position); - b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jointDef = b2_defaultRevoluteJointDef; jointDef.bodyIdA = m_bones[bone->parentIndex].bodyId; jointDef.bodyIdB = bone->bodyId; jointDef.localAnchorA = b2Body_GetLocalPoint(jointDef.bodyIdA, pivot); @@ -101,7 +101,7 @@ void Human::Spawn(b2WorldId worldId, b2Vec2 position, float scale, int groupInde b2CreateCapsuleShape(bone->bodyId, &shapeDef, &capsule); b2Vec2 pivot = b2Add({0.0f, 1.4f * s}, position); - b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jointDef = b2_defaultRevoluteJointDef; jointDef.bodyIdA = m_bones[bone->parentIndex].bodyId; jointDef.bodyIdB = bone->bodyId; jointDef.localAnchorA = b2Body_GetLocalPoint(jointDef.bodyIdA, pivot); @@ -128,7 +128,7 @@ void Human::Spawn(b2WorldId worldId, b2Vec2 position, float scale, int groupInde b2CreateCapsuleShape(bone->bodyId, &shapeDef, &capsule); b2Vec2 pivot = b2Add({0.0f, 0.9f * s}, position); - b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jointDef = b2_defaultRevoluteJointDef; jointDef.bodyIdA = m_bones[bone->parentIndex].bodyId; jointDef.bodyIdB = bone->bodyId; jointDef.localAnchorA = b2Body_GetLocalPoint(jointDef.bodyIdA, pivot); @@ -161,7 +161,7 @@ void Human::Spawn(b2WorldId worldId, b2Vec2 position, float scale, int groupInde b2CreateCapsuleShape(bone->bodyId, &footShapeDef, &capsule); b2Vec2 pivot = b2Add({0.0f, 0.625f * s}, position); - b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jointDef = b2_defaultRevoluteJointDef; jointDef.bodyIdA = m_bones[bone->parentIndex].bodyId; jointDef.bodyIdB = bone->bodyId; jointDef.localAnchorA = b2Body_GetLocalPoint(jointDef.bodyIdA, pivot); @@ -188,7 +188,7 @@ void Human::Spawn(b2WorldId worldId, b2Vec2 position, float scale, int groupInde b2CreateCapsuleShape(bone->bodyId, &shapeDef, &capsule); b2Vec2 pivot = b2Add({0.0f, 0.9f * s}, position); - b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jointDef = b2_defaultRevoluteJointDef; jointDef.bodyIdA = m_bones[bone->parentIndex].bodyId; jointDef.bodyIdB = bone->bodyId; jointDef.localAnchorA = b2Body_GetLocalPoint(jointDef.bodyIdA, pivot); @@ -221,7 +221,7 @@ void Human::Spawn(b2WorldId worldId, b2Vec2 position, float scale, int groupInde b2CreateCapsuleShape(bone->bodyId, &footShapeDef, &capsule); b2Vec2 pivot = b2Add({0.0f, 0.625f * s}, position); - b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jointDef = b2_defaultRevoluteJointDef; jointDef.bodyIdA = m_bones[bone->parentIndex].bodyId; jointDef.bodyIdB = bone->bodyId; jointDef.localAnchorA = b2Body_GetLocalPoint(jointDef.bodyIdA, pivot); @@ -248,7 +248,7 @@ void Human::Spawn(b2WorldId worldId, b2Vec2 position, float scale, int groupInde b2CreateCapsuleShape(bone->bodyId, &shapeDef, &capsule); b2Vec2 pivot = b2Add({0.0f, 1.35f * s}, position); - b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jointDef = b2_defaultRevoluteJointDef; jointDef.bodyIdA = m_bones[bone->parentIndex].bodyId; jointDef.bodyIdB = bone->bodyId; jointDef.localAnchorA = b2Body_GetLocalPoint(jointDef.bodyIdA, pivot); @@ -275,7 +275,7 @@ void Human::Spawn(b2WorldId worldId, b2Vec2 position, float scale, int groupInde b2CreateCapsuleShape(bone->bodyId, &shapeDef, &capsule); b2Vec2 pivot = b2Add({0.0f, 1.1f * s}, position); - b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jointDef = b2_defaultRevoluteJointDef; jointDef.bodyIdA = m_bones[bone->parentIndex].bodyId; jointDef.bodyIdB = bone->bodyId; jointDef.localAnchorA = b2Body_GetLocalPoint(jointDef.bodyIdA, pivot); @@ -302,7 +302,7 @@ void Human::Spawn(b2WorldId worldId, b2Vec2 position, float scale, int groupInde b2CreateCapsuleShape(bone->bodyId, &shapeDef, &capsule); b2Vec2 pivot = b2Add({0.0f, 1.35f * s}, position); - b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jointDef = b2_defaultRevoluteJointDef; jointDef.bodyIdA = m_bones[bone->parentIndex].bodyId; jointDef.bodyIdB = bone->bodyId; jointDef.localAnchorA = b2Body_GetLocalPoint(jointDef.bodyIdA, pivot); @@ -329,7 +329,7 @@ void Human::Spawn(b2WorldId worldId, b2Vec2 position, float scale, int groupInde b2CreateCapsuleShape(bone->bodyId, &shapeDef, &capsule); b2Vec2 pivot = b2Add({0.0f, 1.1f * s}, position); - b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jointDef = b2_defaultRevoluteJointDef; jointDef.bodyIdA = m_bones[bone->parentIndex].bodyId; jointDef.bodyIdB = bone->bodyId; jointDef.localAnchorA = b2Body_GetLocalPoint(jointDef.bodyIdA, pivot); diff --git a/samples/collection/sample_bodies.cpp b/samples/collection/sample_bodies.cpp index aed73287..b6660994 100644 --- a/samples/collection/sample_bodies.cpp +++ b/samples/collection/sample_bodies.cpp @@ -52,7 +52,7 @@ class BodyType : public Sample shapeDef.density = 2.0f; b2CreatePolygonShape(m_platformId, &shapeDef, &box); - b2RevoluteJointDef revoluteDef = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef revoluteDef = b2_defaultRevoluteJointDef; b2Vec2 pivot = {0.0f, 5.0f}; revoluteDef.bodyIdA = m_attachmentId; revoluteDef.bodyIdB = m_platformId; @@ -62,7 +62,7 @@ class BodyType : public Sample revoluteDef.enableMotor = true; b2CreateRevoluteJoint(m_worldId, &revoluteDef); - b2PrismaticJointDef prismaticDef = b2DefaultPrismaticJointDef(); + b2PrismaticJointDef prismaticDef = b2_defaultPrismaticJointDef; b2Vec2 anchor = {0.0f, 5.0f}; prismaticDef.bodyIdA = groundId; prismaticDef.bodyIdB = m_platformId; @@ -377,7 +377,7 @@ class Weeble : public Sample // See: https://en.wikipedia.org/wiki/Parallel_axis_theorem I += mass * offset * offset; - b2MassData massData = {mass, {0.0f, -offset}, I, 2.0f, 4.0f}; + b2MassData massData = {mass, {0.0f, -offset}, I}; b2Body_SetMassData(m_weebleId, massData); } } diff --git a/samples/collection/sample_events.cpp b/samples/collection/sample_events.cpp index 86ea4c34..28ddcf80 100644 --- a/samples/collection/sample_events.cpp +++ b/samples/collection/sample_events.cpp @@ -127,7 +127,7 @@ class SensorEvent : public Sample b2CreatePolygonShape(bodyId, &shapeDef, &box); - b2RevoluteJointDef revoluteDef = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef revoluteDef = b2_defaultRevoluteJointDef; revoluteDef.bodyIdA = groundId; revoluteDef.bodyIdB = bodyId; revoluteDef.localAnchorA = bodyDef.position; diff --git a/samples/collection/sample_joints.cpp b/samples/collection/sample_joints.cpp index 5e3a2220..492204ed 100644 --- a/samples/collection/sample_joints.cpp +++ b/samples/collection/sample_joints.cpp @@ -78,7 +78,7 @@ class DistanceJoint : public Sample float yOffset = 20.0f; - b2DistanceJointDef jointDef = b2DefaultDistanceJointDef(); + b2DistanceJointDef jointDef = b2_defaultDistanceJointDef; b2BodyId prevBodyId = m_groundId; for (int32_t i = 0; i < m_count; ++i) @@ -237,7 +237,7 @@ class MotorJoint : public Sample m_maxTorque = 500.0f; m_correctionFactor = 0.3f; - b2MotorJointDef jointDef = b2DefaultMotorJointDef(); + b2MotorJointDef jointDef = b2_defaultMotorJointDef; jointDef.bodyIdA = groundId; jointDef.bodyIdB = bodyId; jointDef.maxForce = m_maxForce; @@ -358,7 +358,7 @@ class RevoluteJoint : public Sample b2CreatePolygonShape(bodyId, &shapeDef, &box); b2Vec2 pivot = {-10.0f, 20.5f}; - b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jointDef = b2_defaultRevoluteJointDef; jointDef.bodyIdA = groundId; jointDef.bodyIdB = bodyId; jointDef.localAnchorA = b2Body_GetLocalPoint(jointDef.bodyIdA, pivot); @@ -400,7 +400,7 @@ class RevoluteJoint : public Sample b2CreatePolygonShape(body, &shapeDef, &box); b2Vec2 pivot = {19.0f, 10.0f}; - b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jointDef = b2_defaultRevoluteJointDef; jointDef.bodyIdA = groundId; jointDef.bodyIdB = body; jointDef.localAnchorA = b2Body_GetLocalPoint(jointDef.bodyIdA, pivot); @@ -505,7 +505,7 @@ class PrismaticJoint : public Sample b2Vec2 pivot = {0.0f, 9.0f}; b2Vec2 axis = b2Normalize({1.0f, 1.0f}); - b2PrismaticJointDef jointDef = b2DefaultPrismaticJointDef(); + b2PrismaticJointDef jointDef = b2_defaultPrismaticJointDef; jointDef.bodyIdA = groundId; jointDef.bodyIdB = bodyId; jointDef.localAxisA = b2Body_GetLocalVector(jointDef.bodyIdA, axis); @@ -609,7 +609,7 @@ class WheelJoint : public Sample b2Vec2 pivot = {0.0f, 10.0f}; b2Vec2 axis = b2Normalize({1.0f, 1.0f}); - b2WheelJointDef jointDef = b2DefaultWheelJointDef(); + b2WheelJointDef jointDef = b2_defaultWheelJointDef; jointDef.bodyIdA = groundId; jointDef.bodyIdB = bodyId; jointDef.localAxisA = b2Body_GetLocalVector(jointDef.bodyIdA, axis); @@ -721,7 +721,7 @@ class Bridge : public Sample b2ShapeDef shapeDef = b2_defaultShapeDef; shapeDef.density = 20.0f; - b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jointDef = b2_defaultRevoluteJointDef; int32_t jointIndex = 0; m_frictionTorque = 200.0f; @@ -857,7 +857,7 @@ class BallAndChain : public Sample b2ShapeDef shapeDef = b2_defaultShapeDef; shapeDef.density = 20.0f; - b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jointDef = b2_defaultRevoluteJointDef; int32_t jointIndex = 0; @@ -964,7 +964,7 @@ class Cantilever : public Sample b2ShapeDef shapeDef = b2_defaultShapeDef; shapeDef.density = 20.0f; - b2WeldJointDef jointDef = b2DefaultWeldJointDef(); + b2WeldJointDef jointDef = b2_defaultWeldJointDef; b2BodyId prevBodyId = groundId; for (int32_t i = 0; i < e_count; ++i) @@ -1072,7 +1072,7 @@ class FixedRotation : public Sample float length = 2.0f; b2Vec2 pivot1 = {position.x, position.y + 1.0f + length}; b2Vec2 pivot2 = {position.x, position.y + 1.0f}; - b2DistanceJointDef jointDef = b2DefaultDistanceJointDef(); + b2DistanceJointDef jointDef = b2_defaultDistanceJointDef; jointDef.bodyIdA = m_groundId; jointDef.bodyIdB = m_bodyIds[index]; jointDef.localAnchorA = b2Body_GetLocalPoint(jointDef.bodyIdA, pivot1); @@ -1094,7 +1094,7 @@ class FixedRotation : public Sample b2CreatePolygonShape(m_bodyIds[index], &b2_defaultShapeDef, &box); b2Vec2 pivot = {position.x - 1.0f, position.y}; - b2MotorJointDef jointDef = b2DefaultMotorJointDef(); + b2MotorJointDef jointDef = b2_defaultMotorJointDef; jointDef.bodyIdA = m_groundId; jointDef.bodyIdB = m_bodyIds[index]; jointDef.linearOffset = position; @@ -1115,7 +1115,7 @@ class FixedRotation : public Sample b2CreatePolygonShape(m_bodyIds[index], &b2_defaultShapeDef, &box); b2Vec2 pivot = {position.x - 1.0f, position.y}; - b2PrismaticJointDef jointDef = b2DefaultPrismaticJointDef(); + b2PrismaticJointDef jointDef = b2_defaultPrismaticJointDef; jointDef.bodyIdA = m_groundId; jointDef.bodyIdB = m_bodyIds[index]; jointDef.localAnchorA = b2Body_GetLocalPoint(jointDef.bodyIdA, pivot); @@ -1136,7 +1136,7 @@ class FixedRotation : public Sample b2CreatePolygonShape(m_bodyIds[index], &b2_defaultShapeDef, &box); b2Vec2 pivot = {position.x - 1.0f, position.y}; - b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jointDef = b2_defaultRevoluteJointDef; jointDef.bodyIdA = m_groundId; jointDef.bodyIdB = m_bodyIds[index]; jointDef.localAnchorA = b2Body_GetLocalPoint(jointDef.bodyIdA, pivot); @@ -1156,7 +1156,7 @@ class FixedRotation : public Sample b2CreatePolygonShape(m_bodyIds[index], &b2_defaultShapeDef, &box); b2Vec2 pivot = {position.x - 1.0f, position.y}; - b2WeldJointDef jointDef = b2DefaultWeldJointDef(); + b2WeldJointDef jointDef = b2_defaultWeldJointDef; jointDef.bodyIdA = m_groundId; jointDef.bodyIdB = m_bodyIds[index]; jointDef.localAnchorA = b2Body_GetLocalPoint(jointDef.bodyIdA, pivot); @@ -1180,7 +1180,7 @@ class FixedRotation : public Sample b2CreatePolygonShape(m_bodyIds[index], &b2_defaultShapeDef, &box); b2Vec2 pivot = {position.x - 1.0f, position.y}; - b2WheelJointDef jointDef = b2DefaultWheelJointDef(); + b2WheelJointDef jointDef = b2_defaultWheelJointDef; jointDef.bodyIdA = m_groundId; jointDef.bodyIdB = m_bodyIds[index]; jointDef.localAnchorA = b2Body_GetLocalPoint(jointDef.bodyIdA, pivot); @@ -1413,7 +1413,7 @@ class Car : public Sample b2CreatePolygonShape(bodyId, &b2_defaultShapeDef, &box); b2Vec2 pivot = bodyDef.position; - b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jointDef = b2_defaultRevoluteJointDef; jointDef.bodyIdA = groundId; jointDef.bodyIdB = bodyId; jointDef.localAnchorA = b2Body_GetLocalPoint(jointDef.bodyIdA, pivot); @@ -1429,7 +1429,7 @@ class Car : public Sample int N = 20; b2Capsule capsule = {{-1.0f, 0.0f}, {1.0f, 0.0f}, 0.125f}; - b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef(); + b2RevoluteJointDef jointDef = b2_defaultRevoluteJointDef; b2BodyId prevBodyId = groundId; for (int i = 0; i < N; ++i) @@ -1534,7 +1534,7 @@ class Car : public Sample b2Vec2 pivot = b2Body_GetPosition(m_wheelId1); - b2WheelJointDef jointDef = b2DefaultWheelJointDef(); + b2WheelJointDef jointDef = b2_defaultWheelJointDef; jointDef.bodyIdA = m_carId; jointDef.bodyIdB = m_wheelId1; diff --git a/samples/collection/sample_manifold.cpp b/samples/collection/sample_manifold.cpp index dc982af7..b3fc82c3 100644 --- a/samples/collection/sample_manifold.cpp +++ b/samples/collection/sample_manifold.cpp @@ -537,7 +537,7 @@ class Manifold : public Sample // smooth-segment vs circle { - b2SmoothSegment segment = {{2.0f, 1.0f}, {{1.0f, 1.0f}, {-1.0f, 0.0f}}, {-2.0f, 0.0f}}; + b2SmoothSegment segment = {{2.0f, 1.0f}, {{1.0f, 1.0f}, {-1.0f, 0.0f}}, {-2.0f, 0.0f}, -1}; b2Circle circle = {{0.0f, 0.0f}, 0.5f}; b2Transform xf1 = {offset, b2Rot_identity}; @@ -564,12 +564,12 @@ class Manifold : public Sample // smooth-segment vs rounded polygon { - b2SmoothSegment segment1 = {{2.0f, 1.0f}, {{1.0f, 1.0f}, {-1.0f, 0.0f}}, {-2.0f, 0.0f}}; - b2SmoothSegment segment2 = {{3.0f, 1.0f}, {{2.0f, 1.0f}, {1.0f, 1.0f}}, {-1.0f, 0.0f}}; - //b2SmoothSegment segment1 = {{2.0f, 0.0f}, {{1.0f, 0.0f}, {-1.0f, 0.0f}}, {-2.0f, 0.0f}}; - //b2SmoothSegment segment2 = {{3.0f, 0.0f}, {{2.0f, 0.0f}, {1.0f, 0.0f}}, {-1.0f, 0.0f}}; - //b2SmoothSegment segment1 = {{0.5f, 1.0f}, {{0.0f, 2.0f}, {-0.5f, 1.0f}}, {-1.0f, 0.0f}}; - //b2SmoothSegment segment2 = {{1.0f, 0.0f}, {{0.5f, 1.0f}, {0.0f, 2.0f}}, {-0.5f, 1.0f}}; + b2SmoothSegment segment1 = {{2.0f, 1.0f}, {{1.0f, 1.0f}, {-1.0f, 0.0f}}, {-2.0f, 0.0f}, -1}; + b2SmoothSegment segment2 = {{3.0f, 1.0f}, {{2.0f, 1.0f}, {1.0f, 1.0f}}, {-1.0f, 0.0f}, -1}; + //b2SmoothSegment segment1 = {{2.0f, 0.0f}, {{1.0f, 0.0f}, {-1.0f, 0.0f}}, {-2.0f, 0.0f}, -1}; + //b2SmoothSegment segment2 = {{3.0f, 0.0f}, {{2.0f, 0.0f}, {1.0f, 0.0f}}, {-1.0f, 0.0f}, -1}; + //b2SmoothSegment segment1 = {{0.5f, 1.0f}, {{0.0f, 2.0f}, {-0.5f, 1.0f}}, {-1.0f, 0.0f}, -1}; + //b2SmoothSegment segment2 = {{1.0f, 0.0f}, {{0.5f, 1.0f}, {0.0f, 2.0f}}, {-0.5f, 1.0f}, -1}; float h = 0.5f - m_round; b2Polygon rox = b2MakeRoundedBox(h, h, m_round); @@ -629,8 +629,8 @@ class Manifold : public Sample // smooth-segment vs capsule { - b2SmoothSegment segment1 = {{2.0f, 1.0f}, {{1.0f, 1.0f}, {-1.0f, 0.0f}}, {-2.0f, 0.0f}}; - b2SmoothSegment segment2 = {{3.0f, 1.0f}, {{2.0f, 1.0f}, {1.0f, 1.0f}}, {-1.0f, 0.0f}}; + b2SmoothSegment segment1 = {{2.0f, 1.0f}, {{1.0f, 1.0f}, {-1.0f, 0.0f}}, {-2.0f, 0.0f}, -1}; + b2SmoothSegment segment2 = {{3.0f, 1.0f}, {{2.0f, 1.0f}, {1.0f, 1.0f}}, {-1.0f, 0.0f}, -1}; b2Capsule capsule = {{-0.5f, 0.0f}, {0.5f, 0.0}, 0.25f}; b2Transform xf1 = {offset, b2Rot_identity}; @@ -794,7 +794,7 @@ class SmoothManifold : public Sample b2Vec2 p2 = points[i2]; b2Vec2 g2 = points[i3]; - m_segments[i] = {g1, {p1, p2}, g2}; + m_segments[i] = {g1, {p1, p2}, g2, -1}; } } diff --git a/samples/collection/sample_shapes.cpp b/samples/collection/sample_shapes.cpp index a5a3f84c..de52c21b 100644 --- a/samples/collection/sample_shapes.cpp +++ b/samples/collection/sample_shapes.cpp @@ -407,3 +407,215 @@ class CompoundShapes : public Sample }; static int sampleCompoundShape = RegisterSample("Shapes", "Compound Shapes", CompoundShapes::Create); + +class ShapeFilter : public Sample +{ +public: + + enum CollisionBits + { + GROUND = 0x00000001, + TEAM1 = 0x00000002, + TEAM2 = 0x00000004, + TEAM3 = 0x00000008, + + ALL_BITS = (~0u) + }; + + ShapeFilter(const Settings& settings) + : Sample(settings) + { + if (settings.restart == false) + { + g_camera.m_zoom = 0.5f; + g_camera.m_center = {0.0f, 5.0f}; + } + + b2BodyId groundId; + { + groundId = b2CreateBody(m_worldId, &b2_defaultBodyDef); + b2Segment segment = {{-20.0f, 0.0f}, {20.0f, 0.0f}}; + + b2ShapeDef shapeDef = b2_defaultShapeDef; + shapeDef.filter.categoryBits = GROUND; + shapeDef.filter.maskBits = ALL_BITS; + + b2CreateSegmentShape(groundId, &b2_defaultShapeDef, &segment); + } + + // Define motorized body + { + b2BodyDef bodyDef = b2_defaultBodyDef; + bodyDef.type = b2_dynamicBody; + + bodyDef.position = {0.0f, 4.0f}; + m_player1Id = b2CreateBody(m_worldId, &bodyDef); + + bodyDef.position = {0.0f, 8.0f}; + m_player2Id = b2CreateBody(m_worldId, &bodyDef); + + bodyDef.position = {0.0f, 12.0f}; + m_player3Id = b2CreateBody(m_worldId, &bodyDef); + + b2Polygon box = b2MakeBox(2.0f, 1.0f); + + b2ShapeDef shapeDef = b2_defaultShapeDef; + + shapeDef.filter.categoryBits = TEAM1; + shapeDef.filter.maskBits = GROUND | TEAM2 | TEAM3; + m_shape1Id = b2CreatePolygonShape(m_player1Id, &shapeDef, &box); + + shapeDef.filter.categoryBits = TEAM2; + shapeDef.filter.maskBits = GROUND | TEAM1 | TEAM3; + m_shape2Id = b2CreatePolygonShape(m_player2Id, &shapeDef, &box); + + shapeDef.filter.categoryBits = TEAM3; + shapeDef.filter.maskBits = GROUND | TEAM1 | TEAM2; + m_shape3Id = b2CreatePolygonShape(m_player3Id, &shapeDef, &box); + } + } + + void UpdateUI() override + { + ImGui::SetNextWindowPos(ImVec2(10.0f, 100.0f)); + ImGui::SetNextWindowSize(ImVec2(250.0f, 240.0f)); + ImGui::Begin("Shape Filter", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize); + + ImGui::Text("Player 1 Collides With"); + { + b2Filter filter1 = b2Shape_GetFilter(m_shape1Id); + bool team2 = (filter1.maskBits & TEAM2) == TEAM2; + if (ImGui::Checkbox("Team 2##1", &team2)) + { + if (team2) + { + filter1.maskBits |= TEAM2; + } + else + { + filter1.maskBits &= ~TEAM2; + } + + b2Shape_SetFilter(m_shape1Id, filter1); + } + + bool team3 = (filter1.maskBits & TEAM3) == TEAM3; + if (ImGui::Checkbox("Team 3##1", &team3)) + { + if (team3) + { + filter1.maskBits |= TEAM3; + } + else + { + filter1.maskBits &= ~TEAM3; + } + + b2Shape_SetFilter(m_shape1Id, filter1); + } + } + + ImGui::Separator(); + + ImGui::Text("Player 2 Collides With"); + { + b2Filter filter2 = b2Shape_GetFilter(m_shape2Id); + bool team1 = (filter2.maskBits & TEAM1) == TEAM1; + if (ImGui::Checkbox("Team 1##2", &team1)) + { + if (team1) + { + filter2.maskBits |= TEAM1; + } + else + { + filter2.maskBits &= ~TEAM1; + } + + b2Shape_SetFilter(m_shape2Id, filter2); + } + + bool team3 = (filter2.maskBits & TEAM3) == TEAM3; + if (ImGui::Checkbox("Team 3##2", &team3)) + { + if (team3) + { + filter2.maskBits |= TEAM3; + } + else + { + filter2.maskBits &= ~TEAM3; + } + + b2Shape_SetFilter(m_shape2Id, filter2); + } + } + + ImGui::Separator(); + + ImGui::Text("Player 3 Collides With"); + { + b2Filter filter3 = b2Shape_GetFilter(m_shape3Id); + bool team1 = (filter3.maskBits & TEAM1) == TEAM1; + if (ImGui::Checkbox("Team 1##3", &team1)) + { + if (team1) + { + filter3.maskBits |= TEAM1; + } + else + { + filter3.maskBits &= ~TEAM1; + } + + b2Shape_SetFilter(m_shape3Id, filter3); + } + + bool team2 = (filter3.maskBits & TEAM2) == TEAM2; + if (ImGui::Checkbox("Team 2##3", &team2)) + { + if (team2) + { + filter3.maskBits |= TEAM2; + } + else + { + filter3.maskBits &= ~TEAM2; + } + + b2Shape_SetFilter(m_shape3Id, filter3); + } + } + + ImGui::End(); + } + + void Step(Settings& settings) override + { + Sample::Step(settings); + + b2Vec2 p1 = b2Body_GetPosition(m_player1Id); + g_draw.DrawString({p1.x - 0.5f, p1.y}, "player 1"); + + b2Vec2 p2 = b2Body_GetPosition(m_player2Id); + g_draw.DrawString({p2.x - 0.5f, p2.y}, "player 2"); + + b2Vec2 p3 = b2Body_GetPosition(m_player3Id); + g_draw.DrawString({p3.x - 0.5f, p3.y}, "player 3"); + } + + static Sample* Create(const Settings& settings) + { + return new ShapeFilter(settings); + } + + b2BodyId m_player1Id; + b2BodyId m_player2Id; + b2BodyId m_player3Id; + + b2ShapeId m_shape1Id; + b2ShapeId m_shape2Id; + b2ShapeId m_shape3Id; +}; + +static int sampleShapeFilter = RegisterSample("Shapes", "Filter", ShapeFilter::Create); diff --git a/samples/main.cpp b/samples/main.cpp index 669fd8de..af0b7522 100644 --- a/samples/main.cpp +++ b/samples/main.cpp @@ -565,7 +565,7 @@ int main(int, char**) // MSAA glfwWindowHint(GLFW_SAMPLES, 4); - snprintf(buffer, 128, "Box2D Version %d.%d.%d Smooth", b2_version.major, b2_version.minor, b2_version.revision); + snprintf(buffer, 128, "Box2D Version %d.%d.%d (alpha)", b2_version.major, b2_version.minor, b2_version.revision); if (GLFWmonitor* primaryMonitor = glfwGetPrimaryMonitor()) { diff --git a/samples/sample.cpp b/samples/sample.cpp index a2060ec7..4e2b4b98 100644 --- a/samples/sample.cpp +++ b/samples/sample.cpp @@ -56,7 +56,7 @@ Sample::Sample(const Settings& settings) m_scheduler.Initialize(settings.workerCount); m_taskCount = 0; - b2WorldDef worldDef = b2DefaultWorldDef(); + b2WorldDef worldDef = b2_defaultWorldDef; worldDef.workerCount = settings.workerCount; worldDef.enqueueTask = &EnqueueTask; worldDef.finishTask = &FinishTask; @@ -66,7 +66,7 @@ Sample::Sample(const Settings& settings) // These are not ideal, but useful for testing Box2D worldDef.bodyCapacity = 2; worldDef.contactCapacity = 2; - worldDef.stackAllocatorCapacity = 0; + worldDef.arenaAllocatorCapacity = 0; m_worldId = b2CreateWorld(&worldDef); m_textLine = 30; @@ -149,7 +149,7 @@ void Sample::MouseDown(b2Vec2 p, int button, int mod) m_groundBodyId = b2CreateBody(m_worldId, &b2_defaultBodyDef); - b2MouseJointDef jd = b2DefaultMouseJointDef(); + b2MouseJointDef jd = b2_defaultMouseJointDef; jd.bodyIdA = m_groundBodyId; jd.bodyIdB = queryContext.bodyId; jd.target = p; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eba33982..84f1b8ba 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,3 @@ -configure_file(user_constants.h.in user_constants.h) - set(BOX2D_SOURCE_FILES aabb.c aabb.h @@ -87,9 +85,16 @@ set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) add_library(box2d ${BOX2D_SOURCE_FILES} ${BOX2D_API_FILES}) +if (BOX2D_USER_CONSTANTS) + # this file allows users to override constants + configure_file(user_constants.h.in user_constants.h) + target_compile_definitions(box2d PUBLIC BOX2D_USER_CONSTANTS) +endif() + # Generate box2d_export.h to handles shared library builds -include(GenerateExportHeader) -generate_export_header(box2d) +# turned this off to make Box2D easier to use without cmake +# include(GenerateExportHeader) +# generate_export_header(box2d) target_include_directories(box2d PUBLIC @@ -112,7 +117,27 @@ set_target_properties(box2d PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR} ) +if (BOX2D_PROFILE) + target_compile_definitions(box2d PRIVATE BOX2D_PROFILE) + + FetchContent_Declare( + tracy + GIT_REPOSITORY https://github.com/wolfpld/tracy.git + GIT_TAG master + GIT_SHALLOW TRUE + GIT_PROGRESS TRUE + ) + FetchContent_MakeAvailable(tracy) + + target_link_libraries(box2d PUBLIC TracyClient) +endif() + if (MSVC) + if (BUILD_SHARED_LIBS) + # this is needed by DLL users to import Box2D symbols + target_compile_definitions(box2d INTERFACE BOX2D_DLL) + endif() + # Visual Studio won't load the natvis unless it is in the project target_sources(box2d PRIVATE box2d.natvis) @@ -136,21 +161,6 @@ elseif (APPLE) # target_compile_options(box2d PRIVATE) endif() -if (BOX2D_PROFILE) - target_compile_definitions(box2d PRIVATE BOX2D_PROFILE) - - FetchContent_Declare( - tracy - GIT_REPOSITORY https://github.com/wolfpld/tracy.git - GIT_TAG master - GIT_SHALLOW TRUE - GIT_PROGRESS TRUE - ) - FetchContent_MakeAvailable(tracy) - - target_link_libraries(box2d PUBLIC TracyClient) -endif() - source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" PREFIX "src" FILES ${BOX2D_SOURCE_FILES}) source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/../include" PREFIX "include" FILES ${BOX2D_API_FILES}) diff --git a/src/body.c b/src/body.c index 933633bc..c6c5027c 100644 --- a/src/body.c +++ b/src/body.c @@ -189,7 +189,7 @@ static void b2DisableBody(b2World* world, b2Body* body) } } -BOX2D_API b2BodyId b2CreateBody(b2WorldId worldId, const b2BodyDef* def) +B2_API b2BodyId b2CreateBody(b2WorldId worldId, const b2BodyDef* def) { b2World* world = b2GetWorldFromId(worldId); B2_ASSERT(world->locked == false); @@ -331,7 +331,7 @@ void b2DestroyBodyInternal(b2World* world, b2Body* body) b2FreeObject(&world->bodyPool, &body->object); } -BOX2D_API void b2DestroyBody(b2BodyId bodyId) +B2_API void b2DestroyBody(b2BodyId bodyId) { b2World* world = b2GetWorldFromIndex(bodyId.world); B2_ASSERT(world->locked == false); @@ -481,13 +481,13 @@ static void b2ComputeMass(b2World* world, b2Body* body) } b2MassData massData = b2ComputeShapeMass(s); - body->mass += massData.mass; localCenter = b2MulAdd(localCenter, massData.mass, massData.center); body->I += massData.I; - body->minExtent = B2_MIN(body->minExtent, massData.minExtent); - body->maxExtent = B2_MAX(body->maxExtent, massData.maxExtent); + b2ShapeExtent extent = b2ComputeShapeExtent(s); + body->minExtent = B2_MIN(body->minExtent, extent.minExtent); + body->maxExtent = B2_MAX(body->maxExtent, extent.maxExtent); } // Compute center of mass. @@ -730,6 +730,7 @@ b2ChainId b2CreateChain(b2BodyId bodyId, const b2ChainDef* def) b2ChainShape* chainShape = (b2ChainShape*)b2AllocObject(&world->chainPool); world->chains = (b2ChainShape*)world->chainPool.memory; + int32_t chainIndex = chainShape->object.index; chainShape->bodyIndex = bodyId.index; chainShape->nextIndex = body->chainList; body->chainList = chainShape->object.index; @@ -759,6 +760,7 @@ b2ChainId b2CreateChain(b2BodyId bodyId, const b2ChainDef* def) smoothSegment.segment.point1 = points[i]; smoothSegment.segment.point2 = points[i + 1]; smoothSegment.ghost2 = points[i + 2]; + smoothSegment.chainIndex = chainIndex; prevIndex = i; b2ShapeId shapeId = b2CreateShape(bodyId, &shapeDef, &smoothSegment, b2_smoothSegmentShape); @@ -770,6 +772,7 @@ b2ChainId b2CreateChain(b2BodyId bodyId, const b2ChainDef* def) smoothSegment.segment.point1 = points[n - 2]; smoothSegment.segment.point2 = points[n - 1]; smoothSegment.ghost2 = points[0]; + smoothSegment.chainIndex = chainIndex; b2ShapeId shapeId = b2CreateShape(bodyId, &shapeDef, &smoothSegment, b2_smoothSegmentShape); chainShape->shapeIndices[n - 2] = shapeId.index; } @@ -779,6 +782,7 @@ b2ChainId b2CreateChain(b2BodyId bodyId, const b2ChainDef* def) smoothSegment.segment.point1 = points[n - 1]; smoothSegment.segment.point2 = points[0]; smoothSegment.ghost2 = points[1]; + smoothSegment.chainIndex = chainIndex; b2ShapeId shapeId = b2CreateShape(bodyId, &shapeDef, &smoothSegment, b2_smoothSegmentShape); chainShape->shapeIndices[n - 1] = shapeId.index; } @@ -796,6 +800,7 @@ b2ChainId b2CreateChain(b2BodyId bodyId, const b2ChainDef* def) smoothSegment.segment.point1 = points[i + 1]; smoothSegment.segment.point2 = points[i + 2]; smoothSegment.ghost2 = points[i + 3]; + smoothSegment.chainIndex = chainIndex; b2ShapeId shapeId = b2CreateShape(bodyId, &shapeDef, &smoothSegment, b2_smoothSegmentShape); chainShape->shapeIndices[i] = shapeId.index; @@ -1189,6 +1194,27 @@ void b2Body_SetMassData(b2BodyId bodyId, b2MassData massData) body->invI = body->I > 0.0f ? 1.0f / body->I : 0.0f; } +void b2Body_SetLinearDamping(b2BodyId bodyId, float linearDamping) +{ + b2World* world = b2GetWorldFromIndex(bodyId.world); + b2Body* body = b2GetBody(world, bodyId); + body->linearDamping = linearDamping; +} + +void b2Body_SetAngularDamping(b2BodyId bodyId, float angularDamping) +{ + b2World* world = b2GetWorldFromIndex(bodyId.world); + b2Body* body = b2GetBody(world, bodyId); + body->angularDamping = angularDamping; +} + +void b2Body_SetGravityScale(b2BodyId bodyId, float gravityScale) +{ + b2World* world = b2GetWorldFromIndex(bodyId.world); + b2Body* body = b2GetBody(world, bodyId); + body->gravityScale = gravityScale; +} + bool b2Body_IsAwake(b2BodyId bodyId) { b2World* world = b2GetWorldFromIndex(bodyId.world); diff --git a/src/dynamic_tree.c b/src/dynamic_tree.c index 364ab566..ac3f5474 100644 --- a/src/dynamic_tree.c +++ b/src/dynamic_tree.c @@ -797,10 +797,9 @@ int32_t b2DynamicTree_GetProxyCount(const b2DynamicTree* tree) void b2DynamicTree_MoveProxy(b2DynamicTree* tree, int32_t proxyId, b2AABB aabb) { - B2_ASSERT(-b2_huge < aabb.lowerBound.x && aabb.lowerBound.x < b2_huge); - B2_ASSERT(-b2_huge < aabb.lowerBound.y && aabb.lowerBound.y < b2_huge); - B2_ASSERT(-b2_huge < aabb.upperBound.x && aabb.upperBound.x < b2_huge); - B2_ASSERT(-b2_huge < aabb.upperBound.y && aabb.upperBound.y < b2_huge); + B2_ASSERT(b2AABB_IsValid(aabb)); + B2_ASSERT(aabb.upperBound.x - aabb.lowerBound.x < b2_huge); + B2_ASSERT(aabb.upperBound.y - aabb.lowerBound.y < b2_huge); B2_ASSERT(0 <= proxyId && proxyId < tree->nodeCapacity); B2_ASSERT(b2IsLeaf(tree->nodes + proxyId)); @@ -816,10 +815,9 @@ void b2DynamicTree_EnlargeProxy(b2DynamicTree* tree, int32_t proxyId, b2AABB aab { b2TreeNode* nodes = tree->nodes; - B2_ASSERT(-b2_huge < aabb.lowerBound.x && aabb.lowerBound.x < b2_huge); - B2_ASSERT(-b2_huge < aabb.lowerBound.y && aabb.lowerBound.y < b2_huge); - B2_ASSERT(-b2_huge < aabb.upperBound.x && aabb.upperBound.x < b2_huge); - B2_ASSERT(-b2_huge < aabb.upperBound.y && aabb.upperBound.y < b2_huge); + B2_ASSERT(b2AABB_IsValid(aabb)); + B2_ASSERT(aabb.upperBound.x - aabb.lowerBound.x < b2_huge); + B2_ASSERT(aabb.upperBound.y - aabb.lowerBound.y < b2_huge); B2_ASSERT(0 <= proxyId && proxyId < tree->nodeCapacity); B2_ASSERT(b2IsLeaf(tree->nodes + proxyId)); diff --git a/src/geometry.c b/src/geometry.c index 7f440bba..5698b6c4 100644 --- a/src/geometry.c +++ b/src/geometry.c @@ -189,9 +189,6 @@ b2MassData b2ComputeCircleMass(const b2Circle* shape, float density) // inertia about the local origin massData.I = massData.mass * (0.5f * rr + b2Dot(shape->point, shape->point)); - massData.minExtent = shape->radius; - massData.maxExtent = b2Length(shape->point) + shape->radius; - return massData; } @@ -231,9 +228,6 @@ b2MassData b2ComputeCapsuleMass(const b2Capsule* shape, float density) float boxInertia = boxMass * (4.0f * rr + ll) / 12.0f; massData.I = circleInertia + boxInertia; - massData.minExtent = radius; - massData.maxExtent = B2_MAX(b2Length(shape->point1), b2Length(shape->point2)) + shape->radius; - return massData; } @@ -368,20 +362,6 @@ b2MassData b2ComputePolygonMass(const b2Polygon* shape, float density) // Shift to center of mass then to original body origin. massData.I += massData.mass * (b2Dot(massData.center, massData.center) - b2Dot(center, center)); - float minExtent = b2_huge; - float maxExtent = 0.0f; - for (int32_t i = 0; i < count; ++i) - { - float planeOffset = b2Dot(shape->normals[i], b2Sub(shape->vertices[i], massData.center)); - minExtent = B2_MIN(minExtent, planeOffset); - - float distanceSqr = b2LengthSquared(shape->vertices[i]); - maxExtent = B2_MAX(maxExtent, distanceSqr); - } - - massData.minExtent = minExtent + shape->radius; - massData.maxExtent = maxExtent + shape->radius; - return massData; } diff --git a/src/shape.c b/src/shape.c index 3d770b61..dde3eb81 100644 --- a/src/shape.c +++ b/src/shape.c @@ -66,11 +66,58 @@ b2MassData b2ComputeShapeMass(const b2Shape* shape) return b2ComputePolygonMass(&shape->polygon, shape->density); default: { - B2_ASSERT(false); - b2MassData data = {0}; - return data; + return (b2MassData){0}; + } + } +} + +b2ShapeExtent b2ComputeShapeExtent(const b2Shape* shape) +{ + b2ShapeExtent extent = {0}; + + switch (shape->type) + { + case b2_capsuleShape: + { + float radius = shape->capsule.radius; + extent.minExtent = radius; + extent.maxExtent = B2_MAX(b2Length(shape->capsule.point1), b2Length(shape->capsule.point2)) + radius; + } + break; + + case b2_circleShape: + { + float radius = shape->circle.radius; + extent.minExtent = radius; + extent.maxExtent = b2Length(shape->circle.point) + radius; + } + break; + + case b2_polygonShape: + { + const b2Polygon* poly = &shape->polygon; + float minExtent = b2_huge; + float maxExtent = 0.0f; + int32_t count = poly->count; + for (int32_t i = 0; i < count; ++i) + { + float planeOffset = b2Dot(poly->normals[i], b2Sub(poly->vertices[i], poly->centroid)); + minExtent = B2_MIN(minExtent, planeOffset); + + float distanceSqr = b2LengthSquared(poly->vertices[i]); + maxExtent = B2_MAX(maxExtent, distanceSqr); + } + + extent.minExtent = minExtent + poly->radius; + extent.maxExtent = maxExtent + poly->radius; } + break; + + default: + break; } + + return extent; } b2RayCastOutput b2RayCastShape(const b2RayCastInput* input, const b2Shape* shape, b2Transform xf) @@ -265,6 +312,49 @@ void b2Shape_SetRestitution(b2ShapeId shapeId, float restitution) shape->restitution = restitution; } +b2Filter b2Shape_GetFilter(b2ShapeId shapeId) +{ + b2World* world = b2GetWorldFromIndex(shapeId.world); + b2Shape* shape = b2GetShape(world, shapeId); + return shape->filter; +} + +void b2Shape_SetFilter(b2ShapeId shapeId, b2Filter filter) +{ + b2World* world = b2GetWorldFromIndex(shapeId.world); + b2Shape* shape = b2GetShape(world, shapeId); + shape->filter = filter; + + b2Body* body = world->bodies + shape->bodyIndex; + B2_ASSERT(b2ObjectValid(&body->object)); + + // Destroy any contacts associated with the shape + int32_t contactKey = body->contactList; + while (contactKey != B2_NULL_INDEX) + { + int32_t contactIndex = contactKey >> 1; + int32_t edgeIndex = contactKey & 1; + + b2Contact* contact = world->contacts + contactIndex; + contactKey = contact->edges[edgeIndex].nextKey; + + if (contact->shapeIndexA == shapeId.index || contact->shapeIndexB == shapeId.index) + { + b2DestroyContact(world, contact); + } + } + + if (body->isEnabled) + { + b2DestroyShapeProxy(shape, &world->broadPhase); + b2CreateShapeProxy(shape, &world->broadPhase, body->type, body->transform); + } + else + { + B2_ASSERT(shape->proxyKey == B2_NULL_INDEX); + } +} + b2ShapeType b2Shape_GetType(b2ShapeId shapeId) { b2World* world = b2GetWorldFromIndex(shapeId.world); @@ -312,6 +402,26 @@ const b2Polygon* b2Shape_GetPolygon(b2ShapeId shapeId) return &shape->polygon; } +b2ChainId b2Shape_GetParentChain(b2ShapeId shapeId) +{ + b2World* world = b2GetWorldFromIndex(shapeId.world); + b2Shape* shape = b2GetShape(world, shapeId); + if (shape->type == b2_smoothSegmentShape) + { + int32_t chainIndex = shape->smoothSegment.chainIndex; + if (chainIndex != B2_NULL_INDEX) + { + B2_ASSERT(0 <= chainIndex && chainIndex < world->chainPool.capacity); + b2ChainShape* chain = world->chains + chainIndex; + B2_ASSERT(b2ObjectValid(&chain->object)); + b2ChainId chainId = {chainIndex, shapeId.world, chain->object.revision}; + return chainId; + } + } + + return b2_nullChainId; +} + void b2Chain_SetFriction(b2ChainId chainId, float friction) { b2World* world = b2GetWorldFromIndex(chainId.world); diff --git a/src/shape.h b/src/shape.h index dac5cdd0..2dbf3903 100644 --- a/src/shape.h +++ b/src/shape.h @@ -58,10 +58,17 @@ typedef struct b2ChainShape int32_t count; } b2ChainShape; +typedef struct b2ShapeExtent +{ + float minExtent; + float maxExtent; +} b2ShapeExtent; + void b2CreateShapeProxy(b2Shape* shape, b2BroadPhase* bp, b2BodyType type, b2Transform xf); void b2DestroyShapeProxy(b2Shape* shape, b2BroadPhase* bp); b2MassData b2ComputeShapeMass(const b2Shape* shape); +b2ShapeExtent b2ComputeShapeExtent(const b2Shape* shape); b2AABB b2ComputeShapeAABB(const b2Shape* shape, b2Transform xf); b2Vec2 b2GetShapeCentroid(const b2Shape* shape); diff --git a/src/world.c b/src/world.c index e8c97032..7f6b411c 100644 --- a/src/world.c +++ b/src/world.c @@ -93,7 +93,7 @@ b2WorldId b2CreateWorld(const b2WorldDef* def) world->index = id.index; world->blockAllocator = b2CreateBlockAllocator(); - world->stackAllocator = b2CreateStackAllocator(def->stackAllocatorCapacity); + world->stackAllocator = b2CreateStackAllocator(def->arenaAllocatorCapacity); b2CreateBroadPhase(&world->broadPhase); b2CreateGraph(&world->graph, def->bodyCapacity, def->contactCapacity, def->jointCapacity); diff --git a/test/test_determinism.c b/test/test_determinism.c index 731e2f11..e3807750 100644 --- a/test/test_determinism.c +++ b/test/test_determinism.c @@ -101,7 +101,7 @@ void TiltedStacks(int testIndex, int workerCount) b2Vec2 gravity = {0.0f, -10.0f}; // Construct a world object, which will hold and simulate the rigid bodies. - b2WorldDef worldDef = b2DefaultWorldDef(); + b2WorldDef worldDef = b2_defaultWorldDef; worldDef.gravity = gravity; worldDef.enqueueTask = EnqueueTask; worldDef.finishTask = FinishTask; diff --git a/test/test_world.c b/test/test_world.c index 99ca0b9f..a2b48a4a 100644 --- a/test/test_world.c +++ b/test/test_world.c @@ -19,7 +19,7 @@ int HelloWorld(void) b2Vec2 gravity = {0.0f, -10.0f}; // Construct a world object, which will hold and simulate the rigid bodies. - b2WorldDef worldDef = b2DefaultWorldDef(); + b2WorldDef worldDef = b2_defaultWorldDef; worldDef.gravity = gravity; b2WorldId worldId = b2CreateWorld(&worldDef); @@ -98,7 +98,7 @@ int HelloWorld(void) int EmptyWorld(void) { - b2WorldDef worldDef = b2DefaultWorldDef(); + b2WorldDef worldDef = b2_defaultWorldDef; b2WorldId worldId = b2CreateWorld(&worldDef); ENSURE(b2World_IsValid(worldId) == true);