File: src\classes\NearPhase.js
/**
* Takes possible contacts found by a broad phase and determines if they are legitimate contacts
*
* @class NearPhase
* @constructor
*/
Goblin.NearPhase = function() {
/**
* holds all contacts which currently exist in the scene
*
* @property contact_manifolds
* @type Goblin.ContactManifoldList
*/
this.contact_manifolds = new Goblin.ContactManifoldList();
};
/**
* Iterates over all contact manifolds, updating penetration depth & contact locations
*
* @method updateContactManifolds
*/
Goblin.NearPhase.prototype.updateContactManifolds = function() {
var current = this.contact_manifolds.first,
prev = null;
while ( current !== null ) {
current.update();
if ( current.points.length === 0 ) {
Goblin.ObjectPool.freeObject( 'ContactManifold', current );
if ( prev == null ) {
this.contact_manifolds.first = current.next_manifold;
} else {
prev.next_manifold = current.next_manifold;
}
current = current.next_manifold;
} else {
prev = current;
current = current.next_manifold;
}
}
};
Goblin.NearPhase.prototype.midPhase = function( object_a, object_b ) {
var compound,
other;
if ( object_a.shape instanceof Goblin.CompoundShape ) {
compound = object_a;
other = object_b;
} else {
compound = object_b;
other = object_a;
}
var proxy = Goblin.ObjectPool.getObject( 'RigidBodyProxy' ),
child_shape, contact;
for ( var i = 0; i < compound.shape.child_shapes.length; i++ ) {
child_shape = compound.shape.child_shapes[i];
proxy.setFrom( compound, child_shape );
if ( proxy.shape instanceof Goblin.CompoundShape || other.shape instanceof Goblin.CompoundShape ) {
this.midPhase( proxy, other );
} else {
contact = this.getContact( proxy, other );
if ( contact != null ) {
var parent_a, parent_b;
if ( contact.object_a === proxy ) {
contact.object_a = compound;
parent_a = proxy;
parent_b = other;
} else {
contact.object_b = compound;
parent_a = other;
parent_b = proxy;
}
if ( parent_a instanceof Goblin.RigidBodyProxy ) {
while ( parent_a.parent ) {
if ( parent_a instanceof Goblin.RigidBodyProxy ) {
parent_a.shape_data.transform.transformVector3( contact.contact_point_in_a );
}
parent_a = parent_a.parent;
}
}
if ( parent_b instanceof Goblin.RigidBodyProxy ) {
while ( parent_b.parent ) {
if ( parent_b instanceof Goblin.RigidBodyProxy ) {
parent_b.shape_data.transform.transformVector3( contact.contact_point_in_b );
}
parent_b = parent_b.parent;
}
}
contact.object_a = parent_a;
contact.object_b = parent_b;
this.addContact( parent_a, parent_b, contact );
}
}
}
Goblin.ObjectPool.freeObject( 'RigidBodyProxy', proxy );
};
/**
* Tests two objects for contact
*
* @method getContact
* @param {RigidBody} object_a
* @param {RigidBody} object_b
*/
Goblin.NearPhase.prototype.getContact = function( object_a, object_b ) {
if ( object_a.shape instanceof Goblin.CompoundShape || object_b.shape instanceof Goblin.CompoundShape ) {
this.midPhase( object_a, object_b );
return;
}
var contact;
if ( object_a.shape instanceof Goblin.SphereShape && object_b.shape instanceof Goblin.SphereShape ) {
// Sphere - Sphere contact check
contact = Goblin.SphereSphere( object_a, object_b );
} else if (
object_a.shape instanceof Goblin.SphereShape && object_b.shape instanceof Goblin.BoxShape ||
object_a.shape instanceof Goblin.BoxShape && object_b.shape instanceof Goblin.SphereShape
) {
// Sphere - Box contact check
contact = Goblin.BoxSphere( object_a, object_b );
} else {
// contact check based on GJK
if ( (contact = Goblin.GjkEpa2.GJK( object_a, object_b )) != null ) {
contact = Goblin.GjkEpa2.EPA( contact );
}
}
return contact;
};
Goblin.NearPhase.prototype.addContact = function( object_a, object_b, contact ) {
this.contact_manifolds.getManifoldForObjects( object_a, object_b ).addContact( contact );
};
/**
* Loops over the passed array of object pairs which may be in contact
* valid contacts are put in this object's `contacts` property
*
* @param possible_contacts {Array}
*/
Goblin.NearPhase.prototype.generateContacts = function( possible_contacts ) {
var i,
contact,
possible_contacts_length = possible_contacts.length;
// Make sure all of the manifolds are up to date
this.updateContactManifolds();
for ( i = 0; i < possible_contacts_length; i++ ) {
contact = this.getContact( possible_contacts[i][0], possible_contacts[i][1] );
if ( contact != null ) {
this.addContact( possible_contacts[i][0], possible_contacts[i][1], contact );
}
}
};