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