2 * Copyright (c) 2009-2010 jMonkeyEngine
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
32 package com.jme3.bullet.objects;
34 import com.jme3.math.Vector3f;
35 import com.jme3.scene.Spatial;
36 import com.jme3.bullet.PhysicsSpace;
37 import com.jme3.bullet.collision.PhysicsCollisionObject;
38 import com.jme3.bullet.collision.shapes.CollisionShape;
39 import com.jme3.bullet.collision.shapes.MeshCollisionShape;
40 import com.jme3.bullet.joints.PhysicsJoint;
41 import com.jme3.bullet.objects.infos.RigidBodyMotionState;
42 import com.jme3.export.InputCapsule;
43 import com.jme3.export.JmeExporter;
44 import com.jme3.export.JmeImporter;
45 import com.jme3.export.OutputCapsule;
46 import com.jme3.math.Matrix3f;
47 import com.jme3.math.Quaternion;
48 import com.jme3.scene.Geometry;
49 import com.jme3.scene.Node;
50 import com.jme3.scene.debug.Arrow;
51 import java.io.IOException;
52 import java.util.ArrayList;
53 import java.util.Iterator;
54 import java.util.List;
55 import java.util.logging.Level;
56 import java.util.logging.Logger;
59 * <p>PhysicsRigidBody - Basic physics object</p>
60 * @author normenhansen
62 public class PhysicsRigidBody extends PhysicsCollisionObject {
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>();
69 public PhysicsRigidBody() {
73 * Creates a new PhysicsRigidBody with the supplied collision shape
77 public PhysicsRigidBody(CollisionShape shape) {
78 collisionShape = shape;
82 public PhysicsRigidBody(CollisionShape shape, float mass) {
83 collisionShape = shape;
89 * Builds/rebuilds the phyiscs body when parameters have changed
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!");
97 if (isInWorld(objectId)) {
98 PhysicsSpace.getPhysicsSpace().remove(this);
101 Logger.getLogger(this.getClass().getName()).log(Level.FINE, "Clearing RigidBody {0}", Long.toHexString(objectId));
102 finalizeNative(objectId);
105 objectId = createRigidBody(mass, motionState.getObjectId(), collisionShape.getObjectId());
106 Logger.getLogger(this.getClass().getName()).log(Level.FINE, "Created RigidBody {0}", Long.toHexString(objectId));
109 PhysicsSpace.getPhysicsSpace().add(this);
113 protected void preRebuild() {
116 private native long createRigidBody(float mass, long motionStateId, long collisionShapeId);
118 protected void postRebuild() {
120 setStatic(objectId, true);
122 setStatic(objectId, false);
128 * @return the motionState
130 public RigidBodyMotionState getMotionState() {
134 public boolean isInWorld() {
135 return isInWorld(objectId);
138 private native boolean isInWorld(long objectId);
141 * Sets the physics object location
142 * @param location the location of the actual physics object
144 public void setPhysicsLocation(Vector3f location) {
145 setPhysicsLocation(objectId, location);
148 private native void setPhysicsLocation(long objectId, Vector3f location);
151 * Sets the physics object rotation
152 * @param rotation the rotation of the actual physics object
154 public void setPhysicsRotation(Matrix3f rotation) {
155 setPhysicsRotation(objectId, rotation);
158 private native void setPhysicsRotation(long objectId, Matrix3f rotation);
161 * Sets the physics object rotation
162 * @param rotation the rotation of the actual physics object
164 public void setPhysicsRotation(Quaternion rotation) {
165 setPhysicsRotation(objectId, rotation);
168 private native void setPhysicsRotation(long objectId, Quaternion rotation);
171 * @return the physicsLocation
173 public Vector3f getPhysicsLocation(Vector3f trans) {
175 trans = new Vector3f();
177 getPhysicsLocation(objectId, trans);
181 private native void getPhysicsLocation(long objectId, Vector3f vector);
184 * @return the physicsLocation
186 public Quaternion getPhysicsRotation(Quaternion rot) {
188 rot = new Quaternion();
190 getPhysicsRotation(objectId, rot);
194 private native void getPhysicsRotation(long objectId, Quaternion rot);
197 * @return the physicsLocation
199 public Matrix3f getPhysicsRotationMatrix(Matrix3f rot) {
201 rot = new Matrix3f();
203 getPhysicsRotationMatrix(objectId, rot);
207 private native void getPhysicsRotationMatrix(long objectId, Matrix3f rot);
210 * @return the physicsLocation
212 public Vector3f getPhysicsLocation() {
213 Vector3f vec = new Vector3f();
214 getPhysicsLocation(objectId, vec);
219 * @return the physicsLocation
221 public Quaternion getPhysicsRotation() {
222 Quaternion quat = new Quaternion();
223 getPhysicsRotation(objectId, quat);
227 public Matrix3f getPhysicsRotationMatrix() {
228 Matrix3f mtx = new Matrix3f();
229 getPhysicsRotationMatrix(objectId, mtx);
234 // * Gets the physics object location
235 // * @param location the location of the actual physics object is stored in this Vector3f
237 // public Vector3f getInterpolatedPhysicsLocation(Vector3f location) {
238 // if (location == null) {
239 // location = new Vector3f();
241 // rBody.getInterpolationWorldTransform(tempTrans);
242 // return Converter.convert(tempTrans.origin, location);
246 // * Gets the physics object rotation
247 // * @param rotation the rotation of the actual physics object is stored in this Matrix3f
249 // public Matrix3f getInterpolatedPhysicsRotation(Matrix3f rotation) {
250 // if (rotation == null) {
251 // rotation = new Matrix3f();
253 // rBody.getInterpolationWorldTransform(tempTrans);
254 // return Converter.convert(tempTrans.basis, rotation);
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.
262 public void setKinematic(boolean kinematic) {
263 this.kinematic = kinematic;
264 setKinematic(objectId, kinematic);
267 private native void setKinematic(long objectId, boolean kinematic);
269 public boolean isKinematic() {
273 public void setCcdSweptSphereRadius(float radius) {
274 setCcdSweptSphereRadius(objectId, radius);
277 private native void setCcdSweptSphereRadius(long objectId, float radius);
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)
284 public void setCcdMotionThreshold(float threshold) {
285 setCcdMotionThreshold(objectId, threshold);
288 private native void setCcdMotionThreshold(long objectId, float threshold);
290 public float getCcdSweptSphereRadius() {
291 return getCcdSweptSphereRadius(objectId);
294 private native float getCcdSweptSphereRadius(long objectId);
296 public float getCcdMotionThreshold() {
297 return getCcdMotionThreshold(objectId);
300 private native float getCcdMotionThreshold(long objectId);
302 public float getCcdSquareMotionThreshold() {
303 return getCcdSquareMotionThreshold(objectId);
306 private native float getCcdSquareMotionThreshold(long objectId);
308 public float getMass() {
313 * Sets the mass of this PhysicsRigidBody, objects with mass=0 are static.
316 public void setMass(float mass) {
318 if (collisionShape instanceof MeshCollisionShape && mass != 0) {
319 throw new IllegalStateException("Dynamic rigidbody can not have mesh collision shape!");
322 if (collisionShape != null) {
323 updateMassProps(objectId, collisionShape.getObjectId(), mass);
326 setStatic(objectId, true);
328 setStatic(objectId, false);
333 private native void setStatic(long objectId, boolean state);
335 private native long updateMassProps(long objectId, long collisionShapeId, float mass);
337 public Vector3f getGravity() {
338 return getGravity(null);
341 public Vector3f getGravity(Vector3f gravity) {
342 if (gravity == null) {
343 gravity = new Vector3f();
345 getGravity(objectId, gravity);
349 private native void getGravity(long objectId, Vector3f gravity);
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
357 public void setGravity(Vector3f gravity) {
358 setGravity(objectId, gravity);
361 private native void setGravity(long objectId, Vector3f gravity);
363 public float getFriction() {
364 return getFriction(objectId);
367 private native float getFriction(long objectId);
370 * Sets the friction of this physics object
371 * @param friction the friction of this physics object
373 public void setFriction(float friction) {
374 setFriction(objectId, friction);
377 private native void setFriction(long objectId, float friction);
379 public void setDamping(float linearDamping, float angularDamping) {
380 setDamping(objectId, linearDamping, angularDamping);
383 private native void setDamping(long objectId, float linearDamping, float angularDamping);
385 // private native void setRestitution(long objectId, float factor);
387 // public void setLinearDamping(float linearDamping) {
388 // constructionInfo.linearDamping = linearDamping;
389 // rBody.setDamping(linearDamping, constructionInfo.angularDamping);
392 // private native void setRestitution(long objectId, float factor);
394 // public void setAngularDamping(float angularDamping) {
395 //// constructionInfo.angularDamping = angularDamping;
396 //// rBody.setDamping(constructionInfo.linearDamping, angularDamping);
399 private native void setAngularDamping(long objectId, float factor);
401 public float getLinearDamping() {
402 return getLinearDamping(objectId);
405 private native float getLinearDamping(long objectId);
407 public float getAngularDamping() {
408 return getAngularDamping(objectId);
411 private native float getAngularDamping(long objectId);
413 public float getRestitution() {
414 return getRestitution(objectId);
417 private native float getRestitution(long objectId);
420 * The "bouncyness" of the PhysicsRigidBody, best performance if restitution=0
423 public void setRestitution(float restitution) {
424 setRestitution(objectId, restitution);
427 private native void setRestitution(long objectId, float factor);
430 * Get the current angular velocity of this PhysicsRigidBody
431 * @return the current linear velocity
433 public Vector3f getAngularVelocity() {
434 Vector3f vec = new Vector3f();
435 getAngularVelocity(objectId, vec);
439 private native void getAngularVelocity(long objectId, Vector3f vec);
442 * Get the current angular velocity of this PhysicsRigidBody
443 * @param vec the vector to store the velocity in
445 public void getAngularVelocity(Vector3f vec) {
446 getAngularVelocity(objectId, vec);
450 * Sets the angular velocity of this PhysicsRigidBody
451 * @param vec the angular velocity of this PhysicsRigidBody
453 public void setAngularVelocity(Vector3f vec) {
454 setAngularVelocity(objectId, vec);
458 private native void setAngularVelocity(long objectId, Vector3f vec);
461 * Get the current linear velocity of this PhysicsRigidBody
462 * @return the current linear velocity
464 public Vector3f getLinearVelocity() {
465 Vector3f vec = new Vector3f();
466 getLinearVelocity(objectId, vec);
470 private native void getLinearVelocity(long objectId, Vector3f vec);
473 * Get the current linear velocity of this PhysicsRigidBody
474 * @param vec the vector to store the velocity in
476 public void getLinearVelocity(Vector3f vec) {
477 getLinearVelocity(objectId, vec);
481 * Sets the linear velocity of this PhysicsRigidBody
482 * @param vec the linear velocity of this PhysicsRigidBody
484 public void setLinearVelocity(Vector3f vec) {
485 setLinearVelocity(objectId, vec);
489 private native void setLinearVelocity(long objectId, Vector3f vec);
492 * Apply a force to the PhysicsRigidBody, only applies force if the next physics update call
493 * updates the physics space.<br>
494 * To apply an impulse, use applyImpulse, use applyContinuousForce to apply continuous force.
495 * @param force the force
496 * @param location the location of the force
498 public void applyForce(Vector3f force, Vector3f location) {
499 applyForce(objectId, force, location);
503 private native void applyForce(long objectId, Vector3f force, Vector3f location);
506 * Apply a force to the PhysicsRigidBody, only applies force if the next physics update call
507 * updates the physics space.<br>
508 * To apply an impulse, use applyImpulse.
510 * @param force the force
512 public void applyCentralForce(Vector3f force) {
513 applyCentralForce(objectId, force);
517 private native void applyCentralForce(long objectId, Vector3f force);
520 * Apply a force to the PhysicsRigidBody, only applies force if the next physics update call
521 * updates the physics space.<br>
522 * To apply an impulse, use applyImpulse.
524 * @param torque the torque
526 public void applyTorque(Vector3f torque) {
527 applyTorque(objectId, torque);
531 private native void applyTorque(long objectId, Vector3f vec);
534 * Apply an impulse to the PhysicsRigidBody in the next physics update.
535 * @param impulse applied impulse
536 * @param rel_pos location relative to object
538 public void applyImpulse(Vector3f impulse, Vector3f rel_pos) {
539 applyImpulse(objectId, impulse, rel_pos);
543 private native void applyImpulse(long objectId, Vector3f impulse, Vector3f rel_pos);
546 * Apply a torque impulse to the PhysicsRigidBody in the next physics update.
549 public void applyTorqueImpulse(Vector3f vec) {
550 applyTorqueImpulse(objectId, vec);
554 private native void applyTorqueImpulse(long objectId, Vector3f vec);
557 * Clear all forces from the PhysicsRigidBody
560 public void clearForces() {
561 clearForces(objectId);
564 private native void clearForces(long objectId);
566 public void setCollisionShape(CollisionShape collisionShape) {
567 super.setCollisionShape(collisionShape);
568 if (collisionShape instanceof MeshCollisionShape && mass != 0) {
569 throw new IllegalStateException("Dynamic rigidbody can not have mesh collision shape!");
574 setCollisionShape(objectId, collisionShape.getObjectId());
575 updateMassProps(objectId, collisionShape.getObjectId(), mass);
579 private native void setCollisionShape(long objectId, long collisionShapeId);
582 * reactivates this PhysicsRigidBody when it has been deactivated because it was not moving
584 public void activate() {
588 private native void activate(long objectId);
590 public boolean isActive() {
591 return isActive(objectId);
594 private native boolean isActive(long objectId);
597 * sets the sleeping thresholds, these define when the object gets deactivated
598 * to save ressources. Low values keep the object active when it barely moves
599 * @param linear the linear sleeping threshold
600 * @param angular the angular sleeping threshold
602 public void setSleepingThresholds(float linear, float angular) {
603 setSleepingThresholds(objectId, linear, angular);
606 private native void setSleepingThresholds(long objectId, float linear, float angular);
608 public void setLinearSleepingThreshold(float linearSleepingThreshold) {
609 setLinearSleepingThreshold(objectId, linearSleepingThreshold);
612 private native void setLinearSleepingThreshold(long objectId, float linearSleepingThreshold);
614 public void setAngularSleepingThreshold(float angularSleepingThreshold) {
615 setAngularSleepingThreshold(objectId, angularSleepingThreshold);
618 private native void setAngularSleepingThreshold(long objectId, float angularSleepingThreshold);
620 public float getLinearSleepingThreshold() {
621 return getLinearSleepingThreshold(objectId);
624 private native float getLinearSleepingThreshold(long objectId);
626 public float getAngularSleepingThreshold() {
627 return getAngularSleepingThreshold(objectId);
630 private native float getAngularSleepingThreshold(long objectId);
632 public float getAngularFactor() {
633 return getAngularFactor(objectId);
636 private native float getAngularFactor(long objectId);
638 public void setAngularFactor(float factor) {
639 setAngularFactor(objectId, factor);
642 private native void setAngularFactor(long objectId, float factor);
645 * do not use manually, joints are added automatically
647 public void addJoint(PhysicsJoint joint) {
648 if (!joints.contains(joint)) {
657 public void removeJoint(PhysicsJoint joint) {
658 joints.remove(joint);
662 * Returns a list of connected joints. This list is only filled when
663 * the PhysicsRigidBody is actually added to the physics space or loaded from disk.
664 * @return list of active joints connected to this PhysicsRigidBody
666 public List<PhysicsJoint> getJoints() {
671 protected Spatial getDebugShape() {
673 Spatial shape = super.getDebugShape();
675 if (shape instanceof Node) {
678 node = new Node("DebugShapeNode");
679 node.attachChild(shape);
682 for (Iterator<PhysicsJoint> it = joints.iterator(); it.hasNext();) {
683 PhysicsJoint physicsJoint = it.next();
684 Vector3f pivot = null;
685 if (physicsJoint.getBodyA() == this) {
686 pivot = physicsJoint.getPivotA();
688 pivot = physicsJoint.getPivotB();
690 Arrow arrow = new Arrow(pivot);
691 Geometry geom = new Geometry("DebugBone" + i, arrow);
692 geom.setMaterial(debugMaterialGreen);
693 node.attachChild(geom);
700 public void write(JmeExporter e) throws IOException {
702 OutputCapsule capsule = e.getCapsule(this);
704 capsule.write(getMass(), "mass", 1.0f);
706 capsule.write(getGravity(), "gravity", Vector3f.ZERO);
707 capsule.write(getFriction(), "friction", 0.5f);
708 capsule.write(getRestitution(), "restitution", 0);
709 capsule.write(getAngularFactor(), "angularFactor", 1);
710 capsule.write(kinematic, "kinematic", false);
712 capsule.write(getLinearDamping(), "linearDamping", 0);
713 capsule.write(getAngularDamping(), "angularDamping", 0);
714 capsule.write(getLinearSleepingThreshold(), "linearSleepingThreshold", 0.8f);
715 capsule.write(getAngularSleepingThreshold(), "angularSleepingThreshold", 1.0f);
717 capsule.write(getCcdMotionThreshold(), "ccdMotionThreshold", 0);
718 capsule.write(getCcdSweptSphereRadius(), "ccdSweptSphereRadius", 0);
720 capsule.write(getPhysicsLocation(new Vector3f()), "physicsLocation", new Vector3f());
721 capsule.write(getPhysicsRotationMatrix(new Matrix3f()), "physicsRotation", new Matrix3f());
723 capsule.writeSavableArrayList(joints, "joints", null);
727 public void read(JmeImporter e) throws IOException {
730 InputCapsule capsule = e.getCapsule(this);
731 float mass = capsule.readFloat("mass", 1.0f);
734 setGravity((Vector3f) capsule.readSavable("gravity", Vector3f.ZERO.clone()));
735 setFriction(capsule.readFloat("friction", 0.5f));
736 setKinematic(capsule.readBoolean("kinematic", false));
738 setRestitution(capsule.readFloat("restitution", 0));
739 setAngularFactor(capsule.readFloat("angularFactor", 1));
740 setDamping(capsule.readFloat("linearDamping", 0), capsule.readFloat("angularDamping", 0));
741 setSleepingThresholds(capsule.readFloat("linearSleepingThreshold", 0.8f), capsule.readFloat("angularSleepingThreshold", 1.0f));
742 setCcdMotionThreshold(capsule.readFloat("ccdMotionThreshold", 0));
743 setCcdSweptSphereRadius(capsule.readFloat("ccdSweptSphereRadius", 0));
745 setPhysicsLocation((Vector3f) capsule.readSavable("physicsLocation", new Vector3f()));
746 setPhysicsRotation((Matrix3f) capsule.readSavable("physicsRotation", new Matrix3f()));
748 joints = capsule.readSavableArrayList("joints", null);