1/*
2 * Copyright (c) 2009-2012 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 */
32package com.jme3.bullet.objects;
33
34import com.bulletphysics.collision.dispatch.CollisionFlags;
35import com.bulletphysics.dynamics.RigidBody;
36import com.bulletphysics.dynamics.RigidBodyConstructionInfo;
37import com.bulletphysics.linearmath.Transform;
38import com.jme3.bullet.PhysicsSpace;
39import com.jme3.bullet.collision.PhysicsCollisionObject;
40import com.jme3.bullet.collision.shapes.CollisionShape;
41import com.jme3.bullet.collision.shapes.MeshCollisionShape;
42import com.jme3.bullet.joints.PhysicsJoint;
43import com.jme3.bullet.objects.infos.RigidBodyMotionState;
44import com.jme3.bullet.util.Converter;
45import com.jme3.export.InputCapsule;
46import com.jme3.export.JmeExporter;
47import com.jme3.export.JmeImporter;
48import com.jme3.export.OutputCapsule;
49import com.jme3.math.Matrix3f;
50import com.jme3.math.Quaternion;
51import com.jme3.math.Vector3f;
52import com.jme3.scene.Geometry;
53import com.jme3.scene.Node;
54import com.jme3.scene.Spatial;
55import com.jme3.scene.debug.Arrow;
56import java.io.IOException;
57import java.util.ArrayList;
58import java.util.Iterator;
59import java.util.List;
60
61/**
62 * <p>PhysicsRigidBody - Basic physics object</p>
63 * @author normenhansen
64 */
65public class PhysicsRigidBody extends PhysicsCollisionObject {
66
67    protected RigidBodyConstructionInfo constructionInfo;
68    protected RigidBody rBody;
69    protected RigidBodyMotionState motionState = new RigidBodyMotionState();
70    protected float mass = 1.0f;
71    protected boolean kinematic = false;
72    protected javax.vecmath.Vector3f tempVec = new javax.vecmath.Vector3f();
73    protected javax.vecmath.Vector3f tempVec2 = new javax.vecmath.Vector3f();
74    protected Transform tempTrans = new Transform(new javax.vecmath.Matrix3f());
75    protected javax.vecmath.Matrix3f tempMatrix = new javax.vecmath.Matrix3f();
76    //TEMP VARIABLES
77    protected javax.vecmath.Vector3f localInertia = new javax.vecmath.Vector3f();
78    protected ArrayList<PhysicsJoint> joints = new ArrayList<PhysicsJoint>();
79
80    public PhysicsRigidBody() {
81    }
82
83    /**
84     * Creates a new PhysicsRigidBody with the supplied collision shape
85     * @param shape
86     */
87    public PhysicsRigidBody(CollisionShape shape) {
88        collisionShape = shape;
89        rebuildRigidBody();
90    }
91
92    public PhysicsRigidBody(CollisionShape shape, float mass) {
93        collisionShape = shape;
94        this.mass = mass;
95        rebuildRigidBody();
96    }
97
98    /**
99     * Builds/rebuilds the phyiscs body when parameters have changed
100     */
101    protected void rebuildRigidBody() {
102        boolean removed = false;
103        if(collisionShape instanceof MeshCollisionShape && mass != 0){
104            throw new IllegalStateException("Dynamic rigidbody can not have mesh collision shape!");
105        }
106        if (rBody != null) {
107            if (rBody.isInWorld()) {
108                PhysicsSpace.getPhysicsSpace().remove(this);
109                removed = true;
110            }
111            rBody.destroy();
112        }
113        preRebuild();
114        rBody = new RigidBody(constructionInfo);
115        postRebuild();
116        if (removed) {
117            PhysicsSpace.getPhysicsSpace().add(this);
118        }
119    }
120
121    protected void preRebuild() {
122        collisionShape.calculateLocalInertia(mass, localInertia);
123        if (constructionInfo == null) {
124            constructionInfo = new RigidBodyConstructionInfo(mass, motionState, collisionShape.getCShape(), localInertia);
125        } else {
126            constructionInfo.mass = mass;
127            constructionInfo.collisionShape = collisionShape.getCShape();
128            constructionInfo.motionState = motionState;
129        }
130    }
131
132    protected void postRebuild() {
133        rBody.setUserPointer(this);
134        if (mass == 0.0f) {
135            rBody.setCollisionFlags(rBody.getCollisionFlags() | CollisionFlags.STATIC_OBJECT);
136        } else {
137            rBody.setCollisionFlags(rBody.getCollisionFlags() & ~CollisionFlags.STATIC_OBJECT);
138        }
139    }
140
141    /**
142     * @return the motionState
143     */
144    public RigidBodyMotionState getMotionState() {
145        return motionState;
146    }
147
148    /**
149     * Sets the physics object location
150     * @param location the location of the actual physics object
151     */
152    public void setPhysicsLocation(Vector3f location) {
153        rBody.getCenterOfMassTransform(tempTrans);
154        Converter.convert(location, tempTrans.origin);
155        rBody.setCenterOfMassTransform(tempTrans);
156        motionState.setWorldTransform(tempTrans);
157    }
158
159    /**
160     * Sets the physics object rotation
161     * @param rotation the rotation of the actual physics object
162     */
163    public void setPhysicsRotation(Matrix3f rotation) {
164        rBody.getCenterOfMassTransform(tempTrans);
165        Converter.convert(rotation, tempTrans.basis);
166        rBody.setCenterOfMassTransform(tempTrans);
167        motionState.setWorldTransform(tempTrans);
168    }
169
170    /**
171     * Sets the physics object rotation
172     * @param rotation the rotation of the actual physics object
173     */
174    public void setPhysicsRotation(Quaternion rotation) {
175        rBody.getCenterOfMassTransform(tempTrans);
176        Converter.convert(rotation, tempTrans.basis);
177        rBody.setCenterOfMassTransform(tempTrans);
178        motionState.setWorldTransform(tempTrans);
179    }
180
181    /**
182     * Gets the physics object location, instantiates a new Vector3f object
183     */
184    public Vector3f getPhysicsLocation() {
185        return getPhysicsLocation(null);
186    }
187
188    /**
189     * Gets the physics object rotation
190     */
191    public Matrix3f getPhysicsRotationMatrix() {
192        return getPhysicsRotationMatrix(null);
193    }
194
195    /**
196     * Gets the physics object location, no object instantiation
197     * @param location the location of the actual physics object is stored in this Vector3f
198     */
199    public Vector3f getPhysicsLocation(Vector3f location) {
200        if (location == null) {
201            location = new Vector3f();
202        }
203        rBody.getCenterOfMassTransform(tempTrans);
204        return Converter.convert(tempTrans.origin, location);
205    }
206
207    /**
208     * Gets the physics object rotation as a matrix, no conversions and no object instantiation
209     * @param rotation the rotation of the actual physics object is stored in this Matrix3f
210     */
211    public Matrix3f getPhysicsRotationMatrix(Matrix3f rotation) {
212        if (rotation == null) {
213            rotation = new Matrix3f();
214        }
215        rBody.getCenterOfMassTransform(tempTrans);
216        return Converter.convert(tempTrans.basis, rotation);
217    }
218
219    /**
220     * Gets the physics object rotation as a quaternion, converts the bullet Matrix3f value,
221     * instantiates new object
222     */
223    public Quaternion getPhysicsRotation(){
224        return getPhysicsRotation(null);
225    }
226
227    /**
228     * Gets the physics object rotation as a quaternion, converts the bullet Matrix3f value
229     * @param rotation the rotation of the actual physics object is stored in this Quaternion
230     */
231    public Quaternion getPhysicsRotation(Quaternion rotation){
232        if (rotation == null) {
233            rotation = new Quaternion();
234        }
235        rBody.getCenterOfMassTransform(tempTrans);
236        return Converter.convert(tempTrans.basis, rotation);
237    }
238
239    /**
240     * Gets the physics object location
241     * @param location the location of the actual physics object is stored in this Vector3f
242     */
243    public Vector3f getInterpolatedPhysicsLocation(Vector3f location) {
244        if (location == null) {
245            location = new Vector3f();
246        }
247        rBody.getInterpolationWorldTransform(tempTrans);
248        return Converter.convert(tempTrans.origin, location);
249    }
250
251    /**
252     * Gets the physics object rotation
253     * @param rotation the rotation of the actual physics object is stored in this Matrix3f
254     */
255    public Matrix3f getInterpolatedPhysicsRotation(Matrix3f rotation) {
256        if (rotation == null) {
257            rotation = new Matrix3f();
258        }
259        rBody.getInterpolationWorldTransform(tempTrans);
260        return Converter.convert(tempTrans.basis, rotation);
261    }
262
263    /**
264     * Sets the node to kinematic mode. in this mode the node is not affected by physics
265     * but affects other physics objects. Its kinetic force is calculated by the amount
266     * of movement it is exposed to and its weight.
267     * @param kinematic
268     */
269    public void setKinematic(boolean kinematic) {
270        this.kinematic = kinematic;
271        if (kinematic) {
272            rBody.setCollisionFlags(rBody.getCollisionFlags() | CollisionFlags.KINEMATIC_OBJECT);
273            rBody.setActivationState(com.bulletphysics.collision.dispatch.CollisionObject.DISABLE_DEACTIVATION);
274        } else {
275            rBody.setCollisionFlags(rBody.getCollisionFlags() & ~CollisionFlags.KINEMATIC_OBJECT);
276            rBody.setActivationState(com.bulletphysics.collision.dispatch.CollisionObject.ACTIVE_TAG);
277        }
278    }
279
280    public boolean isKinematic() {
281        return kinematic;
282    }
283
284    public void setCcdSweptSphereRadius(float radius) {
285        rBody.setCcdSweptSphereRadius(radius);
286    }
287
288    /**
289     * Sets the amount of motion that has to happen in one physics tick to trigger the continuous motion detection<br/>
290     * This avoids the problem of fast objects moving through other objects, set to zero to disable (default)
291     * @param threshold
292     */
293    public void setCcdMotionThreshold(float threshold) {
294        rBody.setCcdMotionThreshold(threshold);
295    }
296
297    public float getCcdSweptSphereRadius() {
298        return rBody.getCcdSweptSphereRadius();
299    }
300
301    public float getCcdMotionThreshold() {
302        return rBody.getCcdMotionThreshold();
303    }
304
305    public float getCcdSquareMotionThreshold() {
306        return rBody.getCcdSquareMotionThreshold();
307    }
308
309    public float getMass() {
310        return mass;
311    }
312
313    /**
314     * Sets the mass of this PhysicsRigidBody, objects with mass=0 are static.
315     * @param mass
316     */
317    public void setMass(float mass) {
318        this.mass = mass;
319        if(collisionShape instanceof MeshCollisionShape && mass != 0){
320            throw new IllegalStateException("Dynamic rigidbody can not have mesh collision shape!");
321        }
322        if (collisionShape != null) {
323            collisionShape.calculateLocalInertia(mass, localInertia);
324        }
325        if (rBody != null) {
326            rBody.setMassProps(mass, localInertia);
327            if (mass == 0.0f) {
328                rBody.setCollisionFlags(rBody.getCollisionFlags() | CollisionFlags.STATIC_OBJECT);
329            } else {
330                rBody.setCollisionFlags(rBody.getCollisionFlags() & ~CollisionFlags.STATIC_OBJECT);
331            }
332        }
333    }
334
335    public Vector3f getGravity() {
336        return getGravity(null);
337    }
338
339    public Vector3f getGravity(Vector3f gravity) {
340        if (gravity == null) {
341            gravity = new Vector3f();
342        }
343        rBody.getGravity(tempVec);
344        return Converter.convert(tempVec, gravity);
345    }
346
347    /**
348     * Set the local gravity of this PhysicsRigidBody<br/>
349     * Set this after adding the node to the PhysicsSpace,
350     * the PhysicsSpace assigns its current gravity to the physics node when its added.
351     * @param gravity the gravity vector to set
352     */
353    public void setGravity(Vector3f gravity) {
354        rBody.setGravity(Converter.convert(gravity, tempVec));
355    }
356
357    public float getFriction() {
358        return rBody.getFriction();
359    }
360
361    /**
362     * Sets the friction of this physics object
363     * @param friction the friction of this physics object
364     */
365    public void setFriction(float friction) {
366        constructionInfo.friction = friction;
367        rBody.setFriction(friction);
368    }
369
370    public void setDamping(float linearDamping, float angularDamping) {
371        constructionInfo.linearDamping = linearDamping;
372        constructionInfo.angularDamping = angularDamping;
373        rBody.setDamping(linearDamping, angularDamping);
374    }
375
376    public void setLinearDamping(float linearDamping) {
377        constructionInfo.linearDamping = linearDamping;
378        rBody.setDamping(linearDamping, constructionInfo.angularDamping);
379    }
380
381    public void setAngularDamping(float angularDamping) {
382        constructionInfo.angularDamping = angularDamping;
383        rBody.setDamping(constructionInfo.linearDamping, angularDamping);
384    }
385
386    public float getLinearDamping() {
387        return constructionInfo.linearDamping;
388    }
389
390    public float getAngularDamping() {
391        return constructionInfo.angularDamping;
392    }
393
394    public float getRestitution() {
395        return rBody.getRestitution();
396    }
397
398    /**
399     * The "bouncyness" of the PhysicsRigidBody, best performance if restitution=0
400     * @param restitution
401     */
402    public void setRestitution(float restitution) {
403        constructionInfo.restitution = restitution;
404        rBody.setRestitution(restitution);
405    }
406
407    /**
408     * Get the current angular velocity of this PhysicsRigidBody
409     * @return the current linear velocity
410     */
411    public Vector3f getAngularVelocity() {
412        return Converter.convert(rBody.getAngularVelocity(tempVec));
413    }
414
415    /**
416     * Get the current angular velocity of this PhysicsRigidBody
417     * @param vec the vector to store the velocity in
418     */
419    public void getAngularVelocity(Vector3f vec) {
420        Converter.convert(rBody.getAngularVelocity(tempVec), vec);
421    }
422
423    /**
424     * Sets the angular velocity of this PhysicsRigidBody
425     * @param vec the angular velocity of this PhysicsRigidBody
426     */
427    public void setAngularVelocity(Vector3f vec) {
428        rBody.setAngularVelocity(Converter.convert(vec, tempVec));
429        rBody.activate();
430    }
431
432    /**
433     * Get the current linear velocity of this PhysicsRigidBody
434     * @return the current linear velocity
435     */
436    public Vector3f getLinearVelocity() {
437        return Converter.convert(rBody.getLinearVelocity(tempVec));
438    }
439
440    /**
441     * Get the current linear velocity of this PhysicsRigidBody
442     * @param vec the vector to store the velocity in
443     */
444    public void getLinearVelocity(Vector3f vec) {
445        Converter.convert(rBody.getLinearVelocity(tempVec), vec);
446    }
447
448    /**
449     * Sets the linear velocity of this PhysicsRigidBody
450     * @param vec the linear velocity of this PhysicsRigidBody
451     */
452    public void setLinearVelocity(Vector3f vec) {
453        rBody.setLinearVelocity(Converter.convert(vec, tempVec));
454        rBody.activate();
455    }
456
457    /**
458     * Apply a force to the PhysicsRigidBody, only applies force if the next physics update call
459     * updates the physics space.<br>
460     * To apply an impulse, use applyImpulse, use applyContinuousForce to apply continuous force.
461     * @param force the force
462     * @param location the location of the force
463     */
464    public void applyForce(final Vector3f force, final Vector3f location) {
465        rBody.applyForce(Converter.convert(force, tempVec), Converter.convert(location, tempVec2));
466        rBody.activate();
467    }
468
469    /**
470     * Apply a force to the PhysicsRigidBody, only applies force if the next physics update call
471     * updates the physics space.<br>
472     * To apply an impulse, use applyImpulse.
473     *
474     * @param force the force
475     */
476    public void applyCentralForce(final Vector3f force) {
477        rBody.applyCentralForce(Converter.convert(force, tempVec));
478        rBody.activate();
479    }
480
481    /**
482     * Apply a force to the PhysicsRigidBody, only applies force if the next physics update call
483     * updates the physics space.<br>
484     * To apply an impulse, use applyImpulse.
485     *
486     * @param torque the torque
487     */
488    public void applyTorque(final Vector3f torque) {
489        rBody.applyTorque(Converter.convert(torque, tempVec));
490        rBody.activate();
491    }
492
493    /**
494     * Apply an impulse to the PhysicsRigidBody in the next physics update.
495     * @param impulse applied impulse
496     * @param rel_pos location relative to object
497     */
498    public void applyImpulse(final Vector3f impulse, final Vector3f rel_pos) {
499        rBody.applyImpulse(Converter.convert(impulse, tempVec), Converter.convert(rel_pos, tempVec2));
500        rBody.activate();
501    }
502
503    /**
504     * Apply a torque impulse to the PhysicsRigidBody in the next physics update.
505     * @param vec
506     */
507    public void applyTorqueImpulse(final Vector3f vec) {
508        rBody.applyTorqueImpulse(Converter.convert(vec, tempVec));
509        rBody.activate();
510    }
511
512    /**
513     * Clear all forces from the PhysicsRigidBody
514     *
515     */
516    public void clearForces() {
517        rBody.clearForces();
518    }
519
520    public void setCollisionShape(CollisionShape collisionShape) {
521        super.setCollisionShape(collisionShape);
522        if(collisionShape instanceof MeshCollisionShape && mass!=0){
523            throw new IllegalStateException("Dynamic rigidbody can not have mesh collision shape!");
524        }
525        if (rBody == null) {
526            rebuildRigidBody();
527        } else {
528            collisionShape.calculateLocalInertia(mass, localInertia);
529            constructionInfo.collisionShape = collisionShape.getCShape();
530            rBody.setCollisionShape(collisionShape.getCShape());
531        }
532    }
533
534    /**
535     * reactivates this PhysicsRigidBody when it has been deactivated because it was not moving
536     */
537    public void activate() {
538        rBody.activate();
539    }
540
541    public boolean isActive() {
542        return rBody.isActive();
543    }
544
545    /**
546     * sets the sleeping thresholds, these define when the object gets deactivated
547     * to save ressources. Low values keep the object active when it barely moves
548     * @param linear the linear sleeping threshold
549     * @param angular the angular sleeping threshold
550     */
551    public void setSleepingThresholds(float linear, float angular) {
552        constructionInfo.linearSleepingThreshold = linear;
553        constructionInfo.angularSleepingThreshold = angular;
554        rBody.setSleepingThresholds(linear, angular);
555    }
556
557    public void setLinearSleepingThreshold(float linearSleepingThreshold) {
558        constructionInfo.linearSleepingThreshold = linearSleepingThreshold;
559        rBody.setSleepingThresholds(linearSleepingThreshold, constructionInfo.angularSleepingThreshold);
560    }
561
562    public void setAngularSleepingThreshold(float angularSleepingThreshold) {
563        constructionInfo.angularSleepingThreshold = angularSleepingThreshold;
564        rBody.setSleepingThresholds(constructionInfo.linearSleepingThreshold, angularSleepingThreshold);
565    }
566
567    public float getLinearSleepingThreshold() {
568        return constructionInfo.linearSleepingThreshold;
569    }
570
571    public float getAngularSleepingThreshold() {
572        return constructionInfo.angularSleepingThreshold;
573    }
574
575    public float getAngularFactor() {
576        return rBody.getAngularFactor();
577    }
578
579    public void setAngularFactor(float factor) {
580        rBody.setAngularFactor(factor);
581    }
582
583    /**
584     * do not use manually, joints are added automatically
585     */
586    public void addJoint(PhysicsJoint joint) {
587        if (!joints.contains(joint)) {
588            joints.add(joint);
589        }
590        updateDebugShape();
591    }
592
593    /**
594     *
595     */
596    public void removeJoint(PhysicsJoint joint) {
597        joints.remove(joint);
598    }
599
600    /**
601     * Returns a list of connected joints. This list is only filled when
602     * the PhysicsRigidBody is actually added to the physics space or loaded from disk.
603     * @return list of active joints connected to this PhysicsRigidBody
604     */
605    public List<PhysicsJoint> getJoints() {
606        return joints;
607    }
608
609    /**
610     * used internally
611     */
612    public RigidBody getObjectId() {
613        return rBody;
614    }
615
616    /**
617     * destroys this PhysicsRigidBody and removes it from memory
618     */
619    public void destroy() {
620        rBody.destroy();
621    }
622
623    @Override
624    protected Spatial getDebugShape() {
625        //add joints
626        Spatial shape = super.getDebugShape();
627        Node node = null;
628        if (shape instanceof Node) {
629            node = (Node) shape;
630        } else {
631            node = new Node("DebugShapeNode");
632            node.attachChild(shape);
633        }
634        int i = 0;
635        for (Iterator<PhysicsJoint> it = joints.iterator(); it.hasNext();) {
636            PhysicsJoint physicsJoint = it.next();
637            Vector3f pivot = null;
638            if (physicsJoint.getBodyA() == this) {
639                pivot = physicsJoint.getPivotA();
640            } else {
641                pivot = physicsJoint.getPivotB();
642            }
643            Arrow arrow = new Arrow(pivot);
644            Geometry geom = new Geometry("DebugBone" + i, arrow);
645            geom.setMaterial(debugMaterialGreen);
646            node.attachChild(geom);
647            i++;
648        }
649        return node;
650    }
651
652    @Override
653    public void write(JmeExporter e) throws IOException {
654        super.write(e);
655        OutputCapsule capsule = e.getCapsule(this);
656
657        capsule.write(getMass(), "mass", 1.0f);
658
659        capsule.write(getGravity(), "gravity", Vector3f.ZERO);
660        capsule.write(getFriction(), "friction", 0.5f);
661        capsule.write(getRestitution(), "restitution", 0);
662        capsule.write(getAngularFactor(), "angularFactor", 1);
663        capsule.write(kinematic, "kinematic", false);
664
665        capsule.write(constructionInfo.linearDamping, "linearDamping", 0);
666        capsule.write(constructionInfo.angularDamping, "angularDamping", 0);
667        capsule.write(constructionInfo.linearSleepingThreshold, "linearSleepingThreshold", 0.8f);
668        capsule.write(constructionInfo.angularSleepingThreshold, "angularSleepingThreshold", 1.0f);
669
670        capsule.write(getCcdMotionThreshold(), "ccdMotionThreshold", 0);
671        capsule.write(getCcdSweptSphereRadius(), "ccdSweptSphereRadius", 0);
672
673        capsule.write(getPhysicsLocation(new Vector3f()), "physicsLocation", new Vector3f());
674        capsule.write(getPhysicsRotationMatrix(new Matrix3f()), "physicsRotation", new Matrix3f());
675
676        capsule.writeSavableArrayList(joints, "joints", null);
677    }
678
679    @Override
680    public void read(JmeImporter e) throws IOException {
681        super.read(e);
682
683        InputCapsule capsule = e.getCapsule(this);
684        float mass = capsule.readFloat("mass", 1.0f);
685        this.mass = mass;
686        rebuildRigidBody();
687        setGravity((Vector3f) capsule.readSavable("gravity", Vector3f.ZERO.clone()));
688        setFriction(capsule.readFloat("friction", 0.5f));
689        setKinematic(capsule.readBoolean("kinematic", false));
690
691        setRestitution(capsule.readFloat("restitution", 0));
692        setAngularFactor(capsule.readFloat("angularFactor", 1));
693        setDamping(capsule.readFloat("linearDamping", 0), capsule.readFloat("angularDamping", 0));
694        setSleepingThresholds(capsule.readFloat("linearSleepingThreshold", 0.8f), capsule.readFloat("angularSleepingThreshold", 1.0f));
695        setCcdMotionThreshold(capsule.readFloat("ccdMotionThreshold", 0));
696        setCcdSweptSphereRadius(capsule.readFloat("ccdSweptSphereRadius", 0));
697
698        setPhysicsLocation((Vector3f) capsule.readSavable("physicsLocation", new Vector3f()));
699        setPhysicsRotation((Matrix3f) capsule.readSavable("physicsRotation", new Matrix3f()));
700
701        joints = capsule.readSavableArrayList("joints", null);
702    }
703}
704