• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 	 */
Feature(Space space, Long oma, BlenderContext blenderContext)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 	 */
Feature(Spatial spatial, Space space, Long oma, BlenderContext blenderContext)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 	 */
Feature(Bone bone, Space space, Long oma, BlenderContext blenderContext)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 	 */
update()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 	 */
getOma()104 	public Long getOma() {
105 		return oma;
106 	}
107 
108 	/**
109 	 * @return the object held by the feature (either bone or spatial)
110 	 */
getObject()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")
getTransform()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 	 */
applyTransform(Transform transform)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 	 */
getWorldTransformMatrix()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 	 */
getParentWorldTransformMatrix()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 	 */
toMatrix(Transform transform)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