001: /*
002: * $RCSfile: Screen3D.java,v $
003: *
004: * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
006: *
007: * This code is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License version 2 only, as
009: * published by the Free Software Foundation. Sun designates this
010: * particular file as subject to the "Classpath" exception as provided
011: * by Sun in the LICENSE file that accompanied this code.
012: *
013: * This code is distributed in the hope that it will be useful, but WITHOUT
014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: * version 2 for more details (a copy is included in the LICENSE file that
017: * accompanied this code).
018: *
019: * You should have received a copy of the GNU General Public License version
020: * 2 along with this work; if not, write to the Free Software Foundation,
021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
022: *
023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
024: * CA 95054 USA or visit www.sun.com if you need additional information or
025: * have any questions.
026: *
027: * $Revision: 1.8 $
028: * $Date: 2008/02/28 20:17:29 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import javax.vecmath.*;
035: import java.awt.*;
036: import java.util.ArrayList;
037: import java.util.Hashtable;
038:
039: /**
040: * The Screen3D Object contains all information about a particular screen.
041: * All Canvas3D objects on the same physical screen (display device)
042: * refer to the same Screen3D object. Note that Screen3D has no public
043: * constructors--it is obtained from the Canvas3D via the getScreen3D
044: * method.
045: * <p>
046: * Default values for Screen3D parameters are as follows:
047: * <ul>
048: * physical screen width : 0.0254/90.0 * screen width (in pixels)<br>
049: * physical screen height : 0.0254/90.0 * screen height (in pixels)<br>
050: * tracker base to image plate transform : identity<br>
051: * head tracker to left image plate transform : identity<br>
052: * head tracker to right image plate transform : identity<br>
053: * off-screen size : (0,0)<br>
054: * </ul>
055: * <P>
056: * <b>Offscreen Rendering</b><P>
057: * New for Java 3D 1.2, an off-screen rendering mode allows rendering
058: * to a memory image, which is possibly larger than the screen. The
059: * setSize and getSize methods are defined specifically for this
060: * mode. Note that the off-screen size, physical width, and physical height
061: * must be set prior to rendering
062: * to the associated off-screen canvas. Failure to do so will result
063: * in an exception.<P>
064: * <b>Calibration Parameters</b><P>
065: * The Screen3D object must be calibrated with the coexistence volume.
066: * The Screen3D class provides several methods for defining the
067: * calibration parameters.<P>
068: * <UL>Measured Parameters<P>
069: * The screen's (image plate's) physical width and height (in meters)
070: * is set once, typically by a browser, calibration program, system
071: * administrator, or system calibrator, not by an applet. These values
072: * must be determined by measuring the display's active image width
073: * and height. In the case of a head-mounted display, this should be
074: * the display's apparent width and height at the focal plane. These
075: * values are defined by the setPhysicalScreenWidth and
076: * setPhysicalScreenHeight methods.<P>
077: *
078: * Head-tracker Coordinate System<P>
079: * If head tracking is enabled, one of two parameters need to be specified:<P>
080: * <UL><LI>If the view policy is SCREEN_VIEW, the tracker-base-to-image-plate
081: * coordinate system must be specified (setTrackerBaseToImagePlate method).
082: * This coordinate system must be recalibrated whenever the image
083: * plate moves relative to the tracker.</LI><P>
084: *
085: * <LI>If the view policy is HMD_VIEW, the head-tracker-to-left-image-plate
086: * and head-tracker-to-right-image-plate coordinate systems must be
087: * specified (setHeadTrackerToLeftImagePlate and
088: * setHeadTrackerToRightImagePlate methods).</LI><P></UL>
089: * </UL><P>
090: *
091: * <p>
092: * <b>Additional Information</b>
093: * <p>
094: * For more information, see the
095: * <a href="doc-files/intro.html">Introduction to the Java 3D API</a> and
096: * <a href="doc-files/ViewModel.html">View Model</a>
097: * documents.
098: *
099: * @see Canvas3D
100: * @see Canvas3D#getScreen3D
101: */
102:
103: public class Screen3D extends Object {
104: private static final boolean debug = false;
105:
106: // Assume a default of 90 DPI: 90 pix/inch = 1/90 inch/pix =
107: // 0.0254/90 meter/pix
108: private static final double METERS_PER_PIXEL = 0.0254 / 90.0;
109:
110: // GraphicsDevice associated with this Screen3D object. Note that
111: // all on-screen Canvas3D objects that are created on the same
112: // GraphicsDevice will share the same Screen3D.
113: GraphicsDevice graphicsDevice;
114:
115: // Flag indicating whether this Screen3D is associated with
116: // an off-screen Canvas3D or with one or more on-screen Canvas3Ds
117: boolean offScreen;
118:
119: // The display connection (native OGL pipeline on X11 only)
120: long display;
121:
122: // Screen number
123: int screen;
124:
125: // The width and height of the screen in meters.
126: double physicalScreenWidth;
127: double physicalScreenHeight;
128:
129: // Screen size in pixels
130: Dimension screenSize = new Dimension(0, 0);
131:
132: //
133: // Tracker-base coordinate system to image-plate coordinate
134: // system transform. This transform
135: // is typically a calibration constant.
136: // This is used only in SCREEN_VIEW mode.
137: //
138: Transform3D trackerBaseToImagePlate = new Transform3D();
139:
140: //
141: // Head-tracker coordinate system to left and right image-plate
142: // coordinate system transforms. These transforms are typically
143: // calibration constants. These are used only in HMD_VIEW mode.
144: //
145: Transform3D headTrackerToLeftImagePlate = new Transform3D();
146: Transform3D headTrackerToRightImagePlate = new Transform3D();
147:
148: // Physical screen size related field has changed.
149: static final int PHYSICAL_SCREEN_SIZE_DIRTY = 0x01;
150: // Screen size field has changed.
151: static final int SCREEN_SIZE_DIRTY_DIRTY = 0x02;
152: // Tracker base to image plate field has changed.
153: static final int TRACKER_BASE_TO_IMAGE_PLATE_DIRTY = 0x04;
154: // Head tracker to image plate field has changed.
155: static final int HEAD_TRACKER_TO_IMAGE_PLATE_DIRTY = 0x08;
156:
157: // Mask that indicates this Screen3D view dependence info. has changed,
158: // and CanvasViewCache may need to recompute the final view matries.
159: int scrDirtyMask = (PHYSICAL_SCREEN_SIZE_DIRTY
160: | SCREEN_SIZE_DIRTY_DIRTY
161: | TRACKER_BASE_TO_IMAGE_PLATE_DIRTY | HEAD_TRACKER_TO_IMAGE_PLATE_DIRTY);
162:
163: //
164: // View cache for this screen
165: //
166: ScreenViewCache screenViewCache = null;
167:
168: // The renderer for this screen
169: Renderer renderer = null;
170:
171: // Hashtable that maps a GraphicsDevice to its associated renderer
172: static Hashtable deviceRendererMap = new Hashtable();
173:
174: // A count of the number of canvases associated with this screen
175: int canvasCount = 0;
176:
177: // A count of the number of active View associated with this screen
178: UnorderList activeViews = new UnorderList(1, View.class);
179:
180: // A list of Canvas3D Objects that refer to this
181: ArrayList users = new ArrayList();
182:
183: void addActiveView(View v) {
184: activeViews.addUnique(v);
185: }
186:
187: void removeActiveView(View v) {
188: activeViews.remove(v);
189: }
190:
191: boolean activeViewEmpty() {
192: return activeViews.isEmpty();
193: }
194:
195: // Add a user to the list of users
196: synchronized void removeUser(Canvas3D c) {
197: int idx = users.indexOf(c);
198: if (idx >= 0) {
199: users.remove(idx);
200: }
201: }
202:
203: // Add a user to the list of users
204: synchronized void addUser(Canvas3D c) {
205: int idx = users.indexOf(c);
206: if (idx < 0) {
207: users.add(c);
208: }
209: }
210:
211: // Add a user to the list of users
212: synchronized void notifyUsers() {
213: int i;
214: Canvas3D c;
215:
216: for (i = 0; i < users.size(); i++) {
217: c = (Canvas3D) users.get(i);
218: c.redraw();
219: }
220: }
221:
222: /**
223: * Retrieves the width and height (in pixels) of this Screen3D.
224: *
225: * @return a new Dimension object containing the width and height
226: * of this Screen3D.
227: */
228: public Dimension getSize() {
229: return new Dimension(screenSize);
230: }
231:
232: /**
233: * Retrieves the width and height (in pixels) of this Screen3D
234: * and copies it into the specified Dimension object.
235: *
236: * @param rv Dimension object into which the size of
237: * this Screen3D is copied.
238: * If <code>rv</code> is null, a new Dimension object is allocated.
239: *
240: * @return <code>rv</code>
241: *
242: * @since Java 3D 1.2
243: */
244: public Dimension getSize(Dimension rv) {
245: if (rv == null) {
246: return new Dimension(screenSize);
247: } else {
248: rv.setSize(screenSize);
249: return rv;
250: }
251: }
252:
253: /**
254: * Sets the width and height (in pixels) of this off-screen Screen3D.
255: * The default size for off-screen Screen3D objects is (0,0).
256: * <br>
257: * NOTE: the size must be
258: * set prior to rendering to the associated off-screen canvas.
259: * Failure to do so will result in an exception.
260: *
261: * @param width the new width of this Screen3D object
262: * @param height the new height of this Screen3D object
263: *
264: * @exception IllegalStateException if this Screen3D is not in
265: * off-screen mode.
266: *
267: * @since Java 3D 1.2
268: */
269: public void setSize(int width, int height) {
270:
271: if (!offScreen)
272: throw new IllegalStateException(J3dI18N
273: .getString("Screen3D1"));
274:
275: synchronized (this ) {
276: screenSize.width = width;
277: screenSize.height = height;
278: scrDirtyMask |= SCREEN_SIZE_DIRTY_DIRTY;
279: }
280: }
281:
282: /**
283: * Sets the width and height (in pixels) of this off-screen Screen3D.
284: * The default size for off-screen Screen3D objects is (0,0).
285: * <br>
286: * NOTE: the size must be
287: * set prior to rendering to the associated off-screen canvas.
288: * Failure to do so will result in an exception.
289: *
290: * @param d the new dimension of this Screen3D object
291: *
292: * @exception IllegalStateException if this Screen3D is not in
293: * off-screen mode.
294: *
295: * @since Java 3D 1.2
296: */
297: public void setSize(Dimension d) {
298: if (!offScreen)
299: throw new IllegalStateException(J3dI18N
300: .getString("Screen3D1"));
301:
302: synchronized (this ) {
303: screenSize.width = d.width;
304: screenSize.height = d.height;
305: scrDirtyMask |= SCREEN_SIZE_DIRTY_DIRTY;
306: }
307: }
308:
309: /**
310: * Sets the screen physical width in meters. In the case of a
311: * head-mounted display, this should be the apparent width
312: * at the focal plane.
313: * @param width the screen's physical width in meters
314: */
315: public void setPhysicalScreenWidth(double width) {
316: synchronized (this ) {
317: physicalScreenWidth = width;
318: scrDirtyMask |= PHYSICAL_SCREEN_SIZE_DIRTY;
319: }
320: notifyUsers();
321: }
322:
323: /**
324: * Retrieves the screen's physical width in meters.
325: * @return the screen's physical width in meters
326: */
327: public double getPhysicalScreenWidth() {
328: return physicalScreenWidth;
329: }
330:
331: /**
332: * Sets the screen physical height in meters. In the case of a
333: * head-mounted display, this should be the apparent height
334: * at the focal plane.
335: * @param height the screen's physical height in meters
336: */
337: public void setPhysicalScreenHeight(double height) {
338: synchronized (this ) {
339: physicalScreenHeight = height;
340: scrDirtyMask |= PHYSICAL_SCREEN_SIZE_DIRTY;
341: }
342: notifyUsers();
343: }
344:
345: /**
346: * Retrieves the the screen's physical height in meters.
347: * @return the screen's physical height in meters
348: */
349: public double getPhysicalScreenHeight() {
350: return physicalScreenHeight;
351: }
352:
353: public String toString() {
354: return "Screen3D: size = " + "(" + getSize().width + " x "
355: + getSize().height + ")" + ", physical size = " + "("
356: + getPhysicalScreenWidth() + "m x "
357: + getPhysicalScreenHeight() + "m)";
358: }
359:
360: // Static initializer for Screen3D class
361: static {
362: VirtualUniverse.loadLibraries();
363: }
364:
365: /**
366: * Construct a new Screen3D object with the specified size in pixels.
367: * Note that currently, there is no AWT equivalent of screen so Java 3D
368: * users need to get this through the Canvas3D object (via getScreen()) if
369: * they need it.
370: * @param graphicsConfiguration the AWT graphics configuration associated
371: * with this Screen3D
372: * @param offScreen a flag that indicates whether this Screen3D is
373: * associated with an off-screen Canvas3D
374: */
375: Screen3D(GraphicsConfiguration graphicsConfiguration,
376: boolean offScreen) {
377: this .offScreen = offScreen;
378: this .graphicsDevice = graphicsConfiguration.getDevice();
379:
380: screenViewCache = new ScreenViewCache(this );
381:
382: // Get the display handle and the screen number from the Pipeline
383: display = Pipeline.getPipeline().getDisplay();
384: screen = Pipeline.getPipeline().getScreen(graphicsDevice);
385:
386: if (debug)
387: System.err.println("Screen3D: display " + display
388: + " screen " + screen + " hashcode "
389: + this .hashCode());
390:
391: if (!offScreen) {
392: // Store the information in this screen object
393: Rectangle bounds = graphicsConfiguration.getBounds();
394: screenSize.width = bounds.width;
395: screenSize.height = bounds.height;
396: }
397:
398: // Set the default physical size based on size in pixels
399: physicalScreenWidth = screenSize.width * METERS_PER_PIXEL;
400: physicalScreenHeight = screenSize.height * METERS_PER_PIXEL;
401: }
402:
403: /**
404: * Sets the tracker-base coordinate system to image-plate coordinate
405: * system transform. This transform
406: * is typically a calibration constant.
407: * This is used only in SCREEN_VIEW mode.
408: * @param t the new transform
409: * @exception BadTransformException if the transform is not rigid
410: */
411: public void setTrackerBaseToImagePlate(Transform3D t) {
412: synchronized (this ) {
413: if (!t.isRigid()) {
414: throw new BadTransformException(J3dI18N
415: .getString("Screen3D0"));
416: }
417: trackerBaseToImagePlate.setWithLock(t);
418: scrDirtyMask |= Screen3D.TRACKER_BASE_TO_IMAGE_PLATE_DIRTY;
419: }
420: notifyUsers();
421: }
422:
423: /**
424: * Retrieves the tracker-base coordinate system to image-plate
425: * coordinate system transform and copies it into the specified
426: * Transform3D object.
427: * @param t the object that will receive the transform
428: */
429: public void getTrackerBaseToImagePlate(Transform3D t) {
430: t.set(trackerBaseToImagePlate);
431: }
432:
433: /**
434: * Sets the head-tracker coordinate system to left image-plate coordinate
435: * system transform. This transform
436: * is typically a calibration constant.
437: * This is used only in HMD_VIEW mode.
438: * @param t the new transform
439: * @exception BadTransformException if the transform is not rigid
440: */
441: public void setHeadTrackerToLeftImagePlate(Transform3D t) {
442: synchronized (this ) {
443: if (!t.isRigid()) {
444: throw new BadTransformException(J3dI18N
445: .getString("Screen3D0"));
446: }
447: headTrackerToLeftImagePlate.setWithLock(t);
448: scrDirtyMask |= Screen3D.HEAD_TRACKER_TO_IMAGE_PLATE_DIRTY;
449: }
450: notifyUsers();
451: }
452:
453: /**
454: * Retrieves the head-tracker coordinate system to left image-plate
455: * coordinate system transform and copies it into the specified
456: * Transform3D object.
457: * @param t the object that will receive the transform
458: */
459: public void getHeadTrackerToLeftImagePlate(Transform3D t) {
460: t.set(headTrackerToLeftImagePlate);
461: }
462:
463: /**
464: * Sets the head-tracker coordinate system to right image-plate coordinate
465: * system transform. This transform
466: * is typically a calibration constant.
467: * This is used only in HMD_VIEW mode.
468: * @param t the new transform
469: * @exception BadTransformException if the transform is not rigid
470: */
471: public void setHeadTrackerToRightImagePlate(Transform3D t) {
472: synchronized (this ) {
473: if (!t.isRigid()) {
474: throw new BadTransformException(J3dI18N
475: .getString("Screen3D0"));
476: }
477: headTrackerToRightImagePlate.setWithLock(t);
478: scrDirtyMask |= Screen3D.HEAD_TRACKER_TO_IMAGE_PLATE_DIRTY;
479: }
480: notifyUsers();
481: }
482:
483: /**
484: * Retrieves the head-tracker coordinate system to right image-plate
485: * coordinate system transform and copies it into the specified
486: * Transform3D object.
487: * @param t the object that will receive the transform
488: */
489: public void getHeadTrackerToRightImagePlate(Transform3D t) {
490: t.set(headTrackerToRightImagePlate);
491: }
492:
493: /**
494: * Update the view cache associated with this screen.
495: */
496: void updateViewCache() {
497: if (false)
498: System.err.println("Screen3D.updateViewCache()");
499: synchronized (this ) {
500: screenViewCache.snapshot();
501: }
502: }
503:
504: /**
505: * Increment canvas count, initialize renderer if needed
506: */
507: synchronized void incCanvasCount() {
508: canvasCount++;
509: }
510:
511: /**
512: * Decrement canvas count, kill renderer if needed
513: */
514: synchronized void decCanvasCount() {
515: canvasCount--;
516: }
517:
518: }
|