001: /*
002: * Copyright (c) 2000-2001 Silvere Martin-Michiellot All Rights Reserved.
003: *
004: * Silvere Martin-Michiellot grants you ("Licensee") a non-exclusive,
005: * royalty free, license to use, but not to modify or redistribute this
006: * software in source and binary code form,
007: * provided that i) this copyright notice and license appear on all copies of
008: * the software; and ii) Licensee does not utilize the software in a manner
009: * which is disparaging to Silvere Martin-Michiellot.
010: *
011: * This software is provided "AS IS," without a warranty of any kind. ALL
012: * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
013: * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
014: * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. Silvere Martin-Michiellot
015: * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES
016: * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
017: * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
018: * Silvere Martin-Michiellot OR ITS LICENSORS BE LIABLE
019: * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
020: * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
021: * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
022: * OR INABILITY TO USE SOFTWARE, EVEN IF Silvere Martin-Michiellot HAS BEEN
023: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
024: *
025: * This software is not designed or intended for use in on-line control of
026: * aircraft, air traffic, aircraft navigation or aircraft communications; or in
027: * the design, construction, operation or maintenance of any nuclear
028: * facility. Licensee represents and warrants that it will not use or
029: * redistribute the Software for such purposes.
030: *
031: * @Author: Silvere Martin-Michiellot for Digital Biosphere
032: * @Version: 1.1 (to stay in touch with h-anim)
033: *
034: */
035:
036: package com.db.hanim;
037:
038: import java.util.*;
039: import javax.vecmath.*;
040: import javax.media.j3d.*;
041:
042: /**
043: * This class is to implement a GestureSequence. A GestureSequence is a sequence of actions built out successive gestures. This class is useful when you want a single smooth interpolation between two or more gestures. For example run and leap is a common combination.
044: *
045: * @author Silvere Martin-Michiellot
046: * @version 1.0, 01 Mar 2000
047: */
048:
049: public class GestureSequence extends Object {
050:
051: private static final long DEFAULT_INTERVAL = 20L;
052:
053: /**
054: * Constructs a new GestureSequence. This class needs only to be instanciated once.
055: */
056: public GestureSequence() {
057:
058: super ();
059:
060: }
061:
062: /**
063: * Gets the Gesture that is the combination of the successive Gestures of the Vector. You have to set-up and fill your own vector. This vector should contain only Gesture of the same Humanoid and mustn't loop.
064: * Resultant duration is the sum of all Gestures duration times their loop plus the number of gesture minus one times the interval.
065: * Resultant loop will value 1.
066: * @param interval the time interval between two consecutive gestures
067: * @return a single Gesture that is the sequence of the consecutive Gestures
068: */
069: //Outputs a Gesture that is the combination of the successive Gestures of the Vector
070: //duration is the sum of all Gestures duration times their loop plus the number of gesture minus one times the interval
071: //resultant loop will value 1
072: public static Gesture getGesture(Vector vector, long interval) {
073:
074: Gesture gesture;
075: Gesture currentGesture;
076: Humanoid humanoid;
077: String gestureName;
078: long gestureDuration;
079: int gestureLoop;
080: BranchGroup branchGroup;
081: Vector gestureSequenceJoints;
082: String currentJointName;
083: Interpolator gestureInterpolator;
084: Vector knots;
085: Vector positions;
086: Vector quats;
087: float intervalKnots;
088: float[] gestureKnots;
089: Point3f[] gesturePositions;
090: Quat4f[] gestureQuats;
091: float currentGestureDuration;
092: float currentGestureBeginning;
093: Point3f position;
094: Quat4f quat;
095: Object[] objects;
096: float[] floats;
097:
098: int i;
099: int j;
100: boolean good;
101:
102: if ((vector != null) && (vector.size() > 0)
103: && (interval > 0.0f)) {
104:
105: //Vector must contain only Gestures
106: i = 0;
107: good = true;
108:
109: while ((i < vector.size()) && good) {
110: good = (vector.elementAt(i) instanceof Gesture);
111: i++;
112: }
113:
114: if (good) {
115: //humanoid must always be the same otherwise the combination if meaningless
116: //mustn't loop indefinately otherwise combination does not include the last Gestures
117: if (vector.size() > 1) {
118:
119: i = 0;
120: good = true;
121: humanoid = ((Gesture) vector.elementAt(i))
122: .getHumanoid();
123:
124: while ((i < vector.size()) && good) {
125: good = (((Gesture) vector.elementAt(i))
126: .getHumanoid() == humanoid);
127: i++;
128: }
129:
130: } else {
131: good = true;
132: }
133:
134: if (good) {
135: i = 0;
136: good = true;
137:
138: while ((i < vector.size()) && good) {
139: good = (((Gesture) vector.elementAt(i))
140: .getLoop() != -1);
141: i++;
142: }
143:
144: if (good) {
145: //quicker implementations surely exist but calls to GestureSequence should be relatively rare and concerns
146: //mostly designers that can use the GestureSequence at design time and propose their final compiled code with the
147: //already converted GestureSequence.
148:
149: //browse each BranchGroup of the Vector and build a String[] of all Joint names used in any of the Gestures
150: humanoid = ((Gesture) vector.elementAt(0))
151: .getHumanoid();
152: gestureName = new String();
153: gestureDuration = 0L + (vector.size() - 1)
154: * interval;
155: gestureLoop = 1;
156: gestureSequenceJoints = new Vector();
157: for (i = 0; i < vector.size(); i++) {
158: currentGesture = (Gesture) vector
159: .elementAt(i);
160: gestureName = gestureName
161: .concat(currentGesture.getName());
162: gestureDuration = gestureDuration
163: + (currentGesture.getLoop() * currentGesture
164: .getDuration());
165: branchGroup = currentGesture
166: .getBranchGroup();
167: for (j = 0; j < branchGroup.numChildren(); j++) {
168: currentJointName = (String) (branchGroup
169: .getChild(j).getUserData());
170: if (!exists(gestureSequenceJoints,
171: currentJointName)) {
172: gestureSequenceJoints
173: .add(currentJointName);
174: }
175: }
176: }
177:
178: gesture = new Gesture(humanoid, gestureName,
179: gestureDuration, gestureLoop);
180: //for each jointName (appearing in the resulting sequence) browse the Gestures to build the corresponding Interpolator
181: intervalKnots = interval / gestureDuration;
182: for (i = 0; i < gestureSequenceJoints.size(); i++) {
183: currentGestureDuration = 0.0f;
184: currentGestureBeginning = 0.0f;
185: knots = new Vector();
186: positions = new Vector();
187: quats = new Vector();
188: for (j = 0; j < vector.size(); j++) {
189: gestureInterpolator = find(
190: (Gesture) vector.elementAt(j),
191: (String) gestureSequenceJoints
192: .get(i));
193: currentGestureBeginning = currentGestureBeginning
194: + currentGestureDuration;
195: currentGestureDuration = ((float) (((Gesture) vector
196: .elementAt(j)).getLoop() * ((Gesture) vector
197: .elementAt(j)).getDuration()))
198: / ((float) gestureDuration);
199: if (gestureInterpolator != null) {
200: //if it is the continuation of the sequence for that joint
201: if (knots.size() > 0) {
202: if (gestureInterpolator instanceof PositionPathInterpolator) {
203: gestureKnots = new float[((PositionPathInterpolator) gestureInterpolator)
204: .getArrayLengths()];
205: gesturePositions = new Point3f[((PositionPathInterpolator) gestureInterpolator)
206: .getArrayLengths()];
207: ((PositionPathInterpolator) gestureInterpolator)
208: .getKnots(gestureKnots);
209: ((PositionPathInterpolator) gestureInterpolator)
210: .getPositions(gesturePositions);
211: for (int k = 0; k < gestureKnots.length; k++) {
212: knots
213: .add(new Float(
214: ((Float) knots
215: .lastElement())
216: .floatValue()
217: + intervalKnots
218: + (gestureKnots[k] * currentGestureDuration)));
219: }
220: positions
221: .addAll(Arrays
222: .asList(gesturePositions));
223: } else {
224: if (gestureInterpolator instanceof RotationPathInterpolator) {
225: gestureKnots = new float[((RotationPathInterpolator) gestureInterpolator)
226: .getArrayLengths()];
227: gestureQuats = new Quat4f[((RotationPathInterpolator) gestureInterpolator)
228: .getArrayLengths()];
229: ((RotationPathInterpolator) gestureInterpolator)
230: .getKnots(gestureKnots);
231: ((RotationPathInterpolator) gestureInterpolator)
232: .getQuats(gestureQuats);
233: for (int k = 0; k < gestureKnots.length; k++) {
234: knots
235: .add(new Float(
236: ((Float) knots
237: .lastElement())
238: .floatValue()
239: + intervalKnots
240: + (gestureKnots[k] * currentGestureDuration)));
241: }
242: quats
243: .addAll(Arrays
244: .asList(gestureQuats));
245: } else {
246: //gestureInterpolator instanceof RotPosPathInterpolator
247: gestureKnots = new float[((RotPosPathInterpolator) gestureInterpolator)
248: .getArrayLengths()];
249: gesturePositions = new Point3f[((RotPosPathInterpolator) gestureInterpolator)
250: .getArrayLengths()];
251: gestureQuats = new Quat4f[((RotPosPathInterpolator) gestureInterpolator)
252: .getArrayLengths()];
253: ((RotPosPathInterpolator) gestureInterpolator)
254: .getKnots(gestureKnots);
255: ((RotPosPathInterpolator) gestureInterpolator)
256: .getPositions(gesturePositions);
257: ((RotPosPathInterpolator) gestureInterpolator)
258: .getQuats(gestureQuats);
259: for (int k = 0; k < gestureKnots.length; k++) {
260: knots
261: .add(new Float(
262: ((Float) knots
263: .lastElement())
264: .floatValue()
265: + intervalKnots
266: + (gestureKnots[k] * currentGestureDuration)));
267: }
268: positions
269: .addAll(Arrays
270: .asList(gesturePositions));
271: quats
272: .addAll(Arrays
273: .asList(gestureQuats));
274: }
275: }
276: } else {
277: //if it is the first time, initialize the values and fill preceding gap
278: knots.add(new Float(0.0f));
279: knots
280: .add(new Float(
281: currentGestureBeginning));
282: if (gestureInterpolator instanceof PositionPathInterpolator) {
283: gestureKnots = new float[((PositionPathInterpolator) gestureInterpolator)
284: .getArrayLengths()];
285: gesturePositions = new Point3f[((PositionPathInterpolator) gestureInterpolator)
286: .getArrayLengths()];
287: ((PositionPathInterpolator) gestureInterpolator)
288: .getKnots(gestureKnots);
289: ((PositionPathInterpolator) gestureInterpolator)
290: .getPositions(gesturePositions);
291: for (int k = 0; k < gestureKnots.length; k++) {
292: knots
293: .add(new Float(
294: ((Float) knots
295: .lastElement())
296: .floatValue()
297: + intervalKnots
298: + (gestureKnots[k] * currentGestureDuration)));
299: }
300: position = new Point3f();
301: ((PositionPathInterpolator) gestureInterpolator)
302: .getPosition(0,
303: position);
304: positions.add(position);
305: positions.add(position);
306: positions
307: .addAll(Arrays
308: .asList(gesturePositions));
309: } else {
310: if (gestureInterpolator instanceof RotationPathInterpolator) {
311: gestureKnots = new float[((RotationPathInterpolator) gestureInterpolator)
312: .getArrayLengths()];
313: gestureQuats = new Quat4f[((RotationPathInterpolator) gestureInterpolator)
314: .getArrayLengths()];
315: ((RotationPathInterpolator) gestureInterpolator)
316: .getKnots(gestureKnots);
317: ((RotationPathInterpolator) gestureInterpolator)
318: .getQuats(gestureQuats);
319: for (int k = 0; k < gestureKnots.length; k++) {
320: knots
321: .add(new Float(
322: ((Float) knots
323: .lastElement())
324: .floatValue()
325: + intervalKnots
326: + (gestureKnots[k] * currentGestureDuration)));
327: }
328: quat = new Quat4f();
329: ((RotationPathInterpolator) gestureInterpolator)
330: .getQuat(0,
331: quat);
332: quats.add(quat);
333: quats.add(quat);
334: quats
335: .addAll(Arrays
336: .asList(gestureQuats));
337: } else {
338: //(gestureInterpolator instanceof RotPosPathInterpolator
339: gestureKnots = new float[((RotPosPathInterpolator) gestureInterpolator)
340: .getArrayLengths()];
341: gesturePositions = new Point3f[((RotPosPathInterpolator) gestureInterpolator)
342: .getArrayLengths()];
343: gestureQuats = new Quat4f[((RotPosPathInterpolator) gestureInterpolator)
344: .getArrayLengths()];
345: ((RotPosPathInterpolator) gestureInterpolator)
346: .getKnots(gestureKnots);
347: ((RotPosPathInterpolator) gestureInterpolator)
348: .getPositions(gesturePositions);
349: ((RotPosPathInterpolator) gestureInterpolator)
350: .getQuats(gestureQuats);
351: for (int k = 0; k < gestureKnots.length; k++) {
352: knots
353: .add(new Float(
354: ((Float) knots
355: .lastElement())
356: .floatValue()
357: + intervalKnots
358: + (gestureKnots[k] * currentGestureDuration)));
359: }
360: position = new Point3f();
361: ((RotPosPathInterpolator) gestureInterpolator)
362: .getPosition(0,
363: position);
364: positions.add(position);
365: positions.add(position);
366: positions
367: .addAll(Arrays
368: .asList(gesturePositions));
369: quat = new Quat4f();
370: ((RotPosPathInterpolator) gestureInterpolator)
371: .getQuat(0,
372: quat);
373: quats.add(quat);
374: quats.add(quat);
375: quats
376: .addAll(Arrays
377: .asList(gestureQuats));
378: }
379: }
380: }
381: }
382: }
383: //finally, build up the gesture interpolator for given joint with the corresponding interpolator
384: objects = knots.toArray();
385: floats = new float[objects.length];
386: for (int k = 0; k < objects.length; k++) {
387: floats[k] = ((Float) (objects[k]))
388: .floatValue();
389: }
390: if ((positions.size() > 0)
391: && (quats.size() > 0)) {
392: gesture
393: .addGestureRotPosComponent(
394: humanoid
395: .findJoint((String) gestureSequenceJoints
396: .get(i)),
397: floats,
398: (Quat4f[]) (quats
399: .toArray()),
400: (Point3f[]) (positions
401: .toArray()));
402: } else {
403: if (positions.size() > 0) {
404: gesture
405: .addGesturePositionComponent(
406: humanoid
407: .findJoint((String) gestureSequenceJoints
408: .get(i)),
409: floats,
410: (Point3f[]) (positions
411: .toArray()));
412: } else {
413: gesture
414: .addGestureRotationComponent(
415: humanoid
416: .findJoint((String) gestureSequenceJoints
417: .get(i)),
418: floats,
419: (Quat4f[]) (quats
420: .toArray()));
421: }
422: }
423: }
424: return gesture;
425: } else {
426: throw new java.lang.IllegalArgumentException(
427: "Gestures of GestureSequence mustn't loop indefinately.");
428: }
429: } else {
430: throw new java.lang.IllegalArgumentException(
431: "GestureSequence contains Gestures from different Humanoids.");
432: }
433: } else {
434: throw new java.lang.IllegalArgumentException(
435: "GestureSequence contains Objects that are not Gestures.");
436: }
437:
438: } else {
439: return null;
440: }
441: }
442:
443: /**
444: * Gets the Gesture that is the combination of the successive Gestures of the Vector. You have to set-up and fill your own vector. This vector should contain only Gesture of the same Humanoid and mustn't loop.
445: * Resultant duration is the sum of all Gestures duration times their loop plus the number of gesture minus one times the interval.
446: * Resultant loop will value 1.
447: * Equivalent to GestureSequence.getGesture(vector).getBranchGroup()
448: * @return a single Gesture that is the sequence of the consecutive Gestures
449: */
450: //use the internal default interval which is set to 20 ms
451: public static Gesture getGesture(Vector vector) {
452:
453: return GestureSequence.getGesture(vector, DEFAULT_INTERVAL);
454:
455: }
456:
457: /**
458: * Gets the BranchGroup directly out of the Gesture that is the combination of the successive Gestures of the Vector. You have to set-up and fill your own vector. This vector should contain only Gesture of the same Humanoid and mustn't loop.
459: * Resultant duration is the sum of all Gestures duration times their loop plus the number of gesture minus one times the interval.
460: * Resultant loop will value 1.
461: * The time interval between two consecutive gestures is set to 20ms.
462: * Equivalent to GestureSequence.getGesture(vector).getBranchGroup()
463: * @return a single Gesture that is the sequence of the consecutive Gestures
464: */
465: //Equivalent to GestureSequence.getGesture(vector, interval).getBranchGroup()
466: public static BranchGroup getBranchGroup(Vector vector,
467: long interval) {
468:
469: return GestureSequence.getGesture(vector, interval)
470: .getBranchGroup();
471:
472: }
473:
474: /**
475: * Gets the BranchGroup directly out of the Gesture that is the combination of the successive Gestures of the Vector. You have to set-up and fill your own vector. This vector should contain only Gesture of the same Humanoid and mustn't loop.
476: * Resultant duration is the sum of all Gestures duration times their loop plus the number of gesture minus one times the interval.
477: * Resultant loop will value 1.
478: * The time interval between two consecutive gestures is set to 20ms.
479: * Equivalent to GestureSequence.getGesture(vector).getBranchGroup()
480: * @return a single Gesture that is the sequence of the consecutive Gestures
481: */
482: public static BranchGroup getBranchGroup(Vector vector) {
483:
484: return GestureSequence.getGesture(vector).getBranchGroup();
485:
486: }
487:
488: private static Interpolator find(Gesture gesture, String jointName) {
489:
490: BranchGroup branchGroup;
491: int i;
492: boolean found;
493:
494: branchGroup = gesture.getBranchGroup();
495:
496: i = 0;
497: found = false;
498: while ((i < branchGroup.numChildren()) && (!found)) {
499: found = branchGroup.getChild(i).getUserData().equals(
500: jointName);
501: i++;
502: }
503:
504: if (found) {
505: return (Interpolator) branchGroup.getChild(i - 1);
506: } else {
507: return null;
508: }
509: }
510:
511: private static boolean exists(Vector gestureSequenceJoints,
512: String jointName) {
513:
514: int i;
515: boolean found;
516:
517: i = 0;
518: found = false;
519: while ((i < gestureSequenceJoints.size()) && (!found)) {
520: found = ((String) gestureSequenceJoints.get(i))
521: .equals(jointName);
522: i++;
523: }
524: return found;
525: }
526:
527: }
|