|
@@ -12,6 +12,7 @@
|
|
|
#include <Jolt/Physics/Collision/Shape/RotatedTranslatedShape.h>
|
|
|
#include <Jolt/Physics/Body/BodyLockMulti.h>
|
|
|
#include <Jolt/Physics/Constraints/PointConstraint.h>
|
|
|
+#include <Jolt/Physics/StateRecorderImpl.h>
|
|
|
|
|
|
TEST_SUITE("PhysicsTests")
|
|
|
{
|
|
@@ -113,7 +114,7 @@ TEST_SUITE("PhysicsTests")
|
|
|
CHECK_FALSE(lock1.Succeeded());
|
|
|
CHECK_FALSE(lock1.SucceededAndIsInBroadPhase());
|
|
|
}
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
TEST_CASE("TestPhysicsBodyLockMulti")
|
|
|
{
|
|
@@ -378,12 +379,12 @@ TEST_SUITE("PhysicsTests")
|
|
|
Body &body = ioContext.CreateBox(cInitialPos, Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::Discrete, Layers::MOVING, Vec3(1, 1, 1));
|
|
|
CHECK_APPROX_EQUAL(cInitialPos, body.GetPosition());
|
|
|
CHECK_APPROX_EQUAL(Vec3::sZero(), body.GetLinearVelocity());
|
|
|
-
|
|
|
+
|
|
|
ioContext.Simulate(cSimulationTime);
|
|
|
-
|
|
|
+
|
|
|
// Test resulting velocity (due to gravity)
|
|
|
CHECK_APPROX_EQUAL(cSimulationTime * cGravity, body.GetLinearVelocity(), 1.0e-4f);
|
|
|
-
|
|
|
+
|
|
|
// Test resulting position
|
|
|
RVec3 expected_pos = ioContext.PredictPosition(cInitialPos, Vec3::sZero(), cGravity, cSimulationTime);
|
|
|
CHECK_APPROX_EQUAL(expected_pos, body.GetPosition());
|
|
@@ -422,10 +423,10 @@ TEST_SUITE("PhysicsTests")
|
|
|
|
|
|
// Simulate while applying force
|
|
|
ioContext.Simulate(cSimulationTime, [&]() { body.AddForce(mass * cAcceleration); });
|
|
|
-
|
|
|
+
|
|
|
// Test resulting velocity (due to gravity and applied force)
|
|
|
CHECK_APPROX_EQUAL(cSimulationTime * (cGravity + cAcceleration), body.GetLinearVelocity(), 1.0e-4f);
|
|
|
-
|
|
|
+
|
|
|
// Test resulting position
|
|
|
RVec3 expected_pos = ioContext.PredictPosition(cInitialPos, Vec3::sZero(), cGravity + cAcceleration, cSimulationTime);
|
|
|
CHECK_APPROX_EQUAL(expected_pos, body.GetPosition());
|
|
@@ -463,13 +464,13 @@ TEST_SUITE("PhysicsTests")
|
|
|
CHECK_APPROX_EQUAL(1.0f / mass, body.GetMotionProperties()->GetInverseMass());
|
|
|
constexpr float inertia = mass * 8.0f / 12.0f; // See: https://en.wikipedia.org/wiki/List_of_moments_of_inertia
|
|
|
CHECK_APPROX_EQUAL(Mat44::sScale(1.0f / inertia), body.GetMotionProperties()->GetLocalSpaceInverseInertia());
|
|
|
-
|
|
|
+
|
|
|
// Simulate while applying torque
|
|
|
ioContext.Simulate(cSimulationTime, [&]() { body.AddTorque(inertia * cAngularAcceleration); });
|
|
|
-
|
|
|
+
|
|
|
// Get resulting angular velocity
|
|
|
CHECK_APPROX_EQUAL(cSimulationTime * cAngularAcceleration, body.GetAngularVelocity(), 1.0e-4f);
|
|
|
-
|
|
|
+
|
|
|
// Test resulting rotation
|
|
|
Quat expected_rot = ioContext.PredictOrientation(Quat::sIdentity(), Vec3::sZero(), cAngularAcceleration, cSimulationTime);
|
|
|
CHECK_APPROX_EQUAL(expected_rot, body.GetRotation(), 1.0e-4f);
|
|
@@ -488,7 +489,7 @@ TEST_SUITE("PhysicsTests")
|
|
|
|
|
|
PhysicsTestContext c2(4.0f / 60.0f, 4);
|
|
|
TestPhysicsApplyTorque(c2);
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
// Let a sphere bounce on the floor with restition = 1
|
|
|
static void TestPhysicsCollisionElastic(PhysicsTestContext &ioContext)
|
|
@@ -509,13 +510,13 @@ TEST_SUITE("PhysicsTests")
|
|
|
CHECK_APPROX_EQUAL(cFloorHitPos, body.GetPosition());
|
|
|
|
|
|
// Assert collision not yet processed
|
|
|
- CHECK_APPROX_EQUAL(cSimulationTime * cGravity, body.GetLinearVelocity(), 1.0e-4f);
|
|
|
+ CHECK_APPROX_EQUAL(cSimulationTime * cGravity, body.GetLinearVelocity(), 1.0e-4f);
|
|
|
|
|
|
// Simulate one more step to process the collision
|
|
|
ioContext.Simulate(ioContext.GetDeltaTime());
|
|
|
|
|
|
- // Assert that collision is processed and velocity is reversed (which is required for a fully elastic collision).
|
|
|
- // Note that the physics engine will first apply gravity for the time step and then do collision detection,
|
|
|
+ // Assert that collision is processed and velocity is reversed (which is required for a fully elastic collision).
|
|
|
+ // Note that the physics engine will first apply gravity for the time step and then do collision detection,
|
|
|
// hence the reflected velocity is actually 1 step times gravity bigger than it would be in reality
|
|
|
// For the remainder of cDeltaTime normal gravity will be applied
|
|
|
float sub_step_delta_time = ioContext.GetStepDeltaTime();
|
|
@@ -550,7 +551,7 @@ TEST_SUITE("PhysicsTests")
|
|
|
|
|
|
PhysicsTestContext c2(4.0f / 60.0f, 4);
|
|
|
TestPhysicsCollisionElastic(c2);
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
// Let a sphere bounce on the floor with restitution = 0
|
|
|
static void TestPhysicsCollisionInelastic(PhysicsTestContext &ioContext)
|
|
@@ -571,7 +572,7 @@ TEST_SUITE("PhysicsTests")
|
|
|
CHECK_APPROX_EQUAL(cFloorHitPos, body.GetPosition());
|
|
|
|
|
|
// Assert collision not yet processed
|
|
|
- CHECK_APPROX_EQUAL(cSimulationTime * cGravity, body.GetLinearVelocity(), 1.0e-4f);
|
|
|
+ CHECK_APPROX_EQUAL(cSimulationTime * cGravity, body.GetLinearVelocity(), 1.0e-4f);
|
|
|
|
|
|
// Simulate one more step to process the collision
|
|
|
ioContext.Simulate(ioContext.GetDeltaTime());
|
|
@@ -601,8 +602,8 @@ TEST_SUITE("PhysicsTests")
|
|
|
|
|
|
PhysicsTestContext c2(4.0f / 60.0f, 4);
|
|
|
TestPhysicsCollisionInelastic(c2);
|
|
|
- }
|
|
|
-
|
|
|
+ }
|
|
|
+
|
|
|
// Let box intersect with floor by cPenetrationSlop. It should not move, this is the maximum penetration allowed.
|
|
|
static void TestPhysicsPenetrationSlop1(PhysicsTestContext &ioContext)
|
|
|
{
|
|
@@ -636,7 +637,7 @@ TEST_SUITE("PhysicsTests")
|
|
|
|
|
|
PhysicsTestContext c2(4.0f / 60.0f, 4);
|
|
|
TestPhysicsPenetrationSlop1(c2);
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
// Let box intersect with floor with more than cPenetrationSlop. It should be resolved by SolvePositionConstraint until interpenetration is cPenetrationSlop.
|
|
|
static void TestPhysicsPenetrationSlop2(PhysicsTestContext &ioContext)
|
|
@@ -672,7 +673,7 @@ TEST_SUITE("PhysicsTests")
|
|
|
|
|
|
PhysicsTestContext c2(4.0f / 60.0f, 4);
|
|
|
TestPhysicsPenetrationSlop2(c2);
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
// Let box intersect with floor with less than cPenetrationSlop. Body should not move because SolveVelocityConstraint should reset velocity.
|
|
|
static void TestPhysicsPenetrationSlop3(PhysicsTestContext &ioContext)
|
|
@@ -797,7 +798,7 @@ TEST_SUITE("PhysicsTests")
|
|
|
|
|
|
// Sphere has only 1 contact point so is much more accurate
|
|
|
CHECK_APPROX_EQUAL(sphere.GetPosition(), RVec3(5, 1, 0));
|
|
|
- CHECK_APPROX_EQUAL(sphere.GetLinearVelocity(), cExpectedVelocity, 1.0e-4f);
|
|
|
+ CHECK_APPROX_EQUAL(sphere.GetLinearVelocity(), cExpectedVelocity, 1.0e-4f);
|
|
|
CHECK_APPROX_EQUAL(sphere.GetAngularVelocity(), Vec3::sZero(), 1.0e-4f);
|
|
|
|
|
|
// Simulate a step
|
|
@@ -815,7 +816,7 @@ TEST_SUITE("PhysicsTests")
|
|
|
|
|
|
// Sphere should have come to rest
|
|
|
CHECK_APPROX_EQUAL(sphere.GetPosition(), RVec3(5, 1, 0), 1.0e-4f);
|
|
|
- CHECK_APPROX_EQUAL(sphere.GetLinearVelocity(), Vec3::sZero(), 1.0e-4f);
|
|
|
+ CHECK_APPROX_EQUAL(sphere.GetLinearVelocity(), Vec3::sZero(), 1.0e-4f);
|
|
|
CHECK_APPROX_EQUAL(sphere.GetAngularVelocity(), Vec3::sZero(), 1.0e-4f);
|
|
|
}
|
|
|
|
|
@@ -858,12 +859,12 @@ TEST_SUITE("PhysicsTests")
|
|
|
|
|
|
// Box collision is less accurate than sphere as it hits with 4 corners so there's some floating point precision loss in the calculation
|
|
|
CHECK_APPROX_EQUAL(box.GetPosition(), cInitialPosBox - cVelocity * c.GetDeltaTime(), 0.01f);
|
|
|
- CHECK_APPROX_EQUAL(box.GetLinearVelocity(), -cVelocity, 0.1f);
|
|
|
+ CHECK_APPROX_EQUAL(box.GetLinearVelocity(), -cVelocity, 0.1f);
|
|
|
CHECK_APPROX_EQUAL(box.GetAngularVelocity(), Vec3::sZero(), 0.02f);
|
|
|
|
|
|
// Sphere has only 1 contact point so is much more accurate
|
|
|
CHECK_APPROX_EQUAL(sphere.GetPosition(), cInitialPosSphere - cVelocity * c.GetDeltaTime(), 1.0e-5f);
|
|
|
- CHECK_APPROX_EQUAL(sphere.GetLinearVelocity(), -cVelocity, 2.0e-4f);
|
|
|
+ CHECK_APPROX_EQUAL(sphere.GetLinearVelocity(), -cVelocity, 2.0e-4f);
|
|
|
CHECK_APPROX_EQUAL(sphere.GetAngularVelocity(), Vec3::sZero(), 2.0e-4f);
|
|
|
|
|
|
// Simulate a step
|
|
@@ -967,12 +968,12 @@ TEST_SUITE("PhysicsTests")
|
|
|
|
|
|
// Box should have moved unimpeded
|
|
|
CHECK_APPROX_EQUAL(box.GetPosition(), cInitialPosBox + cVelocity * c.GetDeltaTime());
|
|
|
- CHECK_APPROX_EQUAL(box.GetLinearVelocity(), cVelocity);
|
|
|
+ CHECK_APPROX_EQUAL(box.GetLinearVelocity(), cVelocity);
|
|
|
CHECK_APPROX_EQUAL(box.GetAngularVelocity(), Vec3::sZero());
|
|
|
|
|
|
// Sphere should have moved unimpeded
|
|
|
CHECK_APPROX_EQUAL(sphere.GetPosition(), cInitialPosSphere + cVelocity * c.GetDeltaTime());
|
|
|
- CHECK_APPROX_EQUAL(sphere.GetLinearVelocity(), cVelocity);
|
|
|
+ CHECK_APPROX_EQUAL(sphere.GetLinearVelocity(), cVelocity);
|
|
|
CHECK_APPROX_EQUAL(sphere.GetAngularVelocity(), Vec3::sZero());
|
|
|
|
|
|
// Simulate a step
|
|
@@ -1088,7 +1089,7 @@ TEST_SUITE("PhysicsTests")
|
|
|
|
|
|
// Step the world
|
|
|
ioContext.SimulateSingleStep();
|
|
|
-
|
|
|
+
|
|
|
// Other bodies should now be awake and each body should only collide with its neighbour
|
|
|
CHECK(activation_listener.GetEntryCount() == cNumBodies - 1);
|
|
|
CHECK(contact_listener.GetEntryCount() == 2 * (cNumBodies - 1));
|
|
@@ -1321,7 +1322,7 @@ TEST_SUITE("PhysicsTests")
|
|
|
// Check that the bodies in the different systems updated correctly
|
|
|
CHECK_APPROX_EQUAL(lock1.GetBody().GetPosition(), cBox1Position + cBox1Velocity * cTime, 1.0e-5f);
|
|
|
CHECK_APPROX_EQUAL(lock2.GetBody().GetPosition(), cBox2Position + cBox2Velocity * cTime, 1.0e-5f);
|
|
|
- }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
TEST_CASE("TestOutOfBodies")
|
|
@@ -1477,4 +1478,191 @@ TEST_SUITE("PhysicsTests")
|
|
|
CHECK_APPROX_EQUAL(box.GetRotation(), expected_rotation);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ TEST_CASE("TestSelectiveStateSaveAndRestore")
|
|
|
+ {
|
|
|
+ class MyFilter : public StateRecorderFilter
|
|
|
+ {
|
|
|
+ public:
|
|
|
+ bool ShouldSaveBody(const BodyID &inBodyID) const
|
|
|
+ {
|
|
|
+ return find(mIgnoreBodies.cbegin(), mIgnoreBodies.cend(), inBodyID) == mIgnoreBodies.cend();
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual bool ShouldSaveBody(const Body &inBody) const override
|
|
|
+ {
|
|
|
+ return ShouldSaveBody(inBody.GetID());
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual bool ShouldSaveContact(const BodyID &inBody1, const BodyID &inBody2) const override
|
|
|
+ {
|
|
|
+ return ShouldSaveBody(inBody1) && ShouldSaveBody(inBody2);
|
|
|
+ }
|
|
|
+
|
|
|
+ Array<BodyID> mIgnoreBodies;
|
|
|
+ };
|
|
|
+
|
|
|
+ for (int mode = 0; mode < 2; mode++)
|
|
|
+ {
|
|
|
+ PhysicsTestContext c;
|
|
|
+
|
|
|
+ Vec3 gravity = c.GetSystem()->GetGravity();
|
|
|
+ Vec3 upside_down_gravity = -gravity;
|
|
|
+
|
|
|
+ // Create the ground.
|
|
|
+ Body &ground = c.CreateFloor();
|
|
|
+
|
|
|
+ // Create two sets of bodies that each overlap
|
|
|
+ Body &box1 = c.CreateBox(RVec3(0, 1, 0), Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::Discrete, Layers::MOVING, Vec3::sReplicate(1.0f), EActivation::Activate);
|
|
|
+ Body &sphere1 = c.CreateSphere(RVec3(0, 1, 0.1f), 1.0f, EMotionType::Dynamic, EMotionQuality::Discrete, Layers::MOVING, EActivation::Activate);
|
|
|
+
|
|
|
+ Body &box2 = c.CreateBox(RVec3(5, 1, 0), Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::Discrete, Layers::MOVING, Vec3::sReplicate(1.0f), EActivation::Activate);
|
|
|
+ Body &sphere2 = c.CreateSphere(RVec3(5, 1, 0.1f), 1.0f, EMotionType::Dynamic, EMotionQuality::Discrete, Layers::MOVING, EActivation::Activate);
|
|
|
+
|
|
|
+ // Store the absolute initial state, that will be used for the final test.
|
|
|
+ StateRecorderImpl absolute_initial_state;
|
|
|
+ c.GetSystem()->SaveState(absolute_initial_state);
|
|
|
+
|
|
|
+ EStateRecorderState state_to_save = EStateRecorderState::All;
|
|
|
+ MyFilter filter;
|
|
|
+ if (mode == 1)
|
|
|
+ {
|
|
|
+ // Don't save the global state
|
|
|
+ state_to_save = EStateRecorderState(uint(EStateRecorderState::All) ^ uint(EStateRecorderState::Global));
|
|
|
+
|
|
|
+ // Don't save some bodies
|
|
|
+ filter.mIgnoreBodies.push_back(ground.GetID());
|
|
|
+ filter.mIgnoreBodies.push_back(box2.GetID());
|
|
|
+ filter.mIgnoreBodies.push_back(sphere2.GetID());
|
|
|
+ }
|
|
|
+
|
|
|
+ // Store the initial transform.
|
|
|
+ const RMat44 initial_box1_transform = box1.GetWorldTransform();
|
|
|
+ const RMat44 initial_sphere1_transform = sphere1.GetWorldTransform();
|
|
|
+ const RMat44 initial_box2_transform = box2.GetWorldTransform();
|
|
|
+ const RMat44 initial_sphere2_transform = sphere2.GetWorldTransform();
|
|
|
+
|
|
|
+ // Save partial state
|
|
|
+ StateRecorderImpl initial_state;
|
|
|
+ c.GetSystem()->SaveState(initial_state, state_to_save, &filter);
|
|
|
+
|
|
|
+ // Simulate for 2 seconds
|
|
|
+ c.Simulate(2.0f);
|
|
|
+
|
|
|
+ // The bodies should have moved and come to rest
|
|
|
+ const RMat44 intermediate_box1_transform = box1.GetWorldTransform();
|
|
|
+ const RMat44 intermediate_sphere1_transform = sphere1.GetWorldTransform();
|
|
|
+ const RMat44 intermediate_box2_transform = box2.GetWorldTransform();
|
|
|
+ const RMat44 intermediate_sphere2_transform = sphere2.GetWorldTransform();
|
|
|
+ CHECK(intermediate_box1_transform != initial_box1_transform);
|
|
|
+ CHECK(intermediate_sphere1_transform != initial_sphere1_transform);
|
|
|
+ CHECK(intermediate_box2_transform != initial_box2_transform);
|
|
|
+ CHECK(intermediate_sphere2_transform != initial_sphere2_transform);
|
|
|
+ CHECK(!box1.IsActive());
|
|
|
+ CHECK(!sphere1.IsActive());
|
|
|
+ CHECK(!box2.IsActive());
|
|
|
+ CHECK(!sphere2.IsActive());
|
|
|
+
|
|
|
+ // Save the intermediate state.
|
|
|
+ StateRecorderImpl intermediate_state;
|
|
|
+ c.GetSystem()->SaveState(intermediate_state, state_to_save, &filter);
|
|
|
+
|
|
|
+ // Change the gravity.
|
|
|
+ c.GetSystem()->SetGravity(upside_down_gravity);
|
|
|
+
|
|
|
+ // Restore the initial state.
|
|
|
+ c.GetSystem()->RestoreState(initial_state);
|
|
|
+
|
|
|
+ // Make sure the state is properly set back to the initial state.
|
|
|
+ CHECK(box1.GetWorldTransform() == initial_box1_transform);
|
|
|
+ CHECK(sphere1.GetWorldTransform() == initial_sphere1_transform);
|
|
|
+ CHECK(box1.IsActive());
|
|
|
+ CHECK(sphere1.IsActive());
|
|
|
+ if (mode == 0)
|
|
|
+ {
|
|
|
+ // Make sure the gravity is restored.
|
|
|
+ CHECK(c.GetSystem()->GetGravity() == gravity);
|
|
|
+
|
|
|
+ // The second set of bodies should have been restored as well
|
|
|
+ CHECK(box2.GetWorldTransform() == initial_box2_transform);
|
|
|
+ CHECK(sphere2.GetWorldTransform() == initial_sphere2_transform);
|
|
|
+ CHECK(box2.IsActive());
|
|
|
+ CHECK(sphere2.IsActive());
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // Make sure the gravity is NOT restored.
|
|
|
+ CHECK(c.GetSystem()->GetGravity() == upside_down_gravity);
|
|
|
+ c.GetSystem()->SetGravity(gravity);
|
|
|
+
|
|
|
+ // The second set of bodies should NOT have been restored
|
|
|
+ CHECK(box2.GetWorldTransform() == intermediate_box2_transform);
|
|
|
+ CHECK(sphere2.GetWorldTransform() == intermediate_sphere2_transform);
|
|
|
+ CHECK(!box2.IsActive());
|
|
|
+ CHECK(!sphere2.IsActive());
|
|
|
+
|
|
|
+ // Apply a velocity to the second set of bodies to make sure they are active again
|
|
|
+ c.GetBodyInterface().SetLinearVelocity(box2.GetID(), Vec3(0, 0, 0.1f));
|
|
|
+ c.GetBodyInterface().SetLinearVelocity(sphere2.GetID(), Vec3(0, 0, 0.1f));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Simulate for 2 seconds - again
|
|
|
+ c.Simulate(2.0f);
|
|
|
+
|
|
|
+ // The first set of bodies have been saved and should have returned to the same positions again
|
|
|
+ CHECK(box1.GetWorldTransform() == intermediate_box1_transform);
|
|
|
+ CHECK(sphere1.GetWorldTransform() == intermediate_sphere1_transform);
|
|
|
+ CHECK(!box1.IsActive());
|
|
|
+ CHECK(!sphere1.IsActive());
|
|
|
+ if (mode == 0)
|
|
|
+ {
|
|
|
+ // The second set of bodies have been saved and should have returned to the same positions again
|
|
|
+ CHECK(box2.GetWorldTransform() == intermediate_box2_transform);
|
|
|
+ CHECK(sphere2.GetWorldTransform() == intermediate_sphere2_transform);
|
|
|
+ CHECK(!box2.IsActive());
|
|
|
+ CHECK(!sphere2.IsActive());
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // The second set of bodies have not been saved and should have moved on
|
|
|
+ CHECK(box2.GetWorldTransform() != intermediate_box2_transform);
|
|
|
+ CHECK(sphere2.GetWorldTransform() != intermediate_sphere2_transform);
|
|
|
+ CHECK(!box2.IsActive());
|
|
|
+ CHECK(sphere2.IsActive()); // The sphere keeps rolling
|
|
|
+ }
|
|
|
+
|
|
|
+ // Save the final state
|
|
|
+ StateRecorderImpl final_state;
|
|
|
+ c.GetSystem()->SaveState(final_state, state_to_save, &filter);
|
|
|
+
|
|
|
+ // Compare the states to make sure they are the same
|
|
|
+ CHECK(final_state.IsEqual(intermediate_state));
|
|
|
+
|
|
|
+ // Now restore the absolute initial state and make sure all the
|
|
|
+ // bodies are being active and ready to be processed again
|
|
|
+ c.GetSystem()->RestoreState(absolute_initial_state);
|
|
|
+
|
|
|
+ CHECK(box1.GetWorldTransform() == initial_box1_transform);
|
|
|
+ CHECK(sphere1.GetWorldTransform() == initial_sphere1_transform);
|
|
|
+ CHECK(box2.GetWorldTransform() == initial_box2_transform);
|
|
|
+ CHECK(sphere2.GetWorldTransform() == initial_sphere2_transform);
|
|
|
+ CHECK(box1.IsActive());
|
|
|
+ CHECK(sphere1.IsActive());
|
|
|
+ CHECK(box2.IsActive());
|
|
|
+ CHECK(sphere2.IsActive());
|
|
|
+
|
|
|
+ // Simulate for 2 seconds - again
|
|
|
+ c.Simulate(2.0f);
|
|
|
+
|
|
|
+ // We should have reached the same state as before
|
|
|
+ CHECK(box1.GetWorldTransform() == intermediate_box1_transform);
|
|
|
+ CHECK(sphere1.GetWorldTransform() == intermediate_sphere1_transform);
|
|
|
+ CHECK(box2.GetWorldTransform() == intermediate_box2_transform);
|
|
|
+ CHECK(sphere2.GetWorldTransform() == intermediate_sphere2_transform);
|
|
|
+ CHECK(!box1.IsActive());
|
|
|
+ CHECK(!sphere1.IsActive());
|
|
|
+ CHECK(!box2.IsActive());
|
|
|
+ CHECK(!sphere2.IsActive());
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|