00001 /* 00002 * Copyright (c) 2006-2009 Erin Catto http://www.box2d.org 00003 * 00004 * This software is provided 'as-is', without any express or implied 00005 * warranty. In no event will the authors be held liable for any damages 00006 * arising from the use of this software. 00007 * Permission is granted to anyone to use this software for any purpose, 00008 * including commercial applications, and to alter it and redistribute it 00009 * freely, subject to the following restrictions: 00010 * 1. The origin of this software must not be misrepresented; you must not 00011 * claim that you wrote the original software. If you use this software 00012 * in a product, an acknowledgment in the product documentation would be 00013 * appreciated but is not required. 00014 * 2. Altered source versions must be plainly marked as such, and must not be 00015 * misrepresented as being the original software. 00016 * 3. This notice may not be removed or altered from any source distribution. 00017 */ 00018 00019 #include <Box2D/Dynamics/b2ContactManager.h> 00020 #include <Box2D/Dynamics/b2Body.h> 00021 #include <Box2D/Dynamics/b2Fixture.h> 00022 #include <Box2D/Dynamics/b2WorldCallbacks.h> 00023 #include <Box2D/Dynamics/Contacts/b2Contact.h> 00024 00025 b2ContactFilter b2_defaultFilter; 00026 b2ContactListener b2_defaultListener; 00027 00028 b2ContactManager::b2ContactManager() 00029 { 00030 m_contactList = NULL; 00031 m_contactCount = 0; 00032 m_contactFilter = &b2_defaultFilter; 00033 m_contactListener = &b2_defaultListener; 00034 m_allocator = NULL; 00035 } 00036 00037 void b2ContactManager::Destroy(b2Contact* c) 00038 { 00039 b2Fixture* fixtureA = c->GetFixtureA(); 00040 b2Fixture* fixtureB = c->GetFixtureB(); 00041 b2Body* bodyA = fixtureA->GetBody(); 00042 b2Body* bodyB = fixtureB->GetBody(); 00043 00044 if (m_contactListener && c->IsTouching()) 00045 { 00046 m_contactListener->EndContact(c); 00047 } 00048 00049 // Remove from the world. 00050 if (c->m_prev) 00051 { 00052 c->m_prev->m_next = c->m_next; 00053 } 00054 00055 if (c->m_next) 00056 { 00057 c->m_next->m_prev = c->m_prev; 00058 } 00059 00060 if (c == m_contactList) 00061 { 00062 m_contactList = c->m_next; 00063 } 00064 00065 // Remove from body 1 00066 if (c->m_nodeA.prev) 00067 { 00068 c->m_nodeA.prev->next = c->m_nodeA.next; 00069 } 00070 00071 if (c->m_nodeA.next) 00072 { 00073 c->m_nodeA.next->prev = c->m_nodeA.prev; 00074 } 00075 00076 if (&c->m_nodeA == bodyA->m_contactList) 00077 { 00078 bodyA->m_contactList = c->m_nodeA.next; 00079 } 00080 00081 // Remove from body 2 00082 if (c->m_nodeB.prev) 00083 { 00084 c->m_nodeB.prev->next = c->m_nodeB.next; 00085 } 00086 00087 if (c->m_nodeB.next) 00088 { 00089 c->m_nodeB.next->prev = c->m_nodeB.prev; 00090 } 00091 00092 if (&c->m_nodeB == bodyB->m_contactList) 00093 { 00094 bodyB->m_contactList = c->m_nodeB.next; 00095 } 00096 00097 // Call the factory. 00098 b2Contact::Destroy(c, m_allocator); 00099 --m_contactCount; 00100 } 00101 00102 // This is the top level collision call for the time step. Here 00103 // all the narrow phase collision is processed for the world 00104 // contact list. 00105 void b2ContactManager::Collide() 00106 { 00107 // Update awake contacts. 00108 b2Contact* c = m_contactList; 00109 while (c) 00110 { 00111 b2Fixture* fixtureA = c->GetFixtureA(); 00112 b2Fixture* fixtureB = c->GetFixtureB(); 00113 int32 indexA = c->GetChildIndexA(); 00114 int32 indexB = c->GetChildIndexB(); 00115 b2Body* bodyA = fixtureA->GetBody(); 00116 b2Body* bodyB = fixtureB->GetBody(); 00117 00118 // Is this contact flagged for filtering? 00119 if (c->m_flags & b2Contact::e_filterFlag) 00120 { 00121 // Should these bodies collide? 00122 if (bodyB->ShouldCollide(bodyA) == false) 00123 { 00124 b2Contact* cNuke = c; 00125 c = cNuke->GetNext(); 00126 Destroy(cNuke); 00127 continue; 00128 } 00129 00130 // Check user filtering. 00131 if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false) 00132 { 00133 b2Contact* cNuke = c; 00134 c = cNuke->GetNext(); 00135 Destroy(cNuke); 00136 continue; 00137 } 00138 00139 // Clear the filtering flag. 00140 c->m_flags &= ~b2Contact::e_filterFlag; 00141 } 00142 00143 bool activeA = bodyA->IsAwake() && bodyA->m_type != b2_staticBody; 00144 bool activeB = bodyB->IsAwake() && bodyB->m_type != b2_staticBody; 00145 00146 // At least one body must be awake and it must be dynamic or kinematic. 00147 if (activeA == false && activeB == false) 00148 { 00149 c = c->GetNext(); 00150 continue; 00151 } 00152 00153 int32 proxyIdA = fixtureA->m_proxies[indexA].proxyId; 00154 int32 proxyIdB = fixtureB->m_proxies[indexB].proxyId; 00155 bool overlap = m_broadPhase.TestOverlap(proxyIdA, proxyIdB); 00156 00157 // Here we destroy contacts that cease to overlap in the broad-phase. 00158 if (overlap == false) 00159 { 00160 b2Contact* cNuke = c; 00161 c = cNuke->GetNext(); 00162 Destroy(cNuke); 00163 continue; 00164 } 00165 00166 // The contact persists. 00167 c->Update(m_contactListener); 00168 c = c->GetNext(); 00169 } 00170 } 00171 00172 void b2ContactManager::FindNewContacts() 00173 { 00174 m_broadPhase.UpdatePairs(this); 00175 } 00176 00177 void b2ContactManager::AddPair(void* proxyUserDataA, void* proxyUserDataB) 00178 { 00179 b2FixtureProxy* proxyA = (b2FixtureProxy*)proxyUserDataA; 00180 b2FixtureProxy* proxyB = (b2FixtureProxy*)proxyUserDataB; 00181 00182 b2Fixture* fixtureA = proxyA->fixture; 00183 b2Fixture* fixtureB = proxyB->fixture; 00184 00185 int32 indexA = proxyA->childIndex; 00186 int32 indexB = proxyB->childIndex; 00187 00188 b2Body* bodyA = fixtureA->GetBody(); 00189 b2Body* bodyB = fixtureB->GetBody(); 00190 00191 // Are the fixtures on the same body? 00192 if (bodyA == bodyB) 00193 { 00194 return; 00195 } 00196 00197 // TODO_ERIN use a hash table to remove a potential bottleneck when both 00198 // bodies have a lot of contacts. 00199 // Does a contact already exist? 00200 b2ContactEdge* edge = bodyB->GetContactList(); 00201 while (edge) 00202 { 00203 if (edge->other == bodyA) 00204 { 00205 b2Fixture* fA = edge->contact->GetFixtureA(); 00206 b2Fixture* fB = edge->contact->GetFixtureB(); 00207 int32 iA = edge->contact->GetChildIndexA(); 00208 int32 iB = edge->contact->GetChildIndexB(); 00209 00210 if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB) 00211 { 00212 // A contact already exists. 00213 return; 00214 } 00215 00216 if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA) 00217 { 00218 // A contact already exists. 00219 return; 00220 } 00221 } 00222 00223 edge = edge->next; 00224 } 00225 00226 // Does a joint override collision? Is at least one body dynamic? 00227 if (bodyB->ShouldCollide(bodyA) == false) 00228 { 00229 return; 00230 } 00231 00232 // Check user filtering. 00233 if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false) 00234 { 00235 return; 00236 } 00237 00238 // Call the factory. 00239 b2Contact* c = b2Contact::Create(fixtureA, indexA, fixtureB, indexB, m_allocator); 00240 if (c == NULL) 00241 { 00242 return; 00243 } 00244 00245 // Contact creation may swap fixtures. 00246 fixtureA = c->GetFixtureA(); 00247 fixtureB = c->GetFixtureB(); 00248 indexA = c->GetChildIndexA(); 00249 indexB = c->GetChildIndexB(); 00250 bodyA = fixtureA->GetBody(); 00251 bodyB = fixtureB->GetBody(); 00252 00253 // Insert into the world. 00254 c->m_prev = NULL; 00255 c->m_next = m_contactList; 00256 if (m_contactList != NULL) 00257 { 00258 m_contactList->m_prev = c; 00259 } 00260 m_contactList = c; 00261 00262 // Connect to island graph. 00263 00264 // Connect to body A 00265 c->m_nodeA.contact = c; 00266 c->m_nodeA.other = bodyB; 00267 00268 c->m_nodeA.prev = NULL; 00269 c->m_nodeA.next = bodyA->m_contactList; 00270 if (bodyA->m_contactList != NULL) 00271 { 00272 bodyA->m_contactList->prev = &c->m_nodeA; 00273 } 00274 bodyA->m_contactList = &c->m_nodeA; 00275 00276 // Connect to body B 00277 c->m_nodeB.contact = c; 00278 c->m_nodeB.other = bodyA; 00279 00280 c->m_nodeB.prev = NULL; 00281 c->m_nodeB.next = bodyB->m_contactList; 00282 if (bodyB->m_contactList != NULL) 00283 { 00284 bodyB->m_contactList->prev = &c->m_nodeB; 00285 } 00286 bodyB->m_contactList = &c->m_nodeB; 00287 00288 // Wake up the bodies 00289 if (fixtureA->IsSensor() == false && fixtureB->IsSensor() == false) 00290 { 00291 bodyA->SetAwake(true); 00292 bodyB->SetAwake(true); 00293 } 00294 00295 ++m_contactCount; 00296 }