Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Capsules, segments, performance, and fixes #47

Merged
merged 12 commits into from
Aug 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ if (MSVC AND WIN32)
# add_link_options($<$<CONFIG:Debug>:/INCREMENTAL>)
# add_compile_options($<$<CONFIG:Debug>:/ZI>)
# add_compile_options(/fsanitize=address)
# set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/GS- /Gy /O2 /Oi /Ot")
# set(CMAKE_CXX_FLAGS_RELEASE "/GS- /Gy /O2 /Oi /Ot")
# set(CMAKE_C_FLAGS_RELWITHDEBINFO "/GS- /Gy /O2 /Oi /Ot")
# set(CMAKE_C_FLAGS_RELEASE "/GS- /Gy /O2 /Oi /Ot")
endif()

SET(ENKITS_BUILD_EXAMPLES OFF CACHE BOOL "Build enkiTS examples")
Expand Down
8 changes: 4 additions & 4 deletions include/box2d/aabb.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@ static inline b2AABB b2AABB_Union(b2AABB a, b2AABB b)
static inline b2AABB b2AABB_Extend(b2AABB a)
{
b2AABB c;
c.lowerBound.x = a.lowerBound.x - b2_aabbExtension;
c.lowerBound.y = a.lowerBound.y - b2_aabbExtension;
c.upperBound.x = a.upperBound.x + b2_aabbExtension;
c.upperBound.y = a.upperBound.y + b2_aabbExtension;
c.lowerBound.x = a.lowerBound.x - b2_aabbMargin;
c.lowerBound.y = a.lowerBound.y - b2_aabbMargin;
c.upperBound.x = a.upperBound.x + b2_aabbMargin;
c.upperBound.y = a.upperBound.y + b2_aabbMargin;
return c;
}

Expand Down
4 changes: 3 additions & 1 deletion include/box2d/box2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "box2d/timer.h"
#include "box2d/types.h"

typedef struct b2Capsule b2Capsule;
typedef struct b2Circle b2Circle;
typedef struct b2Polygon b2Polygon;
typedef struct b2DebugDraw b2DebugDraw;
Expand Down Expand Up @@ -64,8 +65,9 @@ BOX2D_API void b2Body_Wake(b2BodyId bodyId);
/// Create a shape and attach it to a body. Contacts are not created until the next time step.
/// @warning This function is locked during callbacks.
BOX2D_API b2ShapeId b2Body_CreateCircle(b2BodyId bodyId, const b2ShapeDef* def, const b2Circle* circle);
BOX2D_API b2ShapeId b2Body_CreatePolygon(b2BodyId bodyId, const b2ShapeDef* def, const b2Polygon* polygon);
BOX2D_API b2ShapeId b2Body_CreateSegment(b2BodyId bodyId, const b2ShapeDef* def, const b2Segment* segment);
BOX2D_API b2ShapeId b2Body_CreateCapsule(b2BodyId bodyId, const b2ShapeDef* def, const b2Capsule* capsule);
BOX2D_API b2ShapeId b2Body_CreatePolygon(b2BodyId bodyId, const b2ShapeDef* def, const b2Polygon* polygon);

BOX2D_API b2BodyId b2Shape_GetBody(b2ShapeId shapeId);
BOX2D_API bool b2Shape_TestPoint(b2ShapeId shapeId, b2Vec2 point);
Expand Down
21 changes: 20 additions & 1 deletion include/box2d/color.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ typedef struct b2Color
float r, g, b, a;
} b2Color;

enum b2Colors
enum b2HexColor
{
b2_colorSnow = 0xfffafa,
b2_colorGhostWhite = 0xf8f8ff,
Expand Down Expand Up @@ -578,3 +578,22 @@ enum b2Colors
b2_colorSilver = 0xc0c0c0,
b2_colorTeal = 0x008080
};

#ifdef __cplusplus
extern "C"
{
#endif

static inline b2Color b2MakeColor(enum b2HexColor hexCode, float alpha)
{
b2Color color;
color.r = ((hexCode >> 16) & 0xFF) / 255.0f;
color.g = ((hexCode >> 8) & 0xFF) / 255.0f;
color.b = (hexCode & 0xFF) / 255.0f;
color.a = alpha;
return color;
}

#ifdef __cplusplus
}
#endif
2 changes: 1 addition & 1 deletion include/box2d/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ extern float b2_lengthUnitsPerMeter;
/// to move by a small amount without triggering a tree adjustment.
/// This is in meters.
/// @warning modifying this can have a significant impact on performance
#define b2_aabbExtension (0.1f * b2_lengthUnitsPerMeter)
#define b2_aabbMargin (0.1f * b2_lengthUnitsPerMeter)

/// A small length used as a collision and constraint tolerance. Usually it is
/// chosen to be numerically significant, but visually insignificant. In meters.
Expand Down
6 changes: 6 additions & 0 deletions include/box2d/debug_draw.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ typedef struct b2DebugDraw
/// Draw a solid circle.
void (*DrawSolidCircle)(b2Vec2 center, float radius, b2Vec2 axis, b2Color color, void* context);

/// Draw a capsule.
void (*DrawCapsule)(b2Vec2 p1, b2Vec2 p2, float radius, b2Color color, void* context);

/// Draw a solid capsule.
void (*DrawSolidCapsule)(b2Vec2 p1, b2Vec2 p2, float radius, b2Color color, void* context);

/// Draw a line segment.
void (*DrawSegment)(b2Vec2 p1, b2Vec2 p2, b2Color color, void* context);

Expand Down
2 changes: 1 addition & 1 deletion include/box2d/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ typedef struct b2Profile
float buildIslands;
float solveIslands;
float broadphase;
float continuous;
} b2Profile;

static const b2Profile b2_emptyProfile = {0};
Expand All @@ -28,7 +29,6 @@ typedef struct b2Statistics
int32_t jointCount;
int32_t proxyCount;
int32_t treeHeight;
int32_t contactPointCount;
int32_t stackCapacity;
int32_t stackUsed;
int32_t byteCount;
Expand Down
22 changes: 16 additions & 6 deletions include/box2d/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,21 @@ typedef struct b2RayCastOutput
} b2RayCastOutput;

/// Task interface
/// This is prototype for a Box2D task
typedef void b2TaskCallback(int32_t startIndex, int32_t endIndex, uint32_t threadIndex, void* context);
/// This is prototype for a Box2D task. Your task system is expected to invoke the Box2D task with these arguments.
/// The task spans a range of the parallel-for: [startIndex, endIndex)
/// The thread index must correctly identify each thread in the user thread pool, expected in [0, workerCount)
/// The task context is the context pointer sent from Box2D when it is enqueued.
typedef void b2TaskCallback(int32_t startIndex, int32_t endIndex, uint32_t threadIndex, void* taskContext);

/// These functions can be provided to Box2D to invoke a task system
typedef void b2EnqueueTaskCallback(b2TaskCallback* task, int32_t itemCount, int32_t minRange, void* taskContext, void* userContext);
typedef void b2FinishTasksCallback(void* userContext);
/// These functions can be provided to Box2D to invoke a task system. These are designed to work well with enkiTS.
/// Returns a pointer to the user's task object. May be nullptr.
typedef void* b2EnqueueTaskCallback(b2TaskCallback* task, int32_t itemCount, int32_t minRange, void* taskContext, void* userContext);

/// Finishes a user task object that wraps a Box2D task.
typedef void b2FinishTaskCallback(void* userTask, void* userContext);

/// Finishes all tasks.
typedef void b2FinishAllTasksCallback(void* userContext);

typedef struct b2WorldDef
{
Expand Down Expand Up @@ -113,7 +122,8 @@ typedef struct b2WorldDef
/// task system hookup
uint32_t workerCount;
b2EnqueueTaskCallback* enqueueTask;
b2FinishTasksCallback* finishTasks;
b2FinishTaskCallback* finishTask;
b2FinishAllTasksCallback* finishAllTasks;
void* userTaskContext;

} b2WorldDef;
Expand Down
2 changes: 2 additions & 0 deletions samples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ set(BOX2D_SAMPLES
collection/benchmark_barrel.cpp
collection/benchmark_create_destroy.cpp
collection/benchmark_joint_grid.cpp
collection/benchmark_many_tumblers.cpp
collection/benchmark_pyramid.cpp
collection/benchmark_tumbler.cpp

Expand All @@ -75,6 +76,7 @@ set(BOX2D_SAMPLES
collection/sample_hull.cpp
collection/sample_manifold.cpp
collection/sample_ray_cast.cpp
collection/sample_restitution.cpp
collection/sample_revolute_joint.cpp
collection/sample_shape_cast.cpp
collection/sample_tilted_stacks.cpp
Expand Down
229 changes: 229 additions & 0 deletions samples/collection/benchmark_many_tumblers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
// SPDX-FileCopyrightText: 2022 Erin Catto
// SPDX-License-Identifier: MIT

#include "sample.h"

#include "box2d/box2d.h"
#include "box2d/geometry.h"

#include <GLFW/glfw3.h>
#include <imgui.h>

class BenchmarkManyTumblers : public Sample
{
public:
BenchmarkManyTumblers(const Settings& settings)
: Sample(settings)
{
b2BodyDef bd = b2DefaultBodyDef();
m_groundId = b2World_CreateBody(m_worldId, &bd);

m_rowCount = g_sampleDebug ? 1 : 19;
m_columnCount = g_sampleDebug ? 1 : 19;

m_tumblerIds = nullptr;
m_jointIds = nullptr;
m_positions = nullptr;
m_tumblerCount = 0;

m_bodyIds = nullptr;
m_bodyCount = 0;
m_bodyIndex = 0;

m_motorSpeed = 0.0f;
m_shapeType = 0;

CreateScene();
}

~BenchmarkManyTumblers()
{
free(m_jointIds);
free(m_tumblerIds);
free(m_positions);
free(m_bodyIds);
}

void CreateTumbler(b2Vec2 position, int index)
{
b2BodyDef bd = b2DefaultBodyDef();
bd.type = b2_dynamicBody;
bd.enableSleep = false;
bd.position = {position.x, position.y};
b2BodyId bodyId = b2World_CreateBody(m_worldId, &bd);
m_tumblerIds[index] = bodyId;

b2ShapeDef sd = b2DefaultShapeDef();
sd.density = 50.0f;

b2Polygon polygon;
polygon = b2MakeOffsetBox(0.25f, 2.0f, {2.0f, 0.0f}, 0.0);
b2Body_CreatePolygon(bodyId, &sd, &polygon);
polygon = b2MakeOffsetBox(0.25f, 2.0f, {-2.0f, 0.0f}, 0.0);
b2Body_CreatePolygon(bodyId, &sd, &polygon);
polygon = b2MakeOffsetBox(2.0f, 0.25f, {0.0f, 2.0f}, 0.0);
b2Body_CreatePolygon(bodyId, &sd, &polygon);
polygon = b2MakeOffsetBox(2.0f, 0.25f, {0.0f, -2.0f}, 0.0);
b2Body_CreatePolygon(bodyId, &sd, &polygon);

b2RevoluteJointDef jd = b2DefaultRevoluteJointDef();
jd.bodyIdA = m_groundId;
jd.bodyIdB = bodyId;
jd.localAnchorA = position;
jd.localAnchorB = {0.0f, 0.0f};
jd.referenceAngle = 0.0f;
jd.motorSpeed = (b2_pi / 180.0f) * m_motorSpeed;
jd.maxMotorTorque = 1e8f;
jd.enableMotor = true;

m_jointIds[index] = b2World_CreateRevoluteJoint(m_worldId, &jd);
}

void CreateScene()
{
for (int32_t i = 0; i < m_bodyCount; ++i)
{
if (B2_NON_NULL(m_bodyIds[i]))
{
b2World_DestroyBody(m_bodyIds[i]);
}
}

for (int32_t i = 0; i < m_tumblerCount; ++i)
{
b2World_DestroyJoint(m_jointIds[i]);
b2World_DestroyBody(m_tumblerIds[i]);
}

free(m_jointIds);
free(m_tumblerIds);
free(m_positions);

m_tumblerCount = m_rowCount * m_columnCount;
m_tumblerIds = static_cast<b2BodyId*>(malloc(m_tumblerCount * sizeof(b2BodyId)));
m_jointIds = static_cast<b2JointId*>(malloc(m_tumblerCount * sizeof(b2JointId)));
m_positions = static_cast<b2Vec2*>(malloc(m_tumblerCount * sizeof(b2Vec2)));

int32_t index = 0;
float x = -4.0f * m_rowCount;
for (int32_t i = 0; i < m_rowCount; ++i)
{
float y = -4.0f * m_columnCount;
for (int32_t j = 0; j < m_columnCount; ++j)
{
m_positions[index] = {x, y};
CreateTumbler(m_positions[index], index);
++index;
y += 8.0f;
}

x += 8.0f;
}

free(m_bodyIds);

int32_t bodiesPerTumbler = g_sampleDebug ? 1 : 50;
m_bodyCount = bodiesPerTumbler * m_tumblerCount;

m_bodyIds = static_cast<b2BodyId*>(malloc(m_bodyCount * sizeof(b2BodyId)));

// 0xFF is a fast way to make all bodies satisfy B2_IS_NULL
memset(m_bodyIds, 0XFF, m_bodyCount * sizeof(b2BodyId));
m_bodyIndex = 0;

m_shapeType = 0;
}

void UpdateUI() override
{
ImGui::SetNextWindowPos(ImVec2(10.0f, 300.0f), ImGuiCond_Once);
ImGui::SetNextWindowSize(ImVec2(240.0f, 230.0f));
ImGui::Begin("Tumbler", nullptr, ImGuiWindowFlags_NoResize);

bool changed = false;
changed = changed || ImGui::SliderInt("Row Count", &m_rowCount, 1, 32);
changed = changed || ImGui::SliderInt("Column Count", &m_columnCount, 1, 32);

if (changed)
{
CreateScene();
}

if (ImGui::SliderFloat("Speed", &m_motorSpeed, 0.0f, 100.0f, "%.f"))
{
for (int i = 0; i < m_tumblerCount; ++i)
{
b2RevoluteJoint_SetMotorSpeed(m_jointIds[i], (b2_pi / 180.0f) * m_motorSpeed);
}
}

ImGui::End();
}

void Step(Settings& settings) override
{
Sample::Step(settings);

if (m_bodyIndex < m_bodyCount && (m_stepCount & 0x7) == 0)
{
b2ShapeDef sd = b2DefaultShapeDef();
sd.density = 1.0f;

b2Circle circle = {{0.0f, 0.0f}, 0.125f};
b2Polygon polygon = b2MakeBox(0.125f, 0.125f);
b2Capsule capsule = {{-0.1f, 0.0f}, {0.1f, 0.0f}, 0.075f};
int j = m_shapeType % 3;

for (int i = 0; i < m_tumblerCount; ++i)
{
assert(m_bodyIndex < m_bodyCount);

b2BodyDef bd = b2DefaultBodyDef();
bd.type = b2_dynamicBody;
bd.position = m_positions[i];
m_bodyIds[m_bodyIndex] = b2World_CreateBody(m_worldId, &bd);

//if (j == 0)
//{
// b2Body_CreatePolygon(m_bodyIds[m_bodyIndex], &sd, &polygon);
//}
//else if (j == 1)
{
b2Body_CreateCapsule(m_bodyIds[m_bodyIndex], &sd, &capsule);
}
//else
//{
// b2Body_CreateCircle(m_bodyIds[m_bodyIndex], &sd, &circle);
//}

m_bodyIndex += 1;
}

m_shapeType += 1;
}
}

static Sample* Create(const Settings& settings)
{
return new BenchmarkManyTumblers(settings);
}

b2BodyId m_groundId;

int32_t m_rowCount;
int32_t m_columnCount;

b2BodyId* m_tumblerIds;
b2JointId* m_jointIds;
b2Vec2* m_positions;
int32_t m_tumblerCount;

b2BodyId* m_bodyIds;
int32_t m_bodyCount;
int32_t m_bodyIndex;
int32_t m_shapeType;

float m_motorSpeed;
};

static int testIndex = RegisterSample("Benchmark", "Many Tumblers", BenchmarkManyTumblers::Create);
Loading