aboutsummaryrefslogtreecommitdiffstats
path: root/src/javax/media/j3d/Canvas3D.java
diff options
context:
space:
mode:
authorHarvey Harrison <[email protected]>2015-04-19 21:02:06 -0700
committerHarvey Harrison <[email protected]>2015-04-19 21:02:06 -0700
commit7a2e20caac9db6f789a7b3fab344b9758af45335 (patch)
treeb5236ff2570178de356eab569225108948eb4d30 /src/javax/media/j3d/Canvas3D.java
parentf76ce302c4bb2a9f03bbee571ec5d05c29633023 (diff)
j3dcore: flatten the directory structure a bit
Signed-off-by: Harvey Harrison <[email protected]>
Diffstat (limited to 'src/javax/media/j3d/Canvas3D.java')
-rw-r--r--src/javax/media/j3d/Canvas3D.java4951
1 files changed, 4951 insertions, 0 deletions
diff --git a/src/javax/media/j3d/Canvas3D.java b/src/javax/media/j3d/Canvas3D.java
new file mode 100644
index 0000000..080bd18
--- /dev/null
+++ b/src/javax/media/j3d/Canvas3D.java
@@ -0,0 +1,4951 @@
+/*
+ * Copyright 1997-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.awt.Canvas;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.IllegalComponentStateException;
+import java.awt.Point;
+import java.awt.Window;
+import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+
+import javax.vecmath.Color3f;
+import javax.vecmath.Point2d;
+import javax.vecmath.Point3d;
+import javax.vecmath.Vector4d;
+
+
+/**
+ * The Canvas3D class provides a drawing canvas for 3D rendering. It
+ * is used either for on-screen rendering or off-screen rendering.
+ * Canvas3D is an extension of the AWT Canvas class that users may
+ * further subclass to implement additional functionality.
+ * <p>
+ * The Canvas3D object extends the Canvas object to include
+ * 3D-related information such as the size of the canvas in pixels,
+ * the Canvas3D's location, also in pixels, within a Screen3D object,
+ * and whether or not the canvas has stereo enabled.
+ * <p>
+ * Because all Canvas3D objects contain a
+ * reference to a Screen3D object and because Screen3D objects define
+ * the size of a pixel in physical units, Java 3D can convert a Canvas3D
+ * size in pixels to a physical world size in meters. It can also
+ * determine the Canvas3D's position and orientation in the
+ * physical world.
+ * <p>
+ * <b>On-screen Rendering vs. Off-screen Rendering</b>
+ * <p>
+ * The Canvas3D class is used either for on-screen rendering or
+ * off-screen rendering.
+ * On-screen Canvas3Ds are added to AWT or Swing Container objects
+ * like any other canvas. Java 3D automatically and continuously
+ * renders to all on-screen canvases that are attached to an active
+ * View object. On-screen Canvas3Ds can be either single or double
+ * buffered and they can be either stereo or monoscopic.
+ * <p>
+ * Off-screen Canvas3Ds must not be added to any Container. Java 3D
+ * renders to off-screen canvases in response to the
+ * <code>renderOffScreenBuffer</code> method. Off-screen Canvas3Ds
+ * are single buffered. However, on many systems, the actual
+ * rendering is done to an off-screen hardware buffer or to a 3D
+ * library-specific buffer and only copied to the off-screen buffer of
+ * the Canvas when the rendering is complete, at "buffer swap" time.
+ * Off-screen Canvas3Ds are monoscopic.
+ * <p>
+ * The setOffScreenBuffer method sets the off-screen buffer for this
+ * Canvas3D. The specified image is written into by the Java 3D renderer.
+ * The size of the specified ImageComponent determines the size, in
+ * pixels, of this Canvas3D - the size inherited from Component is
+ * ignored. Note that the size, physical width, and physical height of the
+ * associated Screen3D must be set
+ * explicitly prior to rendering. Failure to do so will result in an
+ * exception.
+ * <p>
+ * The getOffScreenBuffer method retrieves the off-screen
+ * buffer for this Canvas3D.
+ * <p>
+ * The renderOffScreenBuffer method schedules the rendering of a frame
+ * into this Canvas3D's off-screen buffer. The rendering is done from
+ * the point of view of the View object to which this Canvas3D has been
+ * added. No rendering is performed if this Canvas3D object has not been
+ * added to an active View. This method does not wait for the rendering
+ * to actually happen. An application that wishes to know when the
+ * rendering is complete must either subclass Canvas3D and
+ * override the postSwap method, or call waitForOffScreenRendering.
+ * <p>
+ * The setOfScreenLocation methods set the location of this off-screen
+ * Canvas3D. The location is the upper-left corner of the Canvas3D
+ * relative to the upper-left corner of the corresponding off-screen
+ * Screen3D. The function of these methods is similar to that of
+ * Component.setLocation for on-screen Canvas3D objects. The default
+ * location is (0,0).
+ * <p>
+ * <b>Accessing and Modifying an Eye's Image Plate Position</b>
+ * <p>
+ * A Canvas3D object provides sophisticated applications with access
+ * to the eye's position information in head-tracked, room-mounted
+ * runtime environments. It also allows applications to manipulate
+ * the position of an eye relative to an image plate in non-head-tracked
+ * runtime environments.
+ * <p>
+ * The setLeftManualEyeInImagePlate and setRightManualEyeInImagePlate
+ * methods set the position of the manual left and right eyes in image
+ * plate coordinates. These values determine eye placement when a head
+ * tracker is not in use and the application is directly controlling the
+ * eye position in image plate coordinates. In head-tracked mode or
+ * when the windowEyepointPolicy is RELATIVE_TO_FIELD_OF_VIEW or
+ * RELATIVE_TO_COEXISTENCE, this
+ * value is ignored. When the windowEyepointPolicy is RELATIVE_TO_WINDOW,
+ * only the Z value is used.
+ * <p>
+ * The getLeftEyeInImagePlate, getRightEyeInImagePlate, and
+ * getCenterEyeInImagePlate methods retrieve the actual position of the
+ * left eye, right eye, and center eye in image plate coordinates and
+ * copy that value into the object provided. The center eye is the
+ * fictional eye half-way between the left and right eye. These three
+ * values are a function of the windowEyepointPolicy, the tracking
+ * enable flag, and the manual left, right, and center eye positions.
+ * <p>
+ * <b>Monoscopic View Policy</b>
+ * <p>
+ * The setMonoscopicViewPolicy and getMonoscopicViewPolicy methods
+ * set and retrieve the policy regarding how Java 3D generates monoscopic
+ * view. If the policy is set to View.LEFT_EYE_VIEW, the view generated
+ * corresponds to the view as seen from the left eye. If set to
+ * View.RIGHT_EYE_VIEW, the view generated corresponds to the view as
+ * seen from the right eye. If set to View.CYCLOPEAN_EYE_VIEW, the view
+ * generated corresponds to the view as seen from the "center eye," the
+ * fictional eye half-way between the left and right eye. The default
+ * monoscopic view policy is View.CYCLOPEAN_EYE_VIEW.
+ * <p>
+ * <b>Immediate Mode Rendering</b>
+ * <p>
+ * Pure immediate-mode rendering provides for those applications and
+ * applets that do not want Java 3D to do any automatic rendering of
+ * the scene graph. Such applications may not even wish to build a
+ * scene graph to represent their graphical data. However, they use
+ * Java 3D's attribute objects to set graphics state and Java 3D's
+ * geometric objects to render geometry.
+ * <p>
+ * A pure immediate mode application must create a minimal set of
+ * Java 3D objects before rendering. In addition to a Canvas3D object,
+ * the application must create a View object, with its associated
+ * PhysicalBody and PhysicalEnvironment objects, and the following
+ * scene graph elements: a VirtualUniverse object, a high-resolution
+ * Locale object, a BranchGroup node object, a TransformGroup node
+ * object with associated transform, and a ViewPlatform
+ * leaf node object that defines the position and orientation within
+ * the virtual universe that generates the view.
+ * <p>
+ * In immediate mode, all rendering is done completely under user
+ * control. It is necessary for the user to clear the 3D canvas,
+ * render all geometry, and swap the buffers. Additionally,
+ * rendering the right and left eye for stereo viewing becomes the
+ * sole responsibility of the application. In pure immediate mode,
+ * the user must stop the Java 3D renderer, via the
+ * Canvas3D object <code>stopRenderer</code> method, prior to adding the
+ * Canvas3D object to an active View object (that is, one that is
+ * attached to a live ViewPlatform object).
+ * <p>
+ * Other Canvas3D methods related to immediate mode rendering are:
+ * <p>
+ * <ul>
+ * <code>getGraphicsContext3D</code> retrieves the immediate-mode
+ * 3D graphics context associated with this Canvas3D. It creates a
+ * new graphics context if one does not already exist.
+ * <p>
+ * <code>getGraphics2D</code> retrieves the
+ * 2D graphics object associated with this Canvas3D. It creates a
+ * new 2D graphics object if one does not already exist.
+ * <p>
+ * <code>swap</code> synchronizes and swaps buffers on a
+ * double-buffered canvas for this Canvas3D object. This method
+ * should only be called if the Java 3D renderer has been stopped.
+ * In the normal case, the renderer automatically swaps
+ * the buffer.
+ * </ul>
+ *
+ * <p>
+ * <b>Mixed Mode Rendering</b>
+ * <p>
+ * Mixing immediate mode and retained or compiled-retained mode
+ * requires more structure than pure immediate mode. In mixed mode,
+ * the Java 3D renderer is running continuously, rendering the scene
+ * graph into the canvas.
+ *
+ * <p>
+ * Canvas3D methods related to mixed mode rendering are:
+ *
+ * <p>
+ * <ul>
+ * <code>preRender</code> called by the Java 3D rendering loop after
+ * clearing the canvas and before any rendering has been done for
+ * this frame.
+ * <p>
+ * <code>postRender</code> called by the Java 3D rendering loop after
+ * completing all rendering to the canvas for this frame and before
+ * the buffer swap.
+ * <p>
+ * <code>postSwap</code> called by the Java 3D rendering loop after
+ * completing all rendering to the canvas, and all other canvases
+ * associated with this view, for this frame following the
+ * buffer swap.
+ * <p>
+ * <code>renderField</code> called by the Java 3D rendering loop
+ * during the execution of the rendering loop. It is called once
+ * for each field (i.e., once per frame on a mono system or once
+ * each for the right eye and left eye on a two-pass stereo system.
+ * </ul>
+ * <p>
+ * The above callback methods are called by the Java 3D rendering system
+ * and should <i>not</i> be called by an application directly.
+ *
+ * <p>
+ * The basic Java 3D <i>stereo</i> rendering loop,
+ * executed for each Canvas3D, is as follows:
+ * <ul><pre>
+ * clear canvas (both eyes)
+ * call preRender() // user-supplied method
+ * set left eye view
+ * render opaque scene graph objects
+ * call renderField(FIELD_LEFT) // user-supplied method
+ * render transparent scene graph objects
+ * set right eye view
+ * render opaque scene graph objects again
+ * call renderField(FIELD_RIGHT) // user-supplied method
+ * render transparent scene graph objects again
+ * call postRender() // user-supplied method
+ * synchronize and swap buffers
+ * call postSwap() // user-supplied method
+ * </pre></ul>
+ * <p>
+ * The basic Java 3D <i>monoscopic</i> rendering loop is as follows:
+ * <ul><pre>
+ * clear canvas
+ * call preRender() // user-supplied method
+ * set view
+ * render opaque scene graph objects
+ * call renderField(FIELD_ALL) // user-supplied method
+ * render transparent scene graph objects
+ * call postRender() // user-supplied method
+ * synchronize and swap buffers
+ * call postSwap() // user-supplied method
+ * </pre></ul>
+ * <p>
+ * In both cases, the entire loop, beginning with clearing the canvas
+ * and ending with swapping the buffers, defines a frame. The application
+ * is given the opportunity to render immediate-mode geometry at any of
+ * the clearly identified spots in the rendering loop. A user specifies
+ * his or her own rendering methods by extending the Canvas3D class and
+ * overriding the preRender, postRender, postSwap, and/or renderField
+ * methods.
+ * Updates to live Geometry, Texture, and ImageComponent objects
+ * in the scene graph are not allowed from any of these callback
+ * methods.
+ *
+ * <p>
+ * <b>Serialization</b>
+ * <p>
+ * Canvas3D does <i>not</i> support serialization. An attempt to
+ * serialize a Canvas3D object will result in an
+ * UnsupportedOperationException being thrown.
+ *
+ * <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 Screen3D
+ * @see View
+ * @see GraphicsContext3D
+ */
+public class Canvas3D extends Canvas {
+ /**
+ * Specifies the left field of a field-sequential stereo rendering loop.
+ * A left field always precedes a right field.
+ */
+ public static final int FIELD_LEFT = 0;
+
+ /**
+ * Specifies the right field of a field-sequential stereo rendering loop.
+ * A right field always follows a left field.
+ */
+ public static final int FIELD_RIGHT = 1;
+
+ /**
+ * Specifies a single-field rendering loop.
+ */
+ public static final int FIELD_ALL = 2;
+
+ //
+ // The following constants are bit masks to specify which of the node
+ // components are dirty and need updates.
+ //
+ // Values for the geometryType field.
+ static final int POLYGONATTRS_DIRTY = 0x01;
+ static final int LINEATTRS_DIRTY = 0x02;
+ static final int POINTATTRS_DIRTY = 0x04;
+ static final int MATERIAL_DIRTY = 0x08;
+ static final int TRANSPARENCYATTRS_DIRTY = 0x10;
+ static final int COLORINGATTRS_DIRTY = 0x20;
+
+ // Values for lightbin, env set, texture, texture setting etc.
+ static final int LIGHTBIN_DIRTY = 0x40;
+ static final int LIGHTENABLES_DIRTY = 0x80;
+ static final int AMBIENTLIGHT_DIRTY = 0x100;
+ static final int ATTRIBUTEBIN_DIRTY = 0x200;
+ static final int TEXTUREBIN_DIRTY = 0x400;
+ static final int TEXTUREATTRIBUTES_DIRTY = 0x800;
+ static final int RENDERMOLECULE_DIRTY = 0x1000;
+ static final int FOG_DIRTY = 0x2000;
+ static final int MODELCLIP_DIRTY = 0x4000;
+ static final int VIEW_MATRIX_DIRTY = 0x8000;
+ // static final int SHADER_DIRTY = 0x10000; Not ready for this yet -- JADA
+
+ //
+ // Flag that indicates whether this Canvas3D is an off-screen Canvas3D
+ //
+ boolean offScreen = false;
+
+ //
+ // Issue 131: Flag that indicates whether this Canvas3D is a manually
+ // rendered Canvas3D (versus an automatically rendered Canvas3D).
+ //
+ // NOTE: manualRendering only applies to off-screen Canvas3Ds at this time.
+ // We have no plans to ever change this, but if we do, it might be necessary
+ // to determine which, if any, of the uses of "manualRendering" should be
+ // changed to "manualRendering&&offScreen"
+ //
+ boolean manualRendering = false;
+
+ // user specified offScreen Canvas location
+ Point offScreenCanvasLoc;
+
+ // user specified offScreen Canvas dimension
+ Dimension offScreenCanvasSize;
+
+ //
+ // Flag that indicates whether off-screen rendering is in progress or not
+ //
+ volatile boolean offScreenRendering = false;
+
+ //
+ // Flag that indicates we are waiting for an off-screen buffer to be
+ // created or destroyed by the Renderer.
+ //
+ volatile boolean offScreenBufferPending = false;
+
+ //
+ // ImageComponent used for off-screen rendering
+ //
+ ImageComponent2D offScreenBuffer = null;
+
+ // flag that indicates whether this canvas will use shared context
+ boolean useSharedCtx = true;
+
+ //
+ // Read-only flag that indicates whether stereo is supported for this
+ // canvas. This is always false for off-screen canvases.
+ //
+ boolean stereoAvailable;
+
+ //
+ // Flag to enable stereo rendering, if allowed by the
+ // stereoAvailable flag.
+ //
+ boolean stereoEnable = true;
+
+ //
+ // This flag is set when stereo mode is both enabled and
+ // available. Code that looks at stereo mode should use this
+ // flag.
+ //
+ boolean useStereo;
+
+ // Indicate whether it is left or right stereo pass currently
+ boolean rightStereoPass = false;
+
+ //
+ // Specifies how Java 3D generates monoscopic view
+ // (LEFT_EYE_VIEW, RIGHT_EYE_VIEW, or CYCLOPEAN_EYE_VIEW).
+ //
+ int monoscopicViewPolicy = View.CYCLOPEAN_EYE_VIEW;
+
+ // User requested stencil size
+ int requestedStencilSize;
+
+ // Actual stencil size return for this canvas
+ int actualStencilSize;
+
+ // True if stencil buffer is available for user
+ boolean userStencilAvailable;
+
+ // True if stencil buffer is available for system ( decal )
+ boolean systemStencilAvailable;
+
+ //
+ // Read-only flag that indicates whether double buffering is supported
+ // for this canvas. This is always false for off-screen canvases.
+ //
+ boolean doubleBufferAvailable;
+
+ //
+ // Flag to enable double buffered rendering, if allowed by the
+ // doubleBufferAvailable flag.
+ //
+ boolean doubleBufferEnable = true;
+
+ //
+ // This flag is set when doubleBuffering is both enabled and
+ // available Code that enables or disables double buffering should
+ // use this flag.
+ //
+ boolean useDoubleBuffer;
+
+ //
+ // Read-only flag that indicates whether scene antialiasing
+ // is supported for this canvas.
+ //
+ boolean sceneAntialiasingAvailable;
+ boolean sceneAntialiasingMultiSamplesAvailable;
+
+ // Use to see whether antialiasing is already set
+ private boolean antialiasingSet = false;
+
+ //
+ // Read-only flag that indicates the size of the texture color
+ // table for this canvas. A value of 0 indicates that the texture
+ // color table is not supported.
+ //
+ int textureColorTableSize;
+
+ // number of active/enabled texture unit
+ int numActiveTexUnit = 0;
+
+ // index iof last enabled texture unit
+ int lastActiveTexUnit = -1;
+
+ // True if shadingLanguage is supported, otherwise false.
+ boolean shadingLanguageGLSL = false;
+
+ // Query properties
+ J3dQueryProps queryProps;
+
+ // Flag indicating a fatal rendering error of some sort
+ private boolean fatalError = false;
+
+ //
+ // The positions of the manual left and right eyes in image-plate
+ // coordinates.
+ // By default, we will use the center of the screen for X and Y values
+ // (X values are adjusted for default eye separation), and
+ // 0.4572 meters (18 inches) for the Z value.
+ // These match defaults elsewhere in the system.
+ //
+ Point3d leftManualEyeInImagePlate = new Point3d(0.142, 0.135, 0.4572);
+ Point3d rightManualEyeInImagePlate = new Point3d(0.208, 0.135, 0.4572);
+
+ //
+ // View that is attached to this Canvas3D.
+ //
+ View view = null;
+
+ // View waiting to be set
+ View pendingView;
+
+ //
+ // View cache for this canvas and its associated view.
+ //
+ CanvasViewCache canvasViewCache = null;
+
+ // Issue 109: View cache for this canvas, for computing view frustum planes
+ CanvasViewCache canvasViewCacheFrustum = null;
+
+ // Since multiple renderAtomListInfo, share the same vecBounds
+ // we want to do the intersection test only once per renderAtom
+ // this flag is set to true after the first intersect and set to
+ // false during checkForCompaction in renderBin
+ boolean raIsVisible = false;
+
+ RenderAtom ra = null;
+
+ // Stereo related field has changed.
+ static final int STEREO_DIRTY = 0x01;
+ // MonoscopicViewPolicy field has changed.
+ static final int MONOSCOPIC_VIEW_POLICY_DIRTY = 0x02;
+ // Left/right eye in image plate field has changed.
+ static final int EYE_IN_IMAGE_PLATE_DIRTY = 0x04;
+ // Canvas has moved/resized.
+ static final int MOVED_OR_RESIZED_DIRTY = 0x08;
+
+ // Canvas Background changed (this may affect doInfinite flag)
+ static final int BACKGROUND_DIRTY = 0x10;
+
+ // Canvas Background Image changed
+ static final int BACKGROUND_IMAGE_DIRTY = 0x20;
+
+
+ // Mask that indicates this Canvas view dependence info. has changed,
+ // and CanvasViewCache may need to recompute the final view matries.
+ static final int VIEW_INFO_DIRTY = (STEREO_DIRTY |
+ MONOSCOPIC_VIEW_POLICY_DIRTY |
+ EYE_IN_IMAGE_PLATE_DIRTY |
+ MOVED_OR_RESIZED_DIRTY |
+ BACKGROUND_DIRTY |
+ BACKGROUND_IMAGE_DIRTY);
+
+ // Issue 163: Array of dirty bits is used because the Renderer and
+ // RenderBin run asynchronously. Now that they each have a separate
+ // instance of CanvasViewCache (due to the fix for Issue 109), they
+ // need separate dirty bits. Array element 0 is used for the Renderer and
+ // element 1 is used for the RenderBin.
+ static final int RENDERER_DIRTY_IDX = 0;
+ static final int RENDER_BIN_DIRTY_IDX = 1;
+ int[] cvDirtyMask = new int[2];
+
+ // This boolean informs the J3DGraphics2DImpl that the window is resized
+ boolean resizeGraphics2D = true;
+ //
+ // This boolean allows an application to start and stop the render
+ // loop on this canvas.
+ //
+ volatile boolean isRunning = true;
+
+ // This is used by MasterControl only. MC relay on this in a
+ // single loop to set renderer thread. During this time,
+ // the isRunningStatus can't change by user thread.
+ volatile boolean isRunningStatus = true;
+
+ // This is true when the canvas is ready to be rendered into
+ boolean active = false;
+
+ // This is true when the canvas is visible
+ boolean visible = false;
+
+ // This is true if context need to recreate
+ boolean ctxReset = true;
+
+ // The Screen3D that corresponds to this Canvas3D
+ Screen3D screen = null;
+
+ // Flag to indicate that image is render completely
+ // so swap is valid.
+ boolean imageReady = false;
+
+ // The 3D Graphics context used for immediate mode rendering
+ // into this canvas.
+ GraphicsContext3D graphicsContext3D = null;
+ boolean waiting = false;
+ boolean swapDone = false;
+
+ GraphicsConfiguration graphicsConfiguration;
+
+ // The Java 3D Graphics2D object used for Java2D/AWT rendering
+ // into this Canvas3D
+ J3DGraphics2DImpl graphics2D = null;
+
+ // Lock used to synchronize the creation of the 2D and 3D
+ // graphics context objects
+ Object gfxCreationLock = new Object();
+
+ // The source of the currently loaded localToVWorld for this Canvas3D
+ // (used to only update the model matrix when it changes)
+ // Transform3D localToVWorldSrc = null;
+
+ // The current vworldToEc Transform
+ Transform3D vworldToEc = new Transform3D();
+
+ // The view transform (VPC to EC) for the current eye.
+ // NOTE that this is *read-only*
+ Transform3D vpcToEc;
+
+ // Opaque object representing the underlying drawable (window). This
+ // is defined by the Pipeline.
+ Drawable drawable = null;
+
+ // graphicsConfigTable is a static hashtable which allows getBestConfiguration()
+ // in NativeConfigTemplate3D to map a GraphicsConfiguration to the pointer
+ // to the actual GLXFBConfig that glXChooseFBConfig() returns. The Canvas3D
+ // doesn't exist at the time getBestConfiguration() is called, and
+ // X11GraphicsConfig neither maintains this pointer nor provides a public
+ // constructor to allow Java 3D to extend it.
+ static Hashtable<GraphicsConfiguration,GraphicsConfigInfo> graphicsConfigTable =
+ new Hashtable<GraphicsConfiguration,GraphicsConfigInfo>();
+
+ // The native graphics version, vendor, and renderer information
+ String nativeGraphicsVersion = "<UNKNOWN>";
+ String nativeGraphicsVendor = "<UNKNOWN>";
+ String nativeGraphicsRenderer = "<UNKNOWN>";
+
+ boolean firstPaintCalled = false;
+
+ // This reflects whether or not this canvas has seen an addNotify. It is
+ // forced to true for off-screen canvases
+ boolean added = false;
+
+ // Flag indicating whether addNotify has been called (so we don't process it twice).
+ private boolean addNotifyCalled = false;
+
+ // This is the id for the underlying graphics context structure.
+ Context ctx = null;
+
+ // since the ctx id can be the same as the previous one,
+ // we need to keep a time stamp to differentiate the contexts with the
+ // same id
+ volatile long ctxTimeStamp = 0;
+
+ // The current context setting for local eye lighting
+ boolean ctxEyeLightingEnable = false;
+
+ // This AppearanceRetained Object refelects the current state of this
+ // canvas. It is used to optimize setting of attributes at render time.
+ AppearanceRetained currentAppear = new AppearanceRetained();
+
+ // This MaterialRetained Object refelects the current state of this canvas.
+ // It is used to optimize setting of attributes at render time.
+ MaterialRetained currentMaterial = new MaterialRetained();
+
+ /**
+ * The object used for View Frustum Culling
+ */
+ CachedFrustum viewFrustum = new CachedFrustum();
+
+ /**
+ * The RenderBin bundle references used to decide what the underlying
+ * context contains.
+ */
+ LightBin lightBin = null;
+ EnvironmentSet environmentSet = null;
+ AttributeBin attributeBin = null;
+ ShaderBin shaderBin = null;
+ RenderMolecule renderMolecule = null;
+ PolygonAttributesRetained polygonAttributes = null;
+ LineAttributesRetained lineAttributes = null;
+ PointAttributesRetained pointAttributes = null;
+ MaterialRetained material = null;
+ boolean enableLighting = false;
+ TransparencyAttributesRetained transparency = null;
+ ColoringAttributesRetained coloringAttributes = null;
+ Transform3D modelMatrix = null;
+ Transform3D projTrans = null;
+ TextureBin textureBin = null;
+
+
+ /**
+ * cached RenderBin states for lazy native states update
+ */
+ LightRetained lights[] = null;
+ int frameCount[] = null;
+ long enableMask = -1;
+ FogRetained fog = null;
+ ModelClipRetained modelClip = null;
+ Color3f sceneAmbient = new Color3f();
+ TextureUnitStateRetained[] texUnitState = null;
+
+ /**
+ * These cached values are only used in Pure Immediate and Mixed Mode rendering
+ */
+ TextureRetained texture = null;
+ TextureAttributesRetained texAttrs = null;
+ TexCoordGenerationRetained texCoordGeneration = null;
+ RenderingAttributesRetained renderingAttrs = null;
+ AppearanceRetained appearance = null;
+
+ ShaderProgramRetained shaderProgram = null;
+
+ // only used in Mixed Mode rendering
+ Object appHandle = null;
+
+ /**
+ * Dirty bit to determine if the NodeComponent needs to be re-sent
+ * down to the underlying API
+ */
+ int canvasDirty = 0xffff;
+
+ // True when either one of dirtyRenderMoleculeList,
+ // dirtyDlistPerRinfoList, dirtyRenderAtomList size > 0
+ boolean dirtyDisplayList = false;
+
+ArrayList<RenderMolecule> dirtyRenderMoleculeList = new ArrayList<RenderMolecule>();
+ArrayList<RenderAtomListInfo> dirtyRenderAtomList = new ArrayList<RenderAtomListInfo>();
+// List of (Rm, rInfo) pair of individual dlists that need to be rebuilt
+ArrayList<Object[]> dirtyDlistPerRinfoList = new ArrayList<Object[]>();
+
+ArrayList<Integer> displayListResourceFreeList = new ArrayList<Integer>();
+ArrayList<Integer> textureIdResourceFreeList = new ArrayList<Integer>();
+
+ // an unique bit to identify this canvas
+ int canvasBit = 0;
+ // an unique number to identify this canvas : ( canvasBit = 1 << canvasId)
+ int canvasId = 0;
+ // Indicates whether the canvasId has been allocated
+ private boolean canvasIdAlloc = false;
+
+ // Avoid using this as lock, it cause deadlock
+ Object cvLock = new Object();
+ Object evaluateLock = new Object();
+ Object dirtyMaskLock = new Object();
+
+ // For D3D, instead of using the same variable in Renderer,
+ // each canvas has to build its own displayList.
+ boolean needToRebuildDisplayList = false;
+
+ // Read-only flag that indicates whether the following texture features
+ // are supported for this canvas.
+
+ static final int TEXTURE_3D = 0x0001;
+ static final int TEXTURE_COLOR_TABLE = 0x0002;
+ static final int TEXTURE_MULTI_TEXTURE = 0x0004;
+ static final int TEXTURE_COMBINE = 0x0008;
+ static final int TEXTURE_COMBINE_DOT3 = 0x0010;
+ static final int TEXTURE_COMBINE_SUBTRACT = 0x0020;
+ static final int TEXTURE_REGISTER_COMBINERS = 0x0040;
+ static final int TEXTURE_CUBE_MAP = 0x0080;
+ static final int TEXTURE_SHARPEN = 0x0100;
+ static final int TEXTURE_DETAIL = 0x0200;
+ static final int TEXTURE_FILTER4 = 0x0400;
+ static final int TEXTURE_ANISOTROPIC_FILTER = 0x0800;
+ static final int TEXTURE_LOD_RANGE = 0x1000;
+ static final int TEXTURE_LOD_OFFSET = 0x2000;
+ // Use by D3D to indicate using one pass Blend mode
+ // if Texture interpolation mode is support.
+ static final int TEXTURE_LERP = 0x4000;
+ static final int TEXTURE_NON_POWER_OF_TWO = 0x8000;
+ static final int TEXTURE_AUTO_MIPMAP_GENERATION = 0x10000;
+
+ int textureExtendedFeatures = 0;
+
+ // Extensions supported by the underlying canvas
+ //
+ // NOTE: we should remove EXT_BGR and EXT_ABGR when the imaging code is
+ // rewritten
+ // killed global alpha
+ //static final int SUN_GLOBAL_ALPHA = 0x1;
+ static final int EXT_ABGR = 0x2;
+ static final int EXT_BGR = 0x4;
+ static final int MULTISAMPLE = 0x8;
+
+ // The following 10 variables are set by the native
+ // createNewContext()/createQueryContext() methods
+
+ // Supported Extensions
+ int extensionsSupported = 0;
+
+ // Anisotropic Filter degree
+ float anisotropicDegreeMax = 1.0f;
+
+ // Texture Boundary Width Max
+ int textureBoundaryWidthMax = 0;
+
+ boolean multiTexAccelerated = false;
+
+ // Max number of texture coordinate sets
+ int maxTexCoordSets = 1;
+
+ // Max number of fixed-function texture units
+ int maxTextureUnits = 1;
+
+ // Max number of fragment shader texture units
+ int maxTextureImageUnits = 0;
+
+ // Max number of vertex shader texture units
+ int maxVertexTextureImageUnits = 0;
+
+ // Max number of combined shader texture units
+ int maxCombinedTextureImageUnits = 0;
+
+ // Max number of vertex attrs (not counting coord, etc.)
+ int maxVertexAttrs = 0;
+
+ // End of variables set by createNewContext()/createQueryContext()
+
+ // The total available number of texture units used by either the
+ // fixed-function or programmable shader pipeline.
+ // This is computed as: max(maxTextureUnits, maxTextureImageUnits)
+ int maxAvailableTextureUnits;
+
+ // Texture Width, Height Max
+ int textureWidthMax = 0;
+ int textureHeightMax = 0;
+
+ // Texture3D Width, Heigh, Depth Max
+ int texture3DWidthMax = -1;
+ int texture3DHeightMax = -1;
+ int texture3DDepthMax = -1;
+
+ // Cached position & size for CanvasViewCache.
+ // We don't want to call canvas.getxx method in Renderer
+ // since it will cause deadlock as removeNotify() need to get
+ // component lock of Canvas also and need to wait Renderer to
+ // finish before continue. So we invoke the method now in
+ // CanvasViewEventCatcher.
+ Point newPosition = new Point();
+ Dimension newSize = new Dimension();
+
+// Remember OGL context resources to free
+// before context is destroy.
+// It is used when sharedCtx = false;
+ArrayList<TextureRetained> textureIDResourceTable = new ArrayList<TextureRetained>(5);
+
+ // The following variables are used by the lazy download of
+ // states code to keep track of the set of current to be update bins
+
+ static final int LIGHTBIN_BIT = 0x0;
+ static final int ENVIRONMENTSET_BIT = 0x1;
+ static final int ATTRIBUTEBIN_BIT = 0x2;
+ static final int TEXTUREBIN_BIT = 0x3;
+ static final int RENDERMOLECULE_BIT = 0x4;
+ static final int TRANSPARENCY_BIT = 0x5;
+ static final int SHADERBIN_BIT = 0x6;
+
+ // bitmask to specify if the corresponding "bin" needs to be updated
+ int stateUpdateMask = 0;
+
+ // the set of current "bins" that is to be updated, the stateUpdateMask
+ // specifies if each bin in this set is updated or not.
+ Object curStateToUpdate[] = new Object[7];
+
+ /**
+ * The list of lights that are currently being represented in the native
+ * graphics context.
+ */
+ LightRetained[] currentLights = null;
+
+ /**
+ * Flag to override RenderAttributes.depthBufferWriteEnable
+ */
+ boolean depthBufferWriteEnableOverride = false;
+
+ /**
+ * Flag to override RenderAttributes.depthBufferEnable
+ */
+ boolean depthBufferEnableOverride = false;
+
+ // current state of depthBufferWriteEnable
+ boolean depthBufferWriteEnable = true;
+
+ boolean vfPlanesValid = false;
+
+ // The event catcher for this canvas.
+ EventCatcher eventCatcher;
+
+ // The view event catcher for this canvas.
+ private CanvasViewEventCatcher canvasViewEventCatcher;
+
+ // The top-level parent window for this canvas.
+ private Window windowParent;
+
+ // Issue 458 - list of all parent containers for this canvas
+ // (includes top-level parent window)
+ private LinkedList<Container> containerParentList = new LinkedList<Container>();
+
+ // flag that indicates if light has changed
+ boolean lightChanged = false;
+
+ // resource control object
+ DrawingSurfaceObject drawingSurfaceObject;
+
+ // true if context is valid for rendering
+ boolean validCtx = false;
+
+ // true if canvas is valid for rendering
+ boolean validCanvas = false;
+
+ // true if ctx changed between render and swap. In this case
+ // cv.canvasDirty flag will not reset in Renderer.
+ // This case happen when GraphicsContext3D invoked doClear()
+ // and canvas removeNotify() called while Renderer is running
+ boolean ctxChanged = false;
+
+ // Default graphics configuration
+ private static GraphicsConfiguration defaultGcfg = null;
+
+ // Returns default graphics configuration if user passes null
+ // into the Canvas3D constructor
+ private static synchronized GraphicsConfiguration defaultGraphicsConfiguration() {
+ if (defaultGcfg == null) {
+ GraphicsConfigTemplate3D template = new GraphicsConfigTemplate3D();
+ defaultGcfg = GraphicsEnvironment.getLocalGraphicsEnvironment().
+ getDefaultScreenDevice().getBestConfiguration(template);
+ }
+ return defaultGcfg;
+ }
+
+ // Returns true if this is a valid graphics configuration, obtained
+ // via a GraphicsConfigTemplate3D.
+ private static boolean isValidConfig(GraphicsConfiguration gconfig) {
+ // If this is a valid GraphicsConfiguration object, then it will
+ // be in the graphicsConfigTable
+ return graphicsConfigTable.containsKey(gconfig);
+ }
+
+ // Checks the given graphics configuration, and throws an exception if
+ // the config is null or invalid.
+ private static synchronized GraphicsConfiguration
+ checkForValidGraphicsConfig(GraphicsConfiguration gconfig, boolean offScreen) {
+
+ // Issue 266 - for backwards compatibility with legacy applications,
+ // we will accept a null GraphicsConfiguration for an on-screen Canvas3D
+ // only if the "allowNullGraphicsConfig" system property is set to true.
+ if (!offScreen && VirtualUniverse.mc.allowNullGraphicsConfig) {
+ if (gconfig == null) {
+ // Print out warning if Canvas3D is called with a
+ // null GraphicsConfiguration
+ System.err.println(J3dI18N.getString("Canvas3D7"));
+ System.err.println(" " + J3dI18N.getString("Canvas3D18"));
+
+ // Use a default graphics config
+ gconfig = defaultGraphicsConfiguration();
+ }
+ }
+
+ // Validate input graphics config
+ if (gconfig == null) {
+ throw new NullPointerException(J3dI18N.getString("Canvas3D19"));
+ } else if (!isValidConfig(gconfig)) {
+ throw new IllegalArgumentException(J3dI18N.getString("Canvas3D17"));
+ }
+
+ return gconfig;
+ }
+
+ // Return the actual graphics config that will be used to construct
+ // the AWT Canvas. This is permitted to be non-unique or null.
+ private static GraphicsConfiguration getGraphicsConfig(GraphicsConfiguration gconfig) {
+ return Pipeline.getPipeline().getGraphicsConfig(gconfig);
+ }
+
+ /**
+ * Constructs and initializes a new Canvas3D object that Java 3D
+ * can render into. The following Canvas3D attributes are initialized
+ * to default values as shown:
+ * <ul>
+ * left manual eye in image plate : (0.142, 0.135, 0.4572)<br>
+ * right manual eye in image plate : (0.208, 0.135, 0.4572)<br>
+ * stereo enable : true<br>
+ * double buffer enable : true<br>
+ * monoscopic view policy : View.CYCLOPEAN_EYE_VIEW<br>
+ * off-screen mode : false<br>
+ * off-screen buffer : null<br>
+ * off-screen location : (0,0)<br>
+ * </ul>
+ *
+ * @param graphicsConfiguration a valid GraphicsConfiguration object that
+ * will be used to create the canvas. This object should not be null and
+ * should be created using a GraphicsConfigTemplate3D or the
+ * getPreferredConfiguration() method of the SimpleUniverse utility. For
+ * backward compatibility with earlier versions of Java 3D, a null or
+ * default GraphicsConfiguration will still work when used to create a
+ * Canvas3D on the default screen, but an error message will be printed.
+ * A NullPointerException or IllegalArgumentException will be thrown in a
+ * subsequent release.
+ *
+ * @exception IllegalArgumentException if the specified
+ * GraphicsConfiguration does not support 3D rendering
+ */
+ public Canvas3D(GraphicsConfiguration graphicsConfiguration) {
+ this(null, checkForValidGraphicsConfig(graphicsConfiguration, false), false);
+ }
+
+ /**
+ * Constructs and initializes a new Canvas3D object that Java 3D
+ * can render into.
+ *
+ * @param graphicsConfiguration a valid GraphicsConfiguration object
+ * that will be used to create the canvas. This must be created either
+ * with a GraphicsConfigTemplate3D or by using the
+ * getPreferredConfiguration() method of the SimpleUniverse utility.
+ *
+ * @param offScreen a flag that indicates whether this canvas is
+ * an off-screen 3D rendering canvas. Note that if offScreen
+ * is set to true, this Canvas3D object cannot be used for normal
+ * rendering; it should not be added to any Container object.
+ *
+ * @exception NullPointerException if the GraphicsConfiguration
+ * is null.
+ *
+ * @exception IllegalArgumentException if the specified
+ * GraphicsConfiguration does not support 3D rendering
+ *
+ * @since Java 3D 1.2
+ */
+ public Canvas3D(GraphicsConfiguration graphicsConfiguration, boolean offScreen) {
+ this(null, checkForValidGraphicsConfig(graphicsConfiguration, offScreen), offScreen);
+ }
+
+ // Private constructor only called by the two public constructors after
+ // they have validated the graphics config (and possibly constructed a new
+ // default config).
+ // The graphics config must be valid, unique, and non-null.
+ private Canvas3D(Object dummyObj1,
+ GraphicsConfiguration graphicsConfiguration,
+ boolean offScreen) {
+ this(dummyObj1,
+ graphicsConfiguration,
+ getGraphicsConfig(graphicsConfiguration),
+ offScreen);
+ }
+
+ // Private constructor only called by the previous private constructor.
+ // The graphicsConfiguration parameter is used by Canvas3D to lookup the
+ // graphics device and graphics template. The graphicsConfiguration2
+ // parameter is generated by the Pipeline from graphicsConfiguration and
+ // is only used to initialize the java.awt.Canvas.
+ private Canvas3D(Object dummyObj1,
+ GraphicsConfiguration graphicsConfiguration,
+ GraphicsConfiguration graphicsConfiguration2,
+ boolean offScreen) {
+
+ super(graphicsConfiguration2);
+
+ this.offScreen = offScreen;
+ this.graphicsConfiguration = graphicsConfiguration;
+
+ // Issue 131: Set the autoOffScreen variable based on whether this
+ // canvas3d implements the AutoOffScreenCanvas3D tagging interface.
+ // Eventually, we may replace this with an actual API.
+ boolean autoOffScreenCanvas3D = false;
+ if (this instanceof AutoOffScreenCanvas3D) {
+ autoOffScreenCanvas3D = true;
+ }
+
+ // Throw an illegal argument exception if an on-screen canvas is tagged
+ // as an auto-off-screen canvas
+ if (autoOffScreenCanvas3D && !offScreen) {
+ throw new IllegalArgumentException(J3dI18N.getString("Canvas3D25"));
+ }
+
+ // Issue 163 : Set dirty bits for both Renderer and RenderBin
+ cvDirtyMask[0] = VIEW_INFO_DIRTY;
+ cvDirtyMask[1] = VIEW_INFO_DIRTY;
+
+ GraphicsConfigInfo gcInfo = graphicsConfigTable.get(graphicsConfiguration);
+ requestedStencilSize = gcInfo.getGraphicsConfigTemplate3D().getStencilSize();
+
+ if (offScreen) {
+
+ // Issue 131: set manual rendering flag based on whether this is
+ // an auto-off-screen Canvas3D.
+ manualRendering = !autoOffScreenCanvas3D;
+
+ screen = new Screen3D(graphicsConfiguration, offScreen);
+
+ // QUESTION: keep a list of off-screen Screen3D objects?
+ // Does this list need to be grouped by GraphicsDevice?
+
+ synchronized(dirtyMaskLock) {
+ cvDirtyMask[0] |= MOVED_OR_RESIZED_DIRTY;
+ cvDirtyMask[1] |= MOVED_OR_RESIZED_DIRTY;
+ }
+
+ // this canvas will not receive the paint callback,
+ // so we need to set the necessary flags here
+ firstPaintCalled = true;
+
+ if (manualRendering) {
+ // since this canvas will not receive the addNotify
+ // callback from AWT, set the added flag here for
+ // evaluateActive to work correctly
+ added = true;
+ }
+
+ evaluateActive();
+
+ // create the rendererStructure object
+ //rendererStructure = new RendererStructure();
+ offScreenCanvasLoc = new Point(0, 0);
+ offScreenCanvasSize = new Dimension(0, 0);
+
+ this.setLocation(offScreenCanvasLoc);
+ this.setSize(offScreenCanvasSize);
+ newSize = offScreenCanvasSize;
+ newPosition = offScreenCanvasLoc;
+
+ // Issue 131: create event catchers for auto-offScreen
+ if (!manualRendering) {
+ eventCatcher = new EventCatcher(this);
+ canvasViewEventCatcher = new CanvasViewEventCatcher(this);
+ }
+ } else {
+
+ GraphicsDevice graphicsDevice;
+ graphicsDevice = graphicsConfiguration.getDevice();
+
+ eventCatcher = new EventCatcher(this);
+ canvasViewEventCatcher = new CanvasViewEventCatcher(this);
+
+ synchronized(VirtualUniverse.mc.deviceScreenMap) {
+ screen = VirtualUniverse.mc.deviceScreenMap.get(graphicsDevice);
+
+ if (screen == null) {
+ screen = new Screen3D(graphicsConfiguration, offScreen);
+ VirtualUniverse.mc.deviceScreenMap.put(graphicsDevice, screen);
+ }
+ }
+
+ }
+
+ lights = new LightRetained[VirtualUniverse.mc.maxLights];
+ frameCount = new int[VirtualUniverse.mc.maxLights];
+ for (int i=0; i<frameCount.length;i++) {
+ frameCount[i] = -1;
+ }
+
+ // Construct the drawing surface object for this Canvas3D
+ drawingSurfaceObject =
+ Pipeline.getPipeline().createDrawingSurfaceObject(this);
+
+ // Get double buffer, stereo available, scene antialiasing
+ // flags from graphics config
+ GraphicsConfigTemplate3D.getGraphicsConfigFeatures(this);
+
+ useDoubleBuffer = doubleBufferEnable && doubleBufferAvailable;
+ useStereo = stereoEnable && stereoAvailable;
+ useSharedCtx = VirtualUniverse.mc.isSharedCtx;
+
+ // Issue 131: assert that only an off-screen canvas can be demand-driven
+ assert (!offScreen && manualRendering) == false;
+
+ // Assert that offScreen is *not* stereo
+ assert (offScreen && useStereo) == false;
+ }
+
+ /**
+ * This method overrides AWT's handleEvent class...
+ */
+ void sendEventToBehaviorScheduler(AWTEvent evt) {
+
+ ViewPlatform vp;
+
+
+ if ((view != null) && ((vp = view.getViewPlatform()) != null)) {
+ VirtualUniverse univ =
+ ((ViewPlatformRetained)(vp.retained)).universe;
+ if (univ != null) {
+ univ.behaviorStructure.handleAWTEvent(evt);
+ }
+ }
+ }
+
+ /**
+ * Method to return whether or not the Canvas3D is recursively visible;
+ * that is, whether the Canas3D is currently visible on the screen. Note
+ * that we don't directly use isShowing() because that won't work for an
+ * auto-offScreen Canvas3D.
+ */
+ private boolean isRecursivelyVisible() {
+ Container parent = getParent();
+ return isVisible() && parent != null && parent.isShowing();
+ }
+
+ /**
+ * Method to return whether the top-level Window parent is iconified
+ */
+ private boolean isIconified() {
+ if (windowParent instanceof Frame) {
+ return (((Frame)windowParent).getExtendedState() & Frame.ICONIFIED) != 0;
+ }
+
+ return false;
+ }
+
+ // Issue 458 - evaluate this Canvas3D's visibility whenever we get a
+ // Window or Component Event that could change it.
+ void evaluateVisiblilty() {
+ boolean nowVisible = isRecursivelyVisible() && !isIconified();
+
+ // Only need to reevaluate and repaint if visibility has changed
+ if (this.visible != nowVisible) {
+ this.visible = nowVisible;
+ evaluateActive();
+ if (nowVisible) {
+ if (view != null) {
+ view.repaint();
+ }
+ }
+ }
+ }
+
+ /**
+ * This version looks for the view and notifies it.
+ */
+ void redraw() {
+ if ((view != null) && active && isRunning) {
+ view.repaint();
+ }
+ }
+
+ /**
+ * Canvas3D uses the paint callback to track when it is possible to
+ * render into the canvas. Subclasses of Canvas3D that override this
+ * method need to call super.paint() in their paint method for Java 3D
+ * to function properly.
+ * @param g the graphics context
+ */
+ @Override
+ public void paint(Graphics g) {
+
+ if (!firstPaintCalled && added && validCanvas &&
+ validGraphicsMode()) {
+
+ try {
+ newSize = getSize();
+ newPosition = getLocationOnScreen();
+ } catch (IllegalComponentStateException e) {
+ return;
+ }
+
+ synchronized (drawingSurfaceObject) {
+ drawingSurfaceObject.getDrawingSurfaceObjectInfo();
+ }
+
+ firstPaintCalled = true;
+ visible = true;
+ evaluateActive();
+ }
+ redraw();
+ }
+
+ // When this canvas is added to a frame, this notification gets called. We
+ // can get drawing surface information at this time. Note: we cannot get
+ // the X11 window id yet, unless it is a reset condition.
+ /**
+ * Canvas3D uses the addNotify callback to track when it is added
+ * to a container. Subclasses of Canvas3D that override this
+ * method need to call super.addNotify() in their addNotify() method for Java 3D
+ * to function properly.
+ */
+ @Override
+ public void addNotify() {
+ // Return immediately if addNotify called twice with no removeNotify
+ if (addNotifyCalled) {
+ return;
+ }
+ addNotifyCalled = true;
+
+ // Issue 131: This method is now being called by JCanvas3D for its
+ // off-screen Canvas3D, so we need to handle off-screen properly here.
+ // Do nothing for manually-rendered off-screen canvases
+ if (manualRendering) {
+ return;
+ }
+
+ Renderer rdr = null;
+
+ if (isRunning && (screen != null)) {
+ // If there is other Canvas3D in the same screen
+ // rendering, stop it before JDK create new Canvas
+
+ rdr = screen.renderer;
+ if (rdr != null) {
+ VirtualUniverse.mc.postRequest(MasterControl.STOP_RENDERER, rdr);
+ while (!rdr.userStop) {
+ MasterControl.threadYield();
+ }
+ }
+ }
+
+ // Issue 131: Don't call super for off-screen Canvas3D
+ if (!offScreen) {
+ super.addNotify();
+ }
+ screen.addUser(this);
+
+ // Issue 458 - Add the eventCatcher as a component listener for each
+ // parent container in the window hierarchy
+ assert containerParentList.isEmpty();
+
+ windowParent = null;
+ Container container = this.getParent();
+ while (container != null) {
+ if (container instanceof Window) {
+ windowParent = (Window)container;
+ }
+ container.addComponentListener(eventCatcher);
+ container.addComponentListener(canvasViewEventCatcher);
+ containerParentList.add(container);
+ container = container.getParent();
+ }
+
+ this.addComponentListener(eventCatcher);
+ this.addComponentListener(canvasViewEventCatcher);
+
+ if (windowParent != null) {
+ windowParent.addWindowListener(eventCatcher);
+ }
+
+ synchronized(dirtyMaskLock) {
+ cvDirtyMask[0] |= MOVED_OR_RESIZED_DIRTY;
+ cvDirtyMask[1] |= MOVED_OR_RESIZED_DIRTY;
+ }
+
+ allocateCanvasId();
+
+ validCanvas = true;
+ added = true;
+
+ // Since we won't get a paint call for off-screen canvases, we need
+ // to set the first paint and visible flags here. We also need to
+ // call evaluateActive for the same reason.
+ if (offScreen) {
+ firstPaintCalled = true;
+ visible = true;
+ evaluateActive();
+ }
+
+ // In case the same canvas is removed and add back,
+ // we have to change isRunningStatus back to true;
+ if (isRunning && !fatalError) {
+ isRunningStatus = true;
+ }
+
+ ctxTimeStamp = 0;
+ if ((view != null) && (view.universe != null)) {
+ view.universe.checkForEnableEvents();
+ }
+
+ if (rdr != null) {
+ // Issue 84: Send a message to MC to restart renderer
+ // Note that this also obviates the need for the earlier fix to
+ // issue 131 which called redraw() for auto-off-screen Canvas3Ds
+ // (and this is a more robust fix)
+ VirtualUniverse.mc.postRequest(MasterControl.START_RENDERER, rdr);
+ while (rdr.userStop) {
+ MasterControl.threadYield();
+ }
+ }
+ }
+
+ // When this canvas is removed a frame, this notification gets called. We
+ // need to release the native context at this time. The underlying window
+ // is about to go away.
+ /**
+ * Canvas3D uses the removeNotify callback to track when it is removed
+ * from a container. Subclasses of Canvas3D that override this
+ * method need to call super.removeNotify() in their removeNotify()
+ * method for Java 3D to function properly.
+ */
+ @Override
+ public void removeNotify() {
+ // Return immediately if addNotify not called first
+ if (!addNotifyCalled) {
+ return;
+ }
+ addNotifyCalled = false;
+
+ // Do nothing for manually-rendered off-screen canvases
+ if (manualRendering) {
+ return;
+ }
+
+ Renderer rdr = null;
+
+ if (isRunning && (screen != null)) {
+ // If there is other Canvas3D in the same screen
+ // rendering, stop it before JDK create new Canvas
+
+ rdr = screen.renderer;
+ if (rdr != null) {
+ VirtualUniverse.mc.postRequest(MasterControl.STOP_RENDERER, rdr);
+ while (!rdr.userStop) {
+ MasterControl.threadYield();
+ }
+ }
+ }
+
+ // Note that although renderer userStop is true,
+ // MasterControl can still schedule renderer to run through
+ // runMonotor(RUN_RENDERER_CLEANUP) which skip userStop
+ // thread checking.
+ // For non-offscreen rendering the following call will
+ // block waiting until all resources is free before
+ // continue
+
+ synchronized (drawingSurfaceObject) {
+ validCtx = false;
+ validCanvas = false;
+ }
+
+ removeCtx();
+
+ Pipeline.getPipeline().freeDrawingSurface(this, drawingSurfaceObject);
+
+ // Clear first paint and visible flags
+ firstPaintCalled = false;
+ visible = false;
+
+ screen.removeUser(this);
+ evaluateActive();
+
+ freeCanvasId();
+
+ ra = null;
+ graphicsContext3D = null;
+
+ ctx = null;
+ // must be after removeCtx() because
+ // it will free graphics2D textureID
+ graphics2D = null;
+
+ super.removeNotify();
+
+ // Release and clear.
+ for (Container container : containerParentList) {
+ container.removeComponentListener(eventCatcher);
+ container.removeComponentListener(canvasViewEventCatcher);
+ }
+ containerParentList.clear();
+ this.removeComponentListener(eventCatcher);
+ this.removeComponentListener(canvasViewEventCatcher);
+
+ if (eventCatcher != null) {
+ this.removeFocusListener(eventCatcher);
+ this.removeKeyListener(eventCatcher);
+ this.removeMouseListener(eventCatcher);
+ this.removeMouseMotionListener(eventCatcher);
+ this.removeMouseWheelListener(eventCatcher);
+ eventCatcher.reset();
+ }
+
+ if (windowParent != null) {
+ windowParent.removeWindowListener(eventCatcher);
+ windowParent.requestFocus();
+ }
+
+ added = false;
+
+ if (rdr != null) {
+ // Issue 84: Send a message to MC to restart renderer
+ VirtualUniverse.mc.postRequest(MasterControl.START_RENDERER, rdr);
+ while (rdr.userStop) {
+ MasterControl.threadYield();
+ }
+ }
+
+ // Fix for issue 102 removing strong reference and avoiding memory leak
+ // due retention of parent container
+ this.windowParent = null;
+ }
+
+ void allocateCanvasId() {
+ if (!canvasIdAlloc) {
+ canvasId = VirtualUniverse.mc.getCanvasId();
+ canvasBit = 1 << canvasId;
+ canvasIdAlloc = true;
+ }
+ }
+
+ void freeCanvasId() {
+ if (canvasIdAlloc) {
+ VirtualUniverse.mc.freeCanvasId(canvasId);
+ canvasBit = 0;
+ canvasId = 0;
+ canvasIdAlloc = false;
+ }
+ }
+
+ // This decides if the canvas is active
+ void evaluateActive() {
+ // Note that no need to check for isRunning, we want
+ // view register in order to create scheduler in pure immedite mode
+ // Also we can't use this as lock, otherwise there is a
+ // deadlock where updateViewCache get a lock of this and
+ // get a lock of this component. But Container
+ // remove will get a lock of this component follows by evaluateActive.
+
+ synchronized (evaluateLock) {
+ if ((visible || manualRendering) && firstPaintCalled) {
+
+ if (!active) {
+ active = true;
+ if (pendingView != null) {
+ pendingView.evaluateActive();
+ }
+ } else {
+ if ((pendingView != null) &&
+ !pendingView.activeStatus) {
+ pendingView.evaluateActive();
+ }
+ }
+ } else {
+ if (active) {
+ active = false;
+ if (view != null) {
+ view.evaluateActive();
+ }
+ }
+ }
+ }
+
+ if ((view != null) && (!active)) {
+ VirtualUniverse u = view.universe;
+ if ((u != null) && !u.isSceneGraphLock) {
+ u.waitForMC();
+ }
+ }
+ }
+
+ void setFrustumPlanes(Vector4d[] planes) {
+
+ if(VirtualUniverse.mc.viewFrustumCulling) {
+ /* System.err.println("Canvas3D.setFrustumPlanes()"); */
+ viewFrustum.set(planes);
+ }
+ }
+
+
+ /**
+ * Retrieve the Screen3D object that this Canvas3D is attached to.
+ * If this Canvas3D is an off-screen buffer, a new Screen3D object
+ * is created corresponding to the off-screen buffer.
+ * @return the 3D screen object that this Canvas3D is attached to
+ */
+ public Screen3D getScreen3D() {
+ return screen;
+ }
+
+ /**
+ * Get the immediate mode 3D graphics context associated with
+ * this Canvas3D. A new graphics context object is created if one does
+ * not already exist.
+ * @return a GraphicsContext3D object that can be used for immediate
+ * mode rendering to this Canvas3D.
+ */
+ public GraphicsContext3D getGraphicsContext3D() {
+
+ synchronized(gfxCreationLock) {
+ if (graphicsContext3D == null)
+ graphicsContext3D = new GraphicsContext3D(this);
+ }
+
+ return graphicsContext3D;
+ }
+
+ /**
+ * Get the 2D graphics object associated with
+ * this Canvas3D. A new 2D graphics object is created if one does
+ * not already exist.
+ *
+ * @return a Graphics2D object that can be used for Java 2D
+ * rendering into this Canvas3D.
+ *
+ * @since Java 3D 1.2
+ */
+ public J3DGraphics2D getGraphics2D() {
+ synchronized(gfxCreationLock) {
+ if (graphics2D == null)
+ graphics2D = new J3DGraphics2DImpl(this);
+ }
+
+ return graphics2D;
+ }
+
+ /**
+ * This routine is called by the Java 3D rendering loop after clearing
+ * the canvas and before any rendering has been done for this frame.
+ * Applications that wish to perform operations in the rendering loop,
+ * prior to any actual rendering may override this function.
+ *
+ * <p>
+ * Updates to live Geometry, Texture, and ImageComponent objects
+ * in the scene graph are not allowed from this method.
+ *
+ * <p>
+ * NOTE: Applications should <i>not</i> call this method.
+ */
+ public void preRender() {
+ // Do nothing; the user overrides this to cause some action
+ }
+
+ /**
+ * This routine is called by the Java 3D rendering loop after completing
+ * all rendering to the canvas for this frame and before the buffer swap.
+ * Applications that wish to perform operations in the rendering loop,
+ * following any actual rendering may override this function.
+ *
+ * <p>
+ * Updates to live Geometry, Texture, and ImageComponent objects
+ * in the scene graph are not allowed from this method.
+ *
+ * <p>
+ * NOTE: Applications should <i>not</i> call this method.
+ */
+ public void postRender() {
+ // Do nothing; the user overrides this to cause some action
+ }
+
+ /**
+ * This routine is called by the Java 3D rendering loop after completing
+ * all rendering to the canvas, and all other canvases associated with
+ * this view, for this frame following the buffer swap.
+ * Applications that wish to perform operations at the very
+ * end of the rendering loop may override this function.
+ * In off-screen mode, all rendering is copied to the off-screen
+ * buffer before this method is called.
+ *
+ * <p>
+ * Updates to live Geometry, Texture, and ImageComponent objects
+ * in the scene graph are not allowed from this method.
+ *
+ * <p>
+ * NOTE: Applications should <i>not</i> call this method.
+ */
+ public void postSwap() {
+ // Do nothing; the user overrides this to cause some action
+ }
+
+ /**
+ * This routine is called by the Java 3D rendering loop during the
+ * execution of the rendering loop. It is called once for each
+ * field (i.e., once per frame on
+ * a mono system or once each for the right eye and left eye on a
+ * two-pass stereo system. This is intended for use by applications that
+ * want to mix retained/compiled-retained mode rendering with some
+ * immediate mode rendering. Applications that wish to perform
+ * operations during the rendering loop, may override this
+ * function.
+ *
+ * <p>
+ * Updates to live Geometry, Texture, and ImageComponent objects
+ * in the scene graph are not allowed from this method.
+ *
+ * <p>
+ * NOTE: Applications should <i>not</i> call this method.
+ * <p>
+ *
+ * @param fieldDesc field description, one of: FIELD_LEFT, FIELD_RIGHT or
+ * FIELD_ALL. Applications that wish to work correctly in stereo mode
+ * should render the same image for both FIELD_LEFT and FIELD_RIGHT calls.
+ * If Java 3D calls the renderer with FIELD_ALL then the immediate mode
+ * rendering only needs to be done once.
+ */
+ public void renderField(int fieldDesc) {
+ // Do nothing; the user overrides this to cause some action
+ }
+
+ /**
+ * Stop the Java 3D renderer on this Canvas3D object. If the
+ * Java 3D renderer is currently running, the rendering will be
+ * synchronized before being stopped. No further rendering will be done
+ * to this canvas by Java 3D until the renderer is started again.
+ * In pure immediate mode this method should be called prior to adding
+ * this canvas to an active View object.
+ *
+ * @exception IllegalStateException if this Canvas3D is in
+ * off-screen mode.
+ */
+ public final void stopRenderer() {
+ // Issue 131: renderer can't be stopped only if it is an offscreen,
+ // manual canvas. Otherwise, it has to be seen as an onscreen canvas.
+ if (manualRendering)
+ throw new IllegalStateException(J3dI18N.getString("Canvas3D14"));
+
+ if (isRunning) {
+ VirtualUniverse.mc.postRequest(MasterControl.STOP_RENDERER, this);
+ isRunning = false;
+ }
+ }
+
+
+ /**
+ * Start the Java 3D renderer on this Canvas3D object. If the
+ * Java 3D renderer is not currently running, any rendering to other
+ * Canvas3D objects sharing the same View will be synchronized before this
+ * Canvas3D's renderer is (re)started. When a Canvas3D is created, it is
+ * initially marked as being started. This means that as soon as the
+ * Canvas3D is added to an active View object, the rendering loop will
+ * render the scene graph to the canvas.
+ */
+ public final void startRenderer() {
+ // Issue 260 : ignore attempt to start renderer if fatal error
+ if (fatalError) {
+ return;
+ }
+
+ if (!isRunning) {
+ VirtualUniverse.mc.postRequest(MasterControl.START_RENDERER, this);
+ isRunning = true;
+ redraw();
+ }
+ }
+
+ /**
+ * Retrieves the state of the renderer for this Canvas3D object.
+ * @return the state of the renderer
+ *
+ * @since Java 3D 1.2
+ */
+ public final boolean isRendererRunning() {
+ return isRunning;
+ }
+
+ // Returns the state of the fatal error flag
+ boolean isFatalError() {
+ return fatalError;
+ }
+
+ // Sets the fatal error flag to true; stop the renderer for this canvas
+ void setFatalError() {
+ fatalError = true;
+
+ if (isRunning) {
+ isRunning = false;
+
+ if (!manualRendering) {
+ VirtualUniverse.mc.postRequest(MasterControl.STOP_RENDERER, this);
+ }
+ }
+ }
+
+
+ /**
+ * Retrieves a flag indicating whether this Canvas3D is an
+ * off-screen canvas.
+ *
+ * @return <code>true</code> if this Canvas3D is an off-screen canvas;
+ * <code>false</code> if this is an on-screen canvas.
+ *
+ * @since Java 3D 1.2
+ */
+ public boolean isOffScreen() {
+ return offScreen;
+ }
+
+
+ /**
+ * Sets the off-screen buffer for this Canvas3D. The specified
+ * image is written into by the Java 3D renderer. The size of the
+ * specified ImageComponent determines the size, in pixels, of
+ * this Canvas3D--the size inherited from Component is ignored.
+ * <p>
+ * NOTE: the size, physical width, and physical height of the associated
+ * Screen3D must be set explicitly prior to rendering.
+ * Failure to do so will result in an exception.
+ * <p>
+ *
+ * @param buffer the image component that will be rendered into by
+ * subsequent calls to renderOffScreenBuffer. The image component must not
+ * be part of a live scene graph, nor may it subsequently be made part of a
+ * live scene graph while being used as an off-screen buffer; an
+ * IllegalSharingException is thrown in such cases. The buffer may be null,
+ * indicating that the previous off-screen buffer is released without a new
+ * buffer being set.
+ *
+ * @exception IllegalStateException if this Canvas3D is not in
+ * off-screen mode.
+ *
+ * @exception RestrictedAccessException if an off-screen rendering
+ * is in process for this Canvas3D.
+ *
+ * @exception IllegalSharingException if the specified ImageComponent2D
+ * is part of a live scene graph
+ *
+ * @exception IllegalSharingException if the specified ImageComponent2D is
+ * being used by an immediate mode context, or by another Canvas3D as
+ * an off-screen buffer.
+ *
+ * @exception IllegalArgumentException if the image class of the specified
+ * ImageComponent2D is <i>not</i> ImageClass.BUFFERED_IMAGE.
+ *
+ * @exception IllegalArgumentException if the specified
+ * ImageComponent2D is in by-reference mode and its
+ * RenderedImage is null.
+ *
+ * @exception IllegalArgumentException if the ImageComponent2D format
+ * is <i>not</i> a 3-component format (e.g., FORMAT_RGB)
+ * or a 4-component format (e.g., FORMAT_RGBA).
+ *
+ * @see #renderOffScreenBuffer
+ * @see Screen3D#setSize(int, int)
+ * @see Screen3D#setSize(Dimension)
+ * @see Screen3D#setPhysicalScreenWidth
+ * @see Screen3D#setPhysicalScreenHeight
+ *
+ * @since Java 3D 1.2
+ */
+ public void setOffScreenBuffer(ImageComponent2D buffer) {
+ int width, height;
+ boolean freeCanvasId = false;
+
+ if (!offScreen)
+ throw new IllegalStateException(J3dI18N.getString("Canvas3D1"));
+
+ if (offScreenRendering)
+ throw new RestrictedAccessException(J3dI18N.getString("Canvas3D2"));
+
+ // Check that offScreenBufferPending is not already set
+ J3dDebug.doAssert(!offScreenBufferPending, "!offScreenBufferPending");
+
+ if (offScreenBuffer != null && offScreenBuffer != buffer) {
+ ImageComponent2DRetained i2dRetained =
+ (ImageComponent2DRetained)offScreenBuffer.retained;
+ i2dRetained.setUsedByOffScreen(false);
+ }
+
+ if (buffer != null) {
+ ImageComponent2DRetained bufferRetained =
+ (ImageComponent2DRetained)buffer.retained;
+
+ if (bufferRetained.byReference &&
+ !(bufferRetained.getRefImage(0) instanceof BufferedImage)) {
+
+ throw new IllegalArgumentException(J3dI18N.getString("Canvas3D15"));
+ }
+
+ if (bufferRetained.getNumberOfComponents() < 3 ) {
+ throw new IllegalArgumentException(J3dI18N.getString("Canvas3D16"));
+ }
+
+ if (buffer.isLive()) {
+ throw new IllegalSharingException(J3dI18N.getString("Canvas3D26"));
+ }
+
+ if (bufferRetained.getInImmCtx()) {
+ throw new IllegalSharingException(J3dI18N.getString("Canvas3D27"));
+ }
+
+ if (buffer != offScreenBuffer && bufferRetained.getUsedByOffScreen()) {
+ throw new IllegalSharingException(J3dI18N.getString("Canvas3D28"));
+ }
+
+ bufferRetained.setUsedByOffScreen(true);
+
+ width = bufferRetained.width;
+ height = bufferRetained.height;
+
+ // Issues 347, 348 - assign a canvasId for off-screen Canvas3D
+ if (manualRendering) {
+ sendAllocateCanvasId();
+ }
+ }
+ else {
+ width = height = 0;
+
+ // Issues 347, 348 - release canvasId for off-screen Canvas3D
+ if (manualRendering) {
+ freeCanvasId = true;
+ }
+ }
+
+ if ((offScreenCanvasSize.width != width) ||
+ (offScreenCanvasSize.height != height)) {
+
+ if (drawable != null) {
+ // Fix for Issue 18 and Issue 175
+ // Will do destroyOffScreenBuffer in the Renderer thread.
+ sendDestroyCtxAndOffScreenBuffer();
+ drawable = null;
+ }
+ // Issue 396. Since context is invalid here, we should set it to null.
+ ctx = null;
+
+ // set the canvas dimension according to the buffer dimension
+ offScreenCanvasSize.setSize(width, height);
+ this.setSize(offScreenCanvasSize);
+
+ if (width > 0 && height > 0) {
+ sendCreateOffScreenBuffer();
+ }
+
+ }
+ else if (ctx != null) {
+ removeCtx();
+ }
+
+ if (freeCanvasId) {
+ sendFreeCanvasId();
+ }
+
+ offScreenBuffer = buffer;
+
+ synchronized(dirtyMaskLock) {
+ cvDirtyMask[0] |= MOVED_OR_RESIZED_DIRTY;
+ cvDirtyMask[1] |= MOVED_OR_RESIZED_DIRTY;
+ }
+ }
+
+ /**
+ * Retrieves the off-screen buffer for this Canvas3D.
+ *
+ * @return the current off-screen buffer for this Canvas3D.
+ *
+ * @exception IllegalStateException if this Canvas3D is not in
+ * off-screen mode.
+ *
+ * @since Java 3D 1.2
+ */
+ public ImageComponent2D getOffScreenBuffer() {
+
+ if (!offScreen)
+ throw new IllegalStateException(J3dI18N.getString("Canvas3D1"));
+
+ return (offScreenBuffer);
+ }
+
+
+ /**
+ * Schedules the rendering of a frame into this Canvas3D's
+ * off-screen buffer. The rendering is done from the point of
+ * view of the View object to which this Canvas3D has been added.
+ * No rendering is performed if this Canvas3D object has not been
+ * added to an active View. This method does not wait for the rendering
+ * to actually happen. An application that wishes to know when
+ * the rendering is complete must either subclass Canvas3D and
+ * override the <code>postSwap</code> method, or call
+ * <code>waitForOffScreenRendering</code>.
+ *
+ * @exception NullPointerException if the off-screen buffer is null.
+ * @exception IllegalStateException if this Canvas3D is not in
+ * off-screen mode, or if either the width or the height of
+ * the associated Screen3D's size is <= 0, or if the associated
+ * Screen3D's physical width or height is <= 0.
+ * @exception RestrictedAccessException if an off-screen rendering
+ * is already in process for this Canvas3D or if the Java 3D renderer
+ * is stopped.
+ *
+ * @see #setOffScreenBuffer
+ * @see Screen3D#setSize(int, int)
+ * @see Screen3D#setSize(Dimension)
+ * @see Screen3D#setPhysicalScreenWidth
+ * @see Screen3D#setPhysicalScreenHeight
+ * @see #waitForOffScreenRendering
+ * @see #postSwap
+ *
+ * @since Java 3D 1.2
+ */
+ public void renderOffScreenBuffer() {
+
+ if (!offScreen)
+ throw new IllegalStateException(J3dI18N.getString("Canvas3D1"));
+
+ // Issue 131: Cannot manually render to an automatic canvas.
+ if (!manualRendering)
+ throw new IllegalStateException(J3dI18N.getString("Canvas3D24"));
+
+ // Issue 260 : Cannot render if we already have a fatal error
+ if (fatalError) {
+ throw new IllegalRenderingStateException(J3dI18N.getString("Canvas3D30"));
+ }
+
+ if (offScreenBuffer == null)
+ throw new NullPointerException(J3dI18N.getString("Canvas3D10"));
+
+ Dimension screenSize = screen.getSize();
+
+ if (screenSize.width <= 0)
+ throw new IllegalStateException(J3dI18N.getString("Canvas3D8"));
+
+ if (screenSize.height <= 0)
+ throw new IllegalStateException(J3dI18N.getString("Canvas3D9"));
+
+ if (screen.getPhysicalScreenWidth() <= 0.0)
+ throw new IllegalStateException(J3dI18N.getString("Canvas3D12"));
+
+ if (screen.getPhysicalScreenHeight() <= 0.0)
+ throw new IllegalStateException(J3dI18N.getString("Canvas3D13"));
+
+ if (offScreenRendering)
+ throw new RestrictedAccessException(J3dI18N.getString("Canvas3D2"));
+
+ if (!isRunning)
+ throw new RestrictedAccessException(J3dI18N.getString("Canvas3D11"));
+
+ // Fix to issue 66
+ if ((!active) || (pendingView == null)) {
+ /* No rendering is performed if this Canvas3D object has not been
+ added to an active View. */
+ return;
+ }
+
+ // Issue 131: moved code that determines off-screen boundary to separate
+ // method that is called from the renderer
+
+ offScreenRendering = true;
+
+ // Fix to issue 66.
+ /* This is an attempt to do the following check in one atomic operation :
+ ((view != null) && (view.inCanvasCallback)) */
+
+ boolean inCanvasCallback = false;
+ try {
+ inCanvasCallback = view.inCanvasCallback;
+
+ } catch (NullPointerException npe) {
+ /* Do nothing here */
+ }
+
+ if (inCanvasCallback) {
+ // Here we assume that view is stable if inCanvasCallback
+ // is true. This assumption is valid among all j3d threads as
+ // all access to view is synchronized by MasterControl.
+ // Issue : user threads access to view isn't synchronize hence
+ // is model will break.
+ if (screen.renderer == null) {
+
+ // It is possible that screen.renderer = null when this View
+ // is shared by another onScreen Canvas and this callback
+ // is from that Canvas. In this case it need one more
+ // round before the renderer.
+ screen.renderer = Screen3D.deviceRendererMap.get(screen.graphicsDevice);
+ // screen.renderer may equal to null when multiple
+ // screen is used and this Canvas3D is in different
+ // screen sharing the same View not yet initialize.
+ }
+
+ // if called from render call back, send a message directly to
+ // the renderer message queue, and call renderer doWork
+ // to do the offscreen rendering now
+ if (Thread.currentThread() == screen.renderer) {
+
+ J3dMessage createMessage = new J3dMessage();
+ createMessage.threads = J3dThread.RENDER_THREAD;
+ createMessage.type = J3dMessage.RENDER_OFFSCREEN;
+ createMessage.universe = this.view.universe;
+ createMessage.view = this.view;
+ createMessage.args[0] = this;
+
+ screen.renderer.rendererStructure.addMessage(createMessage);
+
+ // modify the args to reflect offScreen rendering
+ screen.renderer.args = new Object[4];
+ screen.renderer.args[0] = new Integer(Renderer.REQUESTRENDER);
+ screen.renderer.args[1] = this;
+ screen.renderer.args[2] = view;
+ // This extra argument 3 is needed in MasterControl to
+ // test whether offscreen Rendering is used or not
+ screen.renderer.args[3] = null;
+
+ // call renderer doWork directly since we are already in
+ // the renderer thread
+ screen.renderer.doWork(0);
+ } else {
+
+ // XXXX:
+ // Now we are in trouble, this will cause deadlock if
+ // waitForOffScreenRendering() is invoked
+ J3dMessage createMessage = new J3dMessage();
+ createMessage.threads = J3dThread.RENDER_THREAD;
+ createMessage.type = J3dMessage.RENDER_OFFSCREEN;
+ createMessage.universe = this.view.universe;
+ createMessage.view = this.view;
+ createMessage.args[0] = this;
+ screen.renderer.rendererStructure.addMessage(createMessage);
+ VirtualUniverse.mc.setWorkForRequestRenderer();
+ }
+
+ } else if (Thread.currentThread() instanceof BehaviorScheduler) {
+
+ // If called from behavior scheduler, send a message directly to
+ // the renderer message queue.
+ // Note that we didn't use
+ // currentThread() == view.universe.behaviorScheduler
+ // since the caller may be another universe Behavior
+ // scheduler.
+ J3dMessage createMessage = new J3dMessage();
+ createMessage.threads = J3dThread.RENDER_THREAD;
+ createMessage.type = J3dMessage.RENDER_OFFSCREEN;
+ createMessage.universe = this.view.universe;
+ createMessage.view = this.view;
+ createMessage.args[0] = this;
+ screen.renderer.rendererStructure.addMessage(createMessage);
+ VirtualUniverse.mc.setWorkForRequestRenderer();
+
+ } else {
+ // send a message to renderBin
+ // Fix for issue 66 : Since view might not been set yet,
+ // we have to use pendingView instead.
+ J3dMessage createMessage = new J3dMessage();
+ createMessage.threads = J3dThread.UPDATE_RENDER;
+ createMessage.type = J3dMessage.RENDER_OFFSCREEN;
+ createMessage.universe = this.pendingView.universe;
+ createMessage.view = this.pendingView;
+ createMessage.args[0] = this;
+ createMessage.args[1] = offScreenBuffer;
+ VirtualUniverse.mc.processMessage(createMessage);
+ }
+ }
+
+
+ /**
+ * Waits for this Canvas3D's off-screen rendering to be done.
+ * This method will wait until the <code>postSwap</code> method of this
+ * off-screen Canvas3D has completed. If this Canvas3D has not
+ * been added to an active view or if the renderer is stopped for this
+ * Canvas3D, then this method will return
+ * immediately. This method must not be called from a render
+ * callback method of an off-screen Canvas3D.
+ *
+ * @exception IllegalStateException if this Canvas3D is not in
+ * off-screen mode, or if this method is called from a render
+ * callback method of an off-screen Canvas3D.
+ *
+ * @see #renderOffScreenBuffer
+ * @see #postSwap
+ *
+ * @since Java 3D 1.2
+ */
+ public void waitForOffScreenRendering() {
+
+ if (!offScreen) {
+ throw new IllegalStateException(J3dI18N.getString("Canvas3D1"));
+ }
+
+ if (Thread.currentThread() instanceof Renderer) {
+ throw new IllegalStateException(J3dI18N.getString("Canvas3D31"));
+ }
+
+ while (offScreenRendering) {
+ MasterControl.threadYield();
+ }
+ }
+
+
+ /**
+ * Sets the location of this off-screen Canvas3D. The location is
+ * the upper-left corner of the Canvas3D relative to the
+ * upper-left corner of the corresponding off-screen Screen3D.
+ * The function of this method is similar to that of
+ * <code>Component.setLocation</code> for on-screen Canvas3D
+ * objects. The default location is (0,0).
+ *
+ * @param x the <i>x</i> coordinate of the upper-left corner of
+ * the new location.
+ * @param y the <i>y</i> coordinate of the upper-left corner of
+ * the new location.
+ *
+ * @exception IllegalStateException if this Canvas3D is not in
+ * off-screen mode.
+ *
+ * @since Java 3D 1.2
+ */
+ public void setOffScreenLocation(int x, int y) {
+
+ if (!offScreen)
+ throw new IllegalStateException(J3dI18N.getString("Canvas3D1"));
+
+ synchronized(cvLock) {
+ offScreenCanvasLoc.setLocation(x, y);
+ }
+ }
+
+
+ /**
+ * Sets the location of this off-screen Canvas3D. The location is
+ * the upper-left corner of the Canvas3D relative to the
+ * upper-left corner of the corresponding off-screen Screen3D.
+ * The function of this method is similar to that of
+ * <code>Component.setLocation</code> for on-screen Canvas3D
+ * objects. The default location is (0,0).
+ *
+ * @param p the point defining the upper-left corner of the new
+ * location.
+ *
+ * @exception IllegalStateException if this Canvas3D is not in
+ * off-screen mode.
+ *
+ * @since Java 3D 1.2
+ */
+ public void setOffScreenLocation(Point p) {
+
+ if (!offScreen)
+ throw new IllegalStateException(J3dI18N.getString("Canvas3D1"));
+
+ synchronized(cvLock) {
+ offScreenCanvasLoc.setLocation(p);
+ }
+ }
+
+
+ /**
+ * Retrieves the location of this off-screen Canvas3D. The
+ * location is the upper-left corner of the Canvas3D relative to
+ * the upper-left corner of the corresponding off-screen Screen3D.
+ * The function of this method is similar to that of
+ * <code>Component.getLocation</code> for on-screen Canvas3D
+ * objects.
+ *
+ * @return a new point representing the upper-left corner of the
+ * location of this off-screen Canvas3D.
+ *
+ * @exception IllegalStateException if this Canvas3D is not in
+ * off-screen mode.
+ *
+ * @since Java 3D 1.2
+ */
+ public Point getOffScreenLocation() {
+ if (!offScreen)
+ throw new IllegalStateException(J3dI18N.getString("Canvas3D1"));
+
+ return (new Point(offScreenCanvasLoc));
+ }
+
+
+ /**
+ * Retrieves the location of this off-screen Canvas3D and stores
+ * it in the specified Point object. The location is the
+ * upper-left corner of the Canvas3D relative to the upper-left
+ * corner of the corresponding off-screen Screen3D. The function
+ * of this method is similar to that of
+ * <code>Component.getLocation</code> for on-screen Canvas3D
+ * objects. This version of <code>getOffScreenLocation</code> is
+ * useful if the caller wants to avoid allocating a new Point
+ * object on the heap.
+ *
+ * @param rv Point object into which the upper-left corner of the
+ * location of this off-screen Canvas3D is copied.
+ * If <code>rv</code> is null, a new Point is allocated.
+ *
+ * @return <code>rv</code>
+ *
+ * @exception IllegalStateException if this Canvas3D is not in
+ * off-screen mode.
+ *
+ * @since Java 3D 1.2
+ */
+ public Point getOffScreenLocation(Point rv) {
+
+ if (!offScreen)
+ throw new IllegalStateException(J3dI18N.getString("Canvas3D1"));
+
+ if (rv == null)
+ return (new Point(offScreenCanvasLoc));
+
+ else {
+ rv.setLocation(offScreenCanvasLoc);
+ return rv;
+ }
+ }
+
+ void endOffScreenRendering() {
+
+ ImageComponent2DRetained icRetained = (ImageComponent2DRetained)offScreenBuffer.retained;
+ boolean isByRef = icRetained.isByReference();
+ ImageComponentRetained.ImageData imageData = icRetained.getImageData(false);
+
+ if(!isByRef) {
+ // If icRetained has a null image ( BufferedImage)
+ if (imageData == null) {
+ assert (!isByRef);
+ icRetained.createBlankImageData();
+ imageData = icRetained.getImageData(false);
+ }
+ // Check for possible format conversion in imageData
+ else {
+ // Format convert imageData if format is unsupported.
+ icRetained.evaluateExtensions(this);
+ }
+ // read the image from the offscreen buffer
+ readOffScreenBuffer(ctx, icRetained.getImageFormatTypeIntValue(false),
+ icRetained.getImageDataTypeIntValue(), imageData.get(),
+ offScreenCanvasSize.width, offScreenCanvasSize.height);
+
+ } else {
+ icRetained.geomLock.getLock();
+ // Create a copy of format converted image in imageData if format is unsupported.
+ icRetained.evaluateExtensions(this);
+
+ // read the image from the offscreen buffer
+ readOffScreenBuffer(ctx, icRetained.getImageFormatTypeIntValue(false),
+ icRetained.getImageDataTypeIntValue(), imageData.get(),
+ offScreenCanvasSize.width, offScreenCanvasSize.height);
+
+ // For byRef, we might have to copy buffer back into
+ // the user's referenced ImageComponent2D
+ if(!imageData.isDataByRef()) {
+ if(icRetained.isImageTypeSupported()) {
+ icRetained.copyToRefImage(0);
+ } else {
+ // This method only handle RGBA conversion.
+ icRetained.copyToRefImageWithFormatConversion(0);
+ }
+ }
+
+ icRetained.geomLock.unLock();
+ }
+ }
+
+ /**
+ * Synchronize and swap buffers on a double buffered canvas for
+ * this Canvas3D object. This method should only be called if the
+ * Java 3D renderer has been stopped. In the normal case, the renderer
+ * automatically swaps the buffer.
+ * This method calls the <code>flush(true)</code> methods of the
+ * associated 2D and 3D graphics contexts, if they have been allocated.
+ *
+ * @exception RestrictedAccessException if the Java 3D renderer is
+ * running.
+ * @exception IllegalStateException if this Canvas3D is in
+ * off-screen mode.
+ *
+ * @see #stopRenderer
+ * @see GraphicsContext3D#flush
+ * @see J3DGraphics2D#flush
+ */
+ public void swap() {
+ if (offScreen)
+ throw new IllegalStateException(J3dI18N.getString("Canvas3D14"));
+
+ if (isRunning)
+ throw new RestrictedAccessException(J3dI18N.getString("Canvas3D0"));
+
+ if (!firstPaintCalled) {
+ return;
+ }
+
+ if (view != null && graphicsContext3D != null) {
+ if ((view.universe != null) &&
+ (Thread.currentThread() == view.universe.behaviorScheduler)) {
+ graphicsContext3D.sendRenderMessage(false, GraphicsContext3D.SWAP, null, null);
+ } else {
+ graphicsContext3D.sendRenderMessage(true, GraphicsContext3D.SWAP, null, null);
+ }
+ graphicsContext3D.runMonitor(J3dThread.WAIT);
+ }
+ }
+
+ void doSwap() {
+
+ if (firstPaintCalled && useDoubleBuffer) {
+ try {
+ if (validCtx && (ctx != null) && (view != null)) {
+ synchronized (drawingSurfaceObject) {
+ if (validCtx) {
+ if (!drawingSurfaceObject.renderLock()) {
+ graphicsContext3D.runMonitor(J3dThread.NOTIFY);
+ return;
+ }
+ this.syncRender(ctx, true);
+ swapBuffers(ctx, drawable);
+ drawingSurfaceObject.unLock();
+ }
+ }
+ }
+ } catch (NullPointerException ne) {
+ drawingSurfaceObject.unLock();
+ }
+ }
+ // Increment the elapsedFrame for the behavior structure
+ // to trigger any interpolators
+ view.universe.behaviorStructure.incElapsedFrames();
+ graphicsContext3D.runMonitor(J3dThread.NOTIFY);
+ }
+
+ /**
+ * Wrapper for native createNewContext method.
+ */
+ Context createNewContext(Context shareCtx, boolean isSharedCtx) {
+ Context retVal = createNewContext(
+ this.drawable,
+ shareCtx, isSharedCtx,
+ this.offScreen);
+ // compute the max available texture units
+ maxAvailableTextureUnits = Math.max(maxTextureUnits, maxTextureImageUnits);
+ // reset 'antialiasingSet' if new context is created for an already existing Canvas3D,
+ // e.g. resizing offscreen Canvas3D
+ antialiasingSet = false;
+
+ return retVal;
+ }
+
+ /**
+ * Make the context associated with the specified canvas current.
+ */
+ final void makeCtxCurrent() {
+ makeCtxCurrent(ctx, drawable);
+ }
+
+ /**
+ * Make the specified context current.
+ */
+ final void makeCtxCurrent(Context ctx) {
+ makeCtxCurrent(ctx, drawable);
+ }
+
+ final void makeCtxCurrent(Context ctx, Drawable drawable) {
+ if (ctx != screen.renderer.currentCtx || drawable != screen.renderer.currentDrawable) {
+ if (!drawingSurfaceObject.isLocked()) {
+ drawingSurfaceObject.renderLock();
+ useCtx(ctx, drawable);
+ drawingSurfaceObject.unLock();
+ } else {
+ useCtx(ctx, drawable);
+ }
+ screen.renderer.currentCtx = ctx;
+ screen.renderer.currentDrawable = drawable;
+ }
+ }
+
+ // Give the pipeline a chance to release the context; the Pipeline may
+ // or may not ignore this call.
+ void releaseCtx() {
+ if (screen.renderer.currentCtx != null) {
+ boolean needLock = !drawingSurfaceObject.isLocked();
+ if (needLock) {
+ drawingSurfaceObject.renderLock();
+ }
+ if (releaseCtx(screen.renderer.currentCtx)) {
+ screen.renderer.currentCtx = null;
+ screen.renderer.currentDrawable = null;
+ }
+ if (needLock) {
+ drawingSurfaceObject.unLock();
+ }
+ }
+ }
+
+
+ /**
+ * Sets the position of the manual left eye in image-plate
+ * coordinates. This value determines eye placement when a head
+ * tracker is not in use and the application is directly controlling
+ * the eye position in image-plate coordinates.
+ * In head-tracked mode or when the windowEyePointPolicy is
+ * RELATIVE_TO_FIELD_OF_VIEW or RELATIVE_TO_COEXISTENCE, this value
+ * is ignored. When the
+ * windowEyepointPolicy is RELATIVE_TO_WINDOW only the Z value is
+ * used.
+ * @param position the new manual left eye position
+ */
+ public void setLeftManualEyeInImagePlate(Point3d position) {
+
+ this.leftManualEyeInImagePlate.set(position);
+ synchronized(dirtyMaskLock) {
+ cvDirtyMask[0] |= EYE_IN_IMAGE_PLATE_DIRTY;
+ cvDirtyMask[1] |= EYE_IN_IMAGE_PLATE_DIRTY;
+ }
+ redraw();
+ }
+
+ /**
+ * Sets the position of the manual right eye in image-plate
+ * coordinates. This value determines eye placement when a head
+ * tracker is not in use and the application is directly controlling
+ * the eye position in image-plate coordinates.
+ * In head-tracked mode or when the windowEyePointPolicy is
+ * RELATIVE_TO_FIELD_OF_VIEW or RELATIVE_TO_COEXISTENCE, this value
+ * is ignored. When the
+ * windowEyepointPolicy is RELATIVE_TO_WINDOW only the Z value is
+ * used.
+ * @param position the new manual right eye position
+ */
+ public void setRightManualEyeInImagePlate(Point3d position) {
+
+ this.rightManualEyeInImagePlate.set(position);
+ synchronized(dirtyMaskLock) {
+ cvDirtyMask[0] |= EYE_IN_IMAGE_PLATE_DIRTY;
+ cvDirtyMask[1] |= EYE_IN_IMAGE_PLATE_DIRTY;
+ }
+ redraw();
+ }
+
+ /**
+ * Retrieves the position of the user-specified, manual left eye
+ * in image-plate
+ * coordinates and copies that value into the object provided.
+ * @param position the object that will receive the position
+ */
+ public void getLeftManualEyeInImagePlate(Point3d position) {
+ position.set(this.leftManualEyeInImagePlate);
+ }
+
+ /**
+ * Retrieves the position of the user-specified, manual right eye
+ * in image-plate
+ * coordinates and copies that value into the object provided.
+ * @param position the object that will receive the position
+ */
+ public void getRightManualEyeInImagePlate(Point3d position) {
+ position.set(this.rightManualEyeInImagePlate);
+ }
+
+ /**
+ * Retrieves the actual position of the left eye
+ * in image-plate
+ * coordinates and copies that value into the object provided.
+ * This value is a function of the windowEyepointPolicy, the tracking
+ * enable flag, and the manual left eye position.
+ * @param position the object that will receive the position
+ */
+ public void getLeftEyeInImagePlate(Point3d position) {
+ if (canvasViewCache != null) {
+ synchronized(canvasViewCache) {
+ position.set(canvasViewCache.getLeftEyeInImagePlate());
+ }
+ }
+ else {
+ position.set(leftManualEyeInImagePlate);
+ }
+ }
+
+ /**
+ * Retrieves the actual position of the right eye
+ * in image-plate
+ * coordinates and copies that value into the object provided.
+ * This value is a function of the windowEyepointPolicy, the tracking
+ * enable flag, and the manual right eye position.
+ * @param position the object that will receive the position
+ */
+ public void getRightEyeInImagePlate(Point3d position) {
+ if (canvasViewCache != null) {
+ synchronized(canvasViewCache) {
+ position.set(canvasViewCache.getRightEyeInImagePlate());
+ }
+ }
+ else {
+ position.set(rightManualEyeInImagePlate);
+ }
+ }
+
+ /**
+ * Retrieves the actual position of the center eye
+ * in image-plate
+ * coordinates and copies that value into the object provided.
+ * The center eye is the fictional eye half-way between the left and
+ * right eye.
+ * This value is a function of the windowEyepointPolicy, the tracking
+ * enable flag, and the manual right and left eye positions.
+ * @param position the object that will receive the position
+ * @see #setMonoscopicViewPolicy
+ */
+ // XXXX: This might not make sense for field-sequential HMD.
+ public void getCenterEyeInImagePlate(Point3d position) {
+ if (canvasViewCache != null) {
+ synchronized(canvasViewCache) {
+ position.set(canvasViewCache.getCenterEyeInImagePlate());
+ }
+ }
+ else {
+ Point3d cenEye = new Point3d();
+ cenEye.add(leftManualEyeInImagePlate, rightManualEyeInImagePlate);
+ cenEye.scale(0.5);
+ position.set(cenEye);
+ }
+ }
+
+ /**
+ * Retrieves the current ImagePlate coordinates to Virtual World
+ * coordinates transform and places it into the specified object.
+ * @param t the Transform3D object that will receive the
+ * transform
+ */
+ // TODO: Document -- This will return the transform of left plate.
+ public void getImagePlateToVworld(Transform3D t) {
+ if (canvasViewCache != null) {
+ synchronized(canvasViewCache) {
+ t.set(canvasViewCache.getImagePlateToVworld());
+ }
+ }
+ else {
+ t.setIdentity();
+ }
+ }
+
+ /**
+ * Computes the position of the specified AWT pixel value
+ * in image-plate
+ * coordinates and copies that value into the object provided.
+ * @param x the X coordinate of the pixel relative to the upper-left
+ * hand corner of the window.
+ * @param y the Y coordinate of the pixel relative to the upper-left
+ * hand corner of the window.
+ * @param imagePlatePoint the object that will receive the position in
+ * physical image plate coordinates (relative to the lower-left
+ * corner of the screen).
+ */
+ // TODO: Document -- This transform the pixel location to the left image plate.
+ public void getPixelLocationInImagePlate(int x, int y,
+ Point3d imagePlatePoint) {
+
+ if (canvasViewCache != null) {
+ synchronized(canvasViewCache) {
+ imagePlatePoint.x =
+ canvasViewCache.getWindowXInImagePlate((double)x);
+ imagePlatePoint.y =
+ canvasViewCache.getWindowYInImagePlate((double)y);
+ imagePlatePoint.z = 0.0;
+ }
+ } else {
+ imagePlatePoint.set(0.0, 0.0, 0.0);
+ }
+ }
+
+
+ void getPixelLocationInImagePlate(double x, double y, double z,
+ Point3d imagePlatePoint) {
+ if (canvasViewCache != null) {
+ synchronized(canvasViewCache) {
+ canvasViewCache.getPixelLocationInImagePlate(
+ x, y, z, imagePlatePoint);
+ }
+ } else {
+ imagePlatePoint.set(0.0, 0.0, 0.0);
+ }
+ }
+
+
+ /**
+ * Computes the position of the specified AWT pixel value
+ * in image-plate
+ * coordinates and copies that value into the object provided.
+ * @param pixelLocation the coordinates of the pixel relative to
+ * the upper-left hand corner of the window.
+ * @param imagePlatePoint the object that will receive the position in
+ * physical image plate coordinates (relative to the lower-left
+ * corner of the screen).
+ *
+ * @since Java 3D 1.2
+ */
+ // TODO: Document -- This transform the pixel location to the left image plate.
+ public void getPixelLocationInImagePlate(Point2d pixelLocation,
+ Point3d imagePlatePoint) {
+
+ if (canvasViewCache != null) {
+ synchronized(canvasViewCache) {
+ imagePlatePoint.x =
+ canvasViewCache.getWindowXInImagePlate(pixelLocation.x);
+ imagePlatePoint.y =
+ canvasViewCache.getWindowYInImagePlate(pixelLocation.y);
+ imagePlatePoint.z = 0.0;
+ }
+ }
+ else {
+ imagePlatePoint.set(0.0, 0.0, 0.0);
+ }
+ }
+
+
+ /**
+ * Projects the specified point from image plate coordinates
+ * into AWT pixel coordinates. The AWT pixel coordinates are
+ * copied into the object provided.
+ * @param imagePlatePoint the position in
+ * physical image plate coordinates (relative to the lower-left
+ * corner of the screen).
+ * @param pixelLocation the object that will receive the coordinates
+ * of the pixel relative to the upper-left hand corner of the window.
+ *
+ * @since Java 3D 1.2
+ */
+ // TODO: Document -- This transform the pixel location from the left image plate.
+ public void getPixelLocationFromImagePlate(Point3d imagePlatePoint,
+ Point2d pixelLocation) {
+ if (canvasViewCache != null) {
+ synchronized(canvasViewCache) {
+ canvasViewCache.getPixelLocationFromImagePlate(
+ imagePlatePoint, pixelLocation);
+ }
+ }
+ else {
+ pixelLocation.set(0.0, 0.0);
+ }
+ }
+
+ /**
+ * Copies the current Vworld projection transform for each eye
+ * into the specified Transform3D objects. This transform takes
+ * points in virtual world coordinates and projects them into
+ * clipping coordinates, which are in the range [-1,1] in
+ * <i>X</i>, <i>Y</i>, and <i>Z</i> after clipping and perspective
+ * division.
+ * In monoscopic mode, the same projection transform will be
+ * copied into both the right and left eye Transform3D objects.
+ *
+ * @param leftProjection the Transform3D object that will receive
+ * a copy of the current projection transform for the left eye.
+ *
+ * @param rightProjection the Transform3D object that will receive
+ * a copy of the current projection transform for the right eye.
+ *
+ * @since Java 3D 1.3
+ */
+ public void getVworldProjection(Transform3D leftProjection,
+ Transform3D rightProjection) {
+ if (canvasViewCache != null) {
+ ViewPlatformRetained viewPlatformRetained =
+ (ViewPlatformRetained)view.getViewPlatform().retained;
+
+ synchronized(canvasViewCache) {
+ leftProjection.mul(canvasViewCache.getLeftProjection(),
+ canvasViewCache.getLeftVpcToEc());
+ leftProjection.mul(viewPlatformRetained.getVworldToVpc());
+
+ // caluclate right eye if in stereo, otherwise
+ // this is the same as the left eye.
+ if (useStereo) {
+ rightProjection.mul(canvasViewCache.getRightProjection(),
+ canvasViewCache.getRightVpcToEc());
+ rightProjection.mul(viewPlatformRetained.getVworldToVpc());
+ }
+ else {
+ rightProjection.set(leftProjection);
+ }
+ }
+ }
+ else {
+ leftProjection.setIdentity();
+ rightProjection.setIdentity();
+ }
+ }
+
+ /**
+ * Copies the inverse of the current Vworld projection transform
+ * for each eye into the specified Transform3D objects. This
+ * transform takes points in clipping coordinates, which are in
+ * the range [-1,1] in <i>X</i>, <i>Y</i>, and <i>Z</i> after
+ * clipping and perspective division, and transforms them into
+ * virtual world coordinates.
+ * In monoscopic mode, the same inverse projection transform will
+ * be copied into both the right and left eye Transform3D objects.
+ *
+ * @param leftInverseProjection the Transform3D object that will
+ * receive a copy of the current inverse projection transform for
+ * the left eye.
+ * @param rightInverseProjection the Transform3D object that will
+ * receive a copy of the current inverse projection transform for
+ * the right eye.
+ *
+ * @since Java 3D 1.3
+ */
+ public void getInverseVworldProjection(Transform3D leftInverseProjection,
+ Transform3D rightInverseProjection) {
+ if (canvasViewCache != null) {
+ synchronized(canvasViewCache) {
+ leftInverseProjection.set(
+ canvasViewCache.getLeftCcToVworld());
+
+ // caluclate right eye if in stereo, otherwise
+ // this is the same as the left eye.
+ if (useStereo) {
+ rightInverseProjection.set(
+ canvasViewCache.getRightCcToVworld());
+ }
+ else {
+ rightInverseProjection.set(leftInverseProjection);
+ }
+ }
+
+ }
+ else {
+ leftInverseProjection.setIdentity();
+ rightInverseProjection.setIdentity();
+ }
+ }
+
+
+ /**
+ * Retrieves the physical width of this canvas window in meters.
+ * @return the physical window width in meters.
+ */
+ public double getPhysicalWidth() {
+ double width = 0.0;
+
+ if (canvasViewCache != null) {
+ synchronized(canvasViewCache) {
+ width = canvasViewCache.getPhysicalWindowWidth();
+ }
+ }
+
+ return width;
+ }
+
+ /**
+ * Retrieves the physical height of this canvas window in meters.
+ * @return the physical window height in meters.
+ */
+ public double getPhysicalHeight() {
+ double height = 0.0;
+
+ if (canvasViewCache != null) {
+ synchronized(canvasViewCache) {
+ height = canvasViewCache.getPhysicalWindowHeight();
+ }
+ }
+
+ return height;
+ }
+
+ /**
+ * Retrieves the current Virtual World coordinates to ImagePlate
+ * coordinates transform and places it into the specified object.
+ * @param t the Transform3D object that will receive the
+ * transform
+ */
+ // TODO: Document -- This will return the transform of left plate.
+ public void getVworldToImagePlate(Transform3D t) {
+ if (canvasViewCache != null) {
+ synchronized(canvasViewCache) {
+ t.set(canvasViewCache.getVworldToImagePlate());
+ }
+ }
+ else {
+ t.setIdentity();
+ }
+ }
+
+ void getLastVworldToImagePlate(Transform3D t) {
+ if (canvasViewCache != null) {
+ synchronized(canvasViewCache) {
+ t.set(canvasViewCache.getLastVworldToImagePlate());
+ }
+ }
+ else {
+ t.setIdentity();
+ }
+ }
+
+ /**
+ * Sets view that points to this Canvas3D.
+ * @param view view object that points to this Canvas3D
+ */
+ void setView(View view) {
+ pendingView = view;
+
+ // We can't set View directly here in user thread since
+ // other threads may using canvas.view
+ // e.g. In Renderer, we use canvas3d.view.inCallBack
+ // before and after postSwap(), if view change in between
+ // than view.inCallBack may never reset to false.
+ VirtualUniverse.mc.postRequest(MasterControl.SET_VIEW, this);
+ evaluateActive();
+ }
+
+ void computeViewCache() {
+ synchronized(cvLock) {
+ if (view == null) {
+ canvasViewCache = null;
+ canvasViewCacheFrustum = null;
+ } else {
+
+ canvasViewCache = new CanvasViewCache(this,
+ screen.screenViewCache,
+ view.viewCache);
+ // Issue 109 : construct a separate canvasViewCache for
+ // computing view frustum
+ canvasViewCacheFrustum = new CanvasViewCache(this,
+ screen.screenViewCache,
+ view.viewCache);
+ synchronized (dirtyMaskLock) {
+ cvDirtyMask[0] = VIEW_INFO_DIRTY;
+ cvDirtyMask[1] = VIEW_INFO_DIRTY;
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets view that points to this Canvas3D.
+ * @return view object that points to this Canvas3D
+ */
+ public View getView() {
+ return pendingView;
+ }
+
+ /**
+ * Returns a status flag indicating whether or not stereo
+ * is available.
+ * This is equivalent to:
+ * <ul>
+ * <code>
+ * ((Boolean)queryProperties().
+ * get("stereoAvailable")).
+ * booleanValue()
+ * </code>
+ * </ul>
+ *
+ * @return a flag indicating whether stereo is available
+ */
+ public boolean getStereoAvailable() {
+ return ((Boolean)queryProperties().get("stereoAvailable")).
+ booleanValue();
+ }
+
+ /**
+ * Turns stereo on or off. Note that this attribute is used
+ * only when stereo is available. Enabling stereo on a Canvas3D
+ * that does not support stereo has no effect.
+ * @param flag enables or disables the display of stereo
+ *
+ * @see #queryProperties
+ */
+ public void setStereoEnable(boolean flag) {
+ stereoEnable = flag;
+ useStereo = stereoEnable && stereoAvailable;
+ synchronized(dirtyMaskLock) {
+ cvDirtyMask[0] |= STEREO_DIRTY;
+ cvDirtyMask[1] |= STEREO_DIRTY;
+ }
+ redraw();
+ }
+
+ /**
+ * Returns a status flag indicating whether or not stereo
+ * is enabled.
+ * @return a flag indicating whether stereo is enabled
+ */
+ public boolean getStereoEnable() {
+ return this.stereoEnable;
+ }
+
+
+ /**
+ * Specifies how Java 3D generates monoscopic view. If set to
+ * View.LEFT_EYE_VIEW, the view generated corresponds to the view as
+ * seen from the left eye. If set to View.RIGHT_EYE_VIEW, the view
+ * generated corresponds to the view as seen from the right
+ * eye. If set to View.CYCLOPEAN_EYE_VIEW, the view generated
+ * corresponds to the view as seen from the 'center eye', the
+ * fictional eye half-way between the left and right eye. The
+ * default monoscopic view policy is View.CYCLOPEAN_EYE_VIEW.
+ * <p>
+ * NOTE: for backward compatibility with Java 3D 1.1, if this
+ * attribute is set to its default value of
+ * View.CYCLOPEAN_EYE_VIEW, the monoscopic view policy in the
+ * View object will be used. An application should not use both
+ * the deprecated View method and this Canvas3D method at the same
+ * time.
+ * @param policy one of View.LEFT_EYE_VIEW, View.RIGHT_EYE_VIEW, or
+ * View.CYCLOPEAN_EYE_VIEW.
+ *
+ * @exception IllegalStateException if the specified
+ * policy is CYCLOPEAN_EYE_VIEW, the canvas is a stereo canvas,
+ * and the viewPolicy for the associated view is HMD_VIEW
+ *
+ * @since Java 3D 1.2
+ */
+ public void setMonoscopicViewPolicy(int policy) {
+
+
+ if((view !=null) && (view.viewPolicy == View.HMD_VIEW) &&
+ (monoscopicViewPolicy == View.CYCLOPEAN_EYE_VIEW) &&
+ (!useStereo)) {
+ throw new
+ IllegalStateException(J3dI18N.getString("View31"));
+ }
+
+ monoscopicViewPolicy = policy;
+ synchronized(dirtyMaskLock) {
+ cvDirtyMask[0] |= MONOSCOPIC_VIEW_POLICY_DIRTY;
+ cvDirtyMask[1] |= MONOSCOPIC_VIEW_POLICY_DIRTY;
+ }
+ redraw();
+ }
+
+
+ /**
+ * Returns policy on how Java 3D generates monoscopic view.
+ * @return policy one of View.LEFT_EYE_VIEW, View.RIGHT_EYE_VIEW or
+ * View.CYCLOPEAN_EYE_VIEW.
+ *
+ * @since Java 3D 1.2
+ */
+ public int getMonoscopicViewPolicy() {
+ return this.monoscopicViewPolicy;
+ }
+
+
+ /**
+ * Returns a status flag indicating whether or not double
+ * buffering is available.
+ * This is equivalent to:
+ * <ul>
+ * <code>
+ * ((Boolean)queryProperties().
+ * get("doubleBufferAvailable")).
+ * booleanValue()
+ * </code>
+ * </ul>
+ *
+ * @return a flag indicating whether double buffering is available.
+ */
+ public boolean getDoubleBufferAvailable() {
+ return ((Boolean)queryProperties().get("doubleBufferAvailable")).
+ booleanValue();
+ }
+
+ /**
+ * Turns double buffering on or off. If double buffering
+ * is off, all drawing is to the front buffer and no buffer swap
+ * is done between frames. It should be stressed that running
+ * Java 3D with double buffering disabled is not recommended.
+ * Enabling double buffering on a Canvas3D
+ * that does not support double buffering has no effect.
+ *
+ * @param flag enables or disables double buffering.
+ *
+ * @see #queryProperties
+ */
+ public void setDoubleBufferEnable(boolean flag) {
+ doubleBufferEnable = flag;
+ useDoubleBuffer = doubleBufferEnable && doubleBufferAvailable;
+ if (Thread.currentThread() == screen.renderer) {
+ setRenderMode(ctx, FIELD_ALL, useDoubleBuffer);
+ }
+ redraw();
+ }
+
+ /**
+ * Returns a status flag indicating whether or not double
+ * buffering is enabled.
+ * @return a flag indicating if double buffering is enabled.
+ */
+ public boolean getDoubleBufferEnable() {
+ return doubleBufferEnable;
+ }
+
+ /**
+ * Returns a status flag indicating whether or not scene
+ * antialiasing is available.
+ * This is equivalent to:
+ * <ul>
+ * <code>
+ * ((Boolean)queryProperties().
+ * get("sceneAntialiasingAvailable")).
+ * booleanValue()
+ * </code>
+ * </ul>
+ *
+ * @return a flag indicating whether scene antialiasing is available.
+ */
+ public boolean getSceneAntialiasingAvailable() {
+ return ((Boolean)queryProperties().get("sceneAntialiasingAvailable")).
+ booleanValue();
+ }
+
+
+ /**
+ * Returns a flag indicating whether or not the specified shading
+ * language is supported. A ShaderError will be generated if an
+ * unsupported shading language is used.
+ *
+ * @param shadingLanguage the shading language being queried, one of:
+ * <code>Shader.SHADING_LANGUAGE_GLSL</code> or
+ * <code>Shader.SHADING_LANGUAGE_CG</code>.
+ *
+ * @return true if the specified shading language is supported,
+ * false otherwise.
+ *
+ * @since Java 3D 1.4
+ */
+ public boolean isShadingLanguageSupported(int shadingLanguage) {
+ // Call queryProperties to ensure that the shading language flags are valid
+ queryProperties();
+
+ if (shadingLanguage == Shader.SHADING_LANGUAGE_GLSL)
+ return shadingLanguageGLSL;
+
+ return false;
+ }
+
+
+ /**
+ * Returns a read-only Map object containing key-value pairs that define
+ * various properties for this Canvas3D. All of the keys are
+ * String objects. The values are key-specific, but most will be
+ * Boolean, Integer, Float, Double, or String objects.
+ *
+ * <p>
+ * The currently defined keys are:
+ *
+ * <p>
+ * <ul>
+ * <table BORDER=1 CELLSPACING=1 CELLPADDING=1>
+ * <tr>
+ * <td><b>Key (String)</b></td>
+ * <td><b>Value Type</b></td>
+ * </tr>
+ * <tr>
+ * <td><code>shadingLanguageCg</code></td>
+ * <td>Boolean</td>
+ * </tr>
+ * <tr>
+ * <td><code>shadingLanguageGLSL</code></td>
+ * <td>Boolean</td>
+ * </tr>
+ * <tr>
+ * <td><code>doubleBufferAvailable</code></td>
+ * <td>Boolean</td>
+ * </tr>
+ * <tr>
+ * <td><code>stereoAvailable</code></td>
+ * <td>Boolean</td>
+ * </tr>
+ * <tr>
+ * <td><code>sceneAntialiasingAvailable</code></td>
+ * <td>Boolean</td>
+ * </tr>
+ * <tr>
+ * <td><code>sceneAntialiasingNumPasses</code></td>
+ * <td>Integer</td>
+ * </tr>
+ * <tr>
+ * <td><code>stencilSize</code></td>
+ * <td>Integer</td>
+ * </tr>
+ * <tr>
+ * <td><code>texture3DAvailable</code></td>
+ * <td>Boolean</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureColorTableSize</code></td>
+ * <td>Integer</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureLodRangeAvailable</code></td>
+ * <td>Boolean</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureLodOffsetAvailable</code></td>
+ * <td>Boolean</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureWidthMax</code></td>
+ * <td>Integer</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureHeightMax</code></td>
+ * <td>Integer</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureBoundaryWidthMax</code></td>
+ * <td>Integer</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureEnvCombineAvailable</code></td>
+ * <td>Boolean</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureCombineDot3Available</code></td>
+ * <td>Boolean</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureCombineSubtractAvailable</code></td>
+ * <td>Boolean</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureCoordSetsMax</code></td>
+ * <td>Integer</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureUnitStateMax</code></td>
+ * <td>Integer</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureImageUnitsMax</code></td>
+ * <td>Integer</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureImageUnitsVertexMax</code></td>
+ * <td>Integer</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureImageUnitsCombinedMax</code></td>
+ * <td>Integer</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureCubeMapAvailable</code></td>
+ * <td>Boolean</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureDetailAvailable</code></td>
+ * <td>Boolean</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureSharpenAvailable</code></td>
+ * <td>Boolean</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureFilter4Available</code></td>
+ * <td>Boolean</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureAnisotropicFilterDegreeMax</code></td>
+ * <td>Float</td>
+ * </tr>
+ * <tr>
+ * <td><code>textureNonPowerOfTwoAvailable</code></td>
+ * <td>Boolean</td>
+ * </tr>
+ * <tr>
+ * <td><code>vertexAttrsMax</code></td>
+ * <td>Integer</td>
+ * </tr>
+ * <tr>
+ * <td><code>compressedGeometry.majorVersionNumber</code></td>
+ * <td>Integer</td>
+ * </tr>
+ * <tr>
+ * <td><code>compressedGeometry.minorVersionNumber</code></td>
+ * <td>Integer</td>
+ * </tr>
+ * <tr>
+ * <td><code>compressedGeometry.minorMinorVersionNumber</code></td>
+ * <td>Integer</td>
+ * </tr>
+ * <tr>
+ * <td><code>native.version</code></td>
+ * <td>String</td>
+ * </tr>
+ * </table>
+ * </ul>
+ *
+ * <p>
+ * The descriptions of the values returned for each key are as follows:
+ *
+ * <p>
+ * <ul>
+ * <li>
+ * <code>shadingLanguageCg</code>
+ * <ul>
+ * A Boolean indicating whether or not Cg shading Language
+ * is available for this Canvas3D.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>shadingLanguageGLSL</code>
+ * <ul>
+ * A Boolean indicating whether or not GLSL shading Language
+ * is available for this Canvas3D.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>doubleBufferAvailable</code>
+ * <ul>
+ * A Boolean indicating whether or not double buffering
+ * is available for this Canvas3D. This is equivalent to
+ * the getDoubleBufferAvailable method. If this flag is false,
+ * the Canvas3D will be rendered in single buffer mode; requests
+ * to enable double buffering will be ignored.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>stereoAvailable</code>
+ * <ul>
+ * A Boolean indicating whether or not stereo
+ * is available for this Canvas3D. This is equivalent to
+ * the getStereoAvailable method. If this flag is false,
+ * the Canvas3D will be rendered in monoscopic mode; requests
+ * to enable stereo will be ignored.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>sceneAntialiasingAvailable</code>
+ * <ul>
+ * A Boolean indicating whether or not scene antialiasing
+ * is available for this Canvas3D. This is equivalent to
+ * the getSceneAntialiasingAvailable method. If this flag is false,
+ * requests to enable scene antialiasing will be ignored.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>sceneAntialiasingNumPasses</code>
+ * <ul>
+ * An Integer indicating the number of passes scene antialiasing
+ * requires to render a single frame for this Canvas3D.
+ * If this value is zero, scene antialiasing is not supported.
+ * If this value is one, multisampling antialiasing is used.
+ * Otherwise, the number indicates the number of rendering passes
+ * needed.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>stencilSize</code>
+ * <ul>
+ * An Integer indicating the number of stencil bits that are available
+ * for this Canvas3D.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>texture3DAvailable</code>
+ * <ul>
+ * A Boolean indicating whether or not 3D Texture mapping
+ * is available for this Canvas3D. If this flag is false,
+ * 3D texture mapping is either not supported by the underlying
+ * rendering layer or is otherwise unavailable for this
+ * particular Canvas3D. All use of 3D texture mapping will be
+ * ignored in this case.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>textureColorTableSize</code>
+ * <ul>
+ * An Integer indicating the maximum size of the texture color
+ * table for this Canvas3D. If the size is 0, the texture
+ * color table is either not supported by the underlying rendering
+ * layer or is otherwise unavailable for this particular
+ * Canvas3D. An attempt to use a texture color table larger than
+ * textureColorTableSize will be ignored; no color lookup will be
+ * performed.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>textureLodRangeAvailable</code>
+ * <ul>
+ * A Boolean indicating whether or not setting only a subset of mipmap
+ * levels and setting a range of texture LOD are available for this
+ * Canvas3D.
+ * If it indicates false, setting a subset of mipmap levels and
+ * setting a texture LOD range are not supported by the underlying
+ * rendering layer, and an attempt to set base level, or maximum level,
+ * or minimum LOD, or maximum LOD will be ignored. In this case,
+ * images for all mipmap levels must be defined for the texture to be
+ * valid.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>textureLodOffsetAvailable</code>
+ * <ul>
+ * A Boolean indicating whether or not setting texture LOD offset is
+ * available for this Canvas3D. If it indicates false, setting
+ * texture LOD offset is not supported by the underlying rendering
+ * layer, and an attempt to set the texture LOD offset will be ignored.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>textureWidthMax</code>
+ * <ul>
+ * An Integer indicating the maximum texture width supported by
+ * this Canvas3D. If the width of a texture exceeds the maximum texture
+ * width for a Canvas3D, then the texture will be effectively disabled
+ * for that Canvas3D.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>textureHeightMax</code>
+ * <ul>
+ * An Integer indicating the maximum texture height supported by
+ * this Canvas3D. If the height of a texture exceeds the maximum texture
+ * height for a Canvas3D, then the texture will be effectively disabled
+ * for that Canvas3D.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>textureBoundaryWidthMax</code>
+ * <ul>
+ * An Integer indicating the maximum texture boundary width
+ * supported by the underlying rendering layer for this Canvas3D. If
+ * the maximum supported texture boundary width is 0, then texture
+ * boundary is not supported by the underlying rendering layer.
+ * An attempt to specify a texture boundary width > the
+ * textureBoundaryWidthMax will effectively disable the texture.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>textureEnvCombineAvailable</code>
+ * <ul>
+ * A Boolean indicating whether or not texture environment combine
+ * operation is supported for this Canvas3D. If it indicates false,
+ * then texture environment combine is not supported by the
+ * underlying rendering layer, and an attempt to specify COMBINE
+ * as the texture mode will be ignored. The texture mode in effect
+ * will be REPLACE.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>textureCombineDot3Available</code>
+ * <ul>
+ * A Boolean indicating whether or not texture combine mode
+ * COMBINE_DOT3 is
+ * supported for this Canvas3D. If it indicates false, then
+ * texture combine mode COMBINE_DOT3 is not supported by
+ * the underlying rendering layer, and an attempt to specify
+ * COMBINE_DOT3 as the texture combine mode will be ignored.
+ * The texture combine mode in effect will be COMBINE_REPLACE.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>textureCombineSubtractAvailable</code>
+ * <ul>
+ * A Boolean indicating whether or not texture combine mode
+ * COMBINE_SUBTRACT is
+ * supported for this Canvas3D. If it indicates false, then
+ * texture combine mode COMBINE_SUBTRACT is not supported by
+ * the underlying rendering layer, and an attempt to specify
+ * COMBINE_SUBTRACT as the texture combine mode will be ignored.
+ * The texture combine mode in effect will be COMBINE_REPLACE.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>textureCoordSetsMax</code>
+ * <ul>
+ * An Integer indicating the maximum number of texture coordinate sets
+ * supported by the underlying rendering layer.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>textureUnitStateMax</code>
+ * <ul>
+ * An Integer indicating the maximum number of fixed-function texture units
+ * supported by the underlying rendering layer. If the number of
+ * application-sepcified texture unit states exceeds the maximum number
+ * for a Canvas3D, and the fixed-function rendering pipeline is used, then
+ * the texture will be effectively disabled for that Canvas3D.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>textureImageUnitsMax</code>
+ * <ul>
+ * An Integer indicating the maximum number of texture image units
+ * that can be accessed by the fragment shader when programmable shaders
+ * are used.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>textureImageUnitsVertexMax</code>
+ * <ul>
+ * An Integer indicating the maximum number of texture image units
+ * that can be accessed by the vertex shader when programmable shaders
+ * are used.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>textureImageUnitsCombinedMax</code>
+ * <ul>
+ * An Integer indicating the combined maximum number of texture image units
+ * that can be accessed by the vertex shader and the fragment shader when
+ * programmable shaders are used.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>textureCubeMapAvailable</code>
+ * <ul>
+ * A Boolean indicating whether or not texture cube map is supported
+ * for this Canvas3D. If it indicates false, then texture cube map
+ * is not supported by the underlying rendering layer, and an attempt
+ * to specify NORMAL_MAP or REFLECTION_MAP as the texture generation
+ * mode will be ignored. The texture generation mode in effect will
+ * be SPHERE_MAP.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>textureDetailAvailable</code>
+ * <ul>
+ * A Boolean indicating whether or not detail texture is supported
+ * for this Canvas3D. If it indicates false, then detail texture is
+ * not supported by the underlying rendering layer, and an attempt
+ * to specify LINEAR_DETAIL, LINEAR_DETAIL_ALPHA or
+ * LINEAR_DETAIL_RGB as the texture magnification filter mode will
+ * be ignored. The texture magnification filter mode in effect will
+ * be BASE_LEVEL_LINEAR.
+ * As of Java 3D 1.5, this property is always false.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>textureSharpenAvailable</code>
+ * <ul>
+ * A Boolean indicating whether or not sharpen texture is supported
+ * for this Canvas3D. If it indicates false, then sharpen texture
+ * is not supported by the underlying rendering layer, and an attempt
+ * to specify LINEAR_SHARPEN, LINEAR_SHARPEN_ALPHA or
+ * LINEAR_SHARPEN_RGB as the texture magnification filter mode
+ * will be ignored. The texture magnification filter mode in effect
+ * will be BASE_LEVEL_LINEAR.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>textureFilter4Available</code>
+ * <ul>
+ * A Boolean indicating whether or not filter4 is supported for this
+ * Canvas3D. If it indicates flase, then filter4 is not supported
+ * by the underlying rendering layer, and an attempt to specify
+ * FILTER_4 as the texture minification filter mode or texture
+ * magnification filter mode will be ignored. The texture filter mode
+ * in effect will be BASE_LEVEL_LINEAR.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>textureAnisotropicFilterDegreeMax</code>
+ * <ul>
+ * A Float indicating the maximum degree of anisotropic filter
+ * available for this Canvas3D. If it indicates 1.0, setting
+ * anisotropic filter is not supported by the underlying rendering
+ * layer, and an attempt to set anisotropic filter degree will be ignored.
+ * </ul>
+ * </li>
+
+ * <li>
+ * <code>textureNonPowerOfTwoAvailable</code>
+ * <ul>
+ * A Boolean indicating whether or not texture dimensions that are
+ * not powers of two are supported for
+ * for this Canvas3D. If it indicates false, then textures with
+ * non power of two sizes will be ignored. Set the property
+ * j3d.textureEnforcePowerOfTwo to revert to the pre-1.5 behavior
+ * of throwing exceptions for non power of two textures.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>vertexAttrsMax</code>
+ * <ul>
+ * An Integer indicating the maximum number of vertex attributes
+ * supported by the underlying rendering layer. This is in addition to
+ * the vertex coordinate (position), color, normal, and so forth.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>compressedGeometry.majorVersionNumber</code><br>
+ * <code>compressedGeometry.minorVersionNumber</code><br>
+ * <code>compressedGeometry.minorMinorVersionNumber</code>
+ * <ul>
+ * Integers indicating the major, minor, and minor-minor
+ * version numbers, respectively, of the version of compressed
+ * geometry supported by this version of Java 3D.
+ * </ul>
+ * </li>
+ *
+ * <li>
+ * <code>native.version</code>
+ * <ul>
+ * A String indicating the version number of the native graphics
+ * library. The format of this string is defined by the native
+ * library.
+ * </ul>
+ * </li>
+ * </ul>
+ *
+ * @return the properties of this Canavs3D
+ *
+ * @since Java 3D 1.2
+ */
+ public final Map queryProperties() {
+ if (queryProps == null) {
+ boolean createDummyCtx = false;
+
+ synchronized (VirtualUniverse.mc.contextCreationLock) {
+ if (ctx == null) {
+ createDummyCtx = true;
+ }
+ }
+
+ if (createDummyCtx) {
+ GraphicsConfigTemplate3D.setQueryProps(this);
+ }
+
+ //create query Properties
+ createQueryProps();
+ }
+
+ if (fatalError) {
+ throw new IllegalStateException(J3dI18N.getString("Canvas3D29"));
+ }
+
+ return queryProps;
+ }
+
+ void createQueryContext() {
+ // create a dummy context to query for support of certain
+ // extensions, the context will destroy immediately
+ // inside the native code after setting the various
+ // fields in this object
+ createQueryContext(drawable, offScreen, 1, 1);
+ // compute the max available texture units
+ maxAvailableTextureUnits = Math.max(maxTextureUnits, maxTextureImageUnits);
+ }
+
+ /**
+ * Creates the query properties for this Canvas.
+ */
+ private void createQueryProps() {
+ // Create lists of keys and values
+ ArrayList<String> keys = new ArrayList<String>();
+ ArrayList<Object> values = new ArrayList<Object>();
+ int pass = 0;
+
+ // properties not associated with graphics context
+ keys.add("doubleBufferAvailable");
+ values.add(new Boolean(doubleBufferAvailable));
+
+ keys.add("stereoAvailable");
+ values.add(new Boolean(stereoAvailable));
+
+ keys.add("sceneAntialiasingAvailable");
+ values.add(new Boolean(sceneAntialiasingAvailable));
+
+ keys.add("sceneAntialiasingNumPasses");
+
+ if (sceneAntialiasingAvailable) {
+ pass = (sceneAntialiasingMultiSamplesAvailable ?
+ 1: Renderer.NUM_ACCUMULATION_SAMPLES);
+ }
+ values.add(new Integer(pass));
+
+ keys.add("stencilSize");
+ // Return the actual stencil size if the user owns it, otherwise
+ // return 0
+ if (userStencilAvailable) {
+ values.add(new Integer(actualStencilSize));
+ } else {
+ values.add(new Integer(0));
+ }
+
+ keys.add("compressedGeometry.majorVersionNumber");
+ values.add(new Integer(GeometryDecompressor.majorVersionNumber));
+ keys.add("compressedGeometry.minorVersionNumber");
+ values.add(new Integer(GeometryDecompressor.minorVersionNumber));
+ keys.add("compressedGeometry.minorMinorVersionNumber");
+ values.add(new Integer(GeometryDecompressor.minorMinorVersionNumber));
+
+ // Properties associated with graphics context
+ keys.add("texture3DAvailable");
+ values.add(new Boolean((textureExtendedFeatures & TEXTURE_3D) != 0));
+
+ keys.add("textureColorTableSize");
+ values.add(new Integer(textureColorTableSize));
+
+ keys.add("textureEnvCombineAvailable");
+ values.add(new Boolean(
+ (textureExtendedFeatures & TEXTURE_COMBINE) != 0));
+
+ keys.add("textureCombineDot3Available");
+ values.add(new Boolean(
+ (textureExtendedFeatures & TEXTURE_COMBINE_DOT3) != 0));
+
+ keys.add("textureCombineSubtractAvailable");
+ values.add(new Boolean(
+ (textureExtendedFeatures & TEXTURE_COMBINE_SUBTRACT) != 0));
+
+ keys.add("textureCubeMapAvailable");
+ values.add(new Boolean(
+ (textureExtendedFeatures & TEXTURE_CUBE_MAP) != 0));
+
+ keys.add("textureSharpenAvailable");
+ values.add(new Boolean(
+ (textureExtendedFeatures & TEXTURE_SHARPEN) != 0));
+
+ keys.add("textureDetailAvailable");
+ values.add(new Boolean(
+ (textureExtendedFeatures & TEXTURE_DETAIL) != 0));
+
+ keys.add("textureFilter4Available");
+ values.add(new Boolean(
+ (textureExtendedFeatures & TEXTURE_FILTER4) != 0));
+
+ keys.add("textureAnisotropicFilterDegreeMax");
+ values.add(new Float(anisotropicDegreeMax));
+
+ keys.add("textureWidthMax");
+ values.add(new Integer(textureWidthMax));
+
+ keys.add("textureHeightMax");
+ values.add(new Integer(textureHeightMax));
+
+ keys.add("texture3DWidthMax");
+ values.add(new Integer(texture3DWidthMax));
+
+ keys.add("texture3DHeightMax");
+ values.add(new Integer(texture3DHeightMax));
+
+ keys.add("texture3DDepthMax");
+ values.add(new Integer(texture3DDepthMax));
+
+ keys.add("textureBoundaryWidthMax");
+ values.add(new Integer(textureBoundaryWidthMax));
+
+ keys.add("textureLodRangeAvailable");
+ values.add(new Boolean(
+ (textureExtendedFeatures & TEXTURE_LOD_RANGE) != 0));
+
+ keys.add("textureLodOffsetAvailable");
+ values.add(new Boolean(
+ (textureExtendedFeatures & TEXTURE_LOD_OFFSET) != 0));
+
+ keys.add("textureNonPowerOfTwoAvailable");
+ values.add(new Boolean(
+ (textureExtendedFeatures & TEXTURE_NON_POWER_OF_TWO) != 0));
+
+ keys.add("textureAutoMipMapGenerationAvailable");
+ values.add(new Boolean(
+ (textureExtendedFeatures & TEXTURE_AUTO_MIPMAP_GENERATION) != 0));
+
+ keys.add("textureCoordSetsMax");
+ values.add(new Integer(maxTexCoordSets));
+
+ keys.add("textureUnitStateMax");
+ values.add(new Integer(maxTextureUnits));
+
+ keys.add("textureImageUnitsMax");
+ values.add(new Integer(maxTextureImageUnits));
+
+ keys.add("textureImageUnitsVertexMax");
+ values.add(new Integer(maxVertexTextureImageUnits));
+
+ keys.add("textureImageUnitsCombinedMax");
+ values.add(new Integer(maxCombinedTextureImageUnits));
+
+ keys.add("vertexAttrsMax");
+ values.add(new Integer(maxVertexAttrs));
+
+ keys.add("shadingLanguageGLSL");
+ values.add(new Boolean(shadingLanguageGLSL));
+
+ keys.add("native.version");
+ values.add(nativeGraphicsVersion);
+
+ keys.add("native.vendor");
+ values.add(nativeGraphicsVendor);
+
+ keys.add("native.renderer");
+ values.add(nativeGraphicsRenderer);
+
+ // Now Create read-only properties object
+ queryProps = new J3dQueryProps(keys, values);
+ }
+
+
+ /**
+ * Update the view cache associated with this canvas.
+ */
+ void updateViewCache(boolean flag, CanvasViewCache cvc,
+ BoundingBox frustumBBox, boolean doInfinite) {
+
+ assert cvc == null;
+ synchronized(cvLock) {
+ if (firstPaintCalled && (canvasViewCache != null)) {
+ assert canvasViewCacheFrustum != null;
+ // Issue 109 : choose the appropriate cvCache
+ if (frustumBBox != null) {
+ canvasViewCacheFrustum.snapshot(true);
+ canvasViewCacheFrustum.computeDerivedData(flag, null,
+ frustumBBox, doInfinite);
+ } else {
+ canvasViewCache.snapshot(false);
+ canvasViewCache.computeDerivedData(flag, null,
+ null, doInfinite);
+ }
+ }
+ }
+ }
+
+ /**
+ * Set depthBufferWriteEnableOverride flag
+ */
+ void setDepthBufferWriteEnableOverride(boolean flag) {
+ depthBufferWriteEnableOverride = flag;
+ }
+
+ /**
+ * Set depthBufferEnableOverride flag
+ */
+ void setDepthBufferEnableOverride(boolean flag) {
+ depthBufferEnableOverride = flag;
+ }
+
+ // Static initializer for Canvas3D class
+ static {
+ VirtualUniverse.loadLibraries();
+ }
+
+
+ void resetTexture(Context ctx, int texUnitIndex) {
+ // D3D also need to reset texture attributes
+ this.resetTextureNative(ctx, texUnitIndex);
+
+ if (texUnitIndex < 0) {
+ texUnitIndex = 0;
+ }
+ texUnitState[texUnitIndex].mirror = null;
+ texUnitState[texUnitIndex].texture = null;
+ }
+
+// reset all attributes so that everything e.g. display list,
+// texture will recreate again in the next frame
+void resetRendering() {
+ reset();
+
+ synchronized (dirtyMaskLock) {
+ cvDirtyMask[0] |= VIEW_INFO_DIRTY;
+ cvDirtyMask[1] |= VIEW_INFO_DIRTY;
+ }
+
+}
+
+ void reset() {
+ int i;
+ currentAppear = new AppearanceRetained();
+ currentMaterial = new MaterialRetained();
+ viewFrustum = new CachedFrustum();
+ canvasDirty = 0xffff;
+ lightBin = null;
+ environmentSet = null;
+ attributeBin = null;
+ shaderBin = null;
+ textureBin = null;
+ renderMolecule = null;
+ polygonAttributes = null;
+ lineAttributes = null;
+ pointAttributes = null;
+ material = null;
+ enableLighting = false;
+ transparency = null;
+ coloringAttributes = null;
+ shaderProgram = null;
+ texture = null;
+ texAttrs = null;
+ if (texUnitState != null) {
+ TextureUnitStateRetained tus;
+ for (i=0; i < texUnitState.length; i++) {
+ tus = texUnitState[i];
+ if (tus != null) {
+ tus.texAttrs = null;
+ tus.texGen = null;
+ }
+ }
+ }
+ texCoordGeneration = null;
+ renderingAttrs = null;
+ appearance = null;
+ appHandle = null;
+ dirtyRenderMoleculeList.clear();
+ displayListResourceFreeList.clear();
+
+ dirtyDlistPerRinfoList.clear();
+ textureIdResourceFreeList.clear();
+
+ lightChanged = true;
+ modelMatrix = null;
+ modelClip = null;
+ fog = null;
+ sceneAmbient = new Color3f();
+
+
+ for (i=0; i< frameCount.length;i++) {
+ frameCount[i] = -1;
+ }
+
+ for (i=0; i < lights.length; i++) {
+ lights[i] = null;
+ }
+
+ if (currentLights != null) {
+ for (i=0; i < currentLights.length; i++) {
+ currentLights[i] = null;
+ }
+ }
+
+ enableMask = -1;
+ stateUpdateMask = 0;
+ depthBufferWriteEnableOverride = false;
+ depthBufferEnableOverride = false;
+ depthBufferWriteEnable = true;
+ vfPlanesValid = false;
+ lightChanged = false;
+
+ for (i=0; i < curStateToUpdate.length; i++) {
+ curStateToUpdate[i] = null;
+ }
+
+ // Issue 362 - need to reset display lists and ctxTimeStamp in this
+ // method, so that display lists will be recreated when canvas is
+ // removed from a view and then added back into a view with another
+ // canvas
+ needToRebuildDisplayList = true;
+ ctxTimeStamp = VirtualUniverse.mc.getContextTimeStamp();
+ }
+
+
+void resetImmediateRendering() {
+ canvasDirty = 0xffff;
+ ra = null;
+
+ setSceneAmbient(ctx, 0.0f, 0.0f, 0.0f);
+ disableFog(ctx);
+ resetRenderingAttributes(ctx, false, false);
+
+ resetTexture(ctx, -1);
+ resetTexCoordGeneration(ctx);
+ resetTextureAttributes(ctx);
+ texUnitState[0].texAttrs = null;
+ texUnitState[0].texGen = null;
+
+ resetPolygonAttributes(ctx);
+ resetLineAttributes(ctx);
+ resetPointAttributes(ctx);
+ resetTransparency(ctx,
+ RenderMolecule.SURFACE,
+ PolygonAttributes.POLYGON_FILL,
+ false, false);
+ resetColoringAttributes(ctx,
+ 1.0f, 1.0f,
+ 1.0f, 1.0f, false);
+ updateMaterial(ctx, 1.0f, 1.0f, 1.0f, 1.0f);
+ resetRendering();
+ makeCtxCurrent();
+ synchronized (dirtyMaskLock) {
+ cvDirtyMask[0] |= VIEW_INFO_DIRTY;
+ cvDirtyMask[1] |= VIEW_INFO_DIRTY;
+ }
+ needToRebuildDisplayList = true;
+
+ ctxTimeStamp = VirtualUniverse.mc.getContextTimeStamp();
+}
+
+@Override
+public Point getLocationOnScreen() {
+ try {
+ return super.getLocationOnScreen();
+ }
+ catch (IllegalComponentStateException e) {}
+
+ return new Point();
+}
+
+ void setProjectionMatrix(Context ctx, Transform3D projTrans) {
+ this.projTrans = projTrans;
+ setProjectionMatrix(ctx, projTrans.mat);
+ }
+
+ void setModelViewMatrix(Context ctx, double[] viewMatrix, Transform3D mTrans) {
+ setModelViewMatrix(ctx, viewMatrix, mTrans.mat);
+ if (!useStereo) {
+ this.modelMatrix = mTrans;
+ } else {
+ // TODO : This seems wrong to do only for the right eye.
+ // A possible approach is to invalidate the cache at begin of
+ // each eye.
+ if (rightStereoPass) {
+ // Only set cache in right stereo pass, otherwise
+ // if the left stereo pass set the cache value,
+ // setModelViewMatrix() in right stereo pass will not
+ // perform in RenderMolecules.
+ this.modelMatrix = mTrans;
+ }
+ }
+ }
+
+ void setDepthBufferWriteEnable(boolean mode) {
+ depthBufferWriteEnable = mode;
+ setDepthBufferWriteEnable(ctx, mode);
+ }
+
+ void setNumActiveTexUnit(int n) {
+ numActiveTexUnit = n;
+ }
+
+ int getNumActiveTexUnit() {
+ return numActiveTexUnit;
+ }
+
+ void setLastActiveTexUnit(int n) {
+ lastActiveTexUnit = n;
+ }
+
+ int getLastActiveTexUnit() {
+ return lastActiveTexUnit;
+ }
+
+ // Create the texture state array
+ void createTexUnitState() {
+ texUnitState = new TextureUnitStateRetained[maxAvailableTextureUnits];
+ for (int t = 0; t < maxAvailableTextureUnits; t++) {
+ texUnitState[t] = new TextureUnitStateRetained();
+ texUnitState[t].texture = null;
+ texUnitState[t].mirror = null;
+ }
+ }
+
+ /**
+ * Enable separate specular color if it is not overriden by the
+ * property j3d.disableSeparateSpecular.
+ */
+ void enableSeparateSpecularColor() {
+ boolean enable = !VirtualUniverse.mc.disableSeparateSpecularColor;
+ updateSeparateSpecularColorEnable(ctx, enable);
+ }
+
+ // Send a createOffScreenBuffer message to Renderer (via
+ // MasterControl) and wait for it to be done
+ private void sendCreateOffScreenBuffer() {
+ // Wait for the buffer to be created unless called from
+ // a Behavior or from a Rendering thread
+ if (!(Thread.currentThread() instanceof BehaviorScheduler) &&
+ !(Thread.currentThread() instanceof Renderer)) {
+
+ offScreenBufferPending = true;
+ }
+
+ // Send message to Renderer thread to perform createOffScreenBuffer.
+ VirtualUniverse.mc.sendCreateOffScreenBuffer(this);
+
+ // Wait for off-screen buffer to be created
+ while (offScreenBufferPending) {
+ // Issue 364: create master control thread if needed
+ VirtualUniverse.mc.createMasterControlThread();
+ MasterControl.threadYield();
+ }
+ }
+
+ // Send a destroyOffScreenBuffer message to Renderer (via
+ // MasterControl) and wait for it to be done
+ private void sendDestroyCtxAndOffScreenBuffer() {
+ // Wait for the buffer to be destroyed unless called from
+ // a Behavior or from a Rendering thread
+ Thread currentThread = Thread.currentThread();
+ if (!(currentThread instanceof BehaviorScheduler) &&
+ !(currentThread instanceof Renderer)) {
+
+ offScreenBufferPending = true;
+ }
+
+ // Fix for Issue 18 and Issue 175
+ // Send message to Renderer thread to perform remove Ctx and destroyOffScreenBuffer.
+
+ VirtualUniverse.mc.sendDestroyCtxAndOffScreenBuffer(this);
+
+ // Wait for ctx and off-screen buffer to be destroyed
+ while (offScreenBufferPending) {
+ // Issue 364: create master control thread if needed
+ VirtualUniverse.mc.createMasterControlThread();
+ MasterControl.threadYield();
+ }
+ }
+
+ // Send a allocateCanvasId message to Renderer (via MasterControl) without
+ // waiting for it to be done
+ private void sendAllocateCanvasId() {
+ // Send message to Renderer thread to allocate a canvasId
+ VirtualUniverse.mc.sendAllocateCanvasId(this);
+ }
+
+ // Send a freeCanvasId message to Renderer (via MasterControl) without
+ // waiting for it to be done
+ private void sendFreeCanvasId() {
+ // Send message to Renderer thread to free the canvasId
+ VirtualUniverse.mc.sendFreeCanvasId(this);
+ }
+
+ private void removeCtx() {
+
+ if ((screen != null) &&
+ (screen.renderer != null) &&
+ (ctx != null)) {
+ VirtualUniverse.mc.postRequest(MasterControl.FREE_CONTEXT,
+ new Object[]{this,
+ Long.valueOf(0L),
+ drawable,
+ ctx});
+ // Fix for Issue 19
+ // Wait for the context to be freed unless called from
+ // a Behavior or from a Rendering thread
+ Thread currentThread = Thread.currentThread();
+ if (!(currentThread instanceof BehaviorScheduler) &&
+ !(currentThread instanceof Renderer)) {
+ while (ctxTimeStamp != 0) {
+ MasterControl.threadYield();
+ }
+ }
+ ctx = null;
+ }
+ }
+
+ /**
+ * Serialization of Canvas3D objects is not supported.
+ *
+ * @exception UnsupportedOperationException this method is not supported
+ *
+ * @since Java 3D 1.3
+ */
+ private void writeObject(java.io.ObjectOutputStream out)
+ throws java.io.IOException {
+
+ throw new UnsupportedOperationException(J3dI18N.getString("Canvas3D20"));
+ }
+
+ /**
+ * Serialization of Canvas3D objects is not supported.
+ *
+ * @exception UnsupportedOperationException this method is not supported
+ *
+ * @since Java 3D 1.3
+ */
+ private void readObject(java.io.ObjectInputStream in)
+ throws java.io.IOException, ClassNotFoundException {
+
+ throw new UnsupportedOperationException(J3dI18N.getString("Canvas3D20"));
+ }
+
+
+ // mark that the current bin specified by the bit is already updated
+ void setStateIsUpdated(int bit) {
+ stateUpdateMask &= ~(1 << bit);
+ }
+
+ // mark that the bin specified by the bit needs to be updated
+ void setStateToUpdate(int bit, Object bin) {
+ stateUpdateMask |= 1 << bit;
+ curStateToUpdate[bit] = bin;
+ }
+
+ // update LightBin, EnvironmentSet, AttributeBin & ShaderBin if neccessary
+ // according to the stateUpdateMask
+
+ static int ENV_STATE_MASK = (1 << LIGHTBIN_BIT) |
+ (1 << ENVIRONMENTSET_BIT) |
+ (1 << ATTRIBUTEBIN_BIT) |
+ (1 << SHADERBIN_BIT);
+
+ void updateEnvState() {
+
+ if ((stateUpdateMask & ENV_STATE_MASK) == 0)
+ return;
+
+ if ((stateUpdateMask & (1 << LIGHTBIN_BIT)) != 0) {
+ ((LightBin)curStateToUpdate[LIGHTBIN_BIT]).updateAttributes(this);
+ }
+
+ if ((stateUpdateMask & (1 << ENVIRONMENTSET_BIT)) != 0) {
+ ((EnvironmentSet)
+ curStateToUpdate[ENVIRONMENTSET_BIT]).updateAttributes(this);
+ }
+
+ if ((stateUpdateMask & (1 << ATTRIBUTEBIN_BIT)) != 0) {
+ ((AttributeBin)
+ curStateToUpdate[ATTRIBUTEBIN_BIT]).updateAttributes(this);
+ }
+
+ if ((stateUpdateMask & (1 << SHADERBIN_BIT)) != 0) {
+ ((ShaderBin)
+ curStateToUpdate[SHADERBIN_BIT]).updateAttributes(this);
+ }
+
+
+ // reset the state update mask for those environment state bits
+ stateUpdateMask &= ~ENV_STATE_MASK;
+ }
+
+ /**
+ * update state if neccessary according to the stateUpdatedMask
+ */
+ void updateState( int dirtyBits) {
+
+
+ if (stateUpdateMask == 0)
+ return;
+
+ updateEnvState();
+
+ if ((stateUpdateMask & (1 << TEXTUREBIN_BIT)) != 0) {
+ ((TextureBin)
+ curStateToUpdate[TEXTUREBIN_BIT]).updateAttributes(this);
+ }
+
+ if ((stateUpdateMask & (1 << RENDERMOLECULE_BIT)) != 0) {
+ ((RenderMolecule)
+ curStateToUpdate[RENDERMOLECULE_BIT]).updateAttributes(this,
+ dirtyBits);
+
+ }
+
+ if ((stateUpdateMask & (1 << TRANSPARENCY_BIT)) != 0) {
+ ((RenderMolecule)curStateToUpdate[RENDERMOLECULE_BIT]).updateTransparencyAttributes(this);
+ stateUpdateMask &= ~(1 << TRANSPARENCY_BIT);
+ }
+
+ // reset state update mask
+ stateUpdateMask = 0;
+ }
+
+
+ // This method updates this Texture2D for raster.
+ // Note : No multi-texture is not used.
+ void updateTextureForRaster(Texture2DRetained texture) {
+
+ // Setup texture and texture attributes for texture unit 0.
+ Pipeline.getPipeline().updateTextureUnitState(ctx, 0, true);
+ setLastActiveTexUnit(0);
+ setNumActiveTexUnit(1);
+
+ texture.updateNative(this);
+ resetTexCoordGeneration(ctx);
+ resetTextureAttributes(ctx);
+
+ for(int i=1; i < maxTextureUnits; i++) {
+ resetTexture(ctx, i);
+ }
+
+ // set the active texture unit back to 0
+ activeTextureUnit(ctx, 0);
+
+ // Force the next textureBin to reload.
+ canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY | Canvas3D.TEXTUREATTRIBUTES_DIRTY;
+ }
+
+ void restoreTextureBin() {
+
+ // Need to check TextureBin's shaderBin for null
+ // TextureBin can get clear() if there isn't any RM under it.
+ if((textureBin != null) && (textureBin.shaderBin != null)) {
+ textureBin.updateAttributes(this);
+ }
+ }
+
+ void textureFill(RasterRetained raster, Point2d winCoord,
+ float mapZ, float alpha) {
+
+ int winWidth = canvasViewCache.getCanvasWidth();
+ int winHeight = canvasViewCache.getCanvasHeight();
+
+ int rasterImageWidth = raster.image.width;
+ int rasterImageHeight = raster.image.height;
+
+ float texMinU = 0, texMinV = 0, texMaxU = 0, texMaxV = 0;
+ float mapMinX = 0, mapMinY = 0, mapMaxX = 0, mapMaxY = 0;
+
+ Point rasterSrcOffset = new Point();
+ raster.getSrcOffset(rasterSrcOffset);
+
+ Dimension rasterSize = new Dimension();
+ raster.getSize(rasterSize);
+
+// System.err.println("rasterImageWidth " + rasterImageWidth + " rasterImageHeight " + rasterImageHeight);
+// System.err.println("rasterSrcOffset " + rasterSrcOffset + " rasterSize " + rasterSize);
+
+ int rasterMinX = rasterSrcOffset.x;
+ int rasterMaxX = rasterSrcOffset.x + rasterSize.width;
+ int rasterMinY = rasterSrcOffset.y;
+ int rasterMaxY = rasterSrcOffset.y + rasterSize.height;
+
+ if ((rasterMinX >= rasterImageWidth) || (rasterMinY >= rasterImageHeight) ||
+ (rasterMaxX <= 0) || (rasterMaxY <= 0)) {
+ return;
+ }
+
+ if (rasterMinX < 0) {
+ rasterMinX = 0;
+ }
+ if (rasterMinY < 0) {
+ rasterMinY = 0;
+ }
+
+ if (rasterMaxX > rasterImageWidth) {
+ rasterMaxX = rasterImageWidth;
+ }
+
+ if (rasterMaxY > rasterImageHeight) {
+ rasterMaxY = rasterImageHeight;
+ }
+
+ texMinU = (float) rasterMinX / (float) rasterImageWidth;
+ texMaxU = (float) rasterMaxX / (float) rasterImageWidth;
+ mapMinX = (float) winCoord.x / (float) winWidth;
+ mapMaxX = (float) (winCoord.x + (rasterMaxX - rasterMinX)) / (float) winWidth;
+
+ if (raster.image.isYUp()) {
+ texMinV = (float) rasterMinY / (float) rasterImageHeight;
+ texMaxV = (float) rasterMaxY / (float) rasterImageHeight;
+ } else {
+ // System.err.println("In yUp is false case");
+ texMinV = 1.0f - (float) rasterMaxY / (float) rasterImageHeight;
+ texMaxV = 1.0f - (float) rasterMinY / (float) rasterImageHeight;
+ }
+
+ mapMinY = 1.0f - ((float) (winCoord.y + (rasterMaxY - rasterMinY)) / (float) winHeight);
+ mapMaxY = 1.0f - ((float) winCoord.y / (float) winHeight);
+
+ textureFillRaster(ctx, texMinU, texMaxU, texMinV, texMaxV,
+ mapMinX, mapMaxX, mapMinY, mapMaxY, mapZ, alpha, raster.image.useBilinearFilter());
+
+ }
+
+ void textureFill(BackgroundRetained bg, int winWidth, int winHeight) {
+
+ final int maxX = bg.image.width;
+ final int maxY = bg.image.height;
+
+// System.err.println("maxX " + maxX + " maxY " + maxY);
+
+ float xzoom = (float)winWidth / maxX;
+ float yzoom = (float)winHeight / maxY;
+ float zoom = 0;
+ float texMinU = 0, texMinV = 0, texMaxU = 0, texMaxV = 0, adjustV = 0;
+ float mapMinX = 0, mapMinY = 0, mapMaxX = 0, mapMaxY = 0;
+ float halfWidth = 0, halfHeight = 0;
+
+ switch (bg.imageScaleMode) {
+ case Background.SCALE_NONE:
+ texMinU = 0.0f;
+ texMinV = 0.0f;
+ texMaxU = 1.0f;
+ texMaxV = 1.0f;
+ halfWidth = (float)winWidth/2.0f;
+ halfHeight = (float)winHeight/2.0f;
+ mapMinX = (float) ((0 - halfWidth)/halfWidth);
+ mapMinY = (float) ((0 - halfHeight)/halfHeight);
+ mapMaxX = (float) ((maxX - halfWidth)/halfWidth);
+ mapMaxY = (float) ((maxY - halfHeight)/halfHeight);
+ adjustV = ((float)winHeight - (float)maxY)/halfHeight;
+ mapMinY += adjustV;
+ mapMaxY += adjustV;
+ break;
+ case Background.SCALE_FIT_MIN:
+ zoom = Math.min(xzoom, yzoom);
+ texMinU = 0.0f;
+ texMinV = 0.0f;
+ texMaxU = 1.0f;
+ texMaxV = 1.0f;
+ mapMinX = -1.0f;
+ mapMaxY = 1.0f;
+ if (xzoom < yzoom) {
+ mapMaxX = 1.0f;
+ mapMinY = -1.0f + 2.0f * ( 1.0f - zoom * (float)maxY/(float) winHeight );
+ } else {
+ mapMaxX = -1.0f + zoom * (float)maxX/winWidth * 2;
+ mapMinY = -1.0f;
+ }
+ break;
+ case Background.SCALE_FIT_MAX:
+ zoom = Math.max(xzoom, yzoom);
+ mapMinX = -1.0f;
+ mapMinY = -1.0f;
+ mapMaxX = 1.0f;
+ mapMaxY = 1.0f;
+ if (xzoom < yzoom) {
+ texMinU = 0.0f;
+ texMinV = 0.0f;
+ texMaxU = (float)winWidth/maxX/zoom;
+ texMaxV = 1.0f;
+ } else {
+ texMinU = 0.0f;
+ texMinV = 1.0f - (float)winHeight/maxY/zoom;
+ texMaxU = 1.0f;
+ texMaxV = 1.0f;
+ }
+ break;
+ case Background.SCALE_FIT_ALL:
+ texMinU = 0.0f;
+ texMinV = 0.0f;
+ texMaxU = 1.0f;
+ texMaxV = 1.0f;
+ mapMinX = -1.0f;
+ mapMinY = -1.0f;
+ mapMaxX = 1.0f;
+ mapMaxY = 1.0f;
+ break;
+ case Background.SCALE_REPEAT:
+
+ texMinU = 0.0f;
+ texMinV = - yzoom;
+ texMaxU = xzoom;
+ texMaxV = 0.0f;
+ mapMinX = -1.0f;
+ mapMinY = -1.0f;
+ mapMaxX = 1.0f;
+ mapMaxY = 1.0f;
+ break;
+ case Background.SCALE_NONE_CENTER:
+ // TODO : Why is there a zoom ?
+ if(xzoom >= 1.0f){
+ texMinU = 0.0f;
+ texMaxU = 1.0f;
+ mapMinX = -(float)maxX/winWidth;
+ mapMaxX = (float)maxX/winWidth;
+ } else {
+ texMinU = 0.5f - (float)winWidth/maxX/2;
+ texMaxU = 0.5f + (float)winWidth/maxX/2;
+ mapMinX = -1.0f;
+ mapMaxX = 1.0f;
+ }
+ if (yzoom >= 1.0f) {
+ texMinV = 0.0f;
+ texMaxV = 1.0f;
+ mapMinY = -(float)maxY/winHeight;
+ mapMaxY = (float)maxY/winHeight;
+ } else {
+ texMinV = 0.5f - (float)winHeight/maxY/2;
+ texMaxV = 0.5f + (float)winHeight/maxY/2;
+ mapMinY = -1.0f;
+ mapMaxY = 1.0f;
+ }
+ break;
+ }
+
+// System.err.println("Java 3D : mapMinX " + mapMinX + " mapMinY " + mapMinY +
+// " mapMaxX " + mapMaxX + " mapMaxY " + mapMaxY);
+ textureFillBackground(ctx, texMinU, texMaxU, texMinV, texMaxV,
+ mapMinX, mapMaxX, mapMinY, mapMaxY, bg.image.useBilinearFilter());
+
+ }
+
+
+ void clear(BackgroundRetained bg, int winWidth, int winHeight) {
+
+ // Issue 239 - clear stencil if requested and available
+ // Note that this is a partial solution, since we eventually want an API
+ // to control this.
+ boolean clearStencil = VirtualUniverse.mc.stencilClear &&
+ userStencilAvailable;
+
+ clear(ctx, bg.color.x, bg.color.y, bg.color.z, clearStencil);
+
+ // TODO : This is a bug on not mirror bg. Will fix this as a bug after 1.5 beta.
+ // For now, as a workaround, we will check bg.image and bg.image.imageData not null.
+ if((bg.image != null) && (bg.image.imageData != null)) {
+ // setup Texture pipe.
+ updateTextureForRaster(bg.texture);
+
+ textureFill(bg, winWidth, winHeight);
+
+ // Restore texture pipe.
+ restoreTextureBin();
+ }
+ }
+
+ /**
+ * obj is either TextureRetained or DetailTextureImage
+ * if obj is DetailTextureImage then we just clear
+ * the resourceCreationMask of all the formats
+ * no matter it is create or not since we don't
+ * remember the format information for simplicity.
+ * We don't need to check duplicate value of id in the
+ * table since this procedure is invoke only when id
+ * of texture is -1 one time only.
+ * This is always call from Renderer thread.
+ */
+void addTextureResource(int id, TextureRetained obj) {
+ if (id <= 0) {
+ return;
+ }
+
+ if (useSharedCtx) {
+ screen.renderer.addTextureResource(id, obj);
+ } else {
+ // This will replace the previous key if exists
+ if (textureIDResourceTable.size() <= id) {
+ for (int i=textureIDResourceTable.size();
+ i < id; i++) {
+ textureIDResourceTable.add(null);
+ }
+ textureIDResourceTable.add(obj);
+ } else {
+ textureIDResourceTable.set(id, obj);
+ }
+
+ }
+ }
+
+ // handle free resource in the FreeList
+ void freeResourcesInFreeList(Context ctx) {
+ Iterator<Integer> it;
+ int val;
+
+ // free resource for those canvases that
+ // don't use shared ctx
+ if (displayListResourceFreeList.size() > 0) {
+ for (it = displayListResourceFreeList.iterator(); it.hasNext();) {
+ val = it.next().intValue();
+ if (val <= 0) {
+ continue;
+ }
+ Canvas3D.freeDisplayList(ctx, val);
+ }
+ displayListResourceFreeList.clear();
+ }
+
+ if (textureIdResourceFreeList.size() > 0) {
+ for (it = textureIdResourceFreeList.iterator(); it.hasNext();) {
+ val = it.next().intValue();
+ if (val <= 0) {
+ continue;
+ }
+ if (val >= textureIDResourceTable.size()) {
+ System.err.println("Error in freeResourcesInFreeList : ResourceIDTableSize = " +
+ textureIDResourceTable.size() +
+ " val = " + val);
+ } else {
+ TextureRetained tex = textureIDResourceTable.get(val);
+ if (tex != null) {
+ synchronized (tex.resourceLock) {
+ tex.resourceCreationMask &= ~canvasBit;
+ if (tex.resourceCreationMask == 0) {
+ tex.freeTextureId(val);
+ }
+ }
+ }
+
+ textureIDResourceTable.set(val, null);
+ }
+ Canvas3D.freeTexture(ctx, val);
+ }
+ textureIdResourceFreeList.clear();
+ }
+ }
+
+ void freeContextResources(Renderer rdr, boolean freeBackground,
+ Context ctx) {
+ TextureRetained tex;
+
+ // Just return if we don't have a valid renderer or context
+ if (rdr == null || ctx == null) {
+ return;
+ }
+
+ if (freeBackground) {
+ // Dispose of Graphics2D Texture
+ if (graphics2D != null) {
+ graphics2D.dispose();
+ }
+ }
+
+ for (int id = textureIDResourceTable.size()-1; id >= 0; id--) {
+ tex = textureIDResourceTable.get(id);
+ if (tex == null) {
+ continue;
+ }
+
+ // Issue 403 : this assertion doesn't hold in some cases
+ // TODO KCR : determine why this is the case
+// assert id == ((TextureRetained)obj).objectId;
+
+ Canvas3D.freeTexture(ctx, id);
+ synchronized (tex.resourceLock) {
+ tex.resourceCreationMask &= ~canvasBit;
+ if (tex.resourceCreationMask == 0) {
+
+ tex.freeTextureId(id);
+ }
+ }
+ }
+ textureIDResourceTable.clear();
+
+ freeAllDisplayListResources(ctx);
+ }
+
+ void freeAllDisplayListResources(Context ctx) {
+ if ((view != null) && (view.renderBin != null)) {
+ view.renderBin.freeAllDisplayListResources(this, ctx);
+ if (useSharedCtx) {
+ // We need to rebuild all other Canvas3D resource
+ // shared by this Canvas3D. Since we didn't
+ // remember resource in Renderer but RenderBin only.
+ if ((screen != null) && (screen.renderer != null)) {
+ screen.renderer.needToRebuildDisplayList = true;
+ }
+ }
+ }
+
+ }
+
+
+ // *****************************************************************
+ // Wrappers for native methods go below here
+ // *****************************************************************
+
+ // This is the native method for creating the underlying graphics context.
+ private Context createNewContext(Drawable drawable,
+ Context shareCtx, boolean isSharedCtx,
+ boolean offScreen) {
+ return Pipeline.getPipeline().createNewContext(this, drawable,
+ shareCtx, isSharedCtx,
+ offScreen);
+ }
+
+ private void createQueryContext(Drawable drawable,
+ boolean offScreen, int width, int height) {
+ Pipeline.getPipeline().createQueryContext(this, drawable,
+ offScreen, width, height);
+ }
+
+ // This is the native for creating offscreen buffer
+ Drawable createOffScreenBuffer(Context ctx, int width, int height) {
+ return Pipeline.getPipeline().createOffScreenBuffer(this,
+ ctx, width, height);
+ }
+
+ void destroyOffScreenBuffer(Context ctx, Drawable drawable) {
+ assert drawable != null;
+ Pipeline.getPipeline().destroyOffScreenBuffer(this, ctx, drawable);
+ }
+
+ // This is the native for reading the image from the offscreen buffer
+ private void readOffScreenBuffer(Context ctx, int format, int type, Object data, int width, int height) {
+ Pipeline.getPipeline().readOffScreenBuffer(this, ctx, format, type, data, width, height);
+ }
+
+// The native method for swapBuffers
+void swapBuffers(Context ctx, Drawable drawable) {
+ Pipeline.getPipeline().swapBuffers(this, ctx, drawable);
+}
+
+ // -----------------------------------------------------------------------------
+
+ // native method for setting Material when no material is present
+ void updateMaterial(Context ctx, float r, float g, float b, float a) {
+ Pipeline.getPipeline().updateMaterialColor(ctx, r, g, b, a);
+ }
+
+ static void destroyContext(Drawable drawable, Context ctx) {
+ Pipeline.getPipeline().destroyContext(drawable, ctx);
+ }
+
+ // This is the native method for doing accumulation.
+ void accum(Context ctx, float value) {
+ Pipeline.getPipeline().accum(ctx, value);
+ }
+
+ // This is the native method for doing accumulation return.
+ void accumReturn(Context ctx) {
+ Pipeline.getPipeline().accumReturn(ctx);
+ }
+
+ // This is the native method for clearing the accumulation buffer.
+ void clearAccum(Context ctx) {
+ Pipeline.getPipeline().clearAccum(ctx);
+ }
+
+ // This is the native method for getting the number of lights the underlying
+ // native library can support.
+ int getNumCtxLights(Context ctx) {
+ return Pipeline.getPipeline().getNumCtxLights(ctx);
+ }
+
+ // Native method for decal 1st child setup
+ boolean decal1stChildSetup(Context ctx) {
+ return Pipeline.getPipeline().decal1stChildSetup(ctx);
+ }
+
+ // Native method for decal nth child setup
+ void decalNthChildSetup(Context ctx) {
+ Pipeline.getPipeline().decalNthChildSetup(ctx);
+ }
+
+ // Native method for decal reset
+ void decalReset(Context ctx, boolean depthBufferEnable) {
+ Pipeline.getPipeline().decalReset(ctx, depthBufferEnable);
+ }
+
+ // Native method for decal reset
+ void ctxUpdateEyeLightingEnable(Context ctx, boolean localEyeLightingEnable) {
+ Pipeline.getPipeline().ctxUpdateEyeLightingEnable(ctx, localEyeLightingEnable);
+ }
+
+ // The following three methods are used in multi-pass case
+
+ // native method for setting blend color
+ void setBlendColor(Context ctx, float red, float green,
+ float blue, float alpha) {
+ Pipeline.getPipeline().setBlendColor(ctx, red, green,
+ blue, alpha);
+ }
+
+ // native method for setting blend func
+ void setBlendFunc(Context ctx, int src, int dst) {
+ Pipeline.getPipeline().setBlendFunc(ctx, src, dst);
+ }
+
+ // native method for setting fog enable flag
+ void setFogEnableFlag(Context ctx, boolean enableFlag) {
+ Pipeline.getPipeline().setFogEnableFlag(ctx, enableFlag);
+ }
+
+boolean isAntialiasingSet() {
+ return antialiasingSet;
+}
+
+ // Setup the full scene antialising in D3D and ogl when GL_ARB_multisamle supported
+ void setFullSceneAntialiasing(Context ctx, boolean enable) {
+ Pipeline.getPipeline().setFullSceneAntialiasing(ctx, enable);
+ antialiasingSet = enable;
+ }
+
+ // Native method to update separate specular color control
+ void updateSeparateSpecularColorEnable(Context ctx, boolean control) {
+ Pipeline.getPipeline().updateSeparateSpecularColorEnable(ctx, control);
+ }
+
+ // True under Solaris,
+ // False under windows when display mode <= 8 bit
+ private boolean validGraphicsMode() {
+ return Pipeline.getPipeline().validGraphicsMode();
+ }
+
+ // native method for setting light enables
+ void setLightEnables(Context ctx, long enableMask, int maxLights) {
+ Pipeline.getPipeline().setLightEnables(ctx, enableMask, maxLights);
+ }
+
+ // native method for setting scene ambient
+ void setSceneAmbient(Context ctx, float red, float green, float blue) {
+ Pipeline.getPipeline().setSceneAmbient(ctx, red, green, blue);
+ }
+
+ // native method for disabling fog
+ void disableFog(Context ctx) {
+ Pipeline.getPipeline().disableFog(ctx);
+ }
+
+ // native method for disabling modelClip
+ void disableModelClip(Context ctx) {
+ Pipeline.getPipeline().disableModelClip(ctx);
+ }
+
+ // native method for setting default RenderingAttributes
+ void resetRenderingAttributes(Context ctx,
+ boolean depthBufferWriteEnableOverride,
+ boolean depthBufferEnableOverride) {
+ Pipeline.getPipeline().resetRenderingAttributes(ctx,
+ depthBufferWriteEnableOverride,
+ depthBufferEnableOverride);
+ }
+
+ // native method for setting default texture
+ void resetTextureNative(Context ctx, int texUnitIndex) {
+ Pipeline.getPipeline().resetTextureNative(ctx, texUnitIndex);
+ }
+
+ // native method for activating a particular texture unit
+ void activeTextureUnit(Context ctx, int texUnitIndex) {
+ Pipeline.getPipeline().activeTextureUnit(ctx, texUnitIndex);
+ }
+
+ // native method for setting default TexCoordGeneration
+ void resetTexCoordGeneration(Context ctx) {
+ Pipeline.getPipeline().resetTexCoordGeneration(ctx);
+ }
+
+ // native method for setting default TextureAttributes
+ void resetTextureAttributes(Context ctx) {
+ Pipeline.getPipeline().resetTextureAttributes(ctx);
+ }
+
+ // native method for setting default PolygonAttributes
+ void resetPolygonAttributes(Context ctx) {
+ Pipeline.getPipeline().resetPolygonAttributes(ctx);
+ }
+
+ // native method for setting default LineAttributes
+ void resetLineAttributes(Context ctx) {
+ Pipeline.getPipeline().resetLineAttributes(ctx);
+ }
+
+ // native method for setting default PointAttributes
+ void resetPointAttributes(Context ctx) {
+ Pipeline.getPipeline().resetPointAttributes(ctx);
+ }
+
+ // native method for setting default TransparencyAttributes
+ void resetTransparency(Context ctx, int geometryType,
+ int polygonMode, boolean lineAA,
+ boolean pointAA) {
+ Pipeline.getPipeline().resetTransparency(ctx, geometryType,
+ polygonMode, lineAA,
+ pointAA);
+ }
+
+ // native method for setting default ColoringAttributes
+ void resetColoringAttributes(Context ctx,
+ float r, float g,
+ float b, float a,
+ boolean enableLight) {
+ Pipeline.getPipeline().resetColoringAttributes(ctx,
+ r, g,
+ b, a,
+ enableLight);
+ }
+
+ /**
+ * This native method makes sure that the rendering for this canvas
+ * gets done now.
+ */
+ void syncRender(Context ctx, boolean wait) {
+ Pipeline.getPipeline().syncRender(ctx, wait);
+ }
+
+ // The native method that sets this ctx to be the current one
+ static boolean useCtx(Context ctx, Drawable drawable) {
+ return Pipeline.getPipeline().useCtx(ctx, drawable);
+ }
+
+ // Give the Pipeline a chance to release the context. The return
+ // value indicates whether the context was released.
+ private boolean releaseCtx(Context ctx) {
+ return Pipeline.getPipeline().releaseCtx(ctx);
+ }
+
+ void clear(Context ctx, float r, float g, float b, boolean clearStencil) {
+ Pipeline.getPipeline().clear(ctx, r, g, b, clearStencil);
+ }
+
+ void textureFillBackground(Context ctx, float texMinU, float texMaxU, float texMinV, float texMaxV,
+ float mapMinX, float mapMaxX, float mapMinY, float mapMaxY, boolean useBiliearFilter) {
+ Pipeline.getPipeline().textureFillBackground(ctx, texMinU, texMaxU, texMinV, texMaxV,
+ mapMinX, mapMaxX, mapMinY, mapMaxY, useBiliearFilter);
+ }
+
+ void textureFillRaster(Context ctx, float texMinU, float texMaxU, float texMinV, float texMaxV,
+ float mapMinX, float mapMaxX, float mapMinY, float mapMaxY, float mapZ, float alpha, boolean useBiliearFilter) {
+ Pipeline.getPipeline().textureFillRaster(ctx, texMinU, texMaxU, texMinV, texMaxV,
+ mapMinX, mapMaxX, mapMinY, mapMaxY, mapZ, alpha, useBiliearFilter);
+ }
+
+ void executeRasterDepth(Context ctx, float posX, float posY, float posZ,
+ int srcOffsetX, int srcOffsetY, int rasterWidth, int rasterHeight,
+ int depthWidth, int depthHeight, int depthType, Object depthData) {
+ Pipeline.getPipeline().executeRasterDepth(ctx, posX, posY, posZ,
+ srcOffsetX, srcOffsetY, rasterWidth, rasterHeight, depthWidth, depthHeight, depthType, depthData);
+ }
+
+ // The native method for setting the ModelView matrix.
+ void setModelViewMatrix(Context ctx, double[] viewMatrix, double[] modelMatrix) {
+ Pipeline.getPipeline().setModelViewMatrix(ctx, viewMatrix, modelMatrix);
+ }
+
+ // The native method for setting the Projection matrix.
+ void setProjectionMatrix(Context ctx, double[] projMatrix) {
+ Pipeline.getPipeline().setProjectionMatrix(ctx, projMatrix);
+ }
+
+ // The native method for setting the Viewport.
+ void setViewport(Context ctx, int x, int y, int width, int height) {
+ Pipeline.getPipeline().resizeOffscreenLayer(this, width, height);
+ Pipeline.getPipeline().setViewport(ctx, x, y, width, height);
+ }
+
+ // used for display Lists
+ void newDisplayList(Context ctx, int displayListId) {
+ Pipeline.getPipeline().newDisplayList(ctx, displayListId);
+ }
+ void endDisplayList(Context ctx) {
+ Pipeline.getPipeline().endDisplayList(ctx);
+ }
+ void callDisplayList(Context ctx, int id, boolean isNonUniformScale) {
+ Pipeline.getPipeline().callDisplayList(ctx, id, isNonUniformScale);
+ }
+
+ static void freeDisplayList(Context ctx, int id) {
+ Pipeline.getPipeline().freeDisplayList(ctx, id);
+ }
+ static void freeTexture(Context ctx, int id) {
+ Pipeline.getPipeline().freeTexture(ctx, id);
+ }
+
+ static int generateTexID(Context ctx) {
+ return Pipeline.getPipeline().generateTexID(ctx);
+ }
+
+ void texturemapping(Context ctx,
+ int px, int py,
+ int xmin, int ymin, int xmax, int ymax,
+ int texWidth, int texHeight,
+ int rasWidth,
+ int format, int objectId,
+ byte[] image,
+ int winWidth, int winHeight) {
+ Pipeline.getPipeline().texturemapping(ctx,
+ px, py,
+ xmin, ymin, xmax, ymax,
+ texWidth, texHeight,
+ rasWidth,
+ format, objectId,
+ image,
+ winWidth, winHeight);
+ }
+
+ boolean initTexturemapping(Context ctx, int texWidth,
+ int texHeight, int objectId) {
+ return Pipeline.getPipeline().initTexturemapping(ctx, texWidth,
+ texHeight, objectId);
+ }
+
+
+ // Set internal render mode to one of FIELD_ALL, FIELD_LEFT or
+ // FIELD_RIGHT. Note that it is up to the caller to ensure that
+ // stereo is available before setting the mode to FIELD_LEFT or
+ // FIELD_RIGHT. The boolean isTRUE for double buffered mode, FALSE
+ // foe single buffering.
+ void setRenderMode(Context ctx, int mode, boolean doubleBuffer) {
+ Pipeline.getPipeline().setRenderMode(ctx, mode, doubleBuffer);
+ }
+
+ // Set glDepthMask.
+ void setDepthBufferWriteEnable(Context ctx, boolean mode) {
+ Pipeline.getPipeline().setDepthBufferWriteEnable(ctx, mode);
+ }
+
+ // Methods to get actual capabilities from Canvas3D
+
+ boolean hasDoubleBuffer() {
+ return Pipeline.getPipeline().hasDoubleBuffer(this);
+ }
+
+ boolean hasStereo() {
+ return Pipeline.getPipeline().hasStereo(this);
+ }
+
+ int getStencilSize() {
+ return Pipeline.getPipeline().getStencilSize(this);
+ }
+
+ boolean hasSceneAntialiasingMultisample() {
+ return Pipeline.getPipeline().hasSceneAntialiasingMultisample(this);
+ }
+
+ boolean hasSceneAntialiasingAccum() {
+ return Pipeline.getPipeline().hasSceneAntialiasingAccum(this);
+ }
+
+}