summaryrefslogtreecommitdiff
path: root/Source/external/Box2D/Dynamics/b2ContactManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/external/Box2D/Dynamics/b2ContactManager.cpp')
-rw-r--r--Source/external/Box2D/Dynamics/b2ContactManager.cpp296
1 files changed, 296 insertions, 0 deletions
diff --git a/Source/external/Box2D/Dynamics/b2ContactManager.cpp b/Source/external/Box2D/Dynamics/b2ContactManager.cpp
new file mode 100644
index 0000000..051cc2f
--- /dev/null
+++ b/Source/external/Box2D/Dynamics/b2ContactManager.cpp
@@ -0,0 +1,296 @@
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "Box2D/Dynamics/b2ContactManager.h"
+#include "Box2D/Dynamics/b2Body.h"
+#include "Box2D/Dynamics/b2Fixture.h"
+#include "Box2D/Dynamics/b2WorldCallbacks.h"
+#include "Box2D/Dynamics/Contacts/b2Contact.h"
+
+b2ContactFilter b2_defaultFilter;
+b2ContactListener b2_defaultListener;
+
+b2ContactManager::b2ContactManager()
+{
+ m_contactList = nullptr;
+ m_contactCount = 0;
+ m_contactFilter = &b2_defaultFilter;
+ m_contactListener = &b2_defaultListener;
+ m_allocator = nullptr;
+}
+
+void b2ContactManager::Destroy(b2Contact* c)
+{
+ b2Fixture* fixtureA = c->GetFixtureA();
+ b2Fixture* fixtureB = c->GetFixtureB();
+ b2Body* bodyA = fixtureA->GetBody();
+ b2Body* bodyB = fixtureB->GetBody();
+
+ if (m_contactListener && c->IsTouching())
+ {
+ m_contactListener->EndContact(c);
+ }
+
+ // Remove from the world.
+ if (c->m_prev)
+ {
+ c->m_prev->m_next = c->m_next;
+ }
+
+ if (c->m_next)
+ {
+ c->m_next->m_prev = c->m_prev;
+ }
+
+ if (c == m_contactList)
+ {
+ m_contactList = c->m_next;
+ }
+
+ // Remove from body 1
+ if (c->m_nodeA.prev)
+ {
+ c->m_nodeA.prev->next = c->m_nodeA.next;
+ }
+
+ if (c->m_nodeA.next)
+ {
+ c->m_nodeA.next->prev = c->m_nodeA.prev;
+ }
+
+ if (&c->m_nodeA == bodyA->m_contactList)
+ {
+ bodyA->m_contactList = c->m_nodeA.next;
+ }
+
+ // Remove from body 2
+ if (c->m_nodeB.prev)
+ {
+ c->m_nodeB.prev->next = c->m_nodeB.next;
+ }
+
+ if (c->m_nodeB.next)
+ {
+ c->m_nodeB.next->prev = c->m_nodeB.prev;
+ }
+
+ if (&c->m_nodeB == bodyB->m_contactList)
+ {
+ bodyB->m_contactList = c->m_nodeB.next;
+ }
+
+ // Call the factory.
+ b2Contact::Destroy(c, m_allocator);
+ --m_contactCount;
+}
+
+// This is the top level collision call for the time step. Here
+// all the narrow phase collision is processed for the world
+// contact list.
+void b2ContactManager::Collide()
+{
+ // Update awake contacts.
+ b2Contact* c = m_contactList;
+ while (c)
+ {
+ b2Fixture* fixtureA = c->GetFixtureA();
+ b2Fixture* fixtureB = c->GetFixtureB();
+ int32 indexA = c->GetChildIndexA();
+ int32 indexB = c->GetChildIndexB();
+ b2Body* bodyA = fixtureA->GetBody();
+ b2Body* bodyB = fixtureB->GetBody();
+
+ // Is this contact flagged for filtering?
+ if (c->m_flags & b2Contact::e_filterFlag)
+ {
+ // Should these bodies collide?
+ if (bodyB->ShouldCollide(bodyA) == false)
+ {
+ b2Contact* cNuke = c;
+ c = cNuke->GetNext();
+ Destroy(cNuke);
+ continue;
+ }
+
+ // Check user filtering.
+ if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false)
+ {
+ b2Contact* cNuke = c;
+ c = cNuke->GetNext();
+ Destroy(cNuke);
+ continue;
+ }
+
+ // Clear the filtering flag.
+ c->m_flags &= ~b2Contact::e_filterFlag;
+ }
+
+ bool activeA = bodyA->IsAwake() && bodyA->m_type != b2_staticBody;
+ bool activeB = bodyB->IsAwake() && bodyB->m_type != b2_staticBody;
+
+ // At least one body must be awake and it must be dynamic or kinematic.
+ if (activeA == false && activeB == false)
+ {
+ c = c->GetNext();
+ continue;
+ }
+
+ int32 proxyIdA = fixtureA->m_proxies[indexA].proxyId;
+ int32 proxyIdB = fixtureB->m_proxies[indexB].proxyId;
+ bool overlap = m_broadPhase.TestOverlap(proxyIdA, proxyIdB);
+
+ // Here we destroy contacts that cease to overlap in the broad-phase.
+ if (overlap == false)
+ {
+ b2Contact* cNuke = c;
+ c = cNuke->GetNext();
+ Destroy(cNuke);
+ continue;
+ }
+
+ // The contact persists.
+ c->Update(m_contactListener);
+ c = c->GetNext();
+ }
+}
+
+void b2ContactManager::FindNewContacts()
+{
+ m_broadPhase.UpdatePairs(this);
+}
+
+void b2ContactManager::AddPair(void* proxyUserDataA, void* proxyUserDataB)
+{
+ b2FixtureProxy* proxyA = (b2FixtureProxy*)proxyUserDataA;
+ b2FixtureProxy* proxyB = (b2FixtureProxy*)proxyUserDataB;
+
+ b2Fixture* fixtureA = proxyA->fixture;
+ b2Fixture* fixtureB = proxyB->fixture;
+
+ int32 indexA = proxyA->childIndex;
+ int32 indexB = proxyB->childIndex;
+
+ b2Body* bodyA = fixtureA->GetBody();
+ b2Body* bodyB = fixtureB->GetBody();
+
+ // Are the fixtures on the same body?
+ if (bodyA == bodyB)
+ {
+ return;
+ }
+
+ // TODO_ERIN use a hash table to remove a potential bottleneck when both
+ // bodies have a lot of contacts.
+ // Does a contact already exist?
+ b2ContactEdge* edge = bodyB->GetContactList();
+ while (edge)
+ {
+ if (edge->other == bodyA)
+ {
+ b2Fixture* fA = edge->contact->GetFixtureA();
+ b2Fixture* fB = edge->contact->GetFixtureB();
+ int32 iA = edge->contact->GetChildIndexA();
+ int32 iB = edge->contact->GetChildIndexB();
+
+ if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB)
+ {
+ // A contact already exists.
+ return;
+ }
+
+ if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA)
+ {
+ // A contact already exists.
+ return;
+ }
+ }
+
+ edge = edge->next;
+ }
+
+ // Does a joint override collision? Is at least one body dynamic?
+ if (bodyB->ShouldCollide(bodyA) == false)
+ {
+ return;
+ }
+
+ // Check user filtering.
+ if (m_contactFilter && m_contactFilter->ShouldCollide(fixtureA, fixtureB) == false)
+ {
+ return;
+ }
+
+ // Call the factory.
+ b2Contact* c = b2Contact::Create(fixtureA, indexA, fixtureB, indexB, m_allocator);
+ if (c == nullptr)
+ {
+ return;
+ }
+
+ // Contact creation may swap fixtures.
+ fixtureA = c->GetFixtureA();
+ fixtureB = c->GetFixtureB();
+ indexA = c->GetChildIndexA();
+ indexB = c->GetChildIndexB();
+ bodyA = fixtureA->GetBody();
+ bodyB = fixtureB->GetBody();
+
+ // Insert into the world.
+ c->m_prev = nullptr;
+ c->m_next = m_contactList;
+ if (m_contactList != nullptr)
+ {
+ m_contactList->m_prev = c;
+ }
+ m_contactList = c;
+
+ // Connect to island graph.
+
+ // Connect to body A
+ c->m_nodeA.contact = c;
+ c->m_nodeA.other = bodyB;
+
+ c->m_nodeA.prev = nullptr;
+ c->m_nodeA.next = bodyA->m_contactList;
+ if (bodyA->m_contactList != nullptr)
+ {
+ bodyA->m_contactList->prev = &c->m_nodeA;
+ }
+ bodyA->m_contactList = &c->m_nodeA;
+
+ // Connect to body B
+ c->m_nodeB.contact = c;
+ c->m_nodeB.other = bodyA;
+
+ c->m_nodeB.prev = nullptr;
+ c->m_nodeB.next = bodyB->m_contactList;
+ if (bodyB->m_contactList != nullptr)
+ {
+ bodyB->m_contactList->prev = &c->m_nodeB;
+ }
+ bodyB->m_contactList = &c->m_nodeB;
+
+ // Wake up the bodies
+ if (fixtureA->IsSensor() == false && fixtureB->IsSensor() == false)
+ {
+ bodyA->SetAwake(true);
+ bodyB->SetAwake(true);
+ }
+
+ ++m_contactCount;
+}