package com.jme3.scene.plugins.blender.animations;

import java.util.List;

import com.jme3.animation.BoneTrack;
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
import com.jme3.scene.plugins.blender.BlenderContext;
import com.jme3.scene.plugins.blender.curves.BezierCurve;
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
import com.jme3.scene.plugins.blender.file.BlenderInputStream;
import com.jme3.scene.plugins.blender.file.FileBlockHeader;
import com.jme3.scene.plugins.blender.file.Pointer;
import com.jme3.scene.plugins.blender.file.Structure;

/**
 * This class helps to compute values from interpolation curves for features
 * like animation or constraint influence. The curves are 3rd degree bezier
 * curves.
 * 
 * @author Marcin Roguski
 */
public class IpoHelper extends AbstractBlenderHelper {

	/**
	 * This 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 IpoHelper(String blenderVersion, boolean fixUpAxis) {
		super(blenderVersion, fixUpAxis);
	}

	/**
	 * This method creates an ipo object used for interpolation calculations.
	 * 
	 * @param ipoStructure
	 *            the structure with ipo definition
	 * @param blenderContext
	 *            the blender context
	 * @return the ipo object
	 * @throws BlenderFileException
	 *             this exception is thrown when the blender file is somehow
	 *             corrupted
	 */
	public Ipo fromIpoStructure(Structure ipoStructure, BlenderContext blenderContext) throws BlenderFileException {
		Structure curvebase = (Structure) ipoStructure.getFieldValue("curve");

		// preparing bezier curves
		Ipo result = null;
		List<Structure> curves = curvebase.evaluateListBase(blenderContext);// IpoCurve
		if (curves.size() > 0) {
			BezierCurve[] bezierCurves = new BezierCurve[curves.size()];
			int frame = 0;
			for (Structure curve : curves) {
				Pointer pBezTriple = (Pointer) curve.getFieldValue("bezt");
				List<Structure> bezTriples = pBezTriple.fetchData(blenderContext.getInputStream());
				int type = ((Number) curve.getFieldValue("adrcode")).intValue();
				bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2);
			}
			curves.clear();
			result = new Ipo(bezierCurves, fixUpAxis);
			blenderContext.addLoadedFeatures(ipoStructure.getOldMemoryAddress(), ipoStructure.getName(), ipoStructure, result);
		}
		return result;
	}

	/**
	 * This method creates an ipo object used for interpolation calculations. It
	 * should be called for blender version 2.50 and higher.
	 * 
	 * @param actionStructure
	 *            the structure with action definition
	 * @param blenderContext
	 *            the blender context
	 * @return the ipo object
	 * @throws BlenderFileException
	 *             this exception is thrown when the blender file is somehow
	 *             corrupted
	 */
	public Ipo fromAction(Structure actionStructure, BlenderContext blenderContext) throws BlenderFileException {
		Ipo result = null;
		List<Structure> curves = ((Structure) actionStructure.getFieldValue("curves")).evaluateListBase(blenderContext);// FCurve
		if (curves.size() > 0) {
			BezierCurve[] bezierCurves = new BezierCurve[curves.size()];
			int frame = 0;
			for (Structure curve : curves) {
				Pointer pBezTriple = (Pointer) curve.getFieldValue("bezt");
				List<Structure> bezTriples = pBezTriple.fetchData(blenderContext.getInputStream());
				int type = this.getCurveType(curve, blenderContext);
				bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2);
			}
			curves.clear();
			result = new Ipo(bezierCurves, fixUpAxis);
		}
		return result;
	}

	/**
	 * This method returns the type of the ipo curve.
	 * 
	 * @param structure
	 *            the structure must contain the 'rna_path' field and
	 *            'array_index' field (the type is not important here)
	 * @param blenderContext
	 *            the blender context
	 * @return the type of the curve
	 */
	public int getCurveType(Structure structure, BlenderContext blenderContext) {
		// reading rna path first
		BlenderInputStream bis = blenderContext.getInputStream();
		int currentPosition = bis.getPosition();
		Pointer pRnaPath = (Pointer) structure.getFieldValue("rna_path");
		FileBlockHeader dataFileBlock = blenderContext.getFileBlock(pRnaPath.getOldMemoryAddress());
		bis.setPosition(dataFileBlock.getBlockPosition());
		String rnaPath = bis.readString();
		bis.setPosition(currentPosition);
		int arrayIndex = ((Number) structure.getFieldValue("array_index")).intValue();

		// determining the curve type
		if (rnaPath.endsWith("location")) {
			return Ipo.AC_LOC_X + arrayIndex;
		}
		if (rnaPath.endsWith("rotation_quaternion")) {
			return Ipo.AC_QUAT_W + arrayIndex;
		}
		if (rnaPath.endsWith("scale")) {
			return Ipo.AC_SIZE_X + arrayIndex;
		}
		if (rnaPath.endsWith("rotation")) {
			return Ipo.OB_ROT_X + arrayIndex;
		}
		throw new IllegalStateException("Unknown curve rna path: " + rnaPath);
	}

	/**
	 * This method creates an ipo with only a single value. No track type is
	 * specified so do not use it for calculating tracks.
	 * 
	 * @param constValue
	 *            the value of this ipo
	 * @return constant ipo
	 */
	public Ipo fromValue(float constValue) {
		return new ConstIpo(constValue);
	}

	@Override
	public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
		return true;
	}

	/**
	 * Ipo constant curve. This is a curve with only one value and no specified
	 * type. This type of ipo cannot be used to calculate tracks. It should only
	 * be used to calculate single value for a given frame.
	 * 
	 * @author Marcin Roguski
	 */
	private class ConstIpo extends Ipo {

		/** The constant value of this ipo. */
		private float	constValue;

		/**
		 * Constructor. Stores the constant value of this ipo.
		 * 
		 * @param constValue
		 *            the constant value of this ipo
		 */
		public ConstIpo(float constValue) {
			super(null, false);
			this.constValue = constValue;
		}

		@Override
		public float calculateValue(int frame) {
			return constValue;
		}

		@Override
		public float calculateValue(int frame, int curveIndex) {
			return constValue;
		}

		@Override
		public int getCurvesAmount() {
			return 0;
		}

		@Override
		public BoneTrack calculateTrack(int boneIndex, int startFrame, int stopFrame, int fps, boolean boneTrack) {
			throw new IllegalStateException("Constatnt ipo object cannot be used for calculating bone tracks!");
		}
	}
}

@@ -5187,24 +5187,62 @@
 (%22rotation%22)
+ %7C%7C rnaPath.endsWith(%22rotation_euler%22)
 ) %7B%0D%0A%09%09%09retu

Fix to loading object animation for Blender 2.62+ (found by 'reactlogic').