aboutsummaryrefslogtreecommitdiff
path: root/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java')
-rw-r--r--engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java203
1 files changed, 203 insertions, 0 deletions
diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java
new file mode 100644
index 0000000..d75728f
--- /dev/null
+++ b/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintHelper.java
@@ -0,0 +1,203 @@
+package com.jme3.scene.plugins.blender.constraints;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
+import com.jme3.scene.plugins.blender.BlenderContext;
+import com.jme3.scene.plugins.blender.animations.Ipo;
+import com.jme3.scene.plugins.blender.animations.IpoHelper;
+import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
+import com.jme3.scene.plugins.blender.file.Pointer;
+import com.jme3.scene.plugins.blender.file.Structure;
+
+/**
+ * This class should be used for constraint calculations.
+ * @author Marcin Roguski (Kaelthas)
+ */
+public class ConstraintHelper extends AbstractBlenderHelper {
+ private static final Logger LOGGER = Logger.getLogger(ConstraintHelper.class.getName());
+
+ private static final Map<String, Class<? extends Constraint>> constraintClasses = new HashMap<String, Class<? extends Constraint>>(22);
+ static {
+ constraintClasses.put("bActionConstraint", ConstraintAction.class);
+ constraintClasses.put("bChildOfConstraint", ConstraintChildOf.class);
+ constraintClasses.put("bClampToConstraint", ConstraintClampTo.class);
+ constraintClasses.put("bDistLimitConstraint", ConstraintDistLimit.class);
+ constraintClasses.put("bFollowPathConstraint", ConstraintFollowPath.class);
+ constraintClasses.put("bKinematicConstraint", ConstraintInverseKinematics.class);
+ constraintClasses.put("bLockTrackConstraint", ConstraintLockTrack.class);
+ constraintClasses.put("bLocateLikeConstraint", ConstraintLocLike.class);
+ constraintClasses.put("bLocLimitConstraint", ConstraintLocLimit.class);
+ constraintClasses.put("bMinMaxConstraint", ConstraintMinMax.class);
+ constraintClasses.put("bNullConstraint", ConstraintNull.class);
+ constraintClasses.put("bPythonConstraint", ConstraintPython.class);
+ constraintClasses.put("bRigidBodyJointConstraint", ConstraintRigidBodyJoint.class);
+ constraintClasses.put("bRotateLikeConstraint", ConstraintRotLike.class);
+ constraintClasses.put("bShrinkWrapConstraint", ConstraintShrinkWrap.class);
+ constraintClasses.put("bSizeLikeConstraint", ConstraintSizeLike.class);
+ constraintClasses.put("bSizeLimitConstraint", ConstraintSizeLimit.class);
+ constraintClasses.put("bStretchToConstraint", ConstraintStretchTo.class);
+ constraintClasses.put("bTransformConstraint", ConstraintTransform.class);
+ constraintClasses.put("bRotLimitConstraint", ConstraintRotLimit.class);
+ //Blender 2.50+
+ constraintClasses.put("bSplineIKConstraint", ConstraintSplineInverseKinematic.class);
+ constraintClasses.put("bDampTrackConstraint", ConstraintDampTrack.class);
+ constraintClasses.put("bPivotConstraint", ConstraintDampTrack.class);
+ }
+
+ /**
+ * Helper constructor. It's main task is to generate the affection functions. These functions are common to all
+ * ConstraintHelper instances. Unfortunately this constructor might grow large. If it becomes too large - I shall
+ * consider refactoring. The constructor parses the given blender version and stores the result. Some
+ * functionalities may differ in different blender versions.
+ * @param blenderVersion
+ * the version read from the blend file
+ * @param fixUpAxis
+ * a variable that indicates if the Y asxis is the UP axis or not
+ */
+ public ConstraintHelper(String blenderVersion, BlenderContext blenderContext, boolean fixUpAxis) {
+ super(blenderVersion, fixUpAxis);
+ }
+
+ /**
+ * This method reads constraints for for the given structure. The
+ * constraints are loaded only once for object/bone.
+ *
+ * @param objectStructure
+ * the structure we read constraint's for
+ * @param blenderContext
+ * the blender context
+ * @throws BlenderFileException
+ */
+ public void loadConstraints(Structure objectStructure, BlenderContext blenderContext) throws BlenderFileException {
+ LOGGER.fine("Loading constraints.");
+ // reading influence ipos for the constraints
+ IpoHelper ipoHelper = blenderContext.getHelper(IpoHelper.class);
+ Map<String, Map<String, Ipo>> constraintsIpos = new HashMap<String, Map<String, Ipo>>();
+ Pointer pActions = (Pointer) objectStructure.getFieldValue("action");
+ if (pActions.isNotNull()) {
+ List<Structure> actions = pActions.fetchData(blenderContext.getInputStream());
+ for (Structure action : actions) {
+ Structure chanbase = (Structure) action.getFieldValue("chanbase");
+ List<Structure> actionChannels = chanbase.evaluateListBase(blenderContext);
+ for (Structure actionChannel : actionChannels) {
+ Map<String, Ipo> ipos = new HashMap<String, Ipo>();
+ Structure constChannels = (Structure) actionChannel.getFieldValue("constraintChannels");
+ List<Structure> constraintChannels = constChannels.evaluateListBase(blenderContext);
+ for (Structure constraintChannel : constraintChannels) {
+ Pointer pIpo = (Pointer) constraintChannel.getFieldValue("ipo");
+ if (pIpo.isNotNull()) {
+ String constraintName = constraintChannel.getFieldValue("name").toString();
+ Ipo ipo = ipoHelper.fromIpoStructure(pIpo.fetchData(blenderContext.getInputStream()).get(0), blenderContext);
+ ipos.put(constraintName, ipo);
+ }
+ }
+ String actionName = actionChannel.getFieldValue("name").toString();
+ constraintsIpos.put(actionName, ipos);
+ }
+ }
+ }
+
+ //loading constraints connected with the object's bones
+ Pointer pPose = (Pointer) objectStructure.getFieldValue("pose");
+ if (pPose.isNotNull()) {
+ List<Structure> poseChannels = ((Structure) pPose.fetchData(blenderContext.getInputStream()).get(0).getFieldValue("chanbase")).evaluateListBase(blenderContext);
+ for (Structure poseChannel : poseChannels) {
+ List<Constraint> constraintsList = new ArrayList<Constraint>();
+ Long boneOMA = Long.valueOf(((Pointer) poseChannel.getFieldValue("bone")).getOldMemoryAddress());
+
+ //the name is read directly from structure because bone might not yet be loaded
+ String name = blenderContext.getFileBlock(boneOMA).getStructure(blenderContext).getFieldValue("name").toString();
+ List<Structure> constraints = ((Structure) poseChannel.getFieldValue("constraints")).evaluateListBase(blenderContext);
+ for (Structure constraint : constraints) {
+ String constraintName = constraint.getFieldValue("name").toString();
+ Map<String, Ipo> ipoMap = constraintsIpos.get(name);
+ Ipo ipo = ipoMap==null ? null : ipoMap.get(constraintName);
+ if (ipo == null) {
+ float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
+ ipo = ipoHelper.fromValue(enforce);
+ }
+ constraintsList.add(this.createConstraint(constraint, boneOMA, ipo, blenderContext));
+ }
+ blenderContext.addConstraints(boneOMA, constraintsList);
+ }
+ }
+
+ //loading constraints connected with the object itself
+ List<Structure> constraints = ((Structure)objectStructure.getFieldValue("constraints")).evaluateListBase(blenderContext);
+ List<Constraint> constraintsList = new ArrayList<Constraint>(constraints.size());
+
+ for(Structure constraint : constraints) {
+ String constraintName = constraint.getFieldValue("name").toString();
+ String objectName = objectStructure.getName();
+
+ Map<String, Ipo> objectConstraintsIpos = constraintsIpos.get(objectName);
+ Ipo ipo = objectConstraintsIpos!=null ? objectConstraintsIpos.get(constraintName) : null;
+ if (ipo == null) {
+ float enforce = ((Number) constraint.getFieldValue("enforce")).floatValue();
+ ipo = ipoHelper.fromValue(enforce);
+ }
+ constraintsList.add(this.createConstraint(constraint, objectStructure.getOldMemoryAddress(), ipo, blenderContext));
+ }
+ blenderContext.addConstraints(objectStructure.getOldMemoryAddress(), constraintsList);
+ }
+
+ /**
+ * This method creates the constraint instance.
+ *
+ * @param constraintStructure
+ * the constraint's structure (bConstraint clss in blender 2.49).
+ * @param ownerOMA
+ * the old memory address of the constraint's owner
+ * @param influenceIpo
+ * the ipo curve of the influence factor
+ * @param blenderContext
+ * the blender context
+ * @throws BlenderFileException
+ * this exception is thrown when the blender file is somehow
+ * corrupted
+ */
+ protected Constraint createConstraint(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo,
+ BlenderContext blenderContext) throws BlenderFileException {
+ String constraintClassName = this.getConstraintClassName(constraintStructure, blenderContext);
+ Class<? extends Constraint> constraintClass = constraintClasses.get(constraintClassName);
+ if(constraintClass != null) {
+ try {
+ return (Constraint) constraintClass.getDeclaredConstructors()[0].newInstance(constraintStructure, ownerOMA, influenceIpo,
+ blenderContext);
+ } catch (IllegalArgumentException e) {
+ throw new BlenderFileException(e.getLocalizedMessage(), e);
+ } catch (SecurityException e) {
+ throw new BlenderFileException(e.getLocalizedMessage(), e);
+ } catch (InstantiationException e) {
+ throw new BlenderFileException(e.getLocalizedMessage(), e);
+ } catch (IllegalAccessException e) {
+ throw new BlenderFileException(e.getLocalizedMessage(), e);
+ } catch (InvocationTargetException e) {
+ throw new BlenderFileException(e.getLocalizedMessage(), e);
+ }
+ } else {
+ throw new BlenderFileException("Unknown constraint type: " + constraintClassName);
+ }
+ }
+
+ protected String getConstraintClassName(Structure constraintStructure, BlenderContext blenderContext) throws BlenderFileException {
+ Pointer pData = (Pointer)constraintStructure.getFieldValue("data");
+ if(pData.isNotNull()) {
+ Structure data = pData.fetchData(blenderContext.getInputStream()).get(0);
+ return data.getType();
+
+ }
+ return constraintStructure.getType();
+ }
+
+ @Override
+ public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
+ return true;
+ }
+}