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