Home | History | Annotate | Download | only in constraints
      1 package com.jme3.scene.plugins.blender.constraints;
      2 
      3 import com.jme3.animation.Animation;
      4 import com.jme3.animation.Bone;
      5 import com.jme3.math.FastMath;
      6 import com.jme3.math.Quaternion;
      7 import com.jme3.math.Transform;
      8 import com.jme3.scene.Spatial;
      9 import com.jme3.scene.plugins.blender.BlenderContext;
     10 import com.jme3.scene.plugins.blender.animations.Ipo;
     11 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
     12 import com.jme3.scene.plugins.blender.file.Structure;
     13 import com.jme3.scene.plugins.ogre.AnimData;
     14 
     15 /**
     16  * This class represents 'Rot limit' constraint type in blender.
     17  *
     18  * @author Marcin Roguski (Kaelthas)
     19  */
     20 /* package */class ConstraintRotLimit extends Constraint {
     21 	private static final int	LIMIT_XROT	= 0x01;
     22 	private static final int	LIMIT_YROT	= 0x02;
     23 	private static final int	LIMIT_ZROT	= 0x04;
     24 
     25 	protected float[][]			limits		= new float[3][2];
     26 	protected int				flag;
     27 	protected boolean			updated;
     28 
     29 	/**
     30 	 * This constructor creates the constraint instance.
     31 	 *
     32 	 * @param constraintStructure
     33 	 *            the constraint's structure (bConstraint clss in blender 2.49).
     34 	 * @param ownerOMA
     35 	 *            the old memory address of the constraint owner
     36 	 * @param influenceIpo
     37 	 *            the ipo curve of the influence factor
     38 	 * @param blenderContext
     39 	 *            the blender context
     40 	 * @throws BlenderFileException
     41 	 *             this exception is thrown when the blender file is somehow
     42 	 *             corrupted
     43 	 */
     44 	public ConstraintRotLimit(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
     45 		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
     46 
     47 		flag = ((Number) data.getFieldValue("flag")).intValue();
     48 		if (blenderContext.getBlenderKey().isFixUpAxis() && owner.spatial != null) {
     49 			limits[0][0] = ((Number) data.getFieldValue("xmin")).floatValue();
     50 			limits[0][1] = ((Number) data.getFieldValue("xmax")).floatValue();
     51 			limits[2][0] = -((Number) data.getFieldValue("ymin")).floatValue();
     52 			limits[2][1] = -((Number) data.getFieldValue("ymax")).floatValue();
     53 			limits[1][0] = ((Number) data.getFieldValue("zmin")).floatValue();
     54 			limits[1][1] = ((Number) data.getFieldValue("zmax")).floatValue();
     55 
     56 			// swapping Y and X limits flag in the bitwise flag
     57 			int limitY = flag & LIMIT_YROT;
     58 			int limitZ = flag & LIMIT_ZROT;
     59 			flag &= LIMIT_XROT;// clear the other flags to swap them
     60 			flag |= limitY << 1;
     61 			flag |= limitZ >> 1;
     62 		} else {
     63 			limits[0][0] = ((Number) data.getFieldValue("xmin")).floatValue();
     64 			limits[0][1] = ((Number) data.getFieldValue("xmax")).floatValue();
     65 			limits[1][0] = ((Number) data.getFieldValue("ymin")).floatValue();
     66 			limits[1][1] = ((Number) data.getFieldValue("ymax")).floatValue();
     67 			limits[2][0] = ((Number) data.getFieldValue("zmin")).floatValue();
     68 			limits[2][1] = ((Number) data.getFieldValue("zmax")).floatValue();
     69 		}
     70 
     71 		// until blender 2.49 the rotations values were stored in degrees
     72 		if (blenderContext.getBlenderVersion() <= 249) {
     73 			for (int i = 0; i < limits.length; ++i) {
     74 				limits[i][0] *= FastMath.DEG_TO_RAD;
     75 				limits[i][1] *= FastMath.DEG_TO_RAD;
     76 			}
     77 		}
     78 	}
     79 
     80 	@Override
     81 	protected void bakeConstraint() {
     82 		this.update();
     83 		Object owner = this.owner.getObject();
     84 		AnimData animData = blenderContext.getAnimData(this.owner.getOma());
     85 		if (animData != null) {
     86 			for (Animation animation : animData.anims) {
     87 				BlenderTrack track = this.getTrack(owner, animData.skeleton, animation);
     88 				Quaternion[] rotations = track.getRotations();
     89 				float[] angles = new float[3];
     90 				int maxFrames = rotations.length;
     91 				for (int frame = 0; frame < maxFrames; ++frame) {
     92 					rotations[frame].toAngles(angles);
     93 					this.rotLimit(angles, ipo.calculateValue(frame));
     94 					rotations[frame].fromAngles(angles);
     95 				}
     96 				track.setKeyframes(track.getTimes(), track.getTranslations(), rotations, track.getScales());
     97 			}
     98 		}
     99 
    100 		if (owner instanceof Spatial) {
    101 			Transform ownerTransform = this.owner.getTransform();
    102 			float[] angles = ownerTransform.getRotation().toAngles(null);
    103 			this.rotLimit(angles, ipo.calculateValue(0));
    104 			ownerTransform.getRotation().fromAngles(angles);
    105 			this.owner.applyTransform(ownerTransform);
    106 		}
    107 	}
    108 
    109 	/**
    110 	 * This method computes new constrained angles.
    111 	 *
    112 	 * @param angles
    113 	 *            angles to be altered
    114 	 * @param influence
    115 	 *            the alteration influence
    116 	 */
    117 	private void rotLimit(float[] angles, float influence) {
    118 		if ((flag & LIMIT_XROT) != 0) {
    119 			float difference = 0.0f;
    120 			if (angles[0] < limits[0][0]) {
    121 				difference = (angles[0] - limits[0][0]) * influence;
    122 			} else if (angles[0] > limits[0][1]) {
    123 				difference = (angles[0] - limits[0][1]) * influence;
    124 			}
    125 			angles[0] -= difference;
    126 		}
    127 		if ((flag & LIMIT_YROT) != 0) {
    128 			float difference = 0.0f;
    129 			if (angles[1] < limits[1][0]) {
    130 				difference = (angles[1] - limits[1][0]) * influence;
    131 			} else if (angles[1] > limits[1][1]) {
    132 				difference = (angles[1] - limits[1][1]) * influence;
    133 			}
    134 			angles[1] -= difference;
    135 		}
    136 		if ((flag & LIMIT_ZROT) != 0) {
    137 			float difference = 0.0f;
    138 			if (angles[2] < limits[2][0]) {
    139 				difference = (angles[2] - limits[2][0]) * influence;
    140 			} else if (angles[2] > limits[2][1]) {
    141 				difference = (angles[2] - limits[2][1]) * influence;
    142 			}
    143 			angles[2] -= difference;
    144 		}
    145 	}
    146 
    147 	/**
    148 	 * This method is called before baking (performes its operations only once).
    149 	 * It is important to update the state of the limits and owner/target before
    150 	 * baking the constraint.
    151 	 */
    152 	private void update() {
    153 		if (!updated) {
    154 			updated = true;
    155 			if (owner != null) {
    156 				owner.update();
    157 			}
    158 			if (target != null) {
    159 				target.update();
    160 			}
    161 			if (this.owner.getObject() instanceof Bone) {// for bones we need to
    162 															// change the sign
    163 															// of the limits
    164 				for (int i = 0; i < limits.length; ++i) {
    165 					limits[i][0] *= -1;
    166 					limits[i][1] *= -1;
    167 				}
    168 			}
    169 
    170 			// sorting the limits (lower is always first)
    171 			for (int i = 0; i < limits.length; ++i) {
    172 				if (limits[i][0] > limits[i][1]) {
    173 					float temp = limits[i][0];
    174 					limits[i][0] = limits[i][1];
    175 					limits[i][1] = temp;
    176 				}
    177 			}
    178 		}
    179 	}
    180 }
    181