From b0e751c81acfeea1de98da636a260d387a8bb42a Mon Sep 17 00:00:00 2001 From: jmekaelthas Date: Sun, 28 Jun 2015 15:48:49 +0200 Subject: [PATCH] Bugfix: avoiding infinite loops while applying constraints. --- .../blender/constraints/SimulationNode.java | 69 ++++++++++--------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SimulationNode.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SimulationNode.java index 031676b94..711e0a338 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SimulationNode.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SimulationNode.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.Stack; import java.util.logging.Logger; import com.jme3.animation.AnimChannel; @@ -38,9 +39,9 @@ import com.jme3.util.TempVars; * @author Marcin Roguski (Kaelthas) */ public class SimulationNode { - private static final Logger LOGGER = Logger.getLogger(SimulationNode.class.getName()); + private static final Logger LOGGER = Logger.getLogger(SimulationNode.class.getName()); - private Long featureOMA; + private Long featureOMA; /** The blender context. */ private BlenderContext blenderContext; /** The name of the node (for debugging purposes). */ @@ -51,11 +52,11 @@ public class SimulationNode { private List animations; /** The nodes spatial (if null then the boneContext should be set). */ - private Spatial spatial; + private Spatial spatial; /** The skeleton of the bone (not null if the node simulated the bone). */ - private Skeleton skeleton; + private Skeleton skeleton; /** Animation controller for the node's feature. */ - private AnimControl animControl; + private AnimControl animControl; /** * The star transform of a spatial. Needed to properly reset the spatial to @@ -64,7 +65,7 @@ public class SimulationNode { private Transform spatialStartTransform; /** Star transformations for bones. Needed to properly reset the bones. */ private Map boneStartTransforms; - + /** * Builds the nodes tree for the given feature. The feature (bone or * spatial) is found by its OMA. The feature must be a root bone or a root @@ -208,8 +209,7 @@ public class SimulationNode { if (animations != null) { TempVars vars = TempVars.get(); AnimChannel animChannel = animControl.createChannel(); - - // List bonesWithConstraints = this.collectBonesWithConstraints(skeleton); + for (Animation animation : animations) { float[] animationTimeBoundaries = this.computeAnimationTimeBoundaries(animation); int maxFrame = (int) animationTimeBoundaries[0]; @@ -233,7 +233,7 @@ public class SimulationNode { for (Bone rootBone : skeleton.getRoots()) { // ignore the 0-indexed bone if (skeleton.getBoneIndex(rootBone) > 0) { - this.applyConstraints(rootBone, alteredOmas, applied, frame); + this.applyConstraints(rootBone, alteredOmas, applied, frame, new Stack()); } } @@ -294,34 +294,39 @@ public class SimulationNode { * the set of OMAS of the altered bones (is populated if necessary) * @param frame * the current frame of the animation + * @param bonesStack + * the stack of bones used to avoid infinite loops while applying constraints */ - private void applyConstraints(Bone bone, Set alteredOmas, Set applied, int frame) { - BoneContext boneContext = blenderContext.getBoneContext(bone); - if(!applied.contains(boneContext.getBoneOma())) { - List constraints = this.findConstraints(boneContext.getBoneOma(), blenderContext); - if (constraints != null && constraints.size() > 0) { - // TODO: BEWARE OF INFINITE LOOPS !!!!!!!!!!!!!!!!!!!!!!!!!! - for (Constraint constraint : constraints) { - if (constraint.getTargetOMA() != null && constraint.getTargetOMA() > 0L) { - // first apply constraints of the target bone - BoneContext targetBone = blenderContext.getBoneContext(constraint.getTargetOMA()); - this.applyConstraints(targetBone.getBone(), alteredOmas, applied, frame); - } - constraint.apply(frame); - if (constraint.getAlteredOmas() != null) { - alteredOmas.addAll(constraint.getAlteredOmas()); + private void applyConstraints(Bone bone, Set alteredOmas, Set applied, int frame, Stack bonesStack) { + if (!bonesStack.contains(bone)) { + bonesStack.push(bone); + BoneContext boneContext = blenderContext.getBoneContext(bone); + if (!applied.contains(boneContext.getBoneOma())) { + List constraints = this.findConstraints(boneContext.getBoneOma(), blenderContext); + if (constraints != null && constraints.size() > 0) { + for (Constraint constraint : constraints) { + if (constraint.getTargetOMA() != null && constraint.getTargetOMA() > 0L) { + // first apply constraints of the target bone + BoneContext targetBone = blenderContext.getBoneContext(constraint.getTargetOMA()); + this.applyConstraints(targetBone.getBone(), alteredOmas, applied, frame, bonesStack); + } + constraint.apply(frame); + if (constraint.getAlteredOmas() != null) { + alteredOmas.addAll(constraint.getAlteredOmas()); + } + alteredOmas.add(boneContext.getBoneOma()); } - alteredOmas.add(boneContext.getBoneOma()); } + applied.add(boneContext.getBoneOma()); } - applied.add(boneContext.getBoneOma()); - } - - List children = bone.getChildren(); - if (children != null && children.size() > 0) { - for (Bone child : bone.getChildren()) { - this.applyConstraints(child, alteredOmas, applied, frame); + + List children = bone.getChildren(); + if (children != null && children.size() > 0) { + for (Bone child : bone.getChildren()) { + this.applyConstraints(child, alteredOmas, applied, frame, bonesStack); + } } + bonesStack.pop(); } }