From ffc61ada01771b28a47eff94f3b7f483110fbdc4 Mon Sep 17 00:00:00 2001 From: Andrew Dolce Date: Tue, 7 Aug 2012 12:06:10 -0400 Subject: [PATCH 01/22] Add raycasts to performance test --- tests/js/performance.js | 53 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/tests/js/performance.js b/tests/js/performance.js index c7d63e4..99c503f 100644 --- a/tests/js/performance.js +++ b/tests/js/performance.js @@ -20,6 +20,53 @@ var collisionShapes = []; + (function(){ + var _DOWN = Bump.Vector3.create( 0, -1, 0 ); + var _down = Bump.Vector3.create(); + var _from = Bump.Vector3.create(); + var _to = Bump.Vector3.create(); + + // for now test the 4 corners + var testPoints = [ + Bump.Vector3.create( -1, -1, -1 ), + Bump.Vector3.create( -1, -1, 1 ), + Bump.Vector3.create( 1, -1, -1 ), + Bump.Vector3.create( 1, -1, 1 ) + ]; + + var boxTrans = Bump.Transform.getIdentity(); + + var rayCallback = Bump.CollisionWorld.ClosestRayResultCallback.create( _from, _to ); + rayCallback.collisionFilterMask = + Bump.BroadphaseProxy.CollisionFilterGroups.AllFilter; + + // set up a internal pre-tick callback to test a bunch of raycasts per object + dynamicsWorld.setInternalTickCallback( function() { + + // cast rays for each collision object, slipping object 0, + // which is the dryer + for ( var i = 1; i < dynamicsWorld.getNumCollisionObjects(); ++i ) { + var colObj = dynamicsWorld.getCollisionObjectArray()[ i ]; + var body = Bump.RigidBody.upcast( colObj ); + body.getMotionState().getWorldTransform( boxTrans ); + + boxTrans.multiplyVector( _DOWN, _down ); + + for ( var j = 0; j < testPoints.length; j++ ) { + boxTrans.multiplyVector( testPoints[ j ], _from ); + _from.add( _down, _to ); + rayCallback.rayFromWorld = _from; + rayCallback.rayToWorld = _to; + + dynamicsWorld.rayTest( _from, _to, rayCallback ); + + if( rayCallback.hasHit() ) { + // do something + } + } + } + }, undefined, true ); + }()); var groundBody; (function( size ) { var groundHalfExtents = Bump.Vector3.create( size, size, size ); @@ -88,7 +135,7 @@ renderer.addBox({ size: 20, wireframe: true }); (function() { - var num = 7; + var num = 2; var j = 4; for ( var i = 0; i < num; ++i ) { for ( var k = 0; k < num; ++k ) { @@ -111,7 +158,7 @@ var time = 0; var step = function () { - time += 16; + time += 160; stats.begin(); groundRot.setEuler( 0, 0, rate + amp * Math.sin( time / 500 ) ); @@ -119,7 +166,7 @@ newTransform.basis.multiplyMatrix( Bump.Matrix3x3.createWithQuaternion( groundRot ), newTransform.basis ); groundBody.getMotionState().setWorldTransform( newTransform ); - dynamicsWorld.stepSimulation( 0.016 ); + dynamicsWorld.stepSimulation( 0.16, 20, 0.016 ); for ( var i = 0; i < dynamicsWorld.getNumCollisionObjects(); ++i ) { var colObj = dynamicsWorld.getCollisionObjectArray()[i]; From d455c6bb0f64a968b1dd593a69de653e498f9458 Mon Sep 17 00:00:00 2001 From: Andrew Dolce Date: Tue, 7 Aug 2012 12:08:40 -0400 Subject: [PATCH 02/22] Remove allocations in CollisionWorld.rayTestSingle Allocations are replaced with get and del functions to recycle objects from memory pools. In some cases, "set" functions were added to a few object types so that they can be easily reinitialized without causing unwanted allocation. --- .../CollisionDispatch/CollisionWorld.js | 224 +++++++++++++++--- .../NarrowPhaseCollision/RaycastCallback.js | 11 + 2 files changed, 199 insertions(+), 36 deletions(-) diff --git a/src/BulletCollision/CollisionDispatch/CollisionWorld.js b/src/BulletCollision/CollisionDispatch/CollisionWorld.js index 40ad7a6..1db1532 100644 --- a/src/BulletCollision/CollisionDispatch/CollisionWorld.js +++ b/src/BulletCollision/CollisionDispatch/CollisionWorld.js @@ -3,17 +3,46 @@ // load: BulletCollision/NarrowPhaseCollision/RaycastCallback.js // load: BulletCollision/BroadphaseCollision/Dbvt.js // load: BulletCollision/BroadphaseCollision/BroadphaseInterface.js +// load: BulletCollision/BroadphaseCollision/BroadphaseProxy.js +// load: BulletCollision/CollisionDispatch/CollisionObject.js +// load: BulletCollision/NarrowPhaseCollision/VoronoiSimplexSolver.js +// load: BulletCollision/NarrowPhaseCollision/SubSimplexConvexCast.js +// load: BulletCollision/CollisionShapes/SphereShape.js // run: LinearMath/Transform.js // run: LinearMath/TransformUtil.js // run: BulletCollision/BroadphaseCollision/BroadphaseProxy.js // run: BulletCollision/BroadphaseCollision/Dispatcher.js -// run: BulletCollision/CollisionDispatch/CollisionObject.js -// run: BulletCollision/NarrowPhaseCollision/VoronoiSimplexSolver.js -// run: BulletCollision/NarrowPhaseCollision/SubSimplexConvexCast.js -// run: BulletCollision/CollisionShapes/SphereShape.js + (function( window, Bump ) { + + // memory pool management + + // dummyArgs is an array of arguments to be used when creating + // a new object of Type, as some Types expect args within their + // create functions + var createGetter = function( Type, pool, dummyArgs ) { + // if there are dummy args, use them + if( dummyArgs ) { + return function() { + return pool.pop() || Type.create.apply( Type, dummyArgs ); + }; + } else { + return function() { + return pool.pop() || Type.create(); + }; + } + }; + + var createDeller = function( pool ) { + return function() { + for ( var i = 0; i < arguments.length; ++i ) { + pool.push( arguments[i] ); + } + }; + }; + var tmpV1 = Bump.Vector3.create(); // port of btCollisionWorld::RayResultCallback (stored on Bump.CollisionWorld after its @@ -63,6 +92,25 @@ }, members: { + // ASD: added for easy recycling, since init() calls clone + set: function BridgeTriangleRaycastCallback( from, + to, + resultCallback, + collisionObject, + triangleMesh, + colObjWorldTransform + ) { + //@BP Mod + Bump.TriangleRaycastCallback.set.call( + this, from, to, resultCallback.flags + ); + this.resultCallback = resultCallback; + this.collisionObject = collisionObject; + this.triangleMesh = triangleMesh; + this.colObjWorldTransform.assign( colObjWorldTransform ); + return this; + }, + reportHit: function( hitNormalLocal, hitFraction, partId, triangleIndex ) { var shapeInfo = Bump.CollisionWorld.LocalShapeInfo.create(); shapeInfo.shapePart = partId; @@ -140,6 +188,27 @@ }, members: { + + // ASD: added for easy recycling of RayTester objects, since init calls + // clone() + set: function( + collisionObject, // btCollisionObject* + compoundShape, // const btCompoundShape* + colObjWorldTransform, // const btTransform& + rayFromTrans, // const btTransform& + rayToTrans, // const btTransform& + resultCallback // RayResultCallback& + ) { + this.collisionObject = collisionObject; + this.compoundShape = compoundShape; + this.colObjWorldTransform.assign( colObjWorldTransform ); + this.rayFromTrans.assign( rayFromTrans ); + this.rayToTrans.assign( rayToTrans ); + this.resultCallback = resultCallback; + + return this; + }, + // ASD: this function actually doesn't overwrite anything in ICollide, so we will leave it named as // `Process` for now... Process: function( i ) { @@ -172,6 +241,74 @@ } }); + // port of btCollisionWorld::LocalRayResult, stored on + // Bump.CollisionWorld after its definition below + var LocalRayResult = Bump.type({ + init: function LocalRayResult ( + collisionObject, // btCollisionObject* + localShapeInfo, // LocalShapeInfo* + hitNormalLocal, // const btVector3& + hitFraction // btScalar + ) { + this.collisionObject = collisionObject; + this.localShapeInfo = localShapeInfo; + this.hitNormalLocal = hitNormalLocal; + this.hitFraction = hitFraction; + } + }); + + + // Collision World memory pools + var vector3Pool = []; + var sphereShapePool = []; + var voronoiPool = []; + var convexCastPool = []; + var castResultPool = []; + var localRayResultPool = []; + var bridgeTriangleRCBPool = []; + var rayTesterPool = []; + + var getVector3 = createGetter( Bump.Vector3, vector3Pool ); + var getSphereShape = createGetter( Bump.SphereShape, sphereShapePool, [ 0.0 ] ); + var getVoronoiSimplexSolver = createGetter( Bump.VoronoiSimplexSolver, voronoiPool ); + var getSubsimplexConvexCast = createGetter( Bump.SubsimplexConvexCast, convexCastPool ); + var getCastResult = createGetter( Bump.ConvexCast.CastResult, castResultPool ); + var getLocalRayResult = createGetter( LocalRayResult, localRayResultPool ); + + var getBridgeTriangleRaycastCallback = createGetter( + BridgeTriangleRaycastCallback, + bridgeTriangleRCBPool, + [ + Bump.Vector3.create(), + Bump.Vector3.create(), + { flags: 0 }, // dummy value for `resultCallback` param + undefined, + undefined, + Bump.Transform.getIdentity() + ] + ); + + var getRayTester = createGetter( RayTester, rayTesterPool, [ + undefined, + undefined, + Bump.Transform.getIdentity(), + Bump.Transform.getIdentity(), + Bump.Transform.getIdentity(), + undefined + ]); + + var delVector3 = createDeller( vector3Pool ); + var delSphereShape = createDeller( sphereShapePool ); + var delVoronoiSimplexSolver = createDeller( voronoiPool ); + var delSubsimplexConvexCast = createDeller( convexCastPool ); + var delCastResult = createDeller( castResultPool ); + var delLocalRayResult = createDeller( localRayResultPool ); + var delBridgeTriangleRaycastCallback = createDeller( bridgeTriangleRCBPool ); + var delRayTester = createDeller( rayTesterPool ); + + // used to reinitialize a SphereShape in rayTestSingle + var emptySphereShape = Bump.SphereShape.create( 0.0 ); + emptySphereShape.setMargin( 0 ); Bump.CollisionWorld = Bump.type({ @@ -459,23 +596,37 @@ colObjWorldTransform, resultCallback ) { - var pointShape = Bump.SphereShape.create( 0.0 ); - pointShape.setMargin( 0 ); - - var castShape = pointShape; + // allocate temporaries + // TODO: not all of these are needed for every rayTestSingle call, + // so allocations could be moved to where they are needed + var tmpVec1 = getVector3(); + var tmpVec2 = getVector3(); + var tmpSS = getSphereShape(); + var tmpCR = getCastResult(); + var tmpVSS = getVoronoiSimplexSolver(); + var tmpSSCC = getSubsimplexConvexCast(); + var tmpLRR = getLocalRayResult(); + var tmpBTRC = getBridgeTriangleRaycastCallback(); + var tmpRT = getRayTester(); + + // TODO: to get best speed-up, could in-line the clone code here + // to avoid multiple calls to _super functions + var castShape = emptySphereShape.clone( tmpSS ); var worldTocollisionObject, rayFromLocal, rayToLocal, rcb; if ( collisionShape.isConvex() ) { - var castResult = Bump.ConvexCast.CastResult.create(); + var castResult = tmpCR; castResult.fraction = resultCallback.closestHitFraction; var convexShape = collisionShape; - var simplexSolver = Bump.VoronoiSimplexSolver.create(); + var simplexSolver = tmpVSS; + simplexSolver.reset(); // #define USE_SUBSIMPLEX_CONVEX_CAST 1 // #ifdef USE_SUBSIMPLEX_CONVEX_CAST - var convexCaster = Bump.SubsimplexConvexCast.create( castShape, convexShape, simplexSolver ); + var convexCaster = tmpSSCC; + convexCaster.init( castShape, convexShape, simplexSolver ); // #else // //btGjkConvexCast convexCaster(castShape,convexShape,&simplexSolver); // //btContinuousConvexCollision convexCaster(castShape,convexShape,&simplexSolver,0); @@ -497,7 +648,8 @@ // #endif //USE_SUBSIMPLEX_CONVEX_CAST castResult.normal.normalize(); - var localRayResult = Bump.CollisionWorld.LocalRayResult.create( + var localRayResult = tmpLRR; + localRayResult.init( collisionObject, 0, castResult.normal, @@ -524,7 +676,7 @@ // ConvexCast::CastResult // ASD: in-function declaration of BridgeTriangleRaycastCallback went here - rcb = BridgeTriangleRaycastCallback.create( + rcb = tmpBTRC.set( rayFromLocal, rayToLocal, resultCallback, @@ -551,7 +703,7 @@ // but since it was line-for-line identical to the first declaration, the two were // were consolidated into a single Bump.type() outside of CollisionWorld. - rcb = BridgeTriangleRaycastCallback.create( + rcb = tmpBTRC.set( rayFromLocal, rayToLocal, resultCallback, @@ -561,9 +713,9 @@ ); rcb.hitFraction = resultCallback.closestHitFraction; - var rayAabbMinLocal = rayFromLocal.clone(); + var rayAabbMinLocal = rayFromLocal.clone( tmpVec1 ); rayAabbMinLocal.setMin( rayToLocal ); - var rayAabbMaxLocal = rayFromLocal.clone(); + var rayAabbMaxLocal = rayFromLocal.clone( tmpVec2 ); rayAabbMaxLocal.setMax( rayToLocal ); concaveShape.processAllTriangles( rcb, rayAabbMinLocal, rayAabbMaxLocal ); @@ -578,8 +730,7 @@ var compoundShape = collisionShape; var dbvt = compoundShape.getDynamicAabbTree(); - - var rayCB = RayTester.create( + var rayCB = tmpRT.set( collisionObject, compoundShape, colObjWorldTransform, @@ -589,19 +740,33 @@ ); if ( dbvt ) { - var localRayFrom = colObjWorldTransform.inverseTimes( rayFromTrans ).getOrigin().clone(); - var localRayTo = colObjWorldTransform.inverseTimes( rayToTrans ).getOrigin().clone(); + var localRayFrom = colObjWorldTransform + .inverseTimes( rayFromTrans ) + .getOrigin().clone( tmpVec1 ); + var localRayTo = colObjWorldTransform + .inverseTimes( rayToTrans ) + .getOrigin().clone( tmpVec2 ); Bump.Dbvt.rayTest( dbvt.root, localRayFrom, localRayTo, rayCB ); } else { for ( var i = 0, n = compoundShape.getNumChildShapes(); i < n; ++i ) { rayCB.Process( i ); } } - } } } + + // free temporaries + delVector3( tmpVec1 ); + delVector3( tmpVec2 ); + delSphereShape( tmpSS ); + delCastResult( tmpCR ); + delVoronoiSimplexSolver( tmpVSS ); + delSubsimplexConvexCast( tmpSSCC ); + delLocalRayResult( tmpLRR ); + delBridgeTriangleRaycastCallback( tmpBTRC ); + delRayTester( tmpRT ); } } }); @@ -679,21 +844,8 @@ } }); - // port of btCollisionWorld::LocalRayResult - Bump.CollisionWorld.LocalRayResult = Bump.type({ - init: function LocalRayResult ( - collisionObject, // btCollisionObject* - localShapeInfo, // LocalShapeInfo* - hitNormalLocal, // const btVector3& - hitFraction // btScalar - ) { - this.collisionObject = collisionObject; - this.localShapeInfo = localShapeInfo; - this.hitNormalLocal = hitNormalLocal; - this.hitFraction = hitFraction; - } - }); - + // defined above for dependency reasons + Bump.CollisionWorld.LocalRayResult = LocalRayResult; Bump.CollisionWorld.RayResultCallback = RayResultCallback; // port of btCollisionWorld::ClosestRayResultCallback diff --git a/src/BulletCollision/NarrowPhaseCollision/RaycastCallback.js b/src/BulletCollision/NarrowPhaseCollision/RaycastCallback.js index a0124ff..163aa39 100644 --- a/src/BulletCollision/NarrowPhaseCollision/RaycastCallback.js +++ b/src/BulletCollision/NarrowPhaseCollision/RaycastCallback.js @@ -16,6 +16,17 @@ }, members: { + + // ASD: added for easy recycling, since init() calls clone + set: function( from, to, flags ) { + this.from.assign( from ); + this.to.assign( to ); + this.flags = flags || 0; + this.hitFraction = 1; + + return this; + }, + processTriangle: function( triangle, // originally btVector3*, ported as array partId, From cf22db1fd564dd54498e6b59641af9ba36df9c6a Mon Sep 17 00:00:00 2001 From: Andrew Dolce Date: Tue, 7 Aug 2012 16:22:07 -0400 Subject: [PATCH 03/22] Remove allocation from rayTest --- .../CollisionDispatch/CollisionWorld.js | 185 +++++++++++------- 1 file changed, 119 insertions(+), 66 deletions(-) diff --git a/src/BulletCollision/CollisionDispatch/CollisionWorld.js b/src/BulletCollision/CollisionDispatch/CollisionWorld.js index 1db1532..4affa33 100644 --- a/src/BulletCollision/CollisionDispatch/CollisionWorld.js +++ b/src/BulletCollision/CollisionDispatch/CollisionWorld.js @@ -44,6 +44,7 @@ }; var tmpV1 = Bump.Vector3.create(); + var tmpV2 = Bump.Vector3.create(); // port of btCollisionWorld::RayResultCallback (stored on Bump.CollisionWorld after its // definition below @@ -241,6 +242,110 @@ } }); + // port of btCollisionWorld::SingleRayCallback, stored on + // Bump.CollisionWorld after its definition below + var SingleRayCallback = Bump.type({ + parent: Bump.BroadphaseRayCallback, + + init: function SingleRayCallback( + rayFromWorld, // const btVector3& + rayToWorld, // const btVector3& + world, // const btCollisionWorld* + resultCallback // btCollisionWorld::RayResultCallback& + ) { + this.rayFromWorld = rayFromWorld.clone(); + this.rayToWorld = rayToWorld.clone(); + this.hitNormal = Bump.Vector3.create(); + + this.world = world; + this.resultCallback = resultCallback; + + this.rayFromTrans = Bump.Transform.getIdentity(); + this.rayFromTrans.setOrigin( this.rayFromWorld ); + this.rayToTrans = Bump.Transform.getIdentity(); + this.rayToTrans.setOrigin( this.rayToWorld ); + + var rayDir = rayToWorld.subtract( rayFromWorld, tmpV1 ).normalize(); + + // what about division by zero? --> just set rayDirection[i] to INF/BT_LARGE_FLOAT + this.rayDirectionInverse = Bump.Vector3.create(); + this.signs = Bump.Vector3.create(); + this.rayDirectionInverse[ 0 ] = rayDir[ 0 ] === 0 ? Infinity : 1 / rayDir[ 0 ]; + this.rayDirectionInverse[ 1 ] = rayDir[ 1 ] === 0 ? Infinity : 1 / rayDir[ 1 ]; + this.rayDirectionInverse[ 2 ] = rayDir[ 2 ] === 0 ? Infinity : 1 / rayDir[ 2 ]; + this.signs[ 0 ] = this.rayDirectionInverse[ 0 ] < 0 ? 1 : 0; + this.signs[ 1 ] = this.rayDirectionInverse[ 1 ] < 0 ? 1 : 0; + this.signs[ 2 ] = this.rayDirectionInverse[ 2 ] < 0 ? 1 : 0; + + this.lambda_max = rayDir.dot( this.rayToWorld.subtract( this.rayFromWorld, tmpV2 )); + }, + + members: { + + // ASD: added for easy recycling without extra allocations + set: function( + rayFromWorld, // const btVector3& + rayToWorld, // const btVector3& + world, // const btCollisionWorld* + resultCallback // btCollisionWorld::RayResultCallback& + ) { + this.rayFromWorld.assign( rayFromWorld ); + this.rayToWorld.assign( rayToWorld ); + this.hitNormal.setZero(); + + this.world = world; + this.resultCallback = resultCallback; + + this.rayFromTrans.setIdentity(); + this.rayFromTrans.setOrigin( this.rayFromWorld ); + this.rayToTrans.setIdentity(); + this.rayToTrans.setOrigin( this.rayToWorld ); + + var rayDir = rayToWorld.subtract( rayFromWorld, tmpV1 ).normalize(); + + // what about division by zero? --> just set rayDirection[i] to INF/BT_LARGE_FLOAT + this.rayDirectionInverse.setZero(); + this.signs.setZero(); + this.rayDirectionInverse[ 0 ] = rayDir[ 0 ] === 0 ? Infinity : 1 / rayDir[ 0 ]; + this.rayDirectionInverse[ 1 ] = rayDir[ 1 ] === 0 ? Infinity : 1 / rayDir[ 1 ]; + this.rayDirectionInverse[ 2 ] = rayDir[ 2 ] === 0 ? Infinity : 1 / rayDir[ 2 ]; + this.signs[ 0 ] = this.rayDirectionInverse[ 0 ] < 0 ? 1 : 0; + this.signs[ 1 ] = this.rayDirectionInverse[ 1 ] < 0 ? 1 : 0; + this.signs[ 2 ] = this.rayDirectionInverse[ 2 ] < 0 ? 1 : 0; + + this.lambda_max = rayDir.dot( this.rayToWorld.subtract( this.rayFromWorld, tmpV2 )); + + return this; + }, + + process: function( proxy ) { + // terminate further ray tests, once the closestHitFraction reached zero + if ( this.resultCallback.closestHitFraction === 0 ) { + return false; + } + var collisionObject = proxy.clientObject; + + // only perform raycast if filterMask matches + if ( this.resultCallback.needsCollision( collisionObject.getBroadphaseHandle() )) { + // RigidcollisionObject* collisionObject = ctrl.GetRigidcollisionObject(); + // btVector3 collisionObjectAabbMin,collisionObjectAabbMax; + // btScalar hitLambda = this.resultCallback.closestHitFraction; + // culling already done by broadphase + // if ( btRayAabb( this.rayFromWorld, this.rayToWorld, collisionObjectAabbMin, collisionObjectAabbMax, hitLambda, this.hitNormal ) ) + this.world.rayTestSingle( + this.rayFromTrans, + this.rayToTrans, + collisionObject, + collisionObject.getCollisionShape(), + collisionObject.getWorldTransform(), + this.resultCallback + ); + } + return true; + } + } + }); + // port of btCollisionWorld::LocalRayResult, stored on // Bump.CollisionWorld after its definition below var LocalRayResult = Bump.type({ @@ -258,7 +363,17 @@ }); - // Collision World memory pools + // Collision World memory pools and temporaries + + // for rayTest + var tmpSingleRayCallback = SingleRayCallback.create( + Bump.Vector3.create(), + Bump.Vector3.create(), + undefined, + undefined + ); + + // for rayTestSingle var vector3Pool = []; var sphereShapePool = []; var voronoiPool = []; @@ -456,7 +571,7 @@ // aabb and for each object with ray-aabb overlap, perform an exact ray // test. rayTest: function( rayFromWorld, rayToWorld, resultCallback ) { - var rayCB = Bump.CollisionWorld.SingleRayCallback.create( rayFromWorld, rayToWorld, this, resultCallback ); + var rayCB = tmpSingleRayCallback.set( rayFromWorld, rayToWorld, this, resultCallback ); this.broadphasePairCache.rayTest( rayFromWorld, rayToWorld, rayCB ); }, @@ -771,70 +886,8 @@ } }); - Bump.CollisionWorld.SingleRayCallback = Bump.type({ - parent: Bump.BroadphaseRayCallback, - - init: function SingleRayCallback( - rayFromWorld, // const btVector3& - rayToWorld, // const btVector3& - world, // const btCollisionWorld* - resultCallback // btCollisionWorld::RayResultCallback& - ) { - this.rayFromWorld = rayFromWorld.clone(); - this.rayToWorld = rayToWorld.clone(); - this.hitNormal = Bump.Vector3.create(); - - this.world = world; - this.resultCallback = resultCallback; - - this.rayFromTrans = Bump.Transform.getIdentity(); - this.rayFromTrans.setOrigin( this.rayFromWorld ); - this.rayToTrans = Bump.Transform.getIdentity(); - this.rayToTrans.setOrigin( this.rayToWorld ); - - var rayDir = rayToWorld.subtract( rayFromWorld ).normalize(); - - // what about division by zero? --> just set rayDirection[i] to INF/BT_LARGE_FLOAT - this.rayDirectionInverse = Bump.Vector3.create(); - this.signs = Bump.Vector3.create(); - this.rayDirectionInverse[ 0 ] = rayDir[ 0 ] === 0 ? Infinity : 1 / rayDir[ 0 ]; - this.rayDirectionInverse[ 1 ] = rayDir[ 1 ] === 0 ? Infinity : 1 / rayDir[ 1 ]; - this.rayDirectionInverse[ 2 ] = rayDir[ 2 ] === 0 ? Infinity : 1 / rayDir[ 2 ]; - this.signs[ 0 ] = this.rayDirectionInverse[ 0 ] < 0 ? 1 : 0; - this.signs[ 1 ] = this.rayDirectionInverse[ 1 ] < 0 ? 1 : 0; - this.signs[ 2 ] = this.rayDirectionInverse[ 2 ] < 0 ? 1 : 0; - - this.lambda_max = rayDir.dot( this.rayToWorld.subtract( this.rayFromWorld )); - }, - - members: { - process: function( proxy ) { - // terminate further ray tests, once the closestHitFraction reached zero - if ( this.resultCallback.closestHitFraction === 0 ) { - return false; - } - var collisionObject = proxy.clientObject; - - // only perform raycast if filterMask matches - if ( this.resultCallback.needsCollision( collisionObject.getBroadphaseHandle() )) { - // RigidcollisionObject* collisionObject = ctrl.GetRigidcollisionObject(); - // btVector3 collisionObjectAabbMin,collisionObjectAabbMax; - // btScalar hitLambda = this.resultCallback.closestHitFraction; - // culling already done by broadphase - // if ( btRayAabb( this.rayFromWorld, this.rayToWorld, collisionObjectAabbMin, collisionObjectAabbMax, hitLambda, this.hitNormal ) ) - this.world.rayTestSingle( - this.rayFromTrans, - this.rayToTrans, - collisionObject, - collisionObject.getCollisionShape(), - collisionObject.getWorldTransform(), - this.resultCallback - ); - } - return true; - } - } - }); + // defined above for dependency reasons + Bump.CollisionWorld.SingleRayCallback = SingleRayCallback; // port of btCollisionWorld::LocalShapeInfo Bump.CollisionWorld.LocalShapeInfo = Bump.type({ From 8111a2be7630b3c215433a23f6ee9e9cc0a1a1e3 Mon Sep 17 00:00:00 2001 From: Andrew Dolce Date: Tue, 7 Aug 2012 16:35:38 -0400 Subject: [PATCH 04/22] Remove allocations from updateClosestVectorAndPoints --- .../VoronoiSimplexSolver.js | 65 ++++++++++++------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/src/BulletCollision/NarrowPhaseCollision/VoronoiSimplexSolver.js b/src/BulletCollision/NarrowPhaseCollision/VoronoiSimplexSolver.js index bf3a99e..2f6774b 100644 --- a/src/BulletCollision/NarrowPhaseCollision/VoronoiSimplexSolver.js +++ b/src/BulletCollision/NarrowPhaseCollision/VoronoiSimplexSolver.js @@ -3,6 +3,26 @@ // run: LinearMath/Vector3.js (function( window, Bump ) { + var createGetter = function( Type, pool ) { + return function() { + return pool.pop() || Type.create(); + }; + }; + + var createDeller = function( pool ) { + return function() { + for ( var i = 0; i < arguments.length; ++i ) { + pool.push( arguments[i] ); + } + }; + }; + + // memory pool for recycling Vector3 objects + var vector3Pool = []; + + var getVector3 = createGetter( Bump.Vector3, vector3Pool ); + var delVector3 = createDeller( vector3Pool ); + var VORONOI_SIMPLEX_MAX_VERTS = 5, VORONOI_DEFAULT_EQUAL_VERTEX_THRESHOLD = 0.0001, VERTA = 0, @@ -185,7 +205,12 @@ }, updateClosestVectorAndPoints: function() { - var tmpV1, tmpV2, p, a, b, c, d; + var tmpV1 = getVector3().setZero(); + var tmpV2 = getVector3().setZero(); + var tmpV3 = getVector3().setZero(); + var tmpV4 = getVector3().setZero(); + var p = getVector3().setZero(); + var a, b, c, d; if ( this.needsUpdate ) { this.cachedBC.reset(); @@ -198,11 +223,9 @@ break; case 1: - tmpV1 = Bump.Vector3.create(); - this.cachedP1.assign( this.simplexPointsP[0] ); this.cachedP2.assign( this.simplexPointsQ[0] ); - this.cachedV.assign( this.cachedP1.subtract( this.cachedP2 ) ); + this.cachedV.assign( this.cachedP1.subtract( this.cachedP2, tmpV1 )); this.cachedBC.reset(); this.cachedBC.setBarycentricCoordinates( 1, 0, 0, 0 ); this.cachedValidClosest = this.cachedBC.isValid(); @@ -210,15 +233,12 @@ // Closest point origin from line segment. case 2: - tmpV1 = Bump.Vector3.create(); - - var from = this.simplexVectorW[0], - to = this.simplexVectorW[1], - nearest = Bump.Vector3.create(); + var from = this.simplexVectorW[0]; + var to = this.simplexVectorW[1]; + // nearest = Bump.Vector3.create(); - p = Bump.Vector3.create( 0, 0, 0 ); - var diff = p.subtract( from ), - v = to.subtract( from ), + var diff = p.subtract( from, tmpV3 ), + v = to.subtract( from, tmpV4 ), t = v.dot( diff ); if ( t > 0 ) { @@ -240,7 +260,8 @@ this.cachedBC.usedVertices.usedVertexA = true; } this.cachedBC.setBarycentricCoordinates( 1 - t, t ); - nearest.assign( from.add( v.multiplyScalar( t, tmpV1 ), tmpV1 ) ); + // ASD: commented this out since it is apparently never used + // nearest.assign( from.add( v.multiplyScalar( t, tmpV1 ), tmpV1 ) ); this.cachedP1.assign( this.simplexPointsP[0].add( this.simplexPointsP[1].subtract( this.simplexPointsP[0], tmpV1 ).multiplyScalar( t, tmpV1 ), tmpV1 ) ); this.cachedP2.assign( this.simplexPointsQ[0].add( this.simplexPointsQ[1].subtract( this.simplexPointsQ[0], tmpV1 ).multiplyScalar( t, tmpV1 ), tmpV1 ) ); @@ -253,11 +274,6 @@ // Closest point origin from triangle. case 3: - tmpV1 = Bump.Vector3.create(); - tmpV2 = Bump.Vector3.create(); - - p = Bump.Vector3.create( 0, 0, 0 ); - a = this.simplexVectorW[0]; b = this.simplexVectorW[1]; c = this.simplexVectorW[2]; @@ -283,11 +299,6 @@ break; case 4: - tmpV1 = Bump.Vector3.create(); - tmpV2 = Bump.Vector3.create(); - - p = Bump.Vector3.create( 0, 0, 0 ); - a = this.simplexVectorW[0]; b = this.simplexVectorW[1]; c = this.simplexVectorW[2]; @@ -310,7 +321,7 @@ .add( this.simplexPointsQ[3].multiplyScalar( this.cachedBC.barycentricCoords[3], tmpV1 ), tmpV2 ) ); - this.cachedV.assign( this.cachedP1.subtract( this.cachedP2 ) ); + this.cachedV.assign( this.cachedP1.subtract( this.cachedP2, tmpV1 ) ); this.reduceVertices( this.cachedBC.usedVertices ); } else { // console.log( 'sub distance got penetration' ); @@ -335,6 +346,12 @@ } } + delVector3( tmpV1 ); + delVector3( tmpV2 ); + delVector3( tmpV3 ); + delVector3( tmpV4 ); + delVector3( p ); + return this.cachedValidClosest; }, From 85d24f1abaa9d8f2607b75e35920c5fe098b7b47 Mon Sep 17 00:00:00 2001 From: Andrew Dolce Date: Fri, 10 Aug 2012 10:52:27 -0400 Subject: [PATCH 05/22] Remove allocations in SphereShape --- src/BulletCollision/CollisionShapes/SphereShape.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/BulletCollision/CollisionShapes/SphereShape.js b/src/BulletCollision/CollisionShapes/SphereShape.js index fdff379..8cf040e 100644 --- a/src/BulletCollision/CollisionShapes/SphereShape.js +++ b/src/BulletCollision/CollisionShapes/SphereShape.js @@ -6,6 +6,8 @@ (function( window, Bump ) { + var tmpV1 = Bump.Vector3.create(); + Bump.SphereShape = Bump.type({ parent: Bump.ConvexInternalShape, @@ -32,12 +34,12 @@ var supVertex = dest; supVertex = this.localGetSupportingVertexWithoutMargin( vec, supVertex ); - var vecnorm = vec.clone(); + var vecnorm = vec.clone( tmpV1 ); if ( vecnorm.length2() < Bump.SIMD_EPSILON * Bump.SIMD_EPSILON ) { vecnorm.setValue( -1, -1, -1 ); } vecnorm.normalize(); - supVertex.addSelf( vecnorm.multiplyScalar( this.getMargin() ) ); + supVertex.addSelf( vecnorm.multiplyScalar( this.getMargin(), tmpV1 ) ); return supVertex; }, From 180068a61832eba9f4baacadd35520bf660f6ad2 Mon Sep 17 00:00:00 2001 From: Andrew Dolce Date: Fri, 10 Aug 2012 10:53:48 -0400 Subject: [PATCH 06/22] Remove allocation from CollisionWorld rayTestSingle Transform inverseTimes() was being called without a destination. --- .../CollisionDispatch/CollisionWorld.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/BulletCollision/CollisionDispatch/CollisionWorld.js b/src/BulletCollision/CollisionDispatch/CollisionWorld.js index 4affa33..95f667f 100644 --- a/src/BulletCollision/CollisionDispatch/CollisionWorld.js +++ b/src/BulletCollision/CollisionDispatch/CollisionWorld.js @@ -375,6 +375,7 @@ // for rayTestSingle var vector3Pool = []; + var transformPool = []; var sphereShapePool = []; var voronoiPool = []; var convexCastPool = []; @@ -384,6 +385,7 @@ var rayTesterPool = []; var getVector3 = createGetter( Bump.Vector3, vector3Pool ); + var getTransform = createGetter( Bump.Transform, transformPool ); var getSphereShape = createGetter( Bump.SphereShape, sphereShapePool, [ 0.0 ] ); var getVoronoiSimplexSolver = createGetter( Bump.VoronoiSimplexSolver, voronoiPool ); var getSubsimplexConvexCast = createGetter( Bump.SubsimplexConvexCast, convexCastPool ); @@ -413,6 +415,7 @@ ]); var delVector3 = createDeller( vector3Pool ); + var delTransform = createDeller( transformPool ); var delSphereShape = createDeller( sphereShapePool ); var delVoronoiSimplexSolver = createDeller( voronoiPool ); var delSubsimplexConvexCast = createDeller( convexCastPool ); @@ -573,7 +576,7 @@ rayTest: function( rayFromWorld, rayToWorld, resultCallback ) { var rayCB = tmpSingleRayCallback.set( rayFromWorld, rayToWorld, this, resultCallback ); - this.broadphasePairCache.rayTest( rayFromWorld, rayToWorld, rayCB ); + this.broadphasePairCache.rayTest( rayFromWorld, rayToWorld, rayCB, tmpV1, tmpV2 ); }, // Use the broadphase to accelerate the search for objects, based on their @@ -716,6 +719,7 @@ // so allocations could be moved to where they are needed var tmpVec1 = getVector3(); var tmpVec2 = getVector3(); + var tmpTrans = getTransform(); var tmpSS = getSphereShape(); var tmpCR = getCastResult(); var tmpVSS = getVoronoiSimplexSolver(); @@ -856,10 +860,10 @@ if ( dbvt ) { var localRayFrom = colObjWorldTransform - .inverseTimes( rayFromTrans ) + .inverseTimes( rayFromTrans, tmpTrans ) .getOrigin().clone( tmpVec1 ); var localRayTo = colObjWorldTransform - .inverseTimes( rayToTrans ) + .inverseTimes( rayToTrans, tmpTrans ) .getOrigin().clone( tmpVec2 ); Bump.Dbvt.rayTest( dbvt.root, localRayFrom, localRayTo, rayCB ); } else { @@ -875,6 +879,7 @@ // free temporaries delVector3( tmpVec1 ); delVector3( tmpVec2 ); + delTransform( tmpTrans ); delSphereShape( tmpSS ); delCastResult( tmpCR ); delVoronoiSimplexSolver( tmpVSS ); From 7a3c223a319ef980127dc483b50494a388cf4074 Mon Sep 17 00:00:00 2001 From: Andrew Dolce Date: Fri, 10 Aug 2012 10:55:53 -0400 Subject: [PATCH 07/22] Remove allocation in DbvtBroadphase rayTest --- src/BulletCollision/BroadphaseCollision/DbvtBroadphase.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/BulletCollision/BroadphaseCollision/DbvtBroadphase.js b/src/BulletCollision/BroadphaseCollision/DbvtBroadphase.js index daad35d..6478d7e 100644 --- a/src/BulletCollision/BroadphaseCollision/DbvtBroadphase.js +++ b/src/BulletCollision/BroadphaseCollision/DbvtBroadphase.js @@ -122,6 +122,8 @@ } }); + var tmpBroadphaseRayTester = Bump.BroadphaseRayTester.create(); + Bump.DbvtBroadphase = Bump.type({ parent: Bump.BroadphaseInterface, @@ -359,7 +361,9 @@ aabbMin = aabbMin || Bump.Vector3.create(); aabbMax = aabbMin || Bump.Vector3.create(); - var callback = Bump.BroadphaseRayTester.create( rayCallback ); + //var callback = Bump.BroadphaseRayTester.create( rayCallback ); + var callback = tmpBroadphaseRayTester; + callback.init( rayCallback ); this.sets[0].rayTestInternal( this.sets[0].root, From 54fdaf47496bc334d865e56a1ee1d4ad2f695292 Mon Sep 17 00:00:00 2001 From: Andrew Dolce Date: Fri, 10 Aug 2012 10:59:07 -0400 Subject: [PATCH 08/22] Remove allocations from VoronoiSimplexSolver Removed allocations in closestPtPointTetrahedron and pointOutsideOfPlane. Also removed a pointless conditional from closestPtPointTetrahedron. --- .../VoronoiSimplexSolver.js | 76 ++++++++++++++----- 1 file changed, 56 insertions(+), 20 deletions(-) diff --git a/src/BulletCollision/NarrowPhaseCollision/VoronoiSimplexSolver.js b/src/BulletCollision/NarrowPhaseCollision/VoronoiSimplexSolver.js index 2f6774b..bf09572 100644 --- a/src/BulletCollision/NarrowPhaseCollision/VoronoiSimplexSolver.js +++ b/src/BulletCollision/NarrowPhaseCollision/VoronoiSimplexSolver.js @@ -125,6 +125,7 @@ this.degenerate = false; this.setBarycentricCoordinates(); this.usedVertices.reset(); + return this; }, isValid: function() { @@ -150,6 +151,17 @@ } }); + + // memory pool for recycling SubSimplexClosestResult objects + var subSimplexClosestResultPool = []; + + var getSubSimplexClosestResult = createGetter( + Bump.SubSimplexClosestResult, + subSimplexClosestResultPool + ); + var delSubSimplexClosestResult = createDeller( subSimplexClosestResultPool ); + + Bump.VoronoiSimplexSolver = Bump.type({ init: function VoronoiSimplexSolver() { this.numVertices = 0; @@ -357,11 +369,11 @@ }, closestPtPointTetrahedron: function( p, a, b, c, d, finalResult ) { - var tempResult = Bump.SubSimplexClosestResult.create(); - // Start out assuming point inside all halfspaces, so closest to itself. finalResult.closestPointOnSimplex.assign( p ); - finalResult.usedVertices.reset(); + // ASD: removed reset() since this is immediately undone by setting + // all the usedVertex values to true + // finalResult.usedVertices.reset(); finalResult.usedVertices.usedVertexA = true; finalResult.usedVertices.usedVertexB = true; finalResult.usedVertices.usedVertexC = true; @@ -381,9 +393,11 @@ return false; } - var tmpV1 = Bump.Vector3.create(), - tmpV2 = Bump.Vector3.create(), - tmpV3 = Bump.Vector3.create(); + // get some recycled temporaries + var tempResult = getSubSimplexClosestResult().reset(); + var tmpV1 = getVector3().setZero(); + var tmpV2 = getVector3().setZero(); + var tmpV3 = getVector3().setZero(); var q, sqDist, bestSqDist = Infinity; // If point outside face abc then compute closest point on abc @@ -470,7 +484,7 @@ q = tempResult.closestPointOnSimplex.clone( tmpV1 ); // Convert result bitmask! - sqDist = q.subtract( p ).dot( q.subtract( p ) ); + sqDist = q.subtract( p, tmpV2 ).dot( q.subtract( p, tmpV3 ) ); if ( sqDist < bestSqDist ) { bestSqDist = sqDist; finalResult.closestPointOnSimplex.assign( q ); @@ -490,21 +504,26 @@ } } + // ASD: commented out because unnecessary // Help! We ended up full! - if ( finalResult.usedVertices.usedVertexA && - finalResult.usedVertices.usedVertexB && - finalResult.usedVertices.usedVertexC && - finalResult.usedVertices.usedVertexD ) - { - return true; - } + // if ( finalResult.usedVertices.usedVertexA && + // finalResult.usedVertices.usedVertexB && + // finalResult.usedVertices.usedVertexC && + // finalResult.usedVertices.usedVertexD ) + // { + // return true; + // } + + // deallocate the temporaries + delSubSimplexClosestResult( tempResult ); + delVector3( tmpV1, tmpV2, tmpV3 ); return true; }, pointOutsideOfPlane: function( p, a, b, c, d ) { - var tmpV1 = Bump.Vector3.create(), - tmpV2 = Bump.Vector3.create(); + var tmpV1 = getVector3(); + var tmpV2 = getVector3(); // `normal` uses `tmpV2`. var normal = b.subtract( a, tmpV1 ).cross( c.subtract( a, tmpV2 ), tmpV2 ); @@ -512,6 +531,8 @@ var signp = p.subtract( a, tmpV1 ).dot( normal ), // [AP AB AC] signd = d.subtract( a, tmpV1 ).dot( normal ); // [AD AB AC] + delVector3( tmpV1, tmpV2 ); + if ( signd * signd < ( 1e-8 * 1e-8 ) ) { return -1; } @@ -524,9 +545,13 @@ result.usedVertices.reset(); - var tmpV1 = Bump.Vector3.create(), - ab = b.subtract( a ), - ac = c.subtract( a ); + var tmpV1 = getVector3(); + var tmpV2 = getVector3(); + var tmpVab = getVector3(); + var tmpVac = getVector3(); + + var ab = b.subtract( a, tmpVab ); + var ac = c.subtract( a, tmpVac ); // Check if P in vertex region outside A. var ap = p.subtract( a, tmpV1 ), @@ -536,6 +561,8 @@ result.closestPointOnSimplex.assign( a ); result.usedVertices.usedVertexA = true; result.setBarycentricCoordinates( 1, 0, 0 ); + + delVector3( tmpV1, tmpV2, tmpVab, tmpVac ); return true; } @@ -548,6 +575,7 @@ result.usedVertices.usedVertexB = true; result.setBarycentricCoordinates( 0, 1, 0 ); + delVector3( tmpV1, tmpV2, tmpVab, tmpVac ); return true; } @@ -562,6 +590,8 @@ result.usedVertices.usedVertexA = true; result.usedVertices.usedVertexB = true; result.setBarycentricCoordinates( 1 - v, v, 0 ); + + delVector3( tmpV1, tmpV2, tmpVab, tmpVac ); return true; } @@ -573,6 +603,8 @@ result.closestPointOnSimplex.assign( c ); result.usedVertices.usedVertexC = true; result.setBarycentricCoordinates( 0, 0, 1 ); + + delVector3( tmpV1, tmpV2, tmpVab, tmpVac ); return true; } @@ -585,6 +617,8 @@ result.usedVertices.usedVertexA = true; result.usedVertices.usedVertexC = true; result.setBarycentricCoordinates( 1 - w, 0, w ); + + delVector3( tmpV1, tmpV2, tmpVab, tmpVac ); return true; } @@ -602,6 +636,8 @@ result.usedVertices.usedVertexB = true; result.usedVertices.usedVertexC = true; result.setBarycentricCoordinates( 0, 1 - w, w ); + + delVector3( tmpV1, tmpV2, tmpVab, tmpVac ); return true; } @@ -611,7 +647,6 @@ v = vb * denom; w = vc * denom; - var tmpV2 = Bump.Vector3.create(); result.closestPointOnSimplex.assign( a .add( ab.multiplyScalar( v, tmpV2 ), tmpV1 ) @@ -622,6 +657,7 @@ result.usedVertices.usedVertexC = true; result.setBarycentricCoordinates( 1 - v - w, v, w ); + delVector3( tmpV1, tmpV2, tmpVab, tmpVac ); return true; }, From 7d6147a5a64bbf274f46b441b6ee063b1b0a13a2 Mon Sep 17 00:00:00 2001 From: Andrew Dolce Date: Fri, 10 Aug 2012 11:07:34 -0400 Subject: [PATCH 09/22] Remove allocations from SubsimplexConvexCast --- .../SubSimplexConvexCast.js | 50 +++++++++++-------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/src/BulletCollision/NarrowPhaseCollision/SubSimplexConvexCast.js b/src/BulletCollision/NarrowPhaseCollision/SubSimplexConvexCast.js index 68daf99..101f441 100644 --- a/src/BulletCollision/NarrowPhaseCollision/SubSimplexConvexCast.js +++ b/src/BulletCollision/NarrowPhaseCollision/SubSimplexConvexCast.js @@ -1,17 +1,26 @@ // load: bump.js // load: BulletCollision/NarrowPhaseCollision/ConvexCast.js +// load: LinearMath/Vector3.js +// load: LinearMath/Transform.js -// run: LinearMath/Vector3.js -// run: LinearMath/Transform.js // run: BulletCollision/CollisionShapes/ConvexShape.js (function( window, Bump ) { - var MAX_ITERATIONS = 64; - var tmpV1 = Bump.Vector3.create(); var tmpV2 = Bump.Vector3.create(); - var tmpV3 = Bump.Vector3.create(); + + var tmpTITA = Bump.Transform.getIdentity(); + var tmpTITB = Bump.Transform.getIdentity(); + + var tmpVr = Bump.Vector3.create(); + var tmpVSVA = Bump.Vector3.create(); + var tmpVSVB = Bump.Vector3.create(); + var tmpVv = Bump.Vector3.create(); + var tmpVn = Bump.Vector3.create(); + var tmpVw = Bump.Vector3.create(); + + var MAX_ITERATIONS = 64; Bump.SubsimplexConvexCast = Bump.type({ parent: Bump.ConvexCast, @@ -34,19 +43,18 @@ toB, // Bump.Transform result // CastResult ) { - this.simplexSolver.reset(); - var linVelA = toA.getOrigin().subtract( fromA.getOrigin() ); - var linVelB = toB.getOrigin().subtract( fromB.getOrigin() ); + var linVelA = toA.getOrigin().subtract( fromA.getOrigin(), tmpV1 ); + var linVelB = toB.getOrigin().subtract( fromB.getOrigin(), tmpV2 ); var lambda = 0; - var interpolatedTransA = fromA.clone(); - var interpolatedTransB = fromB.clone(); + var interpolatedTransA = fromA.clone( tmpTITA ); + var interpolatedTransB = fromB.clone( tmpTITB ); // take relative motion - var r = linVelA.subtract( linVelB ); + var r = linVelA.subtract( linVelB, tmpVr ); var v; var supVertexA = fromA.transform( @@ -54,7 +62,7 @@ fromA.getBasis().vectorMultiply( r.negate( tmpV1 ), tmpV1 ), tmpV1 ), - tmpV1 + tmpVSVA ); var supVertexB = fromB.transform( @@ -62,16 +70,16 @@ fromB.getBasis().vectorMultiply( r, tmpV2 ), tmpV2 ), - tmpV2 + tmpVSVB ); - v = supVertexA.subtract( supVertexB ); + v = supVertexA.subtract( supVertexB, tmpVv ); var maxIter = MAX_ITERATIONS; - var n = Bump.Vector3.create(); + var n = tmpVn.setZero(); // n.setValue( 0, 0, 0 ); var hasResult = false; - var c = Bump.Vector3.create(); + // var c = tmpVc.setZero(); // ASD: not used? var lastLambda = lambda; @@ -82,8 +90,8 @@ // #else // btScalar epsilon = btScalar(0.0001); // #endif //BT_USE_DOUBLE_PRECISION - var w = Bump.Vector3.create(); - var p = Bump.Vector3.create(); + var w = tmpVw.setZero(); + // var p = tmpVp.setZero(); // ASD: not used? var VdotR; while ( ( dist2 > epsilon ) && maxIter-- ) { @@ -92,14 +100,14 @@ interpolatedTransA.getBasis().vectorMultiply( v.negate( tmpV1 ), tmpV1 ), tmpV1 ), - tmpV1 + tmpVSVA ); supVertexB = interpolatedTransB.transform( this.convexB.localGetSupportingVertex( interpolatedTransB.getBasis().vectorMultiply( v, tmpV2 ), tmpV2 ), - tmpV2 + tmpVSVB ); supVertexA.subtract( supVertexB, w ); @@ -172,7 +180,7 @@ // var hitB = Bump.Vector3.create(); // this.simplexSolver.compute_points( hitA, hitB ); // result.hitPoint = hitB; - this.simplexSolver.compute_points( tmpV3, result.hitPoint ); + this.simplexSolver.compute_points( tmpV1, result.hitPoint ); return true; } From 9e557ca1e53c3ded493987c292d6a230d2735445 Mon Sep 17 00:00:00 2001 From: Andrew Dolce Date: Fri, 10 Aug 2012 15:24:08 -0400 Subject: [PATCH 10/22] Remove allocations from Dbvt rayTest Recycle Vector3 and array objects. The `stack` array is handled as a special case with its own memory pool. This is because the stack array needs to be resized and could end up being large. By recycling it and only resizing when we need the length to increase, we can make it so that the resize only happens a finite number of times, until there exist arrays of sufficient length for all future ray tests. --- .../BroadphaseCollision/Dbvt.js | 85 +++++++++++++++---- 1 file changed, 70 insertions(+), 15 deletions(-) diff --git a/src/BulletCollision/BroadphaseCollision/Dbvt.js b/src/BulletCollision/BroadphaseCollision/Dbvt.js index 69bc202..3d1425f 100644 --- a/src/BulletCollision/BroadphaseCollision/Dbvt.js +++ b/src/BulletCollision/BroadphaseCollision/Dbvt.js @@ -10,6 +10,46 @@ (function( window, Bump ) { + var createGetter = function( Type, pool ) { + return function() { + return pool.pop() || Type.create(); + }; + }; + + var createDeller = function( pool ) { + return function() { + for ( var i = 0; i < arguments.length; ++i ) { + pool.push( arguments[i] ); + } + }; + }; + + // memory pool for recycling Vector3 objects + var vector3Pool = []; + + var getVector3 = createGetter( Bump.Vector3, vector3Pool ); + var delVector3 = createDeller( vector3Pool ); + + // memory pool for recycling arrays + var arrayPool = []; + + var getArray = function() { + return arrayPool.pop() || []; + }; + var delArray = function( arr ) { + arr.length = 0; + arrayPool.push( arr ); + }; + + // memory pool for recycling arrays for the rayTest function + var rayTestStackPool = []; + var getRayTestStackArray = function( length ) { + return rayTestStackPool.pop() || new Array( length ); + }; + var delRayTestStackArray = function( arr ) { + rayTestStackPool.push( arr ); + }; + // Used in collideTV var tmpCTVVol1; @@ -1204,35 +1244,45 @@ rayTest: function( root, rayFrom, rayTo, policy ) { if ( root ) { - var diff = rayTo.subtract( rayFrom ), - rayDir = diff.normalized(); + var tmpV1 = getVector3(); + var tmpV2 = getVector3(); + var tmpV3 = getVector3(); + var tmpV4 = getVector3(); + var tmpV5 = getVector3(); + + var diff = rayTo.subtract( rayFrom, tmpV1 ), + rayDir = diff.normalized( tmpV2 ); - var rayDirectionInverse = Bump.Vector3.create( + var rayDirectionInverse = tmpV3.setValue( rayDir.x === 0 ? Infinity : 1 / rayDir.x, rayDir.y === 0 ? Infinity : 1 / rayDir.y, rayDir.z === 0 ? Infinity : 1 / rayDir.z ); - var signs = [ - rayDirectionInverse.x < 0 ? 1 : 0, - rayDirectionInverse.y < 0 ? 1 : 0, - rayDirectionInverse.z < 0 ? 1 : 0 - ]; + var signs = getArray(); + signs[ 0 ] = rayDirectionInverse.x < 0 ? 1 : 0; + signs[ 1 ] = rayDirectionInverse.y < 0 ? 1 : 0; + signs[ 2 ] = rayDirectionInverse.z < 0 ? 1 : 0; + var lambda_max = rayDir.dot( diff ); var resultNormal; - var stack = []; + var stack = getRayTestStackArray( Bump.Dbvt.DOUBLE_STACKSIZE ); + // note that it is possible that stack's length is greater than the + // requested size, if it has been recycled from a previous call + var depth = 1; - var threshold = Bump.Dbvt.DOUBLE_STACKSIZE - 2; + var threshold = stack.length - 2; - stack[ Bump.Dbvt.DOUBLE_STACKSIZE - 1 ] = undefined; stack[ 0 ] = root; - var bounds = [ Bump.Vector3.create(), Bump.Vector3.create() ]; + var bounds = getArray(); + bounds[ 0 ] = tmpV4; + bounds[ 1 ] = tmpV5; do { var node = stack[ --depth ]; - bounds[ 0 ] = node.volume.Mins(); - bounds[ 1 ] = node.volume.Maxs(); + bounds[ 0 ].assign( node.volume.Mins() ); + bounds[ 1 ].assign( node.volume.Maxs() ); var tmin = { tmin: 1 }, lambda_min = 0, @@ -1241,7 +1291,8 @@ if ( result1 ) { if ( node.isinternal() ) { if ( depth > threshold ) { - stack[ stack.length * 2 - 1] = undefined; + // if we are resizing, just discard the old array + Bump.resize( stack, stack.length * 2 ); threshold = stack.length - 2; } stack[ depth++ ] = node.childs[ 0 ]; @@ -1252,6 +1303,9 @@ } } } while ( depth ); + + delVector3( tmpV1, tmpV2, tmpV3, tmpV4, tmpV5 ); + delRayTestStackArray( stack ); } }, @@ -1583,3 +1637,4 @@ sStkNNZero = Bump.Dbvt.sStkNN.create(); })( this, this.Bump ); + \ No newline at end of file From 109c34e46de541522519c4b3b76d5070c5fd8dae Mon Sep 17 00:00:00 2001 From: "Michael \"Z\" Goddard" Date: Fri, 10 Aug 2012 13:37:41 -0400 Subject: [PATCH 11/22] mempool LocalAddrInfo2 for RayTester add LocalAddrInfo2.set to set values of objects acquired from mempool. --- .../CollisionDispatch/CollisionWorld.js | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/BulletCollision/CollisionDispatch/CollisionWorld.js b/src/BulletCollision/CollisionDispatch/CollisionWorld.js index 95f667f..87ec090 100644 --- a/src/BulletCollision/CollisionDispatch/CollisionWorld.js +++ b/src/BulletCollision/CollisionDispatch/CollisionWorld.js @@ -145,6 +145,16 @@ }, members: { + set: function( + i, + user + ) { + this.userCallback = user; + this.i = i; + this.closestHitFraction = this.userCallback.closestHitFraction; + return this; + }, + needsCollision: function( p // Bump.BroadphaseProxy ) { @@ -215,13 +225,14 @@ Process: function( i ) { var childCollisionShape = this.compoundShape.getChildShape( i ); var childTrans = this.compoundShape.getChildTransform( i ); - var childWorldTrans = this.colObjWorldTransform.multiplyTransform( childTrans ); + var childWorldTrans = this.colObjWorldTransform.multiplyTransform( childTrans, getTransform() ); // replace collision shape so that callback can determine the triangle var saveCollisionShape = this.collisionObject.getCollisionShape(); this.collisionObject.internalSetTemporaryCollisionShape( childCollisionShape ); - var my_cb = LocalInfoAdder2.create( i, this.resultCallback ); + // var my_cb = LocalInfoAdder2.create( i, this.resultCallback ); + var my_cb = getLocalAddrInfo2().set( i, this.resultCallback ); Bump.CollisionWorld.rayTestSingle( this.rayFromTrans, @@ -234,6 +245,9 @@ // restore this.collisionObject.internalSetTemporaryCollisionShape( saveCollisionShape ); + + delTransform( childWorldTrans ); + delLocalAddrInfo2( my_cb ); }, ProcessNode: function( leaf ) { @@ -383,6 +397,7 @@ var localRayResultPool = []; var bridgeTriangleRCBPool = []; var rayTesterPool = []; + var localAddrInfo2Pool = []; var getVector3 = createGetter( Bump.Vector3, vector3Pool ); var getTransform = createGetter( Bump.Transform, transformPool ); @@ -414,6 +429,13 @@ undefined ]); + var getLocalAddrInfo2 = createGetter( LocalInfoAdder2, localAddrInfo2Pool, [ + undefined, + { + closestHitFraction: 0 + } + ] ); + var delVector3 = createDeller( vector3Pool ); var delTransform = createDeller( transformPool ); var delSphereShape = createDeller( sphereShapePool ); @@ -423,6 +445,7 @@ var delLocalRayResult = createDeller( localRayResultPool ); var delBridgeTriangleRaycastCallback = createDeller( bridgeTriangleRCBPool ); var delRayTester = createDeller( rayTesterPool ); + var delLocalAddrInfo2 = createDeller( localAddrInfo2Pool ); // used to reinitialize a SphereShape in rayTestSingle var emptySphereShape = Bump.SphereShape.create( 0.0 ); From 2cdfe6f8f0da9b8013f04b7522b925bfb8288398 Mon Sep 17 00:00:00 2001 From: "Michael \"Z\" Goddard" Date: Fri, 10 Aug 2012 14:01:20 -0400 Subject: [PATCH 12/22] mempool Vector3 handling in Dbvt.rayTest add delArray to Dbvt.rayCast remove tmpV4 and tmpV5. Bounds isn't edited in RayAabb2 so we don't need them. --- src/BulletCollision/BroadphaseCollision/Dbvt.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/BulletCollision/BroadphaseCollision/Dbvt.js b/src/BulletCollision/BroadphaseCollision/Dbvt.js index 3d1425f..31a1b16 100644 --- a/src/BulletCollision/BroadphaseCollision/Dbvt.js +++ b/src/BulletCollision/BroadphaseCollision/Dbvt.js @@ -1247,8 +1247,6 @@ var tmpV1 = getVector3(); var tmpV2 = getVector3(); var tmpV3 = getVector3(); - var tmpV4 = getVector3(); - var tmpV5 = getVector3(); var diff = rayTo.subtract( rayFrom, tmpV1 ), rayDir = diff.normalized( tmpV2 ); @@ -1276,13 +1274,11 @@ stack[ 0 ] = root; var bounds = getArray(); - bounds[ 0 ] = tmpV4; - bounds[ 1 ] = tmpV5; do { var node = stack[ --depth ]; - bounds[ 0 ].assign( node.volume.Mins() ); - bounds[ 1 ].assign( node.volume.Maxs() ); + bounds[ 0 ] = node.volume.Mins(); + bounds[ 1 ] = node.volume.Maxs(); var tmin = { tmin: 1 }, lambda_min = 0, @@ -1306,6 +1302,7 @@ delVector3( tmpV1, tmpV2, tmpV3, tmpV4, tmpV5 ); delRayTestStackArray( stack ); + delArray( signs, bounds ); } }, From 3108c4a3d589435c5d470cc6b7faabd9e71edd85 Mon Sep 17 00:00:00 2001 From: "Michael \"Z\" Goddard" Date: Fri, 10 Aug 2012 14:10:40 -0400 Subject: [PATCH 13/22] mempool Vector3 in Dbvt.rayTestInternal --- src/BulletCollision/BroadphaseCollision/Dbvt.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/BulletCollision/BroadphaseCollision/Dbvt.js b/src/BulletCollision/BroadphaseCollision/Dbvt.js index 31a1b16..f6de2ad 100644 --- a/src/BulletCollision/BroadphaseCollision/Dbvt.js +++ b/src/BulletCollision/BroadphaseCollision/Dbvt.js @@ -1152,12 +1152,13 @@ policy ) { if ( root ) { - var resultNormal = Bump.Vector3.create(); + // not used + // var resultNormal = Bump.Vector3.create(); var depth = 1, threshold = Bump.Dbvt.DOUBLE_STACKSIZE - 2, stack = this.rayTestStack, - bounds = [ Bump.Vector3.create(), Bump.Vector3.create() ]; + bounds = [ getVector3(), getVector3() ]; Bump.resize( stack, Bump.Dbvt.DOUBLE_STACKSIZE, undefined ); stack[ 0 ] = root; do { @@ -1185,6 +1186,7 @@ } } while ( depth ); + delVector3( bounds[ 0 ], bounds[ 1 ] ) } } @@ -1634,4 +1636,4 @@ sStkNNZero = Bump.Dbvt.sStkNN.create(); })( this, this.Bump ); - \ No newline at end of file + From d0c7675488ecee77103cd4081315dde25ad62641 Mon Sep 17 00:00:00 2001 From: Eric Li Date: Mon, 13 Aug 2012 14:20:24 -0400 Subject: [PATCH 14/22] Make tmin reference in RayAabb2 consistent Change object to be of the form { "value": 0 } instead of { "tmin": 0 } to be consistent with other uses of scalar references in the port. --- src/BulletCollision/BroadphaseCollision/Dbvt.js | 4 ++-- src/LinearMath/AabbUtil2.js | 16 ++++++++-------- tests/unit/LinearMath/test.AabbUtil2.js | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/BulletCollision/BroadphaseCollision/Dbvt.js b/src/BulletCollision/BroadphaseCollision/Dbvt.js index f6de2ad..5daabe5 100644 --- a/src/BulletCollision/BroadphaseCollision/Dbvt.js +++ b/src/BulletCollision/BroadphaseCollision/Dbvt.js @@ -1165,7 +1165,7 @@ var node = stack[ --depth ]; node.volume.Mins().subtract( aabbMax, bounds[ 0 ] ); node.volume.Maxs().subtract( aabbMin, bounds[ 1 ] ); - var tmin = { tmin: 1 }, // primitive "passed by reference" + var tmin = { value: 1 }, // primitive "passed by reference" lambda_min = 0, result1 = false; result1 = Bump.RayAabb2( rayFrom, rayDirectionInverse, signs, bounds, @@ -1282,7 +1282,7 @@ bounds[ 0 ] = node.volume.Mins(); bounds[ 1 ] = node.volume.Maxs(); - var tmin = { tmin: 1 }, + var tmin = { value: 1 }, lambda_min = 0, result1 = Bump.RayAabb2( rayFrom, rayDirectionInverse, signs, bounds, tmin, lambda_min, lambda_max ); diff --git a/src/LinearMath/AabbUtil2.js b/src/LinearMath/AabbUtil2.js index 0956702..2ed8adc 100644 --- a/src/LinearMath/AabbUtil2.js +++ b/src/LinearMath/AabbUtil2.js @@ -66,17 +66,17 @@ AabbUtil2.RayAabb2 = function( rayFrom, rayInvDirection, raySign, bounds, tmin, lambda_min, lambda_max ) { var tmax, tymin, tymax, tzmin, tzmax; - tmin.tmin = ( bounds[ raySign[0] ].x - rayFrom.x ) * rayInvDirection.x; + tmin.value = ( bounds[ raySign[0] ].x - rayFrom.x ) * rayInvDirection.x; tmax = ( bounds[ 1 - raySign[0] ].x - rayFrom.x ) * rayInvDirection.x; tymin = ( bounds[ raySign[1] ].y - rayFrom.y ) * rayInvDirection.y; tymax = ( bounds[ 1 - raySign[1] ].y - rayFrom.y ) * rayInvDirection.y; - if ( ( tmin.tmin > tymax ) || ( tymin > tmax ) ) { + if ( ( tmin.value > tymax ) || ( tymin > tmax ) ) { return false; } - if ( tymin > tmin.tmin ) { - tmin.tmin = tymin; + if ( tymin > tmin.value ) { + tmin.value = tymin; } if ( tymax < tmax ) { @@ -86,19 +86,19 @@ tzmin = ( bounds[ raySign[2] ].z - rayFrom.z ) * rayInvDirection.z; tzmax = ( bounds[ 1 - raySign[2] ].z - rayFrom.z ) * rayInvDirection.z; - if ( ( tmin.tmin > tzmax ) || ( tzmin > tmax ) ) { + if ( ( tmin.value > tzmax ) || ( tzmin > tmax ) ) { return false; } - if ( tzmin > tmin.tmin ) { - tmin.tmin = tzmin; + if ( tzmin > tmin.value ) { + tmin.value = tzmin; } if ( tzmax < tmax ) { tmax = tzmax; } - return ( ( tmin.tmin < lambda_max ) && ( tmax > lambda_min ) ); + return ( tmin.value < lambda_max ) && ( tmax > lambda_min ); }; AabbUtil2.RayAabb = function( rayFrom, rayTo, aabbMin, aabbMax, param, normal ) { diff --git a/tests/unit/LinearMath/test.AabbUtil2.js b/tests/unit/LinearMath/test.AabbUtil2.js index 133f748..61fb691 100644 --- a/tests/unit/LinearMath/test.AabbUtil2.js +++ b/tests/unit/LinearMath/test.AabbUtil2.js @@ -151,7 +151,7 @@ test( 'basic', function() { testFunc( Bump, 'RayAabb2', { isStaticFunc: true, args: [ - [ rayStart, rayInvDir, signs, bounds, { param: tMin, expected: { tmin: 0 } }, 0, 1 ] + [ rayStart, rayInvDir, signs, bounds, { param: tMin, expected: { value: 0 } }, 0, 1 ] ], expected: [ false From b667edd04f81651c67807126cc7c99d64b2422aa Mon Sep 17 00:00:00 2001 From: Eric Li Date: Mon, 13 Aug 2012 14:45:28 -0400 Subject: [PATCH 15/22] Remove allocations in Dbvt.js List of allocations removed: - array in rayTestInternal - scalar reference in rayTestInternal - scalar reference in rayTest - scalar reference in maxdepth --- .../BroadphaseCollision/Dbvt.js | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/src/BulletCollision/BroadphaseCollision/Dbvt.js b/src/BulletCollision/BroadphaseCollision/Dbvt.js index 5daabe5..f3b4b8d 100644 --- a/src/BulletCollision/BroadphaseCollision/Dbvt.js +++ b/src/BulletCollision/BroadphaseCollision/Dbvt.js @@ -50,6 +50,18 @@ rayTestStackPool.push( arr ); }; + var scalarRefPool = []; + var getScalarRef = function( init ) { + var ref = scalarRefPool.pop(); + if ( ref ) { + ref.value = init; + return ref; + } + + return { value: init }; + }; + var delScalarRef = createDeller( scalarRefPool ); + // Used in collideTV var tmpCTVVol1; @@ -1158,14 +1170,17 @@ var depth = 1, threshold = Bump.Dbvt.DOUBLE_STACKSIZE - 2, stack = this.rayTestStack, - bounds = [ getVector3(), getVector3() ]; + bounds = getArray(); + bounds[ 0 ] = getVector3(); + bounds[ 1 ] = getVector3(); + Bump.resize( stack, Bump.Dbvt.DOUBLE_STACKSIZE, undefined ); stack[ 0 ] = root; do { var node = stack[ --depth ]; node.volume.Mins().subtract( aabbMax, bounds[ 0 ] ); node.volume.Maxs().subtract( aabbMin, bounds[ 1 ] ); - var tmin = { value: 1 }, // primitive "passed by reference" + var tmin = getScalarRef( 1 ), // primitive "passed by reference" lambda_min = 0, result1 = false; result1 = Bump.RayAabb2( rayFrom, rayDirectionInverse, signs, bounds, @@ -1184,9 +1199,12 @@ policy.ProcessNode( node ); } } + + delScalarRef( tmin ); } while ( depth ); - delVector3( bounds[ 0 ], bounds[ 1 ] ) + delVector3( bounds[ 0 ], bounds[ 1 ] ); + delArray( bounds ); } } @@ -1194,10 +1212,14 @@ typeMembers: { maxdepth: function( node ) { - var depth = { value: 0 }; + var depth = getScalarRef( 0 ); if ( node ) { getmaxdepth( node, 1, depth ); } + + // !!!: if delScalarRef changes the value of depth, then + // return value should be saved and then returned. + delScalarRef( depth ); return depth.value; }, @@ -1276,13 +1298,15 @@ stack[ 0 ] = root; var bounds = getArray(); + bounds[ 0 ] = getVector3(); + bounds[ 1 ] = getVector3(); do { var node = stack[ --depth ]; - bounds[ 0 ] = node.volume.Mins(); - bounds[ 1 ] = node.volume.Maxs(); + bounds[ 0 ].assign( node.volume.Mins() ); + bounds[ 1 ].assign( node.volume.Maxs() ); - var tmin = { value: 1 }, + var tmin = getScalarRef( 1 ), lambda_min = 0, result1 = Bump.RayAabb2( rayFrom, rayDirectionInverse, signs, bounds, tmin, lambda_min, lambda_max ); @@ -1300,9 +1324,11 @@ policy.ProcessNode( node ); } } + + delScalarRef( tmin ); } while ( depth ); - delVector3( tmpV1, tmpV2, tmpV3, tmpV4, tmpV5 ); + delVector3( tmpV1, tmpV2, tmpV3, bounds[0], bounds[1] ); delRayTestStackArray( stack ); delArray( signs, bounds ); } From 5e6be76bcd0348e256714af73090e1ea72735eca Mon Sep 17 00:00:00 2001 From: Eric Li Date: Mon, 13 Aug 2012 15:18:51 -0400 Subject: [PATCH 16/22] WS: Whitespace and formatting in Dbvt.js --- .../BroadphaseCollision/Dbvt.js | 377 +++++++++--------- 1 file changed, 190 insertions(+), 187 deletions(-) diff --git a/src/BulletCollision/BroadphaseCollision/Dbvt.js b/src/BulletCollision/BroadphaseCollision/Dbvt.js index f3b4b8d..166d099 100644 --- a/src/BulletCollision/BroadphaseCollision/Dbvt.js +++ b/src/BulletCollision/BroadphaseCollision/Dbvt.js @@ -156,34 +156,34 @@ SignedExpand: function( e ) { if ( e.x > 0 ) { this.mx.x += e.x; - } - else{ + } else { this.mi.x += e.x; } + if ( e.y > 0 ) { this.mx.y += e.y; - } - else{ + } else { this.mi.y += e.y; } + if ( e.z > 0 ) { this.mx.z += e.z; - } - else{ + } else { this.mi.z += e.z; } + return this; }, // Given `DbvtAabbMm` `a`, return true if `a`s bounding box is contained // within `this` bounding box. Contain: function( a ) { - return( ( this.mi.x <= a.mi.x ) && + return (( this.mi.x <= a.mi.x ) && ( this.mi.y <= a.mi.y ) && ( this.mi.z <= a.mi.z ) && ( this.mx.x >= a.mx.x ) && ( this.mx.y >= a.mx.y ) && - ( this.mx.z >= a.mx.z ) ); + ( this.mx.z >= a.mx.z )); }, // Classify `this` DbvtAabbMm based on which side of a specified plane it @@ -203,8 +203,8 @@ // Note: There seems to be a bug here, in which intersections are not // reliably detected... Classify: function( n, o, s ) { - var pi = Bump.Vector3.create(), - px = Bump.Vector3.create(); + var pi = Bump.Vector3.create(); + var px = Bump.Vector3.create(); switch ( s ) { case ( 0 + 0 + 0 ): @@ -272,24 +272,23 @@ if ( d.x < 0 ) { span.smi += this.mx.x * d.x; span.smx += this.mi.x * d.x; - } - else{ + } else { span.smi += this.mi.x * d.x; span.smx += this.mx.x * d.x; } + if ( d.y < 0 ) { span.smi += this.mx.y * d.y; span.smx += this.mi.y * d.y; - } - else{ + } else { span.smi += this.mi.y * d.y; span.smx += this.mx.y * d.y; } + if ( d.z < 0 ) { span.smi += this.mx.z * d.z; span.smx += this.mi.z * d.z; - } - else{ + } else { span.smi += this.mi.z * d.z; span.smx += this.mx.z * d.z; } @@ -345,23 +344,23 @@ // Intersect test for 2 `DbvtAabbMm`s Bump.Intersect.DbvtAabbMm2 = function( a, b ) { - return ( ( a.mi.x <= b.mx.x ) && - ( a.mx.x >= b.mi.x ) && - ( a.mi.y <= b.mx.y ) && - ( a.mx.y >= b.mi.y ) && - ( a.mi.z <= b.mx.z ) && - ( a.mx.z >= b.mi.z ) ); + return (( a.mi.x <= b.mx.x ) && + ( a.mx.x >= b.mi.x ) && + ( a.mi.y <= b.mx.y ) && + ( a.mx.y >= b.mi.y ) && + ( a.mi.z <= b.mx.z ) && + ( a.mx.z >= b.mi.z )); }; Bump.Intersect.DbvtVolume2 = Bump.Intersect.DbvtAabbMm2; // typedef consistency // Intersect test for `DbvtAabbMm` `a` and `Vector3` `b` Bump.Intersect.DbvtAabbMm.Vector3 = function( a, b ) { - return ( ( b.x >= a.mi.x ) && - ( b.y >= a.mi.y ) && - ( b.z >= a.mi.z ) && - ( b.x <= a.mx.x ) && - ( b.y <= a.mx.y ) && - ( b.z <= a.mx.z ) ); + return (( b.x >= a.mi.x ) && + ( b.y >= a.mi.y ) && + ( b.z >= a.mi.z ) && + ( b.x <= a.mx.x ) && + ( b.y <= a.mx.y ) && + ( b.z <= a.mx.z )); }; Bump.Proximity = {}; @@ -392,40 +391,37 @@ // unrolled to avoid array-like vector access (for speed) if ( a.mi.x < b.mi.x ) { r.mi.x = a.mi.x; - } - else { + } else { r.mi.x = b.mi.x; } + if ( a.mx.x > b.mx.x ) { r.mx.x = a.mx.x; - } - else { + } else { r.mx.x = b.mx.x; } if ( a.mi.y < b.mi.y ) { r.mi.y = a.mi.y; - } - else { + } else { r.mi.y = b.mi.y; } + if ( a.mx.y > b.mx.y ) { r.mx.y = a.mx.y; - } - else { + } else { r.mx.y = b.mx.y; } if ( a.mi.z < b.mi.z ) { r.mi.z = a.mi.z; - } - else { + } else { r.mi.z = b.mi.z; } + if ( a.mx.z > b.mx.z ) { r.mx.z = a.mx.z; - } - else { + } else { r.mx.z = b.mx.z; } }; @@ -496,35 +492,34 @@ // static DBVT_INLINE int indexof(const btDbvtNode* node) var indexof = function( node ) { return node.parent.childs[ 1 ] === node ? 1 : 0; - }, + }; - merge = function( a, b ) { + var merge = function( a, b ) { var res = Bump.DbvtVolume.create(); Bump.Merge.DbvtVolume3( a, b, res ); return res; - }, + }; - size = function( a ) { + var size = function( a ) { var edges = a.Lengths(); return edges.x * edges.y * edges.z + edges.x + edges.y + edges.z; - }, + }; - getmaxdepth = function( node, depth, maxdepthRef ) { + var getmaxdepth = function( node, depth, maxdepthRef ) { if ( node.isinternal() ) { getmaxdepth( node.childs[ 0 ], depth + 1, maxdepthRef ); getmaxdepth( node.childs[ 1 ], depth + 1, maxdepthRef ); - } - else { + } else { maxdepthRef.value = Math.max( maxdepthRef.value, depth ); } - }, + }; - deletenode = function( pdbvt, node ) { + var deletenode = function( pdbvt, node ) { // btAlignedFree(pdbvt->free); pdbvt.free = node; - }, + }; - recursedeletenode = function( pdbvt, node ) { + var recursedeletenode = function( pdbvt, node ) { if ( node.isleaf() ) { recursedeletenode( pdbvt, node.childs[ 0 ] ); recursedeletenode( pdbvt, node.childs[ 1 ] ); @@ -535,10 +530,10 @@ } deletenode( pdbvt, node ); - }, + }; // overloaded createnode functions have been renamed - createnodeTreeParentData = function( pdbvt, parent, data ) { + var createnodeTreeParentData = function( pdbvt, parent, data ) { var node; if ( pdbvt.free ) { node = pdbvt.free; @@ -551,21 +546,21 @@ node.data = data; node.childs[ 1 ] = 0; // redundant? return node; - }, + }; - createnodeTreeParentVolumeData = function( pdbvt, parent, volume, data ) { + var createnodeTreeParentVolumeData = function( pdbvt, parent, volume, data ) { var node = createnodeTreeParentData( pdbvt, parent, data ); volume.clone( node.volume ); return node; - }, + }; - createnodeTreeParentVolume2Data = function( pdbvt, parent, volume0, volume1, data ) { + var createnodeTreeParentVolume2Data = function( pdbvt, parent, volume0, volume1, data ) { var node = createnodeTreeParentData( pdbvt, parent, data ); Bump.Merge.DbvtVolume3( volume0, volume1, node.volume ); return node; - }, + }; - insertleaf = function( pdbvt, root, leaf ) { + var insertleaf = function( pdbvt, root, leaf ) { if ( !pdbvt.root ) { pdbvt.root = leaf; leaf.parent = 0; @@ -575,9 +570,7 @@ if ( !root.isleaf() ) { do { root = root.childs[ - Bump.Select.DbvtVolume3( leaf.volume, - root.childs[0].volume, - root.childs[1].volume ) + Bump.Select.DbvtVolume3( leaf.volume, root.childs[0].volume, root.childs[1].volume ) ]; } while ( !root.isleaf() ); } @@ -592,7 +585,7 @@ leaf.parent = node; do { if ( !prev.volume.Contain( node.volume ) ) { - Bump.Merge.DbvtVolume3( prev.childs[ 0 ].volume, prev.childs[ 1 ].volume, prev.volume ); + Bump.Merge.DbvtVolume3( prev.childs[0].volume, prev.childs[1].volume, prev.volume ); } else { break; } @@ -609,12 +602,12 @@ pdbvt.root = node; } } - }, + }; - removeleaf = function( pdbvt, leaf ) { + var removeleaf = function( pdbvt, leaf ) { if ( leaf === pdbvt.root ) { - pdbvt.root = 0; - return 0; + pdbvt.root = 0; + return 0; } else { @@ -627,7 +620,7 @@ deletenode( pdbvt, parent ); while ( prev ) { var pb = prev.volume; - Bump.Merge.DbvtVolume3( prev.childs[ 0 ].volume, prev.childs[ 1 ].volume, prev.volume ); + Bump.Merge.DbvtVolume3( prev.childs[0].volume, prev.childs[1].volume, prev.volume ); if ( Bump.NotEqual.DbvtVolume2( pb, prev.volume ) ) { prev = prev.parent; } else { @@ -644,44 +637,44 @@ return pdbvt.root; } } - }, + }; - fetchleaves = function( pdbvt, root, leaves, depth ) { + var fetchleaves = function( pdbvt, root, leaves, depth ) { depth = ( depth === undefined ) ? -1 : depth; if ( root.isinternal() && depth ) { - fetchleaves( pdbvt, root.childs[ 0 ], leaves, depth - 1 ); - fetchleaves( pdbvt, root.childs[ 1 ], leaves, depth - 1 ); + fetchleaves( pdbvt, root.childs[0], leaves, depth - 1 ); + fetchleaves( pdbvt, root.childs[1], leaves, depth - 1 ); deletenode( pdbvt, root ); } else { leaves.push( root ); } - }, + }; - split = function( leaves, left, right, org, axis ) { + var split = function( leaves, left, right, org, axis ) { left.splice( 0 ); // left.resize( 0 ); right.splice( 0 ); // right.resize( 0 ); var tmpVector3 = Bump.Vector3.create(); for ( var i = 0, ni = leaves.length; i < ni; ++i ) { - if ( axis.dot( leaves[ i ].volume.Center().subract( org, tmpVector3 ) ) < 0 ) { - left.push( leaves[ i ] ); + if ( axis.dot( leaves[i].volume.Center().subract( org, tmpVector3 ) ) < 0 ) { + left.push( leaves[i] ); } else { - right.push( leaves[ i ] ); + right.push( leaves[i] ); } } - }, + }; - bounds = function( leaves ) { + var bounds = function( leaves ) { var volume = leaves[0].volume.clone(); for ( var i = 1, ni = leaves.length; i < ni; ++i ) { Bump.Merge.DbvtVolume3( volume, leaves[i].volume, volume ); } return volume; - }, + }; - bottomup = function( pdbvt, leaves ) { + var bottomup = function( pdbvt, leaves ) { while ( leaves.length > 1 ) { - var minsize = Bump.SIMD_INFINITY, - minidx = [ -1, -1 ]; + var minsize = Bump.SIMD_INFINITY; + var minidx = [ -1, -1 ]; for ( var i = 0; i < leaves.length; ++i ) { for ( var j = i + 1; j < leaves.length; ++j ) { var sz = size( merge( leaves[i].volume, leaves[j].volume ) ); @@ -692,8 +685,9 @@ } } } - var n = [ leaves[ minidx[0] ], leaves[ minidx[1] ] ], - p = createnodeTreeParentVolume2Data( pdbvt, 0, n[0].volume, n[1].volume, 0 ); + + var n = [ leaves[ minidx[0] ], leaves[ minidx[1] ] ]; + var p = createnodeTreeParentVolume2Data( pdbvt, 0, n[0].volume, n[1].volume, 0 ); p.childs[0] = n[0]; p.childs[1] = n[1]; n[0].parent = p; @@ -702,9 +696,9 @@ leaves[ minidx[1] ] = leaves[ leaves.length - 1 ]; // instead of swap leaves.pop(); } - }, + }; - topdown = function( pdbvt, leaves, bu_threshold ) { + var topdown = function( pdbvt, leaves, bu_threshold ) { var axis = [ Bump.Vector3.create( 1, 0, 0 ), Bump.Vector3.create( 0, 1, 0 ), @@ -713,13 +707,13 @@ if ( leaves.length > 1 ) { if ( leaves.length > bu_threshold ) { - var vol = bounds( leaves ), - org = vol.Center().clone(), - sets = [], - bestaxis = -1, - bestmidp = leaves.length, - splitcount = [ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ], - i; + var vol = bounds( leaves ); + var org = vol.Center().clone(); + var sets = []; + var bestaxis = -1; + var bestmidp = leaves.length; + var splitcount = [ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ]; + var i; for ( i = 0; i < leaves.length; ++i ) { var x = leaves[i].volume.Center().subtract( org ); @@ -749,12 +743,13 @@ sets[ k & 1 ].push( leaves[k] ); } } + var node = createnodeTreeParentVolumeData( pdbvt, 0, vol, 0 ); node.childs[0] = topdown( pdbvt, sets[0], bu_threshold ); node.childs[1] = topdown( pdbvt, sets[1], bu_threshold ); node.childs[0].parent = node; node.childs[1].parent = node; - return( node ); + return node; } else { bottomup( pdbvt, leaves ); return leaves[0]; @@ -762,24 +757,23 @@ } return leaves[0]; - }, + }; // `n` : `DbvtNode`, // `rRef` : a "by-reference" `DbvtNode` - sort = function( n, rRef ) { + var sort = function( n, rRef ) { var p = n.parent; // Bump.Assert( n.isinternal() ); if ( p > n ) { - var i = indexof( n ), - j = 1 - i, - s = p.childs[ j ], - q = p.parent; + var i = indexof( n ); + var j = 1 - i; + var s = p.childs[ j ]; + var q = p.parent; // Bump.Assert( n === p.childs[i] ); if ( q ) { q.childs[ indexof( p ) ] = n; - } - else { + } else { rRef.value = n; } s.parent = n; @@ -868,10 +862,11 @@ if ( passes < 0 ) { passes = this.leaves; } + if ( this.root && ( passes > 0 ) ) { do { - var node = this.root, - bit = 0; + var node = this.root; + var bit = 0; while ( node.isinternal() ) { node = sort( node, this.root ).childs[ ( this.opath >> bit ) & 1 ]; // bit = ( bit + 1 ) & ( sizeof ( unsigned ) * 8 - 1 ); @@ -967,17 +962,18 @@ Bump.Dbvt.enumNodes( this.root, nodes ); iwriter.Prepare( this.root, nodes.nodes.length ); for ( var i = 0; i < nodes.nodes.length; ++i ) { - var n = nodes.nodes[ i ], - p = -1; + var n = nodes.nodes[ i ]; + var p = -1; + if ( n.parent ) { p = nodes.nodes.indexOf( n.parent ); } + if ( n.isinternal() ) { var c0 = nodes.nodes.indexOf( n.childs[0] ); var c1 = nodes.nodes.indexOf( n.childs[1] ); iwriter.WriteNode( n, i, p, c0, c1 ); - } - else { + } else { iwriter.WriteLeaf( n, i, p ); } } @@ -1001,14 +997,15 @@ if ( e.parent !== 0 ) { // e.parent.childs[ i & 1 ] = n; nice trick, but doesn't work if you want an exact clone e.parent.childs[ indexof( e.node ) ] = n; - } - else { + } else { dest.root = n; } + if ( e.node.isinternal() ) { stack.push( Bump.Dbvt.sStkCLN.create(e.node.childs[0], n ) ); stack.push( Bump.Dbvt.sStkCLN.create(e.node.childs[1], n ) ); } + else if ( iclone ) { // added if to make sure iclone is defined iclone.CloneLeaf( n ); } @@ -1021,9 +1018,9 @@ // TODO : Add description of use. collideTT: function( root0, root1, policy ) { if ( root0 && root1 ) { - var depth = 1, - threshold = Bump.Dbvt.DOUBLE_STACKSIZE - 4, - stkStack = []; + var depth = 1; + var threshold = Bump.Dbvt.DOUBLE_STACKSIZE - 4; + var stkStack = []; stkStack[ Bump.Dbvt.DOUBLE_STACKSIZE - 1 ] = undefined; // stkStack.resize( DOUBLE_STACKSIZE ); stkStack[ 0 ] = Bump.Dbvt.sStkNN.create( root0, root1 ); @@ -1047,8 +1044,7 @@ stkStack[ depth++ ] = Bump.Dbvt.sStkNN.create( p.a.childs[ 1 ], p.b.childs[ 0 ] ); stkStack[ depth++ ] = Bump.Dbvt.sStkNN.create( p.a.childs[ 0 ], p.b.childs[ 1 ] ); stkStack[ depth++ ] = Bump.Dbvt.sStkNN.create( p.a.childs[ 1 ], p.b.childs[ 1 ] ); - } - else { + } else { stkStack[ depth++ ] = Bump.Dbvt.sStkNN.create( p.a.childs[ 0 ], p.b ); stkStack[ depth++ ] = Bump.Dbvt.sStkNN.create( p.a.childs[ 1 ], p.b ); } @@ -1064,13 +1060,14 @@ } } } while ( depth ); + } }, collideTTpersistentStack: function( root0, root1, policy ) { if ( root0 && root1 ) { - var depth = 1, - threshold = Bump.Dbvt.DOUBLE_STACKSIZE - 4; + var depth = 1; + var threshold = Bump.Dbvt.DOUBLE_STACKSIZE - 4; Bump.resize( this.stkStack, Bump.Dbvt.DOUBLE_STACKSIZE, sStkNNZero ); this.stkStack[0].set( root0, root1 ); @@ -1167,10 +1164,10 @@ // not used // var resultNormal = Bump.Vector3.create(); - var depth = 1, - threshold = Bump.Dbvt.DOUBLE_STACKSIZE - 2, - stack = this.rayTestStack, - bounds = getArray(); + var depth = 1; + var threshold = Bump.Dbvt.DOUBLE_STACKSIZE - 2; + var stack = this.rayTestStack; + var bounds = getArray(); bounds[ 0 ] = getVector3(); bounds[ 1 ] = getVector3(); @@ -1180,9 +1177,9 @@ var node = stack[ --depth ]; node.volume.Mins().subtract( aabbMax, bounds[ 0 ] ); node.volume.Maxs().subtract( aabbMin, bounds[ 1 ] ); - var tmin = getScalarRef( 1 ), // primitive "passed by reference" - lambda_min = 0, - result1 = false; + var tmin = getScalarRef( 1 ); // primitive "passed by reference" + var lambda_min = 0; + var result1 = false; result1 = Bump.RayAabb2( rayFrom, rayDirectionInverse, signs, bounds, tmin, lambda_min, lambda_max ); if ( result1 ) { @@ -1203,7 +1200,7 @@ delScalarRef( tmin ); } while ( depth ); - delVector3( bounds[ 0 ], bounds[ 1 ] ); + delVector3( bounds[0], bounds[1] ); delArray( bounds ); } } @@ -1225,20 +1222,18 @@ countLeaves: function( node ) { if ( node.isinternal() ) { - return( Bump.Dbvt.countLeaves( node.childs[ 0 ] ) + - Bump.Dbvt.countLeaves( node.childs[ 1 ] ) ); - } - else { + return( Bump.Dbvt.countLeaves( node.childs[0] ) + + Bump.Dbvt.countLeaves( node.childs[1] ) ); + } else { return 1; } }, extractLeaves: function( node, leaves ) { if ( node.isinternal() ) { - Bump.Dbvt.extractLeaves( node.childs[ 0 ], leaves ); - Bump.Dbvt.extractLeaves( node.childs[ 1 ], leaves ); - } - else { + Bump.Dbvt.extractLeaves( node.childs[0], leaves ); + Bump.Dbvt.extractLeaves( node.childs[1], leaves ); + } else { leaves.push( node ); } }, @@ -1250,18 +1245,17 @@ enumNodes: function( root, policy ) { policy.ProcessNode( root ); if ( root.isinternal() ) { - Bump.Dbvt.enumNodes( root.childs[ 0 ], policy ); - Bump.Dbvt.enumNodes( root.childs[ 1 ], policy ); + Bump.Dbvt.enumNodes( root.childs[0], policy ); + Bump.Dbvt.enumNodes( root.childs[1], policy ); } }, // iterate over only the leaf nodes and process according to the given policy enumLeaves: function( root, policy ) { if ( root.isinternal() ) { - Bump.Dbvt.enumLeaves( root.childs[ 0 ], policy ); - Bump.Dbvt.enumLeaves( root.childs[ 1 ], policy ); - } - else { + Bump.Dbvt.enumLeaves( root.childs[0], policy ); + Bump.Dbvt.enumLeaves( root.childs[1], policy ); + } else { policy.ProcessNode( root ); } }, @@ -1320,6 +1314,7 @@ stack[ depth++ ] = node.childs[ 0 ]; stack[ depth++ ] = node.childs[ 1 ]; } + else { policy.ProcessNode( node ); } @@ -1336,23 +1331,23 @@ collideKDOP: function( root, normals, offsets, count, policy ) { if ( root ) { - var inside = ( 1 << count ) - 1, - stack = [], - signs = [], - i, j; + var inside = ( 1 << count ) - 1; + var stack = []; + var signs = []; + var i, j; // Bump.Assert( count < sizeof(signs) / sizeof(signs[0]) ); for ( i = 0; i < count; i++ ) { - signs[ i ] = ( ( normals[ i ].x >= 0 ) ? 1 : 0 ) + - ( ( normals[ i ].y >= 0 ) ? 2 : 0 ) + - ( ( normals[ i ].z >= 0 ) ? 4 : 0 ); + signs[ i ] = ( ( normals[i].x >= 0 ) ? 1 : 0 ) + + ( ( normals[i].y >= 0 ) ? 2 : 0 ) + + ( ( normals[i].z >= 0 ) ? 4 : 0 ); } // stack.reserve( SIMPLE_STACKSIZE ); stack.push( Bump.Dbvt.sStkNP.create( root, 0 ) ); do { - var se = stack[ stack.length() - 1 ], - out = false; + var se = stack[ stack.length() - 1 ]; + var out = false; stack.pop(); for ( i = 0, j = 1; ( !out ) && ( i < count ); ++i, j <<= 1 ) { @@ -1366,12 +1361,12 @@ } } } + if ( !out ) { if ( (se.mask !== inside) && (se.node.isinternal()) ) { stack.push( Bump.Dbvt.sStkNP.create( se.node.childs[0],se.mask ) ); stack.push( Bump.Dbvt.sStkNP.create( se.node.childs[1],se.mask ) ); - } - else { + } else { if ( policy.AllLeaves( se.node ) ) { Bump.Dbvt.enumLeaves( se.node, policy ); } @@ -1386,29 +1381,34 @@ if ( root ) { var srtsgns = ( sortaxis.x >= 0 ? 1 : 0 ) + - ( sortaxis.y >= 0 ? 2 : 0 ) + - ( sortaxis.z >= 0 ? 4 : 0 ), - inside = (1 << count ) - 1, - stock = [], - ifree= [], - stack = [], - signs = [], - i, j, k; + ( sortaxis.y >= 0 ? 2 : 0 ) + + ( sortaxis.z >= 0 ? 4 : 0 ); + var inside = ( 1 << count ) - 1; + var stock = []; + var ifree = []; + var stack = []; + var signs = []; + var i, j, k; // Bump.Assert( count < sizeof(signs) / sizeof(signs[0]) ); for ( i = 0; i < count; ++i ) { - signs[ i ] = ( ( normals[ i ].x >= 0 ) ? 1 : 0 ) + - ( ( normals[ i ].y >= 0 ) ? 2 : 0 ) + - ( ( normals[ i ].z >= 0 ) ? 4 : 0 ); + signs[ i ] = ( ( normals[i].x >= 0 ) ? 1 : 0 ) + + ( ( normals[i].y >= 0 ) ? 2 : 0 ) + + ( ( normals[i].z >= 0 ) ? 4 : 0 ); } // stock.reserve(SIMPLE_STACKSIZE); // stack.reserve(SIMPLE_STACKSIZE); // ifree.reserve(SIMPLE_STACKSIZE); - stack.push( Bump.Dbvt.allocate( ifree, - stock, - Bump.Dbvt.sStkNPS.create( root, - 0, - root.volume.ProjectMinimum( - sortaxis, srtsgns ) ) ) ); + + stack.push( Bump.Dbvt.allocate( + ifree, + stock, + Bump.Dbvt.sStkNPS.create( + root, + 0, + root.volume.ProjectMinimum( sortaxis, srtsgns ) + ) + )); + do { var id = stack[ stack.length - 1 ], se = stock[ id ]; @@ -1427,24 +1427,28 @@ } } } + if ( out ) { continue; } } + if ( policy.Descent( se.node ) ) { if ( se.node.isinternal() ) { - var pns = [ se.node.childs[ 0 ], se.node.childs[ 1 ] ], - nes = [ - Bump.Dbvt.sStkNPS.create( pns[ 0 ], - se.mask, - pns[ 0 ].volume.ProjectMinimum( sortaxis, - srtsgns ) ), - Bump.Dbvt.sStkNPS.create( pns[ 1 ], - se.mask, - pns[ 1 ].volume.ProjectMinimum( sortaxis, - srtsgns ) ) - ], - q = nes[ 0 ].value < nes[ 1 ].value ? 1 : 0; + var pns = [ se.node.childs[ 0 ], se.node.childs[ 1 ] ]; + var nes = [ + Bump.Dbvt.sStkNPS.create( + pns[ 0 ], + se.mask, + pns[ 0 ].volume.ProjectMinimum( sortaxis, srtsgns ) + ), + Bump.Dbvt.sStkNPS.create( + pns[ 1 ], + se.mask, + pns[ 1 ].volume.ProjectMinimum( sortaxis, srtsgns ) + ) + ]; + var q = nes[ 0 ].value < nes[ 1 ].value ? 1 : 0; j = stack.length; @@ -1464,11 +1468,13 @@ } stack[ j ] = Bump.Dbvt.allocate( ifree, stock, nes[ 1 - q ] ); } + else { stack.push( Bump.Dbvt.allocate( ifree, stock, nes[ q ] ) ); stack.push( Bump.Dbvt.allocate( ifree, stock, nes[ 1 - q ] ) ); } } + else { policy.Process( se.node, se.value ); } @@ -1489,8 +1495,7 @@ if ( n.isinternal() ) { stack.push( n.childs[ 0 ] ); stack.push( n.childs[ 1 ] ); - } - else { + } else { policy.Process( n ); } } @@ -1508,10 +1513,9 @@ var m = 0; while ( l < h ) { m = ( l + h ) >> 1; - if ( a[ i[ m ] ].value >= v ) { + if ( a[i[ m ]].value >= v ) { l = m + 1; - } - else { + } else { h = m; } } @@ -1662,4 +1666,3 @@ sStkNNZero = Bump.Dbvt.sStkNN.create(); })( this, this.Bump ); - From 46bb945614087caa8ac1d5e32685f5f40de3d5a2 Mon Sep 17 00:00:00 2001 From: Andrew Dolce Date: Mon, 13 Aug 2012 16:24:40 -0400 Subject: [PATCH 17/22] Fix Array vs Vector3 confusion in SingleRayCallback The `signs` property was incorrectly initialized as a Vector3, but is now correctly initialized as an Array. Also removed unnecessary array-like access to Vector3 variables. --- .../CollisionDispatch/CollisionWorld.js | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/BulletCollision/CollisionDispatch/CollisionWorld.js b/src/BulletCollision/CollisionDispatch/CollisionWorld.js index 87ec090..1c4e0ce 100644 --- a/src/BulletCollision/CollisionDispatch/CollisionWorld.js +++ b/src/BulletCollision/CollisionDispatch/CollisionWorld.js @@ -283,13 +283,13 @@ // what about division by zero? --> just set rayDirection[i] to INF/BT_LARGE_FLOAT this.rayDirectionInverse = Bump.Vector3.create(); - this.signs = Bump.Vector3.create(); - this.rayDirectionInverse[ 0 ] = rayDir[ 0 ] === 0 ? Infinity : 1 / rayDir[ 0 ]; - this.rayDirectionInverse[ 1 ] = rayDir[ 1 ] === 0 ? Infinity : 1 / rayDir[ 1 ]; - this.rayDirectionInverse[ 2 ] = rayDir[ 2 ] === 0 ? Infinity : 1 / rayDir[ 2 ]; - this.signs[ 0 ] = this.rayDirectionInverse[ 0 ] < 0 ? 1 : 0; - this.signs[ 1 ] = this.rayDirectionInverse[ 1 ] < 0 ? 1 : 0; - this.signs[ 2 ] = this.rayDirectionInverse[ 2 ] < 0 ? 1 : 0; + this.rayDirectionInverse.x = rayDir.x === 0 ? Infinity : 1 / rayDir.x; + this.rayDirectionInverse.y = rayDir.y === 0 ? Infinity : 1 / rayDir.y; + this.rayDirectionInverse.z = rayDir.z === 0 ? Infinity : 1 / rayDir.z; + this.signs = new Array( 3 ); + this.signs[ 0 ] = this.rayDirectionInverse.x < 0 ? 1 : 0; + this.signs[ 1 ] = this.rayDirectionInverse.y < 0 ? 1 : 0; + this.signs[ 2 ] = this.rayDirectionInverse.z < 0 ? 1 : 0; this.lambda_max = rayDir.dot( this.rayToWorld.subtract( this.rayFromWorld, tmpV2 )); }, @@ -318,14 +318,12 @@ var rayDir = rayToWorld.subtract( rayFromWorld, tmpV1 ).normalize(); // what about division by zero? --> just set rayDirection[i] to INF/BT_LARGE_FLOAT - this.rayDirectionInverse.setZero(); - this.signs.setZero(); - this.rayDirectionInverse[ 0 ] = rayDir[ 0 ] === 0 ? Infinity : 1 / rayDir[ 0 ]; - this.rayDirectionInverse[ 1 ] = rayDir[ 1 ] === 0 ? Infinity : 1 / rayDir[ 1 ]; - this.rayDirectionInverse[ 2 ] = rayDir[ 2 ] === 0 ? Infinity : 1 / rayDir[ 2 ]; - this.signs[ 0 ] = this.rayDirectionInverse[ 0 ] < 0 ? 1 : 0; - this.signs[ 1 ] = this.rayDirectionInverse[ 1 ] < 0 ? 1 : 0; - this.signs[ 2 ] = this.rayDirectionInverse[ 2 ] < 0 ? 1 : 0; + this.rayDirectionInverse.x = rayDir.x === 0 ? Infinity : 1 / rayDir.x; + this.rayDirectionInverse.y = rayDir.y === 0 ? Infinity : 1 / rayDir.y; + this.rayDirectionInverse.z = rayDir.z === 0 ? Infinity : 1 / rayDir.z; + this.signs[ 0 ] = this.rayDirectionInverse.x < 0 ? 1 : 0; + this.signs[ 1 ] = this.rayDirectionInverse.y < 0 ? 1 : 0; + this.signs[ 2 ] = this.rayDirectionInverse.z < 0 ? 1 : 0; this.lambda_max = rayDir.dot( this.rayToWorld.subtract( this.rayFromWorld, tmpV2 )); From 1cd2b4694f326d2f1471c19adbcfef2510de2878 Mon Sep 17 00:00:00 2001 From: Andrew Dolce Date: Tue, 14 Aug 2012 11:00:40 -0400 Subject: [PATCH 18/22] Add efficient `set` function to SphereShape. The `set` function is used in place of `clone` when re-initializing a recycled SphereShape. It is similar to `init` but unrolls all the calls to _super into a single function and removes any unnecessary or redundant statements. Currently used in `CollisionWorld.rayTestSingle`. --- .../CollisionDispatch/CollisionWorld.js | 6 ++---- .../CollisionShapes/SphereShape.js | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/BulletCollision/CollisionDispatch/CollisionWorld.js b/src/BulletCollision/CollisionDispatch/CollisionWorld.js index 1c4e0ce..0826c2d 100644 --- a/src/BulletCollision/CollisionDispatch/CollisionWorld.js +++ b/src/BulletCollision/CollisionDispatch/CollisionWorld.js @@ -734,7 +734,6 @@ collisionShape, colObjWorldTransform, resultCallback ) { - // allocate temporaries // TODO: not all of these are needed for every rayTestSingle call, // so allocations could be moved to where they are needed @@ -749,9 +748,8 @@ var tmpBTRC = getBridgeTriangleRaycastCallback(); var tmpRT = getRayTester(); - // TODO: to get best speed-up, could in-line the clone code here - // to avoid multiple calls to _super functions - var castShape = emptySphereShape.clone( tmpSS ); + // re-init the recycled SphereShape using `set` + var castShape = tmpSS.set( emptySphereShape ); var worldTocollisionObject, rayFromLocal, rayToLocal, rcb; diff --git a/src/BulletCollision/CollisionShapes/SphereShape.js b/src/BulletCollision/CollisionShapes/SphereShape.js index 8cf040e..12216e4 100644 --- a/src/BulletCollision/CollisionShapes/SphereShape.js +++ b/src/BulletCollision/CollisionShapes/SphereShape.js @@ -21,6 +21,24 @@ }, members: { + // !!!: added for fast, easy initialization of recycled SphereShapes + set: function( other ) { + // !!!: unroll the calls to super for performance + // from CollisionShape: + this.userPointer = other.userPointer; + + // nothing from ConvexShape + + // from ConvexInternalShape: + this.localScaling.assign( other.localScaling ); + + this.shapeType = other.shapeType; + this.implicitShapeDimensions.x = other.implicitShapeDimensions.x; + this.collisionMargin = other.collisionMargin; + + return this; + }, + clone: function( dest ) { dest = dest || Bump.SphereShape.create( this.collisionMargin ); From 623dbad94fa62f8956d3d87fb36e5957976ed9c3 Mon Sep 17 00:00:00 2001 From: Andrew Dolce Date: Tue, 14 Aug 2012 14:51:08 -0400 Subject: [PATCH 19/22] Fix SingleRayCallback unit test The unit test had not been updated to reflect the newly corrected type for the `signs` property. --- .../BulletCollision/CollisionDispatch/test.CollisionWorld.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/BulletCollision/CollisionDispatch/test.CollisionWorld.js b/tests/unit/BulletCollision/CollisionDispatch/test.CollisionWorld.js index 533f4a0..c302090 100644 --- a/tests/unit/BulletCollision/CollisionDispatch/test.CollisionWorld.js +++ b/tests/unit/BulletCollision/CollisionDispatch/test.CollisionWorld.js @@ -94,7 +94,7 @@ test( 'test skipped', function() { [ 'rayFromTrans', Bump.Transform ], [ 'rayToTrans', Bump.Transform ], [ 'rayDirectionInverse', Bump.Vector3 ], - [ 'signs', Bump.Vector3 ], + [ 'signs', 'array' ], [ 'lambda_max', 'number' ] ]; From 80907cd021a0451d1af06ea132faa4ccdf22cbe5 Mon Sep 17 00:00:00 2001 From: Andrew Dolce Date: Tue, 14 Aug 2012 16:37:56 -0400 Subject: [PATCH 20/22] Separate ray-cast perf test from general perf test Made separate ray-performance test, and restored performance.js to match with the general performance test from the develop branch. Changed the ray-performance `stats.begin()` and `stats.end()` calls to match with the updated ones from develop. --- tests/js/performance.js | 60 ++--------- tests/js/ray-performance.js | 201 ++++++++++++++++++++++++++++++++++++ tests/ray-performance.html | 25 +++++ 3 files changed, 233 insertions(+), 53 deletions(-) create mode 100644 tests/js/ray-performance.js create mode 100644 tests/ray-performance.html diff --git a/tests/js/performance.js b/tests/js/performance.js index 99c503f..73460bb 100644 --- a/tests/js/performance.js +++ b/tests/js/performance.js @@ -20,53 +20,6 @@ var collisionShapes = []; - (function(){ - var _DOWN = Bump.Vector3.create( 0, -1, 0 ); - var _down = Bump.Vector3.create(); - var _from = Bump.Vector3.create(); - var _to = Bump.Vector3.create(); - - // for now test the 4 corners - var testPoints = [ - Bump.Vector3.create( -1, -1, -1 ), - Bump.Vector3.create( -1, -1, 1 ), - Bump.Vector3.create( 1, -1, -1 ), - Bump.Vector3.create( 1, -1, 1 ) - ]; - - var boxTrans = Bump.Transform.getIdentity(); - - var rayCallback = Bump.CollisionWorld.ClosestRayResultCallback.create( _from, _to ); - rayCallback.collisionFilterMask = - Bump.BroadphaseProxy.CollisionFilterGroups.AllFilter; - - // set up a internal pre-tick callback to test a bunch of raycasts per object - dynamicsWorld.setInternalTickCallback( function() { - - // cast rays for each collision object, slipping object 0, - // which is the dryer - for ( var i = 1; i < dynamicsWorld.getNumCollisionObjects(); ++i ) { - var colObj = dynamicsWorld.getCollisionObjectArray()[ i ]; - var body = Bump.RigidBody.upcast( colObj ); - body.getMotionState().getWorldTransform( boxTrans ); - - boxTrans.multiplyVector( _DOWN, _down ); - - for ( var j = 0; j < testPoints.length; j++ ) { - boxTrans.multiplyVector( testPoints[ j ], _from ); - _from.add( _down, _to ); - rayCallback.rayFromWorld = _from; - rayCallback.rayToWorld = _to; - - dynamicsWorld.rayTest( _from, _to, rayCallback ); - - if( rayCallback.hasHit() ) { - // do something - } - } - } - }, undefined, true ); - }()); var groundBody; (function( size ) { var groundHalfExtents = Bump.Vector3.create( size, size, size ); @@ -135,7 +88,7 @@ renderer.addBox({ size: 20, wireframe: true }); (function() { - var num = 2; + var num = 7; var j = 4; for ( var i = 0; i < num; ++i ) { for ( var k = 0; k < num; ++k ) { @@ -150,6 +103,7 @@ var groundRot = Bump.Quaternion.createWithEuler( 0, 0, Math.PI * 0.003 ); var quat = Bump.Quaternion.create(); var newTransform = Bump.Transform.create(); + var tmpMat = Bump.Matrix3x3.create(); var rate = Math.PI / 60 / 5; var amp = rate / 2; @@ -158,15 +112,16 @@ var time = 0; var step = function () { - time += 160; + time += 16; - stats.begin(); groundRot.setEuler( 0, 0, rate + amp * Math.sin( time / 500 ) ); groundBody.getMotionState().getWorldTransform( newTransform ); - newTransform.basis.multiplyMatrix( Bump.Matrix3x3.createWithQuaternion( groundRot ), newTransform.basis ); + newTransform.basis.multiplyMatrix( tmpMat.setRotation( groundRot ), newTransform.basis ); groundBody.getMotionState().setWorldTransform( newTransform ); - dynamicsWorld.stepSimulation( 0.16, 20, 0.016 ); + stats.begin(); + dynamicsWorld.stepSimulation( 0.016 ); + stats.end(); for ( var i = 0; i < dynamicsWorld.getNumCollisionObjects(); ++i ) { var colObj = dynamicsWorld.getCollisionObjectArray()[i]; @@ -179,7 +134,6 @@ } renderer.render(); - stats.end(); window.requestAnimationFrame( step ); }; diff --git a/tests/js/ray-performance.js b/tests/js/ray-performance.js new file mode 100644 index 0000000..a56515c --- /dev/null +++ b/tests/js/ray-performance.js @@ -0,0 +1,201 @@ +/*global Stats:false THREEWrapper:false*/ + +(function() { + var stats = new Stats(); + // stats.setMode(1); + + // Align top-left + stats.domElement.style.position = 'absolute'; + stats.domElement.style.left = '0px'; + stats.domElement.style.top = '0px'; + + document.body.appendChild( stats.domElement ); + + var collisionConfiguration = Bump.DefaultCollisionConfiguration.create(); + var dispatcher = Bump.CollisionDispatcher.create( collisionConfiguration ); + var overlappingPairCache = Bump.DbvtBroadphase.create(); + var solver = Bump.SequentialImpulseConstraintSolver.create(); + var dynamicsWorld = Bump.DiscreteDynamicsWorld.create( dispatcher, overlappingPairCache, solver, collisionConfiguration ); + dynamicsWorld.setGravity( Bump.Vector3.create( 0, -9.8, 0 ) ); + + var collisionShapes = []; + + (function(){ + var _DOWN = Bump.Vector3.create( 0, -1, 0 ); + var _down = Bump.Vector3.create(); + var _from = Bump.Vector3.create(); + var _to = Bump.Vector3.create(); + + // for now test the 4 corners + var testPoints = [ + Bump.Vector3.create( -1, -1, -1 ), + Bump.Vector3.create( -1, -1, 1 ), + Bump.Vector3.create( 1, -1, -1 ), + Bump.Vector3.create( 1, -1, 1 ) + ]; + + var boxTrans = Bump.Transform.getIdentity(); + + var rayCallback = Bump.CollisionWorld.ClosestRayResultCallback.create( _from, _to ); + rayCallback.collisionFilterMask = + Bump.BroadphaseProxy.CollisionFilterGroups.AllFilter; + + // set up a internal pre-tick callback to test a bunch of raycasts per object + dynamicsWorld.setInternalTickCallback( function() { + + // cast rays for each collision object, slipping object 0, + // which is the dryer + for ( var i = 1; i < dynamicsWorld.getNumCollisionObjects(); ++i ) { + var colObj = dynamicsWorld.getCollisionObjectArray()[ i ]; + var body = Bump.RigidBody.upcast( colObj ); + body.getMotionState().getWorldTransform( boxTrans ); + + boxTrans.multiplyVector( _DOWN, _down ); + + for ( var j = 0; j < testPoints.length; j++ ) { + boxTrans.multiplyVector( testPoints[ j ], _from ); + _from.add( _down, _to ); + rayCallback.rayFromWorld = _from; + rayCallback.rayToWorld = _to; + + dynamicsWorld.rayTest( _from, _to, rayCallback ); + + if( rayCallback.hasHit() ) { + // do something + } + } + } + }, undefined, true ); + }()); + var groundBody; + (function( size ) { + var groundHalfExtents = Bump.Vector3.create( size, size, size ); + var groundBoxShape = Bump.BoxShape.create( groundHalfExtents ); + var groundShape = Bump.CompoundShape.create(); + + collisionShapes.push( groundShape ); + collisionShapes.push( groundBoxShape ); + + var sizeAndHalf = 1.5 * size; + [ + Bump.Vector3.create( 0, -sizeAndHalf, 0 ), + Bump.Vector3.create( 0, sizeAndHalf, 0 ), + Bump.Vector3.create( -sizeAndHalf, 0, 0 ), + Bump.Vector3.create( sizeAndHalf, 0, 0 ), + Bump.Vector3.create( 0, 0, -sizeAndHalf ), + Bump.Vector3.create( 0, 0, sizeAndHalf ) + ].forEach(function( position ) { + var localTransform = Bump.Transform.getIdentity(); + localTransform.setOrigin( position ); + + groundShape.addChildShape( localTransform, groundBoxShape ); + }); + + var groundTransform = Bump.Transform.getIdentity(); + + var myMotionState = Bump.DefaultMotionState.create( groundTransform ); + var rbInfo = Bump.RigidBody.RigidBodyConstructionInfo.create( 0, myMotionState, groundShape, Bump.Vector3.create() ); + // var rbInfo = Bump.RigidBody.RigidBodyConstructionInfo.create( 0, myMotionState, groundBoxShape, Bump.Vector3.create() ); + groundBody = Bump.RigidBody.create( rbInfo ); + + groundBody.setCollisionFlags( groundBody.getCollisionFlags() | Bump.CollisionObject.CollisionFlags.CF_KINEMATIC_OBJECT ); + groundBody.setActivationState( Bump.CollisionObject.DISABLE_DEACTIVATION ); + + dynamicsWorld.addRigidBody( groundBody ); + }( 20 )); + + var boxCubeShape = Bump.BoxShape.create( Bump.Vector3.create( 0.5, 0.5, 0.5 ) ); + collisionShapes.push( boxCubeShape ); + + var createCube = function( i, j, k, startRotation ) { + if ( !startRotation ) { + startRotation = Bump.Quaternion.getIdentity(); + } + + var localInertia = Bump.Vector3.create(); + boxCubeShape.calculateLocalInertia( 1, localInertia ); + + var startTransform = Bump.Transform.create(); + startTransform.setIdentity(); + startTransform.setRotation( startRotation ); + startTransform.setOrigin( Bump.Vector3.create( i, j, k ) ); + + var myMotionState = Bump.DefaultMotionState.create( startTransform ); + var rbInfo = Bump.RigidBody.RigidBodyConstructionInfo.create( 1, myMotionState, boxCubeShape, localInertia ); + var body = Bump.RigidBody.create( rbInfo ); + + body.setFriction( 0.1 ); + + dynamicsWorld.addRigidBody( body ); + }; + + var renderer = new THREEWrapper(); + renderer.init(); + + renderer.addBox({ size: 20, wireframe: true }); + + (function() { + var num = 2; + var j = 4; + for ( var i = 0; i < num; ++i ) { + for ( var k = 0; k < num; ++k ) { + createCube( i - (num - 1) / 2, j, k - (num - 1) / 2 ); + + renderer.addBox({ size: 1 }); + + } + } + }()); + + var groundRot = Bump.Quaternion.createWithEuler( 0, 0, Math.PI * 0.003 ); + var quat = Bump.Quaternion.create(); + var newTransform = Bump.Transform.create(); + + var rate = Math.PI / 60 / 5; + var amp = rate / 2; + + var startSimulation = function() { + var time = 0; + + var step = function () { + time += 160; + + groundRot.setEuler( 0, 0, rate + amp * Math.sin( time / 500 ) ); + groundBody.getMotionState().getWorldTransform( newTransform ); + newTransform.basis.multiplyMatrix( Bump.Matrix3x3.createWithQuaternion( groundRot ), newTransform.basis ); + groundBody.getMotionState().setWorldTransform( newTransform ); + + stats.begin(); + dynamicsWorld.stepSimulation( 0.16, 20, 0.016 ); + stats.end(); + + for ( var i = 0; i < dynamicsWorld.getNumCollisionObjects(); ++i ) { + var colObj = dynamicsWorld.getCollisionObjectArray()[i]; + var body = Bump.RigidBody.upcast( colObj ); + body.getMotionState().getWorldTransform( newTransform ); + + var mesh = renderer.meshes[ i ]; + mesh.position.copy( newTransform.origin ); + mesh.quaternion.copy( newTransform.getRotation( quat ) ); + } + + renderer.render(); + + window.requestAnimationFrame( step ); + }; + + window.requestAnimationFrame( step ); + }; + + var keylistener = function( evt ) { + // Enter key + if ( evt.keyCode === 13 ) { + document.body.removeEventListener( 'keyup', keylistener ); + + startSimulation(); + } + }; + + document.body.addEventListener( 'keyup', keylistener ); + +}()); diff --git a/tests/ray-performance.html b/tests/ray-performance.html new file mode 100644 index 0000000..3180046 --- /dev/null +++ b/tests/ray-performance.html @@ -0,0 +1,25 @@ + + + + + Bump Performance Tests + + + + + + + + + + + +
+ + + + + + + + From 5070cc4c79754b7df741c3062cb5bc96546c69ee Mon Sep 17 00:00:00 2001 From: Eric Li Date: Wed, 15 Aug 2012 11:21:44 -0400 Subject: [PATCH 21/22] WS: Whitespace and formatting --- .../BroadphaseCollision/DbvtBroadphase.js | 2 +- .../CollisionDispatch/CollisionWorld.js | 28 +++++++++---------- .../VoronoiSimplexSolver.js | 18 ++++++------ 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/BulletCollision/BroadphaseCollision/DbvtBroadphase.js b/src/BulletCollision/BroadphaseCollision/DbvtBroadphase.js index 6478d7e..4e9d1bd 100644 --- a/src/BulletCollision/BroadphaseCollision/DbvtBroadphase.js +++ b/src/BulletCollision/BroadphaseCollision/DbvtBroadphase.js @@ -361,7 +361,7 @@ aabbMin = aabbMin || Bump.Vector3.create(); aabbMax = aabbMin || Bump.Vector3.create(); - //var callback = Bump.BroadphaseRayTester.create( rayCallback ); + // var callback = Bump.BroadphaseRayTester.create( rayCallback ); var callback = tmpBroadphaseRayTester; callback.init( rayCallback ); diff --git a/src/BulletCollision/CollisionDispatch/CollisionWorld.js b/src/BulletCollision/CollisionDispatch/CollisionWorld.js index 0826c2d..d45397c 100644 --- a/src/BulletCollision/CollisionDispatch/CollisionWorld.js +++ b/src/BulletCollision/CollisionDispatch/CollisionWorld.js @@ -77,13 +77,13 @@ var BridgeTriangleRaycastCallback = Bump.type({ parent: Bump.TriangleRaycastCallback, - init: function BridgeTriangleRaycastCallback( from, - to, - resultCallback, - collisionObject, - triangleMesh, - colObjWorldTransform - ) { + init: function BridgeTriangleRaycastCallback( + from, to, + resultCallback, + collisionObject, + triangleMesh, + colObjWorldTransform + ) { //@BP Mod this._super( from, to, resultCallback.flags ); this.resultCallback = resultCallback; @@ -94,13 +94,13 @@ members: { // ASD: added for easy recycling, since init() calls clone - set: function BridgeTriangleRaycastCallback( from, - to, - resultCallback, - collisionObject, - triangleMesh, - colObjWorldTransform - ) { + set: function BridgeTriangleRaycastCallback( + from, to, + resultCallback, + collisionObject, + triangleMesh, + colObjWorldTransform + ) { //@BP Mod Bump.TriangleRaycastCallback.set.call( this, from, to, resultCallback.flags diff --git a/src/BulletCollision/NarrowPhaseCollision/VoronoiSimplexSolver.js b/src/BulletCollision/NarrowPhaseCollision/VoronoiSimplexSolver.js index bf09572..b967459 100644 --- a/src/BulletCollision/NarrowPhaseCollision/VoronoiSimplexSolver.js +++ b/src/BulletCollision/NarrowPhaseCollision/VoronoiSimplexSolver.js @@ -129,10 +129,10 @@ }, isValid: function() { - var valid = ( ( this.barycentricCoords[0] >= 0 ) && - ( this.barycentricCoords[1] >= 0 ) && - ( this.barycentricCoords[2] >= 0 ) && - ( this.barycentricCoords[3] >= 0 ) ); + var valid = (( this.barycentricCoords[0] >= 0 ) && + ( this.barycentricCoords[1] >= 0 ) && + ( this.barycentricCoords[2] >= 0 ) && + ( this.barycentricCoords[3] >= 0 )); return valid; }, @@ -247,11 +247,11 @@ case 2: var from = this.simplexVectorW[0]; var to = this.simplexVectorW[1]; - // nearest = Bump.Vector3.create(); + // nearest = Bump.Vector3.create(); - var diff = p.subtract( from, tmpV3 ), - v = to.subtract( from, tmpV4 ), - t = v.dot( diff ); + var diff = p.subtract( from, tmpV3 ); + var v = to.subtract( from, tmpV4 ); + var t = v.dot( diff ); if ( t > 0 ) { var dotVV = v.dot( v ); @@ -272,7 +272,7 @@ this.cachedBC.usedVertices.usedVertexA = true; } this.cachedBC.setBarycentricCoordinates( 1 - t, t ); - // ASD: commented this out since it is apparently never used + // !!!: ASD: commented this out since it is apparently never used // nearest.assign( from.add( v.multiplyScalar( t, tmpV1 ), tmpV1 ) ); this.cachedP1.assign( this.simplexPointsP[0].add( this.simplexPointsP[1].subtract( this.simplexPointsP[0], tmpV1 ).multiplyScalar( t, tmpV1 ), tmpV1 ) ); From d54a1ff1581ca0b11424529d81d55ca76ec08218 Mon Sep 17 00:00:00 2001 From: Eric Li Date: Wed, 15 Aug 2012 11:40:09 -0400 Subject: [PATCH 22/22] Eschew clone for assign --- .../CollisionDispatch/CollisionWorld.js | 16 ++++++++-------- .../CollisionShapes/SphereShape.js | 2 +- .../NarrowPhaseCollision/SubSimplexConvexCast.js | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/BulletCollision/CollisionDispatch/CollisionWorld.js b/src/BulletCollision/CollisionDispatch/CollisionWorld.js index d45397c..f2a5b68 100644 --- a/src/BulletCollision/CollisionDispatch/CollisionWorld.js +++ b/src/BulletCollision/CollisionDispatch/CollisionWorld.js @@ -851,9 +851,9 @@ ); rcb.hitFraction = resultCallback.closestHitFraction; - var rayAabbMinLocal = rayFromLocal.clone( tmpVec1 ); + var rayAabbMinLocal = tmpVec1.assign( rayFromLocal ); rayAabbMinLocal.setMin( rayToLocal ); - var rayAabbMaxLocal = rayFromLocal.clone( tmpVec2 ); + var rayAabbMaxLocal = tmpVec2.assign( rayFromLocal ); rayAabbMaxLocal.setMax( rayToLocal ); concaveShape.processAllTriangles( rcb, rayAabbMinLocal, rayAabbMaxLocal ); @@ -878,12 +878,12 @@ ); if ( dbvt ) { - var localRayFrom = colObjWorldTransform - .inverseTimes( rayFromTrans, tmpTrans ) - .getOrigin().clone( tmpVec1 ); - var localRayTo = colObjWorldTransform - .inverseTimes( rayToTrans, tmpTrans ) - .getOrigin().clone( tmpVec2 ); + var localRayFrom = tmpVec1.assign( + colObjWorldTransform.inverseTimes( rayFromTrans, tmpTrans ).origin + ); + var localRayTo = tmpVec2.assign( + colObjWorldTransform.inverseTimes( rayToTrans, tmpTrans ).origin + ); Bump.Dbvt.rayTest( dbvt.root, localRayFrom, localRayTo, rayCB ); } else { for ( var i = 0, n = compoundShape.getNumChildShapes(); i < n; ++i ) { diff --git a/src/BulletCollision/CollisionShapes/SphereShape.js b/src/BulletCollision/CollisionShapes/SphereShape.js index 12216e4..e6d41b7 100644 --- a/src/BulletCollision/CollisionShapes/SphereShape.js +++ b/src/BulletCollision/CollisionShapes/SphereShape.js @@ -52,7 +52,7 @@ var supVertex = dest; supVertex = this.localGetSupportingVertexWithoutMargin( vec, supVertex ); - var vecnorm = vec.clone( tmpV1 ); + var vecnorm = tmpV1.assign( vec ); if ( vecnorm.length2() < Bump.SIMD_EPSILON * Bump.SIMD_EPSILON ) { vecnorm.setValue( -1, -1, -1 ); } diff --git a/src/BulletCollision/NarrowPhaseCollision/SubSimplexConvexCast.js b/src/BulletCollision/NarrowPhaseCollision/SubSimplexConvexCast.js index 101f441..f6ee107 100644 --- a/src/BulletCollision/NarrowPhaseCollision/SubSimplexConvexCast.js +++ b/src/BulletCollision/NarrowPhaseCollision/SubSimplexConvexCast.js @@ -50,8 +50,8 @@ var lambda = 0; - var interpolatedTransA = fromA.clone( tmpTITA ); - var interpolatedTransB = fromB.clone( tmpTITB ); + var interpolatedTransA = tmpTITA.assign( fromA ); + var interpolatedTransB = tmpTITB.assign( fromB ); // take relative motion var r = linVelA.subtract( linVelB, tmpVr );