1/*
2 * Copyright (c) 2009-2012 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.collision;
33
34import com.jme3.asset.AssetManager;
35import com.jme3.bullet.collision.shapes.CollisionShape;
36import com.jme3.bullet.util.DebugShapeFactory;
37import com.jme3.export.*;
38import com.jme3.material.Material;
39import com.jme3.math.ColorRGBA;
40import com.jme3.math.Vector3f;
41import com.jme3.scene.Geometry;
42import com.jme3.scene.Node;
43import com.jme3.scene.Spatial;
44import com.jme3.scene.debug.Arrow;
45import java.io.IOException;
46import java.util.Iterator;
47import java.util.List;
48
49/**
50 * Base class for collision objects (PhysicsRigidBody, PhysicsGhostObject)
51 * @author normenhansen
52 */
53public abstract class PhysicsCollisionObject implements Savable {
54
55    protected Spatial debugShape;
56    protected Arrow debugArrow;
57    protected Geometry debugArrowGeom;
58    protected Material debugMaterialBlue;
59    protected Material debugMaterialRed;
60    protected Material debugMaterialGreen;
61    protected Material debugMaterialYellow;
62    protected CollisionShape collisionShape;
63    public static final int COLLISION_GROUP_NONE = 0x00000000;
64    public static final int COLLISION_GROUP_01 = 0x00000001;
65    public static final int COLLISION_GROUP_02 = 0x00000002;
66    public static final int COLLISION_GROUP_03 = 0x00000004;
67    public static final int COLLISION_GROUP_04 = 0x00000008;
68    public static final int COLLISION_GROUP_05 = 0x00000010;
69    public static final int COLLISION_GROUP_06 = 0x00000020;
70    public static final int COLLISION_GROUP_07 = 0x00000040;
71    public static final int COLLISION_GROUP_08 = 0x00000080;
72    public static final int COLLISION_GROUP_09 = 0x00000100;
73    public static final int COLLISION_GROUP_10 = 0x00000200;
74    public static final int COLLISION_GROUP_11 = 0x00000400;
75    public static final int COLLISION_GROUP_12 = 0x00000800;
76    public static final int COLLISION_GROUP_13 = 0x00001000;
77    public static final int COLLISION_GROUP_14 = 0x00002000;
78    public static final int COLLISION_GROUP_15 = 0x00004000;
79    public static final int COLLISION_GROUP_16 = 0x00008000;
80    protected int collisionGroup = 0x00000001;
81    protected int collisionGroupsMask = 0x00000001;
82    private Object userObject;
83
84    /**
85     * Sets a CollisionShape to this physics object, note that the object should
86     * not be in the physics space when adding a new collision shape as it is rebuilt
87     * on the physics side.
88     * @param collisionShape the CollisionShape to set
89     */
90    public void setCollisionShape(CollisionShape collisionShape) {
91        this.collisionShape = collisionShape;
92        updateDebugShape();
93    }
94
95    /**
96     * @return the CollisionShape of this PhysicsNode, to be able to reuse it with
97     * other physics nodes (increases performance)
98     */
99    public CollisionShape getCollisionShape() {
100        return collisionShape;
101    }
102
103    /**
104     * Returns the collision group for this collision shape
105     * @return
106     */
107    public int getCollisionGroup() {
108        return collisionGroup;
109    }
110
111    /**
112     * Sets the collision group number for this physics object. <br>
113     * The groups are integer bit masks and some pre-made variables are available in CollisionObject.
114     * All physics objects are by default in COLLISION_GROUP_01.<br>
115     * Two object will collide when <b>one</b> of the partys has the
116     * collisionGroup of the other in its collideWithGroups set.
117     * @param collisionGroup the collisionGroup to set
118     */
119    public void setCollisionGroup(int collisionGroup) {
120        this.collisionGroup = collisionGroup;
121    }
122
123    /**
124     * Add a group that this object will collide with.<br>
125     * Two object will collide when <b>one</b> of the partys has the
126     * collisionGroup of the other in its collideWithGroups set.<br>
127     * @param collisionGroup
128     */
129    public void addCollideWithGroup(int collisionGroup) {
130        this.collisionGroupsMask = this.collisionGroupsMask | collisionGroup;
131    }
132
133    /**
134     * Remove a group from the list this object collides with.
135     * @param collisionGroup
136     */
137    public void removeCollideWithGroup(int collisionGroup) {
138        this.collisionGroupsMask = this.collisionGroupsMask & ~collisionGroup;
139    }
140
141    /**
142     * Directly set the bitmask for collision groups that this object collides with.
143     * @param collisionGroups
144     */
145    public void setCollideWithGroups(int collisionGroups) {
146        this.collisionGroupsMask = collisionGroups;
147    }
148
149    /**
150     * Gets the bitmask of collision groups that this object collides with.
151     * @return
152     */
153    public int getCollideWithGroups() {
154        return collisionGroupsMask;
155    }
156
157    /**
158     * Creates a visual debug shape of the current collision shape of this physics object<br/>
159     * <b>Does not work with detached physics, please switch to PARALLEL or SEQUENTIAL for debugging</b>
160     * @param manager AssetManager to load the default wireframe material for the debug shape
161     */
162    protected Spatial attachDebugShape(AssetManager manager) {
163        debugMaterialBlue = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md");
164        debugMaterialBlue.getAdditionalRenderState().setWireframe(true);
165        debugMaterialBlue.setColor("Color", ColorRGBA.Blue);
166        debugMaterialGreen = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md");
167        debugMaterialGreen.getAdditionalRenderState().setWireframe(true);
168        debugMaterialGreen.setColor("Color", ColorRGBA.Green);
169        debugMaterialRed = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md");
170        debugMaterialRed.getAdditionalRenderState().setWireframe(true);
171        debugMaterialRed.setColor("Color", ColorRGBA.Red);
172        debugMaterialYellow = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md");
173        debugMaterialYellow.getAdditionalRenderState().setWireframe(true);
174        debugMaterialYellow.setColor("Color", ColorRGBA.Yellow);
175        debugArrow = new Arrow(Vector3f.UNIT_XYZ);
176        debugArrowGeom = new Geometry("DebugArrow", debugArrow);
177        debugArrowGeom.setMaterial(debugMaterialGreen);
178        return attachDebugShape();
179    }
180
181    /**
182     * creates a debug shape for this CollisionObject
183     * @param manager
184     * @return
185     */
186    public Spatial createDebugShape(AssetManager manager){
187        return attachDebugShape(manager);
188    }
189
190    protected Spatial attachDebugShape(Material material) {
191        debugMaterialBlue = material;
192        debugMaterialGreen = material;
193        debugMaterialRed = material;
194        debugMaterialYellow = material;
195        debugArrow = new Arrow(Vector3f.UNIT_XYZ);
196        debugArrowGeom = new Geometry("DebugArrow", debugArrow);
197        debugArrowGeom.setMaterial(debugMaterialGreen);
198        return attachDebugShape();
199    }
200
201    public Spatial debugShape() {
202        return debugShape;
203    }
204
205    /**
206     * Creates a visual debug shape of the current collision shape of this physics object<br/>
207     * <b>Does not work with detached physics, please switch to PARALLEL or SEQUENTIAL for debugging</b>
208     * @param material Material to use for the debug shape
209     */
210    protected Spatial attachDebugShape() {
211        if (debugShape != null) {
212            detachDebugShape();
213        }
214        Spatial spatial = getDebugShape();
215        this.debugShape = spatial;
216        return debugShape;
217    }
218
219    protected void updateDebugShape() {
220        if (debugShape != null) {
221            detachDebugShape();
222            attachDebugShape();
223        }
224    }
225
226    protected Spatial getDebugShape() {
227        Spatial spatial = DebugShapeFactory.getDebugShape(collisionShape);
228        if (spatial == null) {
229            return new Node("nullnode");
230        }
231        if (spatial instanceof Node) {
232            List<Spatial> children = ((Node) spatial).getChildren();
233            for (Iterator<Spatial> it1 = children.iterator(); it1.hasNext();) {
234                Spatial spatial1 = it1.next();
235                Geometry geom = ((Geometry) spatial1);
236                geom.setMaterial(debugMaterialBlue);
237                geom.setCullHint(Spatial.CullHint.Never);
238            }
239        } else {
240            Geometry geom = ((Geometry) spatial);
241            geom.setMaterial(debugMaterialBlue);
242            geom.setCullHint(Spatial.CullHint.Never);
243        }
244        spatial.setCullHint(Spatial.CullHint.Never);
245        return spatial;
246    }
247
248    /**
249     * Removes the debug shape
250     */
251    public void detachDebugShape() {
252        debugShape = null;
253    }
254
255    /**
256     * @return the userObject
257     */
258    public Object getUserObject() {
259        return userObject;
260    }
261
262    /**
263     * @param userObject the userObject to set
264     */
265    public void setUserObject(Object userObject) {
266        this.userObject = userObject;
267    }
268
269    @Override
270    public void write(JmeExporter e) throws IOException {
271        OutputCapsule capsule = e.getCapsule(this);
272        capsule.write(collisionGroup, "collisionGroup", 0x00000001);
273        capsule.write(collisionGroupsMask, "collisionGroupsMask", 0x00000001);
274        capsule.write(debugShape, "debugShape", null);
275        capsule.write(collisionShape, "collisionShape", null);
276    }
277
278    @Override
279    public void read(JmeImporter e) throws IOException {
280        InputCapsule capsule = e.getCapsule(this);
281        collisionGroup = capsule.readInt("collisionGroup", 0x00000001);
282        collisionGroupsMask = capsule.readInt("collisionGroupsMask", 0x00000001);
283        debugShape = (Spatial) capsule.readSavable("debugShape", null);
284        CollisionShape shape = (CollisionShape) capsule.readSavable("collisionShape", null);
285        collisionShape = shape;
286    }
287}
288