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.infos;
33
34import com.bulletphysics.linearmath.MotionState;
35import com.bulletphysics.linearmath.Transform;
36import com.jme3.bullet.objects.PhysicsVehicle;
37import com.jme3.bullet.util.Converter;
38import com.jme3.math.Matrix3f;
39import com.jme3.math.Quaternion;
40import com.jme3.math.Vector3f;
41import 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 */
48public 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