• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.jme3.scene.plugins.blender.constraints;
2 
3 import com.jme3.animation.Animation;
4 import com.jme3.animation.Bone;
5 import com.jme3.math.FastMath;
6 import com.jme3.math.Quaternion;
7 import com.jme3.math.Transform;
8 import com.jme3.scene.Spatial;
9 import com.jme3.scene.plugins.blender.BlenderContext;
10 import com.jme3.scene.plugins.blender.animations.Ipo;
11 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
12 import com.jme3.scene.plugins.blender.file.Structure;
13 import com.jme3.scene.plugins.ogre.AnimData;
14 
15 /**
16  * This class represents 'Rot limit' constraint type in blender.
17  *
18  * @author Marcin Roguski (Kaelthas)
19  */
20 /* package */class ConstraintRotLimit extends Constraint {
21 	private static final int	LIMIT_XROT	= 0x01;
22 	private static final int	LIMIT_YROT	= 0x02;
23 	private static final int	LIMIT_ZROT	= 0x04;
24 
25 	protected float[][]			limits		= new float[3][2];
26 	protected int				flag;
27 	protected boolean			updated;
28 
29 	/**
30 	 * This constructor creates the constraint instance.
31 	 *
32 	 * @param constraintStructure
33 	 *            the constraint's structure (bConstraint clss in blender 2.49).
34 	 * @param ownerOMA
35 	 *            the old memory address of the constraint owner
36 	 * @param influenceIpo
37 	 *            the ipo curve of the influence factor
38 	 * @param blenderContext
39 	 *            the blender context
40 	 * @throws BlenderFileException
41 	 *             this exception is thrown when the blender file is somehow
42 	 *             corrupted
43 	 */
ConstraintRotLimit(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext)44 	public ConstraintRotLimit(Structure constraintStructure, Long ownerOMA, Ipo influenceIpo, BlenderContext blenderContext) throws BlenderFileException {
45 		super(constraintStructure, ownerOMA, influenceIpo, blenderContext);
46 
47 		flag = ((Number) data.getFieldValue("flag")).intValue();
48 		if (blenderContext.getBlenderKey().isFixUpAxis() && owner.spatial != null) {
49 			limits[0][0] = ((Number) data.getFieldValue("xmin")).floatValue();
50 			limits[0][1] = ((Number) data.getFieldValue("xmax")).floatValue();
51 			limits[2][0] = -((Number) data.getFieldValue("ymin")).floatValue();
52 			limits[2][1] = -((Number) data.getFieldValue("ymax")).floatValue();
53 			limits[1][0] = ((Number) data.getFieldValue("zmin")).floatValue();
54 			limits[1][1] = ((Number) data.getFieldValue("zmax")).floatValue();
55 
56 			// swapping Y and X limits flag in the bitwise flag
57 			int limitY = flag & LIMIT_YROT;
58 			int limitZ = flag & LIMIT_ZROT;
59 			flag &= LIMIT_XROT;// clear the other flags to swap them
60 			flag |= limitY << 1;
61 			flag |= limitZ >> 1;
62 		} else {
63 			limits[0][0] = ((Number) data.getFieldValue("xmin")).floatValue();
64 			limits[0][1] = ((Number) data.getFieldValue("xmax")).floatValue();
65 			limits[1][0] = ((Number) data.getFieldValue("ymin")).floatValue();
66 			limits[1][1] = ((Number) data.getFieldValue("ymax")).floatValue();
67 			limits[2][0] = ((Number) data.getFieldValue("zmin")).floatValue();
68 			limits[2][1] = ((Number) data.getFieldValue("zmax")).floatValue();
69 		}
70 
71 		// until blender 2.49 the rotations values were stored in degrees
72 		if (blenderContext.getBlenderVersion() <= 249) {
73 			for (int i = 0; i < limits.length; ++i) {
74 				limits[i][0] *= FastMath.DEG_TO_RAD;
75 				limits[i][1] *= FastMath.DEG_TO_RAD;
76 			}
77 		}
78 	}
79 
80 	@Override
bakeConstraint()81 	protected void bakeConstraint() {
82 		this.update();
83 		Object owner = this.owner.getObject();
84 		AnimData animData = blenderContext.getAnimData(this.owner.getOma());
85 		if (animData != null) {
86 			for (Animation animation : animData.anims) {
87 				BlenderTrack track = this.getTrack(owner, animData.skeleton, animation);
88 				Quaternion[] rotations = track.getRotations();
89 				float[] angles = new float[3];
90 				int maxFrames = rotations.length;
91 				for (int frame = 0; frame < maxFrames; ++frame) {
92 					rotations[frame].toAngles(angles);
93 					this.rotLimit(angles, ipo.calculateValue(frame));
94 					rotations[frame].fromAngles(angles);
95 				}
96 				track.setKeyframes(track.getTimes(), track.getTranslations(), rotations, track.getScales());
97 			}
98 		}
99 
100 		if (owner instanceof Spatial) {
101 			Transform ownerTransform = this.owner.getTransform();
102 			float[] angles = ownerTransform.getRotation().toAngles(null);
103 			this.rotLimit(angles, ipo.calculateValue(0));
104 			ownerTransform.getRotation().fromAngles(angles);
105 			this.owner.applyTransform(ownerTransform);
106 		}
107 	}
108 
109 	/**
110 	 * This method computes new constrained angles.
111 	 *
112 	 * @param angles
113 	 *            angles to be altered
114 	 * @param influence
115 	 *            the alteration influence
116 	 */
rotLimit(float[] angles, float influence)117 	private void rotLimit(float[] angles, float influence) {
118 		if ((flag & LIMIT_XROT) != 0) {
119 			float difference = 0.0f;
120 			if (angles[0] < limits[0][0]) {
121 				difference = (angles[0] - limits[0][0]) * influence;
122 			} else if (angles[0] > limits[0][1]) {
123 				difference = (angles[0] - limits[0][1]) * influence;
124 			}
125 			angles[0] -= difference;
126 		}
127 		if ((flag & LIMIT_YROT) != 0) {
128 			float difference = 0.0f;
129 			if (angles[1] < limits[1][0]) {
130 				difference = (angles[1] - limits[1][0]) * influence;
131 			} else if (angles[1] > limits[1][1]) {
132 				difference = (angles[1] - limits[1][1]) * influence;
133 			}
134 			angles[1] -= difference;
135 		}
136 		if ((flag & LIMIT_ZROT) != 0) {
137 			float difference = 0.0f;
138 			if (angles[2] < limits[2][0]) {
139 				difference = (angles[2] - limits[2][0]) * influence;
140 			} else if (angles[2] > limits[2][1]) {
141 				difference = (angles[2] - limits[2][1]) * influence;
142 			}
143 			angles[2] -= difference;
144 		}
145 	}
146 
147 	/**
148 	 * This method is called before baking (performes its operations only once).
149 	 * It is important to update the state of the limits and owner/target before
150 	 * baking the constraint.
151 	 */
update()152 	private void update() {
153 		if (!updated) {
154 			updated = true;
155 			if (owner != null) {
156 				owner.update();
157 			}
158 			if (target != null) {
159 				target.update();
160 			}
161 			if (this.owner.getObject() instanceof Bone) {// for bones we need to
162 															// change the sign
163 															// of the limits
164 				for (int i = 0; i < limits.length; ++i) {
165 					limits[i][0] *= -1;
166 					limits[i][1] *= -1;
167 				}
168 			}
169 
170 			// sorting the limits (lower is always first)
171 			for (int i = 0; i < limits.length; ++i) {
172 				if (limits[i][0] > limits[i][1]) {
173 					float temp = limits[i][0];
174 					limits[i][0] = limits[i][1];
175 					limits[i][1] = temp;
176 				}
177 			}
178 		}
179 	}
180 }
181