/* * Java port of Bullet (c) 2008 Martin Dvorak <jezek2@advel.cz> * * Bullet Continuous Collision Detection and Physics Library * Copyright (c) 2003-2008 Erwin Coumans http://www.bulletphysics.com/ * * This software is provided 'as-is', without any express or implied warranty. * In no event will the authors be held liable for any damages arising from * the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ package com.bulletphysics.collision.dispatch; import com.bulletphysics.collision.broadphase.BroadphaseProxy; import com.bulletphysics.collision.broadphase.Dispatcher; import com.bulletphysics.collision.shapes.ConvexShape; import com.bulletphysics.linearmath.AabbUtil2; import com.bulletphysics.linearmath.Transform; import com.bulletphysics.linearmath.TransformUtil; import com.bulletphysics.util.ObjectArrayList; import com.bulletphysics.util.Stack; import javax.vecmath.Quat4f; import javax.vecmath.Vector3f; /** * GhostObject can keep track of all objects that are overlapping. By default, this * overlap is based on the AABB. This is useful for creating a character controller, * collision sensors/triggers, explosions etc. * * @author tomrbryn */ public class GhostObject extends CollisionObject { protected ObjectArrayList<CollisionObject> overlappingObjects = new ObjectArrayList<CollisionObject>(); public GhostObject() { this.internalType = CollisionObjectType.GHOST_OBJECT; } /** * This method is mainly for expert/internal use only. */ public void addOverlappingObjectInternal(BroadphaseProxy otherProxy, BroadphaseProxy thisProxy) { CollisionObject otherObject = (CollisionObject)otherProxy.clientObject; assert(otherObject != null); // if this linearSearch becomes too slow (too many overlapping objects) we should add a more appropriate data structure int index = overlappingObjects.indexOf(otherObject); if (index == -1) { // not found overlappingObjects.add(otherObject); } } /** * This method is mainly for expert/internal use only. */ public void removeOverlappingObjectInternal(BroadphaseProxy otherProxy, Dispatcher dispatcher, BroadphaseProxy thisProxy) { CollisionObject otherObject = (CollisionObject) otherProxy.clientObject; assert(otherObject != null); int index = overlappingObjects.indexOf(otherObject); if (index != -1) { overlappingObjects.set(index, overlappingObjects.getQuick(overlappingObjects.size()-1)); overlappingObjects.removeQuick(overlappingObjects.size()-1); } } public void convexSweepTest(ConvexShape castShape, Transform convexFromWorld, Transform convexToWorld, CollisionWorld.ConvexResultCallback resultCallback, float allowedCcdPenetration) { Stack stack = Stack.enter(); Transform convexFromTrans = stack.allocTransform(); Transform convexToTrans = stack.allocTransform(); convexFromTrans.set(convexFromWorld); convexToTrans.set(convexToWorld); Vector3f castShapeAabbMin = stack.allocVector3f(); Vector3f castShapeAabbMax = stack.allocVector3f(); // compute AABB that encompasses angular movement { Vector3f linVel = stack.allocVector3f(); Vector3f angVel = stack.allocVector3f(); TransformUtil.calculateVelocity(convexFromTrans, convexToTrans, 1f, linVel, angVel); Transform R = stack.allocTransform(); R.setIdentity(); R.setRotation(convexFromTrans.getRotation(stack.allocQuat4f())); castShape.calculateTemporalAabb(R, linVel, angVel, 1f, castShapeAabbMin, castShapeAabbMax); } Transform tmpTrans = stack.allocTransform(); // go over all objects, and if the ray intersects their aabb + cast shape aabb, // do a ray-shape query using convexCaster (CCD) for (int i=0; i<overlappingObjects.size(); i++) { CollisionObject collisionObject = overlappingObjects.getQuick(i); // only perform raycast if filterMask matches if (resultCallback.needsCollision(collisionObject.getBroadphaseHandle())) { //RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject(); Vector3f collisionObjectAabbMin = stack.allocVector3f(); Vector3f collisionObjectAabbMax = stack.allocVector3f(); collisionObject.getCollisionShape().getAabb(collisionObject.getWorldTransform(tmpTrans), collisionObjectAabbMin, collisionObjectAabbMax); AabbUtil2.aabbExpand(collisionObjectAabbMin, collisionObjectAabbMax, castShapeAabbMin, castShapeAabbMax); float[] hitLambda = new float[]{1f}; // could use resultCallback.closestHitFraction, but needs testing Vector3f hitNormal = stack.allocVector3f(); if (AabbUtil2.rayAabb(convexFromWorld.origin, convexToWorld.origin, collisionObjectAabbMin, collisionObjectAabbMax, hitLambda, hitNormal)) { CollisionWorld.objectQuerySingle(castShape, convexFromTrans, convexToTrans, collisionObject, collisionObject.getCollisionShape(), collisionObject.getWorldTransform(tmpTrans), resultCallback, allowedCcdPenetration); } } } stack.leave(); } public void rayTest(Vector3f rayFromWorld, Vector3f rayToWorld, CollisionWorld.RayResultCallback resultCallback) { Stack stack = Stack.enter(); Transform rayFromTrans = stack.allocTransform(); rayFromTrans.setIdentity(); rayFromTrans.origin.set(rayFromWorld); Transform rayToTrans = stack.allocTransform(); rayToTrans.setIdentity(); rayToTrans.origin.set(rayToWorld); Transform tmpTrans = stack.allocTransform(); for (int i=0; i<overlappingObjects.size(); i++) { CollisionObject collisionObject = overlappingObjects.getQuick(i); // only perform raycast if filterMask matches if (resultCallback.needsCollision(collisionObject.getBroadphaseHandle())) { CollisionWorld.rayTestSingle(rayFromTrans, rayToTrans, collisionObject, collisionObject.getCollisionShape(), collisionObject.getWorldTransform(tmpTrans), resultCallback); } } stack.leave(); } public int getNumOverlappingObjects() { return overlappingObjects.size(); } public CollisionObject getOverlappingObject(int index) { return overlappingObjects.getQuick(index); } public ObjectArrayList<CollisionObject> getOverlappingPairs() { return overlappingObjects; } // // internal cast // public static GhostObject upcast(CollisionObject colObj) { if (colObj.getInternalType() == CollisionObjectType.GHOST_OBJECT) { return (GhostObject)colObj; } return null; } }