Home | History | Annotate | Download | only in control
      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