Przeglądaj źródła

jme3-bullet: add and improve comments, mostly JavaDoc

Stephen Gold 7 lat temu
rodzic
commit
7e17cdc498
62 zmienionych plików z 5958 dodań i 982 usunięć
  1. 215 26
      jme3-bullet/src/common/java/com/jme3/bullet/BulletAppState.java
  2. 15 8
      jme3-bullet/src/common/java/com/jme3/bullet/PhysicsTickListener.java
  3. 13 6
      jme3-bullet/src/common/java/com/jme3/bullet/collision/PhysicsCollisionGroupListener.java
  4. 14 6
      jme3-bullet/src/common/java/com/jme3/bullet/collision/PhysicsCollisionListener.java
  5. 12 1
      jme3-bullet/src/common/java/com/jme3/bullet/collision/RagdollCollisionListener.java
  6. 39 1
      jme3-bullet/src/common/java/com/jme3/bullet/collision/shapes/infos/ChildCollisionShape.java
  7. 115 28
      jme3-bullet/src/common/java/com/jme3/bullet/control/AbstractPhysicsControl.java
  8. 167 114
      jme3-bullet/src/common/java/com/jme3/bullet/control/BetterCharacterControl.java
  9. 129 6
      jme3-bullet/src/common/java/com/jme3/bullet/control/GhostControl.java
  10. 323 75
      jme3-bullet/src/common/java/com/jme3/bullet/control/KinematicRagdollControl.java
  11. 26 10
      jme3-bullet/src/common/java/com/jme3/bullet/control/PhysicsControl.java
  12. 146 14
      jme3-bullet/src/common/java/com/jme3/bullet/control/RigidBodyControl.java
  13. 112 7
      jme3-bullet/src/common/java/com/jme3/bullet/control/VehicleControl.java
  14. 10 1
      jme3-bullet/src/common/java/com/jme3/bullet/control/ragdoll/HumanoidRagdollPreset.java
  15. 58 1
      jme3-bullet/src/common/java/com/jme3/bullet/control/ragdoll/RagdollPreset.java
  16. 70 25
      jme3-bullet/src/common/java/com/jme3/bullet/control/ragdoll/RagdollUtils.java
  17. 31 1
      jme3-bullet/src/common/java/com/jme3/bullet/debug/AbstractPhysicsDebugControl.java
  18. 44 1
      jme3-bullet/src/common/java/com/jme3/bullet/debug/BulletCharacterDebugControl.java
  19. 95 5
      jme3-bullet/src/common/java/com/jme3/bullet/debug/BulletDebugAppState.java
  20. 47 1
      jme3-bullet/src/common/java/com/jme3/bullet/debug/BulletGhostObjectDebugControl.java
  21. 32 1
      jme3-bullet/src/common/java/com/jme3/bullet/debug/BulletJointDebugControl.java
  22. 47 1
      jme3-bullet/src/common/java/com/jme3/bullet/debug/BulletRigidBodyDebugControl.java
  23. 32 1
      jme3-bullet/src/common/java/com/jme3/bullet/debug/BulletVehicleDebugControl.java
  24. 129 1
      jme3-bullet/src/common/java/com/jme3/bullet/debug/DebugTools.java
  25. 71 26
      jme3-bullet/src/common/java/com/jme3/bullet/util/CollisionShapeFactory.java
  26. 386 91
      jme3-bullet/src/main/java/com/jme3/bullet/PhysicsSpace.java
  27. 202 9
      jme3-bullet/src/main/java/com/jme3/bullet/collision/PhysicsCollisionEvent.java
  28. 10 0
      jme3-bullet/src/main/java/com/jme3/bullet/collision/PhysicsCollisionEventFactory.java
  29. 157 28
      jme3-bullet/src/main/java/com/jme3/bullet/collision/PhysicsCollisionObject.java
  30. 29 9
      jme3-bullet/src/main/java/com/jme3/bullet/collision/PhysicsRayTestResult.java
  31. 34 5
      jme3-bullet/src/main/java/com/jme3/bullet/collision/PhysicsSweepTestResult.java
  32. 36 5
      jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/BoxCollisionShape.java
  33. 64 12
      jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/CapsuleCollisionShape.java
  34. 75 6
      jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/CollisionShape.java
  35. 44 11
      jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/CompoundCollisionShape.java
  36. 55 2
      jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/ConeCollisionShape.java
  37. 54 8
      jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/CylinderCollisionShape.java
  38. 34 3
      jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/GImpactCollisionShape.java
  39. 65 9
      jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/HeightfieldCollisionShape.java
  40. 42 1
      jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/HullCollisionShape.java
  41. 51 24
      jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/MeshCollisionShape.java
  42. 32 3
      jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/PlaneCollisionShape.java
  43. 52 2
      jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/SimplexCollisionShape.java
  44. 38 5
      jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/SphereCollisionShape.java
  45. 62 6
      jme3-bullet/src/main/java/com/jme3/bullet/joints/ConeJoint.java
  46. 116 22
      jme3-bullet/src/main/java/com/jme3/bullet/joints/HingeJoint.java
  47. 94 10
      jme3-bullet/src/main/java/com/jme3/bullet/joints/PhysicsJoint.java
  48. 70 7
      jme3-bullet/src/main/java/com/jme3/bullet/joints/Point2PointJoint.java
  49. 112 20
      jme3-bullet/src/main/java/com/jme3/bullet/joints/SixDofJoint.java
  50. 70 11
      jme3-bullet/src/main/java/com/jme3/bullet/joints/SixDofSpringJoint.java
  51. 357 7
      jme3-bullet/src/main/java/com/jme3/bullet/joints/SliderJoint.java
  52. 119 1
      jme3-bullet/src/main/java/com/jme3/bullet/joints/motors/RotationalLimitMotor.java
  53. 79 1
      jme3-bullet/src/main/java/com/jme3/bullet/joints/motors/TranslationalLimitMotor.java
  54. 243 21
      jme3-bullet/src/main/java/com/jme3/bullet/objects/PhysicsCharacter.java
  55. 127 24
      jme3-bullet/src/main/java/com/jme3/bullet/objects/PhysicsGhostObject.java
  56. 358 76
      jme3-bullet/src/main/java/com/jme3/bullet/objects/PhysicsRigidBody.java
  57. 276 116
      jme3-bullet/src/main/java/com/jme3/bullet/objects/PhysicsVehicle.java
  58. 315 43
      jme3-bullet/src/main/java/com/jme3/bullet/objects/VehicleWheel.java
  59. 53 9
      jme3-bullet/src/main/java/com/jme3/bullet/objects/infos/RigidBodyMotionState.java
  60. 23 2
      jme3-bullet/src/main/java/com/jme3/bullet/objects/infos/VehicleTuning.java
  61. 12 1
      jme3-bullet/src/main/java/com/jme3/bullet/util/DebugMeshCallback.java
  62. 20 5
      jme3-bullet/src/main/java/com/jme3/bullet/util/DebugShapeFactory.java

+ 215 - 26
jme3-bullet/src/common/java/com/jme3/bullet/BulletAppState.java

@@ -43,66 +43,136 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * <code>BulletAppState</code> allows using bullet physics in an Application.
+ * An app state to manage a single Bullet physics space.
+ * <p>
+ * This class is shared between JBullet and Native Bullet.
  *
  * @author normenhansen
  */
 public class BulletAppState implements AppState, PhysicsTickListener {
 
+    /**
+     * true if-and-only-if the physics simulation is running (started but not
+     * yet stopped)
+     */
     protected boolean initialized = false;
     protected Application app;
+    /**
+     * manager that manages this state, set during attach
+     */
     protected AppStateManager stateManager;
+    /**
+     * executor service for physics tasks, or null if parallel simulation is not
+     * running
+     */
     protected ScheduledThreadPoolExecutor executor;
+    /**
+     * physics space managed by this state, or null if no simulation running
+     */
     protected PhysicsSpace pSpace;
+    /**
+     * threading mode to use (not null)
+     */
     protected ThreadingType threadingType = ThreadingType.SEQUENTIAL;
+    /**
+     * broadphase collision-detection algorithm for the physics space to use
+     * (not null)
+     */
     protected BroadphaseType broadphaseType = BroadphaseType.DBVT;
+    /**
+     * minimum coordinate values for the physics space when using AXIS_SWEEP
+     * broadphase algorithms (not null)
+     */
     protected Vector3f worldMin = new Vector3f(-10000f, -10000f, -10000f);
+    /**
+     * maximum coordinate values for the physics space when using AXIS_SWEEP
+     * broadphase algorithms (not null)
+     */
     protected Vector3f worldMax = new Vector3f(10000f, 10000f, 10000f);
+    /**
+     * simulation speed multiplier (default=1, paused=0)
+     */
     protected float speed = 1;
+    /**
+     * true if-and-only-if this state is enabled
+     */
     protected boolean active = true;
+    /**
+     * true if-and-only-if debug visualization is enabled
+     */
     protected boolean debugEnabled = false;
+    /**
+     * app state to manage the debug visualization, or null if none
+     */
     protected BulletDebugAppState debugAppState;
+    /**
+     * time interval between frames (in seconds) from the most recent update
+     */
     protected float tpf;
+    /**
+     * current physics task, or null if none
+     */
     protected Future physicsFuture;
 
     /**
-     * Creates a new BulletAppState running a PhysicsSpace for physics
-     * simulation, use getStateManager().attach(bulletAppState) to enable
-     * physics for an Application.
+     * Instantiate an app state to manage a new PhysicsSpace with DBVT collision
+     * detection.
+     * <p>
+     * Use getStateManager().addState(bulletAppState) to start physics.
      */
     public BulletAppState() {
     }
 
     /**
-     * Creates a new BulletAppState running a PhysicsSpace for physics
-     * simulation, use getStateManager().attach(bulletAppState) to enable
-     * physics for an Application.
+     * Instantiate an app state to manage a new PhysicsSpace.
+     * <p>
+     * Use getStateManager().addState(bulletAppState) to start physics.
      *
-     * @param broadphaseType The type of broadphase collision detection,
-     * BroadphaseType.DVBT is the default
+     * @param broadphaseType which broadphase collision-detection algorithm to
+     * use (not null)
      */
     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().attach(bulletAppState) to enable
-     * physics for an Application. An AxisSweep broadphase is used.
+     * Instantiate an app state to manage a new PhysicsSpace with AXIS_SWEEP_3
+     * collision detection.
+     * <p>
+     * Use getStateManager().addState(bulletAppState) to start physics.
      *
-     * @param worldMin The minimum world extent
-     * @param worldMax The maximum world extent
+     * @param worldMin the desired minimum coordinate values (not null,
+     * unaffected, default=-10k,-10k,-10k)
+     * @param worldMax the desired maximum coordinate values (not null,
+     * unaffected, default=10k,10k,10k)
      */
     public BulletAppState(Vector3f worldMin, Vector3f worldMax) {
         this(worldMin, worldMax, BroadphaseType.AXIS_SWEEP_3);
     }
 
+    /**
+     * Instantiate an app state to manage a new PhysicsSpace.
+     * <p>
+     * Use getStateManager().addState(bulletAppState) to enable physics.
+     *
+     * @param worldMin the desired minimum coordinate values (not null,
+     * unaffected, default=-10k,-10k,-10k)
+     * @param worldMax the desired maximum coordinate values (not null,
+     * unaffected, default=10k,10k,10k)
+     * @param broadphaseType which broadphase collision-detection algorithm to
+     * use (not null)
+     */
     public BulletAppState(Vector3f worldMin, Vector3f worldMax, BroadphaseType broadphaseType) {
         this.worldMin.set(worldMin);
         this.worldMax.set(worldMax);
         this.broadphaseType = broadphaseType;
     }
 
+    /**
+     * Allocate the physics space and start physics for ThreadingType.PARALLEL.
+     *
+     * @return true if successful, otherwise false
+     */
     private boolean startPhysicsOnExecutor() {
         if (executor != null) {
             executor.shutdown();
@@ -145,6 +215,12 @@ public class BulletAppState implements AppState, PhysicsTickListener {
         }
     };
 
+    /**
+     * Access the PhysicsSpace managed by this state. Normally there is none
+     * until the state is attached.
+     *
+     * @return the pre-existing instance, or null if no simulation running
+     */
     public PhysicsSpace getPhysicsSpace() {
         return pSpace;
     }
@@ -179,6 +255,9 @@ public class BulletAppState implements AppState, PhysicsTickListener {
         initialized = true;
     }
 
+    /**
+     * Stop physics after this state is detached.
+     */
     public void stopPhysics() {
         if(!initialized){
             return;
@@ -192,32 +271,72 @@ public class BulletAppState implements AppState, PhysicsTickListener {
         initialized = false;
     }
 
+    /**
+     * Initialize this state prior to its 1st update. Should be invoked only by
+     * a subclass or by the AppStateManager.
+     *
+     * @param stateManager the manager for this state (not null)
+     * @param app the application which owns this state (not null)
+     */
     public void initialize(AppStateManager stateManager, Application app) {
         this.app = app;
         this.stateManager = stateManager;
         startPhysics();
     }
 
+    /**
+     * Test whether the physics simulation is running (started but not yet
+     * stopped).
+     *
+     * @return true if running, otherwise false
+     */
     public boolean isInitialized() {
         return initialized;
     }
 
+    /**
+     * Enable or disable this state.
+     *
+     * @param enabled true &rarr; enable, false &rarr; disable
+     */
     public void setEnabled(boolean enabled) {
         this.active = enabled;
     }
 
+    /**
+     * Test whether this state is enabled.
+     *
+     * @return true if enabled, otherwise false
+     */
     public boolean isEnabled() {
         return active;
     }
 
+    /**
+     * Alter whether debug visualization is enabled.
+     *
+     * @param debugEnabled true &rarr; enable, false &rarr; disable
+     */
     public void setDebugEnabled(boolean debugEnabled) {
         this.debugEnabled = debugEnabled;
     }
 
+
+    /**
+     * Test whether debug visualization is enabled.
+     *
+     * @return true if enabled, otherwise false
+     */
     public boolean isDebugEnabled() {
         return debugEnabled;
     }
 
+    /**
+     * Transition this state from detached to initializing. Should be invoked
+     * only by a subclass or by the AppStateManager.
+     *
+     * @param stateManager (not null)
+     */
     public void stateAttached(AppStateManager stateManager) {
         if (!initialized) {
             startPhysics();
@@ -231,9 +350,22 @@ public class BulletAppState implements AppState, PhysicsTickListener {
         }
     }
 
+    /**
+     * Transition this state from running to terminating. Should be invoked only
+     * by a subclass or by the AppStateManager.
+     *
+     * @param stateManager (not null)
+     */
     public void stateDetached(AppStateManager stateManager) {
     }
 
+    /**
+     * Update this state prior to rendering. Should be invoked only by a
+     * subclass or by the AppStateManager. Invoked once per frame, provided the
+     * state is attached and enabled.
+     *
+     * @param tpf the time interval between frames (in seconds, &ge;0)
+     */
     public void update(float tpf) {
         if (debugEnabled && debugAppState == null && pSpace != null) {
             debugAppState = new BulletDebugAppState(pSpace);
@@ -249,6 +381,13 @@ public class BulletAppState implements AppState, PhysicsTickListener {
         this.tpf = tpf;
     }
 
+    /**
+     * Render this state. Should be invoked only by a subclass or by the
+     * AppStateManager. Invoked once per frame, provided the state is attached
+     * and enabled.
+     *
+     * @param rm the render manager (not null)
+     */
     public void render(RenderManager rm) {
         if (!active) {
             return;
@@ -261,6 +400,11 @@ public class BulletAppState implements AppState, PhysicsTickListener {
         }
     }
 
+    /**
+     * Update this state after all rendering commands are flushed. Should be
+     * invoked only by a subclass or by the AppStateManager. Invoked once per
+     * frame, provided the state is attached and enabled.
+     */
     public void postRender() {
         if (physicsFuture != null) {
             try {
@@ -274,6 +418,12 @@ public class BulletAppState implements AppState, PhysicsTickListener {
         }
     }
 
+    /**
+     * Transition this state from terminating to detached. Should be invoked
+     * only by a subclass or by the AppStateManager. Invoked once for each time
+     * {@link #initialize(com.jme3.app.state.AppStateManager, com.jme3.app.Application)}
+     * is invoked.
+     */
     public void cleanup() {
         if (debugAppState != null) {
             stateManager.detach(debugAppState);
@@ -283,67 +433,106 @@ public class BulletAppState implements AppState, PhysicsTickListener {
     }
 
     /**
-     * @return the threadingType
+     * Read which type of threading this app state uses.
+     *
+     * @return the threadingType (not null)
      */
     public ThreadingType getThreadingType() {
         return threadingType;
     }
 
     /**
-     * Use before attaching state
+     * Alter which type of threading this app state uses. Not allowed after
+     * attaching the app state.
      *
-     * @param threadingType the threadingType to set
+     * @param threadingType the desired type (not null, default=SEQUENTIAL)
      */
     public void setThreadingType(ThreadingType threadingType) {
         this.threadingType = threadingType;
     }
 
     /**
-     * Use before attaching state
+     * Alter the broadphase type the physics space will use. Not allowed after
+     * attaching the app state.
+     *
+     * @param broadphaseType an enum value (not null, default=DBVT)
      */
     public void setBroadphaseType(BroadphaseType broadphaseType) {
         this.broadphaseType = broadphaseType;
     }
 
     /**
-     * Use before attaching state
+     * Alter the coordinate range. Not allowed after attaching the app state.
+     *
+     * @param worldMin the desired minimum coordinate values when using
+     * AXIS_SWEEP broadphase algorithms (not null, alias created,
+     * default=-10k,-10k,-10k)
      */
     public void setWorldMin(Vector3f worldMin) {
         this.worldMin = worldMin;
     }
 
     /**
-     * Use before attaching state
+     * Alter the coordinate range. Not allowed after attaching the app state.
+     *
+     * @param worldMax the desired maximum coordinate values when using
+     * AXIS_SWEEP broadphase algorithms (not null, alias created,
+     * default=10k,10k,10k)
      */
     public void setWorldMax(Vector3f worldMax) {
         this.worldMax = worldMax;
     }
 
+    /**
+     * Read the simulation speed.
+     *
+     * @return speed (&ge;0, default=1)
+     */
     public float getSpeed() {
         return speed;
     }
 
+    /**
+     * Alter the simulation speed.
+     *
+     * @param speed the desired speed (&ge;0, default=1)
+     */
     public void setSpeed(float speed) {
         this.speed = speed;
     }
-
+    /**
+     * Callback from Bullet, invoked just before the physics is stepped. A good
+     * time to clear/apply forces.
+     *
+     * @param space the space that is about to be stepped (not null)
+     * @param f the time per physics step (in seconds, &ge;0)
+     */
     public void prePhysicsTick(PhysicsSpace space, float f) {
     }
 
+    /**
+     * Callback from Bullet, invoked just after the physics is stepped. A good
+     * time to clear/apply forces.
+     *
+     * @param space the space that is about to be stepped (not null)
+     * @param f the time per physics step (in seconds, &ge;0)
+     */
     public void physicsTick(PhysicsSpace space, float f) {
     }
 
+    /**
+     * Enumerate threading modes.
+     */
     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.<br/> Multiple BulletAppStates will
-         * execute in parallel in this mode.
+         * Parallel threaded mode: physics update and rendering are executed in
+         * parallel, update order is maintained.
          */
         PARALLEL,
     }

+ 15 - 8
jme3-bullet/src/common/java/com/jme3/bullet/PhysicsTickListener.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,22 +32,29 @@
 package com.jme3.bullet;
 
 /**
- * Implement this interface to be called from the physics thread on a physics update.
+ * Callback interface from the physics thread, used to clear/apply forces.
+ * <p>
+ * This interface is shared between JBullet and Native Bullet.
+ *
  * @author normenhansen
  */
 public interface PhysicsTickListener {
 
     /**
-     * Called before the physics is actually stepped, use to apply forces etc.
-     * @param space the physics space
-     * @param tpf the time per frame in seconds 
+     * Callback from Bullet, invoked just before the physics is stepped. A good
+     * time to clear/apply forces.
+     *
+     * @param space the space that is about to be stepped (not null)
+     * @param tpf the time per physics step (in seconds, &ge;0)
      */
     public void prePhysicsTick(PhysicsSpace space, float tpf);
 
     /**
-     * Called after the physics has been stepped, use to check for forces etc.
-     * @param space the physics space
-     * @param tpf the time per frame in seconds
+     * Callback from Bullet, invoked just after the physics has been stepped,
+     * use to check for forces etc.
+     *
+     * @param space the space that was just stepped (not null)
+     * @param tpf the time per physics step (in seconds, &ge;0)
      */
     public void physicsTick(PhysicsSpace space, float tpf);
 

+ 13 - 6
jme3-bullet/src/common/java/com/jme3/bullet/collision/PhysicsCollisionGroupListener.java

@@ -32,18 +32,25 @@
 package com.jme3.bullet.collision;
 
 /**
+ * Interface to receive notifications whenever an object in a particular
+ * collision group is about to collide.
+ * <p>
+ * This interface is shared between JBullet and Native Bullet.
  *
  * @author normenhansen
  */
 public interface PhysicsCollisionGroupListener {
 
     /**
-     * Called when two physics objects of the registered group are about to collide, <i>called from physics thread</i>.<br>
-     * This is only called when the collision will happen based on the collisionGroup and collideWithGroups
-     * settings in the PhysicsCollisionObject. That is the case when <b>one</b> of the parties has the
-     * collisionGroup of the other in its collideWithGroups set.<br>
-     * @param nodeA CollisionObject #1
-     * @param nodeB CollisionObject #2
+     * Invoked when two physics objects of the registered group are about to
+     * collide. <i>invoked on the physics thread</i>.<br>
+     * This is only invoked when the collision will happen based on the
+     * collisionGroup and collideWithGroups settings in the
+     * PhysicsCollisionObject. That is the case when <b>one</b> of the parties
+     * has the collisionGroup of the other in its collideWithGroups set.
+     *
+     * @param nodeA collision object #1
+     * @param nodeB collision object #2
      * @return true if the collision should happen, false otherwise
      */
     public boolean collide(PhysicsCollisionObject nodeA, PhysicsCollisionObject nodeB);

+ 14 - 6
jme3-bullet/src/common/java/com/jme3/bullet/collision/PhysicsCollisionListener.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,16 +32,24 @@
 package com.jme3.bullet.collision;
 
 /**
- * Interface for Objects that want to be informed about collision events in the physics space
+ * Interface to receive notifications whenever an object in a particular physics
+ * space collides.
+ * <p>
+ * This interface is shared between JBullet and Native Bullet.
+ *
  * @author normenhansen
  */
 public interface PhysicsCollisionListener {
 
     /**
-     * Called when a collision happened in the PhysicsSpace, <i>called from render thread</i>.
-     * 
-     * Do not store the event object as it will be cleared after the method has finished.
-     * @param event the CollisionEvent
+     * Invoked when a collision happened in the PhysicsSpace. <i>Invoked on the
+     * render thread.</i>
+     * <p>
+     * Do not retain the event object, as it will be reused after the
+     * collision() method returns. Copy any data you need during the collide()
+     * method.
+     *
+     * @param event the event that occurred (not null, reusable)
      */
     public void collision(PhysicsCollisionEvent event);
 

+ 12 - 1
jme3-bullet/src/common/java/com/jme3/bullet/collision/RagdollCollisionListener.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,11 +34,22 @@ package com.jme3.bullet.collision;
 import com.jme3.animation.Bone;
 
 /**
+ * Interface to receive notifications whenever a KinematicRagdollControl
+ * collides with another physics object.
+ * <p>
+ * This interface is shared between JBullet and Native Bullet.
  *
  * @author Nehon
  */
 public interface RagdollCollisionListener {
     
+    /**
+     * Invoked when a collision involving a KinematicRagdollControl occurs.
+     *
+     * @param bone the ragdoll bone that collided (not null)
+     * @param object the collision object that collided with the bone (not null)
+     * @param event other event details (not null)
+     */    
     public void collide(Bone bone, PhysicsCollisionObject object, PhysicsCollisionEvent event);
     
 }

+ 39 - 1
jme3-bullet/src/common/java/com/jme3/bullet/collision/shapes/infos/ChildCollisionShape.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -39,24 +39,56 @@ import com.jme3.math.Vector3f;
 import java.io.IOException;
 
 /**
+ * An element of a CompoundCollisionShape, consisting of a (non-compound) child
+ * shape, offset and rotated with respect to its parent.
+ * <p>
+ * This class is shared between JBullet and Native Bullet.
  *
  * @author normenhansen
  */
 public class ChildCollisionShape implements Savable {
 
+    /**
+     * translation relative to parent shape (not null)
+     */
     public Vector3f location;
+    /**
+     * rotation relative to parent shape (not null)
+     */
     public Matrix3f rotation;
+    /**
+     * base shape (not null, not a compound shape)
+     */
     public CollisionShape shape;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public ChildCollisionShape() {
     }
 
+    /**
+     * Instantiate a child shape for use in a compound shape.
+     *
+     * @param location translation relative to the parent (not null, alias
+     * created)
+     * @param rotation rotation relative to the parent (not null, alias created)
+     * @param shape the base shape (not null, not a compound shape, alias
+     * created)
+     */
     public ChildCollisionShape(Vector3f location, Matrix3f rotation, CollisionShape shape) {
         this.location = location;
         this.rotation = rotation;
         this.shape = shape;
     }
 
+    /**
+     * Serialize this shape, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     public void write(JmeExporter ex) throws IOException {
         OutputCapsule capsule = ex.getCapsule(this);
         capsule.write(location, "location", new Vector3f());
@@ -64,6 +96,12 @@ public class ChildCollisionShape implements Savable {
         capsule.write(shape, "shape", new BoxCollisionShape(new Vector3f(1, 1, 1)));
     }
 
+    /**
+     * De-serialize this shape, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     public void read(JmeImporter im) throws IOException {
         InputCapsule capsule = im.getCapsule(this);
         location = (Vector3f) capsule.readSavable("location", new Vector3f());

+ 115 - 28
jme3-bullet/src/common/java/com/jme3/bullet/control/AbstractPhysicsControl.java

@@ -46,82 +46,113 @@ import com.jme3.util.clone.JmeCloneable;
 import java.io.IOException;
 
 /**
- * AbstractPhysicsControl manages the lifecycle of a physics object that is
- * attached to a spatial in the SceneGraph.
+ * Manage the life cycle of a physics object linked to a spatial in a scene
+ * graph.
+ * <p>
+ * This class is shared between JBullet and Native Bullet.
  *
  * @author normenhansen
  */
 public abstract class AbstractPhysicsControl implements PhysicsControl, JmeCloneable {
 
+    /**
+     * temporary storage during calculations
+     */
     private final Quaternion tmp_inverseWorldRotation = new Quaternion();
+    /**
+     * spatial to which this control is added, or null if none
+     */
     protected Spatial spatial;
+    /**
+     * true&rarr;control is enabled, false&rarr;control is disabled
+     */
     protected boolean enabled = true;
+    /**
+     * true&rarr;body is added to the physics space, false&rarr;not added
+     */
     protected boolean added = false;
+    /**
+     * space to which the physics object is (or would be) added
+     */
     protected PhysicsSpace space = null;
+    /**
+     * true &rarr; physics coordinates match local transform, false &rarr;
+     * physics coordinates match world transform
+     */
     protected boolean applyLocal = false;
 
     /**
-     * Called when the control is added to a new spatial, create any
-     * spatial-dependent data here.
+     * Create spatial-dependent data. Invoked when this control is added to a
+     * spatial.
      *
-     * @param spat The new spatial, guaranteed not to be null
+     * @param spat the controlled spatial (not null)
      */
     protected abstract void createSpatialData(Spatial spat);
 
     /**
-     * Called when the control is removed from a spatial, remove any
-     * spatial-dependent data here.
+     * Destroy spatial-dependent data. Invoked when this control is removed from
+     * a spatial.
      *
-     * @param spat The old spatial, guaranteed not to be null
+     * @param spat the previously controlled spatial (not null)
      */
     protected abstract void removeSpatialData(Spatial spat);
 
     /**
-     * Called when the physics object is supposed to move to the spatial
-     * position.
+     * Translate the physics object to the specified location.
      *
-     * @param vec
+     * @param vec desired location (not null, unaffected)
      */
     protected abstract void setPhysicsLocation(Vector3f vec);
 
     /**
-     * Called when the physics object is supposed to move to the spatial
-     * rotation.
+     * Rotate the physics object to the specified orientation.
      *
-     * @param quat
+     * @param quat desired orientation (not null, unaffected)
      */
     protected abstract void setPhysicsRotation(Quaternion quat);
 
     /**
-     * Called when the physics object is supposed to add all objects it needs to
-     * manage to the physics space.
+     * Add all managed physics objects to the specified space.
      *
-     * @param space
+     * @param space which physics space to add to (not null)
      */
     protected abstract void addPhysics(PhysicsSpace space);
 
     /**
-     * Called when the physics object is supposed to remove all objects added to
-     * the physics space.
+     * Remove all managed physics objects from the specified space.
      *
-     * @param space
+     * @param space which physics space to remove from (not null)
      */
     protected abstract void removePhysics(PhysicsSpace space);
 
+    /**
+     * Test whether physics-space coordinates should match the spatial's local
+     * coordinates.
+     *
+     * @return true if matching local coordinates, false if matching world
+     * coordinates
+     */
     public boolean isApplyPhysicsLocal() {
         return applyLocal;
     }
 
     /**
-     * When set to true, the physics coordinates will be applied to the local
-     * translation of the Spatial
+     * Alter whether physics-space coordinates should match the spatial's local
+     * coordinates.
      *
-     * @param applyPhysicsLocal
+     * @param applyPhysicsLocal true&rarr;match local coordinates,
+     * false&rarr;match world coordinates (default=false)
      */
     public void setApplyPhysicsLocal(boolean applyPhysicsLocal) {
         applyLocal = applyPhysicsLocal;
     }
 
+    /**
+     * Access whichever spatial translation corresponds to the physics location.
+     *
+     * @return the pre-existing location vector (in physics-space coordinates,
+     * not null)
+     */
     protected Vector3f getSpatialTranslation() {
         if (applyLocal) {
             return spatial.getLocalTranslation();
@@ -129,6 +160,12 @@ public abstract class AbstractPhysicsControl implements PhysicsControl, JmeClone
         return spatial.getWorldTranslation();
     }
 
+    /**
+     * Access whichever spatial rotation corresponds to the physics rotation.
+     *
+     * @return the pre-existing quaternion (in physics-space coordinates, not
+     * null)
+     */
     protected Quaternion getSpatialRotation() {
         if (applyLocal) {
             return spatial.getLocalRotation();
@@ -137,10 +174,12 @@ public abstract class AbstractPhysicsControl implements PhysicsControl, JmeClone
     }
 
     /**
-     * Applies a physics transform to the spatial
+     * Apply a physics transform to the spatial.
      *
-     * @param worldLocation
-     * @param worldRotation
+     * @param worldLocation location vector (in physics-space coordinates, not
+     * null, unaffected)
+     * @param worldRotation orientation (in physics-space coordinates, not null,
+     * unaffected)
      */
     protected void applyPhysicsTransform(Vector3f worldLocation, Quaternion worldRotation) {
         if (enabled && spatial != null) {
@@ -162,13 +201,29 @@ public abstract class AbstractPhysicsControl implements PhysicsControl, JmeClone
         }
 
     }
-    
+
+    /**
+     * Callback from {@link com.jme3.util.clone.Cloner} to convert this
+     * shallow-cloned control into a deep-cloned one, using the specified cloner
+     * and original to resolve copied fields.
+     *
+     * @param cloner the cloner currently cloning this control (not null)
+     * @param original the control from which this control was shallow-cloned
+     * (unused)
+     */
     @Override   
     public void cloneFields( Cloner cloner, Object original ) { 
         this.spatial = cloner.clone(spatial);
         createSpatialData(this.spatial);
     }
          
+    /**
+     * Alter which spatial is controlled. Invoked when the control is added to
+     * or removed from a spatial. Should be invoked only by a subclass or from
+     * Spatial. Do not invoke directly from user code.
+     *
+     * @param spatial the spatial to control (or null)
+     */
     public void setSpatial(Spatial spatial) {
         if (this.spatial != null && this.spatial != spatial) {
             removeSpatialData(this.spatial);
@@ -184,6 +239,15 @@ public abstract class AbstractPhysicsControl implements PhysicsControl, JmeClone
         setPhysicsRotation(getSpatialRotation());
     }
 
+    /**
+     * Enable or disable this control.
+     * <p>
+     * When the control is disabled, the physics object is removed from physics
+     * space. When the control is enabled again, the physics object is moved to
+     * the spatial's location and then added to the physics space.
+     *
+     * @param enabled true&rarr;enable the control, false&rarr;disable it
+     */
     public void setEnabled(boolean enabled) {
         this.enabled = enabled;
         if (space != null) {
@@ -201,6 +265,11 @@ public abstract class AbstractPhysicsControl implements PhysicsControl, JmeClone
         }
     }
 
+    /**
+     * Test whether this control is enabled.
+     *
+     * @return true if enabled, otherwise false
+     */
     public boolean isEnabled() {
         return enabled;
     }
@@ -214,7 +283,7 @@ public abstract class AbstractPhysicsControl implements PhysicsControl, JmeClone
     /**
      * If enabled, add this control's physics object to the specified physics
      * space. If not enabled, alter where the object would be added. The object
-     * is removed from any other space it's currently in.
+     * is removed from any other space it's in.
      *
      * @param newSpace where to add, or null to simply remove
      */
@@ -238,10 +307,21 @@ public abstract class AbstractPhysicsControl implements PhysicsControl, JmeClone
         space = newSpace;
     }
 
+    /**
+     * Access the physics space to which the object is (or would be) added.
+     *
+     * @return the pre-existing space, or null for none
+     */
     public PhysicsSpace getPhysicsSpace() {
         return space;
     }
 
+    /**
+     * Serialize this object, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     @Override
     public void write(JmeExporter ex) throws IOException {
         OutputCapsule oc = ex.getCapsule(this);
@@ -250,6 +330,13 @@ public abstract class AbstractPhysicsControl implements PhysicsControl, JmeClone
         oc.write(spatial, "spatial", null);
     }
 
+    /**
+     * De-serialize this control from the specified importer, for example when
+     * loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     @Override
     public void read(JmeImporter im) throws IOException {
         InputCapsule ic = im.getCapsule(this);

+ 167 - 114
jme3-bullet/src/common/java/com/jme3/bullet/control/BetterCharacterControl.java

@@ -58,15 +58,18 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * This is intended to be a replacement for the internal bullet character class.
- * A RigidBody with cylinder collision shape is used and its velocity is set
- * continuously, a ray test is used to check if the character is on the ground.
- *
- * The character keeps his own local coordinate system which adapts based on the
- * gravity working on the character so the character will always stand upright.
- *
- * Forces in the local x/z plane are dampened while those in the local y
- * direction are applied fully (e.g. jumping, falling).
+ * This class is intended to replace the CharacterControl class.
+ * <p>
+ * A rigid body with cylinder collision shape is used and its velocity is set
+ * continuously. A ray test is used to test whether the character is on the
+ * ground.
+ * <p>
+ * The character keeps their own local coordinate system which adapts based on
+ * the gravity working on the character so they will always stand upright.
+ * <p>
+ * Motion in the local X-Z plane is damped.
+ * <p>
+ * This class is shared between JBullet and Native Bullet.
  *
  * @author normenhansen
  */
@@ -76,10 +79,16 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
     protected PhysicsRigidBody rigidBody;
     protected float radius;
     protected float height;
+    /**
+     * mass of this character (&gt;0)
+     */
     protected float mass;
+    /**
+     * relative height when ducked (1=full height)
+     */
     protected float duckedFactor = 0.6f;
     /**
-     * Local up direction, derived from gravity.
+     * local up direction, derived from gravity
      */
     protected final Vector3f localUp = new Vector3f(0, 1, 0);
     /**
@@ -96,22 +105,27 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
      */
     protected final Quaternion localForwardRotation = new Quaternion(Quaternion.DIRECTION_Z);
     /**
-     * Is a z-forward vector based on the view direction and the current local
-     * x/z plane.
+     * a Z-forward vector based on the view direction and the local X-Z plane.
      */
     protected final Vector3f viewDirection = new Vector3f(0, 0, 1);
     /**
-     * Stores final spatial location, corresponds to RigidBody location.
+     * spatial location, corresponds to RigidBody location.
      */
     protected final Vector3f location = new Vector3f();
     /**
-     * Stores final spatial rotation, is a z-forward rotation based on the view
-     * direction and the current local x/z plane. See also rotatedViewDirection.
+     * spatial rotation, a Z-forward rotation based on the view direction and
+     * local X-Z plane.
+     *
+     * @see #rotatedViewDirection
      */
     protected final Quaternion rotation = new Quaternion(Quaternion.DIRECTION_Z);
     protected final Vector3f rotatedViewDirection = new Vector3f(0, 0, 1);
     protected final Vector3f walkDirection = new Vector3f();
     protected final Vector3f jumpForce;
+    /**
+     * X-Z motion damping factor (0&rarr;no damping, 1=no external forces,
+     * default=0.9)
+     */
     protected float physicsDamping = 0.9f;
     protected final Vector3f scale = new Vector3f(1, 1, 1);
     protected final Vector3f velocity = new Vector3f();
@@ -121,20 +135,23 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
     protected boolean wantToUnDuck = false;
 
     /**
-     * Only used for serialization, do not use this constructor.
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
      */
     public BetterCharacterControl() {
         jumpForce = new Vector3f();
     }
 
     /**
-     * Creates a new character with the given properties. Note that to avoid
-     * issues the final height when ducking should be larger than 2x radius. The
-     * jumpForce will be set to an upwards force of 5x mass.
+     * Instantiate an enabled control with the specified properties.
+     * <p>
+     * The final height when ducking must be larger than 2x radius. The
+     * jumpForce will be set to an upward force of 5x mass.
      *
-     * @param radius
-     * @param height
-     * @param mass
+     * @param radius the radius of the character's collision shape (&gt;0)
+     * @param height the height of the character's collision shape
+     * (&gt;2*radius)
+     * @param mass the character's mass (&ge;0)
      */
     public BetterCharacterControl(float radius, float height, float mass) {
         this.radius = radius;
@@ -145,6 +162,13 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
         rigidBody.setAngularFactor(0);
     }
 
+    /**
+     * Update this control. Invoked once per frame during the logical-state
+     * update, provided the control is added to a scene graph. Do not invoke
+     * directly from user code.
+     *
+     * @param tpf the time interval between frames (in seconds, &ge;0)
+     */
     @Override
     public void update(float tpf) {
         super.update(tpf);
@@ -153,16 +177,24 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
         applyPhysicsTransform(location, rotation);
     }
 
+    /**
+     * Render this control. Invoked once per view port per frame, provided the
+     * control is added to a scene. Should be invoked only by a subclass or by
+     * the RenderManager.
+     *
+     * @param rm the render manager (not null)
+     * @param vp the view port to render (not null)
+     */
     @Override
     public void render(RenderManager rm, ViewPort vp) {
         super.render(rm, vp);
     }
 
     /**
-     * Used internally, don't call manually
+     * Callback from Bullet, invoked just before the physics is stepped.
      *
-     * @param space
-     * @param tpf
+     * @param space the space that is about to be stepped (not null)
+     * @param tpf the time per physics step (in seconds, &ge;0)
      */
     public void prePhysicsTick(PhysicsSpace space, float tpf) {
         checkOnGround();
@@ -174,8 +206,8 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
         TempVars vars = TempVars.get();
 
         Vector3f currentVelocity = vars.vect2.set(velocity);
-        
-        // dampen existing x/z forces
+
+        // Attenuate any existing X-Z motion.
         float existingLeftVelocity = velocity.dot(localLeft);
         float existingForwardVelocity = velocity.dot(localForward);
         Vector3f counter = vars.vect1;
@@ -210,20 +242,20 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
     }
 
     /**
-     * Used internally, don't call manually
+     * Callback from Bullet, invoked just after the physics has been stepped.
      *
-     * @param space
-     * @param tpf
+     * @param space the space that was just stepped (not null)
+     * @param tpf the time per physics step (in seconds, &ge;0)
      */
     public void physicsTick(PhysicsSpace space, float tpf) {
         rigidBody.getLinearVelocity(velocity);
     }
 
     /**
-     * Move the character somewhere. Note the character also takes the location
-     * of any spatial its being attached to in the moment it is attached.
+     * Move the character somewhere. Note the character also warps to the
+     * location of the spatial when the control is added.
      *
-     * @param vec The new character location.
+     * @param vec the desired character location (not null)
      */
     public void warp(Vector3f vec) {
         setPhysicsLocation(vec);
@@ -241,21 +273,20 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
     }
 
     /**
-     * Set the jump force as a Vector3f. The jump force is local to the
-     * characters coordinate system, which normally is always z-forward (in
-     * world coordinates, parent coordinates when set to applyLocalPhysics)
+     * Alter the jump force. The jump force is local to the character's
+     * coordinate system, which normally is always z-forward (in world
+     * coordinates, parent coordinates when set to applyLocalPhysics)
      *
-     * @param jumpForce The new jump force
+     * @param jumpForce the desired jump force (not null, unaffected)
      */
     public void setJumpForce(Vector3f jumpForce) {
         this.jumpForce.set(jumpForce);
     }
 
     /**
-     * Gets the current jump force. The default is 5 * character mass in y
-     * direction.
+     * Access the jump force. The default is 5 * character mass in Y direction.
      *
-     * @return
+     * @return the pre-existing vector (not null)
      */
     public Vector3f getJumpForce() {
         return jumpForce;
@@ -266,7 +297,7 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
      * in the center of the character and might return false even if the
      * character is not falling yet.
      *
-     * @return
+     * @return true if on the ground, otherwise false
      */
     public boolean isOnGround() {
         return onGround;
@@ -279,7 +310,7 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
      * can in fact unduck and only do so when its possible. You can check the
      * state of the unducking by checking isDucked().
      *
-     * @param enabled
+     * @param enabled true&rarr;duck, false&rarr;unduck
      */
     public void setDucked(boolean enabled) {
         if (enabled) {
@@ -300,33 +331,33 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
      * Check if the character is ducking, either due to user input or due to
      * unducking being impossible at the moment (obstacle above).
      *
-     * @return
+     * @return true if ducking, otherwise false
      */
     public boolean isDucked() {
         return ducked;
     }
 
     /**
-     * Sets the height multiplication factor for ducking.
+     * Alter the height multiplier for ducking.
      *
-     * @param factor The factor by which the height should be multiplied when
-     * ducking
+     * @param factor the factor by which the height should be multiplied when
+     * ducking (&ge;0, &le;1)
      */
     public void setDuckedFactor(float factor) {
         duckedFactor = factor;
     }
 
     /**
-     * Gets the height multiplication factor for ducking.
+     * Read the height multiplier for ducking.
      *
-     * @return
+     * @return the factor (&ge;0, &le;1)
      */
     public float getDuckedFactor() {
         return duckedFactor;
     }
 
     /**
-     * Sets the walk direction of the character. This parameter is framerate
+     * Alter the character's the walk direction. This parameter is framerate
      * independent and the character will move continuously in the direction
      * given by the vector with the speed given by the vector length in m/s.
      *
@@ -337,20 +368,19 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
     }
 
     /**
-     * Gets the current walk direction and speed of the character. The length of
-     * the vector defines the speed.
+     * Read the walk velocity. The length of the vector defines the speed.
      *
-     * @return
+     * @return the pre-existing vector (not null)
      */
     public Vector3f getWalkDirection() {
         return walkDirection;
     }
 
     /**
-     * Sets the view direction for the character. Note this only defines the
-     * rotation of the spatial in the local x/z plane of the character.
+     * Alter the character's view direction. Note this only defines the
+     * orientation in the local X-Z plane.
      *
-     * @param vec
+     * @param vec a direction vector (not null, unaffected)
      */
     public void setViewDirection(Vector3f vec) {
         viewDirection.set(vec);
@@ -358,10 +388,10 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
     }
 
     /**
-     * Gets the current view direction, note this doesn't need to correspond
-     * with the spatials forward direction.
+     * Access the view direction. This need not agree with the spatial's forward
+     * direction.
      *
-     * @return
+     * @return the pre-existing vector (not null)
      */
     public Vector3f getViewDirection() {
         return viewDirection;
@@ -369,15 +399,15 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
 
     /**
      * Realign the local forward vector to given direction vector, if null is
-     * supplied Vector3f.UNIT_Z is used. Input vector has to be perpendicular to
-     * current gravity vector. This normally only needs to be called when the
+     * supplied Vector3f.UNIT_Z is used. The input vector must be perpendicular
+     * to gravity vector. This normally only needs to be invoked when the
      * gravity direction changed continuously and the local forward vector is
      * off due to drift. E.g. after walking around on a sphere "planet" for a
-     * while and then going back to a y-up coordinate system the local z-forward
-     * might not be 100% alinged with Z axis.
+     * while and then going back to a Y-up coordinate system the local Z-forward
+     * might not be 100% aligned with the Z axis.
      *
-     * @param vec The new forward vector, has to be perpendicular to the current
-     * gravity vector!
+     * @param vec the desired forward vector (perpendicular to the gravity
+     * vector, may be null, default=0,0,1)
      */
     public void resetForward(Vector3f vec) {
         if (vec == null) {
@@ -388,23 +418,21 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
     }
 
     /**
-     * Get the current linear velocity along the three axes of the character.
-     * This is prepresented in world coordinates, parent coordinates when the
-     * control is set to applyLocalPhysics.
+     * Access the character's linear velocity in physics-space coordinates.
      *
-     * @return The current linear velocity of the character
+     * @return the pre-existing vector (not null)
      */
     public Vector3f getVelocity() {
         return velocity;
     }
 
     /**
-     * Set the gravity for this character. Note that this also realigns the
-     * local coordinate system of the character so that continuous changes in
-     * gravity direction are possible while maintaining a sensible control over
-     * the character.
+     * Alter the gravity acting on this character. Note that this also realigns
+     * the local coordinate system of the character so that continuous changes
+     * in gravity direction are possible while maintaining a sensible control
+     * over the character.
      *
-     * @param gravity
+     * @param gravity an acceleration vector (not null, unaffected)
      */
     public void setGravity(Vector3f gravity) {
         rigidBody.setGravity(gravity);
@@ -413,46 +441,48 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
     }
 
     /**
-     * Get the current gravity of the character.
+     * Copy the character's gravity vector.
      *
-     * @return
+     * @return a new acceleration vector (not null)
      */
     public Vector3f getGravity() {
         return rigidBody.getGravity();
     }
 
     /**
-     * Get the current gravity of the character.
+     * Copy the character's gravity vector.
      *
-     * @param store The vector to store the result in
-     * @return
+     * @param store storage for the result (modified if not null)
+     * @return an acceleration vector (either the provided storage or a new
+     * vector, not null)
      */
     public Vector3f getGravity(Vector3f store) {
         return rigidBody.getGravity(store);
     }
 
     /**
-     * Sets how much the physics forces in the local x/z plane should be
-     * dampened.
-     * @param physicsDamping The dampening value, 0 = no dampening, 1 = no external force, default = 0.9
+     * Alter how much motion in the local X-Z plane is damped.
+     *
+     * @param physicsDamping the desired damping factor (0&rarr;no damping, 1=no
+     * external forces, default=0.9)
      */
     public void setPhysicsDamping(float physicsDamping) {
         this.physicsDamping = physicsDamping;
     }
 
     /**
-     * Gets how much the physics forces in the local x/z plane should be
-     * dampened.
+     * Read how much motion in the local X-Z plane is damped.
+     *
+     * @return the damping factor (0&rarr;no damping, 1=no external forces)
      */
     public float getPhysicsDamping() {
         return physicsDamping;
     }
 
     /**
-     * This actually sets a new collision shape to the character to change the
-     * height of the capsule.
+     * Alter the height of collision shape.
      *
-     * @param percent
+     * @param percent the desired height, as a percentage of the full height
      */
     protected void setHeightPercent(float percent) {
         scale.setY(percent);
@@ -460,7 +490,7 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
     }
 
     /**
-     * This checks if the character is on the ground by doing a ray test.
+     * Test whether the character is on the ground, by means of a ray test.
      */
     protected void checkOnGround() {
         TempVars vars = TempVars.get();
@@ -501,12 +531,10 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
     }
 
     /**
-     * Gets a new collision shape based on the current scale parameter. The
-     * created collisionshape is a capsule collision shape that is attached to a
-     * compound collision shape with an offset to set the object center at the
-     * bottom of the capsule.
+     * Create a collision shape based on the scale parameter. The new shape is a
+     * compound shape containing an offset capsule.
      *
-     * @return
+     * @return a new compound shape (not null)
      */
     protected CollisionShape getShape() {
         //TODO: cleanup size mess..
@@ -518,18 +546,18 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
     }
 
     /**
-     * Gets the scaled height.
+     * Calculate the character's scaled height.
      *
-     * @return
+     * @return the height
      */
     protected float getFinalHeight() {
         return height * scale.getY();
     }
 
     /**
-     * Gets the scaled radius.
+     * Calculate the character's scaled radius.
      *
-     * @return
+     * @return the radius
      */
     protected float getFinalRadius() {
         return radius * scale.getZ();
@@ -538,7 +566,7 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
     /**
      * Updates the local coordinate system from the localForward and localUp
      * vectors, adapts localForward, sets localForwardRotation quaternion to
-     * local z-forward rotation.
+     * local Z-forward rotation.
      */
     protected void updateLocalCoordinateSystem() {
         //gravity vector has possibly changed, calculate new world forward (UNIT_Z)
@@ -549,8 +577,8 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
     }
 
     /**
-     * Updates the local x/z-flattened view direction and the corresponding
-     * rotation quaternion for the spatial.
+     * Updates the local X-Z view direction and the corresponding rotation
+     * quaternion for the spatial.
      */
     protected void updateLocalViewDirection() {
         //update local rotation quaternion to use for view rotation
@@ -570,7 +598,6 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
      * set to the new direction
      * @param worldUpVector The up vector to use, the result direction will be
      * perpendicular to this
-     * @return
      */
     protected final void calculateNewForward(Quaternion rotation, Vector3f direction, Vector3f worldUpVector) {
         if (direction == null) {
@@ -602,10 +629,9 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
     }
 
     /**
-     * This is implemented from AbstractPhysicsControl and called when the
-     * spatial is attached for example.
+     * Translate the character to the specified location.
      *
-     * @param vec
+     * @param vec desired location (not null, unaffected)
      */
     @Override
     protected void setPhysicsLocation(Vector3f vec) {
@@ -614,12 +640,12 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
     }
 
     /**
-     * This is implemented from AbstractPhysicsControl and called when the
-     * spatial is attached for example. We don't set the actual physics rotation
-     * but the view rotation here. It might actually be altered by the
-     * calculateNewForward method.
+     * Rotate the physics object to the specified orientation.
+     * <p>
+     * We don't set the actual physics rotation but the view rotation here. It
+     * might actually be altered by the calculateNewForward method.
      *
-     * @param quat
+     * @param quat desired orientation (not null, unaffected)
      */
     @Override
     protected void setPhysicsRotation(Quaternion quat) {
@@ -629,10 +655,9 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
     }
 
     /**
-     * This is implemented from AbstractPhysicsControl and called when the
-     * control is supposed to add all objects to the physics space.
+     * Add all managed physics objects to the specified space.
      *
-     * @param space
+     * @param space which physics space to add to (not null)
      */
     @Override
     protected void addPhysics(PhysicsSpace space) {
@@ -644,10 +669,9 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
     }
 
     /**
-     * This is implemented from AbstractPhysicsControl and called when the
-     * control is supposed to remove all objects from the physics space.
+     * Remove all managed physics objects from the specified space.
      *
-     * @param space
+     * @param space which physics space to remove from (not null)
      */
     @Override
     protected void removePhysics(PhysicsSpace space) {
@@ -655,16 +679,33 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
         space.removeTickListener(this);
     }
 
+    /**
+     * Create spatial-dependent data. Invoked when this control is added to a
+     * spatial.
+     *
+     * @param spat the controlled spatial (not null, alias created)
+     */
     @Override
     protected void createSpatialData(Spatial spat) {
         rigidBody.setUserObject(spatial);
     }
 
+    /**
+     * Destroy spatial-dependent data. Invoked when this control is removed from
+     * a spatial.
+     *
+     * @param spat the previously controlled spatial (not null)
+     */
     @Override
     protected void removeSpatialData(Spatial spat) {
         rigidBody.setUserObject(null);
     }
 
+    /**
+     * Create a shallow clone for the JME cloner.
+     *
+     * @return a new control (not null)
+     */
     @Override
     public Control cloneForSpatial(Spatial spatial) {
         BetterCharacterControl control = new BetterCharacterControl(radius, height, mass);
@@ -680,6 +721,12 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
         return control;
     }     
 
+    /**
+     * Serialize this control, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     @Override
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
@@ -691,6 +738,12 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
         oc.write(physicsDamping, "physicsDamping", 0.9f);
     }
 
+    /**
+     * De-serialize this control, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     @Override
     public void read(JmeImporter im) throws IOException {
         super.read(im);

+ 129 - 6
jme3-bullet/src/common/java/com/jme3/bullet/control/GhostControl.java

@@ -49,38 +49,82 @@ import com.jme3.util.clone.JmeCloneable;
 import java.io.IOException;
 
 /**
- * A GhostControl moves with the spatial it is attached to and can be used to check
- * overlaps with other physics objects (e.g. aggro radius).
+ * A physics control to link a PhysicsGhostObject to a spatial.
+ * <p>
+ * The ghost object moves with the spatial it is attached to and can be used to
+ * detect overlaps with other physics objects (e.g. aggro radius).
+ * <p>
+ * This class is shared between JBullet and Native Bullet.
+ *
  * @author normenhansen
  */
 public class GhostControl extends PhysicsGhostObject implements PhysicsControl, JmeCloneable {
 
+    /**
+     * spatial to which this control is added, or null if none
+     */
     protected Spatial spatial;
+    /**
+     * true&rarr;control is enabled, false&rarr;control is disabled
+     */
     protected boolean enabled = true;
+    /**
+     * true&rarr;body is added to the physics space, false&rarr;not added
+     */
     protected boolean added = false;
+    /**
+     * space to which the ghost object is (or would be) added
+     */
     protected PhysicsSpace space = null;
+    /**
+     * true &rarr; physics coordinates match local transform, false &rarr;
+     * physics coordinates match world transform
+     */
     protected boolean applyLocal = false;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public GhostControl() {
     }
 
+    /**
+     * Instantiate an enabled control with the specified shape.
+     *
+     * @param shape (not null)
+     */
     public GhostControl(CollisionShape shape) {
         super(shape);
     }
 
+    /**
+     * Test whether physics-space coordinates should match the spatial's local
+     * coordinates.
+     *
+     * @return true if matching local coordinates, false if matching world
+     * coordinates
+     */
     public boolean isApplyPhysicsLocal() {
         return applyLocal;
     }
 
     /**
-     * When set to true, the physics coordinates will be applied to the local
-     * translation of the Spatial
-     * @param applyPhysicsLocal
+     * Alter whether physics-space coordinates should match the spatial's local
+     * coordinates.
+     *
+     * @param applyPhysicsLocal true&rarr;match local coordinates,
+     * false&rarr;match world coordinates (default=false)
      */
     public void setApplyPhysicsLocal(boolean applyPhysicsLocal) {
         applyLocal = applyPhysicsLocal;
     }
 
+    /**
+     * Access whichever spatial translation corresponds to the physics location.
+     *
+     * @return the pre-existing vector (not null)
+     */
     private Vector3f getSpatialTranslation() {
         if (applyLocal) {
             return spatial.getLocalTranslation();
@@ -88,6 +132,11 @@ public class GhostControl extends PhysicsGhostObject implements PhysicsControl,
         return spatial.getWorldTranslation();
     }
 
+    /**
+     * Access whichever spatial rotation corresponds to the physics rotation.
+     *
+     * @return the pre-existing quaternion (not null)
+     */
     private Quaternion getSpatialRotation() {
         if (applyLocal) {
             return spatial.getLocalRotation();
@@ -95,6 +144,12 @@ public class GhostControl extends PhysicsGhostObject implements PhysicsControl,
         return spatial.getWorldRotation();
     }
 
+    /**
+     * Clone this control for a different spatial. No longer used as of JME 3.1.
+     *
+     * @param spatial the spatial for the clone to control (or null)
+     * @return a new control (not null)
+     */
     @Override
     public Control cloneForSpatial(Spatial spatial) {
         GhostControl control = new GhostControl(collisionShape);
@@ -108,7 +163,12 @@ public class GhostControl extends PhysicsGhostObject implements PhysicsControl,
         return control;
     }
 
-    @Override   
+    /**
+     * Create a shallow clone for the JME cloner.
+     *
+     * @return a new control (not null)
+     */
+    @Override
     public Object jmeClone() {
         GhostControl control = new GhostControl(collisionShape);
         control.setCcdMotionThreshold(getCcdMotionThreshold());
@@ -122,11 +182,27 @@ public class GhostControl extends PhysicsGhostObject implements PhysicsControl,
         return control;
     }     
 
+    /**
+     * Callback from {@link com.jme3.util.clone.Cloner} to convert this
+     * shallow-cloned control into a deep-cloned one, using the specified cloner
+     * and original to resolve copied fields.
+     *
+     * @param cloner the cloner currently cloning this control (not null)
+     * @param original the control from which this control was shallow-cloned
+     * (unused)
+     */
     @Override   
     public void cloneFields( Cloner cloner, Object original ) { 
         this.spatial = cloner.clone(spatial);
     }
          
+    /**
+     * Alter which spatial is controlled. Invoked when the control is added to
+     * or removed from a spatial. Should be invoked only by a subclass or from
+     * Spatial. Do not invoke directly from user code.
+     *
+     * @param spatial the spatial to control (or null)
+     */
     public void setSpatial(Spatial spatial) {
         this.spatial = spatial;
         setUserObject(spatial);
@@ -137,6 +213,15 @@ public class GhostControl extends PhysicsGhostObject implements PhysicsControl,
         setPhysicsRotation(getSpatialRotation());
     }
 
+    /**
+     * Enable or disable this control.
+     * <p>
+     * When the control is disabled, the ghost object is removed from physics
+     * space. When the control is enabled again, the object is moved to the
+     * current location of the spatial and then added to the physics space.
+     *
+     * @param enabled true&rarr;enable the control, false&rarr;disable it
+     */
     public void setEnabled(boolean enabled) {
         this.enabled = enabled;
         if (space != null) {
@@ -154,10 +239,22 @@ public class GhostControl extends PhysicsGhostObject implements PhysicsControl,
         }
     }
 
+    /**
+     * Test whether this control is enabled.
+     *
+     * @return true if enabled, otherwise false
+     */
     public boolean isEnabled() {
         return enabled;
     }
 
+    /**
+     * Update this control. Invoked once per frame during the logical-state
+     * update, provided the control is added to a scene. Do not invoke directly
+     * from user code.
+     *
+     * @param tpf the time interval between frames (in seconds, &ge;0)
+     */
     public void update(float tpf) {
         if (!enabled) {
             return;
@@ -166,6 +263,14 @@ public class GhostControl extends PhysicsGhostObject implements PhysicsControl,
         setPhysicsRotation(getSpatialRotation());
     }
 
+    /**
+     * Render this control. Invoked once per view port per frame, provided the
+     * control is added to a scene. Should be invoked only by a subclass or by
+     * the RenderManager.
+     *
+     * @param rm the render manager (not null)
+     * @param vp the view port to render (not null)
+     */
     public void render(RenderManager rm, ViewPort vp) {
     }
 
@@ -196,10 +301,22 @@ public class GhostControl extends PhysicsGhostObject implements PhysicsControl,
         space = newSpace;
     }
 
+    /**
+     * Access the physics space to which the ghost object is (or would be)
+     * added.
+     *
+     * @return the pre-existing space, or null for none
+     */
     public PhysicsSpace getPhysicsSpace() {
         return space;
     }
 
+    /**
+     * Serialize this control, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     @Override
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
@@ -209,6 +326,12 @@ public class GhostControl extends PhysicsGhostObject implements PhysicsControl,
         oc.write(spatial, "spatial", null);
     }
 
+    /**
+     * De-serialize this control, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     @Override
     public void read(JmeImporter im) throws IOException {
         super.read(im);

+ 323 - 75
jme3-bullet/src/common/java/com/jme3/bullet/control/KinematicRagdollControl.java

@@ -73,29 +73,38 @@ import java.util.logging.Logger;
  * use this control you need a model with an AnimControl and a
  * SkeletonControl.<br> This should be the case if you imported an animated
  * model from Ogre or blender.<br> Note enabling/disabling the control
- * add/removes it from the physics space<br> <p> This control creates collision
- * shapes for each bones of the skeleton when you call
- * spatial.addControl(ragdollControl). <ul> <li>The shape is HullCollision shape
- * based on the vertices associated with each bone and based on a tweakable
- * weight threshold (see setWeightThreshold)</li> <li>If you don't want each
- * bone to be a collision shape, you can specify what bone to use by using the
- * addBoneName method<br> By using this method, bone that are not used to create
- * a shape, are "merged" to their parent to create the collision shape. </li>
- * </ul> </p> <p> There are 2 modes for this control : <ul> <li><strong>The
- * kinematic modes :</strong><br> this is the default behavior, this means that
- * the collision shapes of the body are able to interact with physics enabled
- * objects. in this mode physics shapes follow the motion of the animated
- * skeleton (for example animated by a key framed animation) this mode is
- * enabled by calling setKinematicMode(); </li> <li><strong>The ragdoll modes
- * :</strong><br> To enable this behavior, you need to call setRagdollMode()
- * method. In this mode the character is entirely controlled by physics, so it
- * will fall under the gravity and move if any force is applied to it. </li>
- * </ul> </p>
+ * add/removes it from the physics space<br>
+ * <p>
+ * This control creates collision shapes for each bones of the skeleton when you
+ * invoke spatial.addControl(ragdollControl). <ul> <li>The shape is
+ * HullCollision shape based on the vertices associated with each bone and based
+ * on a tweakable weight threshold (see setWeightThreshold)</li> <li>If you
+ * don't want each bone to be a collision shape, you can specify what bone to
+ * use by using the addBoneName method<br> By using this method, bone that are
+ * not used to create a shape, are "merged" to their parent to create the
+ * collision shape. </li>
+ * </ul>
+ * <p>
+ * There are 2 modes for this control : <ul> <li><strong>The kinematic modes
+ * :</strong><br> this is the default behavior, this means that the collision
+ * shapes of the body are able to interact with physics enabled objects. in this
+ * mode physics shapes follow the motion of the animated skeleton (for example
+ * animated by a key framed animation) this mode is enabled by calling
+ * setKinematicMode(); </li> <li><strong>The ragdoll modes:</strong><br> To
+ * enable this behavior, you need to invoke the setRagdollMode() method. In this
+ * mode the character is entirely controlled by physics, so it will fall under
+ * the gravity and move if any force is applied to it.</li>
+ * </ul>
+ * <p>
+ * This class is shared between JBullet and Native Bullet.
  *
  * @author Normen Hansen and Rémy Bouquet (Nehon)
  */
 public class KinematicRagdollControl extends AbstractPhysicsControl implements PhysicsCollisionListener, JmeCloneable {
 
+    /**
+     * list of registered collision listeners
+     */
     protected static final Logger logger = Logger.getLogger(KinematicRagdollControl.class.getName());
     protected List<RagdollCollisionListener> listeners;
     protected final Set<String> boneList = new TreeSet<String>();
@@ -103,7 +112,13 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
     protected final Vector3f modelPosition = new Vector3f();
     protected final Quaternion modelRotation = new Quaternion();
     protected final PhysicsRigidBody baseRigidBody;
+    /**
+     * model being controlled
+     */
     protected Spatial targetModel;
+    /**
+     * skeleton being controlled
+     */
     protected Skeleton skeleton;
     protected RagdollPreset preset = new HumanoidRagdollPreset();
     protected Vector3f initScale;
@@ -112,23 +127,52 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
     protected boolean blendedControl = false;
     protected float weightThreshold = -1.0f;
     protected float blendStart = 0.0f;
+    /**
+     * blending interval for animations (in seconds, &ge;0)
+     */
     protected float blendTime = 1.0f;
     protected float eventDispatchImpulseThreshold = 10;
     protected float rootMass = 15;
+    /**
+     * accumulate total mass of ragdoll when control is added to a scene
+     */
     protected float totalMass = 0;
     private Map<String, Vector3f> ikTargets = new HashMap<String, Vector3f>();
     private Map<String, Integer> ikChainDepth = new HashMap<String, Integer>();
+    /**
+     * rotational speed for inverse kinematics (radians per second, default=7)
+     */
     private float ikRotSpeed = 7f;
+    /**
+     * viscous limb-damping ratio (0&rarr;no damping, 1&rarr;critically damped,
+     * default=0.6)
+     */
     private float limbDampening = 0.6f;
-
+    /**
+     * distance threshold for inverse kinematics (default=0.1)
+     */
     private float IKThreshold = 0.1f;
+    /**
+     * Enumerate joint-control modes for this control.
+     */
     public static enum Mode {
-
+        /**
+         * collision shapes follow the movements of bones in the skeleton
+         */
         Kinematic,
+        /**
+         * skeleton is controlled by Bullet physics (gravity and collisions)
+         */
         Ragdoll,
+        /**
+         * skeleton is controlled by inverse-kinematic targets
+         */
         IK
     }
 
+    /**
+     * Link a bone to a jointed rigid body.
+     */
     public class PhysicsBoneLink implements Savable {
 
         protected PhysicsRigidBody rigidBody;
@@ -138,17 +182,36 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
         protected Quaternion startBlendingRot = new Quaternion();
         protected Vector3f startBlendingPos = new Vector3f();
 
+        /**
+         * Instantiate an uninitialized link.
+         */
         public PhysicsBoneLink() {
         }
 
+        /**
+         * Access the linked bone.
+         *
+         * @return the pre-existing instance or null
+         */
         public Bone getBone() {
             return bone;
         }
 
+        /**
+         * Access the linked body.
+         *
+         * @return the pre-existing instance or null
+         */
         public PhysicsRigidBody getRigidBody() {
             return rigidBody;
         }
 
+        /**
+         * Serialize this bone link, for example when saving to a J3O file.
+         *
+         * @param ex exporter (not null)
+         * @throws IOException from exporter
+         */
         public void write(JmeExporter ex) throws IOException {
             OutputCapsule oc = ex.getCapsule(this);
             oc.write(rigidBody, "rigidBody", null);
@@ -159,6 +222,13 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
             oc.write(startBlendingPos, "startBlendingPos", new Vector3f());
         }
 
+        /**
+         * De-serialize this bone link, for example when loading from a J3O
+         * file.
+         *
+         * @param im importer (not null)
+         * @throws IOException from importer
+         */
         public void read(JmeImporter im) throws IOException {
             InputCapsule ic = im.getCapsule(this);
             rigidBody = (PhysicsRigidBody) ic.readSavable("rigidBody", null);
@@ -171,29 +241,53 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
     }
 
     /**
-     * construct a KinematicRagdollControl
+     * Instantiate an enabled control.
      */
     public KinematicRagdollControl() {
         baseRigidBody = new PhysicsRigidBody(new BoxCollisionShape(Vector3f.UNIT_XYZ.mult(0.1f)), 1);
         baseRigidBody.setKinematic(mode == Mode.Kinematic);
     }
 
+    /**
+     * Instantiate an enabled control with the specified weight threshold.
+     *
+     * @param weightThreshold (&gt;0, &lt;1)
+     */
     public KinematicRagdollControl(float weightThreshold) {
         this();
         this.weightThreshold = weightThreshold;
     }
 
+    /**
+     * Instantiate an enabled control with the specified preset and weight
+     * threshold.
+     *
+     * @param preset (not null)
+     * @param weightThreshold (&gt;0, &lt;1)
+     */
     public KinematicRagdollControl(RagdollPreset preset, float weightThreshold) {
         this();
         this.preset = preset;
         this.weightThreshold = weightThreshold;
     }
 
+    /**
+     * Instantiate an enabled control with the specified preset.
+     *
+     * @param preset (not null)
+     */
     public KinematicRagdollControl(RagdollPreset preset) {
         this();
         this.preset = preset;
     }
 
+    /**
+     * Update this control. Invoked once per frame during the logical-state
+     * update, provided the control is added to a scene. Do not invoke directly
+     * from user code.
+     *
+     * @param tpf the time interval between frames (in seconds, &ge;0)
+     */
     public void update(float tpf) {
         if (!enabled) {
             return;
@@ -208,6 +302,11 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
         }
     }
 
+    /**
+     * Update this control in Ragdoll mode, based on Bullet physics.
+     *
+     * @param tpf the time interval between frames (in seconds, &ge;0)
+     */
     protected void ragDollUpdate(float tpf) {
         TempVars vars = TempVars.get();
         Quaternion tmpRot1 = vars.quat1;
@@ -225,7 +324,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
             //retrieving bone rotation in physics world space
             Quaternion q = link.rigidBody.getMotionState().getWorldRotationQuat();
 
-            //multiplying this rotation by the initialWorld rotation of the bone, 
+            //multiplying this rotation by the initialWorld rotation of the bone,
             //then transforming it with the inverse world rotation of the model
             tmpRot1.set(q).multLocal(link.initalWorldRotation);
             tmpRot2.set(targetModel.getWorldRotation()).inverseLocal().mult(tmpRot1, tmpRot1);
@@ -249,13 +348,13 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
                 link.bone.setUserTransformsInModelSpace(position, tmpRot1);
 
             } else {
-                //if boneList is empty, this means that every bone in the ragdoll has a collision shape,
-                //so we just update the bone position
+                //If boneList is empty, every bone has a collision shape,
+                //so we simply update the bone position.
                 if (boneList.isEmpty()) {
                     link.bone.setUserTransformsInModelSpace(position, tmpRot1);
                 } else {
                     //boneList is not empty, this means some bones of the skeleton might not be associated with a collision shape.
-                    //So we update them recursively
+                    //So we update them recusively
                     RagdollUtils.setTransform(link.bone, position, tmpRot1, false, boneList);
                 }
             }
@@ -263,6 +362,11 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
         vars.release();
     }
 
+    /**
+     * Update this control in Kinematic mode, based on bone animation tracks.
+     *
+     * @param tpf the time interval between frames (in seconds, &ge;0)
+     */
     protected void kinematicUpdate(float tpf) {
         //the ragdoll does not have control, so the keyframed animation updates the physics position of the physics bonces
         TempVars vars = TempVars.get();
@@ -273,7 +377,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
 //            if(link.usedbyIK){
 //                continue;
 //            }
-            //if blended control this means, keyframed animation is updating the skeleton, 
+            //if blended control this means, keyframed animation is updating the skeleton,
             //but to allow smooth transition, we blend this transformation with the saved position of the ragdoll
             if (blendedControl) {
                 Vector3f position2 = vars.vect2;
@@ -313,6 +417,11 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
         }
         vars.release();
     }
+    /**
+     * Update this control in IK mode, based on IK targets.
+     *
+     * @param tpf the time interval between frames (in seconds, &ge;0)
+     */
     private void ikUpdate(float tpf){
         TempVars vars = TempVars.get();
 
@@ -349,6 +458,19 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
         vars.release();
     }
     
+    /**
+     * Update a bone and its ancestors in IK mode. Note: recursive!
+     *
+     * @param link the bone link for the affected bone (may be null)
+     * @param tpf the time interval between frames (in seconds, &ge;0)
+     * @param vars unused
+     * @param tmpRot1 temporary storage used in calculations (not null)
+     * @param tmpRot2 temporary storage used in calculations (not null)
+     * @param tipBone (not null)
+     * @param target the location target in model space (not null, unaffected)
+     * @param depth depth of the recursion (&ge;0)
+     * @param maxDepth recursion limit (&ge;0)
+     */
     public void updateBone(PhysicsBoneLink link, float tpf, TempVars vars, Quaternion tmpRot1, Quaternion[] tmpRot2, Bone tipBone, Vector3f target, int depth, int maxDepth) {
         if (link == null || link.bone.getParent() == null) {
             return;
@@ -403,13 +525,12 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
     }
 
     /**
-     * Set the transforms of a rigidBody to match the transforms of a bone. this
-     * is used to make the ragdoll follow the skeleton motion while in Kinematic
-     * mode
+     * Alter the transforms of a rigidBody to match the transforms of a bone.
+     * This is used to make the ragdoll follow animated motion in Kinematic mode
      *
-     * @param link the link containing the bone and the rigidBody
-     * @param position just a temp vector for position
-     * @param tmpRot1 just a temp quaternion for rotation
+     * @param link the bone link connecting the bone and the rigidBody
+     * @param position temporary storage used in calculations (not null)
+     * @param tmpRot1 temporary storage used in calculations (not null)
      */
     protected void matchPhysicObjectToBone(PhysicsBoneLink link, Vector3f position, Quaternion tmpRot1) {
         //computing position from rotation and scale
@@ -427,8 +548,8 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
     }
 
     /**
-     * rebuild the ragdoll this is useful if you applied scale on the ragdoll
-     * after it's been initialized, same as reattaching.
+     * Rebuild the ragdoll. This is useful if you applied scale on the ragdoll
+     * after it was initialized. Same as re-attaching.
      */
     public void reBuild() {
         if (spatial == null) {
@@ -438,6 +559,12 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
         createSpatialData(spatial);
     }
 
+    /**
+     * Create spatial-dependent data. Invoked when this control is added to a
+     * scene.
+     *
+     * @param model the controlled spatial (not null)
+     */
     @Override
     protected void createSpatialData(Spatial model) {
         targetModel = model;
@@ -463,7 +590,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
         model.addControl(sc);
 
         // put into bind pose and compute bone transforms in model space
-        // maybe dont reset to ragdoll out of animations?
+        // maybe don't reset to ragdoll out of animations?
         scanSpatial(model);
 
 
@@ -481,6 +608,12 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
         logger.log(Level.FINE, "Created physics ragdoll for skeleton {0}", skeleton);
     }
 
+    /**
+     * Destroy spatial-dependent data. Invoked when this control is removed from
+     * a spatial.
+     *
+     * @param spat the previously controlled spatial (not null)
+     */
     @Override
     protected void removeSpatialData(Spatial spat) {
         if (added) {
@@ -490,15 +623,22 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
     }
 
     /**
-     * Add a bone name to this control Using this method you can specify which
-     * bones of the skeleton will be used to build the collision shapes.
+     * Add a bone name to this control. Repeated invocations of this method can
+     * be used to specify which bones to use when generating collision shapes.
+     * <p>
+     * Not allowed after attaching the control.
      *
-     * @param name
+     * @param name the name of the bone to add
      */
     public void addBoneName(String name) {
         boneList.add(name);
     }
 
+    /**
+     * Generate physics shapes and bone links for the skeleton.
+     *
+     * @param model the spatial with the model's SkeletonControl (not null)
+     */
     protected void scanSpatial(Spatial model) {
         AnimControl animControl = model.getControl(AnimControl.class);
         Map<Integer, List<Float>> pointsMap = null;
@@ -517,6 +657,16 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
         }
     }
 
+    /**
+     * Generate a physics shape and bone links for the specified bone. Note:
+     * recursive!
+     *
+     * @param model the spatial with the model's SkeletonControl (not null)
+     * @param bone the bone to be linked (not null)
+     * @param parent the body linked to the parent bone (not null)
+     * @param reccount depth of the recursion (&ge;1)
+     * @param pointsMap (not null)
+     */
     protected void boneRecursion(Spatial model, Bone bone, PhysicsRigidBody parent, int reccount, Map<Integer, List<Float>> pointsMap) {
         PhysicsRigidBody parentShape = parent;
         if (boneList.isEmpty() || boneList.contains(bone.getName())) {
@@ -524,7 +674,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
             PhysicsBoneLink link = new PhysicsBoneLink();
             link.bone = bone;
 
-            //creating the collision shape 
+            //create the collision shape
             HullCollisionShape shape = null;
             if (pointsMap != null) {
                 //build a shape for the bone, using the vertices that are most influenced by this bone
@@ -567,16 +717,16 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
     }
 
     /**
-     * Set the joint limits for the joint between the given bone and its parent.
-     * This method can't work before attaching the control to a spatial
+     * Alter the limits of the joint connecting the specified bone to its
+     * parent. Can only be invoked after adding the control to a spatial.
      *
      * @param boneName the name of the bone
-     * @param maxX the maximum rotation on the x axis (in radians)
-     * @param minX the minimum rotation on the x axis (in radians)
-     * @param maxY the maximum rotation on the y axis (in radians)
-     * @param minY the minimum rotation on the z axis (in radians)
-     * @param maxZ the maximum rotation on the z axis (in radians)
-     * @param minZ the minimum rotation on the z axis (in radians)
+     * @param maxX the maximum rotation on the X axis (in radians)
+     * @param minX the minimum rotation on the X axis (in radians)
+     * @param maxY the maximum rotation on the Y axis (in radians)
+     * @param minY the minimum rotation on the Y axis (in radians)
+     * @param maxZ the maximum rotation on the Z axis (in radians)
+     * @param minZ the minimum rotation on the Z axis (in radians)
      */
     public void setJointLimit(String boneName, float maxX, float minX, float maxY, float minY, float maxZ, float minZ) {
         PhysicsBoneLink link = boneLinks.get(boneName);
@@ -588,8 +738,8 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
     }
 
     /**
-     * Return the joint between the given bone and its parent. This return null
-     * if it's called before attaching the control to a spatial
+     * Return the joint between the specified bone and its parent. This return
+     * null if it's invoked before adding the control to a spatial
      *
      * @param boneName the name of the bone
      * @return the joint between the given bone and its parent
@@ -654,9 +804,9 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
     }
 
     /**
-     * For internal use only callback for collisionevent
+     * For internal use only: callback for collision event
      *
-     * @param event
+     * @param event (not null)
      */
     public void collision(PhysicsCollisionEvent event) {
         PhysicsCollisionObject objA = event.getObjectA();
@@ -711,7 +861,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
      * be animated by the keyframe animation, but will be able to physically
      * interact with its physics environment
      *
-     * @param ragdollEnabled
+     * @param mode an enum value (not null)
      */
     protected void setMode(Mode mode) {
         this.mode = mode;
@@ -789,9 +939,9 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
     }
 
     /**
-     * Set the control into Kinematic mode In this mode, the collision shapes
-     * follow the movements of the skeleton, and can interact with physical
-     * environment
+     * Put the control into Kinematic mode. In this mode, the collision shapes
+     * follow the movements of the skeleton while interacting with the physics
+     * environment.
      */
     public void setKinematicMode() {
         if (mode != Mode.Kinematic) {
@@ -810,8 +960,8 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
     }
 
     /**
-     * Sets the control into Inverse Kinematics mode. The affected bones are affected by IK.
-     * physics.
+     * Sets the control into Inverse Kinematics mode. The affected bones are
+     * affected by IK. physics.
      */
     public void setIKMode() {
         if (mode != Mode.IK) {
@@ -822,16 +972,16 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
     /**
      * returns the mode of this control
      *
-     * @return
+     * @return an enum value
      */
     public Mode getMode() {
         return mode;
     }
 
     /**
-     * add a
+     * Add a collision listener to this control.
      *
-     * @param listener
+     * @param listener (not null, alias created)
      */
     public void addCollisionListener(RagdollCollisionListener listener) {
         if (listeners == null) {
@@ -840,35 +990,66 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
         listeners.add(listener);
     }
 
+    /**
+     * Alter the ragdoll's root mass.
+     *
+     * @param rootMass the desired mass (&ge;0)
+     */
     public void setRootMass(float rootMass) {
         this.rootMass = rootMass;
     }
 
+    /**
+     * Read the ragdoll's total mass.
+     *
+     * @return mass (&ge;0)
+     */
     public float getTotalMass() {
         return totalMass;
     }
 
+    /**
+     * Read the ragdoll's weight threshold.
+     *
+     * @return threshold
+     */
     public float getWeightThreshold() {
         return weightThreshold;
     }
 
+    /**
+     * Alter the ragdoll's weight threshold.
+     *
+     * @param weightThreshold the desired threshold
+     */
     public void setWeightThreshold(float weightThreshold) {
         this.weightThreshold = weightThreshold;
     }
 
+    /**
+     * Read the ragdoll's event-dispatch impulse threshold.
+     *
+     * @return threshold
+     */
     public float getEventDispatchImpulseThreshold() {
         return eventDispatchImpulseThreshold;
     }
 
+    /**
+     * Alter the ragdoll's event-dispatch impulse threshold.
+     *
+     * @param eventDispatchImpulseThreshold desired threshold
+     */
     public void setEventDispatchImpulseThreshold(float eventDispatchImpulseThreshold) {
         this.eventDispatchImpulseThreshold = eventDispatchImpulseThreshold;
     }
 
     /**
-     * Set the CcdMotionThreshold of all the bone's rigidBodies of the ragdoll
+     * Alter the CcdMotionThreshold of all rigid bodies in the ragdoll.
      *
      * @see PhysicsRigidBody#setCcdMotionThreshold(float)
-     * @param value
+     * @param value the desired threshold value (velocity, &gt;0) or zero to
+     * disable CCD (default=0)
      */
     public void setCcdMotionThreshold(float value) {
         for (PhysicsBoneLink link : boneLinks.values()) {
@@ -877,10 +1058,11 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
     }
 
     /**
-     * Set the CcdSweptSphereRadius of all the bone's rigidBodies of the ragdoll
+     * Alter the CcdSweptSphereRadius of all rigid bodies in the ragdoll.
      *
      * @see PhysicsRigidBody#setCcdSweptSphereRadius(float)
-     * @param value
+     * @param value the desired radius of the sphere used for continuous
+     * collision detection (&ge;0)
      */
     public void setCcdSweptSphereRadius(float value) {
         for (PhysicsBoneLink link : boneLinks.values()) {
@@ -889,7 +1071,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
     }
 
     /**
-     * return the rigidBody associated to the given bone
+     * Access the rigidBody associated with the named bone.
      *
      * @param boneName the name of the bone
      * @return the associated rigidBody.
@@ -903,15 +1085,22 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
     }
 
     /**
-     * For internal use only specific render for the ragdoll (if debugging)
+     * Render this control. Invoked once per view port per frame, provided the
+     * control is added to a scene. Should be invoked only by a subclass or by
+     * the RenderManager.
      *
-     * @param rm
-     * @param vp
+     * @param rm the render manager (not null)
+     * @param vp the view port to render (not null)
      */
     @Override
     public void render(RenderManager rm, ViewPort vp) {
     }
 
+    /**
+     * Create a shallow clone for the JME cloner.
+     *
+     * @return a new control (not null)
+     */
     @Override
     public Control cloneForSpatial(Spatial spatial) {
         KinematicRagdollControl control = new KinematicRagdollControl(preset, weightThreshold);
@@ -933,6 +1122,14 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
         return control;
     }     
 
+    /**
+     * Add a target for inverse kinematics.
+     *
+     * @param bone which bone the IK applies to (not null)
+     * @param worldPos the world coordinates of the goal (not null)
+     * @param chainLength number of bones in the chain
+     * @return a new instance (not null, already added to ikTargets)
+     */
     public Vector3f setIKTarget(Bone bone, Vector3f worldPos, int chainLength) {
         Vector3f target = worldPos.subtract(targetModel.getWorldTranslation());
         ikTargets.put(bone.getName(), target);
@@ -951,6 +1148,11 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
         return target;
     }
 
+    /**
+     * Remove the inverse-kinematics target for the specified bone.
+     *
+     * @param bone which bone has the target (not null, modified)
+     */
     public void removeIKTarget(Bone bone) {
         int depth = ikChainDepth.remove(bone.getName());
         int i = 0;
@@ -964,11 +1166,19 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
         }
     }
     
+    /**
+     * Remove all inverse-kinematics targets.
+     */
     public void removeAllIKTargets(){
         ikTargets.clear();
         ikChainDepth.clear();
         applyUserControl();
     }
+
+    /**
+     * Ensure that user control is enabled for any bones used by inverse
+     * kinematics and disabled for any other bones.
+     */
     public void applyUserControl() {
         for (Bone bone : skeleton.getRoots()) {
             RagdollUtils.setUserControl(bone, false);
@@ -995,39 +1205,77 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
             vars.release();
         }
     }
+
+    /**
+     * Read the rotation speed for inverse kinematics.
+     *
+     * @return speed (&ge;0)
+     */
     public float getIkRotSpeed() {
         return ikRotSpeed;
     }
 
+    /**
+     * Alter the rotation speed for inverse kinematics.
+     *
+     * @param ikRotSpeed the desired speed (&ge;0, default=7)
+     */
     public void setIkRotSpeed(float ikRotSpeed) {
         this.ikRotSpeed = ikRotSpeed;
     }
 
+    /**
+     * Read the distance threshold for inverse kinematics.
+     *
+     * @return distance threshold
+     */
     public float getIKThreshold() {
         return IKThreshold;
     }
 
+    /**
+     * Alter the distance threshold for inverse kinematics.
+     *
+     * @param IKThreshold the desired distance threshold (default=0.1)
+     */
     public void setIKThreshold(float IKThreshold) {
         this.IKThreshold = IKThreshold;
     }
 
-    
+    /**
+     * Read the limb damping.
+     *
+     * @return the viscous damping ratio (0&rarr;no damping, 1&rarr;critically
+     * damped)
+     */
     public float getLimbDampening() {
         return limbDampening;
     }
 
+    /**
+     * Alter the limb damping.
+     *
+     * @param limbDampening the desired viscous damping ratio (0&rarr;no
+     * damping, 1&rarr;critically damped, default=0.6)
+     */
     public void setLimbDampening(float limbDampening) {
         this.limbDampening = limbDampening;
     }
     
+    /**
+     * Access the named bone.
+     *
+     * @param name which bone to access
+     * @return the pre-existing instance, or null if not found
+     */
     public Bone getBone(String name){
         return skeleton.getBone(name);
     }
     /**
-     * serialize this control
+     * Serialize this control, for example when saving to a J3O file.
      *
-     * @param ex
-     * @throws IOException
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
      */
     @Override
     public void write(JmeExporter ex) throws IOException {
@@ -1054,10 +1302,10 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
     }
 
     /**
-     * de-serialize this control
+     * De-serialize this control, for example when loading from a J3O file.
      *
-     * @param im
-     * @throws IOException
+     * @param im importer (not null)
+     * @throws IOException from importer
      */
     @Override
     public void read(JmeImporter im) throws IOException {

+ 26 - 10
jme3-bullet/src/common/java/com/jme3/bullet/control/PhysicsControl.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,47 @@ import com.jme3.bullet.PhysicsSpace;
 import com.jme3.scene.control.Control;
 
 /**
+ * An interface for a scene-graph control that links a physics object to a
+ * Spatial.
+ * <p>
+ * This interface is shared between JBullet and Native Bullet.
  *
  * @author normenhansen
  */
 public interface PhysicsControl extends Control {
 
     /**
-     * Only used internally, do not call.
-     * @param space
+     * If enabled, add this control's physics object to the specified physics
+     * space. In not enabled, alter where the object would be added. The object
+     * is removed from any other space it's currently in.
+     *
+     * @param space where to add, or null to simply remove
      */
     public void setPhysicsSpace(PhysicsSpace space);
 
+    /**
+     * Access the physics space to which the object is (or would be) added.
+     *
+     * @return the pre-existing space, or null for none
+     */
     public PhysicsSpace getPhysicsSpace();
 
     /**
-     * The physics object is removed from the physics space when the control
-     * is disabled. When the control is enabled  again the physics object is
-     * moved to the current location of the spatial and then added to the physics
-     * space. This allows disabling/enabling physics to move the spatial freely.
-     * @param state
+     * Enable or disable this control.
+     * <p>
+     * The physics object is removed from its physics space when the control is
+     * disabled. When the control is enabled again, the physics object is moved
+     * to the current location of the spatial and then added to the physics
+     * space.
+     *
+     * @param state true&rarr;enable the control, false&rarr;disable it
      */
     public void setEnabled(boolean state);
 
     /**
-     * Returns the current enabled state of the physics control
-     * @return current enabled state
+     * Test whether this control is enabled.
+     *
+     * @return true if enabled, otherwise false
      */
     public boolean isEnabled();
 }

+ 146 - 14
jme3-bullet/src/common/java/com/jme3/bullet/control/RigidBodyControl.java

@@ -57,41 +57,81 @@ import com.jme3.util.clone.JmeCloneable;
 import java.io.IOException;
 
 /**
+ * A physics control to link a PhysicsRigidBody to a spatial.
+ * <p>
+ * This class is shared between JBullet and Native Bullet.
  *
  * @author normenhansen
  */
 public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl, JmeCloneable {
 
+    /**
+     * spatial to which this control is added, or null if none
+     */
     protected Spatial spatial;
+    /**
+     * true&rarr;control is enabled, false&rarr;control is disabled
+     */
     protected boolean enabled = true;
+    /**
+     * true&rarr;body is added to the physics space, false&rarr;not added
+     */
     protected boolean added = false;
+    /**
+     * space to which the body is (or would be) added
+     */
     protected PhysicsSpace space = null;
+    /**
+     * true&rarr;body is kinematic, false&rarr;body is static or dynamic
+     */
     protected boolean kinematicSpatial = true;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public RigidBodyControl() {
     }
 
     /**
-     * When using this constructor, the CollisionShape for the RigidBody is generated
-     * automatically when the Control is added to a Spatial.
-     * @param mass When not 0, a HullCollisionShape is generated, otherwise a MeshCollisionShape is used. For geometries with box or sphere meshes the proper box or sphere collision shape is used.
+     * When using this constructor, the CollisionShape for the RigidBody is
+     * generated automatically when the control is added to a spatial.
+     *
+     * @param mass When not 0, a HullCollisionShape is generated, otherwise a
+     * MeshCollisionShape is used. For geometries with box or sphere meshes the
+     * proper box or sphere collision shape is used.
      */
     public RigidBodyControl(float mass) {
         this.mass = mass;
     }
 
     /**
-     * Creates a new PhysicsNode with the supplied collision shape and mass 1
-     * @param shape
+     * Instantiate an enabled control with mass=1 and the specified collision
+     * shape.
+     *
+     * @param shape the desired shape (not null, alias created)
      */
     public RigidBodyControl(CollisionShape shape) {
         super(shape);
     }
 
+    /**
+     * Instantiate an enabled control with the specified collision shape and
+     * mass.
+     *
+     * @param shape the desired shape (not null, alias created)
+     * @param mass the desired mass (&ge;0)
+     */
     public RigidBodyControl(CollisionShape shape, float mass) {
         super(shape, mass);
     }
 
+    /**
+     * Clone this control for a different spatial. No longer used as of JME 3.1.
+     *
+     * @param spatial the spatial for the clone to control (or null)
+     * @return a new control (not null)
+     */
     @Override
     public Control cloneForSpatial(Spatial spatial) {
         RigidBodyControl control = new RigidBodyControl(collisionShape, mass);
@@ -119,6 +159,11 @@ public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl
         return control;
     }
 
+    /**
+     * Create a shallow clone for the JME cloner.
+     *
+     * @return a new control (not null)
+     */
     @Override   
     public Object jmeClone() {
         RigidBodyControl control = new RigidBodyControl(collisionShape, mass);
@@ -149,11 +194,27 @@ public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl
         return control;
     }     
 
+    /**
+     * Callback from {@link com.jme3.util.clone.Cloner} to convert this
+     * shallow-cloned control into a deep-cloned one, using the specified cloner
+     * and original to resolve copied fields.
+     *
+     * @param cloner the cloner currently cloning this control (not null)
+     * @param original the control from which this control was shallow-cloned
+     * (unused)
+     */
     @Override   
     public void cloneFields( Cloner cloner, Object original ) { 
         this.spatial = cloner.clone(spatial);
     }
          
+    /**
+     * Alter which spatial is controlled. Invoked when the control is added to
+     * or removed from a spatial. Should be invoked only by a subclass or from
+     * Spatial. Do not invoke directly from user code.
+     *
+     * @param spatial the spatial to control (or null)
+     */
     public void setSpatial(Spatial spatial) {
         this.spatial = spatial;
         setUserObject(spatial);
@@ -168,6 +229,10 @@ public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl
         setPhysicsRotation(getSpatialRotation());
     }
 
+    /**
+     * Set the collision shape based on the controlled spatial and its
+     * descendents.
+     */
     protected void createCollisionShape() {
         if (spatial == null) {
             return;
@@ -190,6 +255,15 @@ public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl
         }
     }
 
+    /**
+     * Enable or disable this control.
+     * <p>
+     * When the control is disabled, the body is removed from physics space.
+     * When the control is enabled again, the body is moved to the current
+     * location of the spatial and then added to the physics space.
+     *
+     * @param enabled true&rarr;enable the control, false&rarr;disable it
+     */
     public void setEnabled(boolean enabled) {
         this.enabled = enabled;
         if (space != null) {
@@ -207,40 +281,62 @@ public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl
         }
     }
 
+    /**
+     * Test whether this control is enabled.
+     *
+     * @return true if enabled, otherwise false
+     */
     public boolean isEnabled() {
         return enabled;
     }
 
     /**
-     * Checks if this control is in kinematic spatial mode.
-     * @return true if the spatial location is applied to this kinematic rigidbody
+     * Test whether this control is in kinematic mode.
+     *
+     * @return true if the spatial location and rotation are applied to the
+     * rigid body, otherwise false
      */
     public boolean isKinematicSpatial() {
         return kinematicSpatial;
     }
 
     /**
-     * Sets this control to kinematic spatial mode so that the spatials transform will
-     * be applied to the rigidbody in kinematic mode, defaults to true.
-     * @param kinematicSpatial
+     * Enable or disable kinematic mode. In kinematic mode, the spatial's
+     * location and rotation will be applied to the rigid body.
+     *
+     * @param kinematicSpatial true&rarr;kinematic, false&rarr;dynamic or static
      */
     public void setKinematicSpatial(boolean kinematicSpatial) {
         this.kinematicSpatial = kinematicSpatial;
     }
 
+    /**
+     * Test whether physics-space coordinates should match the spatial's local
+     * coordinates.
+     *
+     * @return true if matching local coordinates, false if matching world
+     * coordinates
+     */
     public boolean isApplyPhysicsLocal() {
         return motionState.isApplyPhysicsLocal();
     }
 
     /**
-     * When set to true, the physics coordinates will be applied to the local
-     * translation of the Spatial instead of the world translation.
-     * @param applyPhysicsLocal
+     * Alter whether physics-space coordinates should match the spatial's local
+     * coordinates.
+     *
+     * @param applyPhysicsLocal true&rarr;match local coordinates,
+     * false&rarr;match world coordinates (default=false)
      */
     public void setApplyPhysicsLocal(boolean applyPhysicsLocal) {
         motionState.setApplyPhysicsLocal(applyPhysicsLocal);
     }
 
+    /**
+     * Access whichever spatial translation corresponds to the physics location.
+     *
+     * @return the pre-existing vector (not null)
+     */
     private Vector3f getSpatialTranslation(){
         if(motionState.isApplyPhysicsLocal()){
             return spatial.getLocalTranslation();
@@ -248,6 +344,11 @@ public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl
         return spatial.getWorldTranslation();
     }
 
+    /**
+     * Access whichever spatial rotation corresponds to the physics rotation.
+     *
+     * @return the pre-existing quaternion (not null)
+     */
     private Quaternion getSpatialRotation(){
         if(motionState.isApplyPhysicsLocal()){
             return spatial.getLocalRotation();
@@ -255,6 +356,12 @@ public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl
         return spatial.getWorldRotation();
     }
 
+    /**
+     * Update this control. Invoked once per frame, during the logical-state
+     * update, provided the control is added to a scene.
+     *
+     * @param tpf the time interval between frames (in seconds, &ge;0)
+     */
     public void update(float tpf) {
         if (enabled && spatial != null) {
             if (isKinematic() && kinematicSpatial) {
@@ -266,6 +373,14 @@ public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl
         }
     }
 
+    /**
+     * Render this control. Invoked once per view port per frame, provided the
+     * control is added to a scene. Should be invoked only by a subclass or by
+     * the RenderManager.
+     *
+     * @param rm the render manager (not null)
+     * @param vp the view port to render (not null)
+     */
     public void render(RenderManager rm, ViewPort vp) {
     }
 
@@ -296,10 +411,21 @@ public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl
         space = newSpace;
     }
 
+    /**
+     * Access the physics space to which the body is (or would be) added.
+     *
+     * @return the pre-existing space, or null for none
+     */
     public PhysicsSpace getPhysicsSpace() {
         return space;
     }
 
+    /**
+     * Serialize this control, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     @Override
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
@@ -310,6 +436,12 @@ public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl
         oc.write(spatial, "spatial", null);
     }
 
+    /**
+     * De-serialize this control, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     @Override
     public void read(JmeImporter im) throws IOException {
         super.read(im);
@@ -320,4 +452,4 @@ public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl
         motionState.setApplyPhysicsLocal(ic.readBoolean("applyLocalPhysics", false));
         setUserObject(spatial);
     }
-}
+}

+ 112 - 7
jme3-bullet/src/common/java/com/jme3/bullet/control/VehicleControl.java

@@ -52,39 +52,75 @@ import java.io.IOException;
 import java.util.Iterator;
 
 /**
+ * A physics control to link a PhysicsVehicle to a spatial.
+ * <p>
+ * This class is shared between JBullet and Native Bullet.
  *
  * @author normenhansen
  */
 public class VehicleControl extends PhysicsVehicle implements PhysicsControl, JmeCloneable {
 
+    /**
+     * spatial to which this control is added, or null if none
+     */
     protected Spatial spatial;
+    /**
+     * true&rarr;control is enabled, false&rarr;control is disabled
+     */
     protected boolean enabled = true;
+    /**
+     * space to which the vehicle is (or would be) added
+     */
     protected PhysicsSpace space = null;
+    /**
+     * true&rarr;vehicle is added to the physics space, false&rarr;not added
+     */
     protected boolean added = false;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public VehicleControl() {
     }
 
     /**
-     * Creates a new PhysicsNode with the supplied collision shape
-     * @param shape
+     * Instantiate an enabled control with mass=1 and the specified collision
+     * shape.
+     *
+     * @param shape the desired shape (not null, alias created)
      */
     public VehicleControl(CollisionShape shape) {
         super(shape);
     }
 
+    /**
+     * Instantiate an enabled with the specified collision shape and mass.
+     *
+     * @param shape the desired shape (not null, alias created)
+     * @param mass (&gt;0)
+     */
     public VehicleControl(CollisionShape shape, float mass) {
         super(shape, mass);
     }
 
+    /**
+     * Test whether physics-space coordinates should match the spatial's local
+     * coordinates.
+     *
+     * @return true if matching local coordinates, false if matching world
+     * coordinates
+     */
     public boolean isApplyPhysicsLocal() {
         return motionState.isApplyPhysicsLocal();
     }
 
     /**
-     * When set to true, the physics coordinates will be applied to the local
-     * translation of the Spatial
-     * @param applyPhysicsLocal
+     * Alter whether physics-space coordinates should match the spatial's local
+     * coordinates.
+     *
+     * @param applyPhysicsLocal true&rarr;match local coordinates,
+     * false&rarr;match world coordinates (default=false)
      */
     public void setApplyPhysicsLocal(boolean applyPhysicsLocal) {
         motionState.setApplyPhysicsLocal(applyPhysicsLocal);
@@ -108,6 +144,12 @@ public class VehicleControl extends PhysicsVehicle implements PhysicsControl, Jm
         return spatial.getWorldRotation();
     }
 
+    /**
+     * Clone this control for a different spatial. No longer used as of JME 3.1.
+     *
+     * @param spatial the spatial for the clone to control (or null)
+     * @return a new control (not null)
+     */
     @Override
     public Control cloneForSpatial(Spatial spatial) {
         VehicleControl control = new VehicleControl(collisionShape, mass);
@@ -158,7 +200,11 @@ public class VehicleControl extends PhysicsVehicle implements PhysicsControl, Jm
         return control;
     }
 
-    @Override   
+    /**
+     * Create a shallow clone for the JME cloner.
+     *
+     * @return a new control (not null)
+     */
     public Object jmeClone() {
         VehicleControl control = new VehicleControl(collisionShape, mass);
         control.setAngularFactor(getAngularFactor());
@@ -206,6 +252,15 @@ public class VehicleControl extends PhysicsVehicle implements PhysicsControl, Jm
         return control;
     }     
 
+    /**
+     * Callback from {@link com.jme3.util.clone.Cloner} to convert this
+     * shallow-cloned control into a deep-cloned one, using the specified cloner
+     * and original to resolve copied fields.
+     *
+     * @param cloner the cloner currently cloning this control (not null)
+     * @param original the control from which this control was shallow-cloned
+     * (unused)
+     */
     @Override   
     public void cloneFields( Cloner cloner, Object original ) {
         this.spatial = cloner.clone(spatial);
@@ -216,6 +271,11 @@ public class VehicleControl extends PhysicsVehicle implements PhysicsControl, Jm
         }        
     }
          
+    /**
+     * Alter which spatial is controlled.
+     *
+     * @param spatial spatial to control (or null)
+     */
     public void setSpatial(Spatial spatial) {
         this.spatial = spatial;
         setUserObject(spatial);
@@ -226,6 +286,15 @@ public class VehicleControl extends PhysicsVehicle implements PhysicsControl, Jm
         setPhysicsRotation(getSpatialRotation());
     }
 
+    /**
+     * Enable or disable this control.
+     * <p>
+     * When the control is disabled, the vehicle is removed from physics space.
+     * When the control is enabled again, the physics object is moved to the
+     * spatial's location and then added to the physics space.
+     *
+     * @param enabled true&rarr;enable the control, false&rarr;disable it
+     */
     public void setEnabled(boolean enabled) {
         this.enabled = enabled;
         if (space != null) {
@@ -243,10 +312,21 @@ public class VehicleControl extends PhysicsVehicle implements PhysicsControl, Jm
         }
     }
 
+    /**
+     * Test whether this control is enabled.
+     *
+     * @return true if enabled, otherwise false
+     */
     public boolean isEnabled() {
         return enabled;
     }
 
+    /**
+     * Update this control. Invoked once per frame, during the logical-state
+     * update, provided the control is added to a scene.
+     *
+     * @param tpf the time interval between frames (in seconds, &ge;0)
+     */
     public void update(float tpf) {
         if (enabled && spatial != null) {
             if (getMotionState().applyTransform(spatial)) {
@@ -258,6 +338,14 @@ public class VehicleControl extends PhysicsVehicle implements PhysicsControl, Jm
         }
     }
 
+    /**
+     * Render this control. Invoked once per view port per frame, provided the
+     * control is added to a scene. Should be invoked only by a subclass or by
+     * the RenderManager.
+     *
+     * @param rm the render manager (not null)
+     * @param vp the view port to render (not null)
+     */
     public void render(RenderManager rm, ViewPort vp) {
     }
 
@@ -288,10 +376,21 @@ public class VehicleControl extends PhysicsVehicle implements PhysicsControl, Jm
         space = newSpace;
     }
 
+    /**
+     * Access the physics space to which the vehicle is (or would be) added.
+     *
+     * @return the pre-existing space, or null for none
+     */
     public PhysicsSpace getPhysicsSpace() {
         return space;
     }
 
+    /**
+     * Serialize this control, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     @Override
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
@@ -301,6 +400,12 @@ public class VehicleControl extends PhysicsVehicle implements PhysicsControl, Jm
         oc.write(spatial, "spatial", null);
     }
 
+    /**
+     * De-serialize this control, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     @Override
     public void read(JmeImporter im) throws IOException {
         super.read(im);
@@ -310,4 +415,4 @@ public class VehicleControl extends PhysicsVehicle implements PhysicsControl, Jm
         motionState.setApplyPhysicsLocal(ic.readBoolean("applyLocalPhysics", false));
         setUserObject(spatial);
     }
-}
+}

+ 10 - 1
jme3-bullet/src/common/java/com/jme3/bullet/control/ragdoll/HumanoidRagdollPreset.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,11 +34,17 @@ package com.jme3.bullet.control.ragdoll;
 import com.jme3.math.FastMath;
 
 /**
+ * Example ragdoll presets for a typical humanoid skeleton.
+ * <p>
+ * This class is shared between JBullet and Native Bullet.
  *
  * @author Nehon
  */
 public class HumanoidRagdollPreset extends RagdollPreset {
 
+    /**
+     * Initialize the map from bone names to joint presets.
+     */
     @Override
     protected void initBoneMap() {
         boneMap.put("head", new JointPreset(FastMath.QUARTER_PI, -FastMath.QUARTER_PI, FastMath.QUARTER_PI, -FastMath.QUARTER_PI, FastMath.QUARTER_PI, -FastMath.QUARTER_PI));
@@ -59,6 +65,9 @@ public class HumanoidRagdollPreset extends RagdollPreset {
 
     }
 
+    /**
+     * Initialize the lexicon.
+     */
     @Override
     protected void initLexicon() {
         LexiconEntry entry = new LexiconEntry();

+ 58 - 1
jme3-bullet/src/common/java/com/jme3/bullet/control/ragdoll/RagdollPreset.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,14 +43,35 @@ import java.util.logging.Logger;
  */
 public abstract class RagdollPreset {
 
+    /**
+     * message logger for this class
+     */
     protected static final Logger logger = Logger.getLogger(RagdollPreset.class.getName());
+    /**
+     * map bone names to joint presets
+     */
     protected Map<String, JointPreset> boneMap = new HashMap<String, JointPreset>();
+    /**
+     * lexicon to map bone names to entries
+     */
     protected Map<String, LexiconEntry> lexicon = new HashMap<String, LexiconEntry>();
 
+    /**
+     * Initialize the map from bone names to joint presets.
+     */
     protected abstract void initBoneMap();
 
+    /**
+     * Initialize the lexicon.
+     */
     protected abstract void initLexicon();
 
+    /**
+     * Apply the preset for the named bone to the specified joint.
+     *
+     * @param boneName name
+     * @param joint where to apply the preset (not null, modified)
+     */
     public void setupJointForBone(String boneName, SixDofJoint joint) {
 
         if (boneMap.isEmpty()) {
@@ -87,14 +108,30 @@ public abstract class RagdollPreset {
 
     }
 
+    /**
+     * Range of motion for a joint.
+     */
     protected class JointPreset {
 
         private float maxX, minX, maxY, minY, maxZ, minZ;
 
+        /**
+         * Instantiate a preset with no motion allowed.
+         */
         public JointPreset() {
         }
 
         public JointPreset(float maxX, float minX, float maxY, float minY, float maxZ, float minZ) {
+        /**
+         * Instantiate a preset with the specified range of motion.
+         *
+         * @param maxX the maximum rotation on the X axis (in radians)
+         * @param minX the minimum rotation on the X axis (in radians)
+         * @param maxY the maximum rotation on the Y axis (in radians)
+         * @param minY the minimum rotation on the Y axis (in radians)
+         * @param maxZ the maximum rotation on the Z axis (in radians)
+         * @param minZ the minimum rotation on the Z axis (in radians)
+         */
             this.maxX = maxX;
             this.minX = minX;
             this.maxY = maxY;
@@ -103,6 +140,11 @@ public abstract class RagdollPreset {
             this.minZ = minZ;
         }
 
+        /**
+         * Apply this preset to the specified joint.
+         *
+         * @param joint where to apply (not null, modified)
+         */
         public void setupJoint(SixDofJoint joint) {
             joint.getRotationalLimitMotor(0).setHiLimit(maxX);
             joint.getRotationalLimitMotor(0).setLoLimit(minX);
@@ -113,13 +155,28 @@ public abstract class RagdollPreset {
         }
     }
 
+    /**
+     * One entry in a bone lexicon.
+     */
     protected class LexiconEntry extends HashMap<String, Integer> {
 
+        /**
+         * Add a synonym with the specified score.
+         *
+         * @param word a substring that might occur in a bone name (not null)
+         * @param score larger value means more likely to correspond
+         */
         public void addSynonym(String word, int score) {
             put(word.toLowerCase(), score);
         }
 
         public int getScore(String word) {
+        /**
+         * Calculate a total score for the specified bone name.
+         *
+         * @param name the name of a bone (not null)
+         * @return total score: larger value means more likely to correspond
+         */
             int score = 0;
             String searchWord = word.toLowerCase();
             for (String key : this.keySet()) {

+ 70 - 25
jme3-bullet/src/common/java/com/jme3/bullet/control/ragdoll/RagdollUtils.java

@@ -48,11 +48,25 @@ import java.nio.FloatBuffer;
 import java.util.*;
 
 /**
+ * Utility methods used by KinematicRagdollControl.
+ * <p>
+ * This class is shared between JBullet and Native Bullet.
  *
  * @author Nehon
  */
 public class RagdollUtils {
 
+    /**
+     * Alter the limits of the specified 6-DOF joint.
+     *
+     * @param joint which joint to alter (not null)
+     * @param maxX the maximum rotation on the X axis (in radians)
+     * @param minX the minimum rotation on the X axis (in radians)
+     * @param maxY the maximum rotation on the Y axis (in radians)
+     * @param minY the minimum rotation on the Y axis (in radians)
+     * @param maxZ the maximum rotation on the Z axis (in radians)
+     * @param minZ the minimum rotation on the Z axis (in radians)
+     */
     public static void setJointLimit(SixDofJoint joint, float maxX, float minX, float maxY, float minY, float maxZ, float minZ) {
 
         joint.getRotationalLimitMotor(0).setHiLimit(maxX);
@@ -63,6 +77,12 @@ public class RagdollUtils {
         joint.getRotationalLimitMotor(2).setLoLimit(minZ);
     }
 
+    /**
+     * Build a map of mesh vertices in a subtree of the scene graph.
+     *
+     * @param model the root of the subtree (may be null)
+     * @return a new map (not null)
+     */
     public static Map<Integer, List<Float>> buildPointMap(Spatial model) {
 
 
@@ -122,14 +142,15 @@ public class RagdollUtils {
     }
 
     /**
-     * Create a hull collision shape from linked vertices to this bone.
-     * Vertices have to be previously gathered in a map using buildPointMap method
-     * 
-     * @param pointsMap
-     * @param boneIndices
-     * @param initialScale
-     * @param initialPosition
-     * @return 
+     * Create a hull collision shape from linked vertices to this bone. Vertices
+     * must have previously been gathered using buildPointMap().
+     *
+     * @param pointsMap map from bone indices to coordinates (not null,
+     * unaffected)
+     * @param boneIndices (not null, unaffected)
+     * @param initialScale scale factors (not null, unaffected)
+     * @param initialPosition location (not null, unaffected)
+     * @return a new shape (not null)
      */
     public static HullCollisionShape makeShapeFromPointMap(Map<Integer, List<Float>> pointsMap, List<Integer> boneIndices, Vector3f initialScale, Vector3f initialPosition) {
 
@@ -160,7 +181,15 @@ public class RagdollUtils {
         return new HullCollisionShape(p);
     }
 
-    //returns the list of bone indices of the given bone and its child (if they are not in the boneList)
+    /**
+     * Enumerate the bone indices of the specified bone and all its descendents.
+     *
+     * @param bone the input bone (not null)
+     * @param skeleton the skeleton containing the bone (not null)
+     * @param boneList a set of bone names (not null, unaffected)
+     *
+     * @return a new list (not null)
+     */
     public static List<Integer> getBoneIndices(Bone bone, Skeleton skeleton, Set<String> boneList) {
         List<Integer> list = new LinkedList<Integer>();
         if (boneList.isEmpty()) {
@@ -178,13 +207,13 @@ public class RagdollUtils {
 
     /**
      * Create a hull collision shape from linked vertices to this bone.
-     * 
-     * @param model
-     * @param boneIndices
-     * @param initialScale
-     * @param initialPosition
-     * @param weightThreshold
-     * @return 
+     *
+     * @param model the model on which to base the shape
+     * @param boneIndices indices of relevant bones (not null, unaffected)
+     * @param initialScale scale factors
+     * @param initialPosition location
+     * @param weightThreshold minimum weight for inclusion
+     * @return a new shape
      */
     public static HullCollisionShape makeShapeFromVerticeWeights(Spatial model, List<Integer> boneIndices, Vector3f initialScale, Vector3f initialPosition, float weightThreshold) {
 
@@ -216,12 +245,18 @@ public class RagdollUtils {
     }
 
     /**
-     * returns a list of points for the given bone
-     * @param mesh
-     * @param boneIndex
-     * @param offset
-     * @param link
-     * @return 
+     * Enumerate vertices that meet the weight threshold for the indexed bone.
+     *
+     * @param mesh the mesh to analyze (not null)
+     * @param boneIndex the index of the bone (&ge;0)
+     * @param initialScale a scale applied to vertex positions (not null,
+     * unaffected)
+     * @param offset an offset subtracted from vertex positions (not null,
+     * unaffected)
+     * @param weightThreshold the minimum bone weight for inclusion in the
+     * result (&ge;0, &le;1)
+     * @return a new list of vertex coordinates (not null, length a multiple of
+     * 3)
      */
     private static List<Float> getPoints(Mesh mesh, int boneIndex, Vector3f initialScale, Vector3f offset, float weightThreshold) {
 
@@ -265,12 +300,16 @@ public class RagdollUtils {
     }
 
     /**
-     * Updates a bone position and rotation.
-     * if the child bones are not in the bone list this means, they are not associated with a physics shape.
-     * So they have to be updated
+     * Updates a bone position and rotation. if the child bones are not in the
+     * bone list this means, they are not associated with a physics shape. So
+     * they have to be updated
+     *
      * @param bone the bone
      * @param pos the position
      * @param rot the rotation
+     * @param restoreBoneControl true &rarr; user-control flag should be set
+     * @param boneList the names of all bones without collision shapes (not
+     * null, unaffected)
      */
     public static void setTransform(Bone bone, Vector3f pos, Quaternion rot, boolean restoreBoneControl, Set<String> boneList) {
         //we ensure that we have the control
@@ -292,6 +331,12 @@ public class RagdollUtils {
         }
     }
 
+    /**
+     * Alter the user-control flags of a bone and all its descendents.
+     *
+     * @param bone the ancestor bone (not null, modified)
+     * @param bool true to enable user control, false to disable
+     */
     public static void setUserControl(Bone bone, boolean bool) {
         bone.setUserControl(bool);
         for (Bone child : bone.getChildren()) {

+ 31 - 1
jme3-bullet/src/common/java/com/jme3/bullet/debug/AbstractPhysicsDebugControl.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -37,14 +37,27 @@ import com.jme3.scene.Spatial;
 import com.jme3.scene.control.AbstractControl;
 
 /**
+ * The abstract base class for physics-debug controls (such as
+ * BulletRigidBodyDebugControl) used to visualize individual collision objects
+ * and joints.
+ * <p>
+ * This class is shared between JBullet and Native Bullet.
  *
  * @author normenhansen
  */
 public abstract class AbstractPhysicsDebugControl extends AbstractControl {
 
     private final Quaternion tmp_inverseWorldRotation = new Quaternion();
+    /**
+     * the app state that this control serves
+     */
     protected final BulletDebugAppState debugAppState;
 
+    /**
+     * Instantiate an enabled control to serve the specified debug app state.
+     *
+     * @param debugAppState which app state (not null, alias created)
+     */
     public AbstractPhysicsDebugControl(BulletDebugAppState debugAppState) {
         this.debugAppState = debugAppState;
     }
@@ -55,10 +68,27 @@ public abstract class AbstractPhysicsDebugControl extends AbstractControl {
     @Override
     protected abstract void controlUpdate(float tpf);
 
+    /**
+     * Apply the specified location and orientation to the controlled spatial.
+     *
+     * @param worldLocation location vector (in physics-space coordinates, not
+     * null, unaffected)
+     * @param worldRotation orientation (in physics-space coordinates, not null,
+     * unaffected)
+     */
     protected void applyPhysicsTransform(Vector3f worldLocation, Quaternion worldRotation) {
         applyPhysicsTransform(worldLocation, worldRotation, this.spatial);
     }
 
+    /**
+     * Apply the specified location and orientation to the specified spatial.
+     *
+     * @param worldLocation location vector (in physics-space coordinates, not
+     * null, unaffected)
+     * @param worldRotation orientation (in physics-space coordinates, not null,
+     * unaffected)
+     * @param spatial where to apply (may be null)
+     */
     protected void applyPhysicsTransform(Vector3f worldLocation, Quaternion worldRotation, Spatial spatial) {
         if (spatial != null) {
             Vector3f localLocation = spatial.getLocalTranslation();

+ 44 - 1
jme3-bullet/src/common/java/com/jme3/bullet/debug/BulletCharacterDebugControl.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,16 +42,37 @@ import com.jme3.scene.Node;
 import com.jme3.scene.Spatial;
 
 /**
+ * A physics-debug control used to visualize a PhysicsCharacter.
+ * <p>
+ * This class is shared between JBullet and Native Bullet.
  *
  * @author normenhansen
  */
 public class BulletCharacterDebugControl extends AbstractPhysicsDebugControl {
 
+    /**
+     * character to visualize (not null)
+     */
     protected final PhysicsCharacter body;
+    /**
+     * temporary storage for physics location
+     */
     protected final Vector3f location = new Vector3f();
     protected final Quaternion rotation = new Quaternion();
+    /**
+     * shape for which geom was generated
+     */
     protected CollisionShape myShape;
+    /**
+     * geometry to visualize myShape (not null)
+     */
     protected Spatial geom;
+    /**
+     * Instantiate an enabled control to visualize the specified character.
+     *
+     * @param debugAppState which app state (not null, alias created)
+     * @param body the character to visualize (not null, alias created)
+     */
 
     public BulletCharacterDebugControl(BulletDebugAppState debugAppState, PhysicsCharacter body) {
         super(debugAppState);
@@ -61,6 +82,13 @@ public class BulletCharacterDebugControl extends AbstractPhysicsDebugControl {
         geom.setMaterial(debugAppState.DEBUG_PINK);
     }
 
+    /**
+     * Alter which spatial is controlled. Invoked when the control is added to
+     * or removed from a spatial. Should be invoked only by a subclass or from
+     * Spatial. Do not invoke directly from user code.
+     *
+     * @param spatial the spatial to control (or null)
+     */
     @Override
     public void setSpatial(Spatial spatial) {
         if (spatial != null && spatial instanceof Node) {
@@ -73,6 +101,13 @@ public class BulletCharacterDebugControl extends AbstractPhysicsDebugControl {
         super.setSpatial(spatial);
     }
 
+    /**
+     * Update this control. Invoked once per frame during the logical-state
+     * update, provided the control is enabled and added to a scene. Should be
+     * invoked only by a subclass or by AbstractControl.
+     *
+     * @param tpf the time interval between frames (in seconds, &ge;0)
+     */
     @Override
     protected void controlUpdate(float tpf) {
         if(myShape != body.getCollisionShape()){
@@ -86,6 +121,14 @@ public class BulletCharacterDebugControl extends AbstractPhysicsDebugControl {
         geom.setLocalScale(body.getCollisionShape().getScale());
     }
 
+    /**
+     * Render this control. Invoked once port per frame, provided the
+     * control is enabled and added to a scene. Should be invoked only by a
+     * subclass or by AbstractControl.
+     *
+     * @param rm the render manager (not null)
+     * @param vp the view port to render (not null)
+     */
     @Override
     protected void controlRender(RenderManager rm, ViewPort vp) {
     }

+ 95 - 5
jme3-bullet/src/common/java/com/jme3/bullet/debug/BulletDebugAppState.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -55,31 +55,84 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
+ * An app state to manage a debug visualization of a physics space.
+ * <p>
+ * This class is shared between JBullet and Native Bullet.
  *
  * @author normenhansen
  */
 public class BulletDebugAppState extends AbstractAppState {
 
+    /**
+     * message logger for this class
+     */
     protected static final Logger logger = Logger.getLogger(BulletDebugAppState.class.getName());
+    /**
+     * limit which objects are visualized, or null to visualize all objects
+     */
     protected DebugAppStateFilter filter;
     protected Application app;
     protected AssetManager assetManager;
+    /**
+     * physics space to visualize (not null)
+     */
     protected final PhysicsSpace space;
+    /**
+     * scene-graph node to parent the geometries
+     */
     protected final Node physicsDebugRootNode = new Node("Physics Debug Root Node");
+    /**
+     * view port in which to render (not null)
+     */
     protected ViewPort viewPort;
     protected RenderManager rm;
+    /**
+     * material for inactive rigid bodies
+     */
     public Material DEBUG_BLUE;
     public Material DEBUG_RED;
+    /**
+     * material for joints
+     */
     public Material DEBUG_GREEN;
+    /**
+     * material for ghosts
+     */
     public Material DEBUG_YELLOW;
+    /**
+     * material for vehicles and active rigid bodies
+     */
     public Material DEBUG_MAGENTA;
+    /**
+     * material for physics characters
+     */
     public Material DEBUG_PINK;
+    /**
+     * map rigid bodies to visualizations
+     */
     protected HashMap<PhysicsRigidBody, Spatial> bodies = new HashMap<PhysicsRigidBody, Spatial>();
+    /**
+     * map joints to visualizations
+     */
     protected HashMap<PhysicsJoint, Spatial> joints = new HashMap<PhysicsJoint, Spatial>();
+    /**
+     * map ghosts to visualizations
+     */
     protected HashMap<PhysicsGhostObject, Spatial> ghosts = new HashMap<PhysicsGhostObject, Spatial>();
+    /**
+     * map physics characters to visualizations
+     */
     protected HashMap<PhysicsCharacter, Spatial> characters = new HashMap<PhysicsCharacter, Spatial>();
+    /**
+     * map vehicles to visualizations
+     */
     protected HashMap<PhysicsVehicle, Spatial> vehicles = new HashMap<PhysicsVehicle, Spatial>();
-
+    /**
+     * Instantiate an app state to visualize the specified space. This constructor should be invoked only by
+     * BulletAppState.
+     *
+     * @param space physics space to visualize (not null, alias created)
+     */
     public BulletDebugAppState(PhysicsSpace space) {
         this.space = space;
     }
@@ -88,10 +141,22 @@ public class BulletDebugAppState extends AbstractAppState {
         return new DebugTools(assetManager);
     }
 
+    /**
+     * Alter which objects are visualized.
+     *
+     * @param filter the desired filter, or or null to visualize all objects
+     */
     public void setFilter(DebugAppStateFilter filter) {
         this.filter = filter;
     }
     
+    /**
+     * Initialize this state prior to its 1st update. Should be invoked only by
+     * a subclass or by the AppStateManager.
+     *
+     * @param stateManager the manager for this state (not null)
+     * @param app the application which owns this state (not null)
+     */
     @Override
     public void initialize(AppStateManager stateManager, Application app) {
         super.initialize(stateManager, app);
@@ -105,12 +170,25 @@ public class BulletDebugAppState extends AbstractAppState {
         viewPort.attachScene(physicsDebugRootNode);
     }
 
+    /**
+     * Transition this state from terminating to detached. Should be invoked
+     * only by a subclass or by the AppStateManager. Invoked once for each time
+     * {@link #initialize(com.jme3.app.state.AppStateManager, com.jme3.app.Application)}
+     * is invoked.
+     */
     @Override
     public void cleanup() {
         rm.removeMainView(viewPort);
         super.cleanup();
     }
 
+    /**
+     * Update this state prior to rendering. Should be invoked only by a
+     * subclass or by the AppStateManager. Invoked once per frame, provided the
+     * state is attached and enabled.
+     *
+     * @param tpf the time interval between frames (in seconds, &ge;0)
+     */
     @Override
     public void update(float tpf) {
         super.update(tpf);
@@ -125,6 +203,13 @@ public class BulletDebugAppState extends AbstractAppState {
         physicsDebugRootNode.updateGeometricState();
     }
 
+    /**
+     * Render this state. Should be invoked only by a subclass or by the
+     * AppStateManager. Invoked once per frame, provided the state is attached
+     * and enabled.
+     *
+     * @param rm the render manager (not null)
+     */
     @Override
     public void render(RenderManager rm) {
         super.render(rm);
@@ -133,6 +218,11 @@ public class BulletDebugAppState extends AbstractAppState {
         }
     }
 
+    /**
+     * Initialize the materials.
+     *
+     * @param app the application which owns this state (not null)
+     */
     private void setupMaterials(Application app) {
         AssetManager manager = app.getAssetManager();
         DEBUG_BLUE = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md");
@@ -311,14 +401,14 @@ public class BulletDebugAppState extends AbstractAppState {
     }
 
     /**
-     * Interface that allows filtering out objects from the debug display
+     * Interface to restrict which physics objects are visualized.
      */
     public static interface DebugAppStateFilter {
 
         /**
-         * Queries an object to be displayed
+         * Test whether the specified physics object should be displayed.
          *
-         * @param obj The object to be displayed
+         * @param obj the joint or collision object to test (unaffected)
          * @return return true if the object should be displayed, false if not
          */
         public boolean displayObject(Object obj);

+ 47 - 1
jme3-bullet/src/common/java/com/jme3/bullet/debug/BulletGhostObjectDebugControl.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,17 +42,41 @@ import com.jme3.scene.Node;
 import com.jme3.scene.Spatial;
 
 /**
+ * A physics-debug control used to visualize a PhysicsGhostObject.
+ * <p>
+ * This class is shared between JBullet and Native Bullet.
  *
  * @author normenhansen
  */
 public class BulletGhostObjectDebugControl extends AbstractPhysicsDebugControl {
 
+    /**
+     * ghost object to visualize (not null)
+     */
     protected final PhysicsGhostObject body;
+    /**
+     * temporary storage for physics location
+     */
     protected final Vector3f location = new Vector3f();
+    /**
+     * temporary storage for physics rotation
+     */
     protected final Quaternion rotation = new Quaternion();
+    /**
+     * shape for which geom was generated (not null)
+     */
     protected CollisionShape myShape;
+    /**
+     * geometry to visualize myShape (not null)
+     */
     protected Spatial geom;
 
+    /**
+     * Instantiate an enabled control to visualize the specified ghost object.
+     *
+     * @param debugAppState which app state (not null, alias created)
+     * @param body which object to visualize (not null, alias created)
+     */
     public BulletGhostObjectDebugControl(BulletDebugAppState debugAppState, PhysicsGhostObject body) {
         super(debugAppState);
         this.body = body;
@@ -63,6 +87,13 @@ public class BulletGhostObjectDebugControl extends AbstractPhysicsDebugControl {
         geom.setMaterial(debugAppState.DEBUG_YELLOW);
     }
 
+    /**
+     * Alter which spatial is controlled. Invoked when the control is added to
+     * or removed from a spatial. Should be invoked only by a subclass or from
+     * Spatial. Do not invoke directly from user code.
+     *
+     * @param spatial the spatial to control (or null)
+     */
     @Override
     public void setSpatial(Spatial spatial) {
         if (spatial != null && spatial instanceof Node) {
@@ -75,6 +106,13 @@ public class BulletGhostObjectDebugControl extends AbstractPhysicsDebugControl {
         super.setSpatial(spatial);
     }
 
+    /**
+     * Update this control. Invoked once per frame during the logical-state
+     * update, provided the control is enabled and added to a scene. Should be
+     * invoked only by a subclass or by AbstractControl.
+     *
+     * @param tpf the time interval between frames (in seconds, &ge;0)
+     */
     @Override
     protected void controlUpdate(float tpf) {
         if (myShape != body.getCollisionShape()) {
@@ -88,6 +126,14 @@ public class BulletGhostObjectDebugControl extends AbstractPhysicsDebugControl {
         geom.setLocalScale(body.getCollisionShape().getScale());
     }
 
+    /**
+     * Render this control. Invoked once per frame, provided the
+     * control is enabled and added to a scene. Should be invoked only by a
+     * subclass or by AbstractControl.
+     *
+     * @param rm the render manager (not null)
+     * @param vp the view port to render (not null)
+     */
     @Override
     protected void controlRender(RenderManager rm, ViewPort vp) {
     }

+ 32 - 1
jme3-bullet/src/common/java/com/jme3/bullet/debug/BulletJointDebugControl.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,6 +43,9 @@ import com.jme3.scene.Spatial;
 import com.jme3.scene.debug.Arrow;
 
 /**
+ * A physics-debug control used to visualize a PhysicsJoint.
+ * <p>
+ * This class is shared between JBullet and Native Bullet.
  *
  * @author normenhansen
  */
@@ -58,6 +61,12 @@ public class BulletJointDebugControl extends AbstractPhysicsDebugControl {
     protected final Vector3f offA = new Vector3f();
     protected final Vector3f offB = new Vector3f();
 
+    /**
+     * Instantiate an enabled control to visualize the specified joint.
+     *
+     * @param debugAppState which app state (not null, alias created)
+     * @param body the joint to visualize (not null, alias created)
+     */
     public BulletJointDebugControl(BulletDebugAppState debugAppState, PhysicsJoint body) {
         super(debugAppState);
         this.body = body;
@@ -71,6 +80,13 @@ public class BulletJointDebugControl extends AbstractPhysicsDebugControl {
         geomB.setMaterial(debugAppState.DEBUG_GREEN);
     }
 
+    /**
+     * Alter which spatial is controlled. Invoked when the control is added to
+     * or removed from a spatial. Should be invoked only by a subclass or from
+     * Spatial. Do not invoke directly from user code.
+     *
+     * @param spatial the spatial to control (or null)
+     */
     @Override
     public void setSpatial(Spatial spatial) {
         if (spatial != null && spatial instanceof Node) {
@@ -85,6 +101,13 @@ public class BulletJointDebugControl extends AbstractPhysicsDebugControl {
         super.setSpatial(spatial);
     }
 
+    /**
+     * Update this control. Invoked once per frame during the logical-state
+     * update, provided the control is enabled and added to a scene. Should be
+     * invoked only by a subclass or by AbstractControl.
+     *
+     * @param tpf the time interval between frames (in seconds, &ge;0)
+     */
     @Override
     protected void controlUpdate(float tpf) {
         body.getBodyA().getPhysicsLocation(a.getTranslation());
@@ -100,6 +123,14 @@ public class BulletJointDebugControl extends AbstractPhysicsDebugControl {
         arrowB.setArrowExtent(body.getPivotB());
     }
 
+    /**
+     * Render this control. Invoked once per frame, provided the
+     * control is enabled and added to a scene. Should be invoked only by a
+     * subclass or by AbstractControl.
+     *
+     * @param rm the render manager (not null)
+     * @param vp the view port to render (not null)
+     */
     @Override
     protected void controlRender(RenderManager rm, ViewPort vp) {
     }

+ 47 - 1
jme3-bullet/src/common/java/com/jme3/bullet/debug/BulletRigidBodyDebugControl.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,17 +42,41 @@ import com.jme3.scene.Node;
 import com.jme3.scene.Spatial;
 
 /**
+ * A physics-debug control used to visualize a PhysicsRigidBody.
+ * <p>
+ * This class is shared between JBullet and Native Bullet.
  *
  * @author normenhansen
  */
 public class BulletRigidBodyDebugControl extends AbstractPhysicsDebugControl {
 
+    /**
+     * rigid body to visualize (not null)
+     */
     protected final PhysicsRigidBody body;
+    /**
+     * temporary storage for physics location
+     */
     protected final Vector3f location = new Vector3f();
+    /**
+     * temporary storage for physics rotation
+     */
     protected final Quaternion rotation = new Quaternion();
+    /**
+     * shape for which geom was generated (not null)
+     */
     protected CollisionShape myShape;
+    /**
+     * geometry to visualize myShape (not null)
+     */
     protected Spatial geom;
 
+    /**
+     * Instantiate an enabled control to visualize the specified body.
+     *
+     * @param debugAppState which app state (not null, alias created)
+     * @param body which body to visualize (not null, alias created)
+     */
     public BulletRigidBodyDebugControl(BulletDebugAppState debugAppState, PhysicsRigidBody body) {
         super(debugAppState);
         this.body = body;
@@ -62,6 +86,13 @@ public class BulletRigidBodyDebugControl extends AbstractPhysicsDebugControl {
         geom.setMaterial(debugAppState.DEBUG_BLUE);
     }
 
+    /**
+     * Alter which spatial is controlled. Invoked when the control is added to
+     * or removed from a spatial. Should be invoked only by a subclass or from
+     * Spatial. Do not invoke directly from user code.
+     *
+     * @param spatial the spatial to control (or null)
+     */
     @Override
     public void setSpatial(Spatial spatial) {
         if (spatial != null && spatial instanceof Node) {
@@ -74,6 +105,13 @@ public class BulletRigidBodyDebugControl extends AbstractPhysicsDebugControl {
         super.setSpatial(spatial);
     }
 
+    /**
+     * Update this control. Invoked once per frame during the logical-state
+     * update, provided the control is enabled and added to a scene. Should be
+     * invoked only by a subclass or by AbstractControl.
+     *
+     * @param tpf the time interval between frames (in seconds, &ge;0)
+     */
     @Override
     protected void controlUpdate(float tpf) {
         if(myShape != body.getCollisionShape()){
@@ -91,6 +129,14 @@ public class BulletRigidBodyDebugControl extends AbstractPhysicsDebugControl {
         geom.setLocalScale(body.getCollisionShape().getScale());
     }
 
+    /**
+     * Render this control. Invoked once per frame, provided the
+     * control is enabled and added to a scene. Should be invoked only by a
+     * subclass or by AbstractControl.
+     *
+     * @param rm the render manager (not null)
+     * @param vp the view port to render (not null)
+     */
     @Override
     protected void controlRender(RenderManager rm, ViewPort vp) {
     }

+ 32 - 1
jme3-bullet/src/common/java/com/jme3/bullet/debug/BulletVehicleDebugControl.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,6 +43,9 @@ import com.jme3.scene.Spatial;
 import com.jme3.scene.debug.Arrow;
 
 /**
+ * A physics-debug control used to visualize a PhysicsVehicle.
+ * <p>
+ * This class is shared between JBullet and Native Bullet.
  *
  * @author normenhansen
  */
@@ -53,6 +56,12 @@ public class BulletVehicleDebugControl extends AbstractPhysicsDebugControl {
     protected final Vector3f location = new Vector3f();
     protected final Quaternion rotation = new Quaternion();
 
+    /**
+     * Instantiate an enabled control to visualize the specified vehicle.
+     *
+     * @param debugAppState which app state (not null, alias created)
+     * @param body which vehicle to visualize (not null, alias created)
+     */
     public BulletVehicleDebugControl(BulletDebugAppState debugAppState, PhysicsVehicle body) {
         super(debugAppState);
         this.body = body;
@@ -60,6 +69,13 @@ public class BulletVehicleDebugControl extends AbstractPhysicsDebugControl {
         createVehicle();
     }
 
+    /**
+     * Alter which spatial is controlled. Invoked when the control is added to
+     * or removed from a spatial. Should be invoked only by a subclass or from
+     * Spatial. Do not invoke directly from user code.
+     *
+     * @param spatial the spatial to control (or null)
+     */
     @Override
     public void setSpatial(Spatial spatial) {
         if (spatial != null && spatial instanceof Node) {
@@ -104,6 +120,13 @@ public class BulletVehicleDebugControl extends AbstractPhysicsDebugControl {
         }
     }
 
+    /**
+     * Update this control. Invoked once per frame during the logical-state
+     * update, provided the control is enabled and added to a scene. Should be
+     * invoked only by a subclass or by AbstractControl.
+     *
+     * @param tpf the time interval between frames (in seconds, &ge;0)
+     */
     @Override
     protected void controlUpdate(float tpf) {
         for (int i = 0; i < body.getNumWheels(); i++) {
@@ -136,6 +159,14 @@ public class BulletVehicleDebugControl extends AbstractPhysicsDebugControl {
         applyPhysicsTransform(body.getPhysicsLocation(location), body.getPhysicsRotation(rotation));
     }
 
+    /**
+     * Render this control. Invoked once per frame, provided the
+     * control is enabled and added to a scene. Should be invoked only by a
+     * subclass or by AbstractControl.
+     *
+     * @param rm the render manager (not null)
+     * @param vp the view port to render (not null)
+     */
     @Override
     protected void controlRender(RenderManager rm, ViewPort vp) {
     }

+ 129 - 1
jme3-bullet/src/common/java/com/jme3/bullet/debug/DebugTools.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,43 +42,129 @@ import com.jme3.scene.Node;
 import com.jme3.scene.debug.Arrow;
 
 /**
+ * Debugging aids.
+ * <p>
+ * This class is shared between JBullet and Native Bullet.
  *
  * @author normenhansen
  */
 public class DebugTools {
 
     protected final AssetManager manager;
+    /**
+     * unshaded blue material
+     */
     public Material DEBUG_BLUE;
+    /**
+     * unshaded red material
+     */
     public Material DEBUG_RED;
+    /**
+     * unshaded green material
+     */
     public Material DEBUG_GREEN;
+    /**
+     * unshaded yellow material
+     */
     public Material DEBUG_YELLOW;
+    /**
+     * unshaded magenta material
+     */
     public Material DEBUG_MAGENTA;
+    /**
+     * unshaded pink material
+     */
     public Material DEBUG_PINK;
+    /**
+     * node for attaching debug geometries
+     */
     public Node debugNode = new Node("Debug Node");
+    /**
+     * mesh for the blue arrow
+     */
     public Arrow arrowBlue = new Arrow(Vector3f.ZERO);
+    /**
+     * geometry for the blue arrow
+     */
     public Geometry arrowBlueGeom = new Geometry("Blue Arrow", arrowBlue);
+    /**
+     * mesh for the green arrow
+     */
     public Arrow arrowGreen = new Arrow(Vector3f.ZERO);
+    /**
+     * geometry for the green arrow
+     */
     public Geometry arrowGreenGeom = new Geometry("Green Arrow", arrowGreen);
+    /**
+     * mesh for the red arrow
+     */
     public Arrow arrowRed = new Arrow(Vector3f.ZERO);
+    /**
+     * geometry for the red arrow
+     */
     public Geometry arrowRedGeom = new Geometry("Red Arrow", arrowRed);
+    /**
+     * mesh for the magenta arrow
+     */
     public Arrow arrowMagenta = new Arrow(Vector3f.ZERO);
+    /**
+     * geometry for the magenta arrow
+     */
     public Geometry arrowMagentaGeom = new Geometry("Magenta Arrow", arrowMagenta);
+    /**
+     * mesh for the yellow arrow
+     */
     public Arrow arrowYellow = new Arrow(Vector3f.ZERO);
+    /**
+     * geometry for the yellow arrow
+     */
     public Geometry arrowYellowGeom = new Geometry("Yellow Arrow", arrowYellow);
+    /**
+     * mesh for the pink arrow
+     */
     public Arrow arrowPink = new Arrow(Vector3f.ZERO);
+    /**
+     * geometry for the pink arrow
+     */
     public Geometry arrowPinkGeom = new Geometry("Pink Arrow", arrowPink);
+    /**
+     * local copy of {@link com.jme3.math.Vector3f#UNIT_X}
+     */
     protected static final Vector3f UNIT_X_CHECK = new Vector3f(1, 0, 0);
+    /**
+     * local copy of {@link com.jme3.math.Vector3f#UNIT_Y}
+     */
     protected static final Vector3f UNIT_Y_CHECK = new Vector3f(0, 1, 0);
+    /**
+     * local copy of {@link com.jme3.math.Vector3f#UNIT_Z}
+     */
     protected static final Vector3f UNIT_Z_CHECK = new Vector3f(0, 0, 1);
+    /**
+     * local copy of {@link com.jme3.math.Vector3f#UNIT_XYZ}
+     */
     protected static final Vector3f UNIT_XYZ_CHECK = new Vector3f(1, 1, 1);
+    /**
+     * local copy of {@link com.jme3.math.Vector3f#ZERO}
+     */
     protected static final Vector3f ZERO_CHECK = new Vector3f(0, 0, 0);
 
+    /**
+     * Instantiate a set of debug tools.
+     *
+     * @param manager for loading assets (not null, alias created)
+     */
     public DebugTools(AssetManager manager) {
         this.manager = manager;
         setupMaterials();
         setupDebugNode();
     }
 
+    /**
+     * Render all the debug geometries to the specified view port.
+     *
+     * @param rm the render manager (not null)
+     * @param vp the view port (not null)
+     */
     public void show(RenderManager rm, ViewPort vp) {
         if (!Vector3f.UNIT_X.equals(UNIT_X_CHECK) || !Vector3f.UNIT_Y.equals(UNIT_Y_CHECK) || !Vector3f.UNIT_Z.equals(UNIT_Z_CHECK)
                 || !Vector3f.UNIT_XYZ.equals(UNIT_XYZ_CHECK) || !Vector3f.ZERO.equals(ZERO_CHECK)) {
@@ -94,36 +180,75 @@ public class DebugTools {
         rm.renderScene(debugNode, vp);
     }
 
+    /**
+     * Alter the location and extent of the blue arrow.
+     *
+     * @param location the coordinates of the tail (not null, unaffected)
+     * @param extent the offset of the tip from the tail (not null, unaffected)
+     */
     public void setBlueArrow(Vector3f location, Vector3f extent) {
         arrowBlueGeom.setLocalTranslation(location);
         arrowBlue.setArrowExtent(extent);
     }
 
+    /**
+     * Alter the location and extent of the green arrow.
+     *
+     * @param location the coordinates of the tail (not null, unaffected)
+     * @param extent the offset of the tip from the tail (not null, unaffected)
+     */
     public void setGreenArrow(Vector3f location, Vector3f extent) {
         arrowGreenGeom.setLocalTranslation(location);
         arrowGreen.setArrowExtent(extent);
     }
 
+    /**
+     * Alter the location and extent of the red arrow.
+     *
+     * @param location the coordinates of the tail (not null, unaffected)
+     * @param extent the offset of the tip from the tail (not null, unaffected)
+     */
     public void setRedArrow(Vector3f location, Vector3f extent) {
         arrowRedGeom.setLocalTranslation(location);
         arrowRed.setArrowExtent(extent);
     }
 
+    /**
+     * Alter the location and extent of the magenta arrow.
+     *
+     * @param location the coordinates of the tail (not null, unaffected)
+     * @param extent the offset of the tip from the tail (not null, unaffected)
+     */
     public void setMagentaArrow(Vector3f location, Vector3f extent) {
         arrowMagentaGeom.setLocalTranslation(location);
         arrowMagenta.setArrowExtent(extent);
     }
 
+    /**
+     * Alter the location and extent of the yellow arrow.
+     *
+     * @param location the coordinates of the tail (not null, unaffected)
+     * @param extent the offset of the tip from the tail (not null, unaffected)
+     */
     public void setYellowArrow(Vector3f location, Vector3f extent) {
         arrowYellowGeom.setLocalTranslation(location);
         arrowYellow.setArrowExtent(extent);
     }
 
+    /**
+     * Alter the location and extent of the pink arrow.
+     *
+     * @param location the coordinates of the tail (not null, unaffected)
+     * @param extent the offset of the tip from the tail (not null, unaffected)
+     */
     public void setPinkArrow(Vector3f location, Vector3f extent) {
         arrowPinkGeom.setLocalTranslation(location);
         arrowPink.setArrowExtent(extent);
     }
 
+    /**
+     * Attach all the debug geometries to the debug node.
+     */
     protected void setupDebugNode() {
         arrowBlueGeom.setMaterial(DEBUG_BLUE);
         arrowGreenGeom.setMaterial(DEBUG_GREEN);
@@ -139,6 +264,9 @@ public class DebugTools {
         debugNode.attachChild(arrowPinkGeom);
     }
 
+    /**
+     * Initialize all the DebugTools materials.
+     */
     protected void setupMaterials() {
         DEBUG_BLUE = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md");
         DEBUG_BLUE.getAdditionalRenderState().setWireframe(true);

+ 71 - 26
jme3-bullet/src/common/java/com/jme3/bullet/util/CollisionShapeFactory.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,17 +44,21 @@ import java.util.Iterator;
 import java.util.LinkedList;
 
 /**
+ * A utility class for generating collision shapes from Spatials.
+ * <p>
+ * This class is shared between JBullet and Native Bullet.
  *
  * @author normenhansen, tim8dev
  */
 public class CollisionShapeFactory {
 
     /**
-     * returns the correct transform for a collisionshape in relation
-     * to the ancestor for which the collisionshape is generated
+     * Calculate the correct transform for a collision shape relative to the
+     * ancestor for which the shape was generated.
+     *
      * @param spat
      * @param parent
-     * @return
+     * @return a new instance (not null)
      */
     private static Transform getTransform(Spatial spat, Spatial parent) {
         Transform shapeTransform = new Transform();
@@ -135,30 +139,48 @@ public class CollisionShapeFactory {
     }
 
     /**
-     * This type of collision shape is mesh-accurate and meant for immovable "world objects".
-     * Examples include terrain, houses or whole shooter levels.<br>
-     * Objects with "mesh" type collision shape will not collide with each other.
+     * This type of collision shape is mesh-accurate and meant for immovable
+     * "world objects". Examples include terrain, houses or whole shooter
+     * levels.
+     * <p>
+     * Objects with "mesh" type collision shape will not collide with each
+     * other.
+     *
+     * @param rootNode the node on which to base the shape (not null)
+     * @return a new shape (not null)
      */
     private static CompoundCollisionShape createMeshCompoundShape(Node rootNode) {
         return createCompoundShape(rootNode, new CompoundCollisionShape(), true);
     }
 
     /**
-     * This type of collision shape creates a CompoundShape made out of boxes that
-     * are based on the bounds of the Geometries  in the tree.
-     * @param rootNode
-     * @return
+     * This type of collision shape creates a CompoundShape made out of boxes
+     * that are based on the bounds of the Geometries in the tree.
+     *
+     * @param rootNode the node on which to base the shape (not null)
+     * @return a new shape (not null)
      */
     private static CompoundCollisionShape createBoxCompoundShape(Node rootNode) {
         return createCompoundShape(rootNode, new CompoundCollisionShape(), false);
     }
 
     /**
-     * This type of collision shape is mesh-accurate and meant for immovable "world objects".
-     * Examples include terrain, houses or whole shooter levels.<br/>
-     * Objects with "mesh" type collision shape will not collide with each other.<br/>
-     * Creates a HeightfieldCollisionShape if the supplied spatial is a TerrainQuad.
-     * @return A MeshCollisionShape or a CompoundCollisionShape with MeshCollisionShapes as children if the supplied spatial is a Node. A HeightieldCollisionShape if a TerrainQuad was supplied.
+     * Create a mesh shape for the given Spatial.
+     * <p>
+     * This type of collision shape is mesh-accurate and meant for immovable
+     * "world objects". Examples include terrain, houses or whole shooter
+     * levels.
+     * <p>
+     * Objects with "mesh" type collision shape will not collide with each
+     * other.
+     * <p>
+     * Creates a HeightfieldCollisionShape if the supplied spatial is a
+     * TerrainQuad.
+     *
+     * @param spatial the spatial on which to base the shape (not null)
+     * @return A MeshCollisionShape or a CompoundCollisionShape with
+     * MeshCollisionShapes as children if the supplied spatial is a Node. A
+     * HeightieldCollisionShape if a TerrainQuad was supplied.
      */
     public static CollisionShape createMeshShape(Spatial spatial) {
         if (spatial instanceof TerrainQuad) {
@@ -177,9 +199,14 @@ public class CollisionShapeFactory {
     }
 
     /**
-     * This method creates a hull shape for the given Spatial.<br>
-     * If you want to have mesh-accurate dynamic shapes (CPU intense!!!) use GImpact shapes, its probably best to do so with a low-poly version of your model.
-     * @return A HullCollisionShape or a CompoundCollisionShape with HullCollisionShapes as children if the supplied spatial is a Node.
+     * Create a hull shape for the given Spatial.
+     * <p>
+     * For mesh-accurate animated meshes (CPU intense!) use GImpact shapes.
+     *
+     * @param spatial the spatial on which to base the shape (not null)
+     * @return a HullCollisionShape (if spatial is a Geometry) or a
+     * CompoundCollisionShape with HullCollisionShapes as children (if spatial
+     * is a Node)
      */
     public static CollisionShape createDynamicMeshShape(Spatial spatial) {
         if (spatial instanceof Geometry) {
@@ -192,6 +219,14 @@ public class CollisionShapeFactory {
 
     }
 
+    /**
+     * Create a box shape for the given Spatial.
+     *
+     * @param spatial the spatial on which to base the shape (not null)
+     * @return a BoxCollisionShape (if spatial is a Geometry) or a
+     * CompoundCollisionShape with BoxCollisionShapes as children (if spatial is
+     * a Node)
+     */
     public static CollisionShape createBoxShape(Spatial spatial) {
         if (spatial instanceof Geometry) {
             return createSingleBoxShape((Geometry) spatial, spatial);
@@ -203,9 +238,12 @@ public class CollisionShapeFactory {
     }
 
     /**
-     * This type of collision shape is mesh-accurate and meant for immovable "world objects".
-     * Examples include terrain, houses or whole shooter levels.<br>
-     * Objects with "mesh" type collision shape will not collide with each other.
+     * This type of collision shape is mesh-accurate and meant for immovable
+     * "world objects". Examples include terrain, houses or whole shooter
+     * levels.
+     * <p>
+     * Objects with "mesh" type collision shape will not collide with each
+     * other.
      */
     private static MeshCollisionShape createSingleMeshShape(Geometry geom, Spatial parent) {
         Mesh mesh = geom.getMesh();
@@ -220,9 +258,13 @@ public class CollisionShapeFactory {
     }
 
     /**
-     * Uses the bounding box of the supplied spatial to create a BoxCollisionShape
-     * @param spatial
-     * @return BoxCollisionShape with the size of the spatials BoundingBox
+     * Use the bounding box of the supplied spatial to create a
+     * BoxCollisionShape.
+     *
+     * @param spatial the spatial on which to base the shape (not null)
+     * @param parent unused
+     * @return a new shape with the dimensions of the spatial's bounding box
+     * (not null)
      */
     private static BoxCollisionShape createSingleBoxShape(Spatial spatial, Spatial parent) {
         //TODO: using world bound here instead of "local world" bound...
@@ -232,7 +274,10 @@ public class CollisionShapeFactory {
     }
 
     /**
-     * This method creates a hull collision shape for the given mesh.<br>
+     * Create a hull collision shape for the specified geometry.
+     *
+     * @param geom the geometry on which to base the shape (not null)
+     * @param parent
      */
     private static HullCollisionShape createSingleDynamicMeshShape(Geometry geom, Spatial parent) {
         Mesh mesh = geom.getMesh();

+ 386 - 91
jme3-bullet/src/main/java/com/jme3/bullet/PhysicsSpace.java

@@ -62,17 +62,36 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * <p>PhysicsSpace - The central jbullet-jme physics space</p>
+ * A jbullet-jme physics space with its own btDynamicsWorld.
  *
  * @author normenhansen
  */
 public class PhysicsSpace {
 
+    /**
+     * message logger for this class
+     */
     private static final Logger logger = Logger.getLogger(PhysicsSpace.class.getName());
+    /**
+     * index of the X axis
+     */
     public static final int AXIS_X = 0;
+    /**
+     * index of the Y axis
+     */
     public static final int AXIS_Y = 1;
+    /**
+     * index of the Z axis
+     */
     public static final int AXIS_Z = 2;
+    /**
+     * Bullet identifier of the physics space. The constructor sets this to a
+     * non-zero value.
+     */
     private long physicsSpaceId = 0;
+    /**
+     * first-in/first-out (FIFO) queue of physics tasks for each thread
+     */
     private static ThreadLocal<ConcurrentLinkedQueue<AppTask<?>>> pQueueTL =
             new ThreadLocal<ConcurrentLinkedQueue<AppTask<?>>>() {
                 @Override
@@ -80,8 +99,17 @@ public class PhysicsSpace {
                     return new ConcurrentLinkedQueue<AppTask<?>>();
                 }
             };
+    /**
+     * first-in/first-out (FIFO) queue of physics tasks
+     */
     private ConcurrentLinkedQueue<AppTask<?>> pQueue = new ConcurrentLinkedQueue<AppTask<?>>();
+    /**
+     * physics space for each thread
+     */
     private static ThreadLocal<PhysicsSpace> physicsSpaceTL = new ThreadLocal<PhysicsSpace>();
+    /**
+     * copy of type of acceleration structure used
+     */
     private BroadphaseType broadphaseType = BroadphaseType.DBVT;
 //    private DiscreteDynamicsWorld dynamicsWorld = null;
 //    private BroadphaseInterface broadphase;
@@ -99,10 +127,32 @@ public class PhysicsSpace {
     private Map<Integer, PhysicsCollisionGroupListener> collisionGroupListeners = new ConcurrentHashMap<Integer, PhysicsCollisionGroupListener>();
     private ConcurrentLinkedQueue<PhysicsTickListener> tickListeners = new ConcurrentLinkedQueue<PhysicsTickListener>();
     private PhysicsCollisionEventFactory eventFactory = new PhysicsCollisionEventFactory();
+    /**
+     * copy of minimum coordinate values when using AXIS_SWEEP broadphase
+     * algorithms
+     */
     private Vector3f worldMin = new Vector3f(-10000f, -10000f, -10000f);
+    /**
+     * copy of maximum coordinate values when using AXIS_SWEEP broadphase
+     * algorithms
+     */
     private Vector3f worldMax = new Vector3f(10000f, 10000f, 10000f);
+    /**
+     * physics time step (in seconds, &gt;0)
+     */
     private float accuracy = 1f / 60f;
-    private int maxSubSteps = 4, rayTestFlags = 1 << 2;
+    /**
+     * maximum number of physics steps per frame (&ge;0, default=4)
+     */
+    private int maxSubSteps = 4;
+    /**
+     * flags used in ray tests
+     */
+    private int rayTestFlags = 1 << 2;
+    /**
+     * copy of number of iterations used by the contact-and-constraint solver
+     * (default=10)
+     */
     private int solverNumIterations = 10;
 
     static {
@@ -111,9 +161,8 @@ public class PhysicsSpace {
     }
 
     /**
-     * Get the current PhysicsSpace <b>running on this thread</b><br/> For
-     * parallel physics, this can also be called from the OpenGL thread to
-     * receive the PhysicsSpace
+     * Access the PhysicsSpace <b>running on this thread</b>. For parallel
+     * physics, this can be invoked from the OpenGL thread.
      *
      * @return the PhysicsSpace running on this thread
      */
@@ -124,24 +173,47 @@ public class PhysicsSpace {
     /**
      * Used internally
      *
-     * @param space
+     * @param space which physics space to simulate on this thread
      */
     public static void setLocalThreadPhysicsSpace(PhysicsSpace space) {
         physicsSpaceTL.set(space);
     }
 
+    /**
+     * Instantiate a PhysicsSpace. Must be invoked on the designated physics
+     * thread.
+     */
     public PhysicsSpace() {
         this(new Vector3f(-10000f, -10000f, -10000f), new Vector3f(10000f, 10000f, 10000f), BroadphaseType.DBVT);
     }
 
+    /**
+     * Instantiate a PhysicsSpace. Must be invoked on the designated physics
+     * thread.
+     */
     public PhysicsSpace(BroadphaseType broadphaseType) {
         this(new Vector3f(-10000f, -10000f, -10000f), new Vector3f(10000f, 10000f, 10000f), broadphaseType);
     }
 
+    /**
+     * Instantiate a PhysicsSpace. Must be invoked on the designated physics
+     * thread.
+     */
     public PhysicsSpace(Vector3f worldMin, Vector3f worldMax) {
         this(worldMin, worldMax, BroadphaseType.AXIS_SWEEP_3);
     }
 
+    /**
+     * Instantiate a PhysicsSpace. Must be invoked on the designated physics
+     * thread.
+     *
+     * @param worldMin the desired minimum coordinates values (not null,
+     * unaffected, default=-10k,-10k,-10k)
+     * @param worldMax the desired minimum coordinates values (not null,
+     * unaffected, default=10k,10k,10k)
+     * @param broadphaseType which broadphase collision-detection algorithm to
+     * use (not null)
+     */
     public PhysicsSpace(Vector3f worldMin, Vector3f worldMax, BroadphaseType broadphaseType) {
         this.worldMin.set(worldMin);
         this.worldMax.set(worldMax);
@@ -150,7 +222,7 @@ public class PhysicsSpace {
     }
 
     /**
-     * Has to be called from the (designated) physics thread
+     * Must be invoked on the designated physics thread.
      */
     public void create() {
         physicsSpaceId = createPhysicsSpace(worldMin.x, worldMin.y, worldMin.z, worldMax.x, worldMax.y, worldMax.z, broadphaseType.ordinal(), false);
@@ -191,6 +263,13 @@ public class PhysicsSpace {
 
     private native long createPhysicsSpace(float minX, float minY, float minZ, float maxX, float maxY, float maxZ, int broadphaseType, boolean threading);
 
+    /**
+     * Callback invoked just before the physics is stepped.
+     * <p>
+     * This method is invoked from native code.
+     *
+     * @param timeStep the time per physics step (in seconds, &ge;0)
+     */
     private void preTick_native(float f) {
         AppTask task;
         while((task=pQueue.poll())!=null){
@@ -208,6 +287,13 @@ public class PhysicsSpace {
         }
     }
 
+    /**
+     * Callback invoked just after the physics is stepped.
+     * <p>
+     * This method is invoked from native code.
+     *
+     * @param timeStep the time per physics step (in seconds, &ge;0)
+     */
     private void postTick_native(float f) {
         for (Iterator<PhysicsTickListener> it = tickListeners.iterator(); it.hasNext();) {
             PhysicsTickListener physicsTickCallback = it.next();
@@ -215,6 +301,9 @@ public class PhysicsSpace {
         }
     }
 
+    /**
+     * This method is invoked from native code.
+     */
     private void addCollision_native() {
     }
 
@@ -334,6 +423,9 @@ public class PhysicsSpace {
         collisionEvents.add(eventFactory.getEvent(PhysicsCollisionEvent.TYPE_PROCESSED, node, node1, manifoldPointObjectId));
     }
     
+    /**
+     * This method is invoked from native code.
+     */    
     private boolean notifyCollisionGroupListeners_native(PhysicsCollisionObject node, PhysicsCollisionObject node1){
         PhysicsCollisionGroupListener listener = collisionGroupListeners.get(node.getCollisionGroup());
         PhysicsCollisionGroupListener listener1 = collisionGroupListeners.get(node1.getCollisionGroup());
@@ -350,19 +442,21 @@ public class PhysicsSpace {
     }
 
     /**
-     * updates the physics space
+     * Update this space. Invoked (by the Bullet app state) once per frame while
+     * the app state is attached and enabled.
      *
-     * @param time the current time value
+     * @param time time-per-frame multiplied by speed (in seconds, &ge;0)
      */
     public void update(float time) {
         update(time, maxSubSteps);
     }
 
     /**
-     * updates the physics space, uses maxSteps<br>
+     * Simulate for the specified time interval, using no more than the
+     * specified number of steps.
      *
-     * @param time the current time value
-     * @param maxSteps
+     * @param time the time interval (in seconds, &ge;0)
+     * @param maxSteps the maximum number of steps (&ge;1)
      */
     public void update(float time, int maxSteps) {
 //        if (getDynamicsWorld() == null) {
@@ -374,6 +468,9 @@ public class PhysicsSpace {
 
     private native void stepSimulation(long space, float time, int maxSteps, float accuracy);
 
+    /**
+     * Distribute each collision event to all listeners.
+     */
     public void distributeEvents() {
         //add collision callbacks
         int clistsize = collisionListeners.size();
@@ -387,6 +484,13 @@ public class PhysicsSpace {
         }
     }
 
+    /**
+     * Enqueue a callable on the currently executing thread.
+     *
+     * @param <V> the task's result type
+     * @param callable the task to be executed
+     * @return a new task (not null)
+     */
     public static <V> Future<V> enqueueOnThisThread(Callable<V> callable) {
         AppTask<V> task = new AppTask<V>(callable);
         System.out.println("created apptask");
@@ -395,11 +499,11 @@ public class PhysicsSpace {
     }
 
     /**
-     * calls the callable on the next physics tick (ensuring e.g. force
-     * applying)
+     * Invoke the specified callable during the next physics tick. This is
+     * useful for applying forces.
      *
-     * @param <V>
-     * @param callable
+     * @param <V> the return type of the callable
+     * @param callable which callable to invoke
      * @return Future object
      */
     public <V> Future<V> enqueue(Callable<V> callable) {
@@ -409,9 +513,10 @@ public class PhysicsSpace {
     }
 
     /**
-     * adds an object to the physics space
+     * Add the specified object to this space.
      *
-     * @param obj the PhysicsControl or Spatial with PhysicsControl to add
+     * @param obj the PhysicsControl, Spatial-with-PhysicsControl,
+     * PhysicsCollisionObject, or PhysicsJoint to add (not null, modified)
      */
     public void add(Object obj) {
         if (obj instanceof PhysicsControl) {
@@ -432,6 +537,11 @@ public class PhysicsSpace {
         }
     }
 
+    /**
+     * Add the specified collision object to this space.
+     *
+     * @param obj the PhysicsCollisionObject to add (not null, modified)
+     */
     public void addCollisionObject(PhysicsCollisionObject obj) {
         if (obj instanceof PhysicsGhostObject) {
             addGhostObject((PhysicsGhostObject) obj);
@@ -445,9 +555,9 @@ public class PhysicsSpace {
     }
 
     /**
-     * removes an object from the physics space
+     * Remove the specified object from this space.
      *
-     * @param obj the PhysicsControl or Spatial with PhysicsControl to remove
+     * @param obj the PhysicsCollisionObject to add, or null (modified)
      */
     public void remove(Object obj) {
         if (obj == null) return;
@@ -469,6 +579,11 @@ public class PhysicsSpace {
         }
     }
 
+    /**
+     * Remove the specified collision object from this space.
+     *
+     * @param obj the PhysicsControl or Spatial with PhysicsControl to remove
+     */
     public void removeCollisionObject(PhysicsCollisionObject obj) {
         if (obj instanceof PhysicsGhostObject) {
             removeGhostObject((PhysicsGhostObject) obj);
@@ -480,9 +595,10 @@ public class PhysicsSpace {
     }
 
     /**
-     * adds all physics controls and joints in the given spatial node to the physics space
-     * (e.g. after loading from disk) - recursive if node
-     * @param spatial the rootnode containing the physics objects
+     * Add all physics controls and joints in the specified subtree of the scene
+     * graph to this space (e.g. after loading from disk). Note: recursive!
+     *
+     * @param spatial the root of the subtree (not null)
      */
     public void addAll(Spatial spatial) {
         add(spatial);
@@ -510,9 +626,11 @@ public class PhysicsSpace {
     }
 
     /**
-     * Removes all physics controls and joints in the given spatial from the physics space
-     * (e.g. before saving to disk) - recursive if node
-     * @param spatial the rootnode containing the physics objects
+     * Remove all physics controls and joints in the specified subtree of the
+     * scene graph from the physics space (e.g. before saving to disk) Note:
+     * recursive!
+     *
+     * @param spatial the root of the subtree (not null)
      */
     public void removeAll(Spatial spatial) {
         if (spatial.getControl(RigidBodyControl.class) != null) {
@@ -611,6 +729,12 @@ public class PhysicsSpace {
 //        dynamicsWorld.removeCollisionObject(node.getObjectId());
     }
 
+    /**
+     * NOTE: When a rigid body is added, its gravity gets set to that of the
+     * physics space.
+     *
+     * @param node the body to add (not null, not already in the space)
+     */
     private void addRigidBody(PhysicsRigidBody node) {
         if (physicsBodies.containsKey(node.getObjectId())) {
             logger.log(Level.WARNING, "RigidBody {0} already exists in PhysicsSpace, cannot add.", node);
@@ -619,7 +743,7 @@ public class PhysicsSpace {
         physicsBodies.put(node.getObjectId(), node);
 
         //Workaround
-        //It seems that adding a Kinematic RigidBody to the dynamicWorld prevent it from being non kinematic again afterward.
+        //It seems that adding a Kinematic RigidBody to the dynamicWorld prevents it from being non-kinematic again afterward.
         //so we add it non kinematic, then set it kinematic again.
         boolean kinematic = false;
         if (node.isKinematic()) {
@@ -682,30 +806,64 @@ public class PhysicsSpace {
 //        dynamicsWorld.removeConstraint(joint.getObjectId());
     }
 
+    /**
+     * Copy the list of rigid bodies that have been added to this space and not
+     * yet removed.
+     *
+     * @return a new list (not null)
+     */
     public Collection<PhysicsRigidBody> getRigidBodyList() {
         return new LinkedList<PhysicsRigidBody>(physicsBodies.values());
     }
 
+    /**
+     * Copy the list of ghost objects that have been added to this space and not
+     * yet removed.
+     *
+     * @return a new list (not null)
+     */
     public Collection<PhysicsGhostObject> getGhostObjectList() {
         return new LinkedList<PhysicsGhostObject>(physicsGhostObjects.values());
     }
 
+    /**
+     * Copy the list of physics characters that have been added to this space
+     * and not yet removed.
+     *
+     * @return a new list (not null)
+     */
     public Collection<PhysicsCharacter> getCharacterList() {
         return new LinkedList<PhysicsCharacter>(physicsCharacters.values());
     }
 
+    /**
+     * Copy the list of physics joints that have been added to this space and
+     * not yet removed.
+     *
+     * @return a new list (not null)
+     */
     public Collection<PhysicsJoint> getJointList() {
         return new LinkedList<PhysicsJoint>(physicsJoints.values());
     }
 
+    /**
+     * Copy the list of physics vehicles that have been added to this space and
+     * not yet removed.
+     *
+     * @return a new list (not null)
+     */
     public Collection<PhysicsVehicle> getVehicleList() {
         return new LinkedList<PhysicsVehicle>(physicsVehicles.values());
     }
 
     /**
-     * Sets the gravity of the PhysicsSpace, set before adding physics objects!
+     * Alter the gravitational acceleration acting on newly-added bodies.
+     * <p>
+     * Whenever a rigid body is added to a space, the body's gravity gets set to
+     * that of the space. Thus it makes sense to set the space's vector before
+     * adding any bodies to the space.
      *
-     * @param gravity
+     * @param gravity the desired acceleration vector (not null, unaffected)
      */
     public void setGravity(Vector3f gravity) {
         this.gravity.set(gravity);
@@ -714,8 +872,17 @@ public class PhysicsSpace {
 
     private native void setGravity(long spaceId, Vector3f gravity);
 
-    //TODO: getGravity
+    /**
+     * copy of gravity-acceleration vector (default is 9.81 in the -Y direction,
+     * corresponding to Earth-normal in MKS units)
+     */
     private final Vector3f gravity = new Vector3f(0,-9.81f,0);
+    /**
+     * Copy the gravitational acceleration acting on newly-added bodies.
+     *
+     * @param gravity storage for the result (not null, modified)
+     * @return acceleration (in the vector provided)
+     */
     public Vector3f getGravity(Vector3f gravity) {
         return gravity.set(this.gravity);
     }
@@ -735,57 +902,89 @@ public class PhysicsSpace {
 //    }
 //
     /**
-     * Adds the specified listener to the physics tick listeners. The listeners
-     * are called on each physics step, which is not necessarily each frame but
-     * is determined by the accuracy of the physics space.
+     * Register the specified tick listener with this space.
+     * <p>
+     * Tick listeners are notified before and after each physics step. A physics
+     * step is not necessarily the same as a frame; it is more influenced by the
+     * accuracy of the physics space.
      *
-     * @param listener
+     * @see #setAccuracy(float)
+     *
+     * @param listener the listener to register (not null)
      */
     public void addTickListener(PhysicsTickListener listener) {
         tickListeners.add(listener);
     }
 
+    /**
+     * De-register the specified tick listener.
+     *
+     * @see #addTickListener(com.jme3.bullet.PhysicsTickListener)
+     * @param listener the listener to de-register (not null)
+     */
     public void removeTickListener(PhysicsTickListener listener) {
         tickListeners.remove(listener);
     }
 
     /**
-     * Adds a CollisionListener that will be informed about collision events
+     * Register the specified collision listener with this space.
+     * <p>
+     * Collision listeners are notified when collisions occur in the space.
      *
-     * @param listener the CollisionListener to add
+     * @param listener the listener to register (not null, alias created)
      */
     public void addCollisionListener(PhysicsCollisionListener listener) {
         collisionListeners.add(listener);
     }
 
     /**
-     * Removes a CollisionListener from the list
+     * De-register the specified collision listener.
      *
-     * @param listener the CollisionListener to remove
+     * @see
+     * #addCollisionListener(com.jme3.bullet.collision.PhysicsCollisionListener)
+     * @param listener the listener to de-register (not null)
      */
     public void removeCollisionListener(PhysicsCollisionListener listener) {
         collisionListeners.remove(listener);
     }
 
     /**
-     * Adds a listener for a specific collision group, such a listener can
-     * disable collisions when they happen.<br> There can be only one listener
-     * per collision group.
+     * Register the specified collision-group listener with the specified
+     * collision group of this space.
+     * <p>
+     * Such a listener can disable collisions when they occur. There can be only
+     * one listener per collision group per space.
      *
-     * @param listener
-     * @param collisionGroup
+     * @param listener the listener to register (not null)
+     * @param collisionGroup which group it should listen for (bit mask with
+     * exactly one bit set)
      */
     public void addCollisionGroupListener(PhysicsCollisionGroupListener listener, int collisionGroup) {
         collisionGroupListeners.put(collisionGroup, listener);
     }
 
+    /**
+     * De-register the specified collision-group listener.
+     *
+     * @see
+     * #addCollisionGroupListener(com.jme3.bullet.collision.PhysicsCollisionGroupListener,
+     * int)
+     * @param collisionGroup the group of the listener to de-register (bit mask
+     * with exactly one bit set)
+     */
     public void removeCollisionGroupListener(int collisionGroup) {
         collisionGroupListeners.remove(collisionGroup);
     }
     
     /**
-     * Performs a ray collision test and returns the results as a list of
-     * PhysicsRayTestResults ordered by it hitFraction (lower to higher)
+     * Perform a ray-collision test and return the results as a list of
+     * PhysicsRayTestResults sorted by ascending hitFraction.
+     *
+     * @param from the starting location (physics-space coordinates, not null,
+     * unaffected)
+     * @param to the ending location (in physics-space coordinates, not null,
+     * unaffected)
+     * @return a new list of results (not null)
      */
     public List rayTest(Vector3f from, Vector3f to) {
         List<PhysicsRayTestResult> results = new ArrayList<PhysicsRayTestResult>();
@@ -795,8 +994,14 @@ public class PhysicsSpace {
     }
     
     /**
-     * Performs a ray collision test and returns the results as a list of
-     * PhysicsRayTestResults without performing any sort operation
+     * Perform a ray-collision test and return the results as a list of
+     * PhysicsRayTestResults in arbitrary order.
+     *
+     * @param from the starting location (in physics-space coordinates, not
+     * null, unaffected)
+     * @param to the ending location (in physics-space coordinates, not null,
+     * unaffected)
+     * @return a new list of results (not null)
      */
     public List rayTestRaw(Vector3f from, Vector3f to) {
         List<PhysicsRayTestResult> results = new ArrayList<PhysicsRayTestResult>();
@@ -806,17 +1011,22 @@ public class PhysicsSpace {
     }
 
     /**
-     * Sets m_flags for raytest, see https://code.google.com/p/bullet/source/browse/trunk/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h
+     * Alters the m_flags used in ray tests. see
+     * https://code.google.com/p/bullet/source/browse/trunk/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h
      * for possible options. Defaults to using the faster, approximate raytest.
+     *
+     * @param flags the desired flags, ORed together (default=0x4)
      */
     public void SetRayTestFlags(int flags) {
         rayTestFlags = flags;
     }
 
     /**
-     * Gets m_flags for raytest, see https://code.google.com/p/bullet/source/browse/trunk/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h
+     * Reads m_flags used in ray tests. see
+     * https://code.google.com/p/bullet/source/browse/trunk/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h
      * for possible options.
-     * @return rayTestFlags
+     *
+     * @return which flags are used
      */
     public int GetRayTestFlags() {
         return rayTestFlags;
@@ -831,8 +1041,15 @@ public class PhysicsSpace {
     };
     
     /**
-     * Performs a ray collision test and returns the results as a list of
-     * PhysicsRayTestResults ordered by it hitFraction (lower to higher)
+     * Perform a ray-collision test and return the results as a list of
+     * PhysicsRayTestResults sorted by ascending hitFraction.
+     *
+     * @param from coordinates of the starting location (in physics space, not
+     * null, unaffected)
+     * @param to coordinates of the ending location (in physics space, not null,
+     * unaffected)
+     * @param results the list to hold results (not null, modified)
+     * @return results
      */
     public List<PhysicsRayTestResult> rayTest(Vector3f from, Vector3f to, List<PhysicsRayTestResult> results) {
         results.clear();
@@ -843,8 +1060,15 @@ public class PhysicsSpace {
     }
     
     /**
-     * Performs a ray collision test and returns the results as a list of
-     * PhysicsRayTestResults without performing any sort operation
+     * Perform a ray-collision test and return the results as a list of
+     * PhysicsRayTestResults in arbitrary order.
+     *
+     * @param from coordinates of the starting location (in physics space, not
+     * null, unaffected)
+     * @param to coordinates of the ending location (in physics space, not null,
+     * unaffected)
+     * @param results the list to hold results (not null, modified)
+     * @return results
      */
     public List<PhysicsRayTestResult> rayTestRaw(Vector3f from, Vector3f to, List<PhysicsRayTestResult> results) {
         results.clear();
@@ -874,11 +1098,18 @@ public class PhysicsSpace {
 
 
     /**
-     * Performs a sweep collision test and returns the results as a list of
-     * PhysicsSweepTestResults<br/> You have to use different Transforms for
-     * start and end (at least distance > 0.4f). SweepTest will not see a
-     * collision if it starts INSIDE an object and is moving AWAY from its
-     * center.
+     * Perform a sweep-collision test and return the results as a new list.
+     * <p>
+     * The starting and ending locations must be at least 0.4f physics-space
+     * units apart.
+     * <p>
+     * A sweep test will miss a collision if it starts inside an object and
+     * sweeps away from the object's center.
+     *
+     * @param shape the shape to sweep (not null)
+     * @param start the starting physics-space transform (not null)
+     * @param end the ending physics-space transform (not null)
+     * @return a new list of results
      */
     public List<PhysicsSweepTestResult> sweepTest(CollisionShape shape, Transform start, Transform end) {
         List results = new LinkedList();
@@ -886,17 +1117,41 @@ public class PhysicsSpace {
         return (List<PhysicsSweepTestResult>) results;
     }
 
+    /**
+     * Perform a sweep-collision test and store the results in an existing list.
+     * <p>
+     * The starting and ending locations must be at least 0.4f physics-space
+     * units apart.
+     * <p>
+     * A sweep test will miss a collision if it starts inside an object and
+     * sweeps away from the object's center.
+     *
+     * @param shape the shape to sweep (not null)
+     * @param start the starting physics-space transform (not null)
+     * @param end the ending physics-space transform (not null)
+     * @param results the list to hold results (not null, modified)
+     * @return results
+     */    
     public List<PhysicsSweepTestResult> sweepTest(CollisionShape shape, Transform start, Transform end, List<PhysicsSweepTestResult> results) {
         return sweepTest(shape, start, end, results, 0.0f);
     }
 
     public native void sweepTest_native(long shape, Transform from, Transform to, long physicsSpaceId, List<PhysicsSweepTestResult> results, float allowedCcdPenetration);
     /**
-     * Performs a sweep collision test and returns the results as a list of
-     * PhysicsSweepTestResults<br/> You have to use different Transforms for
-     * start and end (at least distance > allowedCcdPenetration). SweepTest will not see a
-     * collision if it starts INSIDE an object and is moving AWAY from its
-     * center.
+     * Perform a sweep-collision test and store the results in an existing list.
+     * <p>
+     * The starting and ending locations must be at least 0.4f physics-space
+     * units apart.
+     * <p>
+     * A sweep test will miss a collision if it starts inside an object and
+     * sweeps away from the object's center.
+     *
+     * @param shape the shape to sweep (not null)
+     * @param start the starting physics-space transform (not null)
+     * @param end the ending physics-space transform (not null)
+     * @param results the list to hold results (not null, modified)
+     * @param allowedCcdPenetration true&rarr;allow, false&rarr;disallow
+     * @return results
      */
     public List<PhysicsSweepTestResult> sweepTest(CollisionShape shape, Transform start, Transform end, List<PhysicsSweepTestResult> results, float allowedCcdPenetration ) {
         results.clear();
@@ -923,7 +1178,7 @@ public class PhysicsSpace {
     */
     
     /**
-     * destroys the current PhysicsSpace so that a new one can be created
+     * Destroy this space so that a new one can be instantiated.
      */
     public void destroy() {
         physicsBodies.clear();
@@ -942,59 +1197,87 @@ public class PhysicsSpace {
         return physicsSpaceId;
     }
 
+    /**
+     * Read the type of acceleration structure used.
+     *
+     * @return an enum value (not null)
+     */
     public BroadphaseType getBroadphaseType() {
         return broadphaseType;
     }
 
+    /**
+     * Alter the type of acceleration structure used.
+     * 
+     * @param broadphaseType the desired algorithm (not null)
+     */
     public void setBroadphaseType(BroadphaseType broadphaseType) {
         this.broadphaseType = broadphaseType;
     }
 
     /**
-     * Sets the maximum amount of extra steps that will be used to step the
-     * physics when the fps is below the physics fps. Doing this maintains
-     * determinism in physics. For example a maximum number of 2 can compensate
-     * for framerates as low as 30fps when the physics has the default accuracy
-     * of 60 fps. Note that setting this value too high can make the physics
-     * drive down its own fps in case it's overloaded.
+     * Alter the maximum number of physics steps per frame.
+     * <p>
+     * Extra physics steps help maintain determinism when the render fps drops
+     * below 1/accuracy. For example a value of 2 can compensate for frame rates
+     * as low as 30fps, assuming the physics has an accuracy of 1/60 sec.
+     * <p>
+     * Setting this value too high can depress the frame rate.
      *
-     * @param steps The maximum number of extra steps, default is 4.
+     * @param steps the desired maximum number of steps per frame (&ge;1,
+     * default=4)
      */
     public void setMaxSubSteps(int steps) {
         maxSubSteps = steps;
     }
 
     /**
-     * get the current accuracy of the physics computation
+     * Read the accuracy (time step) of the physics simulation.
      *
-     * @return the current accuracy
+     * @return the timestep (in seconds, &gt;0)
      */
     public float getAccuracy() {
         return accuracy;
     }
 
     /**
-     * sets the accuracy of the physics computation, default=1/60s<br>
+     * Alter the accuracy (time step) of the physics simulation.
+     * <p>
+     * In general, the smaller the time step, the more accurate (and
+     * compute-intensive) the simulation will be. Bullet works best with a
+     * timestep of no more than 1/60 second.
      *
-     * @param accuracy
+     * @param accuracy the desired time step (in seconds, &gt;0, default=1/60)
      */
     public void setAccuracy(float accuracy) {
         this.accuracy = accuracy;
     }
 
+    /**
+     * Access the minimum coordinate values for this space.
+     *
+     * @return the pre-existing vector
+     */
     public Vector3f getWorldMin() {
         return worldMin;
     }
 
     /**
-     * only applies for AXIS_SWEEP broadphase
+     * Alter the minimum coordinate values for this space. (only affects
+     * AXIS_SWEEP broadphase algorithms)
      *
-     * @param worldMin
+     * @param worldMin the desired minimum coordinate values (not null,
+     * unaffected)
      */
     public void setWorldMin(Vector3f worldMin) {
         this.worldMin.set(worldMin);
     }
 
+    /**
+     * Access the maximum coordinate values for this space.
+     *
+     * @return the pre-existing vector (not null)
+     */
     public Vector3f getWorldMax() {
         return worldMax;
     }
@@ -1009,11 +1292,11 @@ public class PhysicsSpace {
     }
 
     /**
-     * Set the number of iterations used by the contact solver.
-     * 
-     * The default is 10. Use 4 for low quality, 20 for high quality.
-     * 
-     * @param numIterations The number of iterations used by the contact & constraint solver.
+     * Alter the number of iterations used by the contact-and-constraint solver.
+     * <p>
+     * Use 4 for low quality, 20 for high quality.
+     *
+     * @param numIterations the desired number of iterations (&ge;1, default=10)
      */
     public void setSolverNumIterations(int numIterations) {
         this.solverNumIterations = numIterations;
@@ -1021,9 +1304,9 @@ public class PhysicsSpace {
     }
     
     /**
-     * Get the number of iterations used by the contact solver.
-     * 
-     * @return The number of iterations used by the contact & constraint solver.
+     * Read the number of iterations used by the contact-and-constraint solver.
+     *
+     * @return the number of iterations used
      */
     public int getSolverNumIterations() {
         return solverNumIterations;
@@ -1034,28 +1317,40 @@ public class PhysicsSpace {
     public static native void initNativePhysics();
 
     /**
-     * interface with Broadphase types
+     * Enumerate the available acceleration structures for broadphase collision
+     * detection.
      */
     public enum BroadphaseType {
 
         /**
-         * basic Broadphase
+         * btSimpleBroadphase: a brute-force reference implementation for
+         * debugging purposes
          */
         SIMPLE,
         /**
-         * better Broadphase, needs worldBounds , max Object number = 16384
+         * btAxisSweep3: uses incremental 3-D sweep and prune, requires world
+         * bounds, limited to 16_384 objects
          */
         AXIS_SWEEP_3,
         /**
-         * better Broadphase, needs worldBounds , max Object number = 65536
+         * bt32BitAxisSweep3: uses incremental 3-D sweep and prune, requires
+         * world bounds, limited to 65_536 objects
          */
         AXIS_SWEEP_3_32,
         /**
-         * Broadphase allowing quicker adding/removing of physics objects
+         * btDbvtBroadphase: uses a fast, dynamic bounding-volume hierarchy
+         * based on AABB tree to allow quicker addition/removal of physics
+         * objects
          */
         DBVT;
     }
 
+    /**
+     * Finalize this physics space just before it is destroyed. Should be
+     * invoked only by a subclass or by the garbage collector.
+     *
+     * @throws Throwable ignored by the garbage collector
+     */
     @Override
     protected void finalize() throws Throwable {
         super.finalize();

+ 202 - 9
jme3-bullet/src/main/java/com/jme3/bullet/collision/PhysicsCollisionEvent.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,21 +36,53 @@ import com.jme3.scene.Spatial;
 import java.util.EventObject;
 
 /**
- * A CollisionEvent stores all information about a collision in the PhysicsWorld.
- * Do not store this Object, as it will be reused after the collision() method has been called.
- * Get/reference all data you need in the collide method.
+ * An event that describes a collision in the physics world.
+ * <p>
+ * Do not retain this object, as it will be reused after the collision() method
+ * returns. Copy any data you need during the collide() method.
+ *
  * @author normenhansen
  */
 public class PhysicsCollisionEvent extends EventObject {
 
+    /**
+     * type value to indicate a new event
+     */
     public static final int TYPE_ADDED = 0;
+    /**
+     * type value to indicate an event that has been added to a PhysicsSpace
+     * queue
+     */
     public static final int TYPE_PROCESSED = 1;
+    /**
+     * type value to indicate a cleaned/destroyed event
+     */
     public static final int TYPE_DESTROYED = 2;
+    /**
+     * type value that indicates the event's status
+     */
     private int type;
+    /**
+     * 1st involved object
+     */
     private PhysicsCollisionObject nodeA;
+    /**
+     * 2nd involved object
+     */
     private PhysicsCollisionObject nodeB;
+    /**
+     * Bullet identifier of the btManifoldPoint
+     */
     private long manifoldPointObjectId = 0;
 
+    /**
+     * Instantiate a collision event.
+     *
+     * @param type event type (0=added/1=processed/2=destroyed)
+     * @param nodeA 1st involved object (alias created)
+     * @param nodeB 2nd involved object (alias created)
+     * @param manifoldPointObjectId Bullet identifier of the btManifoldPoint
+     */
     public PhysicsCollisionEvent(int type, PhysicsCollisionObject nodeA, PhysicsCollisionObject nodeB, long manifoldPointObjectId) {
         super(nodeA);
         this.type = type;
@@ -58,9 +90,9 @@ public class PhysicsCollisionEvent extends EventObject {
         this.nodeB = nodeB;
         this.manifoldPointObjectId = manifoldPointObjectId;
     }
-    
+
     /**
-     * used by event factory, called when event is destroyed
+     * Destroy this event.
      */
     public void clean() {
         source = null;
@@ -71,7 +103,12 @@ public class PhysicsCollisionEvent extends EventObject {
     }
 
     /**
-     * used by event factory, called when event reused
+     * Reuse this event.
+     *
+     * @param type event type (added/processed/destroyed)
+     * @param source 1st involved object (alias created)
+     * @param nodeB 2nd involved object (alias created)
+     * @param manifoldPointObjectId Bullet identifier
      */
     public void refactor(int type, PhysicsCollisionObject source, PhysicsCollisionObject nodeB, long manifoldPointObjectId) {
         this.source = source;
@@ -81,12 +118,19 @@ public class PhysicsCollisionEvent extends EventObject {
         this.manifoldPointObjectId = manifoldPointObjectId;
     }
 
+    /**
+     * Read the type of event.
+     *
+     * @return added/processed/destroyed
+     */
     public int getType() {
         return type;
     }
 
     /**
-     * @return A Spatial if the UserObject of the PhysicsCollisionObject is a Spatial
+     * Access the user object of collision object A, provided it's a Spatial.
+     *
+     * @return the pre-existing Spatial, or null if none
      */
     public Spatial getNodeA() {
         if (nodeA.getUserObject() instanceof Spatial) {
@@ -96,7 +140,9 @@ public class PhysicsCollisionEvent extends EventObject {
     }
 
     /**
-     * @return A Spatial if the UserObject of the PhysicsCollisionObject is a Spatial
+     * Access the user object of collision object B, provided it's a Spatial.
+     *
+     * @return the pre-existing Spatial, or null if none
      */
     public Spatial getNodeB() {
         if (nodeB.getUserObject() instanceof Spatial) {
@@ -105,139 +151,286 @@ public class PhysicsCollisionEvent extends EventObject {
         return null;
     }
 
+    /**
+     * Access collision object A.
+     *
+     * @return the pre-existing object (not null)
+     */
     public PhysicsCollisionObject getObjectA() {
         return nodeA;
     }
 
+    /**
+     * Access collision object B.
+     *
+     * @return the pre-existing object (not null)
+     */
     public PhysicsCollisionObject getObjectB() {
         return nodeB;
     }
 
+    /**
+     * Read the collision's applied impulse.
+     *
+     * @return impulse
+     */
     public float getAppliedImpulse() {
         return getAppliedImpulse(manifoldPointObjectId);
     }
     private native float getAppliedImpulse(long manifoldPointObjectId);
 
+    /**
+     * Read the collision's applied lateral impulse #1.
+     *
+     * @return impulse
+     */
     public float getAppliedImpulseLateral1() {
         return getAppliedImpulseLateral1(manifoldPointObjectId);
     }
     private native float getAppliedImpulseLateral1(long manifoldPointObjectId);
 
+    /**
+     * Read the collision's applied lateral impulse #2.
+     *
+     * @return impulse
+     */
     public float getAppliedImpulseLateral2() {
         return getAppliedImpulseLateral2(manifoldPointObjectId);
     }
     private native float getAppliedImpulseLateral2(long manifoldPointObjectId);
 
+    /**
+     * Read the collision's combined friction.
+     *
+     * @return friction
+     */
     public float getCombinedFriction() {
         return getCombinedFriction(manifoldPointObjectId);
     }
     private native float getCombinedFriction(long manifoldPointObjectId);
 
+    /**
+     * Read the collision's combined restitution.
+     *
+     * @return restitution
+     */
     public float getCombinedRestitution() {
         return getCombinedRestitution(manifoldPointObjectId);
     }
     private native float getCombinedRestitution(long manifoldPointObjectId);
 
+    /**
+     * Read the collision's distance #1.
+     *
+     * @return distance
+     */
     public float getDistance1() {
         return getDistance1(manifoldPointObjectId);
     }
     private native float getDistance1(long manifoldPointObjectId);
 
+    /**
+     * Read the collision's index 0.
+     *
+     * @return index
+     */
     public int getIndex0() {
         return getIndex0(manifoldPointObjectId);
     }
     private native int getIndex0(long manifoldPointObjectId);
 
+    /**
+     * Read the collision's index 1.
+     *
+     * @return index
+     */
     public int getIndex1() {
         return getIndex1(manifoldPointObjectId);
     }
     private native int getIndex1(long manifoldPointObjectId);
 
+    /**
+     * Copy the collision's lateral friction direction #1.
+     *
+     * @return a new vector (not null)
+     */
     public Vector3f getLateralFrictionDir1() {
         return getLateralFrictionDir1(new Vector3f());
     }
 
+    /**
+     * Copy the collision's lateral friction direction #1.
+     *
+     * @param lateralFrictionDir1 storage for the result (not null, modified)
+     * @return direction vector (not null)
+     */
     public Vector3f getLateralFrictionDir1(Vector3f lateralFrictionDir1) {
         getLateralFrictionDir1(manifoldPointObjectId, lateralFrictionDir1);
         return lateralFrictionDir1;
     }
     private native void getLateralFrictionDir1(long manifoldPointObjectId, Vector3f lateralFrictionDir1);
 
+    /**
+     * Copy the collision's lateral friction direction #2.
+     *
+     * @return a new vector
+     */
     public Vector3f getLateralFrictionDir2() {
         return getLateralFrictionDir2(new Vector3f());
     }
 
+    /**
+     * Copy the collision's lateral friction direction #2.
+     *
+     * @param lateralFrictionDir2 storage for the result (not null, modified)
+     * @return direction vector (not null)
+     */
     public Vector3f getLateralFrictionDir2(Vector3f lateralFrictionDir2) {
         getLateralFrictionDir2(manifoldPointObjectId, lateralFrictionDir2);
         return lateralFrictionDir2;
     }
     private native void getLateralFrictionDir2(long manifoldPointObjectId, Vector3f lateralFrictionDir2);
 
+    /**
+     * Test whether the collision's lateral friction is initialized.
+     *
+     * @return true if initialized, otherwise false
+     */
     public boolean isLateralFrictionInitialized() {
         return isLateralFrictionInitialized(manifoldPointObjectId);
     }
     private native boolean isLateralFrictionInitialized(long manifoldPointObjectId);
 
+    /**
+     * Read the collision's lifetime.
+     *
+     * @return lifetime
+     */
     public int getLifeTime() {
         return getLifeTime(manifoldPointObjectId);
     }
     private native int getLifeTime(long manifoldPointObjectId);
 
+    /**
+     * Copy the collision's location in the local coordinates of object A.
+     *
+     * @return a new location vector (in local coordinates, not null)
+     */
     public Vector3f getLocalPointA() {
         return getLocalPointA(new Vector3f());
     }
     
+    /**
+     * Copy the collision's location in the local coordinates of object A.
+     *
+     * @param localPointA storage for the result (not null, modified)
+     * @return a location vector (in local coordinates, not null)
+     */
     public Vector3f getLocalPointA(Vector3f localPointA) {
         getLocalPointA(manifoldPointObjectId, localPointA);
         return localPointA;
     }
     private native void getLocalPointA(long manifoldPointObjectId, Vector3f localPointA);
 
+    /**
+     * Copy the collision's location in the local coordinates of object B.
+     *
+     * @return a new location vector (in local coordinates, not null)
+     */
     public Vector3f getLocalPointB() {
         return getLocalPointB(new Vector3f());
     }
     
+    /**
+     * Copy the collision's location in the local coordinates of object B.
+     *
+     * @param localPointB storage for the result (not null, modified)
+     * @return a location vector (in local coordinates, not null)
+     */
     public Vector3f getLocalPointB(Vector3f localPointB) {
         getLocalPointB(manifoldPointObjectId, localPointB);
         return localPointB;
     }
     private native void getLocalPointB(long manifoldPointObjectId, Vector3f localPointB);
 
+    /**
+     * Copy the collision's normal on object B.
+     *
+     * @return a new normal vector (in physics-space coordinates, not null)
+     */
     public Vector3f getNormalWorldOnB() {
         return getNormalWorldOnB(new Vector3f());
     }
 
+    /**
+     * Copy the collision's normal on object B.
+     *
+     * @param normalWorldOnB storage for the result (not null, modified)
+     * @return a normal vector (in physics-space coordinates, not null)
+     */
     public Vector3f getNormalWorldOnB(Vector3f normalWorldOnB) {
         getNormalWorldOnB(manifoldPointObjectId, normalWorldOnB);
         return normalWorldOnB;
     }
     private native void getNormalWorldOnB(long manifoldPointObjectId, Vector3f normalWorldOnB);
 
+    /**
+     * Read part identifier 0.
+     *
+     * @return identifier
+     */
     public int getPartId0() {
         return getPartId0(manifoldPointObjectId);
     }
     private native int getPartId0(long manifoldPointObjectId);
 
+    /**
+     * Read part identifier 1.
+     *
+     * @return identifier
+     */
     public int getPartId1() {
         return getPartId1(manifoldPointObjectId);
     }
 
     private native int getPartId1(long manifoldPointObjectId);
 
+    /**
+     * Copy the collision's location.
+     *
+     * @return a new vector (in physics-space coordinates, not null)
+     */
     public Vector3f getPositionWorldOnA() {
         return getPositionWorldOnA(new Vector3f());
     }
 
+    /**
+     * Copy the collision's location.
+     *
+     * @param positionWorldOnA storage for the result (not null, modified)
+     * @return a location vector (in physics-space coordinates, not null)
+     */
     public Vector3f getPositionWorldOnA(Vector3f positionWorldOnA) {
         getPositionWorldOnA(manifoldPointObjectId, positionWorldOnA);
         return positionWorldOnA;
     }
     private native void getPositionWorldOnA(long manifoldPointObjectId, Vector3f positionWorldOnA);
 
+    /**
+     * Copy the collision's location.
+     *
+     * @return a new location vector (in physics-space coordinates, not null)
+     */
     public Vector3f getPositionWorldOnB() {
         return getPositionWorldOnB(new Vector3f());
     }
 
+    /**
+     * Copy the collision's location.
+     *
+     * @param positionWorldOnB storage for the result (not null, modified)
+     * @return a location vector (in physics-space coordinates, not null)
+     */
     public Vector3f getPositionWorldOnB(Vector3f positionWorldOnB) {
         getPositionWorldOnB(manifoldPointObjectId, positionWorldOnB);
         return positionWorldOnB;

+ 10 - 0
jme3-bullet/src/main/java/com/jme3/bullet/collision/PhysicsCollisionEventFactory.java

@@ -41,6 +41,11 @@ public class PhysicsCollisionEventFactory {
 
     private ConcurrentLinkedQueue<PhysicsCollisionEvent> eventBuffer = new ConcurrentLinkedQueue<PhysicsCollisionEvent>();
 
+    /**
+     * Obtain an unused event.
+     * 
+     * @return an event (not null)
+     */
     public PhysicsCollisionEvent getEvent(int type, PhysicsCollisionObject source, PhysicsCollisionObject nodeB, long manifoldPointObjectId) {
         PhysicsCollisionEvent event = eventBuffer.poll();
         if (event == null) {
@@ -51,6 +56,11 @@ public class PhysicsCollisionEventFactory {
         return event;
     }
 
+    /**
+     * Recycle the specified event.
+     * 
+     * @param event 
+     */
     public void recycle(PhysicsCollisionEvent event) {
         event.clean();
         eventBuffer.add(event);

+ 157 - 28
jme3-bullet/src/main/java/com/jme3/bullet/collision/PhysicsCollisionObject.java

@@ -38,67 +38,147 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * Base class for collision objects (PhysicsRigidBody, PhysicsGhostObject)
+ * The abstract base class for collision objects based on Bullet's
+ * btCollisionObject.
+ * <p>
+ * Collision objects include PhysicsCharacter, PhysicsRigidBody, and
+ * PhysicsGhostObject.
+ *
  * @author normenhansen
  */
 public abstract class PhysicsCollisionObject implements Savable {
 
+    /**
+     * Unique identifier of the btCollisionObject. Constructors are responsible
+     * for setting this to a non-zero value. The id might change if the object
+     * gets rebuilt.
+     */
     protected long objectId = 0;
+    /**
+     * shape associated with this object (not null)
+     */
     protected CollisionShape collisionShape;
+    /**
+     * collideWithGroups bitmask that represents "no groups"
+     */
     public static final int COLLISION_GROUP_NONE = 0x00000000;
+    /**
+     * collisionGroup/collideWithGroups bitmask that represents group #1
+     */
     public static final int COLLISION_GROUP_01 = 0x00000001;
+    /**
+     * collisionGroup/collideWithGroups bitmask that represents group #2
+     */
     public static final int COLLISION_GROUP_02 = 0x00000002;
+    /**
+     * collisionGroup/collideWithGroups bitmask that represents group #3
+     */
     public static final int COLLISION_GROUP_03 = 0x00000004;
+    /**
+     * collisionGroup/collideWithGroups bitmask that represents group #4
+     */
     public static final int COLLISION_GROUP_04 = 0x00000008;
+    /**
+     * collisionGroup/collideWithGroups bitmask that represents group #5
+     */
     public static final int COLLISION_GROUP_05 = 0x00000010;
+    /**
+     * collisionGroup/collideWithGroups bitmask that represents group #6
+     */
     public static final int COLLISION_GROUP_06 = 0x00000020;
+    /**
+     * collisionGroup/collideWithGroups bitmask that represents group #7
+     */
     public static final int COLLISION_GROUP_07 = 0x00000040;
+    /**
+     * collisionGroup/collideWithGroups bitmask that represents group #8
+     */
     public static final int COLLISION_GROUP_08 = 0x00000080;
+    /**
+     * collisionGroup/collideWithGroups bitmask that represents group #9
+     */
     public static final int COLLISION_GROUP_09 = 0x00000100;
+    /**
+     * collisionGroup/collideWithGroups bitmask that represents group #10
+     */
     public static final int COLLISION_GROUP_10 = 0x00000200;
+    /**
+     * collisionGroup/collideWithGroups bitmask that represents group #11
+     */
     public static final int COLLISION_GROUP_11 = 0x00000400;
+    /**
+     * collisionGroup/collideWithGroups bitmask that represents group #12
+     */
     public static final int COLLISION_GROUP_12 = 0x00000800;
+    /**
+     * collisionGroup/collideWithGroups bitmask that represents group #13
+     */
     public static final int COLLISION_GROUP_13 = 0x00001000;
+    /**
+     * collisionGroup/collideWithGroups bitmask that represents group #14
+     */
     public static final int COLLISION_GROUP_14 = 0x00002000;
+    /**
+     * collisionGroup/collideWithGroups bitmask that represents group #15
+     */
     public static final int COLLISION_GROUP_15 = 0x00004000;
+    /**
+     * collisionGroup/collideWithGroups bitmask that represents group #16
+     */
     public static final int COLLISION_GROUP_16 = 0x00008000;
+    /**
+     * collision group to which this physics object belongs (default=group #1)
+     */
     protected int collisionGroup = 0x00000001;
+    /**
+     * collision groups with which this object can collide (default=only group
+     * #1)
+     */
     protected int collisionGroupsMask = 0x00000001;
     private Object userObject;
 
     /**
-     * Sets a CollisionShape to this physics object, note that the object should
-     * not be in the physics space when adding a new collision shape as it is rebuilt
-     * on the physics side.
-     * @param collisionShape the CollisionShape to set
+     * Apply the specified CollisionShape to this object. Note that the object
+     * should not be in any physics space while changing shape; the object gets
+     * rebuilt on the physics side.
+     *
+     * @param collisionShape the shape to apply (not null, alias created)
      */
     public void setCollisionShape(CollisionShape collisionShape) {
         this.collisionShape = collisionShape;
     }
 
     /**
-     * @return the CollisionShape of this PhysicsNode, to be able to reuse it with
-     * other physics nodes (increases performance)
+     * Access the shape of this physics object.
+     *
+     * @return the pre-existing instance, which can then be applied to other
+     * physics objects (increases performance)
      */
     public CollisionShape getCollisionShape() {
         return collisionShape;
     }
 
     /**
-     * Returns the collision group for this collision shape
-     * @return The collision group
+     * Read the collision group for this physics object.
+     *
+     * @return the collision group (bit mask with exactly one bit set)
      */
     public int getCollisionGroup() {
         return collisionGroup;
     }
 
     /**
-     * Sets the collision group number for this physics object. <br>
-     * The groups are integer bit masks and some pre-made variables are available in CollisionObject.
-     * All physics objects are by default in COLLISION_GROUP_01.<br>
-     * Two object will collide when <b>one</b> of the parties has the
-     * collisionGroup of the other in its collideWithGroups set.
-     * @param collisionGroup the collisionGroup to set
+     * Alter the collision group for this physics object.
+     * <p>
+     * Groups are represented by integer bit masks with exactly 1 bit set.
+     * Pre-made variables are available in PhysicsCollisionObject. By default,
+     * physics objects are in COLLISION_GROUP_01.
+     * <p>
+     * Two objects can collide only if one of them has the collisionGroup of the
+     * other in its collideWithGroups set.
+     *
+     * @param collisionGroup the collisionGroup to apply (bit mask with exactly
+     * 1 bit set)
      */
     public void setCollisionGroup(int collisionGroup) {
         this.collisionGroup = collisionGroup;
@@ -108,10 +188,12 @@ public abstract class PhysicsCollisionObject implements Savable {
     }
 
     /**
-     * Add a group that this object will collide with.<br>
-     * Two object will collide when <b>one</b> of the parties has the
-     * collisionGroup of the other in its collideWithGroups set.<br>
-     * @param collisionGroup
+     * Add collision groups to the set with which this object can collide.
+     *
+     * Two objects can collide only if one of them has the collisionGroup of the
+     * other in its collideWithGroups set.
+     *
+     * @param collisionGroup groups to add (bit mask)
      */
     public void addCollideWithGroup(int collisionGroup) {
         this.collisionGroupsMask = this.collisionGroupsMask | collisionGroup;
@@ -121,8 +203,9 @@ public abstract class PhysicsCollisionObject implements Savable {
     }
 
     /**
-     * Remove a group from the list this object collides with.
-     * @param collisionGroup
+     * Remove collision groups from the set with which this object can collide.
+     *
+     * @param collisionGroup groups to remove, ORed together (bit mask)
      */
     public void removeCollideWithGroup(int collisionGroup) {
         this.collisionGroupsMask = this.collisionGroupsMask & ~collisionGroup;
@@ -132,8 +215,9 @@ public abstract class PhysicsCollisionObject implements Savable {
     }
 
     /**
-     * Directly set the bitmask for collision groups that this object collides with.
-     * @param collisionGroups
+     * Directly alter the collision groups with which this object can collide.
+     *
+     * @param collisionGroups desired groups, ORed together (bit mask)
      */
     public void setCollideWithGroups(int collisionGroups) {
         this.collisionGroupsMask = collisionGroups;
@@ -143,13 +227,17 @@ public abstract class PhysicsCollisionObject implements Savable {
     }
 
     /**
-     * Gets the bitmask of collision groups that this object collides with.
-     * @return Collision groups mask
+     * Read the set of collision groups with which this object can collide.
+     *
+     * @return bit mask
      */
     public int getCollideWithGroups() {
         return collisionGroupsMask;
     }
 
+    /**
+     * Initialize the user pointer and collision-group information of this object.
+     */
     protected void initUserPointer() {
         Logger.getLogger(this.getClass().getName()).log(Level.FINE, "initUserPointer() objectId = {0}", Long.toHexString(objectId));
         initUserPointer(objectId, collisionGroup, collisionGroupsMask);
@@ -157,27 +245,51 @@ public abstract class PhysicsCollisionObject implements Savable {
     native void initUserPointer(long objectId, int group, int groups);
 
     /**
-     * @return the userObject
+     * Access the user object associated with this collision object.
+     *
+     * @return the pre-existing instance, or null if none
      */
     public Object getUserObject() {
         return userObject;
     }
 
     /**
-     * @param userObject the userObject to set
+     * Associate a user object (such as a Spatial) with this collision object.
+     *
+     * @param userObject the object to associate with this collision object
+     * (alias created, may be null)
      */
     public void setUserObject(Object userObject) {
         this.userObject = userObject;
     }
     
-    public long getObjectId(){
+    /**
+     * Read the id of the btCollisionObject.
+     *
+     * @return the unique identifier (not zero)
+     */
+     public long getObjectId(){
         return objectId;
     }
     
+    /**
+     * Attach the identified btCollisionShape to the identified
+     * btCollisionObject. Native method.
+     *
+     * @param objectId the unique identifier of the btCollisionObject (not zero)
+     * @param collisionShapeId the unique identifier of the btCollisionShape
+     * (not zero)
+     */
     protected native void attachCollisionShape(long objectId, long collisionShapeId);
     native void setCollisionGroup(long objectId, int collisionGroup);
     native void setCollideWithGroups(long objectId, int collisionGroups);
 
+    /**
+     * Serialize this object, for example when saving to a J3O file.
+     *
+     * @param e exporter (not null)
+     * @throws IOException from exporter
+     */
     @Override
     public void write(JmeExporter e) throws IOException {
         OutputCapsule capsule = e.getCapsule(this);
@@ -186,6 +298,12 @@ public abstract class PhysicsCollisionObject implements Savable {
         capsule.write(collisionShape, "collisionShape", null);
     }
 
+    /**
+     * De-serialize this object, for example when loading from a J3O file.
+     *
+     * @param e importer (not null)
+     * @throws IOException from importer
+     */
     @Override
     public void read(JmeImporter e) throws IOException {
         InputCapsule capsule = e.getCapsule(this);
@@ -195,6 +313,12 @@ public abstract class PhysicsCollisionObject implements Savable {
         collisionShape = shape;
     }
 
+    /**
+     * Finalize this collision object just before it is destroyed. Should be
+     * invoked only by a subclass or by the garbage collector.
+     *
+     * @throws Throwable ignored by the garbage collector
+     */
     @Override
     protected void finalize() throws Throwable {
         super.finalize();
@@ -202,5 +326,10 @@ public abstract class PhysicsCollisionObject implements Savable {
         finalizeNative(objectId);
     }
 
+    /**
+     * Finalize the identified btCollisionObject. Native method.
+     *
+     * @param objectId the unique identifier of the btCollisionObject (not zero)
+     */
     protected native void finalizeNative(long objectId);
 }

+ 29 - 9
jme3-bullet/src/main/java/com/jme3/bullet/collision/PhysicsRayTestResult.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,47 +34,67 @@ package com.jme3.bullet.collision;
 import com.jme3.math.Vector3f;
 
 /**
- * Contains the results of a PhysicsSpace rayTest
- *  bulletAppState.getPhysicsSpace().rayTest(new Vector3f(0,1000,0),new Vector3f(0,-1000,0));
-    javap -s java.util.List
+ * Represent the results of a Bullet ray test.
+ *
  * @author Empire-Phoenix,normenhansen
  */
 public class PhysicsRayTestResult {
 
+    /**
+     * collision object that was hit
+     */
     private PhysicsCollisionObject collisionObject;
+    /**
+     * normal vector at the point of contact
+     */
     private Vector3f hitNormalLocal;
+    /**
+     * fraction of the ray's total length (from=0, to=1, &ge;0, &le;1)
+     */
     private float hitFraction;
+    /**
+     * true&rarr;need to transform normal into world space
+     */
     private boolean normalInWorldSpace = true;
 
     /**
-     * allocated by native code only
+     * A private constructor to inhibit instantiation of this class by Java.
+     * These results are instantiated exclusively by native code.
      */
     private PhysicsRayTestResult() {
     }
 
     /**
-     * @return the collisionObject
+     * Access the collision object that was hit.
+     *
+     * @return the pre-existing instance
      */
     public PhysicsCollisionObject getCollisionObject() {
         return collisionObject;
     }
 
     /**
-     * @return the hitNormalLocal
+     * Access the normal vector at the point of contact.
+     *
+     * @return the pre-existing vector (not null)
      */
     public Vector3f getHitNormalLocal() {
         return hitNormalLocal;
     }
 
     /**
-     * @return the hitFraction
+     * Read the fraction of the ray's total length.
+     *
+     * @return fraction (from=0, to=1, &ge;0, &le;1)
      */
     public float getHitFraction() {
         return hitFraction;
     }
 
     /**
-     * @return the normalInWorldSpace
+     * Test whether the normal is in world space.
+     *
+     * @return true if in world space, otherwise false
      */
     public boolean isNormalInWorldSpace() {
         return normalInWorldSpace;

+ 34 - 5
jme3-bullet/src/main/java/com/jme3/bullet/collision/PhysicsSweepTestResult.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,13 +35,26 @@ import com.jme3.math.Vector3f;
 
 /**
  * Contains the results of a PhysicsSpace rayTest
+ *
  * @author normenhansen
  */
 public class PhysicsSweepTestResult {
 
+    /**
+     * collision object that was hit
+     */
     private PhysicsCollisionObject collisionObject;
+    /**
+     * normal vector at the point of contact
+     */
     private Vector3f hitNormalLocal;
+    /**
+     * fraction of the way between the transforms (from=0, to=1, &ge;0, &le;1)
+     */
     private float hitFraction;
+    /**
+     * true&rarr;need to transform normal into world space
+     */
     private boolean normalInWorldSpace;
 
     public PhysicsSweepTestResult() {
@@ -55,33 +68,49 @@ public class PhysicsSweepTestResult {
     }
 
     /**
-     * @return the collisionObject
+     * Access the collision object that was hit.
+     *
+     * @return the pre-existing instance
      */
     public PhysicsCollisionObject getCollisionObject() {
         return collisionObject;
     }
 
     /**
-     * @return the hitNormalLocal
+     * Access the normal vector at the point of contact.
+     *
+     * @return the pre-existing vector (not null)
      */
     public Vector3f getHitNormalLocal() {
         return hitNormalLocal;
     }
 
     /**
-     * @return the hitFraction
+     * Read the hit fraction.
+     *
+     * @return fraction (from=0, to=1, &ge;0, &le;1)
      */
     public float getHitFraction() {
         return hitFraction;
     }
 
     /**
-     * @return the normalInWorldSpace
+     * Test whether the normal is in world space.
+     *
+     * @return true if in world space, otherwise false
      */
     public boolean isNormalInWorldSpace() {
         return normalInWorldSpace;
     }
 
+    /**
+     * Fill in the fields of this result.
+     * 
+     * @param collisionObject
+     * @param hitNormalLocal
+     * @param hitFraction
+     * @param normalInWorldSpace 
+     */
     public void fill(PhysicsCollisionObject collisionObject, Vector3f hitNormalLocal, float hitFraction, boolean normalInWorldSpace) {
         this.collisionObject = collisionObject;
         this.hitNormalLocal = hitNormalLocal;

+ 36 - 5
jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/BoxCollisionShape.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -41,35 +41,63 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * Basic box collision shape
+ * A rectangular-solid collision shape based on Bullet's btBoxShape.
+ *
  * @author normenhansen
  */
 public class BoxCollisionShape extends CollisionShape {
 
+    /**
+     * copy of half-extents of the box on each local axis (not null, no negative
+     * component)
+     */
     private Vector3f halfExtents;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public BoxCollisionShape() {
     }
 
     /**
-     * creates a collision box from the given halfExtents
-     * @param halfExtents the halfExtents of the CollisionBox
+     * Instantiate a box shape with the specified half extents.
+     *
+     * @param halfExtents the desired half extents (not null, no negative
+     * component, alias created)
      */
     public BoxCollisionShape(Vector3f halfExtents) {
         this.halfExtents = halfExtents;
         createShape();
     }
 
+    /**
+     * Access the half extents.
+     *
+     * @return the pre-existing instance (not null, no negative component)
+     */
     public final Vector3f getHalfExtents() {
         return halfExtents;
     }
-    
+
+    /**
+     * Serialize this shape, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
         OutputCapsule capsule = ex.getCapsule(this);
         capsule.write(halfExtents, "halfExtents", new Vector3f(1, 1, 1));
     }
 
+    /**
+     * De-serialize this shape, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     public void read(JmeImporter im) throws IOException {
         super.read(im);
         InputCapsule capsule = im.getCapsule(this);
@@ -78,6 +106,9 @@ public class BoxCollisionShape extends CollisionShape {
         createShape();
     }
 
+    /**
+     * Instantiate the configured shape in Bullet.
+     */
     protected void createShape() {
         objectId = createShape(halfExtents);
         Logger.getLogger(this.getClass().getName()).log(Level.FINE, "Created Shape {0}", Long.toHexString(objectId));

+ 64 - 12
jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/CapsuleCollisionShape.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -41,20 +41,37 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * Basic capsule collision shape
+ * A capsule collision shape based on Bullet's btCapsuleShapeX, btCapsuleShape,
+ * or btCapsuleShapeZ.
+ *
  * @author normenhansen
  */
 public class CapsuleCollisionShape extends CollisionShape{
-    protected float radius,height;
-    protected int axis;
+    /**
+     * copy of height of the cylindrical portion (&ge;0)
+     */
+    private float height;
+    /**
+     * copy of radius (&ge;0)
+     */
+    private float radius;
+    /**
+     * copy of main (height) axis (0&rarr;X, 1&rarr;Y, 2&rarr;Z)
+     */
+    private int axis;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public CapsuleCollisionShape() {
     }
 
     /**
-     * creates a new CapsuleCollisionShape with the given radius and height
-     * @param radius the radius of the capsule
-     * @param height the height of the capsule
+     * Instantiate a Y-axis capsule shape with the specified radius and height.
+     *
+     * @param radius the desired radius (&ge;0)
+     * @param height the desired height (of the cylindrical portion) (&ge;0)
      */
     public CapsuleCollisionShape(float radius, float height) {
         this.radius=radius;
@@ -64,10 +81,11 @@ public class CapsuleCollisionShape extends CollisionShape{
     }
 
     /**
-     * creates a capsule shape around the given axis (0=X,1=Y,2=Z)
-     * @param radius
-     * @param height
-     * @param axis
+     * Instantiate a capsule shape around the specified main (height) axis.
+     *
+     * @param radius the desired radius (&ge;0)
+     * @param height the desired height (of the cylindrical portion) (&ge;0)
+     * @param axis which local axis: 0&rarr;X, 1&rarr;Y, 2&rarr;Z
      */
     public CapsuleCollisionShape(float radius, float height, int axis) {
         this.radius=radius;
@@ -76,20 +94,39 @@ public class CapsuleCollisionShape extends CollisionShape{
         createShape();
     }
 
+    /**
+     * Read the radius of the capsule.
+     *
+     * @return radius (&ge;0)
+     */
     public float getRadius() {
         return radius;
     }
 
+    /**
+     * Read the height (of the cylindrical portion) of the capsule.
+     *
+     * @return height (&ge;0)
+     */
     public float getHeight() {
         return height;
     }
 
+    /**
+     * Determine the main (height) axis of the capsule.
+     *
+     * @return 0 for local X, 1 for local Y, or 2 for local Z
+     */
     public int getAxis() {
         return axis;
     }
 
     /**
-     * WARNING - CompoundCollisionShape scaling has no effect.
+     * Alter the scaling factors of this shape. Scaling is disabled
+     * for capsule shapes.
+     *
+     * @param scale the desired scaling factor for each local axis (not null, no
+     * negative component, unaffected, default=1,1,1)
      */
     @Override
     public void setScale(Vector3f scale) {
@@ -98,6 +135,12 @@ public class CapsuleCollisionShape extends CollisionShape{
         }
     }
 
+    /**
+     * Serialize this shape, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
         OutputCapsule capsule = ex.getCapsule(this);
@@ -106,6 +149,12 @@ public class CapsuleCollisionShape extends CollisionShape{
         capsule.write(axis, "axis", 1);
     }
 
+    /**
+     * De-serialize this shape, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     public void read(JmeImporter im) throws IOException {
         super.read(im);
         InputCapsule capsule = im.getCapsule(this);
@@ -115,6 +164,9 @@ public class CapsuleCollisionShape extends CollisionShape{
         createShape();
     }
 
+    /**
+     * Instantiate the configured shape in Bullet.
+     */
     protected void createShape(){
         objectId = createShape(axis, radius, height);
         Logger.getLogger(this.getClass().getName()).log(Level.FINE, "Created Shape {0}", Long.toHexString(objectId));

+ 75 - 6
jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/CollisionShape.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,15 +38,32 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * This Object holds information about a jbullet CollisionShape to be able to reuse
- * CollisionShapes (as suggested in bullet manuals)
- * TODO: add static methods to create shapes from nodes (like jbullet-jme constructor)
+ * The abstract base class for collision shapes based on Bullet's
+ * btCollisionShape.
+ * <p>
+ * Collision shapes include BoxCollisionShape and CapsuleCollisionShape. As
+ * suggested in the Bullet manual, a single collision shape can be shared among
+ * multiple collision objects.
+ *
  * @author normenhansen
  */
 public abstract class CollisionShape implements Savable {
 
+    /**
+     * unique identifier of the Bullet shape
+     * <p>
+     * Constructors are responsible for setting this to a non-zero value. After
+     * that, the id never changes.
+     */
     protected long objectId = 0;
+    /**
+     * copy of scaling factors: one for each local axis (default=1,1,1)
+     */
     protected Vector3f scale = new Vector3f(1, 1, 1);
+    /**
+     * copy of collision margin (in physics-space units, &gt;0,
+     * default=0)
+     */
     protected float margin = 0.0f;
 
     public CollisionShape() {
@@ -70,7 +87,9 @@ public abstract class CollisionShape implements Savable {
 //    private native void calculateLocalInertia(long objectId, long shapeId, float mass);
 
     /**
-     * used internally
+     * Read the id of the Bullet shape.
+     *
+     * @return the unique identifier (not zero)
      */
     public long getObjectId() {
         return objectId;
@@ -83,21 +102,52 @@ public abstract class CollisionShape implements Savable {
         this.objectId = id;
     }
 
+    /**
+     * Alter the scaling factors of this shape. CAUTION: Not all shapes can be
+     * scaled.
+     * <p>
+     * Note that if the shape is shared (between collision objects and/or
+     * compound shapes) changes can have unintended consequences.
+     *
+     * @param scale the desired scaling factor for each local axis (not null, no
+     * negative component, unaffected, default=1,1,1)
+     */
     public void setScale(Vector3f scale) {
         this.scale.set(scale);
         setLocalScaling(objectId, scale);
     }
-    
+    /**
+     * Access the scaling factors.
+     *
+     * @return the pre-existing vector (not null)
+     */
     public Vector3f getScale() {
         return scale;
     }
 
+    /**
+     * Read the collision margin for this shape.
+     *
+     * @return the margin distance (in physics-space units, &gt;0)
+     */
     public float getMargin() {
         return getMargin(objectId);
     }
     
     private native float getMargin(long objectId);
 
+    /**
+     * Alter the collision margin for this shape. CAUTION: Margin is applied
+     * differently, depending on the type of shape. Generally the collision
+     * margin expands the object, creating a gap. Don't set the collision margin
+     * to zero.
+     * <p>
+     * Note that if the shape is shared (between collision objects and/or
+     * compound shapes) changes can have unintended consequences.
+     *
+     * @param margin the desired margin distance (in physics-space units, &gt;0,
+     * default=0)
+     */
     public void setMargin(float margin) {
         setMargin(objectId, margin);
         this.margin = margin;
@@ -107,18 +157,37 @@ public abstract class CollisionShape implements Savable {
     
     private native void setMargin(long objectId, float margin);
 
+    /**
+     * Serialize this shape, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     public void write(JmeExporter ex) throws IOException {
         OutputCapsule capsule = ex.getCapsule(this);
         capsule.write(scale, "scale", new Vector3f(1, 1, 1));
         capsule.write(getMargin(), "margin", 0.0f);
     }
 
+    /**
+     * De-serialize this shape, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
+    @Override
     public void read(JmeImporter im) throws IOException {
         InputCapsule capsule = im.getCapsule(this);
         this.scale = (Vector3f) capsule.readSavable("scale", new Vector3f(1, 1, 1));
         this.margin = capsule.readFloat("margin", 0.0f);
     }
 
+    /**
+     * Finalize this shape just before it is destroyed. Should be invoked only
+     * by a subclass or by the garbage collector.
+     *
+     * @throws Throwable ignored by the garbage collector
+     */
     @Override
     protected void finalize() throws Throwable {
         super.finalize();

+ 44 - 11
jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/CompoundCollisionShape.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -46,23 +46,33 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * A CompoundCollisionShape allows combining multiple base shapes
- * to generate a more sophisticated shape.
+ * A collision shape formed by combining convex child shapes, based on Bullet's
+ * btCompoundShape.
+ *
  * @author normenhansen
  */
 public class CompoundCollisionShape extends CollisionShape {
 
+    /**
+     * children of this shape
+     */
     protected ArrayList<ChildCollisionShape> children = new ArrayList<ChildCollisionShape>();
 
+    /**
+     * Instantiate an empty compound shape (with no children).
+     */
     public CompoundCollisionShape() {
         objectId = createShape();//new CompoundShape();
         Logger.getLogger(this.getClass().getName()).log(Level.FINE, "Created Shape {0}", Long.toHexString(objectId));
     }
 
     /**
-     * adds a child shape at the given local translation
-     * @param shape the child shape to add
-     * @param location the local location of the child shape
+     * Add a child shape with the specified local translation.
+     *
+     * @param shape the child shape to add (not null, not a compound shape,
+     * alias created)
+     * @param location the local coordinates of the child shape's center (not
+     * null, unaffected)
      */
     public void addChildShape(CollisionShape shape, Vector3f location) {
 //        Transform transA = new Transform(Converter.convert(new Matrix3f()));
@@ -73,9 +83,14 @@ public class CompoundCollisionShape extends CollisionShape {
     }
 
     /**
-     * adds a child shape at the given local translation
-     * @param shape the child shape to add
-     * @param location the local location of the child shape
+     * Add a child shape with the specified local translation and orientation.
+     *
+     * @param shape the child shape to add (not null, not a compound shape,
+     * alias created)
+     * @param location the local coordinates of the child shape's center (not
+     * null, unaffected)
+     * @param rotation the local orientation of the child shape (not null,
+     * unaffected)
      */
     public void addChildShape(CollisionShape shape, Vector3f location, Matrix3f rotation) {
         if(shape instanceof CompoundCollisionShape){
@@ -101,8 +116,9 @@ public class CompoundCollisionShape extends CollisionShape {
     }
 
     /**
-     * removes a child shape
-     * @param shape the child shape to remove
+     * Remove a child from this shape.
+     *
+     * @param shape the child shape to remove (not null)
      */
     public void removeChildShape(CollisionShape shape) {
         removeChildShape(objectId, shape.getObjectId());
@@ -115,6 +131,11 @@ public class CompoundCollisionShape extends CollisionShape {
         }
     }
 
+    /**
+     * Access the list of children.
+     *
+     * @return the pre-existing list (not null)
+     */
     public List<ChildCollisionShape> getChildren() {
         return children;
     }
@@ -125,12 +146,24 @@ public class CompoundCollisionShape extends CollisionShape {
     
     private native long removeChildShape(long objectId, long childId);
     
+    /**
+     * Serialize this shape, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
         OutputCapsule capsule = ex.getCapsule(this);
         capsule.writeSavableArrayList(children, "children", new ArrayList<ChildCollisionShape>());
     }
 
+    /**
+     * De-serialize this shape, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     public void read(JmeImporter im) throws IOException {
         super.read(im);
         InputCapsule capsule = im.getCapsule(this);

+ 55 - 2
jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/ConeCollisionShape.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -41,18 +41,40 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
+ * A conical collision shape based on Bullet's btConeShapeX, btConeShape, or
+ * btConeShapeZ.
  *
  * @author normenhansen
  */
 public class ConeCollisionShape extends CollisionShape {
 
+    /**
+     * copy of radius (&ge;0)
+     */
     protected float radius;
+    /**
+     * copy of height (&ge;0)
+     */
     protected float height;
+    /**
+     * copy of main (height) axis (0&rarr;X, 1&rarr;Y, 2&rarr;Z)
+     */
     protected int axis;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public ConeCollisionShape() {
     }
 
+    /**
+     * Instantiate a cone shape around the specified main (height) axis.
+     *
+     * @param radius the desired radius (&ge;0)
+     * @param height the desired height (&ge;0)
+     * @param axis which local axis: 0&rarr;X, 1&rarr;Y, 2&rarr;Z
+     */
     public ConeCollisionShape(float radius, float height, int axis) {
         this.radius = radius;
         this.height = height;
@@ -60,6 +82,12 @@ public class ConeCollisionShape extends CollisionShape {
         createShape();
     }
 
+    /**
+     * Instantiate a cone shape oriented along the Y axis.
+     *
+     * @param radius the desired radius (&ge;0)
+     * @param height the desired height (&ge;0)
+     */
     public ConeCollisionShape(float radius, float height) {
         this.radius = radius;
         this.height = height;
@@ -67,14 +95,30 @@ public class ConeCollisionShape extends CollisionShape {
         createShape();
     }
 
+    /**
+     * Read the radius of the cone.
+     *
+     * @return radius (&ge;0)
+     */
     public float getRadius() {
         return radius;
     }
-    
+
+    /**
+     * Read the height of the cone.
+     *
+     * @return height (&ge;0)
+     */
     public float getHeight() {
         return height;
     }
 
+    /**
+     * Serialize this shape, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
         OutputCapsule capsule = ex.getCapsule(this);
@@ -83,6 +127,12 @@ public class ConeCollisionShape extends CollisionShape {
         capsule.write(axis, "axis", PhysicsSpace.AXIS_Y);
     }
 
+    /**
+     * De-serialize this shape, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     public void read(JmeImporter im) throws IOException {
         super.read(im);
         InputCapsule capsule = im.getCapsule(this);
@@ -92,6 +142,9 @@ public class ConeCollisionShape extends CollisionShape {
         createShape();
     }
 
+    /**
+     * Instantiate the configured shape in Bullet.
+     */
     protected void createShape() {
         objectId = createShape(axis, radius, height);
         Logger.getLogger(this.getClass().getName()).log(Level.FINE, "Created Shape {0}", Long.toHexString(objectId));

+ 54 - 8
jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/CylinderCollisionShape.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -41,20 +41,35 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * Basic cylinder collision shape
+ * A cylindrical collision shape based on Bullet's btCylinderShapeX, new
+ * btCylinderShape, or btCylinderShapeZ.
+ *
  * @author normenhansen
  */
 public class CylinderCollisionShape extends CollisionShape {
 
+    /**
+     * copy of half-extents of the cylinder on each local axis (not null, no
+     * negative component)
+     */
     protected Vector3f halfExtents;
+    /**
+     * main (height) axis (0&rarr;X, 1&rarr;Y, 2&rarr;Z)
+     */
     protected int axis;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public CylinderCollisionShape() {
     }
 
     /**
-     * creates a cylinder shape from the given halfextents
-     * @param halfExtents the halfextents to use
+     * Instantiate a Z-axis cylinder shape with the specified half extents.
+     *
+     * @param halfExtents the desired half extents (not null, no negative
+     * component, alias created)
      */
     public CylinderCollisionShape(Vector3f halfExtents) {
         this.halfExtents = halfExtents;
@@ -63,9 +78,11 @@ public class CylinderCollisionShape extends CollisionShape {
     }
 
     /**
-     * Creates a cylinder shape around the given axis from the given halfextents
-     * @param halfExtents the halfextents to use
-     * @param axis (0=X,1=Y,2=Z)
+     * Instantiate a cylinder shape around the specified axis.
+     *
+     * @param halfExtents the desired half extents (not null, no negative
+     * component, alias created)
+     * @param axis which local axis: 0&rarr;X, 1&rarr;Y, 2&rarr;Z
      */
     public CylinderCollisionShape(Vector3f halfExtents, int axis) {
         this.halfExtents = halfExtents;
@@ -73,16 +90,30 @@ public class CylinderCollisionShape extends CollisionShape {
         createShape();
     }
 
+    /**
+     * Access the half extents of the cylinder.
+     *
+     * @return the pre-existing vector (not null, no negative component)
+     */
     public final Vector3f getHalfExtents() {
         return halfExtents;
     }
 
+    /**
+     * Determine the main axis of the cylinder.
+     *
+     * @return 0&rarr;X, 1&rarr;Y, 2&rarr;Z
+     */
     public int getAxis() {
         return axis;
     }
 
     /**
-     * WARNING - CompoundCollisionShape scaling has no effect.
+     * Alter the scaling factors of this shape. Scaling is disabled
+     * for cylinder shapes.
+     *
+     * @param scale the desired scaling factor for each local axis (not null, no
+     * negative component, unaffected, default=1,1,1)
      */
     @Override
     public void setScale(Vector3f scale) {
@@ -91,6 +122,12 @@ public class CylinderCollisionShape extends CollisionShape {
     	 }
     }
 
+    /**
+     * Serialize this shape, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
         OutputCapsule capsule = ex.getCapsule(this);
@@ -98,6 +135,12 @@ public class CylinderCollisionShape extends CollisionShape {
         capsule.write(axis, "axis", 1);
     }
 
+    /**
+     * De-serialize this shape, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     public void read(JmeImporter im) throws IOException {
         super.read(im);
         InputCapsule capsule = im.getCapsule(this);
@@ -106,6 +149,9 @@ public class CylinderCollisionShape extends CollisionShape {
         createShape();
     }
 
+    /**
+     * Instantiate the configured shape in Bullet.
+     */
     protected void createShape() {
         objectId = createShape(axis, halfExtents);
         Logger.getLogger(this.getClass().getName()).log(Level.FINE, "Created Shape {0}", Long.toHexString(objectId));

+ 34 - 3
jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/GImpactCollisionShape.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -47,7 +47,8 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * Basic mesh collision shape
+ * A mesh collision shape based on Bullet's btGImpactMeshShape.
+ *
  * @author normenhansen
  */
 public class GImpactCollisionShape extends CollisionShape {
@@ -55,14 +56,23 @@ public class GImpactCollisionShape extends CollisionShape {
 //    protected Vector3f worldScale;
     protected int numVertices, numTriangles, vertexStride, triangleIndexStride;
     protected ByteBuffer triangleIndexBase, vertexBase;
+    /**
+     * Unique identifier of the Bullet mesh. The constructor sets this to a
+     * non-zero value.
+     */
     protected long meshId = 0;
 //    protected IndexedMesh bulletMesh;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public GImpactCollisionShape() {
     }
 
     /**
-     * creates a collision shape from the given Mesh
+     * Instantiate a shape based on the specified JME mesh.
+     *
      * @param mesh the Mesh to use
      */
     public GImpactCollisionShape(Mesh mesh) {
@@ -105,6 +115,12 @@ public class GImpactCollisionShape extends CollisionShape {
 //    public Mesh createJmeMesh() {
 //        return Converter.convert(bulletMesh);
 //    }
+    /**
+     * Serialize this shape, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
         OutputCapsule capsule = ex.getCapsule(this);
@@ -118,6 +134,12 @@ public class GImpactCollisionShape extends CollisionShape {
         capsule.write(vertexBase.array(), "vertexBase", new byte[0]);
     }
 
+    /**
+     * De-serialize this shape, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     public void read(JmeImporter im) throws IOException {
         super.read(im);
         InputCapsule capsule = im.getCapsule(this);
@@ -132,6 +154,9 @@ public class GImpactCollisionShape extends CollisionShape {
         createShape();
     }
 
+    /**
+     * Instantiate the configured shape in Bullet.
+     */
     protected void createShape() {
 //        bulletMesh = new IndexedMesh();
 //        bulletMesh.numVertices = numVertices;
@@ -157,6 +182,12 @@ public class GImpactCollisionShape extends CollisionShape {
 
     private native long createShape(long meshId);
 
+    /**
+     * Finalize this shape just before it is destroyed. Should be invoked only
+     * by a subclass or by the garbage collector.
+     *
+     * @throws Throwable ignored by the garbage collector
+     */
     @Override
     protected void finalize() throws Throwable {
         super.finalize();

+ 65 - 9
jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/HeightfieldCollisionShape.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -45,36 +45,72 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * Uses Bullet Physics Heightfield terrain collision system. This is MUCH faster
- * than using a regular mesh.
- * There are a couple tricks though:
- *	-No rotation or translation is supported.
- *	-The collision bbox must be centered around 0,0,0 with the height above and below the y-axis being
- *	equal on either side. If not, the whole collision box is shifted vertically and things don't collide
- *	as they should.
- * 
+ * A terrain collision shape based on Bullet's btHeightfieldTerrainShape.
+ * <p>
+ * This is much more efficient than a regular mesh, but it has a couple
+ * limitations:
+ * <ul>
+ * <li>No rotation or translation.</li>
+ * <li>The collision bounding box must be centered on (0,0,0) with the height
+ * above and below the X-Z plane being equal on either side. If not, the whole
+ * collision box is shifted vertically and objects won't collide properly.</li>
+ * </ul>
+ *
  * @author Brent Owens
  */
 public class HeightfieldCollisionShape extends CollisionShape {
 
+    /**
+     * number of rows in the heightfield (&gt;1)
+     */
     protected int heightStickWidth;
+    /**
+     * number of columns in the heightfield (&gt;1)
+     */
     protected int heightStickLength;
+    /**
+     * array of heightfield samples
+     */
     protected float[] heightfieldData;
     protected float heightScale;
     protected float minHeight;
     protected float maxHeight;
+    /**
+     * index of the height axis (0&rarr;X, 1&rarr;Y, 2&rarr;Z)
+     */
     protected int upAxis;
     protected boolean flipQuadEdges;
+    /**
+     * buffer for passing height data to Bullet
+     * <p>
+     * A Java reference must persist after createShape() completes, or else the
+     * buffer might get garbaged collected.
+     */    
     protected ByteBuffer bbuf;
 //    protected FloatBuffer fbuf;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public HeightfieldCollisionShape() {
     }
 
+    /**
+     * Instantiate a new shape for the specified height map.
+     *
+     * @param heightmap (not null, length&ge;4, length a perfect square)
+     */
     public HeightfieldCollisionShape(float[] heightmap) {
         createCollisionHeightfield(heightmap, Vector3f.UNIT_XYZ);
     }
 
+    /**
+     * Instantiate a new shape for the specified height map and scale vector.
+     *
+     * @param heightmap (not null, length&ge;4, length a perfect square)
+     * @param scale (not null, no negative component, unaffected, default=1,1,1)
+     */
     public HeightfieldCollisionShape(float[] heightmap, Vector3f scale) {
         createCollisionHeightfield(heightmap, scale);
     }
@@ -120,6 +156,9 @@ public class HeightfieldCollisionShape extends CollisionShape {
         createShape();
     }
 
+    /**
+     * Instantiate the configured shape in Bullet.
+     */
     protected void createShape() {
         bbuf = BufferUtils.createByteBuffer(heightfieldData.length * 4); 
 //        fbuf = bbuf.asFloatBuffer();//FloatBuffer.wrap(heightfieldData);
@@ -138,11 +177,22 @@ public class HeightfieldCollisionShape extends CollisionShape {
 
     private native long createShape(int heightStickWidth, int heightStickLength, ByteBuffer heightfieldData, float heightScale, float minHeight, float maxHeight, int upAxis, boolean flipQuadEdges);
 
+    /**
+     * Does nothing.
+     * 
+     * @return null
+     */
     public Mesh createJmeMesh() {
         //TODO return Converter.convert(bulletMesh);
         return null;
     }
 
+    /**
+     * Serialize this shape, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
         OutputCapsule capsule = ex.getCapsule(this);
@@ -156,6 +206,12 @@ public class HeightfieldCollisionShape extends CollisionShape {
         capsule.write(flipQuadEdges, "flipQuadEdges", false);
     }
 
+    /**
+     * De-serialize this shape, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     public void read(JmeImporter im) throws IOException {
         super.read(im);
         InputCapsule capsule = im.getCapsule(this);

+ 42 - 1
jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/HullCollisionShape.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,24 +44,50 @@ import java.nio.FloatBuffer;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+/**
+ * A convex hull collision shape based on Bullet's btConvexHullShape.
+ */
 public class HullCollisionShape extends CollisionShape {
 
     private float[] points;
 //    protected FloatBuffer fbuf;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public HullCollisionShape() {
     }
 
+    /**
+     * Instantiate a collision shape based on the specified JME mesh. For best
+     * performance and stability, use the mesh should have no more than 100
+     * vertices.
+     *
+     * @param mesh a mesh on which to base the shape (not null)
+     */
     public HullCollisionShape(Mesh mesh) {
         this.points = getPoints(mesh);
         createShape();
     }
 
+    /**
+     * Instantiate a collision shape based on the specified JME mesh.
+     *
+     * @param points an array of coordinates on which to base the shape (not
+     * null, length a multiple of 3)
+     */
     public HullCollisionShape(float[] points) {
         this.points = points;
         createShape();
     }
 
+    /**
+     * Serialize this shape, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     @Override
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
@@ -70,6 +96,12 @@ public class HullCollisionShape extends CollisionShape {
         capsule.write(points, "points", null);
     }
 
+    /**
+     * De-serialize this shape, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     @Override
     public void read(JmeImporter im) throws IOException {
         super.read(im);
@@ -89,6 +121,9 @@ public class HullCollisionShape extends CollisionShape {
         createShape();
     }
 
+    /**
+     * Instantiate the configured shape in Bullet.
+     */
     protected void createShape() {
 //        ObjectArrayList<Vector3f> pointList = new ObjectArrayList<Vector3f>();
 //        for (int i = 0; i < points.length; i += 3) {
@@ -114,6 +149,12 @@ public class HullCollisionShape extends CollisionShape {
 
     private native long createShape(ByteBuffer points);
 
+    /**
+     * Copy the vertex positions from a JME mesh.
+     *
+     * @param mesh the mesh to read (not null)
+     * @return a new array (not null, length a multiple of 3)
+     */
     protected float[] getPoints(Mesh mesh) {
         FloatBuffer vertices = mesh.getFloatBuffer(Type.Position);
         vertices.rewind();

+ 51 - 24
jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/MeshCollisionShape.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -49,7 +49,7 @@ import com.jme3.scene.mesh.IndexBuffer;
 import com.jme3.util.BufferUtils;
 
 /**
- * Basic mesh collision shape
+ * A mesh collision shape based on Bullet's btBvhTriangleMeshShape.
  *
  * @author normenhansen
  */
@@ -64,38 +64,45 @@ public class MeshCollisionShape extends CollisionShape {
     private static final String NATIVE_BVH = "nativeBvh";
     protected int numVertices, numTriangles, vertexStride, triangleIndexStride;
     protected ByteBuffer triangleIndexBase, vertexBase;
+    /**
+     * Unique identifier of the Bullet mesh. The constructor sets this to a
+     * non-zero value.
+     */
     protected long meshId = 0;
     protected long nativeBVHBuffer = 0;
     private boolean memoryOptimized;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public MeshCollisionShape() {
     }
 
     /**
-     * Creates a collision shape from the given Mesh. 
-     * Default behavior, more optimized for memory usage.
+     * Instantiate a collision shape based on the specified JME mesh, optimized
+     * for memory usage.
      *
-     * @param mesh
+     * @param mesh the mesh on which to base the shape (not null)
      */
     public MeshCollisionShape(Mesh mesh) {
         this(mesh, true);
     }
 
     /**
-     * Creates a collision shape from the given Mesh.
-     * <code>memoryOptimized</code> determines if optimized instead of 
-     * quantized BVH will be used.
-     * Internally, <code>memoryOptimized</code> BVH is slower to calculate (~4x) 
-     * but also smaller (~0.5x). 
-     * It is preferable to use the memory optimized version and then serialize
-     * the resulting MeshCollisionshape as this will also save the
-     * generated BVH. 
-     * An exception can be procedurally / generated collision shapes, where
-     * the generation time is more of a concern
+     * Instantiate a collision shape based on the specified JME mesh.
+     * <p>
+     * <code>memoryOptimized</code> determines if optimized instead of quantized
+     * BVH will be used. Internally, <code>memoryOptimized</code> BVH is slower
+     * to calculate (~4x) but also smaller (~0.5x). It is preferable to use the
+     * memory optimized version and then serialize the resulting
+     * MeshCollisionshape as this will also save the generated BVH. An exception
+     * can be procedurally / generated collision shapes, where the generation
+     * time is more of a concern
      *
-     * @param mesh the Mesh to use
-     * @param memoryOptimized True to generate a memory optimized BVH,
-     * false to generate quantized BVH.
+     * @param mesh the mesh on which to base the shape (not null)
+     * @param memoryOptimized true to generate a memory-optimized BVH, false to
+     * generate quantized BVH
      */
     public MeshCollisionShape(final Mesh mesh, final boolean memoryOptimized) {
         this.memoryOptimized = memoryOptimized;
@@ -103,16 +110,15 @@ public class MeshCollisionShape extends CollisionShape {
     }
 
     /**
-     * Advanced constructor, usually you don’t want to use this, but the Mesh
-     * based one. Passing false values can lead to a crash, use at own risk
-     *
+     * An advanced constructor. Passing false values can lead to a crash.
+     * Usually you don’t want to use this. Use at own risk.
+     * <p>
      * This constructor bypasses all copy logic normally used, this allows for
-     * faster bullet shape generation when using procedurally generated Meshes.
-     *
+     * faster Bullet shape generation when using procedurally generated Meshes.
      *
      * @param indices the raw index buffer
      * @param vertices the raw vertex buffer
-     * @param memoryOptimized use quantisize BVH, uses less memory, but slower
+     * @param memoryOptimized use quantized BVH, uses less memory, but slower
      */
     public MeshCollisionShape(ByteBuffer indices, ByteBuffer vertices, boolean memoryOptimized) {
         this.triangleIndexBase = indices;
@@ -153,6 +159,12 @@ public class MeshCollisionShape extends CollisionShape {
         this.createShape(null);
     }
 
+    /**
+     * Serialize this shape, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     @Override
     public void write(final JmeExporter ex) throws IOException {
         super.write(ex);
@@ -178,6 +190,12 @@ public class MeshCollisionShape extends CollisionShape {
         }
     }
 
+    /**
+     * De-serialize this shape, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     @Override
     public void read(final JmeImporter im) throws IOException {
         super.read(im);
@@ -195,6 +213,9 @@ public class MeshCollisionShape extends CollisionShape {
         createShape(nativeBvh);
     }
 
+    /**
+     * Instantiate the configured shape in Bullet.
+     */
     private void createShape(byte bvh[]) {
         boolean buildBvh=bvh==null||bvh.length==0;
         this.meshId = NativeMeshUtil.createTriangleIndexVertexArray(this.triangleIndexBase, this.vertexBase, this.numTriangles, this.numVertices, this.vertexStride, this.triangleIndexStride);
@@ -216,6 +237,12 @@ public class MeshCollisionShape extends CollisionShape {
     
     private native long createShape(boolean memoryOptimized, boolean buildBvt, long meshId);
 
+    /**
+     * Finalize this shape just before it is destroyed. Should be invoked only
+     * by a subclass or by the garbage collector.
+     *
+     * @throws Throwable ignored by the garbage collector
+     */
     @Override
     public void finalize() throws Throwable {
         super.finalize();

+ 32 - 3
jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/PlaneCollisionShape.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,34 +42,60 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
+ * A planar collision shape based on Bullet's btStaticPlaneShape.
  *
  * @author normenhansen
  */
 public class PlaneCollisionShape extends CollisionShape{
+    /**
+     * description of the plane
+     */
     private Plane plane;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public PlaneCollisionShape() {
     }
 
     /**
-     * Creates a plane Collision shape
-     * @param plane the plane that defines the shape
+     * Instantiate a plane shape defined by the specified plane.
+     *
+     * @param plane the desired plane (not null, alias created)
      */
     public PlaneCollisionShape(Plane plane) {
         this.plane = plane;
         createShape();
     }
 
+    /**
+     * Access the defining plane.
+     *
+     * @return the pre-existing instance (not null)
+     */
     public final Plane getPlane() {
         return plane;
     }
 
+    /**
+     * Serialize this shape, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
         OutputCapsule capsule = ex.getCapsule(this);
         capsule.write(plane, "collisionPlane", new Plane());
     }
 
+    /**
+     * De-serialize this shape, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     public void read(JmeImporter im) throws IOException {
         super.read(im);
         InputCapsule capsule = im.getCapsule(this);
@@ -77,6 +103,9 @@ public class PlaneCollisionShape extends CollisionShape{
         createShape();
     }
 
+    /**
+     * Instantiate the configured shape in Bullet.
+     */
     protected void createShape() {
         objectId = createShape(plane.getNormal(), plane.getConstant());
         Logger.getLogger(this.getClass().getName()).log(Level.FINE, "Created Shape {0}", Long.toHexString(objectId));

+ 52 - 2
jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/SimplexCollisionShape.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -41,16 +41,33 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * A simple point, line, triangle or quad collisionShape based on one to four points-
+ * A simple point, line-segment, triangle, or tetrahedron collision shape based
+ * on Bullet's btBU_Simplex1to4.
+ *
  * @author normenhansen
  */
 public class SimplexCollisionShape extends CollisionShape {
 
+    /**
+     * vertex positions
+     */
     private Vector3f vector1, vector2, vector3, vector4;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public SimplexCollisionShape() {
     }
 
+    /**
+     * Instantiate a tetrahedral collision shape based on the specified points.
+     *
+     * @param point1 the coordinates of 1st point (not null, alias created)
+     * @param point2 the coordinates of 2nd point (not null, alias created)
+     * @param point3 the coordinates of 3rd point (not null, alias created)
+     * @param point4 the coordinates of 4th point (not null, alias created)
+     */
     public SimplexCollisionShape(Vector3f point1, Vector3f point2, Vector3f point3, Vector3f point4) {
         vector1 = point1;
         vector2 = point2;
@@ -59,6 +76,13 @@ public class SimplexCollisionShape extends CollisionShape {
         createShape();
     }
 
+    /**
+     * Instantiate a triangular collision shape based on the specified points.
+     *
+     * @param point1 the coordinates of 1st point (not null, alias created)
+     * @param point2 the coordinates of 2nd point (not null, alias created)
+     * @param point3 the coordinates of 3rd point (not null, alias created)
+     */
     public SimplexCollisionShape(Vector3f point1, Vector3f point2, Vector3f point3) {
         vector1 = point1;
         vector2 = point2;
@@ -66,17 +90,34 @@ public class SimplexCollisionShape extends CollisionShape {
         createShape();
     }
 
+    /**
+     * Instantiate a line-segment collision shape based on the specified points.
+     *
+     * @param point1 the coordinates of 1st point (not null, alias created)
+     * @param point2 the coordinates of 2nd point (not null, alias created)
+     */
     public SimplexCollisionShape(Vector3f point1, Vector3f point2) {
         vector1 = point1;
         vector2 = point2;
         createShape();
     }
 
+    /**
+     * Instantiate a point collision shape based on the specified points.
+     *
+     * @param point1 the coordinates of point (not null, alias created)
+     */
     public SimplexCollisionShape(Vector3f point1) {
         vector1 = point1;
         createShape();
     }
 
+    /**
+     * Serialize this shape, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
         OutputCapsule capsule = ex.getCapsule(this);
@@ -86,6 +127,12 @@ public class SimplexCollisionShape extends CollisionShape {
         capsule.write(vector4, "simplexPoint4", null);
     }
 
+    /**
+     * De-serialize this shape, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     public void read(JmeImporter im) throws IOException {
         super.read(im);
         InputCapsule capsule = im.getCapsule(this);
@@ -96,6 +143,9 @@ public class SimplexCollisionShape extends CollisionShape {
         createShape();
     }
 
+    /**
+     * Instantiate the configured shape in Bullet.
+     */
     protected void createShape() {
         if (vector4 != null) {
             objectId = createShape(vector1, vector2, vector3, vector4);

+ 38 - 5
jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/SphereCollisionShape.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -41,35 +41,61 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * Basic sphere collision shape
+ * A spherical collision shape based on Bullet's btSphereShape.
+ *
  * @author normenhansen
  */
 public class SphereCollisionShape extends CollisionShape {
 
+    /**
+     * copy of radius (&ge;0)
+     */
     protected float radius;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public SphereCollisionShape() {
     }
 
     /**
-     * creates a SphereCollisionShape with the given radius
-     * @param radius
+     * Instantiate a sphere shape with the specified radius.
+     *
+     * @param radius the desired radius (&ge;0)
      */
     public SphereCollisionShape(float radius) {
         this.radius = radius;
         createShape();
     }
 
+    /**
+     * Read the radius of this shape.
+     *
+     * @return the radius (&ge;0)
+     */
     public float getRadius() {
         return radius;
     }
 
+    /**
+     * Serialize this shape, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
         OutputCapsule capsule = ex.getCapsule(this);
         capsule.write(radius, "radius", 0.5f);
     }
 
+    /**
+     * De-serialize this shape, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     public void read(JmeImporter im) throws IOException {
         super.read(im);
         InputCapsule capsule = im.getCapsule(this);
@@ -78,7 +104,11 @@ public class SphereCollisionShape extends CollisionShape {
     }
 
     /**
-     * WARNING - CompoundCollisionShape scaling has no effect.
+     * Alter the scaling factors of this shape. Scaling is disabled
+     * for sphere shapes.
+     *
+     * @param scale the desired scaling factor for each local axis (not null, no
+     * negative component, unaffected, default=1,1,1)
      */
     @Override
     public void setScale(Vector3f scale) {
@@ -87,6 +117,9 @@ public class SphereCollisionShape extends CollisionShape {
         }
     }
 
+    /**
+     * Instantiate the configured shape in Bullet.
+     */
     protected void createShape() {
         objectId = createShape(radius);
         Logger.getLogger(this.getClass().getName()).log(Level.FINE, "Created Shape {0}", Long.toHexString(objectId));

+ 62 - 6
jme3-bullet/src/main/java/com/jme3/bullet/joints/ConeJoint.java

@@ -43,10 +43,13 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * <i>From bullet manual:</i><br>
- * To create ragdolls, the cone twist constraint is very useful for limbs like the upper arm.
- * It is a special point to point constraint that adds cone and twist axis limits.
- * The x-axis serves as twist axis.
+ * A joint based on Bullet's btConeTwistConstraint.
+ * <p>
+ * <i>From the Bullet manual:</i><br>
+ * To create ragdolls, the cone twist constraint is very useful for limbs like
+ * the upper arm. It is a special point to point constraint that adds cone and
+ * twist axis limits. The x-axis serves as twist axis.
+ *
  * @author normenhansen
  */
 public class ConeJoint extends PhysicsJoint {
@@ -57,12 +60,25 @@ public class ConeJoint extends PhysicsJoint {
     protected float twistSpan = 1e30f;
     protected boolean angularOnly = false;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public ConeJoint() {
     }
 
     /**
-     * @param pivotA local translation of the joint connection point in node A
-     * @param pivotB local translation of the joint connection point in node B
+     * Instantiate a ConeJoint. To be effective, the joint must be added to a
+     * physics space.
+     *
+     * @param nodeA the 1st body connected by the joint (not null, alias
+     * created)
+     * @param nodeB the 2nd body connected by the joint (not null, alias
+     * created)
+     * @param pivotA the local offset of the connection point in node A (not
+     * null, alias created)
+     * @param pivotB the local offset of the connection point in node B (not
+     * null, alias created)
      */
     public ConeJoint(PhysicsRigidBody nodeA, PhysicsRigidBody nodeB, Vector3f pivotA, Vector3f pivotB) {
         super(nodeA, nodeB, pivotA, pivotB);
@@ -72,8 +88,21 @@ public class ConeJoint extends PhysicsJoint {
     }
 
     /**
+     * Instantiate a ConeJoint. To be effective, the joint must be added to a
+     * physics space.
+     *
+     * @param nodeA the 1st body connected by the joint (not null, alias
+     * created)
+     * @param nodeB the 2nd body connected by the joint (not null, alias
+     * created)
      * @param pivotA local translation of the joint connection point in node A
+     * (not null, alias created)
      * @param pivotB local translation of the joint connection point in node B
+     * (not null, alias created)
+     * @param rotA the local orientation of the connection to node A (not null,
+     * alias created)
+     * @param rotB the local orientation of the connection to node B (not null,
+     * alias created)
      */
     public ConeJoint(PhysicsRigidBody nodeA, PhysicsRigidBody nodeB, Vector3f pivotA, Vector3f pivotB, Matrix3f rotA, Matrix3f rotB) {
         super(nodeA, nodeB, pivotA, pivotB);
@@ -82,6 +111,13 @@ public class ConeJoint extends PhysicsJoint {
         createJoint();
     }
 
+    /**
+     * Alter the angular limits for this joint.
+     *
+     * @param swingSpan1 angle (in radians)
+     * @param swingSpan2 angle (in radians)
+     * @param twistSpan angle (in radians)
+     */
     public void setLimit(float swingSpan1, float swingSpan2, float twistSpan) {
         this.swingSpan1 = swingSpan1;
         this.swingSpan2 = swingSpan2;
@@ -91,6 +127,11 @@ public class ConeJoint extends PhysicsJoint {
 
     private native void setLimit(long objectId, float swingSpan1, float swingSpan2, float twistSpan);
 
+    /**
+     * Alter whether this joint is angular only.
+     *
+     * @param value the desired setting (default=false)
+     */
     public void setAngularOnly(boolean value) {
         angularOnly = value;
         setAngularOnly(objectId, value);
@@ -98,6 +139,12 @@ public class ConeJoint extends PhysicsJoint {
 
     private native void setAngularOnly(long objectId, boolean value);
 
+    /**
+     * Serialize this joint, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     @Override
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
@@ -111,6 +158,12 @@ public class ConeJoint extends PhysicsJoint {
         capsule.write(twistSpan, "twistSpan", 1e30f);
     }
 
+    /**
+     * De-serialize this joint, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     @Override
     public void read(JmeImporter im) throws IOException {
         super.read(im);
@@ -125,6 +178,9 @@ public class ConeJoint extends PhysicsJoint {
         createJoint();
     }
 
+    /**
+     * Create the configured joint in Bullet.
+     */
     protected void createJoint() {
         objectId = createJoint(nodeA.getObjectId(), nodeB.getObjectId(), pivotA, rotA, pivotB, rotB);
         Logger.getLogger(this.getClass().getName()).log(Level.FINE, "Created Joint {0}", Long.toHexString(objectId));

+ 116 - 22
jme3-bullet/src/main/java/com/jme3/bullet/joints/HingeJoint.java

@@ -42,29 +42,63 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * <i>From bullet manual:</i><br>
- * Hinge constraint, or revolute joint restricts two additional angular degrees of freedom,
- * so the body can only rotate around one axis, the hinge axis.
- * This can be useful to represent doors or wheels rotating around one axis.
- * The user can specify limits and motor for the hinge.
+ * A joint based on Bullet's btHingeConstraint.
+ * <p>
+ * <i>From the Bullet manual:</i><br>
+ * Hinge constraint, or revolute joint restricts two additional angular degrees
+ * of freedom, so the body can only rotate around one axis, the hinge axis. This
+ * can be useful to represent doors or wheels rotating around one axis. The user
+ * can specify limits and motor for the hinge.
+ *
  * @author normenhansen
  */
 public class HingeJoint extends PhysicsJoint {
 
     protected Vector3f axisA;
     protected Vector3f axisB;
+    /**
+     * copy of the angular-only flag (default=false)
+     */
     protected boolean angularOnly = false;
+    /**
+     * copy of the limit's bias factor, how strictly position errors (drift) is
+     * corrected (default=0.3)
+     */
     protected float biasFactor = 0.3f;
+    /**
+     * copy of the limit's relaxation factor, the rate at which velocity errors
+     * are corrected (default=1)
+     */
     protected float relaxationFactor = 1.0f;
+    /**
+     * copy of the limit's softness, the range fraction at which velocity-error
+     * correction starts operating (default=0.9)
+     */
     protected float limitSoftness = 0.9f;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public HingeJoint() {
     }
 
     /**
-     * Creates a new HingeJoint
-     * @param pivotA local translation of the joint connection point in node A
-     * @param pivotB local translation of the joint connection point in node B
+     * Instantiate a HingeJoint. To be effective, the joint must be added to a
+     * physics space.
+     *
+     * @param nodeA the 1st body connected by the joint (not null, alias
+     * created)
+     * @param nodeB the 2nd body connected by the joint (not null, alias
+     * created)
+     * @param pivotA the local offset of the connection point in node A (not
+     * null, alias created)
+     * @param pivotB the local offset of the connection point in node B (not
+     * null, alias created)
+     * @param axisA the local axis of the connection to node A (not null, alias
+     * created)
+     * @param axisB the local axis of the connection to node B (not null, alias
+     * created)
      */
     public HingeJoint(PhysicsRigidBody nodeA, PhysicsRigidBody nodeB, Vector3f pivotA, Vector3f pivotB, Vector3f axisA, Vector3f axisB) {
         super(nodeA, nodeB, pivotA, pivotB);
@@ -74,10 +108,11 @@ public class HingeJoint extends PhysicsJoint {
     }
 
     /**
-     * Enables the motor.
-     * @param enable if true, motor is enabled.
-     * @param targetVelocity the target velocity of the rotation.
-     * @param maxMotorImpulse the max force applied to the hinge to rotate it.
+     * Enable or disable this joint's motor.
+     *
+     * @param enable true to enable, false to disable
+     * @param targetVelocity the desired target velocity
+     * @param maxMotorImpulse the desired maximum rotational force
      */
     public void enableMotor(boolean enable, float targetVelocity, float maxMotorImpulse) {
         enableMotor(objectId, enable, targetVelocity, maxMotorImpulse);
@@ -85,18 +120,33 @@ public class HingeJoint extends PhysicsJoint {
 
     private native void enableMotor(long objectId, boolean enable, float targetVelocity, float maxMotorImpulse);
 
+    /**
+     * Test whether this joint's motor is enabled.
+     *
+     * @return true if enabled, otherwise false
+     */
     public boolean getEnableMotor() {
         return getEnableAngularMotor(objectId);
     }
 
     private native boolean getEnableAngularMotor(long objectId);
 
+    /**
+     * Read the motor's target velocity.
+     *
+     * @return velocity
+     */
     public float getMotorTargetVelocity() {
         return getMotorTargetVelocity(objectId);
     }
 
     private native float getMotorTargetVelocity(long objectId);
 
+    /**
+     * Read the motor's maximum impulse.
+     *
+     * @return impulse
+     */
     public float getMaxMotorImpulse() {
         return getMaxMotorImpulse(objectId);
     }
@@ -104,9 +154,10 @@ public class HingeJoint extends PhysicsJoint {
     private native float getMaxMotorImpulse(long objectId);
 
     /**
-     * Sets the limits of this joint.
-     * @param low the low limit in radians.
-     * @param high the high limit in radians.
+     * Alter this joint's limits.
+     *
+     * @param low the desired lower limit of the hinge angle (in radians)
+     * @param high the desired upper limit of the joint angle (in radians)
      */
     public void setLimit(float low, float high) {
         setLimit(objectId, low, high);
@@ -115,13 +166,20 @@ public class HingeJoint extends PhysicsJoint {
     private native void setLimit(long objectId, float low, float high);
 
     /**
-     * Sets the limits of this joint.
-     * If you're above the softness, velocities that would shoot through the actual limit are slowed down. The bias be in the range of 0.2 - 0.5.
-     * @param low the low limit in radians.
-     * @param high the high limit in radians.
-     * @param _softness the factor at which the velocity error correction starts operating,i.e a softness of 0.9 means that the vel. corr starts at 90% of the limit range.
-     * @param _biasFactor the magnitude of the position correction. It tells you how strictly the position error (drift ) is corrected.
-     * @param _relaxationFactor the rate at which velocity errors are corrected. This can be seen as the strength of the limits. A low value will make the limits more spongy.
+     * Alter this joint's limits. If you're above the softness, velocities that
+     * would shoot through the actual limit are slowed down. The bias should be
+     * in the range of 0.2 - 0.5.
+     *
+     * @param low the desired lower limit of the hinge angle (in radians)
+     * @param high the desired upper limit of the joint angle (in radians)
+     * @param _softness the desired range fraction at which velocity-error
+     * correction starts operating. A softness of 0.9 means that the correction
+     * starts at 90% of the limit range. (default=0.9)
+     * @param _biasFactor the desired magnitude of the position correction, how
+     * strictly position errors (drift) is corrected. (default=0.3)
+     * @param _relaxationFactor the desired rate at which velocity errors are
+     * corrected. This can be seen as the strength of the limits. A low value
+     * will make the limits more spongy. (default=1)
      */
     public void setLimit(float low, float high, float _softness, float _biasFactor, float _relaxationFactor) {
         biasFactor = _biasFactor;
@@ -132,18 +190,34 @@ public class HingeJoint extends PhysicsJoint {
 
     private native void setLimit(long objectId, float low, float high, float _softness, float _biasFactor, float _relaxationFactor);
 
+    /**
+     * Read the upper limit of the hinge angle.
+     *
+     * @return angle (in radians)
+     */
     public float getUpperLimit() {
         return getUpperLimit(objectId);
     }
 
     private native float getUpperLimit(long objectId);
 
+    /**
+     * Read the lower limit of the hinge angle.
+     *
+     * @return the angle (in radians)
+     */
     public float getLowerLimit() {
         return getLowerLimit(objectId);
     }
 
     private native float getLowerLimit(long objectId);
 
+    /**
+     * Alter the hinge translation flag.
+     *
+     * @param angularOnly true&rarr;rotate only, false&rarr;rotate and translate
+     * (default=false)
+     */
     public void setAngularOnly(boolean angularOnly) {
         this.angularOnly = angularOnly;
         setAngularOnly(objectId, angularOnly);
@@ -151,12 +225,23 @@ public class HingeJoint extends PhysicsJoint {
 
     private native void setAngularOnly(long objectId, boolean angularOnly);
 
+    /**
+     * Read the hinge angle.
+     *
+     * @return the angle (in radians)
+     */
     public float getHingeAngle() {
         return getHingeAngle(objectId);
     }
 
     private native float getHingeAngle(long objectId);
 
+    /**
+     * Serialize this joint, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
         OutputCapsule capsule = ex.getCapsule(this);
@@ -177,6 +262,12 @@ public class HingeJoint extends PhysicsJoint {
         capsule.write(getMaxMotorImpulse(), "maxMotorImpulse", 0.0f);
     }
 
+    /**
+     * De-serialize this joint, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     public void read(JmeImporter im) throws IOException {
         super.read(im);
         InputCapsule capsule = im.getCapsule(this);
@@ -200,6 +291,9 @@ public class HingeJoint extends PhysicsJoint {
         setLimit(lowerLimit, upperLimit, limitSoftness, biasFactor, relaxationFactor);
     }
 
+    /**
+     * Create the configured joint in Bullet.
+     */
     protected void createJoint() {
         objectId = createJoint(nodeA.getObjectId(), nodeB.getObjectId(), pivotA, axisA, pivotB, axisB);
         Logger.getLogger(this.getClass().getName()).log(Level.FINE, "Created Joint {0}", Long.toHexString(objectId));

+ 94 - 10
jme3-bullet/src/main/java/com/jme3/bullet/joints/PhysicsJoint.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -39,24 +39,59 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * <p>PhysicsJoint - Basic Phyiscs Joint</p>
+ * The abstract base class for physics joints based on Bullet's
+ * btTypedConstraint, used to connect 2 dynamic rigid bodies in the same
+ * physics space.
+ * <p>
+ * Joints include ConeJoint, HingeJoint, Point2PointJoint, and SixDofJoint.
+ *
  * @author normenhansen
  */
 public abstract class PhysicsJoint implements Savable {
 
+    /**
+     * Unique identifier of the Bullet constraint. Constructors are responsible
+     * for setting this to a non-zero value. After that, the id never changes.
+     */
     protected long objectId = 0;
+    /**
+     * one of the connected rigid bodies
+     */
     protected PhysicsRigidBody nodeA;
+    /**
+     * the other connected rigid body
+     */
     protected PhysicsRigidBody nodeB;
+    /**
+     * local offset of this joint's connection point in node A
+     */
     protected Vector3f pivotA;
+    /**
+     * local offset of this joint's connection point in node B
+     */
     protected Vector3f pivotB;
     protected boolean collisionBetweenLinkedBodys = true;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public PhysicsJoint() {
     }
 
     /**
-     * @param pivotA local translation of the joint connection point in node A
-     * @param pivotB local translation of the joint connection point in node B
+     * Instantiate a PhysicsJoint. To be effective, the joint must be added to
+     * the physics space of the two bodies. Also, the bodies must be dynamic and
+     * distinct.
+     *
+     * @param nodeA the 1st body connected by the joint (not null, alias
+     * created)
+     * @param nodeB the 2nd body connected by the joint (not null, alias
+     * created)
+     * @param pivotA local offset of the joint connection point in node A (not
+     * null, alias created)
+     * @param pivotB local offset of the joint connection point in node B (not
+     * null, alias created)
      */
     public PhysicsJoint(PhysicsRigidBody nodeA, PhysicsRigidBody nodeB, Vector3f pivotA, Vector3f pivotB) {
         this.nodeA = nodeA;
@@ -67,6 +102,11 @@ public abstract class PhysicsJoint implements Savable {
         nodeB.addJoint(this);
     }
 
+    /**
+     * Read the magnitude of the applied impulse.
+     *
+     * @return impulse
+     */
     public float getAppliedImpulse() {
         return getAppliedImpulse(objectId);
     }
@@ -74,52 +114,84 @@ public abstract class PhysicsJoint implements Savable {
     private native float getAppliedImpulse(long objectId);
 
     /**
-     * @return the constraint
+     * Read the id of the Bullet constraint.
+     *
+     * @return the unique identifier (not zero)
      */
     public long getObjectId() {
         return objectId;
     }
 
     /**
-     * @return the collisionBetweenLinkedBodys
+     * Test whether collisions are allowed between the linked bodies.
+     *
+     * @return true if collision are allowed, otherwise false
      */
     public boolean isCollisionBetweenLinkedBodys() {
         return collisionBetweenLinkedBodys;
     }
 
     /**
-     * toggles collisions between linked bodys<br>
-     * joint has to be removed from and added to PhyiscsSpace to apply this.
-     * @param collisionBetweenLinkedBodys set to false to have no collisions between linked bodys
+     * Enable or disable collisions between the linked bodies. The joint must be
+     * removed from and added to PhysicsSpace for this change to be effective.
+     *
+     * @param collisionBetweenLinkedBodys true &rarr; allow collisions, false &rarr; prevent them
      */
     public void setCollisionBetweenLinkedBodys(boolean collisionBetweenLinkedBodys) {
         this.collisionBetweenLinkedBodys = collisionBetweenLinkedBodys;
     }
 
+    /**
+     * Access the 1st body specified in during construction.
+     *
+     * @return the pre-existing body
+     */
     public PhysicsRigidBody getBodyA() {
         return nodeA;
     }
 
+    /**
+     * Access the 2nd body specified in during construction.
+     *
+     * @return the pre-existing body
+     */
     public PhysicsRigidBody getBodyB() {
         return nodeB;
     }
 
+    /**
+     * Access the local offset of the joint connection point in node A.
+     *
+     * @return the pre-existing vector
+     */
     public Vector3f getPivotA() {
         return pivotA;
     }
 
+    /**
+     * Access the local offset of the joint connection point in node A.
+     *
+     * @return the pre-existing vector
+     */
     public Vector3f getPivotB() {
         return pivotB;
     }
 
     /**
-     * destroys this joint and removes it from its connected PhysicsRigidBodys joint lists
+     * Destroy this joint and remove it from the joint lists of its connected
+     * bodies.
      */
     public void destroy() {
         getBodyA().removeJoint(this);
         getBodyB().removeJoint(this);
     }
 
+    /**
+     * Serialize this joint, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     public void write(JmeExporter ex) throws IOException {
         OutputCapsule capsule = ex.getCapsule(this);
         capsule.write(nodeA, "nodeA", null);
@@ -128,6 +200,12 @@ public abstract class PhysicsJoint implements Savable {
         capsule.write(pivotB, "pivotB", null);
     }
 
+    /**
+     * De-serialize this joint, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     public void read(JmeImporter im) throws IOException {
         InputCapsule capsule = im.getCapsule(this);
         this.nodeA = ((PhysicsRigidBody) capsule.readSavable("nodeA", new PhysicsRigidBody()));
@@ -136,6 +214,12 @@ public abstract class PhysicsJoint implements Savable {
         this.pivotB = (Vector3f) capsule.readSavable("pivotB", new Vector3f());
     }
 
+    /**
+     * Finalize this physics joint just before it is destroyed. Should be
+     * invoked only by a subclass or by the garbage collector.
+     *
+     * @throws Throwable ignored by the garbage collector
+     */
     @Override
     protected void finalize() throws Throwable {
         super.finalize();

+ 70 - 7
jme3-bullet/src/main/java/com/jme3/bullet/joints/Point2PointJoint.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,62 +42,116 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * <i>From bullet manual:</i><br>
- * Point to point constraint, also known as ball socket joint limits the translation
- * so that the local pivot points of 2 rigidbodies match in worldspace.
- * A chain of rigidbodies can be connected using this constraint.
+ * A joint based on Bullet's btPoint2PointConstraint.
+ * <p>
+ * <i>From the Bullet manual:</i><br>
+ * Point to point constraint limits the translation so that the local pivot
+ * points of 2 rigidbodies match in worldspace. A chain of rigidbodies can be
+ * connected using this constraint.
+ *
  * @author normenhansen
  */
 public class Point2PointJoint extends PhysicsJoint {
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public Point2PointJoint() {
     }
 
     /**
-     * @param pivotA local translation of the joint connection point in node A
-     * @param pivotB local translation of the joint connection point in node B
+     * Instantiate a Point2PointJoint. To be effective, the joint must be added
+     * to a physics space.
+     *
+     * @param nodeA the 1st body connected by the joint (not null, alias
+     * created)
+     * @param nodeB the 2nd body connected by the joint (not null, alias
+     * created)
+     * @param pivotA the local offset of the connection point in node A (not
+     * null, alias created)
+     * @param pivotB the local offset of the connection point in node B (not
+     * null, alias created)
      */
     public Point2PointJoint(PhysicsRigidBody nodeA, PhysicsRigidBody nodeB, Vector3f pivotA, Vector3f pivotB) {
         super(nodeA, nodeB, pivotA, pivotB);
         createJoint();
     }
 
+    /**
+     * Alter the joint's damping.
+     *
+     * @param value the desired viscous damping ratio (0&rarr;no damping,
+     * 1&rarr;critically damped, default=1)
+     */
     public void setDamping(float value) {
         setDamping(objectId, value);
     }
 
     private native void setDamping(long objectId, float value);
 
+    /**
+     * Alter the joint's impulse clamp.
+     *
+     * @param value the desired impulse clamp value (default=0)
+     */
     public void setImpulseClamp(float value) {
         setImpulseClamp(objectId, value);
     }
 
     private native void setImpulseClamp(long objectId, float value);
 
+    /**
+     * Alter the joint's tau value.
+     *
+     * @param value the desired tau value (default=0.3)
+     */
     public void setTau(float value) {
         setTau(objectId, value);
     }
 
     private native void setTau(long objectId, float value);
 
+    /**
+     * Read the joint's damping ratio.
+     *
+     * @return the viscous damping ratio (0&rarr;no damping, 1&rarr;critically
+     * damped)
+     */
     public float getDamping() {
         return getDamping(objectId);
     }
 
     private native float getDamping(long objectId);
 
+    /**
+     * Read the joint's impulse clamp.
+     *
+     * @return the clamp value
+     */
     public float getImpulseClamp() {
         return getImpulseClamp(objectId);
     }
 
     private native float getImpulseClamp(long objectId);
 
+    /**
+     * Read the joint's tau value.
+     *
+     * @return the tau value
+     */
     public float getTau() {
         return getTau(objectId);
     }
 
     private native float getTau(long objectId);
 
+    /**
+     * Serialize this joint, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     @Override
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
@@ -107,6 +161,12 @@ public class Point2PointJoint extends PhysicsJoint {
         cap.write(getImpulseClamp(), "impulseClamp", 0f);
     }
 
+    /**
+     * De-serialize this joint, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     @Override
     public void read(JmeImporter im) throws IOException {
         super.read(im);
@@ -117,6 +177,9 @@ public class Point2PointJoint extends PhysicsJoint {
         setDamping(cap.readFloat("impulseClamp", 0f));
     }
 
+    /**
+     * Create the configured joint in Bullet.
+     */
     protected void createJoint() {
         objectId = createJoint(nodeA.getObjectId(), nodeB.getObjectId(), pivotA, pivotB);
         Logger.getLogger(this.getClass().getName()).log(Level.FINE, "Created Joint {0}", Long.toHexString(objectId));

+ 112 - 20
jme3-bullet/src/main/java/com/jme3/bullet/joints/SixDofJoint.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -47,33 +47,79 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * <i>From bullet manual:</i><br>
- * This generic constraint can emulate a variety of standard constraints,
- * by configuring each of the 6 degrees of freedom (dof).
- * The first 3 dof axis are linear axis, which represent translation of rigidbodies,
- * and the latter 3 dof axis represent the angular motion. Each axis can be either locked,
- * free or limited. On construction of a new btGeneric6DofConstraint, all axis are locked.
- * Afterwards the axis can be reconfigured. Note that several combinations that
- * include free and/or limited angular degrees of freedom are undefined.
+ * A joint based on Bullet's btGeneric6DofConstraint.
+ * <p>
+ * <i>From the Bullet manual:</i><br>
+ * This generic constraint can emulate a variety of standard constraints, by
+ * configuring each of the 6 degrees of freedom (dof). The first 3 dof axis are
+ * linear axis, which represent translation of rigidbodies, and the latter 3 dof
+ * axis represent the angular motion. Each axis can be either locked, free or
+ * limited. On construction of a new btGeneric6DofSpring2Constraint, all axis
+ * are locked. Afterwards the axis can be reconfigured. Note that several
+ * combinations that include free and/or limited angular degrees of freedom are
+ * undefined.
+ * <p>
+ * For each axis:<ul>
+ * <li>Lowerlimit = Upperlimit &rarr; axis is locked</li>
+ * <li>Lowerlimit &gt; Upperlimit &rarr; axis is free</li>
+ * <li>Lowerlimit &lt; Upperlimit &rarr; axis it limited in that range</li>
+ * </ul>
+ *
  * @author normenhansen
  */
 public class SixDofJoint extends PhysicsJoint {
 
     Matrix3f rotA, rotB;
+    /**
+     * true&rarr;limits give the allowable range of movement of frameB in frameA
+     * space, false&rarr;limits give the allowable range of movement of frameA
+     * in frameB space
+     */
     boolean useLinearReferenceFrameA;
     LinkedList<RotationalLimitMotor> rotationalMotors = new LinkedList<RotationalLimitMotor>();
     TranslationalLimitMotor translationalMotor;
+    /**
+     * upper limits for rotation of all 3 axes
+     */
     Vector3f angularUpperLimit = new Vector3f(Vector3f.POSITIVE_INFINITY);
+    /**
+     * lower limits for rotation of all 3 axes
+     */
     Vector3f angularLowerLimit = new Vector3f(Vector3f.NEGATIVE_INFINITY);
+    /**
+     * upper limit for translation of all 3 axes
+     */
     Vector3f linearUpperLimit = new Vector3f(Vector3f.POSITIVE_INFINITY);
+    /**
+     * lower limits for translation of all 3 axes
+     */
     Vector3f linearLowerLimit = new Vector3f(Vector3f.NEGATIVE_INFINITY);
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public SixDofJoint() {
     }
 
     /**
-     * @param pivotA local translation of the joint connection point in node A
-     * @param pivotB local translation of the joint connection point in node B
+     * Instantiate a SixDofJoint. To be effective, the joint must be added to a
+     * physics space.
+     *
+     * @param nodeA the 1st body connected by the joint (not null, alias
+     * created)
+     * @param nodeB the 2nd body connected by the joint (not null, alias
+     * created)
+     * @param pivotA the local offset of the connection point in node A (not
+     * null, alias created)
+     * @param pivotB the local offset of the connection point in node B (not
+     * null, alias created)
+     * @param rotA the local orientation of the connection to node A (not null,
+     * alias created)
+     * @param rotB the local orientation of the connection to node B (not null,
+     * alias created)
+     * @param useLinearReferenceFrameA true&rarr;use node A, false&rarr;use node
+     * B
      */
     public SixDofJoint(PhysicsRigidBody nodeA, PhysicsRigidBody nodeB, Vector3f pivotA, Vector3f pivotB, Matrix3f rotA, Matrix3f rotB, boolean useLinearReferenceFrameA) {
         super(nodeA, nodeB, pivotA, pivotB);
@@ -87,8 +133,19 @@ public class SixDofJoint extends PhysicsJoint {
     }
 
     /**
-     * @param pivotA local translation of the joint connection point in node A
-     * @param pivotB local translation of the joint connection point in node B
+     * Instantiate a SixDofJoint. To be effective, the joint must be added to a
+     * physics space.
+     *
+     * @param nodeA the 1st body connected by the joint (not null, alias
+     * created)
+     * @param nodeB the 2nd body connected by the joint (not null, alias
+     * created)
+     * @param pivotA the local offset of the connection point in node A (not
+     * null, alias created)
+     * @param pivotB the local offset of the connection point in node B (not
+     * null, alias created)
+     * @param useLinearReferenceFrameA true&rarr;use node A, false&rarr;use node
+     * B
      */
     public SixDofJoint(PhysicsRigidBody nodeA, PhysicsRigidBody nodeB, Vector3f pivotA, Vector3f pivotB, boolean useLinearReferenceFrameA) {
         super(nodeA, nodeB, pivotA, pivotB);
@@ -114,24 +171,32 @@ public class SixDofJoint extends PhysicsJoint {
     private native long getTranslationalLimitMotor(long objectId);
 
     /**
-     * returns the TranslationalLimitMotor of this 6DofJoint which allows
-     * manipulating the translational axis
-     * @return the TranslationalLimitMotor
+     * Access the TranslationalLimitMotor of this joint, the motor which
+     * influences translation on all 3 axes.
+     *
+     * @return the pre-existing instance
      */
     public TranslationalLimitMotor getTranslationalLimitMotor() {
         return translationalMotor;
     }
 
     /**
-     * returns one of the three RotationalLimitMotors of this 6DofJoint which
-     * allow manipulating the rotational axes
-     * @param index the index of the RotationalLimitMotor
-     * @return the RotationalLimitMotor at the given index
+     * Access the indexed RotationalLimitMotor of this joint, the motor which
+     * influences rotation around one axis.
+     *
+     * @param index the axis index of the desired motor: 0&rarr;X, 1&rarr;Y,
+     * 2&rarr;Z
+     * @return the pre-existing instance
      */
     public RotationalLimitMotor getRotationalLimitMotor(int index) {
         return rotationalMotors.get(index);
     }
 
+    /**
+     * Alter the joint's upper limits for translation of all 3 axes.
+     *
+     * @param vector the desired upper limits (not null, unaffected)
+     */
     public void setLinearUpperLimit(Vector3f vector) {
         linearUpperLimit.set(vector);
         setLinearUpperLimit(objectId, vector);
@@ -139,6 +204,11 @@ public class SixDofJoint extends PhysicsJoint {
 
     private native void setLinearUpperLimit(long objctId, Vector3f vector);
 
+    /**
+     * Alter the joint's lower limits for translation of all 3 axes.
+     *
+     * @param vector the desired lower limits (not null, unaffected)
+     */
     public void setLinearLowerLimit(Vector3f vector) {
         linearLowerLimit.set(vector);
         setLinearLowerLimit(objectId, vector);
@@ -146,6 +216,11 @@ public class SixDofJoint extends PhysicsJoint {
 
     private native void setLinearLowerLimit(long objctId, Vector3f vector);
 
+    /**
+     * Alter the joint's upper limits for rotation of all 3 axes.
+     *
+     * @param vector the desired upper limits (in radians, not null, unaffected)
+     */
     public void setAngularUpperLimit(Vector3f vector) {
         angularUpperLimit.set(vector);
         setAngularUpperLimit(objectId, vector);
@@ -153,6 +228,11 @@ public class SixDofJoint extends PhysicsJoint {
 
     private native void setAngularUpperLimit(long objctId, Vector3f vector);
 
+    /**
+     * Alter the joint's lower limits for rotation of all 3 axes.
+     *
+     * @param vector the desired lower limits (in radians, not null, unaffected)
+     */
     public void setAngularLowerLimit(Vector3f vector) {
         angularLowerLimit.set(vector);
         setAngularLowerLimit(objectId, vector);
@@ -162,6 +242,12 @@ public class SixDofJoint extends PhysicsJoint {
 
     native long createJoint(long objectIdA, long objectIdB, Vector3f pivotA, Matrix3f rotA, Vector3f pivotB, Matrix3f rotB, boolean useLinearReferenceFrameA);
 
+    /**
+     * De-serialize this joint, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     @Override
     public void read(JmeImporter im) throws IOException {
         super.read(im);
@@ -197,6 +283,12 @@ public class SixDofJoint extends PhysicsJoint {
         getTranslationalLimitMotor().setUpperLimit((Vector3f) capsule.readSavable("transMotor_UpperLimit", Vector3f.ZERO));
     }
 
+    /**
+     * Serialize this joint, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     @Override
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);

+ 70 - 11
jme3-bullet/src/main/java/com/jme3/bullet/joints/SixDofSpringJoint.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,14 +36,24 @@ import com.jme3.math.Matrix3f;
 import com.jme3.math.Vector3f;
 
 /**
- * <i>From bullet manual:</i><br>
- * This generic constraint can emulate a variety of standard constraints,
- * by configuring each of the 6 degrees of freedom (dof).
- * The first 3 dof axis are linear axis, which represent translation of rigidbodies,
- * and the latter 3 dof axis represent the angular motion. Each axis can be either locked,
- * free or limited. On construction of a new btGeneric6DofConstraint, all axis are locked.
- * Afterwards the axis can be reconfigured. Note that several combinations that
- * include free and/or limited angular degrees of freedom are undefined.
+ * A 6 degree-of-freedom joint based on Bullet's btGeneric6DofSpringConstraint.
+ * <p>
+ * <i>From the Bullet manual:</i><br>
+ * This generic constraint can emulate a variety of standard constraints, by
+ * configuring each of the 6 degrees of freedom (dof). The first 3 dof axis are
+ * linear axis, which represent translation of rigidbodies, and the latter 3 dof
+ * axis represent the angular motion. Each axis can be either locked, free or
+ * limited. On construction of a new btGeneric6DofSpring2Constraint, all axis
+ * are locked. Afterwards the axis can be reconfigured. Note that several
+ * combinations that include free and/or limited angular degrees of freedom are
+ * undefined.
+ * <p>
+ * For each axis:<ul>
+ * <li>Lowerlimit = Upperlimit &rarr; axis is locked</li>
+ * <li>Lowerlimit &gt; Upperlimit &rarr; axis is free</li>
+ * <li>Lowerlimit &lt; Upperlimit &rarr; axis it limited in that range</li>
+ * </ul>
+ *
  * @author normenhansen
  */
 public class SixDofSpringJoint extends SixDofJoint {
@@ -53,35 +63,84 @@ public class SixDofSpringJoint extends SixDofJoint {
    final float springStiffness[] = new float[6];
    final float springDamping[] = new float[6]; // between 0 and 1 (1 == no damping)
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public SixDofSpringJoint() {
     }
 
     /**
-     * @param pivotA local translation of the joint connection point in node A
-     * @param pivotB local translation of the joint connection point in node B
+     * Instantiate a SixDofSpringJoint. To be effective, the joint must be added
+     * to a physics space.
+     *
+     * @param nodeA the 1st body connected by the joint (not null, alias
+     * created)
+     * @param nodeB the 2nd body connected by the joint (not null, alias
+     * created)
+     * @param pivotA the local offset of the connection point in node A (not
+     * null, alias created)
+     * @param pivotB the local offset of the connection point in node B (not
+     * null, alias created)
+     * @param rotA the local orientation of the connection to node A (not
+     * null, alias created)
+     * @param rotB the local orientation of the connection to node B (not
+     * null, alias created)
+     * @param useLinearReferenceFrameA true&rarr;use node A, false&rarr;use node
+     * B
      */
     public SixDofSpringJoint(PhysicsRigidBody nodeA, PhysicsRigidBody nodeB, Vector3f pivotA, Vector3f pivotB, Matrix3f rotA, Matrix3f rotB, boolean useLinearReferenceFrameA) {
         super(nodeA, nodeB, pivotA, pivotB, rotA, rotB, useLinearReferenceFrameA);
     }
+
+    /**
+     * Enable or disable the spring for the indexed degree of freedom.
+     *
+     * @param index which degree of freedom (&ge;0, &lt;6)
+     * @param onOff true &rarr; enable, false &rarr; disable
+     */
     public void enableSpring(int index, boolean onOff) {
         enableSpring(objectId, index, onOff);
     }
     native void enableSpring(long objctId, int index, boolean onOff);
 
+    /**
+     * Alter the spring stiffness for the indexed degree of freedom.
+     *
+     * @param index which degree of freedom (&ge;0, &lt;6)
+     * @param stiffness the desired stiffness
+     */
     public void setStiffness(int index, float stiffness) {
         setStiffness(objectId, index, stiffness);
     }
     native void setStiffness(long objctId, int index, float stiffness);
 
+    /**
+     * Alter the damping for the indexed degree of freedom.
+     *
+     * @param index which degree of freedom (&ge;0, &lt;6)
+     * @param damping the desired viscous damping ratio (0&rarr;no damping,
+     * 1&rarr;critically damped, default=1)
+     */
     public void setDamping(int index, float damping) {
         setDamping(objectId, index, damping);
 
     }
     native void setDamping(long objctId, int index, float damping);
+    /**
+     * Alter the equilibrium points for all degrees of freedom, based on the
+     * current constraint position/orientation.
+     */
     public void setEquilibriumPoint() { // set the current constraint position/orientation as an equilibrium point for all DOF
         setEquilibriumPoint(objectId);
     }
     native void setEquilibriumPoint(long objctId);
+    /**
+     * Alter the equilibrium point of the indexed degree of freedom, based on
+     * the current constraint position/orientation.
+     *
+     * @param index which degree of freedom (&ge;0, &lt;6)
+     */
     public void setEquilibriumPoint(int index){ // set the current constraint position/orientation as an equilibrium point for given DOF
         setEquilibriumPoint(objectId, index);
     }

+ 357 - 7
jme3-bullet/src/main/java/com/jme3/bullet/joints/SliderJoint.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,8 +43,12 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * <i>From bullet manual:</i><br>
- * The slider constraint allows the body to rotate around one axis and translate along this axis.
+ * A slider joint based on Bullet's btSliderConstraint.
+ * <p>
+ * <i>From the Bullet manual:</i><br>
+ * The slider constraint allows the body to rotate around one axis and translate
+ * along this axis.
+ *
  * @author normenhansen
  */
 public class SliderJoint extends PhysicsJoint {
@@ -52,12 +56,29 @@ public class SliderJoint extends PhysicsJoint {
     protected Matrix3f rotA, rotB;
     protected boolean useLinearReferenceFrameA;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public SliderJoint() {
     }
 
     /**
-     * @param pivotA local translation of the joint connection point in node A
-     * @param pivotB local translation of the joint connection point in node B
+     * Instantiate a SliderJoint. To be effective, the joint must be added to a
+     * physics space.
+     *
+     * @param nodeA the 1st body connected by the joint (not null, alias
+     * created)
+     * @param nodeB the 2nd body connected by the joint (not null, alias
+     * created)
+     * @param pivotA the local offset of the connection point in node A (not
+     * null, alias created)
+     * @param pivotB the local offset of the connection point in node B (not
+     * null, alias created)
+     * @param rotA the local orientation of the connection to node A (not null, alias created)
+     * @param rotB the local orientation of the connection to node B (not null, alias created)
+     * @param useLinearReferenceFrameA true&rarr;use node A, false&rarr;use node
+     * B
      */
     public SliderJoint(PhysicsRigidBody nodeA, PhysicsRigidBody nodeB, Vector3f pivotA, Vector3f pivotB, Matrix3f rotA, Matrix3f rotB, boolean useLinearReferenceFrameA) {
         super(nodeA, nodeB, pivotA, pivotB);
@@ -68,8 +89,19 @@ public class SliderJoint extends PhysicsJoint {
     }
 
     /**
-     * @param pivotA local translation of the joint connection point in node A
-     * @param pivotB local translation of the joint connection point in node B
+     * Instantiate a SliderJoint. To be effective, the joint must be added to a
+     * physics space.
+     *
+     * @param nodeA the 1st body connected by the joint (not null, alias
+     * created)
+     * @param nodeB the 2nd body connected by the joint (not null, alias
+     * created)
+     * @param pivotA the local offset of the connection point in node A (not
+     * null, alias created)
+     * @param pivotB the local offset of the connection point in node B (not
+     * null, alias created)
+     * @param useLinearReferenceFrameA true&rarr;use node A, false&rarr;use node
+     * B
      */
     public SliderJoint(PhysicsRigidBody nodeA, PhysicsRigidBody nodeB, Vector3f pivotA, Vector3f pivotB, boolean useLinearReferenceFrameA) {
         super(nodeA, nodeB, pivotA, pivotB);
@@ -79,342 +111,651 @@ public class SliderJoint extends PhysicsJoint {
         createJoint();
     }
 
+    /**
+     * Read the joint's lower limit for on-axis translation.
+     *
+     * @return the lower limit
+     */
     public float getLowerLinLimit() {
         return getLowerLinLimit(objectId);
     }
 
     private native float getLowerLinLimit(long objectId);
 
+    /**
+     * Alter the joint's lower limit for on-axis translation.
+     *
+     * @param lowerLinLimit the desired lower limit (default=-1)
+     */
     public void setLowerLinLimit(float lowerLinLimit) {
         setLowerLinLimit(objectId, lowerLinLimit);
     }
 
     private native void setLowerLinLimit(long objectId, float value);
 
+    /**
+     * Read the joint's upper limit for on-axis translation.
+     *
+     * @return the upper limit
+     */
     public float getUpperLinLimit() {
         return getUpperLinLimit(objectId);
     }
 
     private native float getUpperLinLimit(long objectId);
 
+    /**
+     * Alter the joint's upper limit for on-axis translation.
+     *
+     * @param upperLinLimit the desired upper limit (default=1)
+     */
     public void setUpperLinLimit(float upperLinLimit) {
         setUpperLinLimit(objectId, upperLinLimit);
     }
 
     private native void setUpperLinLimit(long objectId, float value);
 
+    /**
+     * Read the joint's lower limit for on-axis rotation.
+     *
+     * @return the lower limit angle (in radians)
+     */
     public float getLowerAngLimit() {
         return getLowerAngLimit(objectId);
     }
 
     private native float getLowerAngLimit(long objectId);
 
+    /**
+     * Alter the joint's lower limit for on-axis rotation.
+     *
+     * @param lowerAngLimit the desired lower limit angle (in radians,
+     * default=0)
+     */
     public void setLowerAngLimit(float lowerAngLimit) {
         setLowerAngLimit(objectId, lowerAngLimit);
     }
 
     private native void setLowerAngLimit(long objectId, float value);
 
+    /**
+     * Read the joint's upper limit for on-axis rotation.
+     *
+     * @return the upper limit angle (in radians)
+     */
     public float getUpperAngLimit() {
         return getUpperAngLimit(objectId);
     }
 
     private native float getUpperAngLimit(long objectId);
 
+    /**
+     * Alter the joint's upper limit for on-axis rotation.
+     *
+     * @param upperAngLimit the desired upper limit angle (in radians,
+     * default=0)
+     */
     public void setUpperAngLimit(float upperAngLimit) {
         setUpperAngLimit(objectId, upperAngLimit);
     }
 
     private native void setUpperAngLimit(long objectId, float value);
 
+    /**
+     * Read the joint's softness for on-axis translation between the limits.
+     *
+     * @return the softness
+     */
     public float getSoftnessDirLin() {
         return getSoftnessDirLin(objectId);
     }
 
     private native float getSoftnessDirLin(long objectId);
 
+    /**
+     * Alter the joint's softness for on-axis translation between the limits.
+     *
+     * @param softnessDirLin the desired softness (default=1)
+     */
     public void setSoftnessDirLin(float softnessDirLin) {
         setSoftnessDirLin(objectId, softnessDirLin);
     }
 
     private native void setSoftnessDirLin(long objectId, float value);
 
+    /**
+     * Read the joint's restitution for on-axis translation between the limits.
+     *
+     * @return the restitution (bounce) factor
+     */
     public float getRestitutionDirLin() {
         return getRestitutionDirLin(objectId);
     }
 
     private native float getRestitutionDirLin(long objectId);
 
+    /**
+     * Alter the joint's restitution for on-axis translation between the limits.
+     *
+     * @param restitutionDirLin the desired restitution (bounce) factor
+     * (default=0.7)
+     */
     public void setRestitutionDirLin(float restitutionDirLin) {
         setRestitutionDirLin(objectId, restitutionDirLin);
     }
 
     private native void setRestitutionDirLin(long objectId, float value);
 
+    /**
+     * Read the joint's damping for on-axis translation between the limits.
+     *
+     * @return the viscous damping ratio (0&rarr;no damping, 1&rarr;critically
+     * damped)
+     */
     public float getDampingDirLin() {
         return getDampingDirLin(objectId);
     }
 
     private native float getDampingDirLin(long objectId);
 
+    /**
+     * Alter the joint's damping for on-axis translation between the limits.
+     *
+     * @param dampingDirLin the desired viscous damping ratio (0&rarr;no
+     * damping, 1&rarr;critically damped, default=0)
+     */
     public void setDampingDirLin(float dampingDirLin) {
         setDampingDirLin(objectId, dampingDirLin);
     }
 
     private native void setDampingDirLin(long objectId, float value);
 
+    /**
+     * Read the joint's softness for on-axis rotation between the limits.
+     *
+     * @return the softness
+     */
     public float getSoftnessDirAng() {
         return getSoftnessDirAng(objectId);
     }
 
     private native float getSoftnessDirAng(long objectId);
 
+    /**
+     * Alter the joint's softness for on-axis rotation between the limits.
+     *
+     * @param softnessDirAng the desired softness (default=1)
+     */
     public void setSoftnessDirAng(float softnessDirAng) {
         setSoftnessDirAng(objectId, softnessDirAng);
     }
 
     private native void setSoftnessDirAng(long objectId, float value);
 
+    /**
+     * Read the joint's restitution for on-axis rotation between the limits.
+     *
+     * @return the restitution (bounce) factor
+     */
     public float getRestitutionDirAng() {
         return getRestitutionDirAng(objectId);
     }
 
     private native float getRestitutionDirAng(long objectId);
 
+    /**
+     * Alter the joint's restitution for on-axis rotation between the limits.
+     *
+     * @param restitutionDirAng the desired restitution (bounce) factor
+     * (default=0.7)
+     */
     public void setRestitutionDirAng(float restitutionDirAng) {
         setRestitutionDirAng(objectId, restitutionDirAng);
     }
 
     private native void setRestitutionDirAng(long objectId, float value);
 
+    /**
+     * Read the joint's damping for on-axis rotation between the limits.
+     *
+     * @return the viscous damping ratio (0&rarr;no damping, 1&rarr;critically
+     * damped)
+     */
     public float getDampingDirAng() {
         return getDampingDirAng(objectId);
     }
 
     private native float getDampingDirAng(long objectId);
 
+    /**
+     * Alter the joint's damping for on-axis rotation between the limits.
+     *
+     * @param dampingDirAng the desired viscous damping ratio (0&rarr;no
+     * damping, 1&rarr;critically damped, default=0)
+     */
     public void setDampingDirAng(float dampingDirAng) {
         setDampingDirAng(objectId, dampingDirAng);
     }
 
     private native void setDampingDirAng(long objectId, float value);
 
+    /**
+     * Read the joint's softness for on-axis translation hitting the limits.
+     *
+     * @return the softness
+     */
     public float getSoftnessLimLin() {
         return getSoftnessLimLin(objectId);
     }
 
     private native float getSoftnessLimLin(long objectId);
 
+    /**
+     * Alter the joint's softness for on-axis translation hitting the limits.
+     *
+     * @param softnessLimLin the desired softness (default=1)
+     */
     public void setSoftnessLimLin(float softnessLimLin) {
         setSoftnessLimLin(objectId, softnessLimLin);
     }
 
     private native void setSoftnessLimLin(long objectId, float value);
 
+    /**
+     * Read the joint's restitution for on-axis translation hitting the limits.
+     *
+     * @return the restitution (bounce) factor
+     */
     public float getRestitutionLimLin() {
         return getRestitutionLimLin(objectId);
     }
 
     private native float getRestitutionLimLin(long objectId);
 
+    /**
+     * Alter the joint's restitution for on-axis translation hitting the limits.
+     *
+     * @param restitutionLimLin the desired restitution (bounce) factor
+     * (default=0.7)
+     */
     public void setRestitutionLimLin(float restitutionLimLin) {
         setRestitutionLimLin(objectId, restitutionLimLin);
     }
 
     private native void setRestitutionLimLin(long objectId, float value);
 
+    /**
+     * Read the joint's damping for on-axis translation hitting the limits.
+     *
+     * @return the viscous damping ratio (0&rarr;no damping, 1&rarr;critically
+     * damped)
+     */
     public float getDampingLimLin() {
         return getDampingLimLin(objectId);
     }
 
     private native float getDampingLimLin(long objectId);
 
+    /**
+     * Alter the joint's damping for on-axis translation hitting the limits.
+     *
+     * @param dampingLimLin the desired viscous damping ratio (0&rarr;no
+     * damping, 1&rarr;critically damped, default=1)
+     */
     public void setDampingLimLin(float dampingLimLin) {
         setDampingLimLin(objectId, dampingLimLin);
     }
 
     private native void setDampingLimLin(long objectId, float value);
 
+    /**
+     * Read the joint's softness for on-axis rotation hitting the limits.
+     *
+     * @return the softness
+     */
     public float getSoftnessLimAng() {
         return getSoftnessLimAng(objectId);
     }
 
     private native float getSoftnessLimAng(long objectId);
 
+    /**
+     * Alter the joint's softness for on-axis rotation hitting the limits.
+     *
+     * @param softnessLimAng the desired softness (default=1)
+     */
     public void setSoftnessLimAng(float softnessLimAng) {
         setSoftnessLimAng(objectId, softnessLimAng);
     }
 
     private native void setSoftnessLimAng(long objectId, float value);
 
+    /**
+     * Read the joint's restitution for on-axis rotation hitting the limits.
+     *
+     * @return the restitution (bounce) factor
+     */
     public float getRestitutionLimAng() {
         return getRestitutionLimAng(objectId);
     }
 
     private native float getRestitutionLimAng(long objectId);
 
+    /**
+     * Alter the joint's restitution for on-axis rotation hitting the limits.
+     *
+     * @param restitutionLimAng the desired restitution (bounce) factor
+     * (default=0.7)
+     */
     public void setRestitutionLimAng(float restitutionLimAng) {
         setRestitutionLimAng(objectId, restitutionLimAng);
     }
 
     private native void setRestitutionLimAng(long objectId, float value);
 
+    /**
+     * Read the joint's damping for on-axis rotation hitting the limits.
+     *
+     * @return the viscous damping ratio (0&rarr;no damping, 1&rarr;critically
+     * damped)
+     */
     public float getDampingLimAng() {
         return getDampingLimAng(objectId);
     }
 
     private native float getDampingLimAng(long objectId);
 
+    /**
+     * Alter the joint's damping for on-axis rotation hitting the limits.
+     *
+     * @param dampingLimAng the desired viscous damping ratio (0&rarr;no
+     * damping, 1&rarr;critically damped, default=1)
+     */
     public void setDampingLimAng(float dampingLimAng) {
         setDampingLimAng(objectId, dampingLimAng);
     }
 
     private native void setDampingLimAng(long objectId, float value);
 
+    /**
+     * Read the joint's softness for off-axis translation.
+     *
+     * @return the softness
+     */
     public float getSoftnessOrthoLin() {
         return getSoftnessOrthoLin(objectId);
     }
 
     private native float getSoftnessOrthoLin(long objectId);
 
+    /**
+     * Alter the joint's softness for off-axis translation.
+     *
+     * @param softnessOrthoLin the desired softness (default=1)
+     */
     public void setSoftnessOrthoLin(float softnessOrthoLin) {
         setSoftnessOrthoLin(objectId, softnessOrthoLin);
     }
 
     private native void setSoftnessOrthoLin(long objectId, float value);
 
+    /**
+     * Read the joint's restitution for off-axis translation.
+     *
+     * @return the restitution (bounce) factor
+     */
     public float getRestitutionOrthoLin() {
         return getRestitutionOrthoLin(objectId);
     }
 
     private native float getRestitutionOrthoLin(long objectId);
 
+    /**
+     * Alter the joint's restitution for off-axis translation.
+     *
+     * @param restitutionOrthoLin the desired restitution (bounce) factor
+     * (default=0.7)
+     */
     public void setRestitutionOrthoLin(float restitutionOrthoLin) {
         setDampingOrthoLin(objectId, restitutionOrthoLin);
     }
 
     private native void setRestitutionOrthoLin(long objectId, float value);
 
+    /**
+     * Read the joint's damping for off-axis translation.
+     *
+     * @return the viscous damping ratio (0&rarr;no damping, 1&rarr;critically
+     * damped)
+     */
     public float getDampingOrthoLin() {
         return getDampingOrthoLin(objectId);
     }
 
     private native float getDampingOrthoLin(long objectId);
 
+    /**
+     * Alter the joint's damping for off-axis translation.
+     *
+     * @param dampingOrthoLin the desired viscous damping ratio (0&rarr;no
+     * damping, 1&rarr;critically damped, default=1)
+     */
     public void setDampingOrthoLin(float dampingOrthoLin) {
         setDampingOrthoLin(objectId, dampingOrthoLin);
     }
 
     private native void setDampingOrthoLin(long objectId, float value);
 
+    /**
+     * Read the joint's softness for off-axis rotation.
+     *
+     * @return the softness
+     */
     public float getSoftnessOrthoAng() {
         return getSoftnessOrthoAng(objectId);
     }
 
     private native float getSoftnessOrthoAng(long objectId);
 
+    /**
+     * Alter the joint's softness for off-axis rotation.
+     *
+     * @param softnessOrthoAng the desired softness (default=1)
+     */
     public void setSoftnessOrthoAng(float softnessOrthoAng) {
         setSoftnessOrthoAng(objectId, softnessOrthoAng);
     }
 
     private native void setSoftnessOrthoAng(long objectId, float value);
 
+    /**
+     * Read the joint's restitution for off-axis rotation.
+     *
+     * @return the restitution (bounce) factor
+     */
     public float getRestitutionOrthoAng() {
         return getRestitutionOrthoAng(objectId);
     }
 
     private native float getRestitutionOrthoAng(long objectId);
 
+    /**
+     * Alter the joint's restitution for off-axis rotation.
+     *
+     * @param restitutionOrthoAng the desired restitution (bounce) factor
+     * (default=0.7)
+     */
     public void setRestitutionOrthoAng(float restitutionOrthoAng) {
         setRestitutionOrthoAng(objectId, restitutionOrthoAng);
     }
 
     private native void setRestitutionOrthoAng(long objectId, float value);
 
+    /**
+     * Read the joint's damping for off-axis rotation.
+     *
+     * @return the viscous damping ratio (0&rarr;no damping, 1&rarr;critically
+     * damped)
+     */
     public float getDampingOrthoAng() {
         return getDampingOrthoAng(objectId);
     }
 
     private native float getDampingOrthoAng(long objectId);
 
+    /**
+     * Alter the joint's damping for off-axis rotation.
+     *
+     * @param dampingOrthoAng the desired viscous damping ratio (0&rarr;no
+     * damping, 1&rarr;critically damped, default=1)
+     */
     public void setDampingOrthoAng(float dampingOrthoAng) {
         setDampingOrthoAng(objectId, dampingOrthoAng);
     }
 
     private native void setDampingOrthoAng(long objectId, float value);
 
+    /**
+     * Test whether the translation motor is powered.
+     *
+     * @return true if powered, otherwise false
+     */
     public boolean isPoweredLinMotor() {
         return isPoweredLinMotor(objectId);
     }
 
     private native boolean isPoweredLinMotor(long objectId);
 
+    /**
+     * Alter whether the translation motor is powered.
+     *
+     * @param poweredLinMotor true to power the motor, false to de-power it
+     * (default=false)
+     */
     public void setPoweredLinMotor(boolean poweredLinMotor) {
         setPoweredLinMotor(objectId, poweredLinMotor);
     }
 
     private native void setPoweredLinMotor(long objectId, boolean value);
 
+    /**
+     * Read the velocity target of the translation motor.
+     *
+     * @return the velocity target
+     */
     public float getTargetLinMotorVelocity() {
         return getTargetLinMotorVelocity(objectId);
     }
 
     private native float getTargetLinMotorVelocity(long objectId);
 
+    /**
+     * Alter the velocity target of the translation motor.
+     *
+     * @param targetLinMotorVelocity the desired velocity target (default=0)
+     */
     public void setTargetLinMotorVelocity(float targetLinMotorVelocity) {
         setTargetLinMotorVelocity(objectId, targetLinMotorVelocity);
     }
 
     private native void setTargetLinMotorVelocity(long objectId, float value);
 
+    /**
+     * Read the maximum force of the translation motor.
+     *
+     * @return the maximum force
+     */
     public float getMaxLinMotorForce() {
         return getMaxLinMotorForce(objectId);
     }
 
     private native float getMaxLinMotorForce(long objectId);
 
+    /**
+     * Alter the maximum force of the translation motor.
+     *
+     * @param maxLinMotorForce the desired maximum force (default=0)
+     */
     public void setMaxLinMotorForce(float maxLinMotorForce) {
         setMaxLinMotorForce(objectId, maxLinMotorForce);
     }
 
     private native void setMaxLinMotorForce(long objectId, float value);
 
+    /**
+     * Test whether the rotation motor is powered.
+     *
+     * @return true if powered, otherwise false
+     */
     public boolean isPoweredAngMotor() {
         return isPoweredAngMotor(objectId);
     }
 
     private native boolean isPoweredAngMotor(long objectId);
 
+    /**
+     * Alter whether the rotation motor is powered.
+     *
+     * @param poweredAngMotor true to power the motor, false to de-power it
+     * (default=false)
+     */
     public void setPoweredAngMotor(boolean poweredAngMotor) {
         setPoweredAngMotor(objectId, poweredAngMotor);
     }
 
     private native void setPoweredAngMotor(long objectId, boolean value);
 
+    /**
+     * Read the velocity target of the rotation motor.
+     *
+     * @return the velocity target (in radians per second)
+     */
     public float getTargetAngMotorVelocity() {
         return getTargetAngMotorVelocity(objectId);
     }
 
     private native float getTargetAngMotorVelocity(long objectId);
 
+    /**
+     * Alter the velocity target of the rotation motor.
+     *
+     * @param targetAngMotorVelocity the desired velocity target (in radians per
+     * second, default=0)
+     */
     public void setTargetAngMotorVelocity(float targetAngMotorVelocity) {
         setTargetAngMotorVelocity(objectId, targetAngMotorVelocity);
     }
 
     private native void setTargetAngMotorVelocity(long objectId, float value);
 
+    /**
+     * Read the maximum force of the rotation motor.
+     *
+     * @return the maximum force
+     */
     public float getMaxAngMotorForce() {
         return getMaxAngMotorForce(objectId);
     }
 
     private native float getMaxAngMotorForce(long objectId);
 
+    /**
+     * Alter the maximum force of the rotation motor.
+     *
+     * @param maxAngMotorForce the desired maximum force (default=0)
+     */
     public void setMaxAngMotorForce(float maxAngMotorForce) {
         setMaxAngMotorForce(objectId, maxAngMotorForce);
     }
 
     private native void setMaxAngMotorForce(long objectId, float value);
 
+    /**
+     * Serialize this joint, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     @Override
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
@@ -455,6 +796,12 @@ public class SliderJoint extends PhysicsJoint {
         capsule.write(useLinearReferenceFrameA, "useLinearReferenceFrameA", false);
     }
 
+    /**
+     * De-serialize this joint, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     @Override
     public void read(JmeImporter im) throws IOException {
         super.read(im);
@@ -528,6 +875,9 @@ public class SliderJoint extends PhysicsJoint {
         setUpperLinLimit(upperLinLimit);
     }
 
+    /**
+     * Instantiate the configured constraint in Bullet.
+     */
     protected void createJoint() {
         objectId = createJoint(nodeA.getObjectId(), nodeB.getObjectId(), pivotA, rotA, pivotB, rotB, useLinearReferenceFrameA);
         Logger.getLogger(this.getClass().getName()).log(Level.FINE, "Created Joint {0}", Long.toHexString(objectId));

+ 119 - 1
jme3-bullet/src/main/java/com/jme3/bullet/joints/motors/RotationalLimitMotor.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,135 +32,253 @@
 package com.jme3.bullet.joints.motors;
 
 /**
+ * A motor based on Bullet's btRotationalLimitMotor. Motors are used to drive
+ * joints.
  *
  * @author normenhansen
  */
 public class RotationalLimitMotor {
 
+    /**
+     * Unique identifier of the btRotationalLimitMotor. The constructor sets
+     * this to a non-zero value.
+     */
     private long motorId = 0;
 
+    /**
+     * Instantiate a motor for the identified btRotationalLimitMotor.
+     *
+     * @param motor the unique identifier (not zero)
+     */
     public RotationalLimitMotor(long motor) {
         this.motorId = motor;
     }
 
+    /**
+     * Read the id of the btRotationalLimitMotor.
+     *
+     * @return the identifier of the btRotationalLimitMotor (not zero)
+     */
     public long getMotor() {
         return motorId;
     }
 
+    /**
+     * Read this motor's constraint lower limit.
+     *
+     * @return the limit value
+     */
     public float getLoLimit() {
         return getLoLimit(motorId);
     }
 
     private native float getLoLimit(long motorId);
 
+    /**
+     * Alter this motor's constraint lower limit.
+     *
+     * @param loLimit the desired limit value
+     */
     public void setLoLimit(float loLimit) {
         setLoLimit(motorId, loLimit);
     }
 
     private native void setLoLimit(long motorId, float loLimit);
 
+    /**
+     * Read this motor's constraint upper limit.
+     *
+     * @return the limit value
+     */
     public float getHiLimit() {
         return getHiLimit(motorId);
     }
 
     private native float getHiLimit(long motorId);
 
+    /**
+     * Alter this motor's constraint upper limit.
+     *
+     * @param hiLimit the desired limit value
+     */
     public void setHiLimit(float hiLimit) {
         setHiLimit(motorId, hiLimit);
     }
 
     private native void setHiLimit(long motorId, float hiLimit);
 
+    /**
+     * Read this motor's target velocity.
+     *
+     * @return the target velocity (in radians per second)
+     */
     public float getTargetVelocity() {
         return getTargetVelocity(motorId);
     }
 
     private native float getTargetVelocity(long motorId);
 
+    /**
+     * Alter this motor's target velocity.
+     *
+     * @param targetVelocity the desired target velocity (in radians per second)
+     */
     public void setTargetVelocity(float targetVelocity) {
         setTargetVelocity(motorId, targetVelocity);
     }
 
     private native void setTargetVelocity(long motorId, float targetVelocity);
 
+    /**
+     * Read this motor's maximum force.
+     *
+     * @return the maximum force
+     */
     public float getMaxMotorForce() {
         return getMaxMotorForce(motorId);
     }
 
     private native float getMaxMotorForce(long motorId);
 
+    /**
+     * Alter this motor's maximum force.
+     *
+     * @param maxMotorForce the desired maximum force on the motor
+     */
     public void setMaxMotorForce(float maxMotorForce) {
         setMaxMotorForce(motorId, maxMotorForce);
     }
 
     private native void setMaxMotorForce(long motorId, float maxMotorForce);
 
+    /**
+     * Read the limit's maximum force.
+     *
+     * @return the maximum force on the limit
+     */
     public float getMaxLimitForce() {
         return getMaxLimitForce(motorId);
     }
 
     private native float getMaxLimitForce(long motorId);
 
+    /**
+     * Alter the limit's maximum force.
+     *
+     * @param maxLimitForce the desired maximum force on the limit
+     */
     public void setMaxLimitForce(float maxLimitForce) {
         setMaxLimitForce(motorId, maxLimitForce);
     }
 
     private native void setMaxLimitForce(long motorId, float maxLimitForce);
 
+    /**
+     * Read this motor's damping.
+     *
+     * @return the viscous damping ratio (0&rarr;no damping, 1&rarr;critically
+     * damped)
+     */
     public float getDamping() {
         return getDamping(motorId);
     }
 
     private native float getDamping(long motorId);
 
+    /**
+     * Alter this motor's damping.
+     *
+     * @param damping the desired viscous damping ratio (0&rarr;no damping,
+     * 1&rarr;critically damped, default=1)
+     */
     public void setDamping(float damping) {
         setDamping(motorId, damping);
     }
 
     private native void setDamping(long motorId, float damping);
 
+    /**
+     * Read this motor's limit softness.
+     *
+     * @return the limit softness
+     */
     public float getLimitSoftness() {
         return getLimitSoftness(motorId);
     }
 
     private native float getLimitSoftness(long motorId);
 
+    /**
+     * Alter this motor's limit softness.
+     *
+     * @param limitSoftness the desired limit softness
+     */
     public void setLimitSoftness(float limitSoftness) {
         setLimitSoftness(motorId, limitSoftness);
     }
 
     private native void setLimitSoftness(long motorId, float limitSoftness);
 
+    /**
+     * Read this motor's error tolerance at limits.
+     *
+     * @return the error tolerance (&gt;0)
+     */
     public float getERP() {
         return getERP(motorId);
     }
 
     private native float getERP(long motorId);
 
+    /**
+     * Alter this motor's error tolerance at limits.
+     *
+     * @param ERP the desired error tolerance (&gt;0)
+     */
     public void setERP(float ERP) {
         setERP(motorId, ERP);
     }
 
     private native void setERP(long motorId, float ERP);
 
+    /**
+     * Read this motor's bounce.
+     *
+     * @return the bounce (restitution factor)
+     */
     public float getBounce() {
         return getBounce(motorId);
     }
 
     private native float getBounce(long motorId);
 
+    /**
+     * Alter this motor's bounce.
+     *
+     * @param bounce the desired bounce (restitution factor)
+     */
     public void setBounce(float bounce) {
         setBounce(motorId, bounce);
     }
 
     private native void setBounce(long motorId, float limitSoftness);
 
+    /**
+     * Test whether this motor is enabled.
+     *
+     * @return true if enabled, otherwise false
+     */
     public boolean isEnableMotor() {
         return isEnableMotor(motorId);
     }
 
     private native boolean isEnableMotor(long motorId);
 
+    /**
+     * Enable or disable this motor.
+     *
+     * @param enableMotor true&rarr;enable, false&rarr;disable
+     */
     public void setEnableMotor(boolean enableMotor) {
         setEnableMotor(motorId, enableMotor);
     }

+ 79 - 1
jme3-bullet/src/main/java/com/jme3/bullet/joints/motors/TranslationalLimitMotor.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,21 +34,42 @@ package com.jme3.bullet.joints.motors;
 import com.jme3.math.Vector3f;
 
 /**
+ * A motor based on Bullet's btTranslationalLimitMotor. Motors are used to drive
+ * joints.
  *
  * @author normenhansen
  */
 public class TranslationalLimitMotor {
 
+    /**
+     * Unique identifier of the btTranslationalLimitMotor. The constructor sets
+     * this to a non-zero value. After that, the id never changes.
+     */
     private long motorId = 0;
 
+    /**
+     * Instantiate a motor for the identified btTranslationalLimitMotor.
+     *
+     * @param motor the unique identifier (not zero)
+     */
     public TranslationalLimitMotor(long motor) {
         this.motorId = motor;
     }
 
+    /**
+     * Read the id of the btTranslationalLimitMotor.
+     *
+     * @return the unique identifier (not zero)
+     */
     public long getMotor() {
         return motorId;
     }
 
+    /**
+     * Copy this motor's constraint lower limits.
+     *
+     * @return a new vector (not null)
+     */
     public Vector3f getLowerLimit() {
         Vector3f vec = new Vector3f();
         getLowerLimit(motorId, vec);
@@ -57,12 +78,22 @@ public class TranslationalLimitMotor {
 
     private native void getLowerLimit(long motorId, Vector3f vector);
 
+    /**
+     * Alter the constraint lower limits.
+     *
+     * @param lowerLimit (unaffected, not null)
+     */
     public void setLowerLimit(Vector3f lowerLimit) {
         setLowerLimit(motorId, lowerLimit);
     }
 
     private native void setLowerLimit(long motorId, Vector3f vector);
     
+    /**
+     * Copy this motor's constraint upper limits.
+     *
+     * @return a new vector (not null)
+     */
     public Vector3f getUpperLimit() {
         Vector3f vec = new Vector3f();
         getUpperLimit(motorId, vec);
@@ -71,12 +102,22 @@ public class TranslationalLimitMotor {
 
     private native void getUpperLimit(long motorId, Vector3f vector);
 
+    /**
+     * Alter the constraint upper limits.
+     *
+     * @param upperLimit (unaffected, not null)
+     */
     public void setUpperLimit(Vector3f upperLimit) {
         setUpperLimit(motorId, upperLimit);
     }
 
     private native void setUpperLimit(long motorId, Vector3f vector);
 
+    /**
+     * Copy the accumulated impulse.
+     *
+     * @return a new vector (not null)
+     */
     public Vector3f getAccumulatedImpulse() {
         Vector3f vec = new Vector3f();
         getAccumulatedImpulse(motorId, vec);
@@ -85,42 +126,79 @@ public class TranslationalLimitMotor {
 
     private native void getAccumulatedImpulse(long motorId, Vector3f vector);
     
+    /**
+     * Alter the accumulated impulse.
+     *
+     * @param accumulatedImpulse the desired vector (not null, unaffected)
+     */
     public void setAccumulatedImpulse(Vector3f accumulatedImpulse) {
         setAccumulatedImpulse(motorId, accumulatedImpulse);
     }
 
     private native void setAccumulatedImpulse(long motorId, Vector3f vector);
 
+    /**
+     * Read this motor's limit softness.
+     *
+     * @return the softness
+     */
     public float getLimitSoftness() {
         return getLimitSoftness(motorId);
     }
     
     private native float getLimitSoftness(long motorId);
 
+    /**
+     * Alter the limit softness.
+     *
+     * @param limitSoftness the desired limit softness (default=0.5)
+     */
     public void setLimitSoftness(float limitSoftness) {
         setLimitSoftness(motorId, limitSoftness);
     }
     
     private native void setLimitSoftness(long motorId, float limitSoftness);
 
+    /**
+     * Read this motor's damping.
+     *
+     * @return the viscous damping ratio (0&rarr;no damping, 1&rarr;critically
+     * damped)
+     */
     public float getDamping() {
         return getDamping(motorId);
     }
 
     private native float getDamping(long motorId);
     
+    /**
+     * Alter this motor's damping.
+     *
+     * @param damping the desired viscous damping ratio (0&rarr;no damping,
+     * 1&rarr;critically damped, default=1)
+     */
     public void setDamping(float damping) {
         setDamping(motorId, damping);
     }
 
     private native void setDamping(long motorId, float damping);
     
+    /**
+     * Read this motor's restitution.
+     *
+     * @return the restitution (bounce) factor
+     */
     public float getRestitution() {
         return getRestitution(motorId);
     }
     
     private native float getRestitution(long motorId);
 
+    /**
+     * Alter this motor's restitution.
+     *
+     * @param restitution the desired restitution (bounce) factor
+     */
     public void setRestitution(float restitution) {
         setRestitution(motorId, restitution);
     }

+ 243 - 21
jme3-bullet/src/main/java/com/jme3/bullet/objects/PhysicsCharacter.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,11 +44,19 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * Basic Bullet Character
+ * A collision object for simplified character simulation, based on Bullet's
+ * btKinematicCharacterController.
+ *
  * @author normenhansen
  */
 public class PhysicsCharacter extends PhysicsCollisionObject {
 
+   /**
+     * Unique identifier of btKinematicCharacterController (as opposed to its
+     * collision object, which is a ghost). Constructors are responsible for
+     * setting this to a non-zero value. The id might change if the character
+     * gets rebuilt.
+     */
     protected long characterId = 0;
     protected float stepHeight;
     protected Vector3f walkDirection = new Vector3f();
@@ -59,12 +67,19 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
     //TEMP VARIABLES
     protected final Quaternion tmp_inverseWorldRotation = new Quaternion();
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public PhysicsCharacter() {
     }
 
     /**
-     * @param shape The CollisionShape (no Mesh or CompoundCollisionShapes)
-     * @param stepHeight The quantization size for vertical movement
+     * Instantiate a character with the specified collision shape and step
+     * height.
+     *
+     * @param shape the desired shape (not null, alias created)
+     * @param stepHeight the quantization size for vertical movement
      */
     public PhysicsCharacter(CollisionShape shape, float stepHeight) {
         this.collisionShape = shape;
@@ -75,6 +90,9 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
         buildObject();
     }
 
+    /**
+     * Create the configured character in Bullet.
+     */
     protected void buildObject() {
         if (objectId == 0) {
             objectId = createGhostObject();
@@ -98,8 +116,9 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
     private native long createCharacterObject(long objectId, long shapeId, float stepHeight);
 
     /**
-     * Sets the location of this physics character
-     * @param location
+     * Directly alter the location of this character's center of mass.
+     *
+     * @param location the desired physics location (not null, unaffected)
      */
     public void warp(Vector3f location) {
         warp(characterId, location);
@@ -108,11 +127,11 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
     private native void warp(long characterId, Vector3f location);
 
     /**
-     * Set the walk direction, works continuously.
-     * This should probably be called setPositionIncrementPerSimulatorStep.
-     * This is neither a direction nor a velocity, but the amount to
-     * increment the position each physics tick. So vector length = accuracy*speed in m/s
-     * @param vec the walk direction to set
+     * Alter the walk offset. The offset will continue to be applied until
+     * altered again.
+     *
+     * @param vec the desired position increment for each physics tick (not
+     * null, unaffected)
      */
     public void setWalkDirection(Vector3f vec) {
         walkDirection.set(vec);
@@ -122,7 +141,9 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
     private native void setWalkDirection(long characterId, Vector3f vec);
 
     /**
-     * @return the currently set walkDirection
+     * Access the walk offset.
+     *
+     * @return the pre-existing instance
      */
     public Vector3f getWalkDirection() {
         return walkDirection;
@@ -130,6 +151,7 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
     
     /**
      * @deprecated Deprecated in bullet 2.86.1 use setUp(Vector3f) instead
+     * @param axis which axis: 0&rarr;X, 1&rarr;Y, 2&rarr;Z
      */
     @Deprecated
 	public void setUpAxis(int axis) {
@@ -147,6 +169,11 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
 		}
 	}
     
+    /**
+     * Alter this character's "up" direction.
+     *
+     * @param axis the desired direction (not null, not zero, unaffected)
+     */
     public void setUp(Vector3f axis) {
         setUp(characterId, axis);
     }
@@ -154,6 +181,11 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
 
     private native void setUp(long characterId, Vector3f axis);
 
+    /**
+     * Alter this character's angular velocity.
+     *
+     * @param v the desired angular velocity vector (not null, unaffected)
+     */
     
     public void setAngularVelocity(Vector3f v){
     	setAngularVelocity(characterId,v);
@@ -161,7 +193,13 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
         
     private native void setAngularVelocity(long characterId, Vector3f v);
 
-
+    /**
+     * Copy this character's angular velocity.
+     *
+     * @param out storage for the result (modified if not null)
+     * @return the velocity vector (either the provided storage or a new vector,
+     * not null)
+     */
     public Vector3f getAngularVelocity(Vector3f out){
     	if(out==null)out=new Vector3f();
     	getAngularVelocity(characterId,out);
@@ -171,13 +209,23 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
     private native void getAngularVelocity(long characterId, Vector3f out);
     
 
+    /**
+     * Alter the linear velocity of this character's center of mass.
+     *
+     * @param v the desired velocity vector (not null)
+     */
     public void setLinearVelocity(Vector3f v){
     	setLinearVelocity(characterId,v);
     }
         
     private native void setLinearVelocity(long characterId, Vector3f v);
 
-
+    /**
+     * Copy the linear velocity of this character's center of mass.
+     *
+     * @param out storage for the result (modified if not null)
+     * @return a vector (either the provided storage or a new vector, not null)
+     */
     public Vector3f getLinearVelocity(Vector3f out){
     	if(out==null)out=new Vector3f();
     	getLinearVelocity(characterId,out);
@@ -187,10 +235,20 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
     private native void getLinearVelocity(long characterId, Vector3f out);
         
 
+    /**
+     * Read the index of the "up" axis.
+     *
+     * @return which axis: 0&rarr;X, 1&rarr;Y, 2&rarr;Z
+     */
     public int getUpAxis() {
         return upAxis;
     }
 
+    /**
+     * Alter this character's fall speed.
+     *
+     * @param fallSpeed the desired speed (default=55)
+     */
     public void setFallSpeed(float fallSpeed) {
         this.fallSpeed = fallSpeed;
         setFallSpeed(characterId, fallSpeed);
@@ -198,10 +256,20 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
 
     private native void setFallSpeed(long characterId, float fallSpeed);
 
+    /**
+     * Read this character's fall speed.
+     *
+     * @return speed
+     */
     public float getFallSpeed() {
         return fallSpeed;
     }
 
+    /**
+     * Alter this character's jump speed.
+     *
+     * @param jumpSpeed the desired speed (default=10)
+     */
     public void setJumpSpeed(float jumpSpeed) {
         this.jumpSpeed = jumpSpeed;
         setJumpSpeed(characterId, jumpSpeed);
@@ -209,18 +277,30 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
 
     private native void setJumpSpeed(long characterId, float jumpSpeed);
 
+    /**
+     * Read this character's jump speed.
+     *
+     * @return speed
+     */
     public float getJumpSpeed() {
         return jumpSpeed;
     }
 
     /**
      * @deprecated Deprecated in bullet 2.86.1. Use setGravity(Vector3f) instead.
+     * @param value the desired upward component of the acceleration (typically
+     * negative)
      */
     @Deprecated
     public void setGravity(float value) {
     	setGravity(new Vector3f(0,value,0));
     }
     
+    /**
+     * Alter this character's gravitational acceleration.
+     *
+     * @param value the desired acceleration vector (not null, unaffected)
+     */
     public void setGravity(Vector3f value) {
         setGravity(characterId, value);
     }
@@ -229,12 +309,20 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
 
     /**
      * @deprecated Deprecated in bullet 2.86.1. Use getGravity(Vector3f) instead.
+     * @return the upward component of the acceleration (typically negative)
      */
     @Deprecated
     public float getGravity() {
         return getGravity(null).y;
     }
 
+    /**
+     * Copy this character's gravitational acceleration.
+     *
+     * @param out storage for the result (modified if not null)
+     * @return the acceleration vector (either the provided storage or a new
+     * vector, not null)
+     */
     public Vector3f getGravity(Vector3f out) {
     	if(out==null)out=new Vector3f();
     	getGravity(characterId,out);
@@ -244,12 +332,24 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
     private native void getGravity(long characterId,Vector3f out);
 
         
+    /**
+     * Read this character's linear damping.
+     *
+     * @return the viscous damping ratio (0&rarr;no damping, 1&rarr;critically
+     * damped)
+     */        
     public float getLinearDamping(){
     	return getLinearDamping(characterId);
     }
     
     private native float getLinearDamping(long characterId);
     
+    /**
+     * Alter this character's linear damping.
+     *
+     * @param v the desired viscous damping ratio (0&rarr;no damping,
+     * 1&rarr;critically damped)
+     */
         
     public void setLinearDamping(float v ){
     	setLinearDamping(characterId,v );
@@ -258,13 +358,24 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
     private native void setLinearDamping(long characterId,float v);
     
     
+    /**
+     * Read this character's angular damping.
+     *
+     * @return the viscous damping ratio (0&rarr;no damping, 1&rarr;critically
+     * damped)
+     */
     public float getAngularDamping(){
     	return getAngularDamping(characterId);
     }
     
     private native float getAngularDamping(long characterId);
     
-        
+    /**
+     * Alter this character's angular damping.
+     *
+     * @param v the desired viscous damping ratio (0&rarr;no damping,
+     * 1&rarr;critically damped, default=0)
+     */        
     public void setAngularDamping(float v ){
     	setAngularDamping(characterId,v );
     }
@@ -272,13 +383,22 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
     private native void setAngularDamping(long characterId,float v);
     
     
+    /**
+     * Read this character's step height.
+     *
+     * @return the height (in physics-space units)
+     */
     public float getStepHeight(){
     	return getStepHeight(characterId);
     }
     
     private native float getStepHeight(long characterId);
     
-        
+    /**
+     * Alter this character's step height.
+     *
+     * @param v the desired height (in physics-space units)
+     */        
     public void setStepHeight(float v ){
     	setStepHeight(characterId,v );
     }
@@ -286,13 +406,22 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
     private native void setStepHeight(long characterId,float v);
     
     
+    /**
+     * Read this character's maximum penetration depth.
+     *
+     * @return the depth (in physics-space units)
+     */
     public float getMaxPenetrationDepth(){
     	return getMaxPenetrationDepth(characterId);
     }
     
     private native float getMaxPenetrationDepth(long characterId);
     
-        
+    /**
+     * Alter this character's maximum penetration depth.
+     *
+     * @param v the desired depth (in physics-space units)
+     */        
     public void setMaxPenetrationDepth(float v ){
     	setMaxPenetrationDepth(characterId,v );
     }
@@ -303,18 +432,33 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
     
     
     
+    /**
+     * Alter this character's maximum slope angle.
+     *
+     * @param slopeRadians the desired angle (in radians)
+     */
     public void setMaxSlope(float slopeRadians) {
         setMaxSlope(characterId, slopeRadians);
     }
 
     private native void setMaxSlope(long characterId, float slopeRadians);
 
+    /**
+     * Read this character's maximum slope angle.
+     *
+     * @return the angle (in radians)
+     */
     public float getMaxSlope() {
         return getMaxSlope(characterId);
     }
 
     private native float getMaxSlope(long characterId);
 
+    /**
+     * Test whether this character is on the ground.
+     *
+     * @return true if on the ground, otherwise false
+     */
     public boolean onGround() {
         return onGround(characterId);
     }
@@ -330,12 +474,24 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
     }
     
     
+    /**
+     * Jump in the specified direction.
+     *
+     * @param dir desired jump direction (not null, unaffected)
+     */
     public void jump(Vector3f dir) {
     	jump(characterId,dir);
     }
     
     private native void jump(long characterId,Vector3f v);
 
+    /**
+     * Apply the specified CollisionShape to this character. Note that the
+     * character should not be in any physics space while changing shape; the
+     * character gets rebuilt on the physics side.
+     *
+     * @param collisionShape the shape to apply (not null, alias created)
+     */
     @Override
     public void setCollisionShape(CollisionShape collisionShape) {
 //        if (!(collisionShape.getObjectId() instanceof ConvexShape)) {
@@ -350,15 +506,21 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
     }
 
     /**
-     * Set the physics location (same as warp())
-     * @param location the location of the actual physics object
+     * Directly alter this character's location. (Same as
+     * {@link #warp(com.jme3.math.Vector3f)}).)
+     *
+     * @param location the desired location (not null, unaffected)
      */
     public void setPhysicsLocation(Vector3f location) {
         warp(location);
     }
 
     /**
-     * @return the physicsLocation
+     * Copy the location of this character's center of mass.
+     *
+     * @param trans storage for the result (modified if not null)
+     * @return the location vector (either the provided storage or a new vector,
+     * not null)
      */
     public Vector3f getPhysicsLocation(Vector3f trans) {
         if (trans == null) {
@@ -371,36 +533,72 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
     private native void getPhysicsLocation(long objectId, Vector3f vec);
 
     /**
-     * @return the physicsLocation
+     * Copy the location of this character's center of mass.
+     *
+     * @return a new location vector (not null)
      */
     public Vector3f getPhysicsLocation() {
         return getPhysicsLocation(null);
     }
 
+    /**
+     * Alter this character's continuous collision detection (CCD) swept sphere
+     * radius.
+     *
+     * @param radius (&ge;0, default=0)
+     */
     public void setCcdSweptSphereRadius(float radius) {
         setCcdSweptSphereRadius(objectId, radius);
     }
 
     private native void setCcdSweptSphereRadius(long objectId, float radius);
 
+    /**
+     * Alter the amount of motion required to activate continuous collision
+     * detection (CCD).
+     * <p>
+     * This addresses the issue of fast objects passing through other objects
+     * with no collision detected.
+     *
+     * @param threshold the desired threshold velocity (&gt;0) or zero to
+     * disable CCD (default=0)
+     */
     public void setCcdMotionThreshold(float threshold) {
         setCcdMotionThreshold(objectId, threshold);
     }
 
     private native void setCcdMotionThreshold(long objectId, float threshold);
 
+    /**
+     * Read the radius of the sphere used for continuous collision detection
+     * (CCD).
+     *
+     * @return radius (&ge;0)
+     */
     public float getCcdSweptSphereRadius() {
         return getCcdSweptSphereRadius(objectId);
     }
 
     private native float getCcdSweptSphereRadius(long objectId);
 
+    /**
+     * Calculate this character's continuous collision detection (CCD) motion
+     * threshold.
+     *
+     * @return the threshold velocity (&ge;0)
+     */
     public float getCcdMotionThreshold() {
         return getCcdMotionThreshold(objectId);
     }
 
     private native float getCcdMotionThreshold(long objectId);
 
+    /**
+     * Calculate the square of this character's continuous collision detection
+     * (CCD) motion threshold.
+     *
+     * @return the threshold velocity squared (&ge;0)
+     */
     public float getCcdSquareMotionThreshold() {
         return getCcdSquareMotionThreshold(objectId);
     }
@@ -409,14 +607,25 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
 
     /**
      * used internally
+     *
+     * @return the Bullet id
      */
     public long getControllerId() {
         return characterId;
     }
 
+    /**
+     * Has no effect.
+     */
     public void destroy() {
     }
 
+    /**
+     * Serialize this character, for example when saving to a J3O file.
+     *
+     * @param e exporter (not null)
+     * @throws IOException from exporter
+     */
     @Override
     public void write(JmeExporter e) throws IOException {
         super.write(e);
@@ -432,6 +641,13 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
         capsule.write(getPhysicsLocation(new Vector3f()), "physicsLocation", new Vector3f());
     }
 
+    /**
+     * De-serialize this character from the specified importer, for example when
+     * loading from a J3O file.
+     *
+     * @param e importer (not null)
+     * @throws IOException from importer
+     */
     @Override
     public void read(JmeImporter e) throws IOException {
         super.read(e);
@@ -448,6 +664,12 @@ public class PhysicsCharacter extends PhysicsCollisionObject {
         setPhysicsLocation((Vector3f) capsule.readSavable("physicsLocation", new Vector3f()));
     }
 
+    /**
+     * Finalize this physics character just before it is destroyed. Should be
+     * invoked only by a subclass or by the garbage collector.
+     *
+     * @throws Throwable ignored by the garbage collector
+     */
     @Override
     protected void finalize() throws Throwable {
         super.finalize();

+ 127 - 24
jme3-bullet/src/main/java/com/jme3/bullet/objects/PhysicsGhostObject.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,11 +48,14 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
+ * A collision object for intangibles, based on Bullet's
+ * btPairCachingGhostObject. This is useful for creating a character controller,
+ * collision sensors/triggers, explosions etc.
+ * <p>
  * <i>From Bullet manual:</i><br>
- * GhostObject can keep track of all objects that are overlapping.
- * By default, this overlap is based on the AABB.
- * This is useful for creating a character controller,
- * collision sensors/triggers, explosions etc.<br>
+ * btGhostObject is a special btCollisionObject, useful for fast localized
+ * collision queries.
+ *
  * @author normenhansen
  */
 public class PhysicsGhostObject extends PhysicsCollisionObject {
@@ -61,9 +64,18 @@ public class PhysicsGhostObject extends PhysicsCollisionObject {
     protected final Quaternion tmp_inverseWorldRotation = new Quaternion();
     private List<PhysicsCollisionObject> overlappingObjects = new LinkedList<PhysicsCollisionObject>();
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public PhysicsGhostObject() {
     }
 
+    /**
+     * Instantiate an object with the specified collision shape.
+     *
+     * @param shape the desired shape (not null, alias created)
+     */
     public PhysicsGhostObject(CollisionShape shape) {
         collisionShape = shape;
         buildObject();
@@ -74,6 +86,9 @@ public class PhysicsGhostObject extends PhysicsCollisionObject {
         buildObject();
     }
 
+    /**
+     * Create the configured object in Bullet.
+     */
     protected void buildObject() {
         if (objectId == 0) {
 //            gObject = new PairCachingGhostObject();
@@ -93,6 +108,13 @@ public class PhysicsGhostObject extends PhysicsCollisionObject {
 
     private native void setGhostFlags(long objectId);
 
+    /**
+     * Apply the specified CollisionShape to this object. Note that the object
+     * should not be in any physics space while changing shape; the object gets
+     * rebuilt on the physics side.
+     *
+     * @param collisionShape the shape to apply (not null, alias created)
+     */
     @Override
     public void setCollisionShape(CollisionShape collisionShape) {
         super.setCollisionShape(collisionShape);
@@ -104,8 +126,9 @@ public class PhysicsGhostObject extends PhysicsCollisionObject {
     }
 
     /**
-     * Sets the physics object location
-     * @param location the location of the actual physics object
+     * Directly alter the location of this object's center.
+     *
+     * @param location the desired location (not null, unaffected)
      */
     public void setPhysicsLocation(Vector3f location) {
         setPhysicsLocation(objectId, location);
@@ -114,8 +137,10 @@ public class PhysicsGhostObject extends PhysicsCollisionObject {
     private native void setPhysicsLocation(long objectId, Vector3f location);
 
     /**
-     * Sets the physics object rotation
-     * @param rotation the rotation of the actual physics object
+     * Directly alter this object's orientation.
+     *
+     * @param rotation the desired orientation (rotation matrix, not null,
+     * unaffected)
      */
     public void setPhysicsRotation(Matrix3f rotation) {
         setPhysicsRotation(objectId, rotation);
@@ -124,8 +149,10 @@ public class PhysicsGhostObject extends PhysicsCollisionObject {
     private native void setPhysicsRotation(long objectId, Matrix3f rotation);
 
     /**
-     * Sets the physics object rotation
-     * @param rotation the rotation of the actual physics object
+     * Directly alter this object's orientation.
+     *
+     * @param rotation the desired orientation (quaternion, not null,
+     * unaffected)
      */
     public void setPhysicsRotation(Quaternion rotation) {
         setPhysicsRotation(objectId, rotation);
@@ -134,7 +161,11 @@ public class PhysicsGhostObject extends PhysicsCollisionObject {
     private native void setPhysicsRotation(long objectId, Quaternion rotation);
 
     /**
-     * @return the physicsLocation
+     * Copy the location of this object's center.
+     *
+     * @param trans storage for the result (modified if not null)
+     * @return the physics location (either the provided storage or a new
+     * vector, not null)
      */
     public Vector3f getPhysicsLocation(Vector3f trans) {
         if (trans == null) {
@@ -147,7 +178,11 @@ public class PhysicsGhostObject extends PhysicsCollisionObject {
     private native void getPhysicsLocation(long objectId, Vector3f vector);
 
     /**
-     * @return the physicsLocation
+     * Copy this object's orientation to a quaternion.
+     *
+     * @param rot storage for the result (modified if not null)
+     * @return the physics orientation (either the provided storage or a new
+     * quaternion, not null)
      */
     public Quaternion getPhysicsRotation(Quaternion rot) {
         if (rot == null) {
@@ -160,7 +195,11 @@ public class PhysicsGhostObject extends PhysicsCollisionObject {
     private native void getPhysicsRotation(long objectId, Quaternion rot);
 
     /**
-     * @return the physicsLocation
+     * Copy this object's orientation to a matrix.
+     *
+     * @param rot storage for the result (modified if not null)
+     * @return the orientation (either the provided storage or a new matrix, not
+     * null)
      */
     public Matrix3f getPhysicsRotationMatrix(Matrix3f rot) {
         if (rot == null) {
@@ -173,7 +212,9 @@ public class PhysicsGhostObject extends PhysicsCollisionObject {
     private native void getPhysicsRotationMatrix(long objectId, Matrix3f rot);
 
     /**
-     * @return the physicsLocation
+     * Copy the location of this object's center.
+     *
+     * @return a new location vector (not null)
      */
     public Vector3f getPhysicsLocation() {
         Vector3f vec = new Vector3f();
@@ -182,7 +223,9 @@ public class PhysicsGhostObject extends PhysicsCollisionObject {
     }
 
     /**
-     * @return the physicsLocation
+     * Copy this object's orientation to a quaternion.
+     *
+     * @return a new quaternion (not null)
      */
     public Quaternion getPhysicsRotation() {
         Quaternion quat = new Quaternion();
@@ -190,6 +233,11 @@ public class PhysicsGhostObject extends PhysicsCollisionObject {
         return quat;
     }
 
+    /**
+     * Copy this object's orientation to a matrix.
+     *
+     * @return a new matrix (not null)
+     */
     public Matrix3f getPhysicsRotationMatrix() {
         Matrix3f mtx = new Matrix3f();
         getPhysicsRotationMatrix(objectId, mtx);
@@ -203,16 +251,18 @@ public class PhysicsGhostObject extends PhysicsCollisionObject {
 //        return gObject;
 //    }
     /**
-     * destroys this PhysicsGhostNode and removes it from memory
+     * Has no effect.
      */
     public void destroy() {
     }
 
     /**
-     * Another Object is overlapping with this GhostNode,
-     * if and if only there CollisionShapes overlaps.
-     * They could be both regular PhysicsRigidBodys or PhysicsGhostObjects.
-     * @return All CollisionObjects overlapping with this GhostNode.
+     * Access a list of overlapping objects.
+     * <p>
+     * Another object overlaps with this one if and if only their
+     * CollisionShapes overlap.
+     *
+     * @return an internal list which may get reused (not null)
      */
     public List<PhysicsCollisionObject> getOverlappingObjects() {
         overlappingObjects.clear();
@@ -225,13 +275,19 @@ public class PhysicsGhostObject extends PhysicsCollisionObject {
 
     protected native void getOverlappingObjects(long objectId);
 
+    /**
+     * This method is invoked from native code.
+     *
+     * @param co the collision object to add
+     */
     private void addOverlappingObject_native(PhysicsCollisionObject co) {
         overlappingObjects.add(co);
     }
 
     /**
+     * Count how many CollisionObjects this object overlaps.
      *
-     * @return With how many other CollisionObjects this GhostNode is currently overlapping.
+     * @return count (&ge;0)
      */
     public int getOverlappingCount() {
         return getOverlappingCount(objectId);
@@ -240,44 +296,84 @@ public class PhysicsGhostObject extends PhysicsCollisionObject {
     private native int getOverlappingCount(long objectId);
 
     /**
+     * Access an overlapping collision object by its position in the list.
      *
-     * @param index The index of the overlapping Node to retrieve.
-     * @return The Overlapping CollisionObject at the given index.
+     * @param index which list position (&ge;0, &lt;count)
+     * @return the pre-existing object
      */
     public PhysicsCollisionObject getOverlapping(int index) {
         return overlappingObjects.get(index);
     }
 
+    /**
+     * Alter the continuous collision detection (CCD) swept sphere radius for
+     * this object.
+     *
+     * @param radius (&ge;0)
+     */
     public void setCcdSweptSphereRadius(float radius) {
         setCcdSweptSphereRadius(objectId, radius);
     }
 
     private native void setCcdSweptSphereRadius(long objectId, float radius);
 
+    /**
+     * Alter the amount of motion required to trigger continuous collision
+     * detection (CCD).
+     * <p>
+     * This addresses the issue of fast objects passing through other objects
+     * with no collision detected.
+     *
+     * @param threshold the desired threshold value (squared velocity, &gt;0) or
+     * zero to disable CCD (default=0)
+     */
     public void setCcdMotionThreshold(float threshold) {
         setCcdMotionThreshold(objectId, threshold);
     }
 
     private native void setCcdMotionThreshold(long objectId, float threshold);
 
+    /**
+     * Read the radius of the sphere used for continuous collision detection
+     * (CCD).
+     *
+     * @return radius (&ge;0)
+     */
     public float getCcdSweptSphereRadius() {
         return getCcdSweptSphereRadius(objectId);
     }
 
     private native float getCcdSweptSphereRadius(long objectId);
 
+    /**
+     * Read the continuous collision detection (CCD) motion threshold for this
+     * object.
+     *
+     * @return threshold value (squared velocity, &ge;0)
+     */
     public float getCcdMotionThreshold() {
         return getCcdMotionThreshold(objectId);
     }
 
     private native float getCcdMotionThreshold(long objectId);
 
+    /**
+     * Read the CCD square motion threshold for this object.
+     *
+     * @return threshold value (&ge;0)
+     */
     public float getCcdSquareMotionThreshold() {
         return getCcdSquareMotionThreshold(objectId);
     }
 
     private native float getCcdSquareMotionThreshold(long objectId);
 
+    /**
+     * Serialize this object, for example when saving to a J3O file.
+     *
+     * @param e exporter (not null)
+     * @throws IOException from exporter
+     */
     @Override
     public void write(JmeExporter e) throws IOException {
         super.write(e);
@@ -288,6 +384,13 @@ public class PhysicsGhostObject extends PhysicsCollisionObject {
         capsule.write(getCcdSweptSphereRadius(), "ccdSweptSphereRadius", 0);
     }
 
+    /**
+     * De-serialize this object from the specified importer, for example when
+     * loading from a J3O file.
+     *
+     * @param e importer (not null)
+     * @throws IOException from importer
+     */
     @Override
     public void read(JmeImporter e) throws IOException {
         super.read(e);

+ 358 - 76
jme3-bullet/src/main/java/com/jme3/bullet/objects/PhysicsRigidBody.java

@@ -51,29 +51,56 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * <p>PhysicsRigidBody - Basic physics object</p>
+ * A collision object for a rigid body, based on Bullet's btRigidBody.
+ *
  * @author normenhansen
  */
 public class PhysicsRigidBody extends PhysicsCollisionObject {
 
+    /**
+     * motion state
+     */
     protected RigidBodyMotionState motionState = new RigidBodyMotionState();
+    /**
+     * copy of mass (&gt;0) of a dynamic body, or 0 for a static body
+     * (default=1)
+     */
     protected float mass = 1.0f;
+    /**
+     * copy of kinematic flag: true&rarr;set kinematic mode (spatial controls
+     * body), false&rarr;dynamic/static mode (body controls spatial)
+     * (default=false)
+     */
     protected boolean kinematic = false;
+    /**
+     * joint list
+     */
     protected ArrayList<PhysicsJoint> joints = new ArrayList<PhysicsJoint>();
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public PhysicsRigidBody() {
     }
 
     /**
-     * Creates a new PhysicsRigidBody with the supplied collision shape
-     * @param child
-     * @param shape
+     * Instantiate a dynamic body with mass=1 and the specified collision shape.
+     *
+     * @param shape the desired shape (not null, alias created)
      */
     public PhysicsRigidBody(CollisionShape shape) {
         collisionShape = shape;
         rebuildRigidBody();
     }
 
+    /**
+     * Instantiate a body with the specified collision shape and mass.
+     *
+     * @param shape the desired shape (not null, alias created)
+     * @param mass if 0, a static body is created; otherwise a dynamic body is
+     * created (&ge;0)
+     */
     public PhysicsRigidBody(CollisionShape shape, float mass) {
         collisionShape = shape;
         this.mass = mass;
@@ -81,7 +108,7 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     }
 
     /**
-     * Builds/rebuilds the phyiscs body when parameters have changed
+     * Build/rebuild this body after parameters have changed.
      */
     protected void rebuildRigidBody() {
         boolean removed = false;
@@ -105,11 +132,17 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
         }
     }
 
+    /**
+     * For use by subclasses.
+     */
     protected void preRebuild() {
     }
 
     private native long createRigidBody(float mass, long motionStateId, long collisionShapeId);
 
+    /**
+     * For use by subclasses.
+     */
     protected void postRebuild() {
         if (mass == 0.0f) {
             setStatic(objectId, true);
@@ -120,12 +153,19 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     }
 
     /**
-     * @return the motionState
+     * Access this body's motion state.
+     *
+     * @return the pre-existing instance
      */
     public RigidBodyMotionState getMotionState() {
         return motionState;
     }
 
+    /**
+     * Test whether this body is in a physics space.
+     *
+     * @return true&rarr;in a space, false&rarr;not in a space
+     */
     public boolean isInWorld() {
         return isInWorld(objectId);
     }
@@ -133,8 +173,9 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native boolean isInWorld(long objectId);
 
     /**
-     * Sets the physics object location
-     * @param location the location of the actual physics object
+     * Directly alter the location of this body's center of mass.
+     *
+     * @param location the desired location (not null, unaffected)
      */
     public void setPhysicsLocation(Vector3f location) {
         setPhysicsLocation(objectId, location);
@@ -143,8 +184,10 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native void setPhysicsLocation(long objectId, Vector3f location);
 
     /**
-     * Sets the physics object rotation
-     * @param rotation the rotation of the actual physics object
+     * Directly alter this body's orientation.
+     *
+     * @param rotation the desired orientation (rotation matrix, not null,
+     * unaffected)
      */
     public void setPhysicsRotation(Matrix3f rotation) {
         setPhysicsRotation(objectId, rotation);
@@ -153,8 +196,10 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native void setPhysicsRotation(long objectId, Matrix3f rotation);
 
     /**
-     * Sets the physics object rotation
-     * @param rotation the rotation of the actual physics object
+     * Directly alter this body's orientation.
+     *
+     * @param rotation the desired orientation (quaternion, not null,
+     * unaffected)
      */
     public void setPhysicsRotation(Quaternion rotation) {
         setPhysicsRotation(objectId, rotation);
@@ -163,7 +208,11 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native void setPhysicsRotation(long objectId, Quaternion rotation);
 
     /**
-     * @return the physicsLocation
+     * Copy the location of this body's center of mass.
+     *
+     * @param trans storage for the result (modified if not null)
+     * @return the location (either the provided storage or a new vector, not
+     * null)
      */
     public Vector3f getPhysicsLocation(Vector3f trans) {
         if (trans == null) {
@@ -176,7 +225,11 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native void getPhysicsLocation(long objectId, Vector3f vector);
 
     /**
-     * @return the physicsLocation
+     * Copy this body's orientation to a quaternion.
+     *
+     * @param rot storage for the result (modified if not null)
+     * @return the orientation (either the provided storage or a new quaternion,
+     * not null)
      */
     public Quaternion getPhysicsRotation(Quaternion rot) {
         if (rot == null) {
@@ -185,12 +238,23 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
         getPhysicsRotation(objectId, rot);
         return rot;
     }
-    
+
+    /**
+     * Alter the principal components of the local inertia tensor.
+     *
+     * @param gravity (not null, unaffected)
+     */
     public void setInverseInertiaLocal(Vector3f gravity) {
     	setInverseInertiaLocal(objectId, gravity);
     }
     private native void setInverseInertiaLocal(long objectId, Vector3f gravity);
-    
+
+    /**
+     * Read the principal components of the local inverse inertia tensor.
+     *
+     * @param trans storage for the result (modified if not null)
+     * @return a vector (either the provided storage or a new vector, not null)
+     */
     public Vector3f getInverseInertiaLocal(Vector3f trans) {
         if (trans == null) {
             trans = new Vector3f();
@@ -204,7 +268,11 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native void getPhysicsRotation(long objectId, Quaternion rot);
 
     /**
-     * @return the physicsLocation
+     * Copy this body's orientation to a matrix.
+     *
+     * @param rot storage for the result (modified if not null)
+     * @return the orientation (either the provided storage or a new matrix, not
+     * null)
      */
     public Matrix3f getPhysicsRotationMatrix(Matrix3f rot) {
         if (rot == null) {
@@ -217,7 +285,9 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native void getPhysicsRotationMatrix(long objectId, Matrix3f rot);
 
     /**
-     * @return the physicsLocation
+     * Copy the location of this body's center of mass.
+     *
+     * @return a new location vector (not null)
      */
     public Vector3f getPhysicsLocation() {
         Vector3f vec = new Vector3f();
@@ -226,7 +296,9 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     }
 
     /**
-     * @return the physicsLocation
+     * Copy this body's orientation to a quaternion.
+     *
+     * @return a new quaternion (not null)
      */
     public Quaternion getPhysicsRotation() {
         Quaternion quat = new Quaternion();
@@ -234,6 +306,11 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
         return quat;
     }
 
+    /**
+     * Copy this body's orientation to a matrix.
+     *
+     * @return a new matrix (not null)
+     */
     public Matrix3f getPhysicsRotationMatrix() {
         Matrix3f mtx = new Matrix3f();
         getPhysicsRotationMatrix(objectId, mtx);
@@ -264,10 +341,14 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
 //        return Converter.convert(tempTrans.basis, rotation);
 //    }
     /**
-     * Sets the node to kinematic mode. in this mode the node is not affected by physics
-     * but affects other physics objects. Its kinetic force is calculated by the amount
-     * of movement it is exposed to and its weight.
-     * @param kinematic
+     * Put this body into kinematic mode or take it out of kinematic mode.
+     * <p>
+     * In kinematic mode, the body is not influenced by physics but can affect
+     * other physics objects. Its kinetic force is calculated based on its
+     * movement and weight.
+     *
+     * @param kinematic true&rarr;set kinematic mode, false&rarr;set
+     * dynamic/static mode (default=false)
      */
     public void setKinematic(boolean kinematic) {
         this.kinematic = kinematic;
@@ -276,10 +357,25 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
 
     private native void setKinematic(long objectId, boolean kinematic);
 
+    /**
+     * Test whether this body is in kinematic mode.
+     * <p>
+     * In kinematic mode, the body is not influenced by physics but can affect
+     * other physics objects. Its kinetic force is calculated based on its
+     * movement and weight.
+     *
+     * @return true if in kinematic mode, otherwise false (dynamic/static mode)
+     */
     public boolean isKinematic() {
         return kinematic;
     }
 
+    /**
+     * Alter the radius of the swept sphere used for continuous collision
+     * detection (CCD).
+     *
+     * @param radius the desired radius (&ge;0, default=0)
+     */
     public void setCcdSweptSphereRadius(float radius) {
         setCcdSweptSphereRadius(objectId, radius);
     }
@@ -287,9 +383,14 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native void setCcdSweptSphereRadius(long objectId, float radius);
 
     /**
-     * Sets the amount of motion that has to happen in one physics tick to trigger the continuous motion detection<br/>
-     * This avoids the problem of fast objects moving through other objects, set to zero to disable (default)
-     * @param threshold
+     * Alter the amount of motion required to activate continuous collision
+     * detection (CCD).
+     * <p>
+     * This addresses the issue of fast objects passing through other objects
+     * with no collision detected.
+     *
+     * @param threshold the desired threshold velocity (&gt;0) or zero to
+     * disable CCD (default=0)
      */
     public void setCcdMotionThreshold(float threshold) {
         setCcdMotionThreshold(objectId, threshold);
@@ -297,31 +398,56 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
 
     private native void setCcdMotionThreshold(long objectId, float threshold);
 
+    /**
+     * Read the radius of the swept sphere used for continuous collision
+     * detection (CCD).
+     *
+     * @return radius (&ge;0)
+     */
     public float getCcdSweptSphereRadius() {
         return getCcdSweptSphereRadius(objectId);
     }
 
     private native float getCcdSweptSphereRadius(long objectId);
 
+    /**
+     * Calculate this body's continuous collision detection (CCD) motion
+     * threshold.
+     *
+     * @return the threshold velocity (&ge;0)
+     */
     public float getCcdMotionThreshold() {
         return getCcdMotionThreshold(objectId);
     }
 
     private native float getCcdMotionThreshold(long objectId);
 
+    /**
+     * Calculate the square of this body's continuous collision detection (CCD)
+     * motion threshold.
+     *
+     * @return the threshold velocity squared (&ge;0)
+     */
     public float getCcdSquareMotionThreshold() {
         return getCcdSquareMotionThreshold(objectId);
     }
 
     private native float getCcdSquareMotionThreshold(long objectId);
 
+    /**
+     * Read this body's mass.
+     *
+     * @return the mass (&gt;0) or zero for a static body
+     */
     public float getMass() {
         return mass;
     }
 
     /**
-     * Sets the mass of this PhysicsRigidBody, objects with mass=0 are static.
-     * @param mass
+     * Alter this body's mass. Bodies with mass=0 are static. For dynamic
+     * bodies, it is best to keep the mass around 1.
+     *
+     * @param mass the desired mass (&gt;0) or 0 for a static body (default=1)
      */
     public void setMass(float mass) {
         this.mass = mass;
@@ -344,10 +470,22 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
 
     private native long updateMassProps(long objectId, long collisionShapeId, float mass);
 
+    /**
+     * Copy this body's gravitational acceleration.
+     *
+     * @return a new acceleration vector (not null)
+     */
     public Vector3f getGravity() {
         return getGravity(null);
     }
 
+    /**
+     * Copy this body's gravitational acceleration.
+     *
+     * @param gravity storage for the result (modified if not null)
+     * @return an acceleration vector (either the provided storage or a new
+     * vector, not null)
+     */
     public Vector3f getGravity(Vector3f gravity) {
         if (gravity == null) {
             gravity = new Vector3f();
@@ -359,16 +497,23 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native void getGravity(long objectId, Vector3f gravity);
 
     /**
-     * Set the local gravity of this PhysicsRigidBody<br/>
-     * Set this after adding the node to the PhysicsSpace,
-     * the PhysicsSpace assigns its current gravity to the physics node when its added.
-     * @param gravity the gravity vector to set
+     * Alter this body's gravitational acceleration.
+     * <p>
+     * Invoke this after adding the body to a PhysicsSpace. Adding a body to a
+     * PhysicsSpace alters its gravity.
+     *
+     * @param gravity the desired acceleration vector (not null, unaffected)
      */
     public void setGravity(Vector3f gravity) {
         setGravity(objectId, gravity);
     }
     private native void setGravity(long objectId, Vector3f gravity);
 
+    /**
+     * Read this body's friction.
+     *
+     * @return friction value
+     */
     public float getFriction() {
         return getFriction(objectId);
     }
@@ -376,8 +521,9 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native float getFriction(long objectId);
 
     /**
-     * Sets the friction of this physics object
-     * @param friction the friction of this physics object
+     * Alter this body's friction.
+     *
+     * @param friction the desired friction value (default=0.5)
      */
     public void setFriction(float friction) {
         setFriction(objectId, friction);
@@ -385,6 +531,12 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
 
     private native void setFriction(long objectId, float friction);
 
+    /**
+     * Alter this body's damping.
+     *
+     * @param linearDamping the desired linear damping value (default=0)
+     * @param angularDamping the desired angular damping value (default=0)
+     */
     public void setDamping(float linearDamping, float angularDamping) {
         setDamping(objectId, linearDamping, angularDamping);
     }
@@ -400,27 +552,52 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
 //
 //    private native void setRestitution(long objectId, float factor);
 //
+    /**
+     * Alter this body's linear damping.
+     *
+     * @param linearDamping the desired linear damping value (default=0)
+     */
     public void setLinearDamping(float linearDamping) {
         setDamping(objectId, linearDamping, getAngularDamping());
     }
-    
+
+    /**
+     * Alter this body's angular damping.
+     *
+     * @param angularDamping the desired angular damping value (default=0)
+     */
     public void setAngularDamping(float angularDamping) {
         setAngularDamping(objectId, angularDamping);
     }
     private native void setAngularDamping(long objectId, float factor);
 
+    /**
+     * Read this body's linear damping.
+     *
+     * @return damping value
+     */
     public float getLinearDamping() {
         return getLinearDamping(objectId);
     }
 
     private native float getLinearDamping(long objectId);
 
+    /**
+     * Read this body's angular damping.
+     *
+     * @return damping value
+     */
     public float getAngularDamping() {
         return getAngularDamping(objectId);
     }
 
     private native float getAngularDamping(long objectId);
 
+    /**
+     * Read this body's restitution (bounciness).
+     *
+     * @return restitution value
+     */
     public float getRestitution() {
         return getRestitution(objectId);
     }
@@ -428,8 +605,10 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native float getRestitution(long objectId);
 
     /**
-     * The "bouncyness" of the PhysicsRigidBody, best performance if restitution=0
-     * @param restitution
+     * Alter this body's restitution (bounciness). For best performance, set
+     * restitution=0.
+     *
+     * @param restitution the desired value (default=0)
      */
     public void setRestitution(float restitution) {
         setRestitution(objectId, restitution);
@@ -438,8 +617,9 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native void setRestitution(long objectId, float factor);
 
     /**
-     * Get the current angular velocity of this PhysicsRigidBody
-     * @return the current linear velocity
+     * Copy this body's angular velocity.
+     *
+     * @return a new velocity vector (not null)
      */
     public Vector3f getAngularVelocity() {
         Vector3f vec = new Vector3f();
@@ -450,16 +630,18 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native void getAngularVelocity(long objectId, Vector3f vec);
 
     /**
-     * Get the current angular velocity of this PhysicsRigidBody
-     * @param vec the vector to store the velocity in
+     * Copy this body's angular velocity.
+     *
+     * @param vec storage for the result (not null, modified)
      */
     public void getAngularVelocity(Vector3f vec) {
         getAngularVelocity(objectId, vec);
     }
 
     /**
-     * Sets the angular velocity of this PhysicsRigidBody
-     * @param vec the angular velocity of this PhysicsRigidBody
+     * Alter this body's angular velocity.
+     *
+     * @param vec the desired angular velocity vector (not null, unaffected)
      */
     public void setAngularVelocity(Vector3f vec) {
         setAngularVelocity(objectId, vec);
@@ -469,8 +651,9 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native void setAngularVelocity(long objectId, Vector3f vec);
 
     /**
-     * Get the current linear velocity of this PhysicsRigidBody
-     * @return the current linear velocity
+     * Copy the linear velocity of this body's center of mass.
+     *
+     * @return a new velocity vector (not null)
      */
     public Vector3f getLinearVelocity() {
         Vector3f vec = new Vector3f();
@@ -481,16 +664,18 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native void getLinearVelocity(long objectId, Vector3f vec);
 
     /**
-     * Get the current linear velocity of this PhysicsRigidBody
-     * @param vec the vector to store the velocity in
+     * Copy the linear velocity of this body's center of mass.
+     *
+     * @param vec storage for the result (not null, modified)
      */
     public void getLinearVelocity(Vector3f vec) {
         getLinearVelocity(objectId, vec);
     }
 
     /**
-     * Sets the linear velocity of this PhysicsRigidBody
-     * @param vec the linear velocity of this PhysicsRigidBody
+     * Alter the linear velocity of this body's center of mass.
+     *
+     * @param vec the desired velocity vector (not null)
      */
     public void setLinearVelocity(Vector3f vec) {
         setLinearVelocity(objectId, vec);
@@ -500,9 +685,12 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native void setLinearVelocity(long objectId, Vector3f vec);
 
     /**
-     * Apply a force to the PhysicsRigidBody, only applies force if the next physics update call
-     * updates the physics space.<br>
-     * To apply an impulse, use applyImpulse, use applyContinuousForce to apply continuous force.
+     * Apply a force to the PhysicsRigidBody. Effective only if the next physics
+     * update steps the physics space.
+     * <p>
+     * To apply an impulse, use applyImpulse, use applyContinuousForce to apply
+     * continuous force.
+     *
      * @param force the force
      * @param location the location of the force
      */
@@ -514,10 +702,12 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native void applyForce(long objectId, Vector3f force, Vector3f location);
 
     /**
-     * Apply a force to the PhysicsRigidBody, only applies force if the next physics update call
-     * updates the physics space.<br>
-     * To apply an impulse, use applyImpulse.
-     * 
+     * Apply a force to the PhysicsRigidBody. Effective only if the next physics
+     * update steps the physics space.
+     * <p>
+     * To apply an impulse, use
+     * {@link #applyImpulse(com.jme3.math.Vector3f, com.jme3.math.Vector3f)}.
+     *
      * @param force the force
      */
     public void applyCentralForce(Vector3f force) {
@@ -528,10 +718,12 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native void applyCentralForce(long objectId, Vector3f force);
 
     /**
-     * Apply a force to the PhysicsRigidBody, only applies force if the next physics update call
-     * updates the physics space.<br>
-     * To apply an impulse, use applyImpulse.
-     * 
+     * Apply a force to the PhysicsRigidBody. Effective only if the next physics
+     * update steps the physics space.
+     * <p>
+     * To apply an impulse, use
+     * {@link #applyImpulse(com.jme3.math.Vector3f, com.jme3.math.Vector3f)}.
+     *
      * @param torque the torque
      */
     public void applyTorque(Vector3f torque) {
@@ -542,7 +734,8 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native void applyTorque(long objectId, Vector3f vec);
 
     /**
-     * Apply an impulse to the PhysicsRigidBody in the next physics update.
+     * Apply an impulse to the body the next physics update.
+     *
      * @param impulse applied impulse
      * @param rel_pos location relative to object
      */
@@ -554,8 +747,9 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native void applyImpulse(long objectId, Vector3f impulse, Vector3f rel_pos);
 
     /**
-     * Apply a torque impulse to the PhysicsRigidBody in the next physics update.
-     * @param vec
+     * Apply a torque impulse to the body in the next physics update.
+     *
+     * @param vec the torque to apply
      */
     public void applyTorqueImpulse(Vector3f vec) {
         applyTorqueImpulse(objectId, vec);
@@ -565,8 +759,7 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native void applyTorqueImpulse(long objectId, Vector3f vec);
 
     /**
-     * Clear all forces from the PhysicsRigidBody
-     * 
+     * Clear all forces acting on this body.
      */
     public void clearForces() {
         clearForces(objectId);
@@ -574,6 +767,14 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
 
     private native void clearForces(long objectId);
 
+    /**
+     * Apply the specified CollisionShape to this body.
+     * <p>
+     * Note that the body should not be in any physics space while changing
+     * shape; the body gets rebuilt on the physics side.
+     *
+     * @param collisionShape the shape to apply (not null, alias created)
+     */
     public void setCollisionShape(CollisionShape collisionShape) {
         super.setCollisionShape(collisionShape);
         if (collisionShape instanceof MeshCollisionShape && mass != 0) {
@@ -590,7 +791,7 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native void setCollisionShape(long objectId, long collisionShapeId);
 
     /**
-     * reactivates this PhysicsRigidBody when it has been deactivated because it was not moving
+     * Reactivates this body if it has been deactivated due to lack of motion.
      */
     public void activate() {
         activate(objectId);
@@ -598,6 +799,11 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
 
     private native void activate(long objectId);
 
+    /**
+     * Test whether this body has been deactivated due to lack of motion.
+     *
+     * @return true if still active, false if deactivated
+     */
     public boolean isActive() {
         return isActive(objectId);
     }
@@ -605,10 +811,13 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     private native boolean isActive(long objectId);
 
     /**
-     * sets the sleeping thresholds, these define when the object gets deactivated
-     * to save ressources. Low values keep the object active when it barely moves
-     * @param linear the linear sleeping threshold
-     * @param angular the angular sleeping threshold
+     * Alter this body's sleeping thresholds.
+     * <p>
+     * These thresholds determine when the body can be deactivated to save
+     * resources. Low values keep the body active when it barely moves.
+     *
+     * @param linear the desired linear sleeping threshold (&ge;0, default=0.8)
+     * @param angular the desired angular sleeping threshold (&ge;0, default=1)
      */
     public void setSleepingThresholds(float linear, float angular) {
         setSleepingThresholds(objectId, linear, angular);
@@ -616,36 +825,67 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
 
     private native void setSleepingThresholds(long objectId, float linear, float angular);
 
+    /**
+     * Alter this body's linear sleeping threshold.
+     *
+     * @param linearSleepingThreshold the desired threshold (&ge;0, default=0.8)
+     */
     public void setLinearSleepingThreshold(float linearSleepingThreshold) {
         setLinearSleepingThreshold(objectId, linearSleepingThreshold);
     }
 
     private native void setLinearSleepingThreshold(long objectId, float linearSleepingThreshold);
 
+    /**
+     * Alter this body's angular sleeping threshold.
+     *
+     * @param angularSleepingThreshold the desired threshold (&ge;0, default=1)
+     */
     public void setAngularSleepingThreshold(float angularSleepingThreshold) {
         setAngularSleepingThreshold(objectId, angularSleepingThreshold);
     }
 
     private native void setAngularSleepingThreshold(long objectId, float angularSleepingThreshold);
 
+    /**
+     * Read this body's linear sleeping threshold.
+     *
+     * @return the linear sleeping threshold (&ge;0)
+     */
     public float getLinearSleepingThreshold() {
         return getLinearSleepingThreshold(objectId);
     }
 
     private native float getLinearSleepingThreshold(long objectId);
 
+    /**
+     * Read this body's angular sleeping threshold.
+     *
+     * @return the angular sleeping threshold (&ge;0)
+     */
     public float getAngularSleepingThreshold() {
         return getAngularSleepingThreshold(objectId);
     }
 
     private native float getAngularSleepingThreshold(long objectId);
 
+    /**
+     * Read the X-component of this body's angular factor.
+     *
+     * @return the X-component of the angular factor
+     */
     public float getAngularFactor() {
         return getAngularFactor(null).getX();
     }
 
+    /**
+     * Copy this body's angular factors.
+     *
+     * @param store storage for the result (modified if not null)
+     * @return a vector (either the provided storage or a new vector, not null)
+     */
     public Vector3f getAngularFactor(Vector3f store) {
-        // doing like this prevent from breaking the API
+        // Done this way to prevent breaking the API.
         if (store == null) {
             store = new Vector3f();
         }
@@ -655,16 +895,33 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
 
     private native void getAngularFactor(long objectId, Vector3f vec);
 
+    /**
+     * Alter this body's angular factor.
+     *
+     * @param factor the desired angular factor for all axes (not null,
+     * unaffected, default=1)
+     */
     public void setAngularFactor(float factor) {
         setAngularFactor(objectId, new Vector3f(factor, factor, factor));
     }
 
+    /**
+     * Alter this body's angular factors.
+     *
+     * @param factor the desired angular factor for each axis (not null,
+     * unaffected, default=(1,1,1))
+     */
     public void setAngularFactor(Vector3f factor) {
 	setAngularFactor(objectId, factor);
     }
 
     private native void setAngularFactor(long objectId, Vector3f factor);
 
+    /**
+     * Copy this body's linear factors.
+     *
+     * @return a new vector (not null)
+     */
     public Vector3f getLinearFactor() {
         Vector3f vec = new Vector3f();
 	getLinearFactor(objectId, vec);
@@ -673,6 +930,12 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
 
     private native void getLinearFactor(long objectId, Vector3f vec);
 
+    /**
+     * Alter this body's linear factors.
+     *
+     * @param factor the desired linear factor for each axis (not null,
+     * unaffected, default=(1,1,1))
+     */
     public void setLinearFactor(Vector3f factor) {
 	setLinearFactor(objectId, factor);
     }
@@ -681,7 +944,9 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
 
 
     /**
-     * do not use manually, joints are added automatically
+     * Do not invoke directly! Joints are added automatically when created.
+     *
+     * @param joint the joint to add (not null)
      */
     public void addJoint(PhysicsJoint joint) {
         if (!joints.contains(joint)) {
@@ -690,21 +955,32 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
     }
 
     /**
-     * 
+     * Do not invoke directly! Joints are removed automatically when destroyed.
+     *
+     * @param joint the joint to remove (not null)
      */
     public void removeJoint(PhysicsJoint joint) {
         joints.remove(joint);
     }
 
     /**
-     * Returns a list of connected joints. This list is only filled when
-     * the PhysicsRigidBody is actually added to the physics space or loaded from disk.
-     * @return list of active joints connected to this PhysicsRigidBody
+     * Access the list of joints connected with this body.
+     * <p>
+     * This list is only filled when the PhysicsRigidBody is added to a physics
+     * space.
+     *
+     * @return the pre-existing list (not null)
      */
     public List<PhysicsJoint> getJoints() {
         return joints;
     }
 
+    /**
+     * Serialize this body, for example when saving to a J3O file.
+     *
+     * @param e exporter (not null)
+     * @throws IOException from exporter
+     */
     @Override
     public void write(JmeExporter e) throws IOException {
         super.write(e);
@@ -738,6 +1014,12 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
         capsule.writeSavableArrayList(joints, "joints", null);
     }
 
+    /**
+     * De-serialize this body, for example when loading from a J3O file.
+     *
+     * @param e importer (not null)
+     * @throws IOException from importer
+     */
     @Override
     public void read(JmeImporter e) throws IOException {
         super.read(e);

+ 276 - 116
jme3-bullet/src/main/java/com/jme3/bullet/objects/PhysicsVehicle.java

@@ -46,34 +46,68 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * <p>PhysicsVehicleNode - Special PhysicsNode that implements vehicle functions</p>
+ * A collision object for simplified vehicle simulation based on Bullet's
+ * btRaycastVehicle.
  * <p>
- * <i>From bullet manual:</i><br>
- * For most vehicle simulations, it is recommended to use the simplified Bullet
- * vehicle model as provided in btRaycastVehicle. Instead of simulation each wheel
- * and chassis as separate rigid bodies, connected by constraints, it uses a simplified model.
- * This simplified model has many benefits, and is widely used in commercial driving games.<br>
- * The entire vehicle is represented as a single rigidbody, the chassis.
- * The collision detection of the wheels is approximated by ray casts,
- * and the tire friction is a basic anisotropic friction model.
- * </p>
+ * <i>From Bullet manual:</i><br>
+ * For arcade style vehicle simulations, it is recommended to use the simplified
+ * Bullet vehicle model as provided in btRaycastVehicle. Instead of simulation
+ * each wheel and chassis as separate rigid bodies, connected by constraints, it
+ * uses a simplified model. This simplified model has many benefits, and is
+ * widely used in commercial driving games.
+ * <p>
+ * The entire vehicle is represented as a single rigidbody, the chassis. The
+ * collision detection of the wheels is approximated by ray casts, and the tire
+ * friction is a basic anisotropic friction model.
+ *
  * @author normenhansen
  */
 public class PhysicsVehicle extends PhysicsRigidBody {
 
+    /**
+     * Unique identifier of the btRaycastVehicle. The constructor sets this to a
+     * non-zero value.
+     */
     protected long vehicleId = 0;
+    /**
+     * Unique identifier of the ray caster.
+     */
     protected long rayCasterId = 0;
+    /**
+     * tuning parameters
+     */
     protected VehicleTuning tuning = new VehicleTuning();
+    /**
+     * list of wheels
+     */
     protected ArrayList<VehicleWheel> wheels = new ArrayList<VehicleWheel>();
+    /**
+     * physics space where this vehicle is added, or null if none
+     */
     protected PhysicsSpace physicsSpace;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public PhysicsVehicle() {
     }
 
+    /**
+     * Instantiate a vehicle with the specified collision shape and mass=1.
+     *
+     * @param shape the desired shape (not null, alias created)
+     */
     public PhysicsVehicle(CollisionShape shape) {
         super(shape);
     }
 
+    /**
+     * Instantiate a vehicle with the specified collision shape and mass.
+     *
+     * @param shape the desired shape (not null, alias created)
+     * @param mass (&gt;0)
+     */
     public PhysicsVehicle(CollisionShape shape, float mass) {
         super(shape, mass);
     }
@@ -111,7 +145,10 @@ public class PhysicsVehicle extends PhysicsRigidBody {
     }
 
     /**
-     * Used internally, creates the actual vehicle constraint when vehicle is added to phyicsspace
+     * Used internally, creates the actual vehicle constraint when vehicle is
+     * added to physics space.
+     *
+     * @param space which physics space
      */
     public void createVehicle(PhysicsSpace space) {
         physicsSpace = space;
@@ -145,14 +182,20 @@ public class PhysicsVehicle extends PhysicsRigidBody {
     private native int addWheel(long objectId, Vector3f location, Vector3f direction, Vector3f axle, float restLength, float radius, VehicleTuning tuning, boolean frontWheel);
 
     /**
-     * Add a wheel to this vehicle
-     * @param connectionPoint The starting point of the ray, where the suspension connects to the chassis (chassis space)
-     * @param direction the direction of the wheel (should be -Y / 0,-1,0 for a normal car)
-     * @param axle The axis of the wheel, pointing right in vehicle direction (should be -X / -1,0,0 for a normal car)
-     * @param suspensionRestLength The current length of the suspension (metres)
-     * @param wheelRadius the wheel radius
-     * @param isFrontWheel sets if this wheel is a front wheel (steering)
-     * @return the PhysicsVehicleWheel object to get/set infos on the wheel
+     * Add a wheel to this vehicle.
+     *
+     * @param connectionPoint the location where the suspension connects to the
+     * chassis (in chassis coordinates, not null, unaffected)
+     * @param direction the suspension direction (in chassis coordinates, not
+     * null, unaffected, typically down/0,-1,0)
+     * @param axle the axis direction (in chassis coordinates, not null,
+     * unaffected, typically -1,0,0)
+     * @param suspensionRestLength the rest length of the suspension (in
+     * physics-space units)
+     * @param wheelRadius the wheel radius (in physics-space units, &gt;0)
+     * @param isFrontWheel true&rarr;front (steering) wheel,
+     * false&rarr;non-front wheel
+     * @return a new VehicleWheel for access (not null)
      */
     public VehicleWheel addWheel(Vector3f connectionPoint, Vector3f direction, Vector3f axle, float suspensionRestLength, float wheelRadius, boolean isFrontWheel) {
         return addWheel(null, connectionPoint, direction, axle, suspensionRestLength, wheelRadius, isFrontWheel);
@@ -160,14 +203,20 @@ public class PhysicsVehicle extends PhysicsRigidBody {
 
     /**
      * Add a wheel to this vehicle
-     * @param spat the wheel Geometry
-     * @param connectionPoint The starting point of the ray, where the suspension connects to the chassis (chassis space)
-     * @param direction the direction of the wheel (should be -Y / 0,-1,0 for a normal car)
-     * @param axle The axis of the wheel, pointing right in vehicle direction (should be -X / -1,0,0 for a normal car)
-     * @param suspensionRestLength The current length of the suspension (metres)
-     * @param wheelRadius the wheel radius
-     * @param isFrontWheel sets if this wheel is a front wheel (steering)
-     * @return the PhysicsVehicleWheel object to get/set infos on the wheel
+     *
+     * @param spat the associated spatial, or null if none
+     * @param connectionPoint the location where the suspension connects to the
+     * chassis (in chassis coordinates, not null, unaffected)
+     * @param direction the suspension direction (in chassis coordinates, not
+     * null, unaffected, typically down/0,-1,0)
+     * @param axle the axis direction (in chassis coordinates, not null,
+     * unaffected, typically -1,0,0)
+     * @param suspensionRestLength the rest length of the suspension (in
+     * physics-space units)
+     * @param wheelRadius the wheel radius (in physics-space units, &gt;0)
+     * @param isFrontWheel true&rarr;front (steering) wheel,
+     * false&rarr;non-front wheel
+     * @return a new VehicleWheel for access (not null)
      */
     public VehicleWheel addWheel(Spatial spat, Vector3f connectionPoint, Vector3f direction, Vector3f axle, float suspensionRestLength, float wheelRadius, boolean isFrontWheel) {
         VehicleWheel wheel = null;
@@ -190,8 +239,9 @@ public class PhysicsVehicle extends PhysicsRigidBody {
     }
 
     /**
-     * This rebuilds the vehicle as there is no way in bullet to remove a wheel.
-     * @param wheel
+     * Remove a wheel.
+     *
+     * @param wheel the index of the wheel to remove (&ge;0)
      */
     public void removeWheel(int wheel) {
         wheels.remove(wheel);
@@ -200,195 +250,276 @@ public class PhysicsVehicle extends PhysicsRigidBody {
     }
 
     /**
-     * You can get access to the single wheels via this method.
-     * @param wheel the wheel index
-     * @return the WheelInfo of the selected wheel
+     * Access the indexed wheel of this vehicle.
+     *
+     * @param wheel the index of the wheel to access (&ge;0, &lt;count)
+     * @return the pre-existing instance
      */
     public VehicleWheel getWheel(int wheel) {
         return wheels.get(wheel);
     }
 
+    /**
+     * Read the number of wheels on this vehicle.
+     *
+     * @return count (&ge;0)
+     */
     public int getNumWheels() {
         return wheels.size();
     }
 
     /**
-     * @return the frictionSlip
+     * Read the initial friction for new wheels.
+     *
+     * @return the coefficient of friction between tyre and ground
+     * (0.8&rarr;realistic car, 10000&rarr;kart racer)
      */
     public float getFrictionSlip() {
         return tuning.frictionSlip;
     }
 
     /**
-     * Use before adding wheels, this is the default used when adding wheels.
-     * After adding the wheel, use direct wheel access.<br>
-     * The coefficient of friction between the tyre and the ground.
-     * Should be about 0.8 for realistic cars, but can increased for better handling.
-     * Set large (10000.0) for kart racers
-     * @param frictionSlip the frictionSlip to set
+     * Alter the initial friction for new wheels. Effective only before adding
+     * wheels. After adding a wheel, use {@link #setFrictionSlip(int, float)}.
+     * <p>
+     * For better handling, increase the friction.
+     *
+     * @param frictionSlip the desired coefficient of friction between tyre and
+     * ground (0.8&rarr;realistic car, 10000&rarr;kart racer, default=10.5)
      */
     public void setFrictionSlip(float frictionSlip) {
         tuning.frictionSlip = frictionSlip;
     }
 
     /**
-     * The coefficient of friction between the tyre and the ground.
-     * Should be about 0.8 for realistic cars, but can increased for better handling.
-     * Set large (10000.0) for kart racers
-     * @param wheel
-     * @param frictionSlip
+     * Alter the friction of the indexed wheel.
+     * <p>
+     * For better handling, increase the friction.
+     *
+     * @param wheel the index of the wheel to modify (&ge;0)
+     * @param frictionSlip the desired coefficient of friction between tyre and
+     * ground (0.8&rarr;realistic car, 10000&rarr;kart racer)
      */
     public void setFrictionSlip(int wheel, float frictionSlip) {
         wheels.get(wheel).setFrictionSlip(frictionSlip);
     }
 
     /**
-     * Reduces the rolling torque applied from the wheels that cause the vehicle to roll over.
-     * This is a bit of a hack, but it's quite effective. 0.0 = no roll, 1.0 = physical behaviour.
-     * If m_frictionSlip is too high, you'll need to reduce this to stop the vehicle rolling over.
-     * You should also try lowering the vehicle's centre of mass
+     * Alter the roll influence of the indexed wheel.
+     * <p>
+     * The roll-influence factor reduces (or magnifies) any torque contributed
+     * by the wheel that would tend to cause the vehicle to roll over. This is a
+     * bit of a hack, but it's quite effective.
+     * <p>
+     * If the friction between the tyres and the ground is too high, you may
+     * reduce this factor to prevent the vehicle from rolling over. You should
+     * also try lowering the vehicle's center of mass.
+     *
+     * @param wheel the index of the wheel to modify (&ge;0)
+     * @param rollInfluence the desired roll-influence factor (0&rarr;no roll
+     * torque, 1&rarr;realistic behavior, default=1)
      */
     public void setRollInfluence(int wheel, float rollInfluence) {
         wheels.get(wheel).setRollInfluence(rollInfluence);
     }
 
     /**
-     * @return the maxSuspensionTravelCm
+     * Read the initial maximum suspension travel distance for new wheels.
+     *
+     * @return the maximum distance the suspension can be compressed (in
+     * centimeters)
      */
     public float getMaxSuspensionTravelCm() {
         return tuning.maxSuspensionTravelCm;
     }
 
     /**
-     * Use before adding wheels, this is the default used when adding wheels.
-     * After adding the wheel, use direct wheel access.<br>
-     * The maximum distance the suspension can be compressed (centimetres)
-     * @param maxSuspensionTravelCm the maxSuspensionTravelCm to set
+     * Alter the initial maximum suspension travel distance for new wheels.
+     * Effective only before adding wheels. After adding a wheel, use
+     * {@link #setMaxSuspensionTravelCm(int, float)}.
+     *
+     * @param maxSuspensionTravelCm the desired maximum distance the suspension
+     * can be compressed (in centimeters, default=500)
      */
     public void setMaxSuspensionTravelCm(float maxSuspensionTravelCm) {
         tuning.maxSuspensionTravelCm = maxSuspensionTravelCm;
     }
 
     /**
-     * The maximum distance the suspension can be compressed (centimetres)
-     * @param wheel
-     * @param maxSuspensionTravelCm
+     * Alter the maximum suspension travel distance for the indexed wheel.
+     *
+     * @param wheel the index of the wheel to modify (&ge;0)
+     * @param maxSuspensionTravelCm the desired maximum distance the suspension
+     * can be compressed (in centimeters)
      */
     public void setMaxSuspensionTravelCm(int wheel, float maxSuspensionTravelCm) {
         wheels.get(wheel).setMaxSuspensionTravelCm(maxSuspensionTravelCm);
     }
 
+    /**
+     * Read the initial maximum suspension force for new wheels.
+     *
+     * @return the maximum force per wheel
+     */
     public float getMaxSuspensionForce() {
         return tuning.maxSuspensionForce;
     }
 
     /**
-     * This value caps the maximum suspension force, raise this above the default 6000 if your suspension cannot
-     * handle the weight of your vehicle.
-     * @param maxSuspensionForce
+     * Alter the initial maximum suspension force for new wheels. Effective only
+     * before adding wheels. After adding a wheel, use
+     * {@link #setMaxSuspensionForce(int, float)}.
+     * <p>
+     * If the suspension cannot handle the vehicle's weight, increase this
+     * limit.
+     *
+     * @param maxSuspensionForce the desired maximum force per wheel
+     * (default=6000)
      */
     public void setMaxSuspensionForce(float maxSuspensionForce) {
         tuning.maxSuspensionForce = maxSuspensionForce;
     }
 
     /**
-     * This value caps the maximum suspension force, raise this above the default 6000 if your suspension cannot
-     * handle the weight of your vehicle.
-     * @param wheel
-     * @param maxSuspensionForce
+     * Alter the maximum suspension force for the specified wheel.
+     * <p>
+     * If the suspension cannot handle the vehicle's weight, increase this
+     * limit.
+     *
+     * @param wheel the index of the wheel to modify (&ge;0)
+     * @param maxSuspensionForce the desired maximum force per wheel
+     * (default=6000)
      */
     public void setMaxSuspensionForce(int wheel, float maxSuspensionForce) {
         wheels.get(wheel).setMaxSuspensionForce(maxSuspensionForce);
     }
 
     /**
-     * @return the suspensionCompression
+     * Read the initial damping (when the suspension is compressed) for new
+     * wheels.
+     *
+     * @return the damping coefficient
      */
     public float getSuspensionCompression() {
         return tuning.suspensionCompression;
     }
 
     /**
-     * Use before adding wheels, this is the default used when adding wheels.
-     * After adding the wheel, use direct wheel access.<br>
-     * The damping coefficient for when the suspension is compressed.
-     * Set to k * 2.0 * FastMath.sqrt(m_suspensionStiffness) so k is proportional to critical damping.<br>
-     * k = 0.0 undamped & bouncy, k = 1.0 critical damping<br>
-     * 0.1 to 0.3 are good values
-     * @param suspensionCompression the suspensionCompression to set
+     * Alter the initial damping (when the suspension is compressed) for new
+     * wheels. Effective only before adding wheels. After adding a wheel, use
+     * {@link #setSuspensionCompression(int, float)}.
+     * <p>
+     * Set to k * 2 * FastMath.sqrt(m_suspensionStiffness) where k is the
+     * damping ratio:
+     * <p>
+     * k = 0.0 undamped and bouncy, k = 1.0 critical damping, k between 0.1 and
+     * 0.3 are good values
+     *
+     * @param suspensionCompression the desired damping coefficient
+     * (default=0.83)
      */
     public void setSuspensionCompression(float suspensionCompression) {
         tuning.suspensionCompression = suspensionCompression;
     }
 
     /**
-     * The damping coefficient for when the suspension is compressed.
-     * Set to k * 2.0 * FastMath.sqrt(m_suspensionStiffness) so k is proportional to critical damping.<br>
-     * k = 0.0 undamped & bouncy, k = 1.0 critical damping<br>
-     * 0.1 to 0.3 are good values
-     * @param wheel
-     * @param suspensionCompression
+     * Alter the damping (when the suspension is compressed) for the indexed
+     * wheel.
+     * <p>
+     * Set to k * 2 * FastMath.sqrt(m_suspensionStiffness) where k is the
+     * damping ratio:
+     * <p>
+     * k = 0.0 undamped and bouncy, k = 1.0 critical damping, k between 0.1 and
+     * 0.3 are good values
+     *
+     * @param wheel the index of the wheel to modify (&ge;0)
+     * @param suspensionCompression the desired damping coefficient
      */
     public void setSuspensionCompression(int wheel, float suspensionCompression) {
         wheels.get(wheel).setWheelsDampingCompression(suspensionCompression);
     }
 
     /**
-     * @return the suspensionDamping
+     * Read the initial damping (when the suspension is expanded) for new
+     * wheels.
+     *
+     * @return the damping coefficient
      */
     public float getSuspensionDamping() {
         return tuning.suspensionDamping;
     }
 
     /**
-     * Use before adding wheels, this is the default used when adding wheels.
-     * After adding the wheel, use direct wheel access.<br>
-     * The damping coefficient for when the suspension is expanding.
-     * See the comments for setSuspensionCompression for how to set k.
-     * @param suspensionDamping the suspensionDamping to set
+     * Alter the initial damping (when the suspension is expanded) for new
+     * wheels. Effective only before adding wheels. After adding a wheel, use
+     * {@link #setSuspensionCompression(int, float)}.
+     * <p>
+     * Set to k * 2 * FastMath.sqrt(m_suspensionStiffness) where k is the
+     * damping ratio:
+     * <p>
+     * k = 0.0 undamped and bouncy, k = 1.0 critical damping, k between 0.1 and
+     * 0.3 are good values
+     *
+     * @param suspensionDamping the desired damping coefficient (default=0.88)
      */
     public void setSuspensionDamping(float suspensionDamping) {
         tuning.suspensionDamping = suspensionDamping;
     }
 
     /**
-     * The damping coefficient for when the suspension is expanding.
-     * See the comments for setSuspensionCompression for how to set k.
-     * @param wheel
-     * @param suspensionDamping
+     * Alter the damping (when the suspension is expanded) for the indexed
+     * wheel.
+     * <p>
+     * Set to k * 2 * FastMath.sqrt(m_suspensionStiffness) where k is the
+     * damping ratio:
+     * <p>
+     * k = 0.0 undamped and bouncy, k = 1.0 critical damping, k between 0.1 and
+     * 0.3 are good values
+     *
+     * @param wheel the index of the wheel to modify (&ge;0)
+     * @param suspensionDamping the desired damping coefficient
      */
     public void setSuspensionDamping(int wheel, float suspensionDamping) {
         wheels.get(wheel).setWheelsDampingRelaxation(suspensionDamping);
     }
 
     /**
-     * @return the suspensionStiffness
+     * Read the initial suspension stiffness for new wheels.
+     *
+     * @return the stiffness constant (10&rarr;off-road buggy, 50&rarr;sports
+     * car, 200&rarr;Formula-1 race car)
      */
     public float getSuspensionStiffness() {
         return tuning.suspensionStiffness;
     }
 
     /**
-     * Use before adding wheels, this is the default used when adding wheels.
-     * After adding the wheel, use direct wheel access.<br>
-     * The stiffness constant for the suspension.  10.0 - Offroad buggy, 50.0 - Sports car, 200.0 - F1 Car
-     * @param suspensionStiffness 
+     * Alter the initial suspension stiffness for new wheels. Effective only
+     * before adding wheels. After adding a wheel, use
+     * {@link #setSuspensionStiffness(int, float)}.
+     *
+     * @param suspensionStiffness the desired stiffness coefficient
+     * (10&rarr;off-road buggy, 50&rarr;sports car, 200&rarr;Formula-1 race car,
+     * default=5.88)
      */
     public void setSuspensionStiffness(float suspensionStiffness) {
         tuning.suspensionStiffness = suspensionStiffness;
     }
 
     /**
-     * The stiffness constant for the suspension.  10.0 - Offroad buggy, 50.0 - Sports car, 200.0 - F1 Car
-     * @param wheel
-     * @param suspensionStiffness
+     * Alter the suspension stiffness of the indexed wheel.
+     *
+     * @param wheel the index of the wheel to modify (&ge;0)
+     * @param suspensionStiffness the desired stiffness coefficient
+     * (10&rarr;off-road buggy, 50&rarr;sports car, 200&rarr;Formula-1 race car,
+     * default=5.88)
      */
     public void setSuspensionStiffness(int wheel, float suspensionStiffness) {
         wheels.get(wheel).setSuspensionStiffness(suspensionStiffness);
     }
 
     /**
-     * Reset the suspension
+     * Reset this vehicle's suspension.
      */
     public void resetSuspension() {
         resetSuspension(vehicleId);
@@ -397,8 +528,9 @@ public class PhysicsVehicle extends PhysicsRigidBody {
     private native void resetSuspension(long vehicleId);
 
     /**
-     * Apply the given engine force to all wheels, works continuously
-     * @param force the force
+     * Apply the specified engine force to all wheels. Works continuously.
+     *
+     * @param force the desired amount of force
      */
     public void accelerate(float force) {
         for (int i = 0; i < wheels.size(); i++) {
@@ -407,9 +539,10 @@ public class PhysicsVehicle extends PhysicsRigidBody {
     }
 
     /**
-     * Apply the given engine force, works continuously
-     * @param wheel the wheel to apply the force on
-     * @param force the force
+     * Apply the given engine force to the indexed wheel. Works continuously.
+     *
+     * @param wheel the index of the wheel to apply the force to (&ge;0)
+     * @param force the desired amount of force
      */
     public void accelerate(int wheel, float force) {
         applyEngineForce(vehicleId, wheel, force);
@@ -419,8 +552,9 @@ public class PhysicsVehicle extends PhysicsRigidBody {
     private native void applyEngineForce(long vehicleId, int wheel, float force);
 
     /**
-     * Set the given steering value to all front wheels (0 = forward)
-     * @param value the steering angle of the front wheels (Pi = 360deg)
+     * Alter the steering angle of all front wheels.
+     *
+     * @param value the desired steering angle (in radians, 0=straight)
      */
     public void steer(float value) {
         for (int i = 0; i < wheels.size(); i++) {
@@ -431,9 +565,10 @@ public class PhysicsVehicle extends PhysicsRigidBody {
     }
 
     /**
-     * Set the given steering value to the given wheel (0 = forward)
-     * @param wheel the wheel to set the steering on
-     * @param value the steering angle of the front wheels (Pi = 360deg)
+     * Alter the steering angle of the indexed wheel.
+     *
+     * @param wheel the index of the wheel to steer (&ge;0)
+     * @param value the desired steering angle (in radians, 0=straight)
      */
     public void steer(int wheel, float value) {
         steer(vehicleId, wheel, value);
@@ -442,8 +577,9 @@ public class PhysicsVehicle extends PhysicsRigidBody {
     private native void steer(long vehicleId, int wheel, float value);
 
     /**
-     * Apply the given brake force to all wheels, works continuously
-     * @param force the force
+     * Apply the given brake force to all wheels. Works continuously.
+     *
+     * @param force the desired amount of force
      */
     public void brake(float force) {
         for (int i = 0; i < wheels.size(); i++) {
@@ -452,9 +588,10 @@ public class PhysicsVehicle extends PhysicsRigidBody {
     }
 
     /**
-     * Apply the given brake force, works continuously
-     * @param wheel the wheel to apply the force on
-     * @param force the force
+     * Apply the given brake force to the indexed wheel. Works continuously.
+     *
+     * @param wheel the index of the wheel to apply the force to (&ge;0)
+     * @param force the desired amount of force
      */
     public void brake(int wheel, float force) {
         brake(vehicleId, wheel, force);
@@ -463,8 +600,9 @@ public class PhysicsVehicle extends PhysicsRigidBody {
     private native void brake(long vehicleId, int wheel, float force);
 
     /**
-     * Get the current speed of the vehicle in km/h
-     * @return
+     * Read the vehicle's speed in km/h.
+     *
+     * @return speed (in kilometers per hour)
      */
     public float getCurrentVehicleSpeedKmHour() {
         return getCurrentVehicleSpeedKmHour(vehicleId);
@@ -473,9 +611,11 @@ public class PhysicsVehicle extends PhysicsRigidBody {
     private native float getCurrentVehicleSpeedKmHour(long vehicleId);
 
     /**
-     * Get the current forward vector of the vehicle in world coordinates
-     * @param vector
-     * @return
+     * Copy the vehicle's forward direction.
+     *
+     * @param vector storage for the result (modified if not null)
+     * @return a direction vector (in physics-space coordinates, either the
+     * provided storage or a new vector)
      */
     public Vector3f getForwardVector(Vector3f vector) {
         if (vector == null) {
@@ -489,11 +629,19 @@ public class PhysicsVehicle extends PhysicsRigidBody {
 
     /**
      * used internally
+     *
+     * @return the unique identifier
      */
     public long getVehicleId() {
         return vehicleId;
     }
 
+    /**
+     * De-serialize this vehicle, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     @Override
     public void read(JmeImporter im) throws IOException {
         InputCapsule capsule = im.getCapsule(this);
@@ -509,6 +657,12 @@ public class PhysicsVehicle extends PhysicsRigidBody {
         super.read(im);
     }
 
+    /**
+     * Serialize this vehicle, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     @Override
     public void write(JmeExporter ex) throws IOException {
         OutputCapsule capsule = ex.getCapsule(this);
@@ -522,6 +676,12 @@ public class PhysicsVehicle extends PhysicsRigidBody {
         super.write(ex);
     }
 
+    /**
+     * Finalize this vehicle just before it is destroyed. Should be invoked only
+     * by a subclass or by the garbage collector.
+     *
+     * @throws Throwable ignored by the garbage collector
+     */
     @Override
     protected void finalize() throws Throwable {
         super.finalize();

+ 315 - 43
jme3-bullet/src/main/java/com/jme3/bullet/objects/VehicleWheel.java

@@ -40,42 +40,142 @@ import com.jme3.scene.Spatial;
 import java.io.IOException;
 
 /**
- * Stores info about one wheel of a PhysicsVehicle
+ * Information about one wheel of a PhysicsVehicle.
+ *
  * @author normenhansen
  */
 public class VehicleWheel implements Savable {
 
+    /**
+     * unique identifier of the btRaycastVehicle
+     */
     protected long wheelId = 0;
+    /**
+     * 0-origin index among the vehicle's wheels (&ge;0)
+     */
     protected int wheelIndex = 0;
+    /**
+     * copy of wheel type: true&rarr;front (steering) wheel,
+     * false&rarr;non-front wheel
+     */
     protected boolean frontWheel;
+    /**
+     * location where the suspension connects to the chassis (in chassis
+     * coordinates)
+     */
     protected Vector3f location = new Vector3f();
+    /**
+     * suspension direction (in chassis coordinates, typically down/0,-1,0)
+     */
     protected Vector3f direction = new Vector3f();
+    /**
+     * axis direction (in chassis coordinates, typically to the right/-1,0,0)
+     */
     protected Vector3f axle = new Vector3f();
+    /**
+     * copy of suspension stiffness constant (10&rarr;off-road buggy, 
+     * 50&rarr;sports car, 200&rarr;Formula-1 race car, default=20)
+     */
     protected float suspensionStiffness = 20.0f;
+    /**
+     * copy of suspension damping when expanded (0&rarr;no damping, default=2.3)
+     */
     protected float wheelsDampingRelaxation = 2.3f;
+    /**
+     * copy of suspension damping when compressed (0&rarr;no damping, 
+     * default=4.4)
+     */
     protected float wheelsDampingCompression = 4.4f;
+    /**
+     * copy of coefficient of friction between tyre and ground
+     * (0.8&rarr;realistic car, 10000&rarr;kart racer, default=10.5)
+     */
     protected float frictionSlip = 10.5f;
+    /**
+     * copy of roll-influence factor (0&rarr;no roll torque, 1&rarr;realistic
+     * behavior, default=1)
+     */
     protected float rollInfluence = 1.0f;
+    /**
+     * copy of maximum suspension travel distance (in centimeters, default=500)
+     */
     protected float maxSuspensionTravelCm = 500f;
+    /**
+     * copy of maximum force exerted by the suspension (default=6000)
+     */
     protected float maxSuspensionForce = 6000f;
+    /**
+     * copy of wheel radius (in physics-space units, &gt;0)
+     */
     protected float radius = 0.5f;
+    /**
+     * copy of rest length of the suspension (in physics-space units)
+     */
     protected float restLength = 1f;
+    /**
+     * wheel location in physics-space coordinates
+     */
     protected Vector3f wheelWorldLocation = new Vector3f();
+    /**
+     * wheel orientation in physics-space coordinates
+     */
     protected Quaternion wheelWorldRotation = new Quaternion();
+    /**
+     * associated spatial, or null if none
+     */
     protected Spatial wheelSpatial;
     protected Matrix3f tmp_Matrix = new com.jme3.math.Matrix3f();
     protected final Quaternion tmp_inverseWorldRotation = new Quaternion();
+    /**
+     * true &rarr; physics coordinates match local transform, false &rarr;
+     * physics coordinates match world transform
+     */
     private boolean applyLocal = false;
 
+    /**
+     * No-argument constructor needed by SavableClassUtil. Do not invoke
+     * directly!
+     */
     public VehicleWheel() {
     }
 
+    /**
+     * Instantiate a wheel.
+     *
+     * @param spat the associated spatial, or null if none
+     * @param location the location where the suspension connects to the chassis
+     * (in chassis coordinates, not null, unaffected)
+     * @param direction the suspension direction (in chassis coordinates, not
+     * null, unaffected, typically down/0,-1,0)
+     * @param axle the axis direction (in chassis coordinates, not null,
+     * unaffected, typically right/-1,0,0)
+     * @param restLength the rest length of the suspension (in physics-space
+     * units)
+     * @param radius the wheel's radius (in physics-space units, &ge;0)
+     * @param frontWheel true&rarr;front (steering) wheel, false&rarr;non-front
+     * wheel
+     */
     public VehicleWheel(Spatial spat, Vector3f location, Vector3f direction, Vector3f axle,
             float restLength, float radius, boolean frontWheel) {
         this(location, direction, axle, restLength, radius, frontWheel);
         wheelSpatial = spat;
     }
 
+    /**
+     * Instantiate a wheel without an associated spatial.
+     *
+     * @param location the location where the suspension connects to the chassis
+     * (in chassis coordinates, not null, unaffected)
+     * @param direction the suspension direction (in chassis coordinates, not
+     * null, unaffected, typically down/0,-1,0)
+     * @param axle the axis direction (in chassis coordinates, not null,
+     * unaffected, typically right/-1,0,0)
+     * @param restLength the rest length of the suspension (in physics-space
+     * units)
+     * @param radius the wheel's radius (in physics-space units, &ge;0)
+     * @param frontWheel true&rarr;front (steering) wheel, false&rarr;non-front
+     * wheel
+     */
     public VehicleWheel(Vector3f location, Vector3f direction, Vector3f axle,
             float restLength, float radius, boolean frontWheel) {
         this.location.set(location);
@@ -86,6 +186,9 @@ public class VehicleWheel implements Savable {
         this.radius = radius;
     }
 
+    /**
+     * Update this wheel's location and orientation in physics space.
+     */
     public void updatePhysicsState() {
         getWheelLocation(wheelId, wheelIndex, wheelWorldLocation);
         getWheelRotation(wheelId, wheelIndex, tmp_Matrix);
@@ -96,6 +199,10 @@ public class VehicleWheel implements Savable {
 
     private native void getWheelRotation(long vehicleId, int wheelId, Matrix3f location);
 
+    /**
+     * Apply this wheel's physics location and orientation to its associated
+     * spatial, if any.
+     */
     public void applyWheelTransform() {
         if (wheelSpatial == null) {
             return;
@@ -118,132 +225,232 @@ public class VehicleWheel implements Savable {
         }
     }
 
+    /**
+     * Read the id of the btRaycastVehicle.
+     *
+     * @return the unique identifier (not zero)
+     */
     public long getWheelId() {
         return wheelId;
     }
 
+    /**
+     * Assign this wheel to a vehicle.
+     *
+     * @param vehicleId the id of the btRaycastVehicle (not zero)
+     * @param wheelIndex index among the vehicle's wheels (&ge;0)
+     */
     public void setVehicleId(long vehicleId, int wheelIndex) {
         this.wheelId = vehicleId;
         this.wheelIndex = wheelIndex;
         applyInfo();
     }
 
+    /**
+     * Test whether this wheel is a front wheel.
+     *
+     * @return true if front wheel, otherwise false
+     */
     public boolean isFrontWheel() {
         return frontWheel;
     }
 
+    /**
+     * Alter whether this wheel is a front (steering) wheel.
+     *
+     * @param frontWheel true&rarr;front wheel, false&rarr;non-front wheel
+     */
     public void setFrontWheel(boolean frontWheel) {
         this.frontWheel = frontWheel;
         applyInfo();
     }
 
+    /**
+     * Access the location where the suspension connects to the chassis.
+     *
+     * @return the pre-existing location vector (in chassis coordinates, not 
+     * null)
+     */
     public Vector3f getLocation() {
         return location;
     }
 
+    /**
+     * Access this wheel's suspension direction.
+     *
+     * @return the pre-existing direction vector (in chassis coordinates, not 
+     * null)
+     */
     public Vector3f getDirection() {
         return direction;
     }
 
+    /**
+     * Access this wheel's axle direction.
+     *
+     * @return the pre-existing direction vector (not null)
+     */
     public Vector3f getAxle() {
         return axle;
     }
 
+    /**
+     * Read the stiffness constant for this wheel's suspension.
+     *
+     * @return the stiffness constant
+     */
     public float getSuspensionStiffness() {
         return suspensionStiffness;
     }
 
     /**
-     * the stiffness constant for the suspension.  10.0 - Offroad buggy, 50.0 - Sports car, 200.0 - F1 Car
-     * @param suspensionStiffness
+     * Alter the stiffness constant for this wheel's suspension.
+     *
+     * @param suspensionStiffness the desired stiffness constant
+     * (10&rarr;off-road buggy, 50&rarr;sports car, 200&rarr;Formula-1 race car,
+     * default=20)
      */
     public void setSuspensionStiffness(float suspensionStiffness) {
         this.suspensionStiffness = suspensionStiffness;
         applyInfo();
     }
 
+    /**
+     * Read this wheel's damping when the suspension is expanded.
+     *
+     * @return the damping
+     */
     public float getWheelsDampingRelaxation() {
         return wheelsDampingRelaxation;
     }
 
     /**
-     * the damping coefficient for when the suspension is expanding.
-     * See the comments for setWheelsDampingCompression for how to set k.
-     * @param wheelsDampingRelaxation
+     * Alter this wheel's damping when the suspension is expanded.
+     * <p>
+     * Set to k * 2 * FastMath.sqrt(m_suspensionStiffness) where k is the
+     * damping ratio:
+     * <p>
+     * k = 0.0 undamped and bouncy, k = 1.0 critical damping, k between 0.1 and
+     * 0.3 are good values
+     *
+     * @param wheelsDampingRelaxation the desired damping (default=2.3)
      */
     public void setWheelsDampingRelaxation(float wheelsDampingRelaxation) {
         this.wheelsDampingRelaxation = wheelsDampingRelaxation;
         applyInfo();
     }
 
+    /**
+     * Read this wheel's damping when the suspension is compressed.
+     *
+     * @return the damping
+     */
     public float getWheelsDampingCompression() {
         return wheelsDampingCompression;
     }
 
     /**
-     * the damping coefficient for when the suspension is compressed.
-     * Set to k * 2.0 * FastMath.sqrt(m_suspensionStiffness) so k is proportional to critical damping.<br>
-     * k = 0.0 undamped & bouncy, k = 1.0 critical damping<br>
-     * 0.1 to 0.3 are good values
-     * @param wheelsDampingCompression
+     * Alter this wheel's damping when the suspension is compressed.
+     * <p>
+     * Set to k * 2 * FastMath.sqrt(m_suspensionStiffness) where k is the
+     * damping ratio:
+     * <p>
+     * k = 0.0 undamped and bouncy, k = 1.0 critical damping, k between 0.1 and
+     * 0.3 are good values
+     *
+     * @param wheelsDampingCompression the desired damping (default=4.4)
      */
     public void setWheelsDampingCompression(float wheelsDampingCompression) {
         this.wheelsDampingCompression = wheelsDampingCompression;
         applyInfo();
     }
 
+    /**
+     * Read the friction between this wheel's tyre and the ground.
+     *
+     * @return the coefficient of friction
+     */
     public float getFrictionSlip() {
         return frictionSlip;
     }
 
     /**
-     * the coefficient of friction between the tyre and the ground.
-     * Should be about 0.8 for realistic cars, but can increased for better handling.
-     * Set large (10000.0) for kart racers
-     * @param frictionSlip
+     * Alter the friction between this wheel's tyre and the ground.
+     * <p>
+     * Should be about 0.8 for realistic cars, but can increased for better
+     * handling. Set large (10000.0) for kart racers.
+     *
+     * @param frictionSlip the desired coefficient of friction (default=10.5)
      */
     public void setFrictionSlip(float frictionSlip) {
         this.frictionSlip = frictionSlip;
         applyInfo();
     }
 
+    /**
+     * Read this wheel's roll influence.
+     *
+     * @return the roll-influence factor
+     */
     public float getRollInfluence() {
         return rollInfluence;
     }
 
     /**
-     * reduces the rolling torque applied from the wheels that cause the vehicle to roll over.
-     * This is a bit of a hack, but it's quite effective. 0.0 = no roll, 1.0 = physical behaviour.
-     * If m_frictionSlip is too high, you'll need to reduce this to stop the vehicle rolling over.
-     * You should also try lowering the vehicle's centre of mass
-     * @param rollInfluence the rollInfluence to set
+     * Alter this wheel's roll influence.
+     * <p>
+     * The roll-influence factor reduces (or magnifies) the torque contributed
+     * by this wheel that tends to cause the vehicle to roll over. This is a bit
+     * of a hack, but it's quite effective.
+     * <p>
+     * If the friction between the tyres and the ground is too high, you may
+     * reduce this factor to prevent the vehicle from rolling over. You should
+     * also try lowering the vehicle's centre of mass.
+     *
+     * @param rollInfluence the desired roll-influence factor (0&rarr;no roll
+     * torque, 1&rarr;realistic behaviour, default=1)
      */
     public void setRollInfluence(float rollInfluence) {
         this.rollInfluence = rollInfluence;
         applyInfo();
     }
 
+    /**
+     * Read the travel distance for this wheel's suspension.
+     *
+     * @return the maximum travel distance (in centimeters)
+     */
     public float getMaxSuspensionTravelCm() {
         return maxSuspensionTravelCm;
     }
 
     /**
-     * the maximum distance the suspension can be compressed (centimetres)
-     * @param maxSuspensionTravelCm
+     * Alter the travel distance for this wheel's suspension.
+     *
+     * @param maxSuspensionTravelCm the desired maximum travel distance (in
+     * centimetres, default=500)
      */
     public void setMaxSuspensionTravelCm(float maxSuspensionTravelCm) {
         this.maxSuspensionTravelCm = maxSuspensionTravelCm;
         applyInfo();
     }
 
+    /**
+     * Read the maximum force exerted by this wheel's suspension.
+     *
+     * @return the maximum force
+     */
     public float getMaxSuspensionForce() {
         return maxSuspensionForce;
     }
 
     /**
-     * The maximum suspension force, raise this above the default 6000 if your suspension cannot
-     * handle the weight of your vehicle.
-     * @param maxSuspensionTravelCm
+     * Alter the maximum force exerted by this wheel's suspension.
+     * <p>
+     * Increase this if your suspension cannot handle the weight of your
+     * vehicle.
+     *
+     * @param maxSuspensionForce the desired maximum force (default=6000)
      */
     public void setMaxSuspensionForce(float maxSuspensionForce) {
         this.maxSuspensionForce = maxSuspensionForce;
@@ -269,19 +476,40 @@ public class VehicleWheel implements Savable {
             boolean frontWheel,
             float suspensionRestLength);
 
+    /**
+     * Read the radius of this wheel.
+     *
+     * @return the radius (in physics-space units, &ge;0)
+     */
     public float getRadius() {
         return radius;
     }
 
+    /**
+     * Alter the radius of this wheel.
+     *
+     * @param radius the desired radius (in physics-space units, &ge;0,
+     * default=0.5)
+     */
     public void setRadius(float radius) {
         this.radius = radius;
         applyInfo();
     }
 
+    /**
+     * Read the rest length of this wheel.
+     *
+     * @return the length
+     */
     public float getRestLength() {
         return restLength;
     }
 
+    /**
+     * Alter the rest length of the suspension of this wheel.
+     *
+     * @param restLength the desired length (default=1)
+     */
     public void setRestLength(float restLength) {
         this.restLength = restLength;
         applyInfo();
@@ -303,7 +531,10 @@ public class VehicleWheel implements Savable {
     }
 
     /**
-     * returns the location where the wheel collides with the ground (world space)
+     * Copy the location where the wheel touches the ground.
+     *
+     * @param vec storage for the result (not null, modified)
+     * @return a new location vector (in physics-space coordinates, not null)
      */
     public Vector3f getCollisionLocation(Vector3f vec) {
         getCollisionLocation(wheelId, wheelIndex, vec);
@@ -313,7 +544,9 @@ public class VehicleWheel implements Savable {
     private native void getCollisionLocation(long wheelId, int wheelIndex, Vector3f vec);
 
     /**
-     * returns the location where the wheel collides with the ground (world space)
+     * Copy the location where the wheel collides with the ground.
+     *
+     * @return a new location vector (in physics-space coordinates)
      */
     public Vector3f getCollisionLocation() {
         Vector3f vec = new Vector3f();
@@ -322,7 +555,10 @@ public class VehicleWheel implements Savable {
     }
 
     /**
-     * returns the normal where the wheel collides with the ground (world space)
+     * Copy the normal where the wheel touches the ground.
+     *
+     * @param vec storage for the result (not null, modified)
+     * @return a unit vector (in physics-space coordinates, not null)
      */
     public Vector3f getCollisionNormal(Vector3f vec) {
         getCollisionNormal(wheelId, wheelIndex, vec);
@@ -332,7 +568,9 @@ public class VehicleWheel implements Savable {
     private native void getCollisionNormal(long wheelId, int wheelIndex, Vector3f vec);
 
     /**
-     * returns the normal where the wheel collides with the ground (world space)
+     * Copy the normal where the wheel touches the ground.
+     *
+     * @return a new unit vector (in physics-space coordinates, not null)
      */
     public Vector3f getCollisionNormal() {
         Vector3f vec = new Vector3f();
@@ -341,8 +579,11 @@ public class VehicleWheel implements Savable {
     }
 
     /**
-     * returns how much the wheel skids on the ground (for skid sounds/smoke etc.)<br>
-     * 0.0 = wheels are sliding, 1.0 = wheels have traction.
+     * Calculate to what extent the wheel is skidding (for skid sounds/smoke
+     * etc.)
+     *
+     * @return the relative amount of traction (0&rarr;wheel is sliding,
+     * 1&rarr;wheel has full traction)
      */
     public float getSkidInfo() {
         return getSkidInfo(wheelId, wheelIndex);
@@ -351,8 +592,9 @@ public class VehicleWheel implements Savable {
     public native float getSkidInfo(long wheelId, int wheelIndex);
     
     /**
-     * returns how many degrees the wheel has turned since the last physics
-     * step.
+     * Calculate how much this wheel has turned since the last physics step.
+     *
+     * @return the rotation angle (in radians)
      */
     public float getDeltaRotation() {
         return getDeltaRotation(wheelId, wheelIndex);
@@ -360,6 +602,12 @@ public class VehicleWheel implements Savable {
     
     public native float getDeltaRotation(long wheelId, int wheelIndex);
 
+    /**
+     * De-serialize this wheel, for example when loading from a J3O file.
+     *
+     * @param im importer (not null)
+     * @throws IOException from importer
+     */
     @Override
     public void read(JmeImporter im) throws IOException {
         InputCapsule capsule = im.getCapsule(this);
@@ -379,6 +627,12 @@ public class VehicleWheel implements Savable {
         restLength = capsule.readFloat("restLength", 1f);
     }
 
+    /**
+     * Serialize this wheel, for example when saving to a J3O file.
+     *
+     * @param ex exporter (not null)
+     * @throws IOException from exporter
+     */
     @Override
     public void write(JmeExporter ex) throws IOException {
         OutputCapsule capsule = ex.getCapsule(this);
@@ -399,41 +653,59 @@ public class VehicleWheel implements Savable {
     }
 
     /**
-     * @return the wheelSpatial
+     * Access the spatial associated with this wheel.
+     *
+     * @return the pre-existing instance, or null
      */
     public Spatial getWheelSpatial() {
         return wheelSpatial;
     }
 
     /**
-     * @param wheelSpatial the wheelSpatial to set
+     * Alter which spatial is associated with this wheel.
+     *
+     * @param wheelSpatial the desired spatial, or null for none
      */
     public void setWheelSpatial(Spatial wheelSpatial) {
         this.wheelSpatial = wheelSpatial;
     }
 
+    /**
+     * Test whether physics coordinates should match the local transform of the
+     * Spatial.
+     *
+     * @return true if matching local transform, false if matching world
+     * transform
+     */
     public boolean isApplyLocal() {
         return applyLocal;
     }
 
+    /**
+     * Alter whether physics coordinates should match the local transform of the
+     * Spatial.
+     *
+     * @param applyLocal true&rarr;match local transform, false&rarr;match world
+     * transform (default=false)
+     */
     public void setApplyLocal(boolean applyLocal) {
         this.applyLocal = applyLocal;
     }
 
     /**
-    * write the content of the wheelWorldRotation into the store
-    * 
-    * @param store
-    */
+     * Copy this wheel's physics-space orientation to the specified quaternion.
+     *
+     * @param store storage for the result (not null, modified)
+     */
     public void getWheelWorldRotation(final Quaternion store) {
         store.set(this.wheelWorldRotation);
     }
 
     /**
-    * write the content of the wheelWorldLocation into the store
-    * 
-    * @param store
-    */
+     * Copy this wheel's physics-space location to the specified vector.
+     *
+     * @param store storage for the result (not null, modified)
+     */
     public void getWheelWorldLocation(final Vector3f store) {
         store.set(this.wheelWorldLocation);
     }

+ 53 - 9
jme3-bullet/src/main/java/com/jme3/bullet/objects/infos/RigidBodyMotionState.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -40,8 +40,8 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * stores transform info of a PhysicsNode in a threadsafe manner to
- * allow multithreaded access from the jme scenegraph and the bullet physicsspace
+ * The motion state (transform) of a rigid body, with thread-safe access.
+ *
  * @author normenhansen
  */
 public class RigidBodyMotionState {
@@ -51,9 +51,16 @@ public class RigidBodyMotionState {
     private Quaternion worldRotationQuat = new Quaternion();
     private Quaternion tmp_inverseWorldRotation = new Quaternion();
     private PhysicsVehicle vehicle;
+    /**
+     * true &rarr; physics coordinates match local transform, false &rarr;
+     * physics coordinates match world transform
+     */
     private boolean applyPhysicsLocal = false;
 //    protected LinkedList<PhysicsMotionStateListener> listeners = new LinkedList<PhysicsMotionStateListener>();
 
+    /**
+     * Instantiate a motion state.
+     */
     public RigidBodyMotionState() {
         this.motionStateId = createMotionState();
         Logger.getLogger(this.getClass().getName()).log(Level.FINE, "Created MotionState {0}", Long.toHexString(motionStateId));
@@ -62,8 +69,11 @@ public class RigidBodyMotionState {
     private native long createMotionState();
 
     /**
-     * applies the current transform to the given jme Node if the location has been updated on the physics side
-     * @param spatial
+     * If the motion state has been updated, apply the new transform to the
+     * specified spatial.
+     *
+     * @param spatial where to apply the physics transform (not null, modified)
+     * @return true if changed
      */
     public boolean applyTransform(Spatial spatial) {
         Vector3f localLocation = spatial.getLocalTranslation();
@@ -97,7 +107,10 @@ public class RigidBodyMotionState {
     private native boolean applyTransform(long stateId, Vector3f location, Quaternion rotation);
 
     /**
-     * @return the worldLocation
+     * Copy the location from this motion state.
+     *
+     * @return the pre-existing location vector (in physics-space coordinates,
+     * not null)
      */
     public Vector3f getWorldLocation() {
         getWorldLocation(motionStateId, worldLocation);
@@ -107,7 +120,10 @@ public class RigidBodyMotionState {
     private native void getWorldLocation(long stateId, Vector3f vec);
 
     /**
-     * @return the worldRotation
+     * Read the rotation of this motion state (as a matrix).
+     *
+     * @return the pre-existing rotation matrix (in physics-space coordinates,
+     * not null)
      */
     public Matrix3f getWorldRotation() {
         getWorldRotation(motionStateId, worldRotation);
@@ -117,7 +133,10 @@ public class RigidBodyMotionState {
     private native void getWorldRotation(long stateId, Matrix3f vec);
 
     /**
-     * @return the worldRotationQuat
+     * Read the rotation of this motion state (as a quaternion).
+     *
+     * @return the pre-existing instance (in physics-space coordinates, not
+     * null)
      */
     public Quaternion getWorldRotationQuat() {
         getWorldRotationQuat(motionStateId, worldRotationQuat);
@@ -127,20 +146,39 @@ public class RigidBodyMotionState {
     private native void getWorldRotationQuat(long stateId, Quaternion vec);
 
     /**
-     * @param vehicle the vehicle to set
+     * @param vehicle which vehicle will use this motion state
      */
     public void setVehicle(PhysicsVehicle vehicle) {
         this.vehicle = vehicle;
     }
 
+    /**
+     * Test whether physics-space coordinates should match the spatial's local
+     * coordinates.
+     *
+     * @return true if matching local coordinates, false if matching world
+     * coordinates
+     */
     public boolean isApplyPhysicsLocal() {
         return applyPhysicsLocal;
     }
 
+    /**
+     * Alter whether physics-space coordinates should match the spatial's local
+     * coordinates.
+     *
+     * @param applyPhysicsLocal true&rarr;match local coordinates,
+     * false&rarr;match world coordinates (default is false)
+     */
     public void setApplyPhysicsLocal(boolean applyPhysicsLocal) {
         this.applyPhysicsLocal = applyPhysicsLocal;
     }
     
+    /**
+     * Read the unique id of the native object.
+     *
+     * @return id (not zero)
+     */
     public long getObjectId(){
         return motionStateId;
     }
@@ -152,6 +190,12 @@ public class RigidBodyMotionState {
 //        listeners.remove(listener);
 //    }
 
+    /**
+     * Finalize this motion state just before it is destroyed. Should be invoked
+     * only by a subclass or by the garbage collector.
+     *
+     * @throws Throwable ignored by the garbage collector
+     */
     @Override
     protected void finalize() throws Throwable {
         super.finalize();

+ 23 - 2
jme3-bullet/src/main/java/com/jme3/bullet/objects/infos/VehicleTuning.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,35 @@
 package com.jme3.bullet.objects.infos;
 
 /**
- * 
+ * Typical tuning parameters for a PhysicsVehicle.
+ *
  * @author normenhansen
  */
 public class VehicleTuning {
+    /**
+     * suspension stiffness constant (10&rarr;off-road buggy, 50&rarr;sports
+     * car, 200&rarr;Formula-1 race car, default=5.88)
+     */
     public float suspensionStiffness = 5.88f;
+    /**
+     * suspension damping when compressed (0&rarr;no damping, default=0.83)
+     */
     public float suspensionCompression = 0.83f;
+    /**
+     * suspension damping when expanded (0&rarr;no damping, default=0.88)
+     */
     public float suspensionDamping = 0.88f;
+    /**
+     * maximum suspension travel distance (in centimeters, default=500)
+     */
     public float maxSuspensionTravelCm = 500f;
+    /**
+     * maximum force exerted by each wheel's suspension (default=6000)
+     */
     public float maxSuspensionForce = 6000f;
+    /**
+     * coefficient of friction between tyres and ground (0.8&rarr;realistic car,
+     * 10000&rarr;kart racer, default=10.5)
+     */
     public float frictionSlip = 10.5f;
 }

+ 12 - 1
jme3-bullet/src/main/java/com/jme3/bullet/util/DebugMeshCallback.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,17 @@ public class DebugMeshCallback {
 
     private ArrayList<Vector3f> list = new ArrayList<Vector3f>();
 
+    /**
+     * Add a vertex to the mesh under construction.
+     * <p>
+     * This method is invoked from native code.
+     *
+     * @param x local X coordinate of new vertex
+     * @param y local Y coordinate of new vertex
+     * @param z local Z coordinate of new vertex
+     * @param part ignored
+     * @param index ignored
+     */
     public void addVector(float x, float y, float z, int part, int index) {
         list.add(new Vector3f(x, y, z));
     }

+ 20 - 5
jme3-bullet/src/main/java/com/jme3/bullet/util/DebugShapeFactory.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2017 jMonkeyEngine
+ * Copyright (c) 2009-2018 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -57,10 +57,13 @@ public class DebugShapeFactory {
 //    private static final Vector3f aabbMin = new Vector3f(-1e30f, -1e30f, -1e30f);
 
     /**
-     * Creates a debug shape from the given collision shape. This is mostly used internally.<br>
-     * To attach a debug shape to a physics object, call <code>attachDebugShape(AssetManager manager);</code> on it.
-     * @param collisionShape
-     * @return
+     * Create a debug spatial from the specified collision shape.
+     * <p>
+     * This is mostly used internally. To attach a debug shape to a physics
+     * object, call <code>attachDebugShape(AssetManager manager);</code> on it.
+     *
+     * @param collisionShape the shape to visualize (may be null, unaffected)
+     * @return a new tree of geometries, or null
      */
     public static Spatial getDebugShape(CollisionShape collisionShape) {
         if (collisionShape == null) {
@@ -102,6 +105,12 @@ public class DebugShapeFactory {
         return debugShape;
     }
 
+    /**
+     * Create a geometry for visualizing the specified shape.
+     *
+     * @param shape (not null, unaffected)
+     * @return a new geometry (not null)
+     */
     private static Geometry createDebugShape(CollisionShape shape) {
         Geometry geom = new Geometry();
         geom.setMesh(DebugShapeFactory.getDebugMesh(shape));
@@ -110,6 +119,12 @@ public class DebugShapeFactory {
         return geom;
     }
 
+    /**
+     * Create a mesh for visualizing the specified shape.
+     *
+     * @param shape (not null, unaffected)
+     * @return a new mesh (not null)
+     */
     public static Mesh getDebugMesh(CollisionShape shape) {
         Mesh mesh = new Mesh();
         DebugMeshCallback callback = new DebugMeshCallback();