Home | History | Annotate | Download | only in animations
      1 package com.jme3.scene.plugins.blender.animations;
      2 
      3 import com.jme3.animation.BoneTrack;
      4 import com.jme3.animation.SpatialTrack;
      5 import com.jme3.animation.Track;
      6 import com.jme3.math.FastMath;
      7 import com.jme3.math.Quaternion;
      8 import com.jme3.math.Vector3f;
      9 import com.jme3.scene.plugins.blender.curves.BezierCurve;
     10 
     11 /**
     12  * This class is used to calculate bezier curves value for the given frames. The
     13  * Ipo (interpolation object) consists of several b-spline curves (connected 3rd
     14  * degree bezier curves) of a different type.
     15  *
     16  * @author Marcin Roguski
     17  */
     18 public class Ipo {
     19 
     20 	public static final int	AC_LOC_X	= 1;
     21 	public static final int	AC_LOC_Y	= 2;
     22 	public static final int	AC_LOC_Z	= 3;
     23 	public static final int	OB_ROT_X	= 7;
     24 	public static final int	OB_ROT_Y	= 8;
     25 	public static final int	OB_ROT_Z	= 9;
     26 	public static final int	AC_SIZE_X	= 13;
     27 	public static final int	AC_SIZE_Y	= 14;
     28 	public static final int	AC_SIZE_Z	= 15;
     29 	public static final int	AC_QUAT_W	= 25;
     30 	public static final int	AC_QUAT_X	= 26;
     31 	public static final int	AC_QUAT_Y	= 27;
     32 	public static final int	AC_QUAT_Z	= 28;
     33 
     34 	/** A list of bezier curves for this interpolation object. */
     35 	private BezierCurve[]	bezierCurves;
     36 	/** Each ipo contains one bone track. */
     37 	private Track			calculatedTrack;
     38 	/** This variable indicates if the Y asxis is the UP axis or not. */
     39 	protected boolean		fixUpAxis;
     40 
     41 	/**
     42 	 * Constructor. Stores the bezier curves.
     43 	 *
     44 	 * @param bezierCurves
     45 	 *            a table of bezier curves
     46 	 */
     47 	public Ipo(BezierCurve[] bezierCurves, boolean fixUpAxis) {
     48 		this.bezierCurves = bezierCurves;
     49 		this.fixUpAxis = fixUpAxis;
     50 	}
     51 
     52 	/**
     53 	 * This method calculates the ipo value for the first curve.
     54 	 *
     55 	 * @param frame
     56 	 *            the frame for which the value is calculated
     57 	 * @return calculated ipo value
     58 	 */
     59 	public float calculateValue(int frame) {
     60 		return this.calculateValue(frame, 0);
     61 	}
     62 
     63 	/**
     64 	 * This method calculates the ipo value for the curve of the specified
     65 	 * index. Make sure you do not exceed the curves amount. Alway chech the
     66 	 * amount of curves before calling this method.
     67 	 *
     68 	 * @param frame
     69 	 *            the frame for which the value is calculated
     70 	 * @param curveIndex
     71 	 *            the index of the curve
     72 	 * @return calculated ipo value
     73 	 */
     74 	public float calculateValue(int frame, int curveIndex) {
     75 		return bezierCurves[curveIndex].evaluate(frame, BezierCurve.Y_VALUE);
     76 	}
     77 
     78 	/**
     79 	 * This method returns the curves amount.
     80 	 *
     81 	 * @return the curves amount
     82 	 */
     83 	public int getCurvesAmount() {
     84 		return bezierCurves.length;
     85 	}
     86 
     87 	/**
     88 	 * This method returns the frame where last bezier triple center point of
     89 	 * the specified bezier curve is located.
     90 	 *
     91 	 * @return the frame number of the last defined bezier triple point for the
     92 	 *         specified ipo
     93 	 */
     94 	public int getLastFrame() {
     95 		int result = 1;
     96 		for (int i = 0; i < bezierCurves.length; ++i) {
     97 			int tempResult = bezierCurves[i].getLastFrame();
     98 			if (tempResult > result) {
     99 				result = tempResult;
    100 			}
    101 		}
    102 		return result;
    103 	}
    104 
    105 	/**
    106 	 * This method calculates the value of the curves as a bone track between
    107 	 * the specified frames.
    108 	 *
    109 	 * @param targetIndex
    110 	 *            the index of the target for which the method calculates the
    111 	 *            tracks IMPORTANT! Aet to -1 (or any negative number) if you
    112 	 *            want to load spatial animation.
    113 	 * @param startFrame
    114 	 *            the firs frame of tracks (inclusive)
    115 	 * @param stopFrame
    116 	 *            the last frame of the tracks (inclusive)
    117 	 * @param fps
    118 	 *            frame rate (frames per second)
    119 	 * @param spatialTrack
    120 	 *            this flag indicates if the track belongs to a spatial or to a
    121 	 *            bone; the diference is important because it appears that bones
    122 	 *            in blender have the same type of coordinate system (Y as UP)
    123 	 *            as jme while other features have different one (Z is UP)
    124 	 * @return bone track for the specified bone
    125 	 */
    126 	public Track calculateTrack(int targetIndex, int startFrame, int stopFrame, int fps, boolean spatialTrack) {
    127 		if (calculatedTrack == null) {
    128 			// preparing data for track
    129 			int framesAmount = stopFrame - startFrame;
    130 			float start = (startFrame - 1.0f) / fps;
    131 			float timeBetweenFrames = 1.0f / fps;
    132 
    133 			float[] times = new float[framesAmount + 1];
    134 			Vector3f[] translations = new Vector3f[framesAmount + 1];
    135 			float[] translation = new float[3];
    136 			Quaternion[] rotations = new Quaternion[framesAmount + 1];
    137 			float[] quaternionRotation = new float[4];
    138 			float[] objectRotation = new float[3];
    139 			Vector3f[] scales = new Vector3f[framesAmount + 1];
    140 			float[] scale = new float[] { 1.0f, 1.0f, 1.0f };
    141 			float degreeToRadiansFactor = FastMath.DEG_TO_RAD * 10;// the values in blender are divided by 10, so we need to mult it here
    142 
    143 			// calculating track data
    144 			for (int frame = startFrame; frame <= stopFrame; ++frame) {
    145 				int index = frame - startFrame;
    146 				times[index] = start + (frame - 1) * timeBetweenFrames;
    147 				for (int j = 0; j < bezierCurves.length; ++j) {
    148 					double value = bezierCurves[j].evaluate(frame, BezierCurve.Y_VALUE);
    149 					switch (bezierCurves[j].getType()) {
    150 					// LOCATION
    151 						case AC_LOC_X:
    152 							translation[0] = (float) value;
    153 							break;
    154 						case AC_LOC_Y:
    155 							if (fixUpAxis && spatialTrack) {
    156 								translation[2] = (float) -value;
    157 							} else {
    158 								translation[1] = (float) value;
    159 							}
    160 							break;
    161 						case AC_LOC_Z:
    162 							translation[fixUpAxis && spatialTrack ? 1 : 2] = (float) value;
    163 							break;
    164 
    165 						// ROTATION (used with object animation)
    166 						// the value here is in degrees divided by 10 (so in
    167 						// example: 9 = PI/2)
    168 						case OB_ROT_X:
    169 							objectRotation[0] = (float) value * degreeToRadiansFactor;
    170 							break;
    171 						case OB_ROT_Y:
    172 							if (fixUpAxis) {
    173 								objectRotation[2] = (float) -value * degreeToRadiansFactor;
    174 							} else {
    175 								objectRotation[1] = (float) value * degreeToRadiansFactor;
    176 							}
    177 							break;
    178 						case OB_ROT_Z:
    179 							objectRotation[fixUpAxis ? 1 : 2] = (float) value * degreeToRadiansFactor;
    180 							break;
    181 
    182 						// SIZE
    183 						case AC_SIZE_X:
    184 							scale[0] = (float) value;
    185 							break;
    186 						case AC_SIZE_Y:
    187 							if (fixUpAxis && spatialTrack) {
    188 								scale[2] = (float) value;
    189 							} else {
    190 								scale[1] = (float) value;
    191 							}
    192 							break;
    193 						case AC_SIZE_Z:
    194 							scale[fixUpAxis && spatialTrack ? 1 : 2] = (float) value;
    195 							break;
    196 
    197 						// QUATERNION ROTATION (used with bone animation), dunno
    198 						// why but here we shouldn't check the
    199 						// spatialTrack flag value
    200 						case AC_QUAT_W:
    201 							quaternionRotation[3] = (float) value;
    202 							break;
    203 						case AC_QUAT_X:
    204 							quaternionRotation[0] = (float) value;
    205 							break;
    206 						case AC_QUAT_Y:
    207 							if (fixUpAxis) {
    208 								quaternionRotation[2] = -(float) value;
    209 							} else {
    210 								quaternionRotation[1] = (float) value;
    211 							}
    212 							break;
    213 						case AC_QUAT_Z:
    214 							if (fixUpAxis) {
    215 								quaternionRotation[1] = (float) value;
    216 							} else {
    217 								quaternionRotation[2] = (float) value;
    218 							}
    219 							break;
    220 						default:
    221 							throw new IllegalStateException("Unknown ipo curve type: " + bezierCurves[j].getType());
    222 					}
    223 				}
    224 				translations[index] = new Vector3f(translation[0], translation[1], translation[2]);
    225 				rotations[index] = spatialTrack ? new Quaternion().fromAngles(objectRotation) : new Quaternion(quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]);
    226 				scales[index] = new Vector3f(scale[0], scale[1], scale[2]);
    227 			}
    228 			if (spatialTrack) {
    229 				calculatedTrack = new SpatialTrack(times, translations, rotations, scales);
    230 			} else {
    231 				calculatedTrack = new BoneTrack(targetIndex, times, translations, rotations, scales);
    232 			}
    233 		}
    234 		return calculatedTrack;
    235 	}
    236 }