// MIT License // Copyright (c) 2019 Erin Catto // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. #ifndef B2_CONTACT_H #define B2_CONTACT_H #include "b2_api.h" #include "b2_collision.h" #include "b2_fixture.h" #include "b2_math.h" #include "b2_shape.h" class b2Body; class b2Contact; class b2Fixture; class b2World; class b2BlockAllocator; class b2StackAllocator; class b2ContactListener; /// Friction mixing law. The idea is to allow either fixture to drive the friction to zero. /// For example, anything slides on ice. inline float b2MixFriction(float friction1, float friction2) { return b2Sqrt(friction1 * friction2); } /// Restitution mixing law. The idea is allow for anything to bounce off an inelastic surface. /// For example, a superball bounces on anything. inline float b2MixRestitution(float restitution1, float restitution2) { return restitution1 > restitution2 ? restitution1 : restitution2; } typedef void b2EvaluateFunction(b2Manifold* manifold, const b2Shape* shapeA, const b2Transform& xfA, const b2Shape* shapeB, const b2Transform& xfB); /// Restitution mixing law. This picks the lowest value. inline float b2MixRestitutionThreshold(float threshold1, float threshold2) { return threshold1 < threshold2 ? threshold1 : threshold2; } /// The class manages contact between two shapes. A contact exists for each overlapping /// AABB in the broad-phase (except if filtered). Therefore a contact object may exist /// that has no contact points. class B2_API b2Contact { public: /// Get the contact manifold. Do not modify the manifold unless you understand the /// internals of Box2D. b2Manifold* GetManifold(); const b2Manifold* GetManifold() const; /// Get the world manifold. void GetWorldManifold(b2WorldManifold* worldManifold) const; /// Is this contact touching? bool IsTouching() const; /// Enable/disable this contact. This can be used inside the pre-solve /// contact listener. The contact is only disabled for the current /// time step (or sub-step in continuous collisions). void SetEnabled(bool flag); /// Has this contact been disabled? bool IsEnabled() const; /// Get the next contact in the world's contact list. b2Contact* GetNext(); const b2Contact* GetNext() const; /// Get fixture A in this contact. b2Fixture* GetFixtureA(); const b2Fixture* GetFixtureA() const; /// Get fixture B in this contact. b2Fixture* GetFixtureB(); const b2Fixture* GetFixtureB() const; #ifdef ENABLE_FRICTION /// Override the default friction mixture. You can call this in b2ContactListener::PreSolve. /// This value persists until set or reset. void SetFriction(float friction); /// Get the friction. float GetFriction() const; /// Reset the friction mixture to the default value. void ResetFriction(); #endif // ENABLE_FRICTION #ifdef ENABLE_RESTITUTION /// Override the default restitution mixture. You can call this in b2ContactListener::PreSolve. /// The value persists until you set or reset. void SetRestitution(float restitution); /// Get the restitution. float GetRestitution() const; /// Reset the restitution to the default value. void ResetRestitution(); /// Override the default restitution velocity threshold mixture. You can call this in b2ContactListener::PreSolve. /// The value persists until you set or reset. void SetRestitutionThreshold(float threshold); /// Get the restitution threshold. float GetRestitutionThreshold() const; /// Reset the restitution threshold to the default value. void ResetRestitutionThreshold(); #endif // ENABLE_RESTITUTION #ifdef ENABLE_TANGENT_SPEED /// Set the desired tangent speed for a conveyor belt behavior. In meters per second. void SetTangentSpeed(float speed); /// Get the desired tangent speed. In meters per second. float GetTangentSpeed() const; #endif // ENABLE_TANGENT_SPEED /// Evaluate this contact with your own manifold and transforms. void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB); protected: friend class b2ContactManager; friend class b2World; friend class b2TOIMinHeap; friend class b2TOIQueryWrapper; friend class b2ContactSolver; friend class b2Body; friend class b2Fixture; // Flags stored in m_flags enum { // Used when crawling contact graph when forming islands. e_islandFlag = 0x0001, // This contact has persisted from the previous step e_persistFlag = 0x0002, // This contact needs filtering because a fixture filter was changed. e_filterFlag = 0x0004, // Set when the shapes are touching. e_touchingFlag = 0x0008, // This contact can be disabled (by user) e_enabledFlag = 0x0010, // This bullet contact had a TOI event e_bulletHitFlag = 0x0020 }; /// Flag this contact for filtering. Filtering will occur the next time step. void FlagForFiltering(); static bool InitializeRegisters(); static b2Contact* Create(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator); static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); b2Contact(b2Fixture* fixtureA, b2Fixture* fixtureB, b2EvaluateFunction* evaluateFunction); void Update(b2ContactListener* listener); float CalculateTOI(); static b2EvaluateFunction* functions[b2Shape::e_typeCount][b2Shape::e_typeCount]; b2EvaluateFunction* m_evaluateFunction; // World pool and list pointers. b2Contact* m_prev; b2Contact* m_next; b2Fixture* m_fixtureA; b2Fixture* m_fixtureB; b2Manifold m_manifold; uint32 m_flags; int32 m_toiIndex; #ifdef ENABLE_FRICTION float m_friction; #endif // ENABLE_FRICTION #ifdef ENABLE_RESTITUTION float m_restitution; float m_restitutionThreshold; #endif // ENABLE_RESTITUTION #ifdef ENABLE_TANGENT_SPEED float m_tangentSpeed; #endif // ENABLE_TANGENT_SPEED }; inline b2Manifold* b2Contact::GetManifold() { return &m_manifold; } inline const b2Manifold* b2Contact::GetManifold() const { return &m_manifold; } inline void b2Contact::GetWorldManifold(b2WorldManifold* worldManifold) const { const b2Body* bodyA = m_fixtureA->GetBody(); const b2Body* bodyB = m_fixtureB->GetBody(); const b2Shape* shapeA = m_fixtureA->GetShape(); const b2Shape* shapeB = m_fixtureB->GetShape(); worldManifold->Initialize(&m_manifold, bodyA->GetTransform(), shapeA->m_radius, bodyB->GetTransform(), shapeB->m_radius); } inline void b2Contact::SetEnabled(bool flag) { if (flag) { m_flags |= e_enabledFlag; } else { m_flags &= ~e_enabledFlag; } } inline bool b2Contact::IsEnabled() const { return (m_flags & e_enabledFlag) == e_enabledFlag; } inline bool b2Contact::IsTouching() const { return (m_flags & e_touchingFlag) == e_touchingFlag; } inline b2Contact* b2Contact::GetNext() { return m_next; } inline const b2Contact* b2Contact::GetNext() const { return m_next; } inline b2Fixture* b2Contact::GetFixtureA() { return m_fixtureA; } inline const b2Fixture* b2Contact::GetFixtureA() const { return m_fixtureA; } inline b2Fixture* b2Contact::GetFixtureB() { return m_fixtureB; } inline const b2Fixture* b2Contact::GetFixtureB() const { return m_fixtureB; } inline void b2Contact::FlagForFiltering() { m_flags |= e_filterFlag; } #ifdef ENABLE_FRICTION inline void b2Contact::SetFriction(float friction) { m_friction = friction; } inline float b2Contact::GetFriction() const { return m_friction; } inline void b2Contact::ResetFriction() { m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction); } #endif // ENABLE_FRICTION #ifdef ENABLE_RESTITUTION inline void b2Contact::SetRestitution(float restitution) { m_restitution = restitution; } inline float b2Contact::GetRestitution() const { return m_restitution; } inline void b2Contact::ResetRestitution() { m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution); } inline void b2Contact::SetRestitutionThreshold(float threshold) { m_restitutionThreshold = threshold; } inline float b2Contact::GetRestitutionThreshold() const { return m_restitutionThreshold; } inline void b2Contact::ResetRestitutionThreshold() { m_restitutionThreshold = b2MixRestitutionThreshold(m_fixtureA->m_restitutionThreshold, m_fixtureB->m_restitutionThreshold); } #endif // ENABLE_RESTITUTION #ifdef ENABLE_TANGENT_SPEED inline void b2Contact::SetTangentSpeed(float speed) { m_tangentSpeed = speed; } inline float b2Contact::GetTangentSpeed() const { return m_tangentSpeed; } #endif // ENABLE_TANGENT_SPEED inline void b2Contact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) { m_evaluateFunction(manifold, m_fixtureA->GetShape(), xfA, m_fixtureB->GetShape(), xfB); } #endif