• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 	 */
Ipo(BezierCurve[] bezierCurves, boolean fixUpAxis)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 	 */
calculateValue(int frame)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 	 */
calculateValue(int frame, int curveIndex)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 	 */
getCurvesAmount()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 	 */
getLastFrame()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 	 */
calculateTrack(int targetIndex, int startFrame, int stopFrame, int fps, boolean spatialTrack)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 }