1 /* 2 * To change this template, choose Tools | Templates 3 * and open the template in the editor. 4 */ 5 package com.jme3.bullet.control; 6 7 import com.jme3.bullet.PhysicsSpace; 8 import com.jme3.bullet.collision.shapes.BoxCollisionShape; 9 import com.jme3.bullet.collision.shapes.CollisionShape; 10 import com.jme3.bullet.collision.shapes.SphereCollisionShape; 11 import com.jme3.bullet.objects.PhysicsRigidBody; 12 import com.jme3.bullet.util.CollisionShapeFactory; 13 import com.jme3.export.InputCapsule; 14 import com.jme3.export.JmeExporter; 15 import com.jme3.export.JmeImporter; 16 import com.jme3.export.OutputCapsule; 17 import com.jme3.math.Quaternion; 18 import com.jme3.math.Vector3f; 19 import com.jme3.renderer.RenderManager; 20 import com.jme3.renderer.ViewPort; 21 import com.jme3.scene.Geometry; 22 import com.jme3.scene.Mesh; 23 import com.jme3.scene.Spatial; 24 import com.jme3.scene.control.Control; 25 import com.jme3.scene.shape.Box; 26 import com.jme3.scene.shape.Sphere; 27 import java.io.IOException; 28 29 /** 30 * 31 * @author normenhansen 32 */ 33 public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl { 34 35 protected Spatial spatial; 36 protected boolean enabled = true; 37 protected boolean added = false; 38 protected PhysicsSpace space = null; 39 protected boolean kinematicSpatial = true; 40 41 public RigidBodyControl() { 42 } 43 44 /** 45 * When using this constructor, the CollisionShape for the RigidBody is generated 46 * automatically when the Control is added to a Spatial. 47 * @param mass When not 0, a HullCollisionShape is generated, otherwise a MeshCollisionShape is used. For geometries with box or sphere meshes the proper box or sphere collision shape is used. 48 */ 49 public RigidBodyControl(float mass) { 50 this.mass = mass; 51 } 52 53 /** 54 * Creates a new PhysicsNode with the supplied collision shape and mass 1 55 * @param shape 56 */ 57 public RigidBodyControl(CollisionShape shape) { 58 super(shape); 59 } 60 61 public RigidBodyControl(CollisionShape shape, float mass) { 62 super(shape, mass); 63 } 64 65 public Control cloneForSpatial(Spatial spatial) { 66 RigidBodyControl control = new RigidBodyControl(collisionShape, mass); 67 control.setAngularFactor(getAngularFactor()); 68 control.setAngularSleepingThreshold(getAngularSleepingThreshold()); 69 control.setCcdMotionThreshold(getCcdMotionThreshold()); 70 control.setCcdSweptSphereRadius(getCcdSweptSphereRadius()); 71 control.setCollideWithGroups(getCollideWithGroups()); 72 control.setCollisionGroup(getCollisionGroup()); 73 control.setDamping(getLinearDamping(), getAngularDamping()); 74 control.setFriction(getFriction()); 75 control.setGravity(getGravity()); 76 control.setKinematic(isKinematic()); 77 control.setKinematicSpatial(isKinematicSpatial()); 78 control.setLinearSleepingThreshold(getLinearSleepingThreshold()); 79 control.setPhysicsLocation(getPhysicsLocation(null)); 80 control.setPhysicsRotation(getPhysicsRotationMatrix(null)); 81 control.setRestitution(getRestitution()); 82 83 if (mass > 0) { 84 control.setAngularVelocity(getAngularVelocity()); 85 control.setLinearVelocity(getLinearVelocity()); 86 } 87 control.setApplyPhysicsLocal(isApplyPhysicsLocal()); 88 89 control.setSpatial(spatial); 90 return control; 91 } 92 93 public void setSpatial(Spatial spatial) { 94 if (getUserObject() == null || getUserObject() == this.spatial) { 95 setUserObject(spatial); 96 } 97 this.spatial = spatial; 98 if (spatial == null) { 99 if (getUserObject() == spatial) { 100 setUserObject(null); 101 } 102 spatial = null; 103 collisionShape = null; 104 return; 105 } 106 if (collisionShape == null) { 107 createCollisionShape(); 108 rebuildRigidBody(); 109 } 110 setPhysicsLocation(getSpatialTranslation()); 111 setPhysicsRotation(getSpatialRotation()); 112 } 113 114 protected void createCollisionShape() { 115 if (spatial == null) { 116 return; 117 } 118 if (spatial instanceof Geometry) { 119 Geometry geom = (Geometry) spatial; 120 Mesh mesh = geom.getMesh(); 121 if (mesh instanceof Sphere) { 122 collisionShape = new SphereCollisionShape(((Sphere) mesh).getRadius()); 123 return; 124 } else if (mesh instanceof Box) { 125 collisionShape = new BoxCollisionShape(new Vector3f(((Box) mesh).getXExtent(), ((Box) mesh).getYExtent(), ((Box) mesh).getZExtent())); 126 return; 127 } 128 } 129 if (mass > 0) { 130 collisionShape = CollisionShapeFactory.createDynamicMeshShape(spatial); 131 } else { 132 collisionShape = CollisionShapeFactory.createMeshShape(spatial); 133 } 134 } 135 136 public void setEnabled(boolean enabled) { 137 this.enabled = enabled; 138 if (space != null) { 139 if (enabled && !added) { 140 if (spatial != null) { 141 setPhysicsLocation(getSpatialTranslation()); 142 setPhysicsRotation(getSpatialRotation()); 143 } 144 space.addCollisionObject(this); 145 added = true; 146 } else if (!enabled && added) { 147 space.removeCollisionObject(this); 148 added = false; 149 } 150 } 151 } 152 153 public boolean isEnabled() { 154 return enabled; 155 } 156 157 /** 158 * Checks if this control is in kinematic spatial mode. 159 * @return true if the spatial location is applied to this kinematic rigidbody 160 */ 161 public boolean isKinematicSpatial() { 162 return kinematicSpatial; 163 } 164 165 /** 166 * Sets this control to kinematic spatial mode so that the spatials transform will 167 * be applied to the rigidbody in kinematic mode, defaults to true. 168 * @param kinematicSpatial 169 */ 170 public void setKinematicSpatial(boolean kinematicSpatial) { 171 this.kinematicSpatial = kinematicSpatial; 172 } 173 174 public boolean isApplyPhysicsLocal() { 175 return motionState.isApplyPhysicsLocal(); 176 } 177 178 /** 179 * When set to true, the physics coordinates will be applied to the local 180 * translation of the Spatial instead of the world traslation. 181 * @param applyPhysicsLocal 182 */ 183 public void setApplyPhysicsLocal(boolean applyPhysicsLocal) { 184 motionState.setApplyPhysicsLocal(applyPhysicsLocal); 185 } 186 187 private Vector3f getSpatialTranslation(){ 188 if(motionState.isApplyPhysicsLocal()){ 189 return spatial.getLocalTranslation(); 190 } 191 return spatial.getWorldTranslation(); 192 } 193 194 private Quaternion getSpatialRotation(){ 195 if(motionState.isApplyPhysicsLocal()){ 196 return spatial.getLocalRotation(); 197 } 198 return spatial.getWorldRotation(); 199 } 200 201 public void update(float tpf) { 202 if (enabled && spatial != null) { 203 if (isKinematic() && kinematicSpatial) { 204 super.setPhysicsLocation(getSpatialTranslation()); 205 super.setPhysicsRotation(getSpatialRotation()); 206 } else { 207 getMotionState().applyTransform(spatial); 208 } 209 } 210 } 211 212 public void render(RenderManager rm, ViewPort vp) { 213 if (enabled && space != null && space.getDebugManager() != null) { 214 if (debugShape == null) { 215 attachDebugShape(space.getDebugManager()); 216 } 217 //TODO: using spatial traslation/rotation.. 218 debugShape.setLocalTranslation(spatial.getWorldTranslation()); 219 debugShape.setLocalRotation(spatial.getWorldRotation()); 220 debugShape.updateLogicalState(0); 221 debugShape.updateGeometricState(); 222 rm.renderScene(debugShape, vp); 223 } 224 } 225 226 public void setPhysicsSpace(PhysicsSpace space) { 227 if (space == null) { 228 if (this.space != null) { 229 this.space.removeCollisionObject(this); 230 added = false; 231 } 232 } else { 233 if(this.space==space) return; 234 space.addCollisionObject(this); 235 added = true; 236 } 237 this.space = space; 238 } 239 240 public PhysicsSpace getPhysicsSpace() { 241 return space; 242 } 243 244 @Override 245 public void write(JmeExporter ex) throws IOException { 246 super.write(ex); 247 OutputCapsule oc = ex.getCapsule(this); 248 oc.write(enabled, "enabled", true); 249 oc.write(motionState.isApplyPhysicsLocal(), "applyLocalPhysics", false); 250 oc.write(kinematicSpatial, "kinematicSpatial", true); 251 oc.write(spatial, "spatial", null); 252 } 253 254 @Override 255 public void read(JmeImporter im) throws IOException { 256 super.read(im); 257 InputCapsule ic = im.getCapsule(this); 258 enabled = ic.readBoolean("enabled", true); 259 kinematicSpatial = ic.readBoolean("kinematicSpatial", true); 260 spatial = (Spatial) ic.readSavable("spatial", null); 261 motionState.setApplyPhysicsLocal(ic.readBoolean("applyLocalPhysics", false)); 262 setUserObject(spatial); 263 } 264 } 265