aboutsummaryrefslogtreecommitdiffstats
path: root/src/javax/media/j3d/GraphicsContext3D.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/javax/media/j3d/GraphicsContext3D.java')
-rw-r--r--src/javax/media/j3d/GraphicsContext3D.java3068
1 files changed, 3068 insertions, 0 deletions
diff --git a/src/javax/media/j3d/GraphicsContext3D.java b/src/javax/media/j3d/GraphicsContext3D.java
new file mode 100644
index 0000000..75b2d1d
--- /dev/null
+++ b/src/javax/media/j3d/GraphicsContext3D.java
@@ -0,0 +1,3068 @@
+/*
+ * 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.Dimension;
+import java.awt.Point;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import javax.vecmath.Color3f;
+import javax.vecmath.Vector3d;
+
+/**
+ * A GraphicsContext3D object is used for immediate mode rendering into
+ * a 3D canvas. It is created by, and associated with, a specific
+ * Canvas3D object. A GraphicsContext3D defines methods to set 3D graphics
+ * state and draw 3D geometric primitives. There are no public
+ * constructors of GraphicsContext3D. An application obtains a 3D graphics
+ * context object from the Canvas3D object that the application wishes
+ * to render into by using the getGraphicsContext3D method. A new graphics
+ * context is created if one does not already exist. A new GraphicsContext3D
+ * initializes its state variables to the following defaults:
+ * <UL>
+ * <LI> Background object: null </LI>
+ * <LI> Fog object: null </LI>
+ * <LI> ModelClip object: null </LI>
+ * <LI> Appearance object: null </LI>
+ * <LI> List of Light objects: empty </LI>
+ * <LI> high-res coordinate: (0, 0, 0) </LI>
+ * <LI> modelTransform: identity </LI>
+ * <LI> AuralAttributes object: null </LI>
+ * <LI> List of Sound objects: empty </LI>
+ * <LI> buffer override: false </LI>
+ * <LI> front buffer rendering: false </LI>
+ * <LI> stereo mode: <code>STEREO_BOTH</code> </LI>
+ * </UL>
+ *
+ * <p>
+ * Note that the drawing methods in this class are not necessarily
+ * executed immediately. They may be buffered up for future
+ * execution. Applications must call the
+ * <code><a href="#flush(boolean)">flush</a>(boolean)</code>
+ * method to ensure that the rendering actually happens. The flush
+ * method is implicitly called in the following cases:
+ *
+ * <ul>
+ * <li>The <code>readRaster</code> method calls
+ * <code>flush(true)</code></li>
+ * <li>The <code>Canvas3D.swap</code> method calls
+ * <code>flush(true)</code></li>
+ * <li>The Java 3D renderer calls <code>flush(true)</code> prior to
+ * swapping the buffer for a double buffered on-screen Canvas3D</li>
+ * <li>The Java 3D renderer calls <code>flush(true)</code> prior to
+ * copying into the off-screen buffer of an off-screen Canvas3D</li>
+ * <li>The Java 3D renderer calls <code>flush(false)</code> after
+ * calling the preRender, renderField, postRender, and postSwap
+ * Canvas3D callback methods.</li>
+ * </ul>
+ *
+ * <p>
+ * A single-buffered, pure-immediate mode application must explicitly
+ * call flush to ensure that the graphics will be rendered to the
+ * Canvas3D.
+ *
+ * @see Canvas3D#getGraphicsContext3D
+ */
+public class GraphicsContext3D extends Object {
+ /**
+ * Specifies that rendering is done to the left eye.
+ * @see #setStereoMode
+ * @since Java 3D 1.2
+ */
+ public static final int STEREO_LEFT = 0;
+
+ /**
+ * Specifies that rendering is done to the right eye.
+ * @see #setStereoMode
+ * @since Java 3D 1.2
+ */
+ public static final int STEREO_RIGHT = 1;
+
+ /**
+ * Specifies that rendering is done to both eyes. This is the
+ * default.
+ * @see #setStereoMode
+ * @since Java 3D 1.2
+ */
+ public static final int STEREO_BOTH = 2;
+
+
+ /**
+ * Canvas3D in which this GraphicsContext3D will render.
+ */
+ Canvas3D canvas3d = null;
+
+//
+// Graphics state
+//
+// current user specified graphics state
+ private Background uBackground = null;
+ private Fog uFog = null;
+ private Appearance uAppearance = null;
+ private Vector<Light> uLights = new Vector<Light>();
+ private HiResCoord uHiRes = new HiResCoord();
+ private Vector<Sound> uSounds = new Vector<Sound>();
+ private AuralAttributes uAuralAttributes = null;
+ private boolean uBufferOverride = false;
+ private boolean uFrontBufferRendering = false;
+ private int uStereoMode = STEREO_BOTH;
+ private ModelClip uModelClip = null;
+
+// Current rendering graphics state
+ // Current background
+ Background background = null;
+
+ // Background to use if background is null;
+ BackgroundRetained black = new BackgroundRetained();
+
+ // Current fog
+ Fog fog = null;
+
+ // Current modelClip
+ ModelClip modelClip = null;
+
+ // Current appearance object
+ Appearance appearance = null;
+
+ // default appearance retained object
+ AppearanceRetained defaultAppearanceRetained = new AppearanceRetained();
+
+ // The vector of lights
+ Vector<Light> lights = new Vector<Light>();
+
+ // Current High resolution coordinate
+ HiResCoord hiRes = new HiResCoord();
+
+ // Current modeling transform
+ Transform3D modelTransform = new Transform3D();
+ Transform3D identityTransform = new Transform3D();
+
+ Transform3D modelClipTransform = null;
+ Transform3D normalTransform = null;
+ boolean normalTransformNeedToUpdate = true;
+
+ // The vector of sounds
+ Vector<Sound> sounds = new Vector<Sound>();
+
+ // Current AuralAttributes state parameters
+ AuralAttributes auralAttributes = null;
+
+ // The render object associated with this context
+ LightSet ls = null;
+
+ // The current list of lights
+ LightRetained[] lightlist = null;
+
+ // Ambient lights
+ Color3f sceneAmbient = new Color3f(0.0f, 0.0f, 0.0f);
+
+ // The current number of lights, may be less than lightlist.length
+ int numLights = 0;
+
+ // Current composite transform: hi-res + modelTransform
+ Transform3D compTransform = new Transform3D();
+
+ // Draw transform: hi-res + modelTransform + view
+ Transform3D drawTransform = new Transform3D();
+
+ // The view transform (VPC to EC).
+ // NOTE that this is *read-only*
+ Transform3D vpcToEc;
+
+ // A boolean that indicates the lights have changed
+ boolean lightsChanged = false;
+
+ // A boolean that indicates the sounds have changed
+ // XXXX: the soundsChanged flag are set like lights methods set
+ // lightsChanged? but where is this supposed to be check???
+ // lightsChanged tested in 'draw'; but Sound are not processed
+ // in draw.
+ boolean soundsChanged = false;
+
+ // Buffer override flag; enables frontBufferRendering and stereoMode
+ // attributes.
+ boolean bufferOverride = false;
+
+ // Forces rendering to the front buffer (if bufferOverride is true)
+ boolean frontBufferRendering = false;
+
+ // Stereo mode for this buffer (if bufferOverride is true)
+ int stereoMode = STEREO_BOTH;
+
+ // Read Buffer for reading raster of color image
+ byte[] byteBuffer = new byte[1];
+
+ // Read Buffer for reading floating depth image
+ float[] floatBuffer = new float[1];
+
+ // Read Buffer for reading integer depth image
+ int[] intBuffer = new int[1];
+
+ /**
+ * The cached ColoringAttributes color value. It is
+ * 1.0, 1.0, 1.0 if there is no ColoringAttributes.
+ */
+ float red = 1.0f;
+ float green = 1.0f;
+ float blue = 1.0f;
+
+
+ /**
+ * Cached diffuse color value
+ */
+ float dRed = 1.0f;
+ float dGreen = 1.0f;
+ float dBlue = 1.0f;
+
+ /**
+ * The cached TransparencyAttributes transparency value. It is
+ * 0.0 if there is no TransparencyAttributes.
+ */
+ float alpha = 0.0f;
+
+ /**
+ * The cached visible flag for geometry.
+ */
+ boolean visible = true;
+
+ /**
+ * Cached values for polygonMode, line antialiasing, and point antialiasing
+ */
+ int polygonMode = PolygonAttributes.POLYGON_FILL;
+ boolean lineAA = false;
+ boolean pointAA = false;
+
+
+ /**
+ /**
+ * A boolean indicating whether or not lighting should be on.
+ */
+ boolean enableLighting = false;
+
+ private Appearance defaultAppearance = null;
+
+ private boolean ignoreVertexColors = false;
+
+ static final int CLEAR = 0;
+ static final int DRAW = 1;
+ static final int SWAP = 2;
+ static final int READ_RASTER = 3;
+ static final int SET_APPEARANCE = 4;
+ static final int SET_BACKGROUND = 5;
+ static final int SET_FOG = 6;
+ static final int SET_LIGHT = 7;
+ static final int INSERT_LIGHT = 8;
+ static final int REMOVE_LIGHT = 9;
+ static final int ADD_LIGHT = 10;
+ static final int SET_HI_RES = 11;
+ static final int SET_MODEL_TRANSFORM = 12;
+ static final int MULTIPLY_MODEL_TRANSFORM = 13;
+ static final int SET_SOUND = 14;
+ static final int INSERT_SOUND = 15;
+ static final int REMOVE_SOUND = 16;
+ static final int ADD_SOUND = 17;
+ static final int SET_AURAL_ATTRIBUTES = 18;
+ static final int SET_BUFFER_OVERRIDE = 19;
+ static final int SET_FRONT_BUFFER_RENDERING = 20;
+ static final int SET_STEREO_MODE = 21;
+ static final int FLUSH = 22;
+ static final int FLUSH2D = 23;
+ static final int DRAWANDFLUSH2D = 24;
+ static final int SET_MODELCLIP = 25;
+ static final int DISPOSE2D = 26;
+ static final int NCOMMANDS = 27; // needs to be incremented
+ // when a new command is to be
+ // added to the list
+
+ private static Integer[] commands = new Integer[NCOMMANDS];
+ private static Integer[] stereoModes = {
+ new Integer(STEREO_LEFT),
+ new Integer(STEREO_RIGHT),
+ new Integer(STEREO_BOTH)
+ };
+
+ // dirty bits
+ private static final int BUFFER_MODE = 0x1;
+ private int dirtyMask = 0;
+
+ // multi-texture
+ private int numActiveTexUnit = 0;
+ private int lastActiveTexUnitIndex = 0;
+
+ // for read raster
+ private volatile boolean readRasterReady = false;
+
+ // for runMonitor
+ private boolean gcReady = false;
+ private int waiting = 0;
+
+
+ /**
+ * Constructs and creates a GraphicsContext3D object with default
+ * values. Users do not call this directly, rather they get a
+ * graphics context from a Canvas3D.
+ */
+ GraphicsContext3D(Canvas3D canvas3d) {
+ this.canvas3d = canvas3d;
+ }
+
+ /**
+ * Gets the Canvas3D that created this GraphicsContext3D.
+ * @return the Canvas3D that created this GraphicsContext3D
+ */
+ public Canvas3D getCanvas3D() {
+ return this.canvas3d;
+ }
+
+//
+// Methods to set/get graphics state
+//
+
+ /**
+ * Sets the current Appearance object to the specified
+ * Appearance component object.
+ * The graphics context stores a reference to the specified
+ * Appearance object. This means that the application may modify
+ * individual appearance attributes by using the appropriate
+ * methods on the Appearance object.
+ * If the Appearance object is null, default values will be used
+ * for all appearance attributes - it is as if an
+ * Appearance node were created using the default constructor.
+ *
+ * @param appearance the new Appearance object
+ *
+ * @exception IllegalSharingException if the specified appearance refers
+ * to an ImageComponent2D that is being used by a Canvas3D as
+ * an off-screen buffer.
+ */
+ public void setAppearance(Appearance appearance) {
+
+ if(appearance == null) {
+ if(defaultAppearance == null) {
+ defaultAppearance = new Appearance();
+ }
+ appearance = defaultAppearance;
+ } else {
+ // Check whether any ImageComponent2D referred to by
+ // the new appearance is being used as an off-screen buffer and throw
+ // IllegalSharingException if it is.
+ TextureRetained texRetained;
+ ImageComponent[] images;
+ AppearanceRetained appRetained = (AppearanceRetained)appearance.retained;
+ if(appRetained.texture != null) {
+ assert (appRetained.texUnitState == null);
+ texRetained = appRetained.texture;
+ images = texRetained.getImages();
+ if(images != null) {
+ for(int i=0; i<images.length; i++) {
+ if(images[i] != null) {
+ ImageComponentRetained imageRetained = (ImageComponentRetained) images[i].retained;
+ // Do illegal sharing check
+ if(imageRetained.getUsedByOffScreen()) {
+ throw new IllegalSharingException(J3dI18N.getString("GraphicsContext3D30"));
+ }
+ }
+ }
+ }
+ }
+ else if(appRetained.texUnitState != null) {
+ for(int j=0; j<appRetained.texUnitState.length; j++) {
+ texRetained = appRetained.texUnitState[j].texture;
+ images = texRetained.getImages();
+ if(images != null) {
+ for(int i=0; i<images.length; i++) {
+ if(images[i] != null) {
+ ImageComponentRetained imageRetained = (ImageComponentRetained) images[i].retained;
+ // Do illegal sharing check
+ if(imageRetained.getUsedByOffScreen()) {
+ throw new IllegalSharingException(J3dI18N.getString("GraphicsContext3D30"));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ uAppearance = appearance;
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doSetAppearance(appearance);
+ } else if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.SET_APPEARANCE, appearance, null);
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.SET_APPEARANCE, appearance, null);
+ }
+ }
+
+ void doSetAppearance(Appearance appearance) {
+ // Appearance can't be null. See setAppearance().
+ assert(appearance != null);
+
+ NodeComponentRetained nc;
+ nc = ((AppearanceRetained)appearance.retained).material;
+ if (nc != null) {
+ nc.setInImmCtx(true);
+ enableLighting = ((MaterialRetained) nc).lightingEnable;
+ dRed = ((MaterialRetained) nc).diffuseColor.x;
+ dGreen = ((MaterialRetained) nc).diffuseColor.y;
+ dBlue = ((MaterialRetained) nc).diffuseColor.z;
+ } else {
+ enableLighting = false;
+ }
+
+ if(appearance instanceof ShaderAppearance){
+ // Handle ShaderProgramRetained.
+ ShaderProgramRetained spR = ((ShaderAppearanceRetained)appearance.retained).shaderProgram;
+ if(spR != null) {
+ spR.setInImmCtx(true);
+ Shader[] sArray = spR.getShaders();
+ if(sArray != null) {
+ for (int i = 0 ; i < sArray.length; i++) {
+ if (sArray[i] != null) {
+ ((ShaderRetained)sArray[i].retained).setInImmCtx(true);
+ }
+ }
+ }
+ }
+
+ //Handle ShaderAttributeSetRetained.
+ ShaderAttributeSetRetained sasR =
+ ((ShaderAppearanceRetained)appearance.retained).shaderAttributeSet;
+ if(sasR != null) {
+ sasR.setInImmCtx(true);
+ ShaderAttribute[] saArray = sasR.getAll();
+ if(saArray != null) {
+ for (int i = 0 ; i < saArray.length; i++) {
+ if (saArray[i] != null) {
+ ((ShaderAttributeRetained)saArray[i].retained).setInImmCtx(true);
+ }
+ }
+ }
+ }
+ }
+
+ if (((AppearanceRetained)appearance.retained).texUnitState != null) {
+ TextureUnitStateRetained[] texUnitState =
+ ((AppearanceRetained)appearance.retained).texUnitState;
+
+ for (int i = 0 ; i < texUnitState.length; i++) {
+ if (texUnitState[i] != null) {
+ texUnitState[i].setInImmCtx(true);
+ }
+ }
+ }
+
+ nc = ((AppearanceRetained)appearance.retained).texture;
+ if (nc != null) {
+ nc.setInImmCtx(true);
+ }
+
+ nc = ((AppearanceRetained)appearance.retained).texCoordGeneration;
+ if (nc != null) {
+ nc.setInImmCtx(true);
+ }
+
+ nc = ((AppearanceRetained)appearance.retained).textureAttributes;
+ if (nc != null) {
+ nc.setInImmCtx(true);
+ }
+
+ nc = ((AppearanceRetained)appearance.retained).coloringAttributes;
+ if (nc != null) {
+ nc.setInImmCtx(true);
+ red = ((ColoringAttributesRetained)nc).color.x;
+ green = ((ColoringAttributesRetained)nc).color.y;
+ blue = ((ColoringAttributesRetained)nc).color.z;
+ } else {
+ red = 1.0f;
+ green = 1.0f;
+ blue = 1.0f;
+ }
+
+ nc = ((AppearanceRetained)appearance.retained).transparencyAttributes;
+ if (nc != null) {
+ nc.setInImmCtx(true);
+ alpha = 1.0f - ((TransparencyAttributesRetained) nc).transparency;
+ } else {
+ alpha = 1.0f;
+ }
+
+ nc = ((AppearanceRetained)appearance.retained).renderingAttributes;
+ if (nc != null) {
+ nc.setInImmCtx(true);
+ visible = ((RenderingAttributesRetained)nc).visible;
+ } else
+ visible = true;
+
+ nc = ((AppearanceRetained)appearance.retained).polygonAttributes;
+ if (nc != null) {
+ nc.setInImmCtx(true);
+ polygonMode = ((PolygonAttributesRetained)nc).polygonMode;
+ } else {
+ polygonMode = PolygonAttributes.POLYGON_FILL;
+ }
+
+ nc = ((AppearanceRetained)appearance.retained).lineAttributes;
+ if (nc != null) {
+ nc.setInImmCtx(true);
+ lineAA = ((LineAttributesRetained)nc).lineAntialiasing;
+
+ } else {
+ lineAA = false;
+ }
+
+ nc = ((AppearanceRetained)appearance.retained).pointAttributes;
+ if (nc != null) {
+ if (nc.source.isLive())
+ nc.setInImmCtx(true);
+ pointAA = ((PointAttributesRetained)nc).pointAntialiasing;
+ } else {
+ pointAA = false;
+ }
+
+ // Reset the inImmCtx flag of this.appearance.
+ if (this.appearance != null) {
+ AppearanceRetained app = (AppearanceRetained)this.appearance.retained;
+ app.setInImmCtx(false);
+ if (app.material != null) {
+ app.material.setInImmCtx(false);
+ }
+
+ if(app instanceof ShaderAppearanceRetained){
+ // Handle ShaderProgramRetained.
+ ShaderProgramRetained spR = ((ShaderAppearanceRetained)app).shaderProgram;
+ if(spR != null) {
+ spR.setInImmCtx(false);
+ Shader[] sArray = spR.getShaders();
+ if(sArray != null) {
+ for (int i = 0 ; i < sArray.length; i++) {
+ if (sArray[i] != null) {
+ ((ShaderRetained)sArray[i].retained).setInImmCtx(false);
+ }
+ }
+ }
+ }
+
+ //Handle ShaderAttributeSetRetained.
+ ShaderAttributeSetRetained sasR = ((ShaderAppearanceRetained)app).shaderAttributeSet;
+ if(sasR != null) {
+ sasR.setInImmCtx(false);
+ ShaderAttribute[] saArray = sasR.getAll();
+ if(saArray != null) {
+ for (int i = 0 ; i < saArray.length; i++) {
+ if (saArray[i] != null) {
+ ((ShaderAttributeRetained)saArray[i].retained).setInImmCtx(false);
+ }
+ }
+ }
+ }
+ }
+
+ if (app.texUnitState != null) {
+ for (int i = 0; i < app.texUnitState.length; i++) {
+ if (app.texUnitState[0] != null)
+ app.texUnitState[0].setInImmCtx(false);
+ }
+ }
+ if (app.texture != null) {
+ app.texture.setInImmCtx(false);
+ }
+ if (app.texCoordGeneration != null) {
+ app.texCoordGeneration.setInImmCtx(false);
+ }
+ if (app.textureAttributes != null) {
+ app.textureAttributes.setInImmCtx(false);
+ }
+ if (app.coloringAttributes != null) {
+ app.coloringAttributes.setInImmCtx(false);
+ }
+ if (app.transparencyAttributes != null) {
+ app.transparencyAttributes.setInImmCtx(false);
+ }
+ if (app.renderingAttributes != null) {
+ app.renderingAttributes.setInImmCtx(false);
+ }
+ if (app.polygonAttributes != null) {
+ app.polygonAttributes.setInImmCtx(false);
+ }
+ if (app.lineAttributes != null) {
+ app.lineAttributes.setInImmCtx(false);
+ }
+ if (app.pointAttributes != null) {
+ app.pointAttributes.setInImmCtx(false);
+ }
+ }
+
+ ((AppearanceRetained)appearance.retained).setInImmCtx(true);
+ this.appearance = appearance;
+ }
+
+ /**
+ * Retrieves the current Appearance component object.
+ * @return the current Appearance object
+ */
+ public Appearance getAppearance() {
+ return this.uAppearance;
+ }
+
+ /**
+ * Sets the current Background to the specified Background
+ * leaf node object.
+ * The graphics context stores a reference to the specified
+ * Background node. This means that the application may modify
+ * the background color or image by using the appropriate
+ * methods on the Background node. The Background node must
+ * not be part of a live scene graph, nor may it subsequently
+ * be made part of a live scene graph-an IllegalSharingException
+ * is thrown in such cases. If the Background object is null,
+ * the default background color of black (0,0,0) is used to clear
+ * the canvas prior to rendering a new frame. The Background
+ * node's application region is ignored for immediate-mode
+ * rendering.
+ *
+ * @param background the new Background object
+ *
+ * @exception IllegalSharingException if the Background node
+ * is part of or is subsequently made part of a live scene graph.
+ *
+ * @exception IllegalSharingException if the specified background node
+ * refers to an ImageComponent2D that is being used by a Canvas3D as
+ * an off-screen buffer.
+ */
+ public void setBackground(Background background) {
+
+ if (background.isLive()) {
+ throw new IllegalSharingException(J3dI18N.getString("GraphicsContext3D11"));
+ }
+ BackgroundRetained bgRetained = (BackgroundRetained)background.retained;
+ ImageComponent2D image = bgRetained.getImage();
+ if(image != null) {
+ ImageComponent2DRetained imageRetained = (ImageComponent2DRetained) image.retained;
+ if(imageRetained.getUsedByOffScreen()) {
+ throw new IllegalSharingException(J3dI18N.getString("GraphicsContext3D31"));
+ }
+ }
+
+ if (((BackgroundRetained)background.retained).geometryBranch != null) {
+ throw new IllegalSharingException(J3dI18N.getString("GraphicsContext3D22"));
+ }
+
+ uBackground = background;
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doSetBackground(background);
+ } else if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.SET_BACKGROUND, background, null);
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.SET_BACKGROUND, background, null);
+ }
+ }
+
+ void doSetBackground(Background background) {
+ BackgroundRetained bg;
+
+ if (this.background != null) {
+ bg = (BackgroundRetained)this.background.retained;
+ bg.setInImmCtx(false);
+ }
+ bg = (BackgroundRetained)background.retained;
+ bg.setInImmCtx(true);
+
+ this.background = background;
+ }
+
+ /**
+ * Retrieves the current Background leaf node object.
+ * @return the current Background object
+ */
+ public Background getBackground() {
+ return this.uBackground;
+ }
+
+ /**
+ * Sets the current Fog to the specified Fog
+ * leaf node object.
+ * The graphics context stores a reference to the specified
+ * Fog node. This means that the application may modify the
+ * fog attributes using the appropriate methods on the Fog
+ * node object. The Fog node must not be part of a live
+ * scene graph, nor may it subsequently be made part of a
+ * live scene graph-an IllegalSharingException is thrown in
+ * such cases. If the Fog object is null, fog is disabled.
+ * Both the region of influence and the hierarchical scope
+ * of the Fog node are ignored for immediate-mode rendering.
+ * @param fog the new Fog object
+ * @exception IllegalSharingException if the Fog node
+ * is part of or is subsequently made part of a live scene graph.
+ */
+ public void setFog(Fog fog) {
+ if (fog != null && fog.isLive()) {
+ throw new IllegalSharingException(J3dI18N.getString("GraphicsContext3D12"));
+ }
+ uFog = fog;
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doSetFog(fog);
+ } else if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.SET_FOG, fog, null);
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.SET_FOG, fog, null);
+ }
+ }
+
+ void doSetFog(Fog fog) {
+ if (this.fog != null) {
+ ((FogRetained)this.fog.retained).setInImmCtx(false);
+ }
+ this.fog = fog;
+ if (fog != null) {
+ ((FogRetained)fog.retained).setInImmCtx(true);
+
+ // Issue 144: updateFogState now called unconditionally
+ updateFogState((FogRetained)fog.retained);
+ }
+ }
+
+ /**
+ * Retrieves the current Fog leaf node object.
+ * @return the current Fog object
+ */
+ public Fog getFog() {
+ return this.uFog;
+ }
+
+
+ /**
+ * Sets the current ModelClip leaf node to the specified object.
+ * The graphics context stores a reference to the specified
+ * ModelClip node. This means that the application may modify the
+ * model clipping attributes using the appropriate methods on the
+ * ModelClip node object. The ModelClip node must not be part of a
+ * live scene graph, nor may it subsequently be made part of a
+ * live scene graph-an IllegalSharingException is thrown in such
+ * cases. If the ModelClip object is null, model clipping is
+ * disabled. Both the region of influence and the hierarchical
+ * scope of the ModelClip node are ignored for immediate-mode
+ * rendering.
+ *
+ * @param modelClip the new ModelClip node
+ *
+ * @exception IllegalSharingException if the ModelClip node
+ * is part of or is subsequently made part of a live scene graph.
+ *
+ * @since Java 3D 1.2
+ */
+ public void setModelClip(ModelClip modelClip) {
+ if ((modelClip != null) && modelClip.isLive()) {
+ throw new IllegalSharingException(J3dI18N.getString("GraphicsContext3D25"));
+ }
+ uModelClip = modelClip;
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doSetModelClip(modelClip);
+ } else if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.SET_MODELCLIP,
+ modelClip, null);
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.SET_MODELCLIP,
+ modelClip, null);
+ }
+ }
+
+ void doSetModelClip(ModelClip modelClip) {
+ ModelClipRetained mc = null;
+
+ this.modelClip = modelClip;
+
+ if (this.modelClip != null) {
+ mc = (ModelClipRetained)this.modelClip.retained;
+ mc.setInImmCtx(true);
+
+ if (modelClipTransform == null)
+ modelClipTransform = new Transform3D();
+
+ // save the current model Transform
+ modelClipTransform.set(compTransform);
+ }
+ }
+
+ /**
+ * Retrieves the current ModelClip leaf node object.
+ * @return the current ModelClip object
+ *
+ * @since Java 3D 1.2
+ */
+ public ModelClip getModelClip() {
+ return this.uModelClip;
+ }
+
+
+ /**
+ * Replaces the specified light with the light provided.
+ * The graphics context stores a reference to each light
+ * object in the list of lights. This means that the
+ * application may modify the light attributes for
+ * any of the lights using the appropriate methods on that
+ * Light node object. None of the Light nodes in the list
+ * of lights may be part of a live scene graph, nor may
+ * they subsequently be made part of a live scene graph -
+ * an IllegalSharingException is thrown in such cases.
+ * @param light the new light
+ * @param index which light to replace
+ * @exception IllegalSharingException if the Light node
+ * is part of or is subsequently made part of a live scene graph.
+ * @exception NullPointerException if the Light object is null.
+ */
+ public void setLight(Light light, int index) {
+ if (light == null) {
+ throw new NullPointerException(J3dI18N.getString("GraphicsContext3D13"));
+ }
+ if (light.isLive()) {
+ throw new IllegalSharingException(J3dI18N.getString("GraphicsContext3D14"));
+ }
+ uLights.set(index, light);
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doSetLight(light, index);
+ } else if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.SET_LIGHT, light,
+ new Integer(index));
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.SET_LIGHT, light,
+ new Integer(index));
+ }
+ }
+
+ void doSetLight(Light light, int index) {
+
+ Light oldlight = this.lights.get(index);
+ if (oldlight != null) {
+ ((LightRetained)oldlight.retained).setInImmCtx(false);
+ }
+ ((LightRetained)light.retained).setInImmCtx(true);
+ updateLightState((LightRetained)light.retained);
+ this.lights.set(index, light);
+ this.lightsChanged = true;
+ }
+
+ /**
+ * Inserts the specified light at the specified index location.
+ * @param light the new light
+ * @param index at which location to insert
+ * @exception IllegalSharingException if the Light node
+ * is part of or is subsequently made part of a live scene graph.
+ * @exception NullPointerException if the Light object is null.
+ */
+ public void insertLight(Light light, int index) {
+ if (light == null) {
+ throw new NullPointerException(J3dI18N.getString("GraphicsContext3D13"));
+ }
+ if (light.isLive()) {
+ throw new IllegalSharingException(J3dI18N.getString("GraphicsContext3D14"));
+ }
+ uLights.add(index, light);
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doInsertLight(light, index);
+ } else if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.INSERT_LIGHT, light,
+ new Integer(index));
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.INSERT_LIGHT, light,
+ new Integer(index));
+ }
+ }
+
+ void doInsertLight(Light light, int index) {
+ ((LightRetained)light.retained).setInImmCtx(true);
+ updateLightState((LightRetained)light.retained);
+ this.lights.add(index, light);
+ this.lightsChanged = true;
+ }
+
+ /**
+ * Removes the light at the specified index location.
+ * @param index which light to remove
+ */
+ public void removeLight(int index) {
+ uLights.remove(index);
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doRemoveLight(index);
+ } else if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.REMOVE_LIGHT,
+ new Integer(index), null);
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.REMOVE_LIGHT,
+ new Integer(index), null);
+ }
+ }
+
+ void doRemoveLight(int index) {
+ Light light = this.lights.get(index);
+
+ ((LightRetained)light.retained).setInImmCtx(false);
+ this.lights.remove(index);
+ this.lightsChanged = true;
+ }
+
+/**
+ * Retrieves the index selected light.
+ * @param index which light to return
+ * @return the light at location index
+ */
+public Light getLight(int index) {
+ return uLights.get(index);
+}
+
+/**
+ * Retrieves the enumeration object of all the lights.
+ * @return the enumeration object of all the lights
+ */
+public Enumeration<Light> getAllLights() {
+ return uLights.elements();
+}
+
+ /**
+ * Appends the specified light to this graphics context's list of lights.
+ * Adding a null Light object to the list will result
+ * in a NullPointerException. Both the region of influence
+ * and the hierarchical scope of all lights in the list
+ * are ignored for immediate-mode rendering.
+ * @param light the light to add
+ * @exception IllegalSharingException if the Light node
+ * is part of or is subsequently made part of a live scene graph.
+ * @exception NullPointerException if the Light object is null.
+ */
+ public void addLight(Light light) {
+ if (light == null) {
+ throw new NullPointerException(J3dI18N.getString("GraphicsContext3D13"));
+ }
+
+ if (light.isLive()) {
+ throw new IllegalSharingException(J3dI18N.getString("GraphicsContext3D14"));
+ }
+ uLights.addElement(light);
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doAddLight(light);
+ } else if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.ADD_LIGHT, light, null);
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.ADD_LIGHT, light, null);
+ }
+ }
+
+ void doAddLight(Light light) {
+
+ ((LightRetained)light.retained).setInImmCtx(true);
+ updateLightState((LightRetained)light.retained);
+ this.lights.add(light);
+ this.lightsChanged = true;
+ }
+
+/**
+ * Retrieves the current number of lights in this graphics context.
+ * @return the current number of lights
+ */
+public int numLights() {
+ return this.uLights.size();
+}
+
+ private Transform3D getNormalTransform() {
+ if (compTransform.isRigid()) {
+ return compTransform;
+ }
+ if (normalTransform == null) {
+ normalTransform = new Transform3D();
+ }
+
+ if (normalTransformNeedToUpdate) {
+ normalTransform.invert(compTransform);
+ normalTransform.transpose();
+ normalTransformNeedToUpdate = false;
+ }
+ return normalTransform;
+ }
+
+
+ void updateFogState(FogRetained fogRet) {
+ // Issue 144: update localToVWorldScale for all types of Fog
+ fogRet.setLocalToVworldScale(modelTransform.getDistanceScale());
+ }
+
+
+ void updateLightState(LightRetained light) {
+
+ if (light instanceof DirectionalLightRetained) {
+ DirectionalLightRetained dl = (DirectionalLightRetained) light;
+
+ Transform3D xform = getNormalTransform();
+ xform.transform(dl.direction, dl.xformDirection);
+ dl.xformDirection.normalize();
+
+ } else if (light instanceof SpotLightRetained) {
+ SpotLightRetained sl = (SpotLightRetained) light;
+
+ Transform3D xform = getNormalTransform();
+ xform.transform(sl.direction, sl.xformDirection);
+ sl.xformDirection.normalize();
+ this.modelTransform.transform(sl.position, sl.xformPosition);
+
+ } else if (light instanceof PointLightRetained) {
+ PointLightRetained pl = (PointLightRetained) light;
+
+ this.modelTransform.transform(pl.position,pl.xformPosition);
+
+ pl.localToVworldScale = modelTransform.getDistanceScale();
+
+ }
+ }
+
+ /**
+ * Sets the HiRes coordinate of this context to the location
+ * specified by the parameters provided.
+ * The parameters x, y, and z are arrays of eight 32-bit
+ * integers that specify the high-resolution coordinates point.
+ * @param x an eight element array specifying the x position
+ * @param y an eight element array specifying the y position
+ * @param z an eight element array specifying the z position
+ * @see HiResCoord
+ */
+ public void setHiRes(int[] x, int[] y, int[] z) {
+ HiResCoord hiRes = new HiResCoord(x, y, z);
+ setHiRes(hiRes);
+ }
+
+ /**
+ * Sets the HiRes coordinate of this context
+ * to the location specified by the HiRes argument.
+ * @param hiRes the HiRes coordinate specifying the a new location
+ */
+ public void setHiRes(HiResCoord hiRes) {
+ uHiRes.setHiResCoord(hiRes);
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doSetHiRes(hiRes);
+ } else if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.SET_HI_RES, hiRes, null);
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.SET_HI_RES, hiRes, null);
+ }
+ }
+
+ void doSetHiRes(HiResCoord hiRes) {
+ this.hiRes.setHiResCoord(hiRes);
+ computeCompositeTransform();
+ }
+
+ /**
+ * Retrieves the current HiRes coordinate of this context.
+ * @param hiRes a HiResCoord object that will receive the
+ * HiRes coordinate of this context
+ */
+ public void getHiRes(HiResCoord hiRes) {
+ uHiRes.getHiResCoord(hiRes);
+ }
+
+ /**
+ * Sets the current model transform to a copy of the specified
+ * transform.
+ * A BadTransformException is thrown if an attempt is made
+ * to specify an illegal Transform3D.
+ * @param t the new model transform
+ * @exception BadTransformException if the transform is not affine.
+ */
+ public void setModelTransform(Transform3D t) {
+
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doSetModelTransform(t);
+ }
+ else {
+ Transform3D uModelTransform = new Transform3D(t);
+ //Transform3D uModelTransform = t;
+ if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.SET_MODEL_TRANSFORM,
+ uModelTransform, null);
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.SET_MODEL_TRANSFORM,
+ uModelTransform, null);
+ }
+ }
+ }
+
+ void doSetModelTransform(Transform3D t) {
+ this.modelTransform.set(t);
+ computeCompositeTransform();
+ normalTransformNeedToUpdate = true;
+ }
+
+ /**
+ * Multiplies the current model transform by the specified
+ * transform and stores the result back into the current
+ * transform. The specified transformation must be affine.
+ * @param t the model transform to be concatenated with the
+ * current model transform
+ * @exception BadTransformException if the transform is not affine.
+ */
+ public void multiplyModelTransform(Transform3D t) {
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doMultiplyModelTransform(t);
+ } else {
+ Transform3D tt = new Transform3D(t);
+ if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.MULTIPLY_MODEL_TRANSFORM,
+ tt, null);
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.MULTIPLY_MODEL_TRANSFORM,
+ tt, null);
+ }
+ }
+ }
+
+ void doMultiplyModelTransform(Transform3D t) {
+ this.modelTransform.mul(t);
+ computeCompositeTransform();
+ normalTransformNeedToUpdate = true;
+ }
+
+ /**
+ * Retrieves the current model transform.
+ * @param t the model transform that will receive the current
+ * model transform
+ */
+ public void getModelTransform(Transform3D t) {
+ t.set(modelTransform);
+ }
+
+ /**
+ * Replaces the specified sound with the sound provided.
+ * The graphics context stores a reference to each sound
+ * object in the list of sounds. This means that the
+ * application may modify the sound attributes for
+ * any of the sounds by using the appropriate methods on
+ * that Sound node object.
+ * @param sound the new sound
+ * @param index which sound to replace
+ * @exception IllegalSharingException if the Sound node
+ * is part of or is subsequently made part of a live scene graph.
+ * @exception NullPointerException if the Sound object is null.
+ */
+ public void setSound(Sound sound, int index) {
+ if (sound == null) {
+ throw new NullPointerException(J3dI18N.getString("GraphicsContext3D17"));
+ }
+ if (sound.isLive()) {
+ throw new IllegalSharingException(J3dI18N.getString("GraphicsContext3D23"));
+ }
+ uSounds.set(index, sound);
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doSetSound(sound, index);
+ } else if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.SET_SOUND, sound,
+ new Integer(index));
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.SET_SOUND, sound,
+ new Integer(index));
+ }
+ }
+
+ void doSetSound(Sound sound, int index) {
+ Sound oldSound = this.sounds.get(index);
+ ((SoundRetained)sound.retained).setInImmCtx(true);
+ if (oldSound != null) {
+ ((SoundRetained)oldSound.retained).setInImmCtx(false);
+ }
+ ((SoundRetained)sound.retained).setInImmCtx(true);
+ updateSoundState((SoundRetained)(sound.retained));
+ this.sounds.set(index, sound);
+ this.soundsChanged = true;
+
+ sendSoundMessage(GraphicsContext3D.SET_SOUND, sound, oldSound);
+ }
+
+ /**
+ * Inserts the specified sound at the specified index location.
+ * Inserting a sound to the list of sounds implicitly starts the
+ * sound playing. Once a sound is finished playing, it can be
+ * restarted by setting the sound's enable flag to true.
+ * The scheduling region of all sounds in the list is ignored
+ * for immediate-mode rendering.
+ * @param sound the new sound
+ * @param index at which location to insert
+ * @exception IllegalSharingException if the Sound node
+ * is part or is subsequently made part of a live scene graph.
+ * @exception NullPointerException if the Sound object is null.
+ */
+ public void insertSound(Sound sound, int index) {
+ if (sound == null) {
+ throw new NullPointerException(J3dI18N.getString("GraphicsContext3D17")); }
+
+ if (sound.isLive()) {
+ throw new IllegalSharingException(J3dI18N.getString("GraphicsContext3D23"));
+ }
+ uSounds.add(index, sound);
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doInsertSound(sound, index);
+ } else if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.INSERT_SOUND, sound,
+ new Integer(index));
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.INSERT_SOUND, sound,
+ new Integer(index));
+ }
+ }
+
+ void doInsertSound(Sound sound, int index) {
+ updateSoundState((SoundRetained)sound.retained);
+ this.sounds.add(index, sound);
+ this.soundsChanged = true;
+ sendSoundMessage(GraphicsContext3D.INSERT_SOUND, sound, null);
+ }
+
+ /**
+ * Removes the sound at the specified index location.
+ * @param index which sound to remove
+ */
+ public void removeSound(int index) {
+ uSounds.remove(index);
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doRemoveSound(index);
+ } else if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.REMOVE_SOUND,
+ new Integer(index), null);
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.REMOVE_SOUND,
+ new Integer(index), null);
+ }
+ }
+
+ void doRemoveSound(int index) {
+ Sound sound = this.sounds.get(index);
+ SoundScheduler soundScheduler = getSoundScheduler();
+ ((SoundRetained)(sound.retained)).setInImmCtx(false);
+ this.sounds.remove(index);
+ this.soundsChanged = true;
+ // stop sound if playing on audioDevice
+ sendSoundMessage(GraphicsContext3D.REMOVE_SOUND, null, sound);
+ }
+
+/**
+ * Retrieves the index selected sound.
+ * @param index which sound to return
+ * @return the sound at location index
+ */
+public Sound getSound(int index) {
+ return uSounds.get(index);
+}
+
+/**
+ * Retrieves the enumeration object of all the sounds.
+ * @return the enumeration object of all the sounds
+ */
+public Enumeration<Sound> getAllSounds() {
+ return uSounds.elements();
+}
+
+ /**
+ * Appends the specified sound to this graphics context's list of sounds.
+ * Adding a sound to the list of sounds implicitly starts the
+ * sound playing. Once a sound is finished playing, it can be
+ * restarted by setting the sound's enable flag to true.
+ * The scheduling region of all sounds in the list is ignored
+ * for immediate-mode rendering.
+ * @param sound the sound to add
+ * @exception IllegalSharingException if the Sound node
+ * is part of or is subsequently made part of a live scene graph.
+ * @exception NullPointerException if the Sound object is null.
+ */
+ public void addSound(Sound sound) {
+ if (sound == null) {
+ throw new NullPointerException(J3dI18N.getString("GraphicsContext3D17")); }
+
+ if (sound.isLive()) {
+ throw new IllegalSharingException(J3dI18N.getString("GraphicsContext3D23"));
+
+ }
+ uSounds.add(sound);
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doAddSound(sound);
+ } else if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.ADD_SOUND, sound, null);
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.ADD_SOUND, sound, null);
+ }
+ }
+
+ void doAddSound(Sound sound) {
+ ((SoundRetained)(sound.retained)).setInImmCtx(true);
+ updateSoundState((SoundRetained)(sound.retained));
+ this.sounds.add(sound);
+ this.soundsChanged = true;
+ sendSoundMessage(GraphicsContext3D.ADD_SOUND, sound, null);
+ }
+
+/**
+ * Retrieves the current number of sounds in this graphics context.
+ * @return the current number of sounds
+ */
+public int numSounds() {
+ return uSounds.size();
+}
+
+ SoundScheduler getSoundScheduler() {
+ if (canvas3d != null && canvas3d.view != null)
+ return canvas3d.view.soundScheduler; // could be null as well
+ else
+ return (SoundScheduler)null;
+ }
+
+ void updateSoundState(SoundRetained sound) {
+ View view = null;
+ if (canvas3d != null)
+ view = canvas3d.view;
+ // Make sure that:
+ // . Current view is not null
+ // . The sound scheduler running (reference to it is not null)
+ if (view != null) {
+ SoundScheduler soundScheduler = getSoundScheduler();
+ if (soundScheduler == null) {
+ // XXXX: Re-implement
+ // start up SoundScheduler since it hasn't already been started
+ }
+ }
+
+ // Update sound fields related to transforms
+ if (sound instanceof ConeSoundRetained) {
+ ConeSoundRetained cs = (ConeSoundRetained) sound;
+ this.modelTransform.transform(cs.direction, cs.xformDirection);
+ cs.xformDirection.normalize();
+ this.modelTransform.transform(cs.position, cs.xformPosition);
+ // XXXX (Question) Is drawTranform equivalent to Vworld-to-Local?
+ cs.trans.setWithLock(drawTransform);
+
+ } else if (sound instanceof PointSoundRetained) {
+ PointSoundRetained ps = (PointSoundRetained) sound;
+ this.modelTransform.transform(ps.position, ps.xformPosition);
+ // XXXX (Question) Is drawTranform equivalent to Vworld-to-Local?
+ ps.trans.setWithLock(drawTransform);
+ }
+ }
+
+ /**
+ * Retrieves the sound playing flag.
+ * @param index which sound
+ * @return flag denoting if sound is currently playing
+ */
+ public boolean isSoundPlaying(int index) {
+ Sound sound;
+ // uSounds isPlaying field is NOT updated, sounds elements are used
+ sound = this.sounds.get(index);
+ return sound.isPlaying();
+ }
+
+ /**
+ * Sets the current AuralAttributes object to the specified
+ * AuralAttributes component object.
+ * This means that the application may modify individual
+ * audio attributes by using the appropriate methods in
+ * the Aural-Attributes object.
+ * @param attributes the new AuralAttributes object
+ */
+ public void setAuralAttributes(AuralAttributes attributes) {
+ uAuralAttributes = attributes;
+
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doSetAuralAttributes(attributes);
+ } else if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.SET_AURAL_ATTRIBUTES,
+ attributes, null);
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.SET_AURAL_ATTRIBUTES,
+ attributes, null);
+ }
+ }
+
+ void doSetAuralAttributes(AuralAttributes attributes) {
+ this.auralAttributes = attributes;
+ sendSoundMessage(GraphicsContext3D.SET_AURAL_ATTRIBUTES, attributes, null);
+ }
+ /**
+ * Retrieves the current AuralAttributes component object.
+ * @return the current AuralAttributes object
+ */
+ public AuralAttributes getAuralAttributes() {
+ return uAuralAttributes;
+ }
+
+
+ /**
+ * Sets a flag that specifies whether the double buffering and
+ * stereo mode from the Canvas3D are overridden. When set to
+ * true, this attribute enables the
+ * <code>frontBufferRendering</code> and <code>stereoMode</code>
+ * attributes.
+ *
+ * @param bufferOverride the new buffer override flag
+ *
+ * @see #setFrontBufferRendering
+ * @see #setStereoMode
+ *
+ * @since Java 3D 1.2
+ */
+ public void setBufferOverride(boolean bufferOverride) {
+ uBufferOverride = bufferOverride;
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doSetBufferOverride(bufferOverride);
+ } else if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.SET_BUFFER_OVERRIDE,
+ new Boolean(bufferOverride), null);
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.SET_BUFFER_OVERRIDE,
+ new Boolean(bufferOverride), null);
+ }
+ }
+
+ void doSetBufferOverride(boolean bufferOverride) {
+ if (bufferOverride != this.bufferOverride) {
+ this.bufferOverride = bufferOverride;
+ dirtyMask |= BUFFER_MODE;
+ }
+ }
+
+
+ /**
+ * Returns the current buffer override flag.
+ * @return true if buffer override is enabled; otherwise,
+ * false is returned
+ *
+ * @since Java 3D 1.2
+ */
+ public boolean getBufferOverride() {
+ return uBufferOverride;
+ }
+
+
+ /**
+ * Sets a flag that enables or disables immediate mode rendering
+ * into the front buffer of a double buffered Canvas3D.
+ * This attribute is only used when the
+ * <code>bufferOverride</code> flag is enabled.
+ * <p>
+ * Note that this attribute has no effect if double buffering
+ * is disabled or is not available on the Canvas3D.
+ *
+ * @param frontBufferRendering the new front buffer rendering flag
+ *
+ * @see #setBufferOverride
+ *
+ * @since Java 3D 1.2
+ */
+ public void setFrontBufferRendering(boolean frontBufferRendering) {
+ uFrontBufferRendering = frontBufferRendering;
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doSetFrontBufferRendering(frontBufferRendering);
+ } else if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.SET_FRONT_BUFFER_RENDERING,
+ new Boolean(frontBufferRendering), null);
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.SET_FRONT_BUFFER_RENDERING,
+ new Boolean(frontBufferRendering), null);
+ }
+ }
+
+ void doSetFrontBufferRendering(boolean frontBufferRendering) {
+ if (frontBufferRendering != this.frontBufferRendering) {
+ this.frontBufferRendering = frontBufferRendering;
+ dirtyMask |= BUFFER_MODE;
+ }
+ }
+
+
+ /**
+ * Returns the current front buffer rendering flag.
+ * @return true if front buffer rendering is enabled; otherwise,
+ * false is returned
+ *
+ * @since Java 3D 1.2
+ */
+ public boolean getFrontBufferRendering() {
+ return uFrontBufferRendering;
+ }
+
+
+ /**
+ * Sets the stereo mode for immediate mode rendering. The
+ * parameter specifies which stereo buffer or buffers is rendered
+ * into. This attribute is only used when the
+ * <code>bufferOverride</code> flag is enabled.
+ * <ul>
+ * <li>
+ * <code>STEREO_LEFT</code> specifies that rendering is done into
+ * the left eye.
+ * </li>
+ * <li>
+ * <code>STEREO_RIGHT</code> specifies that rendering is done into
+ * the right eye.
+ * </li>
+ * <li>
+ * <code>STEREO_BOTH</code> specifies that rendering is done into
+ * both eyes. This is the default.
+ * </li>
+ * </ul>
+ *
+ * <p>
+ * Note that this attribute has no effect if stereo is disabled or
+ * is not available on the Canvas3D.
+ *
+ * @param stereoMode the new stereo mode
+ *
+ * @see #setBufferOverride
+ *
+ * @since Java 3D 1.2
+ */
+ public void setStereoMode(int stereoMode) {
+ uStereoMode = stereoMode;
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doSetStereoMode(stereoMode);
+ } else if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.SET_STEREO_MODE,
+ stereoModes[stereoMode], null);
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.SET_STEREO_MODE,
+ stereoModes[stereoMode], null);
+ }
+ }
+
+ void doSetStereoMode(int stereoMode) {
+ if (stereoMode != this.stereoMode) {
+ this.stereoMode = stereoMode;
+ dirtyMask |= BUFFER_MODE;
+ }
+ }
+
+
+ /**
+ * Returns the current stereo mode.
+ * @return the stereo mode, one of <code>STEREO_LEFT</code>,
+ * <code>STEREO_RIGHT</code>, or <code>STEREO_BOTH</code>.
+ *
+ * @since Java 3D 1.2
+ */
+ public int getStereoMode() {
+ return uStereoMode;
+ }
+
+
+//
+// Methods to draw graphics objects
+//
+
+ /**
+ * Clear the Canvas3D to the color or image specified by the
+ * current background node.
+ */
+ public void clear() {
+ if ((canvas3d.view == null) || (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active)) {
+ return;
+ } else if (Thread.currentThread() == canvas3d.screen.renderer) {
+ doClear();
+ } else if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.CLEAR, null, null);
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.CLEAR, null, null);
+ }
+ }
+
+ void doClear() {
+
+ if (!canvas3d.firstPaintCalled)
+ return;
+
+ RenderBin rb = canvas3d.view.renderBin;
+ BackgroundRetained back = null;
+
+
+ if (this.background != null)
+ back = (BackgroundRetained)this.background.retained;
+ else
+ back = this.black;
+
+ // XXXX: This should ideally be done by the renderer (or by the
+ // canvas itself) when the canvas is first added to a view.
+ /*
+ if ((canvas3d.screen.renderer != null) &&
+ (canvas3d.screen.renderer.renderBin == null))
+ canvas3d.screen.renderer.renderBin = rb;
+ */
+ // If we are in pure immediate mode, update the view cache
+ if (!canvas3d.isRunning)
+ updateViewCache(rb);
+
+ // We need to catch NullPointerException when the dsi
+ // gets yanked from us during a remove.
+
+ try {
+ // Issue 78 - need to get the drawingSurface info every
+ // frame; this is necessary since the HDC (window ID)
+ // on Windows can become invalidated without our
+ // being notified!
+ if (!canvas3d.offScreen) {
+ canvas3d.drawingSurfaceObject.getDrawingSurfaceObjectInfo();
+ }
+
+ if (canvas3d.drawingSurfaceObject.renderLock()) {
+ // XXXX : Fix texture
+ /*
+ if (canvas3d.useSharedCtx) {
+ if (canvas3d.screen.renderer.sharedCtx == 0) {
+ synchronized (VirtualUniverse.mc.contextCreationLock) {
+ canvas3d.screen.renderer.sharedCtx = canvas3d.createNewContext(
+ canvas3d.screen.display,
+ canvas3d.window, 0, true,
+ canvas3d.offScreen);
+ canvas3d.screen.renderer.sharedCtxTimeStamp =
+ VirtualUniverse.mc.getContextTimeStamp();
+ canvas3d.screen.renderer.needToRebuildDisplayList = true;
+ }
+ }
+ }
+ */
+
+ if (canvas3d.ctx == null) {
+ synchronized (VirtualUniverse.mc.contextCreationLock) {
+ canvas3d.ctx = canvas3d.createNewContext(null, false);
+ if (canvas3d.ctx == null) {
+ canvas3d.drawingSurfaceObject.unLock();
+ return;
+ }
+
+ canvas3d.ctxTimeStamp =
+ VirtualUniverse.mc.getContextTimeStamp();
+ canvas3d.screen.renderer.listOfCtxs.add(canvas3d.ctx);
+ canvas3d.screen.renderer.listOfCanvases.add(canvas3d);
+
+ if (canvas3d.graphics2D != null) {
+ canvas3d.graphics2D.init();
+ }
+
+ // enable separate specular color
+ canvas3d.enableSeparateSpecularColor();
+ }
+
+ // create the cache texture state in canvas
+ // for state download checking purpose
+ if (canvas3d.texUnitState == null) {
+ canvas3d.createTexUnitState();
+ }
+
+ canvas3d.drawingSurfaceObject.contextValidated();
+ canvas3d.screen.renderer.currentCtx = canvas3d.ctx;
+ canvas3d.screen.renderer.currentDrawable = canvas3d.drawable;
+ initializeState();
+ canvas3d.ctxChanged = true;
+ canvas3d.canvasDirty = 0xffff;
+ // Update Appearance
+ updateState(rb, RenderMolecule.SURFACE);
+
+ canvas3d.currentLights = new
+ LightRetained[canvas3d.getNumCtxLights(canvas3d.ctx)];
+
+ for (int j=0; j<canvas3d.currentLights.length; j++) {
+ canvas3d.currentLights[j] = null;
+ }
+ }
+
+
+ canvas3d.makeCtxCurrent();
+
+ if ((dirtyMask & BUFFER_MODE) != 0) {
+ if (bufferOverride) {
+ canvas3d.setRenderMode(canvas3d.ctx, stereoMode,
+ canvas3d.useDoubleBuffer && !frontBufferRendering);
+ } else {
+ if (!canvas3d.isRunning) {
+ canvas3d.setRenderMode(canvas3d.ctx,
+ Canvas3D.FIELD_ALL,
+ canvas3d.useDoubleBuffer);
+ }
+ }
+ dirtyMask &= ~BUFFER_MODE;
+ }
+
+ Dimension size = canvas3d.getSize();
+ int winWidth = size.width;
+ int winHeight = size.height;
+ boolean isByRefBackgroundImage = false;
+ if (back.image != null) {
+ if (back.image.isByReference()) {
+ back.image.geomLock.getLock();
+ isByRefBackgroundImage = true;
+ }
+
+ back.image.evaluateExtensions(canvas3d);
+ }
+
+ canvas3d.clear(back, winWidth, winHeight);
+
+ if (isByRefBackgroundImage) {
+ back.image.geomLock.unLock();
+ }
+
+
+ // Set the viewport and view matrices
+ if (!canvas3d.isRunning) {
+ CanvasViewCache cvCache = canvas3d.canvasViewCache;
+ canvas3d.setViewport(canvas3d.ctx,
+ 0, 0,
+ cvCache.getCanvasWidth(),
+ cvCache.getCanvasHeight());
+ if (bufferOverride && (stereoMode == STEREO_RIGHT)) {
+ canvas3d.setProjectionMatrix(canvas3d.ctx,
+ cvCache.getRightProjection());
+ canvas3d.setModelViewMatrix(canvas3d.ctx,
+ cvCache.getRightVpcToEc().mat,
+ rb.vworldToVpc);
+ } else {
+ canvas3d.setProjectionMatrix(canvas3d.ctx,
+ cvCache.getLeftProjection());
+ canvas3d.setModelViewMatrix(canvas3d.ctx,
+ cvCache.getLeftVpcToEc().mat,
+ rb.vworldToVpc);
+ }
+ }
+
+ canvas3d.drawingSurfaceObject.unLock();
+ }
+ } catch (NullPointerException ne) {
+ canvas3d.drawingSurfaceObject.unLock();
+ throw ne;
+ }
+ }
+
+ // Method to update compTransform.
+ private void computeCompositeTransform() {
+ ViewPlatform vp;
+
+ if ((canvas3d == null) ||
+ (canvas3d.view == null) ||
+ (((vp = canvas3d.view.getViewPlatform()) == null)) ||
+ (((ViewPlatformRetained)(vp.retained)) == null)) {
+ compTransform.set(modelTransform);
+ return;
+ }
+
+ ViewPlatformRetained vpR = (ViewPlatformRetained)vp.retained;
+ if ((vpR == null) || (vpR.locale == null)) {
+ compTransform.set(modelTransform);
+ return;
+ }
+
+ HiResCoord localeHiRes = vpR.locale.hiRes;
+
+ if (localeHiRes.equals(hiRes)) {
+ compTransform.set(modelTransform);
+ } else {
+ Transform3D trans = new Transform3D();
+ Vector3d localeTrans = new Vector3d();
+ localeHiRes.difference( hiRes, localeTrans );
+ trans.setTranslation( localeTrans );
+ compTransform.mul(trans, modelTransform);
+ }
+ }
+
+ // Method to update the view cache in pure immediate mode
+ private void updateViewCache(RenderBin rb) {
+
+ ViewPlatform vp = canvas3d.view.getViewPlatform();
+
+ if (vp == null)
+ return;
+
+ ViewPlatformRetained vpR = (ViewPlatformRetained)vp.retained;
+
+ if (!canvas3d.isRunning) {
+ // in pure immediate mode, notify platform transform change
+ vpR.evaluateInitViewPlatformTransform();
+ }
+
+
+ // rb.setVworldToVpc(vp.getVworldToVpc());
+ // rb.setVpcToVworld(vp.getVpcToVworld());
+
+ // XXXX: Fix this
+ rb.vpcToVworld = vpR.getVpcToVworld();
+ rb.vworldToVpc = vpR.getVworldToVpc();
+
+ canvas3d.updateViewCache(true, null, null, false);
+ }
+
+ void doDraw(Geometry geometry) {
+
+ boolean useAlpha;
+ GeometryRetained drawGeo;
+ GeometryArrayRetained geoRetained = null;
+
+
+ if (!canvas3d.firstPaintCalled || !visible) {
+ return;
+ }
+
+ RenderBin rb = canvas3d.view.renderBin;
+
+ if (canvas3d.ctx == null) {
+ // Force an initial clear if one has not yet been done
+ doClear();
+ }
+
+
+ if (J3dDebug.devPhase && J3dDebug.debug) {
+ J3dDebug.doAssert(canvas3d.ctx != null, "canvas3d.ctx != null");
+ }
+
+ // We need to catch NullPointerException when the dsi
+ // gets yanked from us during a remove.
+ try {
+ if (canvas3d.drawingSurfaceObject.renderLock()) {
+
+ // Make the context current
+ canvas3d.makeCtxCurrent();
+
+ if ((dirtyMask & BUFFER_MODE) != 0) {
+ if (bufferOverride) {
+ canvas3d.setRenderMode(canvas3d.ctx, stereoMode,
+ canvas3d.useDoubleBuffer && !frontBufferRendering);
+ } else {
+ canvas3d.setRenderMode(canvas3d.ctx, Canvas3D.FIELD_ALL,
+ canvas3d.useDoubleBuffer);
+ }
+ dirtyMask &= ~BUFFER_MODE;
+ }
+
+ CanvasViewCache cvCache = canvas3d.canvasViewCache;
+
+// vpcToEc = cvCache.getLeftVpcToEc();
+ if (bufferOverride) {
+ switch(stereoMode) {
+ case STEREO_RIGHT:
+ vpcToEc = cvCache.getRightVpcToEc();
+ // XXXX: move this under check for
+ // (dirtyMask & BUFFER_MODE) above after testing
+ // PureImmediate mode
+ canvas3d.setProjectionMatrix(canvas3d.ctx,
+ cvCache.getRightProjection());
+ break;
+ case STEREO_LEFT:
+ case STEREO_BOTH:
+ default:
+ vpcToEc = cvCache.getLeftVpcToEc();
+ // XXXX: move this under check for
+ // (dirtyMask & BUFFER_MODE) above after testing
+ // PureImmediate mode
+ canvas3d.setProjectionMatrix(canvas3d.ctx,
+ cvCache.getLeftProjection());
+ }
+ }
+ else if (!canvas3d.isRunning ||
+ // vpcToEc is not set in the first frame
+ // of preRender() callback
+ (canvas3d.vpcToEc == null)) {
+ vpcToEc = cvCache.getLeftVpcToEc();
+ }
+ else {
+ vpcToEc = canvas3d.vpcToEc;
+ }
+
+ // referred by RenderQueue.updateState
+ // canvas3d.screen.renderer.vpcToEc = vpcToEc;
+ // rb.updateState(canvas3d.screen.renderer.rId, ro, canvas3d, true);
+
+
+ // this.drawTransform.mul(rb.vworldToVpc,
+ // this.compTransform);
+
+ boolean isNonUniformScale = !drawTransform.isCongruent();
+
+ int geometryType = 0;
+ switch (((GeometryRetained)geometry.retained).geoType) {
+ case GeometryRetained.GEO_TYPE_POINT_SET:
+ case GeometryRetained.GEO_TYPE_INDEXED_POINT_SET:
+ geometryType = RenderMolecule.POINT;
+ break;
+ case GeometryRetained.GEO_TYPE_LINE_SET:
+ case GeometryRetained.GEO_TYPE_LINE_STRIP_SET:
+ case GeometryRetained.GEO_TYPE_INDEXED_LINE_SET:
+ case GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET:
+ geometryType = RenderMolecule.LINE;
+ break;
+ case GeometryRetained.GEO_TYPE_RASTER:
+ geometryType = RenderMolecule.RASTER;
+ break;
+ case GeometryRetained.GEO_TYPE_COMPRESSED:
+ geometryType = RenderMolecule.COMPRESSED;
+
+ switch (((CompressedGeometryRetained)geometry.retained).getBufferType()) {
+ case CompressedGeometryHeader.POINT_BUFFER:
+ geometryType |= RenderMolecule.POINT ;
+ break ;
+ case CompressedGeometryHeader.LINE_BUFFER:
+ geometryType |= RenderMolecule.LINE ;
+ break ;
+ default:
+ case CompressedGeometryHeader.TRIANGLE_BUFFER:
+ geometryType |= RenderMolecule.SURFACE ;
+ break ;
+ }
+ break;
+ default:
+ geometryType = RenderMolecule.SURFACE;
+ break;
+ }
+
+ useAlpha = updateState(rb, geometryType);
+
+ canvas3d.setModelViewMatrix(canvas3d.ctx,
+ vpcToEc.mat,
+ rb.vworldToVpc);
+ updateLightAndFog();
+
+ updateModelClip(rb.vworldToVpc);
+
+ this.drawTransform.mul(rb.vworldToVpc, this.compTransform);
+ canvas3d.setModelViewMatrix(canvas3d.ctx,
+ vpcToEc.mat, this.drawTransform);
+
+ if (geometry.retained instanceof GeometryArrayRetained) {
+ geoRetained = (GeometryArrayRetained)geometry.retained;
+
+ geoRetained.geomLock.getLock();
+ // If the geometry is by refernence, then see if we are using alpha
+ // and that there is no global alpha sun extension defined ..
+ if ((( geoRetained.vertexFormat & GeometryArray.BY_REFERENCE)!=0) &&
+ (geoRetained.c4fAllocated == 0) &&
+ ((geoRetained.vertexFormat & GeometryArray.COLOR) != 0) &&
+ useAlpha) {
+
+ if ((geoRetained.vertexFormat & GeometryArray.INTERLEAVED) != 0) {
+ geoRetained.setupMirrorInterleavedColorPointer(true);
+ }
+ else {
+ geoRetained.setupMirrorColorPointer((geoRetained.vertexType & GeometryArrayRetained.COLOR_DEFINED),true);
+ }
+ }
+
+ if ((geometry.retained instanceof IndexedGeometryArrayRetained) &&
+ ((((GeometryArrayRetained)geometry.retained).vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0)) {
+ if (geoRetained.dirtyFlag != 0) {
+ geoRetained.mirrorGeometry =
+ ((IndexedGeometryArrayRetained)geoRetained).cloneNonIndexedGeometry();
+ // Change the source geometry dirtyFlag
+ // drawGeo.execute() will change the
+ // destination geometry dirtyFlag only.
+ geoRetained.dirtyFlag = 0;
+ }
+ drawGeo = (GeometryRetained)geoRetained.mirrorGeometry;
+ } else {
+ drawGeo = geoRetained;
+ }
+
+ geoRetained.setVertexFormat(false, ignoreVertexColors, canvas3d.ctx );
+
+ } else if (geometry.retained instanceof Text3DRetained) {
+ ((Text3DRetained)geometry.retained).setModelViewMatrix(
+ vpcToEc, this.drawTransform);
+ drawGeo = (GeometryRetained)geometry.retained;
+ } else if (geometry.retained instanceof RasterRetained) {
+ ImageComponent2DRetained img = ((RasterRetained)geometry.retained).image;
+ if (img != null) {
+ if(img.isByReference()) {
+ img.geomLock.getLock();
+ img.evaluateExtensions(canvas3d);
+ img.geomLock.unLock();
+ } else {
+ img.evaluateExtensions(canvas3d);
+ }
+ }
+ drawGeo = (GeometryRetained)geometry.retained;
+ } else {
+ drawGeo = (GeometryRetained)geometry.retained;
+ }
+
+ drawGeo.execute(canvas3d, null, isNonUniformScale,
+ false, alpha,
+ canvas3d.screen.screen,
+ ignoreVertexColors);
+
+ if (geoRetained != null) {
+ geoRetained.geomLock.unLock();
+ }
+
+ canvas3d.drawingSurfaceObject.unLock();
+ }
+ } catch (NullPointerException ne) {
+ canvas3d.drawingSurfaceObject.unLock();
+ throw ne;
+ }
+ }
+
+ /**
+ * Draw the specified Geometry component object.
+ * @param geometry the Geometry object to draw.
+ *
+ * @exception IllegalSharingException if the specified geometry is a
+ * Raster that refers to an ImageComponent2D that is being used by a
+ * Canvas3D as an off-screen buffer.
+ */
+ public void draw(Geometry geometry) {
+ // do illegalSharing check
+ if((geometry != null) && (geometry instanceof Raster)) {
+ RasterRetained rasRetained = (RasterRetained) geometry.retained;
+ ImageComponent2D image = rasRetained.getImage();
+ if(image != null) {
+ ImageComponentRetained imageRetained = (ImageComponentRetained) image.retained;
+ // Do illegal sharing check
+ if(imageRetained.getUsedByOffScreen()) {
+ throw new IllegalSharingException(J3dI18N.getString("GraphicsContext3D32"));
+ }
+ }
+ }
+
+ if ((canvas3d.view == null) || (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active)) {
+ return;
+ } else if (Thread.currentThread() == canvas3d.screen.renderer) {
+ doDraw(geometry);
+ } else {
+ if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.DRAW,
+ geometry, null);
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.DRAW, geometry,
+ null);
+ }
+ }
+ }
+
+ /**
+ * Draw the specified Shape3D leaf node object. This is
+ * a convenience method that is identical to calling the
+ * setAppearance(Appearance) and draw(Geometry) methods
+ * passing the appearance and geometry component objects of
+ * the specified shape node as arguments.
+ *
+ * @param shape the Shape3D node containing the Appearance component
+ * object to set and Geometry component object to draw
+ *
+ * @exception IllegalSharingException if the Shape3D node
+ * is part of or is subsequently made part of a live scene graph.
+ *
+ * @exception IllegalSharingException if the Shape3D node's Appearance
+ * refers to an ImageComponent2D that is being used by a
+ * Canvas3D as an off-screen buffer.
+ */
+ public void draw(Shape3D shape) {
+ if (shape.isLive()) {
+ throw new IllegalSharingException(J3dI18N.getString("GraphicsContext3D26"));
+ }
+ ((Shape3DRetained)shape.retained).setInImmCtx(true);
+ setAppearance(shape.getAppearance());
+ draw(shape.getGeometry());
+ }
+
+ /**
+ * Read an image from the frame buffer and copy it into the
+ * ImageComponent and/or DepthComponent
+ * objects referenced by the specified Raster object.
+ * All parameters of the Raster object and the component ImageComponent
+ * and/or DepthComponentImage objects must be set to the desired values
+ * prior to calling this method. These values determine the location,
+ * size, and format of the pixel data that is read.
+ * This method calls <code>flush(true)</code> prior to reading the
+ * frame buffer.
+ *
+ * @param raster the Raster object used to read the
+ * contents of the frame buffer
+ *
+ * @exception IllegalArgumentException if the image class of the specified
+ * Raster's ImageComponent2D is <i>not</i> ImageClass.BUFFERED_IMAGE.
+ *
+ * @exception IllegalArgumentException if the specified Raster's
+ * ImageComponent2D is in by-reference mode and its
+ * RenderedImage is null.
+ *
+ * @exception IllegalArgumentException if the the Raster's
+ * ImageComponent2D format
+ * is <i>not</i> a 3-component format (e.g., FORMAT_RGB)
+ * or a 4-component format (e.g., FORMAT_RGBA).
+ *
+ * @exception IllegalSharingException if the Raster object is
+ * part of a live scene graph, or if the Raster's ImageComponent2D is
+ * part of a live scene graph.
+ *
+ * @exception IllegalSharingException if the Raster's ImageComponent2D is
+ * being used by an immediate mode context, or by a Canvas3D as
+ * an off-screen buffer.
+ *
+ * @see #flush
+ * @see ImageComponent
+ * @see DepthComponent
+ */
+ public void readRaster(Raster raster) {
+ if ((raster != null) && raster.isLive()) {
+ ImageComponent2D image = raster.getImage();
+ if (image != null){
+ ImageComponent2DRetained imageRetained = (ImageComponent2DRetained)image.retained;
+ if (image.getImageClass() != ImageComponent.ImageClass.BUFFERED_IMAGE) {
+ throw new IllegalArgumentException(J3dI18N.getString("GraphicsContext3D33"));
+ }
+ if (image.isByReference() && (image.getImage() == null)) {
+ throw new IllegalArgumentException(J3dI18N.getString("GraphicsContext3D34"));
+ }
+ if (imageRetained.getNumberOfComponents() < 3) {
+ throw new IllegalArgumentException(J3dI18N.getString("GraphicsContext3D35"));
+ }
+ if (image.isLive()) {
+ throw new IllegalSharingException(J3dI18N.getString("GraphicsContext3D36"));
+ }
+ if (imageRetained.getInImmCtx() || imageRetained.getUsedByOffScreen()) {
+ throw new IllegalSharingException(J3dI18N.getString("GraphicsContext3D37"));
+ }
+ }
+ }
+ if ((canvas3d.view == null) || (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active)) {
+ return;
+ } else if (Thread.currentThread() == canvas3d.screen.renderer) {
+ doReadRaster(raster);
+ } else if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ readRasterReady = false;
+ sendRenderMessage(false, GraphicsContext3D.READ_RASTER, raster, null);
+ while (!readRasterReady) {
+ MasterControl.threadYield();
+ }
+ } else {
+ // call from user thread
+ readRasterReady = false;
+ sendRenderMessage(true, GraphicsContext3D.READ_RASTER, raster, null);
+ while (!readRasterReady) {
+ MasterControl.threadYield();
+ }
+ }
+ }
+
+ void doReadRaster(Raster raster) {
+ if (!canvas3d.firstPaintCalled) {
+ readRasterReady = true;
+ return;
+ }
+
+ RasterRetained ras = (RasterRetained)raster.retained;
+ Dimension canvasSize = canvas3d.getSize();
+ Dimension rasterSize = new Dimension();
+ ImageComponent2DRetained image = ras.image;
+
+ int format = 0; // Not use in case of DepthComponent read
+
+ if (canvas3d.ctx == null) {
+ // Force an initial clear if one has not yet been done
+ doClear();
+ }
+
+ if (J3dDebug.devPhase && J3dDebug.debug) {
+ J3dDebug.doAssert(canvas3d.ctx != null, "canvas3d.ctx != null");
+ }
+
+ ras.getSize(rasterSize);
+ // allocate read buffer space
+ if ( (ras.type & Raster.RASTER_COLOR) != 0) {
+ if ((rasterSize.width > ras.image.width) ||
+ (rasterSize.height > ras.image.height)) {
+ throw new RuntimeException(J3dI18N.getString("GraphicsContext3D27"));
+ }
+ }
+
+ if ( (ras.type & Raster.RASTER_DEPTH) != 0) {
+ int size = ras.depthComponent.height * ras.depthComponent.width;
+ if (ras.depthComponent.type
+ == DepthComponentRetained.DEPTH_COMPONENT_TYPE_FLOAT) {
+ if (floatBuffer.length < size)
+ floatBuffer = new float[size];
+ } else { // type INT or NATIVE
+ if (intBuffer.length < size)
+ intBuffer = new int[size];
+ }
+ if ((rasterSize.width > ras.depthComponent.width) ||
+ (rasterSize.height > ras.depthComponent.height)) {
+ throw new RuntimeException(J3dI18N.getString("GraphicsContext3D28"));
+ }
+ }
+
+ if ( (ras.type & Raster.RASTER_COLOR) != 0) {
+
+ // If by reference, check if a copy needs to be made
+ // and also evaluate the storedFormat ..
+ if (image.isByReference()) {
+ image.geomLock.getLock();
+ image.evaluateExtensions(canvas3d);
+ image.geomLock.unLock();
+ } else {
+ // If image has a null buffer ( BufferedImage)
+ if (image.imageData == null) {
+ image.createBlankImageData();
+ }
+ // Check for possible format conversion in imageData
+ else {
+ // Format convert imageData if format is unsupported.
+ image.evaluateExtensions(canvas3d);
+ }
+ }
+ }
+
+ // We need to catch NullPointerException when the dsi
+ // gets yanked from us during a remove.
+ try {
+ if (canvas3d.drawingSurfaceObject.renderLock()) {
+ // Make the context current and read the raster information
+ canvas3d.makeCtxCurrent();
+ canvas3d.syncRender(canvas3d.ctx, true);
+ Point rasterSrcOffset = new Point();
+ ras.getSrcOffset(rasterSrcOffset);
+
+ int depthType = 0;
+ Object depthBuffer = null;
+ if (ras.depthComponent != null) {
+ depthType = ras.depthComponent.type;
+ if (depthType == DepthComponentRetained.DEPTH_COMPONENT_TYPE_FLOAT)
+ depthBuffer = floatBuffer;
+ else
+ depthBuffer = intBuffer;
+ }
+
+ int imageDataType = 0;
+ int imageFormatType = 0;
+ Object imageBuffer = null;
+
+ if ( (ras.type & Raster.RASTER_COLOR) != 0) {
+ imageDataType = image.getImageDataTypeIntValue();
+ imageFormatType = image.getImageFormatTypeIntValue(false);
+ imageBuffer = image.imageData.get();
+ }
+
+ Pipeline.getPipeline().readRaster(canvas3d.ctx,
+ ras.type, rasterSrcOffset.x, rasterSrcOffset.y,
+ rasterSize.width, rasterSize.height, canvasSize.height,
+ imageDataType,
+ imageFormatType,
+ imageBuffer,
+ depthType, depthBuffer);
+
+ canvas3d.drawingSurfaceObject.unLock();
+ }
+ } catch (NullPointerException ne) {
+ canvas3d.drawingSurfaceObject.unLock();
+ throw ne;
+ }
+
+ if ( (ras.type & Raster.RASTER_DEPTH) != 0) {
+ if (ras.depthComponent.type ==
+ DepthComponentRetained.DEPTH_COMPONENT_TYPE_FLOAT)
+ ((DepthComponentFloatRetained)ras.depthComponent).retrieveDepth(
+ floatBuffer, rasterSize.width, rasterSize.height);
+ else if (ras.depthComponent.type ==
+ DepthComponentRetained.DEPTH_COMPONENT_TYPE_INT)
+ ((DepthComponentIntRetained)ras.depthComponent).retrieveDepth(
+ intBuffer, rasterSize.width, rasterSize.height);
+ else if (ras.depthComponent.type ==
+ DepthComponentRetained.DEPTH_COMPONENT_TYPE_NATIVE)
+ ((DepthComponentNativeRetained)ras.depthComponent).retrieveDepth(
+ intBuffer, rasterSize.width, rasterSize.height);
+ }
+ readRasterReady = true;
+ }
+
+ /**
+ * Flushes all previously executed rendering operations to the
+ * drawing buffer for this 3D graphics context.
+ *
+ * @param wait flag indicating whether or not to wait for the
+ * rendering to be complete before returning from this call.
+ *
+ * @since Java 3D 1.2
+ */
+ public void flush(boolean wait) {
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ||
+ (!canvas3d.view.active) ||
+ (Thread.currentThread() == canvas3d.screen.renderer)) {
+ doFlush(wait);
+ } else {
+ Boolean waitArg = (wait ? Boolean.TRUE : Boolean.FALSE);
+
+ if (Thread.currentThread() ==
+ canvas3d.view.universe.behaviorScheduler) {
+ sendRenderMessage(false, GraphicsContext3D.FLUSH, waitArg,
+ null);
+ } else {
+ sendRenderMessage(true, GraphicsContext3D.FLUSH, waitArg,
+ null);
+ }
+ // Issue 131: AutomaticOffscreen canvases must be treated as onscreen ones.
+ if (wait && canvas3d.active && canvas3d.isRunningStatus &&
+ !canvas3d.manualRendering ) {
+ // No need to wait if renderer thread is not schedule
+ runMonitor(J3dThread.WAIT);
+ }
+ }
+ }
+
+ void doFlush(boolean wait) {
+ try {
+ if (canvas3d.drawingSurfaceObject.renderLock()) {
+ canvas3d.syncRender(canvas3d.ctx, wait);
+ canvas3d.drawingSurfaceObject.unLock();
+ if (wait) {
+ runMonitor(J3dThread.NOTIFY);
+ }
+ }
+ } catch (NullPointerException ne) {
+ canvas3d.drawingSurfaceObject.unLock();
+ throw ne;
+ }
+ }
+
+ void updateLightAndFog() {
+ int enableMask = 0;
+ int i;
+ sceneAmbient.x = 0.0f;
+ sceneAmbient.y = 0.0f;
+ sceneAmbient.z = 0.0f;
+
+ int n = 0;
+ int nLight = lights.size();;
+ for (i = 0; i < nLight;i++) {
+ LightRetained lt = (LightRetained)(lights.get(i)).retained;
+ if (lt instanceof AmbientLightRetained) {
+ sceneAmbient.x += lt.color.x;
+ sceneAmbient.y += lt.color.y;
+ sceneAmbient.z += lt.color.z;
+ continue;
+ }
+
+ lt.update(canvas3d.ctx, n,
+ canvas3d.canvasViewCache.getVworldToCoexistenceScale());
+ if (lt.lightOn)
+ enableMask |= (1 << n);
+ n++;
+ }
+ if (sceneAmbient.x > 1.0f) {
+ sceneAmbient.x = 1.0f;
+ }
+ if (sceneAmbient.y > 1.0f) {
+ sceneAmbient.y = 1.0f;
+ }
+ if (sceneAmbient.z > 1.0f) {
+ sceneAmbient.z = 1.0f;
+ }
+
+ canvas3d.setSceneAmbient(canvas3d.ctx, sceneAmbient.x,
+ sceneAmbient.y, sceneAmbient.z);
+
+ canvas3d.canvasDirty |= Canvas3D.AMBIENTLIGHT_DIRTY;
+ canvas3d.sceneAmbient.set(sceneAmbient);
+
+ if (canvas3d.enableMask != enableMask) {
+ canvas3d.canvasDirty |= Canvas3D.LIGHTENABLES_DIRTY;
+ // XXXX: 32 => renderBin.maxLights
+ canvas3d.setLightEnables(canvas3d.ctx, enableMask, 32);
+ canvas3d.enableMask = enableMask;
+ }
+
+ // Force LightBin.updateAttributes and EnvironmentSet.updateAttributes
+ // to use the within frame case.
+ canvas3d.lightBin = null;
+ canvas3d.environmentSet = null;
+
+ if (fog != null) {
+ if (fog.retained != canvas3d.fog) {
+ ((FogRetained)fog.retained).update(canvas3d.ctx,
+ canvas3d.canvasViewCache.getVworldToCoexistenceScale());
+ canvas3d.fog = (FogRetained) fog.retained;
+ canvas3d.canvasDirty |= Canvas3D.FOG_DIRTY;
+ }
+ } else { // Turn off fog
+ if (canvas3d.fog != null) {
+ canvas3d.setFogEnableFlag(canvas3d.ctx, false);
+ canvas3d.fog = null;
+ canvas3d.canvasDirty |= Canvas3D.FOG_DIRTY;
+ }
+ }
+ }
+
+ void updateModelClip(Transform3D vworldToVpc) {
+ if (modelClip != null) {
+ int enableMask = 0;
+ for (int i = 0; i < 6; i++) {
+ if (((ModelClipRetained)modelClip.retained).enables[i])
+ enableMask |= 1 << i;
+ }
+ // planes are already transformed to eye coordinates
+ // in immediate mode
+ if (enableMask != 0) {
+ this.drawTransform.mul(vworldToVpc, this.modelClipTransform);
+ canvas3d.setModelViewMatrix(canvas3d.ctx, vpcToEc.mat,
+ this.drawTransform);
+ }
+ ((ModelClipRetained)modelClip.retained).update(
+ canvas3d.ctx, enableMask,
+ this.drawTransform);
+ canvas3d.canvasDirty |= Canvas3D.MODELCLIP_DIRTY;
+ canvas3d.modelClip = (ModelClipRetained) modelClip.retained;
+ } else {
+ if (canvas3d.modelClip != null) {
+ canvas3d.disableModelClip(canvas3d.ctx);
+ canvas3d.modelClip = null;
+ canvas3d.canvasDirty |= Canvas3D.MODELCLIP_DIRTY;
+ }
+ }
+
+ // Force EnvironmentSet.updateAttributes to use the within frame case.
+ canvas3d.environmentSet = null;
+
+ }
+
+
+
+ boolean updateState(RenderBin rb, int geometryType) {
+
+ boolean useAlpha = false;
+ numActiveTexUnit = 0;
+ lastActiveTexUnitIndex = 0;
+
+ // Update Appearance
+ if (appearance != null) {
+ AppearanceRetained app = (AppearanceRetained) appearance.retained;
+
+ // If the material is not null then check if the one in the canvas
+ // is equivalent to the one being sent down. If Yes, do nothing
+ // Otherwise, cache the sent down material and mark the canvas
+ // dirty flag so that the compiled/compiled-retained rendering
+ // catches the change
+ // if material != null, we will need to load the material
+ // parameter again, because the apps could have changed
+ // the material parameter
+
+ if (app.material != null) {
+ app.material.updateNative(canvas3d.ctx,
+ red,green,blue,
+ alpha,enableLighting);
+ canvas3d.material = app.material;
+ canvas3d.canvasDirty |= Canvas3D.MATERIAL_DIRTY;
+ } else {
+ if (canvas3d.material != null) {
+ canvas3d.updateMaterial(canvas3d.ctx,
+ red, green, blue, alpha);
+ canvas3d.material = null;
+ canvas3d.canvasDirty |= Canvas3D.MATERIAL_DIRTY;
+ }
+ }
+
+ // Set flag indicating whether we are using shaders
+ boolean useShaders = false;
+ if (app instanceof ShaderAppearanceRetained) {
+ ShaderProgramRetained spR = ((ShaderAppearanceRetained)app).shaderProgram;
+ if ( spR != null) {
+ spR.updateNative(canvas3d, true);
+
+ ShaderAttributeSetRetained sasR =
+ ((ShaderAppearanceRetained)app).shaderAttributeSet;
+
+ if (sasR != null) {
+ sasR.updateNative(canvas3d, spR);
+ }
+
+ canvas3d.shaderProgram = spR;
+ useShaders = true;
+ }
+ }
+ else if (canvas3d.shaderProgram != null) {
+ canvas3d.shaderProgram.updateNative(canvas3d, false);
+ canvas3d.shaderProgram = null;
+ useShaders = false;
+ }
+
+ // Set the number of available texture units; this depends on
+ // whether or not shaders are being used.
+ int availableTextureUnits =
+ useShaders ? canvas3d.maxTextureImageUnits : canvas3d.maxTextureUnits;
+
+ int prevNumActiveTexUnit = canvas3d.getNumActiveTexUnit();
+
+ // Get the number of active texture units.
+ // Note that this total number now includes disabled units.
+ if (app.texUnitState != null) {
+ TextureUnitStateRetained tus;
+
+ for (int i = 0; i < app.texUnitState.length; i++) {
+ tus = app.texUnitState[i];
+ if (tus != null && tus.isTextureEnabled()) {
+ lastActiveTexUnitIndex = i;
+ numActiveTexUnit = i + 1;
+ if (tus.texAttrs != null) {
+ useAlpha = useAlpha ||
+ (tus.texAttrs.textureMode ==
+ TextureAttributes.BLEND);
+ }
+ }
+ }
+
+ if (numActiveTexUnit <= availableTextureUnits) {
+ // Normal, single-pass rendering case
+
+ // update all active texture unit states
+ for (int i = 0; i < app.texUnitState.length; i++) {
+ if (i >= availableTextureUnits) {
+ // This can happen if there are disabled units at
+ // the end of the array
+ break;
+ }
+
+ if ((app.texUnitState[i] != null) &&
+ app.texUnitState[i].isTextureEnabled()) {
+ app.texUnitState[i].updateNative(i, canvas3d,
+ false, false);
+ } else {
+ canvas3d.resetTexture(canvas3d.ctx, i);
+ }
+ }
+
+ // reset the remaining texture units
+ for (int i = app.texUnitState.length; i < prevNumActiveTexUnit; i++) {
+ canvas3d.resetTexture(canvas3d.ctx, i);
+ }
+
+ // set the number active texture unit in Canvas3D
+ canvas3d.setNumActiveTexUnit(numActiveTexUnit);
+
+ } else {
+ // Exceeded limit, disable all the texture units
+ for (int i = 0; i < prevNumActiveTexUnit; i++) {
+ canvas3d.resetTexture(canvas3d.ctx, i);
+ }
+ canvas3d.setNumActiveTexUnit(0);
+ }
+
+ // set the active texture unit back to 0
+ canvas3d.activeTextureUnit(canvas3d.ctx, 0);
+ } else {
+ // if texUnitState is null, let's disable
+ // all texture units first
+ if (canvas3d.multiTexAccelerated) {
+ if (canvas3d.texUnitState != null) {
+ for (int i = 0; i < prevNumActiveTexUnit; i++) {
+ TextureUnitStateRetained tur = canvas3d.texUnitState[i];
+ if ((tur != null) && (tur.texture != null)) {
+ canvas3d.resetTexture(canvas3d.ctx, i);
+ canvas3d.texUnitState[i].texture = null;
+ }
+ }
+ }
+
+ // set the active texture unit back to 0
+ canvas3d.activeTextureUnit(canvas3d.ctx, 0);
+ }
+
+ if ((canvas3d.texUnitState != null) &&
+ (canvas3d.texUnitState[0] != null) &&
+ (canvas3d.texUnitState[0].texture != app.texture)) {
+
+ // If the image is by reference, check if the image
+ // should be processed
+ if (app.texture != null) {
+ app.texture.updateNative(canvas3d);
+ canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY;
+ numActiveTexUnit = 1;
+ lastActiveTexUnitIndex = 0;
+ }
+ else {
+ numActiveTexUnit = 0;
+ canvas3d.resetTexture(canvas3d.ctx, -1);
+ canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY;
+ }
+
+ canvas3d.texUnitState[0].texture = app.texture;
+ }
+
+ // set the number active texture unit in Canvas3D
+ canvas3d.setNumActiveTexUnit(numActiveTexUnit);
+
+ if (app.texCoordGeneration != null) {
+ app.texCoordGeneration.updateNative(canvas3d);
+ canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY;
+ if ((canvas3d.texUnitState != null) &&
+ (canvas3d.texUnitState[0] != null)) {
+ canvas3d.texUnitState[0].texGen = app.texCoordGeneration;
+ }
+ }
+ else {
+ // If the canvas does not alreadt have a null texCoordGeneration
+ // load the default
+ if ((canvas3d.texUnitState != null) &&
+ (canvas3d.texUnitState[0] != null) &&
+ (canvas3d.texUnitState[0].texGen != null)) {
+ canvas3d.resetTexCoordGeneration(canvas3d.ctx);
+ canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY;
+ canvas3d.texUnitState[0].texGen = app.texCoordGeneration;
+ }
+ }
+
+
+ if (app.textureAttributes != null) {
+ if ((canvas3d.texUnitState != null) &&
+ (canvas3d.texUnitState[0] != null)) {
+
+ if (canvas3d.texUnitState[0].texture != null) {
+ app.textureAttributes.updateNative(canvas3d, false,
+ canvas3d.texUnitState[0].texture.format);
+ } else {
+ app.textureAttributes.updateNative(canvas3d, false,
+ Texture.RGBA);
+ }
+ canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY;
+ canvas3d.texUnitState[0].texAttrs =
+ app.textureAttributes;
+ }
+ }
+ else {
+ // If the canvas does not already have a null texAttribute
+ // load the default if necessary
+ if ((canvas3d.texUnitState != null) &&
+ (canvas3d.texUnitState[0] != null) &&
+ (canvas3d.texUnitState[0].texAttrs != null)) {
+ canvas3d.resetTextureAttributes(canvas3d.ctx);
+ canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY;
+ canvas3d.texUnitState[0].texAttrs = null;
+ }
+ }
+ }
+
+ if (app.coloringAttributes != null) {
+ app.coloringAttributes.updateNative(canvas3d.ctx,
+ dRed, dBlue,
+ dGreen,
+ alpha, enableLighting);
+ canvas3d.canvasDirty |= Canvas3D.COLORINGATTRS_DIRTY;
+ canvas3d.coloringAttributes = app.coloringAttributes;
+ }
+ else {
+ if (canvas3d.coloringAttributes != null) {
+ canvas3d.resetColoringAttributes(canvas3d.ctx,
+ red, green, blue, alpha,
+ enableLighting);
+ canvas3d.canvasDirty |= Canvas3D.COLORINGATTRS_DIRTY;
+ canvas3d.coloringAttributes = null;
+ }
+ }
+
+
+ if (app.transparencyAttributes != null) {
+ app.transparencyAttributes.updateNative(canvas3d.ctx,
+ alpha, geometryType,
+ polygonMode,
+ lineAA, pointAA);
+ canvas3d.canvasDirty |= Canvas3D.TRANSPARENCYATTRS_DIRTY;
+ canvas3d.transparency = app.transparencyAttributes;
+
+ if (!useAlpha)
+ useAlpha = TransparencyAttributesRetained.useAlpha(app.transparencyAttributes);
+
+ } else {
+ canvas3d.resetTransparency(canvas3d.ctx, geometryType,
+ polygonMode, lineAA, pointAA);
+ canvas3d.canvasDirty |= Canvas3D.TRANSPARENCYATTRS_DIRTY;
+ canvas3d.transparency = null;
+ }
+
+
+ if (app.renderingAttributes != null) {
+ ignoreVertexColors =app.renderingAttributes.ignoreVertexColors;
+ app.renderingAttributes.updateNative(canvas3d,
+ canvas3d.depthBufferWriteEnableOverride,
+ canvas3d.depthBufferEnableOverride);
+ canvas3d.canvasDirty |= Canvas3D.ATTRIBUTEBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY;
+ canvas3d.renderingAttrs = app.renderingAttributes;
+
+ useAlpha = useAlpha ||
+ (app.renderingAttributes.alphaTestFunction
+ != RenderingAttributes.ALWAYS);
+ } else {
+ // If the canvas does not alreadt have a null renderingAttrs
+ // load the default
+ ignoreVertexColors = false;
+ if (canvas3d.renderingAttrs != null) {
+ canvas3d.resetRenderingAttributes(canvas3d.ctx,
+ canvas3d.depthBufferWriteEnableOverride,
+ canvas3d.depthBufferEnableOverride);
+ canvas3d.canvasDirty |= Canvas3D.ATTRIBUTEBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY;
+ canvas3d.renderingAttrs = null;
+ }
+ }
+
+
+ if (app.polygonAttributes != null) {
+ app.polygonAttributes.updateNative(canvas3d.ctx);
+ canvas3d.canvasDirty |= Canvas3D.POLYGONATTRS_DIRTY;
+ canvas3d.polygonAttributes = app.polygonAttributes;
+ } else {
+ // If the canvas does not alreadt have a null polygonAttr
+ // load the default
+ if (canvas3d.polygonAttributes != null) {
+ canvas3d.resetPolygonAttributes(canvas3d.ctx);
+ canvas3d.canvasDirty |= Canvas3D.POLYGONATTRS_DIRTY;
+ canvas3d.polygonAttributes = null;
+ }
+ }
+
+
+
+ if (app.lineAttributes != null) {
+ app.lineAttributes.updateNative(canvas3d.ctx);
+ canvas3d.canvasDirty |= Canvas3D.LINEATTRS_DIRTY;
+ canvas3d.lineAttributes = app.lineAttributes;
+ } else {
+ // If the canvas does not already have a null lineAttr
+ // load the default
+ if (canvas3d.lineAttributes != null) {
+ canvas3d.resetLineAttributes(canvas3d.ctx);
+ canvas3d.canvasDirty |= Canvas3D.LINEATTRS_DIRTY;
+ canvas3d.lineAttributes = null;
+ }
+ }
+
+
+
+ if (app.pointAttributes != null) {
+ app.pointAttributes.updateNative(canvas3d.ctx);
+ canvas3d.canvasDirty |= Canvas3D.POINTATTRS_DIRTY;
+ canvas3d.pointAttributes = app.pointAttributes;
+ } else {
+ // If the canvas does not already have a null pointAttr
+ // load the default
+ if (canvas3d.pointAttributes != null) {
+ canvas3d.resetPointAttributes(canvas3d.ctx);
+ canvas3d.canvasDirty |= Canvas3D.POINTATTRS_DIRTY;
+ canvas3d.pointAttributes = null;
+ }
+ }
+
+ canvas3d.appearance = app;
+
+ } else {
+ if (canvas3d.appearance != null) {
+ resetAppearance();
+ canvas3d.appearance = null;
+ }
+ }
+
+
+ return (useAlpha );
+ }
+
+ void initializeState() {
+
+ canvas3d.setSceneAmbient(canvas3d.ctx, 0.0f, 0.0f, 0.0f);
+ canvas3d.disableFog(canvas3d.ctx);
+ canvas3d.resetRenderingAttributes(canvas3d.ctx,false, false);
+
+ if(canvas3d.shaderProgram != null) {
+ canvas3d.shaderProgram.updateNative(canvas3d, false);
+ canvas3d.shaderProgram = null;
+ }
+
+ // reset the previously enabled texture units
+
+ int prevNumActiveTexUnit = canvas3d.getNumActiveTexUnit();
+
+ if (prevNumActiveTexUnit > 0) {
+ for (int i = 0; i < prevNumActiveTexUnit; i++) {
+ if (canvas3d.texUnitState[i].texture != null) {
+ canvas3d.resetTexture(canvas3d.ctx, i);
+ canvas3d.texUnitState[i].texture = null;
+ }
+ if (canvas3d.texUnitState[i].texAttrs != null) {
+ canvas3d.resetTextureAttributes(canvas3d.ctx);
+ canvas3d.texUnitState[i].texAttrs = null;
+ }
+ if (canvas3d.texUnitState[i].texGen != null) {
+ canvas3d.resetTexCoordGeneration(canvas3d.ctx);
+ canvas3d.texUnitState[i].texGen = null;
+ }
+ canvas3d.texUnitState[i].mirror = null;
+ }
+ canvas3d.setNumActiveTexUnit(0);
+ }
+
+ canvas3d.resetPolygonAttributes(canvas3d.ctx);
+ canvas3d.resetLineAttributes(canvas3d.ctx);
+ canvas3d.resetPointAttributes(canvas3d.ctx);
+ canvas3d.resetTransparency(canvas3d.ctx, RenderMolecule.SURFACE,
+ PolygonAttributes.POLYGON_FILL,
+ false, false);
+ canvas3d.resetColoringAttributes(canvas3d.ctx,1.0f, 1.0f, 1.0f, 1.0f, false);
+ canvas3d.updateMaterial(canvas3d.ctx, 1.0f, 1.0f, 1.0f, 1.0f);
+ }
+
+
+ void resetAppearance() {
+ //System.err.println("GC3D.resetAppearance ....");
+
+ if (canvas3d.material != null) {
+ canvas3d.updateMaterial(canvas3d.ctx,
+ red, green, blue, alpha);
+ canvas3d.material = null;
+ canvas3d.canvasDirty |= Canvas3D.MATERIAL_DIRTY;
+ }
+
+ if(canvas3d.shaderProgram != null) {
+ canvas3d.shaderProgram.updateNative(canvas3d, false);
+ canvas3d.shaderProgram = null;
+ // ShaderBin doesn't use dirty bit.
+ }
+
+ // reset the previously enabled texture units
+ int prevNumActiveTexUnit = canvas3d.getNumActiveTexUnit();
+
+ if (prevNumActiveTexUnit > 0) {
+ for (int i = 0; i < prevNumActiveTexUnit; i++) {
+ if (canvas3d.texUnitState[i].texture != null) {
+ canvas3d.resetTexture(canvas3d.ctx, i);
+ canvas3d.texUnitState[i].texture = null;
+ }
+ if (canvas3d.texUnitState[i].texAttrs != null) {
+ canvas3d.resetTextureAttributes(canvas3d.ctx);
+ canvas3d.texUnitState[i].texAttrs = null;
+ }
+ if (canvas3d.texUnitState[i].texGen != null) {
+ canvas3d.resetTexCoordGeneration(canvas3d.ctx);
+ canvas3d.texUnitState[i].texGen = null;
+ }
+ canvas3d.texUnitState[i].mirror = null;
+ }
+ canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY;
+ canvas3d.setNumActiveTexUnit(0);
+ }
+
+ if (canvas3d.coloringAttributes != null) {
+ canvas3d.resetColoringAttributes(canvas3d.ctx,
+ red, green, blue, alpha, enableLighting);
+ canvas3d.coloringAttributes = null;
+ canvas3d.canvasDirty |= Canvas3D.COLORINGATTRS_DIRTY;
+ }
+
+ if (canvas3d.transparency != null) {
+ canvas3d.resetTransparency(canvas3d.ctx, RenderMolecule.SURFACE,
+ PolygonAttributes.POLYGON_FILL, lineAA, pointAA);
+ canvas3d.transparency = null;
+ canvas3d.canvasDirty |= Canvas3D.TRANSPARENCYATTRS_DIRTY;
+ }
+
+ if (canvas3d.renderingAttrs != null) {
+ ignoreVertexColors = false;
+ canvas3d.resetRenderingAttributes(canvas3d.ctx,
+ canvas3d.depthBufferWriteEnableOverride,
+ canvas3d.depthBufferEnableOverride);
+ canvas3d.renderingAttrs = null;
+ canvas3d.canvasDirty |= Canvas3D.ATTRIBUTEBIN_DIRTY|Canvas3D.TEXTUREATTRIBUTES_DIRTY;
+ }
+
+ if (canvas3d.polygonAttributes != null) {
+ canvas3d.resetPolygonAttributes(canvas3d.ctx);
+ canvas3d.polygonAttributes = null;
+ canvas3d.canvasDirty |= Canvas3D.POLYGONATTRS_DIRTY;
+ }
+
+ if (canvas3d.lineAttributes != null) {
+ canvas3d.resetLineAttributes(canvas3d.ctx);
+ canvas3d.lineAttributes = null;
+ canvas3d.canvasDirty |= Canvas3D.LINEATTRS_DIRTY;
+ }
+
+ if (canvas3d.pointAttributes != null) {
+ canvas3d.resetPointAttributes(canvas3d.ctx);
+ canvas3d.pointAttributes = null;
+ canvas3d.canvasDirty |= Canvas3D.POINTATTRS_DIRTY;
+ }
+ }
+
+ void sendRenderMessage(boolean renderRun, int command,
+ Object arg1, Object arg2) {
+
+ // send a message to the request renderer
+
+ J3dMessage renderMessage = new J3dMessage();
+ renderMessage.threads = J3dThread.RENDER_THREAD;
+ renderMessage.type = J3dMessage.RENDER_IMMEDIATE;
+ renderMessage.universe = null;
+ renderMessage.view = null;
+ renderMessage.args[0] = canvas3d;
+ renderMessage.args[1] = getImmCommand(command);
+ renderMessage.args[2] = arg1;
+ renderMessage.args[3] = arg2;
+
+ while (!canvas3d.view.inRenderThreadData) {
+ // wait until the renderer thread data in added in
+ // MC:RenderThreadData array ready to receive message
+ MasterControl.threadYield();
+ }
+
+ canvas3d.screen.renderer.rendererStructure.addMessage(renderMessage);
+
+ if (renderRun) {
+ // notify mc that there is work to do
+ VirtualUniverse.mc.sendRunMessage(canvas3d.view, J3dThread.RENDER_THREAD);
+ } else {
+ // notify mc that there is work for the request renderer
+ VirtualUniverse.mc.setWorkForRequestRenderer();
+ }
+ }
+
+ void sendSoundMessage(int command, Object arg1, Object arg2) {
+ if ((canvas3d.view == null) ||
+ (canvas3d.view.universe == null) ) {
+ return;
+ }
+ // send a message to the request sound scheduling
+ J3dMessage soundMessage = new J3dMessage();
+ soundMessage.threads = J3dThread.SOUND_SCHEDULER;
+ soundMessage.type = J3dMessage.RENDER_IMMEDIATE;
+ soundMessage.universe = canvas3d.view.universe;
+ soundMessage.view = canvas3d.view;
+ soundMessage.args[0] = getImmCommand(command);
+ soundMessage.args[1] = arg1;
+ soundMessage.args[2] = arg2;
+ // notify mc that there is work to do
+ VirtualUniverse.mc.processMessage(soundMessage);
+ }
+
+ static Integer getImmCommand(int command) {
+ if (commands[command] == null) {
+ commands[command] = new Integer(command);
+ }
+ return commands[command];
+ }
+
+ synchronized void runMonitor(int action) {
+ if (action == J3dThread.WAIT) {
+ while (!gcReady) {
+ waiting++;
+ try {
+ wait();
+ } catch (InterruptedException e){}
+ waiting--;
+ }
+ gcReady = false;
+ } else {
+ gcReady = true;
+ if (waiting > 0) {
+ notify();
+ }
+ }
+ }
+
+}
+