1package com.jme3.scene.plugins.blender.constraints;
2
3import com.jme3.animation.Animation;
4import com.jme3.animation.Skeleton;
5import com.jme3.scene.plugins.blender.BlenderContext;
6import com.jme3.scene.plugins.blender.animations.CalculationBone;
7import com.jme3.scene.plugins.blender.animations.Ipo;
8import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
9import com.jme3.scene.plugins.blender.file.Structure;
10import java.util.logging.Logger;
11
12/**
13 * This class represents 'Inverse kinematics' constraint type in blender.
14 * @author Marcin Roguski (Kaelthas)
15 */
16/*package*/ class ConstraintInverseKinematics extends Constraint {
17	private static final Logger LOGGER = Logger.getLogger(ConstraintInverseKinematics.class.getName());
18	private static final float IK_SOLVER_ERROR = 0.5f;
19
20	/**
21	 * This constructor creates the constraint instance.
22	 *
23	 * @param constraintStructure
24	 *            the constraint's structure (bConstraint clss in blender 2.49).
25	 * @param ownerOMA
26	 *            the old memory address of the constraint owner
27	 * @param influenceIpo
28	 *            the ipo curve of the influence factor
29	 * @param blenderContext
30	 *            the blender context
31	 * @throws BlenderFileException
32	 *             this exception is thrown when the blender file is somehow
33	 *             corrupted
34	 */
35	public ConstraintInverseKinematics(Structure constraintStructure,
36			Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
37		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
38	}
39
40	@Override
41	protected void bakeConstraint() {
42//		try {
43			// IK solver is only attached to bones
44//			Bone ownerBone = (Bone) blenderContext.getLoadedFeature(ownerOMA, LoadedFeatureDataType.LOADED_FEATURE);
45//			AnimData animData = blenderContext.getAnimData(ownerOMA);
46//			if(animData == null) {
47				//TODO: to nie moxe byx null, utworzyx dane bez ruchu, w zalexnoxci czy target six rusza
48//			}
49
50			//prepare a list of all parents of this bone
51//			CalculationBone[] bones = this.getBonesToCalculate(skeleton, boneAnimation);
52
53			// get the target point
54//			Object targetObject = this.getTarget(LoadedFeatureDataType.LOADED_FEATURE);
55//			Vector3f pt = null;// Point Target
56//			if (targetObject instanceof Bone) {
57//				pt = ((Bone) targetObject).getModelSpacePosition();
58//			} else if (targetObject instanceof Spatial) {
59//				pt = ((Spatial) targetObject).getWorldTranslation();
60//			} else if (targetObject instanceof Skeleton) {
61//				Structure armatureNodeStructure = (Structure) this.getTarget(LoadedFeatureDataType.LOADED_STRUCTURE);
62//				ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
63//				Transform transform = objectHelper.getTransformation(armatureNodeStructure, blenderContext);
64//				pt = transform.getTranslation();
65//			} else {
66//				throw new IllegalStateException(
67//						"Unknown target object type! Should be Node, Bone or Skeleton and there is: "
68//						+ targetObject.getClass().getName());
69//			}
70
71			//fetching the owner's bone track
72//			BoneTrack ownerBoneTrack = null;
73//			int boneIndex = skeleton.getBoneIndex(ownerBone);
74//			for (int i = 0; i < boneAnimation.getTracks().length; ++i) {
75//				if (boneAnimation.getTracks()[i].getTargetBoneIndex() == boneIndex) {
76//					ownerBoneTrack = boneAnimation.getTracks()[i];
77//					break;
78//				}
79//			}
80//			int ownerBoneFramesCount = ownerBoneTrack==null ? 0 : ownerBoneTrack.getTimes().length;
81//
82//			// preparing data
83//			int maxIterations = ((Number) data.getFieldValue("iterations")).intValue();
84//			CalculationBone[] bones = this.getBonesToCalculate(ownerBone, skeleton, boneAnimation);
85//			for (int i = 0; i < bones.length; ++i) {
86//				System.out.println(Arrays.toString(bones[i].track.getTranslations()));
87//				System.out.println(Arrays.toString(bones[i].track.getRotations()));
88//				System.out.println("===============================");
89//			}
90//			Quaternion rotation = new Quaternion();
91//			//all tracks should have the same amount of frames
92//			int framesCount = bones[0].getBoneFramesCount();
93//			assert framesCount >=1;
94//			for (int frame = 0; frame < framesCount; ++frame) {
95//				float error = IK_SOLVER_ERROR;
96//				int iteration = 0;
97//				while (error >= IK_SOLVER_ERROR && iteration <= maxIterations) {
98//					// rotating the bones
99//					for (int i = 0; i < bones.length - 1; ++i) {
100//						Vector3f pe = bones[i].getEndPoint();
101//						Vector3f pc = bones[i + 1].getWorldTranslation().clone();
102//
103//						Vector3f peSUBpc = pe.subtract(pc).normalizeLocal();
104//						Vector3f ptSUBpc = pt.subtract(pc).normalizeLocal();
105//
106//						float theta = FastMath.acos(peSUBpc.dot(ptSUBpc));
107//						Vector3f direction = peSUBpc.cross(ptSUBpc).normalizeLocal();
108//						bones[i].rotate(rotation.fromAngleAxis(theta, direction), frame);
109//					}
110//					error = pt.subtract(bones[0].getEndPoint()).length();
111//					++iteration;
112//				}
113//			}
114//
115//			for (CalculationBone bone : bones) {
116//				bone.applyCalculatedTracks();
117//			}
118//
119//			System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
120//			for (int i = 0; i < bones.length; ++i) {
121//				System.out.println(Arrays.toString(bones[i].track.getTranslations()));
122//				System.out.println(Arrays.toString(bones[i].track.getRotations()));
123//				System.out.println("===============================");
124//			}
125//		} catch(BlenderFileException e) {
126//			LOGGER.severe(e.getLocalizedMessage());
127//		}
128	}
129
130	/**
131	 * This method returns bones used for rotation calculations.
132	 * @param bone
133	 *        the bone to which the constraint is applied
134	 * @param skeleton
135	 *        the skeleton owning the bone and its ancestors
136	 * @param boneAnimation
137	 *        the bone animation data that stores the traces for the skeleton's bones
138	 * @return a list of bones to imitate the bone's movement during IK solving
139	 */
140	private CalculationBone[] getBonesToCalculate(Skeleton skeleton, Animation boneAnimation) {
141//		Bone ownerBone = (Bone) blenderContext.getLoadedFeature(ownerOMA, LoadedFeatureDataType.LOADED_FEATURE);
142//		List<CalculationBone> bonesList = new ArrayList<CalculationBone>();
143//		do {
144//			bonesList.add(new CalculationBone(ownerBone, 1));
145//			int boneIndex = skeleton.getBoneIndex(ownerBone);
146//			for (int i = 0; i < boneAnimation.getTracks().length; ++i) {
147//				if (((BoneTrack[])boneAnimation.getTracks())[i].getTargetBoneIndex() == boneIndex) {
148//					bonesList.add(new CalculationBone(ownerBone, (BoneTrack)boneAnimation.getTracks()[i]));
149//					break;
150//				}
151//			}
152//			ownerBone = ownerBone.getParent();
153//		} while (ownerBone != null);
154//		//attaching children
155//		CalculationBone[] result = bonesList.toArray(new CalculationBone[bonesList.size()]);
156//		for (int i = result.length - 1; i > 0; --i) {
157//			result[i].attachChild(result[i - 1]);
158//		}
159//		return result;
160		return null;
161	}
162}
163