File indexing completed on 2025-08-03 03:50:00
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/b2ContactManager.h> 0020 #include <Box2D/Dynamics/b2Body.h> 0021 #include <Box2D/Dynamics/b2Fixture.h> 0022 #include <Box2D/Dynamics/b2WorldCallbacks.h> 0023 #include <Box2D/Dynamics/Contacts/b2Contact.h> 0024 0025 b2ContactFilter b2_defaultFilter; 0026 b2ContactListener b2_defaultListener; 0027 0028 b2ContactManager::b2ContactManager() 0029 { 0030 m_contactList = NULL; 0031 m_contactCount = 0; 0032 m_contactFilter = &b2_defaultFilter; 0033 m_contactListener = &b2_defaultListener; 0034 m_allocator = NULL; 0035 } 0036 0037 void b2ContactManager::Destroy(b2Contact* c) 0038 { 0039 b2Fixture* fixtureA = c->GetFixtureA(); 0040 b2Fixture* fixtureB = c->GetFixtureB(); 0041 b2Body* bodyA = fixtureA->GetBody(); 0042 b2Body* bodyB = fixtureB->GetBody(); 0043 0044 if (m_contactListener && c->IsTouching()) 0045 { 0046 m_contactListener->EndContact(c); 0047 } 0048 0049 // Remove from the world. 0050 if (c->m_prev) 0051 { 0052 c->m_prev->m_next = c->m_next; 0053 } 0054 0055 if (c->m_next) 0056 { 0057 c->m_next->m_prev = c->m_prev; 0058 } 0059 0060 if (c == m_contactList) 0061 { 0062 m_contactList = c->m_next; 0063 } 0064 0065 // Remove from body 1 0066 if (c->m_nodeA.prev) 0067 { 0068 c->m_nodeA.prev->next = c->m_nodeA.next; 0069 } 0070 0071 if (c->m_nodeA.next) 0072 { 0073 c->m_nodeA.next->prev = c->m_nodeA.prev; 0074 } 0075 0076 if (&c->m_nodeA == bodyA->m_contactList) 0077 { 0078 bodyA->m_contactList = c->m_nodeA.next; 0079 } 0080 0081 // Remove from body 2 0082 if (c->m_nodeB.prev) 0083 { 0084 c->m_nodeB.prev->next = c->m_nodeB.next; 0085 } 0086 0087 if (c->m_nodeB.next) 0088 { 0089 c->m_nodeB.next->prev = c->m_nodeB.prev; 0090 } 0091 0092 if (&c->m_nodeB == bodyB->m_contactList) 0093 { 0094 bodyB->m_contactList = c->m_nodeB.next; 0095 } 0096 0097 // Call the factory. 0098 b2Contact::Destroy(c, m_allocator); 0099 --m_contactCount; 0100 } 0101 0102 // This is the top level collision call for the time step. Here 0103 // all the narrow phase collision is processed for the world 0104 // contact list. 0105 void b2ContactManager::Collide() 0106 { 0107 // Update awake contacts. 0108 b2Contact* c = m_contactList; 0109 while (c) 0110 { 0111 b2Fixture* fixtureA = c->GetFixtureA(); 0112 b2Fixture* fixtureB = c->GetFixtureB(); 0113 int32 indexA = c->GetChildIndexA(); 0114 int32 indexB = c->GetChildIndexB(); 0115 b2Body* bodyA = fixtureA->GetBody(); 0116 b2Body* bodyB = fixtureB->GetBody(); 0117 0118 if (bodyA->IsAwake() == false && bodyB->IsAwake() == false) 0119 { 0120 c = c->GetNext(); 0121 continue; 0122 } 0123 0124 // Is this contact flagged for filtering? 0125 if (c->m_flags & b2Contact::e_filterFlag) 0126 { 0127 // Should these bodies collide? 0128 if (bodyB->ShouldCollide(bodyA) == false) 0129 { 0130 b2Contact* cNuke = c; 0131 c = cNuke->GetNext(); 0132 Destroy(cNuke); 0133 continue; 0134 } 0135 0136 // Check user filtering. 0137 if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false) 0138 { 0139 b2Contact* cNuke = c; 0140 c = cNuke->GetNext(); 0141 Destroy(cNuke); 0142 continue; 0143 } 0144 0145 // Clear the filtering flag. 0146 c->m_flags &= ~b2Contact::e_filterFlag; 0147 } 0148 0149 int32 proxyIdA = fixtureA->m_proxies[indexA].proxyId; 0150 int32 proxyIdB = fixtureB->m_proxies[indexB].proxyId; 0151 bool overlap = m_broadPhase.TestOverlap(proxyIdA, proxyIdB); 0152 0153 // Here we destroy contacts that cease to overlap in the broad-phase. 0154 if (overlap == false) 0155 { 0156 b2Contact* cNuke = c; 0157 c = cNuke->GetNext(); 0158 Destroy(cNuke); 0159 continue; 0160 } 0161 0162 // The contact persists. 0163 c->Update(m_contactListener); 0164 c = c->GetNext(); 0165 } 0166 } 0167 0168 void b2ContactManager::FindNewContacts() 0169 { 0170 m_broadPhase.UpdatePairs(this); 0171 } 0172 0173 void b2ContactManager::AddPair(void* proxyUserDataA, void* proxyUserDataB) 0174 { 0175 b2FixtureProxy* proxyA = (b2FixtureProxy*)proxyUserDataA; 0176 b2FixtureProxy* proxyB = (b2FixtureProxy*)proxyUserDataB; 0177 0178 b2Fixture* fixtureA = proxyA->fixture; 0179 b2Fixture* fixtureB = proxyB->fixture; 0180 0181 int32 indexA = proxyA->childIndex; 0182 int32 indexB = proxyB->childIndex; 0183 0184 b2Body* bodyA = fixtureA->GetBody(); 0185 b2Body* bodyB = fixtureB->GetBody(); 0186 0187 // Are the fixtures on the same body? 0188 if (bodyA == bodyB) 0189 { 0190 return; 0191 } 0192 0193 // Does a contact already exist? 0194 b2ContactEdge* edge = bodyB->GetContactList(); 0195 while (edge) 0196 { 0197 if (edge->other == bodyA) 0198 { 0199 b2Fixture* fA = edge->contact->GetFixtureA(); 0200 b2Fixture* fB = edge->contact->GetFixtureB(); 0201 int32 iA = edge->contact->GetChildIndexA(); 0202 int32 iB = edge->contact->GetChildIndexB(); 0203 0204 if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB) 0205 { 0206 // A contact already exists. 0207 return; 0208 } 0209 0210 if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA) 0211 { 0212 // A contact already exists. 0213 return; 0214 } 0215 } 0216 0217 edge = edge->next; 0218 } 0219 0220 // Does a joint override collision? Is at least one body dynamic? 0221 if (bodyB->ShouldCollide(bodyA) == false) 0222 { 0223 return; 0224 } 0225 0226 // Check user filtering. 0227 if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false) 0228 { 0229 return; 0230 } 0231 0232 // Call the factory. 0233 b2Contact* c = b2Contact::Create(fixtureA, indexA, fixtureB, indexB, m_allocator); 0234 0235 // Contact creation may swap fixtures. 0236 fixtureA = c->GetFixtureA(); 0237 fixtureB = c->GetFixtureB(); 0238 indexA = c->GetChildIndexA(); 0239 indexB = c->GetChildIndexB(); 0240 bodyA = fixtureA->GetBody(); 0241 bodyB = fixtureB->GetBody(); 0242 0243 // Insert into the world. 0244 c->m_prev = NULL; 0245 c->m_next = m_contactList; 0246 if (m_contactList != NULL) 0247 { 0248 m_contactList->m_prev = c; 0249 } 0250 m_contactList = c; 0251 0252 // Connect to island graph. 0253 0254 // Connect to body A 0255 c->m_nodeA.contact = c; 0256 c->m_nodeA.other = bodyB; 0257 0258 c->m_nodeA.prev = NULL; 0259 c->m_nodeA.next = bodyA->m_contactList; 0260 if (bodyA->m_contactList != NULL) 0261 { 0262 bodyA->m_contactList->prev = &c->m_nodeA; 0263 } 0264 bodyA->m_contactList = &c->m_nodeA; 0265 0266 // Connect to body B 0267 c->m_nodeB.contact = c; 0268 c->m_nodeB.other = bodyA; 0269 0270 c->m_nodeB.prev = NULL; 0271 c->m_nodeB.next = bodyB->m_contactList; 0272 if (bodyB->m_contactList != NULL) 0273 { 0274 bodyB->m_contactList->prev = &c->m_nodeB; 0275 } 0276 bodyB->m_contactList = &c->m_nodeB; 0277 0278 ++m_contactCount; 0279 }