use of spacegraph.space2d.phys.dynamics.contacts.Contact in project narchy by automenta.
the class ContactManager method popContact.
public Contact popContact(Fixture fixtureA, int indexA, Fixture fixtureB, int indexB) {
final ShapeType type1 = fixtureA.type();
final ShapeType type2 = fixtureB.type();
final ContactRegister reg = contactStacks[type1.ordinal()][type2.ordinal()];
if (reg != null) {
if (reg.primary) {
Contact c = reg.creator.pop();
c.init(fixtureA, indexA, fixtureB, indexB);
return c;
} else {
Contact c = reg.creator.pop();
c.init(fixtureB, indexB, fixtureA, indexA);
return c;
}
} else {
return null;
}
}
use of spacegraph.space2d.phys.dynamics.contacts.Contact in project narchy by automenta.
the class ContactManager method addPair.
/**
* Broad-phase callback.
*
* @param proxyUserDataA
* @param proxyUserDataB
*/
public void addPair(Object proxyUserDataA, Object proxyUserDataB) {
FixtureProxy proxyA = (FixtureProxy) proxyUserDataA;
Fixture fixtureA = proxyA.fixture;
if (fixtureA == null)
// uncreated or threading issue
return;
FixtureProxy proxyB = (FixtureProxy) proxyUserDataB;
Fixture fixtureB = proxyB.fixture;
if (fixtureB == null)
// uncreated or threading issue
return;
int indexA = proxyA.childIndex;
int indexB = proxyB.childIndex;
Body2D bodyA = fixtureA.getBody();
Body2D 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?
ContactEdge edge = bodyB.contacts();
while (edge != null) {
if (edge.other == bodyA) {
Contact ec = edge.contact;
Fixture fA = ec.aFixture;
Fixture fB = ec.bFixture;
int iA = ec.aIndex;
int iB = ec.bIndex;
if (fA == fixtureA && iA == indexA && fB == fixtureB && iB == indexB) {
// A contact already exists.
return;
}
if (fA == fixtureB && iA == indexB && fB == fixtureA && 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)) {
return;
}
// Check user filtering.
if (m_contactFilter != null && !ContactFilter.shouldCollide(fixtureA, fixtureB)) {
return;
}
// Call the factory.
Contact c = popContact(fixtureA, indexA, fixtureB, indexB);
if (c == null) {
return;
}
// Contact creation may swap fixtures.
fixtureA = c.aFixture;
fixtureB = c.bFixture;
// indexA = c.aIndex;
// indexB = c.bIndex;
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.contacts;
if (bodyA.contacts != null) {
bodyA.contacts.prev = c.m_nodeA;
}
bodyA.contacts = 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.contacts;
if (bodyB.contacts != null) {
bodyB.contacts.prev = c.m_nodeB;
}
bodyB.contacts = c.m_nodeB;
// wake up the bodies
if (!fixtureA.isSensor() && !fixtureB.isSensor()) {
bodyA.setAwake(true);
bodyB.setAwake(true);
}
++m_contactCount;
}
use of spacegraph.space2d.phys.dynamics.contacts.Contact in project narchy by automenta.
the class WorldRayCastWrapper method solve.
private void solve(TimeStep step) {
m_profile.solveInit.startAccum();
m_profile.solveVelocity.startAccum();
m_profile.solvePosition.startAccum();
List<Body2D> preRemove = new FasterList(0);
bodies(b -> {
// Clear all the island flags.
b.flags &= ~Body2D.e_islandFlag;
if (!b.preUpdate()) {
preRemove.add(b);
} else {
// update previous transforms
b.transformPrev.set(b);
}
});
preRemove.forEach(this::removeBody);
preRemove.clear();
// Size the island for the worst case.
int bodyCount = bodies.size();
island.init(bodyCount, contactManager.m_contactCount, jointCount, contactManager.contactListener);
for (Contact c = contactManager.m_contactList; c != null; c = c.m_next) {
c.m_flags &= ~Contact.ISLAND_FLAG;
}
joints(j -> j.islandFlag = false);
// Build and simulate all awake islands.
int stackSize = bodyCount;
// TODO djm find a good initial stack number;
Body2D[] stack = new Body2D[stackSize];
bodies(seed -> {
if ((seed.flags & Body2D.e_islandFlag) == Body2D.e_islandFlag)
return;
if (!seed.isAwake() || !seed.isActive())
return;
// The seed can be dynamic or kinematic.
if (seed.getType() == BodyType.STATIC)
return;
// Reset island and stack.
island.clear();
int stackCount = 0;
stack[stackCount++] = seed;
seed.flags |= Body2D.e_islandFlag;
// Perform a depth first search (DFS) on the constraint graph.
while (stackCount > 0) {
// Grab the next body off the stack and add it to the island.
Body2D b = stack[--stackCount];
if (!b.isActive())
continue;
// assert (b.isActive());
island.add(b);
// Make sure the body is awake.
b.setAwake(true);
// propagate islands across static bodies.
if (b.getType() == BodyType.STATIC)
continue;
// Search all contacts connected to this body.
for (ContactEdge ce = b.contacts; ce != null; ce = ce.next) {
Contact contact = ce.contact;
// Has this contact already been added to an island?
if ((contact.m_flags & Contact.ISLAND_FLAG) == Contact.ISLAND_FLAG) {
continue;
}
// Is this contact solid and touching?
if (!contact.isEnabled() || !contact.isTouching()) {
continue;
}
// Skip sensors.
boolean sensorA = contact.aFixture.isSensor;
boolean sensorB = contact.bFixture.isSensor;
if (sensorA || sensorB) {
continue;
}
island.add(contact);
contact.m_flags |= Contact.ISLAND_FLAG;
Body2D other = ce.other;
// Was the other body already added to this island?
if ((other.flags & Body2D.e_islandFlag) == Body2D.e_islandFlag) {
continue;
}
assert (stackCount < stackSize);
stack[stackCount++] = other;
other.flags |= Body2D.e_islandFlag;
}
// Search all joints connect to this body.
for (JointEdge je = b.joints; je != null; je = je.next) {
if (je.joint.islandFlag) {
continue;
}
Body2D other = je.other;
// Don't simulate joints connected to inactive bodies.
if (!other.isActive()) {
continue;
}
island.add(je.joint);
je.joint.islandFlag = true;
if ((other.flags & Body2D.e_islandFlag) == Body2D.e_islandFlag) {
continue;
}
assert (stackCount < stackSize);
stack[stackCount++] = other;
other.flags |= Body2D.e_islandFlag;
}
}
island.solve(m_profile, step, m_gravity, m_allowSleep);
// Post solve cleanup.
for (int i = 0; i < island.m_bodyCount; ++i) {
// Allow static bodies to participate in other islands.
Body2D b = island.bodies[i];
if (b.getType() == BodyType.STATIC) {
b.flags &= ~Body2D.e_islandFlag;
}
}
});
m_profile.solveInit.endAccum();
m_profile.solveVelocity.endAccum();
m_profile.solvePosition.endAccum();
broadphaseTimer.reset();
// Synchronize fixtures, check for out of range bodies.
bodies(b -> {
// If a body was not in an island then it did not move.
if ((b.flags & Body2D.e_islandFlag) == 0 || b.getType() == BodyType.STATIC)
return;
// Update fixtures (for broad-phase).
b.synchronizeFixtures();
b.postUpdate();
});
// Look for new contacts.
contactManager.findNewContacts();
m_profile.broadphase.record(broadphaseTimer.getMilliseconds());
}
use of spacegraph.space2d.phys.dynamics.contacts.Contact in project narchy by automenta.
the class ContactManager method collide.
/**
* This is the top level collision call for the time step. Here all the narrow phase collision is
* processed for the world contact list.
*/
public void collide() {
// Update awake contacts.
Contact c = m_contactList;
while (c != null) {
Fixture fixtureA = c.aFixture;
Fixture fixtureB = c.bFixture;
int indexA = c.aIndex;
int indexB = c.bIndex;
Body2D bodyA = fixtureA.getBody();
Body2D bodyB = fixtureB.getBody();
// is this contact flagged for filtering?
if ((c.m_flags & Contact.FILTER_FLAG) == Contact.FILTER_FLAG) {
// Should these bodies collide?
if (!bodyB.shouldCollide(bodyA)) {
Contact cNuke = c;
c = cNuke.next();
destroy(cNuke);
continue;
}
// Check user filtering.
if (m_contactFilter != null && !ContactFilter.shouldCollide(fixtureA, fixtureB)) {
Contact cNuke = c;
c = cNuke.next();
destroy(cNuke);
continue;
}
// Clear the filtering flag.
c.m_flags &= ~Contact.FILTER_FLAG;
}
// At least one body must be awake and it must be dynamic or kinematic.
if (!(bodyA.isAwake() && bodyA.type != BodyType.STATIC) && !(bodyB.isAwake() && bodyB.type != BodyType.STATIC)) {
c = c.next();
continue;
}
int proxyIdA = fixtureA.proxies[indexA].id;
int proxyIdB = fixtureB.proxies[indexB].id;
boolean overlap = broadPhase.testOverlap(proxyIdA, proxyIdB);
// Here we destroy contacts that cease to overlap in the broad-phase.
if (!overlap) {
Contact cNuke = c;
c = cNuke.next();
destroy(cNuke);
continue;
}
// The contact persists.
c.update(contactListener);
c = c.next();
}
}
use of spacegraph.space2d.phys.dynamics.contacts.Contact in project narchy by automenta.
the class Body2D method removeFixture.
/**
* Destroy a fixture. This removes the fixture from the broad-phase and destroys all contacts
* associated with this fixture. This will automatically adjust the mass of the body if the body
* is dynamic and the fixture has positive density. All fixtures attached to a body are implicitly
* destroyed when the body is destroyed.
*
* @param fixture the fixture to be removed.
* @warning This function is locked during callbacks.
*/
public final void removeFixture(Fixture fixture) {
W.invoke(() -> {
assert (fixture.body == this);
// Remove the fixture from this body's singly linked list.
assert (fixtureCount > 0);
// W.invokeLater(() -> {
Fixture node = fixtures;
// java change
Fixture last = null;
boolean found = false;
while (node != null) {
if (node == fixture) {
node = fixture.next;
found = true;
break;
}
last = node;
node = node.next;
}
// You tried to remove a shape that is not attached to this body.
assert (found);
// java change, remove it from the list
if (last == null) {
fixtures = fixture.next;
} else {
last.next = fixture.next;
}
// Destroy any contacts associated with the fixture.
ContactEdge edge = contacts;
while (edge != null) {
Contact c = edge.contact;
edge = edge.next;
Fixture fixtureA = c.aFixture;
Fixture fixtureB = c.bFixture;
if (fixture == fixtureA || fixture == fixtureB) {
// This destroys the contact and removes it from
// this body's contact list.
W.contactManager.destroy(c);
}
}
if ((flags & e_activeFlag) == e_activeFlag) {
BroadPhase broadPhase = W.contactManager.broadPhase;
fixture.destroyProxies(broadPhase);
}
fixture.destroy();
fixture.body = null;
fixture.next = null;
--fixtureCount;
// Reset the mass data.
resetMassData();
});
}
Aggregations