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 */ 32 package com.jme3.bullet.objects.infos; 33 34 import com.bulletphysics.linearmath.MotionState; 35 import com.bulletphysics.linearmath.Transform; 36 import com.jme3.bullet.objects.PhysicsVehicle; 37 import com.jme3.bullet.util.Converter; 38 import com.jme3.math.Matrix3f; 39 import com.jme3.math.Quaternion; 40 import com.jme3.math.Vector3f; 41 import com.jme3.scene.Spatial; 42 43 /** 44 * stores transform info of a PhysicsNode in a threadsafe manner to 45 * allow multithreaded access from the jme scenegraph and the bullet physicsspace 46 * @author normenhansen 47 */ 48 public class RigidBodyMotionState extends MotionState { 49 //stores the bullet transform 50 51 private Transform motionStateTrans = new Transform(Converter.convert(new Matrix3f())); 52 private Vector3f worldLocation = new Vector3f(); 53 private Matrix3f worldRotation = new Matrix3f(); 54 private Quaternion worldRotationQuat = new Quaternion(); 55 private Vector3f localLocation = new Vector3f(); 56 private Quaternion localRotationQuat = new Quaternion(); 57 //keep track of transform changes 58 private boolean physicsLocationDirty = false; 59 private boolean jmeLocationDirty = false; 60 //temp variable for conversion 61 private Quaternion tmp_inverseWorldRotation = new Quaternion(); 62 private PhysicsVehicle vehicle; 63 private boolean applyPhysicsLocal = false; 64 // protected LinkedList<PhysicsMotionStateListener> listeners = new LinkedList<PhysicsMotionStateListener>(); 65 66 public RigidBodyMotionState() { 67 } 68 69 /** 70 * called from bullet when creating the rigidbody 71 * @param t 72 * @return 73 */ 74 public synchronized Transform getWorldTransform(Transform t) { 75 t.set(motionStateTrans); 76 return t; 77 } 78 79 /** 80 * called from bullet when the transform of the rigidbody changes 81 * @param worldTrans 82 */ 83 public synchronized void setWorldTransform(Transform worldTrans) { 84 if (jmeLocationDirty) { 85 return; 86 } 87 motionStateTrans.set(worldTrans); 88 Converter.convert(worldTrans.origin, worldLocation); 89 Converter.convert(worldTrans.basis, worldRotation); 90 worldRotationQuat.fromRotationMatrix(worldRotation); 91 // for (Iterator<PhysicsMotionStateListener> it = listeners.iterator(); it.hasNext();) { 92 // PhysicsMotionStateListener physicsMotionStateListener = it.next(); 93 // physicsMotionStateListener.stateChanged(worldLocation, worldRotation); 94 // } 95 physicsLocationDirty = true; 96 if (vehicle != null) { 97 vehicle.updateWheels(); 98 } 99 } 100 101 /** 102 * applies the current transform to the given jme Node if the location has been updated on the physics side 103 * @param spatial 104 */ 105 public synchronized boolean applyTransform(Spatial spatial) { 106 if (!physicsLocationDirty) { 107 return false; 108 } 109 if (!applyPhysicsLocal && spatial.getParent() != null) { 110 localLocation.set(worldLocation).subtractLocal(spatial.getParent().getWorldTranslation()); 111 localLocation.divideLocal(spatial.getParent().getWorldScale()); 112 tmp_inverseWorldRotation.set(spatial.getParent().getWorldRotation()).inverseLocal().multLocal(localLocation); 113 114 localRotationQuat.set(worldRotationQuat); 115 tmp_inverseWorldRotation.set(spatial.getParent().getWorldRotation()).inverseLocal().mult(localRotationQuat, localRotationQuat); 116 117 spatial.setLocalTranslation(localLocation); 118 spatial.setLocalRotation(localRotationQuat); 119 } else { 120 spatial.setLocalTranslation(worldLocation); 121 spatial.setLocalRotation(worldRotationQuat); 122 } 123 physicsLocationDirty = false; 124 return true; 125 } 126 127 /** 128 * @return the worldLocation 129 */ 130 public Vector3f getWorldLocation() { 131 return worldLocation; 132 } 133 134 /** 135 * @return the worldRotation 136 */ 137 public Matrix3f getWorldRotation() { 138 return worldRotation; 139 } 140 141 /** 142 * @return the worldRotationQuat 143 */ 144 public Quaternion getWorldRotationQuat() { 145 return worldRotationQuat; 146 } 147 148 /** 149 * @param vehicle the vehicle to set 150 */ 151 public void setVehicle(PhysicsVehicle vehicle) { 152 this.vehicle = vehicle; 153 } 154 155 public boolean isApplyPhysicsLocal() { 156 return applyPhysicsLocal; 157 } 158 159 public void setApplyPhysicsLocal(boolean applyPhysicsLocal) { 160 this.applyPhysicsLocal = applyPhysicsLocal; 161 } 162 // public void addMotionStateListener(PhysicsMotionStateListener listener){ 163 // listeners.add(listener); 164 // } 165 // 166 // public void removeMotionStateListener(PhysicsMotionStateListener listener){ 167 // listeners.remove(listener); 168 // } 169 // public synchronized boolean applyTransform(com.jme3.math.Transform trans) { 170 // if (!physicsLocationDirty) { 171 // return false; 172 // } 173 // trans.setTranslation(worldLocation); 174 // trans.setRotation(worldRotationQuat); 175 // physicsLocationDirty = false; 176 // return true; 177 // } 178 // 179 // /** 180 // * called from jme when the location of the jme Node changes 181 // * @param location 182 // * @param rotation 183 // */ 184 // public synchronized void setWorldTransform(Vector3f location, Quaternion rotation) { 185 // worldLocation.set(location); 186 // worldRotationQuat.set(rotation); 187 // worldRotation.set(rotation.toRotationMatrix()); 188 // Converter.convert(worldLocation, motionStateTrans.origin); 189 // Converter.convert(worldRotation, motionStateTrans.basis); 190 // jmeLocationDirty = true; 191 // } 192 // 193 // /** 194 // * applies the current transform to the given RigidBody if the value has been changed on the jme side 195 // * @param rBody 196 // */ 197 // public synchronized void applyTransform(RigidBody rBody) { 198 // if (!jmeLocationDirty) { 199 // return; 200 // } 201 // assert (rBody != null); 202 // rBody.setWorldTransform(motionStateTrans); 203 // rBody.activate(); 204 // jmeLocationDirty = false; 205 // } 206 } 207