001: /*
002: * $RCSfile: ViewingPlatform.java,v $
003: *
004: * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * - Redistribution of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * - Redistribution in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * Neither the name of Sun Microsystems, Inc. or the names of
019: * contributors may be used to endorse or promote products derived
020: * from this software without specific prior written permission.
021: *
022: * This software is provided "AS IS," without a warranty of any
023: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
024: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
025: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
026: * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
027: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
028: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
029: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
030: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
031: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
032: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
033: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
034: * POSSIBILITY OF SUCH DAMAGES.
035: *
036: * You acknowledge that this software is not designed, licensed or
037: * intended for use in the design, construction, operation or
038: * maintenance of any nuclear facility.
039: *
040: * $Revision: 1.4 $
041: * $Date: 2007/02/09 17:20:45 $
042: * $State: Exp $
043: */
044:
045: package com.sun.j3d.utils.universe;
046:
047: import java.util.Enumeration;
048: import java.util.Hashtable;
049: import java.util.Vector;
050: import java.awt.Component;
051: import javax.media.j3d.*;
052: import javax.vecmath.*;
053: import com.sun.j3d.utils.behaviors.vp.*;
054: import com.sun.j3d.internal.J3dUtilsI18N;
055:
056: /**
057: * This class is used to set up the "view" side of a Java 3D scene graph.
058: * The ViewingPlatform object contains a MultiTransformGroup node to allow
059: * for a series of transforms to be linked together. To this structure
060: * the ViewPlatform is added as well as any geometry to associate with this
061: * view platform.
062: *
063: * @see ViewPlatform
064: */
065: public class ViewingPlatform extends BranchGroup {
066:
067: /**
068: * Cached ViewPlatform associated with this ViewingPlatform object.
069: */
070: protected ViewPlatform viewPlatform;
071:
072: /**
073: * MultiTransformGroup that holds all TransformGroups between
074: * the BranchGroup and the View object.
075: */
076: protected MultiTransformGroup mtg;
077:
078: /**
079: * Used to keep track of added geometry. When geometry
080: * is added to the view platform, an addChild to this BranchGroup
081: * is performed.
082: */
083: protected BranchGroup platformGeometryRoot;
084:
085: /**
086: * Used to keep track of added geometry. When geometry
087: * is added for an avatar, an addChild to this BranchGroup
088: * is performed.
089: */
090: protected BranchGroup avatarRoot;
091:
092: /**
093: * Cached PlatformGeometry object.
094: */
095: protected PlatformGeometry platformGeometry = null;
096:
097: /**
098: * Table of the Viewer objects.
099: */
100: protected Hashtable viewerList;
101:
102: /**
103: * Used to keep track of behaviors.
104: *
105: * @since Java 3D 1.2.1
106: */
107: protected BranchGroup behaviors;
108:
109: /**
110: * The universe to which this viewing platform is attached
111: *
112: * @since Java 3D 1.3
113: */
114: protected SimpleUniverse universe;
115:
116: /**
117: * Creates a default ViewingPlatform object. This consists of a
118: * MultiTransfromGroup node with one transform and a ViewPlatform
119: * object. The ViewPlatform is positioned at (0.0, 0.0, 0.0).
120: */
121: public ViewingPlatform() {
122: // Call main constructor with default values.
123: this (1);
124: }
125:
126: /**
127: * Creates the ViewingPlatform object. This consists of a
128: * MultiTransfromGroup node with the specified number of transforms
129: * (all initialized to the identity transform).
130: * and a ViewPlatform object.
131: *
132: * @param numTransforms The number of transforms the MultiTransformGroup
133: * node should contain. If this number is less than 1, 1 is assumed.
134: */
135: public ViewingPlatform(int numTransforms) {
136: viewerList = new Hashtable();
137:
138: // Set default capabilities for this node.
139: setCapability(Group.ALLOW_CHILDREN_WRITE);
140: setCapability(Group.ALLOW_CHILDREN_EXTEND);
141: setCapability(BranchGroup.ALLOW_DETACH);
142:
143: // Create MultiTransformGroup node.
144: if (numTransforms < 1)
145: numTransforms = 1;
146: mtg = new MultiTransformGroup(numTransforms);
147:
148: // Get first transform and add it to the scene graph.
149: TransformGroup tg = mtg.getTransformGroup(0);
150: addChild(tg);
151:
152: // Create ViewPlatform and add it to the last transform in the
153: // MultiTransformGroup node.
154: tg = mtg.getTransformGroup(numTransforms - 1);
155: viewPlatform = new ViewPlatform();
156: viewPlatform.setCapability(ViewPlatform.ALLOW_POLICY_READ);
157: viewPlatform.setCapability(ViewPlatform.ALLOW_POLICY_WRITE);
158: tg.addChild(viewPlatform);
159:
160: // Set capabilities to allow for changes when live.
161: tg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
162: tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
163:
164: // Initialize the avatarRoot BranchGroup node and add it to the
165: // last transform in the MultiTransformGroup node.
166: avatarRoot = new BranchGroup();
167: avatarRoot.setCapability(Group.ALLOW_CHILDREN_READ);
168: avatarRoot.setCapability(Group.ALLOW_CHILDREN_WRITE);
169: avatarRoot.setCapability(Group.ALLOW_CHILDREN_EXTEND);
170: tg.addChild(avatarRoot);
171:
172: // Initialize the platformGeometry BranchGroup node and add it to the
173: // last transform in the MultiTransformGroup node.
174: platformGeometryRoot = new BranchGroup();
175: platformGeometryRoot.setCapability(Group.ALLOW_CHILDREN_READ);
176: platformGeometryRoot.setCapability(Group.ALLOW_CHILDREN_WRITE);
177: platformGeometryRoot.setCapability(Group.ALLOW_CHILDREN_EXTEND);
178: tg.addChild(platformGeometryRoot);
179: }
180:
181: /**
182: * Sets the ViewPlatform node for this ViewingPlatform object.
183: *
184: * @param vp The ViewPlatform node to associate with this ViewingPlatform
185: * object.
186: */
187: public void setViewPlatform(ViewPlatform vp) {
188: TransformGroup tg = getViewPlatformTransform();
189: tg.removeChild(viewPlatform);
190: tg.addChild(vp);
191: viewPlatform = vp;
192: // Assign this to all Viewers.
193: Enumeration e = viewerList.keys();
194:
195: while (e.hasMoreElements())
196: ((Viewer) e.nextElement()).setViewingPlatform(this );
197: }
198:
199: /**
200: * Returns the ViewPlatform node for this ViewingPlatform object.
201: *
202: * @return The ViewPlatform node associated with this ViewingPlatform
203: * object.
204: */
205: public ViewPlatform getViewPlatform() {
206: return viewPlatform;
207: }
208:
209: /**
210: * Assigns the geometry to associate with the ViewingPlatform.
211: * PlatformGeometry is used to hold any geometry to be associated
212: * with the ViewingPlatform. If the ViewingPlatform is to be the
213: * inside of a car, for instance, than the PlatformGeometry could be
214: * the dashboard of the car.
215: *
216: * @param pg The geometry to be associated with this ViewingPlatform.
217: * Passing in null has the effect of deleting any geometry associated
218: * with this ViewingPlatform.
219: */
220: public void setPlatformGeometry(PlatformGeometry pg) {
221: // Just return if trying to set the same PlatformGeometry object.
222: if (platformGeometry == pg)
223: return;
224:
225: // If the PlatformGeometry is null, will be removing any geometry
226: // already present.
227: if (pg == null) {
228: if (platformGeometryRoot.numChildren() != 0)
229: platformGeometryRoot.removeChild(0);
230: } else {
231:
232: // See if there is an old PlatformGeometry to replace.
233: if (platformGeometryRoot.numChildren() != 0)
234: platformGeometryRoot.setChild(pg, 0);
235: else {
236: platformGeometryRoot.addChild(pg);
237: }
238: }
239: platformGeometry = pg;
240: }
241:
242: /**
243: * Returns the PlatformGeometry associated with this ViewingPlatform
244: *
245: * @return The PlatformGeometry associated with this ViewingPlatform
246: */
247: public PlatformGeometry getPlatformGeometry() {
248: return platformGeometry;
249: }
250:
251: /**
252: * Returns the MultitransformGroup object for this
253: * ViewingPlatform object.
254: *
255: * @return The MultitransformGroup object.
256: */
257: public MultiTransformGroup getMultiTransformGroup() {
258: return mtg;
259: }
260:
261: /**
262: * Returns a reference to the "bottom most" transform in the
263: * MultiTransformGroup that is above the ViewPlatform node.
264: *
265: * @return The TransformGroup that is immediately above the
266: * ViewPlatform object.
267: */
268: public TransformGroup getViewPlatformTransform() {
269: return mtg.getTransformGroup(mtg.getNumTransforms() - 1);
270: }
271:
272: /**
273: * Sets the nominal viewing distance in the ViewPlatform transform based
274: * on the current field of view. If the ViewAttachPolicy is not the
275: * default of View.NOMINAL_HEAD, then this method has no effect.<p>
276: *
277: * The ViewPlatform is moved back along Z so that objects at the origin
278: * spanning the normalized X range of -1.0 to +1.0 can be fully viewed
279: * across the width of the window. This is done by setting a translation
280: * of 1/(tan(fieldOfView/2)) in the ViewPlatform transform.<p>
281: *
282: * If there is no Viewer object associated with this ViewingPlatform
283: * object the default field of view of PI/4.0 is used.<p>
284: *
285: * NOTE: Support for multiple Viewer objects is not available. If
286: * multiple viewers are attached to this ViewingPlatform than a
287: * RuntimeException will be thrown.
288: */
289: public void setNominalViewingTransform() {
290: if (viewPlatform.getViewAttachPolicy() == View.NOMINAL_HEAD) {
291: double fieldOfView;
292:
293: if (viewerList.size() == 0) {
294: // No Viewer associated with this ViewingPlatform, so use the
295: // default field of view value to move the ViewingPlatform.
296: fieldOfView = Math.PI / 4.0;
297: } else {
298: if (viewerList.size() > 1) {
299: throw new RuntimeException(J3dUtilsI18N
300: .getString("ViewingPlatform0"));
301: }
302:
303: Viewer viewer = (Viewer) viewerList.keys()
304: .nextElement();
305: View view = viewer.getView();
306: fieldOfView = view.getFieldOfView();
307: }
308:
309: Transform3D t3d = new Transform3D();
310: double viewDistance = 1.0 / Math.tan(fieldOfView / 2.0);
311: t3d.set(new Vector3d(0.0, 0.0, viewDistance));
312: getViewPlatformTransform().setTransform(t3d);
313: }
314: }
315:
316: /**
317: * Returns the avatarRoot child number of the ViewerAvatar object.
318: * All the children of the avatarRoot are compared with the passed
319: * in ViewerAvatar. If a match is found, the index is returned.
320: *
321: * @param avatar The ViewerAvatar object to look for in the avatarRoot's
322: * child nodes.
323: * @return The index of the child that corresponds to the ViewerAvatar.
324: * If the avatarRoot does not contain the ViewerAvatar -1 is returned.
325: */
326: private int findAvatarChild(ViewerAvatar avatar) {
327: // Search the avatarRoot for the ViewerAvatar associated with
328: // with the Viewer object
329: for (int i = 0; i < avatarRoot.numChildren(); i++) {
330: if (((ViewerAvatar) avatarRoot.getChild(i)) == avatar)
331: return i;
332: }
333:
334: // Should never get here.
335: System.err
336: .println("ViewingPlatform.findAvatarChild:Child not found.");
337: return -1;
338: }
339:
340: /**
341: * Adds the ViewerAvatar to the scene graph. An avatar (geometry)
342: * can be associated with a Viewer object and displayed by Java 3D.
343: *
344: * @param viewer The viewer object to associate with this avatar.
345: * @param avatar The avatar to add to the scene graph. Passing in
346: * null removes any currently assigned avatar.
347: */
348: void setAvatar(Viewer viewer, ViewerAvatar avatar) {
349: Object oldAvatar = viewerList.get(viewer);
350:
351: // A position of -1 means the avatar is not a child of the avatarRoot.
352: int avatarPosition = -1;
353:
354: // Because "null" cannot be used in a put the avatarRoot object
355: // is used to signify that there is no ViewerAvatar associated
356: // with this Viewer.
357: if (oldAvatar != avatarRoot)
358: avatarPosition = findAvatarChild((ViewerAvatar) oldAvatar);
359:
360: // If the avatar is null, will be removing any geometry already present.
361: if (avatar == null) {
362: if (avatarPosition != -1) {
363: avatarRoot.removeChild(avatarPosition);
364:
365: // Reset hashtable entry - avatarRoot == null.
366: viewerList.put(viewer, avatarRoot);
367: }
368: } else {
369: // see if there is an old ViewerAvater to replace
370: if (avatarPosition != -1)
371: avatarRoot.setChild(avatar, avatarPosition);
372: else
373: avatarRoot.addChild(avatar);
374:
375: // Update hashtable with new avatar.
376: viewerList.put(viewer, avatar);
377: }
378: }
379:
380: /**
381: * When a ViewingPlatform is set by a Viewer, the ViewingPlatform
382: * needs to be informed, via a call to this method. This will add
383: * the Viewer to the ViewingPlatform's viewerList for use when
384: * things such as the PlatformGeometry are changed and all Viewer
385: * scene graphs need to be modified.
386: */
387: void addViewer(Viewer viewer) {
388: // Because the viewerList is also used to associate ViewerAvatars
389: // with Viewer objects a hashtable is used. This routine does not
390: // check for the presence of a ViewerAvatar but the Viewer still
391: // needs to be added to the hashtable. Because "null" cannot be
392: // used in a put the avatarRoot object is used to signify that there
393: // is no ViewerAvatar associated with this Viewer.
394: viewerList.put(viewer, avatarRoot);
395: }
396:
397: /*
398: * Cleanup when Viewer set another ViewingPlatform
399: */
400: void removeViewer(Viewer viewer) {
401: viewerList.remove(viewer);
402: }
403:
404: /**
405: * Adds a new ViewPlatformBehavior to the ViewingPlatform
406: */
407: void addViewPlatformBehavior(ViewPlatformBehavior behavior) {
408: behavior.setViewingPlatform(this );
409: if (behaviors == null) {
410: behaviors = new BranchGroup();
411: behaviors.setCapability(BranchGroup.ALLOW_DETACH);
412: behaviors.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
413: }
414: // otherwise detach the BranchGroup so we can add to it
415: else {
416: behaviors.detach();
417: }
418: behaviors.addChild(behavior);
419: this .addChild(behaviors);
420: }
421:
422: /**
423: * Sets the ViewPlatformBehavior which will operate on the ViewPlatform
424: * transform (the TransformGroup returned by
425: * ViewingPlatform.getViewPlatformTransform()). The ViewPlatformBehavior
426: * may be set after the ViewingPlatform is setLive().
427: * If a behavior is already present, it will be detached and it's
428: * setViewingPlatform method will be called with a parameter of null.
429: * @param behavior The ViewPlatformBehavior to add to the ViewingPlatform.
430: * null will remove the ViewingPlatform behavior.
431: * @since Java 3D 1.2.1
432: */
433: public void setViewPlatformBehavior(ViewPlatformBehavior behavior) {
434: if (behaviors != null) {
435: removeViewPlatformBehavior((ViewPlatformBehavior) behaviors
436: .getChild(0));
437: }
438: if (behavior != null) {
439: addViewPlatformBehavior(behavior);
440: }
441: }
442:
443: /**
444: * Removes the specified ViewPlatformBehavior
445: */
446: void removeViewPlatformBehavior(ViewPlatformBehavior behavior) {
447: // remove from the behaviors branch group
448: if (behaviors != null) {
449: behaviors.detach();
450: for (int i = 0; i < behaviors.numChildren(); i++) {
451: if (behaviors.getChild(i) == behavior) {
452: behavior.setViewingPlatform(null);
453: behaviors.removeChild(i);
454: break;
455: }
456: }
457: if (behaviors.numChildren() == 0)
458: behaviors = null;
459: else
460: this .addChild(behaviors);
461: }
462: }
463:
464: /**
465: * Returns the number of ViewPlatformBehaviors on the ViewingPlatform
466: */
467: int getViewPlatformBehaviorCount() {
468: return behaviors.numChildren();
469: }
470:
471: /**
472: * Returns the ViewPlatformBehavior at the specified index
473: */
474: ViewPlatformBehavior getViewPlatformBehavior(int index) {
475: return (ViewPlatformBehavior) behaviors.getChild(index);
476: }
477:
478: /**
479: * Returns the ViewPlatformBehavior
480: * @return the ViewPlatformBehavior for the ViewingPlatform.
481: * Returns null if there is no ViewPlatformBehavior set.
482: * @since Java 3D 1.2.1
483: */
484: public ViewPlatformBehavior getViewPlatformBehavior() {
485: if (behaviors == null) {
486: return null;
487: }
488: return getViewPlatformBehavior(0);
489: }
490:
491: /**
492: * Returns the Viewers attached to this ViewingPlatform
493: *
494: * @return the Viewers attached to this viewing platform
495: * @since Java 3D 1.3
496: */
497: public Viewer[] getViewers() {
498: if (viewerList.size() == 0)
499: return null;
500: return (Viewer[]) viewerList.keySet().toArray(new Viewer[0]);
501: }
502:
503: /**
504: * Returns the Universe to which this ViewingPlatform is attached
505: *
506: * @return the Universe to which this ViewingPlatform is attached
507: * @since Java 3D 1.3
508: */
509: public SimpleUniverse getUniverse() {
510: return universe;
511: }
512:
513: /**
514: * Sets the Universe to which this ViewingPlatform is attached
515: *
516: * @param universe the Universe to which this ViewingPlatform is attached
517: * @since Java 3D 1.3
518: */
519: public void setUniverse(SimpleUniverse universe) {
520: this.universe = universe;
521: }
522: }
|