159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage com.jme3.scene.plugins.blender.constraints;
259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.animation.Animation;
459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Matrix4f;
559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Vector3f;
659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.Spatial;
759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.BlenderContext;
859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.animations.Ipo;
959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.file.Structure;
1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.ogre.AnimData;
1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/**
1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This class represents 'Dist limit' constraint type in blender.
1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Marcin Roguski (Kaelthas)
1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */
1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/*package*/ class ConstraintDistLimit extends Constraint {
1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private static final int LIMITDIST_INSIDE = 0;
1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private static final int LIMITDIST_OUTSIDE = 1;
2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private static final int LIMITDIST_ONSURFACE = 2;
2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	protected int mode;
2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	protected float dist;
2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This constructor creates the constraint instance.
2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *
2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param constraintStructure
2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the constraint's structure (bConstraint clss in blender 2.49).
3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param ownerOMA
3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the old memory address of the constraint owner
3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param influenceIpo
3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the ipo curve of the influence factor
3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param blenderContext
3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *            the blender context
3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @throws BlenderFileException
3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *             this exception is thrown when the blender file is somehow
3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *             corrupted
3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public ConstraintDistLimit(Structure constraintStructure, Long ownerOMA,
4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		mode = ((Number) data.getFieldValue("mode")).intValue();
4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		dist = ((Number) data.getFieldValue("dist")).floatValue();
4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	@Override
4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	protected void bakeConstraint() {
5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		Object owner = this.owner.getObject();
5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		AnimData animData = blenderContext.getAnimData(this.owner.getOma());
5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		if(animData != null) {
5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			if(owner instanceof Spatial) {
5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				Vector3f targetLocation = ((Spatial) owner).getWorldTranslation();
5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				for(Animation animation : animData.anims) {
5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					BlenderTrack blenderTrack = this.getTrack(owner, animData.skeleton, animation);
5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					int maxFrames = blenderTrack.getTimes().length;
5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					Vector3f[] translations = blenderTrack.getTranslations();
5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					for (int frame = 0; frame < maxFrames; ++frame) {
6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta						Vector3f v = translations[frame].subtract(targetLocation);
6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta						this.distLimit(v, targetLocation, ipo.calculateValue(frame));
6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta						translations[frame].addLocal(v);
6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					}
6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					blenderTrack.setKeyframes(blenderTrack.getTimes(), translations, blenderTrack.getRotations(), blenderTrack.getScales());
6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				}
6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			}
6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		// apply static constraint only to spatials
7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		if(owner instanceof Spatial) {
7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			Matrix4f targetWorldMatrix = target.getWorldTransformMatrix();
7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			Vector3f targetLocation = targetWorldMatrix.toTranslationVector();
7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			Matrix4f m = this.owner.getParentWorldTransformMatrix();
7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			m.invertLocal();
7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			Matrix4f ownerWorldMatrix = this.owner.getWorldTransformMatrix();
7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			Vector3f ownerLocation = ownerWorldMatrix.toTranslationVector();
7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			this.distLimit(ownerLocation, targetLocation, ipo.calculateValue(0));
7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			((Spatial) owner).setLocalTranslation(m.mult(ownerLocation));
7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *
8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param currentLocation
8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param targetLocation
8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param influence
8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private void distLimit(Vector3f currentLocation, Vector3f targetLocation, float influence) {
8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		Vector3f v = currentLocation.subtract(targetLocation);
9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		float currentDistance = v.length();
9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		switch (mode) {
9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case LIMITDIST_INSIDE:
9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				if (currentDistance >= dist) {
9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					v.normalizeLocal();
9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					v.multLocal(dist + (currentDistance - dist) * (1.0f - influence));
9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					currentLocation.set(v.addLocal(targetLocation));
9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				}
9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				break;
10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case LIMITDIST_ONSURFACE:
10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				if (currentDistance > dist) {
10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					v.normalizeLocal();
10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					v.multLocal(dist + (currentDistance - dist) * (1.0f - influence));
10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					currentLocation.set(v.addLocal(targetLocation));
10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				} else if(currentDistance < dist) {
10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					v.normalizeLocal().multLocal(dist * influence);
10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					currentLocation.set(targetLocation.add(v));
10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				}
10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				break;
11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			case LIMITDIST_OUTSIDE:
11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				if (currentDistance <= dist) {
11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					v = targetLocation.subtract(currentLocation).normalizeLocal().multLocal(dist * influence);
11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					currentLocation.set(targetLocation.add(v));
11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				}
11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				break;
11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			default:
11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				throw new IllegalStateException("Unknown distance limit constraint mode: " + mode);
11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta}
121