File indexing completed on 2025-08-03 03:49:57

0001 /*
0002 * Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
0003 *
0004 * This software is provided 'as-is', without any express or implied
0005 * warranty.  In no event will the authors be held liable for any damages
0006 * arising from the use of this software.
0007 * Permission is granted to anyone to use this software for any purpose,
0008 * including commercial applications, and to alter it and redistribute it
0009 * freely, subject to the following restrictions:
0010 * 1. The origin of this software must not be misrepresented; you must not
0011 * claim that you wrote the original software. If you use this software
0012 * in a product, an acknowledgment in the product documentation would be
0013 * appreciated but is not required.
0014 * 2. Altered source versions must be plainly marked as such, and must not be
0015 * misrepresented as being the original software.
0016 * 3. This notice may not be removed or altered from any source distribution.
0017 */
0018 
0019 #include <Box2D/Dynamics/Contacts/b2Contact.h>
0020 #include <Box2D/Dynamics/Contacts/b2CircleContact.h>
0021 #include <Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h>
0022 #include <Box2D/Dynamics/Contacts/b2PolygonContact.h>
0023 #include <Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h>
0024 #include <Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h>
0025 #include <Box2D/Dynamics/Contacts/b2LoopAndCircleContact.h>
0026 #include <Box2D/Dynamics/Contacts/b2LoopAndPolygonContact.h>
0027 #include <Box2D/Dynamics/Contacts/b2ContactSolver.h>
0028 
0029 #include <Box2D/Collision/b2TimeOfImpact.h>
0030 #include <Box2D/Common/b2BlockAllocator.h>
0031 #include <Box2D/Dynamics/b2Body.h>
0032 #include <Box2D/Dynamics/b2World.h>
0033 
0034 b2ContactRegister b2Contact::s_registers[b2Shape::e_typeCount][b2Shape::e_typeCount];
0035 bool b2Contact::s_initialized = false;
0036 
0037 void b2Contact::InitializeRegisters()
0038 {
0039     AddType(b2CircleContact::Create, b2CircleContact::Destroy, b2Shape::e_circle, b2Shape::e_circle);
0040     AddType(b2PolygonAndCircleContact::Create, b2PolygonAndCircleContact::Destroy, b2Shape::e_polygon, b2Shape::e_circle);
0041     AddType(b2PolygonContact::Create, b2PolygonContact::Destroy, b2Shape::e_polygon, b2Shape::e_polygon);
0042     AddType(b2EdgeAndCircleContact::Create, b2EdgeAndCircleContact::Destroy, b2Shape::e_edge, b2Shape::e_circle);
0043     AddType(b2EdgeAndPolygonContact::Create, b2EdgeAndPolygonContact::Destroy, b2Shape::e_edge, b2Shape::e_polygon);
0044     AddType(b2LoopAndCircleContact::Create, b2LoopAndCircleContact::Destroy, b2Shape::e_loop, b2Shape::e_circle);
0045     AddType(b2LoopAndPolygonContact::Create, b2LoopAndPolygonContact::Destroy, b2Shape::e_loop, b2Shape::e_polygon);
0046 }
0047 
0048 void b2Contact::AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destoryFcn,
0049                         b2Shape::Type type1, b2Shape::Type type2)
0050 {
0051     b2Assert(b2Shape::e_unknown < type1 && type1 < b2Shape::e_typeCount);
0052     b2Assert(b2Shape::e_unknown < type2 && type2 < b2Shape::e_typeCount);
0053     
0054     s_registers[type1][type2].createFcn = createFcn;
0055     s_registers[type1][type2].destroyFcn = destoryFcn;
0056     s_registers[type1][type2].primary = true;
0057 
0058     if (type1 != type2)
0059     {
0060         s_registers[type2][type1].createFcn = createFcn;
0061         s_registers[type2][type1].destroyFcn = destoryFcn;
0062         s_registers[type2][type1].primary = false;
0063     }
0064 }
0065 
0066 b2Contact* b2Contact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator)
0067 {
0068     if (s_initialized == false)
0069     {
0070         InitializeRegisters();
0071         s_initialized = true;
0072     }
0073 
0074     b2Shape::Type type1 = fixtureA->GetType();
0075     b2Shape::Type type2 = fixtureB->GetType();
0076 
0077     b2Assert(b2Shape::e_unknown < type1 && type1 < b2Shape::e_typeCount);
0078     b2Assert(b2Shape::e_unknown < type2 && type2 < b2Shape::e_typeCount);
0079     
0080     b2ContactCreateFcn* createFcn = s_registers[type1][type2].createFcn;
0081     if (createFcn)
0082     {
0083         if (s_registers[type1][type2].primary)
0084         {
0085             return createFcn(fixtureA, indexA, fixtureB, indexB, allocator);
0086         }
0087         else
0088         {
0089             return createFcn(fixtureB, indexB, fixtureA, indexA, allocator);
0090         }
0091     }
0092     else
0093     {
0094         return NULL;
0095     }
0096 }
0097 
0098 void b2Contact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
0099 {
0100     b2Assert(s_initialized == true);
0101 
0102     if (contact->m_manifold.pointCount > 0)
0103     {
0104         contact->GetFixtureA()->GetBody()->SetAwake(true);
0105         contact->GetFixtureB()->GetBody()->SetAwake(true);
0106     }
0107 
0108     b2Shape::Type typeA = contact->GetFixtureA()->GetType();
0109     b2Shape::Type typeB = contact->GetFixtureB()->GetType();
0110 
0111     b2Assert(b2Shape::e_unknown < typeA && typeB < b2Shape::e_typeCount);
0112     b2Assert(b2Shape::e_unknown < typeA && typeB < b2Shape::e_typeCount);
0113 
0114     b2ContactDestroyFcn* destroyFcn = s_registers[typeA][typeB].destroyFcn;
0115     destroyFcn(contact, allocator);
0116 }
0117 
0118 b2Contact::b2Contact(b2Fixture* fA, int32 indexA, b2Fixture* fB, int32 indexB)
0119 {
0120     m_flags = e_enabledFlag;
0121 
0122     m_fixtureA = fA;
0123     m_fixtureB = fB;
0124 
0125     m_indexA = indexA;
0126     m_indexB = indexB;
0127 
0128     m_manifold.pointCount = 0;
0129 
0130     m_prev = NULL;
0131     m_next = NULL;
0132 
0133     m_nodeA.contact = NULL;
0134     m_nodeA.prev = NULL;
0135     m_nodeA.next = NULL;
0136     m_nodeA.other = NULL;
0137 
0138     m_nodeB.contact = NULL;
0139     m_nodeB.prev = NULL;
0140     m_nodeB.next = NULL;
0141     m_nodeB.other = NULL;
0142 
0143     m_toiCount = 0;
0144 }
0145 
0146 // Update the contact manifold and touching status.
0147 // Note: do not assume the fixture AABBs are overlapping or are valid.
0148 void b2Contact::Update(b2ContactListener* listener)
0149 {
0150     b2Manifold oldManifold = m_manifold;
0151 
0152     // Re-enable this contact.
0153     m_flags |= e_enabledFlag;
0154 
0155     bool touching = false;
0156     bool wasTouching = (m_flags & e_touchingFlag) == e_touchingFlag;
0157 
0158     bool sensorA = m_fixtureA->IsSensor();
0159     bool sensorB = m_fixtureB->IsSensor();
0160     bool sensor = sensorA || sensorB;
0161 
0162     b2Body* bodyA = m_fixtureA->GetBody();
0163     b2Body* bodyB = m_fixtureB->GetBody();
0164     const b2Transform& xfA = bodyA->GetTransform();
0165     const b2Transform& xfB = bodyB->GetTransform();
0166 
0167     // Is this contact a sensor?
0168     if (sensor)
0169     {
0170         const b2Shape* shapeA = m_fixtureA->GetShape();
0171         const b2Shape* shapeB = m_fixtureB->GetShape();
0172         touching = b2TestOverlap(shapeA, m_indexA, shapeB, m_indexB, xfA, xfB);
0173 
0174         // Sensors don't generate manifolds.
0175         m_manifold.pointCount = 0;
0176     }
0177     else
0178     {
0179         Evaluate(&m_manifold, xfA, xfB);
0180         touching = m_manifold.pointCount > 0;
0181 
0182         // Match old contact ids to new contact ids and copy the
0183         // stored impulses to warm start the solver.
0184         for (int32 i = 0; i < m_manifold.pointCount; ++i)
0185         {
0186             b2ManifoldPoint* mp2 = m_manifold.points + i;
0187             mp2->normalImpulse = 0.0f;
0188             mp2->tangentImpulse = 0.0f;
0189             b2ContactID id2 = mp2->id;
0190             bool found = false;
0191 
0192             for (int32 j = 0; j < oldManifold.pointCount; ++j)
0193             {
0194                 b2ManifoldPoint* mp1 = oldManifold.points + j;
0195 
0196                 if (mp1->id.key == id2.key)
0197                 {
0198                     mp2->normalImpulse = mp1->normalImpulse;
0199                     mp2->tangentImpulse = mp1->tangentImpulse;
0200                     found = true;
0201                     break;
0202                 }
0203             }
0204 
0205             if (found == false)
0206             {
0207                 mp2->normalImpulse = 0.0f;
0208                 mp2->tangentImpulse = 0.0f;
0209             }
0210         }
0211 
0212         if (touching != wasTouching)
0213         {
0214             bodyA->SetAwake(true);
0215             bodyB->SetAwake(true);
0216         }
0217     }
0218 
0219     if (touching)
0220     {
0221         m_flags |= e_touchingFlag;
0222     }
0223     else
0224     {
0225         m_flags &= ~e_touchingFlag;
0226     }
0227 
0228     if (wasTouching == false && touching == true && listener)
0229     {
0230         listener->BeginContact(this);
0231     }
0232 
0233     if (wasTouching == true && touching == false && listener)
0234     {
0235         listener->EndContact(this);
0236     }
0237 
0238     if (sensor == false && touching && listener)
0239     {
0240         listener->PreSolve(this, &oldManifold);
0241     }
0242 }