com.sun.j3d.utils.universe.Viewer Maven / Gradle / Ivy
Show all versions of java3d-core Show documentation
/*
* Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any
* kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
* WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
* EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
* NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
* USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
* ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
* CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
* REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
* INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or
* intended for use in the design, construction, operation or
* maintenance of any nuclear facility.
*
*/
package com.sun.j3d.utils.universe;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Frame;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Panel;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.lang.reflect.Constructor;
import java.net.URL;
import javax.media.j3d.AudioDevice;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.GraphicsConfigTemplate3D;
import javax.media.j3d.PhysicalBody;
import javax.media.j3d.PhysicalEnvironment;
import javax.media.j3d.Screen3D;
import javax.media.j3d.Transform3D;
import javax.media.j3d.View;
import javax.swing.JFrame;
import javax.swing.JPanel;
import com.sun.j3d.audioengines.AudioEngine3DL2;
/**
* The Viewer class holds all the information that describes the physical
* and virtual "presence" in the Java 3D universe. The Viewer object
* consists of:
*
* - Physical Objects
*
* - Canvas3D's - used to render with.
* - PhysicalEnvironment - holds characteristics of the hardware platform
* being used to render on.
* - PhysicalBody - holds the physical characteristics and personal
* preferences of the person who will be viewing the Java 3D universe.
*
* - Virtual Objects
*
* - View - the Java 3D View object.
* - ViewerAvatar - the geometry that is used by Java 3D to represent the
* person viewing the Java 3D universe.
*
*
* If the Viewer object is created without any Canvas3D's, or indirectly
* through a configuration file, it will create the Canvas3D's as needed.
* The default Viewer creates one Canvas3D. If the Viewer object creates
* the Canvas3D's, it will also create a JPanel and JFrame for each Canvas3D.
*
* Dynamic video resize is a new feature in Java 3D 1.3.1.
* This feature provides a means for doing swap synchronous resizing
* of the area that is to be magnified (or passed through) to the
* output video resolution. This functionality allows an application
* to draw into a smaller viewport in the framebuffer in order to reduce
* the time spent doing pixel fill. The reduced size viewport is then
* magnified up to the video output resolution using the SUN_video_resize
* extension. This extension is only implemented in XVR-4000 and later
* hardware with back end video out resizing capability.
*
* If video size compensation is enable, the line widths, point sizes and pixel
* operations will be scaled internally with the resize factor to approximately
* compensate for video resizing. The location of the pixel ( x, y ) in the
* resized framebuffer = ( floor( x * factor + 0.5 ), floor( y * factor + 0.5 ) )
*
*
* @see Canvas3D
* @see PhysicalEnvironment
* @see PhysicalBody
* @see View
* @see ViewerAvatar
*/
public class Viewer {
private static final boolean debug = false;
private static PhysicalBody physicalBody = null;
private static PhysicalEnvironment physicalEnvironment = null;
private View view = null;
private ViewerAvatar avatar = null;
private Canvas3D[] canvases = null;
private JFrame[] j3dJFrames = null;
private JPanel[] j3dJPanels = null;
private Window[] j3dWindows = null;
private ViewingPlatform viewingPlatform = null;
/**
* Creates a default viewer object. The default values are used to create
* the PhysicalBody and PhysicalEnvironment. A single RGB, double buffered
* and depth buffered Canvas3D object is created. The View is created
* with a front clip distance of 0.1f and a back clip distance of 10.0f.
*/
public Viewer() {
// Call main constructor with default values.
this(null, null, null, true);
}
/**
* Creates a default viewer object. The default values are used to create
* the PhysicalBody and PhysicalEnvironment. The View is created
* with a front clip distance of 0.1f and a back clip distance of 10.0f.
*
* @param userCanvas the Canvas3D object to be used for rendering;
* if this is null then a single RGB, double buffered and depth buffered
* Canvas3D object is created
* @since Java3D 1.1
*/
public Viewer(Canvas3D userCanvas) {
// Call main constructor.
this(userCanvas == null ? null : new Canvas3D[] {userCanvas},
null, null, true);
}
/**
* Creates a default viewer object. The default values are used to create
* the PhysicalBody and PhysicalEnvironment. The View is created
* with a front clip distance of 0.1f and a back clip distance of 10.0f.
*
* @param userCanvases the Canvas3D objects to be used for rendering;
* if this is null then a single RGB, double buffered and depth buffered
* Canvas3D object is created
* @since Java3D 1.3
*/
public Viewer(Canvas3D[] userCanvases) {
this(userCanvases, null, null, true);
}
/**
* Creates a viewer object. The Canvas3D objects, PhysicalEnvironment, and
* PhysicalBody are taken from the arguments.
*
* @param userCanvases the Canvas3D objects to be used for rendering;
* if this is null then a single RGB, double buffered and depth buffered
* Canvas3D object is created
* @param userBody the PhysicalBody to use for this Viewer; if it is
* null, a default PhysicalBody object is created
* @param userEnvironment the PhysicalEnvironment to use for this Viewer;
* if it is null, a default PhysicalEnvironment object is created
* @param setVisible determines if the Frames should be set to visible once created
* @since Java3D 1.3
*/
public Viewer(Canvas3D[] userCanvases, PhysicalBody userBody,
PhysicalEnvironment userEnvironment, boolean setVisible ) {
if (userBody == null) {
physicalBody = new PhysicalBody();
} else {
physicalBody = userBody;
}
if (userEnvironment == null) {
physicalEnvironment = new PhysicalEnvironment();
} else {
physicalEnvironment = userEnvironment;
}
// Create Canvas3D object if none was passed in.
if (userCanvases == null) {
GraphicsConfiguration config =
ConfiguredUniverse.getPreferredConfiguration();
canvases = new Canvas3D[1];
canvases[0] = new Canvas3D(config);
canvases[0].setFocusable(true);
createFramesAndPanels(setVisible);
}
else {
canvases = new Canvas3D[userCanvases.length];
for (int i=0; i= devices.length)
throw new ArrayIndexOutOfBoundsException(
cs[i].errorMessage(cs[i].creatingCommand,
"Screen " + cs[i].frameBufferNumber + " is invalid; " +
(devices.length-1) + " is the maximum local index."));
Rectangle bounds;
Container contentPane;
GraphicsConfiguration cfg =
devices[cs[i].frameBufferNumber].getBestConfiguration(tpl3D);
if (cfg == null)
throw new RuntimeException(
"No GraphicsConfiguration on screen " +
cs[i].frameBufferNumber + " conforms to template");
// Workaround for Issue 316 - use the default config for the screen
GraphicsConfiguration defCfg = cfg.getDevice().getDefaultConfiguration();
bounds = defCfg.getBounds();
cs[i].j3dJFrame = j3dJFrames[i] =
new JFrame(cs[i].instanceName, defCfg);
if (cs[i].noBorderFullScreen) {
j3dJFrames[i].setUndecorated(true);
cs[i].j3dWindow = j3dWindows[i] = j3dJFrames[i];
contentPane = j3dJFrames[i].getContentPane();
contentPane.setLayout(new BorderLayout());
j3dWindows[i].setSize(bounds.width, bounds.height);
j3dWindows[i].setLocation(bounds.x, bounds.y);
}
else {
cs[i].j3dWindow = j3dWindows[i] = j3dJFrames[i];
contentPane = j3dJFrames[i].getContentPane();
contentPane.setLayout(new BorderLayout());
if (cs[i].fullScreen) {
j3dWindows[i].setSize(bounds.width, bounds.height);
j3dWindows[i].setLocation(bounds.x, bounds.y);
}
else {
j3dWindows[i].setSize(cs[i].windowWidthInPixels,
cs[i].windowHeightInPixels);
j3dWindows[i].setLocation(bounds.x + cs[i].windowX,
bounds.y + cs[i].windowY) ;
}
}
// Create a Canvas3D and set its attributes.
cs[i].j3dCanvas = canvases[i] = new Canvas3D(cfg);
canvases[i].setStereoEnable(cv.stereoEnable);
canvases[i].setMonoscopicViewPolicy(cs[i].monoscopicViewPolicy);
// Get the Screen3D and set its attributes.
Screen3D screen = canvases[i].getScreen3D();
if (cs[i].physicalScreenWidth != 0.0)
screen.setPhysicalScreenWidth(cs[i].physicalScreenWidth);
if (cs[i].physicalScreenHeight != 0.0)
screen.setPhysicalScreenHeight(cs[i].physicalScreenHeight);
if (cs[i].trackerBaseToImagePlate != null)
screen.setTrackerBaseToImagePlate
(new Transform3D(cs[i].trackerBaseToImagePlate));
if (cs[i].headTrackerToLeftImagePlate != null)
screen.setHeadTrackerToLeftImagePlate
(new Transform3D(cs[i].headTrackerToLeftImagePlate));
if (cs[i].headTrackerToRightImagePlate != null)
screen.setHeadTrackerToRightImagePlate
(new Transform3D(cs[i].headTrackerToRightImagePlate));
// Put the Canvas3D into a JPanel.
cs[i].j3dJPanel = j3dJPanels[i] = new JPanel();
j3dJPanels[i].setLayout(new BorderLayout());
j3dJPanels[i].add("Center", canvases[i]);
// Put the JPanel into the content pane used by JWindow or JFrame.
contentPane.add("Center", j3dJPanels[i]);
// Attach the Canvas3D to the View.
view.addCanvas3D(canvases[i]);
// Add a windowListener to detect the window close event.
addWindowCloseListener(j3dWindows[i]);
canvases[i].setFocusable(true);
if (debug) {
System.out.println("Viewer: created Canvas3D for screen " +
cs[i].frameBufferNumber + " with size\n " +
j3dWindows[i].getSize());
System.out.println("Screen3D[" + i + "]: size in pixels (" +
screen.getSize().width + " x " +
screen.getSize().height + ")");
System.out.println(" physical size in meters: (" +
screen.getPhysicalScreenWidth() + " x " +
screen.getPhysicalScreenHeight() + ")");
System.out.println(" hashCode = " + screen.hashCode() + "\n");
}
}
if (setVisible)
// Call setVisible() on all created Window components.
setVisible(true);
}
// Create the JFrames and JPanels for application-supplied Canvas3D
// objects.
private void createFramesAndPanels( boolean setVisible ) {
j3dJFrames = new JFrame[canvases.length];
j3dJPanels = new JPanel[canvases.length];
j3dWindows = new Window[canvases.length];
for (int i = 0; i < canvases.length; i++) {
j3dWindows[i] = j3dJFrames[i] = new JFrame();
j3dJFrames[i].getContentPane().setLayout(new BorderLayout());
j3dJFrames[i].setSize(256, 256);
// Put the Canvas3D into a JPanel.
j3dJPanels[i] = new JPanel();
j3dJPanels[i].setLayout(new BorderLayout());
j3dJPanels[i].add("Center", canvases[i]);
j3dJFrames[i].getContentPane().add("Center", j3dJPanels[i]);
if (setVisible) {
j3dJFrames[i].setVisible(true);
}
addWindowCloseListener(j3dJFrames[i]);
}
}
/**
* Call setVisible() on all Window components created by this Viewer.
*
* @param visible boolean to be passed to the setVisible() calls on the
* Window components created by this Viewer
* @since Java3D 1.3
*/
public void setVisible(boolean visible) {
for (int i = 0; i < j3dWindows.length; i++) {
j3dWindows[i].setVisible(visible);
}
}
/**
* Returns the View object associated with the Viewer object.
*
* @return The View object of this Viewer.
*/
public View getView() {
return view;
}
/**
* Set the ViewingPlatform object used by this Viewer.
*
* @param platform The ViewingPlatform object to set for this
* Viewer object. Use null to unset the current value and
* not assign assign a new ViewingPlatform object.
*/
public void setViewingPlatform(ViewingPlatform platform) {
if (viewingPlatform != null) {
viewingPlatform.removeViewer(this);
}
viewingPlatform = platform;
if (platform != null) {
view.attachViewPlatform(platform.getViewPlatform());
platform.addViewer(this);
if (avatar != null)
viewingPlatform.setAvatar(this, avatar);
}
else
view.attachViewPlatform(null);
}
/**
* Get the ViewingPlatform object used by this Viewer.
*
* @return The ViewingPlatform object used by this
* Viewer object.
*/
public ViewingPlatform getViewingPlatform() {
return viewingPlatform;
}
/**
* Sets the geometry to be associated with the viewer's avatar. The
* avatar is the geometry used to represent the viewer in the virtual
* world.
*
* @param avatar The geometry to associate with this Viewer object.
* Passing in null will cause any geometry associated with the Viewer
* to be removed from the scen graph.
*/
public void setAvatar(ViewerAvatar avatar) {
// Just return if trying to set the same ViewerAvatar object.
if (this.avatar == avatar)
return;
this.avatar = avatar;
if (viewingPlatform != null)
viewingPlatform.setAvatar(this, this.avatar);
}
/**
* Gets the geometry associated with the viewer's avatar. The
* avatar is the geometry used to represent the viewer in the virtual
* world.
*
* @return The root of the scene graph that is used to represent the
* viewer's avatar.
*/
public ViewerAvatar getAvatar() {
return avatar;
}
/**
* Returns the PhysicalBody object associated with the Viewer object.
*
* @return A reference to the PhysicalBody object.
*/
public PhysicalBody getPhysicalBody() {
return physicalBody;
}
/**
* Returns the PhysicalEnvironment object associated with the Viewer
* object.
*
* @return A reference to the PhysicalEnvironment object.
*/
public PhysicalEnvironment getPhysicalEnvironment() {
return physicalEnvironment;
}
/**
* Returns the 0th Canvas3D object associated with this Viewer object
*
* @return a reference to the 0th Canvas3D object associated with this
* Viewer object
* @since Java3D 1.3
*/
public Canvas3D getCanvas3D() {
return canvases[0];
}
/**
* Returns the Canvas3D object at the specified index associated with
* this Viewer object.
*
* @param canvasNum the index of the Canvas3D object to retrieve;
* if there is no Canvas3D object for the given index, null is returned
* @return a reference to a Canvas3D object associated with this
* Viewer object
* @since Java3D 1.3
*/
public Canvas3D getCanvas3D(int canvasNum) {
if (canvasNum > canvases.length) {
return null;
}
return canvases[canvasNum];
}
/**
* Returns all the Canvas3D objects associated with this Viewer object.
*
* @return an array of references to the Canvas3D objects associated with
* this Viewer object
* @since Java3D 1.3
*/
public Canvas3D[] getCanvas3Ds() {
Canvas3D[] ret = new Canvas3D[canvases.length];
for (int i = 0; i < canvases.length; i++) {
ret[i] = canvases[i];
}
return ret;
}
/**
* Returns the canvas associated with this Viewer object.
* @deprecated superceded by getCanvas3D()
*/
public Canvas3D getCanvases() {
return getCanvas3D();
}
/**
* This method is no longer supported since Java 3D 1.3.
* @exception UnsupportedOperationException if called.
* @deprecated AWT Frame components are no longer created by the
* Viewer class.
*/
public Frame getFrame() {
throw new UnsupportedOperationException(
"AWT Frame components are not created by the Viewer class");
}
/**
* Returns the JFrame object created by this Viewer object at the
* specified index. If a Viewer is constructed without any Canvas3D
* objects then the Viewer object will create a Canva3D object, a JPanel
* containing the Canvas3D object, and a JFrame to place the JPanel in.
*
* NOTE: When running under JDK 1.4 or newer, the JFrame always directly
* contains the JPanel which contains the Canvas3D. When running under
* JDK 1.3.1 and creating a borderless full screen through a configuration
* file, the JFrame will instead contain a JWindow which will contain the
* JPanel and Canvas3D.
*
* @param frameNum the index of the JFrame object to retrieve;
* if there is no JFrame object for the given index, null is returned
* @return a reference to JFrame object created by this Viewer object
* @since Java3D 1.3
*/
public JFrame getJFrame(int frameNum) {
if (j3dJFrames == null || frameNum > j3dJFrames.length) {
return(null);
}
return j3dJFrames[frameNum];
}
/**
* Returns all the JFrames created by this Viewer object. If a Viewer is
* constructed without any Canvas3D objects then the Viewer object will
* create a Canva3D object, a JPanel containing the Canvas3D object, and a
* JFrame to place the JPanel in.
*
* NOTE: When running under JDK 1.4 or newer, the JFrame always directly
* contains the JPanel which contains the Canvas3D. When running under
* JDK 1.3.1 and creating a borderless full screen through a configuration
* file, the JFrame will instead contain a JWindow which will contain the
* JPanel and Canvas3D.
*
* @return an array of references to the JFrame objects created by
* this Viewer object, or null if no JFrame objects were created
* @since Java3D 1.3
*/
public JFrame[] getJFrames() {
if (j3dJFrames == null)
return null;
JFrame[] ret = new JFrame[j3dJFrames.length];
for (int i = 0; i < j3dJFrames.length; i++) {
ret[i] = j3dJFrames[i];
}
return ret;
}
/**
* This method is no longer supported since Java 3D 1.3.
* @exception UnsupportedOperationException if called.
* @deprecated AWT Panel components are no longer created by the
* Viewer class.
*/
public Panel getPanel() {
throw new UnsupportedOperationException(
"AWT Panel components are not created by the Viewer class");
}
/**
* Returns the JPanel object created by this Viewer object at the
* specified index. If a Viewer is constructed without any Canvas3D
* objects then the Viewer object will create a Canva3D object and a
* JPanel into which to place the Canvas3D object.
*
* @param panelNum the index of the JPanel object to retrieve;
* if there is no JPanel object for the given index, null is returned
* @return a reference to a JPanel object created by this Viewer object
* @since Java3D 1.3
*/
public JPanel getJPanel(int panelNum) {
if (j3dJPanels == null || panelNum > j3dJPanels.length) {
return(null);
}
return j3dJPanels[panelNum];
}
/**
* Returns all the JPanel objects created by this Viewer object. If a
* Viewer is constructed without any Canvas3D objects then the Viewer
* object will create a Canva3D object and a JPanel into which to place
* the Canvas3D object.
*
* @return an array of references to the JPanel objects created by
* this Viewer object, or null or no JPanel objects were created
* @since Java3D 1.3
*/
public JPanel[] getJPanels() {
if (j3dJPanels == null)
return null;
JPanel[] ret = new JPanel[j3dJPanels.length];
for (int i = 0; i < j3dJPanels.length; i++) {
ret[i] = j3dJPanels[i];
}
return ret;
}
/**
* Used to create and initialize a default AudioDevice3D used for sound
* rendering.
*
* @return reference to created AudioDevice, or null if error occurs.
*/
public AudioDevice createAudioDevice() {
if (physicalEnvironment == null) {
System.err.println("Java 3D: createAudioDevice: physicalEnvironment is null");
return null;
}
try {
String audioDeviceClassName =
(String) java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
@Override
public Object run() {
return System.getProperty("j3d.audiodevice");
}
});
if (audioDeviceClassName == null) {
throw new UnsupportedOperationException("No AudioDevice specified");
}
// Issue 341: try the current class loader first before trying the
// system class loader
Class audioDeviceClass = null;
try {
audioDeviceClass = Class.forName(audioDeviceClassName);
} catch (ClassNotFoundException ex) {
// Ignore excpetion and try system class loader
}
if (audioDeviceClass == null) {
ClassLoader audioDeviceClassLoader =
(ClassLoader) java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
@Override
public Object run() {
return ClassLoader.getSystemClassLoader();
}
});
if (audioDeviceClassLoader == null) {
throw new IllegalStateException("System ClassLoader is null");
}
audioDeviceClass = Class.forName(audioDeviceClassName, true, audioDeviceClassLoader);
}
Class physEnvClass = PhysicalEnvironment.class;
Constructor audioDeviceConstructor =
audioDeviceClass.getConstructor(new Class[] {physEnvClass});
PhysicalEnvironment[] args = new PhysicalEnvironment[] { physicalEnvironment };
AudioEngine3DL2 mixer =
(AudioEngine3DL2) audioDeviceConstructor.newInstance((Object[])args);
mixer.initialize();
return mixer;
}
catch (Throwable e) {
e.printStackTrace();
physicalEnvironment.setAudioDevice(null);
System.err.println("Java 3D: audio is disabled");
return null;
}
}
/**
* Returns the Universe to which this Viewer is attached
*
* @return the Universe to which this Viewer is attached
* @since Java 3D 1.3
*/
public SimpleUniverse getUniverse() {
return getViewingPlatform().getUniverse();
}
/*
* Exit if run as an application
*/
void addWindowCloseListener(Window win) {
SecurityManager sm = System.getSecurityManager();
boolean doExit = true;
if (sm != null) {
try {
sm.checkExit(0);
} catch (SecurityException e) {
doExit = false;
}
}
final boolean _doExit = doExit;
win.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent winEvent) {
Window w = winEvent.getWindow();
w.setVisible(false);
try {
w.dispose();
} catch (IllegalStateException e) {}
if (_doExit) {
System.exit(0);
}
}
});
}
}