aboutsummaryrefslogtreecommitdiff
path: root/engine/src/blender/com/jme3/scene/plugins/blender/constraints/ConstraintDistLimit.java
blob: ff3b99a5122028aedda8d52f4e25565102c2b740 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package com.jme3.scene.plugins.blender.constraints;

import com.jme3.animation.Animation;
import com.jme3.math.Matrix4f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Spatial;
import com.jme3.scene.plugins.blender.BlenderContext;
import com.jme3.scene.plugins.blender.animations.Ipo;
import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
import com.jme3.scene.plugins.blender.file.Structure;
import com.jme3.scene.plugins.ogre.AnimData;

/**
 * This class represents 'Dist limit' constraint type in blender.
 * @author Marcin Roguski (Kaelthas)
 */
/*package*/ class ConstraintDistLimit extends Constraint {
	private static final int LIMITDIST_INSIDE = 0;
	private static final int LIMITDIST_OUTSIDE = 1;
	private static final int LIMITDIST_ONSURFACE = 2;
    
	protected int mode;
	protected float dist;
	
	/**
	 * This constructor creates the constraint instance.
	 * 
	 * @param constraintStructure
	 *            the constraint's structure (bConstraint clss in blender 2.49).
	 * @param ownerOMA
	 *            the old memory address of the constraint owner
	 * @param influenceIpo
	 *            the ipo curve of the influence factor
	 * @param blenderContext
	 *            the blender context
	 * @throws BlenderFileException
	 *             this exception is thrown when the blender file is somehow
	 *             corrupted
	 */
	public ConstraintDistLimit(Structure constraintStructure, Long ownerOMA,
			Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
		
		mode = ((Number) data.getFieldValue("mode")).intValue();
		dist = ((Number) data.getFieldValue("dist")).floatValue();
	}

	@Override
	protected void bakeConstraint() {
		Object owner = this.owner.getObject();
		AnimData animData = blenderContext.getAnimData(this.owner.getOma());
		if(animData != null) {
			if(owner instanceof Spatial) {
				Vector3f targetLocation = ((Spatial) owner).getWorldTranslation();
				for(Animation animation : animData.anims) {
					BlenderTrack blenderTrack = this.getTrack(owner, animData.skeleton, animation);
					int maxFrames = blenderTrack.getTimes().length;
					Vector3f[] translations = blenderTrack.getTranslations();
					for (int frame = 0; frame < maxFrames; ++frame) {
						Vector3f v = translations[frame].subtract(targetLocation);
						this.distLimit(v, targetLocation, ipo.calculateValue(frame));
						translations[frame].addLocal(v);
					}
					blenderTrack.setKeyframes(blenderTrack.getTimes(), translations, blenderTrack.getRotations(), blenderTrack.getScales());
				}
			}
		}
		
		// apply static constraint only to spatials
		if(owner instanceof Spatial) {
			Matrix4f targetWorldMatrix = target.getWorldTransformMatrix();
			Vector3f targetLocation = targetWorldMatrix.toTranslationVector();
			Matrix4f m = this.owner.getParentWorldTransformMatrix();
			m.invertLocal();
			Matrix4f ownerWorldMatrix = this.owner.getWorldTransformMatrix();
			Vector3f ownerLocation = ownerWorldMatrix.toTranslationVector();
			this.distLimit(ownerLocation, targetLocation, ipo.calculateValue(0));
			((Spatial) owner).setLocalTranslation(m.mult(ownerLocation));
		}
	}
	
	/**
	 * 
	 * @param currentLocation
	 * @param targetLocation
	 * @param influence
	 */
	private void distLimit(Vector3f currentLocation, Vector3f targetLocation, float influence) {
		Vector3f v = currentLocation.subtract(targetLocation);
		float currentDistance = v.length();
		
		switch (mode) {
			case LIMITDIST_INSIDE:
				if (currentDistance >= dist) {
					v.normalizeLocal();
					v.multLocal(dist + (currentDistance - dist) * (1.0f - influence));
					currentLocation.set(v.addLocal(targetLocation));
				}
				break;
			case LIMITDIST_ONSURFACE:
				if (currentDistance > dist) {
					v.normalizeLocal();
					v.multLocal(dist + (currentDistance - dist) * (1.0f - influence));
					currentLocation.set(v.addLocal(targetLocation));
				} else if(currentDistance < dist) {
					v.normalizeLocal().multLocal(dist * influence);
					currentLocation.set(targetLocation.add(v));
				}
				break;
			case LIMITDIST_OUTSIDE:
				if (currentDistance <= dist) {
					v = targetLocation.subtract(currentLocation).normalizeLocal().multLocal(dist * influence);
					currentLocation.set(targetLocation.add(v));
				}
				break;
			default:
				throw new IllegalStateException("Unknown distance limit constraint mode: " + mode);
		}
	}
}