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 }