1 /* 2 * Copyright (c) 2009-2010 jMonkeyEngine 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package com.jme3.bullet.objects; 33 34 import com.bulletphysics.collision.dispatch.CollisionFlags; 35 import com.bulletphysics.collision.dispatch.PairCachingGhostObject; 36 import com.bulletphysics.linearmath.Transform; 37 import com.jme3.bullet.collision.PhysicsCollisionObject; 38 import com.jme3.bullet.collision.shapes.CollisionShape; 39 import com.jme3.bullet.util.Converter; 40 import com.jme3.export.InputCapsule; 41 import com.jme3.export.JmeExporter; 42 import com.jme3.export.JmeImporter; 43 import com.jme3.export.OutputCapsule; 44 import com.jme3.math.Matrix3f; 45 import com.jme3.math.Quaternion; 46 import com.jme3.math.Vector3f; 47 import com.jme3.scene.Spatial; 48 import java.io.IOException; 49 import java.util.LinkedList; 50 import java.util.List; 51 52 /** 53 * <i>From Bullet manual:</i><br> 54 * GhostObject can keep track of all objects that are overlapping. 55 * By default, this overlap is based on the AABB. 56 * This is useful for creating a character controller, 57 * collision sensors/triggers, explosions etc.<br> 58 * @author normenhansen 59 */ 60 public class PhysicsGhostObject extends PhysicsCollisionObject { 61 62 protected PairCachingGhostObject gObject; 63 protected boolean locationDirty = false; 64 //TEMP VARIABLES 65 protected final Quaternion tmp_inverseWorldRotation = new Quaternion(); 66 protected Transform tempTrans = new Transform(Converter.convert(new Matrix3f())); 67 private com.jme3.math.Transform physicsLocation = new com.jme3.math.Transform(); 68 protected javax.vecmath.Quat4f tempRot = new javax.vecmath.Quat4f(); 69 private List<PhysicsCollisionObject> overlappingObjects = new LinkedList<PhysicsCollisionObject>(); 70 71 public PhysicsGhostObject() { 72 } 73 74 public PhysicsGhostObject(CollisionShape shape) { 75 collisionShape = shape; 76 buildObject(); 77 } 78 79 public PhysicsGhostObject(Spatial child, CollisionShape shape) { 80 collisionShape = shape; 81 buildObject(); 82 } 83 84 protected void buildObject() { 85 if (gObject == null) { 86 gObject = new PairCachingGhostObject(); 87 gObject.setCollisionFlags(gObject.getCollisionFlags() | CollisionFlags.NO_CONTACT_RESPONSE); 88 } 89 gObject.setCollisionShape(collisionShape.getCShape()); 90 gObject.setUserPointer(this); 91 } 92 93 @Override 94 public void setCollisionShape(CollisionShape collisionShape) { 95 super.setCollisionShape(collisionShape); 96 if (gObject == null) { 97 buildObject(); 98 }else{ 99 gObject.setCollisionShape(collisionShape.getCShape()); 100 } 101 } 102 103 /** 104 * Sets the physics object location 105 * @param location the location of the actual physics object 106 */ 107 public void setPhysicsLocation(Vector3f location) { 108 gObject.getWorldTransform(tempTrans); 109 Converter.convert(location, tempTrans.origin); 110 gObject.setWorldTransform(tempTrans); 111 } 112 113 /** 114 * Sets the physics object rotation 115 * @param rotation the rotation of the actual physics object 116 */ 117 public void setPhysicsRotation(Matrix3f rotation) { 118 gObject.getWorldTransform(tempTrans); 119 Converter.convert(rotation, tempTrans.basis); 120 gObject.setWorldTransform(tempTrans); 121 } 122 123 /** 124 * Sets the physics object rotation 125 * @param rotation the rotation of the actual physics object 126 */ 127 public void setPhysicsRotation(Quaternion rotation) { 128 gObject.getWorldTransform(tempTrans); 129 Converter.convert(rotation, tempTrans.basis); 130 gObject.setWorldTransform(tempTrans); 131 } 132 133 /** 134 * @return the physicsLocation 135 */ 136 public com.jme3.math.Transform getPhysicsTransform() { 137 return physicsLocation; 138 } 139 140 /** 141 * @return the physicsLocation 142 */ 143 public Vector3f getPhysicsLocation(Vector3f trans) { 144 if (trans == null) { 145 trans = new Vector3f(); 146 } 147 gObject.getWorldTransform(tempTrans); 148 Converter.convert(tempTrans.origin, physicsLocation.getTranslation()); 149 return trans.set(physicsLocation.getTranslation()); 150 } 151 152 /** 153 * @return the physicsLocation 154 */ 155 public Quaternion getPhysicsRotation(Quaternion rot) { 156 if (rot == null) { 157 rot = new Quaternion(); 158 } 159 gObject.getWorldTransform(tempTrans); 160 Converter.convert(tempTrans.getRotation(tempRot), physicsLocation.getRotation()); 161 return rot.set(physicsLocation.getRotation()); 162 } 163 164 /** 165 * @return the physicsLocation 166 */ 167 public Matrix3f getPhysicsRotationMatrix(Matrix3f rot) { 168 if (rot == null) { 169 rot = new Matrix3f(); 170 } 171 gObject.getWorldTransform(tempTrans); 172 Converter.convert(tempTrans.getRotation(tempRot), physicsLocation.getRotation()); 173 return rot.set(physicsLocation.getRotation()); 174 } 175 176 /** 177 * @return the physicsLocation 178 */ 179 public Vector3f getPhysicsLocation() { 180 gObject.getWorldTransform(tempTrans); 181 Converter.convert(tempTrans.origin, physicsLocation.getTranslation()); 182 return physicsLocation.getTranslation(); 183 } 184 185 /** 186 * @return the physicsLocation 187 */ 188 public Quaternion getPhysicsRotation() { 189 gObject.getWorldTransform(tempTrans); 190 Converter.convert(tempTrans.getRotation(tempRot), physicsLocation.getRotation()); 191 return physicsLocation.getRotation(); 192 } 193 194 public Matrix3f getPhysicsRotationMatrix() { 195 gObject.getWorldTransform(tempTrans); 196 Converter.convert(tempTrans.getRotation(tempRot), physicsLocation.getRotation()); 197 return physicsLocation.getRotation().toRotationMatrix(); 198 } 199 200 /** 201 * used internally 202 */ 203 public PairCachingGhostObject getObjectId() { 204 return gObject; 205 } 206 207 /** 208 * destroys this PhysicsGhostNode and removes it from memory 209 */ 210 public void destroy() { 211 } 212 213 /** 214 * Another Object is overlapping with this GhostNode, 215 * if and if only there CollisionShapes overlaps. 216 * They could be both regular PhysicsRigidBodys or PhysicsGhostObjects. 217 * @return All CollisionObjects overlapping with this GhostNode. 218 */ 219 public List<PhysicsCollisionObject> getOverlappingObjects() { 220 overlappingObjects.clear(); 221 for (com.bulletphysics.collision.dispatch.CollisionObject collObj : gObject.getOverlappingPairs()) { 222 overlappingObjects.add((PhysicsCollisionObject) collObj.getUserPointer()); 223 } 224 return overlappingObjects; 225 } 226 227 /** 228 * 229 * @return With how many other CollisionObjects this GhostNode is currently overlapping. 230 */ 231 public int getOverlappingCount() { 232 return gObject.getNumOverlappingObjects(); 233 } 234 235 /** 236 * 237 * @param index The index of the overlapping Node to retrieve. 238 * @return The Overlapping CollisionObject at the given index. 239 */ 240 public PhysicsCollisionObject getOverlapping(int index) { 241 return overlappingObjects.get(index); 242 } 243 244 public void setCcdSweptSphereRadius(float radius) { 245 gObject.setCcdSweptSphereRadius(radius); 246 } 247 248 public void setCcdMotionThreshold(float threshold) { 249 gObject.setCcdMotionThreshold(threshold); 250 } 251 252 public float getCcdSweptSphereRadius() { 253 return gObject.getCcdSweptSphereRadius(); 254 } 255 256 public float getCcdMotionThreshold() { 257 return gObject.getCcdMotionThreshold(); 258 } 259 260 public float getCcdSquareMotionThreshold() { 261 return gObject.getCcdSquareMotionThreshold(); 262 } 263 264 @Override 265 public void write(JmeExporter e) throws IOException { 266 super.write(e); 267 OutputCapsule capsule = e.getCapsule(this); 268 capsule.write(getPhysicsLocation(new Vector3f()), "physicsLocation", new Vector3f()); 269 capsule.write(getPhysicsRotationMatrix(new Matrix3f()), "physicsRotation", new Matrix3f()); 270 capsule.write(getCcdMotionThreshold(), "ccdMotionThreshold", 0); 271 capsule.write(getCcdSweptSphereRadius(), "ccdSweptSphereRadius", 0); 272 } 273 274 @Override 275 public void read(JmeImporter e) throws IOException { 276 super.read(e); 277 InputCapsule capsule = e.getCapsule(this); 278 buildObject(); 279 setPhysicsLocation((Vector3f) capsule.readSavable("physicsLocation", new Vector3f())); 280 setPhysicsRotation(((Matrix3f) capsule.readSavable("physicsRotation", new Matrix3f()))); 281 setCcdMotionThreshold(capsule.readFloat("ccdMotionThreshold", 0)); 282 setCcdSweptSphereRadius(capsule.readFloat("ccdSweptSphereRadius", 0)); 283 } 284 } 285