Home | History | Annotate | Download | only in animations
      1 package com.jme3.scene.plugins.blender.animations;
      2 
      3 import java.util.List;
      4 
      5 import com.jme3.animation.BoneTrack;
      6 import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
      7 import com.jme3.scene.plugins.blender.BlenderContext;
      8 import com.jme3.scene.plugins.blender.curves.BezierCurve;
      9 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
     10 import com.jme3.scene.plugins.blender.file.BlenderInputStream;
     11 import com.jme3.scene.plugins.blender.file.FileBlockHeader;
     12 import com.jme3.scene.plugins.blender.file.Pointer;
     13 import com.jme3.scene.plugins.blender.file.Structure;
     14 
     15 /**
     16  * This class helps to compute values from interpolation curves for features
     17  * like animation or constraint influence. The curves are 3rd degree bezier
     18  * curves.
     19  *
     20  * @author Marcin Roguski
     21  */
     22 public class IpoHelper extends AbstractBlenderHelper {
     23 
     24 	/**
     25 	 * This constructor parses the given blender version and stores the result.
     26 	 * Some functionalities may differ in different blender versions.
     27 	 *
     28 	 * @param blenderVersion
     29 	 *            the version read from the blend file
     30 	 * @param fixUpAxis
     31 	 *            a variable that indicates if the Y asxis is the UP axis or not
     32 	 */
     33 	public IpoHelper(String blenderVersion, boolean fixUpAxis) {
     34 		super(blenderVersion, fixUpAxis);
     35 	}
     36 
     37 	/**
     38 	 * This method creates an ipo object used for interpolation calculations.
     39 	 *
     40 	 * @param ipoStructure
     41 	 *            the structure with ipo definition
     42 	 * @param blenderContext
     43 	 *            the blender context
     44 	 * @return the ipo object
     45 	 * @throws BlenderFileException
     46 	 *             this exception is thrown when the blender file is somehow
     47 	 *             corrupted
     48 	 */
     49 	public Ipo fromIpoStructure(Structure ipoStructure, BlenderContext blenderContext) throws BlenderFileException {
     50 		Structure curvebase = (Structure) ipoStructure.getFieldValue("curve");
     51 
     52 		// preparing bezier curves
     53 		Ipo result = null;
     54 		List<Structure> curves = curvebase.evaluateListBase(blenderContext);// IpoCurve
     55 		if (curves.size() > 0) {
     56 			BezierCurve[] bezierCurves = new BezierCurve[curves.size()];
     57 			int frame = 0;
     58 			for (Structure curve : curves) {
     59 				Pointer pBezTriple = (Pointer) curve.getFieldValue("bezt");
     60 				List<Structure> bezTriples = pBezTriple.fetchData(blenderContext.getInputStream());
     61 				int type = ((Number) curve.getFieldValue("adrcode")).intValue();
     62 				bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2);
     63 			}
     64 			curves.clear();
     65 			result = new Ipo(bezierCurves, fixUpAxis);
     66 			blenderContext.addLoadedFeatures(ipoStructure.getOldMemoryAddress(), ipoStructure.getName(), ipoStructure, result);
     67 		}
     68 		return result;
     69 	}
     70 
     71 	/**
     72 	 * This method creates an ipo object used for interpolation calculations. It
     73 	 * should be called for blender version 2.50 and higher.
     74 	 *
     75 	 * @param actionStructure
     76 	 *            the structure with action definition
     77 	 * @param blenderContext
     78 	 *            the blender context
     79 	 * @return the ipo object
     80 	 * @throws BlenderFileException
     81 	 *             this exception is thrown when the blender file is somehow
     82 	 *             corrupted
     83 	 */
     84 	public Ipo fromAction(Structure actionStructure, BlenderContext blenderContext) throws BlenderFileException {
     85 		Ipo result = null;
     86 		List<Structure> curves = ((Structure) actionStructure.getFieldValue("curves")).evaluateListBase(blenderContext);// FCurve
     87 		if (curves.size() > 0) {
     88 			BezierCurve[] bezierCurves = new BezierCurve[curves.size()];
     89 			int frame = 0;
     90 			for (Structure curve : curves) {
     91 				Pointer pBezTriple = (Pointer) curve.getFieldValue("bezt");
     92 				List<Structure> bezTriples = pBezTriple.fetchData(blenderContext.getInputStream());
     93 				int type = this.getCurveType(curve, blenderContext);
     94 				bezierCurves[frame++] = new BezierCurve(type, bezTriples, 2);
     95 			}
     96 			curves.clear();
     97 			result = new Ipo(bezierCurves, fixUpAxis);
     98 		}
     99 		return result;
    100 	}
    101 
    102 	/**
    103 	 * This method returns the type of the ipo curve.
    104 	 *
    105 	 * @param structure
    106 	 *            the structure must contain the 'rna_path' field and
    107 	 *            'array_index' field (the type is not important here)
    108 	 * @param blenderContext
    109 	 *            the blender context
    110 	 * @return the type of the curve
    111 	 */
    112 	public int getCurveType(Structure structure, BlenderContext blenderContext) {
    113 		// reading rna path first
    114 		BlenderInputStream bis = blenderContext.getInputStream();
    115 		int currentPosition = bis.getPosition();
    116 		Pointer pRnaPath = (Pointer) structure.getFieldValue("rna_path");
    117 		FileBlockHeader dataFileBlock = blenderContext.getFileBlock(pRnaPath.getOldMemoryAddress());
    118 		bis.setPosition(dataFileBlock.getBlockPosition());
    119 		String rnaPath = bis.readString();
    120 		bis.setPosition(currentPosition);
    121 		int arrayIndex = ((Number) structure.getFieldValue("array_index")).intValue();
    122 
    123 		// determining the curve type
    124 		if (rnaPath.endsWith("location")) {
    125 			return Ipo.AC_LOC_X + arrayIndex;
    126 		}
    127 		if (rnaPath.endsWith("rotation_quaternion")) {
    128 			return Ipo.AC_QUAT_W + arrayIndex;
    129 		}
    130 		if (rnaPath.endsWith("scale")) {
    131 			return Ipo.AC_SIZE_X + arrayIndex;
    132 		}
    133 		if (rnaPath.endsWith("rotation")) {
    134 			return Ipo.OB_ROT_X + arrayIndex;
    135 		}
    136 		throw new IllegalStateException("Unknown curve rna path: " + rnaPath);
    137 	}
    138 
    139 	/**
    140 	 * This method creates an ipo with only a single value. No track type is
    141 	 * specified so do not use it for calculating tracks.
    142 	 *
    143 	 * @param constValue
    144 	 *            the value of this ipo
    145 	 * @return constant ipo
    146 	 */
    147 	public Ipo fromValue(float constValue) {
    148 		return new ConstIpo(constValue);
    149 	}
    150 
    151 	@Override
    152 	public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
    153 		return true;
    154 	}
    155 
    156 	/**
    157 	 * Ipo constant curve. This is a curve with only one value and no specified
    158 	 * type. This type of ipo cannot be used to calculate tracks. It should only
    159 	 * be used to calculate single value for a given frame.
    160 	 *
    161 	 * @author Marcin Roguski
    162 	 */
    163 	private class ConstIpo extends Ipo {
    164 
    165 		/** The constant value of this ipo. */
    166 		private float	constValue;
    167 
    168 		/**
    169 		 * Constructor. Stores the constant value of this ipo.
    170 		 *
    171 		 * @param constValue
    172 		 *            the constant value of this ipo
    173 		 */
    174 		public ConstIpo(float constValue) {
    175 			super(null, false);
    176 			this.constValue = constValue;
    177 		}
    178 
    179 		@Override
    180 		public float calculateValue(int frame) {
    181 			return constValue;
    182 		}
    183 
    184 		@Override
    185 		public float calculateValue(int frame, int curveIndex) {
    186 			return constValue;
    187 		}
    188 
    189 		@Override
    190 		public int getCurvesAmount() {
    191 			return 0;
    192 		}
    193 
    194 		@Override
    195 		public BoneTrack calculateTrack(int boneIndex, int startFrame, int stopFrame, int fps, boolean boneTrack) {
    196 			throw new IllegalStateException("Constatnt ipo object cannot be used for calculating bone tracks!");
    197 		}
    198 	}
    199 }
    200