159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage com.jme3.scene.plugins.blender.animations;
259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.List;
459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.animation.BoneTrack;
659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.AbstractBlenderHelper;
759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.BlenderContext;
859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.curves.BezierCurve;
959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.file.BlenderInputStream;
1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.file.FileBlockHeader;
1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.file.Pointer;
1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.file.Structure;
1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/**
1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This class helps to compute values from interpolation curves for features
1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * like animation or constraint influence. The curves are 3rd degree bezier
1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * curves.
1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Marcin Roguski
2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */
2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic class IpoHelper extends AbstractBlenderHelper {
2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This constructor parses the given blender version and stores the result.
2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * Some functionalities may differ in different blender versions.
2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *
2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param blenderVersion
2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the version read from the blend file
3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param fixUpAxis
3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            a variable that indicates if the Y asxis is the UP axis or not
3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public IpoHelper(String blenderVersion, boolean fixUpAxis) {
3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		super(blenderVersion, fixUpAxis);
3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This method creates an ipo object used for interpolation calculations.
3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *
4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param ipoStructure
4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the structure with ipo definition
4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param blenderContext
4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the blender context
4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @return the ipo object
4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @throws BlenderFileException
4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *             this exception is thrown when the blender file is somehow
4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *             corrupted
4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public Ipo fromIpoStructure(Structure ipoStructure, BlenderContext blenderContext) throws BlenderFileException {
5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		Structure curvebase = (Structure) ipoStructure.getFieldValue("curve");
5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		// preparing bezier curves
5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		Ipo result = null;
5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		List<Structure> curves = curvebase.evaluateListBase(blenderContext);// IpoCurve
5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		if (curves.size() > 0) {
5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			BezierCurve[] bezierCurves = new BezierCurve[curves.size()];
5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			int frame = 0;
5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			for (Structure curve : curves) {
5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				Pointer pBezTriple = (Pointer) curve.getFieldValue("bezt");
6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				List<Structure> bezTriples = pBezTriple.fetchData(blenderContext.getInputStream());
6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				int type = ((Number) curve.getFieldValue("adrcode")).intValue();
6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2);
6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			}
6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			curves.clear();
6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			result = new Ipo(bezierCurves, fixUpAxis);
6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			blenderContext.addLoadedFeatures(ipoStructure.getOldMemoryAddress(), ipoStructure.getName(), ipoStructure, result);
6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		return result;
6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This method creates an ipo object used for interpolation calculations. It
7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * should be called for blender version 2.50 and higher.
7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *
7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param actionStructure
7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the structure with action definition
7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param blenderContext
7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the blender context
7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @return the ipo object
8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @throws BlenderFileException
8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *             this exception is thrown when the blender file is somehow
8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *             corrupted
8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public Ipo fromAction(Structure actionStructure, BlenderContext blenderContext) throws BlenderFileException {
8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		Ipo result = null;
8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		List<Structure> curves = ((Structure) actionStructure.getFieldValue("curves")).evaluateListBase(blenderContext);// FCurve
8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		if (curves.size() > 0) {
8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			BezierCurve[] bezierCurves = new BezierCurve[curves.size()];
8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			int frame = 0;
9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			for (Structure curve : curves) {
9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				Pointer pBezTriple = (Pointer) curve.getFieldValue("bezt");
9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				List<Structure> bezTriples = pBezTriple.fetchData(blenderContext.getInputStream());
9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				int type = this.getCurveType(curve, blenderContext);
9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2);
9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			}
9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			curves.clear();
9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			result = new Ipo(bezierCurves, fixUpAxis);
9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		return result;
10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This method returns the type of the ipo curve.
10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *
10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param structure
10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the structure must contain the 'rna_path' field and
10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            'array_index' field (the type is not important here)
10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param blenderContext
10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the blender context
11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @return the type of the curve
11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public int getCurveType(Structure structure, BlenderContext blenderContext) {
11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		// reading rna path first
11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		BlenderInputStream bis = blenderContext.getInputStream();
11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		int currentPosition = bis.getPosition();
11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		Pointer pRnaPath = (Pointer) structure.getFieldValue("rna_path");
11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		FileBlockHeader dataFileBlock = blenderContext.getFileBlock(pRnaPath.getOldMemoryAddress());
11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		bis.setPosition(dataFileBlock.getBlockPosition());
11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		String rnaPath = bis.readString();
12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		bis.setPosition(currentPosition);
12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		int arrayIndex = ((Number) structure.getFieldValue("array_index")).intValue();
12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		// determining the curve type
12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		if (rnaPath.endsWith("location")) {
12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			return Ipo.AC_LOC_X + arrayIndex;
12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		if (rnaPath.endsWith("rotation_quaternion")) {
12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			return Ipo.AC_QUAT_W + arrayIndex;
12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		if (rnaPath.endsWith("scale")) {
13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			return Ipo.AC_SIZE_X + arrayIndex;
13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		if (rnaPath.endsWith("rotation")) {
13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			return Ipo.OB_ROT_X + arrayIndex;
13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		throw new IllegalStateException("Unknown curve rna path: " + rnaPath);
13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This method creates an ipo with only a single value. No track type is
14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * specified so do not use it for calculating tracks.
14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *
14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param constValue
14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the value of this ipo
14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @return constant ipo
14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public Ipo fromValue(float constValue) {
14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		return new ConstIpo(constValue);
14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	@Override
15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		return true;
15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * Ipo constant curve. This is a curve with only one value and no specified
15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * type. This type of ipo cannot be used to calculate tracks. It should only
15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * be used to calculate single value for a given frame.
16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *
16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @author Marcin Roguski
16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
16359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private class ConstIpo extends Ipo {
16459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
16559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		/** The constant value of this ipo. */
16659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		private float	constValue;
16759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
16859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		/**
16959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 * Constructor. Stores the constant value of this ipo.
17059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 *
17159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 * @param constValue
17259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 *            the constant value of this ipo
17359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		 */
17459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		public ConstIpo(float constValue) {
17559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			super(null, false);
17659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			this.constValue = constValue;
17759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
17859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
17959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		@Override
18059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		public float calculateValue(int frame) {
18159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			return constValue;
18259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
18359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
18459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		@Override
18559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		public float calculateValue(int frame, int curveIndex) {
18659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			return constValue;
18759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
18859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
18959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		@Override
19059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		public int getCurvesAmount() {
19159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			return 0;
19259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
19359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
19459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		@Override
19559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		public BoneTrack calculateTrack(int boneIndex, int startFrame, int stopFrame, int fps, boolean boneTrack) {
19659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			throw new IllegalStateException("Constatnt ipo object cannot be used for calculating bone tracks!");
19759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
19859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
19959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta}
200