0001: /*
0002: * $RCSfile: GraphicsContext3D.java,v $
0003: *
0004: * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0006: *
0007: * This code is free software; you can redistribute it and/or modify it
0008: * under the terms of the GNU General Public License version 2 only, as
0009: * published by the Free Software Foundation. Sun designates this
0010: * particular file as subject to the "Classpath" exception as provided
0011: * by Sun in the LICENSE file that accompanied this code.
0012: *
0013: * This code is distributed in the hope that it will be useful, but WITHOUT
0014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0016: * version 2 for more details (a copy is included in the LICENSE file that
0017: * accompanied this code).
0018: *
0019: * You should have received a copy of the GNU General Public License version
0020: * 2 along with this work; if not, write to the Free Software Foundation,
0021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0022: *
0023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0024: * CA 95054 USA or visit www.sun.com if you need additional information or
0025: * have any questions.
0026: *
0027: * $Revision: 1.15 $
0028: * $Date: 2008/02/28 20:17:22 $
0029: * $State: Exp $
0030: */
0031:
0032: package javax.media.j3d;
0033:
0034: import java.awt.Point;
0035: import java.awt.image.BufferedImage;
0036: import javax.vecmath.*;
0037: import java.util.Vector;
0038: import java.util.Enumeration;
0039: import java.awt.Dimension;
0040:
0041: /**
0042: * A GraphicsContext3D object is used for immediate mode rendering into
0043: * a 3D canvas. It is created by, and associated with, a specific
0044: * Canvas3D object. A GraphicsContext3D defines methods to set 3D graphics
0045: * state and draw 3D geometric primitives. There are no public
0046: * constructors of GraphicsContext3D. An application obtains a 3D graphics
0047: * context object from the Canvas3D object that the application wishes
0048: * to render into by using the getGraphicsContext3D method. A new graphics
0049: * context is created if one does not already exist. A new GraphicsContext3D
0050: * initializes its state variables to the following defaults:
0051: * <UL>
0052: * <LI> Background object: null </LI>
0053: * <LI> Fog object: null </LI>
0054: * <LI> ModelClip object: null </LI>
0055: * <LI> Appearance object: null </LI>
0056: * <LI> List of Light objects: empty </LI>
0057: * <LI> high-res coordinate: (0, 0, 0) </LI>
0058: * <LI> modelTransform: identity </LI>
0059: * <LI> AuralAttributes object: null </LI>
0060: * <LI> List of Sound objects: empty </LI>
0061: * <LI> buffer override: false </LI>
0062: * <LI> front buffer rendering: false </LI>
0063: * <LI> stereo mode: <code>STEREO_BOTH</code> </LI>
0064: * </UL>
0065: *
0066: * <p>
0067: * Note that the drawing methods in this class are not necessarily
0068: * executed immediately. They may be buffered up for future
0069: * execution. Applications must call the
0070: * <code><a href="#flush(boolean)">flush</a>(boolean)</code>
0071: * method to ensure that the rendering actually happens. The flush
0072: * method is implicitly called in the following cases:
0073: *
0074: * <ul>
0075: * <li>The <code>readRaster</code> method calls
0076: * <code>flush(true)</code></li>
0077: * <li>The <code>Canvas3D.swap</code> method calls
0078: * <code>flush(true)</code></li>
0079: * <li>The Java 3D renderer calls <code>flush(true)</code> prior to
0080: * swapping the buffer for a double buffered on-screen Canvas3D</li>
0081: * <li>The Java 3D renderer calls <code>flush(true)</code> prior to
0082: * copying into the off-screen buffer of an off-screen Canvas3D</li>
0083: * <li>The Java 3D renderer calls <code>flush(false)</code> after
0084: * calling the preRender, renderField, postRender, and postSwap
0085: * Canvas3D callback methods.</li>
0086: * </ul>
0087: *
0088: * <p>
0089: * A single-buffered, pure-immediate mode application must explicitly
0090: * call flush to ensure that the graphics will be rendered to the
0091: * Canvas3D.
0092: *
0093: * @see Canvas3D#getGraphicsContext3D
0094: */
0095: public class GraphicsContext3D extends Object {
0096: /**
0097: * Specifies that rendering is done to the left eye.
0098: * @see #setStereoMode
0099: * @since Java 3D 1.2
0100: */
0101: public static final int STEREO_LEFT = 0;
0102:
0103: /**
0104: * Specifies that rendering is done to the right eye.
0105: * @see #setStereoMode
0106: * @since Java 3D 1.2
0107: */
0108: public static final int STEREO_RIGHT = 1;
0109:
0110: /**
0111: * Specifies that rendering is done to both eyes. This is the
0112: * default.
0113: * @see #setStereoMode
0114: * @since Java 3D 1.2
0115: */
0116: public static final int STEREO_BOTH = 2;
0117:
0118: /**
0119: * Canvas3D in which this GraphicsContext3D will render.
0120: */
0121: Canvas3D canvas3d = null;
0122:
0123: //
0124: // Graphics state
0125: //
0126: // current user specified graphics state
0127: private Background uBackground = null;
0128: private Fog uFog = null;
0129: private Appearance uAppearance = null;
0130: private Vector uLights = new Vector();
0131: private HiResCoord uHiRes = new HiResCoord();
0132: private Vector uSounds = new Vector();
0133: private AuralAttributes uAuralAttributes = null;
0134: private boolean uBufferOverride = false;
0135: private boolean uFrontBufferRendering = false;
0136: private int uStereoMode = STEREO_BOTH;
0137: private ModelClip uModelClip = null;
0138:
0139: // Current rendering graphics state
0140: // Current background
0141: Background background = null;
0142:
0143: // Background to use if background is null;
0144: BackgroundRetained black = new BackgroundRetained();
0145:
0146: // Current fog
0147: Fog fog = null;
0148:
0149: // Current modelClip
0150: ModelClip modelClip = null;
0151:
0152: // Current appearance object
0153: Appearance appearance = null;
0154:
0155: // default appearance retained object
0156: AppearanceRetained defaultAppearanceRetained = new AppearanceRetained();
0157:
0158: // The vector of lights
0159: Vector lights = new Vector();
0160:
0161: // Current High resolution coordinate
0162: HiResCoord hiRes = new HiResCoord();
0163:
0164: // Current modeling transform
0165: Transform3D modelTransform = new Transform3D();
0166: Transform3D identityTransform = new Transform3D();
0167:
0168: Transform3D modelClipTransform = null;
0169: Transform3D normalTransform = null;
0170: boolean normalTransformNeedToUpdate = true;
0171:
0172: // The vector of sounds
0173: Vector sounds = new Vector();
0174:
0175: // Current AuralAttributes state parameters
0176: AuralAttributes auralAttributes = null;
0177:
0178: // The render object associated with this context
0179: LightSet ls = null;
0180:
0181: // The current list of lights
0182: LightRetained[] lightlist = null;
0183:
0184: // Ambient lights
0185: Color3f sceneAmbient = new Color3f(0.0f, 0.0f, 0.0f);
0186:
0187: // The current number of lights, may be less than lightlist.length
0188: int numLights = 0;
0189:
0190: // Current composite transform: hi-res + modelTransform
0191: Transform3D compTransform = new Transform3D();
0192:
0193: // Draw transform: hi-res + modelTransform + view
0194: Transform3D drawTransform = new Transform3D();
0195:
0196: // The view transform (VPC to EC).
0197: // NOTE that this is *read-only*
0198: Transform3D vpcToEc;
0199:
0200: // A boolean that indicates the lights have changed
0201: boolean lightsChanged = false;
0202:
0203: // A boolean that indicates the sounds have changed
0204: // XXXX: the soundsChanged flag are set like lights methods set
0205: // lightsChanged? but where is this supposed to be check???
0206: // lightsChanged tested in 'draw'; but Sound are not processed
0207: // in draw.
0208: boolean soundsChanged = false;
0209:
0210: // Buffer override flag; enables frontBufferRendering and stereoMode
0211: // attributes.
0212: boolean bufferOverride = false;
0213:
0214: // Forces rendering to the front buffer (if bufferOverride is true)
0215: boolean frontBufferRendering = false;
0216:
0217: // Stereo mode for this buffer (if bufferOverride is true)
0218: int stereoMode = STEREO_BOTH;
0219:
0220: // Read Buffer for reading raster of color image
0221: byte[] byteBuffer = new byte[1];
0222:
0223: // Read Buffer for reading floating depth image
0224: float[] floatBuffer = new float[1];
0225:
0226: // Read Buffer for reading integer depth image
0227: int[] intBuffer = new int[1];
0228:
0229: /**
0230: * The cached ColoringAttributes color value. It is
0231: * 1.0, 1.0, 1.0 if there is no ColoringAttributes.
0232: */
0233: float red = 1.0f;
0234: float green = 1.0f;
0235: float blue = 1.0f;
0236:
0237: /**
0238: * Cached diffuse color value
0239: */
0240: float dRed = 1.0f;
0241: float dGreen = 1.0f;
0242: float dBlue = 1.0f;
0243:
0244: /**
0245: * The cached TransparencyAttributes transparency value. It is
0246: * 0.0 if there is no TransparencyAttributes.
0247: */
0248: float alpha = 0.0f;
0249:
0250: /**
0251: * The cached visible flag for geometry.
0252: */
0253: boolean visible = true;
0254:
0255: /**
0256: * Cached values for polygonMode, line antialiasing, and point antialiasing
0257: */
0258: int polygonMode = PolygonAttributes.POLYGON_FILL;
0259: boolean lineAA = false;
0260: boolean pointAA = false;
0261:
0262: /**
0263: /**
0264: * A boolean indicating whether or not lighting should be on.
0265: */
0266: boolean enableLighting = false;
0267:
0268: private Appearance defaultAppearance = null;
0269:
0270: private boolean geometryIsLocked = false;
0271:
0272: private boolean ignoreVertexColors = false;
0273:
0274: static final int CLEAR = 0;
0275: static final int DRAW = 1;
0276: static final int SWAP = 2;
0277: static final int READ_RASTER = 3;
0278: static final int SET_APPEARANCE = 4;
0279: static final int SET_BACKGROUND = 5;
0280: static final int SET_FOG = 6;
0281: static final int SET_LIGHT = 7;
0282: static final int INSERT_LIGHT = 8;
0283: static final int REMOVE_LIGHT = 9;
0284: static final int ADD_LIGHT = 10;
0285: static final int SET_HI_RES = 11;
0286: static final int SET_MODEL_TRANSFORM = 12;
0287: static final int MULTIPLY_MODEL_TRANSFORM = 13;
0288: static final int SET_SOUND = 14;
0289: static final int INSERT_SOUND = 15;
0290: static final int REMOVE_SOUND = 16;
0291: static final int ADD_SOUND = 17;
0292: static final int SET_AURAL_ATTRIBUTES = 18;
0293: static final int SET_BUFFER_OVERRIDE = 19;
0294: static final int SET_FRONT_BUFFER_RENDERING = 20;
0295: static final int SET_STEREO_MODE = 21;
0296: static final int FLUSH = 22;
0297: static final int FLUSH2D = 23;
0298: static final int DRAWANDFLUSH2D = 24;
0299: static final int SET_MODELCLIP = 25;
0300: static final int DISPOSE2D = 26;
0301: static final int NCOMMANDS = 27; // needs to be incremented
0302: // when a new command is to be
0303: // added to the list
0304:
0305: private static Integer[] commands = new Integer[NCOMMANDS];
0306: private static Integer[] stereoModes = { new Integer(STEREO_LEFT),
0307: new Integer(STEREO_RIGHT), new Integer(STEREO_BOTH) };
0308:
0309: // dirty bits
0310: private static final int BUFFER_MODE = 0x1;
0311: private int dirtyMask = 0;
0312:
0313: // multi-texture
0314: private int numActiveTexUnit = 0;
0315: private int lastActiveTexUnitIndex = 0;
0316:
0317: // for read raster
0318: private volatile boolean readRasterReady = false;
0319:
0320: // for runMonitor
0321: private boolean gcReady = false;
0322: private int waiting = 0;
0323:
0324: /**
0325: * Constructs and creates a GraphicsContext3D object with default
0326: * values. Users do not call this directly, rather they get a
0327: * graphics context from a Canvas3D.
0328: */
0329: GraphicsContext3D(Canvas3D canvas3d) {
0330: this .canvas3d = canvas3d;
0331: }
0332:
0333: /**
0334: * Gets the Canvas3D that created this GraphicsContext3D.
0335: * @return the Canvas3D that created this GraphicsContext3D
0336: */
0337: public Canvas3D getCanvas3D() {
0338: return this .canvas3d;
0339: }
0340:
0341: //
0342: // Methods to set/get graphics state
0343: //
0344:
0345: /**
0346: * Sets the current Appearance object to the specified
0347: * Appearance component object.
0348: * The graphics context stores a reference to the specified
0349: * Appearance object. This means that the application may modify
0350: * individual appearance attributes by using the appropriate
0351: * methods on the Appearance object.
0352: * If the Appearance object is null, default values will be used
0353: * for all appearance attributes - it is as if an
0354: * Appearance node were created using the default constructor.
0355: *
0356: * @param appearance the new Appearance object
0357: *
0358: * @exception IllegalSharingException if the specified appearance refers
0359: * to an ImageComponent2D that is being used by a Canvas3D as
0360: * an off-screen buffer.
0361: */
0362: public void setAppearance(Appearance appearance) {
0363:
0364: if (appearance == null) {
0365: if (defaultAppearance == null) {
0366: defaultAppearance = new Appearance();
0367: }
0368: appearance = defaultAppearance;
0369: } else {
0370: // Check whether any ImageComponent2D referred to by
0371: // the new appearance is being used as an off-screen buffer and throw
0372: // IllegalSharingException if it is.
0373: TextureRetained texRetained;
0374: ImageComponent[] images;
0375: AppearanceRetained appRetained = (AppearanceRetained) appearance.retained;
0376: if (appRetained.texture != null) {
0377: assert (appRetained.texUnitState == null);
0378: texRetained = appRetained.texture;
0379: images = texRetained.getImages();
0380: if (images != null) {
0381: for (int i = 0; i < images.length; i++) {
0382: if (images[i] != null) {
0383: ImageComponentRetained imageRetained = (ImageComponentRetained) images[i].retained;
0384: // Do illegal sharing check
0385: if (imageRetained.getUsedByOffScreen()) {
0386: throw new IllegalSharingException(
0387: J3dI18N
0388: .getString("GraphicsContext3D30"));
0389: }
0390: }
0391: }
0392: }
0393: } else if (appRetained.texUnitState != null) {
0394: for (int j = 0; j < appRetained.texUnitState.length; j++) {
0395: texRetained = appRetained.texUnitState[j].texture;
0396: images = texRetained.getImages();
0397: if (images != null) {
0398: for (int i = 0; i < images.length; i++) {
0399: if (images[i] != null) {
0400: ImageComponentRetained imageRetained = (ImageComponentRetained) images[i].retained;
0401: // Do illegal sharing check
0402: if (imageRetained.getUsedByOffScreen()) {
0403: throw new IllegalSharingException(
0404: J3dI18N
0405: .getString("GraphicsContext3D30"));
0406: }
0407: }
0408: }
0409: }
0410: }
0411: }
0412: }
0413:
0414: uAppearance = appearance;
0415: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
0416: || (!canvas3d.view.active)
0417: || (Thread.currentThread() == canvas3d.screen.renderer)) {
0418: doSetAppearance(appearance);
0419: } else if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
0420: sendRenderMessage(false, GraphicsContext3D.SET_APPEARANCE,
0421: appearance, null);
0422: } else {
0423: sendRenderMessage(true, GraphicsContext3D.SET_APPEARANCE,
0424: appearance, null);
0425: }
0426: }
0427:
0428: void doSetAppearance(Appearance appearance) {
0429: // Appearance can't be null. See setAppearance().
0430: assert (appearance != null);
0431:
0432: NodeComponentRetained nc;
0433: nc = ((AppearanceRetained) appearance.retained).material;
0434: if (nc != null) {
0435: nc.setInImmCtx(true);
0436: enableLighting = ((MaterialRetained) nc).lightingEnable;
0437: dRed = ((MaterialRetained) nc).diffuseColor.x;
0438: dGreen = ((MaterialRetained) nc).diffuseColor.y;
0439: dBlue = ((MaterialRetained) nc).diffuseColor.z;
0440: } else {
0441: enableLighting = false;
0442: }
0443:
0444: if (appearance instanceof ShaderAppearance) {
0445: // Handle ShaderProgramRetained.
0446: ShaderProgramRetained spR = ((ShaderAppearanceRetained) appearance.retained).shaderProgram;
0447: if (spR != null) {
0448: spR.setInImmCtx(true);
0449: Shader[] sArray = spR.getShaders();
0450: if (sArray != null) {
0451: for (int i = 0; i < sArray.length; i++) {
0452: if (sArray[i] != null) {
0453: ((ShaderRetained) sArray[i].retained)
0454: .setInImmCtx(true);
0455: }
0456: }
0457: }
0458: }
0459:
0460: //Handle ShaderAttributeSetRetained.
0461: ShaderAttributeSetRetained sasR = ((ShaderAppearanceRetained) appearance.retained).shaderAttributeSet;
0462: if (sasR != null) {
0463: sasR.setInImmCtx(true);
0464: ShaderAttribute[] saArray = sasR.getAll();
0465: if (saArray != null) {
0466: for (int i = 0; i < saArray.length; i++) {
0467: if (saArray[i] != null) {
0468: ((ShaderAttributeRetained) saArray[i].retained)
0469: .setInImmCtx(true);
0470: }
0471: }
0472: }
0473: }
0474: }
0475:
0476: if (((AppearanceRetained) appearance.retained).texUnitState != null) {
0477: TextureUnitStateRetained[] texUnitState = ((AppearanceRetained) appearance.retained).texUnitState;
0478:
0479: for (int i = 0; i < texUnitState.length; i++) {
0480: if (texUnitState[i] != null) {
0481: texUnitState[i].setInImmCtx(true);
0482: }
0483: }
0484: }
0485:
0486: nc = ((AppearanceRetained) appearance.retained).texture;
0487: if (nc != null) {
0488: nc.setInImmCtx(true);
0489: }
0490:
0491: nc = ((AppearanceRetained) appearance.retained).texCoordGeneration;
0492: if (nc != null) {
0493: nc.setInImmCtx(true);
0494: }
0495:
0496: nc = ((AppearanceRetained) appearance.retained).textureAttributes;
0497: if (nc != null) {
0498: nc.setInImmCtx(true);
0499: }
0500:
0501: nc = ((AppearanceRetained) appearance.retained).coloringAttributes;
0502: if (nc != null) {
0503: nc.setInImmCtx(true);
0504: red = ((ColoringAttributesRetained) nc).color.x;
0505: green = ((ColoringAttributesRetained) nc).color.y;
0506: blue = ((ColoringAttributesRetained) nc).color.z;
0507: } else {
0508: red = 1.0f;
0509: green = 1.0f;
0510: blue = 1.0f;
0511: }
0512:
0513: nc = ((AppearanceRetained) appearance.retained).transparencyAttributes;
0514: if (nc != null) {
0515: nc.setInImmCtx(true);
0516: alpha = 1.0f - ((TransparencyAttributesRetained) nc).transparency;
0517: } else {
0518: alpha = 1.0f;
0519: }
0520:
0521: nc = ((AppearanceRetained) appearance.retained).renderingAttributes;
0522: if (nc != null) {
0523: nc.setInImmCtx(true);
0524: visible = ((RenderingAttributesRetained) nc).visible;
0525: } else
0526: visible = true;
0527:
0528: nc = ((AppearanceRetained) appearance.retained).polygonAttributes;
0529: if (nc != null) {
0530: nc.setInImmCtx(true);
0531: polygonMode = ((PolygonAttributesRetained) nc).polygonMode;
0532: } else {
0533: polygonMode = PolygonAttributes.POLYGON_FILL;
0534: }
0535:
0536: nc = ((AppearanceRetained) appearance.retained).lineAttributes;
0537: if (nc != null) {
0538: nc.setInImmCtx(true);
0539: lineAA = ((LineAttributesRetained) nc).lineAntialiasing;
0540:
0541: } else {
0542: lineAA = false;
0543: }
0544:
0545: nc = ((AppearanceRetained) appearance.retained).pointAttributes;
0546: if (nc != null) {
0547: if (nc.source.isLive())
0548: nc.setInImmCtx(true);
0549: pointAA = ((PointAttributesRetained) nc).pointAntialiasing;
0550: } else {
0551: pointAA = false;
0552: }
0553:
0554: // Reset the inImmCtx flag of this.appearance.
0555: if (this .appearance != null) {
0556: AppearanceRetained app = (AppearanceRetained) this .appearance.retained;
0557: app.setInImmCtx(false);
0558: if (app.material != null) {
0559: app.material.setInImmCtx(false);
0560: }
0561:
0562: if (app instanceof ShaderAppearanceRetained) {
0563: // Handle ShaderProgramRetained.
0564: ShaderProgramRetained spR = ((ShaderAppearanceRetained) app).shaderProgram;
0565: if (spR != null) {
0566: spR.setInImmCtx(false);
0567: Shader[] sArray = spR.getShaders();
0568: if (sArray != null) {
0569: for (int i = 0; i < sArray.length; i++) {
0570: if (sArray[i] != null) {
0571: ((ShaderRetained) sArray[i].retained)
0572: .setInImmCtx(false);
0573: }
0574: }
0575: }
0576: }
0577:
0578: //Handle ShaderAttributeSetRetained.
0579: ShaderAttributeSetRetained sasR = ((ShaderAppearanceRetained) app).shaderAttributeSet;
0580: if (sasR != null) {
0581: sasR.setInImmCtx(false);
0582: ShaderAttribute[] saArray = sasR.getAll();
0583: if (saArray != null) {
0584: for (int i = 0; i < saArray.length; i++) {
0585: if (saArray[i] != null) {
0586: ((ShaderAttributeRetained) saArray[i].retained)
0587: .setInImmCtx(false);
0588: }
0589: }
0590: }
0591: }
0592: }
0593:
0594: if (app.texUnitState != null) {
0595: for (int i = 0; i < app.texUnitState.length; i++) {
0596: if (app.texUnitState[0] != null)
0597: app.texUnitState[0].setInImmCtx(false);
0598: }
0599: }
0600: if (app.texture != null) {
0601: app.texture.setInImmCtx(false);
0602: }
0603: if (app.texCoordGeneration != null) {
0604: app.texCoordGeneration.setInImmCtx(false);
0605: }
0606: if (app.textureAttributes != null) {
0607: app.textureAttributes.setInImmCtx(false);
0608: }
0609: if (app.coloringAttributes != null) {
0610: app.coloringAttributes.setInImmCtx(false);
0611: }
0612: if (app.transparencyAttributes != null) {
0613: app.transparencyAttributes.setInImmCtx(false);
0614: }
0615: if (app.renderingAttributes != null) {
0616: app.renderingAttributes.setInImmCtx(false);
0617: }
0618: if (app.polygonAttributes != null) {
0619: app.polygonAttributes.setInImmCtx(false);
0620: }
0621: if (app.lineAttributes != null) {
0622: app.lineAttributes.setInImmCtx(false);
0623: }
0624: if (app.pointAttributes != null) {
0625: app.pointAttributes.setInImmCtx(false);
0626: }
0627: }
0628:
0629: ((AppearanceRetained) appearance.retained).setInImmCtx(true);
0630: this .appearance = appearance;
0631: }
0632:
0633: /**
0634: * Retrieves the current Appearance component object.
0635: * @return the current Appearance object
0636: */
0637: public Appearance getAppearance() {
0638: return this .uAppearance;
0639: }
0640:
0641: /**
0642: * Sets the current Background to the specified Background
0643: * leaf node object.
0644: * The graphics context stores a reference to the specified
0645: * Background node. This means that the application may modify
0646: * the background color or image by using the appropriate
0647: * methods on the Background node. The Background node must
0648: * not be part of a live scene graph, nor may it subsequently
0649: * be made part of a live scene graph-an IllegalSharingException
0650: * is thrown in such cases. If the Background object is null,
0651: * the default background color of black (0,0,0) is used to clear
0652: * the canvas prior to rendering a new frame. The Background
0653: * node's application region is ignored for immediate-mode
0654: * rendering.
0655: *
0656: * @param background the new Background object
0657: *
0658: * @exception IllegalSharingException if the Background node
0659: * is part of or is subsequently made part of a live scene graph.
0660: *
0661: * @exception IllegalSharingException if the specified background node
0662: * refers to an ImageComponent2D that is being used by a Canvas3D as
0663: * an off-screen buffer.
0664: */
0665: public void setBackground(Background background) {
0666:
0667: if (background.isLive()) {
0668: throw new IllegalSharingException(J3dI18N
0669: .getString("GraphicsContext3D11"));
0670: }
0671: BackgroundRetained bgRetained = (BackgroundRetained) background.retained;
0672: ImageComponent2D image = bgRetained.getImage();
0673: if (image != null) {
0674: ImageComponent2DRetained imageRetained = (ImageComponent2DRetained) image.retained;
0675: if (imageRetained.getUsedByOffScreen()) {
0676: throw new IllegalSharingException(J3dI18N
0677: .getString("GraphicsContext3D31"));
0678: }
0679: }
0680:
0681: if (((BackgroundRetained) background.retained).geometryBranch != null) {
0682: throw new IllegalSharingException(J3dI18N
0683: .getString("GraphicsContext3D22"));
0684: }
0685:
0686: uBackground = background;
0687: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
0688: || (!canvas3d.view.active)
0689: || (Thread.currentThread() == canvas3d.screen.renderer)) {
0690: doSetBackground(background);
0691: } else if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
0692: sendRenderMessage(false, GraphicsContext3D.SET_BACKGROUND,
0693: background, null);
0694: } else {
0695: sendRenderMessage(true, GraphicsContext3D.SET_BACKGROUND,
0696: background, null);
0697: }
0698: }
0699:
0700: void doSetBackground(Background background) {
0701: BackgroundRetained bg;
0702:
0703: if (this .background != null) {
0704: bg = (BackgroundRetained) this .background.retained;
0705: bg.setInImmCtx(false);
0706: }
0707: bg = (BackgroundRetained) background.retained;
0708: bg.setInImmCtx(true);
0709:
0710: this .background = background;
0711: }
0712:
0713: /**
0714: * Retrieves the current Background leaf node object.
0715: * @return the current Background object
0716: */
0717: public Background getBackground() {
0718: return this .uBackground;
0719: }
0720:
0721: /**
0722: * Sets the current Fog to the specified Fog
0723: * leaf node object.
0724: * The graphics context stores a reference to the specified
0725: * Fog node. This means that the application may modify the
0726: * fog attributes using the appropriate methods on the Fog
0727: * node object. The Fog node must not be part of a live
0728: * scene graph, nor may it subsequently be made part of a
0729: * live scene graph-an IllegalSharingException is thrown in
0730: * such cases. If the Fog object is null, fog is disabled.
0731: * Both the region of influence and the hierarchical scope
0732: * of the Fog node are ignored for immediate-mode rendering.
0733: * @param fog the new Fog object
0734: * @exception IllegalSharingException if the Fog node
0735: * is part of or is subsequently made part of a live scene graph.
0736: */
0737: public void setFog(Fog fog) {
0738: if (fog != null && fog.isLive()) {
0739: throw new IllegalSharingException(J3dI18N
0740: .getString("GraphicsContext3D12"));
0741: }
0742: uFog = fog;
0743: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
0744: || (!canvas3d.view.active)
0745: || (Thread.currentThread() == canvas3d.screen.renderer)) {
0746: doSetFog(fog);
0747: } else if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
0748: sendRenderMessage(false, GraphicsContext3D.SET_FOG, fog,
0749: null);
0750: } else {
0751: sendRenderMessage(true, GraphicsContext3D.SET_FOG, fog,
0752: null);
0753: }
0754: }
0755:
0756: void doSetFog(Fog fog) {
0757: if (this .fog != null) {
0758: ((FogRetained) this .fog.retained).setInImmCtx(false);
0759: }
0760: this .fog = fog;
0761: if (fog != null) {
0762: ((FogRetained) fog.retained).setInImmCtx(true);
0763:
0764: // Issue 144: updateFogState now called unconditionally
0765: updateFogState((FogRetained) fog.retained);
0766: }
0767: }
0768:
0769: /**
0770: * Retrieves the current Fog leaf node object.
0771: * @return the current Fog object
0772: */
0773: public Fog getFog() {
0774: return this .uFog;
0775: }
0776:
0777: /**
0778: * Sets the current ModelClip leaf node to the specified object.
0779: * The graphics context stores a reference to the specified
0780: * ModelClip node. This means that the application may modify the
0781: * model clipping attributes using the appropriate methods on the
0782: * ModelClip node object. The ModelClip node must not be part of a
0783: * live scene graph, nor may it subsequently be made part of a
0784: * live scene graph-an IllegalSharingException is thrown in such
0785: * cases. If the ModelClip object is null, model clipping is
0786: * disabled. Both the region of influence and the hierarchical
0787: * scope of the ModelClip node are ignored for immediate-mode
0788: * rendering.
0789: *
0790: * @param modelClip the new ModelClip node
0791: *
0792: * @exception IllegalSharingException if the ModelClip node
0793: * is part of or is subsequently made part of a live scene graph.
0794: *
0795: * @since Java 3D 1.2
0796: */
0797: public void setModelClip(ModelClip modelClip) {
0798: if ((modelClip != null) && modelClip.isLive()) {
0799: throw new IllegalSharingException(J3dI18N
0800: .getString("GraphicsContext3D25"));
0801: }
0802: uModelClip = modelClip;
0803: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
0804: || (!canvas3d.view.active)
0805: || (Thread.currentThread() == canvas3d.screen.renderer)) {
0806: doSetModelClip(modelClip);
0807: } else if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
0808: sendRenderMessage(false, GraphicsContext3D.SET_MODELCLIP,
0809: modelClip, null);
0810: } else {
0811: sendRenderMessage(true, GraphicsContext3D.SET_MODELCLIP,
0812: modelClip, null);
0813: }
0814: }
0815:
0816: void doSetModelClip(ModelClip modelClip) {
0817: ModelClipRetained mc = null;
0818:
0819: this .modelClip = modelClip;
0820:
0821: if (this .modelClip != null) {
0822: mc = (ModelClipRetained) this .modelClip.retained;
0823: mc.setInImmCtx(true);
0824:
0825: if (modelClipTransform == null)
0826: modelClipTransform = new Transform3D();
0827:
0828: // save the current model Transform
0829: modelClipTransform.set(compTransform);
0830: }
0831: }
0832:
0833: /**
0834: * Retrieves the current ModelClip leaf node object.
0835: * @return the current ModelClip object
0836: *
0837: * @since Java 3D 1.2
0838: */
0839: public ModelClip getModelClip() {
0840: return this .uModelClip;
0841: }
0842:
0843: /**
0844: * Replaces the specified light with the light provided.
0845: * The graphics context stores a reference to each light
0846: * object in the list of lights. This means that the
0847: * application may modify the light attributes for
0848: * any of the lights using the appropriate methods on that
0849: * Light node object. None of the Light nodes in the list
0850: * of lights may be part of a live scene graph, nor may
0851: * they subsequently be made part of a live scene graph -
0852: * an IllegalSharingException is thrown in such cases.
0853: * @param light the new light
0854: * @param index which light to replace
0855: * @exception IllegalSharingException if the Light node
0856: * is part of or is subsequently made part of a live scene graph.
0857: * @exception NullPointerException if the Light object is null.
0858: */
0859: public void setLight(Light light, int index) {
0860: if (light == null) {
0861: throw new NullPointerException(J3dI18N
0862: .getString("GraphicsContext3D13"));
0863: }
0864: if (light.isLive()) {
0865: throw new IllegalSharingException(J3dI18N
0866: .getString("GraphicsContext3D14"));
0867: }
0868: uLights.setElementAt(light, index);
0869: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
0870: || (!canvas3d.view.active)
0871: || (Thread.currentThread() == canvas3d.screen.renderer)) {
0872: doSetLight(light, index);
0873: } else if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
0874: sendRenderMessage(false, GraphicsContext3D.SET_LIGHT,
0875: light, new Integer(index));
0876: } else {
0877: sendRenderMessage(true, GraphicsContext3D.SET_LIGHT, light,
0878: new Integer(index));
0879: }
0880: }
0881:
0882: void doSetLight(Light light, int index) {
0883:
0884: Light oldlight;
0885: oldlight = (Light) this .lights.elementAt(index);
0886: if (oldlight != null) {
0887: ((LightRetained) oldlight.retained).setInImmCtx(false);
0888: }
0889: ((LightRetained) light.retained).setInImmCtx(true);
0890: updateLightState((LightRetained) light.retained);
0891: this .lights.setElementAt(light, index);
0892: this .lightsChanged = true;
0893: }
0894:
0895: /**
0896: * Inserts the specified light at the specified index location.
0897: * @param light the new light
0898: * @param index at which location to insert
0899: * @exception IllegalSharingException if the Light node
0900: * is part of or is subsequently made part of a live scene graph.
0901: * @exception NullPointerException if the Light object is null.
0902: */
0903: public void insertLight(Light light, int index) {
0904: if (light == null) {
0905: throw new NullPointerException(J3dI18N
0906: .getString("GraphicsContext3D13"));
0907: }
0908: if (light.isLive()) {
0909: throw new IllegalSharingException(J3dI18N
0910: .getString("GraphicsContext3D14"));
0911: }
0912: uLights.insertElementAt(light, index);
0913: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
0914: || (!canvas3d.view.active)
0915: || (Thread.currentThread() == canvas3d.screen.renderer)) {
0916: doInsertLight(light, index);
0917: } else if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
0918: sendRenderMessage(false, GraphicsContext3D.INSERT_LIGHT,
0919: light, new Integer(index));
0920: } else {
0921: sendRenderMessage(true, GraphicsContext3D.INSERT_LIGHT,
0922: light, new Integer(index));
0923: }
0924: }
0925:
0926: void doInsertLight(Light light, int index) {
0927: ((LightRetained) light.retained).setInImmCtx(true);
0928: updateLightState((LightRetained) light.retained);
0929: this .lights.insertElementAt(light, index);
0930: this .lightsChanged = true;
0931: }
0932:
0933: /**
0934: * Removes the light at the specified index location.
0935: * @param index which light to remove
0936: */
0937: public void removeLight(int index) {
0938: uLights.removeElementAt(index);
0939: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
0940: || (!canvas3d.view.active)
0941: || (Thread.currentThread() == canvas3d.screen.renderer)) {
0942: doRemoveLight(index);
0943: } else if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
0944: sendRenderMessage(false, GraphicsContext3D.REMOVE_LIGHT,
0945: new Integer(index), null);
0946: } else {
0947: sendRenderMessage(true, GraphicsContext3D.REMOVE_LIGHT,
0948: new Integer(index), null);
0949: }
0950: }
0951:
0952: void doRemoveLight(int index) {
0953: Light light = (Light) this .lights.elementAt(index);
0954:
0955: ((LightRetained) light.retained).setInImmCtx(false);
0956: this .lights.removeElementAt(index);
0957: this .lightsChanged = true;
0958: }
0959:
0960: /**
0961: * Retrieves the index selected light.
0962: * @param index which light to return
0963: * @return the light at location index
0964: */
0965: public Light getLight(int index) {
0966: return (Light) uLights.elementAt(index);
0967: }
0968:
0969: /**
0970: * Retrieves the enumeration object of all the lights.
0971: * @return the enumeration object of all the lights
0972: */
0973: public Enumeration getAllLights() {
0974: return uLights.elements();
0975: }
0976:
0977: /**
0978: * Appends the specified light to this graphics context's list of lights.
0979: * Adding a null Light object to the list will result
0980: * in a NullPointerException. Both the region of influence
0981: * and the hierarchical scope of all lights in the list
0982: * are ignored for immediate-mode rendering.
0983: * @param light the light to add
0984: * @exception IllegalSharingException if the Light node
0985: * is part of or is subsequently made part of a live scene graph.
0986: * @exception NullPointerException if the Light object is null.
0987: */
0988: public void addLight(Light light) {
0989: if (light == null) {
0990: throw new NullPointerException(J3dI18N
0991: .getString("GraphicsContext3D13"));
0992: }
0993:
0994: if (light.isLive()) {
0995: throw new IllegalSharingException(J3dI18N
0996: .getString("GraphicsContext3D14"));
0997: }
0998: uLights.addElement(light);
0999: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
1000: || (!canvas3d.view.active)
1001: || (Thread.currentThread() == canvas3d.screen.renderer)) {
1002: doAddLight(light);
1003: } else if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
1004: sendRenderMessage(false, GraphicsContext3D.ADD_LIGHT,
1005: light, null);
1006: } else {
1007: sendRenderMessage(true, GraphicsContext3D.ADD_LIGHT, light,
1008: null);
1009: }
1010: }
1011:
1012: void doAddLight(Light light) {
1013:
1014: ((LightRetained) light.retained).setInImmCtx(true);
1015: updateLightState((LightRetained) light.retained);
1016: this .lights.addElement(light);
1017: this .lightsChanged = true;
1018: }
1019:
1020: /**
1021: * Retrieves the current number of lights in this graphics context.
1022: * @return the current number of lights
1023: */
1024: public int numLights() {
1025: return this .uLights.size();
1026: }
1027:
1028: private Transform3D getNormalTransform() {
1029: if (compTransform.isRigid()) {
1030: return compTransform;
1031: }
1032: if (normalTransform == null) {
1033: normalTransform = new Transform3D();
1034: }
1035:
1036: if (normalTransformNeedToUpdate) {
1037: normalTransform.invert(compTransform);
1038: normalTransform.transpose();
1039: normalTransformNeedToUpdate = false;
1040: }
1041: return normalTransform;
1042: }
1043:
1044: void updateFogState(FogRetained fogRet) {
1045: // Issue 144: update localToVWorldScale for all types of Fog
1046: fogRet.setLocalToVworldScale(modelTransform.getDistanceScale());
1047: }
1048:
1049: void updateLightState(LightRetained light) {
1050:
1051: if (light instanceof DirectionalLightRetained) {
1052: DirectionalLightRetained dl = (DirectionalLightRetained) light;
1053:
1054: Transform3D xform = getNormalTransform();
1055: xform.transform(dl.direction, dl.xformDirection);
1056: dl.xformDirection.normalize();
1057:
1058: } else if (light instanceof SpotLightRetained) {
1059: SpotLightRetained sl = (SpotLightRetained) light;
1060:
1061: Transform3D xform = getNormalTransform();
1062: xform.transform(sl.direction, sl.xformDirection);
1063: sl.xformDirection.normalize();
1064: this .modelTransform
1065: .transform(sl.position, sl.xformPosition);
1066:
1067: } else if (light instanceof PointLightRetained) {
1068: PointLightRetained pl = (PointLightRetained) light;
1069:
1070: this .modelTransform
1071: .transform(pl.position, pl.xformPosition);
1072:
1073: pl.localToVworldScale = modelTransform.getDistanceScale();
1074:
1075: }
1076: }
1077:
1078: /**
1079: * Sets the HiRes coordinate of this context to the location
1080: * specified by the parameters provided.
1081: * The parameters x, y, and z are arrays of eight 32-bit
1082: * integers that specify the high-resolution coordinates point.
1083: * @param x an eight element array specifying the x position
1084: * @param y an eight element array specifying the y position
1085: * @param z an eight element array specifying the z position
1086: * @see HiResCoord
1087: */
1088: public void setHiRes(int[] x, int[] y, int[] z) {
1089: HiResCoord hiRes = new HiResCoord(x, y, z);
1090: setHiRes(hiRes);
1091: }
1092:
1093: /**
1094: * Sets the HiRes coordinate of this context
1095: * to the location specified by the HiRes argument.
1096: * @param hiRes the HiRes coordinate specifying the a new location
1097: */
1098: public void setHiRes(HiResCoord hiRes) {
1099: uHiRes.setHiResCoord(hiRes);
1100: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
1101: || (!canvas3d.view.active)
1102: || (Thread.currentThread() == canvas3d.screen.renderer)) {
1103: doSetHiRes(hiRes);
1104: } else if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
1105: sendRenderMessage(false, GraphicsContext3D.SET_HI_RES,
1106: hiRes, null);
1107: } else {
1108: sendRenderMessage(true, GraphicsContext3D.SET_HI_RES,
1109: hiRes, null);
1110: }
1111: }
1112:
1113: void doSetHiRes(HiResCoord hiRes) {
1114: this .hiRes.setHiResCoord(hiRes);
1115: computeCompositeTransform();
1116: }
1117:
1118: /**
1119: * Retrieves the current HiRes coordinate of this context.
1120: * @param hiRes a HiResCoord object that will receive the
1121: * HiRes coordinate of this context
1122: */
1123: public void getHiRes(HiResCoord hiRes) {
1124: uHiRes.getHiResCoord(hiRes);
1125: }
1126:
1127: /**
1128: * Sets the current model transform to a copy of the specified
1129: * transform.
1130: * A BadTransformException is thrown if an attempt is made
1131: * to specify an illegal Transform3D.
1132: * @param t the new model transform
1133: * @exception BadTransformException if the transform is not affine.
1134: */
1135: public void setModelTransform(Transform3D t) {
1136:
1137: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
1138: || (!canvas3d.view.active)
1139: || (Thread.currentThread() == canvas3d.screen.renderer)) {
1140: doSetModelTransform(t);
1141: } else {
1142: Transform3D uModelTransform = new Transform3D(t);
1143: //Transform3D uModelTransform = t;
1144: if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
1145: sendRenderMessage(false,
1146: GraphicsContext3D.SET_MODEL_TRANSFORM,
1147: uModelTransform, null);
1148: } else {
1149: sendRenderMessage(true,
1150: GraphicsContext3D.SET_MODEL_TRANSFORM,
1151: uModelTransform, null);
1152: }
1153: }
1154: }
1155:
1156: void doSetModelTransform(Transform3D t) {
1157: this .modelTransform.set(t);
1158: computeCompositeTransform();
1159: normalTransformNeedToUpdate = true;
1160: }
1161:
1162: /**
1163: * Multiplies the current model transform by the specified
1164: * transform and stores the result back into the current
1165: * transform. The specified transformation must be affine.
1166: * @param t the model transform to be concatenated with the
1167: * current model transform
1168: * @exception BadTransformException if the transform is not affine.
1169: */
1170: public void multiplyModelTransform(Transform3D t) {
1171: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
1172: || (!canvas3d.view.active)
1173: || (Thread.currentThread() == canvas3d.screen.renderer)) {
1174: doMultiplyModelTransform(t);
1175: } else {
1176: Transform3D tt = new Transform3D(t);
1177: if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
1178: sendRenderMessage(false,
1179: GraphicsContext3D.MULTIPLY_MODEL_TRANSFORM, tt,
1180: null);
1181: } else {
1182: sendRenderMessage(true,
1183: GraphicsContext3D.MULTIPLY_MODEL_TRANSFORM, tt,
1184: null);
1185: }
1186: }
1187: }
1188:
1189: void doMultiplyModelTransform(Transform3D t) {
1190: this .modelTransform.mul(t);
1191: computeCompositeTransform();
1192: normalTransformNeedToUpdate = true;
1193: }
1194:
1195: /**
1196: * Retrieves the current model transform.
1197: * @param t the model transform that will receive the current
1198: * model transform
1199: */
1200: public void getModelTransform(Transform3D t) {
1201: t.set(modelTransform);
1202: }
1203:
1204: /**
1205: * Replaces the specified sound with the sound provided.
1206: * The graphics context stores a reference to each sound
1207: * object in the list of sounds. This means that the
1208: * application may modify the sound attributes for
1209: * any of the sounds by using the appropriate methods on
1210: * that Sound node object.
1211: * @param sound the new sound
1212: * @param index which sound to replace
1213: * @exception IllegalSharingException if the Sound node
1214: * is part of or is subsequently made part of a live scene graph.
1215: * @exception NullPointerException if the Sound object is null.
1216: */
1217: public void setSound(Sound sound, int index) {
1218: if (sound == null) {
1219: throw new NullPointerException(J3dI18N
1220: .getString("GraphicsContext3D17"));
1221: }
1222: if (sound.isLive()) {
1223: throw new IllegalSharingException(J3dI18N
1224: .getString("GraphicsContext3D23"));
1225: }
1226: uSounds.setElementAt(sound, index);
1227: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
1228: || (!canvas3d.view.active)
1229: || (Thread.currentThread() == canvas3d.screen.renderer)) {
1230: doSetSound(sound, index);
1231: } else if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
1232: sendRenderMessage(false, GraphicsContext3D.SET_SOUND,
1233: sound, new Integer(index));
1234: } else {
1235: sendRenderMessage(true, GraphicsContext3D.SET_SOUND, sound,
1236: new Integer(index));
1237: }
1238: }
1239:
1240: void doSetSound(Sound sound, int index) {
1241: Sound oldSound;
1242: oldSound = (Sound) (this .sounds.elementAt(index));
1243: ((SoundRetained) sound.retained).setInImmCtx(true);
1244: if (oldSound != null) {
1245: ((SoundRetained) oldSound.retained).setInImmCtx(false);
1246: }
1247: ((SoundRetained) sound.retained).setInImmCtx(true);
1248: updateSoundState((SoundRetained) (sound.retained));
1249: this .sounds.setElementAt(sound, index);
1250: this .soundsChanged = true;
1251:
1252: sendSoundMessage(GraphicsContext3D.SET_SOUND, sound, oldSound);
1253: }
1254:
1255: /**
1256: * Inserts the specified sound at the specified index location.
1257: * Inserting a sound to the list of sounds implicitly starts the
1258: * sound playing. Once a sound is finished playing, it can be
1259: * restarted by setting the sound's enable flag to true.
1260: * The scheduling region of all sounds in the list is ignored
1261: * for immediate-mode rendering.
1262: * @param sound the new sound
1263: * @param index at which location to insert
1264: * @exception IllegalSharingException if the Sound node
1265: * is part or is subsequently made part of a live scene graph.
1266: * @exception NullPointerException if the Sound object is null.
1267: */
1268: public void insertSound(Sound sound, int index) {
1269: if (sound == null) {
1270: throw new NullPointerException(J3dI18N
1271: .getString("GraphicsContext3D17"));
1272: }
1273:
1274: if (sound.isLive()) {
1275: throw new IllegalSharingException(J3dI18N
1276: .getString("GraphicsContext3D23"));
1277: }
1278: uSounds.insertElementAt(sound, index);
1279: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
1280: || (!canvas3d.view.active)
1281: || (Thread.currentThread() == canvas3d.screen.renderer)) {
1282: doInsertSound(sound, index);
1283: } else if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
1284: sendRenderMessage(false, GraphicsContext3D.INSERT_SOUND,
1285: sound, new Integer(index));
1286: } else {
1287: sendRenderMessage(true, GraphicsContext3D.INSERT_SOUND,
1288: sound, new Integer(index));
1289: }
1290: }
1291:
1292: void doInsertSound(Sound sound, int index) {
1293: updateSoundState((SoundRetained) sound.retained);
1294: this .sounds.insertElementAt(sound, index);
1295: this .soundsChanged = true;
1296: sendSoundMessage(GraphicsContext3D.INSERT_SOUND, sound, null);
1297: }
1298:
1299: /**
1300: * Removes the sound at the specified index location.
1301: * @param index which sound to remove
1302: */
1303: public void removeSound(int index) {
1304: uSounds.removeElementAt(index);
1305: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
1306: || (!canvas3d.view.active)
1307: || (Thread.currentThread() == canvas3d.screen.renderer)) {
1308: doRemoveSound(index);
1309: } else if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
1310: sendRenderMessage(false, GraphicsContext3D.REMOVE_SOUND,
1311: new Integer(index), null);
1312: } else {
1313: sendRenderMessage(true, GraphicsContext3D.REMOVE_SOUND,
1314: new Integer(index), null);
1315: }
1316: }
1317:
1318: void doRemoveSound(int index) {
1319: Sound sound = (Sound) (this .sounds.elementAt(index));
1320: SoundScheduler soundScheduler = getSoundScheduler();
1321: ((SoundRetained) (sound.retained)).setInImmCtx(false);
1322: this .sounds.removeElementAt(index);
1323: this .soundsChanged = true;
1324: // stop sound if playing on audioDevice
1325: sendSoundMessage(GraphicsContext3D.REMOVE_SOUND, null, sound);
1326: }
1327:
1328: /**
1329: * Retrieves the index selected sound.
1330: * @param index which sound to return
1331: * @return the sound at location index
1332: */
1333: public Sound getSound(int index) {
1334: Sound sound = (Sound) (uSounds.elementAt(index));
1335: return sound;
1336: }
1337:
1338: /**
1339: * Retrieves the enumeration object of all the sounds.
1340: * @return the enumeration object of all the sounds
1341: */
1342: public Enumeration getAllSounds() {
1343: return uSounds.elements();
1344: }
1345:
1346: /**
1347: * Appends the specified sound to this graphics context's list of sounds.
1348: * Adding a sound to the list of sounds implicitly starts the
1349: * sound playing. Once a sound is finished playing, it can be
1350: * restarted by setting the sound's enable flag to true.
1351: * The scheduling region of all sounds in the list is ignored
1352: * for immediate-mode rendering.
1353: * @param sound the sound to add
1354: * @exception IllegalSharingException if the Sound node
1355: * is part of or is subsequently made part of a live scene graph.
1356: * @exception NullPointerException if the Sound object is null.
1357: */
1358: public void addSound(Sound sound) {
1359: if (sound == null) {
1360: throw new NullPointerException(J3dI18N
1361: .getString("GraphicsContext3D17"));
1362: }
1363:
1364: if (sound.isLive()) {
1365: throw new IllegalSharingException(J3dI18N
1366: .getString("GraphicsContext3D23"));
1367:
1368: }
1369: uSounds.addElement(sound);
1370: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
1371: || (!canvas3d.view.active)
1372: || (Thread.currentThread() == canvas3d.screen.renderer)) {
1373: doAddSound(sound);
1374: } else if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
1375: sendRenderMessage(false, GraphicsContext3D.ADD_SOUND,
1376: sound, null);
1377: } else {
1378: sendRenderMessage(true, GraphicsContext3D.ADD_SOUND, sound,
1379: null);
1380: }
1381: }
1382:
1383: void doAddSound(Sound sound) {
1384: ((SoundRetained) (sound.retained)).setInImmCtx(true);
1385: updateSoundState((SoundRetained) (sound.retained));
1386: this .sounds.addElement(sound);
1387: this .soundsChanged = true;
1388: sendSoundMessage(GraphicsContext3D.ADD_SOUND, sound, null);
1389: }
1390:
1391: /**
1392: * Retrieves the current number of sounds in this graphics context.
1393: * @return the current number of sounds
1394: */
1395: public int numSounds() {
1396: return uSounds.size();
1397: }
1398:
1399: SoundScheduler getSoundScheduler() {
1400: if (canvas3d != null && canvas3d.view != null)
1401: return canvas3d.view.soundScheduler; // could be null as well
1402: else
1403: return (SoundScheduler) null;
1404: }
1405:
1406: void updateSoundState(SoundRetained sound) {
1407: View view = null;
1408: if (canvas3d != null)
1409: view = canvas3d.view;
1410: // Make sure that:
1411: // . Current view is not null
1412: // . The sound scheduler running (reference to it is not null)
1413: if (view != null) {
1414: SoundScheduler soundScheduler = getSoundScheduler();
1415: if (soundScheduler == null) {
1416: // XXXX: Re-implement
1417: // start up SoundScheduler since it hasn't already been started
1418: }
1419: }
1420:
1421: // Update sound fields related to transforms
1422: if (sound instanceof ConeSoundRetained) {
1423: ConeSoundRetained cs = (ConeSoundRetained) sound;
1424: this .modelTransform.transform(cs.direction,
1425: cs.xformDirection);
1426: cs.xformDirection.normalize();
1427: this .modelTransform
1428: .transform(cs.position, cs.xformPosition);
1429: // XXXX (Question) Is drawTranform equivalent to Vworld-to-Local?
1430: cs.trans.setWithLock(drawTransform);
1431:
1432: } else if (sound instanceof PointSoundRetained) {
1433: PointSoundRetained ps = (PointSoundRetained) sound;
1434: this .modelTransform
1435: .transform(ps.position, ps.xformPosition);
1436: // XXXX (Question) Is drawTranform equivalent to Vworld-to-Local?
1437: ps.trans.setWithLock(drawTransform);
1438: }
1439: }
1440:
1441: /**
1442: * Retrieves the sound playing flag.
1443: * @param index which sound
1444: * @return flag denoting if sound is currently playing
1445: */
1446: public boolean isSoundPlaying(int index) {
1447: Sound sound;
1448: // uSounds isPlaying field is NOT updated, sounds elements are used
1449: sound = (Sound) (this .sounds.elementAt(index));
1450: return sound.isPlaying();
1451: }
1452:
1453: /**
1454: * Sets the current AuralAttributes object to the specified
1455: * AuralAttributes component object.
1456: * This means that the application may modify individual
1457: * audio attributes by using the appropriate methods in
1458: * the Aural-Attributes object.
1459: * @param attributes the new AuralAttributes object
1460: */
1461: public void setAuralAttributes(AuralAttributes attributes) {
1462: uAuralAttributes = attributes;
1463:
1464: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
1465: || (!canvas3d.view.active)
1466: || (Thread.currentThread() == canvas3d.screen.renderer)) {
1467: doSetAuralAttributes(attributes);
1468: } else if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
1469: sendRenderMessage(false,
1470: GraphicsContext3D.SET_AURAL_ATTRIBUTES, attributes,
1471: null);
1472: } else {
1473: sendRenderMessage(true,
1474: GraphicsContext3D.SET_AURAL_ATTRIBUTES, attributes,
1475: null);
1476: }
1477: }
1478:
1479: void doSetAuralAttributes(AuralAttributes attributes) {
1480: this .auralAttributes = attributes;
1481: sendSoundMessage(GraphicsContext3D.SET_AURAL_ATTRIBUTES,
1482: attributes, null);
1483: }
1484:
1485: /**
1486: * Retrieves the current AuralAttributes component object.
1487: * @return the current AuralAttributes object
1488: */
1489: public AuralAttributes getAuralAttributes() {
1490: return uAuralAttributes;
1491: }
1492:
1493: /**
1494: * Sets a flag that specifies whether the double buffering and
1495: * stereo mode from the Canvas3D are overridden. When set to
1496: * true, this attribute enables the
1497: * <code>frontBufferRendering</code> and <code>stereoMode</code>
1498: * attributes.
1499: *
1500: * @param bufferOverride the new buffer override flag
1501: *
1502: * @see #setFrontBufferRendering
1503: * @see #setStereoMode
1504: *
1505: * @since Java 3D 1.2
1506: */
1507: public void setBufferOverride(boolean bufferOverride) {
1508: uBufferOverride = bufferOverride;
1509: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
1510: || (!canvas3d.view.active)
1511: || (Thread.currentThread() == canvas3d.screen.renderer)) {
1512: doSetBufferOverride(bufferOverride);
1513: } else if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
1514: sendRenderMessage(false,
1515: GraphicsContext3D.SET_BUFFER_OVERRIDE, new Boolean(
1516: bufferOverride), null);
1517: } else {
1518: sendRenderMessage(true,
1519: GraphicsContext3D.SET_BUFFER_OVERRIDE, new Boolean(
1520: bufferOverride), null);
1521: }
1522: }
1523:
1524: void doSetBufferOverride(boolean bufferOverride) {
1525: if (bufferOverride != this .bufferOverride) {
1526: this .bufferOverride = bufferOverride;
1527: dirtyMask |= BUFFER_MODE;
1528: }
1529: }
1530:
1531: /**
1532: * Returns the current buffer override flag.
1533: * @return true if buffer override is enabled; otherwise,
1534: * false is returned
1535: *
1536: * @since Java 3D 1.2
1537: */
1538: public boolean getBufferOverride() {
1539: return uBufferOverride;
1540: }
1541:
1542: /**
1543: * Sets a flag that enables or disables immediate mode rendering
1544: * into the front buffer of a double buffered Canvas3D.
1545: * This attribute is only used when the
1546: * <code>bufferOverride</code> flag is enabled.
1547: * <p>
1548: * Note that this attribute has no effect if double buffering
1549: * is disabled or is not available on the Canvas3D.
1550: *
1551: * @param frontBufferRendering the new front buffer rendering flag
1552: *
1553: * @see #setBufferOverride
1554: *
1555: * @since Java 3D 1.2
1556: */
1557: public void setFrontBufferRendering(boolean frontBufferRendering) {
1558: uFrontBufferRendering = frontBufferRendering;
1559: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
1560: || (!canvas3d.view.active)
1561: || (Thread.currentThread() == canvas3d.screen.renderer)) {
1562: doSetFrontBufferRendering(frontBufferRendering);
1563: } else if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
1564: sendRenderMessage(false,
1565: GraphicsContext3D.SET_FRONT_BUFFER_RENDERING,
1566: new Boolean(frontBufferRendering), null);
1567: } else {
1568: sendRenderMessage(true,
1569: GraphicsContext3D.SET_FRONT_BUFFER_RENDERING,
1570: new Boolean(frontBufferRendering), null);
1571: }
1572: }
1573:
1574: void doSetFrontBufferRendering(boolean frontBufferRendering) {
1575: if (frontBufferRendering != this .frontBufferRendering) {
1576: this .frontBufferRendering = frontBufferRendering;
1577: dirtyMask |= BUFFER_MODE;
1578: }
1579: }
1580:
1581: /**
1582: * Returns the current front buffer rendering flag.
1583: * @return true if front buffer rendering is enabled; otherwise,
1584: * false is returned
1585: *
1586: * @since Java 3D 1.2
1587: */
1588: public boolean getFrontBufferRendering() {
1589: return uFrontBufferRendering;
1590: }
1591:
1592: /**
1593: * Sets the stereo mode for immediate mode rendering. The
1594: * parameter specifies which stereo buffer or buffers is rendered
1595: * into. This attribute is only used when the
1596: * <code>bufferOverride</code> flag is enabled.
1597: * <ul>
1598: * <li>
1599: * <code>STEREO_LEFT</code> specifies that rendering is done into
1600: * the left eye.
1601: * </li>
1602: * <li>
1603: * <code>STEREO_RIGHT</code> specifies that rendering is done into
1604: * the right eye.
1605: * </li>
1606: * <li>
1607: * <code>STEREO_BOTH</code> specifies that rendering is done into
1608: * both eyes. This is the default.
1609: * </li>
1610: * </ul>
1611: *
1612: * <p>
1613: * Note that this attribute has no effect if stereo is disabled or
1614: * is not available on the Canvas3D.
1615: *
1616: * @param stereoMode the new stereo mode
1617: *
1618: * @see #setBufferOverride
1619: *
1620: * @since Java 3D 1.2
1621: */
1622: public void setStereoMode(int stereoMode) {
1623: uStereoMode = stereoMode;
1624: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
1625: || (!canvas3d.view.active)
1626: || (Thread.currentThread() == canvas3d.screen.renderer)) {
1627: doSetStereoMode(stereoMode);
1628: } else if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
1629: sendRenderMessage(false, GraphicsContext3D.SET_STEREO_MODE,
1630: stereoModes[stereoMode], null);
1631: } else {
1632: sendRenderMessage(true, GraphicsContext3D.SET_STEREO_MODE,
1633: stereoModes[stereoMode], null);
1634: }
1635: }
1636:
1637: void doSetStereoMode(int stereoMode) {
1638: if (stereoMode != this .stereoMode) {
1639: this .stereoMode = stereoMode;
1640: dirtyMask |= BUFFER_MODE;
1641: }
1642: }
1643:
1644: /**
1645: * Returns the current stereo mode.
1646: * @return the stereo mode, one of <code>STEREO_LEFT</code>,
1647: * <code>STEREO_RIGHT</code>, or <code>STEREO_BOTH</code>.
1648: *
1649: * @since Java 3D 1.2
1650: */
1651: public int getStereoMode() {
1652: return uStereoMode;
1653: }
1654:
1655: //
1656: // Methods to draw graphics objects
1657: //
1658:
1659: /**
1660: * Clear the Canvas3D to the color or image specified by the
1661: * current background node.
1662: */
1663: public void clear() {
1664: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
1665: || (!canvas3d.view.active)) {
1666: return;
1667: } else if (Thread.currentThread() == canvas3d.screen.renderer) {
1668: doClear();
1669: } else if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
1670: sendRenderMessage(false, GraphicsContext3D.CLEAR, null,
1671: null);
1672: } else {
1673: sendRenderMessage(true, GraphicsContext3D.CLEAR, null, null);
1674: }
1675: }
1676:
1677: void doClear() {
1678:
1679: if (!canvas3d.firstPaintCalled)
1680: return;
1681:
1682: RenderBin rb = canvas3d.view.renderBin;
1683: BackgroundRetained back = null;
1684:
1685: if (this .background != null)
1686: back = (BackgroundRetained) this .background.retained;
1687: else
1688: back = this .black;
1689:
1690: // XXXX: This should ideally be done by the renderer (or by the
1691: // canvas itself) when the canvas is first added to a view.
1692: /*
1693: if ((canvas3d.screen.renderer != null) &&
1694: (canvas3d.screen.renderer.renderBin == null))
1695: canvas3d.screen.renderer.renderBin = rb;
1696: */
1697: // If we are in pure immediate mode, update the view cache
1698: if (!canvas3d.isRunning)
1699: updateViewCache(rb);
1700:
1701: // We need to catch NullPointerException when the dsi
1702: // gets yanked from us during a remove.
1703:
1704: try {
1705: // Issue 78 - need to get the drawingSurface info every
1706: // frame; this is necessary since the HDC (window ID)
1707: // on Windows can become invalidated without our
1708: // being notified!
1709: if (!canvas3d.offScreen) {
1710: canvas3d.drawingSurfaceObject
1711: .getDrawingSurfaceObjectInfo();
1712: }
1713:
1714: if (canvas3d.drawingSurfaceObject.renderLock()) {
1715: // XXXX : Fix texture
1716: /*
1717: if (canvas3d.useSharedCtx) {
1718: if (canvas3d.screen.renderer.sharedCtx == 0) {
1719: synchronized (VirtualUniverse.mc.contextCreationLock) {
1720: canvas3d.screen.renderer.sharedCtx = canvas3d.createNewContext(
1721: canvas3d.screen.display,
1722: canvas3d.window, 0, true,
1723: canvas3d.offScreen);
1724: canvas3d.screen.renderer.sharedCtxTimeStamp =
1725: VirtualUniverse.mc.getContextTimeStamp();
1726: canvas3d.screen.renderer.needToRebuildDisplayList = true;
1727: }
1728: }
1729: }
1730: */
1731:
1732: if (canvas3d.ctx == null) {
1733: synchronized (VirtualUniverse.mc.contextCreationLock) {
1734: canvas3d.ctx = canvas3d.createNewContext(null,
1735: false);
1736: if (canvas3d.ctx == null) {
1737: canvas3d.drawingSurfaceObject.unLock();
1738: return;
1739: }
1740:
1741: canvas3d.ctxTimeStamp = VirtualUniverse.mc
1742: .getContextTimeStamp();
1743: canvas3d.screen.renderer.listOfCtxs
1744: .add(canvas3d.ctx);
1745: canvas3d.screen.renderer.listOfCanvases
1746: .add(canvas3d);
1747:
1748: canvas3d.beginScene();
1749:
1750: if (canvas3d.graphics2D != null) {
1751: canvas3d.graphics2D.init();
1752: }
1753:
1754: // enable separate specular color
1755: canvas3d.enableSeparateSpecularColor();
1756: }
1757:
1758: // create the cache texture state in canvas
1759: // for state download checking purpose
1760: if (canvas3d.texUnitState == null) {
1761: canvas3d.createTexUnitState();
1762: }
1763:
1764: canvas3d.drawingSurfaceObject.contextValidated();
1765: canvas3d.screen.renderer.currentCtx = canvas3d.ctx;
1766: canvas3d.screen.renderer.currentDrawable = canvas3d.drawable;
1767: initializeState();
1768: canvas3d.ctxChanged = true;
1769: canvas3d.canvasDirty = 0xffff;
1770: // Update Appearance
1771: updateState(rb, RenderMolecule.SURFACE);
1772:
1773: canvas3d.currentLights = new LightRetained[canvas3d
1774: .getNumCtxLights(canvas3d.ctx)];
1775:
1776: for (int j = 0; j < canvas3d.currentLights.length; j++) {
1777: canvas3d.currentLights[j] = null;
1778: }
1779: }
1780:
1781: canvas3d.makeCtxCurrent();
1782:
1783: if ((dirtyMask & BUFFER_MODE) != 0) {
1784: if (bufferOverride) {
1785: canvas3d.setRenderMode(canvas3d.ctx,
1786: stereoMode, canvas3d.useDoubleBuffer
1787: && !frontBufferRendering);
1788: } else {
1789: if (!canvas3d.isRunning) {
1790: canvas3d.setRenderMode(canvas3d.ctx,
1791: Canvas3D.FIELD_ALL,
1792: canvas3d.useDoubleBuffer);
1793: }
1794: }
1795: dirtyMask &= ~BUFFER_MODE;
1796: }
1797:
1798: Dimension size = canvas3d.getSize();
1799: int winWidth = size.width;
1800: int winHeight = size.height;
1801: boolean isByRefBackgroundImage = false;
1802: if (back.image != null) {
1803: if (back.image.isByReference()) {
1804: back.image.geomLock.getLock();
1805: isByRefBackgroundImage = true;
1806: }
1807:
1808: back.image.evaluateExtensions(canvas3d);
1809: }
1810:
1811: canvas3d.clear(back, winWidth, winHeight);
1812:
1813: if (isByRefBackgroundImage) {
1814: back.image.geomLock.unLock();
1815: }
1816:
1817: // Set the viewport and view matrices
1818: if (!canvas3d.isRunning) {
1819: CanvasViewCache cvCache = canvas3d.canvasViewCache;
1820: canvas3d.setViewport(canvas3d.ctx, 0, 0, cvCache
1821: .getCanvasWidth(), cvCache
1822: .getCanvasHeight());
1823: if (bufferOverride && (stereoMode == STEREO_RIGHT)) {
1824: canvas3d.setProjectionMatrix(canvas3d.ctx,
1825: cvCache.getRightProjection());
1826: canvas3d.setModelViewMatrix(canvas3d.ctx,
1827: cvCache.getRightVpcToEc().mat,
1828: rb.vworldToVpc);
1829: } else {
1830: canvas3d.setProjectionMatrix(canvas3d.ctx,
1831: cvCache.getLeftProjection());
1832: canvas3d.setModelViewMatrix(canvas3d.ctx,
1833: cvCache.getLeftVpcToEc().mat,
1834: rb.vworldToVpc);
1835: }
1836: }
1837:
1838: canvas3d.drawingSurfaceObject.unLock();
1839: }
1840: } catch (NullPointerException ne) {
1841: canvas3d.drawingSurfaceObject.unLock();
1842: throw ne;
1843: }
1844: }
1845:
1846: // Method to update compTransform.
1847: private void computeCompositeTransform() {
1848: ViewPlatform vp;
1849:
1850: if ((canvas3d == null) || (canvas3d.view == null)
1851: || (((vp = canvas3d.view.getViewPlatform()) == null))
1852: || (((ViewPlatformRetained) (vp.retained)) == null)) {
1853: compTransform.set(modelTransform);
1854: return;
1855: }
1856:
1857: ViewPlatformRetained vpR = (ViewPlatformRetained) vp.retained;
1858: if ((vpR == null) || (vpR.locale == null)) {
1859: compTransform.set(modelTransform);
1860: return;
1861: }
1862:
1863: HiResCoord localeHiRes = vpR.locale.hiRes;
1864:
1865: if (localeHiRes.equals(hiRes)) {
1866: compTransform.set(modelTransform);
1867: } else {
1868: Transform3D trans = new Transform3D();
1869: Vector3d localeTrans = new Vector3d();
1870: localeHiRes.difference(hiRes, localeTrans);
1871: trans.setTranslation(localeTrans);
1872: compTransform.mul(trans, modelTransform);
1873: }
1874: }
1875:
1876: // Method to update the view cache in pure immediate mode
1877: private void updateViewCache(RenderBin rb) {
1878:
1879: ViewPlatform vp = canvas3d.view.getViewPlatform();
1880:
1881: if (vp == null)
1882: return;
1883:
1884: ViewPlatformRetained vpR = (ViewPlatformRetained) vp.retained;
1885:
1886: if (!canvas3d.isRunning) {
1887: // in pure immediate mode, notify platform transform change
1888: vpR.evaluateInitViewPlatformTransform();
1889: }
1890:
1891: // rb.setVworldToVpc(vp.getVworldToVpc());
1892: // rb.setVpcToVworld(vp.getVpcToVworld());
1893:
1894: // XXXX: Fix this
1895: rb.vpcToVworld = vpR.getVpcToVworld();
1896: rb.vworldToVpc = vpR.getVworldToVpc();
1897:
1898: canvas3d.updateViewCache(true, null, null, false);
1899: }
1900:
1901: void doDraw(Geometry geometry) {
1902:
1903: boolean useAlpha;
1904: GeometryRetained drawGeo;
1905: GeometryArrayRetained geoRetained = null;
1906:
1907: if (!canvas3d.firstPaintCalled || !visible) {
1908: return;
1909: }
1910:
1911: RenderBin rb = canvas3d.view.renderBin;
1912: int i, nlights, activeLights;
1913: LightRetained light;
1914: boolean lightingOn = true;
1915:
1916: if (canvas3d.ctx == null) {
1917: // Force an initial clear if one has not yet been done
1918: doClear();
1919: }
1920:
1921: if (J3dDebug.devPhase && J3dDebug.debug) {
1922: J3dDebug.doAssert(canvas3d.ctx != null,
1923: "canvas3d.ctx != null");
1924: }
1925:
1926: // We need to catch NullPointerException when the dsi
1927: // gets yanked from us during a remove.
1928: try {
1929: if (canvas3d.drawingSurfaceObject.renderLock()) {
1930:
1931: // Make the context current
1932: canvas3d.makeCtxCurrent();
1933:
1934: if ((dirtyMask & BUFFER_MODE) != 0) {
1935: if (bufferOverride) {
1936: canvas3d.setRenderMode(canvas3d.ctx,
1937: stereoMode, canvas3d.useDoubleBuffer
1938: && !frontBufferRendering);
1939: } else {
1940: canvas3d.setRenderMode(canvas3d.ctx,
1941: Canvas3D.FIELD_ALL,
1942: canvas3d.useDoubleBuffer);
1943: }
1944: dirtyMask &= ~BUFFER_MODE;
1945: }
1946:
1947: CanvasViewCache cvCache = canvas3d.canvasViewCache;
1948: Transform3D proj;
1949:
1950: // vpcToEc = cvCache.getLeftVpcToEc();
1951: if (bufferOverride) {
1952: switch (stereoMode) {
1953: case STEREO_RIGHT:
1954: vpcToEc = cvCache.getRightVpcToEc();
1955: // XXXX: move this under check for
1956: // (dirtyMask & BUFFER_MODE) above after testing
1957: // PureImmediate mode
1958: canvas3d.setProjectionMatrix(canvas3d.ctx,
1959: cvCache.getRightProjection());
1960: break;
1961: case STEREO_LEFT:
1962: case STEREO_BOTH:
1963: default:
1964: vpcToEc = cvCache.getLeftVpcToEc();
1965: // XXXX: move this under check for
1966: // (dirtyMask & BUFFER_MODE) above after testing
1967: // PureImmediate mode
1968: canvas3d.setProjectionMatrix(canvas3d.ctx,
1969: cvCache.getLeftProjection());
1970: }
1971: } else if (!canvas3d.isRunning ||
1972: // vpcToEc is not set in the first frame
1973: // of preRender() callback
1974: (canvas3d.vpcToEc == null)) {
1975: vpcToEc = cvCache.getLeftVpcToEc();
1976: } else {
1977: vpcToEc = canvas3d.vpcToEc;
1978: }
1979:
1980: // referred by RenderQueue.updateState
1981: // canvas3d.screen.renderer.vpcToEc = vpcToEc;
1982: // rb.updateState(canvas3d.screen.renderer.rId, ro, canvas3d, true);
1983:
1984: // this.drawTransform.mul(rb.vworldToVpc,
1985: // this.compTransform);
1986:
1987: boolean isNonUniformScale = !drawTransform
1988: .isCongruent();
1989:
1990: int geometryType = 0;
1991: switch (((GeometryRetained) geometry.retained).geoType) {
1992: case GeometryRetained.GEO_TYPE_POINT_SET:
1993: case GeometryRetained.GEO_TYPE_INDEXED_POINT_SET:
1994: geometryType = RenderMolecule.POINT;
1995: break;
1996: case GeometryRetained.GEO_TYPE_LINE_SET:
1997: case GeometryRetained.GEO_TYPE_LINE_STRIP_SET:
1998: case GeometryRetained.GEO_TYPE_INDEXED_LINE_SET:
1999: case GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET:
2000: geometryType = RenderMolecule.LINE;
2001: break;
2002: case GeometryRetained.GEO_TYPE_RASTER:
2003: geometryType = RenderMolecule.RASTER;
2004: break;
2005: case GeometryRetained.GEO_TYPE_COMPRESSED:
2006: geometryType = RenderMolecule.COMPRESSED;
2007:
2008: switch (((CompressedGeometryRetained) geometry.retained)
2009: .getBufferType()) {
2010: case CompressedGeometryHeader.POINT_BUFFER:
2011: geometryType |= RenderMolecule.POINT;
2012: break;
2013: case CompressedGeometryHeader.LINE_BUFFER:
2014: geometryType |= RenderMolecule.LINE;
2015: break;
2016: default:
2017: case CompressedGeometryHeader.TRIANGLE_BUFFER:
2018: geometryType |= RenderMolecule.SURFACE;
2019: break;
2020: }
2021: break;
2022: default:
2023: geometryType = RenderMolecule.SURFACE;
2024: break;
2025: }
2026:
2027: useAlpha = updateState(rb, geometryType);
2028:
2029: canvas3d.setModelViewMatrix(canvas3d.ctx, vpcToEc.mat,
2030: rb.vworldToVpc);
2031: updateLightAndFog();
2032:
2033: updateModelClip(rb.vworldToVpc);
2034:
2035: this .drawTransform.mul(rb.vworldToVpc,
2036: this .compTransform);
2037: canvas3d.setModelViewMatrix(canvas3d.ctx, vpcToEc.mat,
2038: this .drawTransform);
2039:
2040: if (geometry.retained instanceof GeometryArrayRetained) {
2041: geoRetained = (GeometryArrayRetained) geometry.retained;
2042:
2043: geoRetained.geomLock.getLock();
2044: // If the geometry is by refernence, then see if we are using alpha
2045: // and that there is no global alpha sun extension defined ..
2046: if (((geoRetained.vertexFormat & GeometryArray.BY_REFERENCE) != 0)
2047: && (geoRetained.c4fAllocated == 0)
2048: && ((geoRetained.vertexFormat & GeometryArray.COLOR) != 0)
2049: && useAlpha
2050: && (canvas3d.extensionsSupported & Canvas3D.SUN_GLOBAL_ALPHA) == 0) {
2051:
2052: if ((geoRetained.vertexFormat & GeometryArray.INTERLEAVED) != 0) {
2053: geoRetained
2054: .setupMirrorInterleavedColorPointer(true);
2055: } else {
2056: geoRetained
2057: .setupMirrorColorPointer(
2058: (geoRetained.vertexType & GeometryArrayRetained.COLOR_DEFINED),
2059: true);
2060: }
2061: }
2062:
2063: if ((geometry.retained instanceof IndexedGeometryArrayRetained)
2064: && ((((GeometryArrayRetained) geometry.retained).vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0)) {
2065: if (geoRetained.dirtyFlag != 0) {
2066: geoRetained.mirrorGeometry = ((IndexedGeometryArrayRetained) geoRetained)
2067: .cloneNonIndexedGeometry();
2068: // Change the source geometry dirtyFlag
2069: // drawGeo.execute() will change the
2070: // destination geometry dirtyFlag only.
2071: geoRetained.dirtyFlag = 0;
2072: }
2073: drawGeo = (GeometryRetained) geoRetained.mirrorGeometry;
2074: } else {
2075: drawGeo = geoRetained;
2076: }
2077:
2078: geoRetained.setVertexFormat(false,
2079: ignoreVertexColors, canvas3d.ctx);
2080:
2081: } else if (geometry.retained instanceof Text3DRetained) {
2082: ((Text3DRetained) geometry.retained)
2083: .setModelViewMatrix(vpcToEc,
2084: this .drawTransform);
2085: drawGeo = (GeometryRetained) geometry.retained;
2086: } else if (geometry.retained instanceof RasterRetained) {
2087: ImageComponent2DRetained img = ((RasterRetained) geometry.retained).image;
2088: if (img != null) {
2089: if (img.isByReference()) {
2090: img.geomLock.getLock();
2091: img.evaluateExtensions(canvas3d);
2092: img.geomLock.unLock();
2093: } else {
2094: img.evaluateExtensions(canvas3d);
2095: }
2096: }
2097: drawGeo = (GeometryRetained) geometry.retained;
2098: } else {
2099: drawGeo = (GeometryRetained) geometry.retained;
2100: }
2101:
2102: drawGeo.execute(canvas3d, null, isNonUniformScale,
2103: false, alpha, canvas3d.screen.screen,
2104: ignoreVertexColors);
2105:
2106: if (geoRetained != null) {
2107: if (geoRetained.pVertexBuffers != 0) {
2108: // Issue 121: always free D3D vertex buffer memory
2109: // after immediate mode rendering
2110: geoRetained.freeD3DArray(true);
2111: }
2112:
2113: geoRetained.geomLock.unLock();
2114: }
2115:
2116: canvas3d.drawingSurfaceObject.unLock();
2117: }
2118: } catch (NullPointerException ne) {
2119: canvas3d.drawingSurfaceObject.unLock();
2120: throw ne;
2121: }
2122: }
2123:
2124: /**
2125: * Draw the specified Geometry component object.
2126: * @param geometry the Geometry object to draw.
2127: *
2128: * @exception IllegalSharingException if the specified geometry is a
2129: * Raster that refers to an ImageComponent2D that is being used by a
2130: * Canvas3D as an off-screen buffer.
2131: */
2132: public void draw(Geometry geometry) {
2133: // do illegalSharing check
2134: if ((geometry != null) && (geometry instanceof Raster)) {
2135: RasterRetained rasRetained = (RasterRetained) geometry.retained;
2136: ImageComponent2D image = rasRetained.getImage();
2137: if (image != null) {
2138: ImageComponentRetained imageRetained = (ImageComponentRetained) image.retained;
2139: // Do illegal sharing check
2140: if (imageRetained.getUsedByOffScreen()) {
2141: throw new IllegalSharingException(J3dI18N
2142: .getString("GraphicsContext3D32"));
2143: }
2144: }
2145: }
2146:
2147: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
2148: || (!canvas3d.view.active)) {
2149: return;
2150: } else if (Thread.currentThread() == canvas3d.screen.renderer) {
2151: doDraw(geometry);
2152: } else {
2153: if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
2154: sendRenderMessage(false, GraphicsContext3D.DRAW,
2155: geometry, null);
2156: } else {
2157: sendRenderMessage(true, GraphicsContext3D.DRAW,
2158: geometry, null);
2159: }
2160: }
2161: }
2162:
2163: /**
2164: * Draw the specified Shape3D leaf node object. This is
2165: * a convenience method that is identical to calling the
2166: * setAppearance(Appearance) and draw(Geometry) methods
2167: * passing the appearance and geometry component objects of
2168: * the specified shape node as arguments.
2169: *
2170: * @param shape the Shape3D node containing the Appearance component
2171: * object to set and Geometry component object to draw
2172: *
2173: * @exception IllegalSharingException if the Shape3D node
2174: * is part of or is subsequently made part of a live scene graph.
2175: *
2176: * @exception IllegalSharingException if the Shape3D node's Appearance
2177: * refers to an ImageComponent2D that is being used by a
2178: * Canvas3D as an off-screen buffer.
2179: */
2180: public void draw(Shape3D shape) {
2181: if (shape.isLive()) {
2182: throw new IllegalSharingException(J3dI18N
2183: .getString("GraphicsContext3D26"));
2184: }
2185: ((Shape3DRetained) shape.retained).setInImmCtx(true);
2186: setAppearance(shape.getAppearance());
2187: draw(shape.getGeometry());
2188: }
2189:
2190: /**
2191: * Read an image from the frame buffer and copy it into the
2192: * ImageComponent and/or DepthComponent
2193: * objects referenced by the specified Raster object.
2194: * All parameters of the Raster object and the component ImageComponent
2195: * and/or DepthComponentImage objects must be set to the desired values
2196: * prior to calling this method. These values determine the location,
2197: * size, and format of the pixel data that is read.
2198: * This method calls <code>flush(true)</code> prior to reading the
2199: * frame buffer.
2200: *
2201: * @param raster the Raster object used to read the
2202: * contents of the frame buffer
2203: *
2204: * @exception IllegalArgumentException if the image class of the specified
2205: * Raster's ImageComponent2D is <i>not</i> ImageClass.BUFFERED_IMAGE.
2206: *
2207: * @exception IllegalArgumentException if the specified Raster's
2208: * ImageComponent2D is in by-reference mode and its
2209: * RenderedImage is null.
2210: *
2211: * @exception IllegalArgumentException if the the Raster's
2212: * ImageComponent2D format
2213: * is <i>not</i> a 3-component format (e.g., FORMAT_RGB)
2214: * or a 4-component format (e.g., FORMAT_RGBA).
2215: *
2216: * @exception IllegalSharingException if the Raster object is
2217: * part of a live scene graph, or if the Raster's ImageComponent2D is
2218: * part of a live scene graph.
2219: *
2220: * @exception IllegalSharingException if the Raster's ImageComponent2D is
2221: * being used by an immediate mode context, or by a Canvas3D as
2222: * an off-screen buffer.
2223: *
2224: * @see #flush
2225: * @see ImageComponent
2226: * @see DepthComponent
2227: */
2228: public void readRaster(Raster raster) {
2229: if ((raster != null) && raster.isLive()) {
2230: ImageComponent2D image = raster.getImage();
2231: if (image != null) {
2232: ImageComponent2DRetained imageRetained = (ImageComponent2DRetained) image.retained;
2233: if (image.getImageClass() != ImageComponent.ImageClass.BUFFERED_IMAGE) {
2234: throw new IllegalArgumentException(J3dI18N
2235: .getString("GraphicsContext3D33"));
2236: }
2237: if (image.isByReference() && (image.getImage() == null)) {
2238: throw new IllegalArgumentException(J3dI18N
2239: .getString("GraphicsContext3D34"));
2240: }
2241: if (imageRetained.getNumberOfComponents() < 3) {
2242: throw new IllegalArgumentException(J3dI18N
2243: .getString("GraphicsContext3D35"));
2244: }
2245: if (image.isLive()) {
2246: throw new IllegalSharingException(J3dI18N
2247: .getString("GraphicsContext3D36"));
2248: }
2249: if (imageRetained.getInImmCtx()
2250: || imageRetained.getUsedByOffScreen()) {
2251: throw new IllegalSharingException(J3dI18N
2252: .getString("GraphicsContext3D37"));
2253: }
2254: }
2255: }
2256: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
2257: || (!canvas3d.view.active)) {
2258: return;
2259: } else if (Thread.currentThread() == canvas3d.screen.renderer) {
2260: doReadRaster(raster);
2261: } else if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
2262: readRasterReady = false;
2263: sendRenderMessage(false, GraphicsContext3D.READ_RASTER,
2264: raster, null);
2265: while (!readRasterReady) {
2266: MasterControl.threadYield();
2267: }
2268: } else {
2269: // call from user thread
2270: readRasterReady = false;
2271: sendRenderMessage(true, GraphicsContext3D.READ_RASTER,
2272: raster, null);
2273: while (!readRasterReady) {
2274: MasterControl.threadYield();
2275: }
2276: }
2277: }
2278:
2279: void doReadRaster(Raster raster) {
2280: if (!canvas3d.firstPaintCalled) {
2281: readRasterReady = true;
2282: return;
2283: }
2284:
2285: RasterRetained ras = (RasterRetained) raster.retained;
2286: Dimension canvasSize = canvas3d.getSize();
2287: Dimension rasterSize = new Dimension();
2288: ImageComponent2DRetained image = ras.image;
2289:
2290: int format = 0; // Not use in case of DepthComponent read
2291:
2292: if (canvas3d.ctx == null) {
2293: // Force an initial clear if one has not yet been done
2294: doClear();
2295: }
2296:
2297: if (J3dDebug.devPhase && J3dDebug.debug) {
2298: J3dDebug.doAssert(canvas3d.ctx != null,
2299: "canvas3d.ctx != null");
2300: }
2301:
2302: ras.getSize(rasterSize);
2303: // allocate read buffer space
2304: if ((ras.type & Raster.RASTER_COLOR) != 0) {
2305: if ((rasterSize.width > ras.image.width)
2306: || (rasterSize.height > ras.image.height)) {
2307: throw new RuntimeException(J3dI18N
2308: .getString("GraphicsContext3D27"));
2309: }
2310: }
2311:
2312: if ((ras.type & Raster.RASTER_DEPTH) != 0) {
2313: int size = ras.depthComponent.height
2314: * ras.depthComponent.width;
2315: if (ras.depthComponent.type == DepthComponentRetained.DEPTH_COMPONENT_TYPE_FLOAT) {
2316: if (floatBuffer.length < size)
2317: floatBuffer = new float[size];
2318: } else { // type INT or NATIVE
2319: if (intBuffer.length < size)
2320: intBuffer = new int[size];
2321: }
2322: if ((rasterSize.width > ras.depthComponent.width)
2323: || (rasterSize.height > ras.depthComponent.height)) {
2324: throw new RuntimeException(J3dI18N
2325: .getString("GraphicsContext3D28"));
2326: }
2327: }
2328:
2329: if ((ras.type & Raster.RASTER_COLOR) != 0) {
2330:
2331: // If by reference, check if a copy needs to be made
2332: // and also evaluate the storedFormat ..
2333: if (image.isByReference()) {
2334: image.geomLock.getLock();
2335: image.evaluateExtensions(canvas3d);
2336: image.geomLock.unLock();
2337: } else {
2338: // If image has a null buffer ( BufferedImage)
2339: if (image.imageData == null) {
2340: image.createBlankImageData();
2341: }
2342: // Check for possible format conversion in imageData
2343: else {
2344: // Format convert imageData if format is unsupported.
2345: image.evaluateExtensions(canvas3d);
2346: }
2347: }
2348: }
2349:
2350: // We need to catch NullPointerException when the dsi
2351: // gets yanked from us during a remove.
2352: try {
2353: if (canvas3d.drawingSurfaceObject.renderLock()) {
2354: // Make the context current and read the raster information
2355: canvas3d.makeCtxCurrent();
2356: canvas3d.syncRender(canvas3d.ctx, true);
2357: Point rasterSrcOffset = new Point();
2358: ras.getDstOffset(rasterSrcOffset);
2359:
2360: DepthComponentRetained depthComp = ras.depthComponent;
2361: int depthType = 0;
2362: if (depthComp != null) {
2363: depthType = depthComp.type;
2364: }
2365: Pipeline.getPipeline().readRaster(canvas3d.ctx,
2366: ras.type, rasterSrcOffset.x, rasterSrcOffset.y,
2367: rasterSize.width, rasterSize.height,
2368: canvasSize.height,
2369: image.getImageDataTypeIntValue(),
2370: image.getImageFormatTypeIntValue(false),
2371: image.imageData.get(), depthType, depthComp);
2372:
2373: canvas3d.drawingSurfaceObject.unLock();
2374: }
2375: } catch (NullPointerException ne) {
2376: canvas3d.drawingSurfaceObject.unLock();
2377: throw ne;
2378: }
2379:
2380: if ((ras.type & Raster.RASTER_DEPTH) != 0) {
2381: if (ras.depthComponent.type == DepthComponentRetained.DEPTH_COMPONENT_TYPE_FLOAT)
2382: ((DepthComponentFloatRetained) ras.depthComponent)
2383: .retrieveDepth(floatBuffer, rasterSize.width,
2384: rasterSize.height);
2385: else if (ras.depthComponent.type == DepthComponentRetained.DEPTH_COMPONENT_TYPE_INT)
2386: ((DepthComponentIntRetained) ras.depthComponent)
2387: .retrieveDepth(intBuffer, rasterSize.width,
2388: rasterSize.height);
2389: else if (ras.depthComponent.type == DepthComponentRetained.DEPTH_COMPONENT_TYPE_NATIVE)
2390: ((DepthComponentNativeRetained) ras.depthComponent)
2391: .retrieveDepth(intBuffer, rasterSize.width,
2392: rasterSize.height);
2393: }
2394: readRasterReady = true;
2395: }
2396:
2397: /**
2398: * Flushes all previously executed rendering operations to the
2399: * drawing buffer for this 3D graphics context.
2400: *
2401: * @param wait flag indicating whether or not to wait for the
2402: * rendering to be complete before returning from this call.
2403: *
2404: * @since Java 3D 1.2
2405: */
2406: public void flush(boolean wait) {
2407: if ((canvas3d.view == null) || (canvas3d.view.universe == null)
2408: || (!canvas3d.view.active)
2409: || (Thread.currentThread() == canvas3d.screen.renderer)) {
2410: doFlush(wait);
2411: } else {
2412: Boolean waitArg = (wait ? Boolean.TRUE : Boolean.FALSE);
2413:
2414: if (Thread.currentThread() == canvas3d.view.universe.behaviorScheduler) {
2415: sendRenderMessage(false, GraphicsContext3D.FLUSH,
2416: waitArg, null);
2417: } else {
2418: sendRenderMessage(true, GraphicsContext3D.FLUSH,
2419: waitArg, null);
2420: }
2421: // Issue 131: AutomaticOffscreen canvases must be treated as onscreen ones.
2422: if (wait && canvas3d.active && canvas3d.isRunningStatus
2423: && !canvas3d.manualRendering) {
2424: // No need to wait if renderer thread is not schedule
2425: runMonitor(J3dThread.WAIT);
2426: }
2427: }
2428: }
2429:
2430: void doFlush(boolean wait) {
2431: try {
2432: if (canvas3d.drawingSurfaceObject.renderLock()) {
2433: canvas3d.syncRender(canvas3d.ctx, wait);
2434: canvas3d.drawingSurfaceObject.unLock();
2435: if (wait) {
2436: runMonitor(J3dThread.NOTIFY);
2437: }
2438: }
2439: } catch (NullPointerException ne) {
2440: canvas3d.drawingSurfaceObject.unLock();
2441: throw ne;
2442: }
2443: }
2444:
2445: void updateLightAndFog() {
2446: int enableMask = 0;
2447: int i;
2448: sceneAmbient.x = 0.0f;
2449: sceneAmbient.y = 0.0f;
2450: sceneAmbient.z = 0.0f;
2451:
2452: int n = 0;
2453: int nLight = lights.size();
2454: ;
2455: for (i = 0; i < nLight; i++) {
2456: LightRetained lt = (LightRetained) ((Light) lights.get(i)).retained;
2457: if (lt instanceof AmbientLightRetained) {
2458: sceneAmbient.x += lt.color.x;
2459: sceneAmbient.y += lt.color.y;
2460: sceneAmbient.z += lt.color.z;
2461: continue;
2462: }
2463:
2464: lt.update(canvas3d.ctx, n, canvas3d.canvasViewCache
2465: .getVworldToCoexistenceScale());
2466: if (lt.lightOn)
2467: enableMask |= (1 << n);
2468: n++;
2469: }
2470: if (sceneAmbient.x > 1.0f) {
2471: sceneAmbient.x = 1.0f;
2472: }
2473: if (sceneAmbient.y > 1.0f) {
2474: sceneAmbient.y = 1.0f;
2475: }
2476: if (sceneAmbient.z > 1.0f) {
2477: sceneAmbient.z = 1.0f;
2478: }
2479:
2480: canvas3d.setSceneAmbient(canvas3d.ctx, sceneAmbient.x,
2481: sceneAmbient.y, sceneAmbient.z);
2482:
2483: canvas3d.canvasDirty |= Canvas3D.AMBIENTLIGHT_DIRTY;
2484: canvas3d.sceneAmbient.set(sceneAmbient);
2485:
2486: if (canvas3d.enableMask != enableMask) {
2487: canvas3d.canvasDirty |= Canvas3D.LIGHTENABLES_DIRTY;
2488: // XXXX: 32 => renderBin.maxLights
2489: canvas3d.setLightEnables(canvas3d.ctx, enableMask, 32);
2490: canvas3d.enableMask = enableMask;
2491: }
2492:
2493: // Force LightBin.updateAttributes and EnvironmentSet.updateAttributes
2494: // to use the within frame case.
2495: canvas3d.lightBin = null;
2496: canvas3d.environmentSet = null;
2497:
2498: if (fog != null) {
2499: if (fog.retained != canvas3d.fog) {
2500: ((FogRetained) fog.retained).update(canvas3d.ctx,
2501: canvas3d.canvasViewCache
2502: .getVworldToCoexistenceScale());
2503: canvas3d.fog = (FogRetained) fog.retained;
2504: canvas3d.canvasDirty |= Canvas3D.FOG_DIRTY;
2505: }
2506: } else { // Turn off fog
2507: if (canvas3d.fog != null) {
2508: canvas3d.setFogEnableFlag(canvas3d.ctx, false);
2509: canvas3d.fog = null;
2510: canvas3d.canvasDirty |= Canvas3D.FOG_DIRTY;
2511: }
2512: }
2513: }
2514:
2515: void updateModelClip(Transform3D vworldToVpc) {
2516: if (modelClip != null) {
2517: int enableMask = 0;
2518: for (int i = 0; i < 6; i++) {
2519: if (((ModelClipRetained) modelClip.retained).enables[i])
2520: enableMask |= 1 << i;
2521: }
2522: // planes are already transformed to eye coordinates
2523: // in immediate mode
2524: if (enableMask != 0) {
2525: this .drawTransform.mul(vworldToVpc,
2526: this .modelClipTransform);
2527: canvas3d.setModelViewMatrix(canvas3d.ctx, vpcToEc.mat,
2528: this .drawTransform);
2529: }
2530: ((ModelClipRetained) modelClip.retained).update(
2531: canvas3d.ctx, enableMask, this .drawTransform);
2532: canvas3d.canvasDirty |= Canvas3D.MODELCLIP_DIRTY;
2533: canvas3d.modelClip = (ModelClipRetained) modelClip.retained;
2534: } else {
2535: if (canvas3d.modelClip != null) {
2536: canvas3d.disableModelClip(canvas3d.ctx);
2537: canvas3d.modelClip = null;
2538: canvas3d.canvasDirty |= Canvas3D.MODELCLIP_DIRTY;
2539: }
2540: }
2541:
2542: // Force EnvironmentSet.updateAttributes to use the within frame case.
2543: canvas3d.environmentSet = null;
2544:
2545: }
2546:
2547: boolean updateState(RenderBin rb, int geometryType) {
2548:
2549: boolean useAlpha = false;
2550: numActiveTexUnit = 0;
2551: lastActiveTexUnitIndex = 0;
2552:
2553: // Update Appearance
2554: if (appearance != null) {
2555: AppearanceRetained app = (AppearanceRetained) appearance.retained;
2556:
2557: // If the material is not null then check if the one in the canvas
2558: // is equivalent to the one being sent down. If Yes, do nothing
2559: // Otherwise, cache the sent down material and mark the canvas
2560: // dirty flag so that the compiled/compiled-retained rendering
2561: // catches the change
2562: // if material != null, we will need to load the material
2563: // parameter again, because the apps could have changed
2564: // the material parameter
2565:
2566: if (app.material != null) {
2567: app.material.updateNative(canvas3d.ctx, red, green,
2568: blue, alpha, enableLighting);
2569: canvas3d.material = app.material;
2570: canvas3d.canvasDirty |= Canvas3D.MATERIAL_DIRTY;
2571: } else {
2572: if (canvas3d.material != null) {
2573: canvas3d.updateMaterial(canvas3d.ctx, red, green,
2574: blue, alpha);
2575: canvas3d.material = null;
2576: canvas3d.canvasDirty |= Canvas3D.MATERIAL_DIRTY;
2577: }
2578: }
2579:
2580: // Set flag indicating whether we are using shaders
2581: boolean useShaders = false;
2582: if (app instanceof ShaderAppearanceRetained) {
2583: ShaderProgramRetained spR = ((ShaderAppearanceRetained) app).shaderProgram;
2584: if (spR != null) {
2585: spR.updateNative(canvas3d, true);
2586:
2587: ShaderAttributeSetRetained sasR = ((ShaderAppearanceRetained) app).shaderAttributeSet;
2588:
2589: if (sasR != null) {
2590: sasR.updateNative(canvas3d, spR);
2591: }
2592:
2593: canvas3d.shaderProgram = spR;
2594: useShaders = true;
2595: }
2596: } else if (canvas3d.shaderProgram != null) {
2597: canvas3d.shaderProgram.updateNative(canvas3d, false);
2598: canvas3d.shaderProgram = null;
2599: useShaders = false;
2600: }
2601:
2602: // Set the number of available texture units; this depends on
2603: // whether or not shaders are being used.
2604: int availableTextureUnits = useShaders ? canvas3d.maxTextureImageUnits
2605: : canvas3d.maxTextureUnits;
2606:
2607: int prevNumActiveTexUnit = canvas3d.getNumActiveTexUnit();
2608:
2609: // Get the number of active texture units.
2610: // Note that this total number now includes disabled units.
2611: if (app.texUnitState != null) {
2612: TextureUnitStateRetained tus;
2613:
2614: for (int i = 0; i < app.texUnitState.length; i++) {
2615: tus = app.texUnitState[i];
2616: if (tus != null && tus.isTextureEnabled()) {
2617: lastActiveTexUnitIndex = i;
2618: numActiveTexUnit = i + 1;
2619: if (tus.texAttrs != null) {
2620: useAlpha = useAlpha
2621: || (tus.texAttrs.textureMode == TextureAttributes.BLEND);
2622: }
2623: }
2624: }
2625:
2626: if (numActiveTexUnit <= availableTextureUnits) {
2627: // Normal, single-pass rendering case
2628:
2629: // update all active texture unit states
2630: for (int i = 0; i < app.texUnitState.length; i++) {
2631: if (i >= availableTextureUnits) {
2632: // This can happen if there are disabled units at
2633: // the end of the array
2634: break;
2635: }
2636:
2637: if ((app.texUnitState[i] != null)
2638: && app.texUnitState[i]
2639: .isTextureEnabled()) {
2640: app.texUnitState[i].updateNative(i,
2641: canvas3d, false, false);
2642: } else {
2643: canvas3d.resetTexture(canvas3d.ctx, i);
2644: }
2645: }
2646:
2647: // reset the remaining texture units
2648: for (int i = app.texUnitState.length; i < prevNumActiveTexUnit; i++) {
2649: canvas3d.resetTexture(canvas3d.ctx, i);
2650: }
2651:
2652: // set the number active texture unit in Canvas3D
2653: canvas3d.setNumActiveTexUnit(numActiveTexUnit);
2654:
2655: } else {
2656: // Exceeded limit, disable all the texture units
2657: for (int i = 0; i < prevNumActiveTexUnit; i++) {
2658: canvas3d.resetTexture(canvas3d.ctx, i);
2659: }
2660: canvas3d.setNumActiveTexUnit(0);
2661: }
2662:
2663: // set the active texture unit back to 0
2664: canvas3d.activeTextureUnit(canvas3d.ctx, 0);
2665: } else {
2666: // if texUnitState is null, let's disable
2667: // all texture units first
2668: if (canvas3d.multiTexAccelerated) {
2669: if (canvas3d.texUnitState != null) {
2670: for (int i = 0; i < prevNumActiveTexUnit; i++) {
2671: TextureUnitStateRetained tur = canvas3d.texUnitState[i];
2672: if ((tur != null) && (tur.texture != null)) {
2673: canvas3d.resetTexture(canvas3d.ctx, i);
2674: canvas3d.texUnitState[i].texture = null;
2675: }
2676: }
2677: }
2678:
2679: // set the active texture unit back to 0
2680: canvas3d.activeTextureUnit(canvas3d.ctx, 0);
2681: }
2682:
2683: if ((canvas3d.texUnitState != null)
2684: && (canvas3d.texUnitState[0] != null)
2685: && (canvas3d.texUnitState[0].texture != app.texture)) {
2686:
2687: // If the image is by reference, check if the image
2688: // should be processed
2689: if (app.texture != null) {
2690: app.texture.updateNative(canvas3d);
2691: canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY
2692: | Canvas3D.TEXTUREATTRIBUTES_DIRTY;
2693: numActiveTexUnit = 1;
2694: lastActiveTexUnitIndex = 0;
2695: } else {
2696: numActiveTexUnit = 0;
2697: canvas3d.resetTexture(canvas3d.ctx, -1);
2698: canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY
2699: | Canvas3D.TEXTUREATTRIBUTES_DIRTY;
2700: }
2701:
2702: canvas3d.texUnitState[0].texture = app.texture;
2703: }
2704:
2705: // set the number active texture unit in Canvas3D
2706: canvas3d.setNumActiveTexUnit(numActiveTexUnit);
2707:
2708: if (app.texCoordGeneration != null) {
2709: app.texCoordGeneration.updateNative(canvas3d);
2710: canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY
2711: | Canvas3D.TEXTUREATTRIBUTES_DIRTY;
2712: if ((canvas3d.texUnitState != null)
2713: && (canvas3d.texUnitState[0] != null)) {
2714: canvas3d.texUnitState[0].texGen = app.texCoordGeneration;
2715: }
2716: } else {
2717: // If the canvas does not alreadt have a null texCoordGeneration
2718: // load the default
2719: if ((canvas3d.texUnitState != null)
2720: && (canvas3d.texUnitState[0] != null)
2721: && (canvas3d.texUnitState[0].texGen != null)) {
2722: canvas3d.resetTexCoordGeneration(canvas3d.ctx);
2723: canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY
2724: | Canvas3D.TEXTUREATTRIBUTES_DIRTY;
2725: canvas3d.texUnitState[0].texGen = app.texCoordGeneration;
2726: }
2727: }
2728:
2729: if (app.textureAttributes != null) {
2730: if ((canvas3d.texUnitState != null)
2731: && (canvas3d.texUnitState[0] != null)) {
2732:
2733: if (canvas3d.texUnitState[0].texture != null) {
2734: app.textureAttributes
2735: .updateNative(
2736: canvas3d,
2737: false,
2738: canvas3d.texUnitState[0].texture.format);
2739: } else {
2740: app.textureAttributes.updateNative(
2741: canvas3d, false, Texture.RGBA);
2742: }
2743: canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY
2744: | Canvas3D.TEXTUREATTRIBUTES_DIRTY;
2745: canvas3d.texUnitState[0].texAttrs = app.textureAttributes;
2746: }
2747: } else {
2748: // If the canvas does not already have a null texAttribute
2749: // load the default if necessary
2750: if ((canvas3d.texUnitState != null)
2751: && (canvas3d.texUnitState[0] != null)
2752: && (canvas3d.texUnitState[0].texAttrs != null)) {
2753: canvas3d.resetTextureAttributes(canvas3d.ctx);
2754: canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY
2755: | Canvas3D.TEXTUREATTRIBUTES_DIRTY;
2756: canvas3d.texUnitState[0].texAttrs = null;
2757: }
2758: }
2759: }
2760:
2761: if (app.coloringAttributes != null) {
2762: app.coloringAttributes.updateNative(canvas3d.ctx, dRed,
2763: dBlue, dGreen, alpha, enableLighting);
2764: canvas3d.canvasDirty |= Canvas3D.COLORINGATTRS_DIRTY;
2765: canvas3d.coloringAttributes = app.coloringAttributes;
2766: } else {
2767: if (canvas3d.coloringAttributes != null) {
2768: canvas3d.resetColoringAttributes(canvas3d.ctx, red,
2769: green, blue, alpha, enableLighting);
2770: canvas3d.canvasDirty |= Canvas3D.COLORINGATTRS_DIRTY;
2771: canvas3d.coloringAttributes = null;
2772: }
2773: }
2774:
2775: if (app.transparencyAttributes != null) {
2776: app.transparencyAttributes.updateNative(canvas3d.ctx,
2777: alpha, geometryType, polygonMode, lineAA,
2778: pointAA);
2779: canvas3d.canvasDirty |= Canvas3D.TRANSPARENCYATTRS_DIRTY;
2780: canvas3d.transparency = app.transparencyAttributes;
2781:
2782: useAlpha = useAlpha
2783: || ((app.transparencyAttributes.transparencyMode != TransparencyAttributes.NONE) && (VirtualUniverse.mc
2784: .isD3D() || (!VirtualUniverse.mc
2785: .isD3D() && (app.transparencyAttributes.transparencyMode != TransparencyAttributes.SCREEN_DOOR))));
2786: } else {
2787: canvas3d.resetTransparency(canvas3d.ctx, geometryType,
2788: polygonMode, lineAA, pointAA);
2789: canvas3d.canvasDirty |= Canvas3D.TRANSPARENCYATTRS_DIRTY;
2790: canvas3d.transparency = null;
2791: }
2792:
2793: if (app.renderingAttributes != null) {
2794: ignoreVertexColors = app.renderingAttributes.ignoreVertexColors;
2795: app.renderingAttributes.updateNative(canvas3d,
2796: canvas3d.depthBufferWriteEnableOverride,
2797: canvas3d.depthBufferEnableOverride);
2798: canvas3d.canvasDirty |= Canvas3D.ATTRIBUTEBIN_DIRTY
2799: | Canvas3D.TEXTUREATTRIBUTES_DIRTY;
2800: canvas3d.renderingAttrs = app.renderingAttributes;
2801:
2802: useAlpha = useAlpha
2803: || (app.renderingAttributes.alphaTestFunction != RenderingAttributes.ALWAYS);
2804: } else {
2805: // If the canvas does not alreadt have a null renderingAttrs
2806: // load the default
2807: ignoreVertexColors = false;
2808: if (canvas3d.renderingAttrs != null) {
2809: canvas3d.resetRenderingAttributes(canvas3d.ctx,
2810: canvas3d.depthBufferWriteEnableOverride,
2811: canvas3d.depthBufferEnableOverride);
2812: canvas3d.canvasDirty |= Canvas3D.ATTRIBUTEBIN_DIRTY
2813: | Canvas3D.TEXTUREATTRIBUTES_DIRTY;
2814: canvas3d.renderingAttrs = null;
2815: }
2816: }
2817:
2818: if (app.polygonAttributes != null) {
2819: app.polygonAttributes.updateNative(canvas3d.ctx);
2820: canvas3d.canvasDirty |= Canvas3D.POLYGONATTRS_DIRTY;
2821: canvas3d.polygonAttributes = app.polygonAttributes;
2822: } else {
2823: // If the canvas does not alreadt have a null polygonAttr
2824: // load the default
2825: if (canvas3d.polygonAttributes != null) {
2826: canvas3d.resetPolygonAttributes(canvas3d.ctx);
2827: canvas3d.canvasDirty |= Canvas3D.POLYGONATTRS_DIRTY;
2828: canvas3d.polygonAttributes = null;
2829: }
2830: }
2831:
2832: if (app.lineAttributes != null) {
2833: app.lineAttributes.updateNative(canvas3d.ctx);
2834: canvas3d.canvasDirty |= Canvas3D.LINEATTRS_DIRTY;
2835: canvas3d.lineAttributes = app.lineAttributes;
2836: } else {
2837: // If the canvas does not already have a null lineAttr
2838: // load the default
2839: if (canvas3d.lineAttributes != null) {
2840: canvas3d.resetLineAttributes(canvas3d.ctx);
2841: canvas3d.canvasDirty |= Canvas3D.LINEATTRS_DIRTY;
2842: canvas3d.lineAttributes = null;
2843: }
2844: }
2845:
2846: if (app.pointAttributes != null) {
2847: app.pointAttributes.updateNative(canvas3d.ctx);
2848: canvas3d.canvasDirty |= Canvas3D.POINTATTRS_DIRTY;
2849: canvas3d.pointAttributes = app.pointAttributes;
2850: } else {
2851: // If the canvas does not already have a null pointAttr
2852: // load the default
2853: if (canvas3d.pointAttributes != null) {
2854: canvas3d.resetPointAttributes(canvas3d.ctx);
2855: canvas3d.canvasDirty |= Canvas3D.POINTATTRS_DIRTY;
2856: canvas3d.pointAttributes = null;
2857: }
2858: }
2859:
2860: canvas3d.appearance = app;
2861:
2862: } else {
2863: if (canvas3d.appearance != null) {
2864: resetAppearance();
2865: canvas3d.appearance = null;
2866: }
2867: }
2868:
2869: return (useAlpha);
2870: }
2871:
2872: void initializeState() {
2873:
2874: canvas3d.setSceneAmbient(canvas3d.ctx, 0.0f, 0.0f, 0.0f);
2875: canvas3d.disableFog(canvas3d.ctx);
2876: canvas3d.resetRenderingAttributes(canvas3d.ctx, false, false);
2877:
2878: if (canvas3d.shaderProgram != null) {
2879: canvas3d.shaderProgram.updateNative(canvas3d, false);
2880: canvas3d.shaderProgram = null;
2881: }
2882:
2883: // reset the previously enabled texture units
2884:
2885: int prevNumActiveTexUnit = canvas3d.getNumActiveTexUnit();
2886:
2887: if (prevNumActiveTexUnit > 0) {
2888: for (int i = 0; i < prevNumActiveTexUnit; i++) {
2889: if (canvas3d.texUnitState[i].texture != null) {
2890: canvas3d.resetTexture(canvas3d.ctx, i);
2891: canvas3d.texUnitState[i].texture = null;
2892: }
2893: if (canvas3d.texUnitState[i].texAttrs != null) {
2894: canvas3d.resetTextureAttributes(canvas3d.ctx);
2895: canvas3d.texUnitState[i].texAttrs = null;
2896: }
2897: if (canvas3d.texUnitState[i].texGen != null) {
2898: canvas3d.resetTexCoordGeneration(canvas3d.ctx);
2899: canvas3d.texUnitState[i].texGen = null;
2900: }
2901: canvas3d.texUnitState[i].mirror = null;
2902: }
2903: canvas3d.setNumActiveTexUnit(0);
2904: }
2905:
2906: canvas3d.resetPolygonAttributes(canvas3d.ctx);
2907: canvas3d.resetLineAttributes(canvas3d.ctx);
2908: canvas3d.resetPointAttributes(canvas3d.ctx);
2909: canvas3d.resetTransparency(canvas3d.ctx,
2910: RenderMolecule.SURFACE, PolygonAttributes.POLYGON_FILL,
2911: false, false);
2912: canvas3d.resetColoringAttributes(canvas3d.ctx, 1.0f, 1.0f,
2913: 1.0f, 1.0f, false);
2914: canvas3d.updateMaterial(canvas3d.ctx, 1.0f, 1.0f, 1.0f, 1.0f);
2915: }
2916:
2917: void resetAppearance() {
2918: //System.err.println("GC3D.resetAppearance ....");
2919:
2920: if (canvas3d.material != null) {
2921: canvas3d.updateMaterial(canvas3d.ctx, red, green, blue,
2922: alpha);
2923: canvas3d.material = null;
2924: canvas3d.canvasDirty |= Canvas3D.MATERIAL_DIRTY;
2925: }
2926:
2927: if (canvas3d.shaderProgram != null) {
2928: canvas3d.shaderProgram.updateNative(canvas3d, false);
2929: canvas3d.shaderProgram = null;
2930: // ShaderBin doesn't use dirty bit.
2931: }
2932:
2933: // reset the previously enabled texture units
2934: int prevNumActiveTexUnit = canvas3d.getNumActiveTexUnit();
2935:
2936: if (prevNumActiveTexUnit > 0) {
2937: for (int i = 0; i < prevNumActiveTexUnit; i++) {
2938: if (canvas3d.texUnitState[i].texture != null) {
2939: canvas3d.resetTexture(canvas3d.ctx, i);
2940: canvas3d.texUnitState[i].texture = null;
2941: }
2942: if (canvas3d.texUnitState[i].texAttrs != null) {
2943: canvas3d.resetTextureAttributes(canvas3d.ctx);
2944: canvas3d.texUnitState[i].texAttrs = null;
2945: }
2946: if (canvas3d.texUnitState[i].texGen != null) {
2947: canvas3d.resetTexCoordGeneration(canvas3d.ctx);
2948: canvas3d.texUnitState[i].texGen = null;
2949: }
2950: canvas3d.texUnitState[i].mirror = null;
2951: }
2952: canvas3d.canvasDirty |= Canvas3D.TEXTUREBIN_DIRTY
2953: | Canvas3D.TEXTUREATTRIBUTES_DIRTY;
2954: canvas3d.setNumActiveTexUnit(0);
2955: }
2956:
2957: if (canvas3d.coloringAttributes != null) {
2958: canvas3d.resetColoringAttributes(canvas3d.ctx, red, green,
2959: blue, alpha, enableLighting);
2960: canvas3d.coloringAttributes = null;
2961: canvas3d.canvasDirty |= Canvas3D.COLORINGATTRS_DIRTY;
2962: }
2963:
2964: if (canvas3d.transparency != null) {
2965: canvas3d.resetTransparency(canvas3d.ctx,
2966: RenderMolecule.SURFACE,
2967: PolygonAttributes.POLYGON_FILL, lineAA, pointAA);
2968: canvas3d.transparency = null;
2969: canvas3d.canvasDirty |= Canvas3D.TRANSPARENCYATTRS_DIRTY;
2970: }
2971:
2972: if (canvas3d.renderingAttrs != null) {
2973: ignoreVertexColors = false;
2974: canvas3d.resetRenderingAttributes(canvas3d.ctx,
2975: canvas3d.depthBufferWriteEnableOverride,
2976: canvas3d.depthBufferEnableOverride);
2977: canvas3d.renderingAttrs = null;
2978: canvas3d.canvasDirty |= Canvas3D.ATTRIBUTEBIN_DIRTY
2979: | Canvas3D.TEXTUREATTRIBUTES_DIRTY;
2980: }
2981:
2982: if (canvas3d.polygonAttributes != null) {
2983: canvas3d.resetPolygonAttributes(canvas3d.ctx);
2984: canvas3d.polygonAttributes = null;
2985: canvas3d.canvasDirty |= Canvas3D.POLYGONATTRS_DIRTY;
2986: }
2987:
2988: if (canvas3d.lineAttributes != null) {
2989: canvas3d.resetLineAttributes(canvas3d.ctx);
2990: canvas3d.lineAttributes = null;
2991: canvas3d.canvasDirty |= Canvas3D.LINEATTRS_DIRTY;
2992: }
2993:
2994: if (canvas3d.pointAttributes != null) {
2995: canvas3d.resetPointAttributes(canvas3d.ctx);
2996: canvas3d.pointAttributes = null;
2997: canvas3d.canvasDirty |= Canvas3D.POINTATTRS_DIRTY;
2998: }
2999: }
3000:
3001: void sendRenderMessage(boolean renderRun, int command, Object arg1,
3002: Object arg2) {
3003:
3004: // send a message to the request renderer
3005:
3006: J3dMessage renderMessage = new J3dMessage();
3007: renderMessage.threads = J3dThread.RENDER_THREAD;
3008: renderMessage.type = J3dMessage.RENDER_IMMEDIATE;
3009: renderMessage.universe = null;
3010: renderMessage.view = null;
3011: renderMessage.args[0] = canvas3d;
3012: renderMessage.args[1] = getImmCommand(command);
3013: renderMessage.args[2] = arg1;
3014: renderMessage.args[3] = arg2;
3015:
3016: while (!canvas3d.view.inRenderThreadData) {
3017: // wait until the renderer thread data in added in
3018: // MC:RenderThreadData array ready to receive message
3019: MasterControl.threadYield();
3020: }
3021:
3022: canvas3d.screen.renderer.rendererStructure
3023: .addMessage(renderMessage);
3024:
3025: if (renderRun) {
3026: // notify mc that there is work to do
3027: VirtualUniverse.mc.sendRunMessage(canvas3d.view,
3028: J3dThread.RENDER_THREAD);
3029: } else {
3030: // notify mc that there is work for the request renderer
3031: VirtualUniverse.mc.setWorkForRequestRenderer();
3032: }
3033: }
3034:
3035: void sendSoundMessage(int command, Object arg1, Object arg2) {
3036: if ((canvas3d.view == null) || (canvas3d.view.universe == null)) {
3037: return;
3038: }
3039: // send a message to the request sound scheduling
3040: J3dMessage soundMessage = new J3dMessage();
3041: soundMessage.threads = J3dThread.SOUND_SCHEDULER;
3042: soundMessage.type = J3dMessage.RENDER_IMMEDIATE;
3043: soundMessage.universe = canvas3d.view.universe;
3044: soundMessage.view = canvas3d.view;
3045: soundMessage.args[0] = getImmCommand(command);
3046: soundMessage.args[1] = arg1;
3047: soundMessage.args[2] = arg2;
3048: // notify mc that there is work to do
3049: VirtualUniverse.mc.processMessage(soundMessage);
3050: }
3051:
3052: static Integer getImmCommand(int command) {
3053: if (commands[command] == null) {
3054: commands[command] = new Integer(command);
3055: }
3056: return commands[command];
3057: }
3058:
3059: synchronized void runMonitor(int action) {
3060: if (action == J3dThread.WAIT) {
3061: while (!gcReady) {
3062: waiting++;
3063: try {
3064: wait();
3065: } catch (InterruptedException e) {
3066: }
3067: waiting--;
3068: }
3069: gcReady = false;
3070: } else {
3071: gcReady = true;
3072: if (waiting > 0) {
3073: notify();
3074: }
3075: }
3076: }
3077:
3078: }
|