/*
* Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package javax.media.j3d;
import java.awt.AWTEvent;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Vector;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
/**
* The View object contains all parameters needed in rendering a
* three dimensional scene from one viewpoint. A view contains a list
* of Canvas3D objects that the view is rendered into. It exists outside
* of the scene graph, but attaches to a ViewPlatform leaf node object
* in the scene graph. It also contains a reference to a PhysicalBody
* and a PhysicalEnvironment object.
* <P>
* The View object is the main Java 3D object for controlling the
* Java 3D viewing model. All of the components that specify the
* view transform used to render to the 3D canvases are either contained
* in the View object or in objects that are referenced by the View
* object.
* <P>
* Java 3D allows applications to specify multiple simultaneously active
* View objects, each controlling its own set of canvases.
* <P>
* The Java 3D View object has several instance variables and methods,
* but most are calibration variables or user-helping functions. The
* viewing policies defined by the View object are described below.
* <P>
* <b>Policies</b><P>
*
* The View object defines the following policies:<P>
* <UL>
* <LI>View policy - informs Java 3D whether it should generate
* the view using the head-tracked system of transformations or the
* head-mounted system of transformations. These policies are attached
* to the Java 3D View object. There are two view policies:</LI><P>
* <UL>
* <LI>SCREEN_VIEW - specifies that Java 3D should compute a new
* viewpoint using the sequence of transforms appropriate to screen-based
* head-tracked display environments (fish-tank VR/portals/VR-desks).
* This is the default setting.</LI><P>
* <LI>HMD_VIEW - specifies that Java 3D should compute a new viewpoint
* using the sequence of transforms appropriate to head mounted display
* environments. This policy is not available in compatibility mode
* (see the setCompatibilityModeEnable method description).</LI><P>
* </UL>
* <LI>Projection policy - specifies whether Java 3D should generate
* a parallel projection or a perspective projection. This policy
* is attached to the Java 3D View object. There are two projection
* policies:</LI><P>
* <UL>
* <LI>PARALLEL_PROJECTION - specifies that a parallel projection
* transform is computed.</LI><P>
* <LI>PERSPECTIVE_PROJECTION - specifies that a perspective projection
* transform is computed. This is the default policy.</LI><P>
* </UL>
* <LI>Screen scale policy - specifies where the screen scale comes from.
* There are two screen scale policies:</LI><P>
* <UL>
* <LI>SCALE_SCREEN_SIZE - specifies that the scale is derived from the
* physical screen according to the following formula (this is the
* default mode):</LI>
* <UL>
* <code>screenScale = physicalScreenWidth / 2.0</code><P>
* </UL>
* <LI>SCALE_EXPLICIT - pecifies that the scale is taken directly from
* the user-provided <code>screenScale</code> attribute (see the
* setScreenScale method description).</LI><P>
* </UL>
* <LI>Window resize policy - specifies how Java 3D modifies the view
* when users resize windows. When users resize or move windows,
* Java 3D can choose to think of the window as attached either to
* the physical world or to the virtual world. The window resize
* policy allows an application to specify how the
* view model will handle resizing requests.
* There are two window resize policies:</LI><P>
* <UL>
* <LI>VIRTUAL_WORLD - implies that the original image remains the
* same size on the screen but the user sees more or less of the
* virtual world depending on whether the window grew or shrank
* in size.</LI><P>
* <LI>PHYSICAL_WORLD - implies that the original image continues
* to fill the window in the same way using more or less pixels
* depending on whether the window grew or shrank in size.</LI><P>
* </UL>
* <LI>Window movement policy - specifies what part of the virtual
* world Java 3D draws as a function of window placement on the screen.
* There are two window movement policies:</LI><P>
* <UL>
* <LI>VIRTUAL_WORLD - implies that the image seen in the window
* changes as the position of the window shifts on the screen.
* (This mode acts as if the window were a window into the virtual
* world.)</LI><P>
* <LI>PHYSICAL_WORLD - implies that the image seen in the window
* remains the same no matter where the user positions the window
* on the screen.</LI><P>
* </UL>
* <LI>Window eyepoint policy - comes into effect in a non-head-tracked
* environment. The policy tells Java 3D how to construct a new view
* frustum based on changes in the field of view and in the Canvas3D's
* location on the screen. The policy only comes into effect when the
* application changes a parameter that can change the placement of the
* eyepoint relative to the view frustum.
* There are three window eyepoint policies:</LI><P>
* <UL>
* <LI>RELATIVE_TO_SCREEN - tells Java 3D to interpret the eye's position
* relative to the entire screen. No matter where an end user moves a
* window (a Canvas3D), Java 3D continues to interpret the eye's position
* relative to the screen. This implies that the view frustum changes shape
* whenever an end user moves the location of a window on the screen.
* In this mode, the field of view is read-only.</LI><P>
* <LI>RELATIVE_TO_WINDOW - specifies that Java 3D should interpret the
* eye's position information relative to the window (Canvas3D). No matter
* where an end user moves a window (a Canvas3D), Java 3D continues to
* interpret the eye's position relative to that window. This implies
* that the frustum remains the same no matter where the end user
* moves the window on the screen. In this mode, the field of view
* is read-only.</LI><P>
* <LI>RELATIVE_TO_FIELD_OF_VIEW - tells Java 3D that it should
* modify the eyepoint position so it is located at the appropriate
* place relative to the window to match the specified field of view.
* This implies that the view frustum will change whenever the
* application changes the field of view. In this mode, the eye
* position is read-only. This is the default setting.</LI><P>
* <LI>RELATIVE_TO_COEXISTENCE - tells Java 3D to interpret the eye's
* position in coexistence coordinates. In this mode, the eye position
* is taken from the view (rather than the Canvas3D) and transformed from
* coexistence coordinates to image plate coordinates for each
* Canvas3D. The resulting eye position is relative to the screen. As
* in RELATIVE_TO_SCREEN mode, this implies that the view frustum
* changes shape whenever an end user moves the location of a window
* on the screen. In this mode, the field of view is
* read-only.</LI><P>
* </UL>
* <LI>Front and back clip policies - specifies how Java 3D
* interprets clipping distances to both the near and far clip
* planes. The policies can contain one of four values specifying
* whether a distance measurement should be interpreted in
* the physical or the virtual world and whether that distance
* measurement should be interpreted relative to the physical
* eyepoint or the physical screen.
* The front and back clip policies
* are specified separately. The front clip policy determines
* where Java 3D places the front clipping plane. The back clip
* policy determines where Java 3D places the back clipping plane.
* The values for both front and back clipping planes are:</LI><P>
* <UL>
* <LI>VIRTUAL_EYE - specifies that the associated distance is from
* the eye and in units of virtual distance.</LI><P>
* <LI>PHYSICAL_EYE - specifies that the associated distance is from
* the eye and in units of physical distance (in meters).
* This is the default policy for both front and back clipping.</LI><P>
* <LI>VIRTUAL_SCREEN - specifies that the associated distance is
* from the screen and in units of virtual distance. </LI><P>
* <LI>PHYSICAL_SCREEN - specifies that the associated distance is
* from the screen and in units of physical distance (in meters).
* </LI><P>
* </UL>
* <LI>Visibility policy - specifies how visible and invisible objects
* are drawn. There are three visibility policies:</LI><P>
* <UL>
* <LI>VISIBILITY_DRAW_VISIBLE - only visible objects are drawn
* (this is the default).</LI><P>
* <LI>VISIBILITY_DRAW_INVISIBLE - only invisible objects are drawn.</LI><P>
* <LI>VISIBILITY_DRAW_ALL - both visible and invisible
* objects are drawn. </LI><P>
* </UL>
* <LI>Transparency sorting policy - specifies whether and how
* transparent objects are sorted. Sorting multiple transparent
* objects is necessary to avoid artifacts caused by overlapping
* transparent objects. There are two transparency sorting
* policies:</LI><P>
* <UL>
* <LI>TRANSPARENCY_SORT_NONE - no depth sorting of transparent
* objects is performed (this is the default). Transparent objects
* are drawn after opaque objects, but are not sorted from back to
* front.</LI><P>
* <LI>TRANSPARENCY_SORT_GEOMETRY - transparent objects are
* depth-sorted on a per-geometry basis. Each geometry object of each
* transparent Shape3D node is drawn from back to front. Note that
* this policy will not split geometry into smaller pieces, so
* intersecting or intertwined objects may not be sorted
* correctly. The method used for determining which geometry is closer
* is implementation dependent.</LI><P>
* </UL>
* </UL>
* <b>Projection and Clip Parameters</b><P>
* The projection and clip parameters determine the view model's
* field of view and the front and back clipping distances.<P>
* <UL>
* <LI>Field of view - specifies the view model's horizontal
* field of view in radians, when in the default non-head-tracked
* mode. This value is ignored when the view model is operating
* in head-tracked mode, or when the Canvas3D's window eyepoint
* policy is set to a value other than the default setting of
* RELATIVE_TO_FIELD_OF_VIEW.</LI><P>
* <LI>Front clip distance - specifies the distance away from the
* clip origin, specified by the front clip policy variable, in
* the direction of gaze where objects stop disappearing. Objects
* closer than the clip origin (eye or screen)
* plus the front clip distance are not drawn. Measurements are
* done in the space (physical or virtual) that is specified by
* the associated front clip policy parameter.</LI><P>
* <LI>Back clip distance - specifies the distance away from the
* clip origin (specified by the back clip policy variable) in the
* direction of gaze where objects begin disappearing. Objects
* farther away from the clip origin (eye or
* screen) plus the back clip distance are not drawn.
* Measurements are done in the space (physical or virtual) that
* is specified by the associated back clip policy
* parameter. The View object's back clip distance is ignored
* if the scene graph contains an active Clip leaf node.</LI><P>
* There are several considerations to take into account when
* choosing values for the front and back clip distances.<P>
* <UL>
* <LI>The front clip distance must be greater than 0.0 in physical
* eye coordinates.</LI><P>
* <LI>The front clipping plane must be in front of the back clipping
* plane, that is, the front clip distance must be less than the
* back clip distance in physical eye coordinates.</LI><P>
* <LI>The front and back clip distances, in physical eye coordinates,
* must be less than the largest positive single-precision floating
* point value, Float.MAX_VALUE. In practice, since these physical
* eye coordinate distances are in meters, the values
* should be much less than that.</LI><P>
* <LI>The ratio of the back distance divided by the front distance,
* in physical eye coordinates, affects Z-buffer precision. This ratio
* should be less than about 3000 to accommodate 16-bit Z-buffers.
* Values of 100 to less than 1000 will produce better results.</LI><P>
* </UL>
* Violating any of the above rules will result in undefined behavior.
* In many cases, no picture will be drawn.<P>
* </UL>
* <b>Frame Start Time, Duration, and Number</b><P>
*
* There are five methods used to get information about system
* execution and performance:<P>
* <UL>
* <code>getCurrentFrameStartTime</code> returns the time at which
* the most recent rendering frame started.<P>
* <code>getLastFrameDuration</code> returns the duration, in milliseconds, of
* the most recently completed rendering frame.<P>
* <code>getFrameNumber</code> returns the frame number for this view.<P>
* <code>getMaxFrameStartTimes</code> retrieves the implementation-dependent
* maximum number of frames whose start times will be recorded by
* the system.<P>
* <code>getFrameStartTimes</code> copies the last k frame start time values
* into the user-specified array.<P>
* </UL>
* <b>View Traversal and Behavior Scheduling</b><P>
* The following methods control the traversal, the rendering, and
* the execution of the behavior scheduler for this view:<P>
* <UL>
* <code>startBehaviorScheduler</code> starts the behavior scheduler
* running after it has been stopped.<P>
* <code>stopBehaviorScheduler</code> stops the behavior scheduler after all
* currently-scheduled behaviors are executed.<P>
* <code>isBehaviorSchedulerRunning</code> retrieves a flag that indicates
* whether the behavior scheduler is currently running.<P>
* <code>startView</code> starts traversing this view and starts the renderers
* associated with all canvases attached to this view.<P>
* <code>stopView</code> stops traversing this view after the current state of
* the scene graph is reflected on all canvases attached to this
* view.<P>
* <code>isViewRunning</code> returns a flag indicating whether the traverser
* is currently running on this view.<P>
* </UL>
* Note: The above six methods are heavy-weight methods intended
* for verification and image capture (recording). They are not
* intended to be used for flow control.<P>
*
* <b>Scene Antialiasing</b><P>
*
* The following methods set and retrieve the scene antialiasing
* flag. Scene antialiasing is either enabled or disabled for this
* view. If enabled, the entire scene will be antialiased on each
* canvas in which scene antialiasing is available. Scene
* antialiasing is disabled by default.<P>
* <UL>
* <code>setSceneAntialiasingEnable</code> sets the scene antialiasing flag.<P>
* <code>getSceneAntialiasingEnable</code> returns the scene antialiasing
* flag.<P>
* </UL>
* Note that line and point antialiasing are independent of scene
* antialiasing. If antialiasing is enabled for lines and points,
* the lines and points will be antialiased prior to scene antialiasing.
* If scene antialiasing is disabled, antialiased lines and points will
* still be antialiased.
* <p>
* <b>Note:</b> Scene antialiasing is ignored in pure immediate mode,
* but is supported in mixed-immediate mode.
* <p>
* <b>Depth Buffer</b><P>
*
* The following two methods enable and disable automatic freezing
* of the depth buffer for objects rendered during the transparent
* rendering pass (that is, objects rendered using alpha blending)
* for this view. If enabled, depth buffer writes are disabled
* during the transparent rendering pass regardless of the value
* of the depth-buffer-write-enable flag in the RenderingAttributes
* object for a particular node. This flag is enabled by default.<P>
* <UL>
* <code>setDepthBufferFreezeTransparent</code> enables depth buffer freezing.<P>
* <code>getDepthBufferFreezeTransparent</code> retrieves the depth buffer
* flag.<P>
* </UL>
* Transparent objects include BLENDED transparent primitives
* and antialiased lines
* and points. Transparent objects do not include opaque objects
* or primitives rendered with SCREEN_DOOR transparency.<p>
*
* <b>Sensors</b><P>
*
* The following methods retrieve the sensor's location in the
* virtual world:<P>
* <UL>
* <code>getSensorToVworld</code> takes the sensor's last reading and
* generates a sensor-to-vworld coordinate system transform. This
* Transform3D object takes points in that sensor's local coordinate
* system and transforms them into virtual world coordinates.<P>
*
* <code>getSensorHotSpotInVworld</code> retrieves the specified sensor's
* last hotspot location in virtual world coordinates.<P>
* </UL>
*
* <b>Compatibility Mode</b><P>
*
* A camera-based view model allows application programmers to think
* about the images displayed on the computer screen as if a virtual
* camera took those images. Such a view model allows application
* programmers to position and orient a virtual camera within a
* virtual scene, to manipulate some parameters of the virtual
* camera's lens (specify its field of view), and to specify the
* locations of the near and far clipping planes.<P>
* Java 3D allows applications to enable compatibility mode for
* room-mounted, non-head-tracked display environments, or to disable
* compatibility mode using the following methods. Camera-based
* viewing functions are only available in compatibility mode.<P>
* <UL>
* <code>setCompatibilityModeEnable</code> turns compatibility mode on or off.
* Compatibility mode is disabled by default.<P>
* <code>getCompatabilityModeEnable</code> returns the compatibility mode
* enable flag.<P>
* </UL>
* Use of these view-compatibility functions will disable some of
* Java 3D's view model features and limit the portability of Java
* 3D programs. These methods are primarily intended to help
* jump-start porting of existing applications.<P>
*
* Setting the Viewing Transform<P>
*
* The View object provides the following compatibility-mode
* methods that operate on the viewing transform.<P>
* <UL>
* <code>setVpcToEc</code> a compatibility mode method that
* specifies the ViewPlatform
* coordinates (VPC) to eye coordinates viewing transform.<P>
* <code>getVpcToEc</code> returns the VPC.<P>
* </UL>
* Setting the Projection Transform
* <p>
* The View object provides the following compatibility-mode
* methods that operate on the projection transform:<P>
* <UL>
* The <code>setLeftProjection</code> and <code>setRightProjection</code>
* methods specify
* a viewing frustum for the left and right eye that transforms
* points in eye coordinates to clipping coordinates.<P>
*
* The <code>getLeftProjection</code> and <code>getRightProjection</code>
* methods return
* the viewing frustum for the left and right eye.<P>
* </UL>
*
* <p>
* <b>Additional Information</b>
* <p>
* For more information, see the
* <a href="doc-files/intro.html">Introduction to the Java 3D API</a> and
* <a href="doc-files/ViewModel.html">View Model</a>
* documents.
*
* @see Canvas3D
* @see PhysicalBody
* @see PhysicalEnvironment
* @see ViewPlatform
* @see TransparencyAttributes
*/
public class View extends Object {
/**
* Specifies a policy whereby the origin of physical or virtual
* coordinates is relative to the position of the nominal head.
* When used as a view attach policy, this sets the origin of view
* platform coordinates to be at the eyepoint.
* @see ViewPlatform#setViewAttachPolicy
* @see PhysicalEnvironment#setCoexistenceCenterInPworldPolicy
*/
public static final int NOMINAL_HEAD = 0;
/**
* Specifies a policy whereby the origin of physical or virtual
* coordinates is relative to the position of the nominal feet.
* When used as a view attach policy, this sets the origin of view
* platform coordinates to be at the ground plane.
* @see ViewPlatform#setViewAttachPolicy
* @see PhysicalEnvironment#setCoexistenceCenterInPworldPolicy
*/
public static final int NOMINAL_FEET = 1;
/**
* Specifies a policy whereby the origin of physical or virtual
* coordinates is relative to the screen.
* When used as a view attach policy, this sets the origin of view
* platform coordinates to be at the center of the window or screen,
* in effect, allowing the user to view objects from an optimal viewpoint.
* @see ViewPlatform#setViewAttachPolicy
* @see PhysicalEnvironment#setCoexistenceCenterInPworldPolicy
*/
public static final int NOMINAL_SCREEN = 2;
/**
* Specifies that the screen scale for this view is derived from
* the physical screen size. This scale factor is computed as follows:
* <ul>
* physical_screen_width / 2.0
* </ul>
* This allows an application to define a world in a normalized
* [-1,1] space and view it on a screen of any size.
* @see #setScreenScalePolicy
*/
public static final int SCALE_SCREEN_SIZE = 0;
/**
* Specifies that the screen scale for this view is taken directly
* from the user-provided screenScale parameter.
* @see #setScreenScalePolicy
* @see #setScreenScale
*/
public static final int SCALE_EXPLICIT = 1;
/**
* Specifies that the associated distance is measured
* from the screen in virtual world coordinates.
* Policy for interpreting clip plane distances.
* Used in specifying the policy in frontClipPolicy and backClipPolicy.
* @see #setFrontClipPolicy
* @see #setBackClipPolicy
*/
public static final int VIRTUAL_SCREEN = 0;
/**
* Specifies that the associated distance is measured
* from the screen in meters.
* Policy for interpreting clip plane distances.
* Used in specifying the policy in frontClipPolicy and backClipPolicy.
* @see #setFrontClipPolicy
* @see #setBackClipPolicy
*/
public static final int PHYSICAL_SCREEN = 1;
/**
* Specifies that the associated distance is measured
* from the eye in virtual world coordinates.
* Policy for interpreting clip plane distances.
* Used in specifying the policy in frontClipPolicy and backClipPolicy.
* @see #setFrontClipPolicy
* @see #setBackClipPolicy
*/
public static final int VIRTUAL_EYE = 2;
/**
* Specifies that the associated distance is measured
* from the eye in meters.
* Policy for interpreting clip plane distances.
* Used in specifying the policy in frontClipPolicy and backClipPolicy.
* This is the default policy for both front and back clipping.
* @see #setFrontClipPolicy
* @see #setBackClipPolicy
*/
public static final int PHYSICAL_EYE = 3;
/**
* Policy for resizing and moving windows.
* Used in specifying windowResizePolicy and windowMovementPolicy.
* VIRTUAL_WORLD specifies that the associated action takes place
* in the virtual world as well as in the physical world.
* @see #setWindowResizePolicy
* @see #setWindowMovementPolicy
*/
public static final int VIRTUAL_WORLD = 0;
/**
* Policy for resizing and moving windows.
* Used in specifying windowResizePolicy and windowMovementPolicy.
* PHYSICAL_WORLD specifies that the specified action takes place
* only in the physical world.
* @see #setWindowResizePolicy
* @see #setWindowMovementPolicy
*/
public static final int PHYSICAL_WORLD = 1;
/**
* Policy for placing the eyepoint in non-head-tracked modes.
* Specifies that Java 3D should interpret the
* given fixed eyepoint position as relative to the entire screen.
* This implies
* that the view frustum shape will change whenever a
* user moves the location of a window on the screen.
* @see #setWindowEyepointPolicy
*/
public static final int RELATIVE_TO_SCREEN = 0;
/**
* Policy for placing the eyepoint in non-head-tracked modes.
* Specifies that Java 3D should interpret the
* given fixed-eyepoint position as relative to the window.
* @see #setWindowEyepointPolicy
*/
public static final int RELATIVE_TO_WINDOW = 1;
/**
* Policy for placing the eyepoint in non-head-tracked modes.
* Specifies that Java 3D should
* modify the position of the eyepoint to match any changes in field
* of view; the view frustum will change whenever the application
* program changes the field of view.
* <p>
* NOTE: when this policy is specified, the Z coordinate of
* the derived eyepoint is used in place of
* nominalEyeOffsetFromNominalScreen.
* @see #setWindowEyepointPolicy
*/
public static final int RELATIVE_TO_FIELD_OF_VIEW = 2;
/**
* Policy for placing the eyepoint in non-head-tracked modes.
* Specifies that Java 3D should interpret the fixed eyepoint
* position in the view as relative to the origin
* of coexistence coordinates. This eyepoint is transformed from
* coexistence coordinates to image plate coordinates for each
* Canvas3D.
* As in RELATIVE_TO_SCREEN mode, this implies
* that the view frustum shape will change whenever a
* user moves the location of a window on the screen.
* @see #setWindowEyepointPolicy
*
* @since Java 3D 1.2
*/
public static final int RELATIVE_TO_COEXISTENCE = 3;
/**
* Specifies that monoscopic view generated should be the view as seen
* from the left eye.
* @see Canvas3D#setMonoscopicViewPolicy
*/
public static final int LEFT_EYE_VIEW = 0;
/**
* Specifies that monoscopic view generated should be the view as seen
* from the right eye.
* @see Canvas3D#setMonoscopicViewPolicy
*/
public static final int RIGHT_EYE_VIEW = 1;
/**
* Specifies that monoscopic view generated should be the view as seen
* from the 'center eye', the fictional eye half-way between the left and
* right eye.
* @see Canvas3D#setMonoscopicViewPolicy
*/
public static final int CYCLOPEAN_EYE_VIEW = 2;
/**
* Specifies that the viewing environment for this view is a
* standard screen-based display environment.
* In this mode, Java 3D will compute new viewpoints
* using that sequence of transforms appropriate to screen-based,
* display environments, that may or may not include head tracking
* (e.g., a monoscopic screen, fish-tank VR, portals, VR-desks).
* This is the default mode.
* @see #setViewPolicy
*/
public static final int SCREEN_VIEW = 0;
/**
* Specifies that the viewing environment for this view is a
* head-mounted display environment.
* In this mode, Java 3D will compute new viewpoints
* using that sequence of transforms appropriate to head-mounted display
* environments. These environments are generally head-tracked.
* @see #setViewPolicy
*/
public static final int HMD_VIEW = 1;
/**
* Specifies that Java 3D should generate a parallel projection matrix
* for this View.
* @see #setProjectionPolicy
*/
public static final int PARALLEL_PROJECTION = 0;
/**
* Specifies that Java 3D should generate a perspective projection matrix
* for this View.
* This is the default mode.
* @see #setProjectionPolicy
*/
public static final int PERSPECTIVE_PROJECTION = 1;
/**
* Policy that specifies that only visible objects should be drawn.
* This is the default mode.
* @see #setVisibilityPolicy
*
* @since Java 3D 1.2
*/
public static final int VISIBILITY_DRAW_VISIBLE = 0;
/**
* Policy that specifies that only invisible objects should be drawn.
* @see #setVisibilityPolicy
*
* @since Java 3D 1.2
*/
public static final int VISIBILITY_DRAW_INVISIBLE = 1;
/**
* Policy that specifies that both visible and invisible objects
* should be drawn.
* @see #setVisibilityPolicy
*
* @since Java 3D 1.2
*/
public static final int VISIBILITY_DRAW_ALL = 2;
/**
* Policy that specifies that no sorting of transparent objects
* is done.
* This is the default mode.
* @see #setTransparencySortingPolicy
*
* @since Java 3D 1.3
*/
public static final int TRANSPARENCY_SORT_NONE = 0;
/**
* Policy that specifies that transparent objects
* are sorted from back to front on a per-geometry basis.
* @see #setTransparencySortingPolicy
*
* @since Java 3D 1.3
*/
public static final int TRANSPARENCY_SORT_GEOMETRY = 1;
//
// The AWT window for display.
//
// This object can be queried to obtain:
// screen width in pixels
// screen height in pixels
// window width in pixels
// window height in pixels
// window upper left corner location in pixels relative to screen
//
// Use getCanvases() to access this
private Vector<Canvas3D> canvases = new Vector<Canvas3D>(3);
//
// The current universe associated with this view
//
VirtualUniverse universe = null;
//
// The RenderBin associated with this view.
//
RenderBin renderBin = null;
// This is the SoundScheduler associated with this view.
SoundScheduler soundScheduler = null;
// AudioDevice enumerator current position
// AudioDeviceEnumerator allAudioEnumerator = null;
// These are used for tracking the frame times
static final int NUMBER_FRAME_START_TIMES = 10;
long[] frameStartTimes = new long[NUMBER_FRAME_START_TIMES];
long[] frameNumbers = new long[NUMBER_FRAME_START_TIMES];
int currentFrameIndex = 0;
// These are the values that are set at the end of each frame
long currentFrameStartTime = 0;
long currentFrameDuration = 0;
long currentFrameNumber = 0;
// These are the ones that get updated directly by MC
long frameNumber = 0;
long startTime = 0;
long stopTime = 0;
// User adjustable minimum frame cycle time
long minFrameCycleTime;
// True when stopBehaviorScheduler invoke
boolean stopBehavior;
//
// View cache for this view.
//
ViewCache viewCache = null;
// Compatibility mode related field has changed.
// { compatibilityModeEnable, compatVpcToEc, compatLeftProjection,
// compatRightProjection }
static final int COMPATIBILITY_MODE_DIRTY = 0x01;
// ScreenScalePolicy field has changed.
static final int SCREEN_SCALE_POLICY_DIRTY = 0x02;
// Screen scale field has changed.
static final int SCREEN_SCALE_DIRTY = 0x04;
// Window Resize Policy field has changed.
static final int WINDOW_RESIZE_POLICY_DIRTY = 0x08;
// View Policy eye in image plate field has changed.
static final int VIEW_POLICY_DIRTY = 0x10;
// Clip related field has changed.
// { frontClipDistance, backClipDistance, frontClipPolicy, backClipPolicy }
static final int CLIP_DIRTY = 0x20;
// Projection Policy field has changed.
static final int PROJECTION_POLICY_DIRTY = 0x40;
// Window Movement Policy field has changed.
static final int WINDOW_MOVEMENT_POLICY_DIRTY = 0x80;
// Window Eye Point Policy field has changed.
static final int WINDOW_EYE_POINT_POLICY_DIRTY = 0x100;
// Monoscopic View Policy field has changed.
static final int MONOSCOPIC_VIEW_POLICY_DIRTY = 0x200;
// Field Of View field has changed.
static final int FIELD_OF_VIEW_DIRTY = 0x400;
// Tracking Enable field has changed.
static final int TRACKING_ENABLE_DIRTY = 0x800;
// User Head To Vworld Enable field has changed.
static final int USER_HEAD_TO_VWORLD_ENABLE_DIRTY = 0x1000;
// coexistenceCenteringEnable flag has changed.
static final int COEXISTENCE_CENTERING_ENABLE_DIRTY = 0x2000;
// leftManualEyeInCoexistence has changed.
static final int LEFT_MANUAL_EYE_IN_COEXISTENCE_DIRTY = 0x4000;
// rightManualEyeInCoexistence has changed.
static final int RIGHT_MANUAL_EYE_IN_COEXISTENCE_DIRTY = 0x8000;
// visibilityPolicy has changed.
static final int VISIBILITY_POLICY_DIRTY = 0x10000;
// This is not from View object. It is here for the purpose
// keeping all ViewCache's dirty mask bit declaration in one place.
// ViewPlatformRetained viewAttach Policy field has changed.
static final int VPR_VIEW_ATTACH_POLICY_DIRTY = 0x10000;
static final int VPR_VIEWPLATFORM_DIRTY = 0x20000;
// PhysicalEnvironment fields has changed.
static final int PE_COE_TO_TRACKER_BASE_DIRTY = 0x100000;
static final int PE_TRACKING_AVAILABLE_DIRTY = 0x200000;
static final int PE_COE_CENTER_IN_PWORLD_POLICY_DIRTY = 0x400000;
// PhysicalBody fields has changed.
static final int PB_EYE_POSITION_DIRTY = 0x1000000;
static final int PB_EAR_POSITION_DIRTY = 0x2000000;
static final int PB_NOMINAL_EYE_HEIGHT_FROM_GROUND_DIRTY = 0x4000000;
static final int PB_NOMINAL_EYE_OFFSET_FROM_NOMINAL_SCREEN_DIRTY = 0x8000000;
// Mask that indicates this View's view dependence info. has changed,
// and CanvasViewCache may need to recompute the final view matries.
int vDirtyMask = (COMPATIBILITY_MODE_DIRTY | SCREEN_SCALE_POLICY_DIRTY
| SCREEN_SCALE_DIRTY | WINDOW_RESIZE_POLICY_DIRTY
| VIEW_POLICY_DIRTY | CLIP_DIRTY
| PROJECTION_POLICY_DIRTY | WINDOW_MOVEMENT_POLICY_DIRTY
| WINDOW_EYE_POINT_POLICY_DIRTY | MONOSCOPIC_VIEW_POLICY_DIRTY
| FIELD_OF_VIEW_DIRTY | TRACKING_ENABLE_DIRTY
| USER_HEAD_TO_VWORLD_ENABLE_DIRTY
| COEXISTENCE_CENTERING_ENABLE_DIRTY
| LEFT_MANUAL_EYE_IN_COEXISTENCE_DIRTY
| RIGHT_MANUAL_EYE_IN_COEXISTENCE_DIRTY
| VISIBILITY_POLICY_DIRTY);
//
// This object contains a specification of the user's physical body.
//
// Attributes of this object are defined in head coordinates and
// include information such as the location of the user's eyes and
// ears.
// The origin is defined to be halfway between the left and right eye
// in the plane of the face.
// The x-axis extends to the right (of the head looking out from the head).
// The y-axis extends up. The z-axis extends to the rear of the head.
//
PhysicalBody physicalBody;
// This object contains a specification of the physical environment.
PhysicalEnvironment physicalEnvironment;
// View model compatibility mode flag
boolean compatibilityModeEnable = false;
// View model coexistenceCenteringEnable flag
boolean coexistenceCenteringEnable = true;
Point3d leftManualEyeInCoexistence = new Point3d();
Point3d rightManualEyeInCoexistence = new Point3d();
//
// Indicates which major mode of view computation to use:
// HMD mode or screen/fish-tank-VR mode.
//
int viewPolicy = SCREEN_VIEW;
// The current projection policy (parallel versus perspective)
int projectionPolicy = PERSPECTIVE_PROJECTION;
//
// The view model's field of view.
//
double fieldOfView = 45.0 * Math.PI / 180.0;
//
// The distance away from the clip origin
// in the direction of gaze for the front and back clip planes.
// The default values are in meters.
//
double frontClipDistance = 0.1;
double backClipDistance = 10.0;
// This variable specifies where the screen scale comes from
int screenScalePolicy = SCALE_SCREEN_SIZE;
// The screen scale value used when the screen scale policy is
// SCALE_EXPLICIT
double screenScale = 1.0;
//
// This variable specifies how Java 3D modifies the view when
// the window is resized (VIRTUAL_WORLD or PHYSICAL_WORLD).
//
int windowResizePolicy = PHYSICAL_WORLD;
//
// This variable specifies how Java 3D modifies the view when
// the window is moved (VIRTUAL_WORLD or PHYSICAL_WORLD).
//
int windowMovementPolicy = PHYSICAL_WORLD;
//
// Specifies how Java 3D handles the predefined eyepoint in
// non-head-tracked environment (RELATIVE_TO_SCREEN,
// RELATIVE_TO_WINDOW, RELATIVE_TO_FIELD_OF_VIEW, or
// RELATIVE_TO_COEXISTENCE)
//
int windowEyepointPolicy = RELATIVE_TO_FIELD_OF_VIEW;
//
// Specifies how Java 3D generates monoscopic view
// (LEFT_EYE_VIEW, RIGHT_EYE_VIEW, or CYCLOPEAN_EYE_VIEW).
//
int monoscopicViewPolicy = CYCLOPEAN_EYE_VIEW;
/**
* Defines the policy for placing the front clipping plane.
* Legal values include PHYSICAL_EYE, PHYSICAL_SCREEN,
* VIRTUAL_EYE, and VIRTUAL_SCREEN.
*/
int frontClipPolicy = PHYSICAL_EYE;
/**
* Defines the policy for placing the back clipping plane.
*/
int backClipPolicy = PHYSICAL_EYE;
/**
* Defines the visibility policy.
*/
int visibilityPolicy = VISIBILITY_DRAW_VISIBLE;
/**
* Defines the transparency sorting policy.
*/
int transparencySortingPolicy = TRANSPARENCY_SORT_NONE;
/**
* Flag to enable tracking, if so allowed by the trackingAvailable flag.
*/
boolean trackingEnable = false;
/**
* This setting enables the continuous updating by Java 3D of the
* userHeadToVworld transform.
*/
boolean userHeadToVworldEnable = false;
/**
* The view platform currently associated with this view.
*/
private ViewPlatform viewPlatform = null;
// The current compatibility mode view transform
Transform3D compatVpcToEc = new Transform3D();
// The current compatibility mode projection transforms
Transform3D compatLeftProjection = new Transform3D();
Transform3D compatRightProjection = new Transform3D();
// The long id of this view - used for dirty bit evaluation in the scene graph
Integer viewId = null;
int viewIndex = -1;
// A boolean that indicates whether or not this is the primary view
boolean primaryView = false;
// A boolean that indicates whether or not this view is active as
// seen by MasterControl
boolean active = false;
// A boolean that indicates whether or not this view is active as
// seen by this view. There is a delay before MasterControl set
// active flag, so a local activeStatus is used. Otherwise
// activate event may lost if it proceed by deactivate event
// but MC not yet set active to false. This happens in
// viewplatform detach and attach.
boolean activeStatus = false;
// This boolean indicates whether or not the view is running. It
// is used for startView/stopView
volatile boolean isRunning = true;
// A flag to indicate that we are in a canvas callback routine
boolean inCanvasCallback = false;
//
// Flag to enable depth buffer freeze during trasparent rendering pass
//
boolean depthBufferFreezeTransparent = true;
//
// Flag to enable scene antialiasing
//
boolean sceneAntialiasingEnable = false;
//
// Flag to enable local eye lighting
//
boolean localEyeLightingEnable = false;
// Array Lists to track the screens and canvases associated with this View.
// use getScreens() to access this
private ArrayList<Screen3D> screenList = new ArrayList<Screen3D>();
// use getCanvasList() to access this
private ArrayList<ArrayList<Canvas3D>> canvasList = new ArrayList<ArrayList<Canvas3D>>();
private Canvas3D[][] cachedCanvasList;
private Canvas3D[] cachedCanvases;
private Screen3D[] cachedScreens;
private int longestScreenList = 0;
private boolean canvasesDirty = true;
// Flag to notify user thread when renderOnce is finished
volatile boolean renderOnceFinish = true;
// Lock to synchronize start/stop/renderOnce call
private Object startStopViewLock = new Object();
// Lock for evaluateActive() only. This is used to prevent
// using lock this which will cause deadlock when MC call
// snapshot which waitForMC() in user thread.
private Object evaluateLock = new Object();
/**
* use for stop view, when stopview, set to count -1,
* when reach 1, call stopView() in MC and reset to -1.
*/
int stopViewCount = -1;
/**
* False if current frame cycle time less than minimum frame cycle time
*/
boolean isMinCycleTimeAchieve = true;
// Time to sleep if minimum frame cycle time not achieve
long sleepTime = 0;
// use in pure immediate mode to tell whether this view rendering
// thread is added in MC renderThreadData
volatile boolean inRenderThreadData = false;
// use to notify MC that render bin has run once, and is ready for
// renderer to render
boolean renderBinReady = false;
// No of time setUniverse() is invoke
long universeCount = 0;
// The universe count when UNREGISTER_VIEW request is post,
// this is used to distingish whether new setUniverse() is
// invoked after UNREGISTER_VIEW request post to avoid
// resetting the newly set universe.
long resetUnivCount = 0;
// This notify user thread waitForMC() to continue when
// MC finish unregisterView
volatile boolean doneUnregister = false;
static final int TRANSP_SORT_POLICY_CHANGED = 0x0001;
static final int OTHER_ATTRS_CHANGED = 0x0002;
/**
* Constructs a View object with default parameters. The default
* values are as follows:
* <ul>
* view policy : SCREEN_VIEW<br>
* projection policy : PERSPECTIVE_PROJECTION<br>
* screen scale policy : SCALE_SCREEN_SIZE<br>
* window resize policy : PHYSICAL_WORLD<br>
* window movement policy : PHYSICAL_WORLD<br>
* window eyepoint policy : RELATIVE_TO_FIELD_OF_VIEW<br>
* monoscopic view policy : CYCLOPEAN_EYE_VIEW<br>
* front clip policy : PHYSICAL_EYE<br>
* back clip policy : PHYSICAL_EYE<br>
* visibility policy : VISIBILITY_DRAW_VISIBLE<br>
* transparency sorting policy : TRANSPARENCY_SORT_NONE<br>
* coexistenceCentering flag : true<br>
* compatibility mode : false<br>
* left projection : identity<br>
* right projection : identity<br>
* vpc to ec transform : identity<br>
* physical body : null<br>
* physical environment : null<br>
* screen scale : 1.0<br>
* field of view : PI/4<br>
* left manual eye in coexistence : (-0.033, 0.0, 0.4572)<br>
* right manual eye in coexistence : (0.033, 0.0, 0.4572)<br>
* front clip distance : 0.1<br>
* back clip distance : 10.0<br>
* tracking enable : false<br>
* user head to vworld enable : false<br>
* list of Canvas3D objects : empty<br>
* depth buffer freeze transparent : true<br>
* scene antialiasing : false<br>
* local eye lighting : false<br>
* view platform : null<br>
* behavior scheduler running : true<br>
* view running : true<br>
* minimum frame cycle time : 0<br>
* </ul>
*/
public View() {
viewCache = new ViewCache(this);
}
/**
* Sets the policy for view computation.
* This variable specifies how Java 3D uses its transforms in
* computing new viewpoints.
* <UL>
* <LI>SCREEN_VIEW specifies that Java 3D should compute a new viewpoint
* using the sequence of transforms appropriate to screen-based
* head-tracked display environments (fish-tank VR/portals/VR-desks).
* </LI>
* <LI>HMD_VIEW specifies that Java 3D should compute a new viewpoint
* using the sequence of transforms appropriate to head mounted
* display environments.
* </LI>
* </UL>
* The default view policy is SCREEN_VIEW.
* @param policy the new policy, one of SCREEN_VIEW or HMD_VIEW
* @exception IllegalArgumentException if policy is a value other than
* SCREEN_VIEW or HMD_VIEW
* @exception IllegalStateException if the specified policy
* is HMD_VIEW and if any canvas associated with this view is
* a stereo canvas with a monoscopicEyePolicy of CYCLOPEAN_EYE_VIEW
*/
public void setViewPolicy(int policy) {
if (policy != HMD_VIEW &&
policy != SCREEN_VIEW) {
throw new IllegalArgumentException(J3dI18N.getString("View0"));
}
if(policy == HMD_VIEW) {
// Check the following :
// 1) If the view is in HMD mode and there exists a canvas in
// CYCLOPEAN_EYE_VIEW mode then throw exception.
synchronized (canvasList) {
for (int i=canvases.size()-1; i>=0; i--) {
Canvas3D c3d = canvases.elementAt(i);
if ((c3d.monoscopicViewPolicy == View.CYCLOPEAN_EYE_VIEW) &&
(!c3d.useStereo)){
throw new
IllegalStateException(J3dI18N.getString("View31"));
}
}
}
}
synchronized(this) {
this.viewPolicy = policy;
vDirtyMask |= View.VIEW_POLICY_DIRTY;
}
repaint();
}
/**
* Retrieves the current view computation policy for this View.
* @return one of: SCREEN_VIEW or HMD_VIEW.
*/
public int getViewPolicy() {
return this.viewPolicy;
}
/**
* Sets the projection policy for this View.
* This variable specifies the type of projection transform that
* will be generated. A value of PARALLEL_PROJECTION specifies that
* a parallel projection transform is generated. A value of
* PERSPECTIVE_PROJECTION specifies that
* a perspective projection transform is generated.
* The default projection policy is PERSPECTIVE.
* @param policy the new policy, one of PARALLEL_PROJECTION or
* PERSPECTIVE_PROJECTION
* @exception IllegalArgumentException if policy is a value other than
* PARALLEL_PROJECTION or PERSPECTIVE_PROJECTION
*/
public void setProjectionPolicy(int policy) {
if (policy != PERSPECTIVE_PROJECTION &&
policy != PARALLEL_PROJECTION) {
throw new IllegalArgumentException(J3dI18N.getString("View1"));
}
synchronized(this) {
this.projectionPolicy = policy;
vDirtyMask |= View.PROJECTION_POLICY_DIRTY;
}
repaint();
}
/**
* Retrieves the current projection policy for this View.
* @return one of: PARALLEL_PROJECTION or PERSPECTIVE_PROJECTION.
*/
public int getProjectionPolicy() {
return this.projectionPolicy;
}
/**
* Sets the screen scale policy for this view.
* This policy specifies how the screen scale is derived.
* The value is either SCALE_SCREEN_SIZE or SCALE_EXPLICIT.
* A value of SCALE_SCREEN_SIZE specifies that the scale is derived
* from the size of the physical screen. A value of SCALE_EXPLICIT
* specifies that the scale is taken directly from the screenScale
* parameter.
* The default screen scale policy is SCALE_SCREEN_SIZE.
* @param policy the new policy, one of SCALE_SCREEN_SIZE or
* SCALE_EXPLICIT.
*/
public void setScreenScalePolicy(int policy) {
synchronized(this) {
this.screenScalePolicy = policy;
vDirtyMask |= View.SCREEN_SCALE_POLICY_DIRTY;
}
repaint();
}
/**
* Returns the current screen scale policy, one of:
* SCALE_SCREEN_SIZE or SCALE_EXPLICIT.
* @return the current screen scale policy
*/
public int getScreenScalePolicy() {
return this.screenScalePolicy;
}
/**
* Sets the window resize policy.
* This variable specifies how Java 3D modifies the view when
* users resize windows. The variable can contain one of
* VIRTUAL_WORLD or PHYSICAL_WORLD.
* A value of VIRTUAL_WORLD implies that the original image
* remains the same size on the screen but the user sees more
* or less of the virtual world depending on whether the window
* grew or shrank in size.
* A value of PHYSICAL_WORLD implies that the original image
* continues to fill the window in the same way using more or
* less pixels depending on whether the window grew or shrank
* in size.
* The default window resize policy is PHYSICAL_WORLD.
* @param policy the new policy, one of VIRTUAL_WORLD or PHYSICAL_WORLD
*/
public void setWindowResizePolicy(int policy) {
synchronized(this) {
this.windowResizePolicy = policy;
vDirtyMask |= View.WINDOW_RESIZE_POLICY_DIRTY;
}
repaint();
}
/**
* Returns the current window resize policy, one of:
* VIRTUAL_WORLD or PHYSICAL_WORLD.
* @return the current window resize policy
*/
public int getWindowResizePolicy() {
return this.windowResizePolicy;
}
/**
* Sets the window movement policy.
* This variable specifies what part of the virtual world Java 3D
* draws as a function of window placement on the screen. The
* variable can contain one of VIRTUAL_WORLD or PHYSICAL_WORLD.
* A value of VIRTUAL_WORLD implies that the image seen in the
* window changes as the position of the window shifts on the
* screen. (This mode acts as if the window were a window into
* the virtual world.)
* A value of PHYSICAL_WORLD implies that the image seen in the
* window remains the same no matter where the user positions
* the window on the screen.
* The default window movement policy is PHYSICAL_WORLD.
* @param policy the new policy, one of VIRTUAL_WORLD or PHYSICAL_WORLD
*/
public void setWindowMovementPolicy(int policy) {
synchronized(this) {
this.windowMovementPolicy = policy;
vDirtyMask |= View.WINDOW_MOVEMENT_POLICY_DIRTY;
}
repaint();
}
/**
* Returns the current window movement policy,
* one of: VIRTUAL_WORLD or PHYSICAL_WORLD.
* @return the current window movement policy
*/
public int getWindowMovementPolicy() {
return this.windowMovementPolicy;
}
/**
* Sets the view model's window eyepoint policy.
* This variable specifies how Java 3D handles the predefined eye
* point in a non-head-tracked environment. The variable can contain
* one of:
* <UL>
* <LI>RELATIVE_TO_SCREEN, Java 3D should interpret the
* given fixed-eyepoint position as relative to the screen (this
* implies that the view frustum shape will change whenever a
* user moves the location of a window on the screen).
* </LI>
* <LI>RELATIVE_TO_WINDOW, Java 3D should interpret the
* given fixed-eyepoint position as relative to the window. In this
* mode, the X and Y values are taken as the center of the window and
* the Z value is taken from the canvas eyepoint position.
* </LI>
* <LI>RELATIVE_TO_FIELD_OF_VIEW, Java 3D should
* modify the position of the eyepoint to match any changes in field
* of view (the view frustum will change whenever the application
* program changes the field of view).
* </LI>
* <LI>RELATIVE_TO_COEXISTENCE, Java 3D should interpret the eye's
* position in coexistence coordinates. In this mode, the eye position
* is taken from the view (rather than the Canvas3D) and transformed from
* coexistence coordinates to image plate coordinates for each
* Canvas3D. The resulting eye position is relative to the screen (this
* implies that the view frustum shape will change whenever a
* user moves the location of a window on the screen).
* </LI>
* </UL>
* The default window eyepoint policy is RELATIVE_TO_FIELD_OF_VIEW.
* @param policy the new policy, one of RELATIVE_TO_SCREEN,
* RELATIVE_TO_WINDOW, RELATIVE_TO_FIELD_OF_VIEW, or
* RELATIVE_TO_COEXISTENCE
*/
public void setWindowEyepointPolicy(int policy) {
synchronized(this) {
this.windowEyepointPolicy = policy;
vDirtyMask |= View.WINDOW_EYE_POINT_POLICY_DIRTY;
}
repaint();
}
/**
* Returns the current window eyepoint policy, one of:
* RELATIVE_TO_SCREEN, RELATIVE_TO_WINDOW, RELATIVE_TO_FIELD_OF_VIEW or
* RELATIVE_TO_COEXISTENCE.
* @return the current window eyepoint policy
*/
public int getWindowEyepointPolicy() {
return this.windowEyepointPolicy;
}
/**
* @deprecated As of Java 3D version 1.2, replaced by
* <code>Canvas3D.setMonoscopicViewPolicy</code>
*/
public void setMonoscopicViewPolicy(int policy) {
synchronized(this) {
this.monoscopicViewPolicy = policy;
vDirtyMask |= View.MONOSCOPIC_VIEW_POLICY_DIRTY;
}
repaint();
}
/**
* @deprecated As of Java 3D version 1.2, replaced by
* <code>Canvas3D.getMonoscopicViewPolicy</code>
*/
public int getMonoscopicViewPolicy() {
return this.monoscopicViewPolicy;
}
/**
* Sets the coexistenceCentering enable flag to true or false.
* If the coexistenceCentering flag is true, the center of
* coexistence in image plate coordinates, as specified by the
* trackerBaseToImagePlate transform, is translated to the center
* of either the window or the screen in image plate coordinates,
* according to the value of windowMovementPolicy.
*
* <p>
* By default, coexistenceCentering is enabled. It should be
* disabled if the trackerBaseToImagePlate calibration transform
* is set to a value other than the identity (for example, when
* rendering to multiple screens or when head tracking is
* enabled). This flag is ignored for HMD mode, or when the
* coexistenceCenterInPworldPolicy is <i>not</i>
* NOMINAL_SCREEN.
*
* @param flag the new coexistenceCentering enable flag
*
* @since Java 3D 1.2
*/
public void setCoexistenceCenteringEnable(boolean flag) {
synchronized(this) {
this.coexistenceCenteringEnable = flag;
vDirtyMask |= View.COEXISTENCE_CENTERING_ENABLE_DIRTY;
}
repaint();
}
/**
* Retrieves the coexistenceCentering enable flag.
*
* @return the current coexistenceCentering enable flag
*
* @since Java 3D 1.2
*/
public boolean getCoexistenceCenteringEnable() {
return this.coexistenceCenteringEnable;
}
/**
* Sets the compatibility mode enable flag to true or false.
* Compatibility mode is disabled by default.
* @param flag the new compatibility mode enable flag
*/
public void setCompatibilityModeEnable(boolean flag) {
synchronized(this) {
this.compatibilityModeEnable = flag;
vDirtyMask |= View.COMPATIBILITY_MODE_DIRTY;
}
repaint();
}
/**
* Retrieves the compatibility mode enable flag.
* @return the current compatibility mode enable flag
*/
public boolean getCompatibilityModeEnable() {
return this.compatibilityModeEnable;
}
/**
* Compatibility mode method that specifies a viewing frustum for
* the left eye that transforms points in Eye Coordinates (EC) to
* Clipping Coordinates (CC).
* If compatibility mode is disabled, then this transform is not used;
* the actual projection is derived from other values.
* In monoscopic mode, only the left eye projection matrix is used.
* @param projection the new left eye projection transform
* @exception RestrictedAccessException if compatibility mode is disabled.
*/
public void setLeftProjection(Transform3D projection) {
if (!compatibilityModeEnable) {
throw new RestrictedAccessException(J3dI18N.getString("View2"));
}
synchronized(this) {
compatLeftProjection.setWithLock(projection);
vDirtyMask |= View.COMPATIBILITY_MODE_DIRTY;
}
repaint();
}
/**
* Compatibility mode method that specifies a viewing frustum for
* the right eye that transforms points in Eye Coordinates (EC) to
* Clipping Coordinates (CC).
* If compatibility mode is disabled, then this transform is not used;
* the actual projection is derived from other values.
* In monoscopic mode, the right eye projection matrix is ignored.
* @param projection the new right eye projection transform
* @exception RestrictedAccessException if compatibility mode is disabled.
*/
public void setRightProjection(Transform3D projection) {
if (!compatibilityModeEnable) {
throw new RestrictedAccessException(J3dI18N.getString("View2"));
}
synchronized(this) {
compatRightProjection.setWithLock(projection);
vDirtyMask |= View.COMPATIBILITY_MODE_DIRTY;
}
repaint();
}
/**
* Compatibility mode method that retrieves the current
* compatibility mode projection transform for the left eye and
* places it into the specified object.
* @param projection the Transform3D object that will receive the
* projection
* @exception RestrictedAccessException if compatibility mode is disabled.
*/
public void getLeftProjection(Transform3D projection) {
if (!compatibilityModeEnable) {
throw new RestrictedAccessException(J3dI18N.getString("View4"));
}
projection.set(compatLeftProjection);
}
/**
* Compatibility mode method that retrieves the current
* compatibility mode projection transform for the right eye and
* places it into the specified object.
* @param projection the Transform3D object that will receive the
* projection
* @exception RestrictedAccessException if compatibility mode is disabled.
*/
public void getRightProjection(Transform3D projection) {
if (!compatibilityModeEnable) {
throw new RestrictedAccessException(J3dI18N.getString("View4"));
}
projection.set(compatRightProjection);
}
/**
* Compatibility mode method that specifies the ViewPlatform
* Coordinates (VPC) to Eye Coordinates (EC) transform.
* If compatibility mode is disabled, then this transform
* is derived from other values and is read-only.
* @param vpcToEc the new VPC to EC transform
* @exception RestrictedAccessException if compatibility mode is disabled.
* @exception BadTransformException if the transform is not affine.
*/
public void setVpcToEc(Transform3D vpcToEc) {
if (!compatibilityModeEnable) {
throw new RestrictedAccessException(J3dI18N.getString("View6"));
}
if (!vpcToEc.isAffine()) {
throw new BadTransformException(J3dI18N.getString("View7"));
}
synchronized(this) {
compatVpcToEc.setWithLock(vpcToEc);
vDirtyMask |= View.COMPATIBILITY_MODE_DIRTY;
}
repaint();
}
/**
* Compatibility mode method that retrieves the current
* ViewPlatform Coordinates (VPC) system to
* Eye Coordinates (EC) transform and copies it into the specified
* object.
* @param vpcToEc the object that will receive the vpcToEc transform.
* @exception RestrictedAccessException if compatibility mode is disabled.
*/
public void getVpcToEc(Transform3D vpcToEc) {
if (!compatibilityModeEnable) {
throw new RestrictedAccessException(J3dI18N.getString("View8"));
}
vpcToEc.set(compatVpcToEc);
}
/**
* Sets the view model's physical body to the PhysicalBody object provided.
* Java 3D uses the parameters in the PhysicalBody to ensure accurate
* image and sound generation when in head-tracked mode.
* @param physicalBody the new PhysicalBody object
*/
public void setPhysicalBody(PhysicalBody physicalBody) {
// need to synchronize variable activateStatus
synchronized (canvasList) {
if (activeStatus) {
if (this.physicalBody != null) {
this.physicalBody.removeUser(this);
}
physicalBody.addUser(this);
}
}
this.physicalBody = physicalBody;
repaint();
}
/**
* Returns a reference to the view model's PhysicalBody object.
* @return the view object's PhysicalBody object
*/
public PhysicalBody getPhysicalBody() {
return this.physicalBody;
}
/**
* Sets the view model's physical environment to the PhysicalEnvironment
* object provided.
* @param physicalEnvironment the new PhysicalEnvironment object
*/
public void setPhysicalEnvironment(PhysicalEnvironment physicalEnvironment) {
synchronized (canvasList) {
if (activeStatus) {
if (this.physicalEnvironment != null) {
this.physicalEnvironment.removeUser(this);
}
physicalEnvironment.addUser(this);
}
}
this.physicalEnvironment = physicalEnvironment;
if ((viewPlatform != null) && viewPlatform.isLive()) {
VirtualUniverse.mc.postRequest(MasterControl.PHYSICAL_ENV_CHANGE, this);
}
repaint();
}
/**
* Returns a reference to the view model's PhysicalEnvironment object.
* @return the view object's PhysicalEnvironment object
*/
public PhysicalEnvironment getPhysicalEnvironment() {
return this.physicalEnvironment;
}
/**
* Sets the screen scale value for this view.
* This is used when the screen scale policy is SCALE_EXPLICIT.
* The default value is 1.0 (i.e., unscaled).
* @param scale the new screen scale
*/
public void setScreenScale(double scale) {
synchronized(this) {
this.screenScale = scale;
vDirtyMask |= View.SCREEN_SCALE_DIRTY;
}
repaint();
}
/**
* Returns the current screen scale value
* @return the current screen scale value
*/
public double getScreenScale() {
return this.screenScale;
}
/**
* Sets the field of view used to compute the projection transform.
* This is used when head tracking is disabled and when the Canvas3D's
* windowEyepointPolicy is RELATIVE_TO_FIELD_OF_VIEW.
* @param fieldOfView the new field of view in radians
*/
public void setFieldOfView(double fieldOfView) {
synchronized(this) {
this.fieldOfView = fieldOfView;
vDirtyMask |= View.FIELD_OF_VIEW_DIRTY;
}
repaint();
}
/**
* Returns the current field of view.
* @return the current field of view in radians
*/
public double getFieldOfView() {
return this.fieldOfView;
}
/**
* Sets the position of the manual left eye in coexistence
* coordinates. This value determines eye placement when a head
* tracker is not in use and the application is directly controlling
* the eye position in coexistence coordinates. This value is
* ignored when in head-tracked mode or when the
* windowEyePointPolicy is <i>not</i> RELATIVE_TO_COEXISTENCE.
*
* @param position the new manual left eye position
*
* @since Java 3D 1.2
*/
public void setLeftManualEyeInCoexistence(Point3d position) {
synchronized(this) {
leftManualEyeInCoexistence.set(position);
vDirtyMask |= View.LEFT_MANUAL_EYE_IN_COEXISTENCE_DIRTY;
}
repaint();
}
/**
* Sets the position of the manual right eye in coexistence
* coordinates. This value determines eye placement when a head
* tracker is not in use and the application is directly controlling
* the eye position in coexistence coordinates. This value is
* ignored when in head-tracked mode or when the
* windowEyePointPolicy is <i>not</i> RELATIVE_TO_COEXISTENCE.
*
* @param position the new manual right eye position
*
* @since Java 3D 1.2
*/
public void setRightManualEyeInCoexistence(Point3d position) {
synchronized(this) {
rightManualEyeInCoexistence.set(position);
vDirtyMask |= View.RIGHT_MANUAL_EYE_IN_COEXISTENCE_DIRTY;
}
repaint();
}
/**
* Retrieves the position of the user-specified, manual left eye
* in coexistence
* coordinates and copies that value into the object provided.
* @param position the object that will receive the position
*
* @since Java 3D 1.2
*/
public void getLeftManualEyeInCoexistence(Point3d position) {
position.set(leftManualEyeInCoexistence);
}
/**
* Retrieves the position of the user-specified, manual right eye
* in coexistence
* coordinates and copies that value into the object provided.
* @param position the object that will receive the position
*
* @since Java 3D 1.2
*/
public void getRightManualEyeInCoexistence(Point3d position) {
position.set(rightManualEyeInCoexistence);
}
/**
* Sets the view model's front clip distance.
* This value specifies the distance away from the eyepoint
* in the direction of gaze where objects stop disappearing.
* Objects closer to the eye than the front clip
* distance are not drawn. The default value is 0.1 meters.
* <p>
* There are several considerations that need to be taken into
* account when choosing values for the front and back clip
* distances.
* <ul>
* <li>The front clip distance must be greater than
* 0.0 in physical eye coordinates.</li>
* <li>The front clipping plane must be in front of the
* back clipping plane, that is, the front clip distance
* must be less than the back clip distance in physical eye
* coordinates.</li>
* <li>The front and back clip distances, in physical
* eye coordinates, must be less than the largest positive
* single-precision floating point value, <code>Float.MAX_VALUE</code>.
* In practice, since these physical eye coordinate distances are in
* meters, the values should be <i>much</i> less than that.
* <li>The ratio of the back distance divided by the front distance,
* in physical eye coordinates, affects Z-buffer precision. This
* ratio should be less than about 3000 in order to accommodate 16-bit
* Z-buffers. Values of 100 to less than 1000 will produce better
* results.</li>
* </ul>
* Violating any of the above rules will result in undefined
* behavior. In many cases, no picture will be drawn.
*
* @param distance the new front clip distance
* @see #setBackClipDistance
*/
public void setFrontClipDistance(double distance) {
synchronized(this) {
this.frontClipDistance = distance;
vDirtyMask |= View.CLIP_DIRTY;
}
repaint();
}
/**
* Returns the view model's front clip distance.
* @return the current front clip distance
*/
public double getFrontClipDistance() {
return this.frontClipDistance;
}
/**
* Sets the view model's back clip distance.
* The parameter specifies the distance from the eyepoint
* in the direction of gaze to where objects begin disappearing.
* Objects farther away from the eye than the
* back clip distance are not drawn.
* The default value is 10.0 meters.
* <p>
* There are several considerations that need to be taken into
* account when choosing values for the front and back clip
* distances. These are enumerated in the description of
* <a href=#setFrontClipDistance(double)>setFrontClipDistance</a>.
* <p>
* Note that this attribute is only used if there is no Clip node
* that is in scope of the view platform associated with this view.
* @param distance the new back clip distance
* @see #setFrontClipDistance
* @see Clip#setBackDistance
*/
public void setBackClipDistance(double distance) {
synchronized(this) {
this.backClipDistance = distance;
vDirtyMask |= View.CLIP_DIRTY;
}
repaint();
}
/**
* Returns the view model's back clip distance.
* @return the current back clip distance
*/
public double getBackClipDistance() {
return this.backClipDistance;
}
/**
* Retrieves the user-head to virtual-world transform
* and copies that value into the transform provided.
* @param t the Transform3D object that will receive the transform
*/
public void getUserHeadToVworld(Transform3D t) {
if( userHeadToVworldEnable ) {
// get the calculated userHeadToVworld transform
// from the view cache.
// grab the first canvas -- not sure for multiple canvases
Canvas3D canvas = this.canvases.firstElement();
synchronized(canvas.canvasViewCache) {
t.set(canvas.canvasViewCache.getHeadToVworld());
}
}else {
throw new RestrictedAccessException(J3dI18N.getString("View9"));
}
}
/**
* Sets the view model's front clip policy, the policy Java 3D uses
* in computing where to place the front clip plane. The variable
* can contain one of:
* <UL>
* <LI>VIRTUAL_EYE, to specify that the associated distance is
* from the eye and in units of virtual distance
* </LI>
* <LI>PHYSICAL_EYE, to specify that the associated distance is
* from the eye and in units of physical distance (meters)
* </LI>
* <LI>VIRTUAL_SCREEN, to specify that the associated distance is
* from the screen and in units of virtual distance
* </LI>
* <LI>PHYSICAL_SCREEN, to specify that the associated distance is
* from the screen and in units of physical distance (meters)
* </LI>
* </UL>
* The default front clip policy is PHYSICAL_EYE.
* @param policy the new policy, one of PHYSICAL_EYE, PHYSICAL_SCREEN,
* VIRTUAL_EYE, or VIRTUAL_SCREEN
*/
public void setFrontClipPolicy(int policy) {
synchronized(this) {
this.frontClipPolicy = policy;
vDirtyMask |= View.CLIP_DIRTY;
}
repaint();
}
/**
* Returns the view model's current front clip policy.
* @return one of:
* VIRTUAL_EYE, PHYSICAL_EYE, VIRTUAL_SCREEN, or PHYSICAL_SCREEN
*/
public int getFrontClipPolicy() {
return this.frontClipPolicy;
}
/**
* Sets the view model's back clip policy, the policy Java 3D uses
* in computing where to place the back clip plane. The variable
* can contain one of:
* <UL>
* <LI>VIRTUAL_EYE, to specify that the associated distance is
* from the eye and in units of virtual distance
* </LI>
* <LI>PHYSICAL_EYE, to specify that the associated distance is
* from the eye and in units of physical distance (meters)
* </LI>
* <LI>VIRTUAL_SCREEN, to specify that the associated distance is
* from the screen and in units of virtual distance
* </LI>
* <LI>PHYSICAL_SCREEN, to specify that the associated distance is
* from the screen and in units of physical distance (meters)
* </LI>
* </UL>
* The default back clip policy is PHYSICAL_EYE.
* @param policy the new policy, one of PHYSICAL_EYE, PHYSICAL_SCREEN,
* VIRTUAL_EYE, or VIRTUAL_SCREEN
*/
public void setBackClipPolicy(int policy) {
synchronized(this) {
this.backClipPolicy = policy;
vDirtyMask |= View.CLIP_DIRTY;
}
repaint();
}
/**
* Returns the view model's current back clip policy.
* @return one of:
* VIRTUAL_EYE, PHYSICAL_EYE, VIRTUAL_SCREEN, or PHYSICAL_SCREEN
*/
public int getBackClipPolicy() {
return this.backClipPolicy;
}
/**
* Sets the visibility policy for this view. This attribute
* is one of:
* <UL>
* <LI>VISIBILITY_DRAW_VISIBLE, to specify that only visible objects
* are drawn.
* </LI>
* <LI>VISIBILITY_DRAW_INVISIBLE, to specify that only invisible objects
* are drawn.
* </LI>
* <LI>VISIBILITY_DRAW_ALL, to specify that both visible and
* invisible objects are drawn.
* </LI>
* </UL>
* The default visibility policy is VISIBILITY_DRAW_VISIBLE.
*
* @param policy the new policy, one of VISIBILITY_DRAW_VISIBLE,
* VISIBILITY_DRAW_INVISIBLE, or VISIBILITY_DRAW_ALL.
*
* @see RenderingAttributes#setVisible
*
* @since Java 3D 1.2
*/
public void setVisibilityPolicy(int policy) {
synchronized(this) {
this.visibilityPolicy = policy;
vDirtyMask |= View.VISIBILITY_POLICY_DIRTY;
}
if (activeStatus && isRunning) {
J3dMessage vpMessage = new J3dMessage();
vpMessage.universe = universe;
vpMessage.view = this;
vpMessage.type = J3dMessage.UPDATE_VIEW;
vpMessage.threads = J3dThread.UPDATE_RENDER;
vpMessage.args[0] = this;
synchronized(((ViewPlatformRetained)viewPlatform.retained).sphere) {
vpMessage.args[1] = new Float(((ViewPlatformRetained)viewPlatform.
retained).sphere.radius);
}
vpMessage.args[2] = new Integer(OTHER_ATTRS_CHANGED);
vpMessage.args[3] = new Integer(transparencySortingPolicy);
VirtualUniverse.mc.processMessage(vpMessage);
}
}
/**
* Retrieves the current visibility policy.
* @return one of:
* VISIBILITY_DRAW_VISIBLE,
* VISIBILITY_DRAW_INVISIBLE, or VISIBILITY_DRAW_ALL.
*
* @since Java 3D 1.2
*/
public int getVisibilityPolicy() {
return this.visibilityPolicy;
}
/**
* Sets the transparency sorting policy for this view. This attribute
* is one of:
*
* <UL>
* <LI>TRANSPARENCY_SORT_NONE, to specify that no depth sorting of
* transparent objects is performed. Transparent objects are
* drawn after opaque objects, but are not sorted from back to
* front.</LI>
*
* <LI>TRANSPARENCY_SORT_GEOMETRY, to specify that transparent
* objects are depth-sorted on a per-geometry basis. Each
* geometry object of each transparent Shape3D node is drawn from
* back to front. Note that this policy will not split geometry
* into smaller pieces, so intersecting or intertwined objects may
* not be sorted correctly.</LI>
* </UL>
*
* The default policy is TRANSPARENCY_SORT_NONE.
*
* @param policy the new policy, one of TRANSPARENCY_SORT_NONE
* or TRANSPARENCY_SORT_GEOMETRY.
*
* @since Java 3D 1.3
*/
public void setTransparencySortingPolicy(int policy) {
if (policy == transparencySortingPolicy) {
return;
}
transparencySortingPolicy = policy;
if (activeStatus && isRunning) {
J3dMessage vpMessage = new J3dMessage();
vpMessage.universe = universe;
vpMessage.view = this;
vpMessage.type = J3dMessage.UPDATE_VIEW;
vpMessage.threads = J3dThread.UPDATE_RENDER;
vpMessage.args[0] = this;
vpMessage.args[1] = null;
vpMessage.args[2] = new Integer(TRANSP_SORT_POLICY_CHANGED);
vpMessage.args[3] = new Integer(policy);
VirtualUniverse.mc.processMessage(vpMessage);
}
}
/**
* Retrieves the current transparency sorting policy.
* @return one of:
* TRANSPARENCY_SORT_NONE or TRANSPARENCY_SORT_GEOMETRY.
*
* @since Java 3D 1.3
*/
public int getTransparencySortingPolicy() {
return this.transparencySortingPolicy;
}
/**
* Turns head tracking on or off for this view.
* @param flag specifies whether head tracking is enabled or
* disabled for this view
*/
public void setTrackingEnable(boolean flag) {
synchronized(this) {
this.trackingEnable = flag;
vDirtyMask |= View.TRACKING_ENABLE_DIRTY;
}
repaint();
}
/**
* Returns a status flag indicating whether or not head tracking
* is enabled.
* @return a flag telling whether head tracking is enabled
*/
public boolean getTrackingEnable() {
return this.trackingEnable;
}
/**
* Turns on or off the continuous
* updating of the userHeadToVworld transform.
* @param flag enables or disables continuous updating
*/
public void setUserHeadToVworldEnable(boolean flag) {
synchronized(this) {
userHeadToVworldEnable = flag;
vDirtyMask |= View.USER_HEAD_TO_VWORLD_ENABLE_DIRTY;
}
repaint();
}
/**
* Returns a status flag indicating whether or not
* Java 3D is continuously updating the userHeadToVworldEnable transform.
* @return a flag indicating if continuously updating userHeadToVworld
*/
public boolean getUserHeadToVworldEnable() {
return userHeadToVworldEnable;
}
/**
* Computes the sensor to virtual-world transform
* and copies that value into the transform provided.
* The computed transforms takes points in the sensor's coordinate
* system and produces the point's corresponding value in
* virtual-world coordinates.
* @param sensor the sensor in question
* @param t the object that will receive the transform
*/
public void getSensorToVworld(Sensor sensor, Transform3D t) {
// grab the first canvas -- not sure for multiple canvases
Canvas3D canvas = this.canvases.firstElement();
Transform3D localTrans = new Transform3D();
synchronized(canvas.canvasViewCache) {
t.set(canvas.canvasViewCache.getVworldToTrackerBase());
}
t.invert();
sensor.getRead(localTrans);
t.mul(localTrans);
}
/**
* Retrieves the position of the specified Sensor's
* hotspot in virtual-world coordinates
* and copies that value into the position provided.
* This value is derived from other values and is read-only.
* @param sensor the sensor in question
* @param position the variable that will receive the position
*/
public void getSensorHotspotInVworld(Sensor sensor,
Point3f position) {
Transform3D sensorToVworld = new Transform3D();
Point3d hotspot3d = new Point3d();
getSensorToVworld(sensor, sensorToVworld);
sensor.getHotspot(hotspot3d);
position.set(hotspot3d);
sensorToVworld.transform(position);
}
/**
* Retrieves the position of the specified Sensor's
* hotspot in virtual-world coordinates
* and copies that value into the position provided.
* This value is derived from other values and is read-only.
* @param sensor the sensor in question
* @param position the variable that will receive the position
*/
public void getSensorHotspotInVworld(Sensor sensor,
Point3d position) {
Transform3D sensorToVworld = new Transform3D();
getSensorToVworld(sensor, sensorToVworld);
sensor.getHotspot(position);
sensorToVworld.transform(position);
}
/**
* Sets given Canvas3D at the given index position.
* @param canvas3D the given Canvas3D to be set
* @param index the position to be set
* @exception IllegalStateException if the specified canvas is
* a stereo canvas with a monoscopicEyePolicy of CYCLOPEAN_EYE_VIEW,
* and the viewPolicy for this view is HMD_VIEW
* @exception IllegalSharingException if the specified canvas is
* associated with another view
*/
public void setCanvas3D(Canvas3D canvas3D, int index) {
if((viewPolicy == HMD_VIEW) &&
(canvas3D.monoscopicViewPolicy == View.CYCLOPEAN_EYE_VIEW) &&
(!canvas3D.useStereo)){
throw new
IllegalStateException(J3dI18N.getString("View31"));
}
Canvas3D cv;
synchronized(canvasList) {
if (canvas3D.getView() != null)
throw new IllegalSharingException(J3dI18N.getString("View10"));
cv = canvases.elementAt(index);
canvases.setElementAt(canvas3D, index);
removeFromCanvasList(cv);
addToCanvasList(canvas3D);
canvasesDirty = true;
}
canvas3D.setView(this);
cv.setView(null);
if (canvas3D.added) {
evaluateActive();
}
if (cv.added) {
evaluateActive();
}
}
/**
* Gets the Canvas3D at the specified index position.
* @param index the position from which to get Canvas3D object
* @return the Canvas3D at the sprcified index position
*/
public Canvas3D getCanvas3D(int index){
return this.canvases.elementAt(index);
}
/**
* Gets the enumeration object of all the Canvas3Ds.
* @return the enumeration object of all the Canvas3Ds.
*/
public Enumeration<Canvas3D> getAllCanvas3Ds(){
return canvases.elements();
}
/**
* Returns the number of Canvas3Ds in this View.
* @return the number of Canvas3Ds in this View
*
* @since Java 3D 1.2
*/
public int numCanvas3Ds() {
return canvases.size();
}
/**
* Adds the given Canvas3D at the end of the list.
* @param canvas3D the Canvas3D to be added
* @exception IllegalStateException if the specified canvas is
* a stereo canvas with a monoscopicEyePolicy of CYCLOPEAN_EYE_VIEW,
* and the viewPolicy for this view is HMD_VIEW
* @exception IllegalSharingException if the specified canvas is
* associated with another view
*/
public void addCanvas3D(Canvas3D canvas3D){
if((viewPolicy == HMD_VIEW) &&
(canvas3D.monoscopicViewPolicy == View.CYCLOPEAN_EYE_VIEW) &&
(!canvas3D.useStereo)) {
throw new
IllegalStateException(J3dI18N.getString("View31"));
}
synchronized(canvasList) {
if (canvas3D.getView() != null)
throw new IllegalSharingException(J3dI18N.getString("View10"));
canvases.addElement(canvas3D);
addToCanvasList(canvas3D);
canvasesDirty = true;
}
canvas3D.setView(this);
if (canvas3D.added) {
if ((canvas3D.visible || canvas3D.offScreen) &&
canvas3D.firstPaintCalled) {
canvas3D.active = true;
}
evaluateActive();
}
}
/**
* Inserts the Canvas3D at the given index position.
* @param canvas3D the Canvas3D to be inserted
* @param index the position to be inserted at
* @exception IllegalStateException if the specified canvas is
* a stereo canvas with a monoscopicEyePolicy of CYCLOPEAN_EYE_VIEW,
* and the viewPolicy for this view is HMD_VIEW
* @exception IllegalSharingException if the specified canvas is
* associated with another view
*/
public void insertCanvas3D(Canvas3D canvas3D, int index){
if((viewPolicy == HMD_VIEW) &&
(canvas3D.monoscopicViewPolicy == View.CYCLOPEAN_EYE_VIEW) &&
(!canvas3D.useStereo)) {
throw new
IllegalStateException(J3dI18N.getString("View31"));
}
synchronized(canvasList) {
if (canvas3D.getView() != null)
throw new IllegalSharingException(J3dI18N.getString("View10"));
this.canvases.insertElementAt(canvas3D, index);
addToCanvasList(canvas3D);
canvasesDirty = true;
}
canvas3D.setView(this);
if (canvas3D.added) {
if ((canvas3D.visible || canvas3D.offScreen) &&
canvas3D.firstPaintCalled) {
canvas3D.active = true;
}
evaluateActive();
}
}
/**
* Removes the Canvas3D from the given index position.
* @param index the position of Canvas3D object to be removed
*/
public void removeCanvas3D(int index) {
// index -1 is possible if the view is unregistered first
// because viewPlatform is clearLived,
// and then removeCanvas from the view
if (index == -1)
return;
Canvas3D cv;
synchronized(canvasList) {
cv = canvases.elementAt(index);
canvases.removeElementAt(index);
removeFromCanvasList(cv);
canvasesDirty = true;
}
// reset canvas will set view to null also
VirtualUniverse.mc.postRequest(MasterControl.RESET_CANVAS,
cv);
cv.pendingView = null;
computeCanvasesCached();
if (cv.added) {
cv.active = false;
evaluateActive();
}
if (universe != null) {
universe.waitForMC();
}
}
/**
* Retrieves the index of the specified Canvas3D in
* this View's list of Canvas3Ds
*
* @param canvas3D the Canvas3D to be looked up.
* @return the index of the specified Canvas3D;
* returns -1 if the object is not in the list.
*
* @since Java 3D 1.3
*/
public int indexOfCanvas3D(Canvas3D canvas3D) {
return canvases.indexOf(canvas3D);
}
/**
* Removes the specified Canvas3D from this View's
* list of Canvas3Ds.
* If the specified object is not in the list, the list is not modified.
*
* @param canvas3D the Canvas3D to be removed.
*/
public void removeCanvas3D(Canvas3D canvas3D) {
removeCanvas3D(canvases.indexOf(canvas3D));
}
/**
* Removes all Canvas3Ds from this View.
*
* @since Java 3D 1.3
*/
public void removeAllCanvas3Ds() {
LinkedList<Canvas3D> tmpCanvases = new LinkedList<Canvas3D>();
synchronized(canvasList) {
int numCanvases = canvases.size();
// Remove in reverse order to ensure valid indices
for (int index = numCanvases - 1; index >= 0; index--) {
Canvas3D cv = canvases.elementAt(index);
// Record list of canvases to be deleted;
tmpCanvases.add(cv);
canvases.removeElementAt(index);
removeFromCanvasList(cv);
canvasesDirty = true;
}
}
// ISSUE 83: postRequest must *not* be called while holding
// canvasList lock. Holding the lock can cause a deadlock.
Iterator<Canvas3D> iterator = tmpCanvases.iterator();
while (iterator.hasNext()) {
Canvas3D cv = iterator.next();
// reset canvas will set view to null also
VirtualUniverse.mc.postRequest(MasterControl.RESET_CANVAS,
cv);
cv.pendingView = null;
if (cv.added) {
cv.active = false;
}
}
computeCanvasesCached();
evaluateActive();
if (universe != null) {
universe.waitForMC();
}
}
// This adds this canvas and its screen to the screen list.
// Locks are already acquired before this is called.
private void addToCanvasList(Canvas3D c) {
for (int i=screenList.size()-1; i>=0; i--) {
if (screenList.get(i) == c.screen) {
// This is the right screen slot
canvasList.get(i).add(c);
canvasesDirty = true;
return;
}
}
// Add a screen slot
screenList.add(c.screen);
ArrayList<Canvas3D> clist = new ArrayList<Canvas3D>();
canvasList.add(clist);
clist.add(c);
canvasesDirty = true;
}
// This removes this canvas and its screen from the screen list
// Locks are already acquired before this is called.
private void removeFromCanvasList(Canvas3D c) {
for (int i=screenList.size()-1; i>=0; i--) {
if (screenList.get(i) == c.screen) {
// This is the right screen slot
ArrayList<Canvas3D> clist = canvasList.get(i);
clist.remove(clist.indexOf(c));
if (clist.size() == 0) {
canvasList.remove(i);
screenList.remove(i);
canvasesDirty = true;
}
return;
}
}
}
// Locks are not acquired before this is called.
void computeCanvasesCached() {
synchronized (canvasList) {
ArrayList<Canvas3D> cv;
int len = canvases.size();
Canvas3D newCachedCanvases[] = new Canvas3D[len];
for (int i=0; i < len; i++) {
newCachedCanvases[i] = canvases.get(i);
}
// Do this in one instruction so there is no need to
// synchronized getCanvases()
cachedCanvases = newCachedCanvases;
len = 0;
longestScreenList = 0;
cachedCanvasList = new Canvas3D[canvasList.size()][0];
for (int i=0; i < cachedCanvasList.length; i++) {
cv = canvasList.get(i);
len = cv.size();
cachedCanvasList[i] = new Canvas3D[len];
for (int j=0; j < len; j++) {
cachedCanvasList[i][j] = cv.get(j);
}
if (len > longestScreenList) {
longestScreenList = len;
}
}
len = screenList.size();
Screen3D newCachedScreens[] = new Screen3D[len];
for (int i=0; i < len; i++) {
newCachedScreens[i] = screenList.get(i);
}
// Do this in one instruction so there is no need to
// synchronized getScreens()
cachedScreens = newCachedScreens;
canvasesDirty = false;
}
}
// This creates a 2 dimentional list of canvases
// ONLY MC can call this procedure with canCompute=true,
// since MC want the result return by
// evaluateCanvases and updateWorkThreads agree to each other,
// so only evaluateCanvases can compute a new list.
// Other threads should use getCanvasList(false).
Canvas3D[][] getCanvasList(boolean canCompute) {
if (canvasesDirty && canCompute) {
computeCanvasesCached();
}
return cachedCanvasList;
}
// assume getCanvasList is called before
int getLongestScreenList() {
return longestScreenList;
}
// assume getCanvasList is called before
Canvas3D[] getCanvases() {
return cachedCanvases;
}
// assume getCanvasList is called before
Screen3D[] getScreens() {
return cachedScreens;
}
Canvas3D getFirstCanvas() {
synchronized (canvasList) {
if (canvases.size() > 0) {
return canvases.elementAt(0);
}
return null;
}
}
/**
* This method returns the time at which the most recent rendering
* frame started. It is defined as the number of milliseconds
* since January 1, 1970 00:00:00 GMT.
* Since multiple canvases might be attached to this View,
* the start of a frame is defined as the point in time just prior
* to clearing any canvas attached to this view.
* @return the time at which the most recent rendering frame started
*/
public long getCurrentFrameStartTime() {
synchronized (frameStartTimes) {
return currentFrameStartTime;
}
}
/**
* This method returns the duration, in milliseconds, of the most
* recently completed rendering frame. The time taken to render
* all canvases attached to this view is measured. This duration
* is computed as the difference between the start of the most recently
* completed frame and the end of that frame.
* Since multiple canvases might be attached to this View,
* the start of a frame is defined as the point in time just prior
* to clearing any canvas attached to this view--before preRender
* is called for any canvas. Similarly, the end of a frame is
* defined as the point in time just after swapping the buffer for
* all canvases--after postSwap is called for all canvases.
* Note that since the frame duration is measured from start to stop
* for this view only, the value returned is not the same as
* frame rate; it measures only the rendering time for this view.
*
* @return the duration, in milliseconds, of the most recently
* completed rendering frame
*/
public long getLastFrameDuration() {
synchronized (frameStartTimes) {
return currentFrameDuration;
}
}
/**
* This method returns the frame number for this view. The frame
* number starts at 0 and is incremented at the start of each
* frame--prior to clearing all the canvases attached to this
* view.
*
* @return the current frame number for this view
*/
public long getFrameNumber() {
synchronized (frameStartTimes) {
return currentFrameNumber;
}
}
/**
* Retrieves the implementation-dependent maximum number of
* frames whose start times will be recorded by the system. This
* value is guaranteed to be at least 10 for all implementations
* of the Java 3D API.
* @return the maximum number of frame start times recorded
*/
public static int getMaxFrameStartTimes() {
return (NUMBER_FRAME_START_TIMES);
}
/**
* Copies the last <i>k</i> frame start time values into
* the user-specified array. The most recent frame start time is
* copied to location 0 of the array, the next most recent frame
* start time is copied into location 1 of the array, and so forth.
* If times.length is smaller than
* maxFrameStartTimes, then only the last times.length values are
* copied. If times.length is greater than maxFrameStartTimes,
* then all array elements after index maxFrameStartTimes-1 are
* set to 0.
*
* @return the frame number of the most recent frame in the array
*
* @see #setMinimumFrameCycleTime
*/
public long getFrameStartTimes(long[] times) {
int index, i, loopCount;
long lastFrameNumber;
synchronized (frameStartTimes) {
index = currentFrameIndex - 1;
if (index < 0) {
index = NUMBER_FRAME_START_TIMES - 1;
}
lastFrameNumber = frameNumbers[index];
if (times.length <= NUMBER_FRAME_START_TIMES) {
loopCount = times.length;
} else {
loopCount = NUMBER_FRAME_START_TIMES;
}
for (i=0; i<loopCount; i++) {
times[i] = frameStartTimes[index];
index--;
if (index < 0) {
index = NUMBER_FRAME_START_TIMES - 1;
}
}
if (times.length > NUMBER_FRAME_START_TIMES) {
for (; i<times.length; i++) {
times[i] = 0;
}
}
}
return (lastFrameNumber);
}
/**
* Sets the minimum frame cycle time, in milliseconds, for this
* view. The Java 3D renderer will ensure that the time between
* the start of each successive frame is at least the specified
* number of milliseconds. The default value is 0.
*
* @param minimumTime the minimum number of milliseconds between
* successive frames
*
* @exception IllegalArgumentException if <code>minimumTime < 0</code>
*
* @see #getFrameStartTimes
*
* @since Java 3D 1.2
*/
public void setMinimumFrameCycleTime(long minimumTime) {
if (minimumTime < 0L)
throw new IllegalArgumentException(J3dI18N.getString("View27"));
minFrameCycleTime = minimumTime;
VirtualUniverse.mc.setWork();
}
/**
* Retrieves the minimum frame cycle time, in milliseconds, for this view.
* @return the minimum frame cycle time for this view.
*
* @see #getFrameStartTimes
*
* @since Java 3D 1.2
*/
public long getMinimumFrameCycleTime() {
return minFrameCycleTime;
}
/**
* This adds a frame time to the this of frame times
*/
void setFrameTimingValues() {
synchronized (frameStartTimes) {
if (currentFrameIndex == NUMBER_FRAME_START_TIMES) {
currentFrameIndex = 0;
}
frameNumbers[currentFrameIndex] = frameNumber;
frameStartTimes[currentFrameIndex++] = startTime;
currentFrameStartTime = startTime;
currentFrameDuration = stopTime - startTime;
currentFrameNumber = frameNumber;
}
}
/**
* Return true if maximum fps impose by user reach
*/
void computeCycleTime() {
if (minFrameCycleTime == 0) {
isMinCycleTimeAchieve = true;
sleepTime = 0;
} else {
sleepTime = minFrameCycleTime -
(J3dClock.currentTimeMillis() - startTime);
isMinCycleTimeAchieve = (sleepTime <= 0);
}
}
/**
* Enables or disables automatic freezing of the depth buffer for
* objects rendered
* during the transparent rendering pass (i.e., objects rendered
* using alpha blending) for this view.
* If enabled, depth buffer writes will be disabled during the
* transparent rendering pass regardless of the value of
* the depth buffer write enable flag in the RenderingAttributes
* object for a particular node.
* This flag is enabled by default.
* @param flag indicates whether automatic freezing of the depth buffer
* for transparent/antialiased objects is enabled.
* @see RenderingAttributes#setDepthBufferWriteEnable
*/
public void setDepthBufferFreezeTransparent(boolean flag) {
depthBufferFreezeTransparent = flag;
repaint();
}
/**
* Retrieves the current value of the depth buffer freeze transparent
* flag for this view.
* @return a flag that indicates whether or not the depth
* buffer is automatically frozen during the transparent rendering pass.
*/
public boolean getDepthBufferFreezeTransparent() {
return depthBufferFreezeTransparent;
}
/**
* Enables or disables scene antialiasing for this view.
* If enabled, the entire scene will be antialiased on
* each canvas in which scene antialiasing is available.
* Scene antialiasing is disabled by default.
* <p>
* NOTE: Scene antialiasing is ignored in pure immediate mode,
* but is supported in mixed-immediate mode.
* @param flag indicates whether scene antialiasing is enabled
*
* @see Canvas3D#queryProperties
*/
public void setSceneAntialiasingEnable(boolean flag) {
sceneAntialiasingEnable = flag;
repaint();
}
/**
* Returns a flag that indicates whether or not scene antialiasing
* is enabled for this view.
* @return a flag that indicates whether scene antialiasing is enabled
*/
public boolean getSceneAntialiasingEnable() {
return sceneAntialiasingEnable;
}
/**
* Sets a flag that indicates whether the local eyepoint is used in
* lighting calculations for perspective projections.
* If this flag is set to true, the view vector is calculated per-vertex
* based on the direction from the actual eyepoint to the vertex.
* If this flag is set to false, a single view vector is computed from
* the eyepoint to the center of the view frustum. This is
* called infinite eye lighting.
* Local eye lighting is disabled by default, and is ignored for
* parallel projections.
* @param flag indicates whether local eye lighting is enabled
*/
public void setLocalEyeLightingEnable(boolean flag) {
localEyeLightingEnable = flag;
repaint();
}
/**
* Retrieves a flag that indicates whether or not local eye lighting
* is enabled for this view.
* @return a flag that indicates whether local eye lighting is enabled
*/
public boolean getLocalEyeLightingEnable() {
return localEyeLightingEnable;
}
/**
* Attach viewPlatform structure to this view.
* @param vp the viewPlatform to be attached
*/
public void attachViewPlatform(ViewPlatform vp) {
if ((vp != null) && (vp == viewPlatform)) {
return;
}
if (viewPlatform != null) {
((ViewPlatformRetained)viewPlatform.retained).removeView(this);
if (viewPlatform.isLive()) {
synchronized (evaluateLock) {
viewPlatform = null;
// cleanup View stuff for the old platform
evaluateActive();
viewPlatform = vp;
}
if (universe != null) {
universe.waitForMC();
}
} else {
viewPlatform = vp;
}
} else {
viewPlatform = vp;
}
if (vp != null) {
if (vp.isLive()) {
checkView();
setUniverse(((ViewPlatformRetained)vp.retained).universe);
}
((ViewPlatformRetained)vp.retained).setView(this);
}
evaluateActive();
if ((vp == null) && (universe != null)) {
universe.waitForMC();
}
}
/**
* Retrieves the currently attached ViewPlatform object
* @return the currently attached ViewPlatform
*/
public ViewPlatform getViewPlatform() {
return viewPlatform;
}
/**
* Checks view parameters for consistency
*/
void checkView() {
if (physicalBody == null)
throw new IllegalStateException(J3dI18N.getString("View13"));
if (physicalEnvironment == null)
throw new IllegalStateException(J3dI18N.getString("View14"));
}
/**
* Stops the behavior scheduler after all
* currently scheduled behaviors are executed. Any frame-based
* behaviors scheduled to wake up on the next frame will be
* executed at least once before the behavior scheduler is
* stopped.
* <p>
* NOTE: This is a heavy-weight method
* intended for verification and image capture (recording); it
* is <i>not</i> intended to be used for flow control.
* @return a pair of integers that specify the beginning and ending
* time (in milliseconds since January 1, 1970 00:00:00 GMT)
* of the behavior scheduler's last pass
* @exception IllegalStateException if this method is called
* from a Behavior method or from any Canvas3D render callback
* method
*/
public final long[] stopBehaviorScheduler() {
long[] intervalTime = new long[2];
if (checkBehaviorSchedulerState("View15", "View16")) {
if (activeStatus && isRunning &&
(universe.behaviorScheduler != null)) {
// view is active
universe.behaviorScheduler.stopBehaviorScheduler(intervalTime);
} else {
if ((universe != null) &&
(universe.behaviorScheduler != null)) {
universe.behaviorScheduler.userStop = true;
}
}
}
stopBehavior = true;
return intervalTime;
}
/**
* Starts the behavior scheduler running after it has been stopped.
* @exception IllegalStateException if this method is called
* from a Behavior method or from any Canvas3D render callback
* method
*/
public final void startBehaviorScheduler() {
if (checkBehaviorSchedulerState("View17", "View18")) {
if (activeStatus && isRunning &&
(universe.behaviorScheduler != null)) {
universe.behaviorScheduler.startBehaviorScheduler();
} else {
if ((universe != null) &&
(universe.behaviorScheduler != null)) {
universe.behaviorScheduler.userStop = false;
}
}
}
stopBehavior = false;
}
/**
* Check if BehaviorScheduler is in valid state to start/stop
* itself.
* @param s1 Exception String if method is called from a Canvas3D
* @param s2 Exception String if method is called from a Behavior method
* @return true if viewPlatform is live
* @exception IllegalStateException if this method is called
* from a Behavior method or from any Canvas3D render callback
* method
*
*/
boolean checkBehaviorSchedulerState(String s1, String s2) {
Thread me = Thread.currentThread();
if (inCanvasCallback) {
synchronized (canvasList) {
for (int i=canvases.size()-1; i>=0; i--) {
if (canvases.elementAt(i).screen.renderer == me) {
throw new IllegalStateException(J3dI18N.getString(s1));
}
}
}
}
if ((viewPlatform != null) && viewPlatform.isLive()) {
if (universe.inBehavior && (universe.behaviorScheduler == me)) {
throw new IllegalStateException(J3dI18N.getString(s2));
}
return true;
}
return false;
}
/**
* Retrieves a flag that indicates whether the behavior scheduler is
* currently running.
* @return true if the behavior scheduler is running, false otherwise
* @exception IllegalStateException if this method is called
* from a Behavior method or from any Canvas3D render callback
* method
*/
public final boolean isBehaviorSchedulerRunning() {
return (((universe != null) && !stopBehavior &&
(universe.behaviorScheduler != null)) ?
!universe.behaviorScheduler.userStop : false);
}
/**
* Stops traversing the scene graph for this
* view after the current state of the scene graph is reflected on
* all canvases attached to this view. The renderers associated
* with these canvases are also stopped.
* <p>
* NOTE: This is a heavy-weight method
* intended for verification and image capture (recording); it
* is <i>not</i> intended to be used for flow control.
* @exception IllegalStateException if this method is called
* from a Behavior method or from any Canvas3D render callback
* method
*/
public final void stopView() {
checkViewState("View19", "View20");
synchronized (startStopViewLock) {
if (activeStatus && isRunning) {
VirtualUniverse.mc.postRequest(MasterControl.STOP_VIEW, this);
while (isRunning) {
MasterControl.threadYield();
}
} else {
isRunning = false;
}
}
}
/**
* Starts
* traversing this view, and starts the renderers associated
* with all canvases attached to this view.
* @exception IllegalStateException if this method is called
* from a Behavior method or from any Canvas3D render callback
* method
*/
public final void startView() {
checkViewState("View21", "View22");
synchronized (startStopViewLock) {
if (activeStatus && !isRunning) {
VirtualUniverse.mc.postRequest(MasterControl.START_VIEW, this);
while (!isRunning) {
MasterControl.threadYield();
}
VirtualUniverse.mc.sendRunMessage(this,
J3dThread.RENDER_THREAD);
} else {
isRunning = true;
}
}
}
/**
* This will throw IllegalStateException if not in valid state
* for start/stop request.
*/
void checkViewState(String s1, String s2) throws IllegalStateException {
if (inCanvasCallback) {
Thread me = Thread.currentThread();
synchronized (canvasList) {
for (int i= canvases.size()-1; i>=0; i--) {
Canvas3D cv = canvases.elementAt(i);
if (cv.screen.renderer == me) {
throw new
IllegalStateException(J3dI18N.getString(s1));
}
}
}
}
if ((viewPlatform != null) && viewPlatform.isLive()) {
if (universe.inBehavior &&
(Thread.currentThread() == universe.behaviorScheduler)) {
throw new IllegalStateException(J3dI18N.getString(s2));
}
}
}
/**
* Retrieves a flag that indicates whether the traverser is
* currently running on this view.
* @return true if the traverser is running, false otherwise
* @exception IllegalStateException if this method is called
* from a Behavior method or from any Canvas3D render callback
* method
*/
public final boolean isViewRunning() {
return isRunning;
}
/**
* Renders one frame for a stopped View. Functionally, this
* method is equivalent to <code>startView()</code> followed by
* <code>stopview()</code>, except that it is atomic, which
* guarantees that only one frame is rendered.
*
* @exception IllegalStateException if this method is called from
* a Behavior method or from any Canvas3D render callback, or if
* the view is currently running.
*
* @since Java 3D 1.2
*/
public void renderOnce() {
checkViewState("View28", "View29");
synchronized (startStopViewLock) {
if (isRunning) {
throw new IllegalStateException(J3dI18N.getString("View30"));
}
renderOnceFinish = false;
VirtualUniverse.mc.postRequest(MasterControl.RENDER_ONCE, this);
while (!renderOnceFinish) {
MasterControl.threadYield();
}
renderOnceFinish = true;
}
}
/**
* Requests that this View be scheduled for rendering as soon as
* possible. The repaint method may return before the frame has
* been rendered. If the view is stopped, or if the view is
* continuously running (for example, due to a free-running
* interpolator), this method will have no effect. Most
* applications will not need to call this method, since any
* update to the scene graph or to viewing parameters will
* automatically cause all affected views to be rendered.
*
* @since Java 3D 1.2
*/
public void repaint() {
if (activeStatus && isRunning) {
VirtualUniverse.mc.sendRunMessage(this,
J3dThread.RENDER_THREAD);
}
}
/**
* Update the view cache associated with this view. Also, shapshot
* the per-screen parameters associated with all screens attached
* to this view.
*/
final void updateViewCache() {
synchronized(this) {
viewCache.snapshot();
viewCache.computeDerivedData();
}
// Just take the brute force approach and snapshot the
// parameters for each screen attached to each canvas. We won't
// worry about whether a screen is cached more than once.
// Eventually, dirty bits will take care of this.
synchronized (canvasList) {
int i = canvases.size()-1;
while (i>=0) {
Screen3D scr = canvases.elementAt(i--).getScreen3D();
if (scr != null)
scr.updateViewCache();
}
}
}
/**
* This routine activates or deactivates a view based on various information
*/
void evaluateActive() {
synchronized (evaluateLock) {
if (universe == null) {
return;
}
if ((viewPlatform == null) ||
!viewPlatform.isLive() ||
!((ViewPlatformRetained)viewPlatform.retained).switchState.currentSwitchOn) {
if (activeStatus) {
deactivate();
activeStatus = false;
}
// Destroy threads from MC
if (VirtualUniverse.mc.isRegistered(this) &&
(universe.isEmpty() ||
(canvases.isEmpty() &&
((viewPlatform == null) ||
!viewPlatform.isLive())))) {
// We can't wait until MC finish unregister view
// here because user thread may
// holds the universe.sceneGraphLock if branch
// or locale remove in clearLive(). In this way
// There is deadlock since MC also need need
// sceneGraphLock in some threads
// (e.g. TransformStructure update thread)
universe.unRegViewWaiting = this;
resetUnivCount = universeCount;
VirtualUniverse.mc.postRequest(
MasterControl.UNREGISTER_VIEW, this);
}
} else {
// We're on a live view platform. See what the canvases say
// If view not register, MC will register it automatically
int i;
VirtualUniverse u = null;
synchronized (canvasList) {
for (i=canvases.size()-1; i>=0; i--) {
Canvas3D cv = canvases.elementAt(i);
if (cv.active) {
if (!activeStatus && (universeCount > resetUnivCount)) {
u = universe;
}
break;
}
}
}
// We should do this outside canvasList lock,
// otherwise it may cause deadlock with MC
if (u != null) {
activate(u);
activeStatus = true;
return;
}
if ((i < 0) && activeStatus) {
deactivate();
activeStatus = false;
return;
}
if (VirtualUniverse.mc.isRegistered(this)) {
// notify MC that canvases state for this view changed
VirtualUniverse.mc.postRequest(
MasterControl.REEVALUATE_CANVAS, this);
}
}
}
}
void setUniverse(VirtualUniverse universe) {
synchronized (VirtualUniverse.mc.requestObjList) {
if ((renderBin == null) ||
(renderBin.universe != universe)) {
if (renderBin != null) {
renderBin.cleanup();
}
renderBin = new RenderBin(universe, this);
renderBin.universe = universe;
}
if ((soundScheduler == null) ||
(soundScheduler.universe != universe)) {
// create a sound scheduler for this view, with this universe
if (soundScheduler != null) {
soundScheduler.cleanup();
}
soundScheduler = new SoundScheduler(universe, this);
}
// This has to be the last call before
// RenderBin and SoundScheduler construct. Since it is
// possible that canvas receive paint call and invoked
// evaluateActive in another thread - which check for
// universe == null and may let it pass before soundScheduler
// and renderBin initialize.
universeCount++;
this.universe = universe;
}
evaluateActive();
}
/**
* This activates all traversers and renderers associated with this view.
*/
void activate(VirtualUniverse universe) {
universe.checkForEnableEvents();
if (physicalBody != null) {
physicalBody.addUser(this);
}
if (!VirtualUniverse.mc.isRegistered(this)) {
universe.regViewWaiting = this;
}
VirtualUniverse.mc.postRequest(MasterControl.ACTIVATE_VIEW,
this);
if (!universe.isSceneGraphLock) {
universe.waitForMC();
}
if (soundScheduler != null) {
soundScheduler.reset();
}
J3dMessage vpMessage = new J3dMessage();
vpMessage.universe = universe;
vpMessage.view = this;
vpMessage.type = J3dMessage.UPDATE_VIEW;
vpMessage.threads =
J3dThread.SOUND_SCHEDULER |
J3dThread.UPDATE_RENDER |
J3dThread.UPDATE_BEHAVIOR;
vpMessage.args[0] = this;
synchronized(((ViewPlatformRetained)viewPlatform.retained).sphere) {
vpMessage.args[1] = new Float(((ViewPlatformRetained)viewPlatform.retained).sphere.radius);
}
vpMessage.args[2] = new Integer(OTHER_ATTRS_CHANGED);
vpMessage.args[3] = new Integer(transparencySortingPolicy);
VirtualUniverse.mc.processMessage(vpMessage);
}
/**
* This deactivates all traversers and renderers associated with this view.
*/
void deactivate() {
VirtualUniverse.mc.postRequest(MasterControl.DEACTIVATE_VIEW, this);
if (physicalBody != null) {
physicalBody.removeUser(this);
}
// This is a temporary fix for bug 4267395
// XXXX:cleanup in RenderBin after View detach
// universe.addViewIdToFreeList(viewId);
// using new property -Dj3d.forceReleaseView to disable bug fix 4267395
// this bug fix can produce memory leaks in *some* applications which creates
// and destroy Canvas3D from time to time. This just add the view in the
// FreeList earlier.
if (VirtualUniverse.mc.forceReleaseView) {
universe.addViewIdToFreeList(viewId);
}
J3dMessage vpMessage = new J3dMessage();
vpMessage.universe = universe;
vpMessage.view = this;
vpMessage.type = J3dMessage.UPDATE_VIEW;
vpMessage.threads =
J3dThread.SOUND_SCHEDULER |
J3dThread.UPDATE_RENDER |
J3dThread.UPDATE_BEHAVIOR;
vpMessage.args[0] = this;
if (viewPlatform != null) {
synchronized(((ViewPlatformRetained)viewPlatform.retained).sphere) {
vpMessage.args[1] = new Float(((ViewPlatformRetained)viewPlatform.retained).sphere.radius);
}
} else {
vpMessage.args[1] = new Float(0);
}
vpMessage.args[2] = new Integer(OTHER_ATTRS_CHANGED);
vpMessage.args[3] = new Integer(transparencySortingPolicy);
VirtualUniverse.mc.processMessage(vpMessage);
}
void cleanupViewId() {
universe.addViewIdToFreeList(viewId);
viewId = null;
}
void assignViewId () {
if (viewId == null) {
viewId = universe.getViewId();
viewIndex = viewId.intValue();
}
}
/**
* This method passes window event to SoundScheduler
*/
void sendEventToSoundScheduler(AWTEvent evt) {
if (soundScheduler != null) {
soundScheduler.receiveAWTEvent(evt);
}
}
void reset() {
for (int i=0; i < canvases.size(); i++) {
canvases.get(i).reset();
}
// reset the renderBinReady flag
renderBinReady = false;
soundScheduler.cleanup();
soundScheduler = null;
viewCache = new ViewCache(this);
getCanvasList(true);
cleanupViewId();
renderBin.cleanup();
renderBin = null;
universe = null;
}
}