From 8992563b86d26cabc1b99c036a7a5aebb54d445f Mon Sep 17 00:00:00 2001 From: "nor..67" Date: Tue, 5 Feb 2013 19:19:31 +0000 Subject: [PATCH] - add new BulletDebugAppState for physics debugging - fix non-displayed physics objects in debug view - remove dependency of base physics objects to scenegraph api, only jme math dependencies are left git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10342 75d07b2b-3a1a-0410-a2c5-0572b91ccdca --- .../com/jme3/bullet/BulletAppState.java | 84 ++-- .../debug/AbstractPhysicsDebugControl.java | 81 ++++ .../debug/BulletCharacterDebugControl.java | 92 +++++ .../bullet/debug/BulletDebugAppState.java | 361 ++++++++++++++++++ .../debug/BulletGhostObjectDebugControl.java | 91 +++++ .../bullet/debug/BulletJointDebugControl.java | 106 +++++ .../debug/BulletRigidBodyDebugControl.java | 95 +++++ .../debug/BulletVehicleDebugControl.java | 142 +++++++ .../bullet/com/jme3/bullet/PhysicsSpace.java | 2 +- .../jbullet/com/jme3/bullet/PhysicsSpace.java | 2 +- 10 files changed, 1032 insertions(+), 24 deletions(-) create mode 100644 engine/src/bullet-common/com/jme3/bullet/debug/AbstractPhysicsDebugControl.java create mode 100644 engine/src/bullet-common/com/jme3/bullet/debug/BulletCharacterDebugControl.java create mode 100644 engine/src/bullet-common/com/jme3/bullet/debug/BulletDebugAppState.java create mode 100644 engine/src/bullet-common/com/jme3/bullet/debug/BulletGhostObjectDebugControl.java create mode 100644 engine/src/bullet-common/com/jme3/bullet/debug/BulletJointDebugControl.java create mode 100644 engine/src/bullet-common/com/jme3/bullet/debug/BulletRigidBodyDebugControl.java create mode 100644 engine/src/bullet-common/com/jme3/bullet/debug/BulletVehicleDebugControl.java diff --git a/engine/src/bullet-common/com/jme3/bullet/BulletAppState.java b/engine/src/bullet-common/com/jme3/bullet/BulletAppState.java index 8fd167e18..61165c3dd 100644 --- a/engine/src/bullet-common/com/jme3/bullet/BulletAppState.java +++ b/engine/src/bullet-common/com/jme3/bullet/BulletAppState.java @@ -35,6 +35,7 @@ import com.jme3.app.Application; import com.jme3.app.state.AppState; import com.jme3.app.state.AppStateManager; import com.jme3.bullet.PhysicsSpace.BroadphaseType; +import com.jme3.bullet.debug.BulletDebugAppState; import com.jme3.math.Vector3f; import com.jme3.renderer.RenderManager; import java.util.concurrent.*; @@ -43,6 +44,7 @@ import java.util.logging.Logger; /** * BulletAppState allows using bullet physics in an Application. + * * @author normenhansen */ public class BulletAppState implements AppState, PhysicsTickListener { @@ -56,31 +58,38 @@ public class BulletAppState implements AppState, PhysicsTickListener { protected BroadphaseType broadphaseType = BroadphaseType.DBVT; protected Vector3f worldMin = new Vector3f(-10000f, -10000f, -10000f); protected Vector3f worldMax = new Vector3f(10000f, 10000f, 10000f); - private float speed = 1; + protected float speed = 1; protected boolean active = true; + protected boolean debugEnabled = false; + protected BulletDebugAppState debugAppState; protected float tpf; protected Future physicsFuture; /** - * Creates a new BulletAppState running a PhysicsSpace for physics simulation, - * use getStateManager().addState(bulletAppState) to enable physics for an Application. + * Creates a new BulletAppState running a PhysicsSpace for physics + * simulation, use getStateManager().addState(bulletAppState) to enable + * physics for an Application. */ public BulletAppState() { } /** - * Creates a new BulletAppState running a PhysicsSpace for physics simulation, - * use getStateManager().addState(bulletAppState) to enable physics for an Application. - * @param broadphaseType The type of broadphase collision detection, BroadphaseType.DVBT is the default + * Creates a new BulletAppState running a PhysicsSpace for physics + * simulation, use getStateManager().addState(bulletAppState) to enable + * physics for an Application. + * + * @param broadphaseType The type of broadphase collision detection, + * BroadphaseType.DVBT is the default */ public BulletAppState(BroadphaseType broadphaseType) { this(new Vector3f(-10000f, -10000f, -10000f), new Vector3f(10000f, 10000f, 10000f), broadphaseType); } /** - * Creates a new BulletAppState running a PhysicsSpace for physics simulation, - * use getStateManager().addState(bulletAppState) to enable physics for an Application. - * An AxisSweep broadphase is used. + * Creates a new BulletAppState running a PhysicsSpace for physics + * simulation, use getStateManager().addState(bulletAppState) to enable + * physics for an Application. An AxisSweep broadphase is used. + * * @param worldMin The minimum world extent * @param worldMax The maximum world extent */ @@ -101,7 +110,6 @@ public class BulletAppState implements AppState, PhysicsTickListener { executor = new ScheduledThreadPoolExecutor(1); final BulletAppState app = this; Callable call = new Callable() { - public Boolean call() throws Exception { detachedPhysicsLastUpdate = System.currentTimeMillis(); pSpace = new PhysicsSpace(worldMin, worldMax, broadphaseType); @@ -120,7 +128,6 @@ public class BulletAppState implements AppState, PhysicsTickListener { } } private Callable parallelPhysicsUpdate = new Callable() { - public Boolean call() throws Exception { pSpace.update(tpf * getSpeed()); return true; @@ -128,7 +135,6 @@ public class BulletAppState implements AppState, PhysicsTickListener { }; long detachedPhysicsLastUpdate = 0; private Callable detachedPhysicsUpdate = new Callable() { - public Boolean call() throws Exception { pSpace.update(getPhysicsSpace().getAccuracy() * getSpeed()); pSpace.distributeEvents(); @@ -144,8 +150,8 @@ public class BulletAppState implements AppState, PhysicsTickListener { } /** - * The physics system is started automatically on attaching, if you want to start it - * before for some reason, you can use this method. + * The physics system is started automatically on attaching, if you want to + * start it before for some reason, you can use this method. */ public void startPhysics() { //start physics thread(pool) @@ -165,21 +171,30 @@ public class BulletAppState implements AppState, PhysicsTickListener { if (!initialized) { startPhysics(); } + this.stateManager = stateManager; initialized = true; } public boolean isInitialized() { return initialized; } - + public void setEnabled(boolean enabled) { this.active = enabled; } - + public boolean isEnabled() { return active; } + public void setDebugEnabled(boolean debugEnabled) { + this.debugEnabled = debugEnabled; + } + + public boolean isDebugEnabled() { + return debugEnabled; + } + public void stateAttached(AppStateManager stateManager) { if (!initialized) { startPhysics(); @@ -187,17 +202,36 @@ public class BulletAppState implements AppState, PhysicsTickListener { if (threadingType == ThreadingType.PARALLEL) { PhysicsSpace.setLocalThreadPhysicsSpace(pSpace); } + if (debugEnabled) { + debugAppState = new BulletDebugAppState(pSpace); + stateManager.attach(debugAppState); + } } public void stateDetached(AppStateManager stateManager) { } public void update(float tpf) { + if (debugEnabled && debugAppState == null) { + debugAppState = new BulletDebugAppState(pSpace); + stateManager.attach(debugAppState); + pSpace.enableDebug(app.getAssetManager()); + } else if (!debugEnabled && debugAppState != null) { + stateManager.detach(debugAppState); + debugAppState = null; + pSpace.enableDebug(null); + } + //TODO: remove when deprecation of PhysicsSpace.enableDebug is through + if (pSpace.getDebugManager() != null && !debugEnabled) { + debugEnabled = true; + } else if (pSpace.getDebugManager() == null && debugEnabled) { + debugEnabled = false; + } if (!active) { return; } // if (threadingType != ThreadingType.DETACHED) { - pSpace.distributeEvents(); + pSpace.distributeEvents(); // } this.tpf = tpf; } @@ -228,6 +262,10 @@ public class BulletAppState implements AppState, PhysicsTickListener { } public void cleanup() { + if (debugAppState != null) { + stateManager.detach(debugAppState); + debugAppState = null; + } if (executor != null) { executor.shutdown(); executor = null; @@ -245,6 +283,7 @@ public class BulletAppState implements AppState, PhysicsTickListener { /** * Use before attaching state + * * @param threadingType the threadingType to set */ public void setThreadingType(ThreadingType threadingType) { @@ -289,13 +328,14 @@ public class BulletAppState implements AppState, PhysicsTickListener { public enum ThreadingType { /** - * Default mode; user update, physics update and rendering happen sequentially (single threaded) + * Default mode; user update, physics update and rendering happen + * sequentially (single threaded) */ SEQUENTIAL, /** - * Parallel threaded mode; physics update and rendering are executed in parallel, update order is kept.
- * Multiple BulletAppStates will execute in parallel in this mode. + * Parallel threaded mode; physics update and rendering are executed in + * parallel, update order is kept.
Multiple BulletAppStates will + * execute in parallel in this mode. */ - PARALLEL, - } + PARALLEL,} } diff --git a/engine/src/bullet-common/com/jme3/bullet/debug/AbstractPhysicsDebugControl.java b/engine/src/bullet-common/com/jme3/bullet/debug/AbstractPhysicsDebugControl.java new file mode 100644 index 000000000..75e7bbe45 --- /dev/null +++ b/engine/src/bullet-common/com/jme3/bullet/debug/AbstractPhysicsDebugControl.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.bullet.debug; + +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.AbstractControl; + +/** + * + * @author normenhansen + */ +public abstract class AbstractPhysicsDebugControl extends AbstractControl { + + private final Quaternion tmp_inverseWorldRotation = new Quaternion(); + protected final BulletDebugAppState debugAppState; + + public AbstractPhysicsDebugControl(BulletDebugAppState debugAppState) { + this.debugAppState = debugAppState; + } + + /** + * This is called on the physics thread for debug controls + */ + @Override + protected abstract void controlUpdate(float tpf); + + protected void applyPhysicsTransform(Vector3f worldLocation, Quaternion worldRotation) { + applyPhysicsTransform(worldLocation, worldRotation, this.spatial); + } + + protected void applyPhysicsTransform(Vector3f worldLocation, Quaternion worldRotation, Spatial spatial) { + if (spatial != null) { + Vector3f localLocation = spatial.getLocalTranslation(); + Quaternion localRotationQuat = spatial.getLocalRotation(); + if (spatial.getParent() != null) { + localLocation.set(worldLocation).subtractLocal(spatial.getParent().getWorldTranslation()); + localLocation.divideLocal(spatial.getParent().getWorldScale()); + tmp_inverseWorldRotation.set(spatial.getParent().getWorldRotation()).inverseLocal().multLocal(localLocation); + localRotationQuat.set(worldRotation); + tmp_inverseWorldRotation.set(spatial.getParent().getWorldRotation()).inverseLocal().mult(localRotationQuat, localRotationQuat); + spatial.setLocalTranslation(localLocation); + spatial.setLocalRotation(localRotationQuat); + } else { + spatial.setLocalTranslation(worldLocation); + spatial.setLocalRotation(worldRotation); + } + } + + } +} diff --git a/engine/src/bullet-common/com/jme3/bullet/debug/BulletCharacterDebugControl.java b/engine/src/bullet-common/com/jme3/bullet/debug/BulletCharacterDebugControl.java new file mode 100644 index 000000000..de5b03a3f --- /dev/null +++ b/engine/src/bullet-common/com/jme3/bullet/debug/BulletCharacterDebugControl.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.bullet.debug; + +import com.jme3.bullet.objects.PhysicsCharacter; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; + +/** + * + * @author normenhansen + */ +public class BulletCharacterDebugControl extends AbstractPhysicsDebugControl { + + protected final PhysicsCharacter body; + protected final Geometry geom; + protected final Vector3f location = new Vector3f(); + protected final Quaternion rotation = new Quaternion(); + + public BulletCharacterDebugControl(BulletDebugAppState debugAppState, PhysicsCharacter body) { + super(debugAppState); + this.body = body; + this.geom = new Geometry(body.toString()); + geom.setMaterial(debugAppState.DEBUG_PINK); + } + + @Override + public void setSpatial(Spatial spatial) { + if (spatial != null && spatial instanceof Node) { + Node node = (Node) spatial; + node.attachChild(geom); + } else if (spatial == null && this.spatial != null) { + Node node = (Node) this.spatial; + node.detachChild(geom); + } + super.setSpatial(spatial); + } + + @Override + protected void controlUpdate(float tpf) { + Mesh mesh = debugAppState.getShapeBuffer().getShapeMesh(body.getCollisionShape()); + if (mesh != null) { + if (geom.getMesh() != mesh) { + geom.setMesh(mesh); + } + } else { + if (geom.getMesh() != BulletDebugAppState.CollisionShapeBuffer.NO_MESH) { + geom.setMesh(BulletDebugAppState.CollisionShapeBuffer.NO_MESH); + } + } + applyPhysicsTransform(body.getPhysicsLocation(location), Quaternion.IDENTITY); + } + + @Override + protected void controlRender(RenderManager rm, ViewPort vp) { + } +} diff --git a/engine/src/bullet-common/com/jme3/bullet/debug/BulletDebugAppState.java b/engine/src/bullet-common/com/jme3/bullet/debug/BulletDebugAppState.java new file mode 100644 index 000000000..5294d7b9e --- /dev/null +++ b/engine/src/bullet-common/com/jme3/bullet/debug/BulletDebugAppState.java @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.bullet.debug; + +import com.jme3.app.Application; +import com.jme3.app.state.AbstractAppState; +import com.jme3.app.state.AppStateManager; +import com.jme3.asset.AssetManager; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.CollisionShape; +import com.jme3.bullet.joints.PhysicsJoint; +import com.jme3.bullet.objects.PhysicsCharacter; +import com.jme3.bullet.objects.PhysicsGhostObject; +import com.jme3.bullet.objects.PhysicsRigidBody; +import com.jme3.bullet.objects.PhysicsVehicle; +import com.jme3.bullet.util.DebugShapeFactory; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Mesh; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.debug.Arrow; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author normenhansen + */ +public class BulletDebugAppState extends AbstractAppState { + + protected static final Logger logger = Logger.getLogger(BulletDebugAppState.class.getName()); + protected final PhysicsSpace space; + protected final CollisionShapeBuffer shapeBuffer = new CollisionShapeBuffer(); + protected final ArrowBuffer arrowBuffer = new ArrowBuffer(); + protected final Node physicsDebugRootNode = new Node("Physics Debug Root Node"); + protected ViewPort viewPort; + protected RenderManager rm; + public Material DEBUG_BLUE; + public Material DEBUG_RED; + public Material DEBUG_GREEN; + public Material DEBUG_YELLOW; + public Material DEBUG_MAGENTA; + public Material DEBUG_PINK; + protected HashMap bodies = new HashMap(); + protected HashMap joints = new HashMap(); + protected HashMap ghosts = new HashMap(); + protected HashMap characters = new HashMap(); + protected HashMap vehicles = new HashMap(); + + public BulletDebugAppState(PhysicsSpace space) { + this.space = space; + } + + @Override + public void initialize(AppStateManager stateManager, Application app) { + super.initialize(stateManager, app); + this.rm = app.getRenderManager(); + setupMaterials(app); + physicsDebugRootNode.setCullHint(Spatial.CullHint.Never); + viewPort = rm.createMainView("Physics Debug Overlay", app.getCamera()); + viewPort.setClearFlags(false, true, false); + viewPort.attachScene(physicsDebugRootNode); + } + + @Override + public void cleanup() { + rm.removeMainView(viewPort); + super.cleanup(); + } + + @Override + public void update(float tpf) { + super.update(tpf); + //update all object links + updateRigidBodies(); + updateGhosts(); + updateCharacters(); + updateJoints(); + updateVehicles(); + //update our debug root node + physicsDebugRootNode.updateLogicalState(tpf); + physicsDebugRootNode.updateGeometricState(); + //reset shapes -> this removes all meshes for shapes that were not used this update cycle + shapeBuffer.resetShapes(); + //reset arrows -> this makes arrow meshes available for the next update cycle + arrowBuffer.resetArrows(); + } + + @Override + public void render(RenderManager rm) { + super.render(rm); + if (viewPort != null) { + rm.renderScene(physicsDebugRootNode, viewPort); + } + } + + private void setupMaterials(Application app) { + AssetManager manager = app.getAssetManager(); + DEBUG_BLUE = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md"); + DEBUG_BLUE.getAdditionalRenderState().setWireframe(true); + DEBUG_BLUE.setColor("Color", ColorRGBA.Blue); + DEBUG_GREEN = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md"); + DEBUG_GREEN.getAdditionalRenderState().setWireframe(true); + DEBUG_GREEN.setColor("Color", ColorRGBA.Green); + DEBUG_RED = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md"); + DEBUG_RED.getAdditionalRenderState().setWireframe(true); + DEBUG_RED.setColor("Color", ColorRGBA.Red); + DEBUG_YELLOW = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md"); + DEBUG_YELLOW.getAdditionalRenderState().setWireframe(true); + DEBUG_YELLOW.setColor("Color", ColorRGBA.Yellow); + DEBUG_MAGENTA = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md"); + DEBUG_MAGENTA.getAdditionalRenderState().setWireframe(true); + DEBUG_MAGENTA.setColor("Color", ColorRGBA.Magenta); + DEBUG_PINK = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md"); + DEBUG_PINK.getAdditionalRenderState().setWireframe(true); + DEBUG_PINK.setColor("Color", ColorRGBA.Pink); + } + + private void updateRigidBodies() { + HashMap oldObjects = bodies; + bodies = new HashMap(); + Collection current = space.getRigidBodyList(); + //create new map + for (Iterator it = current.iterator(); it.hasNext();) { + PhysicsRigidBody physicsObject = it.next(); + //copy existing spatials + if (oldObjects.containsKey(physicsObject)) { + Spatial spat = oldObjects.get(physicsObject); + bodies.put(physicsObject, spat); + oldObjects.remove(physicsObject); + } else { + logger.log(Level.FINE, "Create new debug RigidBody"); + //create new spatial + Node node = new Node(physicsObject.toString()); + node.addControl(new BulletRigidBodyDebugControl(this, physicsObject)); + bodies.put(physicsObject, node); + physicsDebugRootNode.attachChild(node); + } + } + //remove leftover spatials + for (Map.Entry entry : oldObjects.entrySet()) { + PhysicsRigidBody object = entry.getKey(); + Spatial spatial = entry.getValue(); + spatial.removeFromParent(); + } + } + + private void updateJoints() { + HashMap oldObjects = joints; + joints = new HashMap(); + Collection current = space.getJointList(); + //create new map + for (Iterator it = current.iterator(); it.hasNext();) { + PhysicsJoint physicsObject = it.next(); + //copy existing spatials + if (oldObjects.containsKey(physicsObject)) { + Spatial spat = oldObjects.get(physicsObject); + joints.put(physicsObject, spat); + oldObjects.remove(physicsObject); + } else { + logger.log(Level.FINE, "Create new debug Joint"); + //create new spatial + Node node = new Node(physicsObject.toString()); + node.addControl(new BulletJointDebugControl(this, physicsObject)); + joints.put(physicsObject, node); + physicsDebugRootNode.attachChild(node); + } + } + //remove leftover spatials + for (Map.Entry entry : oldObjects.entrySet()) { + PhysicsJoint object = entry.getKey(); + Spatial spatial = entry.getValue(); + spatial.removeFromParent(); + } + } + + private void updateGhosts() { + HashMap oldObjects = ghosts; + ghosts = new HashMap(); + Collection current = space.getGhostObjectList(); + //create new map + for (Iterator it = current.iterator(); it.hasNext();) { + PhysicsGhostObject physicsObject = it.next(); + //copy existing spatials + if (oldObjects.containsKey(physicsObject)) { + Spatial spat = oldObjects.get(physicsObject); + ghosts.put(physicsObject, spat); + oldObjects.remove(physicsObject); + } else { + logger.log(Level.FINE, "Create new debug GhostObject"); + //create new spatial + Node node = new Node(physicsObject.toString()); + node.addControl(new BulletGhostObjectDebugControl(this, physicsObject)); + ghosts.put(physicsObject, node); + physicsDebugRootNode.attachChild(node); + } + } + //remove leftover spatials + for (Map.Entry entry : oldObjects.entrySet()) { + PhysicsGhostObject object = entry.getKey(); + Spatial spatial = entry.getValue(); + spatial.removeFromParent(); + } + } + + private void updateCharacters() { + HashMap oldObjects = characters; + characters = new HashMap(); + Collection current = space.getCharacterList(); + //create new map + for (Iterator it = current.iterator(); it.hasNext();) { + PhysicsCharacter physicsObject = it.next(); + //copy existing spatials + if (oldObjects.containsKey(physicsObject)) { + Spatial spat = oldObjects.get(physicsObject); + characters.put(physicsObject, spat); + oldObjects.remove(physicsObject); + } else { + logger.log(Level.FINE, "Create new debug Character"); + //create new spatial + Node node = new Node(physicsObject.toString()); + node.addControl(new BulletCharacterDebugControl(this, physicsObject)); + characters.put(physicsObject, node); + physicsDebugRootNode.attachChild(node); + } + } + //remove leftover spatials + for (Map.Entry entry : oldObjects.entrySet()) { + PhysicsCharacter object = entry.getKey(); + Spatial spatial = entry.getValue(); + spatial.removeFromParent(); + } + } + + private void updateVehicles() { + HashMap oldObjects = vehicles; + vehicles = new HashMap(); + Collection current = space.getVehicleList(); + //create new map + for (Iterator it = current.iterator(); it.hasNext();) { + PhysicsVehicle physicsObject = it.next(); + //copy existing spatials + if (oldObjects.containsKey(physicsObject)) { + Spatial spat = oldObjects.get(physicsObject); + vehicles.put(physicsObject, spat); + oldObjects.remove(physicsObject); + } else { + logger.log(Level.FINE, "Create new debug Vehicle"); + //create new spatial + Node node = new Node(physicsObject.toString()); + node.addControl(new BulletVehicleDebugControl(this, physicsObject)); + vehicles.put(physicsObject, node); + physicsDebugRootNode.attachChild(node); + } + } + //remove leftover spatials + for (Map.Entry entry : oldObjects.entrySet()) { + PhysicsVehicle object = entry.getKey(); + Spatial spatial = entry.getValue(); + spatial.removeFromParent(); + } + } + + public ArrowBuffer getArrowBuffer() { + return arrowBuffer; + } + + public CollisionShapeBuffer getShapeBuffer() { + return shapeBuffer; + } + + public static class CollisionShapeBuffer { + + public static final Mesh NO_MESH = new Arrow(new Vector3f(0, 0, 0)); + private HashMap shapes = new HashMap(); + private HashMap usedShapes = new HashMap(); + + public void resetShapes() { + shapes = usedShapes; + usedShapes = new HashMap(); + } + + public Mesh getShapeMesh(CollisionShape shape) { + if (shape == null) { + return null; + } + Mesh mesh = shapes.get(shape); + if (mesh == null) { + logger.log(Level.FINE, "Create new debug MESH"); + mesh = DebugShapeFactory.getDebugMesh(shape); + shapes.put(shape, mesh); + } + usedShapes.put(shape, mesh); + return mesh; + } + } + + public static class ArrowBuffer { + + private final Queue arrows = new ConcurrentLinkedQueue(); + private final Queue usedArrows = new ConcurrentLinkedQueue(); + + public void resetArrows() { + arrows.addAll(usedArrows); + } + + public Arrow getArrow() { + return getArrow(Vector3f.UNIT_Y); + } + + public Arrow getArrow(Vector3f extent) { + Arrow arrow = arrows.poll(); + if (arrow == null) { + arrow = new Arrow(extent); + } else { + arrow.setArrowExtent(extent); + } + usedArrows.add(arrow); + return arrow; + } + } +} diff --git a/engine/src/bullet-common/com/jme3/bullet/debug/BulletGhostObjectDebugControl.java b/engine/src/bullet-common/com/jme3/bullet/debug/BulletGhostObjectDebugControl.java new file mode 100644 index 000000000..6227714e1 --- /dev/null +++ b/engine/src/bullet-common/com/jme3/bullet/debug/BulletGhostObjectDebugControl.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.bullet.debug; + +import com.jme3.bullet.objects.PhysicsGhostObject; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; + +/** + * + * @author normenhansen + */ +public class BulletGhostObjectDebugControl extends AbstractPhysicsDebugControl{ + protected final PhysicsGhostObject body; + protected final Geometry geom; + protected final Vector3f location = new Vector3f(); + protected final Quaternion rotation = new Quaternion(); + + public BulletGhostObjectDebugControl(BulletDebugAppState debugAppState, PhysicsGhostObject body) { + super(debugAppState); + this.body = body; + this.geom = new Geometry(body.toString()); + geom.setMaterial(debugAppState.DEBUG_YELLOW); + } + + @Override + public void setSpatial(Spatial spatial) { + if (spatial != null && spatial instanceof Node) { + Node node = (Node) spatial; + node.attachChild(geom); + } else if (spatial == null && this.spatial != null) { + Node node = (Node) this.spatial; + node.detachChild(geom); + } + super.setSpatial(spatial); + } + + @Override + protected void controlUpdate(float tpf) { + Mesh mesh = debugAppState.getShapeBuffer().getShapeMesh(body.getCollisionShape()); + if (mesh != null) { + if (geom.getMesh() != mesh) { + geom.setMesh(mesh); + } + } else { + if (geom.getMesh() != BulletDebugAppState.CollisionShapeBuffer.NO_MESH) { + geom.setMesh(BulletDebugAppState.CollisionShapeBuffer.NO_MESH); + } + } + applyPhysicsTransform(body.getPhysicsLocation(location), Quaternion.IDENTITY); + } + + @Override + protected void controlRender(RenderManager rm, ViewPort vp) { + } +} diff --git a/engine/src/bullet-common/com/jme3/bullet/debug/BulletJointDebugControl.java b/engine/src/bullet-common/com/jme3/bullet/debug/BulletJointDebugControl.java new file mode 100644 index 000000000..571452811 --- /dev/null +++ b/engine/src/bullet-common/com/jme3/bullet/debug/BulletJointDebugControl.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.bullet.debug; + +import com.jme3.bullet.joints.PhysicsJoint; +import com.jme3.math.Quaternion; +import com.jme3.math.Transform; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.debug.Arrow; + +/** + * + * @author normenhansen + */ +public class BulletJointDebugControl extends AbstractPhysicsDebugControl { + + protected final PhysicsJoint body; + protected final Geometry geomA; + protected final Arrow arrowA; + protected final Geometry geomB; + protected final Arrow arrowB; + protected final Transform a = new Transform(new Vector3f(), new Quaternion()); + protected final Transform b = new Transform(new Vector3f(), new Quaternion()); + protected final Vector3f offA = new Vector3f(); + protected final Vector3f offB = new Vector3f(); + + public BulletJointDebugControl(BulletDebugAppState debugAppState, PhysicsJoint body) { + super(debugAppState); + this.body = body; + this.geomA = new Geometry(body.toString()); + arrowA = new Arrow(Vector3f.ZERO); + geomA.setMesh(arrowA); + geomA.setMaterial(debugAppState.DEBUG_GREEN); + this.geomB = new Geometry(body.toString()); + arrowB = new Arrow(Vector3f.ZERO); + geomB.setMesh(arrowB); + geomB.setMaterial(debugAppState.DEBUG_GREEN); + } + + @Override + public void setSpatial(Spatial spatial) { + if (spatial != null && spatial instanceof Node) { + Node node = (Node) spatial; + node.attachChild(geomA); + node.attachChild(geomB); + } else if (spatial == null && this.spatial != null) { + Node node = (Node) this.spatial; + node.detachChild(geomA); + node.detachChild(geomB); + } + super.setSpatial(spatial); + } + + @Override + protected void controlUpdate(float tpf) { + body.getBodyA().getPhysicsLocation(a.getTranslation()); + body.getBodyA().getPhysicsRotation(a.getRotation()); + + body.getBodyB().getPhysicsLocation(b.getTranslation()); + body.getBodyB().getPhysicsRotation(b.getRotation()); + + geomA.setLocalTransform(a); + geomB.setLocalTransform(b); + + arrowA.setArrowExtent(body.getPivotA()); + arrowB.setArrowExtent(body.getPivotB()); + } + + @Override + protected void controlRender(RenderManager rm, ViewPort vp) { + } +} diff --git a/engine/src/bullet-common/com/jme3/bullet/debug/BulletRigidBodyDebugControl.java b/engine/src/bullet-common/com/jme3/bullet/debug/BulletRigidBodyDebugControl.java new file mode 100644 index 000000000..b82d1e9fc --- /dev/null +++ b/engine/src/bullet-common/com/jme3/bullet/debug/BulletRigidBodyDebugControl.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.bullet.debug; + +import com.jme3.bullet.debug.BulletDebugAppState.CollisionShapeBuffer; +import com.jme3.bullet.objects.PhysicsRigidBody; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import java.util.logging.Logger; + +/** + * + * @author normenhansen + */ +public class BulletRigidBodyDebugControl extends AbstractPhysicsDebugControl { + + private static final Logger logger = Logger.getLogger(BulletRigidBodyDebugControl.class.getName()); + protected final PhysicsRigidBody body; + protected final Geometry geom; + protected final Vector3f location = new Vector3f(); + protected final Quaternion rotation = new Quaternion(); + + public BulletRigidBodyDebugControl(BulletDebugAppState debugAppState, PhysicsRigidBody body) { + super(debugAppState); + this.body = body; + this.geom = new Geometry(body.toString()); + geom.setMaterial(debugAppState.DEBUG_BLUE); + } + + @Override + public void setSpatial(Spatial spatial) { + if (spatial != null && spatial instanceof Node) { + Node node = (Node) spatial; + node.attachChild(geom); + } else if (spatial == null && this.spatial != null) { + Node node = (Node) this.spatial; + node.detachChild(geom); + } + super.setSpatial(spatial); + } + + @Override + protected void controlUpdate(float tpf) { + Mesh mesh = debugAppState.getShapeBuffer().getShapeMesh(body.getCollisionShape()); + if (mesh != null) { + if (geom.getMesh() != mesh) { + geom.setMesh(mesh); + } + } else { + if (geom.getMesh() != CollisionShapeBuffer.NO_MESH) { + geom.setMesh(CollisionShapeBuffer.NO_MESH); + } + } + applyPhysicsTransform(body.getPhysicsLocation(location), body.getPhysicsRotation(rotation)); + } + + @Override + protected void controlRender(RenderManager rm, ViewPort vp) { + } +} diff --git a/engine/src/bullet-common/com/jme3/bullet/debug/BulletVehicleDebugControl.java b/engine/src/bullet-common/com/jme3/bullet/debug/BulletVehicleDebugControl.java new file mode 100644 index 000000000..9b1458c2c --- /dev/null +++ b/engine/src/bullet-common/com/jme3/bullet/debug/BulletVehicleDebugControl.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.bullet.debug; + +import com.jme3.bullet.objects.PhysicsVehicle; +import com.jme3.bullet.objects.VehicleWheel; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.debug.Arrow; + +/** + * + * @author normenhansen + */ +public class BulletVehicleDebugControl extends AbstractPhysicsDebugControl { + + protected final PhysicsVehicle body; + protected final Node suspensionNode; + protected final Vector3f location = new Vector3f(); + protected final Quaternion rotation = new Quaternion(); + + public BulletVehicleDebugControl(BulletDebugAppState debugAppState, PhysicsVehicle body) { + super(debugAppState); + this.body = body; + suspensionNode = new Node("Suspension"); + createVehicle(); + } + + @Override + public void setSpatial(Spatial spatial) { + if (spatial != null && spatial instanceof Node) { + Node node = (Node) spatial; + node.attachChild(suspensionNode); + } else if (spatial == null && this.spatial != null) { + Node node = (Node) this.spatial; + node.detachChild(suspensionNode); + } + super.setSpatial(spatial); + } + + private void createVehicle() { + suspensionNode.detachAllChildren(); + for (int i = 0; i < body.getNumWheels(); i++) { + VehicleWheel physicsVehicleWheel = body.getWheel(i); + Vector3f location = physicsVehicleWheel.getLocation().clone(); + Vector3f direction = physicsVehicleWheel.getDirection().clone(); + Vector3f axle = physicsVehicleWheel.getAxle().clone(); + float restLength = physicsVehicleWheel.getRestLength(); + float radius = physicsVehicleWheel.getRadius(); + + Arrow locArrow = new Arrow(location); + Arrow axleArrow = new Arrow(axle.normalizeLocal().multLocal(0.3f)); + Arrow wheelArrow = new Arrow(direction.normalizeLocal().multLocal(radius)); + Arrow dirArrow = new Arrow(direction.normalizeLocal().multLocal(restLength)); + Geometry locGeom = new Geometry("WheelLocationDebugShape" + i, locArrow); + Geometry dirGeom = new Geometry("WheelDirectionDebugShape" + i, dirArrow); + Geometry axleGeom = new Geometry("WheelAxleDebugShape" + i, axleArrow); + Geometry wheelGeom = new Geometry("WheelRadiusDebugShape" + i, wheelArrow); + dirGeom.setLocalTranslation(location); + axleGeom.setLocalTranslation(location.add(direction)); + wheelGeom.setLocalTranslation(location.add(direction)); + locGeom.setMaterial(debugAppState.DEBUG_GREEN); + dirGeom.setMaterial(debugAppState.DEBUG_GREEN); + axleGeom.setMaterial(debugAppState.DEBUG_GREEN); + wheelGeom.setMaterial(debugAppState.DEBUG_GREEN); + suspensionNode.attachChild(locGeom); + suspensionNode.attachChild(dirGeom); + suspensionNode.attachChild(axleGeom); + suspensionNode.attachChild(wheelGeom); + } + } + + @Override + protected void controlUpdate(float tpf) { + for (int i = 0; i < body.getNumWheels(); i++) { + VehicleWheel physicsVehicleWheel = body.getWheel(i); + Vector3f location = physicsVehicleWheel.getLocation().clone(); + Vector3f direction = physicsVehicleWheel.getDirection().clone(); + Vector3f axle = physicsVehicleWheel.getAxle().clone(); + float restLength = physicsVehicleWheel.getRestLength(); + float radius = physicsVehicleWheel.getRadius(); + + Geometry locGeom = (Geometry) suspensionNode.getChild("WheelLocationDebugShape" + i); + Geometry dirGeom = (Geometry) suspensionNode.getChild("WheelDirectionDebugShape" + i); + Geometry axleGeom = (Geometry) suspensionNode.getChild("WheelAxleDebugShape" + i); + Geometry wheelGeom = (Geometry) suspensionNode.getChild("WheelRadiusDebugShape" + i); + + Arrow locArrow = (Arrow) locGeom.getMesh(); + locArrow.setArrowExtent(location); + Arrow axleArrow = (Arrow) axleGeom.getMesh(); + axleArrow.setArrowExtent(axle.normalizeLocal().multLocal(0.3f)); + Arrow wheelArrow = (Arrow) wheelGeom.getMesh(); + wheelArrow.setArrowExtent(direction.normalizeLocal().multLocal(radius)); + Arrow dirArrow = (Arrow) dirGeom.getMesh(); + dirArrow.setArrowExtent(direction.normalizeLocal().multLocal(restLength)); + + dirGeom.setLocalTranslation(location); + axleGeom.setLocalTranslation(location.addLocal(direction)); + wheelGeom.setLocalTranslation(location); + i++; + } + applyPhysicsTransform(body.getPhysicsLocation(location), body.getPhysicsRotation(rotation)); + } + + @Override + protected void controlRender(RenderManager rm, ViewPort vp) { + } +} diff --git a/engine/src/bullet/com/jme3/bullet/PhysicsSpace.java b/engine/src/bullet/com/jme3/bullet/PhysicsSpace.java index f97ebf198..d84bf62f2 100644 --- a/engine/src/bullet/com/jme3/bullet/PhysicsSpace.java +++ b/engine/src/bullet/com/jme3/bullet/PhysicsSpace.java @@ -920,7 +920,7 @@ public class PhysicsSpace { /** * Enable debug display for physics * @param manager AssetManager to use to create debug materials - * @Deprecated in favor of BulletDebugAppState, use BulletAppState.enableDebug() to add automatically + * @Deprecated in favor of BulletDebugAppState, use BulletAppState.setDebugEnabled(boolean) to add automatically */ @Deprecated public void enableDebug(AssetManager manager) { diff --git a/engine/src/jbullet/com/jme3/bullet/PhysicsSpace.java b/engine/src/jbullet/com/jme3/bullet/PhysicsSpace.java index 123779ad9..90a35f390 100644 --- a/engine/src/jbullet/com/jme3/bullet/PhysicsSpace.java +++ b/engine/src/jbullet/com/jme3/bullet/PhysicsSpace.java @@ -859,7 +859,7 @@ public class PhysicsSpace { /** * Enable debug display for physics * @param manager AssetManager to use to create debug materials - * @Deprecated in favor of BulletDebugAppState, use BulletAppState.enableDebug() to add automatically + * @Deprecated in favor of BulletDebugAppState, use BulletAppState.setDebugEnabled(boolean) to add automatically */ @Deprecated public void enableDebug(AssetManager manager) {