From 581c4364345b46f66d1395c73d4b62feb0b20c32 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Mon, 7 May 2012 14:41:24 -0700 Subject: j3dcore: move Jogl-using classes into the main source folder We now assume Jogl support, keep it with the rest of the code. Signed-off-by: Harvey Harrison --- src/classes/share/javax/media/j3d/JoglContext.java | 166 + .../share/javax/media/j3d/JoglDrawable.java | 49 + .../javax/media/j3d/JoglDrawingSurfaceObject.java | 79 + .../javax/media/j3d/JoglGraphicsConfiguration.java | 138 + .../share/javax/media/j3d/JoglPipeline.java | 8631 ++++++++++++++++++++ .../share/javax/media/j3d/JoglShaderObject.java | 44 + 6 files changed, 9107 insertions(+) create mode 100644 src/classes/share/javax/media/j3d/JoglContext.java create mode 100644 src/classes/share/javax/media/j3d/JoglDrawable.java create mode 100644 src/classes/share/javax/media/j3d/JoglDrawingSurfaceObject.java create mode 100644 src/classes/share/javax/media/j3d/JoglGraphicsConfiguration.java create mode 100644 src/classes/share/javax/media/j3d/JoglPipeline.java create mode 100644 src/classes/share/javax/media/j3d/JoglShaderObject.java (limited to 'src/classes/share') diff --git a/src/classes/share/javax/media/j3d/JoglContext.java b/src/classes/share/javax/media/j3d/JoglContext.java new file mode 100644 index 0000000..a1f33c5 --- /dev/null +++ b/src/classes/share/javax/media/j3d/JoglContext.java @@ -0,0 +1,166 @@ +/* + * $RCSfile$ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.media.j3d; + +import java.nio.Buffer; +import java.nio.FloatBuffer; + +import javax.media.opengl.GL; +import javax.media.opengl.GLContext; + +/** + * Graphics context objects for Jogl rendering pipeline. + */ +class JoglContext implements Context { + private GLContext context; + + // Properties we need to keep track of for efficiency + private int maxTexCoordSets; + private float alphaClearValue; + private int currentTextureUnit; + private int currentCombinerUnit; + private boolean hasMultisample; + + // Needed for vertex attribute implementation + private JoglShaderObject shaderProgram; + + // Implementation of vertex attribute methods + static interface VertexAttributeImpl { + public void vertexAttrPointer(GL gl, + int index, int size, int type, int stride, Buffer pointer); + public void enableVertexAttrArray(GL gl, int index); + public void disableVertexAttrArray(GL gl, int index); + public void vertexAttr1fv(GL gl, int index, FloatBuffer buf); + public void vertexAttr2fv(GL gl, int index, FloatBuffer buf); + public void vertexAttr3fv(GL gl, int index, FloatBuffer buf); + public void vertexAttr4fv(GL gl, int index, FloatBuffer buf); + } + private VertexAttributeImpl vertexAttrImpl; + + class GLSLVertexAttributeImpl implements VertexAttributeImpl { + public void vertexAttrPointer(GL gl, + int index, int size, int type, int stride, Buffer pointer) { + gl.getGL2().glVertexAttribPointerARB(index + glslVertexAttrOffset, + size, type, false, stride, pointer); + } + + public void enableVertexAttrArray(GL gl, int index) { + gl.getGL2().glEnableVertexAttribArrayARB(index + glslVertexAttrOffset); + } + + public void disableVertexAttrArray(GL gl, int index) { + gl.getGL2().glDisableVertexAttribArrayARB(index + glslVertexAttrOffset); + } + + public void vertexAttr1fv(GL gl, int index, FloatBuffer buf) { + gl.getGL2().glVertexAttrib1fvARB(index + glslVertexAttrOffset, buf); + } + + public void vertexAttr2fv(GL gl, int index, FloatBuffer buf) { + gl.getGL2().glVertexAttrib2fvARB(index + glslVertexAttrOffset, buf); + } + + public void vertexAttr3fv(GL gl, int index, FloatBuffer buf) { + gl.getGL2().glVertexAttrib3fvARB(index + glslVertexAttrOffset, buf); + } + + public void vertexAttr4fv(GL gl, int index, FloatBuffer buf) { + gl.getGL2().glVertexAttrib4fvARB(index + glslVertexAttrOffset, buf); + } + } + + // Only used when GLSL shader library is active + private int glslVertexAttrOffset; + + JoglContext(GLContext context) { + this.context = context; + } + + GLContext getGLContext() { + return context; + } + + int getMaxTexCoordSets() { return maxTexCoordSets; } + void setMaxTexCoordSets(int val) { maxTexCoordSets = val; } + float getAlphaClearValue() { return alphaClearValue; } + void setAlphaClearValue(float val) { alphaClearValue = val; } + int getCurrentTextureUnit() { return currentTextureUnit; } + void setCurrentTextureUnit(int val) { currentTextureUnit = val; } + int getCurrentCombinerUnit() { return currentCombinerUnit; } + void setCurrentCombinerUnit(int val) { currentCombinerUnit = val; } + boolean getHasMultisample() { return hasMultisample; } + void setHasMultisample(boolean val){ hasMultisample = val; } + + void initGLSLVertexAttributeImpl() { + if (vertexAttrImpl != null) { + throw new RuntimeException("Should not initialize the vertex attribute implementation twice"); + } + vertexAttrImpl = new GLSLVertexAttributeImpl(); + } + + void vertexAttrPointer(GL gl, + int index, int size, int type, int stride, Buffer pointer) { + vertexAttrImpl.vertexAttrPointer(gl, index, size, type, stride, pointer); + } + + void enableVertexAttrArray(GL gl, int index) { + vertexAttrImpl.enableVertexAttrArray(gl, index); + } + + void disableVertexAttrArray(GL gl, int index) { + vertexAttrImpl.disableVertexAttrArray(gl, index); + } + + void vertexAttr1fv(GL gl, int index, FloatBuffer buf) { + vertexAttrImpl.vertexAttr1fv(gl, index, buf); + } + + void vertexAttr2fv(GL gl, int index, FloatBuffer buf) { + vertexAttrImpl.vertexAttr2fv(gl, index, buf); + } + + void vertexAttr3fv(GL gl, int index, FloatBuffer buf) { + vertexAttrImpl.vertexAttr3fv(gl, index, buf); + } + + void vertexAttr4fv(GL gl, int index, FloatBuffer buf) { + vertexAttrImpl.vertexAttr4fv(gl, index, buf); + } + + // Used in vertex attribute implementation + JoglShaderObject getShaderProgram() { return shaderProgram; } + void setShaderProgram(JoglShaderObject object) { shaderProgram = object; } + + // Only used when GLSL shaders are in use + int getGLSLVertexAttrOffset() { return glslVertexAttrOffset; } + void setGLSLVertexAttrOffset(int offset) { glslVertexAttrOffset = offset; } +} diff --git a/src/classes/share/javax/media/j3d/JoglDrawable.java b/src/classes/share/javax/media/j3d/JoglDrawable.java new file mode 100644 index 0000000..7adabcb --- /dev/null +++ b/src/classes/share/javax/media/j3d/JoglDrawable.java @@ -0,0 +1,49 @@ +/* + * $RCSfile$ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.media.j3d; + +import javax.media.opengl.GLDrawable; + +/** + * Drawable class for the Jogl rendering pipeline. + */ +class JoglDrawable implements Drawable { + private GLDrawable drawable; + + JoglDrawable(GLDrawable drawable) { + this.drawable = drawable; + } + + GLDrawable getGLDrawable() { + return drawable; + } +} diff --git a/src/classes/share/javax/media/j3d/JoglDrawingSurfaceObject.java b/src/classes/share/javax/media/j3d/JoglDrawingSurfaceObject.java new file mode 100644 index 0000000..439213e --- /dev/null +++ b/src/classes/share/javax/media/j3d/JoglDrawingSurfaceObject.java @@ -0,0 +1,79 @@ +/* + * $RCSfile$ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.media.j3d; + +/** + * The DrawingSurfaceObject class is used to manage native drawing surface + */ +class JoglDrawingSurfaceObject extends DrawingSurfaceObject { + + JoglDrawingSurfaceObject(Canvas3D cv) { + super(cv); + + // System.err.println("JoglDrawingSurfaceObject constructed"); + } + + synchronized boolean renderLock() { + // System.err.println("JoglDrawingSurfaceObject.renderLock()"); + gotDsiLock = true; + return true; + } + + synchronized void unLock() { + // System.err.println("JoglDrawingSurfaceObject.unLock()"); + gotDsiLock = false; + } + + synchronized void getDrawingSurfaceObjectInfo() { + // FIXME: we don't have all of the information we need here to + // create a GLDrawable for the Canvas3D, so for now, do nothing + + // FIXME: this mechanism is much too complicated + + /* + System.err.println("JoglDrawingSurfaceObject.getDrawingSurfaceObjectInfo()"); + + if (canvas.drawable == null) { + System.err.println( + "JoglDrawingSurfaceObject.getDrawingSurfaceObjectInfo: window = " + + canvas.drawable); + + // TODO: replace with a real JoglDrawable + canvas.drawable = new JoglDrawable(); + } + */ + } + + synchronized void invalidate() { + System.err.println("JoglDrawingSurfaceObject.invalidate()"); + } +} diff --git a/src/classes/share/javax/media/j3d/JoglGraphicsConfiguration.java b/src/classes/share/javax/media/j3d/JoglGraphicsConfiguration.java new file mode 100644 index 0000000..1f5989e --- /dev/null +++ b/src/classes/share/javax/media/j3d/JoglGraphicsConfiguration.java @@ -0,0 +1,138 @@ +/* + * $RCSfile$ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.media.j3d; + +import java.awt.AWTException; +import java.awt.DisplayMode; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.ImageCapabilities; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.VolatileImage; + +import com.jogamp.nativewindow.awt.AWTGraphicsDevice; +import javax.media.opengl.GLCapabilities; + +/** + * Class implementing the GraphicsConfiguration API, but not a "real" + * GraphicsConfiguration object. Wraps a GLCapabilities object and + * supports either immediate or deferred pixel format / visual + * selection depending on which platform we are running. + */ + +class JoglGraphicsConfiguration extends GraphicsConfiguration { + private GLCapabilities caps; + private int chosenIndex; + private GraphicsDevice device; + private AWTGraphicsDevice awtGraphicsDevice; + // Needed for Screen3D + private int width; + private int height; + + JoglGraphicsConfiguration(GLCapabilities caps, int chosenIndex, GraphicsDevice device) { + super(); + this.caps = caps; + this.chosenIndex = chosenIndex; + this.device = device; + //FIXME unit id? + this.awtGraphicsDevice = new AWTGraphicsDevice(this.device, 0); + DisplayMode m = device.getDisplayMode(); + width = m.getWidth(); + height = m.getHeight(); + } + + GLCapabilities getGLCapabilities() { + return caps; + } + + int getChosenIndex() { + return chosenIndex; + } + + public BufferedImage createCompatibleImage(int width, int height) { + throw new RuntimeException("Unimplemented"); + } + + public BufferedImage createCompatibleImage(int width, int height, + int transparency) { + throw new RuntimeException("Unimplemented"); + } + + public VolatileImage createCompatibleVolatileImage(int width, int height) { + throw new RuntimeException("Unimplemented"); + } + + public VolatileImage createCompatibleVolatileImage(int width, int height, int transparency) { + throw new RuntimeException("Unimplemented"); + } + + public VolatileImage createCompatibleVolatileImage(int width, int height, + ImageCapabilities caps) throws AWTException { + throw new RuntimeException("Unimplemented"); + } + + public VolatileImage createCompatibleVolatileImage(int width, int height, + ImageCapabilities caps, int transparency) throws AWTException { + throw new RuntimeException("Unimplemented"); + } + + public Rectangle getBounds() { + return new Rectangle(0, 0, width, height); + } + + public ColorModel getColorModel() { + throw new RuntimeException("Unimplemented"); + } + + public ColorModel getColorModel(int transparency) { + throw new RuntimeException("Unimplemented"); + } + + public AffineTransform getDefaultTransform() { + throw new RuntimeException("Unimplemented"); + } + + public GraphicsDevice getDevice() { + return device; + } + + public AWTGraphicsDevice getAwtGraphicsDevice() { + return awtGraphicsDevice; + } + + public AffineTransform getNormalizingTransform() { + throw new RuntimeException("Unimplemented"); + } +} diff --git a/src/classes/share/javax/media/j3d/JoglPipeline.java b/src/classes/share/javax/media/j3d/JoglPipeline.java new file mode 100644 index 0000000..d3e3a8d --- /dev/null +++ b/src/classes/share/javax/media/j3d/JoglPipeline.java @@ -0,0 +1,8631 @@ +/* + * $RCSfile$ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.media.j3d; + +import java.awt.BorderLayout; +import java.awt.Canvas; +import java.awt.DisplayMode; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.GraphicsConfigTemplate; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Method; +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.DoubleBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.jogamp.nativewindow.awt.AWTGraphicsConfiguration; +import com.jogamp.nativewindow.awt.AWTGraphicsDevice; +import com.jogamp.nativewindow.awt.AWTGraphicsScreen; +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.CapabilitiesChooser; +import javax.media.nativewindow.CapabilitiesImmutable; +import javax.media.nativewindow.GraphicsConfigurationFactory; +import javax.media.nativewindow.NativeWindow; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.opengl.DefaultGLCapabilitiesChooser; +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLCapabilitiesChooser; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLDrawableFactory; +import javax.media.opengl.GLException; +import javax.media.opengl.GLPbuffer; +import javax.media.opengl.GLProfile; +import javax.media.opengl.Threading; +import javax.media.opengl.glu.GLU; + +import com.jogamp.common.nio.Buffers; + +/** + * Concrete implementation of Pipeline class for the JOGL rendering + * pipeline. + */ +class JoglPipeline extends Pipeline { + // Currently prints for entry points not yet implemented + private static final boolean DEBUG = true; + // Currently prints for entry points already implemented + private static final boolean VERBOSE = false; + // Debugging output for graphics configuration selection + private static final boolean DEBUG_CONFIG = false; + // Prints extra debugging information + private static final boolean EXTRA_DEBUGGING = false; + // Number of milliseconds to wait for windows to pop up on screen + private static final int WAIT_TIME = 1000; + // Configurable constant just in case we want to change this later + private static final int MIN_FRAME_SIZE = 1; + + /** + * Constructor for singleton JoglPipeline instance + */ + protected JoglPipeline() { + } + + /** + * Initialize the pipeline + */ + void initialize(Pipeline.Type pipelineType) { + super.initialize(pipelineType); + + assert pipelineType == Pipeline.Type.JOGL; + + // Java3D maintains strict control over which threads perform OpenGL work + Threading.disableSingleThreading(); + + // TODO: finish this with any other needed initialization + } + + /** + * Returns true if the GLSL library is loaded and available. Note that this + * does not necessarily mean that GLSL is supported by the graphics card. + */ + boolean isGLSLLibraryAvailable() { + return true; + } + + + // --------------------------------------------------------------------- + + // + // GeometryArrayRetained methods + // + + // used for GeometryArrays by Copy or interleaved + void execute(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int startVIndex, int vcount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texUnitOffset, + int numActiveTexUnitState, + int vertexAttrCount, int[] vertexAttrSizes, + float[] varray, float[] carray, int cDirty) { + if (VERBOSE) System.err.println("JoglPipeline.execute()"); + + executeGeometryArray(ctx, geo, geo_type, isNonUniformScale, useAlpha, + ignoreVertexColors, startVIndex, vcount, vformat, + texCoordSetCount, texCoordSetMap, texCoordSetMapLen, + texUnitOffset, numActiveTexUnitState, + vertexAttrCount, vertexAttrSizes, + varray, null, carray, cDirty); + } + + // used by GeometryArray by Reference with java arrays + void executeVA(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int vcount, + int vformat, + int vdefined, + int initialCoordIndex, float[] vfcoords, double[] vdcoords, + int initialColorIndex, float[] cfdata, byte[] cbdata, + int initialNormalIndex, float[] ndata, + int vertexAttrCount, int[] vertexAttrSizes, + int[] vertexAttrIndices, float[][] vertexAttrData, + int texCoordMapLength, + int[] texcoordoffset, + int numActiveTexUnitState, + int[] texIndex, int texstride, Object[] texCoords, + int cdirty) { + if (VERBOSE) System.err.println("JoglPipeline.executeVA()"); + + boolean floatCoordDefined = ((vdefined & GeometryArrayRetained.COORD_FLOAT) != 0); + boolean doubleCoordDefined = ((vdefined & GeometryArrayRetained.COORD_DOUBLE) != 0); + boolean floatColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_FLOAT) != 0); + boolean byteColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_BYTE) != 0); + boolean normalsDefined = ((vdefined & GeometryArrayRetained.NORMAL_FLOAT) != 0); + boolean vattrDefined = ((vdefined & GeometryArrayRetained.VATTR_FLOAT) != 0); + boolean textureDefined = ((vdefined & GeometryArrayRetained.TEXCOORD_FLOAT) != 0); + + FloatBuffer fverts = null; + DoubleBuffer dverts = null; + FloatBuffer fclrs = null; + ByteBuffer bclrs = null; + FloatBuffer[] texCoordBufs = null; + FloatBuffer norms = null; + FloatBuffer[] vertexAttrBufs = null; + + // Get vertex attribute arrays + if (vattrDefined) { + vertexAttrBufs = getVertexAttrSetBuffer(vertexAttrData); + } + + // get texture arrays + if (textureDefined) { + texCoordBufs = getTexCoordSetBuffer(texCoords); + } + + // get coordinate array + if (floatCoordDefined) { + fverts = getVertexArrayBuffer(vfcoords); + } else if (doubleCoordDefined) { + dverts = getVertexArrayBuffer(vdcoords); + } + + // get color array + if (floatColorsDefined) { + fclrs = getColorArrayBuffer(cfdata); + } else if (byteColorsDefined) { + bclrs = getColorArrayBuffer(cbdata); + } + + // get normal array + if (normalsDefined) { + norms = getNormalArrayBuffer(ndata); + } + + int[] sarray = null; + int[] start_array = null; + int strip_len = 0; + if (geo_type == GeometryRetained.GEO_TYPE_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_LINE_STRIP_SET) { + sarray = ((GeometryStripArrayRetained) geo).stripVertexCounts; + strip_len = sarray.length; + start_array = ((GeometryStripArrayRetained) geo).stripStartOffsetIndices; + } + + executeGeometryArrayVA(ctx, geo, geo_type, + isNonUniformScale, ignoreVertexColors, + vcount, vformat, vdefined, + initialCoordIndex, fverts, dverts, + initialColorIndex, fclrs, bclrs, + initialNormalIndex, norms, + vertexAttrCount, vertexAttrSizes, + vertexAttrIndices, vertexAttrBufs, + texCoordMapLength, + texcoordoffset, numActiveTexUnitState, + texIndex, texstride, texCoordBufs, cdirty, + sarray, strip_len, start_array); + } + + // used by GeometryArray by Reference with NIO buffer + void executeVABuffer(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int vcount, + int vformat, + int vdefined, + int initialCoordIndex, + Object vcoords, + int initialColorIndex, + Object cdataBuffer, + float[] cfdata, byte[] cbdata, + int initialNormalIndex, Object ndata, + int vertexAttrCount, int[] vertexAttrSizes, + int[] vertexAttrIndices, Object[] vertexAttrData, + int texCoordMapLength, + int[] texcoordoffset, + int numActiveTexUnitState, + int[] texIndex, int texstride, Object[] texCoords, + int cdirty) { + if (VERBOSE) System.err.println("JoglPipeline.executeVABuffer()"); + + boolean floatCoordDefined = ((vdefined & GeometryArrayRetained.COORD_FLOAT) != 0); + boolean doubleCoordDefined = ((vdefined & GeometryArrayRetained.COORD_DOUBLE) != 0); + boolean floatColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_FLOAT) != 0); + boolean byteColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_BYTE) != 0); + boolean normalsDefined = ((vdefined & GeometryArrayRetained.NORMAL_FLOAT) != 0); + boolean vattrDefined = ((vdefined & GeometryArrayRetained.VATTR_FLOAT) != 0); + boolean textureDefined = ((vdefined & GeometryArrayRetained.TEXCOORD_FLOAT) != 0); + + FloatBuffer fverts = null; + DoubleBuffer dverts = null; + FloatBuffer fclrs = null; + ByteBuffer bclrs = null; + FloatBuffer[] texCoordBufs = null; + FloatBuffer norms = null; + FloatBuffer[] vertexAttrBufs = null; + + // Get vertex attribute arrays + if (vattrDefined) { + vertexAttrBufs = getVertexAttrSetBuffer(vertexAttrData); + } + + // get texture arrays + if (textureDefined) { + texCoordBufs = new FloatBuffer[texCoords.length]; + for (int i = 0; i < texCoords.length; i++) { + texCoordBufs[i] = (FloatBuffer) texCoords[i]; + } + } + + // get coordinate array + if (floatCoordDefined) { + fverts = (FloatBuffer) vcoords; + } else if (doubleCoordDefined) { + dverts = (DoubleBuffer) vcoords; + } + + if (fverts == null && dverts == null) { + return; + } + + // get color array + if (floatColorsDefined) { + if (cfdata != null) + fclrs = getColorArrayBuffer(cfdata); + else + fclrs = (FloatBuffer) cdataBuffer; + } else if (byteColorsDefined) { + if (cbdata != null) + bclrs = getColorArrayBuffer(cbdata); + else + bclrs = (ByteBuffer) cdataBuffer; + } + + // get normal array + if (normalsDefined) { + norms = (FloatBuffer) ndata; + } + + int[] sarray = null; + int[] start_array = null; + int strip_len = 0; + if (geo_type == GeometryRetained.GEO_TYPE_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_LINE_STRIP_SET) { + sarray = ((GeometryStripArrayRetained) geo).stripVertexCounts; + strip_len = sarray.length; + start_array = ((GeometryStripArrayRetained) geo).stripStartOffsetIndices; + } + + executeGeometryArrayVA(ctx, geo, geo_type, + isNonUniformScale, ignoreVertexColors, + vcount, vformat, vdefined, + initialCoordIndex, fverts, dverts, + initialColorIndex, fclrs, bclrs, + initialNormalIndex, norms, + vertexAttrCount, vertexAttrSizes, + vertexAttrIndices, vertexAttrBufs, + texCoordMapLength, + texcoordoffset, numActiveTexUnitState, + texIndex, texstride, texCoordBufs, cdirty, + sarray, strip_len, start_array); + } + + // used by GeometryArray by Reference in interleaved format with NIO buffer + void executeInterleavedBuffer(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int startVIndex, int vcount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texUnitOffset, + int numActiveTexUnit, + Object varray, float[] cdata, int cdirty) { + if (VERBOSE) System.err.println("JoglPipeline.executeInterleavedBuffer()"); + + executeGeometryArray(ctx, geo, geo_type, + isNonUniformScale, useAlpha, ignoreVertexColors, + startVIndex, vcount, vformat, + texCoordSetCount, texCoordSetMap, texCoordSetMapLen, + texUnitOffset, numActiveTexUnit, 0, null, + null, (Buffer) varray, cdata, cdirty); + } + + void setVertexFormat(Context ctx, GeometryArrayRetained geo, + int vformat, boolean useAlpha, boolean ignoreVertexColors) { + if (VERBOSE) System.err.println("JoglPipeline.setVertexFormat()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + // Enable and disable the appropriate pointers + if ((vformat & GeometryArray.NORMALS) != 0) { + gl.glEnableClientState(GL2.GL_NORMAL_ARRAY); + } else { + gl.glDisableClientState(GL2.GL_NORMAL_ARRAY); + } + if (!ignoreVertexColors && ((vformat & GeometryArray.COLOR) != 0)) { + gl.glEnableClientState(GL2.GL_COLOR_ARRAY); + } else { + gl.glDisableClientState(GL2.GL_COLOR_ARRAY); + } + +// FIXME: SUN_global_alpha +// if (gl.isExtensionAvailable("GL_SUN_global_alpha")) { +// if (useAlpha) { +// gl.glEnable(GL.GL_GLOBAL_ALPHA_SUN); +// } else { +// gl.glDisable(GL.GL_GLOBAL_ALPHA_SUN); +// } +// } + + if ((vformat & GeometryArray.COORDINATES) != 0) { + gl.glEnableClientState(GL2.GL_VERTEX_ARRAY); + } else { + gl.glDisableClientState(GL2.GL_VERTEX_ARRAY); + } + } + + void disableGlobalAlpha(Context ctx, GeometryArrayRetained geo, int vformat, + boolean useAlpha, boolean ignoreVertexColors) { + if (VERBOSE) System.err.println("JoglPipeline.disableGlobalAlpha()"); +// FIXME: SUN_global_alpha +// GL gl = context(ctx).getGL(); + +// if (gl.isExtensionAvailable("GL_SUN_global_alpha")) { +// if (!ignoreVertexColors && ((vformat & GeometryArray.COLOR) != 0)) { +// if (useAlpha) { +// gl.glDisable(GL.GL_GLOBAL_ALPHA_SUN); +// } +// } +// } + } + + // used for GeometryArrays + void buildGA(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, boolean updateAlpha, + float alpha, + boolean ignoreVertexColors, + int startVIndex, + int vcount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, int[] texCoordSetMapOffset, + int vertexAttrCount, int[] vertexAttrSizes, + double[] xform, double[] nxform, + float[] varray) { + if (VERBOSE) System.err.println("JoglPipeline.buildGA()"); + JoglContext jctx = (JoglContext) ctx; + GL2 gl = context(ctx).getGL().getGL2(); + FloatBuffer verts = null; + int stride = 0, coordoff = 0, normoff = 0, coloroff = 0, texCoordoff = 0; + int texStride = 0; + int vAttrOff = 0; + if ((vformat & GeometryArray.COORDINATES) != 0) { + stride += 3; + } + if ((vformat & GeometryArray.NORMALS) != 0) { + stride += 3; + coordoff += 3; + } + + if ((vformat & GeometryArray.COLOR) != 0) { + if ((vformat & GeometryArray.BY_REFERENCE) != 0) { + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { + stride += 4; + normoff += 4; + coordoff += 4; + } else { + stride += 3; + normoff += 3; + coordoff += 3; + } + } else { + stride += 4; + normoff += 4; + coordoff += 4; + } + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + texStride = 2 * texCoordSetCount; + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + texStride = 3 * texCoordSetCount; + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + texStride = 4 * texCoordSetCount; + } + stride += texStride; + normoff += texStride; + coloroff += texStride; + coordoff += texStride; + } + + int vAttrStride = 0; + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (int i = 0; i < vertexAttrCount; i++) { + vAttrStride += vertexAttrSizes[i]; + } + stride += vAttrStride; + normoff += vAttrStride; + coloroff += vAttrStride; + coordoff += vAttrStride; + texCoordoff += vAttrStride; + } + + int bstride = stride * Buffers.SIZEOF_FLOAT; + // Start sending down from the startVIndex + int initialOffset = startVIndex * stride; + normoff += initialOffset; + coloroff += initialOffset; + coordoff += initialOffset; + texCoordoff += initialOffset; + vAttrOff += initialOffset; + + // process alpha for geometryArray without alpha + boolean useAlpha = false; + if (updateAlpha && !ignoreVertexColors) { + useAlpha = true; + } + + if (geo_type == GeometryRetained.GEO_TYPE_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_LINE_STRIP_SET) { + int[] sarray = ((GeometryStripArrayRetained) geo).stripVertexCounts; + + int primType = 0; + switch (geo_type) { + case GeometryRetained.GEO_TYPE_TRI_STRIP_SET : + primType = GL.GL_TRIANGLE_STRIP; + break; + case GeometryRetained.GEO_TYPE_TRI_FAN_SET : + primType = GL.GL_TRIANGLE_FAN; + break; + case GeometryRetained.GEO_TYPE_LINE_STRIP_SET : + primType = GL.GL_LINE_STRIP; + break; + } + + if (ignoreVertexColors) { + vformat &= ~GeometryArray.COLOR; + } + + for (int i = 0; i < sarray.length; i++) { + gl.glBegin(primType); + for (int j = 0; j < sarray[i]; j++) { + if ((vformat & GeometryArray.NORMALS) != 0) { + if (nxform != null) { + float nx = (float) (nxform[0] * varray[normoff] + + nxform[1] * varray[normoff+1] + + nxform[2] * varray[normoff+2]); + float ny = (float) (nxform[4] * varray[normoff] + + nxform[5] * varray[normoff+1] + + nxform[6] * varray[normoff+2]); + float nz = (float) (nxform[8] * varray[normoff] + + nxform[9] * varray[normoff+1] + + nxform[10] * varray[normoff+2]); + gl.glNormal3f(nx, ny, nz); + } else { + gl.glNormal3f(varray[normoff], varray[normoff+1], varray[normoff+2]); + } + } + if ((vformat & GeometryArray.COLOR) != 0) { + if (useAlpha) { + gl.glColor4f(varray[coloroff], + varray[coloroff+1], + varray[coloroff+2], + varray[coloroff+3] * alpha); + } else { + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { // alpha is present + gl.glColor4f(varray[coloroff], + varray[coloroff+1], + varray[coloroff+2], + varray[coloroff+3]); + } else { + gl.glColor3f(varray[coloroff], + varray[coloroff+1], + varray[coloroff+2]); + } + } + } + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + int vaOff = vAttrOff; + if (verts == null) { + verts = FloatBuffer.wrap(varray); + } + for (int vaIdx = 0; vaIdx < vertexAttrCount; vaIdx++) { + switch (vertexAttrSizes[vaIdx]) { + case 1: + verts.position(vaOff); + jctx.vertexAttr1fv(gl, vaIdx, verts); + break; + case 2: + verts.position(vaOff); + jctx.vertexAttr2fv(gl, vaIdx, verts); + break; + case 3: + verts.position(vaOff); + jctx.vertexAttr3fv(gl, vaIdx, verts); + break; + case 4: + verts.position(vaOff); + jctx.vertexAttr4fv(gl, vaIdx, verts); + break; + } + + vaOff += vertexAttrSizes[vaIdx]; + } + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + if (texCoordSetMapLen > 0) { + if (gl.isExtensionAvailable("GL_VERSION_1_3")) { + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + for (int k = 0; k < texCoordSetMapLen; k++) { + if (texCoordSetMapOffset[k] != -1) { + int off = texCoordoff + texCoordSetMapOffset[k]; + gl.glMultiTexCoord2f(GL.GL_TEXTURE0 + k, + varray[off], + varray[off + 1]); + } + } + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + for (int k = 0; k < texCoordSetMapLen; k++) { + if (texCoordSetMapOffset[k] != -1) { + int off = texCoordoff + texCoordSetMapOffset[k]; + gl.glMultiTexCoord3f(GL.GL_TEXTURE0 + k, + varray[off], + varray[off + 1], + varray[off + 2]); + } + } + } else { + for (int k = 0; k < texCoordSetMapLen; k++) { + if (texCoordSetMapOffset[k] != -1) { + int off = texCoordoff + texCoordSetMapOffset[k]; + gl.glMultiTexCoord4f(GL.GL_TEXTURE0 + k, + varray[off], + varray[off + 1], + varray[off + 2], + varray[off + 3]); + } + } + } + } else { // no multitexture + if (texCoordSetMapOffset[0] != -1) { + int off = texCoordoff + texCoordSetMapOffset[0]; + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + gl.glTexCoord2f(varray[off], varray[off + 1]); + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + gl.glTexCoord3f(varray[off], varray[off + 1], varray[off + 2]); + } else { + gl.glTexCoord4f(varray[off], varray[off + 1], varray[off + 2], varray[off + 3]); + } + } + } // no multitexture + } + // texCoordSetMapLen can't be 0 if texture coordinates + // is to be specified + } + + if ((vformat & GeometryArray.COORDINATES) != 0) { + if (xform != null) { + // transform the vertex data with the static transform + float w = (float) (xform[12] * varray[coordoff] + + xform[13] * varray[coordoff+1] + + xform[14] * varray[coordoff+2] + + xform[15]); + float winv = 1.0f/w; + float vx = (float) (xform[0] * varray[coordoff] + + xform[1] * varray[coordoff+1] + + xform[2] * varray[coordoff+2] + + xform[3]) * winv; + float vy = (float) (xform[4] * varray[coordoff] + + xform[5] * varray[coordoff+1] + + xform[6] * varray[coordoff+2] + + xform[7]) * winv; + float vz = (float) (xform[8] * varray[coordoff] + + xform[9] * varray[coordoff+1] + + xform[10] * varray[coordoff+2] + + xform[11]) * winv; + gl.glVertex3f(vx, vy, vz); + } else { + gl.glVertex3f(varray[coordoff], varray[coordoff + 1], varray[coordoff + 2]); + } + } + normoff += stride; + coloroff += stride; + coordoff += stride; + texCoordoff += stride; + vAttrOff += stride; + } + gl.glEnd(); + } + } else if ((geo_type == GeometryRetained.GEO_TYPE_QUAD_SET) || + (geo_type == GeometryRetained.GEO_TYPE_TRI_SET) || + (geo_type == GeometryRetained.GEO_TYPE_POINT_SET) || + (geo_type == GeometryRetained.GEO_TYPE_LINE_SET)) { + int primType = 0; + switch (geo_type) { + case GeometryRetained.GEO_TYPE_QUAD_SET : + primType = GL2.GL_QUADS; + break; + case GeometryRetained.GEO_TYPE_TRI_SET : + primType = GL.GL_TRIANGLES; + break; + case GeometryRetained.GEO_TYPE_POINT_SET : + primType = GL.GL_POINTS; + break; + case GeometryRetained.GEO_TYPE_LINE_SET : + primType = GL.GL_LINES; + break; + } + + if (ignoreVertexColors) { + vformat &= ~GeometryArray.COLOR; + } + + gl.glBegin(primType); + for (int j = 0; j < vcount; j++) { + if ((vformat & GeometryArray.NORMALS) != 0) { + if (nxform != null) { + float nx = (float) (nxform[0] * varray[normoff] + + nxform[1] * varray[normoff+1] + + nxform[2] * varray[normoff+2]); + float ny = (float) (nxform[4] * varray[normoff] + + nxform[5] * varray[normoff+1] + + nxform[6] * varray[normoff+2]); + float nz = (float) (nxform[8] * varray[normoff] + + nxform[9] * varray[normoff+1] + + nxform[10] * varray[normoff+2]); + gl.glNormal3f(nx, ny, nz); + } else { + gl.glNormal3f(varray[normoff], varray[normoff + 1], varray[normoff + 2]); + } + } + if ((vformat & GeometryArray.COLOR) != 0) { + if (useAlpha) { + float cr, cg, cb, ca; + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { + cr = varray[coloroff]; + cg = varray[coloroff + 1]; + cb = varray[coloroff + 2]; + ca = varray[coloroff + 3] * alpha; + } else { + cr = varray[coloroff]; + cg = varray[coloroff + 1]; + cb = varray[coloroff + 2]; + ca = alpha; + } + gl.glColor4f(cr, cg, cb, ca); + } else { + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { // alpha is present + gl.glColor4f(varray[coloroff], + varray[coloroff + 1], + varray[coloroff + 2], + varray[coloroff + 3]); + } else { + gl.glColor3f(varray[coloroff], + varray[coloroff + 1], + varray[coloroff + 2]); + } + } + } + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + int vaOff = vAttrOff; + if (verts == null) { + verts = FloatBuffer.wrap(varray); + } + for (int vaIdx = 0; vaIdx < vertexAttrCount; vaIdx++) { + switch (vertexAttrSizes[vaIdx]) { + case 1: + verts.position(vaOff); + jctx.vertexAttr1fv(gl, vaIdx, verts); + break; + case 2: + verts.position(vaOff); + jctx.vertexAttr2fv(gl, vaIdx, verts); + break; + case 3: + verts.position(vaOff); + jctx.vertexAttr3fv(gl, vaIdx, verts); + break; + case 4: + verts.position(vaOff); + jctx.vertexAttr4fv(gl, vaIdx, verts); + break; + } + + vaOff += vertexAttrSizes[vaIdx]; + } + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + if (texCoordSetMapLen > 0) { + if (gl.isExtensionAvailable("GL_VERSION_1_3")) { + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + for (int k = 0; k < texCoordSetMapLen; k++) { + if (texCoordSetMapOffset[k] != -1) { + int off = texCoordoff + texCoordSetMapOffset[k]; + gl.glMultiTexCoord2f(GL.GL_TEXTURE0 + k, + varray[off], + varray[off + 1]); + } + } + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + for (int k = 0; k < texCoordSetMapLen; k++) { + if (texCoordSetMapOffset[k] != -1) { + int off = texCoordoff + texCoordSetMapOffset[k]; + gl.glMultiTexCoord3f(GL.GL_TEXTURE0 + k, + varray[off], + varray[off + 1], + varray[off + 2]); + } + } + } else { + for (int k = 0; k < texCoordSetMapLen; k++) { + if (texCoordSetMapOffset[k] != -1) { + int off = texCoordoff + texCoordSetMapOffset[k]; + gl.glMultiTexCoord4f(GL.GL_TEXTURE0 + k, + varray[off], + varray[off + 1], + varray[off + 2], + varray[off + 3]); + } + } + } + } else { // no multitexture + if (texCoordSetMapOffset[0] != -1) { + int off = texCoordoff + texCoordSetMapOffset[0]; + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + gl.glTexCoord2f(varray[off], varray[off + 1]); + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + gl.glTexCoord3f(varray[off], varray[off + 1], varray[off + 2]); + } else { + gl.glTexCoord4f(varray[off], varray[off + 1], varray[off + 2], varray[off + 3]); + } + } + } // no multitexture + } + // texCoordSetMapLen can't be 0 if texture coordinates is + // to be specified + } + + if ((vformat & GeometryArray.COORDINATES) != 0) { + if (xform != null) { + // transform the vertex data with the static transform + float w = (float) (xform[12] * varray[coordoff] + + xform[13] * varray[coordoff+1] + + xform[14] * varray[coordoff+2] + + xform[15]); + float winv = 1.0f/w; + float vx = (float) (xform[0] * varray[coordoff] + + xform[1] * varray[coordoff+1] + + xform[2] * varray[coordoff+2] + + xform[3]) * winv; + float vy = (float) (xform[4] * varray[coordoff] + + xform[5] * varray[coordoff+1] + + xform[6] * varray[coordoff+2] + + xform[7]) * winv; + float vz = (float) (xform[8] * varray[coordoff] + + xform[9] * varray[coordoff+1] + + xform[10] * varray[coordoff+2] + + xform[11]) * winv; + gl.glVertex3f(vx, vy, vz); + } else { + gl.glVertex3f(varray[coordoff], varray[coordoff + 1], varray[coordoff + 2]); + } + } + normoff += stride; + coloroff += stride; + coordoff += stride; + texCoordoff += stride; + vAttrOff += stride; + } + gl.glEnd(); + } + } + + // used to Build Dlist GeometryArray by Reference with java arrays + void buildGAForByRef(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, boolean updateAlpha, + float alpha, + boolean ignoreVertexColors, + int vcount, + int vformat, + int vdefined, + int initialCoordIndex, float[] vfcoords, double[] vdcoords, + int initialColorIndex, float[] cfdata, byte[] cbdata, + int initialNormalIndex, float[] ndata, + int vertexAttrCount, int[] vertexAttrSizes, + int[] vertexAttrIndices, float[][] vertexAttrData, + int texCoordMapLength, + int[] tcoordsetmap, + int[] texIndices, int texStride, Object[] texCoords, + double[] xform, double[] nxform) { + if (VERBOSE) System.err.println("JoglPipeline.buildGAForByRef()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + boolean floatCoordDefined = ((vdefined & GeometryArrayRetained.COORD_FLOAT) != 0); + boolean doubleCoordDefined = ((vdefined & GeometryArrayRetained.COORD_DOUBLE) != 0); + boolean floatColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_FLOAT) != 0); + boolean byteColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_BYTE) != 0); + boolean normalsDefined = ((vdefined & GeometryArrayRetained.NORMAL_FLOAT) != 0); + boolean vattrDefined = ((vdefined & GeometryArrayRetained.VATTR_FLOAT) != 0); + boolean textureDefined = ((vdefined & GeometryArrayRetained.TEXCOORD_FLOAT) != 0); + + FloatBuffer fverts = null; + DoubleBuffer dverts = null; + FloatBuffer fclrs = null; + ByteBuffer bclrs = null; + FloatBuffer[] texCoordBufs = null; + FloatBuffer norms = null; + FloatBuffer[] vertexAttrBufs = null; + + // Get vertex attribute arrays + if (vattrDefined) { + vertexAttrBufs = getVertexAttrSetBuffer(vertexAttrData); + } + + // get texture arrays + if (textureDefined) { + texCoordBufs = getTexCoordSetBuffer(texCoords); + } + + // process alpha for geometryArray without alpha + boolean useAlpha = false; + if (updateAlpha && !ignoreVertexColors) { + useAlpha = true; + } + + int[] sarray = null; + int[] start_array = null; + int strip_len = 0; + if (geo_type == GeometryRetained.GEO_TYPE_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_LINE_STRIP_SET) { + sarray = ((GeometryStripArrayRetained) geo).stripVertexCounts; + strip_len = sarray.length; + start_array = ((GeometryStripArrayRetained) geo).stripStartOffsetIndices; + } + + if (ignoreVertexColors) { + vformat &= ~GeometryArray.COLOR; + floatColorsDefined = false; + byteColorsDefined = false; + } + + // get coordinate array + if (floatCoordDefined) { + gl.glEnableClientState(GL2.GL_VERTEX_ARRAY); + fverts = getVertexArrayBuffer(vfcoords, (xform == null)); + if (xform != null) { + // Must copy in and transform data + for (int i = initialCoordIndex; i < vcount * 3; i += 3) { + fverts.put(i , (float) (xform[0] * vfcoords[i] + + xform[1] * vfcoords[i+1] + + xform[2] * vfcoords[i+2])); + fverts.put(i+1, (float) (xform[4] * vfcoords[i] + + xform[5] * vfcoords[i+1] + + xform[6] * vfcoords[i+2])); + fverts.put(i+2, (float) (xform[8] * vfcoords[i] + + xform[9] * vfcoords[i+1] + + xform[10] * vfcoords[i+2])); + } + } + } else if (doubleCoordDefined) { + gl.glEnableClientState(GL2.GL_VERTEX_ARRAY); + dverts = getVertexArrayBuffer(vdcoords, (xform == null)); + if (xform != null) { + // Must copy in and transform data + for (int i = initialCoordIndex; i < vcount * 3; i += 3) { + dverts.put(i , (xform[0] * vdcoords[i] + + xform[1] * vdcoords[i+1] + + xform[2] * vdcoords[i+2])); + dverts.put(i+1, (xform[4] * vdcoords[i] + + xform[5] * vdcoords[i+1] + + xform[6] * vdcoords[i+2])); + dverts.put(i+2, (xform[8] * vdcoords[i] + + xform[9] * vdcoords[i+1] + + xform[10] * vdcoords[i+2])); + } + } + } else { + gl.glDisableClientState(GL2.GL_VERTEX_ARRAY); + } + + // get color array + if (floatColorsDefined) { + gl.glEnableClientState(GL2.GL_COLOR_ARRAY); + fclrs = getColorArrayBuffer(cfdata, !useAlpha); + if (useAlpha) { + // Must copy in and modify color data + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { + for (int i = initialColorIndex; i < vcount * 4; i += 4) { + fclrs.put(i , cfdata[i]); + fclrs.put(i+1, cfdata[i+1]); + fclrs.put(i+2, cfdata[i+2]); + fclrs.put(i+3, alpha * cfdata[i+3]); + } + } else { + int k = 0; + for (int i = initialColorIndex; i < vcount * 4; i += 4) { + fclrs.put(i , cfdata[k++]); + fclrs.put(i+1, cfdata[k++]); + fclrs.put(i+2, cfdata[k++]); + fclrs.put(i+3, alpha); + } + } + vformat |= GeometryArray.WITH_ALPHA; + } + } else if (byteColorsDefined) { + gl.glEnableClientState(GL2.GL_COLOR_ARRAY); + bclrs = getColorArrayBuffer(cbdata, !useAlpha); + if (useAlpha) { + // Must copy in and modify color data + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { + for (int i = initialColorIndex; i < vcount * 4; i += 4) { + bclrs.put(i , cbdata[i]); + bclrs.put(i+1, cbdata[i+1]); + bclrs.put(i+2, cbdata[i+2]); + bclrs.put(i+3, (byte) (alpha * (int) (cbdata[i+3] & 0xFF))); + } + } else { + int k = 0; + for (int i = initialColorIndex; i < vcount * 4; i += 4) { + bclrs.put(i , cbdata[k++]); + bclrs.put(i+1, cbdata[k++]); + bclrs.put(i+2, cbdata[k++]); + bclrs.put(i+3, (byte) (alpha * 255.0f)); + } + } + vformat |= GeometryArray.WITH_ALPHA; + } + } else { + gl.glDisableClientState(GL2.GL_COLOR_ARRAY); + } + + // get normal array + if (normalsDefined) { + gl.glEnableClientState(GL2.GL_NORMAL_ARRAY); + norms = getNormalArrayBuffer(ndata, (nxform == null)); + if (nxform != null) { + // Must copy in and transform data + for (int i = initialNormalIndex; i < vcount * 3; i += 3) { + norms.put(i , (float) (nxform[0] * ndata[i] + + nxform[1] * ndata[i+1] + + nxform[2] * ndata[i+2])); + norms.put(i+1, (float) (nxform[4] * ndata[i] + + nxform[5] * ndata[i+1] + + nxform[6] * ndata[i+2])); + norms.put(i+2, (float) (nxform[8] * ndata[i] + + nxform[9] * ndata[i+1] + + nxform[10] * ndata[i+2])); + } + } + } else { + gl.glDisableClientState(GL2.GL_NORMAL_ARRAY); + } + + executeGeometryArrayVA(ctx, geo, geo_type, + isNonUniformScale, ignoreVertexColors, + vcount, vformat, vdefined, + initialCoordIndex, fverts, dverts, + initialColorIndex, fclrs, bclrs, + initialNormalIndex, norms, + vertexAttrCount, vertexAttrSizes, + vertexAttrIndices, vertexAttrBufs, + texCoordMapLength, + tcoordsetmap, texCoordMapLength, + texIndices, texStride, texCoordBufs, 0, + sarray, strip_len, start_array); + } + + //---------------------------------------------------------------------- + // Private helper methods for GeometryArrayRetained + // + + private void + testForInterleavedArrays(int vformat, + boolean[] useInterleavedArrays, + int[] iaFormat) { + if (VERBOSE) System.err.println("JoglPipeline.testForInterleavedArrays()"); + useInterleavedArrays[0] = true; + switch (vformat) { + case GeometryArray.COORDINATES : + iaFormat[0] = GL2.GL_V3F; break; + case (GeometryArray.COORDINATES | GeometryArray.NORMALS) : + iaFormat[0] = GL2.GL_N3F_V3F; break; + case (GeometryArray.COORDINATES | GeometryArray.TEXTURE_COORDINATE_2) : + iaFormat[0] = GL2.GL_T2F_V3F; break; + case (GeometryArray.COORDINATES | GeometryArray.NORMALS | GeometryArray.COLOR) : + case (GeometryArray.COORDINATES | GeometryArray.NORMALS | GeometryArray.COLOR | GeometryArray.WITH_ALPHA) : + iaFormat[0] = GL2.GL_C4F_N3F_V3F; break; + case (GeometryArray.COORDINATES | GeometryArray.NORMALS | GeometryArray.TEXTURE_COORDINATE_2) : + iaFormat[0] = GL2.GL_T2F_N3F_V3F; break; + case (GeometryArray.COORDINATES | GeometryArray.NORMALS | GeometryArray.COLOR | GeometryArray.TEXTURE_COORDINATE_2): + case (GeometryArray.COORDINATES | GeometryArray.NORMALS | GeometryArray.COLOR | GeometryArray.WITH_ALPHA | GeometryArray.TEXTURE_COORDINATE_2): + iaFormat[0] = GL2.GL_T2F_C4F_N3F_V3F; break; + default: + useInterleavedArrays[0] = false; break; + } + } + + private void + enableTexCoordPointer(GL2 gl, + int texUnit, + int texSize, + int texDataType, + int stride, + Buffer pointer) { + if (VERBOSE) System.err.println("JoglPipeline.enableTexCoordPointer()"); + clientActiveTextureUnit(gl, texUnit); + gl.glEnableClientState(GL2.GL_TEXTURE_COORD_ARRAY); + gl.glTexCoordPointer(texSize, texDataType, stride, pointer); + } + + private void disableTexCoordPointer(GL2 gl, int texUnit) { + if (VERBOSE) System.err.println("JoglPipeline.disableTexCoordPointer()"); + clientActiveTextureUnit(gl, texUnit); + gl.glDisableClientState(GL2.GL_TEXTURE_COORD_ARRAY); + } + + private void clientActiveTextureUnit(GL2 gl, int texUnit) { + if (VERBOSE) System.err.println("JoglPipeline.clientActiveTextureUnit()"); + if (gl.isExtensionAvailable("GL_VERSION_1_3")) { + gl.glClientActiveTexture(texUnit + GL.GL_TEXTURE0); + } + } + + + private void + executeTexture(int texCoordSetMapLen, + int texSize, int bstride, int texCoordoff, + int[] texCoordSetMapOffset, + int numActiveTexUnit, + FloatBuffer verts, GL2 gl) { + if (VERBOSE) System.err.println("JoglPipeline.executeTexture()"); + int tus = 0; /* texture unit state index */ + + for (int i = 0; i < numActiveTexUnit; i++) { + + tus = i; + + /* + * it's possible thattexture unit state index (tus) + * is greater than the texCoordSetMapOffsetLen, in this + * case, just disable TexCoordPointer. + */ + if ((tus < texCoordSetMapLen) && + (texCoordSetMapOffset[tus] != -1)) { + if (EXTRA_DEBUGGING) { + System.err.println(" texCoord position " + i + ": " + (texCoordoff + texCoordSetMapOffset[tus])); + } + verts.position(texCoordoff + texCoordSetMapOffset[tus]); + enableTexCoordPointer(gl, i, + texSize, GL.GL_FLOAT, bstride, + verts); + } else { + disableTexCoordPointer(gl, i); + } + } + } + + private void resetTexture(GL2 gl, JoglContext ctx) { + if (VERBOSE) System.err.println("JoglPipeline.resetTexture()"); + /* Disable texture coordinate arrays for all texture units */ + for (int i = 0; i < ctx.getMaxTexCoordSets(); i++) { + disableTexCoordPointer(gl, i); + } + /* Reset client active texture unit to 0 */ + clientActiveTextureUnit(gl, 0); + } + + private void + executeGeometryArray(Context absCtx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int startVIndex, int vcount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetMapOffset, + int numActiveTexUnitState, + int vertexAttrCount, int[] vertexAttrSizes, + float[] varray, Buffer varrayBuffer, + float[] carray, int cDirty) { + if (VERBOSE) System.err.println("JoglPipeline.executeGeometryArray()"); + JoglContext ctx = (JoglContext) absCtx; + GLContext context = context(ctx); + GL2 gl = context.getGL().getGL2(); + + boolean useInterleavedArrays; + int iaFormat = 0; + int primType = 0; + int stride = 0, coordoff = 0, normoff = 0, coloroff = 0, texCoordoff = 0; + int texSize = 0, texStride = 0; + int vAttrOff = 0; + int vAttrStride = 0; + int bstride = 0, cbstride = 0; + FloatBuffer verts = null; + FloatBuffer clrs = null; + int[] sarray = null; + int[] start_array = null; + + if (EXTRA_DEBUGGING) { + System.err.println("Vertex format: " + getVertexDescription(vformat)); + System.err.println("Geometry type: " + getGeometryDescription(geo_type)); + if (carray != null) { + System.err.println(" Separate color array"); + } else { + System.err.println(" Colors (if any) interleaved"); + } + } + + if ((vformat & GeometryArray.COORDINATES) != 0) { + stride += 3; + } + if ((vformat & GeometryArray.NORMALS) != 0) { + stride += 3; + coordoff += 3; + } + if ((vformat & GeometryArray.COLOR) != 0) { + if ((vformat & GeometryArray.WITH_ALPHA) != 0 ) { + stride += 4; + normoff += 4; + coordoff += 4; + } else { /* Handle the case of executeInterleaved 3f */ + stride += 3; + normoff += 3; + coordoff += 3; + } + } + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + if (EXTRA_DEBUGGING) { + System.err.println(" Number of tex coord sets: " + texCoordSetCount); + } + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + texSize = 2; + texStride = 2 * texCoordSetCount; + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + texSize = 3; + texStride = 3 * texCoordSetCount; + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + texSize = 4; + texStride = 4 * texCoordSetCount; + } + stride += texStride; + normoff += texStride; + coloroff += texStride; + coordoff += texStride; + } + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (int i = 0; i < vertexAttrCount; i++) { + vAttrStride += vertexAttrSizes[i]; + } + stride += vAttrStride; + normoff += vAttrStride; + coloroff += vAttrStride; + coordoff += vAttrStride; + texCoordoff += vAttrStride; + } + + bstride = stride * Buffers.SIZEOF_FLOAT; + + if (geo_type == GeometryRetained.GEO_TYPE_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_LINE_STRIP_SET) { + sarray = ((GeometryStripArrayRetained) geo).stripVertexCounts; + start_array = ((GeometryStripArrayRetained) geo).stripStartOffsetIndices; + } + + // We have to copy if the data isn't specified using NIO + if (varray != null) { + verts = getVertexArrayBuffer(varray); + } else if (varrayBuffer != null) { + verts = (FloatBuffer) varrayBuffer; + } else { + // This should never happen + throw new AssertionError("Unable to get vertex pointer"); + } + + // using byRef interleaved array and has a separate pointer, then .. + int cstride = stride; + if (carray != null) { + clrs = getColorArrayBuffer(carray); + cstride = 4; + } else { + // FIXME: need to "auto-slice" this buffer later + clrs = verts; + } + + cbstride = cstride * Buffers.SIZEOF_FLOAT; + + // Enable normalize for non-uniform scale (which rescale can't handle) + if (isNonUniformScale) { + gl.glEnable(GL2.GL_NORMALIZE); + } + + int startVertex = stride * startVIndex; + int startClrs = cstride * startVIndex; + if (clrs == verts) { + startClrs += coloroff; + } + + /*** Handle non-indexed strip GeometryArray first *******/ + if (geo_type == GeometryRetained.GEO_TYPE_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_LINE_STRIP_SET) { + if (ignoreVertexColors || (carray != null) || + ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0 && ((texCoordSetMapLen > 1) || + (texCoordSetCount > 1)))) { + useInterleavedArrays = false; + } else { + boolean[] tmp = new boolean[1]; + int[] tmp2 = new int[1]; + testForInterleavedArrays(vformat, tmp, tmp2); + useInterleavedArrays = tmp[0]; + iaFormat = tmp2[0]; + } + if (useInterleavedArrays) { + verts.position(startVertex); + gl.glInterleavedArrays(iaFormat, bstride, verts); + } else { + if ((vformat & GeometryArray.NORMALS) != 0) { + verts.position(startVertex + normoff); + gl.glNormalPointer(GL.GL_FLOAT, bstride, verts); + } + if (!ignoreVertexColors && (vformat & GeometryArray.COLOR) != 0) { + if (EXTRA_DEBUGGING) { + System.err.println(" Doing colors"); + } + clrs.position(startClrs); + if ((vformat & GeometryArray.WITH_ALPHA) != 0 || useAlpha) { + gl.glColorPointer(4, GL.GL_FLOAT, cbstride, clrs); + } else { + gl.glColorPointer(3, GL.GL_FLOAT, cbstride, clrs); + } + } + if ((vformat & GeometryArray.COORDINATES) != 0) { + verts.position(startVertex + coordoff); + gl.glVertexPointer(3, GL.GL_FLOAT, bstride, verts); + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + executeTexture(texCoordSetMapLen, + texSize, bstride, texCoordoff, + texCoordSetMapOffset, + numActiveTexUnitState, + verts, gl); + } + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + int vAttrOffset = startVertex + vAttrOff; + for (int i = 0; i < vertexAttrCount; i++) { + ctx.enableVertexAttrArray(gl, i); + verts.position(vAttrOffset); + ctx.vertexAttrPointer(gl, i, vertexAttrSizes[i], + GL.GL_FLOAT, bstride, verts); + vAttrOffset += vertexAttrSizes[i]; + } + } + } + + switch (geo_type) { + case GeometryRetained.GEO_TYPE_TRI_STRIP_SET: + primType = GL.GL_TRIANGLE_STRIP; + break; + case GeometryRetained.GEO_TYPE_TRI_FAN_SET: + primType = GL.GL_TRIANGLE_FAN; + break; + case GeometryRetained.GEO_TYPE_LINE_STRIP_SET: + primType = GL.GL_LINE_STRIP; + break; + } + + if (gl.isExtensionAvailable("GL_EXT_multi_draw_arrays")) { + gl.glMultiDrawArrays(primType, start_array, 0, sarray, 0, sarray.length); + } else { + for (int i = 0; i < sarray.length; i++) { + gl.glDrawArrays(primType, start_array[i], sarray[i]); + } + } + } else if ((geo_type == GeometryRetained.GEO_TYPE_QUAD_SET) || + (geo_type == GeometryRetained.GEO_TYPE_TRI_SET) || + (geo_type == GeometryRetained.GEO_TYPE_POINT_SET) || + (geo_type == GeometryRetained.GEO_TYPE_LINE_SET)) { + /******* Handle non-indexed non-striped GeometryArray now *****/ + if (ignoreVertexColors || (carray != null) || + ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0 && ((texCoordSetMapLen > 1) || + (texCoordSetCount > 1)))) { + useInterleavedArrays = false; + } else { + boolean[] tmp = new boolean[1]; + int[] tmp2 = new int[1]; + testForInterleavedArrays(vformat, tmp, tmp2); + useInterleavedArrays = tmp[0]; + iaFormat = tmp2[0]; + } + + if (useInterleavedArrays) { + verts.position(startVertex); + gl.glInterleavedArrays(iaFormat, bstride, verts); + } else { + if (EXTRA_DEBUGGING) { + System.err.println(" startVertex: " + startVertex); + System.err.println(" stride: " + stride); + System.err.println(" bstride: " + bstride); + System.err.println(" normoff: " + normoff); + System.err.println(" coloroff: " + coloroff); + System.err.println(" coordoff: " + coordoff); + System.err.println(" texCoordoff: " + texCoordoff); + } + if ((vformat & GeometryArray.NORMALS) != 0) { + verts.position(startVertex + normoff); + gl.glNormalPointer(GL.GL_FLOAT, bstride, verts); + } + if (!ignoreVertexColors && (vformat & GeometryArray.COLOR) != 0) { + clrs.position(startClrs); + if ((vformat & GeometryArray.WITH_ALPHA) != 0 || useAlpha) { + gl.glColorPointer(4, GL.GL_FLOAT, cbstride, clrs); + } else { + gl.glColorPointer(3, GL.GL_FLOAT, cbstride, clrs); + } + } + if ((vformat & GeometryArray.COORDINATES) != 0) { + verts.position(startVertex + coordoff); + gl.glVertexPointer(3, GL.GL_FLOAT, bstride, verts); + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + executeTexture(texCoordSetMapLen, + texSize, bstride, texCoordoff, + texCoordSetMapOffset, + numActiveTexUnitState, + verts, gl); + } + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + int vAttrOffset = startVertex + vAttrOff; + for (int i = 0; i < vertexAttrCount; i++) { + ctx.enableVertexAttrArray(gl, i); + verts.position(vAttrOffset); + ctx.vertexAttrPointer(gl, i, vertexAttrSizes[i], + GL.GL_FLOAT, bstride, verts); + vAttrOffset += vertexAttrSizes[i]; + } + } + } + switch (geo_type){ + case GeometryRetained.GEO_TYPE_QUAD_SET : gl.glDrawArrays(GL2.GL_QUADS, 0, vcount); break; + case GeometryRetained.GEO_TYPE_TRI_SET : gl.glDrawArrays(GL.GL_TRIANGLES, 0, vcount); break; + case GeometryRetained.GEO_TYPE_POINT_SET: gl.glDrawArrays(GL.GL_POINTS, 0, vcount); break; + case GeometryRetained.GEO_TYPE_LINE_SET : gl.glDrawArrays(GL.GL_LINES, 0, vcount); break; + } + } + + /* clean up if we turned on normalize */ + if (isNonUniformScale) { + gl.glDisable(GL2.GL_NORMALIZE); + } + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + resetVertexAttrs(gl, ctx, vertexAttrCount); + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + resetTexture(gl, ctx); + } + } + + + // glLockArrays() is invoked only for indexed geometry, and the + // vertexCount is guarenteed to be >= 0. + private void lockArray(GL2 gl, int vertexCount) { + if (gl.isExtensionAvailable("GL_EXT_compiled_vertex_array")) { + gl.glLockArraysEXT(0, vertexCount); + } + } + + private void unlockArray(GL2 gl) { + if (gl.isExtensionAvailable("GL_EXT_compiled_vertex_array")) { + gl.glUnlockArraysEXT(); + } + } + + private void + executeGeometryArrayVA(Context absCtx, + GeometryArrayRetained geo, + int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int vcount, + int vformat, + int vdefined, + int initialCoordIndex, FloatBuffer fverts, DoubleBuffer dverts, + int initialColorIndex, FloatBuffer fclrs, ByteBuffer bclrs, + int initialNormalIndex, FloatBuffer norms, + int vertexAttrCount, int[] vertexAttrSizes, + int[] vertexAttrIndices, FloatBuffer[] vertexAttrData, + int texCoordMapLength, + int[] texCoordSetMap, + int numActiveTexUnit, + int[] texindices, int texStride, FloatBuffer[] texCoords, + int cdirty, + int[] sarray, + int strip_len, + int[] start_array) { + JoglContext ctx = (JoglContext) absCtx; + GLContext context = context(ctx); + GL2 gl = context.getGL().getGL2(); + + boolean floatCoordDefined = ((vdefined & GeometryArrayRetained.COORD_FLOAT) != 0); + boolean doubleCoordDefined = ((vdefined & GeometryArrayRetained.COORD_DOUBLE) != 0); + boolean floatColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_FLOAT) != 0); + boolean byteColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_BYTE) != 0); + boolean normalsDefined = ((vdefined & GeometryArrayRetained.NORMAL_FLOAT) != 0); + boolean vattrDefined = ((vdefined & GeometryArrayRetained.VATTR_FLOAT) != 0); + boolean textureDefined = ((vdefined & GeometryArrayRetained.TEXCOORD_FLOAT) != 0); + + // Enable normalize for non-uniform scale (which rescale can't handle) + if (isNonUniformScale) { + gl.glEnable(GL2.GL_NORMALIZE); + } + + int coordoff = 3 * initialCoordIndex; + // Define the data pointers + if (floatCoordDefined) { + fverts.position(coordoff); + gl.glVertexPointer(3, GL.GL_FLOAT, 0, fverts); + } else if (doubleCoordDefined){ + dverts.position(coordoff); + gl.glVertexPointer(3, GL2.GL_DOUBLE, 0, dverts); + } + + if (floatColorsDefined) { + int coloroff; + int sz; + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { + coloroff = 4 * initialColorIndex; + sz = 4; + } else { + coloroff = 3 * initialColorIndex; + sz = 3; + } + fclrs.position(coloroff); + gl.glColorPointer(sz, GL.GL_FLOAT, 0, fclrs); + } else if (byteColorsDefined) { + int coloroff; + int sz; + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { + coloroff = 4 * initialColorIndex; + sz = 4; + } else { + coloroff = 3 * initialColorIndex; + sz = 3; + } + bclrs.position(coloroff); + gl.glColorPointer(sz, GL.GL_UNSIGNED_BYTE, 0, bclrs); + } + if (normalsDefined) { + int normoff = 3 * initialNormalIndex; + norms.position(normoff); + gl.glNormalPointer(GL.GL_FLOAT, 0, norms); + } + + if (vattrDefined) { + for (int i = 0; i < vertexAttrCount; i++) { + FloatBuffer vertexAttrs = vertexAttrData[i]; + int sz = vertexAttrSizes[i]; + int initIdx = vertexAttrIndices[i]; + ctx.enableVertexAttrArray(gl, i); + vertexAttrs.position(initIdx * sz); + ctx.vertexAttrPointer(gl, i, sz, GL.GL_FLOAT, 0, vertexAttrs); + } + } + + if (textureDefined) { + int texSet = 0; + for (int i = 0; i < numActiveTexUnit; i++) { + if (( i < texCoordMapLength) && + ((texSet = texCoordSetMap[i]) != -1)) { + FloatBuffer buf = texCoords[texSet]; + buf.position(texStride * texindices[texSet]); + enableTexCoordPointer(gl, i, texStride, + GL.GL_FLOAT, 0, buf); + } else { + disableTexCoordPointer(gl, i); + } + } + + // Reset client active texture unit to 0 + clientActiveTextureUnit(gl, 0); + } + + if (geo_type == GeometryRetained.GEO_TYPE_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_LINE_STRIP_SET) { + int primType = 0; + switch (geo_type) { + case GeometryRetained.GEO_TYPE_TRI_STRIP_SET: + primType = GL.GL_TRIANGLE_STRIP; + break; + case GeometryRetained.GEO_TYPE_TRI_FAN_SET: + primType = GL.GL_TRIANGLE_FAN; + break; + case GeometryRetained.GEO_TYPE_LINE_STRIP_SET: + primType = GL.GL_LINE_STRIP; + break; + } + if (gl.isExtensionAvailable("GL_EXT_multi_draw_arrays")) { + gl.glMultiDrawArrays(primType, start_array, 0, sarray, 0, strip_len); + } else if (gl.isExtensionAvailable("GL_VERSION_1_4")) { + gl.glMultiDrawArrays(primType, start_array, 0, sarray, 0, strip_len); + } else { + for (int i = 0; i < strip_len; i++) { + gl.glDrawArrays(primType, start_array[i], sarray[i]); + } + } + } else { + switch (geo_type){ + case GeometryRetained.GEO_TYPE_QUAD_SET : gl.glDrawArrays(GL2.GL_QUADS, 0, vcount); break; + case GeometryRetained.GEO_TYPE_TRI_SET : gl.glDrawArrays(GL.GL_TRIANGLES, 0, vcount); break; + case GeometryRetained.GEO_TYPE_POINT_SET : gl.glDrawArrays(GL.GL_POINTS, 0, vcount); break; + case GeometryRetained.GEO_TYPE_LINE_SET : gl.glDrawArrays(GL.GL_LINES, 0, vcount); break; + } + } + + // clean up if we turned on normalize + if (isNonUniformScale) { + gl.glDisable(GL2.GL_NORMALIZE); + } + + if (vattrDefined) { + resetVertexAttrs(gl, ctx, vertexAttrCount); + } + + if (textureDefined) { + resetTexture(gl, ctx); + } + } + + private String getVertexDescription(int vformat) { + String res = ""; + if ((vformat & GeometryArray.COORDINATES) != 0) res += "COORDINATES "; + if ((vformat & GeometryArray.NORMALS) != 0) res += "NORMALS "; + if ((vformat & GeometryArray.COLOR) != 0) res += "COLOR "; + if ((vformat & GeometryArray.WITH_ALPHA) != 0) res += "(WITH_ALPHA) "; + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) res += "TEXTURE_COORDINATE "; + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) != 0) res += "(2) "; + if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) != 0) res += "(3) "; + if ((vformat & GeometryArray.TEXTURE_COORDINATE_4) != 0) res += "(4) "; + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) res += "VERTEX_ATTRIBUTES "; + return res; + } + + private String getGeometryDescription(int geo_type) { + switch (geo_type) { + case GeometryRetained.GEO_TYPE_TRI_STRIP_SET : return "GEO_TYPE_TRI_STRIP_SET"; + case GeometryRetained.GEO_TYPE_TRI_FAN_SET : return "GEO_TYPE_TRI_FAN_SET"; + case GeometryRetained.GEO_TYPE_LINE_STRIP_SET: return "GEO_TYPE_LINE_STRIP_SET"; + case GeometryRetained.GEO_TYPE_QUAD_SET : return "GEO_TYPE_QUAD_SET"; + case GeometryRetained.GEO_TYPE_TRI_SET : return "GEO_TYPE_TRI_SET"; + case GeometryRetained.GEO_TYPE_POINT_SET : return "GEO_TYPE_POINT_SET"; + case GeometryRetained.GEO_TYPE_LINE_SET : return "GEO_TYPE_LINE_SET"; + default: return "(unknown " + geo_type + ")"; + } + } + + private void resetVertexAttrs(GL gl, JoglContext ctx, int vertexAttrCount) { + // Disable specified vertex attr arrays + for (int i = 0; i < vertexAttrCount; i++) { + ctx.disableVertexAttrArray(gl, i); + } + } + + + // --------------------------------------------------------------------- + + // + // IndexedGeometryArrayRetained methods + // + + // by-copy or interleaved, by reference, Java arrays + void executeIndexedGeometry(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int initialIndexIndex, + int indexCount, + int vertexCount, int vformat, + int vertexAttrCount, int[] vertexAttrSizes, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetOffset, + int numActiveTexUnitState, + float[] varray, float[] carray, + int cdirty, + int[] indexCoord) { + if (VERBOSE) System.err.println("JoglPipeline.executeIndexedGeometry()"); + + executeIndexedGeometryArray(ctx, geo, geo_type, + isNonUniformScale, useAlpha, ignoreVertexColors, + initialIndexIndex, indexCount, + vertexCount, vformat, + vertexAttrCount, vertexAttrSizes, + texCoordSetCount, texCoordSetMap, texCoordSetMapLen, + texCoordSetOffset, + numActiveTexUnitState, + varray, null, carray, + cdirty, indexCoord); + } + + // interleaved, by reference, nio buffer + void executeIndexedGeometryBuffer(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int initialIndexIndex, + int indexCount, + int vertexCount, int vformat, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetOffset, + int numActiveTexUnitState, + Object vdata, float[] carray, + int cDirty, + int[] indexCoord) { + if (VERBOSE) System.err.println("JoglPipeline.executeIndexedGeometryBuffer()"); + + executeIndexedGeometryArray(ctx, geo, geo_type, + isNonUniformScale, useAlpha, ignoreVertexColors, + initialIndexIndex, indexCount, vertexCount, vformat, + 0, null, + texCoordSetCount, texCoordSetMap, texCoordSetMapLen, texCoordSetOffset, + numActiveTexUnitState, + null, (FloatBuffer) vdata, carray, + cDirty, indexCoord); + } + + // non interleaved, by reference, Java arrays + void executeIndexedGeometryVA(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int initialIndexIndex, + int validIndexCount, + int vertexCount, + int vformat, + int vdefined, + float[] vfcoords, double[] vdcoords, + float[] cfdata, byte[] cbdata, + float[] ndata, + int vertexAttrCount, int[] vertexAttrSizes, + float[][] vertexAttrData, + int texCoordMapLength, + int[] texcoordoffset, + int numActiveTexUnitState, + int texStride, Object[] texCoords, + int cdirty, + int[] indexCoord) { + if (VERBOSE) System.err.println("JoglPipeline.executeIndexedGeometryVA()"); + + boolean floatCoordDefined = ((vdefined & GeometryArrayRetained.COORD_FLOAT) != 0); + boolean doubleCoordDefined = ((vdefined & GeometryArrayRetained.COORD_DOUBLE) != 0); + boolean floatColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_FLOAT) != 0); + boolean byteColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_BYTE) != 0); + boolean normalsDefined = ((vdefined & GeometryArrayRetained.NORMAL_FLOAT) != 0); + boolean vattrDefined = ((vdefined & GeometryArrayRetained.VATTR_FLOAT) != 0); + boolean textureDefined = ((vdefined & GeometryArrayRetained.TEXCOORD_FLOAT) != 0); + + FloatBuffer fverts = null; + DoubleBuffer dverts = null; + FloatBuffer fclrs = null; + ByteBuffer bclrs = null; + FloatBuffer[] texCoordBufs = null; + FloatBuffer norms = null; + FloatBuffer[] vertexAttrBufs = null; + + // Get vertex attribute arrays + if (vattrDefined) { + vertexAttrBufs = getVertexAttrSetBuffer(vertexAttrData); + } + + // get texture arrays + if (textureDefined) { + texCoordBufs = getTexCoordSetBuffer(texCoords); + } + + int[] sarray = null; + int strip_len = 0; + if (geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET) { + sarray = ((IndexedGeometryStripArrayRetained) geo).stripIndexCounts; + strip_len = sarray.length; + } + + // get coordinate array + if (floatCoordDefined) { + fverts = getVertexArrayBuffer(vfcoords); + } else if (doubleCoordDefined) { + dverts = getVertexArrayBuffer(vdcoords); + } + + // get color array + if (floatColorsDefined) { + fclrs = getColorArrayBuffer(cfdata); + } else if (byteColorsDefined) { + bclrs = getColorArrayBuffer(cbdata); + } + + // get normal array + if (normalsDefined) { + norms = getNormalArrayBuffer(ndata); + } + + executeIndexedGeometryArrayVA(ctx, geo, geo_type, + isNonUniformScale, ignoreVertexColors, + initialIndexIndex, validIndexCount, vertexCount, + vformat, vdefined, + fverts, dverts, + fclrs, bclrs, + norms, + vertexAttrCount, vertexAttrSizes, vertexAttrBufs, + texCoordMapLength, texcoordoffset, + numActiveTexUnitState, + texStride, texCoordBufs, + cdirty, indexCoord, + sarray, strip_len); + } + + // non interleaved, by reference, nio buffer + void executeIndexedGeometryVABuffer(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int initialIndexIndex, + int validIndexCount, + int vertexCount, + int vformat, + int vdefined, + Object vcoords, + Object cdataBuffer, + float[] cfdata, byte[] cbdata, + Object ndata, + int vertexAttrCount, int[] vertexAttrSizes, + Object[] vertexAttrData, + int texCoordMapLength, + int[] texcoordoffset, + int numActiveTexUnitState, + int texStride, Object[] texCoords, + int cdirty, + int[] indexCoord) { + if (VERBOSE) System.err.println("JoglPipeline.executeIndexedGeometryVABuffer()"); + + boolean floatCoordDefined = ((vdefined & GeometryArrayRetained.COORD_FLOAT) != 0); + boolean doubleCoordDefined = ((vdefined & GeometryArrayRetained.COORD_DOUBLE) != 0); + boolean floatColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_FLOAT) != 0); + boolean byteColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_BYTE) != 0); + boolean normalsDefined = ((vdefined & GeometryArrayRetained.NORMAL_FLOAT) != 0); + boolean vattrDefined = ((vdefined & GeometryArrayRetained.VATTR_FLOAT) != 0); + boolean textureDefined = ((vdefined & GeometryArrayRetained.TEXCOORD_FLOAT) != 0); + + FloatBuffer fverts = null; + DoubleBuffer dverts = null; + FloatBuffer fclrs = null; + ByteBuffer bclrs = null; + FloatBuffer[] texCoordBufs = null; + FloatBuffer norms = null; + FloatBuffer[] vertexAttrBufs = null; + + // Get vertex attribute arrays + if (vattrDefined) { + vertexAttrBufs = getVertexAttrSetBuffer(vertexAttrData); + } + + // get texture arrays + if (textureDefined) { + texCoordBufs = new FloatBuffer[texCoords.length]; + for (int i = 0; i < texCoords.length; i++) { + texCoordBufs[i] = (FloatBuffer) texCoords[i]; + } + } + + // get coordinate array + if (floatCoordDefined) { + fverts = (FloatBuffer) vcoords; + } else if (doubleCoordDefined) { + dverts = (DoubleBuffer) vcoords; + } + + if (fverts == null && dverts == null) { + return; + } + + int[] sarray = null; + int strip_len = 0; + if (geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET) { + sarray = ((IndexedGeometryStripArrayRetained) geo).stripIndexCounts; + strip_len = sarray.length; + } + + // get color array + if (floatColorsDefined) { + if (cfdata != null) + fclrs = getColorArrayBuffer(cfdata); + else + fclrs = (FloatBuffer) cdataBuffer; + } else if (byteColorsDefined) { + if (cbdata != null) + bclrs = getColorArrayBuffer(cbdata); + else + bclrs = (ByteBuffer) cdataBuffer; + } + + // get normal array + if (normalsDefined) { + norms = (FloatBuffer) ndata; + } + + executeIndexedGeometryArrayVA(ctx, geo, geo_type, + isNonUniformScale, ignoreVertexColors, + initialIndexIndex, validIndexCount, vertexCount, + vformat, vdefined, + fverts, dverts, + fclrs, bclrs, + norms, + vertexAttrCount, vertexAttrSizes, vertexAttrBufs, + texCoordMapLength, texcoordoffset, + numActiveTexUnitState, + texStride, texCoordBufs, + cdirty, indexCoord, + sarray, strip_len); + } + + // by-copy geometry + void buildIndexedGeometry(Context absCtx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, boolean updateAlpha, + float alpha, + boolean ignoreVertexColors, + int initialIndexIndex, + int validIndexCount, + int vertexCount, + int vformat, + int vertexAttrCount, int[] vertexAttrSizes, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetMapOffset, + double[] xform, double[] nxform, + float[] varray, int[] indexCoord) { + if (VERBOSE) System.err.println("JoglPipeline.buildIndexedGeometry()"); + + JoglContext ctx = (JoglContext) absCtx; + GL2 gl = context(ctx).getGL().getGL2(); + + boolean useInterleavedArrays; + int iaFormat = 0; + int primType = 0; + int stride = 0, coordoff = 0, normoff = 0, coloroff = 0, texCoordoff = 0; + int texSize = 0, texStride = 0; + int vAttrOff = 0; + int vAttrStride = 0; + int bstride = 0, cbstride = 0; + FloatBuffer verts = null; + FloatBuffer clrs = null; + int[] sarray = null; + int strip_len = 0; + boolean useAlpha = false; + + if ((vformat & GeometryArray.COORDINATES) != 0) { + gl.glEnableClientState(GL2.GL_VERTEX_ARRAY); + stride += 3; + } else { + gl.glDisableClientState(GL2.GL_VERTEX_ARRAY); + } + + if ((vformat & GeometryArray.NORMALS) != 0) { + gl.glEnableClientState(GL2.GL_NORMAL_ARRAY); + stride += 3; + coordoff += 3; + } else { + gl.glDisableClientState(GL2.GL_NORMAL_ARRAY); + } + + if ((vformat & GeometryArray.COLOR) != 0) { + gl.glEnableClientState(GL2.GL_COLOR_ARRAY); + stride += 4; + normoff += 4; + coordoff += 4; + } else { + gl.glDisableClientState(GL2.GL_COLOR_ARRAY); + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + texSize = 2; + texStride = 2 * texCoordSetCount; + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + texSize = 3; + texStride = 3 * texCoordSetCount; + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + texSize = 4; + texStride = 4 * texCoordSetCount; + } + stride += texStride; + normoff += texStride; + coloroff += texStride; + coordoff += texStride; + } + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (int i = 0; i < vertexAttrCount; i++) { + vAttrStride += vertexAttrSizes[i]; + } + stride += vAttrStride; + normoff += vAttrStride; + coloroff += vAttrStride; + coordoff += vAttrStride; + texCoordoff += vAttrStride; + } + + bstride = stride * Buffers.SIZEOF_FLOAT; + + // process alpha for geometryArray without alpha + if (updateAlpha && !ignoreVertexColors) { + useAlpha = true; + } + + if (geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET) { + sarray = ((IndexedGeometryStripArrayRetained) geo).stripIndexCounts; + strip_len = sarray.length; + } + + // Copy data into NIO array + verts = getVertexArrayBuffer(varray); + + // Apply normal transform if necessary + if ((vformat & GeometryArray.NORMALS) != 0 && nxform != null) { + int off = normoff; + for (int i = 0; i < vertexCount * 3; i+=3) { + verts.put(off , (float) (nxform[0] * varray[off] + + nxform[1] * varray[off+1] + + nxform[2] * varray[off+2])); + verts.put(off+1, (float) (nxform[4] * varray[off] + + nxform[5] * varray[off+1] + + nxform[6] * varray[off+2])); + verts.put(off+2, (float) (nxform[8] * varray[off] + + nxform[9] * varray[off+1] + + nxform[10] * varray[off+2])); + off += stride; + } + } + + // Apply coordinate transform if necessary + if ((vformat & GeometryArray.COORDINATES) != 0 && xform != null) { + int off = coordoff; + for (int i = 0; i < vertexCount * 3; i+=3) { + verts.put(off , (float) (xform[0] * varray[off] + + xform[1] * varray[off+1] + + xform[2] * varray[off+2])); + verts.put(off+1, (float) (xform[4] * varray[off] + + xform[5] * varray[off+1] + + xform[6] * varray[off+2])); + verts.put(off+2, (float) (xform[8] * varray[off] + + xform[9] * varray[off+1] + + xform[10] * varray[off+2])); + off += stride; + } + } + + if (geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET) { + // Note we can use interleaved arrays even if we have a + // non-null xform since we use the same data layout unlike the + // C code + if (ignoreVertexColors || + (((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) && ((texCoordSetMapLen > 1) || + (texCoordSetCount > 1)))) { + useInterleavedArrays = false; + } else { + boolean[] tmp = new boolean[1]; + int[] tmp2 = new int[1]; + testForInterleavedArrays(vformat, tmp, tmp2); + useInterleavedArrays = tmp[0]; + iaFormat = tmp2[0]; + } + + if (useInterleavedArrays) { + verts.position(0); + gl.glInterleavedArrays(iaFormat, bstride, verts); + } else { + if ((vformat & GeometryArray.NORMALS) != 0) { + verts.position(normoff); + gl.glNormalPointer(GL.GL_FLOAT, bstride, verts); + } + if (!ignoreVertexColors && ((vformat & GeometryArray.COLOR) != 0)) { + verts.position(coloroff); + if (((vformat & GeometryArray.WITH_ALPHA) != 0) || useAlpha) { + gl.glColorPointer(4, GL.GL_FLOAT, bstride, verts); + } else { + gl.glColorPointer(3, GL.GL_FLOAT, bstride, verts); + } + } + if ((vformat & GeometryArray.COORDINATES) != 0) { + verts.position(coordoff); + gl.glVertexPointer(3, GL.GL_FLOAT, bstride, verts); + } + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + executeTexture(texCoordSetMapLen, + texSize, bstride, texCoordoff, + texCoordSetMapOffset, + texCoordSetMapLen, + verts, gl); + } + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + int vAttrOffset = vAttrOff; + for (int i = 0; i < vertexAttrCount; i++) { + ctx.enableVertexAttrArray(gl, i); + verts.position(vAttrOffset); + ctx.vertexAttrPointer(gl, i, vertexAttrSizes[i], + GL.GL_FLOAT, bstride, verts); + vAttrOffset += vertexAttrSizes[i]; + } + } + } + + switch (geo_type) { + case GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET: + primType = GL.GL_TRIANGLE_STRIP; + break; + case GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET: + primType = GL.GL_TRIANGLE_FAN; + break; + case GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET: + primType = GL.GL_LINE_STRIP; + break; + } + + lockArray(gl, vertexCount); + + // Note: using MultiDrawElements is probably more expensive than + // not in this case due to the need to allocate more temporary + // direct buffers and slice up the incoming indices array + int offset = initialIndexIndex; + IntBuffer indicesBuffer = IntBuffer.wrap(indexCoord); + for (int i = 0; i < strip_len; i++) { + indicesBuffer.position(offset); + int count = sarray[i]; + gl.glDrawElements(primType, count, GL.GL_UNSIGNED_INT, indicesBuffer); + offset += count; + } + } else if ((geo_type == GeometryRetained.GEO_TYPE_INDEXED_QUAD_SET) || + (geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_SET) || + (geo_type == GeometryRetained.GEO_TYPE_INDEXED_POINT_SET) || + (geo_type == GeometryRetained.GEO_TYPE_INDEXED_LINE_SET)) { + // Note we can use interleaved arrays even if we have a + // non-null xform since we use the same data layout unlike the + // C code + if (ignoreVertexColors || + (((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) && ((texCoordSetMapLen > 1) || + (texCoordSetCount > 1)))) { + useInterleavedArrays = false; + } else { + boolean[] tmp = new boolean[1]; + int[] tmp2 = new int[1]; + testForInterleavedArrays(vformat, tmp, tmp2); + useInterleavedArrays = tmp[0]; + iaFormat = tmp2[0]; + } + + if (useInterleavedArrays) { + verts.position(0); + gl.glInterleavedArrays(iaFormat, bstride, verts); + } else { + if ((vformat & GeometryArray.NORMALS) != 0) { + verts.position(normoff); + gl.glNormalPointer(GL.GL_FLOAT, bstride, verts); + } + + if (!ignoreVertexColors && ((vformat & GeometryArray.COLOR) != 0)) { + verts.position(coloroff); + if (((vformat & GeometryArray.WITH_ALPHA) != 0) || useAlpha) { + gl.glColorPointer(4, GL.GL_FLOAT, bstride, verts); + } else { + gl.glColorPointer(3, GL.GL_FLOAT, bstride, verts); + } + } + if ((vformat & GeometryArray.COORDINATES) != 0) { + verts.position(coordoff); + gl.glVertexPointer(3, GL.GL_FLOAT, bstride, verts); + } + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + executeTexture(texCoordSetMapLen, + texSize, bstride, texCoordoff, + texCoordSetMapOffset, + texCoordSetMapLen, + verts, gl); + } + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + int vAttrOffset = vAttrOff; + for (int i = 0; i < vertexAttrCount; i++) { + ctx.enableVertexAttrArray(gl, i); + verts.position(vAttrOffset); + ctx.vertexAttrPointer(gl, i, vertexAttrSizes[i], + GL.GL_FLOAT, bstride, verts); + vAttrOffset += vertexAttrSizes[i]; + } + } + + switch (geo_type) { + case GeometryRetained.GEO_TYPE_INDEXED_QUAD_SET : + primType = GL2.GL_QUADS; + break; + case GeometryRetained.GEO_TYPE_INDEXED_TRI_SET : + primType = GL.GL_TRIANGLES; + break; + case GeometryRetained.GEO_TYPE_INDEXED_POINT_SET : + primType = GL.GL_POINTS; + break; + case GeometryRetained.GEO_TYPE_INDEXED_LINE_SET : + primType = GL.GL_LINES; + break; + } + + lockArray(gl, vertexCount); + + IntBuffer indicesBuffer = IntBuffer.wrap(indexCoord); + indicesBuffer.position(initialIndexIndex); + gl.glDrawElements(primType, validIndexCount, GL.GL_UNSIGNED_INT, indicesBuffer); + } + } + + unlockArray(gl); + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + resetVertexAttrs(gl, ctx, vertexAttrCount); + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + resetTexture(gl, ctx); + } + } + + + //---------------------------------------------------------------------- + // + // Helper routines for IndexedGeometryArrayRetained + // + + private void executeIndexedGeometryArray(Context absCtx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean useAlpha, + boolean ignoreVertexColors, + int initialIndexIndex, + int indexCount, + int vertexCount, int vformat, + int vertexAttrCount, int[] vertexAttrSizes, + int texCoordSetCount, int[] texCoordSetMap, + int texCoordSetMapLen, + int[] texCoordSetOffset, + int numActiveTexUnitState, + float[] varray, FloatBuffer vdata, float[] carray, + int cDirty, + int[] indexCoord) { + JoglContext ctx = (JoglContext) absCtx; + GL2 gl = context(ctx).getGL().getGL2(); + + boolean useInterleavedArrays; + int iaFormat = 0; + int primType = 0; + int stride = 0, coordoff = 0, normoff = 0, coloroff = 0, texCoordoff = 0; + int texSize = 0, texStride = 0; + int vAttrOff = 0; + int vAttrStride = 0; + int bstride = 0, cbstride = 0; + FloatBuffer verts = null; + FloatBuffer clrs = null; + int[] sarray = null; + int strip_len = 0; + + if ((vformat & GeometryArray.COORDINATES) != 0) { + stride += 3; + } + if ((vformat & GeometryArray.NORMALS) != 0) { + stride += 3; + coordoff += 3; + } + + if ((vformat & GeometryArray.COLOR) != 0) { + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { + stride += 4; + normoff += 4; + coordoff += 4; + } else { // Handle the case of executeInterleaved 3f + stride += 3; + normoff += 3; + coordoff += 3; + } + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { + texSize = 2; + texStride = 2 * texCoordSetCount; + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_3) != 0) { + texSize = 3; + texStride = 3 * texCoordSetCount; + } else if ((vformat & GeometryArray.TEXTURE_COORDINATE_4) != 0) { + texSize = 4; + texStride = 4 * texCoordSetCount; + } + stride += texStride; + normoff += texStride; + coloroff += texStride; + coordoff += texStride; + } + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + for (int i = 0; i < vertexAttrCount; i++) { + vAttrStride += vertexAttrSizes[i]; + } + stride += vAttrStride; + normoff += vAttrStride; + coloroff += vAttrStride; + coordoff += vAttrStride; + texCoordoff += vAttrStride; + } + + bstride = stride * Buffers.SIZEOF_FLOAT; + + if (geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET) { + sarray = ((IndexedGeometryStripArrayRetained) geo).stripIndexCounts; + strip_len = sarray.length; + } + + // We have to copy if the data isn't specified using NIO + if (varray != null) { + verts = getVertexArrayBuffer(varray); + } else if (vdata != null) { + verts = vdata; + } else { + // This should never happen + throw new AssertionError("Unable to get vertex pointer"); + } + + // using byRef interleaved array and has a separate pointer, then .. + int cstride = stride; + if (carray != null) { + clrs = getColorArrayBuffer(carray); + cstride = 4; + } else { + // FIXME: need to "auto-slice" this buffer later + clrs = verts; + } + + cbstride = cstride * Buffers.SIZEOF_FLOAT; + + // Enable normalize for non-uniform scale (which rescale can't handle) + if (isNonUniformScale) { + gl.glEnable(GL2.GL_NORMALIZE); + } + + /*** Handle non-indexed strip GeometryArray first *******/ + if (geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET) { + if (ignoreVertexColors || (carray != null) || + ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0 && ((texCoordSetMapLen > 1) || + (texCoordSetCount > 1)))) { + useInterleavedArrays = false; + } else { + boolean[] tmp = new boolean[1]; + int[] tmp2 = new int[1]; + testForInterleavedArrays(vformat, tmp, tmp2); + useInterleavedArrays = tmp[0]; + iaFormat = tmp2[0]; + } + if (useInterleavedArrays) { + verts.position(0); + gl.glInterleavedArrays(iaFormat, bstride, verts); + } else { + if ((vformat & GeometryArray.NORMALS) != 0) { + verts.position(normoff); + gl.glNormalPointer(GL.GL_FLOAT, bstride, verts); + } + if (!ignoreVertexColors && (vformat & GeometryArray.COLOR) != 0) { + if (clrs == verts) { + clrs.position(coloroff); + } + if ((vformat & GeometryArray.WITH_ALPHA) != 0 || useAlpha) { + gl.glColorPointer(4, GL.GL_FLOAT, cbstride, clrs); + } else { + gl.glColorPointer(3, GL.GL_FLOAT, cbstride, clrs); + } + } + if ((vformat & GeometryArray.COORDINATES) != 0) { + verts.position(coordoff); + gl.glVertexPointer(3, GL.GL_FLOAT, bstride, verts); + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + /* XXXX: texCoordoff == 0 ???*/ + executeTexture(texCoordSetMapLen, + texSize, bstride, texCoordoff, + texCoordSetOffset, + numActiveTexUnitState, + verts, gl); + } + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + int vAttrOffset = vAttrOff; + for (int i = 0; i < vertexAttrCount; i++) { + ctx.enableVertexAttrArray(gl, i); + verts.position(vAttrOffset); + ctx.vertexAttrPointer(gl, i, vertexAttrSizes[i], + GL.GL_FLOAT, bstride, verts); + vAttrOffset += vertexAttrSizes[i]; + } + } + } + + switch (geo_type) { + case GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET: + primType = GL.GL_TRIANGLE_STRIP; + break; + case GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET: + primType = GL.GL_TRIANGLE_FAN; + break; + case GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET: + primType = GL.GL_LINE_STRIP; + break; + } + + lockArray(gl, vertexCount); + + // Note: using MultiDrawElements is probably more expensive than + // not in this case due to the need to allocate more temporary + // direct buffers and slice up the incoming indices array + int offset = initialIndexIndex; + IntBuffer indicesBuffer = IntBuffer.wrap(indexCoord); + for (int i = 0; i < strip_len; i++) { + indicesBuffer.position(offset); + int count = sarray[i]; + gl.glDrawElements(primType, count, GL.GL_UNSIGNED_INT, indicesBuffer); + offset += count; + } + } else if ((geo_type == GeometryRetained.GEO_TYPE_INDEXED_QUAD_SET) || + (geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_SET) || + (geo_type == GeometryRetained.GEO_TYPE_INDEXED_POINT_SET) || + (geo_type == GeometryRetained.GEO_TYPE_INDEXED_LINE_SET)) { + /******* Handle non-indexed non-striped GeometryArray now *****/ + if (ignoreVertexColors || (carray != null) || + ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0 && ((texCoordSetMapLen > 1) || + (texCoordSetCount > 1)))) { + useInterleavedArrays = false; + } else { + boolean[] tmp = new boolean[1]; + int[] tmp2 = new int[1]; + testForInterleavedArrays(vformat, tmp, tmp2); + useInterleavedArrays = tmp[0]; + iaFormat = tmp2[0]; + } + + if (useInterleavedArrays) { + verts.position(0); + gl.glInterleavedArrays(iaFormat, bstride, verts); + } else { + if ((vformat & GeometryArray.NORMALS) != 0) { + verts.position(normoff); + gl.glNormalPointer(GL.GL_FLOAT, bstride, verts); + } + + if (!ignoreVertexColors && (vformat & GeometryArray.COLOR) != 0) { + if (clrs == verts) { + clrs.position(coloroff); + } + if ((vformat & GeometryArray.WITH_ALPHA) != 0 || useAlpha) { + gl.glColorPointer(4, GL.GL_FLOAT, cbstride, clrs); + } else { + gl.glColorPointer(3, GL.GL_FLOAT, cbstride, clrs); + } + } + if ((vformat & GeometryArray.COORDINATES) != 0) { + verts.position(coordoff); + gl.glVertexPointer(3, GL.GL_FLOAT, bstride, verts); + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + /* XXXX: texCoordoff == 0 ???*/ + executeTexture(texCoordSetMapLen, + texSize, bstride, texCoordoff, + texCoordSetOffset, + numActiveTexUnitState, + verts, gl); + } + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + int vAttrOffset = vAttrOff; + for (int i = 0; i < vertexAttrCount; i++) { + ctx.enableVertexAttrArray(gl, i); + verts.position(vAttrOffset); + ctx.vertexAttrPointer(gl, i, vertexAttrSizes[i], + GL.GL_FLOAT, bstride, verts); + vAttrOffset += vertexAttrSizes[i]; + } + } + } + + lockArray(gl, vertexCount); + IntBuffer buf = IntBuffer.wrap(indexCoord); + buf.position(initialIndexIndex); + switch (geo_type){ + case GeometryRetained.GEO_TYPE_INDEXED_QUAD_SET : gl.glDrawElements(GL2.GL_QUADS, indexCount, GL.GL_UNSIGNED_INT, buf); break; + case GeometryRetained.GEO_TYPE_INDEXED_TRI_SET : gl.glDrawElements(GL.GL_TRIANGLES, indexCount, GL.GL_UNSIGNED_INT, buf); break; + case GeometryRetained.GEO_TYPE_INDEXED_POINT_SET: gl.glDrawElements(GL.GL_POINTS, indexCount, GL.GL_UNSIGNED_INT, buf); break; + case GeometryRetained.GEO_TYPE_INDEXED_LINE_SET : gl.glDrawElements(GL.GL_LINES, indexCount, GL.GL_UNSIGNED_INT, buf); break; + } + } + + unlockArray(gl); + + if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { + resetVertexAttrs(gl, ctx, vertexAttrCount); + } + + if ((vformat & GeometryArray.TEXTURE_COORDINATE) != 0) { + resetTexture(gl, ctx); + } + + // clean up if we turned on normalize + if (isNonUniformScale) { + gl.glDisable(GL2.GL_NORMALIZE); + } + } + + + private void executeIndexedGeometryArrayVA(Context absCtx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int initialIndexIndex, + int validIndexCount, + int vertexCount, int vformat, int vdefined, + FloatBuffer fverts, DoubleBuffer dverts, + FloatBuffer fclrs, ByteBuffer bclrs, + FloatBuffer norms, + int vertexAttrCount, int[] vertexAttrSizes, FloatBuffer[] vertexAttrBufs, + int texCoordSetCount, int[] texCoordSetMap, + int numActiveTexUnitState, + int texStride, + FloatBuffer[] texCoords, + int cDirty, int[] indexCoord, int[] sarray, int strip_len) { + JoglContext ctx = (JoglContext) absCtx; + GL2 gl = context(ctx).getGL().getGL2(); + + boolean floatCoordDefined = ((vdefined & GeometryArrayRetained.COORD_FLOAT) != 0); + boolean doubleCoordDefined = ((vdefined & GeometryArrayRetained.COORD_DOUBLE) != 0); + boolean floatColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_FLOAT) != 0); + boolean byteColorsDefined = ((vdefined & GeometryArrayRetained.COLOR_BYTE) != 0); + boolean normalsDefined = ((vdefined & GeometryArrayRetained.NORMAL_FLOAT) != 0); + boolean vattrDefined = ((vdefined & GeometryArrayRetained.VATTR_FLOAT) != 0); + boolean textureDefined = ((vdefined & GeometryArrayRetained.TEXCOORD_FLOAT) != 0); + + // Enable normalize for non-uniform scale (which rescale can't handle) + if (isNonUniformScale) { + gl.glEnable(GL2.GL_NORMALIZE); + } + + // Define the data pointers + if (floatCoordDefined) { + fverts.position(0); + gl.glVertexPointer(3, GL.GL_FLOAT, 0, fverts); + } else if (doubleCoordDefined){ + dverts.position(0); + gl.glVertexPointer(3, GL2.GL_DOUBLE, 0, dverts); + } + if (floatColorsDefined) { + fclrs.position(0); + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { + gl.glColorPointer(4, GL.GL_FLOAT, 0, fclrs); + } else { + gl.glColorPointer(3, GL.GL_FLOAT, 0, fclrs); + } + } else if (byteColorsDefined) { + bclrs.position(0); + if ((vformat & GeometryArray.WITH_ALPHA) != 0) { + gl.glColorPointer(4, GL.GL_UNSIGNED_BYTE, 0, bclrs); + } else { + gl.glColorPointer(3, GL.GL_UNSIGNED_BYTE, 0, bclrs); + } + } + if (normalsDefined) { + norms.position(0); + gl.glNormalPointer(GL.GL_FLOAT, 0, norms); + } + + if (vattrDefined) { + for (int i = 0; i < vertexAttrCount; i++) { + FloatBuffer vertexAttrs = vertexAttrBufs[i]; + int sz = vertexAttrSizes[i]; + ctx.enableVertexAttrArray(gl, i); + vertexAttrs.position(0); + ctx.vertexAttrPointer(gl, i, sz, GL.GL_FLOAT, 0, vertexAttrs); + } + } + + if (textureDefined) { + int texSet = 0; + for (int i = 0; i < numActiveTexUnitState; i++) { + if ((i < texCoordSetCount) && + ((texSet = texCoordSetMap[i]) != -1)) { + FloatBuffer buf = texCoords[texSet]; + buf.position(0); + enableTexCoordPointer(gl, i, texStride, + GL.GL_FLOAT, 0, buf); + } else { + disableTexCoordPointer(gl, i); + } + } + + // Reset client active texture unit to 0 + clientActiveTextureUnit(gl, 0); + } + + lockArray(gl, vertexCount); + + if (geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET || + geo_type == GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET) { + int primType = 0; + switch (geo_type) { + case GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET: + primType = GL.GL_TRIANGLE_STRIP; + break; + case GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET: + primType = GL.GL_TRIANGLE_FAN; + break; + case GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET: + primType = GL.GL_LINE_STRIP; + break; + } + + // Note: using MultiDrawElements is probably more expensive than + // not in this case due to the need to allocate more temporary + // direct buffers and slice up the incoming indices array + int offset = initialIndexIndex; + IntBuffer indicesBuffer = IntBuffer.wrap(indexCoord); + for (int i = 0; i < strip_len; i++) { + indicesBuffer.position(offset); + int count = sarray[i]; + gl.glDrawElements(primType, count, GL.GL_UNSIGNED_INT, indicesBuffer); + offset += count; + } + } else { + IntBuffer buf = IntBuffer.wrap(indexCoord); + buf.position(initialIndexIndex); + switch (geo_type){ + case GeometryRetained.GEO_TYPE_INDEXED_QUAD_SET : gl.glDrawElements(GL2.GL_QUADS, validIndexCount, GL.GL_UNSIGNED_INT, buf); break; + case GeometryRetained.GEO_TYPE_INDEXED_TRI_SET : gl.glDrawElements(GL.GL_TRIANGLES, validIndexCount, GL.GL_UNSIGNED_INT, buf); break; + case GeometryRetained.GEO_TYPE_INDEXED_POINT_SET: gl.glDrawElements(GL.GL_POINTS, validIndexCount, GL.GL_UNSIGNED_INT, buf); break; + case GeometryRetained.GEO_TYPE_INDEXED_LINE_SET : gl.glDrawElements(GL.GL_LINES, validIndexCount, GL.GL_UNSIGNED_INT, buf); break; + } + } + + unlockArray(gl); + + // clean up if we turned on normalize + if (isNonUniformScale) { + gl.glDisable(GL2.GL_NORMALIZE); + } + + if (vattrDefined) { + resetVertexAttrs(gl, ctx, vertexAttrCount); + } + + if (textureDefined) { + resetTexture(gl, ctx); + } + } + + + // --------------------------------------------------------------------- + + // + // GraphicsContext3D methods + // + + // Native method for readRaster + void readRaster(Context ctx, + int type, int xSrcOffset, int ySrcOffset, + int width, int height, int hCanvas, + int imageDataType, + int imageFormat, + Object imageBuffer, + int depthFormat, + Object depthBuffer) { + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glPixelStorei(GL2.GL_PACK_ROW_LENGTH, width); + gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1); + int yAdjusted = hCanvas - height - ySrcOffset; + + if ((type & Raster.RASTER_COLOR) != 0) { + int oglFormat = 0; + if(imageDataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) { + + switch (imageFormat) { + case ImageComponentRetained.TYPE_BYTE_BGR: + oglFormat = GL2.GL_BGR; + break; + case ImageComponentRetained.TYPE_BYTE_RGB: + oglFormat = GL.GL_RGB; + break; + case ImageComponentRetained.TYPE_BYTE_ABGR: + if (gl.isExtensionAvailable("GL_EXT_abgr")) { // If its zero, should never come here! + oglFormat = GL2.GL_ABGR_EXT; + } else { + assert false; + return; + } + break; + case ImageComponentRetained.TYPE_BYTE_RGBA: + // all RGB types are stored as RGBA + oglFormat = GL.GL_RGBA; + break; + case ImageComponentRetained.TYPE_BYTE_LA: + // all LA types are stored as LA8 + oglFormat = GL.GL_LUMINANCE_ALPHA; + break; + case ImageComponentRetained.TYPE_BYTE_GRAY: + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_INT_BGR: + case ImageComponentRetained.TYPE_INT_RGB: + case ImageComponentRetained.TYPE_INT_ARGB: + default: + assert false; + return; + } + + gl.glReadPixels(xSrcOffset, yAdjusted, width, height, + oglFormat, GL.GL_UNSIGNED_BYTE, ByteBuffer.wrap((byte[]) imageBuffer)); + + + } else if(imageDataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) { + int intType = GL2.GL_UNSIGNED_INT_8_8_8_8; + boolean forceAlphaToOne = false; + + switch (imageFormat) { + /* GL_BGR */ + case ImageComponentRetained.TYPE_INT_BGR: /* Assume XBGR format */ + oglFormat = GL.GL_RGBA; + intType = GL2.GL_UNSIGNED_INT_8_8_8_8_REV; + forceAlphaToOne = true; + break; + case ImageComponentRetained.TYPE_INT_RGB: /* Assume XRGB format */ + forceAlphaToOne = true; + /* Fall through to next case */ + case ImageComponentRetained.TYPE_INT_ARGB: + oglFormat = GL2.GL_BGRA; + intType = GL2.GL_UNSIGNED_INT_8_8_8_8_REV; + break; + /* This method only supports 3 and 4 components formats and INT types. */ + case ImageComponentRetained.TYPE_BYTE_LA: + case ImageComponentRetained.TYPE_BYTE_GRAY: + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_BYTE_BGR: + case ImageComponentRetained.TYPE_BYTE_RGB: + case ImageComponentRetained.TYPE_BYTE_RGBA: + case ImageComponentRetained.TYPE_BYTE_ABGR: + default: + assert false; + return; + } + + /* Force Alpha to 1.0 if needed */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL2.GL_ALPHA_SCALE, 0.0f); + gl.glPixelTransferf(GL2.GL_ALPHA_BIAS, 1.0f); + } + + gl.glReadPixels(xSrcOffset, yAdjusted, width, height, + oglFormat, intType, IntBuffer.wrap((int[]) imageBuffer)); + + /* Restore Alpha scale and bias */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL2.GL_ALPHA_SCALE, 1.0f); + gl.glPixelTransferf(GL2.GL_ALPHA_BIAS, 0.0f); + } + + } else { + assert false; + } + } + + if ((type & Raster.RASTER_DEPTH) != 0) { + + if (depthFormat == DepthComponentRetained.DEPTH_COMPONENT_TYPE_INT) { + // yOffset is adjusted for OpenGL - Y upward + gl.glReadPixels(xSrcOffset, yAdjusted, width, height, + GL2.GL_DEPTH_COMPONENT, GL.GL_UNSIGNED_INT, IntBuffer.wrap((int[]) depthBuffer)); + } else { + // DEPTH_COMPONENT_TYPE_FLOAT + // yOffset is adjusted for OpenGL - Y upward + gl.glReadPixels(xSrcOffset, yAdjusted, width, height, + GL2.GL_DEPTH_COMPONENT, GL.GL_FLOAT, FloatBuffer.wrap((float[]) depthBuffer)); + } + } + + } + + // --------------------------------------------------------------------- + + // + // GLSLShaderProgramRetained methods + // + + // ShaderAttributeValue methods + + ShaderError setGLSLUniform1i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform1i()"); + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniform1iARB(unbox(uniformLocation), value); + return null; + } + + ShaderError setGLSLUniform1f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform1f()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniform1fARB(unbox(uniformLocation), value); + return null; + } + + ShaderError setGLSLUniform2i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform2i()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniform2iARB(unbox(uniformLocation), value[0], value[1]); + return null; + } + + ShaderError setGLSLUniform2f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform2f()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniform2fARB(unbox(uniformLocation), value[0], value[1]); + return null; + } + + ShaderError setGLSLUniform3i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform3i()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniform3iARB(unbox(uniformLocation), value[0], value[1], value[2]); + return null; + } + + ShaderError setGLSLUniform3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform3f()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniform3fARB(unbox(uniformLocation), value[0], value[1], value[2]); + return null; + } + + ShaderError setGLSLUniform4i(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform4i()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniform4iARB(unbox(uniformLocation), value[0], value[1], value[2], value[3]); + return null; + } + + ShaderError setGLSLUniform4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform4f()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniform4fARB(unbox(uniformLocation), value[0], value[1], value[2], value[3]); + return null; + } + + ShaderError setGLSLUniformMatrix3f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniformMatrix3f()"); + + // Load attribute + // transpose is true : each matrix is supplied in row major order + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniformMatrix3fvARB(unbox(uniformLocation), 1, true, value, 0); + return null; + } + + ShaderError setGLSLUniformMatrix4f(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniformMatrix4f()"); + + // Load attribute + // transpose is true : each matrix is supplied in row major order + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniformMatrix4fvARB(unbox(uniformLocation), 1, true, value, 0); + return null; + } + + // ShaderAttributeArray methods + + ShaderError setGLSLUniform1iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform1iArray()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniform1ivARB(unbox(uniformLocation), numElements, value, 0); + return null; + } + + ShaderError setGLSLUniform1fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform1fArray()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniform1fvARB(unbox(uniformLocation), numElements, value, 0); + return null; + } + + ShaderError setGLSLUniform2iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform2iArray()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniform2ivARB(unbox(uniformLocation), numElements, value, 0); + return null; + } + + ShaderError setGLSLUniform2fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform2fArray()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniform2fvARB(unbox(uniformLocation), numElements, value, 0); + return null; + } + + ShaderError setGLSLUniform3iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform3iArray()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniform3ivARB(unbox(uniformLocation), numElements, value, 0); + return null; + } + + ShaderError setGLSLUniform3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform3fArray()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniform3fvARB(unbox(uniformLocation), numElements, value, 0); + return null; + } + + ShaderError setGLSLUniform4iArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + int[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform4iArray()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniform4ivARB(unbox(uniformLocation), numElements, value, 0); + return null; + } + + ShaderError setGLSLUniform4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniform4fArray()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniform4fvARB(unbox(uniformLocation), numElements, value, 0); + return null; + } + + ShaderError setGLSLUniformMatrix3fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniformMatrix3fArray()"); + + // Load attribute + // transpose is true : each matrix is supplied in row major order + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniformMatrix3fvARB(unbox(uniformLocation), numElements, true, value, 0); + return null; + } + + ShaderError setGLSLUniformMatrix4fArray(Context ctx, + ShaderProgramId shaderProgramId, + ShaderAttrLoc uniformLocation, + int numElements, + float[] value) { + if (VERBOSE) System.err.println("JoglPipeline.setGLSLUniformMatrix4fArray()"); + + // Load attribute + // transpose is true : each matrix is supplied in row major order + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUniformMatrix4fvARB(unbox(uniformLocation), numElements, true, value, 0); + return null; + } + + // interfaces for shader compilation, etc. + ShaderError createGLSLShader(Context ctx, int shaderType, ShaderId[] shaderId) { + if (VERBOSE) System.err.println("JoglPipeline.createGLSLShader()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + int shaderHandle = 0; + if (shaderType == Shader.SHADER_TYPE_VERTEX) { + shaderHandle = gl.glCreateShaderObjectARB(GL2.GL_VERTEX_SHADER); + } else if (shaderType == Shader.SHADER_TYPE_FRAGMENT) { + shaderHandle = gl.glCreateShaderObjectARB(GL2.GL_FRAGMENT_SHADER); + } + + if (shaderHandle == 0) { + return new ShaderError(ShaderError.COMPILE_ERROR, + "Unable to create native shader object"); + } + + shaderId[0] = new JoglShaderObject(shaderHandle); + return null; + } + ShaderError destroyGLSLShader(Context ctx, ShaderId shaderId) { + if (VERBOSE) System.err.println("JoglPipeline.destroyGLSLShader()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glDeleteObjectARB(unbox(shaderId)); + return null; + } + ShaderError compileGLSLShader(Context ctx, ShaderId shaderId, String program) { + if (VERBOSE) System.err.println("JoglPipeline.compileGLSLShader()"); + + int id = unbox(shaderId); + if (id == 0) { + throw new AssertionError("shaderId == 0"); + } + + if (program == null) { + throw new AssertionError("shader program string is null"); + } + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glShaderSourceARB(id, 1, new String[] { program }, null, 0); + gl.glCompileShaderARB(id); + int[] status = new int[1]; + gl.glGetObjectParameterivARB(id, GL2.GL_OBJECT_COMPILE_STATUS_ARB, status, 0); + if (status[0] == 0) { + String detailMsg = getInfoLog(gl, id); + ShaderError res = new ShaderError(ShaderError.COMPILE_ERROR, + "GLSL shader compile error"); + res.setDetailMessage(detailMsg); + return res; + } + return null; + } + + ShaderError createGLSLShaderProgram(Context ctx, ShaderProgramId[] shaderProgramId) { + if (VERBOSE) System.err.println("JoglPipeline.createGLSLShaderProgram()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + int shaderProgramHandle = gl.glCreateProgramObjectARB(); + if (shaderProgramHandle == 0) { + return new ShaderError(ShaderError.LINK_ERROR, + "Unable to create native shader program object"); + } + shaderProgramId[0] = new JoglShaderObject(shaderProgramHandle); + return null; + } + ShaderError destroyGLSLShaderProgram(Context ctx, ShaderProgramId shaderProgramId) { + if (VERBOSE) System.err.println("JoglPipeline.destroyGLSLShaderProgram()"); + GL2 gl = context(ctx).getGL().getGL2(); + gl.glDeleteObjectARB(unbox(shaderProgramId)); + return null; + } + ShaderError linkGLSLShaderProgram(Context ctx, ShaderProgramId shaderProgramId, + ShaderId[] shaderIds) { + if (VERBOSE) System.err.println("JoglPipeline.linkGLSLShaderProgram()"); + + GL2 gl = context(ctx).getGL().getGL2(); + int id = unbox(shaderProgramId); + for (int i = 0; i < shaderIds.length; i++) { + gl.glAttachObjectARB(id, unbox(shaderIds[i])); + } + gl.glLinkProgramARB(id); + int[] status = new int[1]; + gl.glGetObjectParameterivARB(id, GL2.GL_OBJECT_LINK_STATUS_ARB, status, 0); + if (status[0] == 0) { + String detailMsg = getInfoLog(gl, id); + ShaderError res = new ShaderError(ShaderError.LINK_ERROR, + "GLSL shader program link error"); + res.setDetailMessage(detailMsg); + return res; + } + return null; + } + ShaderError bindGLSLVertexAttrName(Context ctx, ShaderProgramId shaderProgramId, + String attrName, int attrIndex) { + if (VERBOSE) System.err.println("JoglPipeline.bindGLSLVertexAttrName()"); + + JoglContext jctx = (JoglContext) ctx; + GL2 gl = context(ctx).getGL().getGL2(); + gl.glBindAttribLocation(unbox(shaderProgramId), + attrIndex + VirtualUniverse.mc.glslVertexAttrOffset, + attrName); + return null; + } + void lookupGLSLShaderAttrNames(Context ctx, ShaderProgramId shaderProgramId, + int numAttrNames, String[] attrNames, ShaderAttrLoc[] locArr, + int[] typeArr, int[] sizeArr, boolean[] isArrayArr) { + if (VERBOSE) System.err.println("JoglPipeline.lookupGLSLShaderAttrNames()"); + + // set the loc, type, and size arrays to out-of-bound values + for (int i = 0; i < attrNames.length; i++) { + locArr[i] = null; + typeArr[i] = -1; + sizeArr[i] = -1; + } + + // Loop through the list of active uniform variables, one at a + // time, searching for a match in the attrNames array. + // + // NOTE: Since attrNames isn't sorted, and we don't have a + // hashtable of names to index locations, we will do a + // brute-force, linear search of the array. This leads to an + // O(n^2) algorithm (actually O(n*m) where n is attrNames.length + // and m is the number of uniform variables), but since we expect + // N to be small, we will not optimize this at this time. + int id = unbox(shaderProgramId); + int[] tmp = new int[1]; + int[] tmp2 = new int[1]; + int[] tmp3 = new int[1]; + GL2 gl = context(ctx).getGL().getGL2(); + gl.glGetObjectParameterivARB(id, + GL2.GL_OBJECT_ACTIVE_UNIFORMS_ARB, + tmp, 0); + int numActiveUniforms = tmp[0]; + gl.glGetObjectParameterivARB(id, + GL2.GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB, + tmp, 0); + int maxStrLen = tmp[0]; + byte[] nameBuf = new byte[maxStrLen]; + + for (int i = 0; i < numActiveUniforms; i++) { + gl.glGetActiveUniformARB(id, i, maxStrLen, tmp3, 0, + tmp, 0, + tmp2, 0, + nameBuf, 0); + int size = tmp[0]; + int type = tmp2[0]; + String name = null; + try { + // TODO KCR : Shouldn't this use the default locale? + name = new String(nameBuf, 0, tmp3[0], "US-ASCII"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + + // Issue 247 - we need to workaround an ATI bug where they erroneously + // report individual elements of arrays rather than the array itself + if (name.length() >= 3 && name.endsWith("]")) { + if (name.endsWith("[0]")) { + name = name.substring(0, name.length() - 3); + } else { + // Ignore this name + continue; + } + } + + // Now try to find the name + for (int j = 0; j < numAttrNames; j++) { + if (name.equals(attrNames[j])) { + sizeArr[j] = size; + isArrayArr[j] = (size > 1); + typeArr[j] = glslToJ3dType(type); + break; + } + } + } + + // Now lookup the location of each name in the attrNames array + for (int i = 0; i < numAttrNames; i++) { + // Get uniform attribute location + int loc = gl.glGetUniformLocationARB(id, attrNames[i]); + locArr[i] = new JoglShaderObject(loc); + } + } + + ShaderError useGLSLShaderProgram(Context ctx, ShaderProgramId shaderProgramId) { + if (VERBOSE) System.err.println("JoglPipeline.useGLSLShaderProgram()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glUseProgramObjectARB(unbox(shaderProgramId)); + ((JoglContext) ctx).setShaderProgram((JoglShaderObject) shaderProgramId); + return null; + } + + //---------------------------------------------------------------------- + // Helper methods for above shader routines + // + private int unbox(ShaderAttrLoc loc) { + if (loc == null) + return 0; + return ((JoglShaderObject) loc).getValue(); + } + + private int unbox(ShaderProgramId id) { + if (id == null) + return 0; + return ((JoglShaderObject) id).getValue(); + } + + private int unbox(ShaderId id) { + if (id == null) + return 0; + return ((JoglShaderObject) id).getValue(); + } + + private String getInfoLog(GL2 gl, int id) { + int[] infoLogLength = new int[1]; + gl.glGetObjectParameterivARB(id, GL2.GL_OBJECT_INFO_LOG_LENGTH_ARB, infoLogLength, 0); + if (infoLogLength[0] > 0) { + byte[] storage = new byte[infoLogLength[0]]; + int[] len = new int[1]; + gl.glGetInfoLogARB(id, infoLogLength[0], len, 0, storage, 0); + try { + // TODO KCR : Shouldn't this use the default locale? + return new String(storage, 0, len[0], "US-ASCII"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + return null; + } + + private int glslToJ3dType(int type) { + switch (type) { + case GL2.GL_BOOL_ARB: + case GL2.GL_INT: + case GL2.GL_SAMPLER_2D_ARB: + case GL2.GL_SAMPLER_3D_ARB: + case GL2.GL_SAMPLER_CUBE_ARB: + return ShaderAttributeObjectRetained.TYPE_INTEGER; + + case GL.GL_FLOAT: + return ShaderAttributeObjectRetained.TYPE_FLOAT; + + case GL2.GL_INT_VEC2_ARB: + case GL2.GL_BOOL_VEC2_ARB: + return ShaderAttributeObjectRetained.TYPE_TUPLE2I; + + case GL2.GL_FLOAT_VEC2_ARB: + return ShaderAttributeObjectRetained.TYPE_TUPLE2F; + + case GL2.GL_INT_VEC3_ARB: + case GL2.GL_BOOL_VEC3_ARB: + return ShaderAttributeObjectRetained.TYPE_TUPLE3I; + + case GL2.GL_FLOAT_VEC3_ARB: + return ShaderAttributeObjectRetained.TYPE_TUPLE3F; + + case GL2.GL_INT_VEC4_ARB: + case GL2.GL_BOOL_VEC4_ARB: + return ShaderAttributeObjectRetained.TYPE_TUPLE4I; + + case GL2.GL_FLOAT_VEC4_ARB: + return ShaderAttributeObjectRetained.TYPE_TUPLE4F; + + // case GL.GL_FLOAT_MAT2_ARB: + + case GL2.GL_FLOAT_MAT3_ARB: + return ShaderAttributeObjectRetained.TYPE_MATRIX3F; + + case GL2.GL_FLOAT_MAT4_ARB: + return ShaderAttributeObjectRetained.TYPE_MATRIX4F; + + // Java 3D does not support the following sampler types: + // + // case GL.GL_SAMPLER_1D_ARB: + // case GL.GL_SAMPLER_1D_SHADOW_ARB: + // case GL.GL_SAMPLER_2D_SHADOW_ARB: + // case GL.GL_SAMPLER_2D_RECT_ARB: + // case GL.GL_SAMPLER_2D_RECT_SHADOW_ARB: + } + + return -1; + } + + // --------------------------------------------------------------------- + + // + // Renderer methods + // + + void cleanupRenderer() { + // Nothing to do + } + + + // --------------------------------------------------------------------- + + // + // ColoringAttributesRetained methods + // + + void updateColoringAttributes(Context ctx, + float dRed, float dGreen, float dBlue, + float red, float green, float blue, + float alpha, + boolean lightEnable, + int shadeModel) { + if (VERBOSE) System.err.println("JoglPipeline.updateColoringAttributes()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + float cr, cg, cb; + + if (lightEnable) { + cr = dRed; cg = dGreen; cb = dBlue; + } else { + cr = red; cg = green; cb = blue; + } + gl.glColor4f(cr, cg, cb, alpha); + if (shadeModel == ColoringAttributes.SHADE_FLAT) { + gl.glShadeModel(GL2.GL_FLAT); + } else { + gl.glShadeModel(GL2.GL_SMOOTH); + } + } + + + // --------------------------------------------------------------------- + + // + // DirectionalLightRetained methods + // + + private static final float[] black = new float[4]; + void updateDirectionalLight(Context ctx, + int lightSlot, float red, float green, + float blue, float dirx, float diry, float dirz) { + if (VERBOSE) System.err.println("JoglPipeline.updateDirectionalLight()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + int lightNum = GL2.GL_LIGHT0 + lightSlot; + float[] values = new float[4]; + + values[0] = red; + values[1] = green; + values[2] = blue; + values[3] = 1.0f; + gl.glLightfv(lightNum, GL2.GL_DIFFUSE, values, 0); + gl.glLightfv(lightNum, GL2.GL_SPECULAR, values, 0); + values[0] = -dirx; + values[1] = -diry; + values[2] = -dirz; + values[3] = 0.0f; + gl.glLightfv(lightNum, GL2.GL_POSITION, values, 0); + gl.glLightfv(lightNum, GL2.GL_AMBIENT, black, 0); + gl.glLightf(lightNum, GL2.GL_CONSTANT_ATTENUATION, 1.0f); + gl.glLightf(lightNum, GL2.GL_LINEAR_ATTENUATION, 0.0f); + gl.glLightf(lightNum, GL2.GL_QUADRATIC_ATTENUATION, 0.0f); + gl.glLightf(lightNum, GL2.GL_SPOT_EXPONENT, 0.0f); + gl.glLightf(lightNum, GL2.GL_SPOT_CUTOFF, 180.0f); + } + + + // --------------------------------------------------------------------- + + // + // PointLightRetained methods + // + + void updatePointLight(Context ctx, + int lightSlot, float red, float green, + float blue, float attenx, float atteny, float attenz, + float posx, float posy, float posz) { + if (VERBOSE) System.err.println("JoglPipeline.updatePointLight()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + int lightNum = GL2.GL_LIGHT0 + lightSlot; + float[] values = new float[4]; + + values[0] = red; + values[1] = green; + values[2] = blue; + values[3] = 1.0f; + gl.glLightfv(lightNum, GL2.GL_DIFFUSE, values, 0); + gl.glLightfv(lightNum, GL2.GL_SPECULAR, values, 0); + gl.glLightfv(lightNum, GL2.GL_AMBIENT, black, 0); + values[0] = posx; + values[1] = posy; + values[2] = posz; + gl.glLightfv(lightNum, GL2.GL_POSITION, values, 0); + gl.glLightf(lightNum, GL2.GL_CONSTANT_ATTENUATION, attenx); + gl.glLightf(lightNum, GL2.GL_LINEAR_ATTENUATION, atteny); + gl.glLightf(lightNum, GL2.GL_QUADRATIC_ATTENUATION, attenz); + gl.glLightf(lightNum, GL2.GL_SPOT_EXPONENT, 0.0f); + gl.glLightf(lightNum, GL2.GL_SPOT_CUTOFF, 180.0f); + } + + + // --------------------------------------------------------------------- + + // + // SpotLightRetained methods + // + + void updateSpotLight(Context ctx, + int lightSlot, float red, float green, + float blue, float attenx, float atteny, float attenz, + float posx, float posy, float posz, float spreadAngle, + float concentration, float dirx, float diry, + float dirz) { + if (VERBOSE) System.err.println("JoglPipeline.updateSpotLight()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + int lightNum = GL2.GL_LIGHT0 + lightSlot; + float[] values = new float[4]; + + values[0] = red; + values[1] = green; + values[2] = blue; + values[3] = 1.0f; + gl.glLightfv(lightNum, GL2.GL_DIFFUSE, values, 0); + gl.glLightfv(lightNum, GL2.GL_SPECULAR, values, 0); + gl.glLightfv(lightNum, GL2.GL_AMBIENT, black, 0); + values[0] = posx; + values[1] = posy; + values[2] = posz; + gl.glLightfv(lightNum, GL2.GL_POSITION, values, 0); + gl.glLightf(lightNum, GL2.GL_CONSTANT_ATTENUATION, attenx); + gl.glLightf(lightNum, GL2.GL_LINEAR_ATTENUATION, atteny); + gl.glLightf(lightNum, GL2.GL_QUADRATIC_ATTENUATION, attenz); + values[0] = dirx; + values[1] = diry; + values[2] = dirz; + gl.glLightfv(lightNum, GL2.GL_SPOT_DIRECTION, values, 0); + gl.glLightf(lightNum, GL2.GL_SPOT_EXPONENT, concentration); + gl.glLightf(lightNum, GL2.GL_SPOT_CUTOFF, (float) (spreadAngle * 180.0f / Math.PI)); + } + + + // --------------------------------------------------------------------- + + // + // ExponentialFogRetained methods + // + + void updateExponentialFog(Context ctx, + float red, float green, float blue, + float density) { + if (VERBOSE) System.err.println("JoglPipeline.updateExponentialFog()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + float[] color = new float[3]; + color[0] = red; + color[1] = green; + color[2] = blue; + gl.glFogi(GL2.GL_FOG_MODE, GL2.GL_EXP); + gl.glFogfv(GL2.GL_FOG_COLOR, color, 0); + gl.glFogf(GL2.GL_FOG_DENSITY, density); + gl.glEnable(GL2.GL_FOG); + } + + + // --------------------------------------------------------------------- + + // + // LinearFogRetained methods + // + + void updateLinearFog(Context ctx, + float red, float green, float blue, + double fdist, double bdist) { + if (VERBOSE) System.err.println("JoglPipeline.updateLinearFog()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + float[] color = new float[3]; + color[0] = red; + color[1] = green; + color[2] = blue; + gl.glFogi(GL2.GL_FOG_MODE, GL.GL_LINEAR); + gl.glFogfv(GL2.GL_FOG_COLOR, color, 0); + gl.glFogf(GL2.GL_FOG_START, (float) fdist); + gl.glFogf(GL2.GL_FOG_END, (float) bdist); + gl.glEnable(GL2.GL_FOG); + } + + + // --------------------------------------------------------------------- + + // + // LineAttributesRetained methods + // + + void updateLineAttributes(Context ctx, + float lineWidth, int linePattern, + int linePatternMask, + int linePatternScaleFactor, + boolean lineAntialiasing) { + if (VERBOSE) System.err.println("JoglPipeline.updateLineAttributes()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glLineWidth(lineWidth); + + if (linePattern == LineAttributes.PATTERN_SOLID) { + gl.glDisable(GL2.GL_LINE_STIPPLE); + } else { + if (linePattern == LineAttributes.PATTERN_DASH) { // dashed lines + gl.glLineStipple(1, (short) 0x00ff); + } else if (linePattern == LineAttributes.PATTERN_DOT) { // dotted lines + gl.glLineStipple(1, (short) 0x0101); + } else if (linePattern == LineAttributes.PATTERN_DASH_DOT) { // dash-dotted lines + gl.glLineStipple(1, (short) 0x087f); + } else if (linePattern == LineAttributes.PATTERN_USER_DEFINED) { // user-defined mask + gl.glLineStipple(linePatternScaleFactor, (short) linePatternMask); + } + gl.glEnable(GL2.GL_LINE_STIPPLE); + } + + /* XXXX: Polygon Mode check, blend enable */ + if (lineAntialiasing) { + gl.glEnable(GL.GL_LINE_SMOOTH); + } else { + gl.glDisable(GL.GL_LINE_SMOOTH); + } + } + + + // --------------------------------------------------------------------- + + // + // MaterialRetained methods + // + + void updateMaterial(Context ctx, + float red, float green, float blue, float alpha, + float aRed, float aGreen, float aBlue, + float eRed, float eGreen, float eBlue, + float dRed, float dGreen, float dBlue, + float sRed, float sGreen, float sBlue, + float shininess, int colorTarget, boolean lightEnable) { + if (VERBOSE) System.err.println("JoglPipeline.updateMaterial()"); + + float[] color = new float[4]; + + GL2 gl = context(ctx).getGL().getGL2(); + + gl.glMaterialf(GL.GL_FRONT_AND_BACK, GL2.GL_SHININESS, shininess); + switch (colorTarget) { + case Material.DIFFUSE: + gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE); + break; + case Material.AMBIENT: + gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL2.GL_AMBIENT); + break; + case Material.EMISSIVE: + gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL2.GL_EMISSION); + break; + case Material.SPECULAR: + gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL2.GL_SPECULAR); + break; + case Material.AMBIENT_AND_DIFFUSE: + gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL2.GL_AMBIENT_AND_DIFFUSE); + break; + } + + color[0] = eRed; color[1] = eGreen; color[2] = eBlue; + gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL2.GL_EMISSION, color, 0); + + color[0] = aRed; color[1] = aGreen; color[2] = aBlue; + gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL2.GL_AMBIENT, color, 0); + + color[0] = sRed; color[1] = sGreen; color[2] = sBlue; + gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL2.GL_SPECULAR, color, 0); + + float cr, cg, cb; + + if (lightEnable) { + color[0] = dRed; color[1] = dGreen; color[2] = dBlue; + } else { + color[0] = red; color[1] = green; color[2] = blue; + } + color[3] = alpha; + gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE, color, 0); + gl.glColor4f(color[0], color[1], color[2], color[3]); + + if (lightEnable) { + gl.glEnable(GL2.GL_LIGHTING); + } else { + gl.glDisable(GL2.GL_LIGHTING); + } + } + + + // --------------------------------------------------------------------- + + // + // ModelClipRetained methods + // + + void updateModelClip(Context ctx, int planeNum, boolean enableFlag, + double A, double B, double C, double D) { + if (VERBOSE) System.err.println("JoglPipeline.updateModelClip()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + double[] equation = new double[4]; + int pl = GL2.GL_CLIP_PLANE0 + planeNum; + + // OpenGL clip planes are opposite to J3d clip planes + if (enableFlag) { + equation[0] = -A; + equation[1] = -B; + equation[2] = -C; + equation[3] = -D; + gl.glClipPlane(pl, DoubleBuffer.wrap(equation)); + gl.glEnable(pl); + } else { + gl.glDisable(pl); + } + } + + + // --------------------------------------------------------------------- + + // + // PointAttributesRetained methods + // + + void updatePointAttributes(Context ctx, float pointSize, boolean pointAntialiasing) { + if (VERBOSE) System.err.println("JoglPipeline.updatePointAttributes()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glPointSize(pointSize); + + // XXXX: Polygon Mode check, blend enable + if (pointAntialiasing) { + gl.glEnable(GL2.GL_POINT_SMOOTH); + } else { + gl.glDisable(GL2.GL_POINT_SMOOTH); + } + } + + + // --------------------------------------------------------------------- + + // + // PolygonAttributesRetained methods + // + + void updatePolygonAttributes(Context ctx, + int polygonMode, int cullFace, + boolean backFaceNormalFlip, + float polygonOffset, + float polygonOffsetFactor) { + if (VERBOSE) System.err.println("JoglPipeline.updatePolygonAttributes()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + if (cullFace == PolygonAttributes.CULL_NONE) { + gl.glDisable(GL.GL_CULL_FACE); + } else { + if (cullFace == PolygonAttributes.CULL_BACK) { + gl.glCullFace(GL.GL_BACK); + } else { + gl.glCullFace(GL.GL_FRONT); + } + gl.glEnable(GL.GL_CULL_FACE); + } + + if (backFaceNormalFlip && (cullFace != PolygonAttributes.CULL_BACK)) { + gl.glLightModeli(GL2.GL_LIGHT_MODEL_TWO_SIDE, GL.GL_TRUE); + } else { + gl.glLightModeli(GL2.GL_LIGHT_MODEL_TWO_SIDE, GL.GL_FALSE); + } + + if (polygonMode == PolygonAttributes.POLYGON_POINT) { + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_POINT); + } else if (polygonMode == PolygonAttributes.POLYGON_LINE) { + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_LINE); + } else { + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_FILL); + } + + gl.glPolygonOffset(polygonOffsetFactor, polygonOffset); + + if ((polygonOffsetFactor != 0.0) || (polygonOffset != 0.0)) { + switch (polygonMode) { + case PolygonAttributes.POLYGON_POINT: + gl.glEnable(GL2.GL_POLYGON_OFFSET_POINT); + gl.glDisable(GL2.GL_POLYGON_OFFSET_LINE); + gl.glDisable(GL.GL_POLYGON_OFFSET_FILL); + break; + case PolygonAttributes.POLYGON_LINE: + gl.glEnable(GL2.GL_POLYGON_OFFSET_LINE); + gl.glDisable(GL2.GL_POLYGON_OFFSET_POINT); + gl.glDisable(GL.GL_POLYGON_OFFSET_FILL); + break; + case PolygonAttributes.POLYGON_FILL: + gl.glEnable(GL.GL_POLYGON_OFFSET_FILL); + gl.glDisable(GL2.GL_POLYGON_OFFSET_POINT); + gl.glDisable(GL2.GL_POLYGON_OFFSET_LINE); + break; + } + } else { + gl.glDisable(GL2.GL_POLYGON_OFFSET_POINT); + gl.glDisable(GL2.GL_POLYGON_OFFSET_LINE); + gl.glDisable(GL.GL_POLYGON_OFFSET_FILL); + } + } + + + // --------------------------------------------------------------------- + + // + // RenderingAttributesRetained methods + // + + void updateRenderingAttributes(Context ctx, + boolean depthBufferWriteEnableOverride, + boolean depthBufferEnableOverride, + boolean depthBufferEnable, + boolean depthBufferWriteEnable, + int depthTestFunction, + float alphaTestValue, int alphaTestFunction, + boolean ignoreVertexColors, + boolean rasterOpEnable, int rasterOp, + boolean userStencilAvailable, boolean stencilEnable, + int stencilFailOp, int stencilZFailOp, int stencilZPassOp, + int stencilFunction, int stencilReferenceValue, + int stencilCompareMask, int stencilWriteMask ) { + if (VERBOSE) System.err.println("JoglPipeline.updateRenderingAttributes()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + if (!depthBufferEnableOverride) { + if (depthBufferEnable) { + gl.glEnable(GL.GL_DEPTH_TEST); + gl.glDepthFunc(getFunctionValue(depthTestFunction)); + } else { + gl.glDisable(GL.GL_DEPTH_TEST); + } + } + + if (!depthBufferWriteEnableOverride) { + if (depthBufferWriteEnable) { + gl.glDepthMask(true); + } else { + gl.glDepthMask(false); + } + } + + if (alphaTestFunction == RenderingAttributes.ALWAYS) { + gl.glDisable(GL2.GL_ALPHA_TEST); + } else { + gl.glEnable(GL2.GL_ALPHA_TEST); + gl.glAlphaFunc(getFunctionValue(alphaTestFunction), alphaTestValue); + } + + if (ignoreVertexColors) { + gl.glDisable(GL2.GL_COLOR_MATERIAL); + } else { + gl.glEnable(GL2.GL_COLOR_MATERIAL); + } + + if (rasterOpEnable) { + gl.glEnable(GL.GL_COLOR_LOGIC_OP); + switch (rasterOp) { + case RenderingAttributes.ROP_CLEAR: + gl.glLogicOp(GL.GL_CLEAR); + break; + case RenderingAttributes.ROP_AND: + gl.glLogicOp(GL.GL_AND); + break; + case RenderingAttributes.ROP_AND_REVERSE: + gl.glLogicOp(GL.GL_AND_REVERSE); + break; + case RenderingAttributes.ROP_COPY: + gl.glLogicOp(GL.GL_COPY); + break; + case RenderingAttributes.ROP_AND_INVERTED: + gl.glLogicOp(GL.GL_AND_INVERTED); + break; + case RenderingAttributes.ROP_NOOP: + gl.glLogicOp(GL.GL_NOOP); + break; + case RenderingAttributes.ROP_XOR: + gl.glLogicOp(GL.GL_XOR); + break; + case RenderingAttributes.ROP_OR: + gl.glLogicOp(GL.GL_OR); + break; + case RenderingAttributes.ROP_NOR: + gl.glLogicOp(GL.GL_NOR); + break; + case RenderingAttributes.ROP_EQUIV: + gl.glLogicOp(GL.GL_EQUIV); + break; + case RenderingAttributes.ROP_INVERT: + gl.glLogicOp(GL.GL_INVERT); + break; + case RenderingAttributes.ROP_OR_REVERSE: + gl.glLogicOp(GL.GL_OR_REVERSE); + break; + case RenderingAttributes.ROP_COPY_INVERTED: + gl.glLogicOp(GL.GL_COPY_INVERTED); + break; + case RenderingAttributes.ROP_OR_INVERTED: + gl.glLogicOp(GL.GL_OR_INVERTED); + break; + case RenderingAttributes.ROP_NAND: + gl.glLogicOp(GL.GL_NAND); + break; + case RenderingAttributes.ROP_SET: + gl.glLogicOp(GL.GL_SET); + break; + } + } else { + gl.glDisable(GL.GL_COLOR_LOGIC_OP); + } + + if (userStencilAvailable) { + if (stencilEnable) { + gl.glEnable(GL.GL_STENCIL_TEST); + + gl.glStencilOp(getStencilOpValue(stencilFailOp), + getStencilOpValue(stencilZFailOp), + getStencilOpValue(stencilZPassOp)); + + gl.glStencilFunc(getFunctionValue(stencilFunction), + stencilReferenceValue, stencilCompareMask); + + gl.glStencilMask(stencilWriteMask); + + } else { + gl.glDisable(GL.GL_STENCIL_TEST); + } + } + } + + private int getFunctionValue(int func) { + switch (func) { + case RenderingAttributes.ALWAYS: + func = GL.GL_ALWAYS; + break; + case RenderingAttributes.NEVER: + func = GL.GL_NEVER; + break; + case RenderingAttributes.EQUAL: + func = GL.GL_EQUAL; + break; + case RenderingAttributes.NOT_EQUAL: + func = GL.GL_NOTEQUAL; + break; + case RenderingAttributes.LESS: + func = GL.GL_LESS; + break; + case RenderingAttributes.LESS_OR_EQUAL: + func = GL.GL_LEQUAL; + break; + case RenderingAttributes.GREATER: + func = GL.GL_GREATER; + break; + case RenderingAttributes.GREATER_OR_EQUAL: + func = GL.GL_GEQUAL; + break; + } + + return func; + } + + private int getStencilOpValue(int op) { + switch (op) { + case RenderingAttributes.STENCIL_KEEP: + op = GL.GL_KEEP; + break; + case RenderingAttributes.STENCIL_ZERO: + op = GL.GL_ZERO; + break; + case RenderingAttributes.STENCIL_REPLACE: + op = GL.GL_REPLACE; + break; + case RenderingAttributes.STENCIL_INCR: + op = GL.GL_INCR; + break; + case RenderingAttributes.STENCIL_DECR: + op = GL.GL_DECR; + break; + case RenderingAttributes.STENCIL_INVERT: + op = GL.GL_INVERT; + break; + } + + return op; + } + + + // --------------------------------------------------------------------- + + // + // TexCoordGenerationRetained methods + // + + /** + * This method updates the native context: + * trans contains eyeTovworld transform in d3d + * trans contains vworldToEye transform in ogl + */ + void updateTexCoordGeneration(Context ctx, + boolean enable, int genMode, int format, + float planeSx, float planeSy, float planeSz, float planeSw, + float planeTx, float planeTy, float planeTz, float planeTw, + float planeRx, float planeRy, float planeRz, float planeRw, + float planeQx, float planeQy, float planeQz, float planeQw, + double[] vworldToEc) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexCoordGeneration()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + float[] planeS = new float[4]; + float[] planeT = new float[4]; + float[] planeR = new float[4]; + float[] planeQ = new float[4]; + + if (enable) { + gl.glEnable(GL2.GL_TEXTURE_GEN_S); + gl.glEnable(GL2.GL_TEXTURE_GEN_T); + if (format == TexCoordGeneration.TEXTURE_COORDINATE_3) { + gl.glEnable(GL2.GL_TEXTURE_GEN_R); + gl.glDisable(GL2.GL_TEXTURE_GEN_Q); + } else if (format == TexCoordGeneration.TEXTURE_COORDINATE_4) { + gl.glEnable(GL2.GL_TEXTURE_GEN_R); + gl.glEnable(GL2.GL_TEXTURE_GEN_Q); + } else { + gl.glDisable(GL2.GL_TEXTURE_GEN_R); + gl.glDisable(GL2.GL_TEXTURE_GEN_Q); + } + + if (genMode != TexCoordGeneration.SPHERE_MAP) { + planeS[0] = planeSx; planeS[1] = planeSy; + planeS[2] = planeSz; planeS[3] = planeSw; + planeT[0] = planeTx; planeT[1] = planeTy; + planeT[2] = planeTz; planeT[3] = planeTw; + if (format == TexCoordGeneration.TEXTURE_COORDINATE_3) { + planeR[0] = planeRx; planeR[1] = planeRy; + planeR[2] = planeRz; planeR[3] = planeRw; + } else if (format == TexCoordGeneration.TEXTURE_COORDINATE_4) { + planeR[0] = planeRx; planeR[1] = planeRy; + planeR[2] = planeRz; planeR[3] = planeRw; + planeQ[0] = planeQx; planeQ[1] = planeQy; + planeQ[2] = planeQz; planeQ[3] = planeQw; + } + } + + switch (genMode) { + case TexCoordGeneration.OBJECT_LINEAR: + gl.glTexGeni(GL2.GL_S, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_OBJECT_LINEAR); + gl.glTexGeni(GL2.GL_T, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_OBJECT_LINEAR); + gl.glTexGenfv(GL2.GL_S, GL2.GL_OBJECT_PLANE, planeS, 0); + gl.glTexGenfv(GL2.GL_T, GL2.GL_OBJECT_PLANE, planeT, 0); + + if (format == TexCoordGeneration.TEXTURE_COORDINATE_3) { + gl.glTexGeni(GL2.GL_R, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_OBJECT_LINEAR); + gl.glTexGenfv(GL2.GL_R, GL2.GL_OBJECT_PLANE, planeR, 0); + } else if (format == TexCoordGeneration.TEXTURE_COORDINATE_4) { + gl.glTexGeni(GL2.GL_R, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_OBJECT_LINEAR); + gl.glTexGenfv(GL2.GL_R, GL2.GL_OBJECT_PLANE, planeR, 0); + gl.glTexGeni(GL2.GL_Q, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_OBJECT_LINEAR); + gl.glTexGenfv(GL2.GL_Q, GL2.GL_OBJECT_PLANE, planeQ, 0); + } + break; + case TexCoordGeneration.EYE_LINEAR: + + gl.glMatrixMode(GL2.GL_MODELVIEW); + gl.glPushMatrix(); + + if (gl.isExtensionAvailable("GL_VERSION_1_3")) { + gl.glLoadTransposeMatrixd(vworldToEc, 0); + } else { + double[] v = new double[16]; + copyTranspose(vworldToEc, v); + gl.glLoadMatrixd(v, 0); + } + + gl.glTexGeni(GL2.GL_S, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_EYE_LINEAR); + gl.glTexGeni(GL2.GL_T, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_EYE_LINEAR); + gl.glTexGenfv(GL2.GL_S, GL2.GL_EYE_PLANE, planeS, 0); + gl.glTexGenfv(GL2.GL_T, GL2.GL_EYE_PLANE, planeT, 0); + + if (format == TexCoordGeneration.TEXTURE_COORDINATE_3) { + gl.glTexGeni(GL2.GL_R, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_EYE_LINEAR); + gl.glTexGenfv(GL2.GL_R, GL2.GL_EYE_PLANE, planeR, 0); + } else if (format == TexCoordGeneration.TEXTURE_COORDINATE_4) { + gl.glTexGeni(GL2.GL_R, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_EYE_LINEAR); + gl.glTexGenfv(GL2.GL_R, GL2.GL_EYE_PLANE, planeR, 0); + gl.glTexGeni(GL2.GL_Q, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_EYE_LINEAR); + gl.glTexGenfv(GL2.GL_Q, GL2.GL_EYE_PLANE, planeQ, 0); + } + gl.glPopMatrix(); + break; + case TexCoordGeneration.SPHERE_MAP: + gl.glTexGeni(GL2.GL_S, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_SPHERE_MAP); + gl.glTexGeni(GL2.GL_T, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_SPHERE_MAP); + if (format == TexCoordGeneration.TEXTURE_COORDINATE_3) { + gl.glTexGeni(GL2.GL_R, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_SPHERE_MAP); + } else if (format == TexCoordGeneration.TEXTURE_COORDINATE_4) { + gl.glTexGeni(GL2.GL_R, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_SPHERE_MAP); + gl.glTexGeni(GL2.GL_Q, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_SPHERE_MAP); + } + + break; + case TexCoordGeneration.NORMAL_MAP: + gl.glTexGeni(GL2.GL_S, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_NORMAL_MAP); + gl.glTexGeni(GL2.GL_T, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_NORMAL_MAP); + if (format == TexCoordGeneration.TEXTURE_COORDINATE_3) { + gl.glTexGeni(GL2.GL_R, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_NORMAL_MAP); + } else if (format == TexCoordGeneration.TEXTURE_COORDINATE_4) { + gl.glTexGeni(GL2.GL_R, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_NORMAL_MAP); + gl.glTexGeni(GL2.GL_Q, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_NORMAL_MAP); + } + break; + case TexCoordGeneration.REFLECTION_MAP: + gl.glTexGeni(GL2.GL_S, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_REFLECTION_MAP); + gl.glTexGeni(GL2.GL_T, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_REFLECTION_MAP); + if (format == TexCoordGeneration.TEXTURE_COORDINATE_3) { + gl.glTexGeni(GL2.GL_R, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_REFLECTION_MAP); + } else if (format == TexCoordGeneration.TEXTURE_COORDINATE_4) { + gl.glTexGeni(GL2.GL_R, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_REFLECTION_MAP); + gl.glTexGeni(GL2.GL_Q, GL2.GL_TEXTURE_GEN_MODE, GL2.GL_REFLECTION_MAP); + } + break; + } + } else { + gl.glDisable(GL2.GL_TEXTURE_GEN_S); + gl.glDisable(GL2.GL_TEXTURE_GEN_T); + gl.glDisable(GL2.GL_TEXTURE_GEN_R); + gl.glDisable(GL2.GL_TEXTURE_GEN_Q); + } + } + + + // --------------------------------------------------------------------- + + // + // TransparencyAttributesRetained methods + // + + private static final int screen_door[][] = { + /* 0 / 16 */ + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + /* 1 / 16 */ + { + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + 0x00000000, 0x22222222, 0x00000000, 0x00000000, + }, + /* 2 / 16 */ + { + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + 0x00000000, 0x22222222, 0x00000000, 0x88888888, + }, + /* 3 / 16 */ + { + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0x88888888, + }, + /* 4 / 16 */ + { + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x00000000, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + }, + /* 5 / 16 */ + { + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x00000000, 0xaaaaaaaa, + }, + /* 6 / 16 */ + { + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x11111111, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + }, + /* 7 / 16 */ + { + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x44444444, 0xaaaaaaaa, + }, + /* 8 / 16 */ + { + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x55555555, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + }, + /* 9 / 16 */ + { + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa, + }, + /* 10 / 16 */ + { + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0x77777777, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + }, + /* 11 / 16 */ + { + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xdddddddd, 0xaaaaaaaa, + }, + /* 12 / 16 */ + { + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xaaaaaaaa, 0xffffffff, 0xaaaaaaaa, + }, + /* 13 / 16 */ + { + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xaaaaaaaa, + }, + /* 14 / 16 */ + { + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xbbbbbbbb, 0xffffffff, 0xeeeeeeee, + }, + /* 15 / 16 */ + { + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + 0xffffffff, 0xffffffff, 0xffffffff, 0xeeeeeeee, + }, + /* 16 / 16 */ + { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }; + private static final ByteBuffer[] screen_door_table = new ByteBuffer[screen_door.length]; + static { + int eachLen = screen_door[0].length * Buffers.SIZEOF_INT; + ByteBuffer buf = Buffers.newDirectByteBuffer(screen_door.length * eachLen); + IntBuffer intBuf = buf.asIntBuffer(); + for (int i = 0; i < screen_door.length; i++) { + intBuf.put(screen_door[i]); + } + buf.rewind(); + for (int i = 0; i < screen_door.length; i++) { + buf.position(i * eachLen); + buf.limit((i+1) * eachLen); + screen_door_table[i] = buf.slice(); + } + } + + private static final int[] blendFunctionTable = new int[TransparencyAttributes.MAX_BLEND_FUNC_TABLE_SIZE]; + static { + blendFunctionTable[TransparencyAttributes.BLEND_ZERO] = GL.GL_ZERO; + blendFunctionTable[TransparencyAttributes.BLEND_ONE] = GL.GL_ONE; + blendFunctionTable[TransparencyAttributes.BLEND_SRC_ALPHA] = GL.GL_SRC_ALPHA; + blendFunctionTable[TransparencyAttributes.BLEND_ONE_MINUS_SRC_ALPHA] = GL.GL_ONE_MINUS_SRC_ALPHA; + blendFunctionTable[TransparencyAttributes.BLEND_DST_COLOR] = GL.GL_DST_COLOR; + blendFunctionTable[TransparencyAttributes.BLEND_ONE_MINUS_DST_COLOR] = GL.GL_ONE_MINUS_DST_COLOR; + blendFunctionTable[TransparencyAttributes.BLEND_SRC_COLOR] = GL.GL_SRC_COLOR; + blendFunctionTable[TransparencyAttributes.BLEND_ONE_MINUS_SRC_COLOR] = GL.GL_ONE_MINUS_SRC_COLOR; + blendFunctionTable[TransparencyAttributes.BLEND_CONSTANT_COLOR] = GL2.GL_CONSTANT_COLOR; + } + + void updateTransparencyAttributes(Context ctx, + float alpha, int geometryType, + int polygonMode, + boolean lineAA, boolean pointAA, + int transparencyMode, + int srcBlendFunction, + int dstBlendFunction) { + if (VERBOSE) System.err.println("JoglPipeline.updateTransparencyAttributes()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + if (transparencyMode != TransparencyAttributes.SCREEN_DOOR) { + gl.glDisable(GL2.GL_POLYGON_STIPPLE); + } else { + gl.glEnable(GL2.GL_POLYGON_STIPPLE); + gl.glPolygonStipple(screen_door_table[(int)(alpha * 16)]); + } + + if ((transparencyMode < TransparencyAttributes.SCREEN_DOOR) || + ((((geometryType & RenderMolecule.LINE) != 0) || + (polygonMode == PolygonAttributes.POLYGON_LINE)) + && lineAA) || + ((((geometryType & RenderMolecule.POINT) != 0) || + (polygonMode == PolygonAttributes.POLYGON_POINT)) + && pointAA)) { + gl.glEnable(GL.GL_BLEND); + // valid range of blendFunction 0..3 is already verified in shared code. + gl.glBlendFunc(blendFunctionTable[srcBlendFunction], blendFunctionTable[dstBlendFunction]); + } else { + gl.glDisable(GL.GL_BLEND); + } + } + + + // --------------------------------------------------------------------- + + // + // TextureAttributesRetained methods + // + + void updateTextureAttributes(Context ctx, + double[] transform, boolean isIdentity, int textureMode, + int perspCorrectionMode, + float textureBlendColorRed, + float textureBlendColorGreen, + float textureBlendColorBlue, + float textureBlendColorAlpha, + int textureFormat) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureAttributes()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, + (perspCorrectionMode == TextureAttributes.NICEST) ? GL.GL_NICEST : GL.GL_FASTEST); + + // set OGL texture matrix + gl.glPushAttrib(GL2.GL_TRANSFORM_BIT); + gl.glMatrixMode(GL.GL_TEXTURE); + + if (isIdentity) { + gl.glLoadIdentity(); + } else if (gl.isExtensionAvailable("GL_VERSION_1_3")) { + gl.glLoadTransposeMatrixd(transform, 0); + } else { + double[] mx = new double[16]; + copyTranspose(transform, mx); + gl.glLoadMatrixd(mx, 0); + } + + gl.glPopAttrib(); + + // set texture color + float[] color = new float[4]; + color[0] = textureBlendColorRed; + color[1] = textureBlendColorGreen; + color[2] = textureBlendColorBlue; + color[3] = textureBlendColorAlpha; + gl.glTexEnvfv(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_COLOR, color, 0); + + // set texture environment mode + + switch (textureMode) { + case TextureAttributes.MODULATE: + gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_MODULATE); + break; + case TextureAttributes.DECAL: + gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_DECAL); + break; + case TextureAttributes.BLEND: + gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL.GL_BLEND); + break; + case TextureAttributes.REPLACE: + gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE); + break; + case TextureAttributes.COMBINE: + gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_COMBINE); + break; + } +// FIXME: GL_SGI_texture_color_table +// if (gl.isExtensionAvailable("GL_SGI_texture_color_table")) { +// gl.glDisable(GL.GL_TEXTURE_COLOR_TABLE_SGI); +// } + } + + void updateRegisterCombiners(Context absCtx, + double[] transform, boolean isIdentity, int textureMode, + int perspCorrectionMode, + float textureBlendColorRed, + float textureBlendColorGreen, + float textureBlendColorBlue, + float textureBlendColorAlpha, + int textureFormat, + int combineRgbMode, int combineAlphaMode, + int[] combineRgbSrc, int[] combineAlphaSrc, + int[] combineRgbFcn, int[] combineAlphaFcn, + int combineRgbScale, int combineAlphaScale) { +// FIXME: GL_NV_register_combiners +// if (VERBOSE) System.err.println("JoglPipeline.updateRegisterCombiners()"); +// +// JoglContext ctx = (JoglContext) absCtx; +// GL2 gl = context(ctx).getGL().getGL2(); +// +// if (perspCorrectionMode == TextureAttributes.NICEST) { +// gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST); +// } else { +// gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_FASTEST); +// } +// +// // set OGL texture matrix +// gl.glPushAttrib(GL2.GL_TRANSFORM_BIT); +// gl.glMatrixMode(GL.GL_TEXTURE); +// +// if (isIdentity) { +// gl.glLoadIdentity(); +// } else if (gl.isExtensionAvailable("GL_VERSION_1_3")) { +// gl.glLoadTransposeMatrixd(transform, 0); +// } else { +// double[] mx = new double[16]; +// copyTranspose(transform, mx); +// gl.glLoadMatrixd(mx, 0); +// } +// +// gl.glPopAttrib(); +// +// // set texture color +// float[] color = new float[4]; +// color[0] = textureBlendColorRed; +// color[1] = textureBlendColorGreen; +// color[2] = textureBlendColorBlue; +// color[3] = textureBlendColorAlpha; +// gl.glTexEnvfv(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_COLOR, color, 0); +// +// // set texture environment mode +// gl.glEnable(GL.GL_REGISTER_COMBINERS_NV); +// int textureUnit = ctx.getCurrentTextureUnit(); +// int combinerUnit = ctx.getCurrentCombinerUnit(); +// int fragment; +// if (combinerUnit == GL.GL_COMBINER0_NV) { +// fragment = GL.GL_PRIMARY_COLOR_NV; +// } else { +// fragment = GL.GL_SPARE0_NV; +// } +// +// switch (textureMode) { +// case TextureAttributes.MODULATE: +// gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, +// GL.GL_VARIABLE_A_NV, fragment, +// GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); +// gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, +// GL.GL_VARIABLE_B_NV, textureUnit, +// GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); +// gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, +// GL.GL_VARIABLE_A_NV, fragment, +// GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_ALPHA); +// gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, +// GL.GL_VARIABLE_B_NV, textureUnit, +// GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_ALPHA); +// +// gl.glCombinerOutputNV(combinerUnit, GL.GL_RGB, +// GL.GL_SPARE0_NV, GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, +// GL.GL_NONE, GL.GL_NONE, false, false, false); +// gl.glCombinerOutputNV(combinerUnit, GL.GL_ALPHA, +// GL.GL_SPARE0_NV, GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, +// GL.GL_NONE, GL.GL_NONE, false, false, false); +// break; +// +// case TextureAttributes.DECAL: +// gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, +// GL.GL_VARIABLE_A_NV, fragment, +// GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); +// gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, +// GL.GL_VARIABLE_B_NV, textureUnit, +// GL.GL_UNSIGNED_INVERT_NV, GL.GL_ALPHA); +// gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, +// GL.GL_VARIABLE_C_NV, textureUnit, +// GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); +// gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, +// GL.GL_VARIABLE_D_NV, textureUnit, +// GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_ALPHA); +// +// gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, +// GL.GL_VARIABLE_A_NV, fragment, +// GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_ALPHA); +// gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, +// GL.GL_VARIABLE_B_NV, GL.GL_ZERO, +// GL.GL_UNSIGNED_INVERT_NV, GL.GL_ALPHA); +// +// gl.glCombinerOutputNV(combinerUnit, GL.GL_RGB, +// GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, GL.GL_SPARE0_NV, +// GL.GL_NONE, GL.GL_NONE, false, false, false); +// gl.glCombinerOutputNV(combinerUnit, GL.GL_ALPHA, +// GL.GL_SPARE0_NV, GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, +// GL.GL_NONE, GL.GL_NONE, false, false, false); +// break; +// +// case TextureAttributes.BLEND: +// gl.glCombinerParameterfvNV(GL.GL_CONSTANT_COLOR0_NV, color, 0); +// +// gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, +// GL.GL_VARIABLE_A_NV, fragment, +// GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); +// gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, +// GL.GL_VARIABLE_B_NV, textureUnit, +// GL.GL_UNSIGNED_INVERT_NV, GL.GL_RGB); +// gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, +// GL.GL_VARIABLE_C_NV, GL.GL_CONSTANT_COLOR0_NV, +// GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); +// gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, +// GL.GL_VARIABLE_D_NV, textureUnit, +// GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); +// +// gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, +// GL.GL_VARIABLE_A_NV, fragment, +// GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_ALPHA); +// gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, +// GL.GL_VARIABLE_B_NV, textureUnit, +// GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_ALPHA); +// +// gl.glCombinerOutputNV(combinerUnit, GL.GL_RGB, +// GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, GL.GL_SPARE0_NV, +// GL.GL_NONE, GL.GL_NONE, false, false, false); +// gl.glCombinerOutputNV(combinerUnit, GL.GL_ALPHA, +// GL.GL_SPARE0_NV, GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, +// GL.GL_NONE, GL.GL_NONE, false, false, false); +// break; +// +// case TextureAttributes.REPLACE: +// gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, +// GL.GL_VARIABLE_A_NV, textureUnit, +// GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); +// gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, +// GL.GL_VARIABLE_B_NV, GL.GL_ZERO, +// GL.GL_UNSIGNED_INVERT_NV, GL.GL_RGB); +// gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, +// GL.GL_VARIABLE_A_NV, textureUnit, +// GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_ALPHA); +// gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, +// GL.GL_VARIABLE_B_NV, GL.GL_ZERO, +// GL.GL_UNSIGNED_INVERT_NV, GL.GL_ALPHA); +// +// gl.glCombinerOutputNV(combinerUnit, GL.GL_RGB, +// GL.GL_SPARE0_NV, GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, +// GL.GL_NONE, GL.GL_NONE, false, false, false); +// gl.glCombinerOutputNV(combinerUnit, GL.GL_ALPHA, +// GL.GL_SPARE0_NV, GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, +// GL.GL_NONE, GL.GL_NONE, false, false, false); +// break; +// +// case TextureAttributes.COMBINE: +// if (combineRgbMode == TextureAttributes.COMBINE_DOT3) { +// int color1 = getCombinerArg(gl, combineRgbSrc[0], textureUnit, combinerUnit); +// gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, +// GL.GL_VARIABLE_A_NV, color1, +// GL.GL_EXPAND_NORMAL_NV, GL.GL_RGB); +// int color2 = getCombinerArg(gl, combineRgbSrc[1], textureUnit, combinerUnit); +// gl.glCombinerInputNV(combinerUnit, GL.GL_RGB, +// GL.GL_VARIABLE_B_NV, color2, +// GL.GL_EXPAND_NORMAL_NV, GL.GL_RGB); +// gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, +// GL.GL_VARIABLE_A_NV, GL.GL_ZERO, +// GL.GL_UNSIGNED_INVERT_NV, GL.GL_ALPHA); +// gl.glCombinerInputNV(combinerUnit, GL.GL_ALPHA, +// GL.GL_VARIABLE_B_NV, GL.GL_ZERO, +// GL.GL_UNSIGNED_INVERT_NV, GL.GL_ALPHA); +// +// gl.glCombinerOutputNV(combinerUnit, GL.GL_RGB, +// GL.GL_SPARE0_NV, GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, +// GL.GL_NONE/*SCALE_BY_FOUR_NV*/, GL.GL_NONE, true, +// false, false); +// gl.glCombinerOutputNV(combinerUnit, GL.GL_ALPHA, +// GL.GL_SPARE0_NV, GL.GL_DISCARD_NV, GL.GL_DISCARD_NV, +// GL.GL_NONE, GL.GL_NONE, false, +// false, false); +// } +// break; +// } +// +// gl.glFinalCombinerInputNV(GL.GL_VARIABLE_A_NV, +// GL.GL_SPARE0_NV, GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); +// gl.glFinalCombinerInputNV(GL.GL_VARIABLE_B_NV, +// GL.GL_ZERO, GL.GL_UNSIGNED_INVERT_NV, GL.GL_RGB); +// gl.glFinalCombinerInputNV(GL.GL_VARIABLE_C_NV, +// GL.GL_ZERO, GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); +// gl.glFinalCombinerInputNV(GL.GL_VARIABLE_D_NV, +// GL.GL_ZERO, GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); +// gl.glFinalCombinerInputNV(GL.GL_VARIABLE_E_NV, +// GL.GL_ZERO, GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); +// gl.glFinalCombinerInputNV(GL.GL_VARIABLE_F_NV, +// GL.GL_ZERO, GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_RGB); +// gl.glFinalCombinerInputNV(GL.GL_VARIABLE_G_NV, +// GL.GL_SPARE0_NV, GL.GL_UNSIGNED_IDENTITY_NV, GL.GL_ALPHA); +// +// if (gl.isExtensionAvailable("GL_SGI_texture_color_table")) +// gl.glDisable(GL.GL_TEXTURE_COLOR_TABLE_SGI); + // GL_SGI_texture_color_table + } + + void updateTextureColorTable(Context ctx, int numComponents, + int colorTableSize, + int[] textureColorTable) { +// FIXME: GL_SGI_texture_color_table +// if (VERBOSE) System.err.println("JoglPipeline.updateTextureColorTable()"); +// +// GL gl = context(ctx).getGL(); +// if (gl.isExtensionAvailable("GL_SGI_texture_color_table")) { +// if (numComponents == 3) { +// gl.glColorTable(GL.GL_TEXTURE_COLOR_TABLE_SGI, GL.GL_RGB, +// colorTableSize, GL.GL_RGB, GL2.GL_INT, IntBuffer.wrap(textureColorTable)); +// } else { +// gl.glColorTable(GL.GL_TEXTURE_COLOR_TABLE_SGI, GL.GL_RGBA, +// colorTableSize, GL.GL_RGBA, GL2.GL_INT, IntBuffer.wrap(textureColorTable)); +// } +// gl.glEnable(GL.GL_TEXTURE_COLOR_TABLE_SGI); +// } + } + + void updateCombiner(Context ctx, + int combineRgbMode, int combineAlphaMode, + int[] combineRgbSrc, int[] combineAlphaSrc, + int[] combineRgbFcn, int[] combineAlphaFcn, + int combineRgbScale, int combineAlphaScale) { + if (VERBOSE) System.err.println("JoglPipeline.updateCombiner()"); + + GL2 gl = context(ctx).getGL().getGL2(); + int[] GLrgbMode = new int[1]; + int[] GLalphaMode = new int[1]; + getGLCombineMode(gl, combineRgbMode, combineAlphaMode, + GLrgbMode, GLalphaMode); + gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_COMBINE_RGB, GLrgbMode[0]); + gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_COMBINE_ALPHA, GLalphaMode[0]); + + int nargs; + if (combineRgbMode == TextureAttributes.COMBINE_REPLACE) { + nargs = 1; + } else if (combineRgbMode == TextureAttributes.COMBINE_INTERPOLATE) { + nargs = 3; + } else { + nargs = 2; + } + + for (int i = 0; i < nargs; i++) { + gl.glTexEnvi(GL2.GL_TEXTURE_ENV, _gl_combineRgbSrcIndex[i], + _gl_combineSrc[combineRgbSrc[i]]); + gl.glTexEnvi(GL2.GL_TEXTURE_ENV, _gl_combineRgbOpIndex[i], + _gl_combineFcn[combineRgbFcn[i]]); + } + + if (combineAlphaMode == TextureAttributes.COMBINE_REPLACE) { + nargs = 1; + } else if (combineAlphaMode == TextureAttributes.COMBINE_INTERPOLATE) { + nargs = 3; + } else { + nargs = 2; + } + + for (int i = 0; i < nargs; i++) { + gl.glTexEnvi(GL2.GL_TEXTURE_ENV, _gl_combineAlphaSrcIndex[i], + _gl_combineSrc[combineAlphaSrc[i]]); + gl.glTexEnvi(GL2.GL_TEXTURE_ENV, _gl_combineAlphaOpIndex[i], + _gl_combineFcn[combineAlphaFcn[i]]); + } + + gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_RGB_SCALE, combineRgbScale); + gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_ALPHA_SCALE, combineAlphaScale); + } + + // Helper routines for above + + private void getGLCombineMode(GL gl, int combineRgbMode, int combineAlphaMode, + int[] GLrgbMode, int[] GLalphaMode) { + switch (combineRgbMode) { + case TextureAttributes.COMBINE_REPLACE: + GLrgbMode[0] = GL.GL_REPLACE; + break; + case TextureAttributes.COMBINE_MODULATE: + GLrgbMode[0] = GL2.GL_MODULATE; + break; + case TextureAttributes.COMBINE_ADD: + GLrgbMode[0] = GL2.GL_ADD; + break; + case TextureAttributes.COMBINE_ADD_SIGNED: + GLrgbMode[0] = GL2.GL_ADD_SIGNED; + break; + case TextureAttributes.COMBINE_SUBTRACT: + GLrgbMode[0] = GL2.GL_SUBTRACT; + break; + case TextureAttributes.COMBINE_INTERPOLATE: + GLrgbMode[0] = GL2.GL_INTERPOLATE; + break; + case TextureAttributes.COMBINE_DOT3: + GLrgbMode[0] = GL2.GL_DOT3_RGB; + break; + default: + break; + } + + switch (combineAlphaMode) { + case TextureAttributes.COMBINE_REPLACE: + GLalphaMode[0] = GL.GL_REPLACE; + break; + case TextureAttributes.COMBINE_MODULATE: + GLalphaMode[0] = GL2.GL_MODULATE; + break; + case TextureAttributes.COMBINE_ADD: + GLalphaMode[0] = GL2.GL_ADD; + break; + case TextureAttributes.COMBINE_ADD_SIGNED: + GLalphaMode[0] = GL2.GL_ADD_SIGNED; + break; + case TextureAttributes.COMBINE_SUBTRACT: + GLalphaMode[0] = GL2.GL_SUBTRACT; + break; + case TextureAttributes.COMBINE_INTERPOLATE: + GLalphaMode[0] = GL2.GL_INTERPOLATE; + break; + case TextureAttributes.COMBINE_DOT3: + // dot3 will only make sense for alpha if rgb is also + // doing dot3. So if rgb is not doing dot3, fallback to replace + if (combineRgbMode == TextureAttributes.COMBINE_DOT3) { + GLrgbMode[0] = GL2.GL_DOT3_RGBA; + } else { + GLalphaMode[0] = GL.GL_REPLACE; + } + break; + default: + break; + } + } + + // mapping from java enum to gl enum + private static final int[] _gl_combineRgbSrcIndex = { + GL2.GL_SOURCE0_RGB, + GL2.GL_SOURCE1_RGB, + GL2.GL_SOURCE2_RGB, + }; + + private static final int[] _gl_combineAlphaSrcIndex = { + GL2.GL_SOURCE0_ALPHA, + GL2.GL_SOURCE1_ALPHA, + GL2.GL_SOURCE2_ALPHA, + }; + + private static final int[] _gl_combineRgbOpIndex = { + GL2.GL_OPERAND0_RGB, + GL2.GL_OPERAND1_RGB, + GL2.GL_OPERAND2_RGB, + }; + + private static final int[] _gl_combineAlphaOpIndex = { + GL2.GL_OPERAND0_ALPHA, + GL2.GL_OPERAND1_ALPHA, + GL2.GL_OPERAND2_ALPHA, + }; + + private static final int[] _gl_combineSrc = { + GL2.GL_PRIMARY_COLOR, // TextureAttributes.COMBINE_OBJECT_COLOR + GL.GL_TEXTURE, // TextureAttributes.COMBINE_TEXTURE + GL2.GL_CONSTANT, // TextureAttributes.COMBINE_CONSTANT_COLOR + GL2.GL_PREVIOUS, // TextureAttributes.COMBINE_PREVIOUS_TEXTURE_UNIT_STATE + }; + + private static final int[] _gl_combineFcn = { + GL.GL_SRC_COLOR, // TextureAttributes.COMBINE_SRC_COLOR + GL.GL_ONE_MINUS_SRC_COLOR, // TextureAttributes.COMBINE_ONE_MINUS_SRC_COLOR + GL.GL_SRC_ALPHA, // TextureAttributes.COMBINE_SRC_ALPHA + GL.GL_ONE_MINUS_SRC_ALPHA, // TextureAttributes.COMBINE_ONE_MINUS_SRC_ALPHA + }; + +// FIXME: GL_NV_register_combiners +// private int getCombinerArg(GL gl, int arg, int textureUnit, int combUnit) { +// int comb = 0; +// +// switch (arg) { +// case TextureAttributes.COMBINE_OBJECT_COLOR: +// if (combUnit == GL.GL_COMBINER0_NV) { +// comb = GL.GL_PRIMARY_COLOR_NV; +// } else { +// comb = GL.GL_SPARE0_NV; +// } +// break; +// case TextureAttributes.COMBINE_TEXTURE_COLOR: +// comb = textureUnit; +// break; +// case TextureAttributes.COMBINE_CONSTANT_COLOR: +// comb = GL.GL_CONSTANT_COLOR0_NV; +// break; +// case TextureAttributes.COMBINE_PREVIOUS_TEXTURE_UNIT_STATE: +// comb = textureUnit -1; +// break; +// } +// +// return comb; +// } + + + // --------------------------------------------------------------------- + + // + // TextureUnitStateRetained methods + // + + void updateTextureUnitState(Context ctx, int index, boolean enable) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureUnitState()"); + + GL2 gl = context(ctx).getGL().getGL2(); + JoglContext jctx = (JoglContext) ctx; + + if (index >= 0 && gl.isExtensionAvailable("GL_VERSION_1_3")) { + gl.glActiveTexture(index + GL.GL_TEXTURE0); + gl.glClientActiveTexture(GL.GL_TEXTURE0 + index); +// FIXME: GL_NV_register_combiners +// if (gl.isExtensionAvailable("GL_NV_register_combiners")) { +// jctx.setCurrentTextureUnit(index + GL.GL_TEXTURE0); +// jctx.setCurrentCombinerUnit(index + GL.GL_COMBINER0_NV); +// gl.glCombinerParameteriNV(GL.GL_NUM_GENERAL_COMBINERS_NV, index + 1); +// } + } + + if (!enable) { + // if not enabled, then don't enable any tex mapping + gl.glDisable(GL2.GL_TEXTURE_1D); + gl.glDisable(GL.GL_TEXTURE_2D); + gl.glDisable(GL2.GL_TEXTURE_3D); + gl.glDisable(GL.GL_TEXTURE_CUBE_MAP); + } + + // if it is enabled, the enable flag will be taken care of + // in the bindTexture call + } + + + // --------------------------------------------------------------------- + + // + // TextureRetained methods + // Texture2DRetained methods + // + + void bindTexture2D(Context ctx, int objectId, boolean enable) { + if (VERBOSE) System.err.println("JoglPipeline.bindTexture2D(objectId=" + objectId + ",enable=" + enable + ")"); + + GL gl = context(ctx).getGL(); + gl.glDisable(GL.GL_TEXTURE_CUBE_MAP); + gl.glDisable(GL2.GL_TEXTURE_3D); + + if (!enable) { + gl.glDisable(GL.GL_TEXTURE_2D); + } else { + gl.glBindTexture(GL.GL_TEXTURE_2D, objectId); + gl.glEnable(GL.GL_TEXTURE_2D); + } + } + + void updateTexture2DImage(Context ctx, + int numLevels, int level, + int textureFormat, int imageFormat, + int width, int height, + int boundaryWidth, + int dataType, Object data, boolean useAutoMipMap) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DImage(width=" + width + ",height=" + height + ",level=" + level + ")"); + + updateTexture2DImage(ctx, GL.GL_TEXTURE_2D, + numLevels, level, textureFormat, imageFormat, + width, height, boundaryWidth, dataType, data, useAutoMipMap); + } + + void updateTexture2DSubImage(Context ctx, + int level, int xoffset, int yoffset, + int textureFormat, int imageFormat, + int imgXOffset, int imgYOffset, + int tilew, int width, int height, + int dataType, Object data, boolean useAutoMipMap) { + + /* Note: useAutoMipMap is not use for SubImage in the jogl pipe */ + + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DSubImage()"); + + updateTexture2DSubImage(ctx, GL.GL_TEXTURE_2D, + level, xoffset, yoffset, + textureFormat, imageFormat, + imgXOffset, imgYOffset, tilew, width, height, + dataType, data); + } + + void updateTexture2DLodRange(Context ctx, + int baseLevel, int maximumLevel, + float minimumLOD, float maximumLOD) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DLodRange()"); + + updateTextureLodRange(ctx, GL.GL_TEXTURE_2D, + baseLevel, maximumLevel, + minimumLOD, maximumLOD); + } + + void updateTexture2DLodOffset(Context ctx, + float lodOffsetS, float lodOffsetT, + float lodOffsetR) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DLodOffset()"); + + updateTextureLodOffset(ctx, GL.GL_TEXTURE_2D, + lodOffsetS, lodOffsetT, lodOffsetR); + } + + void updateTexture2DBoundary(Context ctx, + int boundaryModeS, int boundaryModeT, + float boundaryRed, float boundaryGreen, + float boundaryBlue, float boundaryAlpha) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DBoundary()"); + + updateTextureBoundary(ctx, GL.GL_TEXTURE_2D, + boundaryModeS, boundaryModeT, -1, + boundaryRed, boundaryGreen, + boundaryBlue, boundaryAlpha); + } + + void updateTexture2DFilterModes(Context ctx, + int minFilter, int magFilter) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DFilterModes()"); + + updateTextureFilterModes(ctx, GL.GL_TEXTURE_2D, minFilter, magFilter); + } + + void updateTexture2DSharpenFunc(Context ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DSharpenFunc()"); + + updateTextureSharpenFunc(ctx, GL.GL_TEXTURE_2D, + numSharpenTextureFuncPts, sharpenTextureFuncPts); + } + + void updateTexture2DFilter4Func(Context ctx, + int numFilter4FuncPts, + float[] filter4FuncPts) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DFilter4Func()"); + + updateTextureFilter4Func(ctx, GL.GL_TEXTURE_2D, + numFilter4FuncPts, filter4FuncPts); + } + + void updateTexture2DAnisotropicFilter(Context ctx, float degree) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DAnisotropicFilter()"); + + updateTextureAnisotropicFilter(ctx, GL.GL_TEXTURE_2D, degree); + } + + private void updateTextureLodRange(Context ctx, + int target, + int baseLevel, int maximumLevel, + float minimumLOD, float maximumLOD) { + GL gl = context(ctx).getGL(); + // checking of the availability of the extension is already done + // in the shared code + gl.glTexParameteri(target, GL2.GL_TEXTURE_BASE_LEVEL, baseLevel); + gl.glTexParameteri(target, GL2.GL_TEXTURE_MAX_LEVEL, maximumLevel); + gl.glTexParameterf(target, GL2.GL_TEXTURE_MIN_LOD, minimumLOD); + gl.glTexParameterf(target, GL2.GL_TEXTURE_MAX_LOD, maximumLOD); + } + + private void updateTextureLodOffset(Context ctx, + int target, + float lodOffsetS, float lodOffsetT, + float lodOffsetR) { +// FIXME: GL_SGIX_texture_lod_bias +// GL gl = context(ctx).getGL(); + // checking of the availability of the extension is already done + // in the shared code +// gl.glTexParameterf(target, GL.GL_TEXTURE_LOD_BIAS_S_SGIX, lodOffsetS); +// gl.glTexParameterf(target, GL.GL_TEXTURE_LOD_BIAS_T_SGIX, lodOffsetT); +// gl.glTexParameterf(target, GL.GL_TEXTURE_LOD_BIAS_R_SGIX, lodOffsetR); + } + + private void updateTextureAnisotropicFilter(Context ctx, int target, float degree) { + GL gl = context(ctx).getGL(); + // checking of the availability of anisotropic filter functionality + // is already done in the shared code + gl.glTexParameterf(target, + GL.GL_TEXTURE_MAX_ANISOTROPY_EXT, + degree); + } + + // --------------------------------------------------------------------- + + // + // Texture3DRetained methods + // + + void bindTexture3D(Context ctx, int objectId, boolean enable) { + if (VERBOSE) System.err.println("JoglPipeline.bindTexture3D()"); + + GL gl = context(ctx).getGL(); + // textureCubeMap will take precedure over 3D Texture + gl.glDisable(GL.GL_TEXTURE_CUBE_MAP); + + if (!enable) { + gl.glDisable(GL2.GL_TEXTURE_3D); + } else { + gl.glBindTexture(GL2.GL_TEXTURE_3D, objectId); + gl.glEnable(GL2.GL_TEXTURE_3D); + } + } + + void updateTexture3DImage(Context ctx, + int numLevels, int level, + int textureFormat, int imageFormat, + int width, int height, int depth, + int boundaryWidth, + int dataType, Object data, boolean useAutoMipMap) { + + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DImage()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + int format = 0; + int internalFormat = 0; + int type = GL2.GL_UNSIGNED_INT_8_8_8_8; + boolean forceAlphaToOne = false; + + switch (textureFormat) { + case Texture.INTENSITY: + internalFormat = GL2.GL_INTENSITY; + break; + case Texture.LUMINANCE: + internalFormat = GL.GL_LUMINANCE; + break; + case Texture.ALPHA: + internalFormat = GL.GL_ALPHA; + break; + case Texture.LUMINANCE_ALPHA: + internalFormat = GL.GL_LUMINANCE_ALPHA; + break; + case Texture.RGB: + internalFormat = GL.GL_RGB; + break; + case Texture.RGBA: + internalFormat = GL.GL_RGBA; + break; + default: + assert false; + return; + } + + if (useAutoMipMap) { + gl.glTexParameteri(GL2.GL_TEXTURE_3D, GL2.GL_GENERATE_MIPMAP, GL.GL_TRUE); + } + else { + gl.glTexParameteri(GL2.GL_TEXTURE_3D, GL2.GL_GENERATE_MIPMAP, GL.GL_FALSE); + } + + if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_BUFFER)) { + + switch (imageFormat) { + case ImageComponentRetained.TYPE_BYTE_BGR: + format = GL2.GL_BGR; + break; + case ImageComponentRetained.TYPE_BYTE_RGB: + format = GL.GL_RGB; + break; + case ImageComponentRetained.TYPE_BYTE_ABGR: + if (gl.isExtensionAvailable("GL_EXT_abgr")) { // If its zero, should never come here! + format = GL2.GL_ABGR_EXT; + } else { + assert false; + return; + } + break; + case ImageComponentRetained.TYPE_BYTE_RGBA: + // all RGB types are stored as RGBA + format = GL.GL_RGBA; + break; + case ImageComponentRetained.TYPE_BYTE_LA: + // all LA types are stored as LA8 + format = GL.GL_LUMINANCE_ALPHA; + break; + case ImageComponentRetained.TYPE_BYTE_GRAY: + if (internalFormat == GL.GL_ALPHA) { + format = GL.GL_ALPHA; + } else { + format = GL.GL_LUMINANCE; + } + break; + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_INT_BGR: + case ImageComponentRetained.TYPE_INT_RGB: + case ImageComponentRetained.TYPE_INT_ARGB: + default: + assert false; + return; + } + + if(dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) { + + gl.glTexImage3D(GL2.GL_TEXTURE_3D, + level, internalFormat, + width, height, depth, boundaryWidth, + format, GL.GL_UNSIGNED_BYTE, ByteBuffer.wrap((byte[]) data)); + } + else { + gl.glTexImage3D(GL2.GL_TEXTURE_3D, + level, internalFormat, + width, height, depth, boundaryWidth, + format, GL.GL_UNSIGNED_BYTE, (ByteBuffer) data); + } + + } else if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_BUFFER)) { + + switch (imageFormat) { + /* GL_BGR */ + case ImageComponentRetained.TYPE_INT_BGR: /* Assume XBGR format */ + format = GL.GL_RGBA; + type = GL2.GL_UNSIGNED_INT_8_8_8_8_REV; + forceAlphaToOne = true; + break; + case ImageComponentRetained.TYPE_INT_RGB: /* Assume XRGB format */ + forceAlphaToOne = true; + /* Fall through to next case */ + case ImageComponentRetained.TYPE_INT_ARGB: + format = GL2.GL_BGRA; + type = GL2.GL_UNSIGNED_INT_8_8_8_8_REV; + break; + /* This method only supports 3 and 4 components formats and INT types. */ + case ImageComponentRetained.TYPE_BYTE_LA: + case ImageComponentRetained.TYPE_BYTE_GRAY: + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_BYTE_BGR: + case ImageComponentRetained.TYPE_BYTE_RGB: + case ImageComponentRetained.TYPE_BYTE_RGBA: + case ImageComponentRetained.TYPE_BYTE_ABGR: + default: + assert false; + return; + } + + /* Force Alpha to 1.0 if needed */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL2.GL_ALPHA_SCALE, 0.0f); + gl.glPixelTransferf(GL2.GL_ALPHA_BIAS, 1.0f); + } + + if(dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) { + gl.glTexImage3D(GL2.GL_TEXTURE_3D, + level, internalFormat, + width, height, depth, boundaryWidth, + format, type, IntBuffer.wrap((int[]) data)); + } else { + gl.glTexImage3D(GL2.GL_TEXTURE_3D, + level, internalFormat, + width, height, depth, boundaryWidth, + format, type, (Buffer) data); + } + + /* Restore Alpha scale and bias */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL2.GL_ALPHA_SCALE, 1.0f); + gl.glPixelTransferf(GL2.GL_ALPHA_BIAS, 0.0f); + } + } else { + assert false; + } + } + + void updateTexture3DSubImage(Context ctx, + int level, + int xoffset, int yoffset, int zoffset, + int textureFormat, int imageFormat, + int imgXOffset, int imgYOffset, int imgZOffset, + int tilew, int tileh, + int width, int height, int depth, + int dataType, Object data, boolean useAutoMipMap) { + + /* Note: useAutoMipMap is not use for SubImage in the jogl pipe */ + + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DSubImage()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + int format = 0; + int internalFormat = 0; + int type = GL2.GL_UNSIGNED_INT_8_8_8_8; + int numBytes = 0; + boolean forceAlphaToOne = false; + boolean pixelStore = false; + + if (imgXOffset > 0 || (width < tilew)) { + pixelStore = true; + gl.glPixelStorei(GL2.GL_UNPACK_ROW_LENGTH, tilew); + } + + switch (textureFormat) { + case Texture.INTENSITY: + internalFormat = GL2.GL_INTENSITY; + break; + case Texture.LUMINANCE: + internalFormat = GL.GL_LUMINANCE; + break; + case Texture.ALPHA: + internalFormat = GL.GL_ALPHA; + break; + case Texture.LUMINANCE_ALPHA: + internalFormat = GL.GL_LUMINANCE_ALPHA; + break; + case Texture.RGB: + internalFormat = GL.GL_RGB; + break; + case Texture.RGBA: + internalFormat = GL.GL_RGBA; + break; + default: + assert false; + } + + if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_BUFFER)) { + + switch (imageFormat) { + case ImageComponentRetained.TYPE_BYTE_BGR: + format = GL2.GL_BGR; + numBytes = 3; + break; + case ImageComponentRetained.TYPE_BYTE_RGB: + format = GL.GL_RGB; + numBytes = 3; + break; + case ImageComponentRetained.TYPE_BYTE_ABGR: + if (gl.isExtensionAvailable("GL_EXT_abgr")) { // If its zero, should never come here! + format = GL2.GL_ABGR_EXT; + numBytes = 4; + } else { + assert false; + return; + } + break; + case ImageComponentRetained.TYPE_BYTE_RGBA: + // all RGB types are stored as RGBA + format = GL.GL_RGBA; + numBytes = 4; + break; + case ImageComponentRetained.TYPE_BYTE_LA: + // all LA types are stored as LA8 + format = GL.GL_LUMINANCE_ALPHA; + numBytes = 2; + break; + case ImageComponentRetained.TYPE_BYTE_GRAY: + if (internalFormat == GL.GL_ALPHA) { + format = GL.GL_ALPHA; + numBytes = 1; + } else { + format = GL.GL_LUMINANCE; + numBytes = 1; + } + break; + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_INT_BGR: + case ImageComponentRetained.TYPE_INT_RGB: + case ImageComponentRetained.TYPE_INT_ARGB: + default: + assert false; + return; + } + + ByteBuffer buf = null; + if(dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) { + buf = ByteBuffer.wrap((byte[]) data); + } + else { + buf = (ByteBuffer) data; + } + + int offset = (tilew * tileh * imgZOffset + + tilew * imgYOffset + imgXOffset) * numBytes; + buf.position(offset); + gl.glTexSubImage3D(GL2.GL_TEXTURE_3D, + level, xoffset, yoffset, zoffset, + width, height, depth, + format, GL.GL_UNSIGNED_BYTE, + buf); + + } else if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_BUFFER)) { + + switch (imageFormat) { + /* GL_BGR */ + case ImageComponentRetained.TYPE_INT_BGR: /* Assume XBGR format */ + format = GL.GL_RGBA; + type = GL2.GL_UNSIGNED_INT_8_8_8_8_REV; + forceAlphaToOne = true; + break; + case ImageComponentRetained.TYPE_INT_RGB: /* Assume XRGB format */ + forceAlphaToOne = true; + /* Fall through to next case */ + case ImageComponentRetained.TYPE_INT_ARGB: + format = GL2.GL_BGRA; + type = GL2.GL_UNSIGNED_INT_8_8_8_8_REV; + break; + /* This method only supports 3 and 4 components formats and INT types. */ + case ImageComponentRetained.TYPE_BYTE_LA: + case ImageComponentRetained.TYPE_BYTE_GRAY: + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_BYTE_BGR: + case ImageComponentRetained.TYPE_BYTE_RGB: + case ImageComponentRetained.TYPE_BYTE_RGBA: + case ImageComponentRetained.TYPE_BYTE_ABGR: + default: + assert false; + return; + } + + /* Force Alpha to 1.0 if needed */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL2.GL_ALPHA_SCALE, 0.0f); + gl.glPixelTransferf(GL2.GL_ALPHA_BIAS, 1.0f); + } + + IntBuffer buf = null; + if(dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) { + buf = IntBuffer.wrap((int[]) data); + } + else { + buf = (IntBuffer) data; + } + + int offset = tilew * tileh * imgZOffset + + tilew * imgYOffset + imgXOffset; + buf.position(offset); + gl.glTexSubImage3D(GL2.GL_TEXTURE_3D, + level, xoffset, yoffset, zoffset, + width, height, depth, + format, type, + buf); + + /* Restore Alpha scale and bias */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL2.GL_ALPHA_SCALE, 1.0f); + gl.glPixelTransferf(GL2.GL_ALPHA_BIAS, 0.0f); + } + } else { + assert false; + return; + } + + if (pixelStore) { + gl.glPixelStorei(GL2.GL_UNPACK_ROW_LENGTH, 0); + } + + } + + + void updateTexture3DLodRange(Context ctx, + int baseLevel, int maximumLevel, + float minimumLod, float maximumLod) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DLodRange()"); + + updateTextureLodRange(ctx, GL2.GL_TEXTURE_3D, + baseLevel, maximumLevel, + minimumLod, maximumLod); + } + + void updateTexture3DLodOffset(Context ctx, + float lodOffsetS, float lodOffsetT, + float lodOffsetR) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DLodOffset()"); + + updateTextureLodOffset(ctx, GL2.GL_TEXTURE_3D, + lodOffsetS, lodOffsetT, lodOffsetR); + } + + void updateTexture3DBoundary(Context ctx, + int boundaryModeS, int boundaryModeT, + int boundaryModeR, float boundaryRed, + float boundaryGreen, float boundaryBlue, + float boundaryAlpha) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DBoundary()"); + + updateTextureBoundary(ctx, GL.GL_TEXTURE_2D, + boundaryModeS, boundaryModeT, boundaryModeR, + boundaryRed, boundaryGreen, + boundaryBlue, boundaryAlpha); + } + + void updateTexture3DFilterModes(Context ctx, + int minFilter, int magFilter) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DFilterModes()"); + + updateTextureFilterModes(ctx, GL2.GL_TEXTURE_3D, + minFilter, magFilter); + } + + void updateTexture3DSharpenFunc(Context ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DSharpenFunc()"); + + updateTextureSharpenFunc(ctx, GL2.GL_TEXTURE_3D, + numSharpenTextureFuncPts, sharpenTextureFuncPts); + } + + void updateTexture3DFilter4Func(Context ctx, + int numFilter4FuncPts, + float[] filter4FuncPts) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DFilter4Func()"); + + updateTextureFilter4Func(ctx, GL2.GL_TEXTURE_3D, + numFilter4FuncPts, filter4FuncPts); + } + + void updateTexture3DAnisotropicFilter(Context ctx, float degree) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DAnisotropicFilter()"); + + updateTextureAnisotropicFilter(ctx, GL2.GL_TEXTURE_3D, degree); + } + + + // --------------------------------------------------------------------- + + // + // TextureCubeMapRetained methods + // + + void bindTextureCubeMap(Context ctx, int objectId, boolean enable) { + if (VERBOSE) System.err.println("JoglPipeline.bindTextureCubeMap()"); + + GL gl = context(ctx).getGL(); + // TextureCubeMap will take precedure over 3D Texture so + // there is no need to disable 3D Texture here. + if (!enable) { + gl.glDisable(GL.GL_TEXTURE_CUBE_MAP); + } else { + gl.glBindTexture(GL.GL_TEXTURE_CUBE_MAP, objectId); + gl.glEnable(GL.GL_TEXTURE_CUBE_MAP); + } + } + + void updateTextureCubeMapImage(Context ctx, + int face, int numLevels, int level, + int textureFormat, int imageFormat, + int width, int height, + int boundaryWidth, + int dataType, Object data, boolean useAutoMipMap) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapImage()"); + + updateTexture2DImage(ctx, _gl_textureCubeMapFace[face], + numLevels, level, textureFormat, imageFormat, + width, height, boundaryWidth, dataType, data, useAutoMipMap); + } + + void updateTextureCubeMapSubImage(Context ctx, + int face, int level, int xoffset, int yoffset, + int textureFormat,int imageFormat, + int imgXOffset, int imgYOffset, + int tilew, int width, int height, + int dataType, Object data, boolean useAutoMipMap) { + + /* Note: useAutoMipMap is not use for SubImage in the jogl pipe */ + + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapSubImage()"); + + updateTexture2DSubImage(ctx, _gl_textureCubeMapFace[face], + level, xoffset, yoffset, textureFormat, + imageFormat, imgXOffset, imgYOffset, tilew, + width, height, dataType, data); + } + + void updateTextureCubeMapLodRange(Context ctx, + int baseLevel, int maximumLevel, + float minimumLod, float maximumLod) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapLodRange()"); + + updateTextureLodRange(ctx, + GL.GL_TEXTURE_CUBE_MAP, + baseLevel, maximumLevel, + minimumLod, maximumLod); + } + + void updateTextureCubeMapLodOffset(Context ctx, + float lodOffsetS, float lodOffsetT, + float lodOffsetR) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapLodOffset()"); + + updateTextureLodOffset(ctx, + GL.GL_TEXTURE_CUBE_MAP, + lodOffsetS, lodOffsetT, lodOffsetR); + } + + void updateTextureCubeMapBoundary(Context ctx, + int boundaryModeS, int boundaryModeT, + float boundaryRed, float boundaryGreen, + float boundaryBlue, float boundaryAlpha) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapBoundary()"); + + updateTextureBoundary(ctx, + GL.GL_TEXTURE_CUBE_MAP, + boundaryModeS, boundaryModeT, -1, + boundaryRed, boundaryGreen, + boundaryBlue, boundaryAlpha); + } + + void updateTextureCubeMapFilterModes(Context ctx, + int minFilter, int magFilter) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapFilterModes()"); + + updateTextureFilterModes(ctx, + GL.GL_TEXTURE_CUBE_MAP, + minFilter, magFilter); + } + + void updateTextureCubeMapSharpenFunc(Context ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapSharpenFunc()"); + + updateTextureSharpenFunc(ctx, + GL.GL_TEXTURE_CUBE_MAP, + numSharpenTextureFuncPts, sharpenTextureFuncPts); + } + + void updateTextureCubeMapFilter4Func(Context ctx, + int numFilter4FuncPts, + float[] filter4FuncPts) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapFilter4Func()"); + + updateTextureFilter4Func(ctx, + GL.GL_TEXTURE_CUBE_MAP, + numFilter4FuncPts, filter4FuncPts); + } + + void updateTextureCubeMapAnisotropicFilter(Context ctx, float degree) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapAnisotropicFilter()"); + + updateTextureAnisotropicFilter(ctx, + GL.GL_TEXTURE_CUBE_MAP, + degree); + } + + //---------------------------------------------------------------------- + // + // Helper routines for above texture methods + // + + private void updateTexture2DImage(Context ctx, + int target, + int numLevels, + int level, + int textureFormat, + int imageFormat, + int width, + int height, + int boundaryWidth, + int dataType, + Object data, + boolean useAutoMipMap) { + GL2 gl = context(ctx).getGL().getGL2(); + + int format = 0, internalFormat = 0; + int type = GL2.GL_UNSIGNED_INT_8_8_8_8; + boolean forceAlphaToOne = false; + + switch (textureFormat) { + case Texture.INTENSITY: + internalFormat = GL2.GL_INTENSITY; + break; + case Texture.LUMINANCE: + internalFormat = GL.GL_LUMINANCE; + break; + case Texture.ALPHA: + internalFormat = GL.GL_ALPHA; + break; + case Texture.LUMINANCE_ALPHA: + internalFormat = GL.GL_LUMINANCE_ALPHA; + break; + case Texture.RGB: + internalFormat = GL.GL_RGB; + break; + case Texture.RGBA: + internalFormat = GL.GL_RGBA; + break; + default: + assert false; + } + + if (useAutoMipMap) { + gl.glTexParameteri(target, GL2.GL_GENERATE_MIPMAP, GL.GL_TRUE); + } + else { + gl.glTexParameteri(target, GL2.GL_GENERATE_MIPMAP, GL.GL_FALSE); + } + + if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_BUFFER)) { + + switch (imageFormat) { + case ImageComponentRetained.TYPE_BYTE_BGR: + format = GL2.GL_BGR; + break; + case ImageComponentRetained.TYPE_BYTE_RGB: + format = GL.GL_RGB; + break; + case ImageComponentRetained.TYPE_BYTE_ABGR: + if (gl.isExtensionAvailable("GL_EXT_abgr")) { // If its zero, should never come here! + format = GL2.GL_ABGR_EXT; + } else { + assert false; + return; + } + break; + case ImageComponentRetained.TYPE_BYTE_RGBA: + // all RGB types are stored as RGBA + format = GL.GL_RGBA; + break; + case ImageComponentRetained.TYPE_BYTE_LA: + // all LA types are stored as LA8 + format = GL.GL_LUMINANCE_ALPHA; + break; + case ImageComponentRetained.TYPE_BYTE_GRAY: + if (internalFormat == GL.GL_ALPHA) { + format = GL.GL_ALPHA; + } else { + format = GL.GL_LUMINANCE; + } + break; + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_INT_BGR: + case ImageComponentRetained.TYPE_INT_RGB: + case ImageComponentRetained.TYPE_INT_ARGB: + default: + assert false; + return; + } + + if(dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) { + + gl.glTexImage2D(target, level, internalFormat, + width, height, boundaryWidth, + format, GL.GL_UNSIGNED_BYTE, ByteBuffer.wrap((byte[])data)); + } else { + gl.glTexImage2D(target, level, internalFormat, + width, height, boundaryWidth, + format, GL.GL_UNSIGNED_BYTE, (Buffer) data); + } + + } else if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_BUFFER)) { + + switch (imageFormat) { + /* GL_BGR */ + case ImageComponentRetained.TYPE_INT_BGR: /* Assume XBGR format */ + format = GL.GL_RGBA; + type = GL2.GL_UNSIGNED_INT_8_8_8_8_REV; + forceAlphaToOne = true; + break; + case ImageComponentRetained.TYPE_INT_RGB: /* Assume XRGB format */ + forceAlphaToOne = true; + /* Fall through to next case */ + case ImageComponentRetained.TYPE_INT_ARGB: + format = GL2.GL_BGRA; + type = GL2.GL_UNSIGNED_INT_8_8_8_8_REV; + break; + /* This method only supports 3 and 4 components formats and INT types. */ + case ImageComponentRetained.TYPE_BYTE_LA: + case ImageComponentRetained.TYPE_BYTE_GRAY: + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_BYTE_BGR: + case ImageComponentRetained.TYPE_BYTE_RGB: + case ImageComponentRetained.TYPE_BYTE_RGBA: + case ImageComponentRetained.TYPE_BYTE_ABGR: + default: + assert false; + return; + } + + /* Force Alpha to 1.0 if needed */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL2.GL_ALPHA_SCALE, 0.0f); + gl.glPixelTransferf(GL2.GL_ALPHA_BIAS, 1.0f); + } + + if(dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) { + gl.glTexImage2D(target, level, internalFormat, + width, height, boundaryWidth, + format, type, IntBuffer.wrap((int[])data)); + } else { + gl.glTexImage2D(target, level, internalFormat, + width, height, boundaryWidth, + format, type, (Buffer) data); + } + + /* Restore Alpha scale and bias */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL2.GL_ALPHA_SCALE, 1.0f); + gl.glPixelTransferf(GL2.GL_ALPHA_BIAS, 0.0f); + } + } else { + assert false; + } + } + + private void updateTexture2DSubImage(Context ctx, + int target, + int level, int xoffset, int yoffset, + int textureFormat, int imageFormat, + int imgXOffset, int imgYOffset, + int tilew, int width, int height, + int dataType, Object data) { + GL2 gl = context(ctx).getGL().getGL2(); + + int format = 0, internalFormat=0; + int numBytes = 0; + int type = GL2.GL_UNSIGNED_INT_8_8_8_8; + boolean forceAlphaToOne = false; + boolean pixelStore = false; + + if (imgXOffset > 0 || (width < tilew)) { + pixelStore = true; + gl.glPixelStorei(GL2.GL_UNPACK_ROW_LENGTH, tilew); + } + + switch (textureFormat) { + case Texture.INTENSITY: + internalFormat = GL2.GL_INTENSITY; + break; + case Texture.LUMINANCE: + internalFormat = GL.GL_LUMINANCE; + break; + case Texture.ALPHA: + internalFormat = GL.GL_ALPHA; + break; + case Texture.LUMINANCE_ALPHA: + internalFormat = GL.GL_LUMINANCE_ALPHA; + break; + case Texture.RGB: + internalFormat = GL.GL_RGB; + break; + case Texture.RGBA: + internalFormat = GL.GL_RGBA; + break; + default: + assert false; + } + + if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_BUFFER)) { + + switch (imageFormat) { + case ImageComponentRetained.TYPE_BYTE_BGR: + format = GL2.GL_BGR; + numBytes = 3; + break; + case ImageComponentRetained.TYPE_BYTE_RGB: + format = GL.GL_RGB; + numBytes = 3; + break; + case ImageComponentRetained.TYPE_BYTE_ABGR: + if (gl.isExtensionAvailable("GL_EXT_abgr")) { // If its zero, should never come here! + format = GL2.GL_ABGR_EXT; + numBytes = 4; + } else { + assert false; + return; + } + break; + case ImageComponentRetained.TYPE_BYTE_RGBA: + // all RGB types are stored as RGBA + format = GL.GL_RGBA; + numBytes = 4; + break; + case ImageComponentRetained.TYPE_BYTE_LA: + // all LA types are stored as LA8 + format = GL.GL_LUMINANCE_ALPHA; + numBytes = 2; + break; + case ImageComponentRetained.TYPE_BYTE_GRAY: + if (internalFormat == GL.GL_ALPHA) { + format = GL.GL_ALPHA; + numBytes = 1; + } else { + format = GL.GL_LUMINANCE; + numBytes = 1; + } + break; + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_INT_BGR: + case ImageComponentRetained.TYPE_INT_RGB: + case ImageComponentRetained.TYPE_INT_ARGB: + default: + assert false; + return; + } + + ByteBuffer buf = null; + if(dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) { + buf = ByteBuffer.wrap((byte[]) data); + } + else { + buf = (ByteBuffer) data; + } + + // offset by the imageOffset + buf.position((tilew * imgYOffset + imgXOffset) * numBytes); + gl.glTexSubImage2D(target, level, xoffset, yoffset, width, height, + format, GL.GL_UNSIGNED_BYTE, buf); + + } else if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_BUFFER)) { + + switch (imageFormat) { + /* GL_BGR */ + case ImageComponentRetained.TYPE_INT_BGR: /* Assume XBGR format */ + format = GL.GL_RGBA; + type = GL2.GL_UNSIGNED_INT_8_8_8_8_REV; + forceAlphaToOne = true; + break; + case ImageComponentRetained.TYPE_INT_RGB: /* Assume XRGB format */ + forceAlphaToOne = true; + /* Fall through to next case */ + case ImageComponentRetained.TYPE_INT_ARGB: + format = GL2.GL_BGRA; + type = GL2.GL_UNSIGNED_INT_8_8_8_8_REV; + break; + /* This method only supports 3 and 4 components formats and INT types. */ + case ImageComponentRetained.TYPE_BYTE_LA: + case ImageComponentRetained.TYPE_BYTE_GRAY: + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_BYTE_BGR: + case ImageComponentRetained.TYPE_BYTE_RGB: + case ImageComponentRetained.TYPE_BYTE_RGBA: + case ImageComponentRetained.TYPE_BYTE_ABGR: + default: + assert false; + return; + } + /* Force Alpha to 1.0 if needed */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL2.GL_ALPHA_SCALE, 0.0f); + gl.glPixelTransferf(GL2.GL_ALPHA_BIAS, 1.0f); + } + + IntBuffer buf = null; + if(dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) { + buf = IntBuffer.wrap((int[]) data); + } + else { + buf = (IntBuffer) data; + } + + // offset by the imageOffset + buf.position(tilew * imgYOffset + imgXOffset); + gl.glTexSubImage2D(target, level, xoffset, yoffset, width, height, + format, type, buf); + + /* Restore Alpha scale and bias */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL2.GL_ALPHA_SCALE, 1.0f); + gl.glPixelTransferf(GL2.GL_ALPHA_BIAS, 0.0f); + } + } else { + assert false; + return; + } + + if (pixelStore) { + gl.glPixelStorei(GL2.GL_UNPACK_ROW_LENGTH, 0); + } + + } + + void updateTextureFilterModes(Context ctx, + int target, + int minFilter, + int magFilter) { + GL gl = context(ctx).getGL(); + + if (EXTRA_DEBUGGING) { + System.err.println("minFilter: " + getFilterName(minFilter) + + " magFilter: " + getFilterName(magFilter)); + } + + // FIXME: unclear whether we really need to set up the enum values + // in the JoglContext as is done in the native code depending on + // extension availability; maybe this is the defined fallback + // behavior of the various Java3D modes + + // set texture min filter + switch (minFilter) { + case Texture.FASTEST: + case Texture.BASE_LEVEL_POINT: + gl.glTexParameteri(target, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); + break; + case Texture.BASE_LEVEL_LINEAR: + gl.glTexParameteri(target, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); + break; + case Texture.MULTI_LEVEL_POINT: + gl.glTexParameteri(target, GL.GL_TEXTURE_MIN_FILTER, + GL.GL_NEAREST_MIPMAP_NEAREST); + break; + case Texture.NICEST: + case Texture.MULTI_LEVEL_LINEAR: + gl.glTexParameteri(target, GL.GL_TEXTURE_MIN_FILTER, + GL.GL_LINEAR_MIPMAP_LINEAR); + break; + case Texture.FILTER4: +// We should never get here as we've disabled the FILTER4 feature +// gl.glTexParameteri(target, GL.GL_TEXTURE_MIN_FILTER, +// GL.GL_FILTER4_SGIS); + break; + } + + // set texture mag filter + switch (magFilter) { + case Texture.FASTEST: + case Texture.BASE_LEVEL_POINT: + gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); + break; + case Texture.NICEST: + case Texture.BASE_LEVEL_LINEAR: + gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); + break; + case Texture.LINEAR_SHARPEN: +// We should never get here as we've disabled the TEXTURE_SHARPEN feature +// gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, +// GL.GL_LINEAR_SHARPEN_SGIS); + break; + case Texture.LINEAR_SHARPEN_RGB: +// We should never get here as we've disabled the TEXTURE_SHARPEN feature +// gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, +// GL.GL_LINEAR_SHARPEN_COLOR_SGIS); + break; + case Texture.LINEAR_SHARPEN_ALPHA: +// We should never get here as we've disabled the TEXTURE_SHARPEN feature +// gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, +// GL.GL_LINEAR_SHARPEN_ALPHA_SGIS); + break; + case Texture2D.LINEAR_DETAIL: +// We should never get here as we've disabled the TEXTURE_DETAIL feature +// gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, +// GL.GL_LINEAR_DETAIL_SGIS); + break; + case Texture2D.LINEAR_DETAIL_RGB: +// We should never get here as we've disabled the TEXTURE_DETAIL feature +// gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, +// GL.GL_LINEAR_DETAIL_COLOR_SGIS); + break; + case Texture2D.LINEAR_DETAIL_ALPHA: +// We should never get here as we've disabled the TEXTURE_DETAIL feature +// gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, +// GL.GL_LINEAR_DETAIL_ALPHA_SGIS); + break; + case Texture.FILTER4: +// We should never get here as we've disabled the FILTER4 feature +// gl.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, +// GL.GL_FILTER4_SGIS); + break; + } + } + + void updateTextureBoundary(Context ctx, + int target, + int boundaryModeS, + int boundaryModeT, + int boundaryModeR, + float boundaryRed, + float boundaryGreen, + float boundaryBlue, + float boundaryAlpha) { + GL gl = context(ctx).getGL(); + + // set texture wrap parameter + switch (boundaryModeS) { + case Texture.WRAP: + gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT); + break; + case Texture.CLAMP: + gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP); + break; + case Texture.CLAMP_TO_EDGE: + gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_S, + GL.GL_CLAMP_TO_EDGE); + break; + case Texture.CLAMP_TO_BOUNDARY: + gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_S, + GL2.GL_CLAMP_TO_BORDER); + break; + } + + switch (boundaryModeT) { + case Texture.WRAP: + gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT); + break; + case Texture.CLAMP: + gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP); + break; + case Texture.CLAMP_TO_EDGE: + gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_T, + GL.GL_CLAMP_TO_EDGE); + break; + case Texture.CLAMP_TO_BOUNDARY: + gl.glTexParameteri(target, GL.GL_TEXTURE_WRAP_T, + GL2.GL_CLAMP_TO_BORDER); + break; + } + + // applies to Texture3D only + if (boundaryModeR != -1) { + switch (boundaryModeR) { + case Texture.WRAP: + gl.glTexParameteri(target, + GL2.GL_TEXTURE_WRAP_R, GL.GL_REPEAT); + break; + + case Texture.CLAMP: + gl.glTexParameteri(target, + GL2.GL_TEXTURE_WRAP_R, GL2.GL_CLAMP); + break; + case Texture.CLAMP_TO_EDGE: + gl.glTexParameteri(target, + GL2.GL_TEXTURE_WRAP_R, + GL.GL_CLAMP_TO_EDGE); + break; + case Texture.CLAMP_TO_BOUNDARY: + gl.glTexParameteri(target, + GL2.GL_TEXTURE_WRAP_R, + GL2.GL_CLAMP_TO_BORDER); + break; + } + } + + if (boundaryModeS == Texture.CLAMP || + boundaryModeT == Texture.CLAMP || + boundaryModeR == Texture.CLAMP) { + // set texture border color + float[] color = new float[4]; + color[0] = boundaryRed; + color[1] = boundaryGreen; + color[2] = boundaryBlue; + color[3] = boundaryAlpha; + gl.glTexParameterfv(target, GL2.GL_TEXTURE_BORDER_COLOR, color, 0); + } + } + + private static final String getFilterName(int filter) { + switch (filter) { + case Texture.FASTEST: + return "Texture.FASTEST"; + case Texture.NICEST: + return "Texture.NICEST"; + case Texture.BASE_LEVEL_POINT: + return "Texture.BASE_LEVEL_POINT"; + case Texture.BASE_LEVEL_LINEAR: + return "Texture.BASE_LEVEL_LINEAR"; + case Texture.MULTI_LEVEL_POINT: + return "Texture.MULTI_LEVEL_POINT"; + case Texture.MULTI_LEVEL_LINEAR: + return "Texture.MULTI_LEVEL_LINEAR"; + case Texture.FILTER4: + return "Texture.FILTER4"; + case Texture.LINEAR_SHARPEN: + return "Texture.LINEAR_SHARPEN"; + case Texture.LINEAR_SHARPEN_RGB: + return "Texture.LINEAR_SHARPEN_RGB"; + case Texture.LINEAR_SHARPEN_ALPHA: + return "Texture.LINEAR_SHARPEN_ALPHA"; + case Texture2D.LINEAR_DETAIL: + return "Texture.LINEAR_DETAIL"; + case Texture2D.LINEAR_DETAIL_RGB: + return "Texture.LINEAR_DETAIL_RGB"; + case Texture2D.LINEAR_DETAIL_ALPHA: + return "Texture.LINEAR_DETAIL_ALPHA"; + default: + return "(unknown)"; + } + } + + private void updateTextureSharpenFunc(Context ctx, + int target, + int numPts, + float[] pts) { + // checking of the availability of sharpen texture functionality + // is already done in shared code +// FIXME: GL_SGIS_sharpen_texture +// GL gl = context(ctx).getGL(); +// gl.glSharpenTexFuncSGIS(target, numPts, pts, 0); + } + + private void updateTextureFilter4Func(Context ctx, + int target, + int numPts, + float[] pts) { + // checking of the availability of filter4 functionality + // is already done in shared code +// FIXME: GL_SGIS_texture_filter4 +// GL gl = context(ctx).getGL(); +// gl.glTexFilterFuncSGIS(target, GL.GL_FILTER4_SGIS, +// numPts, pts, 0); + } + + // mapping from java enum to gl enum + private static final int[] _gl_textureCubeMapFace = { + GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, + }; + + // --------------------------------------------------------------------- + + // + // MasterControl methods + // + + // Method to return the AWT object + long getAWT() { + if (VERBOSE) System.err.println("JoglPipeline.getAWT()"); + + // FIXME: probably completely unneeded in this implementation, + // but should probably remove this dependence in the shared code + return 0; + } + + // Method to initialize the native J3D library + boolean initializeJ3D(boolean disableXinerama) { + // Dummy method in JOGL pipeline + return true; + } + + // Maximum lights supported by the native API + int getMaximumLights() { + if (VERBOSE) System.err.println("JoglPipeline.getMaximumLights()"); + + // FIXME: this isn't quite what the NativePipeline returns but + // is probably close enough + return 8; + } + + + // --------------------------------------------------------------------- + + // + // Canvas3D methods - native wrappers + // + + // This is the native method for creating the underlying graphics context. + Context createNewContext(Canvas3D cv, long display, Drawable drawable, + long fbConfig, Context shareCtx, boolean isSharedCtx, + boolean offScreen, + boolean glslLibraryAvailable) { + if (VERBOSE) System.err.println("JoglPipeline.createNewContext()"); + GLDrawable draw = null; + GLCapabilitiesChooser indexChooser = null; + JoglGraphicsConfiguration config = (JoglGraphicsConfiguration) cv.graphicsConfiguration; + if (config.getChosenIndex() >= 0) { + indexChooser = new IndexCapabilitiesChooser(config.getChosenIndex()); + } + if (cv.drawable == null) { + AWTGraphicsScreen awtGraphicsScreen = new AWTGraphicsScreen(config.getAwtGraphicsDevice()); + GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(config.getAwtGraphicsDevice()); + AWTGraphicsConfiguration awtGraphicsConfiguration = (AWTGraphicsConfiguration)factory.chooseGraphicsConfiguration(config.getGLCapabilities(), + config.getGLCapabilities(), + indexChooser, awtGraphicsScreen); + NativeWindow nativeWindow = NativeWindowFactory.getNativeWindow(cv, awtGraphicsConfiguration); + draw = GLDrawableFactory.getFactory(getDefaultProfile()).createGLDrawable(nativeWindow); + cv.drawable = new JoglDrawable(draw); + } else { + draw = drawable(cv.drawable); + } + + // FIXME: assuming that this only gets called after addNotify has been called + draw.setRealized(true); + GLContext context = draw.createContext(context(shareCtx)); + + // Apparently we are supposed to make the context current at + // this point and set up a bunch of properties + + // Work around for some low end graphics driver bug, such as Intel Chipset. + // Issue 324 : Lockup Java3D program and throw exception using JOGL renderer + boolean failed = false; + int failCount = 0; + int MAX_FAIL_COUNT = 5; + do { + failed = false; + int res = context.makeCurrent(); + if (res == GLContext.CONTEXT_NOT_CURRENT) { + // System.err.println("makeCurrent fail : " + failCount); + failed = true; + ++failCount; + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + } + } while (failed && (failCount < MAX_FAIL_COUNT)); + if (failCount == MAX_FAIL_COUNT) { + throw new IllegalRenderingStateException("Unable to make new context current after " + failCount + "tries"); + } + + GL2 gl = context.getGL().getGL2(); + JoglContext ctx = new JoglContext(context); + + try { + if (!getPropertiesFromCurrentContext(ctx)) { + throw new IllegalRenderingStateException("Unable to fetch properties from current OpenGL context"); + } + + if(!isSharedCtx){ + // Set up fields in Canvas3D + setupCanvasProperties(cv, ctx, gl, glslLibraryAvailable); + } + + // Enable rescale normal + gl.glEnable(GL2.GL_RESCALE_NORMAL); + + gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE); + gl.glDepthFunc(GL.GL_LEQUAL); + gl.glEnable(GL2.GL_COLOR_MATERIAL); + gl.glReadBuffer(GL.GL_FRONT); + + // Issue 417: JOGL: Mip-mapped NPOT textures rendered incorrectly + // Java 3D images are aligned to 1 byte + gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); + + // Workaround for issue 400: Enable separate specular by default + gl.glLightModeli(GL2.GL_LIGHT_MODEL_COLOR_CONTROL, GL2.GL_SEPARATE_SPECULAR_COLOR); + } finally { + context.release(); + } + + return ctx; + } + + private GLProfile getDefaultProfile() { + return GLProfile.getMaxFixedFunc(true); + } + + void createQueryContext(Canvas3D cv, long display, Drawable drawable, + long fbConfig, boolean offScreen, int width, int height, + boolean glslLibraryAvailable) { + if (VERBOSE) System.err.println("JoglPipeline.createQueryContext()"); + + // FIXME: for now, ignoring the "offscreen" flag -- unclear how + // to create an offscreen buffer at this point -- very likely + // need Canvas3D.offScreenBufferInfo promoted to an Object -- + // this logic will need to be revisited to make sure we capture + // all of the functionality of the NativePipeline + + Frame f = new Frame(); + f.setUndecorated(true); + f.setLayout(new BorderLayout()); + GLCapabilities caps = new GLCapabilities(getDefaultProfile()); + ContextQuerier querier = new ContextQuerier(cv, glslLibraryAvailable); + // FIXME: should know what GraphicsDevice on which to create + // this Canvas / Frame, and this should probably be known from + // the incoming "display" parameter + + JoglGraphicsConfiguration joglGraphicsConfiguration = (JoglGraphicsConfiguration) cv.graphicsConfiguration; + AWTGraphicsDevice awtGraphicsDevice = joglGraphicsConfiguration.getAwtGraphicsDevice(); + AWTGraphicsConfiguration awtGraphicsConfiguration = createAwtGraphicsConfiguration(caps, querier, awtGraphicsDevice/*null*/); + + QueryCanvas canvas = new QueryCanvas(awtGraphicsConfiguration, querier); + f.add(canvas, BorderLayout.CENTER); + f.setSize(MIN_FRAME_SIZE, MIN_FRAME_SIZE); + f.setVisible(true); + canvas.doQuery(); + // Attempt to wait for the frame to become visible, but don't block the EDT + if (!EventQueue.isDispatchThread()) { + synchronized(querier) { + if (!querier.done()) { + try { + querier.wait(WAIT_TIME); + } catch (InterruptedException e) { + } + } + } + } + + disposeOnEDT(f); + } + + // This is the native for creating an offscreen buffer + Drawable createOffScreenBuffer(Canvas3D cv, Context ctx, long display, long fbConfig, int width, int height) { + if (VERBOSE) System.err.println("JoglPipeline.createOffScreenBuffer()"); + + // Note 1: when this is called, the incoming Context argument is + // null because (obviously) no drawable or context has been + // created for the Canvas3D yet. + + // Note 2: we ignore the global j3d.usePbuffer flag; JOGL + // doesn't expose pixmap/bitmap surfaces in its public API. + + // First pick up the JoglGraphicsConfiguration and from there + // the GLCapabilities from the Canvas3D + JoglGraphicsConfiguration jcfg = (JoglGraphicsConfiguration) cv.graphicsConfiguration; + // Note that we ignore any chosen index from a prior call to getBestConfiguration(); + // those only enumerate the on-screen visuals, and we need to find one which is + // pbuffer capable + GLCapabilities caps = jcfg.getGLCapabilities(); + + //FIXME use the real AWTGraphicsDevice + GLPbuffer pbuffer = GLDrawableFactory.getFactory(getDefaultProfile()).createGLPbuffer(GLDrawableFactory.getDesktopFactory().getDefaultDevice() ,caps, null,width, height, GLContext.getCurrent()); + + return new JoglDrawable(pbuffer); + } + + void destroyOffScreenBuffer(Canvas3D cv, Context ctx, long display, long fbConfig, Drawable drawable) { + if (VERBOSE) System.err.println("JoglPipeline.destroyOffScreenBuffer()"); + + JoglDrawable jdraw = (JoglDrawable) drawable; + GLPbuffer pbuffer = (GLPbuffer) jdraw.getGLDrawable(); + pbuffer.destroy(); + } + + // This is the native for reading the image from the offscreen buffer + void readOffScreenBuffer(Canvas3D cv, Context ctx, int format, int dataType, Object data, int width, int height) { + if (VERBOSE) System.err.println("JoglPipeline.readOffScreenBuffer()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glPixelStorei(GL2.GL_PACK_ROW_LENGTH, width); + gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1); + + int type = 0; + if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_BUFFER)) { + + switch (format) { + // GL_BGR + case ImageComponentRetained.TYPE_BYTE_BGR: + type = GL2.GL_BGR; + break; + case ImageComponentRetained.TYPE_BYTE_RGB: + type = GL.GL_RGB; + break; + // GL_ABGR_EXT + case ImageComponentRetained.TYPE_BYTE_ABGR: + if (gl.isExtensionAvailable("GL_EXT_abgr")) { // If false, should never come here! + type = GL2.GL_ABGR_EXT; + } else { + assert false; + return; + } + break; + case ImageComponentRetained.TYPE_BYTE_RGBA: + type = GL.GL_RGBA; + break; + + /* This method only supports 3 and 4 components formats and BYTE types. */ + case ImageComponentRetained.TYPE_BYTE_LA: + case ImageComponentRetained.TYPE_BYTE_GRAY: + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_INT_BGR: + case ImageComponentRetained.TYPE_INT_RGB: + case ImageComponentRetained.TYPE_INT_ARGB: + default: + throw new AssertionError("illegal format " + format); + } + + gl.glReadPixels(0, 0, width, height, type, GL.GL_UNSIGNED_BYTE, ByteBuffer.wrap((byte[]) data)); + + } else if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) || + (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_BUFFER)) { + + int intType = GL2.GL_UNSIGNED_INT_8_8_8_8; + boolean forceAlphaToOne = false; + + switch (format) { + /* GL_BGR */ + case ImageComponentRetained.TYPE_INT_BGR: /* Assume XBGR format */ + type = GL.GL_RGBA; + intType = GL2.GL_UNSIGNED_INT_8_8_8_8_REV; + forceAlphaToOne = true; + break; + case ImageComponentRetained.TYPE_INT_RGB: /* Assume XRGB format */ + forceAlphaToOne = true; + /* Fall through to next case */ + case ImageComponentRetained.TYPE_INT_ARGB: + type = GL2.GL_BGRA; + intType = GL2.GL_UNSIGNED_INT_8_8_8_8_REV; + break; + /* This method only supports 3 and 4 components formats and BYTE types. */ + case ImageComponentRetained.TYPE_BYTE_LA: + case ImageComponentRetained.TYPE_BYTE_GRAY: + case ImageComponentRetained.TYPE_USHORT_GRAY: + case ImageComponentRetained.TYPE_BYTE_BGR: + case ImageComponentRetained.TYPE_BYTE_RGB: + case ImageComponentRetained.TYPE_BYTE_RGBA: + case ImageComponentRetained.TYPE_BYTE_ABGR: + default: + throw new AssertionError("illegal format " + format); + } + + /* Force Alpha to 1.0 if needed */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL2.GL_ALPHA_SCALE, 0.0f); + gl.glPixelTransferf(GL2.GL_ALPHA_BIAS, 1.0f); + } + + gl.glReadPixels(0, 0, width, height, type, intType, IntBuffer.wrap((int[]) data)); + + /* Restore Alpha scale and bias */ + if(forceAlphaToOne) { + gl.glPixelTransferf(GL2.GL_ALPHA_SCALE, 1.0f); + gl.glPixelTransferf(GL2.GL_ALPHA_BIAS, 0.0f); + } + + } else { + throw new AssertionError("illegal image data type " + dataType); + + } + } + + // The native method for swapBuffers + int swapBuffers(Canvas3D cv, Context ctx, long dpy, Drawable drawable) { + if (VERBOSE) System.err.println("JoglPipeline.swapBuffers()"); + GLDrawable draw = drawable(drawable); + draw.swapBuffers(); + return 0; + } + + // native method for setting Material when no material is present + void updateMaterialColor(Context ctx, float r, float g, float b, float a) { + if (VERBOSE) System.err.println("JoglPipeline.updateMaterialColor()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glColor4f(r, g, b, a); + gl.glDisable(GL2.GL_LIGHTING); + } + + void destroyContext(long display, Drawable drawable, Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.destroyContext()"); + GLDrawable draw = drawable(drawable); + GLContext context = context(ctx); + if (GLContext.getCurrent() == context) { + context.release(); + } + context.destroy(); + // FIXME: assuming this is the right point at which to make this call + draw.setRealized(false); + } + + // This is the native method for doing accumulation. + void accum(Context ctx, float value) { + if (VERBOSE) System.err.println("JoglPipeline.accum()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glReadBuffer(GL.GL_BACK); + gl.glAccum(GL2.GL_ACCUM, value); + gl.glReadBuffer(GL.GL_FRONT); + } + + // This is the native method for doing accumulation return. + void accumReturn(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.accumReturn()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glAccum(GL2.GL_RETURN, 1.0f); + } + + // This is the native method for clearing the accumulation buffer. + void clearAccum(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.clearAccum()"); + + GL gl = context(ctx).getGL(); + gl.glClear(GL2.GL_ACCUM_BUFFER_BIT); + } + + // This is the native method for getting the number of lights the underlying + // native library can support. + int getNumCtxLights(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.getNumCtxLights()"); + + GL gl = context(ctx).getGL(); + int[] res = new int[1]; + gl.glGetIntegerv(GL2.GL_MAX_LIGHTS, res, 0); + return res[0]; + } + + // Native method for decal 1st child setup + boolean decal1stChildSetup(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.decal1stChildSetup()"); + + GL gl = context(ctx).getGL(); + gl.glEnable(GL.GL_STENCIL_TEST); + gl.glClearStencil(0x0); + gl.glClear(GL.GL_STENCIL_BUFFER_BIT); + gl.glStencilFunc(GL.GL_ALWAYS, 0x1, 0x1); + gl.glStencilOp(GL.GL_KEEP, GL.GL_KEEP, GL.GL_REPLACE); + if (gl.glIsEnabled(GL.GL_DEPTH_TEST)) + return true; + else + return false; + } + + // Native method for decal nth child setup + void decalNthChildSetup(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.decalNthChildSetup()"); + + GL gl = context(ctx).getGL(); + gl.glDisable(GL.GL_DEPTH_TEST); + gl.glStencilFunc(GL.GL_EQUAL, 0x1, 0x1); + gl.glStencilOp(GL.GL_KEEP, GL.GL_KEEP, GL.GL_KEEP); + } + + // Native method for decal reset + void decalReset(Context ctx, boolean depthBufferEnable) { + if (VERBOSE) System.err.println("JoglPipeline.decalReset()"); + + GL gl = context(ctx).getGL(); + gl.glDisable(GL.GL_STENCIL_TEST); + if (depthBufferEnable) + gl.glEnable(GL.GL_DEPTH_TEST); + } + + // Native method for eye lighting + void ctxUpdateEyeLightingEnable(Context ctx, boolean localEyeLightingEnable) { + if (VERBOSE) System.err.println("JoglPipeline.ctxUpdateEyeLightingEnable()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + if (localEyeLightingEnable) { + gl.glLightModeli(GL2.GL_LIGHT_MODEL_LOCAL_VIEWER, GL.GL_TRUE); + } else { + gl.glLightModeli(GL2.GL_LIGHT_MODEL_LOCAL_VIEWER, GL.GL_FALSE); + } + } + + // The following three methods are used in multi-pass case + + // native method for setting blend color + void setBlendColor(Context ctx, float red, float green, + float blue, float alpha) { + if (VERBOSE) System.err.println("JoglPipeline.setBlendColor()"); + + GL2 gl = context(ctx).getGL().getGL2(); + if (gl.isExtensionAvailable("GL_ARB_imaging")) { + gl.glBlendColor(red, green, blue, alpha); + } + } + + // native method for setting blend func + void setBlendFunc(Context ctx, int srcBlendFunction, int dstBlendFunction) { + if (VERBOSE) System.err.println("JoglPipeline.setBlendFunc()"); + + GL gl = context(ctx).getGL(); + gl.glEnable(GL.GL_BLEND); + gl.glBlendFunc(blendFunctionTable[srcBlendFunction], + blendFunctionTable[dstBlendFunction]); + } + + // native method for setting fog enable flag + void setFogEnableFlag(Context ctx, boolean enable) { + if (VERBOSE) System.err.println("JoglPipeline.setFogEnableFlag()"); + + GL gl = context(ctx).getGL(); + + if (enable) + gl.glEnable(GL2.GL_FOG); + else + gl.glDisable(GL2.GL_FOG); + } + + // Setup the full scene antialising in D3D and ogl when GL_ARB_multisamle supported + void setFullSceneAntialiasing(Context absCtx, boolean enable) { + if (VERBOSE) System.err.println("JoglPipeline.setFullSceneAntialiasing()"); + + JoglContext ctx = (JoglContext) absCtx; + GL gl = context(ctx).getGL(); + if (ctx.getHasMultisample() && !VirtualUniverse.mc.implicitAntialiasing) { + if (enable) { + gl.glEnable(GL.GL_MULTISAMPLE); + } else { + gl.glDisable(GL.GL_MULTISAMPLE); + } + } + } + + void setGlobalAlpha(Context ctx, float alpha) { + if (VERBOSE) System.err.println("JoglPipeline.setGlobalAlpha()"); +// FIXME: SUN_global_alpha +// GL gl = context(ctx).getGL(); +// if (gl.isExtensionAvailable("GL_SUN_global_alpha")) { +// gl.glEnable(GL.GL_GLOBAL_ALPHA_SUN); +// gl.glGlobalAlphaFactorfSUN(alpha); +// } + } + + // Native method to update separate specular color control + void updateSeparateSpecularColorEnable(Context ctx, boolean enable) { + if (VERBOSE) System.err.println("JoglPipeline.updateSeparateSpecularColorEnable()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + if (enable) { + gl.glLightModeli(GL2.GL_LIGHT_MODEL_COLOR_CONTROL, GL2.GL_SEPARATE_SPECULAR_COLOR); + } else { + gl.glLightModeli(GL2.GL_LIGHT_MODEL_COLOR_CONTROL, GL2.GL_SINGLE_COLOR); + } + } + + // True under Solaris, + // False under windows when display mode <= 8 bit + boolean validGraphicsMode() { + if (VERBOSE) System.err.println("JoglPipeline.validGraphicsMode()"); + + // FIXME: believe this should do exactly what the native code + // used to, but not 100% sure (also in theory should only run + // this code on the Windows platform? What about Mac OS X?) + DisplayMode currentMode = + GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode(); + // Note: on X11 platforms, a bit depth < 0 simply indicates that + // multiple visuals are supported on the current display mode + + if (VERBOSE) System.err.println(" Returning " + (currentMode.getBitDepth() < 0 || + currentMode.getBitDepth() > 8)); + + return (currentMode.getBitDepth() < 0 || + currentMode.getBitDepth() > 8); + } + + // native method for setting light enables + void setLightEnables(Context ctx, long enableMask, int maxLights) { + if (VERBOSE) System.err.println("JoglPipeline.setLightEnables()"); + + GL gl = context(ctx).getGL(); + + for (int i = 0; i < maxLights; i++) { + if ((enableMask & (1 << i)) != 0) { + gl.glEnable(GL2.GL_LIGHT0 + i); + } else { + gl.glDisable(GL2.GL_LIGHT0 + i); + } + } + } + + // native method for setting scene ambient + void setSceneAmbient(Context ctx, float red, float green, float blue) { + if (VERBOSE) System.err.println("JoglPipeline.setSceneAmbient()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + float[] color = new float[4]; + color[0] = red; + color[1] = green; + color[2] = blue; + color[3] = 1.0f; + gl.glLightModelfv(GL2.GL_LIGHT_MODEL_AMBIENT, color, 0); + } + + // native method for disabling fog + void disableFog(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.disableFog()"); + + GL gl = context(ctx).getGL(); + gl.glDisable(GL2.GL_FOG); + } + + // native method for disabling modelClip + void disableModelClip(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.disableModelClip()"); + + GL gl = context(ctx).getGL(); + + gl.glDisable(GL2.GL_CLIP_PLANE0); + gl.glDisable(GL2.GL_CLIP_PLANE1); + gl.glDisable(GL2.GL_CLIP_PLANE2); + gl.glDisable(GL2.GL_CLIP_PLANE3); + gl.glDisable(GL2.GL_CLIP_PLANE4); + gl.glDisable(GL2.GL_CLIP_PLANE5); + } + + // native method for setting default RenderingAttributes + void resetRenderingAttributes(Context ctx, + boolean depthBufferWriteEnableOverride, + boolean depthBufferEnableOverride) { + if (VERBOSE) System.err.println("JoglPipeline.resetRenderingAttributes()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + if (!depthBufferWriteEnableOverride) { + gl.glDepthMask(true); + } + if (!depthBufferEnableOverride) { + gl.glEnable(GL.GL_DEPTH_TEST); + } + gl.glAlphaFunc(GL.GL_ALWAYS, 0.0f); + gl.glDepthFunc(GL.GL_LEQUAL); + gl.glEnable(GL2.GL_COLOR_MATERIAL); + gl.glDisable(GL.GL_COLOR_LOGIC_OP); + } + + // native method for setting default texture + void resetTextureNative(Context ctx, int texUnitIndex) { + if (VERBOSE) System.err.println("JoglPipeline.resetTextureNative()"); + + GL2 gl = context(ctx).getGL().getGL2(); + if (texUnitIndex >= 0 && + gl.isExtensionAvailable("GL_VERSION_1_3")) { + gl.glActiveTexture(texUnitIndex + GL.GL_TEXTURE0); + gl.glClientActiveTexture(texUnitIndex + GL.GL_TEXTURE0); + } + + gl.glDisable(GL2.GL_TEXTURE_1D); + gl.glDisable(GL.GL_TEXTURE_2D); + gl.glDisable(GL2.GL_TEXTURE_3D); + gl.glDisable(GL.GL_TEXTURE_CUBE_MAP); + } + + // native method for activating a particular texture unit + void activeTextureUnit(Context ctx, int texUnitIndex) { + if (VERBOSE) System.err.println("JoglPipeline.activeTextureUnit()"); + + GL2 gl = context(ctx).getGL().getGL2(); + if (gl.isExtensionAvailable("GL_VERSION_1_3")) { + gl.glActiveTexture(texUnitIndex + GL.GL_TEXTURE0); + gl.glClientActiveTexture(texUnitIndex + GL.GL_TEXTURE0); + } + } + + // native method for setting default TexCoordGeneration + void resetTexCoordGeneration(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.resetTexCoordGeneration()"); + + GL gl = context(ctx).getGL(); + gl.glDisable(GL2.GL_TEXTURE_GEN_S); + gl.glDisable(GL2.GL_TEXTURE_GEN_T); + gl.glDisable(GL2.GL_TEXTURE_GEN_R); + gl.glDisable(GL2.GL_TEXTURE_GEN_Q); + } + + // native method for setting default TextureAttributes + void resetTextureAttributes(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.resetTextureAttributes()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + float[] color = new float[4]; + + gl.glPushAttrib(GL2.GL_TRANSFORM_BIT); + gl.glMatrixMode(GL.GL_TEXTURE); + gl.glLoadIdentity(); + gl.glPopAttrib(); + gl.glTexEnvfv(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_COLOR, color, 0); + gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE); + gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST); + +// FIXME: GL_NV_register_combiners +// if (gl.isExtensionAvailable("GL_NV_register_combiners")) { +// gl.glDisable(GL.GL_REGISTER_COMBINERS_NV); +// } + +// FIXME: GL_SGI_texture_color_table +// if (gl.isExtensionAvailable("GL_SGI_texture_color_table")) { +// gl.glDisable(GL.GL_TEXTURE_COLOR_TABLE_SGI); +// } + } + + // native method for setting default PolygonAttributes + void resetPolygonAttributes(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.resetPolygonAttributes()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + gl.glCullFace(GL.GL_BACK); + gl.glEnable(GL.GL_CULL_FACE); + + gl.glLightModeli(GL2.GL_LIGHT_MODEL_TWO_SIDE, GL.GL_FALSE); + + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_FILL); + + gl.glPolygonOffset(0.0f, 0.0f); + gl.glDisable(GL2.GL_POLYGON_OFFSET_POINT); + gl.glDisable(GL2.GL_POLYGON_OFFSET_LINE); + gl.glDisable(GL.GL_POLYGON_OFFSET_FILL); + } + + // native method for setting default LineAttributes + void resetLineAttributes(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.resetLineAttributes()"); + + GL gl = context(ctx).getGL(); + gl.glLineWidth(1.0f); + gl.glDisable(GL2.GL_LINE_STIPPLE); + + // XXXX: Polygon Mode check, blend enable + gl.glDisable(GL.GL_LINE_SMOOTH); + } + + // native method for setting default PointAttributes + void resetPointAttributes(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.resetPointAttributes()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glPointSize(1.0f); + + // XXXX: Polygon Mode check, blend enable + gl.glDisable(GL2.GL_POINT_SMOOTH); + } + + // native method for setting default TransparencyAttributes + void resetTransparency(Context ctx, int geometryType, + int polygonMode, boolean lineAA, + boolean pointAA) { + if (VERBOSE) System.err.println("JoglPipeline.resetTransparency()"); + + GL gl = context(ctx).getGL(); + + if (((((geometryType & RenderMolecule.LINE) != 0) || + (polygonMode == PolygonAttributes.POLYGON_LINE)) + && lineAA) || + ((((geometryType & RenderMolecule.POINT) != 0) || + (polygonMode == PolygonAttributes.POLYGON_POINT)) + && pointAA)) { + gl.glEnable(GL.GL_BLEND); + gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); + } else { + gl.glDisable(GL.GL_BLEND); + } + gl.glDisable(GL2.GL_POLYGON_STIPPLE); + } + + // native method for setting default ColoringAttributes + void resetColoringAttributes(Context ctx, + float r, float g, + float b, float a, + boolean enableLight) { + if (VERBOSE) System.err.println("JoglPipeline.resetColoringAttributes()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + if (!enableLight) { + gl.glColor4f(r, g, b, a); + } + gl.glShadeModel(GL2.GL_SMOOTH); + } + + /** + * This native method makes sure that the rendering for this canvas + * gets done now. + */ + void syncRender(Context ctx, boolean wait) { + if (VERBOSE) System.err.println("JoglPipeline.syncRender()"); + + GL gl = context(ctx).getGL(); + + if (wait) + gl.glFinish(); + else + gl.glFlush(); + } + + // The native method that sets this ctx to be the current one + boolean useCtx(Context ctx, long display, Drawable drawable) { + if (VERBOSE) System.err.println("JoglPipeline.useCtx()"); + GLContext context = context(ctx); + int res = context.makeCurrent(); + return (res != GLContext.CONTEXT_NOT_CURRENT); + } + + // Optionally release the context. Returns true if the context was released. + boolean releaseCtx(Context ctx, long dpy) { + if (VERBOSE) System.err.println("JoglPipeline.releaseCtx()"); + GLContext context = context(ctx); + context.release(); + return true; + } + + void clear(Context ctx, float r, float g, float b, boolean clearStencil) { + if (VERBOSE) System.err.println("JoglPipeline.clear()"); + + JoglContext jctx = (JoglContext) ctx; + GLContext context = context(ctx); + GL2 gl = context.getGL().getGL2(); + + // OBSOLETE CLEAR CODE + /* + gl.glClearColor(r, g, b, jctx.getAlphaClearValue()); + gl.glClear(GL.GL_COLOR_BUFFER_BIT); + + // Java 3D always clears the Z-buffer + gl.glPushAttrib(GL.GL_DEPTH_BUFFER_BIT); + gl.glDepthMask(true); + gl.glClear(GL.GL_DEPTH_BUFFER_BIT); + gl.glPopAttrib(); + + // Issue 239 - clear stencil if specified + if (clearStencil) { + gl.glPushAttrib(GL.GL_STENCIL_BUFFER_BIT); + gl.glClearStencil(0); + gl.glStencilMask(~0); + gl.glClear(GL.GL_STENCIL_BUFFER_BIT); + gl.glPopAttrib(); + } + */ + + // Mask of which buffers to clear, this always includes color & depth + int clearMask = GL.GL_DEPTH_BUFFER_BIT | GL.GL_COLOR_BUFFER_BIT; + + // Issue 239 - clear stencil if specified + if (clearStencil) { + gl.glPushAttrib(GL.GL_DEPTH_BUFFER_BIT | GL.GL_STENCIL_BUFFER_BIT); + + gl.glClearStencil(0); + gl.glStencilMask(~0); + clearMask |= GL.GL_STENCIL_BUFFER_BIT; + } else { + gl.glPushAttrib(GL.GL_DEPTH_BUFFER_BIT); + } + + gl.glDepthMask(true); + gl.glClearColor(r, g, b, jctx.getAlphaClearValue()); + gl.glClear(clearMask); + gl.glPopAttrib(); + + } + + void textureFillBackground(Context ctx, float texMinU, float texMaxU, float texMinV, float texMaxV, + float mapMinX, float mapMaxX, float mapMinY, float mapMaxY, boolean useBilinearFilter) { + if (VERBOSE) System.err.println("JoglPipeline.textureFillBackground()"); + + GLContext context = context(ctx); + GL2 gl = context.getGL().getGL2(); + + // Temporarily disable fragment and most 3D operations + gl.glPushAttrib(GL2.GL_ENABLE_BIT | GL2.GL_TEXTURE_BIT | GL2.GL_POLYGON_BIT); + + disableAttribFor2D(gl); + gl.glDepthMask(false); + gl.glEnable(GL.GL_TEXTURE_2D); + + /* Setup filter mode if needed */ + if(useBilinearFilter) { + // System.err.println("JoglPipeline - Background : use bilinear filter\n"); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); + } + + // reset the polygon mode + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_FILL); + + gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); + + // load identity modelview and projection matrix + gl.glMatrixMode(GL2.GL_PROJECTION); + gl.glLoadIdentity(); + gl.glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); + gl.glMatrixMode(GL2.GL_MODELVIEW); + gl.glLoadIdentity(); + gl.glMatrixMode(GL.GL_TEXTURE); + gl.glPushMatrix(); + gl.glLoadIdentity(); + + gl.glBegin(GL2.GL_QUADS); + gl.glTexCoord2f(texMinU, texMinV); gl.glVertex2f(mapMinX,mapMinY); + gl.glTexCoord2f(texMaxU, texMinV); gl.glVertex2f(mapMaxX,mapMinY); + gl.glTexCoord2f(texMaxU, texMaxV); gl.glVertex2f(mapMaxX,mapMaxY); + gl.glTexCoord2f(texMinU, texMaxV); gl.glVertex2f(mapMinX,mapMaxY); + gl.glEnd(); + + // Restore texture Matrix transform + gl.glPopMatrix(); + + gl.glMatrixMode(GL2.GL_MODELVIEW); + // Restore attributes + gl.glPopAttrib(); + + } + + void textureFillRaster(Context ctx, float texMinU, float texMaxU, float texMinV, float texMaxV, + float mapMinX, float mapMaxX, float mapMinY, float mapMaxY, float mapZ, float alpha, + boolean useBilinearFilter) { + + if (VERBOSE) System.err.println("JoglPipeline.textureFillRaster()"); + + GLContext context = context(ctx); + GL2 gl = context.getGL().getGL2(); + + // Temporarily disable fragment and most 3D operations + gl.glPushAttrib(GL2.GL_ENABLE_BIT | GL2.GL_TEXTURE_BIT | GL2.GL_POLYGON_BIT | + GL2.GL_CURRENT_BIT ); + + disableAttribForRaster(gl); + + /* Setup filter mode if needed */ + if(useBilinearFilter) { + // System.err.println("JoglPipeline - Raster : use bilinear filter\n"); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); + } + + gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_MODULATE); + gl.glColor4f(1.0f, 1.0f, 1.0f, alpha); + + // reset the polygon mode + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_FILL); + + gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); + + // load identity modelview and projection matrix + gl.glMatrixMode(GL2.GL_MODELVIEW); + gl.glPushMatrix(); + gl.glLoadIdentity(); + gl.glMatrixMode(GL2.GL_PROJECTION); + gl.glPushMatrix(); + gl.glLoadIdentity(); + gl.glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0); + + gl.glBegin(GL2.GL_QUADS); + gl.glTexCoord2f(texMinU, texMinV); gl.glVertex3f(mapMinX,mapMinY, mapZ); + gl.glTexCoord2f(texMaxU, texMinV); gl.glVertex3f(mapMaxX,mapMinY, mapZ); + gl.glTexCoord2f(texMaxU, texMaxV); gl.glVertex3f(mapMaxX,mapMaxY, mapZ); + gl.glTexCoord2f(texMinU, texMaxV); gl.glVertex3f(mapMinX,mapMaxY, mapZ); + gl.glEnd(); + + // Restore matrices + gl.glPopMatrix(); + gl.glMatrixMode(GL2.GL_MODELVIEW); + gl.glPopMatrix(); + // Restore attributes + gl.glPopAttrib(); + + } + + void executeRasterDepth(Context ctx, float posX, float posY, float posZ, + int srcOffsetX, int srcOffsetY, int rasterWidth, int rasterHeight, + int depthWidth, int depthHeight, int depthFormat, Object depthData) { + if (VERBOSE) System.err.println("JoglPipeline.executeRasterDepth()"); + GLContext context = context(ctx); + GL2 gl = context.getGL().getGL2(); + + + gl.glRasterPos3f(posX, posY, posZ); + + int[] drawBuf = new int[1]; + gl.glGetIntegerv(GL2.GL_DRAW_BUFFER, drawBuf, 0); + /* disable draw buffer */ + gl.glDrawBuffer(GL.GL_NONE); + + /* + * raster position is upper left corner, default for Java3D + * ImageComponent currently has the data reverse in Y + */ + gl.glPixelZoom(1.0f, -1.0f); + gl.glPixelStorei(GL2.GL_UNPACK_ROW_LENGTH, depthWidth); + if (srcOffsetX >= 0) { + gl.glPixelStorei(GL2.GL_UNPACK_SKIP_PIXELS, srcOffsetX); + if (srcOffsetX + rasterWidth > depthWidth) { + rasterWidth = depthWidth - srcOffsetX; + } + } else { + rasterWidth += srcOffsetX; + if (rasterWidth > depthWidth) { + rasterWidth = depthWidth; + } + } + if (srcOffsetY >= 0) { + gl.glPixelStorei(GL2.GL_UNPACK_SKIP_ROWS, srcOffsetY); + if (srcOffsetY + rasterHeight > depthHeight) { + rasterHeight = depthHeight - srcOffsetY; + } + } else { + rasterHeight += srcOffsetY; + if (rasterHeight > depthHeight) { + rasterHeight = depthHeight; + } + } + + + if (depthFormat == DepthComponentRetained.DEPTH_COMPONENT_TYPE_INT) { + gl.glDrawPixels(rasterWidth, rasterHeight, GL2.GL_DEPTH_COMPONENT, + GL.GL_UNSIGNED_INT, IntBuffer.wrap((int[]) depthData)); + } else { /* DepthComponentRetained.DEPTH_COMPONENT_TYPE_FLOAT */ + gl.glDrawPixels(rasterWidth, rasterHeight, GL2.GL_DEPTH_COMPONENT, + GL.GL_FLOAT, FloatBuffer.wrap((float[]) depthData)); + } + + /* re-enable draw buffer */ + gl.glDrawBuffer(drawBuf[0]); + + gl.glPixelStorei(GL2.GL_UNPACK_ROW_LENGTH, 0); + gl.glPixelStorei(GL2.GL_UNPACK_SKIP_PIXELS, 0); + gl.glPixelStorei(GL2.GL_UNPACK_SKIP_ROWS, 0); + + } + + // The native method for setting the ModelView matrix. + void setModelViewMatrix(Context ctx, double[] viewMatrix, double[] modelMatrix) { + if (VERBOSE) System.err.println("JoglPipeline.setModelViewMatrix()"); + GLContext context = context(ctx); + GL2 gl = context.getGL().getGL2(); + + gl.glMatrixMode(GL2.GL_MODELVIEW); + + if (gl.isExtensionAvailable("GL_VERSION_1_3")) { + gl.glLoadTransposeMatrixd(viewMatrix, 0); + gl.glMultTransposeMatrixd(modelMatrix, 0); + } else { + double[] v = new double[16]; + double[] m = new double[16]; + copyTranspose(viewMatrix, v); + copyTranspose(modelMatrix, m); + gl.glLoadMatrixd(v, 0); + gl.glMultMatrixd(m, 0); + } + } + + // The native method for setting the Projection matrix. + void setProjectionMatrix(Context ctx, double[] projMatrix) { + if (VERBOSE) System.err.println("JoglPipeline.setProjectionMatrix()"); + GLContext context = context(ctx); + GL2 gl = context.getGL().getGL2(); + + gl.glMatrixMode(GL2.GL_PROJECTION); + + if (gl.isExtensionAvailable("GL_VERSION_1_3")) { + // Invert the Z value in clipping coordinates because OpenGL uses + // left-handed clipping coordinates, while Java3D defines right-handed + // coordinates everywhere. + projMatrix[8] *= -1.0; + projMatrix[9] *= -1.0; + projMatrix[10] *= -1.0; + projMatrix[11] *= -1.0; + gl.glLoadTransposeMatrixd(projMatrix, 0); + projMatrix[8] *= -1.0; + projMatrix[9] *= -1.0; + projMatrix[10] *= -1.0; + projMatrix[11] *= -1.0; + } else { + double[] p = new double[16]; + copyTranspose(projMatrix, p); + // Invert the Z value in clipping coordinates because OpenGL uses + // left-handed clipping coordinates, while Java3D defines right-handed + // coordinates everywhere. + p[2] *= -1.0; + p[6] *= -1.0; + p[10] *= -1.0; + p[14] *= -1.0; + gl.glLoadMatrixd(p, 0); + } + } + + // The native method for setting the Viewport. + void setViewport(Context ctx, int x, int y, int width, int height) { + if (VERBOSE) System.err.println("JoglPipeline.setViewport()"); + GL gl = context(ctx).getGL(); + gl.glViewport(x, y, width, height); + } + + // used for display Lists + void newDisplayList(Context ctx, int displayListId) { + if (VERBOSE) System.err.println("JoglPipeline.newDisplayList()"); + if (displayListId <= 0) { + System.err.println("JAVA 3D ERROR : glNewList(" + displayListId + ") -- IGNORED"); + } + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glNewList(displayListId, GL2.GL_COMPILE); + } + + void endDisplayList(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.endDisplayList()"); + GL2 gl = context(ctx).getGL().getGL2(); + gl.glEndList(); + } + + int numInvalidLists = 0; + void callDisplayList(Context ctx, int id, boolean isNonUniformScale) { + if (VERBOSE) System.err.println("JoglPipeline.callDisplayList()"); + if (id <= 0) { + if (numInvalidLists < 3) { + ++numInvalidLists; + System.err.println("JAVA 3D ERROR : glCallList(" + id + ") -- IGNORED"); + } else if (numInvalidLists == 3) { + ++numInvalidLists; + System.err.println("JAVA 3D : further glCallList error messages discarded"); + } + return; + } + + GL2 gl = context(ctx).getGL().getGL2(); + // Set normalization if non-uniform scale + if (isNonUniformScale) { + gl.glEnable(GL2.GL_NORMALIZE); + } + + gl.glCallList(id); + + // Turn normalization back off + if (isNonUniformScale) { + gl.glDisable(GL2.GL_NORMALIZE); + } + } + + void freeDisplayList(Context ctx, int id) { + if (VERBOSE) System.err.println("JoglPipeline.freeDisplayList()"); + if (id <= 0) { + System.err.println("JAVA 3D ERROR : glDeleteLists(" + id + ",1) -- IGNORED"); + } + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glDeleteLists(id, 1); + } + void freeTexture(Context ctx, int id) { + if (VERBOSE) System.err.println("JoglPipeline.freeTexture()"); + + GL gl = context(ctx).getGL(); + + if (id > 0) { + int[] tmp = new int[1]; + tmp[0] = id; + gl.glDeleteTextures(1, tmp, 0); + } else { + System.err.println("tried to delete tex with texid <= 0"); + } + } + + + void texturemapping(Context ctx, + int px, int py, + int minX, int minY, int maxX, int maxY, + int texWidth, int texHeight, + int rasWidth, + int format, int objectId, + byte[] imageYdown, + int winWidth, int winHeight) { + if (VERBOSE) System.err.println("JoglPipeline.texturemapping()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + int glType = GL.GL_RGBA; + + // Temporarily disable fragment and most 3D operations + gl.glPushAttrib(GL2.GL_ENABLE_BIT | GL2.GL_TEXTURE_BIT | GL.GL_DEPTH_BUFFER_BIT | GL2.GL_POLYGON_BIT); + disableAttribFor2D(gl); + + // Reset the polygon mode + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_FILL); + + gl.glDepthMask(false); + gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); + gl.glBindTexture(GL.GL_TEXTURE_2D, objectId); + // set up texture parameter + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT); + + gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE); + gl.glEnable(GL.GL_BLEND); + gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); + + gl.glEnable(GL.GL_TEXTURE_2D); + + // loaded identity modelview and projection matrix + gl.glMatrixMode(GL2.GL_PROJECTION); + gl.glLoadIdentity(); + + gl.glOrtho(0.0, winWidth, 0.0, winHeight, 0.0, 0.0); + + gl.glMatrixMode(GL2.GL_MODELVIEW); + gl.glLoadIdentity(); + + if (gl.isExtensionAvailable("GL_EXT_abgr")) { + glType = GL2.GL_ABGR_EXT; + } else { + switch (format) { + case ImageComponentRetained.TYPE_BYTE_RGBA: + glType = GL.GL_RGBA; + break; + case ImageComponentRetained.TYPE_BYTE_RGB: + glType = GL.GL_RGB; + break; + } + } + gl.glPixelStorei(GL2.GL_UNPACK_ROW_LENGTH, rasWidth); + gl.glPixelStorei(GL2.GL_UNPACK_SKIP_PIXELS, minX); + gl.glPixelStorei(GL2.GL_UNPACK_SKIP_ROWS, minY); + gl.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, minX, minY, + maxX - minX, maxY - minY, + glType, GL.GL_UNSIGNED_BYTE, + ByteBuffer.wrap(imageYdown)); + gl.glPixelStorei(GL2.GL_UNPACK_ROW_LENGTH, 0); + gl.glPixelStorei(GL2.GL_UNPACK_SKIP_PIXELS, 0); + gl.glPixelStorei(GL2.GL_UNPACK_SKIP_ROWS, 0); + + float texMinU = (float) minX/ (float) texWidth; + float texMinV = (float) minY/ (float) texHeight; + float texMaxU = (float) maxX/ (float) texWidth; + float texMaxV = (float) maxY/ (float) texHeight; + float halfWidth = (float)winWidth/2.0f; + float halfHeight = (float)winHeight/2.0f; + + float mapMinX = (float) (((px + minX)- halfWidth)/halfWidth); + float mapMinY = (float) ((halfHeight - (py + maxY))/halfHeight); + float mapMaxX = (float) ((px + maxX - halfWidth)/halfWidth); + float mapMaxY = (float) ((halfHeight - (py + minY))/halfHeight); + + gl.glBegin(GL2.GL_QUADS); + + gl.glTexCoord2f(texMinU, texMaxV); gl.glVertex2f(mapMinX,mapMinY); + gl.glTexCoord2f(texMaxU, texMaxV); gl.glVertex2f(mapMaxX,mapMinY); + gl.glTexCoord2f(texMaxU, texMinV); gl.glVertex2f(mapMaxX,mapMaxY); + gl.glTexCoord2f(texMinU, texMinV); gl.glVertex2f(mapMinX,mapMaxY); + gl.glEnd(); + + // Java 3D always clears the Z-buffer + gl.glDepthMask(true); + gl.glClear(GL.GL_DEPTH_BUFFER_BIT); + gl.glPopAttrib(); + } + + boolean initTexturemapping(Context ctx, int texWidth, + int texHeight, int objectId) { + if (VERBOSE) System.err.println("JoglPipeline.initTexturemapping()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + int glType = (gl.isExtensionAvailable("GL_EXT_abgr") ? GL2.GL_ABGR_EXT : GL.GL_RGBA); + + gl.glBindTexture(GL.GL_TEXTURE_2D, objectId); + + gl.glTexImage2D(GL2.GL_PROXY_TEXTURE_2D, 0, GL.GL_RGBA, texWidth, + texHeight, 0, glType, GL.GL_UNSIGNED_BYTE, null); + + int[] width = new int[1]; + gl.glGetTexLevelParameteriv(GL2.GL_PROXY_TEXTURE_2D, 0, + GL2.GL_TEXTURE_WIDTH, width, 0); + + if (width[0] <= 0) { + return false; + } + + // init texture size only without filling the pixels + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, texWidth, + texHeight, 0, glType, GL.GL_UNSIGNED_BYTE, null); + + return true; + } + + + // Set internal render mode to one of FIELD_ALL, FIELD_LEFT or + // FIELD_RIGHT. Note that it is up to the caller to ensure that + // stereo is available before setting the mode to FIELD_LEFT or + // FIELD_RIGHT. The boolean isTRUE for double buffered mode, FALSE + // foe single buffering. + void setRenderMode(Context ctx, int mode, boolean doubleBuffer) { + if (VERBOSE) System.err.println("JoglPipeline.setRenderMode()"); + + GL2 gl = context(ctx).getGL().getGL2(); + int drawBuf = 0; + if (doubleBuffer) { + drawBuf = GL.GL_BACK; + switch (mode) { + case Canvas3D.FIELD_LEFT: + drawBuf = GL2.GL_BACK_LEFT; + break; + case Canvas3D.FIELD_RIGHT: + drawBuf = GL2.GL_BACK_RIGHT; + break; + case Canvas3D.FIELD_ALL: + drawBuf = GL.GL_BACK; + break; + } + } else { + drawBuf = GL.GL_FRONT; + switch (mode) { + case Canvas3D.FIELD_LEFT: + drawBuf = GL2.GL_FRONT_LEFT; + break; + case Canvas3D.FIELD_RIGHT: + drawBuf = GL2.GL_FRONT_RIGHT; + break; + case Canvas3D.FIELD_ALL: + drawBuf = GL.GL_FRONT; + break; + } + } + + gl.glDrawBuffer(drawBuf); + } + + // Set glDepthMask. + void setDepthBufferWriteEnable(Context ctx, boolean mode) { + if (VERBOSE) System.err.println("JoglPipeline.setDepthBufferWriteEnable()"); + + GL gl = context(ctx).getGL(); + if (mode) { + gl.glDepthMask(true); + } else { + gl.glDepthMask(false); + } + } + + //---------------------------------------------------------------------- + // Helper private functions for Canvas3D + // + + private boolean getPropertiesFromCurrentContext(JoglContext ctx) { + GL gl = GLU.getCurrentGL(); + // FIXME: this is a heavily abridged set of the stuff in Canvas3D.c; + // probably need to pull much more in + int[] tmp = new int[1]; + gl.glGetIntegerv(GL2.GL_MAX_TEXTURE_UNITS, tmp, 0); + ctx.setMaxTexCoordSets(tmp[0]); + if (VirtualUniverse.mc.transparentOffScreen) { + ctx.setAlphaClearValue(0.0f); + } else { + ctx.setAlphaClearValue(1.0f); + } + if (gl.isExtensionAvailable("GL_ARB_vertex_shader")) { + gl.glGetIntegerv(GL2.GL_MAX_TEXTURE_COORDS_ARB, tmp, 0); + ctx.setMaxTexCoordSets(tmp[0]); + } + return true; + } + + private int[] extractVersionInfo(String versionString) { + StringTokenizer tok = new StringTokenizer(versionString, ". "); + int major = Integer.valueOf(tok.nextToken()).intValue(); + int minor = Integer.valueOf(tok.nextToken()).intValue(); + + // See if there's vendor-specific information which might + // imply a more recent OpenGL version + tok = new StringTokenizer(versionString, " "); + if (tok.hasMoreTokens()) { + tok.nextToken(); + if (tok.hasMoreTokens()) { + Pattern p = Pattern.compile("\\D*(\\d+)\\.(\\d+)\\.?(\\d*).*"); + Matcher m = p.matcher(tok.nextToken()); + if (m.matches()) { + int altMajor = Integer.valueOf(m.group(1)).intValue(); + int altMinor = Integer.valueOf(m.group(2)).intValue(); + // Avoid possibly confusing situations by requiring + // major version to match + if (altMajor == major && + altMinor > minor) { + minor = altMinor; + } + } + } + } + return new int[] { major, minor }; + } + +// FIXME: GL_SGI_texture_color_table +// private int getTextureColorTableSize(GL gl) { +// if (!gl.isExtensionAvailable("GL_ARB_imaging")) { +// return 0; +// } +// +// gl.glColorTable(GL.GL_PROXY_TEXTURE_COLOR_TABLE_SGI, GL.GL_RGBA, 256, GL.GL_RGB, +// GL2.GL_INT, null); +// int[] tmp = new int[1]; +// gl.glGetColorTableParameteriv(GL.GL_PROXY_TEXTURE_COLOR_TABLE_SGI, +// GL2.GL_COLOR_TABLE_WIDTH, tmp, 0); +// return tmp[0]; +// } + + + private void checkTextureExtensions(Canvas3D cv, + JoglContext ctx, + GL gl, + boolean gl13) { + if (gl13) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_MULTI_TEXTURE; + cv.multiTexAccelerated = true; + int[] tmp = new int[1]; + gl.glGetIntegerv(GL2.GL_MAX_TEXTURE_UNITS, tmp, 0); + cv.maxTextureUnits = tmp[0]; + cv.maxTexCoordSets = cv.maxTextureUnits; + if (gl.isExtensionAvailable("GL_ARB_vertex_shader")) { + gl.glGetIntegerv(GL2.GL_MAX_TEXTURE_COORDS_ARB, tmp, 0); + cv.maxTexCoordSets = tmp[0]; + } + } +// FIXME: GL_SGI_texture_color_table +// if (gl.isExtensionAvailable("GL_SGI_texture_color_table") || +// gl.isExtensionAvailable("GL_ARB_imaging")) { +// cv.textureExtendedFeatures |= Canvas3D.TEXTURE_COLOR_TABLE; +// +// // get texture color table size +// // need to check later +// cv.textureColorTableSize = getTextureColorTableSize(gl); +// if (cv.textureColorTableSize <= 0) { +// cv.textureExtendedFeatures &= ~Canvas3D.TEXTURE_COLOR_TABLE; +// } +// if (cv.textureColorTableSize > 256) { +// cv.textureColorTableSize = 256; +// } +// } + + if (gl.isExtensionAvailable("GL_ARB_texture_env_combine")) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_COMBINE; + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_COMBINE_SUBTRACT; + } else if (gl.isExtensionAvailable("GL_EXT_texture_env_combine")) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_COMBINE; + } + +// FIXME: GL_NV_register_combiners +// if (gl.isExtensionAvailable("GL_NV_register_combiners")) { +// cv.textureExtendedFeatures |= Canvas3D.TEXTURE_REGISTER_COMBINERS; +// } + + if (gl.isExtensionAvailable("GL_ARB_texture_env_dot3") || + gl.isExtensionAvailable("GL_EXT_texture_env_dot3")) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_COMBINE_DOT3; + } + + if (gl13) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_CUBE_MAP; + } + +// FIXME: GL_SGIS_sharpen_texture +// if (gl.isExtensionAvailable("GL_SGIS_sharpen_texture")) { +// cv.textureExtendedFeatures |= Canvas3D.TEXTURE_SHARPEN; +// } + +// FIXME: GL_SGIS_sharpen_texture +// if (gl.isExtensionAvailable("GL_SGIS_detail_texture")) { +// cv.textureExtendedFeatures |= Canvas3D.TEXTURE_DETAIL; +// } + +// FIXME: GL_SGIS_texture_filter4 +// if (gl.isExtensionAvailable("GL_SGIS_texture_filter4")) { +// cv.textureExtendedFeatures |= Canvas3D.TEXTURE_FILTER4; +// } + + if (gl.isExtensionAvailable("GL_EXT_texture_filter_anisotropic")) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_ANISOTROPIC_FILTER; + float[] tmp = new float[1]; + gl.glGetFloatv(GL. GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, tmp, 0); + cv.anisotropicDegreeMax = tmp[0]; + } + +// FIXME: GL_SGIX_texture_lod_bias +// if (gl.isExtensionAvailable("GL_SGIX_texture_lod_bias")) { +// cv.textureExtendedFeatures |= Canvas3D.TEXTURE_LOD_OFFSET; +// } + + if (!VirtualUniverse.mc.enforcePowerOfTwo && + gl.isExtensionAvailable("GL_ARB_texture_non_power_of_two")) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_NON_POWER_OF_TWO; + } + + if (gl.isExtensionAvailable("GL_SGIS_generate_mipmap")) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_AUTO_MIPMAP_GENERATION; + } + + } + + + private void checkGLSLShaderExtensions(Canvas3D cv, + JoglContext ctx, + GL gl, + boolean glslLibraryAvailable) { + if (glslLibraryAvailable && + gl.isExtensionAvailable("GL_ARB_shader_objects") && + gl.isExtensionAvailable("GL_ARB_shading_language_100")) { + // Initialize shader vertex attribute function pointers + ctx.initGLSLVertexAttributeImpl(); + + // FIXME: this isn't complete and would need to set up the + // JoglContext for dispatch of various routines such as those + // related to vertex attributes + int[] tmp = new int[1]; + gl.glGetIntegerv(GL2.GL_MAX_TEXTURE_IMAGE_UNITS_ARB, tmp, 0); + cv.maxTextureImageUnits = tmp[0]; + gl.glGetIntegerv(GL2.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, tmp, 0); + cv.maxVertexTextureImageUnits = tmp[0]; + gl.glGetIntegerv(GL2.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, tmp, 0); + cv.maxCombinedTextureImageUnits = tmp[0]; + int vertexAttrOffset = VirtualUniverse.mc.glslVertexAttrOffset; + ctx.setGLSLVertexAttrOffset(vertexAttrOffset); + gl.glGetIntegerv(GL2.GL_MAX_VERTEX_ATTRIBS_ARB, tmp, 0); + cv.maxVertexAttrs = tmp[0]; + // decr count to allow for reserved vertex attrs + cv.maxVertexAttrs -= vertexAttrOffset; + if (cv.maxVertexAttrs < 0) { + cv.maxVertexAttrs = 0; + } + cv.shadingLanguageGLSL = true; + } + } + + private void setupCanvasProperties(Canvas3D cv, + JoglContext ctx, + GL gl, + boolean glslLibraryAvailable) { + // Note: this includes relevant portions from both the + // NativePipeline's getPropertiesFromCurrentContext and setupCanvasProperties + + // Reset all fields + cv.multiTexAccelerated = false; + cv.maxTextureUnits = 1; + cv.maxTexCoordSets = 1; + cv.maxTextureImageUnits = 0; + cv.maxVertexTextureImageUnits = 0; + cv.maxCombinedTextureImageUnits = 0; + cv.maxVertexAttrs = 0; + cv.extensionsSupported = 0; + cv.textureExtendedFeatures = 0; + cv.textureColorTableSize = 0; + cv.anisotropicDegreeMax = 0; + cv.textureBoundaryWidthMax = 0; + cv.textureWidthMax = 0; + cv.textureHeightMax = 0; + cv.texture3DWidthMax = 0; + cv.texture3DHeightMax = 0; + cv.texture3DDepthMax = 0; + cv.shadingLanguageGLSL = false; + + // Now make queries and set up these fields + String glVersion = gl.glGetString(GL.GL_VERSION); + String glVendor = gl.glGetString(GL.GL_VENDOR); + String glRenderer = gl.glGetString(GL.GL_RENDERER); + cv.nativeGraphicsVersion = glVersion; + cv.nativeGraphicsVendor = glVendor; + cv.nativeGraphicsRenderer = glRenderer; + + // find out the version, major and minor version number + int[] versionNumbers = extractVersionInfo(glVersion); + int major = versionNumbers[0]; + int minor = versionNumbers[1]; + + /////////////////////////////////////////// + // setup the graphics context properties // + + // NOTE: Java 3D now requires OpenGL 1.3 for full functionality. + // For backwards compatibility with certain older graphics cards and + // drivers (e.g., the Linux DRI driver for older ATI cards), + // we will try to run on OpenGL 1.2 in an unsupported manner. However, + // we will not attempt to use OpenGL extensions for any features that + // are available in OpenGL 1.3, specifically multitexture, multisample, + // and cube map textures. + + if (major < 1 || (major == 1 && minor < 2)) { + throw new IllegalRenderingStateException( + "Java 3D ERROR : OpenGL 1.2 or better is required (GL_VERSION=" + + major + "." + minor + ")"); + } + + boolean gl20 = false; + boolean gl14 = false; + boolean gl13 = false; + + if (major == 1) { + if (minor == 2) { + System.err.println("JAVA 3D: OpenGL 1.2 detected; will run with reduced functionality"); + } + if (minor >= 3) { + gl13 = true; + } + if (minor >= 4) { + gl14 = true; + } + } else /* major >= 2 */ { + gl13 = true; + gl14 = true; + gl20 = true; + } + + if (gl20) { + assert gl13; + assert gl14; + assert gl.isExtensionAvailable("GL_VERSION_2_0"); + } + + if (gl14) { + assert gl13; + assert gl.isExtensionAvailable("GL_VERSION_1_4"); + } + + if (gl13) { + assert gl.isExtensionAvailable("GL_VERSION_1_3"); + } + + // Set up properties for OpenGL 1.3 + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_3D; + + // Note that we don't query for GL_ARB_imaging here + + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_LOD_RANGE; + + if (gl14) { + cv.textureExtendedFeatures |= Canvas3D.TEXTURE_AUTO_MIPMAP_GENERATION; + } + + // look for OpenGL 2.0 features + // Fix to Issue 455 : Need to disable NPOT textures for older cards that claim to support it. + // Some older cards (e.g., Nvidia fx500 and ATI 9800) claim to support OpenGL 2.0. + // This means that these cards have to support non-power-of-two (NPOT) texture, + // but their lack the necessary HW force the vendors the emulate this feature in software. + // The result is a ~100x slower down compare to power-of-two textures. + // Do not check for gl20 but instead check of GL_ARB_texture_non_power_of_two extension string + // if (gl20) { + // if(!VirtualUniverse.mc.enforcePowerOfTwo) { + // cv.textureExtendedFeatures |= Canvas3D.TEXTURE_NON_POWER_OF_TWO; + // } + // } + + + // Setup GL_EXT_abgr + if (gl.isExtensionAvailable("GL_EXT_abgr")) { + cv.extensionsSupported |= Canvas3D.EXT_ABGR; + } + + // GL_BGR is always supported + cv.extensionsSupported |= Canvas3D.EXT_BGR; + + // Setup multisample + // FIXME: this is not correct for the Windows platform yet + if (gl13) { + cv.extensionsSupported |= Canvas3D.MULTISAMPLE; + ctx.setHasMultisample(true); + } + + if ((cv.extensionsSupported & Canvas3D.MULTISAMPLE) != 0 && + !VirtualUniverse.mc.implicitAntialiasing) { + gl.glDisable(GL.GL_MULTISAMPLE); + } + + // Check texture extensions + checkTextureExtensions(cv, ctx, gl, gl13); + + // Check shader extensions + if (gl13) { + checkGLSLShaderExtensions(cv, ctx, gl, glslLibraryAvailable); + } else { + // Force shaders to be disabled, since no multitexture support + checkGLSLShaderExtensions(cv, ctx, gl, false); + } + + // Setup GL_SUN_gloabl_alpha +// FIXME: SUN_global_alpha +// if (gl.isExtensionAvailable("GL_SUN_gloabl_alpha")) { +// cv.extensionsSupported |= Canvas3D.SUN_GLOBAL_ALPHA; +// } + + cv.textureBoundaryWidthMax = 1; + { + int[] tmp = new int[1]; + gl.glGetIntegerv(GL.GL_MAX_TEXTURE_SIZE, tmp, 0); + cv.textureWidthMax = tmp[0]; + cv.textureHeightMax = tmp[0]; + + tmp[0] = -1; + gl.glGetIntegerv(GL2.GL_MAX_3D_TEXTURE_SIZE, tmp, 0); + cv.texture3DWidthMax = tmp[0]; + cv.texture3DHeightMax = tmp[0]; + cv.texture3DDepthMax = tmp[0]; + } + } + + /* + * Function to disable most rendering attributes when doing a 2D + * clear, image copy, or image composite operation. Note that the + * caller must save/restore the attributes with + * pushAttrib(GL_ENABLE_BIT|...) and popAttrib() + */ + private void disableAttribFor2D(GL gl) { + gl.glDisable(GL2.GL_ALPHA_TEST); + gl.glDisable(GL.GL_BLEND); + gl.glDisable(GL.GL_COLOR_LOGIC_OP); + gl.glDisable(GL2.GL_COLOR_MATERIAL); + gl.glDisable(GL.GL_CULL_FACE); + gl.glDisable(GL.GL_DEPTH_TEST); + gl.glDisable(GL2.GL_FOG); + gl.glDisable(GL2.GL_LIGHTING); + gl.glDisable(GL.GL_POLYGON_OFFSET_FILL); + gl.glDisable(GL2.GL_POLYGON_STIPPLE); + gl.glDisable(GL.GL_STENCIL_TEST); + gl.glDisable(GL.GL_TEXTURE_2D); + gl.glDisable(GL2.GL_TEXTURE_GEN_Q); + gl.glDisable(GL2.GL_TEXTURE_GEN_R); + gl.glDisable(GL2.GL_TEXTURE_GEN_S); + gl.glDisable(GL2.GL_TEXTURE_GEN_T); + + + for (int i = 0; i < 6; i++) { + gl.glDisable(GL2.GL_CLIP_PLANE0 + i); + } + + gl.glDisable(GL2.GL_TEXTURE_3D); + gl.glDisable(GL.GL_TEXTURE_CUBE_MAP); + +// FIXME: GL_NV_register_combiners +// if (gl.isExtensionAvailable("GL_NV_register_combiners")) { +// gl.glDisable(GL.GL_REGISTER_COMBINERS_NV); +// } +// FIXME: GL_SGI_texture_color_table +// if (gl.isExtensionAvailable("GL_SGI_texture_color_table")) { +// gl.glDisable(GL.GL_TEXTURE_COLOR_TABLE_SGI); +// } +// FIXME: SUN_global_alpha +// if (gl.isExtensionAvailable("GL_SUN_global_alpha")) { +// gl.glDisable(GL.GL_GLOBAL_ALPHA_SUN); +// } + + } + + private void disableAttribForRaster(GL gl) { + + gl.glDisable(GL2.GL_COLOR_MATERIAL); + gl.glDisable(GL.GL_CULL_FACE); + gl.glDisable(GL2.GL_LIGHTING); + gl.glDisable(GL.GL_POLYGON_OFFSET_FILL); + gl.glDisable(GL2.GL_POLYGON_STIPPLE); + + // TODO: Disable if Raster.CLIP_POSITION is true +// for (int i = 0; i < 6; i++) { +// gl.glDisable(GL2.GL_CLIP_PLANE0 + i); +// } + +// FIXME: SUN_global_alpha +// if (gl.isExtensionAvailable("GL_SUN_global_alpha")) { +// gl.glDisable(GL.GL_GLOBAL_ALPHA_SUN); +// } + } + + private void copyTranspose(double[] src, double[] dst) { + dst[0] = src[0]; + dst[1] = src[4]; + dst[2] = src[8]; + dst[3] = src[12]; + dst[4] = src[1]; + dst[5] = src[5]; + dst[6] = src[9]; + dst[7] = src[13]; + dst[8] = src[2]; + dst[9] = src[6]; + dst[10] = src[10]; + dst[11] = src[14]; + dst[12] = src[3]; + dst[13] = src[7]; + dst[14] = src[11]; + dst[15] = src[15]; + } + + // --------------------------------------------------------------------- + + // + // Canvas3D / GraphicsConfigTemplate3D methods - logic dealing with + // native graphics configuration or drawing surface + // + + // Return a graphics config based on the one passed in. Note that we can + // assert that the input config is non-null and was created from a + // GraphicsConfigTemplate3D. + // This method must return a valid GraphicsConfig, or else it must throw + // an exception if one cannot be returned. + GraphicsConfiguration getGraphicsConfig(GraphicsConfiguration gconfig) { + if (VERBOSE) System.err.println("JoglPipeline.getGraphicsConfig()"); + JoglGraphicsConfiguration config = (JoglGraphicsConfiguration) gconfig; + GLCapabilitiesChooser indexChooser = null; + if (config.getChosenIndex() >= 0) { + indexChooser = new IndexCapabilitiesChooser(config.getChosenIndex()); + } + + AWTGraphicsDevice awtGraphicsDevice = ((JoglGraphicsConfiguration)gconfig).getAwtGraphicsDevice()/*new AWTGraphicsDevice(config.getDevice(), 0)*/; + GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(awtGraphicsDevice); + + AbstractGraphicsConfiguration absConfig = + factory.chooseGraphicsConfiguration(config.getGLCapabilities(), config.getGLCapabilities(), + indexChooser, new AWTGraphicsScreen(awtGraphicsDevice)); + if (absConfig == null) { + return null; + } + return ((AWTGraphicsConfiguration) absConfig).getAWTGraphicsConfiguration(); + + /* + + System.err.println("JoglPipeline.getGraphicsConfig()"); + // Just return the input graphics config for now. eventually, we will + // use the input graphics config to get the GraphicsConfigTemplate3D + // parameters, which we will use to create a new graphics config with JOGL. + return gconfig; + */ + } + + // Get the native FBconfig pointer + long getFbConfig(GraphicsConfigInfo gcInfo) { + if (VERBOSE) System.err.println("JoglPipeline.getFbConfig()"); + return 0L; // Dummy method in JOGL + } + + + private static final int DISABLE_STEREO = 1; + private static final int DISABLE_AA = 2; + private static final int DISABLE_DOUBLE_BUFFER = 3; + + // Get best graphics config from pipeline + GraphicsConfiguration getBestConfiguration(GraphicsConfigTemplate3D gct, + GraphicsConfiguration[] gc) { + if (VERBOSE) System.err.println("JoglPipeline.getBestConfiguration()"); + /* + System.err.println("gct.getDoubleBuffer(): " + gct.getDoubleBuffer()); + System.err.println("gct.getStereo(): " + gct.getStereo()); + System.err.println("gct.getDepthBits(): " + gct.getDepthSize()); + System.err.println("gct.getRedSize(): " + gct.getRedSize()); + System.err.println("gct.getGreenSize(): " + gct.getGreenSize()); + System.err.println("gct.getBlueSize(): " + gct.getBlueSize()); + System.err.println("gct.getSceneAntialiasing(): " + gct.getSceneAntialiasing()); + */ + + // Create a GLCapabilities based on the GraphicsConfigTemplate3D + GLCapabilities caps = new GLCapabilities(getDefaultProfile()); + caps.setDoubleBuffered(gct.getDoubleBuffer() <= GraphicsConfigTemplate.PREFERRED); + caps.setStereo (gct.getStereo() <= GraphicsConfigTemplate.PREFERRED); + caps.setDepthBits (gct.getDepthSize()); + caps.setStencilBits (gct.getStencilSize()); + caps.setRedBits (Math.max(5, gct.getRedSize())); + caps.setGreenBits (Math.max(5, gct.getGreenSize())); + caps.setBlueBits (Math.max(5, gct.getBlueSize())); + caps.setSampleBuffers(gct.getSceneAntialiasing() <= GraphicsConfigTemplate.PREFERRED); + // FIXME: should be smarter about choosing the number of samples + // (Java3D's native code has a loop trying 8, 6, 4, 3, and 2 samples) + caps.setNumSamples(4); + + // Issue 399: Request alpha buffer if transparentOffScreen is set + if (VirtualUniverse.mc.transparentOffScreen) { + caps.setAlphaBits(1); + } + + java.util.List capsToDisable = new ArrayList(); + // Add PREFERRED capabilities in order we will try disabling them + if (gct.getStereo() == GraphicsConfigTemplate.PREFERRED) { + capsToDisable.add(new Integer(DISABLE_STEREO)); + } + if (gct.getSceneAntialiasing() == GraphicsConfigTemplate.PREFERRED) { + capsToDisable.add(new Integer(DISABLE_AA)); + } + if (gct.getDoubleBuffer() == GraphicsConfigTemplate.PREFERRED) { + capsToDisable.add(new Integer(DISABLE_DOUBLE_BUFFER)); + } + + // Pick the GraphicsDevice from a random configuration + GraphicsDevice dev = gc[0].getDevice(); + + // Create a Frame and dummy GLCanvas to perform eager pixel format selection + + // Note that we loop in similar fashion to the NativePipeline's + // native code in the situation where we need to disable certain + // capabilities which aren't required + boolean tryAgain = true; + CapabilitiesCapturer capturer = null; + while (tryAgain) { + Frame f = new Frame(dev.getDefaultConfiguration()); + f.setUndecorated(true); + f.setLayout(new BorderLayout()); + capturer = new CapabilitiesCapturer(); + try { + AWTGraphicsConfiguration awtGraphicsConfiguration = createAwtGraphicsConfiguration(caps, capturer, dev/*null*/); + QueryCanvas canvas = new QueryCanvas(awtGraphicsConfiguration, capturer); + f.add(canvas, BorderLayout.CENTER); + f.setSize(MIN_FRAME_SIZE, MIN_FRAME_SIZE); + f.setVisible(true); + canvas.doQuery(); + if (DEBUG_CONFIG) { + System.err.println("Waiting for CapabilitiesCapturer"); + } + // Try to wait for result without blocking EDT + if (!EventQueue.isDispatchThread()) { + synchronized(capturer) { + if (!capturer.done()) { + try { + capturer.wait(WAIT_TIME); + } catch (InterruptedException e) { + } + } + } + } + disposeOnEDT(f); + tryAgain = false; + } catch (GLException e) { + // Failure to select a pixel format; try switching off one + // of the only-preferred capabilities + if (capsToDisable.size() == 0) { + tryAgain = false; + } else { + int whichToDisable = capsToDisable.remove(0).intValue(); + switch (whichToDisable) { + case DISABLE_STEREO: + caps.setStereo(false); + break; + + case DISABLE_AA: + caps.setSampleBuffers(false); + break; + + case DISABLE_DOUBLE_BUFFER: + caps.setDoubleBuffered(false); + break; + + default: + throw new AssertionError("missing case statement"); + } + } + } + } + int chosenIndex = capturer.getChosenIndex(); + GLCapabilities chosenCaps = null; + if (chosenIndex < 0) { + if (DEBUG_CONFIG) { + System.err.println("CapabilitiesCapturer returned invalid index"); + } + // It's possible some platforms or implementations might not + // support the GLCapabilitiesChooser mechanism; feed in the + // same GLCapabilities later which we gave to the selector + chosenCaps = caps; + } else { + if (DEBUG_CONFIG) { + System.err.println("CapabilitiesCapturer returned index=" + chosenIndex); + } + chosenCaps = capturer.getCapabilities(); + } + + JoglGraphicsConfiguration config = new JoglGraphicsConfiguration(chosenCaps, chosenIndex, dev); + + // FIXME: because of the fact that JoglGraphicsConfiguration + // doesn't override hashCode() or equals(), we will basically be + // creating a new one each time getBestConfiguration() is + // called; in theory, we should probably map the same + // GLCapabilities on the same GraphicsDevice to the same + // JoglGraphicsConfiguration object + + // Cache the GraphicsTemplate3D + synchronized (Canvas3D.graphicsConfigTable) { + GraphicsConfigInfo gcInfo = new GraphicsConfigInfo(gct); + // We don't need this + // gcInfo.setPrivateData(privateData); + Canvas3D.graphicsConfigTable.put(config, gcInfo); + } + + return config; + + /* + + // TODO: implement this + + // TODO: construct a unique GraphicsConfiguration object that will be + // used the key in the hashmap so we can lookup the GraphicsTemplate3D + GraphicsConfiguration gc1 = GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice().getDefaultConfiguration(); + + // Cache the GraphicsTemplate3D + synchronized (Canvas3D.graphicsConfigTable) { + if (Canvas3D.graphicsConfigTable.get(gc1) == null) { + GraphicsConfigInfo gcInfo = new GraphicsConfigInfo(gct); + // gcInfo.setPrivateData(privateData); + Canvas3D.graphicsConfigTable.put(gc1, gcInfo); + } + } + return gc1; + + */ + } + + // Determine whether specified graphics config is supported by pipeline + boolean isGraphicsConfigSupported(GraphicsConfigTemplate3D gct, + GraphicsConfiguration gc) { + if (VERBOSE) System.err.println("JoglPipeline.isGraphicsConfigSupported()"); + + // FIXME: it looks like this method is implemented incorrectly + // in the existing NativePipeline in both the Windows and X11 + // ports. According to the semantics of the javadoc, it looks + // like this method is supposed to figure out the OpenGL + // capabilities which would be requested by the passed + // GraphicsConfiguration object were it to be used, and see + // whether it is possible to create a context with them. + // Instead, on both platforms, the implementations basically set + // up a query based on the contents of the + // GraphicsConfigTemplate3D object, using the + // GraphicsConfiguration object only to figure out on which + // GraphicsDevice and screen we're making the request, and see + // whether it's possible to choose an OpenGL pixel format based + // on that information. This makes this method less useful and + // we can probably just safely return true here uniformly + // without breaking anything. + return true; + } + + // Methods to get actual capabilities from Canvas3D + boolean hasDoubleBuffer(Canvas3D cv) { + if (VERBOSE) System.err.println("JoglPipeline.hasDoubleBuffer()"); + if (VERBOSE) System.err.println(" Returning " + caps(cv).getDoubleBuffered()); + return caps(cv).getDoubleBuffered(); + } + + boolean hasStereo(Canvas3D cv) { + if (VERBOSE) System.err.println("JoglPipeline.hasStereo()"); + if (VERBOSE) System.err.println(" Returning " + caps(cv).getStereo()); + return caps(cv).getStereo(); + } + + int getStencilSize(Canvas3D cv) { + if (VERBOSE) System.err.println("JoglPipeline.getStencilSize()"); + if (VERBOSE) System.err.println(" Returning " + caps(cv).getStencilBits()); + return caps(cv).getStencilBits(); + } + + boolean hasSceneAntialiasingMultisample(Canvas3D cv) { + if (VERBOSE) System.err.println("JoglPipeline.hasSceneAntialiasingMultisample()"); + if (VERBOSE) System.err.println(" Returning " + caps(cv).getSampleBuffers()); + + return caps(cv).getSampleBuffers(); + } + + boolean hasSceneAntialiasingAccum(Canvas3D cv) { + if (VERBOSE) System.err.println("JoglPipeline.hasSceneAntialiasingAccum()"); + GLCapabilities caps = caps(cv); + if (VERBOSE) System.err.println(" Returning " + (caps.getAccumRedBits() > 0 && + caps.getAccumGreenBits() > 0 && + caps.getAccumBlueBits() > 0)); + return (caps.getAccumRedBits() > 0 && + caps.getAccumGreenBits() > 0 && + caps.getAccumBlueBits() > 0); + } + + // Methods to get native WS display and screen + long getDisplay() { + if (VERBOSE) System.err.println("JoglPipeline.getDisplay()"); + return 0L; // Dummy method in JOGL + } + + private boolean checkedForGetScreenMethod = false; + private Method getScreenMethod = null; + int getScreen(final GraphicsDevice graphicsDevice) { + if (VERBOSE) System.err.println("JoglPipeline.getScreen()"); + + if (!checkedForGetScreenMethod) { + // All of the Sun GraphicsDevice implementations have a method + // int getScreen(); + // which we want to call reflectively if it's available. + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + try { + getScreenMethod = graphicsDevice.getClass().getDeclaredMethod("getScreen", new Class[] {}); + getScreenMethod.setAccessible(true); + } catch (Exception e) { + } + checkedForGetScreenMethod = true; + return null; + } + }); + } + + if (getScreenMethod != null) { + try { + return ((Integer) getScreenMethod.invoke(graphicsDevice, (Object[]) null)).intValue(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + return 0; + } + + //---------------------------------------------------------------------- + // Helper classes and methods to support query context functionality + // and pixel format selection + + interface ExtendedCapabilitiesChooser extends GLCapabilitiesChooser { + public void init(GLContext context); + } + + // Canvas subclass to help with various query operations such as the + // "query context" mechanism and pixel format selection. + // Must defeat and simplify the single-threading behavior of JOGL's + // GLCanvas in order to be able to set up a temporary pixel format + // and OpenGL context. Apparently simply turning off the + // single-threaded mode isn't enough to do this. + class QueryCanvas extends Canvas { + private GLDrawable drawable; + private ExtendedCapabilitiesChooser chooser; + private boolean alreadyRan; + + public QueryCanvas(AWTGraphicsConfiguration awtGraphicsConfiguration, ExtendedCapabilitiesChooser chooser) { + // The platform-specific GLDrawableFactory will only provide a + // non-null GraphicsConfiguration on platforms where this is + // necessary (currently only X11, as Windows allows the pixel + // format of the window to be set later and Mac OS X seems to + // handle this very differently than all other platforms). On + // other platforms this method returns null; it is the case (at + // least in the Sun AWT implementation) that this will result in + // equivalent behavior to calling the no-arg super() constructor + // for Canvas. + super(unwrap(awtGraphicsConfiguration)); + NativeWindow nativeWindow = NativeWindowFactory.getNativeWindow(this, awtGraphicsConfiguration); + drawable = GLDrawableFactory.getFactory(getDefaultProfile()).createGLDrawable(nativeWindow); + this.chooser = chooser; + } + + public void addNotify() { + super.addNotify(); + drawable.setRealized(true); + } + + // It seems that at least on Mac OS X we need to do the OpenGL + // context-related work outside of the addNotify call because the + // Canvas hasn't been resized to a non-zero size by that point + public void doQuery() { + if (alreadyRan) + return; + GLContext context = drawable.createContext(null); + int res = context.makeCurrent(); + if (res != GLContext.CONTEXT_NOT_CURRENT) { + try { + chooser.init(context); + } finally { + context.release(); + } + } + context.destroy(); + alreadyRan = true; + } + } + + private static AWTGraphicsConfiguration createAwtGraphicsConfiguration(GLCapabilities capabilities, + CapabilitiesChooser chooser, + GraphicsDevice device) { + //FIXME unit id? + AWTGraphicsDevice awtGraphicsDevice = new AWTGraphicsDevice(device, 0); + GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(awtGraphicsDevice); + AWTGraphicsConfiguration awtGraphicsConfiguration = (AWTGraphicsConfiguration) factory.chooseGraphicsConfiguration(capabilities, capabilities, + chooser, new AWTGraphicsScreen(awtGraphicsDevice)); + return awtGraphicsConfiguration; + } + + private static AWTGraphicsConfiguration createAwtGraphicsConfiguration(GLCapabilities capabilities, + CapabilitiesChooser chooser, + AWTGraphicsDevice awtGraphicsDevice) { + GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(awtGraphicsDevice); + AWTGraphicsConfiguration awtGraphicsConfiguration = (AWTGraphicsConfiguration) factory.chooseGraphicsConfiguration(capabilities, capabilities, + chooser, new AWTGraphicsScreen(awtGraphicsDevice)); + return awtGraphicsConfiguration; + } + + private static GraphicsConfiguration unwrap(AWTGraphicsConfiguration config) { + if (config == null) { + return null; + } + return config.getAWTGraphicsConfiguration(); + } + + // Used in conjunction with IndexCapabilitiesChooser in pixel format + // selection -- see getBestConfiguration + class CapabilitiesCapturer extends DefaultGLCapabilitiesChooser implements ExtendedCapabilitiesChooser { + private boolean done; + private GLCapabilities capabilities; + private int chosenIndex = -1; + + public boolean done() { + return done; + } + + public GLCapabilities getCapabilities() { + return capabilities; + } + + public int getChosenIndex() { + return chosenIndex; + } + + public int chooseCapabilities(GLCapabilities desired, + GLCapabilities[] available, + int windowSystemRecommendedChoice) { + int res = super.chooseCapabilities(desired, Arrays.asList(available), windowSystemRecommendedChoice); + capabilities = available[res]; + chosenIndex = res; + markDone(); + return res; + } + + public void init(GLContext context) { + // Avoid hanging things up for several seconds + kick(); + } + + private void markDone() { + synchronized (this) { + done = true; + notifyAll(); + } + } + + private void kick() { + synchronized (this) { + notifyAll(); + } + } + } + + // Used to support the query context mechanism -- needs to be more + // than just a GLCapabilitiesChooser + class ContextQuerier extends DefaultGLCapabilitiesChooser implements ExtendedCapabilitiesChooser { + private Canvas3D canvas; + private boolean glslLibraryAvailable; + private boolean done; + + public ContextQuerier(Canvas3D canvas, + boolean glslLibraryAvailable) { + this.canvas = canvas; + this.glslLibraryAvailable = glslLibraryAvailable; + } + + public boolean done() { + return done; + } + + public void init(GLContext context) { + // This is basically a temporary + JoglContext jctx = new JoglContext(context); + // Set up various properties + if (getPropertiesFromCurrentContext(jctx)) { + setupCanvasProperties(canvas, jctx, context.getGL(), + glslLibraryAvailable); + } + markDone(); + } + + private void markDone() { + synchronized (this) { + done = true; + notifyAll(); + } + } + } + + // Used in two phases of pixel format selection: transforming the + // JoglGraphicsConfiguration to a real AWT GraphicsConfiguration and + // during context creation to select exactly the same graphics + // configuration as was done during getBestConfiguration. + class IndexCapabilitiesChooser implements GLCapabilitiesChooser { + private int indexToChoose; + + IndexCapabilitiesChooser(int indexToChoose) { + this.indexToChoose = indexToChoose; + } + + public int chooseCapabilities(CapabilitiesImmutable desired, + List available, + int windowSystemRecommendedChoice) { + if (DEBUG_CONFIG) { + System.err.println("IndexCapabilitiesChooser returning index=" + indexToChoose); + } + return indexToChoose; + } + } + + private void disposeOnEDT(final Frame f) { + Runnable r = new Runnable() { + public void run() { + f.setVisible(false); + f.dispose(); + } + }; + if (!EventQueue.isDispatchThread()) { + EventQueue.invokeLater(r); + } else { + r.run(); + } + } + + + // --------------------------------------------------------------------- + + // + // DrawingSurfaceObject methods + // + + // Method to construct a new DrawingSurfaceObject + DrawingSurfaceObject createDrawingSurfaceObject(Canvas3D cv) { + if (VERBOSE) System.err.println("JoglPipeline.createDrawingSurfaceObject()"); + return new JoglDrawingSurfaceObject(cv); + } + + // Method to free the drawing surface object + void freeDrawingSurface(Canvas3D cv, DrawingSurfaceObject drawingSurfaceObject) { + if (VERBOSE) System.err.println("JoglPipeline.freeDrawingSurface()"); + // This method is a no-op + } + + // Method to free the native drawing surface object + void freeDrawingSurfaceNative(Object o) { + if (VERBOSE) System.err.println("JoglPipeline.freeDrawingSurfaceNative()"); + // This method is a no-op + } + + //---------------------------------------------------------------------- + // Context-related routines + // + + // Helper used everywhere + GLContext context(Context ctx) { + if (ctx == null) + return null; + return ((JoglContext) ctx).getGLContext(); + } + + // Helper used everywhere + GLDrawable drawable(Drawable drawable) { + if (drawable == null) + return null; + return ((JoglDrawable) drawable).getGLDrawable(); + } + + GLCapabilities caps(Canvas3D ctx) { + return ((JoglGraphicsConfiguration) ctx.graphicsConfiguration).getGLCapabilities(); + } + + //---------------------------------------------------------------------- + // General helper routines + // + + private static ThreadLocal nioVertexTemp = new ThreadLocal(); + private static ThreadLocal nioVertexDoubleTemp = new ThreadLocal(); + private static ThreadLocal nioColorTemp = new ThreadLocal(); + private static ThreadLocal nioColorByteTemp = new ThreadLocal(); + private static ThreadLocal nioNormalTemp = new ThreadLocal(); + private static ThreadLocal nioTexCoordSetTemp = new ThreadLocal(); + private static ThreadLocal nioVertexAttrSetTemp = new ThreadLocal(); + + private static FloatBuffer getVertexArrayBuffer(float[] vertexArray) { + return getVertexArrayBuffer(vertexArray, true); + } + + private static FloatBuffer getVertexArrayBuffer(float[] vertexArray, boolean copyData) { + return getNIOBuffer(vertexArray, nioVertexTemp, copyData); + } + + private static DoubleBuffer getVertexArrayBuffer(double[] vertexArray) { + return getVertexArrayBuffer(vertexArray, true); + } + + private static DoubleBuffer getVertexArrayBuffer(double[] vertexArray, boolean copyData) { + return getNIOBuffer(vertexArray, nioVertexDoubleTemp, true); + } + + private static FloatBuffer getColorArrayBuffer(float[] colorArray) { + return getColorArrayBuffer(colorArray, true); + } + + private static FloatBuffer getColorArrayBuffer(float[] colorArray, boolean copyData) { + return getNIOBuffer(colorArray, nioColorTemp, true); + } + + private static ByteBuffer getColorArrayBuffer(byte[] colorArray) { + return getColorArrayBuffer(colorArray, true); + } + + private static ByteBuffer getColorArrayBuffer(byte[] colorArray, boolean copyData) { + return getNIOBuffer(colorArray, nioColorByteTemp, true); + } + + private static FloatBuffer getNormalArrayBuffer(float[] normalArray) { + return getNormalArrayBuffer(normalArray, true); + } + + private static FloatBuffer getNormalArrayBuffer(float[] normalArray, boolean copyData) { + return getNIOBuffer(normalArray, nioNormalTemp, true); + } + + private static FloatBuffer[] getTexCoordSetBuffer(Object[] texCoordSet) { + return getNIOBuffer(texCoordSet, nioTexCoordSetTemp); + } + + private static FloatBuffer[] getVertexAttrSetBuffer(Object[] vertexAttrSet) { + return getNIOBuffer(vertexAttrSet, nioVertexAttrSetTemp); + } + + private static FloatBuffer getNIOBuffer(float[] array, ThreadLocal threadLocal, boolean copyData) { + if (array == null) { + return null; + } + FloatBuffer buf = threadLocal.get(); + if (buf == null) { + buf = Buffers.newDirectFloatBuffer(array.length); + threadLocal.set(buf); + } else { + buf.rewind(); + if (buf.remaining() < array.length) { + int newSize = Math.max(2 * buf.remaining(), array.length); + buf = Buffers.newDirectFloatBuffer(newSize); + threadLocal.set(buf); + } + } + if (copyData) { + buf.put(array); + buf.rewind(); + } + return buf; + } + + private static DoubleBuffer getNIOBuffer(double[] array, ThreadLocal threadLocal, boolean copyData) { + if (array == null) { + return null; + } + DoubleBuffer buf = threadLocal.get(); + if (buf == null) { + buf = Buffers.newDirectDoubleBuffer(array.length); + threadLocal.set(buf); + } else { + buf.rewind(); + if (buf.remaining() < array.length) { + int newSize = Math.max(2 * buf.remaining(), array.length); + buf = Buffers.newDirectDoubleBuffer(newSize); + threadLocal.set(buf); + } + } + if (copyData) { + buf.put(array); + buf.rewind(); + } + return buf; + } + + private static ByteBuffer getNIOBuffer(byte[] array, ThreadLocal threadLocal, boolean copyData) { + if (array == null) { + return null; + } + ByteBuffer buf = threadLocal.get(); + if (buf == null) { + buf = Buffers.newDirectByteBuffer(array.length); + threadLocal.set(buf); + } else { + buf.rewind(); + if (buf.remaining() < array.length) { + int newSize = Math.max(2 * buf.remaining(), array.length); + buf = Buffers.newDirectByteBuffer(newSize); + threadLocal.set(buf); + } + } + if (copyData) { + buf.put(array); + buf.rewind(); + } + return buf; + } + + private static FloatBuffer[] getNIOBuffer(Object[] array, ThreadLocal threadLocal) { + if (array == null) { + return null; + } + FloatBuffer[] bufs = threadLocal.get(); + + // First resize array of FloatBuffers + if (bufs == null) { + bufs = new FloatBuffer[array.length]; + threadLocal.set(bufs); + } else if (bufs.length < array.length) { + FloatBuffer[] newBufs = new FloatBuffer[array.length]; + System.arraycopy(bufs, 0, newBufs, 0, bufs.length); + bufs = newBufs; + threadLocal.set(bufs); + } + + // Now go down array of arrays, converting each into a direct FloatBuffer + for (int i = 0; i < array.length; i++) { + float[] cur = (float[]) array[i]; + FloatBuffer buf = bufs[i]; + if (buf == null) { + buf = Buffers.newDirectFloatBuffer(cur.length); + bufs[i] = buf; + } else { + buf.rewind(); + if (buf.remaining() < cur.length) { + int newSize = Math.max(2 * buf.remaining(), cur.length); + buf = Buffers.newDirectFloatBuffer(newSize); + bufs[i] = buf; + } + } + buf.put(cur); + buf.rewind(); + } + + return bufs; + } +} diff --git a/src/classes/share/javax/media/j3d/JoglShaderObject.java b/src/classes/share/javax/media/j3d/JoglShaderObject.java new file mode 100644 index 0000000..da4b77c --- /dev/null +++ b/src/classes/share/javax/media/j3d/JoglShaderObject.java @@ -0,0 +1,44 @@ +/* + * $RCSfile$ + * + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.media.j3d; + +class JoglShaderObject implements ShaderProgramId, ShaderId, ShaderAttrLoc { + private int val; + + JoglShaderObject(int val) { + this.val = val; + } + + int getValue() { + return val; + } +} -- cgit v1.2.3