001: /*
002: * Copyright (c) 2000 Silvere Martin-Michiellot All Rights Reserved.
003: *
004: * Silvere Martin-Michiellot grants you ("Licensee") a non-exclusive,
005: * royalty free, license to use, modify and 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: */
032:
033: package com.db.behaviors;
034:
035: import java.io.*;
036: import java.util.*;
037: import javax.media.j3d.*;
038: import javax.vecmath.*;
039: import java.awt.event.*;
040:
041: // This code is repackaged after KeyNavigator
042: // Site http://java.sun.com
043: // Email
044:
045: /**
046: * This is the KeyNavigator class. It accumulates AWT key events (key
047: * press and key release) and computes a new transform based on the
048: * accumulated events and elapsed time.
049: */
050: public class KeyNavigator extends Object {
051:
052: private Vector3d navVec;
053: private long time;
054:
055: private Vector3d fwdAcc;
056: private Vector3d bwdAcc;
057: private Vector3d leftAcc;
058: private Vector3d rightAcc;
059: private Vector3d upAcc;
060: private Vector3d downAcc;
061:
062: private Vector3d fwdDrag;
063: private Vector3d bwdDrag;
064: private Vector3d leftDrag;
065: private Vector3d rightDrag;
066: private Vector3d upDrag;
067: private Vector3d downDrag;
068:
069: private double fwdVMax;
070: private double bwdVMax;
071: private double leftVMax;
072: private double rightVMax;
073: private double upVMax;
074: private double downVMax;
075:
076: private float leftRotAngle;
077: private float rightRotAngle;
078: private float upRotAngle;
079: private float downRotAngle;
080:
081: private double mmx;
082:
083: private Vector3d a = new Vector3d();
084: private Vector3d dv = new Vector3d();
085: private Point3d dp = new Point3d();
086: private Quat4d udQuat = new Quat4d();
087: private Quat4d lrQuat = new Quat4d();
088: private Vector3d vpPos = new Vector3d();
089: private double vpScale;
090: private Quat4d vpQuat = new Quat4d();
091: private Matrix4d vpMatrix = new Matrix4d();
092: private Transform3D vpTrans = new Transform3D();
093: private Matrix4d mat = new Matrix4d();
094: private Vector3d nda = new Vector3d();
095: private Vector3d temp = new Vector3d();
096: private Transform3D nominal = new Transform3D();
097: private TransformGroup targetTG;
098:
099: private static final int UP_ARROW = (1 << 0);
100: private static final int DOWN_ARROW = (1 << 1);
101: private static final int LEFT_ARROW = (1 << 2);
102: private static final int RIGHT_ARROW = (1 << 3);
103:
104: private static final int SPACE = (1 << 6);
105:
106: private static final int CTRL = (1 << 9);
107: private static final int SHIFT = (1 << 10);
108: private static final int ALT = (1 << 11);
109: private static final int META = (1 << 12);
110:
111: private static final int KEY_UP = (1 << 13);
112: private static final int KEY_DOWN = (1 << 14);
113:
114: private int key_state = 0;
115: private int modifier_key_state = 0;
116:
117: /**
118: * Constructs a new key navigator object that operates on the specified
119: * transform group. All parameters are set to their default, idle state.
120: * @param targetTG the target transform group
121: */
122: public KeyNavigator(TransformGroup targetTG) {
123:
124: this .targetTG = targetTG;
125: targetTG.getTransform(nominal);
126:
127: mmx = 128.0;
128: navVec = new Vector3d(0.0, 0.0, 0.0);
129:
130: fwdAcc = new Vector3d(0.0, 0.0, -mmx);
131: bwdAcc = new Vector3d(0.0, 0.0, mmx);
132: leftAcc = new Vector3d(-mmx, 0.0, 0.0);
133: rightAcc = new Vector3d(mmx, 0.0, 0.0);
134: upAcc = new Vector3d(0.0, mmx, 0.0);
135: downAcc = new Vector3d(0.0, -mmx, 0.0);
136:
137: fwdDrag = new Vector3d(0.0, 0.0, mmx);
138: bwdDrag = new Vector3d(0.0, 0.0, -mmx);
139: leftDrag = new Vector3d(mmx, 0.0, 0.0);
140: rightDrag = new Vector3d(-mmx, 0.0, 0.0);
141: upDrag = new Vector3d(0.0, -mmx, 0.0);
142: downDrag = new Vector3d(0.0, mmx, 0.0);
143:
144: fwdVMax = -mmx;
145: bwdVMax = mmx;
146: leftVMax = -mmx;
147: rightVMax = mmx;
148: upVMax = mmx;
149: downVMax = -mmx;
150:
151: leftRotAngle = (float) (-Math.PI * 2.0 / 3.0);
152: rightRotAngle = (float) (Math.PI * 2.0 / 3.0);
153: upRotAngle = (float) (Math.PI * 2.0 / 3.0);
154: downRotAngle = (float) (-Math.PI * 2.0 / 3.0);
155:
156: // Create Timer here.
157: time = System.currentTimeMillis();
158:
159: }
160:
161: private long getDeltaTime() {
162:
163: long newTime = System.currentTimeMillis();
164: long deltaTime = newTime - time;
165: time = newTime;
166: if (deltaTime > 2000)
167: return 0;
168: else
169: return deltaTime;
170:
171: }
172:
173: /* Generate a quaterion as a rotation of radians av about 0/x 1/y 2/z axis */
174: private void genRotQuat(double av, int axis, Quat4d q) {
175:
176: double b;
177:
178: q.x = q.y = q.z = 0.0;
179: q.w = Math.cos(av / 2.0);
180:
181: b = 1.0 - q.w * q.w;
182:
183: if (b > 0.0)
184: b = Math.sqrt(b);
185: else
186: return;
187:
188: if (av < 0.0)
189: b = -b;
190: if (axis == 0)
191: q.x = b;
192: else if (axis == 1)
193: q.y = b;
194: else
195: q.z = b;
196:
197: }
198:
199: private void accKeyAdd(Vector3d a, Vector3d da, Vector3d drag,
200: double scaleVel) {
201:
202: /* Scaling of acceleration due to modification keys */
203: nda.scale(scaleVel, da);
204: /* Addition of sufficent acceleration to counteract drag */
205: nda.sub(drag);
206:
207: /* Summing into overall acceleration */
208: a.add(nda);
209:
210: }
211:
212: /**
213: * Computes a new transform for the next frame based on
214: * the current transform, accumulated keyboard inputs, and
215: * elapsed time. This new transform is written into the target
216: * transform group.
217: * This method should be called once per frame.
218: */
219: public void integrateTransformChanges() {
220:
221: double scaleVel, scaleRot, scaleScale, pre;
222: double udAng, lrAng, r;
223:
224: // Get the current View Platform transform into a transform3D object.
225: targetTG.getTransform(vpTrans);
226: // Extract the position, quaterion, and scale from the transform3D.
227: vpScale = vpTrans.get(vpQuat, vpPos);
228:
229: double deltaTime = (double) getDeltaTime();
230: deltaTime *= 0.001;
231:
232: /* Calculate scale due to modification keys */
233: if ((modifier_key_state & ALT) != 0
234: && (modifier_key_state & META) == 0) {
235: scaleVel = 3.0;
236: scaleRot = 2.0;
237: scaleScale = 4.0;
238: } else if ((modifier_key_state & ALT) == 0
239: && (modifier_key_state & META) != 0) {
240: scaleVel = 0.1;
241: scaleRot = 0.1;
242: scaleScale = 0.1;
243: } else {
244: scaleRot = scaleVel = 1.0;
245: scaleScale = 4.0;
246: }
247:
248: /*
249: * Processing of rectiliear motion keys.
250: */
251:
252: a.x = a.y = a.z = 0.0; /* acceleration initially 0 */
253:
254: /* Acceleration due to keys being down */
255: if ((key_state & UP_ARROW) != 0
256: && (key_state & DOWN_ARROW) == 0)
257: accKeyAdd(a, fwdAcc, fwdDrag, scaleVel);
258: else if ((key_state & UP_ARROW) == 0
259: && (key_state & DOWN_ARROW) != 0)
260: accKeyAdd(a, bwdAcc, bwdDrag, scaleVel);
261:
262: if (((modifier_key_state & ALT) != 0)
263: && (key_state & LEFT_ARROW) != 0
264: && (key_state & RIGHT_ARROW) == 0) {
265: accKeyAdd(a, leftAcc, leftDrag, scaleVel);
266: } else if (((modifier_key_state & ALT) != 0)
267: && (key_state & LEFT_ARROW) == 0
268: && (key_state & RIGHT_ARROW) != 0)
269: accKeyAdd(a, rightAcc, rightDrag, scaleVel);
270:
271: /*
272: * Drag due to new or existing motion
273: */
274: pre = navVec.z + a.z * deltaTime;
275: if (pre < 0.0) {
276: if (pre + fwdDrag.z * deltaTime < 0.0)
277: a.add(fwdDrag);
278: else
279: a.z -= pre / deltaTime;
280: } else if (pre > 0.0) {
281: if (pre + bwdDrag.z * deltaTime > 0.0)
282: a.add(bwdDrag);
283: else
284: a.z -= pre / deltaTime;
285: }
286:
287: pre = navVec.x + a.x * deltaTime;
288: if (pre < 0.0) {
289: if (pre + leftDrag.x * deltaTime < 0.0)
290: a.add(leftDrag);
291: else
292: a.x -= pre / deltaTime;
293: } else if (pre > 0.0) {
294: if (pre + rightDrag.x * deltaTime > 0.0)
295: a.add(rightDrag);
296: else
297: a.x -= pre / deltaTime;
298: }
299:
300: pre = navVec.y + a.y * deltaTime;
301: if (pre < 0.0) {
302: if (pre + downDrag.y * deltaTime < 0.0)
303: a.add(downDrag);
304: else
305: a.y -= pre / deltaTime;
306: } else if (pre > 0.0) {
307: if (pre + upDrag.y * deltaTime > 0.0)
308: a.add(upDrag);
309: else
310: a.y -= pre / deltaTime;
311: }
312:
313: /* Integration of acceleration to velocity */
314: dv.scale(deltaTime, a);
315: navVec.add(dv);
316:
317: /* Speed limits */
318: if (navVec.z < scaleVel * fwdVMax)
319: navVec.z = scaleVel * fwdVMax;
320: if (navVec.z > scaleVel * bwdVMax)
321: navVec.z = scaleVel * bwdVMax;
322: if (navVec.x < scaleVel * leftVMax)
323: navVec.x = scaleVel * leftVMax;
324: if (navVec.x > scaleVel * rightVMax)
325: navVec.x = scaleVel * rightVMax;
326: if (navVec.y > scaleVel * upVMax)
327: navVec.y = scaleVel * upVMax;
328: if (navVec.y < scaleVel * downVMax)
329: navVec.y = scaleVel * downVMax;
330:
331: /* Integration of velocity to distance */
332: dp.scale(deltaTime, navVec);
333:
334: /* Scale our motion to the current avatar scale */
335: // 1.0 eventually needs to be a more complex value (see hs).
336: // r = workplace_coexistence_to_vworld_ori.scale/
337: // one_to_one_coexistence_to_vworld_ori.scale;
338: r = vpScale / 1.0;
339: dp.scale(r, dp);
340:
341: /*
342: * Processing of rotation motion keys.
343: */
344: udAng = lrAng = 0.0;
345:
346: /* Rotation due to keys being down */
347: if (((modifier_key_state & ALT) == 0)
348: && (key_state & LEFT_ARROW) != 0
349: && (key_state & RIGHT_ARROW) == 0)
350: lrAng = (double) leftRotAngle;
351: else if (((modifier_key_state & ALT) == 0)
352: && (key_state & LEFT_ARROW) == 0
353: && (key_state & RIGHT_ARROW) != 0)
354: lrAng = (double) rightRotAngle;
355:
356: lrAng *= scaleRot;
357: udAng *= scaleRot;
358:
359: /* Scaling of angle change to delta time */
360: lrAng *= deltaTime;
361: udAng *= deltaTime;
362:
363: /* Addition to existing orientation */
364: // vr_quat_inverse(&workplace_coexistence_to_vworld_ori.quat, &vpQuat);
365: // vpQuat gotten at top of method.
366: vpQuat.inverse();
367:
368: if (lrAng != 0.0) {
369: genRotQuat(lrAng, 1, lrQuat);
370: vpQuat.mul(lrQuat, vpQuat);
371: }
372:
373: if (udAng != 0.0) {
374: genRotQuat(udAng, 0, udQuat);
375: vpQuat.mul(udQuat, vpQuat);
376: }
377:
378: /* Rotation of distance vector */
379: vpQuat.inverse();
380: vpQuat.normalize(); /* Improvment over HoloSketch */
381: mat.set(vpQuat);
382: mat.transform(dp);
383:
384: /* Processing of scale */
385: if ((key_state & SHIFT) != 0) {
386: vpScale *= (1.0 + (scaleScale * deltaTime));
387: if (vpScale > 10e+14)
388: vpScale = 1.0;
389: } else {
390: vpScale /= (1.0 + (scaleScale * deltaTime));
391: if (vpScale < 10e-14)
392: vpScale = 1.0;
393: }
394:
395: // add dp into current vp position.
396: vpPos.add(dp);
397:
398: if ((key_state & SPACE) != 0) {
399: resetVelocity();
400: // Extract the position, quaterion, and scale from the nominal
401: // transform
402: vpScale = nominal.get(vpQuat, vpPos);
403: }
404:
405: /* Final update of view platform */
406: // Put the transform back into the transform group.
407: vpTrans.set(vpQuat, vpPos, vpScale);
408: targetTG.setTransform(vpTrans);
409:
410: }
411:
412: /**
413: * Resets the keyboard navigation velocity to 0.
414: */
415: private void resetVelocity() {
416:
417: navVec.x = navVec.y = navVec.z = 0.0;
418:
419: }
420:
421: /**
422: * Processed a keyboard event. This routine should be called
423: * every time a KEY_PRESSED or KEY_RELEASED event is received.
424: * @param keyEvent the AWT key event
425: */
426: public void processKeyEvent(KeyEvent keyEvent) {
427:
428: int keyCode = keyEvent.getKeyCode();
429: int keyChar = keyEvent.getKeyChar();
430:
431: //System.err.println("keyCode " + keyCode + " keyChar " + keyChar);
432:
433: if (keyEvent.getID() == KeyEvent.KEY_RELEASED) {
434: switch (keyCode) {
435: case KeyEvent.VK_UP:
436: key_state &= ~UP_ARROW;
437: break;
438: case KeyEvent.VK_DOWN:
439: key_state &= ~DOWN_ARROW;
440: break;
441: case KeyEvent.VK_LEFT:
442: key_state &= ~LEFT_ARROW;
443: break;
444: case KeyEvent.VK_RIGHT:
445: key_state &= ~RIGHT_ARROW;
446: break;
447: case KeyEvent.VK_SPACE:
448: key_state &= ~SPACE;
449: break;
450: }
451: } else if (keyEvent.getID() == KeyEvent.KEY_PRESSED) {
452: switch (keyCode) {
453: case KeyEvent.VK_UP:
454: key_state |= UP_ARROW;
455: break;
456: case KeyEvent.VK_DOWN:
457: key_state |= DOWN_ARROW;
458: break;
459: case KeyEvent.VK_LEFT:
460: key_state |= LEFT_ARROW;
461: break;
462: case KeyEvent.VK_RIGHT:
463: key_state |= RIGHT_ARROW;
464: break;
465: case KeyEvent.VK_SPACE:
466: key_state |= SPACE;
467: break;
468: }
469: }
470:
471: /* Check modifier keys */
472: if (keyEvent.isShiftDown())
473: modifier_key_state |= SHIFT;
474: else
475: modifier_key_state &= ~SHIFT;
476:
477: if (keyEvent.isMetaDown())
478: modifier_key_state |= META;
479: else
480: modifier_key_state &= ~META;
481:
482: if (keyEvent.isAltDown())
483: modifier_key_state |= ALT;
484: else
485: modifier_key_state &= ~ALT;
486:
487: if (keyEvent.isControlDown())
488: modifier_key_state |= META;
489: else
490: modifier_key_state &= ~META;
491:
492: }
493:
494: }
|