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.collision.PhysicsCollisionObject;
35import com.jme3.bullet.collision.shapes.CollisionShape;
36import com.jme3.export.InputCapsule;
37import com.jme3.export.JmeExporter;
38import com.jme3.export.JmeImporter;
39import com.jme3.export.OutputCapsule;
40import com.jme3.math.Matrix3f;
41import com.jme3.math.Quaternion;
42import com.jme3.math.Vector3f;
43import com.jme3.scene.Spatial;
44import java.io.IOException;
45import java.util.LinkedList;
46import java.util.List;
47import java.util.logging.Level;
48import java.util.logging.Logger;
49
50/**
51 * <i>From Bullet manual:</i><br>
52 * GhostObject can keep track of all objects that are overlapping.
53 * By default, this overlap is based on the AABB.
54 * This is useful for creating a character controller,
55 * collision sensors/triggers, explosions etc.<br>
56 * @author normenhansen
57 */
58public class PhysicsGhostObject extends PhysicsCollisionObject {
59
60    protected boolean locationDirty = false;
61    protected final Quaternion tmp_inverseWorldRotation = new Quaternion();
62    private List<PhysicsCollisionObject> overlappingObjects = new LinkedList<PhysicsCollisionObject>();
63
64    public PhysicsGhostObject() {
65    }
66
67    public PhysicsGhostObject(CollisionShape shape) {
68        collisionShape = shape;
69        buildObject();
70    }
71
72    public PhysicsGhostObject(Spatial child, CollisionShape shape) {
73        collisionShape = shape;
74        buildObject();
75    }
76
77    protected void buildObject() {
78        if (objectId == 0) {
79//            gObject = new PairCachingGhostObject();
80            objectId = createGhostObject();
81            Logger.getLogger(this.getClass().getName()).log(Level.INFO, "Created Ghost Object {0}", Long.toHexString(objectId));
82            setGhostFlags(objectId);
83            initUserPointer();
84        }
85//        if (gObject == null) {
86//            gObject = new PairCachingGhostObject();
87//            gObject.setCollisionFlags(gObject.getCollisionFlags() | CollisionFlags.NO_CONTACT_RESPONSE);
88//        }
89        attachCollisionShape(objectId, collisionShape.getObjectId());
90    }
91
92    private native long createGhostObject();
93
94    private native void setGhostFlags(long objectId);
95
96    @Override
97    public void setCollisionShape(CollisionShape collisionShape) {
98        super.setCollisionShape(collisionShape);
99        if (objectId == 0) {
100            buildObject();
101        } else {
102            attachCollisionShape(objectId, collisionShape.getObjectId());
103        }
104    }
105
106    /**
107     * Sets the physics object location
108     * @param location the location of the actual physics object
109     */
110    public void setPhysicsLocation(Vector3f location) {
111        setPhysicsLocation(objectId, location);
112    }
113
114    private native void setPhysicsLocation(long objectId, Vector3f location);
115
116    /**
117     * Sets the physics object rotation
118     * @param rotation the rotation of the actual physics object
119     */
120    public void setPhysicsRotation(Matrix3f rotation) {
121        setPhysicsRotation(objectId, rotation);
122    }
123
124    private native void setPhysicsRotation(long objectId, Matrix3f rotation);
125
126    /**
127     * Sets the physics object rotation
128     * @param rotation the rotation of the actual physics object
129     */
130    public void setPhysicsRotation(Quaternion rotation) {
131        setPhysicsRotation(objectId, rotation);
132    }
133
134    private native void setPhysicsRotation(long objectId, Quaternion rotation);
135
136    /**
137     * @return the physicsLocation
138     */
139    public Vector3f getPhysicsLocation(Vector3f trans) {
140        if (trans == null) {
141            trans = new Vector3f();
142        }
143        getPhysicsLocation(objectId, trans);
144        return trans;
145    }
146
147    private native void getPhysicsLocation(long objectId, Vector3f vector);
148
149    /**
150     * @return the physicsLocation
151     */
152    public Quaternion getPhysicsRotation(Quaternion rot) {
153        if (rot == null) {
154            rot = new Quaternion();
155        }
156        getPhysicsRotation(objectId, rot);
157        return rot;
158    }
159
160    private native void getPhysicsRotation(long objectId, Quaternion rot);
161
162    /**
163     * @return the physicsLocation
164     */
165    public Matrix3f getPhysicsRotationMatrix(Matrix3f rot) {
166        if (rot == null) {
167            rot = new Matrix3f();
168        }
169        getPhysicsRotationMatrix(objectId, rot);
170        return rot;
171    }
172
173    private native void getPhysicsRotationMatrix(long objectId, Matrix3f rot);
174
175    /**
176     * @return the physicsLocation
177     */
178    public Vector3f getPhysicsLocation() {
179        Vector3f vec = new Vector3f();
180        getPhysicsLocation(objectId, vec);
181        return vec;
182    }
183
184    /**
185     * @return the physicsLocation
186     */
187    public Quaternion getPhysicsRotation() {
188        Quaternion quat = new Quaternion();
189        getPhysicsRotation(objectId, quat);
190        return quat;
191    }
192
193    public Matrix3f getPhysicsRotationMatrix() {
194        Matrix3f mtx = new Matrix3f();
195        getPhysicsRotationMatrix(objectId, mtx);
196        return mtx;
197    }
198
199    /**
200     * used internally
201     */
202//    public PairCachingGhostObject getObjectId() {
203//        return gObject;
204//    }
205    /**
206     * destroys this PhysicsGhostNode and removes it from memory
207     */
208    public void destroy() {
209    }
210
211    /**
212     * Another Object is overlapping with this GhostNode,
213     * if and if only there CollisionShapes overlaps.
214     * They could be both regular PhysicsRigidBodys or PhysicsGhostObjects.
215     * @return All CollisionObjects overlapping with this GhostNode.
216     */
217    public List<PhysicsCollisionObject> getOverlappingObjects() {
218        overlappingObjects.clear();
219        getOverlappingObjects(objectId);
220//        for (com.bulletphysics.collision.dispatch.CollisionObject collObj : gObject.getOverlappingPairs()) {
221//            overlappingObjects.add((PhysicsCollisionObject) collObj.getUserPointer());
222//        }
223        return overlappingObjects;
224    }
225
226    protected native void getOverlappingObjects(long objectId);
227
228    private void addOverlappingObject_native(PhysicsCollisionObject co) {
229        overlappingObjects.add(co);
230    }
231
232    /**
233     *
234     * @return With how many other CollisionObjects this GhostNode is currently overlapping.
235     */
236    public int getOverlappingCount() {
237        return getOverlappingCount(objectId);
238    }
239
240    private native int getOverlappingCount(long objectId);
241
242    /**
243     *
244     * @param index The index of the overlapping Node to retrieve.
245     * @return The Overlapping CollisionObject at the given index.
246     */
247    public PhysicsCollisionObject getOverlapping(int index) {
248        return overlappingObjects.get(index);
249    }
250
251    public void setCcdSweptSphereRadius(float radius) {
252        setCcdSweptSphereRadius(objectId, radius);
253    }
254
255    private native void setCcdSweptSphereRadius(long objectId, float radius);
256
257    public void setCcdMotionThreshold(float threshold) {
258        setCcdMotionThreshold(objectId, threshold);
259    }
260
261    private native void setCcdMotionThreshold(long objectId, float threshold);
262
263    public float getCcdSweptSphereRadius() {
264        return getCcdSweptSphereRadius(objectId);
265    }
266
267    private native float getCcdSweptSphereRadius(long objectId);
268
269    public float getCcdMotionThreshold() {
270        return getCcdMotionThreshold(objectId);
271    }
272
273    private native float getCcdMotionThreshold(long objectId);
274
275    public float getCcdSquareMotionThreshold() {
276        return getCcdSquareMotionThreshold(objectId);
277    }
278
279    private native float getCcdSquareMotionThreshold(long objectId);
280
281    @Override
282    public void write(JmeExporter e) throws IOException {
283        super.write(e);
284        OutputCapsule capsule = e.getCapsule(this);
285        capsule.write(getPhysicsLocation(new Vector3f()), "physicsLocation", new Vector3f());
286        capsule.write(getPhysicsRotationMatrix(new Matrix3f()), "physicsRotation", new Matrix3f());
287        capsule.write(getCcdMotionThreshold(), "ccdMotionThreshold", 0);
288        capsule.write(getCcdSweptSphereRadius(), "ccdSweptSphereRadius", 0);
289    }
290
291    @Override
292    public void read(JmeImporter e) throws IOException {
293        super.read(e);
294        InputCapsule capsule = e.getCapsule(this);
295        buildObject();
296        setPhysicsLocation((Vector3f) capsule.readSavable("physicsLocation", new Vector3f()));
297        setPhysicsRotation(((Matrix3f) capsule.readSavable("physicsRotation", new Matrix3f())));
298        setCcdMotionThreshold(capsule.readFloat("ccdMotionThreshold", 0));
299        setCcdSweptSphereRadius(capsule.readFloat("ccdSweptSphereRadius", 0));
300    }
301}
302