diff --git a/Library/include/playrho/Contact.hpp b/Library/include/playrho/Contact.hpp index a8691aa9d1..bffc6d1cee 100644 --- a/Library/include/playrho/Contact.hpp +++ b/Library/include/playrho/Contact.hpp @@ -67,6 +67,9 @@ struct ToiConf; class Contact { public: + /// @brief Default contactable value. + static constexpr auto DefaultContactable = Contactable{InvalidBodyID, InvalidShapeID, 0}; + /// @brief Substep type. using substep_type = TimestepIters; @@ -74,7 +77,11 @@ class Contact constexpr Contact() noexcept = default; /// @brief Initializing constructor. - /// @note This need never be called directly by a user. + /// @param a The "a" contactable value. + /// @param b The "b" contactable value. + /// @post If either @p a or @p b is not the value of @c DefaultContactable then: + /// IsEnabled() and NeedsUpdating() return true, + /// else they return false. constexpr Contact(const Contactable& a, const Contactable& b) noexcept; /// @brief Is this contact touching? @@ -290,10 +297,10 @@ class Contact }; /// @brief Identifying info for the A-side of the 2-bodied contact. - Contactable m_contactableA{InvalidBodyID, InvalidShapeID, 0}; + Contactable m_contactableA = DefaultContactable; /// @brief Identifying info for the B-side of the 2-bodied contact. - Contactable m_contactableB{InvalidBodyID, InvalidShapeID, 0}; + Contactable m_contactableB = DefaultContactable; // initialized on construction (construction-time depedent) @@ -322,7 +329,8 @@ class Contact constexpr Contact::Contact(const Contactable& a, const Contactable& b) noexcept : m_contactableA{a}, m_contactableB{b}, - m_flags{e_enabledFlag | e_dirtyFlag} + m_flags{((a != DefaultContactable) || (b != DefaultContactable)) + ? FlagsType(e_enabledFlag | e_dirtyFlag): FlagsType{}} { } @@ -516,7 +524,8 @@ constexpr void Contact::IncrementToiCount() noexcept /// @relatedalso Contact constexpr bool operator==(const Contact& lhs, const Contact& rhs) noexcept { - return lhs.GetContactableA() == rhs.GetContactableB() && // + return lhs.GetContactableA() == rhs.GetContactableA() && // + lhs.GetContactableB() == rhs.GetContactableB() && // lhs.GetFriction() == rhs.GetFriction() && // lhs.GetRestitution() == rhs.GetRestitution() && // lhs.GetTangentSpeed() == rhs.GetTangentSpeed() && // diff --git a/UnitTests/Contact.cpp b/UnitTests/Contact.cpp index 666604e293..703be650c1 100644 --- a/UnitTests/Contact.cpp +++ b/UnitTests/Contact.cpp @@ -25,29 +25,6 @@ using namespace playrho; using namespace playrho::d2; -TEST(Contact, ByteSize) -{ - // Check size at test runtime instead of compile-time via static_assert to avoid stopping - // builds and to report actual size rather than just reporting that expected size is wrong. - switch (sizeof(Real)) - { - case 4: - EXPECT_EQ(alignof(Contact), 4u); - EXPECT_EQ(sizeof(Contact), std::size_t(36)); - break; - case 8: - EXPECT_EQ(alignof(Contact), 8u); - EXPECT_EQ(sizeof(Contact), std::size_t(56)); - break; - case 16: - EXPECT_EQ(sizeof(Contact), std::size_t(96)); - break; - default: - FAIL(); - break; - } -} - TEST(Contact, Enabled) { const auto bA = BodyID(0u); @@ -63,6 +40,11 @@ TEST(Contact, Enabled) TEST(Contact, DefaultConstruction) { + { + const auto c = Contact(); + EXPECT_EQ(c.GetContactableA(), Contact::DefaultContactable); + EXPECT_EQ(c.GetContactableB(), Contact::DefaultContactable); + } EXPECT_EQ(GetBodyA(Contact()), InvalidBodyID); EXPECT_EQ(GetBodyB(Contact()), InvalidBodyID); EXPECT_EQ(GetShapeA(Contact()), InvalidShapeID); @@ -218,3 +200,78 @@ TEST(Contact, GetOtherBody) EXPECT_EQ(GetOtherBody(contact, bodyIdA), bodyIdB); EXPECT_EQ(GetOtherBody(contact, bodyIdB), bodyIdA); } + +TEST(Contact, Equality) +{ + EXPECT_TRUE(Contact() == Contact()); + EXPECT_TRUE(Contact() == Contact(Contact::DefaultContactable, Contact::DefaultContactable)); + { + auto c = Contact(); + c.SetTouching(); + EXPECT_FALSE(Contact() == c); + } + { + auto c = Contact(); + c.SetEnabled(); + EXPECT_FALSE(Contact() == c); + } + { + auto c = Contact(); + c.SetFriction(NonNegative(2)); + EXPECT_FALSE(Contact() == c); + } + { + auto c = Contact(); + c.SetRestitution(Real(42)); + EXPECT_FALSE(Contact() == c); + } + { + auto c = Contact(); + c.SetTangentSpeed(42_mps); + EXPECT_FALSE(Contact() == c); + } + { + auto c = Contact(); + c.SetToiCount(42u); + EXPECT_FALSE(Contact() == c); + } + { + auto c = Contact(); + c.SetToi(std::optional>(0.5)); + EXPECT_FALSE(Contact() == c); + } + { + auto c = Contact(); + c.FlagForFiltering(); + EXPECT_FALSE(Contact() == c); + } + { + auto c = Contact(); + c.FlagForUpdating(); + EXPECT_FALSE(Contact() == c); + } + { + auto c = Contact(); + c.SetSensor(); + EXPECT_FALSE(Contact() == c); + } + { + auto c = Contact(); + c.SetImpenetrable(); + EXPECT_FALSE(Contact() == c); + } + { + auto c = Contact(); + c.SetIsActive(); + EXPECT_FALSE(Contact() == c); + } + EXPECT_FALSE(Contact() == + Contact(Contactable{BodyID(1u), ShapeID(0u), ChildCounter(0u)}, + Contact::DefaultContactable)); + EXPECT_FALSE(Contact() == + Contact(Contactable{BodyID(0u), ShapeID(1u), ChildCounter(0u)}, + Contact::DefaultContactable)); + EXPECT_FALSE(Contact() == + Contact(Contactable{BodyID(0u), ShapeID(0u), ChildCounter(1u)}, + Contact::DefaultContactable)); +}