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