Commits

Eric Rochester  committed 4a46fbb

Changed to use prototype and box2d-js.

  • Participants
  • Parent commits bfc098b

Comments (0)

Files changed (66)

 		</footer>
 	</div>
 
-	<script src="//ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
-	<script>!window.jQuery && document.write(unescape('%3Cscript src="js/libs/jquery-1.5.1.min.js"%3E%3C/script%3E'))</script>
-  <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.12/jquery-ui.min.js"></script>
+	<script src="//ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js"></script>
+
+  <!-- box2djs -->
+  <script src='js/box2d/common/b2Settings.js'></script>
+  <script src='js/box2d/common/math/b2Vec2.js'></script>
+  <script src='js/box2d/common/math/b2Mat22.js'></script>
+  <script src='js/box2d/common/math/b2Math.js'></script>
+  <script src='js/box2d/collision/b2AABB.js'></script>
+  <script src='js/box2d/collision/b2Bound.js'></script>
+  <script src='js/box2d/collision/b2BoundValues.js'></script>
+  <script src='js/box2d/collision/b2Pair.js'></script>
+  <script src='js/box2d/collision/b2PairCallback.js'></script>
+  <script src='js/box2d/collision/b2BufferedPair.js'></script>
+  <script src='js/box2d/collision/b2PairManager.js'></script>
+  <script src='js/box2d/collision/b2BroadPhase.js'></script>
+  <script src='js/box2d/collision/b2Collision.js'></script>
+  <script src='js/box2d/collision/Features.js'></script>
+  <script src='js/box2d/collision/b2ContactID.js'></script>
+  <script src='js/box2d/collision/b2ContactPoint.js'></script>
+  <script src='js/box2d/collision/b2Distance.js'></script>
+  <script src='js/box2d/collision/b2Manifold.js'></script>
+  <script src='js/box2d/collision/b2OBB.js'></script>
+  <script src='js/box2d/collision/b2Proxy.js'></script>
+  <script src='js/box2d/collision/ClipVertex.js'></script>
+  <script src='js/box2d/collision/shapes/b2Shape.js'></script>
+  <script src='js/box2d/collision/shapes/b2ShapeDef.js'></script>
+  <script src='js/box2d/collision/shapes/b2BoxDef.js'></script>
+  <script src='js/box2d/collision/shapes/b2CircleDef.js'></script>
+  <script src='js/box2d/collision/shapes/b2CircleShape.js'></script>
+  <script src='js/box2d/collision/shapes/b2MassData.js'></script>
+  <script src='js/box2d/collision/shapes/b2PolyDef.js'></script>
+  <script src='js/box2d/collision/shapes/b2PolyShape.js'></script>
+  <script src='js/box2d/dynamics/b2Body.js'></script>
+  <script src='js/box2d/dynamics/b2BodyDef.js'></script>
+  <script src='js/box2d/dynamics/b2CollisionFilter.js'></script>
+  <script src='js/box2d/dynamics/b2Island.js'></script>
+  <script src='js/box2d/dynamics/b2TimeStep.js'></script>
+  <script src='js/box2d/dynamics/contacts/b2ContactNode.js'></script>
+  <script src='js/box2d/dynamics/contacts/b2Contact.js'></script>
+  <script src='js/box2d/dynamics/contacts/b2ContactConstraint.js'></script>
+  <script src='js/box2d/dynamics/contacts/b2ContactConstraintPoint.js'></script>
+  <script src='js/box2d/dynamics/contacts/b2ContactRegister.js'></script>
+  <script src='js/box2d/dynamics/contacts/b2ContactSolver.js'></script>
+  <script src='js/box2d/dynamics/contacts/b2CircleContact.js'></script>
+  <script src='js/box2d/dynamics/contacts/b2Conservative.js'></script>
+  <script src='js/box2d/dynamics/contacts/b2NullContact.js'></script>
+  <script src='js/box2d/dynamics/contacts/b2PolyAndCircleContact.js'></script>
+  <script src='js/box2d/dynamics/contacts/b2PolyContact.js'></script>
+  <script src='js/box2d/dynamics/b2ContactManager.js'></script>
+  <script src='js/box2d/dynamics/b2World.js'></script>
+  <script src='js/box2d/dynamics/b2WorldListener.js'></script>
+  <script src='js/box2d/dynamics/joints/b2JointNode.js'></script>
+  <script src='js/box2d/dynamics/joints/b2Joint.js'></script>
+  <script src='js/box2d/dynamics/joints/b2JointDef.js'></script>
+  <script src='js/box2d/dynamics/joints/b2DistanceJoint.js'></script>
+  <script src='js/box2d/dynamics/joints/b2DistanceJointDef.js'></script>
+  <script src='js/box2d/dynamics/joints/b2Jacobian.js'></script>
+  <script src='js/box2d/dynamics/joints/b2GearJoint.js'></script>
+  <script src='js/box2d/dynamics/joints/b2GearJointDef.js'></script>
+  <script src='js/box2d/dynamics/joints/b2MouseJoint.js'></script>
+  <script src='js/box2d/dynamics/joints/b2MouseJointDef.js'></script>
+  <script src='js/box2d/dynamics/joints/b2PrismaticJoint.js'></script>
+  <script src='js/box2d/dynamics/joints/b2PrismaticJointDef.js'></script>
+  <script src='js/box2d/dynamics/joints/b2PulleyJoint.js'></script>
+  <script src='js/box2d/dynamics/joints/b2PulleyJointDef.js'></script>
+  <script src='js/box2d/dynamics/joints/b2RevoluteJoint.js'></script>
+  <script src='js/box2d/dynamics/joints/b2RevoluteJointDef.js'></script>
+  <!--=============================-->
+  <!-- Copy this part to your app. -->
+  <!-- END                         -->
+  <!--=============================-->
+
 	<script src="js/plugins.js"></script>
 	<script src="js/script.js"></script>
 	<!--[if lt IE 7 ]>

File js/box2d/collision/ClipVertex.js

+/*
+* Copyright (c) 2006-2007 Erin Catto http:
+*
+* 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, and must not be
+* misrepresented the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+
+
+
+var ClipVertex = Class.create();
+ClipVertex.prototype = 
+{
+	v: new b2Vec2(),
+	id: new b2ContactID(),
+	initialize: function() {
+		// initialize instance variables for references
+		this.v = new b2Vec2();
+		this.id = new b2ContactID();
+		//
+}};
+
+

File js/box2d/collision/Features.js

+/*
+* Copyright (c) 2006-2007 Erin Catto http:
+*
+* 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, and must not be
+* misrepresented the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+// We use contact ids to facilitate warm starting.
+var Features = Class.create();
+Features.prototype = 
+{
+	//
+	set_referenceFace: function(value){
+		this._referenceFace = value;
+		this._m_id._key = (this._m_id._key & 0xffffff00) | (this._referenceFace & 0x000000ff)
+	},
+	get_referenceFace: function(){
+		return this._referenceFace;
+	},
+	_referenceFace: 0,
+	//
+	set_incidentEdge: function(value){
+		this._incidentEdge = value;
+		this._m_id._key = (this._m_id._key & 0xffff00ff) | ((this._incidentEdge << 8) & 0x0000ff00)
+	},
+	get_incidentEdge: function(){
+		return this._incidentEdge;
+	},
+	_incidentEdge: 0,
+	//
+	set_incidentVertex: function(value){
+		this._incidentVertex = value;
+		this._m_id._key = (this._m_id._key & 0xff00ffff) | ((this._incidentVertex << 16) & 0x00ff0000)
+	},
+	get_incidentVertex: function(){
+		return this._incidentVertex;
+	},
+	_incidentVertex: 0,
+	//
+	set_flip: function(value){
+		this._flip = value;
+		this._m_id._key = (this._m_id._key & 0x00ffffff) | ((this._flip << 24) & 0xff000000)
+	},
+	get_flip: function(){
+		return this._flip;
+	},
+	_flip: 0,
+	_m_id: null,
+	initialize: function() {}};

File js/box2d/collision/b2AABB.js

+/*
+* Copyright (c) 2006-2007 Erin Catto http:
+*
+* 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, and must not be
+* misrepresented the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+
+// A manifold for two touching convex shapes.
+var b2AABB = Class.create();
+b2AABB.prototype = 
+{
+	IsValid: function(){
+		//var d = b2Math.SubtractVV(this.maxVertex, this.minVertex);
+		var dX = this.maxVertex.x;
+		var dY = this.maxVertex.y;
+		dX = this.maxVertex.x;
+		dY = this.maxVertex.y;
+		dX -= this.minVertex.x;
+		dY -= this.minVertex.y;
+		var valid = dX >= 0.0 && dY >= 0.0;
+		valid = valid && this.minVertex.IsValid() && this.maxVertex.IsValid();
+		return valid;
+	},
+
+	minVertex: new b2Vec2(),
+	maxVertex: new b2Vec2(),
+	initialize: function() {
+		// initialize instance variables for references
+		this.minVertex = new b2Vec2();
+		this.maxVertex = new b2Vec2();
+		//
+}};

File js/box2d/collision/b2Bound.js

+/*
+* Copyright (c) 2006-2007 Erin Catto http:
+*
+* 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, and must not be
+* misrepresented the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+
+var b2Bound = Class.create();
+b2Bound.prototype = {
+	IsLower: function(){ return (this.value & 1) == 0; },
+	IsUpper: function(){ return (this.value & 1) == 1; },
+	Swap: function(b){
+		var tempValue = this.value;
+		var tempProxyId = this.proxyId;
+		var tempStabbingCount = this.stabbingCount;
+
+		this.value = b.value;
+		this.proxyId = b.proxyId;
+		this.stabbingCount = b.stabbingCount;
+
+		b.value = tempValue;
+		b.proxyId = tempProxyId;
+		b.stabbingCount = tempStabbingCount;
+	},
+
+	value: 0,
+	proxyId: 0,
+	stabbingCount: 0,
+
+	initialize: function() {}}

File js/box2d/collision/b2BoundValues.js

+/*
+* Copyright (c) 2006-2007 Erin Catto http:
+*
+* 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, and must not be
+* misrepresented the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+
+var b2BoundValues = Class.create();
+b2BoundValues.prototype = {
+	lowerValues: [0,0],
+	upperValues: [0,0],
+
+	initialize: function() {
+		// initialize instance variables for references
+		this.lowerValues = [0,0];
+		this.upperValues = [0,0];
+		//
+}}

File js/box2d/collision/b2BroadPhase.js

+/*
+* Copyright (c) 2006-2007 Erin Catto http:
+*
+* 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, and must not be
+* misrepresented the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+
+
+
+/*
+This broad phase uses the Sweep and Prune algorithm in:
+Collision Detection in Interactive 3D Environments by Gino van den Bergen
+Also, some ideas, such integral values for fast compares comes from
+Bullet (http:/www.bulletphysics.com).
+*/
+
+
+// Notes:
+// - we use bound arrays instead of linked lists for cache coherence.
+// - we use quantized integral values for fast compares.
+// - we use short indices rather than pointers to save memory.
+// - we use a stabbing count for fast overlap queries (less than order N).
+// - we also use a time stamp on each proxy to speed up the registration of
+//   overlap query results.
+// - where possible, we compare bound indices instead of values to reduce
+//   cache misses (TODO_ERIN).
+// - no broadphase is perfect and neither is this one: it is not great for huge
+//   worlds (use a multi-SAP instead), it is not great for large objects.
+
+var b2BroadPhase = Class.create();
+b2BroadPhase.prototype = 
+{
+//public:
+	initialize: function(worldAABB, callback){
+		// initialize instance variables for references
+		this.m_pairManager = new b2PairManager();
+		this.m_proxyPool = new Array(b2Settings.b2_maxPairs);
+		this.m_bounds = new Array(2*b2Settings.b2_maxProxies);
+		this.m_queryResults = new Array(b2Settings.b2_maxProxies);
+		this.m_quantizationFactor = new b2Vec2();
+		//
+
+		//b2Settings.b2Assert(worldAABB.IsValid());
+		var i = 0;
+
+		this.m_pairManager.Initialize(this, callback);
+
+		this.m_worldAABB = worldAABB;
+
+		this.m_proxyCount = 0;
+
+		// query results
+		for (i = 0; i < b2Settings.b2_maxProxies; i++){
+			this.m_queryResults[i] = 0;
+		}
+
+		// bounds array
+		this.m_bounds = new Array(2);
+		for (i = 0; i < 2; i++){
+			this.m_bounds[i] = new Array(2*b2Settings.b2_maxProxies);
+			for (var j = 0; j < 2*b2Settings.b2_maxProxies; j++){
+				this.m_bounds[i][j] = new b2Bound();
+			}
+		}
+
+		//var d = b2Math.SubtractVV(worldAABB.maxVertex, worldAABB.minVertex);
+		var dX = worldAABB.maxVertex.x;
+		var dY = worldAABB.maxVertex.y;
+		dX -= worldAABB.minVertex.x;
+		dY -= worldAABB.minVertex.y;
+
+		this.m_quantizationFactor.x = b2Settings.USHRT_MAX / dX;
+		this.m_quantizationFactor.y = b2Settings.USHRT_MAX / dY;
+
+		var tProxy;
+		for (i = 0; i < b2Settings.b2_maxProxies - 1; ++i)
+		{
+			tProxy = new b2Proxy();
+			this.m_proxyPool[i] = tProxy;
+			tProxy.SetNext(i + 1);
+			tProxy.timeStamp = 0;
+			tProxy.overlapCount = b2BroadPhase.b2_invalid;
+			tProxy.userData = null;
+		}
+		tProxy = new b2Proxy();
+		this.m_proxyPool[b2Settings.b2_maxProxies-1] = tProxy;
+		tProxy.SetNext(b2Pair.b2_nullProxy);
+		tProxy.timeStamp = 0;
+		tProxy.overlapCount = b2BroadPhase.b2_invalid;
+		tProxy.userData = null;
+		this.m_freeProxy = 0;
+
+		this.m_timeStamp = 1;
+		this.m_queryResultCount = 0;
+	},
+	//~b2BroadPhase();
+
+	// Use this to see if your proxy is in range. If it is not in range,
+	// it should be destroyed. Otherwise you may get O(m^2) pairs, where m
+	// is the number of proxies that are out of range.
+	InRange: function(aabb){
+		//var d = b2Math.b2MaxV(b2Math.SubtractVV(aabb.minVertex, this.m_worldAABB.maxVertex), b2Math.SubtractVV(this.m_worldAABB.minVertex, aabb.maxVertex));
+		var dX;
+		var dY;
+		var d2X;
+		var d2Y;
+
+		dX = aabb.minVertex.x;
+		dY = aabb.minVertex.y;
+		dX -= this.m_worldAABB.maxVertex.x;
+		dY -= this.m_worldAABB.maxVertex.y;
+
+		d2X = this.m_worldAABB.minVertex.x;
+		d2Y = this.m_worldAABB.minVertex.y;
+		d2X -= aabb.maxVertex.x;
+		d2Y -= aabb.maxVertex.y;
+
+		dX = b2Math.b2Max(dX, d2X);
+		dY = b2Math.b2Max(dY, d2Y);
+
+		return b2Math.b2Max(dX, dY) < 0.0;
+	},
+
+	// Get a single proxy. Returns NULL if the id is invalid.
+	GetProxy: function(proxyId){
+		if (proxyId == b2Pair.b2_nullProxy || this.m_proxyPool[proxyId].IsValid() == false)
+		{
+			return null;
+		}
+
+		return this.m_proxyPool[ proxyId ];
+	},
+
+	// Create and destroy proxies. These call Flush first.
+	CreateProxy: function(aabb, userData){
+		var index = 0;
+		var proxy;
+
+		//b2Settings.b2Assert(this.m_proxyCount < b2_maxProxies);
+		//b2Settings.b2Assert(this.m_freeProxy != b2Pair.b2_nullProxy);
+
+		var proxyId = this.m_freeProxy;
+		proxy = this.m_proxyPool[ proxyId ];
+		this.m_freeProxy = proxy.GetNext();
+
+		proxy.overlapCount = 0;
+		proxy.userData = userData;
+
+		var boundCount = 2 * this.m_proxyCount;
+
+		var lowerValues = new Array();
+		var upperValues = new Array();
+		this.ComputeBounds(lowerValues, upperValues, aabb);
+
+		for (var axis = 0; axis < 2; ++axis)
+		{
+			var bounds = this.m_bounds[axis];
+			var lowerIndex = 0;
+			var upperIndex = 0;
+			var lowerIndexOut = [lowerIndex];
+			var upperIndexOut = [upperIndex];
+			this.Query(lowerIndexOut, upperIndexOut, lowerValues[axis], upperValues[axis], bounds, boundCount, axis);
+			lowerIndex = lowerIndexOut[0];
+			upperIndex = upperIndexOut[0];
+
+			// Replace memmove calls
+			//memmove(bounds + upperIndex + 2, bounds + upperIndex, (edgeCount - upperIndex) * sizeof(b2Bound));
+			var tArr = new Array();
+			var j = 0;
+			var tEnd = boundCount - upperIndex
+			var tBound1;
+			var tBound2;
+			// make temp array
+			for (j = 0; j < tEnd; j++){
+				tArr[j] = new b2Bound();
+				tBound1 = tArr[j];
+				tBound2 = bounds[upperIndex+j];
+				tBound1.value = tBound2.value;
+				tBound1.proxyId = tBound2.proxyId;
+				tBound1.stabbingCount = tBound2.stabbingCount;
+			}
+			// move temp array back in to bounds
+			tEnd = tArr.length;
+			var tIndex = upperIndex+2;
+			for (j = 0; j < tEnd; j++){
+				//bounds[tIndex+j] = tArr[j];
+				tBound2 = tArr[j];
+				tBound1 = bounds[tIndex+j]
+				tBound1.value = tBound2.value;
+				tBound1.proxyId = tBound2.proxyId;
+				tBound1.stabbingCount = tBound2.stabbingCount;
+			}
+			//memmove(bounds + lowerIndex + 1, bounds + lowerIndex, (upperIndex - lowerIndex) * sizeof(b2Bound));
+			// make temp array
+			tArr = new Array();
+			tEnd = upperIndex - lowerIndex;
+			for (j = 0; j < tEnd; j++){
+				tArr[j] = new b2Bound();
+				tBound1 = tArr[j];
+				tBound2 = bounds[lowerIndex+j];
+				tBound1.value = tBound2.value;
+				tBound1.proxyId = tBound2.proxyId;
+				tBound1.stabbingCount = tBound2.stabbingCount;
+			}
+			// move temp array back in to bounds
+			tEnd = tArr.length;
+			tIndex = lowerIndex+1;
+			for (j = 0; j < tEnd; j++){
+				//bounds[tIndex+j] = tArr[j];
+				tBound2 = tArr[j];
+				tBound1 = bounds[tIndex+j]
+				tBound1.value = tBound2.value;
+				tBound1.proxyId = tBound2.proxyId;
+				tBound1.stabbingCount = tBound2.stabbingCount;
+			}
+
+			// The upper index has increased because of the lower bound insertion.
+			++upperIndex;
+
+			// Copy in the new bounds.
+			bounds[lowerIndex].value = lowerValues[axis];
+			bounds[lowerIndex].proxyId = proxyId;
+			bounds[upperIndex].value = upperValues[axis];
+			bounds[upperIndex].proxyId = proxyId;
+
+			bounds[lowerIndex].stabbingCount = lowerIndex == 0 ? 0 : bounds[lowerIndex-1].stabbingCount;
+			bounds[upperIndex].stabbingCount = bounds[upperIndex-1].stabbingCount;
+
+			// Adjust the stabbing count between the new bounds.
+			for (index = lowerIndex; index < upperIndex; ++index)
+			{
+				bounds[index].stabbingCount++;
+			}
+
+			// Adjust the all the affected bound indices.
+			for (index = lowerIndex; index < boundCount + 2; ++index)
+			{
+				var proxy2 = this.m_proxyPool[ bounds[index].proxyId ];
+				if (bounds[index].IsLower())
+				{
+					proxy2.lowerBounds[axis] = index;
+				}
+				else
+				{
+					proxy2.upperBounds[axis] = index;
+				}
+			}
+		}
+
+		++this.m_proxyCount;
+
+		//b2Settings.b2Assert(this.m_queryResultCount < b2Settings.b2_maxProxies);
+
+		for (var i = 0; i < this.m_queryResultCount; ++i)
+		{
+			//b2Settings.b2Assert(this.m_queryResults[i] < b2_maxProxies);
+			//b2Settings.b2Assert(this.m_proxyPool[this.m_queryResults[i]].IsValid());
+
+			this.m_pairManager.AddBufferedPair(proxyId, this.m_queryResults[i]);
+		}
+
+		this.m_pairManager.Commit();
+
+		// Prepare for next query.
+		this.m_queryResultCount = 0;
+		this.IncrementTimeStamp();
+
+		return proxyId;
+	},
+
+	DestroyProxy: function(proxyId){
+
+		//b2Settings.b2Assert(0 < this.m_proxyCount && this.m_proxyCount <= b2_maxProxies);
+
+		var proxy = this.m_proxyPool[ proxyId ];
+		//b2Settings.b2Assert(proxy.IsValid());
+
+		var boundCount = 2 * this.m_proxyCount;
+
+		for (var axis = 0; axis < 2; ++axis)
+		{
+			var bounds = this.m_bounds[axis];
+
+			var lowerIndex = proxy.lowerBounds[axis];
+			var upperIndex = proxy.upperBounds[axis];
+			var lowerValue = bounds[lowerIndex].value;
+			var upperValue = bounds[upperIndex].value;
+
+			// replace memmove calls
+			//memmove(bounds + lowerIndex, bounds + lowerIndex + 1, (upperIndex - lowerIndex - 1) * sizeof(b2Bound));
+			var tArr = new Array();
+			var j = 0;
+			var tEnd = upperIndex - lowerIndex - 1;
+			var tBound1;
+			var tBound2;
+			// make temp array
+			for (j = 0; j < tEnd; j++){
+				tArr[j] = new b2Bound();
+				tBound1 = tArr[j];
+				tBound2 = bounds[lowerIndex+1+j];
+				tBound1.value = tBound2.value;
+				tBound1.proxyId = tBound2.proxyId;
+				tBound1.stabbingCount = tBound2.stabbingCount;
+			}
+			// move temp array back in to bounds
+			tEnd = tArr.length;
+			var tIndex = lowerIndex;
+			for (j = 0; j < tEnd; j++){
+				//bounds[tIndex+j] = tArr[j];
+				tBound2 = tArr[j];
+				tBound1 = bounds[tIndex+j]
+				tBound1.value = tBound2.value;
+				tBound1.proxyId = tBound2.proxyId;
+				tBound1.stabbingCount = tBound2.stabbingCount;
+			}
+			//memmove(bounds + upperIndex-1, bounds + upperIndex + 1, (edgeCount - upperIndex - 1) * sizeof(b2Bound));
+			// make temp array
+			tArr = new Array();
+			tEnd = boundCount - upperIndex - 1;
+			for (j = 0; j < tEnd; j++){
+				tArr[j] = new b2Bound();
+				tBound1 = tArr[j];
+				tBound2 = bounds[upperIndex+1+j];
+				tBound1.value = tBound2.value;
+				tBound1.proxyId = tBound2.proxyId;
+				tBound1.stabbingCount = tBound2.stabbingCount;
+			}
+			// move temp array back in to bounds
+			tEnd = tArr.length;
+			tIndex = upperIndex-1;
+			for (j = 0; j < tEnd; j++){
+				//bounds[tIndex+j] = tArr[j];
+				tBound2 = tArr[j];
+				tBound1 = bounds[tIndex+j]
+				tBound1.value = tBound2.value;
+				tBound1.proxyId = tBound2.proxyId;
+				tBound1.stabbingCount = tBound2.stabbingCount;
+			}
+
+			// Fix bound indices.
+			tEnd = boundCount - 2;
+			for (var index = lowerIndex; index < tEnd; ++index)
+			{
+				var proxy2 = this.m_proxyPool[ bounds[index].proxyId ];
+				if (bounds[index].IsLower())
+				{
+					proxy2.lowerBounds[axis] = index;
+				}
+				else
+				{
+					proxy2.upperBounds[axis] = index;
+				}
+			}
+
+			// Fix stabbing count.
+			tEnd = upperIndex - 1;
+			for (var index2 = lowerIndex; index2 < tEnd; ++index2)
+			{
+				bounds[index2].stabbingCount--;
+			}
+
+			// this.Query for pairs to be removed. lowerIndex and upperIndex are not needed.
+			// make lowerIndex and upper output using an array and do this for others if compiler doesn't pick them up
+			this.Query([0], [0], lowerValue, upperValue, bounds, boundCount - 2, axis);
+		}
+
+		//b2Settings.b2Assert(this.m_queryResultCount < b2Settings.b2_maxProxies);
+
+		for (var i = 0; i < this.m_queryResultCount; ++i)
+		{
+			//b2Settings.b2Assert(this.m_proxyPool[this.m_queryResults[i]].IsValid());
+
+			this.m_pairManager.RemoveBufferedPair(proxyId, this.m_queryResults[i]);
+		}
+
+		this.m_pairManager.Commit();
+
+		// Prepare for next query.
+		this.m_queryResultCount = 0;
+		this.IncrementTimeStamp();
+
+		// Return the proxy to the pool.
+		proxy.userData = null;
+		proxy.overlapCount = b2BroadPhase.b2_invalid;
+		proxy.lowerBounds[0] = b2BroadPhase.b2_invalid;
+		proxy.lowerBounds[1] = b2BroadPhase.b2_invalid;
+		proxy.upperBounds[0] = b2BroadPhase.b2_invalid;
+		proxy.upperBounds[1] = b2BroadPhase.b2_invalid;
+
+		proxy.SetNext(this.m_freeProxy);
+		this.m_freeProxy = proxyId;
+		--this.m_proxyCount;
+	},
+
+
+	// Call this.MoveProxy times like, then when you are done
+	// call this.Commit to finalized the proxy pairs (for your time step).
+	MoveProxy: function(proxyId, aabb){
+		var axis = 0;
+		var index = 0;
+		var bound;
+		var prevBound
+		var nextBound
+		var nextProxyId = 0;
+		var nextProxy;
+
+		if (proxyId == b2Pair.b2_nullProxy || b2Settings.b2_maxProxies <= proxyId)
+		{
+			//b2Settings.b2Assert(false);
+			return;
+		}
+
+		if (aabb.IsValid() == false)
+		{
+			//b2Settings.b2Assert(false);
+			return;
+		}
+
+		var boundCount = 2 * this.m_proxyCount;
+
+		var proxy = this.m_proxyPool[ proxyId ];
+		// Get new bound values
+		var newValues = new b2BoundValues();
+		this.ComputeBounds(newValues.lowerValues, newValues.upperValues, aabb);
+
+		// Get old bound values
+		var oldValues = new b2BoundValues();
+		for (axis = 0; axis < 2; ++axis)
+		{
+			oldValues.lowerValues[axis] = this.m_bounds[axis][proxy.lowerBounds[axis]].value;
+			oldValues.upperValues[axis] = this.m_bounds[axis][proxy.upperBounds[axis]].value;
+		}
+
+		for (axis = 0; axis < 2; ++axis)
+		{
+			var bounds = this.m_bounds[axis];
+
+			var lowerIndex = proxy.lowerBounds[axis];
+			var upperIndex = proxy.upperBounds[axis];
+
+			var lowerValue = newValues.lowerValues[axis];
+			var upperValue = newValues.upperValues[axis];
+
+			var deltaLower = lowerValue - bounds[lowerIndex].value;
+			var deltaUpper = upperValue - bounds[upperIndex].value;
+
+			bounds[lowerIndex].value = lowerValue;
+			bounds[upperIndex].value = upperValue;
+
+			//
+			// Expanding adds overlaps
+			//
+
+			// Should we move the lower bound down?
+			if (deltaLower < 0)
+			{
+				index = lowerIndex;
+				while (index > 0 && lowerValue < bounds[index-1].value)
+				{
+					bound = bounds[index];
+					prevBound = bounds[index - 1];
+
+					var prevProxyId = prevBound.proxyId;
+					var prevProxy = this.m_proxyPool[ prevBound.proxyId ];
+
+					prevBound.stabbingCount++;
+
+					if (prevBound.IsUpper() == true)
+					{
+						if (this.TestOverlap(newValues, prevProxy))
+						{
+							this.m_pairManager.AddBufferedPair(proxyId, prevProxyId);
+						}
+
+						prevProxy.upperBounds[axis]++;
+						bound.stabbingCount++;
+					}
+					else
+					{
+						prevProxy.lowerBounds[axis]++;
+						bound.stabbingCount--;
+					}
+
+					proxy.lowerBounds[axis]--;
+
+					// swap
+					//var temp = bound;
+					//bound = prevEdge;
+					//prevEdge = temp;
+					bound.Swap(prevBound);
+					//b2Math.b2Swap(bound, prevEdge);
+					--index;
+				}
+			}
+
+			// Should we move the upper bound up?
+			if (deltaUpper > 0)
+			{
+				index = upperIndex;
+				while (index < boundCount-1 && bounds[index+1].value <= upperValue)
+				{
+					bound = bounds[ index ];
+					nextBound = bounds[ index + 1 ];
+					nextProxyId = nextBound.proxyId;
+					nextProxy = this.m_proxyPool[ nextProxyId ];
+
+					nextBound.stabbingCount++;
+
+					if (nextBound.IsLower() == true)
+					{
+						if (this.TestOverlap(newValues, nextProxy))
+						{
+							this.m_pairManager.AddBufferedPair(proxyId, nextProxyId);
+						}
+
+						nextProxy.lowerBounds[axis]--;
+						bound.stabbingCount++;
+					}
+					else
+					{
+						nextProxy.upperBounds[axis]--;
+						bound.stabbingCount--;
+					}
+
+					proxy.upperBounds[axis]++;
+					// swap
+					//var temp = bound;
+					//bound = nextEdge;
+					//nextEdge = temp;
+					bound.Swap(nextBound);
+					//b2Math.b2Swap(bound, nextEdge);
+					index++;
+				}
+			}
+
+			//
+			// Shrinking removes overlaps
+			//
+
+			// Should we move the lower bound up?
+			if (deltaLower > 0)
+			{
+				index = lowerIndex;
+				while (index < boundCount-1 && bounds[index+1].value <= lowerValue)
+				{
+					bound = bounds[ index ];
+					nextBound = bounds[ index + 1 ];
+
+					nextProxyId = nextBound.proxyId;
+					nextProxy = this.m_proxyPool[ nextProxyId ];
+
+					nextBound.stabbingCount--;
+
+					if (nextBound.IsUpper())
+					{
+						if (this.TestOverlap(oldValues, nextProxy))
+						{
+							this.m_pairManager.RemoveBufferedPair(proxyId, nextProxyId);
+						}
+
+						nextProxy.upperBounds[axis]--;
+						bound.stabbingCount--;
+					}
+					else
+					{
+						nextProxy.lowerBounds[axis]--;
+						bound.stabbingCount++;
+					}
+
+					proxy.lowerBounds[axis]++;
+					// swap
+					//var temp = bound;
+					//bound = nextEdge;
+					//nextEdge = temp;
+					bound.Swap(nextBound);
+					//b2Math.b2Swap(bound, nextEdge);
+					index++;
+				}
+			}
+
+			// Should we move the upper bound down?
+			if (deltaUpper < 0)
+			{
+				index = upperIndex;
+				while (index > 0 && upperValue < bounds[index-1].value)
+				{
+					bound = bounds[index];
+					prevBound = bounds[index - 1];
+
+					prevProxyId = prevBound.proxyId;
+					prevProxy = this.m_proxyPool[ prevProxyId ];
+
+					prevBound.stabbingCount--;
+
+					if (prevBound.IsLower() == true)
+					{
+						if (this.TestOverlap(oldValues, prevProxy))
+						{
+							this.m_pairManager.RemoveBufferedPair(proxyId, prevProxyId);
+						}
+
+						prevProxy.lowerBounds[axis]++;
+						bound.stabbingCount--;
+					}
+					else
+					{
+						prevProxy.upperBounds[axis]++;
+						bound.stabbingCount++;
+					}
+
+					proxy.upperBounds[axis]--;
+					// swap
+					//var temp = bound;
+					//bound = prevEdge;
+					//prevEdge = temp;
+					bound.Swap(prevBound);
+					//b2Math.b2Swap(bound, prevEdge);
+					index--;
+				}
+			}
+		}
+	},
+
+	Commit: function(){
+		this.m_pairManager.Commit();
+	},
+
+	// this.Query an AABB for overlapping proxies, returns the user data and
+	// the count, up to the supplied maximum count.
+	QueryAABB: function(aabb, userData, maxCount){
+		var lowerValues = new Array();
+		var upperValues = new Array();
+		this.ComputeBounds(lowerValues, upperValues, aabb);
+
+		var lowerIndex = 0;
+		var upperIndex = 0;
+		var lowerIndexOut = [lowerIndex];
+		var upperIndexOut = [upperIndex];
+		this.Query(lowerIndexOut, upperIndexOut, lowerValues[0], upperValues[0], this.m_bounds[0], 2*this.m_proxyCount, 0);
+		this.Query(lowerIndexOut, upperIndexOut, lowerValues[1], upperValues[1], this.m_bounds[1], 2*this.m_proxyCount, 1);
+
+		//b2Settings.b2Assert(this.m_queryResultCount < b2Settings.b2_maxProxies);
+
+		var count = 0;
+		for (var i = 0; i < this.m_queryResultCount && count < maxCount; ++i, ++count)
+		{
+			//b2Settings.b2Assert(this.m_queryResults[i] < b2Settings.b2_maxProxies);
+			var proxy = this.m_proxyPool[ this.m_queryResults[i] ];
+			//b2Settings.b2Assert(proxy.IsValid());
+			userData[i] = proxy.userData;
+		}
+
+		// Prepare for next query.
+		this.m_queryResultCount = 0;
+		this.IncrementTimeStamp();
+
+		return count;
+	},
+
+	Validate: function(){
+		var pair;
+		var proxy1;
+		var proxy2;
+		var overlap;
+
+		for (var axis = 0; axis < 2; ++axis)
+		{
+			var bounds = this.m_bounds[axis];
+
+			var boundCount = 2 * this.m_proxyCount;
+			var stabbingCount = 0;
+
+			for (var i = 0; i < boundCount; ++i)
+			{
+				var bound = bounds[i];
+				//b2Settings.b2Assert(i == 0 || bounds[i-1].value <= bound->value);
+				//b2Settings.b2Assert(bound->proxyId != b2_nullProxy);
+				//b2Settings.b2Assert(this.m_proxyPool[bound->proxyId].IsValid());
+
+				if (bound.IsLower() == true)
+				{
+					//b2Settings.b2Assert(this.m_proxyPool[bound.proxyId].lowerBounds[axis] == i);
+					stabbingCount++;
+				}
+				else
+				{
+					//b2Settings.b2Assert(this.m_proxyPool[bound.proxyId].upperBounds[axis] == i);
+					stabbingCount--;
+				}
+
+				//b2Settings.b2Assert(bound.stabbingCount == stabbingCount);
+			}
+		}
+
+	},
+
+//private:
+	ComputeBounds: function(lowerValues, upperValues, aabb)
+	{
+		//b2Settings.b2Assert(aabb.maxVertex.x > aabb.minVertex.x);
+		//b2Settings.b2Assert(aabb.maxVertex.y > aabb.minVertex.y);
+
+		//var minVertex = b2Math.b2ClampV(aabb.minVertex, this.m_worldAABB.minVertex, this.m_worldAABB.maxVertex);
+		var minVertexX = aabb.minVertex.x;
+		var minVertexY = aabb.minVertex.y;
+		minVertexX = b2Math.b2Min(minVertexX, this.m_worldAABB.maxVertex.x);
+		minVertexY = b2Math.b2Min(minVertexY, this.m_worldAABB.maxVertex.y);
+		minVertexX = b2Math.b2Max(minVertexX, this.m_worldAABB.minVertex.x);
+		minVertexY = b2Math.b2Max(minVertexY, this.m_worldAABB.minVertex.y);
+
+		//var maxVertex = b2Math.b2ClampV(aabb.maxVertex, this.m_worldAABB.minVertex, this.m_worldAABB.maxVertex);
+		var maxVertexX = aabb.maxVertex.x;
+		var maxVertexY = aabb.maxVertex.y;
+		maxVertexX = b2Math.b2Min(maxVertexX, this.m_worldAABB.maxVertex.x);
+		maxVertexY = b2Math.b2Min(maxVertexY, this.m_worldAABB.maxVertex.y);
+		maxVertexX = b2Math.b2Max(maxVertexX, this.m_worldAABB.minVertex.x);
+		maxVertexY = b2Math.b2Max(maxVertexY, this.m_worldAABB.minVertex.y);
+
+		// Bump lower bounds downs and upper bounds up. This ensures correct sorting of
+		// lower/upper bounds that would have equal values.
+		// TODO_ERIN implement fast float to uint16 conversion.
+		lowerValues[0] = /*uint*/(this.m_quantizationFactor.x * (minVertexX - this.m_worldAABB.minVertex.x)) & (b2Settings.USHRT_MAX - 1);
+		upperValues[0] = (/*uint*/(this.m_quantizationFactor.x * (maxVertexX - this.m_worldAABB.minVertex.x))& 0x0000ffff) | 1;
+
+		lowerValues[1] = /*uint*/(this.m_quantizationFactor.y * (minVertexY - this.m_worldAABB.minVertex.y)) & (b2Settings.USHRT_MAX - 1);
+		upperValues[1] = (/*uint*/(this.m_quantizationFactor.y * (maxVertexY - this.m_worldAABB.minVertex.y))& 0x0000ffff) | 1;
+	},
+
+	// This one is only used for validation.
+	TestOverlapValidate: function(p1, p2){
+
+		for (var axis = 0; axis < 2; ++axis)
+		{
+			var bounds = this.m_bounds[axis];
+
+			//b2Settings.b2Assert(p1.lowerBounds[axis] < 2 * this.m_proxyCount);
+			//b2Settings.b2Assert(p1.upperBounds[axis] < 2 * this.m_proxyCount);
+			//b2Settings.b2Assert(p2.lowerBounds[axis] < 2 * this.m_proxyCount);
+			//b2Settings.b2Assert(p2.upperBounds[axis] < 2 * this.m_proxyCount);
+
+			if (bounds[p1.lowerBounds[axis]].value > bounds[p2.upperBounds[axis]].value)
+				return false;
+
+			if (bounds[p1.upperBounds[axis]].value < bounds[p2.lowerBounds[axis]].value)
+				return false;
+		}
+
+		return true;
+	},
+
+	TestOverlap: function(b, p)
+	{
+		for (var axis = 0; axis < 2; ++axis)
+		{
+			var bounds = this.m_bounds[axis];
+
+			//b2Settings.b2Assert(p.lowerBounds[axis] < 2 * this.m_proxyCount);
+			//b2Settings.b2Assert(p.upperBounds[axis] < 2 * this.m_proxyCount);
+
+			if (b.lowerValues[axis] > bounds[p.upperBounds[axis]].value)
+				return false;
+
+			if (b.upperValues[axis] < bounds[p.lowerBounds[axis]].value)
+				return false;
+		}
+
+		return true;
+	},
+
+	Query: function(lowerQueryOut, upperQueryOut, lowerValue, upperValue, bounds, boundCount, axis){
+
+		var lowerQuery = b2BroadPhase.BinarySearch(bounds, boundCount, lowerValue);
+		var upperQuery = b2BroadPhase.BinarySearch(bounds, boundCount, upperValue);
+
+		// Easy case: lowerQuery <= lowerIndex(i) < upperQuery
+		// Solution: search query range for min bounds.
+		for (var j = lowerQuery; j < upperQuery; ++j)
+		{
+			if (bounds[j].IsLower())
+			{
+				this.IncrementOverlapCount(bounds[j].proxyId);
+			}
+		}
+
+		// Hard case: lowerIndex(i) < lowerQuery < upperIndex(i)
+		// Solution: use the stabbing count to search down the bound array.
+		if (lowerQuery > 0)
+		{
+			var i = lowerQuery - 1;
+			var s = bounds[i].stabbingCount;
+
+			// Find the s overlaps.
+			while (s)
+			{
+				//b2Settings.b2Assert(i >= 0);
+
+				if (bounds[i].IsLower())
+				{
+					var proxy = this.m_proxyPool[ bounds[i].proxyId ];
+					if (lowerQuery <= proxy.upperBounds[axis])
+					{
+						this.IncrementOverlapCount(bounds[i].proxyId);
+						--s;
+					}
+				}
+				--i;
+			}
+		}
+
+		lowerQueryOut[0] = lowerQuery;
+		upperQueryOut[0] = upperQuery;
+	},
+
+
+	IncrementOverlapCount: function(proxyId){
+		var proxy = this.m_proxyPool[ proxyId ];
+		if (proxy.timeStamp < this.m_timeStamp)
+		{
+			proxy.timeStamp = this.m_timeStamp;
+			proxy.overlapCount = 1;
+		}
+		else
+		{
+			proxy.overlapCount = 2;
+			//b2Settings.b2Assert(this.m_queryResultCount < b2Settings.b2_maxProxies);
+			this.m_queryResults[this.m_queryResultCount] = proxyId;
+			++this.m_queryResultCount;
+		}
+	},
+	IncrementTimeStamp: function(){
+		if (this.m_timeStamp == b2Settings.USHRT_MAX)
+		{
+			for (var i = 0; i < b2Settings.b2_maxProxies; ++i)
+			{
+				this.m_proxyPool[i].timeStamp = 0;
+			}
+			this.m_timeStamp = 1;
+		}
+		else
+		{
+			++this.m_timeStamp;
+		}
+	},
+
+//public:
+	m_pairManager: new b2PairManager(),
+
+	m_proxyPool: new Array(b2Settings.b2_maxPairs),
+	m_freeProxy: 0,
+
+	m_bounds: new Array(2*b2Settings.b2_maxProxies),
+
+	m_queryResults: new Array(b2Settings.b2_maxProxies),
+	m_queryResultCount: 0,
+
+	m_worldAABB: null,
+	m_quantizationFactor: new b2Vec2(),
+	m_proxyCount: 0,
+	m_timeStamp: 0};
+b2BroadPhase.s_validate = false;
+b2BroadPhase.b2_invalid = b2Settings.USHRT_MAX;
+b2BroadPhase.b2_nullEdge = b2Settings.USHRT_MAX;
+b2BroadPhase.BinarySearch = function(bounds, count, value)
+	{
+		var low = 0;
+		var high = count - 1;
+		while (low <= high)
+		{
+			var mid = Math.floor((low + high) / 2);
+			if (bounds[mid].value > value)
+			{
+				high = mid - 1;
+			}
+			else if (bounds[mid].value < value)
+			{
+				low = mid + 1;
+			}
+			else
+			{
+				return /*uint*/(mid);
+			}
+		}
+
+		return /*uint*/(low);
+	};

File js/box2d/collision/b2BufferedPair.js

+/*
+* Copyright (c) 2006-2007 Erin Catto http:
+*
+* 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, and must not be
+* misrepresented the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+
+var b2BufferedPair = Class.create();
+b2BufferedPair.prototype = {
+	proxyId1: 0,
+	proxyId2: 0,
+
+	initialize: function() {}}

File js/box2d/collision/b2Collision.js

+/*
+* Copyright (c) 2006-2007 Erin Catto http:
+*
+* 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, and must not be
+* misrepresented the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+
+
+var b2Collision = Class.create();
+b2Collision.prototype = {
+
+	// Null feature
+
+
+
+
+	// Find the separation between poly1 and poly2 for a give edge normal on poly1.
+
+
+
+
+	// Find the max separation between poly1 and poly2 using edge normals
+	// from poly1.
+
+
+
+
+
+
+
+	// Find edge normal of max separation on A - return if separating axis is found
+	// Find edge normal of max separation on B - return if separation axis is found
+	// Choose reference edge(minA, minB)
+	// Find incident edge
+	// Clip
+	// The normal points from 1 to 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	initialize: function() {}}
+b2Collision.b2_nullFeature = 0x000000ff;
+b2Collision.ClipSegmentToLine = function(vOut, vIn, normal, offset)
+	{
+		// Start with no output points
+		var numOut = 0;
+
+		var vIn0 = vIn[0].v;
+		var vIn1 = vIn[1].v;
+
+		// Calculate the distance of end points to the line
+		var distance0 = b2Math.b2Dot(normal, vIn[0].v) - offset;
+		var distance1 = b2Math.b2Dot(normal, vIn[1].v) - offset;
+
+		// If the points are behind the plane
+		if (distance0 <= 0.0) vOut[numOut++] = vIn[0];
+		if (distance1 <= 0.0) vOut[numOut++] = vIn[1];
+
+		// If the points are on different sides of the plane
+		if (distance0 * distance1 < 0.0)
+		{
+			// Find intersection point of edge and plane
+			var interp = distance0 / (distance0 - distance1);
+			// expanded for performance
+			var tVec = vOut[numOut].v;
+			tVec.x = vIn0.x + interp * (vIn1.x - vIn0.x);
+			tVec.y = vIn0.y + interp * (vIn1.y - vIn0.y);
+			if (distance0 > 0.0)
+			{
+				vOut[numOut].id = vIn[0].id;
+			}
+			else
+			{
+				vOut[numOut].id = vIn[1].id;
+			}
+			++numOut;
+		}
+
+		return numOut;
+	};
+b2Collision.EdgeSeparation = function(poly1, edge1, poly2)
+	{
+		var vert1s = poly1.m_vertices;
+		var count2 = poly2.m_vertexCount;
+		var vert2s = poly2.m_vertices;
+
+		// Convert normal from into poly2's frame.
+		//b2Settings.b2Assert(edge1 < poly1.m_vertexCount);
+
+		//var normal = b2Math.b2MulMV(poly1.m_R, poly1->m_normals[edge1]);
+		var normalX = poly1.m_normals[edge1].x;
+		var normalY = poly1.m_normals[edge1].y;
+		var tX = normalX;
+		var tMat = poly1.m_R;
+		normalX = tMat.col1.x * tX + tMat.col2.x * normalY;
+		normalY = tMat.col1.y * tX + tMat.col2.y * normalY;
+		// ^^^^^^^ normal.MulM(poly1.m_R);
+
+		//var normalLocal2 = b2Math.b2MulTMV(poly2.m_R, normal);
+		var normalLocal2X = normalX;
+		var normalLocal2Y = normalY;
+		tMat = poly2.m_R;
+		tX = normalLocal2X * tMat.col1.x + normalLocal2Y * tMat.col1.y;
+		normalLocal2Y = normalLocal2X * tMat.col2.x + normalLocal2Y * tMat.col2.y;
+		normalLocal2X = tX;
+		// ^^^^^ normalLocal2.MulTM(poly2.m_R);
+
+		// Find support vertex on poly2 for -normal.
+		var vertexIndex2 = 0;
+		var minDot = Number.MAX_VALUE;
+		for (var i = 0; i < count2; ++i)
+		{
+			//var dot = b2Math.b2Dot(vert2s[i], normalLocal2);
+			var tVec = vert2s[i];
+			var dot = tVec.x * normalLocal2X + tVec.y * normalLocal2Y;
+			if (dot < minDot)
+			{
+				minDot = dot;
+				vertexIndex2 = i;
+			}
+		}
+
+		//b2Vec2 v1 = poly1->m_position + b2Mul(poly1->m_R, vert1s[edge1]);
+		tMat = poly1.m_R;
+		var v1X = poly1.m_position.x + (tMat.col1.x * vert1s[edge1].x + tMat.col2.x * vert1s[edge1].y)
+		var v1Y = poly1.m_position.y + (tMat.col1.y * vert1s[edge1].x + tMat.col2.y * vert1s[edge1].y)
+
+		//b2Vec2 v2 = poly2->m_position + b2Mul(poly2->m_R, vert2s[vertexIndex2]);
+		tMat = poly2.m_R;
+		var v2X = poly2.m_position.x + (tMat.col1.x * vert2s[vertexIndex2].x + tMat.col2.x * vert2s[vertexIndex2].y)
+		var v2Y = poly2.m_position.y + (tMat.col1.y * vert2s[vertexIndex2].x + tMat.col2.y * vert2s[vertexIndex2].y)
+
+		//var separation = b2Math.b2Dot( b2Math.SubtractVV( v2, v1 ) , normal);
+		v2X -= v1X;
+		v2Y -= v1Y;
+		//var separation = b2Math.b2Dot( v2 , normal);
+		var separation = v2X * normalX + v2Y * normalY;
+		return separation;
+	};
+b2Collision.FindMaxSeparation = function(edgeIndex /*int ptr*/, poly1, poly2, conservative)
+	{
+		var count1 = poly1.m_vertexCount;
+
+		// Vector pointing from the origin of poly1 to the origin of poly2.
+		//var d = b2Math.SubtractVV( poly2.m_position, poly1.m_position );
+		var dX = poly2.m_position.x - poly1.m_position.x;
+		var dY = poly2.m_position.y - poly1.m_position.y;
+
+		//var dLocal1 = b2Math.b2MulTMV(poly1.m_R, d);
+		var dLocal1X = (dX * poly1.m_R.col1.x + dY * poly1.m_R.col1.y);
+		var dLocal1Y = (dX * poly1.m_R.col2.x + dY * poly1.m_R.col2.y);
+
+		// Get support vertex hint for our search
+		var edge = 0;
+		var maxDot = -Number.MAX_VALUE;
+		for (var i = 0; i < count1; ++i)
+		{
+			//var dot = b2Math.b2Dot(poly.m_normals[i], dLocal1);
+			var dot = (poly1.m_normals[i].x * dLocal1X + poly1.m_normals[i].y * dLocal1Y);
+			if (dot > maxDot)
+			{
+				maxDot = dot;
+				edge = i;
+			}
+		}
+
+		// Get the separation for the edge normal.
+		var s = b2Collision.EdgeSeparation(poly1, edge, poly2);
+		if (s > 0.0 && conservative == false)
+		{
+			return s;
+		}
+
+		// Check the separation for the neighboring edges.
+		var prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1;
+		var sPrev = b2Collision.EdgeSeparation(poly1, prevEdge, poly2);
+		if (sPrev > 0.0 && conservative == false)
+		{
+			return sPrev;
+		}
+
+		var nextEdge = edge + 1 < count1 ? edge + 1 : 0;
+		var sNext = b2Collision.EdgeSeparation(poly1, nextEdge, poly2);
+		if (sNext > 0.0 && conservative == false)
+		{
+			return sNext;
+		}
+
+		// Find the best edge and the search direction.
+		var bestEdge = 0;
+		var bestSeparation;
+		var increment = 0;
+		if (sPrev > s && sPrev > sNext)
+		{
+			increment = -1;
+			bestEdge = prevEdge;
+			bestSeparation = sPrev;
+		}
+		else if (sNext > s)
+		{
+			increment = 1;
+			bestEdge = nextEdge;
+			bestSeparation = sNext;
+		}
+		else
+		{
+			// pointer out
+			edgeIndex[0] = edge;
+			return s;
+		}
+
+		while (true)
+		{
+
+			if (increment == -1)
+				edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1;
+			else
+				edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0;
+
+			s = b2Collision.EdgeSeparation(poly1, edge, poly2);
+			if (s > 0.0 && conservative == false)
+			{
+				return s;
+			}
+
+			if (s > bestSeparation)
+			{
+				bestEdge = edge;
+				bestSeparation = s;
+			}
+			else
+			{
+				break;
+			}
+		}
+
+		// pointer out
+		edgeIndex[0] = bestEdge;
+		return bestSeparation;
+	};
+b2Collision.FindIncidentEdge = function(c, poly1, edge1, poly2)
+	{
+		var count1 = poly1.m_vertexCount;
+		var vert1s = poly1.m_vertices;
+		var count2 = poly2.m_vertexCount;
+		var vert2s = poly2.m_vertices;
+
+		// Get the vertices associated with edge1.
+		var vertex11 = edge1;
+		var vertex12 = edge1 + 1 == count1 ? 0 : edge1 + 1;
+
+		// Get the normal of edge1.
+		var tVec = vert1s[vertex12];
+		//var normal1Local1 = b2Math.b2CrossVF( b2Math.SubtractVV( vert1s[vertex12], vert1s[vertex11] ), 1.0);
+		var normal1Local1X = tVec.x;
+		var normal1Local1Y = tVec.y;
+		tVec = vert1s[vertex11];
+		normal1Local1X -= tVec.x;
+		normal1Local1Y -= tVec.y;
+		var tX = normal1Local1X;
+		normal1Local1X = normal1Local1Y;
+		normal1Local1Y = -tX;
+		// ^^^^ normal1Local1.CrossVF(1.0);
+
+		var invLength = 1.0 / Math.sqrt(normal1Local1X*normal1Local1X + normal1Local1Y*normal1Local1Y);
+		normal1Local1X *= invLength;
+		normal1Local1Y *= invLength;
+		// ^^^^normal1Local1.Normalize();
+		//var normal1 = b2Math.b2MulMV(poly1.m_R, normal1Local1);
+		var normal1X = normal1Local1X;
+		var normal1Y = normal1Local1Y;
+
+		tX = normal1X;
+		var tMat = poly1.m_R;
+		normal1X = tMat.col1.x * tX + tMat.col2.x * normal1Y;
+		normal1Y = tMat.col1.y * tX + tMat.col2.y * normal1Y;
+		// ^^^^ normal1.MulM(poly1.m_R);
+
+		//var normal1Local2 = b2Math.b2MulTMV(poly2.m_R, normal1);
+		var normal1Local2X = normal1X;
+		var normal1Local2Y = normal1Y;
+		tMat = poly2.m_R;
+		tX = normal1Local2X * tMat.col1.x + normal1Local2Y * tMat.col1.y;
+		normal1Local2Y = normal1Local2X * tMat.col2.x + normal1Local2Y * tMat.col2.y;
+		normal1Local2X = tX;
+		// ^^^^ normal1Local2.MulTM(poly2.m_R);
+
+		// Find the incident edge on poly2.
+		var vertex21 = 0;
+		var vertex22 = 0;
+		var minDot = Number.MAX_VALUE;
+		for (var i = 0; i < count2; ++i)
+		{
+			var i1 = i;
+			var i2 = i + 1 < count2 ? i + 1 : 0;
+
+			//var normal2Local2 = b2Math.b2CrossVF( b2Math.SubtractVV( vert2s[i2], vert2s[i1] ), 1.0);
+			tVec = vert2s[i2];
+			var normal2Local2X = tVec.x;
+			var normal2Local2Y = tVec.y;
+			tVec = vert2s[i1];
+			normal2Local2X -= tVec.x;
+			normal2Local2Y -= tVec.y;
+			tX = normal2Local2X;
+			normal2Local2X = normal2Local2Y;
+			normal2Local2Y = -tX;
+			// ^^^^ normal2Local2.CrossVF(1.0);
+
+			invLength = 1.0 / Math.sqrt(normal2Local2X*normal2Local2X + normal2Local2Y*normal2Local2Y);
+			normal2Local2X *= invLength;
+			normal2Local2Y *= invLength;
+			// ^^^^ normal2Local2.Normalize();
+
+			//var dot = b2Math.b2Dot(normal2Local2, normal1Local2);
+			var dot = normal2Local2X * normal1Local2X + normal2Local2Y * normal1Local2Y;
+			if (dot < minDot)
+			{
+				minDot = dot;
+				vertex21 = i1;
+				vertex22 = i2;
+			}
+		}
+
+		var tClip;
+		// Build the clip vertices for the incident edge.
+		tClip = c[0];
+		//tClip.v = b2Math.AddVV(poly2.m_position, b2Math.b2MulMV(poly2.m_R, vert2s[vertex21]));
+		tVec = tClip.v;
+		tVec.SetV(vert2s[vertex21]);
+		tVec.MulM(poly2.m_R);
+		tVec.Add(poly2.m_position);
+
+		tClip.id.features.referenceFace = edge1;
+		tClip.id.features.incidentEdge = vertex21;
+		tClip.id.features.incidentVertex = vertex21;
+
+		tClip = c[1];
+		//tClip.v = b2Math.AddVV(poly2.m_position, b2Math.b2MulMV(poly2.m_R, vert2s[vertex22]));
+		tVec = tClip.v;
+		tVec.SetV(vert2s[vertex22]);
+		tVec.MulM(poly2.m_R);
+		tVec.Add(poly2.m_position);
+		tClip.id.features.referenceFace = edge1;
+		tClip.id.features.incidentEdge = vertex21;
+		tClip.id.features.incidentVertex = vertex22;
+	};
+b2Collision.b2CollidePolyTempVec = new b2Vec2();
+b2Collision.b2CollidePoly = function(manifold, polyA, polyB, conservative)
+	{
+		manifold.pointCount = 0;
+
+		var edgeA = 0;
+		var edgeAOut = [edgeA];
+		var separationA = b2Collision.FindMaxSeparation(edgeAOut, polyA, polyB, conservative);
+		edgeA = edgeAOut[0];
+		if (separationA > 0.0 && conservative == false)
+			return;
+
+		var edgeB = 0;
+		var edgeBOut = [edgeB];
+		var separationB = b2Collision.FindMaxSeparation(edgeBOut, polyB, polyA, conservative);
+		edgeB = edgeBOut[0];
+		if (separationB > 0.0 && conservative == false)
+			return;
+
+		var poly1;
+		var poly2;
+		var edge1 = 0;
+		var flip = 0;
+		var k_relativeTol = 0.98;
+		var k_absoluteTol = 0.001;
+
+		// TODO_ERIN use "radius" of poly for absolute tolerance.
+		if (separationB > k_relativeTol * separationA + k_absoluteTol)
+		{
+			poly1 = polyB;
+			poly2 = polyA;
+			edge1 = edgeB;
+			flip = 1;
+		}
+		else
+		{
+			poly1 = polyA;
+			poly2 = polyB;
+			edge1 = edgeA;
+			flip = 0;
+		}
+
+		var incidentEdge = [new ClipVertex(), new ClipVertex()];
+		b2Collision.FindIncidentEdge(incidentEdge, poly1, edge1, poly2);
+
+		var count1 = poly1.m_vertexCount;
+		var vert1s = poly1.m_vertices;
+
+		var v11 = vert1s[edge1];
+		var v12 = edge1 + 1 < count1 ? vert1s[edge1+1] : vert1s[0];
+
+		//var dv = b2Math.SubtractVV(v12, v11);
+		var dvX = v12.x - v11.x;
+		var dvY = v12.y - v11.y;
+
+		//var sideNormal = b2Math.b2MulMV(poly1.m_R, b2Math.SubtractVV(v12, v11));
+		var sideNormalX = v12.x - v11.x;
+		var sideNormalY = v12.y - v11.y;
+
+		var tX = sideNormalX;
+		var tMat = poly1.m_R;
+		sideNormalX = tMat.col1.x * tX + tMat.col2.x * sideNormalY;
+		sideNormalY = tMat.col1.y * tX + tMat.col2.y * sideNormalY;
+		// ^^^^ sideNormal.MulM(poly1.m_R);
+
+		var invLength = 1.0 / Math.sqrt(sideNormalX*sideNormalX + sideNormalY*sideNormalY);
+		sideNormalX *= invLength;
+		sideNormalY *= invLength;
+		// ^^^^ sideNormal.Normalize();
+
+		//var frontNormal = b2Math.b2CrossVF(sideNormal, 1.0);
+		var frontNormalX = sideNormalX;
+		var frontNormalY = sideNormalY;
+		tX = frontNormalX;
+		frontNormalX = frontNormalY;
+		frontNormalY = -tX;
+		// ^^^^ frontNormal.CrossVF(1.0);
+
+		// Expanded for performance
+		//v11 = b2Math.AddVV(poly1.m_position, b2Math.b2MulMV(poly1.m_R, v11));
+		var v11X = v11.x;
+		var v11Y = v11.y;
+		tX = v11X;
+		tMat = poly1.m_R;
+		v11X = tMat.col1.x * tX + tMat.col2.x * v11Y;
+		v11Y = tMat.col1.y * tX + tMat.col2.y * v11Y;
+		// ^^^^ v11.MulM(poly1.m_R);
+		v11X += poly1.m_position.x;
+		v11Y += poly1.m_position.y;
+		//v12 = b2Math.AddVV(poly1.m_position, b2Math.b2MulMV(poly1.m_R, v12));
+		var v12X = v12.x;
+		var v12Y = v12.y;
+		tX = v12X;
+		tMat = poly1.m_R;
+		v12X = tMat.col1.x * tX + tMat.col2.x * v12Y;
+		v12Y = tMat.col1.y * tX + tMat.col2.y * v12Y;
+		// ^^^^ v12.MulM(poly1.m_R);
+		v12X += poly1.m_position.x;
+		v12Y += poly1.m_position.y;
+
+		//var frontOffset = b2Math.b2Dot(frontNormal, v11);
+		var frontOffset = frontNormalX * v11X + frontNormalY * v11Y;
+		//var sideOffset1 = -b2Math.b2Dot(sideNormal, v11);
+		var sideOffset1 = -(sideNormalX * v11X + sideNormalY * v11Y);
+		//var sideOffset2 = b2Math.b2Dot(sideNormal, v12);
+		var sideOffset2 = sideNormalX * v12X + sideNormalY * v12Y;
+
+		// Clip incident edge against extruded edge1 side edges.
+		var clipPoints1 = [new ClipVertex(), new ClipVertex()];
+		var clipPoints2 = [new ClipVertex(), new ClipVertex()];
+
+		var np = 0;
+
+		// Clip to box side 1
+		b2Collision.b2CollidePolyTempVec.Set(-sideNormalX, -sideNormalY);
+		np = b2Collision.ClipSegmentToLine(clipPoints1, incidentEdge, b2Collision.b2CollidePolyTempVec, sideOffset1);
+
+		if (np < 2)
+			return;
+
+		// Clip to negative box side 1
+		b2Collision.b2CollidePolyTempVec.Set(sideNormalX, sideNormalY);
+		np = b2Collision.ClipSegmentToLine(clipPoints2, clipPoints1,  b2Collision.b2CollidePolyTempVec, sideOffset2);
+
+		if (np < 2)
+			return;
+
+		// Now clipPoints2 contains the clipped points.
+		if (flip){
+			manifold.normal.Set(-frontNormalX, -frontNormalY);
+		}
+		else{
+			manifold.normal.Set(frontNormalX, frontNormalY);
+		}
+		// ^^^^ manifold.normal = flip ? frontNormal.Negative() : frontNormal;
+
+		var pointCount = 0;
+		for (var i = 0; i < b2Settings.b2_maxManifoldPoints; ++i)
+		{
+			//var separation = b2Math.b2Dot(frontNormal, clipPoints2[i].v) - frontOffset;
+			var tVec = clipPoints2[i].v;
+			var separation = (frontNormalX * tVec.x + frontNormalY * tVec.y) - frontOffset;
+
+			if (separation <= 0.0 || conservative == true)
+			{
+				var cp = manifold.points[ pointCount ];
+				cp.separation = separation;
+				cp.position.SetV( clipPoints2[i].v );
+				cp.id.Set( clipPoints2[i].id );
+				cp.id.features.flip = flip;
+				++pointCount;
+			}
+		}
+
+		manifold.pointCount = pointCount;
+	};
+b2Collision.b2CollideCircle = function(manifold, circle1, circle2, conservative)
+	{
+		manifold.pointCount = 0;
+
+		//var d = b2Math.SubtractVV(circle2.m_position, circle1.m_position);
+		var dX = circle2.m_position.x - circle1.m_position.x;
+		var dY = circle2.m_position.y - circle1.m_position.y;
+		//var distSqr = b2Math.b2Dot(d, d);
+		var distSqr = dX * dX + dY * dY;
+		var radiusSum = circle1.m_radius + circle2.m_radius;
+		if (distSqr > radiusSum * radiusSum && conservative == false)
+		{
+			return;
+		}
+
+		var separation;
+		if (distSqr < Number.MIN_VALUE)
+		{
+			separation = -radiusSum;
+			manifold.normal.Set(0.0, 1.0);
+		}
+		else
+		{
+			var dist = Math.sqrt(distSqr);
+			separation = dist - radiusSum;
+			var a = 1.0 / dist;
+			manifold.normal.x = a * dX;
+			manifold.normal.y = a * dY;
+		}
+
+		manifold.pointCount = 1;
+		var tPoint = manifold.points[0];
+		tPoint.id.set_key(0);
+		tPoint.separation = separation;
+		//tPoint.position = b2Math.SubtractVV(circle2.m_position, b2Math.MulFV(circle2.m_radius, manifold.normal));
+		tPoint.position.x = circle2.m_position.x - (circle2.m_radius * manifold.normal.x);
+		tPoint.position.y = circle2.m_position.y - (circle2.m_radius * manifold.normal.y);
+	};
+b2Collision.b2CollidePolyAndCircle = function(manifold, poly, circle, conservative)
+	{
+		manifold.pointCount = 0;
+		var tPoint;
+
+		var dX;
+		var dY;
+
+		// Compute circle position in the frame of the polygon.
+		//var xLocal = b2Math.b2MulTMV(poly.m_R, b2Math.SubtractVV(circle.m_position, poly.m_position));
+		var xLocalX = circle.m_position.x - poly.m_position.x;
+		var xLocalY = circle.m_position.y - poly.m_position.y;
+		var tMat = poly.m_R;
+		var tX = xLocalX * tMat.col1.x + xLocalY * tMat.col1.y;
+		xLocalY = xLocalX * tMat.col2.x + xLocalY * tMat.col2.y;
+		xLocalX = tX;
+
+		var dist;
+
+		// Find the min separating edge.
+		var normalIndex = 0;
+		var separation = -Number.MAX_VALUE;
+		var radius = circle.m_radius;
+		for (var i = 0; i < poly.m_vertexCount; ++i)
+		{
+			//var s = b2Math.b2Dot(poly.m_normals[i], b2Math.SubtractVV(xLocal, poly.m_vertices[i]));
+			var s = poly.m_normals[i].x * (xLocalX-poly.m_vertices[i].x) + poly.m_normals[i].y * (xLocalY-poly.m_vertices[i].y);
+			if (s > radius)
+			{
+				// Early out.
+				return;
+			}
+
+			if (s > separation)
+			{
+				separation = s;
+				normalIndex = i;
+			}
+		}
+
+		// If the center is inside the polygon ...
+		if (separation < Number.MIN_VALUE)
+		{
+			manifold.pointCount = 1;
+			//manifold.normal = b2Math.b2MulMV(poly.m_R, poly.m_normals[normalIndex]);
+			var tVec = poly.m_normals[normalIndex];
+			manifold.normal.x = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y;
+			manifold.normal.y = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y;
+
+			tPoint = manifold.points[0];
+			tPoint.id.features.incidentEdge = normalIndex;
+			tPoint.id.features.incidentVertex = b2Collision.b2_nullFeature;
+			tPoint.id.features.referenceFace = b2Collision.b2_nullFeature;
+			tPoint.id.features.flip = 0;
+			tPoint.position.x = circle.m_position.x - radius * manifold.normal.x;
+			tPoint.position.y = circle.m_position.y - radius * manifold.normal.y;
+			//tPoint.position = b2Math.SubtractVV(circle.m_position , b2Math.MulFV(radius , manifold.normal));
+			tPoint.separation = separation - radius;
+			return;
+		}
+
+		// Project the circle center onto the edge segment.
+		var vertIndex1 = normalIndex;
+		var vertIndex2 = vertIndex1 + 1 < poly.m_vertexCount ? vertIndex1 + 1 : 0;
+		//var e = b2Math.SubtractVV(poly.m_vertices[vertIndex2] , poly.m_vertices[vertIndex1]);
+		var eX = poly.m_vertices[vertIndex2].x - poly.m_vertices[vertIndex1].x;
+		var eY = poly.m_vertices[vertIndex2].y - poly.m_vertices[vertIndex1].y;
+		//var length = e.Normalize();
+		var length = Math.sqrt(eX*eX + eY*eY);
+		eX /= length;
+		eY /= length;
+
+		// If the edge length is zero ...
+		if (length < Number.MIN_VALUE)
+		{
+			//d = b2Math.SubtractVV(xLocal , poly.m_vertices[vertIndex1]);
+			dX = xLocalX - poly.m_vertices[vertIndex1].x;
+			dY = xLocalY - poly.m_vertices[vertIndex1].y;
+			//dist = d.Normalize();
+			dist = Math.sqrt(dX*dX + dY*dY);
+			dX /= dist;
+			dY /= dist;
+			if (dist > radius)
+			{
+				return;
+			}
+
+			manifold.pointCount = 1;
+			//manifold.normal = b2Math.b2MulMV(poly.m_R, d);
+			manifold.normal.Set(tMat.col1.x * dX + tMat.col2.x * dY, tMat.col1.y * dX + tMat.col2.y * dY);
+			tPoint = manifold.points[0];
+			tPoint.id.features.incidentEdge = b2Collision.b2_nullFeature;
+			tPoint.id.features.incidentVertex = vertIndex1;
+			tPoint.id.features.referenceFace = b2Collision.b2_nullFeature;
+			tPoint.id.features.flip = 0;
+			//tPoint.position = b2Math.SubtractVV(circle.m_position , b2Math.MulFV(radius , manifold.normal));
+			tPoint.position.x = circle.m_position.x - radius * manifold.normal.x;
+			tPoint.position.y = circle.m_position.y - radius * manifold.normal.y;
+			tPoint.separation = dist - radius;
+			return;
+		}
+
+		// Project the center onto the edge.
+		//var u = b2Math.b2Dot(b2Math.SubtractVV(xLocal , poly.m_vertices[vertIndex1]) , e);
+		var u = (xLocalX-poly.m_vertices[vertIndex1].x) * eX + (xLocalY-poly.m_vertices[vertIndex1].y) * eY;
+
+		tPoint = manifold.points[0];
+		tPoint.id.features.incidentEdge = b2Collision.b2_nullFeature;
+		tPoint.id.features.incidentVertex = b2Collision.b2_nullFeature;
+		tPoint.id.features.referenceFace = b2Collision.b2_nullFeature;
+		tPoint.id.features.flip = 0;
+
+		var pX, pY;
+		if (u <= 0.0)
+		{
+			pX = poly.m_vertices[vertIndex1].x;
+			pY = poly.m_vertices[vertIndex1].y;
+			tPoint.id.features.incidentVertex = vertIndex1;
+		}
+		else if (u >= length)
+		{
+			pX = poly.m_vertices[vertIndex2].x;
+			pY = poly.m_vertices[vertIndex2].y;
+			tPoint.id.features.incidentVertex = vertIndex2;
+		}
+		else
+		{
+			//p = b2Math.AddVV(poly.m_vertices[vertIndex1] , b2Math.MulFV(u, e));
+			pX = eX * u + poly.m_vertices[vertIndex1].x;
+			pY = eY * u + poly.m_vertices[vertIndex1].y;
+			tPoint.id.features.incidentEdge = vertIndex1;
+		}
+
+		//d = b2Math.SubtractVV(xLocal , p);
+		dX = xLocalX - pX;
+		dY = xLocalY - pY;
+		//dist = d.Normalize();
+		dist = Math.sqrt(dX*dX + dY*dY);
+		dX /= dist;
+		dY /= dist;
+		if (dist > radius)
+		{
+			return;
+		}
+
+		manifold.pointCount = 1;
+		//manifold.normal = b2Math.b2MulMV(poly.m_R, d);
+		manifold.normal.Set(tMat.col1.x * dX + tMat.col2.x * dY, tMat.col1.y * dX + tMat.col2.y * dY);
+		//tPoint.position = b2Math.SubtractVV(circle.m_position , b2Math.MulFV(radius , manifold.normal));
+		tPoint.position.x = circle.m_position.x - radius * manifold.normal.x;
+		tPoint.position.y = circle.m_position.y - radius * manifold.normal.y;
+		tPoint.separation = dist - radius;
+	};
+b2Collision.b2TestOverlap = function(a, b)
+	{
+		var t1 = b.minVertex;
+		var t2 = a.maxVertex;
+		//d1 = b2Math.SubtractVV(b.minVertex, a.maxVertex);
+		var d1X = t1.x - t2.x;
+		var d1Y = t1.y - t2.y;
+		//d2 = b2Math.SubtractVV(a.minVertex, b.maxVertex);
+		t1 = a.minVertex;
+		t2 = b.maxVertex;
+		var d2X = t1.x - t2.x;
+		var d2Y = t1.y - t2.y;
+
+		if (d1X > 0.0 || d1Y > 0.0)
+			return false;
+
+		if (d2X > 0.0 || d2Y > 0.0)