/* * 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. *
* 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. *
* Java 3D allows applications to specify multiple simultaneously active * View objects, each controlling its own set of canvases. *
* 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. *
* Policies
* * The View object defines the following policies:
*
*
*
*
*
*
*
*
screenScale = physicalScreenWidth / 2.0
*
screenScale
attribute (see the
* setScreenScale method description).*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
* The projection and clip parameters determine the view model's * field of view and the front and back clipping distances.
*
*
*
* There are several considerations to take into account when * choosing values for the front and back clip distances.
*
*
*
*
*
*
* * There are five methods used to get information about system * execution and performance:
*
getCurrentFrameStartTime
returns the time at which
* the most recent rendering frame started.
* getLastFrameDuration
returns the duration, in milliseconds, of
* the most recently completed rendering frame.
* getFrameNumber
returns the frame number for this view.
* getMaxFrameStartTimes
retrieves the implementation-dependent
* maximum number of frames whose start times will be recorded by
* the system.
* getFrameStartTimes
copies the last k frame start time values
* into the user-specified array.
*
* The following methods control the traversal, the rendering, and * the execution of the behavior scheduler for this view:
*
startBehaviorScheduler
starts the behavior scheduler
* running after it has been stopped.
* stopBehaviorScheduler
stops the behavior scheduler after all
* currently-scheduled behaviors are executed.
* isBehaviorSchedulerRunning
retrieves a flag that indicates
* whether the behavior scheduler is currently running.
* startView
starts traversing this view and starts the renderers
* associated with all canvases attached to this view.
* stopView
stops traversing this view after the current state of
* the scene graph is reflected on all canvases attached to this
* view.
* isViewRunning
returns a flag indicating whether the traverser
* is currently running on this view.
*
* * Scene Antialiasing
* * 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.
*
setSceneAntialiasingEnable
sets the scene antialiasing flag.
* getSceneAntialiasingEnable
returns the scene antialiasing
* flag.
*
* Note: Scene antialiasing is ignored in pure immediate mode, * but is supported in mixed-immediate mode. *
* Depth Buffer
* * 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.
*
setDepthBufferFreezeTransparent
enables depth buffer freezing.
* getDepthBufferFreezeTransparent
retrieves the depth buffer
* flag.
*
* * Sensors
* * The following methods retrieve the sensor's location in the * virtual world:
*
getSensorToVworld
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.
*
* getSensorHotSpotInVworld
retrieves the specified sensor's
* last hotspot location in virtual world coordinates.
*
* * 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.
* 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.
*
setCompatibilityModeEnable
turns compatibility mode on or off.
* Compatibility mode is disabled by default.
* getCompatabilityModeEnable
returns the compatibility mode
* enable flag.
*
* * Setting the Viewing Transform
* * The View object provides the following compatibility-mode * methods that operate on the viewing transform.
*
setVpcToEc
a compatibility mode method that
* specifies the ViewPlatform
* coordinates (VPC) to eye coordinates viewing transform.
* getVpcToEc
returns the VPC.
*
* The View object provides the following compatibility-mode * methods that operate on the projection transform:
*
setLeftProjection
and setRightProjection
* methods specify
* a viewing frustum for the left and right eye that transforms
* points in eye coordinates to clipping coordinates.
*
* The getLeftProjection
and getRightProjection
* methods return
* the viewing frustum for the left and right eye.
*
* Additional Information *
* For more information, see the * Introduction to the Java 3D API and * View Model * 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: *
* 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
* 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 not
* 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 not 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 not 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.
*
* There are several considerations that need to be taken into
* account when choosing values for the front and back clip
* distances.
*
* 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
* setFrontClipDistance.
*
* 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:
*
* 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.
*
* NOTE: This is a heavy-weight method
* intended for verification and image capture (recording); it
* is not 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.
*
* NOTE: This is a heavy-weight method
* intended for verification and image capture (recording); it
* is not intended to be used for flow control.
* @exception IllegalStateException if this method is called
* from a Behavior method or from any Canvas3D render callback
* method
*/
public final void stopView() {
checkViewState("View19", "View20");
synchronized (startStopViewLock) {
if (activeStatus && isRunning) {
VirtualUniverse.mc.postRequest(MasterControl.STOP_VIEW, this);
while (isRunning) {
MasterControl.threadYield();
}
} else {
isRunning = false;
}
}
}
/**
* Starts
* traversing this view, and starts the renderers associated
* with all canvases attached to this view.
* @exception IllegalStateException if this method is called
* from a Behavior method or from any Canvas3D render callback
* method
*/
public final void startView() {
checkViewState("View21", "View22");
synchronized (startStopViewLock) {
if (activeStatus && !isRunning) {
VirtualUniverse.mc.postRequest(MasterControl.START_VIEW, this);
while (!isRunning) {
MasterControl.threadYield();
}
VirtualUniverse.mc.sendRunMessage(this,
J3dThread.RENDER_THREAD);
} else {
isRunning = true;
}
}
}
/**
* This will throw IllegalStateException if not in valid state
* for start/stop request.
*/
void checkViewState(String s1, String s2) throws IllegalStateException {
if (inCanvasCallback) {
Thread me = Thread.currentThread();
synchronized (canvasList) {
for (int i= canvases.size()-1; i>=0; i--) {
Canvas3D cv = canvases.elementAt(i);
if (cv.screen.renderer == me) {
throw new
IllegalStateException(J3dI18N.getString(s1));
}
}
}
}
if ((viewPlatform != null) && viewPlatform.isLive()) {
if (universe.inBehavior &&
(Thread.currentThread() == universe.behaviorScheduler)) {
throw new IllegalStateException(J3dI18N.getString(s2));
}
}
}
/**
* Retrieves a flag that indicates whether the traverser is
* currently running on this view.
* @return true if the traverser is running, false otherwise
* @exception IllegalStateException if this method is called
* from a Behavior method or from any Canvas3D render callback
* method
*/
public final boolean isViewRunning() {
return isRunning;
}
/**
* Renders one frame for a stopped View. Functionally, this
* method is equivalent to
* view policy : SCREEN_VIEW
*/
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.
*
* projection policy : PERSPECTIVE_PROJECTION
* screen scale policy : SCALE_SCREEN_SIZE
* window resize policy : PHYSICAL_WORLD
* window movement policy : PHYSICAL_WORLD
* window eyepoint policy : RELATIVE_TO_FIELD_OF_VIEW
* monoscopic view policy : CYCLOPEAN_EYE_VIEW
* front clip policy : PHYSICAL_EYE
* back clip policy : PHYSICAL_EYE
* visibility policy : VISIBILITY_DRAW_VISIBLE
* transparency sorting policy : TRANSPARENCY_SORT_NONE
* coexistenceCentering flag : true
* compatibility mode : false
* left projection : identity
* right projection : identity
* vpc to ec transform : identity
* physical body : null
* physical environment : null
* screen scale : 1.0
* field of view : PI/4
* left manual eye in coexistence : (-0.033, 0.0, 0.4572)
* right manual eye in coexistence : (0.033, 0.0, 0.4572)
* front clip distance : 0.1
* back clip distance : 10.0
* tracking enable : false
* user head to vworld enable : false
* list of Canvas3D objects : empty
* depth buffer freeze transparent : true
* scene antialiasing : false
* local eye lighting : false
* view platform : null
* behavior scheduler running : true
* view running : true
* minimum frame cycle time : 0
*
*
* 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:
*
*
* 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
* Canvas3D.setMonoscopicViewPolicy
*/
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
* Canvas3D.getMonoscopicViewPolicy
*/
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.
*
*
*
* 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.
* Float.MAX_VALUE
.
* In practice, since these physical eye coordinate distances are in
* meters, the values should be much less than that.
*
*
* 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:
*
*
* 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:
*
*
* 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:
*
*
*
*
* 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 EnumerationstartView()
followed by
* stopview()
, 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;
}
}