1 package com.jme3.scene.plugins.blender.constraints; 2 3 import com.jme3.animation.Animation; 4 import com.jme3.animation.Bone; 5 import com.jme3.math.FastMath; 6 import com.jme3.math.Quaternion; 7 import com.jme3.math.Transform; 8 import com.jme3.scene.Spatial; 9 import com.jme3.scene.plugins.blender.BlenderContext; 10 import com.jme3.scene.plugins.blender.animations.Ipo; 11 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; 12 import com.jme3.scene.plugins.blender.file.Structure; 13 import com.jme3.scene.plugins.ogre.AnimData; 14 15 /** 16 * This class represents 'Rot limit' constraint type in blender. 17 * 18 * @author Marcin Roguski (Kaelthas) 19 */ 20 /* package */class ConstraintRotLimit extends Constraint { 21 private static final int LIMIT_XROT = 0x01; 22 private static final int LIMIT_YROT = 0x02; 23 private static final int LIMIT_ZROT = 0x04; 24 25 protected float[][] limits = new float[3][2]; 26 protected int flag; 27 protected boolean updated; 28 29 /** 30 * This constructor creates the constraint instance. 31 * 32 * @param constraintStructure 33 * the constraint's structure (bConstraint clss in blender 2.49). 34 * @param ownerOMA 35 * the old memory address of the constraint owner 36 * @param influenceIpo 37 * the ipo curve of the influence factor 38 * @param blenderContext 39 * the blender context 40 * @throws BlenderFileException 41 * this exception is thrown when the blender file is somehow 42 * corrupted 43 */ 44 public ConstraintRotLimit(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException { 45 super(constraintStructure, ownerOMA, influenceIpo, blenderContext); 46 47 flag = ((Number) data.getFieldValue("flag")).intValue(); 48 if (blenderContext.getBlenderKey().isFixUpAxis() && owner.spatial != null) { 49 limits[0][0] = ((Number) data.getFieldValue("xmin")).floatValue(); 50 limits[0][1] = ((Number) data.getFieldValue("xmax")).floatValue(); 51 limits[2][0] = -((Number) data.getFieldValue("ymin")).floatValue(); 52 limits[2][1] = -((Number) data.getFieldValue("ymax")).floatValue(); 53 limits[1][0] = ((Number) data.getFieldValue("zmin")).floatValue(); 54 limits[1][1] = ((Number) data.getFieldValue("zmax")).floatValue(); 55 56 // swapping Y and X limits flag in the bitwise flag 57 int limitY = flag & LIMIT_YROT; 58 int limitZ = flag & LIMIT_ZROT; 59 flag &= LIMIT_XROT;// clear the other flags to swap them 60 flag |= limitY << 1; 61 flag |= limitZ >> 1; 62 } else { 63 limits[0][0] = ((Number) data.getFieldValue("xmin")).floatValue(); 64 limits[0][1] = ((Number) data.getFieldValue("xmax")).floatValue(); 65 limits[1][0] = ((Number) data.getFieldValue("ymin")).floatValue(); 66 limits[1][1] = ((Number) data.getFieldValue("ymax")).floatValue(); 67 limits[2][0] = ((Number) data.getFieldValue("zmin")).floatValue(); 68 limits[2][1] = ((Number) data.getFieldValue("zmax")).floatValue(); 69 } 70 71 // until blender 2.49 the rotations values were stored in degrees 72 if (blenderContext.getBlenderVersion() <= 249) { 73 for (int i = 0; i < limits.length; ++i) { 74 limits[i][0] *= FastMath.DEG_TO_RAD; 75 limits[i][1] *= FastMath.DEG_TO_RAD; 76 } 77 } 78 } 79 80 @Override 81 protected void bakeConstraint() { 82 this.update(); 83 Object owner = this.owner.getObject(); 84 AnimData animData = blenderContext.getAnimData(this.owner.getOma()); 85 if (animData != null) { 86 for (Animation animation : animData.anims) { 87 BlenderTrack track = this.getTrack(owner, animData.skeleton, animation); 88 Quaternion[] rotations = track.getRotations(); 89 float[] angles = new float[3]; 90 int maxFrames = rotations.length; 91 for (int frame = 0; frame < maxFrames; ++frame) { 92 rotations[frame].toAngles(angles); 93 this.rotLimit(angles, ipo.calculateValue(frame)); 94 rotations[frame].fromAngles(angles); 95 } 96 track.setKeyframes(track.getTimes(), track.getTranslations(), rotations, track.getScales()); 97 } 98 } 99 100 if (owner instanceof Spatial) { 101 Transform ownerTransform = this.owner.getTransform(); 102 float[] angles = ownerTransform.getRotation().toAngles(null); 103 this.rotLimit(angles, ipo.calculateValue(0)); 104 ownerTransform.getRotation().fromAngles(angles); 105 this.owner.applyTransform(ownerTransform); 106 } 107 } 108 109 /** 110 * This method computes new constrained angles. 111 * 112 * @param angles 113 * angles to be altered 114 * @param influence 115 * the alteration influence 116 */ 117 private void rotLimit(float[] angles, float influence) { 118 if ((flag & LIMIT_XROT) != 0) { 119 float difference = 0.0f; 120 if (angles[0] < limits[0][0]) { 121 difference = (angles[0] - limits[0][0]) * influence; 122 } else if (angles[0] > limits[0][1]) { 123 difference = (angles[0] - limits[0][1]) * influence; 124 } 125 angles[0] -= difference; 126 } 127 if ((flag & LIMIT_YROT) != 0) { 128 float difference = 0.0f; 129 if (angles[1] < limits[1][0]) { 130 difference = (angles[1] - limits[1][0]) * influence; 131 } else if (angles[1] > limits[1][1]) { 132 difference = (angles[1] - limits[1][1]) * influence; 133 } 134 angles[1] -= difference; 135 } 136 if ((flag & LIMIT_ZROT) != 0) { 137 float difference = 0.0f; 138 if (angles[2] < limits[2][0]) { 139 difference = (angles[2] - limits[2][0]) * influence; 140 } else if (angles[2] > limits[2][1]) { 141 difference = (angles[2] - limits[2][1]) * influence; 142 } 143 angles[2] -= difference; 144 } 145 } 146 147 /** 148 * This method is called before baking (performes its operations only once). 149 * It is important to update the state of the limits and owner/target before 150 * baking the constraint. 151 */ 152 private void update() { 153 if (!updated) { 154 updated = true; 155 if (owner != null) { 156 owner.update(); 157 } 158 if (target != null) { 159 target.update(); 160 } 161 if (this.owner.getObject() instanceof Bone) {// for bones we need to 162 // change the sign 163 // of the limits 164 for (int i = 0; i < limits.length; ++i) { 165 limits[i][0] *= -1; 166 limits[i][1] *= -1; 167 } 168 } 169 170 // sorting the limits (lower is always first) 171 for (int i = 0; i < limits.length; ++i) { 172 if (limits[i][0] > limits[i][1]) { 173 float temp = limits[i][0]; 174 limits[i][0] = limits[i][1]; 175 limits[i][1] = temp; 176 } 177 } 178 } 179 } 180 } 181