diff options
author | Harvey Harrison <[email protected]> | 2015-04-19 21:02:06 -0700 |
---|---|---|
committer | Harvey Harrison <[email protected]> | 2015-04-19 21:02:06 -0700 |
commit | 7a2e20caac9db6f789a7b3fab344b9758af45335 (patch) | |
tree | b5236ff2570178de356eab569225108948eb4d30 /src/javax/media/j3d/Canvas3D.java | |
parent | f76ce302c4bb2a9f03bbee571ec5d05c29633023 (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.java | 4951 |
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); + } + +} |