Home | History | Annotate | Download | only in constraints
      1 package com.jme3.scene.plugins.blender.constraints;
      2 
      3 import com.jme3.animation.Bone;
      4 import com.jme3.math.Matrix4f;
      5 import com.jme3.math.Quaternion;
      6 import com.jme3.math.Transform;
      7 import com.jme3.math.Vector3f;
      8 import com.jme3.scene.Spatial;
      9 import com.jme3.scene.plugins.blender.BlenderContext;
     10 import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
     11 import com.jme3.scene.plugins.blender.constraints.Constraint.Space;
     12 import com.jme3.scene.plugins.blender.file.DynamicArray;
     13 import com.jme3.scene.plugins.blender.file.Structure;
     14 
     15 /**
     16  * This class represents either owner or target of the constraint. It has the
     17  * common methods that take the evalueation space of the feature.
     18  *
     19  * @author Marcin Roguski (Kaelthas)
     20  */
     21 /* package */class Feature {
     22 	/** The evalueation space. */
     23 	protected Space				space;
     24 	/** Old memory address of the feature. */
     25 	protected Long				oma;
     26 	/** The spatial that is hold by the Feature. */
     27 	protected Spatial			spatial;
     28 	/** The bone that is hold by the Feature. */
     29 	protected Bone				bone;
     30 	/** The blender context. */
     31 	protected BlenderContext	blenderContext;
     32 
     33 	/**
     34 	 * Constructs the feature. This object should be loaded later
     35 	 * when it is read from the blender file.
     36 	 * The update method should be called before the feature is used.
     37 	 *
     38 	 * @param space
     39 	 *            the spatial's evaluation space
     40 	 * @param oma
     41 	 *            the spatial's old memory address
     42 	 * @param blenderContext
     43 	 *            the blender context
     44 	 */
     45 	public Feature(Space space, Long oma, BlenderContext blenderContext) {
     46 		this.space = space;
     47 		this.oma = oma;
     48 		this.blenderContext = blenderContext;
     49 	}
     50 
     51 	/**
     52 	 * Constructs the feature based on spatial.
     53 	 *
     54 	 * @param spatial
     55 	 *            the spatial
     56 	 * @param space
     57 	 *            the spatial's evaluation space
     58 	 * @param oma
     59 	 *            the spatial's old memory address
     60 	 * @param blenderContext
     61 	 *            the blender context
     62 	 */
     63 	public Feature(Spatial spatial, Space space, Long oma, BlenderContext blenderContext) {
     64 		this(space, oma, blenderContext);
     65 		this.blenderContext = blenderContext;
     66 	}
     67 
     68 	/**
     69 	 * Constructs the feature based on bone.
     70 	 *
     71 	 * @param bone
     72 	 *            the bone
     73 	 * @param space
     74 	 *            the bone evaluation space
     75 	 * @param oma
     76 	 *            the bone old memory address
     77 	 * @param blenderContext
     78 	 *            the blender context
     79 	 */
     80 	public Feature(Bone bone, Space space, Long oma, BlenderContext blenderContext) {
     81 		this(space, oma, blenderContext);
     82 		this.bone = bone;
     83 	}
     84 
     85 	/**
     86 	 * This method should be called before the feature is used.
     87 	 * It may happen that the object this feature refers to was not yet loaded from blend file
     88 	 * when the instance of this class was created.
     89 	 */
     90 	public void update() {
     91 		Object owner = blenderContext.getLoadedFeature(oma, LoadedFeatureDataType.LOADED_FEATURE);
     92 		if(owner instanceof Spatial) {
     93 			this.spatial = (Spatial) owner;
     94 		} else if(owner instanceof Bone) {
     95 			this.bone = (Bone) owner;
     96 		} else {
     97 			throw new IllegalStateException("Unknown type of owner: " + owner.getClass());
     98 		}
     99 	}
    100 
    101 	/**
    102 	 * @return the feature's old memory address
    103 	 */
    104 	public Long getOma() {
    105 		return oma;
    106 	}
    107 
    108 	/**
    109 	 * @return the object held by the feature (either bone or spatial)
    110 	 */
    111 	public Object getObject() {
    112 		if (spatial != null) {
    113 			return spatial;
    114 		}
    115 		return bone;
    116 	}
    117 
    118 	/**
    119 	 * @return the feature's transform depending on the evaluation space
    120 	 */
    121 	@SuppressWarnings("unchecked")
    122 	public Transform getTransform() {
    123 		if (spatial != null) {
    124 			switch (space) {
    125 				case CONSTRAINT_SPACE_LOCAL:
    126 					Structure targetStructure = (Structure) blenderContext.getLoadedFeature(oma, LoadedFeatureDataType.LOADED_STRUCTURE);
    127 
    128 					DynamicArray<Number> locArray = ((DynamicArray<Number>) targetStructure.getFieldValue("loc"));
    129 					Vector3f loc = new Vector3f(locArray.get(0).floatValue(), locArray.get(1).floatValue(), locArray.get(2).floatValue());
    130 					DynamicArray<Number> rotArray = ((DynamicArray<Number>) targetStructure.getFieldValue("rot"));
    131 					Quaternion rot = new Quaternion(new float[] { rotArray.get(0).floatValue(), rotArray.get(1).floatValue(), rotArray.get(2).floatValue() });
    132 					DynamicArray<Number> sizeArray = ((DynamicArray<Number>) targetStructure.getFieldValue("size"));
    133 					Vector3f size = new Vector3f(sizeArray.get(0).floatValue(), sizeArray.get(1).floatValue(), sizeArray.get(2).floatValue());
    134 
    135 					if (blenderContext.getBlenderKey().isFixUpAxis()) {
    136 						float y = loc.y;
    137 						loc.y = loc.z;
    138 						loc.z = -y;
    139 
    140 						y = rot.getY();
    141 						float z = rot.getZ();
    142 						rot.set(rot.getX(), z, -y, rot.getW());
    143 
    144 						y = size.y;
    145 						size.y = size.z;
    146 						size.z = y;
    147 					}
    148 
    149 					Transform result = new Transform(loc, rot);
    150 					result.setScale(size);
    151 					return result;
    152 				case CONSTRAINT_SPACE_WORLD:
    153 					return spatial.getWorldTransform();
    154 				default:
    155 					throw new IllegalStateException("Invalid space type for target object: " + space.toString());
    156 			}
    157 		}
    158 		// Bone
    159 		switch (space) {
    160 			case CONSTRAINT_SPACE_LOCAL:
    161 				Transform localTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
    162 				localTransform.setScale(bone.getLocalScale());
    163 				return localTransform;
    164 			case CONSTRAINT_SPACE_WORLD:
    165 				Transform worldTransform = new Transform(bone.getWorldBindPosition(), bone.getWorldBindRotation());
    166 				worldTransform.setScale(bone.getWorldBindScale());
    167 				return worldTransform;
    168 			case CONSTRAINT_SPACE_POSE:
    169 				Transform poseTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
    170 				poseTransform.setScale(bone.getLocalScale());
    171 				return poseTransform;
    172 			case CONSTRAINT_SPACE_PARLOCAL:
    173 				Transform parentLocalTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
    174 				parentLocalTransform.setScale(bone.getLocalScale());
    175 				return parentLocalTransform;
    176 			default:
    177 				throw new IllegalStateException("Invalid space type for target object: " + space.toString());
    178 		}
    179 	}
    180 
    181 	/**
    182 	 * This method applies the given transform to the feature in the proper
    183 	 * evaluation space.
    184 	 *
    185 	 * @param transform
    186 	 *            the transform to be applied
    187 	 */
    188 	public void applyTransform(Transform transform) {
    189 		if (spatial != null) {
    190 			switch (space) {
    191 				case CONSTRAINT_SPACE_LOCAL:
    192 					Transform ownerLocalTransform = spatial.getLocalTransform();
    193 					ownerLocalTransform.getTranslation().addLocal(transform.getTranslation());
    194 					ownerLocalTransform.getRotation().multLocal(transform.getRotation());
    195 					ownerLocalTransform.getScale().multLocal(transform.getScale());
    196 					break;
    197 				case CONSTRAINT_SPACE_WORLD:
    198 					Matrix4f m = this.getParentWorldTransformMatrix();
    199 					m.invertLocal();
    200 					Matrix4f matrix = this.toMatrix(transform);
    201 					m.multLocal(matrix);
    202 
    203 					float scaleX = (float) Math.sqrt(m.m00 * m.m00 + m.m10 * m.m10 + m.m20 * m.m20);
    204 					float scaleY = (float) Math.sqrt(m.m01 * m.m01 + m.m11 * m.m11 + m.m21 * m.m21);
    205 					float scaleZ = (float) Math.sqrt(m.m02 * m.m02 + m.m12 * m.m12 + m.m22 * m.m22);
    206 
    207 					transform.setTranslation(m.toTranslationVector());
    208 					transform.setRotation(m.toRotationQuat());
    209 					transform.setScale(scaleX, scaleY, scaleZ);
    210 					spatial.setLocalTransform(transform);
    211 					break;
    212 				case CONSTRAINT_SPACE_PARLOCAL:
    213 				case CONSTRAINT_SPACE_POSE:
    214 					throw new IllegalStateException("Invalid space type (" + space.toString() + ") for owner object.");
    215 				default:
    216 					throw new IllegalStateException("Invalid space type for target object: " + space.toString());
    217 			}
    218 		} else {// Bone
    219 			switch (space) {
    220 				case CONSTRAINT_SPACE_LOCAL:
    221 					bone.setBindTransforms(transform.getTranslation(), transform.getRotation(), transform.getScale());
    222 					break;
    223 				case CONSTRAINT_SPACE_WORLD:
    224 					Matrix4f m = this.getParentWorldTransformMatrix();
    225 //					m.invertLocal();
    226 					transform.setTranslation(m.mult(transform.getTranslation()));
    227 					transform.setRotation(m.mult(transform.getRotation(), null));
    228 					transform.setScale(transform.getScale());
    229 					bone.setBindTransforms(transform.getTranslation(), transform.getRotation(), transform.getScale());
    230 //					float x = FastMath.HALF_PI/2;
    231 //					float y = -FastMath.HALF_PI;
    232 //					float z = -FastMath.HALF_PI/2;
    233 //					bone.setBindTransforms(new Vector3f(0,0,0), new Quaternion().fromAngles(x, y, z), new Vector3f(1,1,1));
    234 					break;
    235 				case CONSTRAINT_SPACE_PARLOCAL:
    236 					Vector3f parentLocalTranslation = bone.getLocalPosition().add(transform.getTranslation());
    237 					Quaternion parentLocalRotation = bone.getLocalRotation().mult(transform.getRotation());
    238 					bone.setBindTransforms(parentLocalTranslation, parentLocalRotation, transform.getScale());
    239 					break;
    240 				case CONSTRAINT_SPACE_POSE:
    241 					bone.setBindTransforms(transform.getTranslation(), transform.getRotation(), transform.getScale());
    242 					break;
    243 				default:
    244 					throw new IllegalStateException("Invalid space type for target object: " + space.toString());
    245 			}
    246 		}
    247 	}
    248 
    249 	/**
    250 	 * @return world transform matrix of the feature
    251 	 */
    252 	public Matrix4f getWorldTransformMatrix() {
    253 		if (spatial != null) {
    254 			Matrix4f result = new Matrix4f();
    255 			Transform t = spatial.getWorldTransform();
    256 			result.setTransform(t.getTranslation(), t.getScale(), t.getRotation().toRotationMatrix());
    257 			return result;
    258 		}
    259 		// Bone
    260 		Matrix4f result = new Matrix4f();
    261 		result.setTransform(bone.getWorldBindPosition(), bone.getWorldBindScale(), bone.getWorldBindRotation().toRotationMatrix());
    262 		return result;
    263 	}
    264 
    265 	/**
    266 	 * @return world transform matrix of the feature's parent or identity matrix
    267 	 *         if the feature has no parent
    268 	 */
    269 	public Matrix4f getParentWorldTransformMatrix() {
    270 		Matrix4f result = new Matrix4f();
    271 		if (spatial != null) {
    272 			if (spatial.getParent() != null) {
    273 				Transform t = spatial.getParent().getWorldTransform();
    274 				result.setTransform(t.getTranslation(), t.getScale(), t.getRotation().toRotationMatrix());
    275 			}
    276 		} else {// Bone
    277 			Bone parent = bone.getParent();
    278 			if (parent != null) {
    279 				result.setTransform(parent.getWorldBindPosition(), parent.getWorldBindScale(), parent.getWorldBindRotation().toRotationMatrix());
    280 			}
    281 		}
    282 		return result;
    283 	}
    284 
    285 	/**
    286 	 * Converts given transform to the matrix.
    287 	 *
    288 	 * @param transform
    289 	 *            the transform to be converted
    290 	 * @return 4x4 matri that represents the given transform
    291 	 */
    292 	protected Matrix4f toMatrix(Transform transform) {
    293 		Matrix4f result = Matrix4f.IDENTITY;
    294 		if (transform != null) {
    295 			result = new Matrix4f();
    296 			result.setTranslation(transform.getTranslation());
    297 			result.setRotationQuaternion(transform.getRotation());
    298 			result.setScale(transform.getScale());
    299 		}
    300 		return result;
    301 	}
    302 }
    303