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.jme3.bullet.objects.PhysicsVehicle;
35import com.jme3.math.Matrix3f;
36import com.jme3.math.Quaternion;
37import com.jme3.math.Vector3f;
38import com.jme3.scene.Spatial;
39import java.util.logging.Level;
40import java.util.logging.Logger;
41
42/**
43 * stores transform info of a PhysicsNode in a threadsafe manner to
44 * allow multithreaded access from the jme scenegraph and the bullet physicsspace
45 * @author normenhansen
46 */
47public class RigidBodyMotionState {
48    long motionStateId = 0;
49    private Vector3f worldLocation = new Vector3f();
50    private Matrix3f worldRotation = new Matrix3f();
51    private Quaternion worldRotationQuat = new Quaternion();
52    private Quaternion tmp_inverseWorldRotation = new Quaternion();
53    private PhysicsVehicle vehicle;
54    private boolean applyPhysicsLocal = false;
55//    protected LinkedList<PhysicsMotionStateListener> listeners = new LinkedList<PhysicsMotionStateListener>();
56
57    public RigidBodyMotionState() {
58        this.motionStateId = createMotionState();
59        Logger.getLogger(this.getClass().getName()).log(Level.INFO, "Created MotionState {0}", Long.toHexString(motionStateId));
60    }
61
62    private native long createMotionState();
63
64    /**
65     * applies the current transform to the given jme Node if the location has been updated on the physics side
66     * @param spatial
67     */
68    public synchronized boolean applyTransform(Spatial spatial) {
69        Vector3f localLocation = spatial.getLocalTranslation();
70        Quaternion localRotationQuat = spatial.getLocalRotation();
71        boolean physicsLocationDirty = applyTransform(motionStateId, localLocation, localRotationQuat);
72        if (!physicsLocationDirty) {
73            return false;
74        }
75        if (!applyPhysicsLocal && spatial.getParent() != null) {
76            localLocation.subtractLocal(spatial.getParent().getWorldTranslation());
77            localLocation.divideLocal(spatial.getParent().getWorldScale());
78            tmp_inverseWorldRotation.set(spatial.getParent().getWorldRotation()).inverseLocal().multLocal(localLocation);
79
80//            localRotationQuat.set(worldRotationQuat);
81            tmp_inverseWorldRotation.mult(localRotationQuat, localRotationQuat);
82
83            spatial.setLocalTranslation(localLocation);
84            spatial.setLocalRotation(localRotationQuat);
85        } else {
86            spatial.setLocalTranslation(localLocation);
87            spatial.setLocalRotation(localRotationQuat);
88//            spatial.setLocalTranslation(worldLocation);
89//            spatial.setLocalRotation(worldRotationQuat);
90        }
91        if (vehicle != null) {
92            vehicle.updateWheels();
93        }
94        return true;
95    }
96
97    private synchronized native boolean applyTransform(long stateId, Vector3f location, Quaternion rotation);
98
99    /**
100     * @return the worldLocation
101     */
102    public Vector3f getWorldLocation() {
103        getWorldLocation(motionStateId, worldLocation);
104        return worldLocation;
105    }
106
107    private native void getWorldLocation(long stateId, Vector3f vec);
108
109    /**
110     * @return the worldRotation
111     */
112    public Matrix3f getWorldRotation() {
113        getWorldRotation(motionStateId, worldRotation);
114        return worldRotation;
115    }
116
117    private native void getWorldRotation(long stateId, Matrix3f vec);
118
119    /**
120     * @return the worldRotationQuat
121     */
122    public Quaternion getWorldRotationQuat() {
123        getWorldRotationQuat(motionStateId, worldRotationQuat);
124        return worldRotationQuat;
125    }
126
127    private native void getWorldRotationQuat(long stateId, Quaternion vec);
128
129    /**
130     * @param vehicle the vehicle to set
131     */
132    public void setVehicle(PhysicsVehicle vehicle) {
133        this.vehicle = vehicle;
134    }
135
136    public boolean isApplyPhysicsLocal() {
137        return applyPhysicsLocal;
138    }
139
140    public void setApplyPhysicsLocal(boolean applyPhysicsLocal) {
141        this.applyPhysicsLocal = applyPhysicsLocal;
142    }
143
144    public long getObjectId(){
145        return motionStateId;
146    }
147//    public void addMotionStateListener(PhysicsMotionStateListener listener){
148//        listeners.add(listener);
149//    }
150//
151//    public void removeMotionStateListener(PhysicsMotionStateListener listener){
152//        listeners.remove(listener);
153//    }
154
155    @Override
156    protected void finalize() throws Throwable {
157        super.finalize();
158        Logger.getLogger(this.getClass().getName()).log(Level.INFO, "Finalizing MotionState {0}", Long.toHexString(motionStateId));
159        finalizeNative(motionStateId);
160    }
161
162    private native void finalizeNative(long objectId);
163}
164