in Box2D/Dynamics/b2ContactManager.cpp [177:296]
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 == NULL)
{
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 = NULL;
c->m_next = m_contactList;
if (m_contactList != NULL)
{
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 = NULL;
c->m_nodeA.next = bodyA->m_contactList;
if (bodyA->m_contactList != NULL)
{
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 = NULL;
c->m_nodeB.next = bodyB->m_contactList;
if (bodyB->m_contactList != NULL)
{
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;
}