Package javax.media.j3d

Source Code of javax.media.j3d.View

/*
* 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 s2throws 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;
    }
}
TOP

Related Classes of javax.media.j3d.View

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.