159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage com.jme3.scene.plugins.blender.animations;
259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.ArrayList;
459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.List;
559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.Map;
659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.animation.Bone;
859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Matrix4f;
959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Quaternion;
1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Transform;
1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Vector3f;
1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.BlenderContext;
1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.file.DynamicArray;
1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.file.Structure;
1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.objects.ObjectHelper;
1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/**
1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This class holds the basic data that describes a bone.
2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Marcin Roguski (Kaelthas)
2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */
2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic class BoneContext {
2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/** The structure of the bone. */
2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private Structure			boneStructure;
2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/** Bone's pose channel structure. */
2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private Structure			poseChannel;
2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/** Bone's name. */
2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private String				boneName;
3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/** This variable indicates if the Y axis should be the UP axis. */
3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private boolean				fixUpAxis;
3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/** The bone's armature matrix. */
3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private Matrix4f			armatureMatrix;
3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/** The parent context. */
3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private BoneContext			parent;
3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/** The children of this context. */
3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private List<BoneContext>	children		= new ArrayList<BoneContext>();
3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/** Created bone (available after calling 'buildBone' method). */
3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private Bone				bone;
4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/** Bone's pose transform (available after calling 'buildBone' method). */
4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private Transform			poseTransform	= new Transform();
4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/** The bone's rest matrix. */
4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private Matrix4f			restMatrix;
4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/** Bone's total inverse transformation. */
4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private Matrix4f			inverseTotalTransformation;
4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/** Bone's parent inverse matrix. */
4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private Matrix4f			inverseParentMatrix;
4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * Constructor. Creates the basic set of bone's data.
5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *
5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param boneStructure
5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the bone's structure
5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param objectToArmatureMatrix
5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            object-to-armature transformation matrix
5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param bonesPoseChannels
5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            a map of pose channels for each bone OMA
5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param blenderContext
5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the blender context
6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @throws BlenderFileException
6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *             an exception is thrown when problem with blender data reading
6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *             occurs
6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public BoneContext(Structure boneStructure, Matrix4f objectToArmatureMatrix, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException {
6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		this(boneStructure, null, objectToArmatureMatrix, bonesPoseChannels, blenderContext);
6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * Constructor. Creates the basic set of bone's data.
7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *
7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param boneStructure
7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the bone's structure
7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param parent
7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            bone's parent (null if the bone is the root bone)
7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param objectToArmatureMatrix
7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            object-to-armature transformation matrix
7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param bonesPoseChannels
7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            a map of pose channels for each bone OMA
7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param blenderContext
8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the blender context
8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @throws BlenderFileException
8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *             an exception is thrown when problem with blender data reading
8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *             occurs
8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private BoneContext(Structure boneStructure, BoneContext parent, Matrix4f objectToArmatureMatrix, final Map<Long, Structure> bonesPoseChannels, BlenderContext blenderContext) throws BlenderFileException {
8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		this.parent = parent;
8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		this.boneStructure = boneStructure;
8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		boneName = boneStructure.getFieldValue("name").toString();
8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		armatureMatrix = objectHelper.getMatrix(boneStructure, "arm_mat", true);
9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		fixUpAxis = blenderContext.getBlenderKey().isFixUpAxis();
9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		this.computeRestMatrix(objectToArmatureMatrix);
9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		List<Structure> childbase = ((Structure) boneStructure.getFieldValue("childbase")).evaluateListBase(blenderContext);
9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		for (Structure child : childbase) {
9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			this.children.add(new BoneContext(child, this, objectToArmatureMatrix, bonesPoseChannels, blenderContext));
9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		poseChannel = bonesPoseChannels.get(boneStructure.getOldMemoryAddress());
10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		blenderContext.setBoneContext(boneStructure.getOldMemoryAddress(), this);
10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This method computes the rest matrix for the bone.
10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *
10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param objectToArmatureMatrix
10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            object-to-armature transformation matrix
10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private void computeRestMatrix(Matrix4f objectToArmatureMatrix) {
11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		if (parent != null) {
11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			inverseParentMatrix = parent.inverseTotalTransformation.clone();
11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		} else if (fixUpAxis) {
11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			inverseParentMatrix = objectToArmatureMatrix.clone();
11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		} else {
11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			inverseParentMatrix = Matrix4f.IDENTITY.clone();
11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		restMatrix = armatureMatrix.clone();
12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		inverseTotalTransformation = restMatrix.invert();
12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		restMatrix = inverseParentMatrix.mult(restMatrix);
12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		for (BoneContext child : this.children) {
12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			child.computeRestMatrix(objectToArmatureMatrix);
12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This method computes the pose transform for the bone.
13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	@SuppressWarnings("unchecked")
13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private void computePoseTransform() {
13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		DynamicArray<Number> loc = (DynamicArray<Number>) poseChannel.getFieldValue("loc");
13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		DynamicArray<Number> size = (DynamicArray<Number>) poseChannel.getFieldValue("size");
13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		DynamicArray<Number> quat = (DynamicArray<Number>) poseChannel.getFieldValue("quat");
13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		if (fixUpAxis) {
13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			poseTransform.setTranslation(loc.get(0).floatValue(), -loc.get(2).floatValue(), loc.get(1).floatValue());
13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			poseTransform.setRotation(new Quaternion(quat.get(1).floatValue(), quat.get(3).floatValue(), -quat.get(2).floatValue(), quat.get(0).floatValue()));
14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			poseTransform.setScale(size.get(0).floatValue(), size.get(2).floatValue(), size.get(1).floatValue());
14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		} else {
14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			poseTransform.setTranslation(loc.get(0).floatValue(), loc.get(1).floatValue(), loc.get(2).floatValue());
14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			poseTransform.setRotation(new Quaternion(quat.get(0).floatValue(), quat.get(1).floatValue(), quat.get(2).floatValue(), quat.get(3).floatValue()));
14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			poseTransform.setScale(size.get(0).floatValue(), size.get(1).floatValue(), size.get(2).floatValue());
14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		Transform localTransform = new Transform(bone.getLocalPosition(), bone.getLocalRotation());
14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		localTransform.setScale(bone.getLocalScale());
14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		localTransform.getTranslation().addLocal(poseTransform.getTranslation());
15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		localTransform.getRotation().multLocal(poseTransform.getRotation());
15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		localTransform.getScale().multLocal(poseTransform.getScale());
15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		poseTransform.set(localTransform);
15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This method builds the bone. It recursively builds the bone's children.
15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *
15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param bones
16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            a list of bones where the newly created bone will be added
16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param boneOMAs
16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the map between bone and its old memory address
16359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param blenderContext
16459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the blender context
16559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @return newly created bone
16659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
16759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public Bone buildBone(List<Bone> bones, Map<Bone, Long> boneOMAs, BlenderContext blenderContext) {
16859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		Long boneOMA = boneStructure.getOldMemoryAddress();
16959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		bone = new Bone(boneName);
17059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		bones.add(bone);
17159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		boneOMAs.put(bone, boneOMA);
17259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		blenderContext.addLoadedFeatures(boneOMA, boneName, boneStructure, bone);
17359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
17459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		Matrix4f pose = this.restMatrix.clone();
17559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
17659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
17759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		Vector3f poseLocation = pose.toTranslationVector();
17859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		Quaternion rotation = pose.toRotationQuat();
17959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		Vector3f scale = objectHelper.getScale(pose);
18059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
18159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		bone.setBindTransforms(poseLocation, rotation, scale);
18259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		for (BoneContext child : children) {
18359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			bone.addChild(child.buildBone(bones, boneOMAs, blenderContext));
18459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
18559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
18659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		this.computePoseTransform();
18759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
18859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		return bone;
18959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
19059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
19159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
19259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @return bone's pose transformation
19359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
19459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public Transform getPoseTransform() {
19559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		return poseTransform;
19659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
19759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
19859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
19959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @return built bone (available after calling 'buildBone' method)
20059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
20159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public Bone getBone() {
20259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		return bone;
20359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
20459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta}
205