diff --git a/engine/src/bullet-common/com/jme3/bullet/control/KinematicRagdollControl.java b/engine/src/bullet-common/com/jme3/bullet/control/KinematicRagdollControl.java index e5720bd3d..63ddf10a7 100644 --- a/engine/src/bullet-common/com/jme3/bullet/control/KinematicRagdollControl.java +++ b/engine/src/bullet-common/com/jme3/bullet/control/KinematicRagdollControl.java @@ -47,8 +47,10 @@ import com.jme3.bullet.control.ragdoll.RagdollPreset; import com.jme3.bullet.control.ragdoll.RagdollUtils; import com.jme3.bullet.joints.SixDofJoint; import com.jme3.bullet.objects.PhysicsRigidBody; +import com.jme3.export.InputCapsule; import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; import com.jme3.renderer.RenderManager; @@ -92,31 +94,28 @@ import java.util.logging.Logger; * * @author Normen Hansen and Rémy Bouquet (Nehon) */ -public class KinematicRagdollControl implements PhysicsControl, PhysicsCollisionListener { +public class KinematicRagdollControl extends AbstractPhysicsControl implements PhysicsCollisionListener { protected static final Logger logger = Logger.getLogger(KinematicRagdollControl.class.getName()); - protected Map boneLinks = new HashMap(); - protected Skeleton skeleton; - protected PhysicsSpace space; - protected boolean enabled = true; - protected boolean debug = false; + protected List listeners; + protected final Set boneList = new TreeSet(); + protected final Map boneLinks = new HashMap(); + protected final Vector3f modelPosition = new Vector3f(); + protected final Quaternion modelRotation = new Quaternion(); protected PhysicsRigidBody baseRigidBody; - protected float weightThreshold = -1.0f; protected Spatial targetModel; + protected Skeleton skeleton; + protected RagdollPreset preset = new HumanoidRagdollPreset(); protected Vector3f initScale; protected Mode mode = Mode.Kinematic; + protected boolean debug = false; protected boolean blendedControl = false; - protected float blendTime = 1.0f; + protected float weightThreshold = -1.0f; protected float blendStart = 0.0f; - protected List listeners; + protected float blendTime = 1.0f; protected float eventDispatchImpulseThreshold = 10; - protected RagdollPreset preset = new HumanoidRagdollPreset(); - protected Set boneList = new TreeSet(); - protected Vector3f modelPosition = new Vector3f(); - protected Quaternion modelRotation = new Quaternion(); protected float rootMass = 15; protected float totalMass = 0; - protected boolean added = false; public static enum Mode { @@ -166,7 +165,7 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision return; } TempVars vars = TempVars.get(); - + Quaternion tmpRot1 = vars.quat1; Quaternion tmpRot2 = vars.quat2; @@ -270,13 +269,15 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision } /** - * 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 + * 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 + * * @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 tmpRot1 just a temp quaternion for rotation */ - private void matchPhysicObjectToBone(PhysicsBoneLink link, Vector3f position, Quaternion tmpRot1) { + protected void matchPhysicObjectToBone(PhysicsBoneLink link, Vector3f position, Quaternion tmpRot1) { //computing position from rotation and scale targetModel.getWorldTransform().transformVector(link.bone.getModelSpacePosition(), position); @@ -291,23 +292,29 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision } - public Control cloneForSpatial(Spatial spatial) { - throw new UnsupportedOperationException("Not supported yet."); - } - /** - * rebuild the ragdoll - * this is useful if you applied scale on the ragdoll after it's been initialized + * rebuild the ragdoll this is useful if you applied scale on the ragdoll + * after it's been initialized, same as reattaching. */ public void reBuild() { - setSpatial(targetModel); - addToPhysicsSpace(); + if (added) { + removePhysics(space); + setSpatial(targetModel); + addPhysics(space); + } else { + setSpatial(targetModel); + } } + @Override public void setSpatial(Spatial model) { + super.setSpatial(model); + if (added) { + removePhysics(space); + } + boneLinks.clear(); + baseRigidBody = null; if (model == null) { - removeFromPhysicsSpace(); - clearData(); return; } targetModel = model; @@ -328,10 +335,7 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision SkeletonControl sc = model.getControl(SkeletonControl.class); model.removeControl(sc); model.addControl(sc); - //---- - removeFromPhysicsSpace(); - clearData(); // put into bind pose and compute bone transforms in model space // maybe dont reset to ragdoll out of animations? scanSpatial(model); @@ -345,19 +349,23 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision model.setLocalRotation(initRotation); model.setLocalScale(initScale); + if (added) { + addPhysics(space); + } logger.log(Level.FINE, "Created physics ragdoll for skeleton {0}", skeleton); } /** - * 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. - * @param name + * 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. + * + * @param name */ public void addBoneName(String name) { boneList.add(name); } - private void scanSpatial(Spatial model) { + protected void scanSpatial(Spatial model) { AnimControl animControl = model.getControl(AnimControl.class); Map> pointsMap = null; if (weightThreshold == -1.0f) { @@ -377,7 +385,7 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision } } - private void boneRecursion(Spatial model, Bone bone, PhysicsRigidBody parent, int reccount, Map> pointsMap) { + protected void boneRecursion(Spatial model, Bone bone, PhysicsRigidBody parent, int reccount, Map> pointsMap) { PhysicsRigidBody parentShape = parent; if (boneList.isEmpty() || boneList.contains(bone.getName())) { @@ -429,6 +437,7 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision /** * 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 + * * @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) @@ -447,8 +456,9 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision } /** - * 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 given bone and its parent. This return null + * if it's called before attaching the control to a spatial + * * @param boneName the name of the bone * @return the joint between the given bone and its parent */ @@ -462,18 +472,24 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision } } - private void clearData() { - boneLinks.clear(); - baseRigidBody = null; + @Override + protected void setPhysicsLocation(Vector3f vec) { + if (baseRigidBody != null) { + baseRigidBody.setPhysicsLocation(vec); + } } - private void addToPhysicsSpace() { - if (space == null) { - return; + @Override + protected void setPhysicsRotation(Quaternion quat) { + if (baseRigidBody != null) { + baseRigidBody.setPhysicsRotation(quat); } + } + + @Override + protected void addPhysics(PhysicsSpace space) { if (baseRigidBody != null) { space.add(baseRigidBody); - added = true; } for (Iterator it = boneLinks.values().iterator(); it.hasNext();) { PhysicsBoneLink physicsBoneLink = it.next(); @@ -483,15 +499,13 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision space.add(physicsBoneLink.joint); } - added = true; } } + space.addCollisionListener(this); } - protected void removeFromPhysicsSpace() { - if (space == null) { - return; - } + @Override + protected void removePhysics(PhysicsSpace space) { if (baseRigidBody != null) { space.remove(baseRigidBody); } @@ -504,92 +518,13 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision } } } - added = false; - } - - /** - * enable or disable the control - * note that if enabled is true and that the physic space has been set on the ragdoll, the ragdoll is added to the physic space - * if enabled is false the ragdoll is removed from physic space. - * @param enabled - */ - public void setEnabled(boolean enabled) { - if (this.enabled == enabled) { - return; - } - this.enabled = enabled; - if (!enabled && space != null) { - removeFromPhysicsSpace(); - } else if (enabled && space != null) { - addToPhysicsSpace(); - } + space.removeCollisionListener(this); } /** - * returns true if the control is enabled - * @return - */ - public boolean isEnabled() { - return enabled; - } - - /** - * For internal use only - * specific render for the ragdoll(if debugging) - * @param rm - * @param vp - */ - public void render(RenderManager rm, ViewPort vp) { - } - - /** - * set the physic space to this ragdoll - * @param space - */ - public void setPhysicsSpace(PhysicsSpace space) { - if (space == null) { - removeFromPhysicsSpace(); - this.space = space; - } else { - if (this.space == space) { - return; - } - this.space = space; - addToPhysicsSpace(); - this.space.addCollisionListener(this); - } - } - - /** - * returns the physic space - * @return - */ - public PhysicsSpace getPhysicsSpace() { - return space; - } - - /** - * serialize this control - * @param ex - * @throws IOException - */ - public void write(JmeExporter ex) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); - } - - /** - * de-serialize this control - * @param im - * @throws IOException - */ - public void read(JmeImporter im) throws IOException { - throw new UnsupportedOperationException("Not supported yet."); - } - - /** - * For internal use only - * callback for collisionevent - * @param event + * For internal use only callback for collisionevent + * + * @param event */ public void collision(PhysicsCollisionEvent event) { PhysicsCollisionObject objA = event.getObjectA(); @@ -639,11 +574,12 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision } /** - * Enable or disable the ragdoll behaviour. - * if ragdollEnabled is true, the character motion will only be powerd by physics - * else, the characted will be animated by the keyframe animation, - * but will be able to physically interact with its physic environnement - * @param ragdollEnabled + * Enable or disable the ragdoll behaviour. if ragdollEnabled is true, the + * character motion will only be powerd by physics else, the characted will + * be animated by the keyframe animation, but will be able to physically + * interact with its physic environnement + * + * @param ragdollEnabled */ protected void setMode(Mode mode) { this.mode = mode; @@ -652,7 +588,7 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision baseRigidBody.setKinematic(mode == Mode.Kinematic); TempVars vars = TempVars.get(); - + for (PhysicsBoneLink link : boneLinks.values()) { link.rigidBody.setKinematic(mode == Mode.Kinematic); if (mode == Mode.Ragdoll) { @@ -671,8 +607,9 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision } /** - * Smoothly blend from Ragdoll mode to Kinematic mode - * This is useful to blend ragdoll actual position to a keyframe animation for example + * Smoothly blend from Ragdoll mode to Kinematic mode This is useful to + * blend ragdoll actual position to a keyframe animation for example + * * @param blendTime the blending time between ragdoll to anim. */ public void blendToKinematicMode(float blendTime) { @@ -686,7 +623,7 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision animControl.setEnabled(true); - TempVars vars = TempVars.get(); + TempVars vars = TempVars.get(); for (PhysicsBoneLink link : boneLinks.values()) { Vector3f p = link.rigidBody.getMotionState().getWorldLocation(); @@ -715,9 +652,9 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision } /** - * Set the control into Kinematic mode - * In theis mode, the collision shapes follow the movements of the skeleton, - * and can interact with physical environement + * Set the control into Kinematic mode In theis mode, the collision shapes + * follow the movements of the skeleton, and can interact with physical + * environement */ public void setKinematicMode() { if (mode != Mode.Kinematic) { @@ -726,8 +663,8 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision } /** - * Sets the control into Ragdoll mode - * The skeleton is entirely controlled by physics. + * Sets the control into Ragdoll mode The skeleton is entirely controlled by + * physics. */ public void setRagdollMode() { if (mode != Mode.Ragdoll) { @@ -737,15 +674,17 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision /** * retruns the mode of this control - * @return + * + * @return */ public Mode getMode() { return mode; } /** - * add a - * @param listener + * add a + * + * @param listener */ public void addCollisionListener(RagdollCollisionListener listener) { if (listeners == null) { @@ -780,8 +719,9 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision /** * Set the CcdMotionThreshold of all the bone's rigidBodies of the ragdoll - * @see PhysicsRigidBody#setCcdMotionThreshold(float) - * @param value + * + * @see PhysicsRigidBody#setCcdMotionThreshold(float) + * @param value */ public void setCcdMotionThreshold(float value) { for (PhysicsBoneLink link : boneLinks.values()) { @@ -791,8 +731,9 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision /** * Set the CcdSweptSphereRadius of all the bone's rigidBodies of the ragdoll - * @see PhysicsRigidBody#setCcdSweptSphereRadius(float) - * @param value + * + * @see PhysicsRigidBody#setCcdSweptSphereRadius(float) + * @param value */ public void setCcdSweptSphereRadius(float value) { for (PhysicsBoneLink link : boneLinks.values()) { @@ -802,6 +743,7 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision /** * return the rigidBody associated to the given bone + * * @param boneName the name of the bone * @return the associated rigidBody. */ @@ -812,4 +754,39 @@ public class KinematicRagdollControl implements PhysicsControl, PhysicsCollision } return null; } + + /** + * For internal use only specific render for the ragdoll(if debugging) + * + * @param rm + * @param vp + */ + public void render(RenderManager rm, ViewPort vp) { + } + + public Control cloneForSpatial(Spatial spatial) { + throw new UnsupportedOperationException("Not supported yet."); + } + + /** + * serialize this control + * + * @param ex + * @throws IOException + */ + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule oc = ex.getCapsule(this); + } + + /** + * de-serialize this control + * + * @param im + * @throws IOException + */ + public void read(JmeImporter im) throws IOException { + super.read(im); + InputCapsule ic = im.getCapsule(this); + } }