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 
RigidBodyControl()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      */
RigidBodyControl(float mass)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      */
RigidBodyControl(CollisionShape shape)57     public RigidBodyControl(CollisionShape shape) {
58         super(shape);
59     }
60 
RigidBodyControl(CollisionShape shape, float mass)61     public RigidBodyControl(CollisionShape shape, float mass) {
62         super(shape, mass);
63     }
64 
cloneForSpatial(Spatial spatial)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 
setSpatial(Spatial spatial)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 
createCollisionShape()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 
setEnabled(boolean enabled)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 
isEnabled()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      */
isKinematicSpatial()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      */
setKinematicSpatial(boolean kinematicSpatial)170     public void setKinematicSpatial(boolean kinematicSpatial) {
171         this.kinematicSpatial = kinematicSpatial;
172     }
173 
isApplyPhysicsLocal()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      */
setApplyPhysicsLocal(boolean applyPhysicsLocal)183     public void setApplyPhysicsLocal(boolean applyPhysicsLocal) {
184         motionState.setApplyPhysicsLocal(applyPhysicsLocal);
185     }
186 
getSpatialTranslation()187     private Vector3f getSpatialTranslation(){
188         if(motionState.isApplyPhysicsLocal()){
189             return spatial.getLocalTranslation();
190         }
191         return spatial.getWorldTranslation();
192     }
193 
getSpatialRotation()194     private Quaternion getSpatialRotation(){
195         if(motionState.isApplyPhysicsLocal()){
196             return spatial.getLocalRotation();
197         }
198         return spatial.getWorldRotation();
199     }
200 
update(float tpf)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 
render(RenderManager rm, ViewPort vp)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 
setPhysicsSpace(PhysicsSpace space)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 
getPhysicsSpace()240     public PhysicsSpace getPhysicsSpace() {
241         return space;
242     }
243 
244     @Override
write(JmeExporter ex)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
read(JmeImporter im)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