/* * 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: * * *

* 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 * flush(boolean) * method to ensure that the rendering actually happens. The flush * method is implicitly called in the following cases: * *

* *

* 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 uLights = new Vector(); private HiResCoord uHiRes = new HiResCoord(); private Vector uSounds = new Vector(); 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 lights = new Vector(); // 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 sounds = new Vector(); // 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 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 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 * frontBufferRendering and stereoMode * 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 * bufferOverride flag is enabled. *

* 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 * bufferOverride flag is enabled. *

* *

* 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 STEREO_LEFT, * STEREO_RIGHT, or STEREO_BOTH. * * @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; jflush(true) 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 not 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 not 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(); } } } }