diff --git a/include/box2d/b2_broad_phase.h b/include/box2d/b2_broad_phase.h index c22a4a13e..cf1cf6773 100644 --- a/include/box2d/b2_broad_phase.h +++ b/include/box2d/b2_broad_phase.h @@ -26,7 +26,6 @@ #include "b2_settings.h" #include "b2_collision.h" #include "b2_dynamic_tree.h" -#include struct b2Pair { @@ -132,22 +131,6 @@ class b2BroadPhase int32 m_queryProxyId; }; -/// This is used to sort pairs. -inline bool b2PairLessThan(const b2Pair& pair1, const b2Pair& pair2) -{ - if (pair1.proxyIdA < pair2.proxyIdA) - { - return true; - } - - if (pair1.proxyIdA == pair2.proxyIdA) - { - return pair1.proxyIdB < pair2.proxyIdB; - } - - return false; -} - inline void* b2BroadPhase::GetUserData(int32 proxyId) const { return m_tree.GetUserData(proxyId); @@ -208,37 +191,30 @@ void b2BroadPhase::UpdatePairs(T* callback) m_tree.Query(this, fatAABB); } - // Reset move buffer - m_moveCount = 0; - - // Sort the pair buffer to expose duplicates. - std::sort(m_pairBuffer, m_pairBuffer + m_pairCount, b2PairLessThan); - - // Send the pairs back to the client. - int32 i = 0; - while (i < m_pairCount) + // Send pairs to caller + for (int32 i = 0; i < m_pairCount; ++i) { b2Pair* primaryPair = m_pairBuffer + i; void* userDataA = m_tree.GetUserData(primaryPair->proxyIdA); void* userDataB = m_tree.GetUserData(primaryPair->proxyIdB); callback->AddPair(userDataA, userDataB); - ++i; + } - // Skip any duplicate pairs. - while (i < m_pairCount) + // Clear move flags + for (int32 i = 0; i < m_moveCount; ++i) + { + int32 proxyId = m_moveBuffer[i]; + if (proxyId == e_nullProxy) { - b2Pair* pair = m_pairBuffer + i; - if (pair->proxyIdA != primaryPair->proxyIdA || pair->proxyIdB != primaryPair->proxyIdB) - { - break; - } - ++i; + continue; } + + m_tree.ClearMoved(proxyId); } - // Try to keep the tree balanced. - //m_tree.Rebalance(4); + // Reset move buffer + m_moveCount = 0; } template diff --git a/include/box2d/b2_dynamic_tree.h b/include/box2d/b2_dynamic_tree.h index 6ad47ff54..b3ddb97ca 100644 --- a/include/box2d/b2_dynamic_tree.h +++ b/include/box2d/b2_dynamic_tree.h @@ -52,6 +52,8 @@ struct b2TreeNode // leaf = 0, free node = -1 int32 height; + + bool moved; }; /// A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt. @@ -87,6 +89,9 @@ class b2DynamicTree /// @return the proxy user data or 0 if the id is invalid. void* GetUserData(int32 proxyId) const; + bool WasMoved(int32 proxyId) const; + void ClearMoved(int32 proxyId); + /// Get the fat AABB for a proxy. const b2AABB& GetFatAABB(int32 proxyId) const; @@ -163,6 +168,18 @@ inline void* b2DynamicTree::GetUserData(int32 proxyId) const return m_nodes[proxyId].userData; } +inline bool b2DynamicTree::WasMoved(int32 proxyId) const +{ + b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); + return m_nodes[proxyId].moved; +} + +inline void b2DynamicTree::ClearMoved(int32 proxyId) +{ + b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); + m_nodes[proxyId].moved = false; +} + inline const b2AABB& b2DynamicTree::GetFatAABB(int32 proxyId) const { b2Assert(0 <= proxyId && proxyId < m_nodeCapacity); diff --git a/include/box2d/b2_settings.h b/include/box2d/b2_settings.h index e3adf2e7a..41dd54260 100644 --- a/include/box2d/b2_settings.h +++ b/include/box2d/b2_settings.h @@ -67,7 +67,7 @@ typedef unsigned int uint32; /// This is used to fatten AABBs in the dynamic tree. This is used to predict /// the future position based on the current displacement. /// This is a dimensionless multiplier. -#define b2_aabbMultiplier 2.0f +#define b2_aabbMultiplier 4.0f /// A small length used as a collision and constraint tolerance. Usually it is /// chosen to be numerically significant, but visually insignificant. diff --git a/include/box2d/b2_world.h b/include/box2d/b2_world.h index 514408f80..03c4393c6 100644 --- a/include/box2d/b2_world.h +++ b/include/box2d/b2_world.h @@ -66,7 +66,7 @@ class b2World void SetContactListener(b2ContactListener* listener); /// Register a routine for debug drawing. The debug draw functions are called - /// inside with b2World::DrawDebugData method. The debug draw object is owned + /// inside with b2World::DebugDraw method. The debug draw object is owned /// by you and must remain in scope. void SetDebugDraw(b2Draw* debugDraw); @@ -109,7 +109,7 @@ class b2World void ClearForces(); /// Call this to draw shapes and other debug draw data. This is intentionally non-const. - void DrawDebugData(); + void DebugDraw(); /// Query the world for all fixtures that potentially overlap the /// provided AABB. diff --git a/src/collision/b2_broad_phase.cpp b/src/collision/b2_broad_phase.cpp index cac359e5e..d063a3aa9 100644 --- a/src/collision/b2_broad_phase.cpp +++ b/src/collision/b2_broad_phase.cpp @@ -21,6 +21,7 @@ // SOFTWARE. #include "box2d/b2_broad_phase.h" +#include b2BroadPhase::b2BroadPhase() { @@ -105,11 +106,18 @@ bool b2BroadPhase::QueryCallback(int32 proxyId) return true; } + const bool moved = m_tree.WasMoved(proxyId); + if (moved && proxyId > m_queryProxyId) + { + // Both proxies are moving. Avoid duplicate pairs. + return true; + } + // Grow the pair buffer as needed. if (m_pairCount == m_pairCapacity) { b2Pair* oldBuffer = m_pairBuffer; - m_pairCapacity *= 2; + m_pairCapacity = m_pairCapacity + (m_pairCapacity >> 1); m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair)); memcpy(m_pairBuffer, oldBuffer, m_pairCount * sizeof(b2Pair)); b2Free(oldBuffer); diff --git a/src/collision/b2_dynamic_tree.cpp b/src/collision/b2_dynamic_tree.cpp index 8c3390c40..45e093320 100644 --- a/src/collision/b2_dynamic_tree.cpp +++ b/src/collision/b2_dynamic_tree.cpp @@ -87,6 +87,7 @@ int32 b2DynamicTree::AllocateNode() m_nodes[nodeId].child2 = b2_nullNode; m_nodes[nodeId].height = 0; m_nodes[nodeId].userData = nullptr; + m_nodes[nodeId].moved = false; ++m_nodeCount; return nodeId; } @@ -115,6 +116,7 @@ int32 b2DynamicTree::CreateProxy(const b2AABB& aabb, void* userData) m_nodes[proxyId].aabb.upperBound = aabb.upperBound + r; m_nodes[proxyId].userData = userData; m_nodes[proxyId].height = 0; + m_nodes[proxyId].moved = true; InsertLeaf(proxyId); @@ -136,43 +138,61 @@ bool b2DynamicTree::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& d b2Assert(m_nodes[proxyId].IsLeaf()); - if (m_nodes[proxyId].aabb.Contains(aabb)) - { - return false; - } - - RemoveLeaf(proxyId); - - // Extend AABB. - b2AABB b = aabb; + // Extend AABB + b2AABB fatAABB; b2Vec2 r(b2_aabbExtension, b2_aabbExtension); - b.lowerBound = b.lowerBound - r; - b.upperBound = b.upperBound + r; + fatAABB.lowerBound = aabb.lowerBound - r; + fatAABB.upperBound = aabb.upperBound + r; - // Predict AABB displacement. + // Predict AABB movement b2Vec2 d = b2_aabbMultiplier * displacement; if (d.x < 0.0f) { - b.lowerBound.x += d.x; + fatAABB.lowerBound.x += d.x; } else { - b.upperBound.x += d.x; + fatAABB.upperBound.x += d.x; } if (d.y < 0.0f) { - b.lowerBound.y += d.y; + fatAABB.lowerBound.y += d.y; } else { - b.upperBound.y += d.y; + fatAABB.upperBound.y += d.y; + } + + const b2AABB& treeAABB = m_nodes[proxyId].aabb; + if (treeAABB.Contains(aabb)) + { + // The tree AABB still contains the object, but it might be too large. + // Perhaps the object was moving fast but has since gone to sleep. + // The huge AABB is larger than the new fat AABB. + b2AABB hugeAABB; + hugeAABB.lowerBound = fatAABB.lowerBound - 4.0f * r; + hugeAABB.upperBound = fatAABB.upperBound + 4.0f * r; + + if (hugeAABB.Contains(treeAABB)) + { + // The tree AABB contains the object AABB and the tree AABB is + // not too large. No tree update needed. + return false; + } + + // Otherwise the tree AABB is huge and needs to be shrunk } - m_nodes[proxyId].aabb = b; + RemoveLeaf(proxyId); + + m_nodes[proxyId].aabb = fatAABB; InsertLeaf(proxyId); + + m_nodes[proxyId].moved = true; + return true; } diff --git a/src/dynamics/b2_body.cpp b/src/dynamics/b2_body.cpp index ed7877e4b..ed43a22d3 100644 --- a/src/dynamics/b2_body.cpp +++ b/src/dynamics/b2_body.cpp @@ -26,6 +26,8 @@ #include "box2d/b2_joint.h" #include "box2d/b2_world.h" +#include + b2Body::b2Body(const b2BodyDef* bd, b2World* world) { b2Assert(bd->position.IsValid()); @@ -449,14 +451,25 @@ void b2Body::SetTransform(const b2Vec2& position, float angle) void b2Body::SynchronizeFixtures() { - b2Transform xf1; - xf1.q.Set(m_sweep.a0); - xf1.p = m_sweep.c0 - b2Mul(xf1.q, m_sweep.localCenter); - b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; - for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + + if (m_flags & b2Body::e_awakeFlag) + { + b2Transform xf1; + xf1.q.Set(m_sweep.a0); + xf1.p = m_sweep.c0 - b2Mul(xf1.q, m_sweep.localCenter); + + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + f->Synchronize(broadPhase, xf1, m_xf); + } + } + else { - f->Synchronize(broadPhase, xf1, m_xf); + for (b2Fixture* f = m_fixtureList; f; f = f->m_next) + { + f->Synchronize(broadPhase, m_xf, m_xf); + } } } diff --git a/src/dynamics/b2_fixture.cpp b/src/dynamics/b2_fixture.cpp index f8f2f2ed0..d0c1579eb 100644 --- a/src/dynamics/b2_fixture.cpp +++ b/src/dynamics/b2_fixture.cpp @@ -171,7 +171,7 @@ void b2Fixture::Synchronize(b2BroadPhase* broadPhase, const b2Transform& transfo proxy->aabb.Combine(aabb1, aabb2); - b2Vec2 displacement = transform2.p - transform1.p; + b2Vec2 displacement = aabb2.GetCenter() - aabb1.GetCenter(); broadPhase->MoveProxy(proxy->proxyId, proxy->aabb, displacement); } diff --git a/src/dynamics/b2_world.cpp b/src/dynamics/b2_world.cpp index 1c5ed7c98..a9c0df305 100644 --- a/src/dynamics/b2_world.cpp +++ b/src/dynamics/b2_world.cpp @@ -1167,7 +1167,7 @@ void b2World::DrawJoint(b2Joint* joint) } } -void b2World::DrawDebugData() +void b2World::DebugDraw() { if (m_debugDraw == nullptr) { @@ -1220,13 +1220,14 @@ void b2World::DrawDebugData() b2Color color(0.3f, 0.9f, 0.9f); for (b2Contact* c = m_contactManager.m_contactList; c; c = c->GetNext()) { - //b2Fixture* fixtureA = c->GetFixtureA(); - //b2Fixture* fixtureB = c->GetFixtureB(); - - //b2Vec2 cA = fixtureA->GetAABB().GetCenter(); - //b2Vec2 cB = fixtureB->GetAABB().GetCenter(); - - //g_debugDraw->DrawSegment(cA, cB, color); + b2Fixture* fixtureA = c->GetFixtureA(); + b2Fixture* fixtureB = c->GetFixtureB(); + int32 indexA = c->GetChildIndexA(); + int32 indexB = c->GetChildIndexB(); + b2Vec2 cA = fixtureA->GetAABB(indexA).GetCenter(); + b2Vec2 cB = fixtureB->GetAABB(indexB).GetCenter(); + + m_debugDraw->DrawSegment(cA, cB, color); } } diff --git a/testbed/CMakeLists.txt b/testbed/CMakeLists.txt index bc745962d..1fa3772da 100644 --- a/testbed/CMakeLists.txt +++ b/testbed/CMakeLists.txt @@ -11,7 +11,7 @@ set (TESTBED_SOURCE_FILES test.cpp test.h tests/add_pair.cpp - tests/apply_forces.cpp + tests/apply_force.cpp tests/body_types.cpp tests/box_stack.cpp tests/breakable.cpp diff --git a/testbed/draw.cpp b/testbed/draw.cpp index ea4b30267..3859d4da0 100644 --- a/testbed/draw.cpp +++ b/testbed/draw.cpp @@ -23,6 +23,7 @@ #include "draw.h" #include #include +#include #include "imgui/imgui.h" diff --git a/testbed/main.cpp b/testbed/main.cpp index 951c45f35..2be4f8178 100644 --- a/testbed/main.cpp +++ b/testbed/main.cpp @@ -30,7 +30,10 @@ #include "settings.h" #include "test.h" +#include #include +#include +#include GLFWwindow* g_mainWindow = nullptr; static int32 s_testSelection = 0; @@ -537,15 +540,17 @@ int main(int, char**) s_test = g_testEntries[s_settings.m_testIndex].createFcn(); // Control the frame rate. One draw per monitor refresh. - glfwSwapInterval(1); + //glfwSwapInterval(1); - double time1 = glfwGetTime(); - double frameTime = 0.0; - glClearColor(0.3f, 0.3f, 0.3f, 1.f); - + + std::chrono::duration frameTime(0.0); + std::chrono::duration sleepAdjust(0.0); + while (!glfwWindowShouldClose(g_mainWindow)) { + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + glfwGetWindowSize(g_mainWindow, &g_camera.m_width, &g_camera.m_height); int bufferWidth, bufferHeight; @@ -574,28 +579,13 @@ int main(int, char**) s_test->Step(s_settings); - if (s_testSelection != s_settings.m_testIndex) - { - s_settings.m_testIndex = s_testSelection; - delete s_test; - s_test = g_testEntries[s_settings.m_testIndex].createFcn(); - g_camera.m_zoom = 1.0f; - g_camera.m_center.Set(0.0f, 20.0f); - } - UpdateUI(); // ImGui::ShowDemoWindow(); - - // Measure speed - double time2 = glfwGetTime(); - double alpha = 0.9; - frameTime = alpha * frameTime + (1.0 - alpha) * (time2 - time1); - time1 = time2; - + if (g_debugDraw.m_showUI) { - sprintf(buffer, "%.1f ms", 1000.0 * frameTime); + sprintf(buffer, "%.1f ms", 1000.0 * frameTime.count()); g_debugDraw.DrawString(5, g_camera.m_height - 20, buffer); } @@ -604,7 +594,33 @@ int main(int, char**) glfwSwapBuffers(g_mainWindow); + if (s_testSelection != s_settings.m_testIndex) + { + s_settings.m_testIndex = s_testSelection; + delete s_test; + s_test = g_testEntries[s_settings.m_testIndex].createFcn(); + g_camera.m_zoom = 1.0f; + g_camera.m_center.Set(0.0f, 20.0f); + } + glfwPollEvents(); + + // Throttle to cap at 60Hz. This adaptive using a sleep adjustment. This could be improved by + // using mm_pause or equivalent for the last millisecond. + std::chrono::steady_clock::time_point t2 = std::chrono::steady_clock::now(); + std::chrono::duration target(1.0 / 60.0); + std::chrono::duration timeUsed = t2 - t1; + std::chrono::duration sleepTime = target - timeUsed + sleepAdjust; + if (sleepTime > std::chrono::duration(0)) + { + std::this_thread::sleep_for(sleepTime); + } + + std::chrono::steady_clock::time_point t3 = std::chrono::steady_clock::now(); + frameTime = t3 - t1; + + // Compute the sleep adjustment using a low pass filter + sleepAdjust = 0.9 * sleepAdjust + 0.1 * (target - frameTime); } delete s_test; diff --git a/testbed/test.cpp b/testbed/test.cpp index 4d8ca89d7..a4d5487f8 100644 --- a/testbed/test.cpp +++ b/testbed/test.cpp @@ -305,7 +305,7 @@ void Test::Step(Settings& settings) m_world->Step(timeStep, settings.m_velocityIterations, settings.m_positionIterations); - m_world->DrawDebugData(); + m_world->DebugDraw(); g_debugDraw.Flush(); if (timeStep > 0.0f) diff --git a/testbed/tests/apply_forces.cpp b/testbed/tests/apply_force.cpp similarity index 71% rename from testbed/tests/apply_forces.cpp rename to testbed/tests/apply_force.cpp index 8bbcae8e6..e743cb79a 100644 --- a/testbed/tests/apply_forces.cpp +++ b/testbed/tests/apply_force.cpp @@ -22,6 +22,9 @@ #include "test.h" +// This test shows how to apply forces and torques to a body. +// It also shows how to use the friction joint that can be useful +// for overhead games. class ApplyForce : public Test { public: @@ -76,7 +79,7 @@ class ApplyForce : public Test b2FixtureDef sd1; sd1.shape = &poly1; - sd1.density = 4.0f; + sd1.density = 2.0f; b2Transform xf2; xf2.q.Set(-0.3524f * b2_pi); @@ -95,15 +98,33 @@ class ApplyForce : public Test b2BodyDef bd; bd.type = b2_dynamicBody; - bd.angularDamping = 2.0f; - bd.linearDamping = 0.5f; - bd.position.Set(0.0f, 2.0); + bd.position.Set(0.0f, 3.0); bd.angle = b2_pi; bd.allowSleep = false; m_body = m_world->CreateBody(&bd); m_body->CreateFixture(&sd1); m_body->CreateFixture(&sd2); + + float gravity = 10.0f; + float I = m_body->GetInertia(); + float mass = m_body->GetMass(); + + // Compute an effective radius that can be used to + // set the max torque for a friction joint + // For a circle: I = 0.5 * m * r * r ==> r = sqrt(2 * I / m) + float radius = b2Sqrt(2.0f * I / mass); + + b2FrictionJointDef jd; + jd.bodyA = ground; + jd.bodyB = m_body; + jd.localAnchorA.SetZero(); + jd.localAnchorB = m_body->GetLocalCenter(); + jd.collideConnected = true; + jd.maxForce = 0.5f * mass * gravity; + jd.maxTorque = 0.2f * mass * radius * gravity; + + m_world->CreateJoint(&jd); } { @@ -120,7 +141,7 @@ class ApplyForce : public Test b2BodyDef bd; bd.type = b2_dynamicBody; - bd.position.Set(0.0f, 5.0f + 1.54f * i); + bd.position.Set(0.0f, 7.0f + 1.54f * i); b2Body* body = m_world->CreateBody(&bd); body->CreateFixture(&fd); @@ -139,37 +160,36 @@ class ApplyForce : public Test jd.bodyB = body; jd.collideConnected = true; jd.maxForce = mass * gravity; - jd.maxTorque = mass * radius * gravity; + jd.maxTorque = 0.1f * mass * radius * gravity; m_world->CreateJoint(&jd); } } } - void Keyboard(int key) override + void Step(Settings& settings) override { - switch (key) + g_debugDraw.DrawString(5, m_textLine, "Forward (W), Turn (A) and (D)"); + m_textLine += m_textIncrement; + + if (glfwGetKey(g_mainWindow, GLFW_KEY_W) == GLFW_PRESS) { - case GLFW_KEY_W: - { - b2Vec2 f = m_body->GetWorldVector(b2Vec2(0.0f, -200.0f)); - b2Vec2 p = m_body->GetWorldPoint(b2Vec2(0.0f, 2.0f)); - m_body->ApplyForce(f, p, true); - } - break; + b2Vec2 f = m_body->GetWorldVector(b2Vec2(0.0f, -50.0f)); + b2Vec2 p = m_body->GetWorldPoint(b2Vec2(0.0f, 3.0f)); + m_body->ApplyForce(f, p, true); + } - case GLFW_KEY_A: - { - m_body->ApplyTorque(50.0f, true); - } - break; + if (glfwGetKey(g_mainWindow, GLFW_KEY_A) == GLFW_PRESS) + { + m_body->ApplyTorque(10.0f, true); + } - case GLFW_KEY_D: - { - m_body->ApplyTorque(-50.0f, true); - } - break; + if (glfwGetKey(g_mainWindow, GLFW_KEY_D) == GLFW_PRESS) + { + m_body->ApplyTorque(-10.0f, true); } + + Test::Step(settings); } static Test* Create() diff --git a/testbed/tests/platformer.cpp b/testbed/tests/platformer.cpp index cf2bd8c1b..722a40e2a 100644 --- a/testbed/tests/platformer.cpp +++ b/testbed/tests/platformer.cpp @@ -113,10 +113,8 @@ class Platformer : public Test void Step(Settings& settings) override { Test::Step(settings); - g_debugDraw.DrawString(5, m_textLine, "Press: (c) create a shape, (d) destroy a shape."); - m_textLine += m_textIncrement; - b2Vec2 v = m_character->GetBody()->GetLinearVelocity(); + b2Vec2 v = m_character->GetBody()->GetLinearVelocity(); g_debugDraw.DrawString(5, m_textLine, "Character Linear Velocity: %f", v.y); m_textLine += m_textIncrement; } diff --git a/testbed/tests/polygon_shapes.cpp b/testbed/tests/polygon_shapes.cpp index 34374dea7..b611f325a 100644 --- a/testbed/tests/polygon_shapes.cpp +++ b/testbed/tests/polygon_shapes.cpp @@ -42,45 +42,6 @@ class PolygonShapesCallback : public b2QueryCallback m_count = 0; } - void DrawFixture(b2Fixture* fixture) - { - b2Color color(0.95f, 0.95f, 0.6f); - const b2Transform& xf = fixture->GetBody()->GetTransform(); - - switch (fixture->GetType()) - { - case b2Shape::e_circle: - { - b2CircleShape* circle = (b2CircleShape*)fixture->GetShape(); - - b2Vec2 center = b2Mul(xf, circle->m_p); - float radius = circle->m_radius; - - g_debugDraw->DrawCircle(center, radius, color); - } - break; - - case b2Shape::e_polygon: - { - b2PolygonShape* poly = (b2PolygonShape*)fixture->GetShape(); - int32 vertexCount = poly->m_count; - b2Assert(vertexCount <= b2_maxPolygonVertices); - b2Vec2 vertices[b2_maxPolygonVertices]; - - for (int32 i = 0; i < vertexCount; ++i) - { - vertices[i] = b2Mul(xf, poly->m_vertices[i]); - } - - g_debugDraw->DrawPolygon(vertices, vertexCount, color); - } - break; - - default: - break; - } - } - /// Called for each fixture found in the query AABB. /// @return false to terminate the query. bool ReportFixture(b2Fixture* fixture) override @@ -94,10 +55,12 @@ class PolygonShapesCallback : public b2QueryCallback b2Shape* shape = fixture->GetShape(); bool overlap = b2TestOverlap(shape, 0, &m_circle, 0, body->GetTransform(), m_transform); - + if (overlap) { - DrawFixture(fixture); + b2Color color(0.95f, 0.95f, 0.6f); + b2Vec2 center = body->GetWorldCenter(); + g_debugDraw->DrawPoint(center, 5.0f, color); ++m_count; } @@ -280,7 +243,7 @@ class PolygonShapes : public Test b2Color color(0.4f, 0.7f, 0.8f); g_debugDraw.DrawCircle(callback.m_circle.m_p, callback.m_circle.m_radius, color); - g_debugDraw.DrawString(5, m_textLine, "Press 1-5 to drop stuff"); + g_debugDraw.DrawString(5, m_textLine, "Press 1-5 to drop stuff, maximum of %d overlaps detected", PolygonShapesCallback::e_maxCount); m_textLine += m_textIncrement; g_debugDraw.DrawString(5, m_textLine, "Press 'a' to enable/disable some bodies"); m_textLine += m_textIncrement; diff --git a/testbed/tests/rope.cpp b/testbed/tests/rope.cpp index 1174c0db8..17a089a94 100644 --- a/testbed/tests/rope.cpp +++ b/testbed/tests/rope.cpp @@ -124,9 +124,9 @@ class Rope : public Test ImGui::EndCombo(); } - ImGui::SliderFloat("Damping##1", &m_tuning1.bendDamping, 0.0f, 4.0f, "%.1f"); - ImGui::SliderFloat("Hertz##1", &m_tuning1.bendHertz, 0.0f, 60.0f, "%.0f"); - ImGui::SliderFloat("Stiffness##1", &m_tuning1.bendStiffness, 0.0f, 1.0f, "%.1f"); + ImGui::SliderFloat("Damping##B1", &m_tuning1.bendDamping, 0.0f, 4.0f, "%.1f"); + ImGui::SliderFloat("Hertz##B1", &m_tuning1.bendHertz, 0.0f, 60.0f, "%.0f"); + ImGui::SliderFloat("Stiffness##B1", &m_tuning1.bendStiffness, 0.0f, 1.0f, "%.1f"); ImGui::Checkbox("Isometric##1", &m_tuning1.isometric); ImGui::Checkbox("Fixed Mass##1", &m_tuning1.fixedEffectiveMass); @@ -152,9 +152,9 @@ class Rope : public Test ImGui::EndCombo(); } - ImGui::SliderFloat("Damping##1", &m_tuning1.stretchDamping, 0.0f, 4.0f, "%.1f"); - ImGui::SliderFloat("Hertz##1", &m_tuning1.stretchHertz, 0.0f, 60.0f, "%.0f"); - ImGui::SliderFloat("Stiffness##1", &m_tuning1.stretchStiffness, 0.0f, 1.0f, "%.1f"); + ImGui::SliderFloat("Damping##S1", &m_tuning1.stretchDamping, 0.0f, 4.0f, "%.1f"); + ImGui::SliderFloat("Hertz##S1", &m_tuning1.stretchHertz, 0.0f, 60.0f, "%.0f"); + ImGui::SliderFloat("Stiffness##S1", &m_tuning1.stretchStiffness, 0.0f, 1.0f, "%.1f"); ImGui::SliderInt("Iterations##1", &m_iterations1, 1, 100, "%d"); @@ -181,9 +181,9 @@ class Rope : public Test ImGui::EndCombo(); } - ImGui::SliderFloat("Damping##2", &m_tuning2.bendDamping, 0.0f, 4.0f, "%.1f"); - ImGui::SliderFloat("Hertz##2", &m_tuning2.bendHertz, 0.0f, 60.0f, "%.0f"); - ImGui::SliderFloat("Stiffness##2", &m_tuning2.bendStiffness, 0.0f, 1.0f, "%.1f"); + ImGui::SliderFloat("Damping##B2", &m_tuning2.bendDamping, 0.0f, 4.0f, "%.1f"); + ImGui::SliderFloat("Hertz##B2", &m_tuning2.bendHertz, 0.0f, 60.0f, "%.0f"); + ImGui::SliderFloat("Stiffness##B2", &m_tuning2.bendStiffness, 0.0f, 1.0f, "%.1f"); ImGui::Checkbox("Isometric##2", &m_tuning2.isometric); ImGui::Checkbox("Fixed Mass##2", &m_tuning2.fixedEffectiveMass); @@ -209,9 +209,9 @@ class Rope : public Test ImGui::EndCombo(); } - ImGui::SliderFloat("Damping##2", &m_tuning2.stretchDamping, 0.0f, 4.0f, "%.1f"); - ImGui::SliderFloat("Hertz##2", &m_tuning2.stretchHertz, 0.0f, 60.0f, "%.0f"); - ImGui::SliderFloat("Stiffness##2", &m_tuning2.stretchStiffness, 0.0f, 1.0f, "%.1f"); + ImGui::SliderFloat("Damping##S2", &m_tuning2.stretchDamping, 0.0f, 4.0f, "%.1f"); + ImGui::SliderFloat("Hertz##S2", &m_tuning2.stretchHertz, 0.0f, 60.0f, "%.0f"); + ImGui::SliderFloat("Stiffness##S2", &m_tuning2.stretchStiffness, 0.0f, 1.0f, "%.1f"); ImGui::SliderInt("Iterations##2", &m_iterations2, 1, 100, "%d");