diff options
Diffstat (limited to 'src/javax/media/j3d/JoglPipeline.java')
-rw-r--r-- | src/javax/media/j3d/JoglPipeline.java | 8963 |
1 files changed, 8963 insertions, 0 deletions
diff --git a/src/javax/media/j3d/JoglPipeline.java b/src/javax/media/j3d/JoglPipeline.java new file mode 100644 index 0000000..2f38fd8 --- /dev/null +++ b/src/javax/media/j3d/JoglPipeline.java @@ -0,0 +1,8963 @@ +/* + * 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. + * + */ + +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.Field; +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.Map; +import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.jogamp.nativewindow.AbstractGraphicsDevice; +import com.jogamp.nativewindow.AbstractGraphicsScreen; +import com.jogamp.nativewindow.CapabilitiesChooser; +import com.jogamp.nativewindow.GraphicsConfigurationFactory; +import com.jogamp.nativewindow.NativeSurface; +import com.jogamp.nativewindow.NativeWindowFactory; +import com.jogamp.nativewindow.ProxySurface; +import com.jogamp.nativewindow.UpstreamSurfaceHook; +import com.jogamp.nativewindow.VisualIDHolder; +import com.jogamp.opengl.DefaultGLCapabilitiesChooser; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLCapabilitiesChooser; +import com.jogamp.opengl.GLCapabilitiesImmutable; +import com.jogamp.opengl.GLContext; +import com.jogamp.opengl.GLDrawable; +import com.jogamp.opengl.GLDrawableFactory; +import com.jogamp.opengl.GLException; +import com.jogamp.opengl.GLFBODrawable; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.Threading; + +import com.jogamp.common.nio.Buffers; +import com.jogamp.nativewindow.awt.AWTGraphicsConfiguration; +import com.jogamp.nativewindow.awt.AWTGraphicsDevice; +import com.jogamp.nativewindow.awt.AWTGraphicsScreen; +import com.jogamp.nativewindow.awt.JAWTWindow; +import com.jogamp.opengl.FBObject; + +/** + * 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; + + private GLProfile profile; + + private Object mainThreadContext; // Fix for Bug 983 + + /** + * Constructor for singleton JoglPipeline instance + */ + protected JoglPipeline() { + // Fix for Bug 983 + try { + // Retrieve main thread AppContext instance by reflection + mainThreadContext = Class.forName("sun.awt.AppContext").getMethod("getAppContext").invoke(null); + } catch (final Throwable ex) { + // Let's consider app context is not necessary for the program + } + } + + /** + * Initialize the pipeline + */ + @Override + 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(); + + profile = GLProfile.getMaxFixedFunc(true); + // TODO: finish this with any other needed initialization + } + + // --------------------------------------------------------------------- + + // + // GeometryArrayRetained methods + // + + // used for GeometryArrays by Copy or interleaved + @Override + 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 + @Override + 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 + @Override + void executeVABuffer(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int vcount, + int vformat, + int vdefined, + int initialCoordIndex, + Buffer vcoords, + int initialColorIndex, + Buffer cdataBuffer, + float[] cfdata, byte[] cbdata, + int initialNormalIndex, FloatBuffer ndata, + int vertexAttrCount, int[] vertexAttrSizes, + int[] vertexAttrIndices, FloatBuffer[] 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 = 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 = 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 + @Override + 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, + FloatBuffer 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, varray, cdata, cdirty); + } + + @Override + 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); + } + + if ((vformat & GeometryArray.COORDINATES) != 0) { + gl.glEnableClientState(GL2.GL_VERTEX_ARRAY); + } else { + gl.glDisableClientState(GL2.GL_VERTEX_ARRAY); + } + } + + // used for GeometryArrays + @Override + 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 + @Override + 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, FloatBuffer 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 = 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 + @Override + 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 + @Override + 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, + FloatBuffer 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, vdata, carray, + cDirty, indexCoord); + } + + // non interleaved, by reference, Java arrays + @Override + 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 + @Override + void executeIndexedGeometryVABuffer(Context ctx, + GeometryArrayRetained geo, int geo_type, + boolean isNonUniformScale, + boolean ignoreVertexColors, + int initialIndexIndex, + int validIndexCount, + int vertexCount, + int vformat, + int vdefined, + Buffer vcoords, + Buffer cdataBuffer, + float[] cfdata, byte[] cbdata, + FloatBuffer ndata, + int vertexAttrCount, int[] vertexAttrSizes, + FloatBuffer[] 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 = 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 = 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 + @Override + 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 + @Override + 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 + + @Override + 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; + } + + @Override + 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; + } + + @Override + 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; + } + + @Override + 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; + } + + @Override + 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; + } + + @Override + 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; + } + + @Override + 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; + } + + @Override + 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; + } + + @Override + 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; + } + + @Override + 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 + + @Override + 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; + } + + @Override + 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; + } + + @Override + 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; + } + + @Override + 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; + } + + @Override + 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; + } + + @Override + 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; + } + + @Override + 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; + } + + @Override + 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; + } + + @Override + 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; + } + + @Override + 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. + @Override + 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 = (int) gl.glCreateShaderObjectARB(GL2.GL_VERTEX_SHADER); + } else if (shaderType == Shader.SHADER_TYPE_FRAGMENT) { + shaderHandle = (int) 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; + } + @Override + 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; + } + @Override + 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; + } + + @Override + ShaderError createGLSLShaderProgram(Context ctx, ShaderProgramId[] shaderProgramId) { + if (VERBOSE) System.err.println("JoglPipeline.createGLSLShaderProgram()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + int shaderProgramHandle = (int) 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; + } + @Override + 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; + } + @Override + 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; + } + @Override + ShaderError bindGLSLVertexAttrName(Context ctx, ShaderProgramId shaderProgramId, + String attrName, int attrIndex) { + if (VERBOSE) System.err.println("JoglPipeline.bindGLSLVertexAttrName()"); + + GL2 gl = context(ctx).getGL().getGL2(); + gl.glBindAttribLocation(unbox(shaderProgramId), + attrIndex + VirtualUniverse.mc.glslVertexAttrOffset, + attrName); + return null; + } + @Override + 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); + } + } + + @Override + 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; + } + + // --------------------------------------------------------------------- + + // + // ColoringAttributesRetained methods + // + + @Override + 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]; + @Override + 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 + // + + @Override + 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 + // + + @Override + 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 + // + + @Override + 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 + // + + @Override + 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 + // + + @Override + 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 + // + + @Override + 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); + + 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 + // + + @Override + 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 + // + + @Override + 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 + // + + @Override + 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 + // + + @Override + 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 + */ + @Override + 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; + } + + @Override + 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 + // + + @Override + 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); +// } + } + + @Override + 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 + } + + @Override + 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); +// } + } + + @Override + 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 + // + + @Override + void updateTextureUnitState(Context ctx, int index, boolean enable) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureUnitState()"); + + GL2 gl = context(ctx).getGL().getGL2(); + + 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 + // + + @Override + 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); + } + } + + @Override + 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); + } + + @Override + 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); + } + + @Override + 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); + } + + @Override + 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); + } + + @Override + 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); + } + + @Override + void updateTexture2DFilterModes(Context ctx, + int minFilter, int magFilter) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DFilterModes()"); + + updateTextureFilterModes(ctx, GL.GL_TEXTURE_2D, minFilter, magFilter); + } + + @Override + void updateTexture2DSharpenFunc(Context ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DSharpenFunc()"); + + updateTextureSharpenFunc(ctx, GL.GL_TEXTURE_2D, + numSharpenTextureFuncPts, sharpenTextureFuncPts); + } + + @Override + void updateTexture2DFilter4Func(Context ctx, + int numFilter4FuncPts, + float[] filter4FuncPts) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DFilter4Func()"); + + updateTextureFilter4Func(ctx, GL.GL_TEXTURE_2D, + numFilter4FuncPts, filter4FuncPts); + } + + @Override + 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 + // + + @Override + 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); + } + } + + @Override + 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; + } + } + + @Override + 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); + } + + } + + + @Override + 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); + } + + @Override + 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); + } + + @Override + 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, GL2.GL_TEXTURE_3D, + boundaryModeS, boundaryModeT, boundaryModeR, + boundaryRed, boundaryGreen, + boundaryBlue, boundaryAlpha); + } + + @Override + void updateTexture3DFilterModes(Context ctx, + int minFilter, int magFilter) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DFilterModes()"); + + updateTextureFilterModes(ctx, GL2.GL_TEXTURE_3D, + minFilter, magFilter); + } + + @Override + void updateTexture3DSharpenFunc(Context ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DSharpenFunc()"); + + updateTextureSharpenFunc(ctx, GL2.GL_TEXTURE_3D, + numSharpenTextureFuncPts, sharpenTextureFuncPts); + } + + @Override + void updateTexture3DFilter4Func(Context ctx, + int numFilter4FuncPts, + float[] filter4FuncPts) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DFilter4Func()"); + + updateTextureFilter4Func(ctx, GL2.GL_TEXTURE_3D, + numFilter4FuncPts, filter4FuncPts); + } + + @Override + void updateTexture3DAnisotropicFilter(Context ctx, float degree) { + if (VERBOSE) System.err.println("JoglPipeline.updateTexture3DAnisotropicFilter()"); + + updateTextureAnisotropicFilter(ctx, GL2.GL_TEXTURE_3D, degree); + } + + + // --------------------------------------------------------------------- + + // + // TextureCubeMapRetained methods + // + + @Override + 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); + } + } + + @Override + 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); + } + + @Override + 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); + } + + @Override + 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); + } + + @Override + 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); + } + + @Override + 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); + } + + @Override + void updateTextureCubeMapFilterModes(Context ctx, + int minFilter, int magFilter) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapFilterModes()"); + + updateTextureFilterModes(ctx, + GL.GL_TEXTURE_CUBE_MAP, + minFilter, magFilter); + } + + @Override + void updateTextureCubeMapSharpenFunc(Context ctx, + int numSharpenTextureFuncPts, + float[] sharpenTextureFuncPts) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapSharpenFunc()"); + + updateTextureSharpenFunc(ctx, + GL.GL_TEXTURE_CUBE_MAP, + numSharpenTextureFuncPts, sharpenTextureFuncPts); + } + + @Override + void updateTextureCubeMapFilter4Func(Context ctx, + int numFilter4FuncPts, + float[] filter4FuncPts) { + if (VERBOSE) System.err.println("JoglPipeline.updateTextureCubeMapFilter4Func()"); + + updateTextureFilter4Func(ctx, + GL.GL_TEXTURE_CUBE_MAP, + numFilter4FuncPts, filter4FuncPts); + } + + @Override + 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 + // + + // Maximum lights supported by the native API + @Override + 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 + // + + // Mac/JRE 7; called from Renderer when resizing is dedected + // Implementation follows the approach in jogamp.opengl.GLDrawableHelper.resizeOffscreenDrawable(..) + @Override + void resizeOffscreenLayer(Canvas3D cv, int cvWidth, int cvHeight) { + if (!isOffscreenLayerSurfaceEnabled(cv)) + return; + + JoglDrawable joglDrawable = (JoglDrawable)cv.drawable; + if (!hasFBObjectSizeChanged(joglDrawable, cvWidth, cvHeight)) + return; + + int newWidth = Math.max(1, cvWidth); + int newHeight = Math.max(1, cvHeight); + + GLDrawable glDrawble = joglDrawable.getGLDrawable(); + GLContext glContext = context(cv.ctx); + + // Assuming glContext != null + + final NativeSurface surface = glDrawble.getNativeSurface(); + final ProxySurface proxySurface = (surface instanceof ProxySurface) ? (ProxySurface)surface : null; + + final int lockRes = surface.lockSurface(); + + try { + // propagate new size - seems not relevant here + if (proxySurface != null) { + final UpstreamSurfaceHook ush = proxySurface.getUpstreamSurfaceHook(); + if (ush instanceof UpstreamSurfaceHook.MutableSize) { + ((UpstreamSurfaceHook.MutableSize)ush).setSurfaceSize(newWidth, newHeight); + } + } + /*else if(DEBUG) { // we have to assume surface contains the new size already, hence size check @ bottom + System.err.println("GLDrawableHelper.resizeOffscreenDrawable: Drawable's offscreen surface n.a. ProxySurface, but "+ns.getClass().getName()+": "+ns); + }*/ + + GL2 gl = glContext.getGL().getGL2(); + + // FBO : should be the default case on Mac OS X + if (glDrawble instanceof GLFBODrawable) { + + // Resize GLFBODrawable + // TODO msaa gets lost +// ((GLFBODrawable)glDrawble).resetSize(gl); + + // Alternative: resize GL_BACK FBObject directly, + // if multisampled the FBO sink (GL_FRONT) will be resized before the swap is executed + int numSamples = ((GLFBODrawable)glDrawble).getChosenGLCapabilities().getNumSamples(); + FBObject fboObjectBack = ((GLFBODrawable)glDrawble).getFBObject( GL.GL_BACK ); + fboObjectBack.reset(gl, newWidth, newHeight, numSamples/*, false*/); // false = don't reset SamplingSinkFBO immediately + fboObjectBack.bind(gl); + + // If double buffered without antialiasing the GL_FRONT FBObject + // will be resized by glDrawble after the next swap-call + } + // pbuffer - not tested because Mac OS X 10.7+ supports FBO + else { + // Create new GLDrawable (pbuffer) and update the coresponding GLContext + + final GLContext currentContext = GLContext.getCurrent(); + final GLDrawableFactory factory = glDrawble.getFactory(); + + // Ensure to sync GL command stream + if (currentContext != glContext) { + glContext.makeCurrent(); + } + gl.glFinish(); + glContext.release(); + + if (proxySurface != null) { + proxySurface.enableUpstreamSurfaceHookLifecycle(false); + } + + try { + glDrawble.setRealized(false); + // New GLDrawable + glDrawble = factory.createGLDrawable(surface); + glDrawble.setRealized(true); + + joglDrawable.setGLDrawable(glDrawble); + } + finally { + if (proxySurface != null) { + proxySurface.enableUpstreamSurfaceHookLifecycle(true); + } + } + + glContext.setGLDrawable(glDrawble, true); // re-association + + // make current last current context + if (currentContext != null) { + currentContext.makeCurrent(); + } + } + } + finally { + surface.unlockSurface(); + } + } + + // Fix for Bug 983 + private void checkAppContext() { + if (mainThreadContext == null) + return; + + try { + // Check by reflection that sun.awt.AppContext.getAppContext() doesn't return null + // (required by ImageIO.write() and other JMF internal calls) to apply workaround proposed at + // http://stackoverflow.com/questions/17223304/appcontext-is-null-from-rmi-thread-with-java-7-update-25 + final Class<?> appContextClass = Class.forName("sun.awt.AppContext"); + if (appContextClass.getMethod("getAppContext").invoke(null) == null) { + final Field field = appContextClass.getDeclaredField("threadGroup2appContext"); + field.setAccessible(true); + final Map threadGroup2appContext = (Map)field.get(null); + final ThreadGroup currentThreadGroup = Thread.currentThread().getThreadGroup(); + threadGroup2appContext.put(currentThreadGroup, mainThreadContext); + } + } catch (Throwable ex) { + // Let's consider app context is not necessary for the program + } + // Don't need mainThreadContext anymore + mainThreadContext = null; + } + + // This is the native method for creating the underlying graphics context. + @Override + Context createNewContext(Canvas3D cv, Drawable drawable, + Context shareCtx, boolean isSharedCtx, + boolean offScreen) { + if (VERBOSE) System.err.println("JoglPipeline.createNewContext()"); + + checkAppContext(); + GLDrawable glDrawable = null; + GLContext glContext = null; + + if (offScreen) { + glDrawable = drawable(cv.drawable); // cv.drawable != null, set in 'createOffScreenBuffer' + glContext = glDrawable.createContext(context(shareCtx)); + } + else { + // determined in 'getBestConfiguration' + GraphicsConfigInfo gcInf0 = Canvas3D.graphicsConfigTable.get(cv.graphicsConfiguration); + AWTGraphicsConfiguration awtConfig = (AWTGraphicsConfiguration)gcInf0.getPrivateData(); + + // JAWTWindow + JAWTWindow nativeWindow = (JAWTWindow)NativeWindowFactory.getNativeWindow(cv, awtConfig); + nativeWindow.lockSurface(); + try { + glDrawable = GLDrawableFactory.getFactory(profile).createGLDrawable(nativeWindow); + glContext = glDrawable.createContext(context(shareCtx)); + } + finally { + nativeWindow.unlockSurface(); + } + + cv.drawable = new JoglDrawable(glDrawable, nativeWindow); + } + + // assuming that this only gets called after addNotify has been called + glDrawable.setRealized(true); + + // 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 J3D program and throw exception using JOGL renderer + boolean failed = false; + int failCount = 0; + int MAX_FAIL_COUNT = 5; + do { + failed = false; + int res = glContext.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 = glContext.getGL().getGL2(); + + JoglContext ctx = new JoglContext(glContext); + + try { + if (!getPropertiesFromCurrentContext(ctx, gl)) { + throw new IllegalRenderingStateException("Unable to fetch properties from current OpenGL context"); + } + + if(!isSharedCtx){ + // Set up fields in Canvas3D + setupCanvasProperties(cv, ctx, gl); + } + + // 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); + + /* + OpenGL specs: + glReadBuffer specifies a color buffer as the source for subsequent glReadPixels. + This source mode is initially GL_FRONT in single-buffered and GL_BACK in double-buffered configurations. + + We leave this mode unchanged in on-screen rendering and adjust it in off-screen rendering. See below. + */ +// gl.glReadBuffer(GL_FRONT); // off window, default for single-buffered non-stereo window + + // Issue 417: JOGL: Mip-mapped NPOT textures rendered incorrectly + // J3D 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); + + + // Mac OS X / JRE 7 : onscreen rendering = offscreen rendering + // bind FBO + if (!offScreen && glDrawable instanceof GLFBODrawable) { + GLFBODrawable fboDrawable = (GLFBODrawable)glDrawable; + // bind GLFBODrawable's drawing FBObject + // GL_BACK returns the correct FBOObject for single/double buffering, incl. multisampling + fboDrawable.getFBObject( GL.GL_BACK ).bind(gl); + } + + + // FBO or pbuffer + if (offScreen) { + + // Final caps + GLCapabilitiesImmutable chosenCaps = glDrawable.getChosenGLCapabilities(); + + // FBO + if (glDrawable instanceof GLFBODrawable) { + GLFBODrawable fboDrawable = (GLFBODrawable)glDrawable; + // bind GLFBODrawable's drawing FBObject + // GL_BACK returns the correct FBOObject for single/double buffering, incl. multisampling + fboDrawable.getFBObject( GL.GL_BACK ).bind(gl); + } + // pbuffer + else { + // Double buffering: read from back buffer, as we don't swap + // Even this setting is identical to the initially mode it is set explicitly + if (chosenCaps.getDoubleBuffered()) { + gl.glReadBuffer(GL.GL_BACK); + } + else { + gl.glReadBuffer(GL.GL_FRONT); + } + } + } + } + finally { + glContext.release(); + } + + return ctx; + } + + @Override + void createQueryContext(Canvas3D cv, Drawable drawable, + boolean offScreen, int width, int height) { + if (VERBOSE) System.err.println("JoglPipeline.createQueryContext()"); + + // Assumes createQueryContext is never called for a drawable != null + + if (offScreen) { + + Drawable offDrawable = createOffScreenBuffer(cv, null, width, height); + + GLDrawable glDrawable = drawable(offDrawable); + + glDrawable.setRealized(true); + + GLContext glContext = glDrawable.createContext(null); + glContext.makeCurrent(); + + JoglContext ctx = new JoglContext(glContext); + + GL2 gl = glContext.getGL().getGL2(); + + // get current context properties + getPropertiesFromCurrentContext(ctx, gl); + // Set up fields in Canvas3D + setupCanvasProperties(cv, ctx, gl); + + // Done ! + + glContext.release(); + glContext.destroy(); + glDrawable.setRealized(false); + } + else { + + // TODO can't find an implementation which avoids the use of QueryCanvas + // JOGL requires a visible Frame for an onscreen context + + Frame f = new Frame(); + f.setUndecorated(true); + f.setLayout(new BorderLayout()); + + ContextQuerier querier = new ContextQuerier(cv); + + AWTGraphicsConfiguration awtConfig = + (AWTGraphicsConfiguration)Canvas3D.graphicsConfigTable.get(cv.graphicsConfiguration).getPrivateData(); + + QueryCanvas canvas = new QueryCanvas(awtConfig, 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 + @Override + Drawable createOffScreenBuffer(Canvas3D cv, Context ctx, int width, int height) { + if (VERBOSE) System.err.println("JoglPipeline.createOffScreenBuffer()"); + + // ctx unused, doesn't exist yet + + // Offscreen Canvas3D's JoglGraphicsConfiguration + JoglGraphicsConfiguration jgc = (JoglGraphicsConfiguration)cv.graphicsConfiguration; + + // Retrieve the offscreen Canvas3D's GraphicsConfigInfo + GraphicsConfigInfo gcInf0 = Canvas3D.graphicsConfigTable.get(jgc); + + // Offscreen Canvas3D's graphics configuration, determined in 'getBestConfiguration' + AWTGraphicsConfiguration awtConfig = (AWTGraphicsConfiguration)gcInf0.getPrivateData(); + + // TODO Offscreen Canvas3D's graphics devise, determined in 'getBestConfiguration' + //AbstractGraphicsDevice device = awtConfig.getScreen().getDevice(); // throws exception + // Alternative: default graphics device + AbstractGraphicsDevice device = GLDrawableFactory.getDesktopFactory().getDefaultDevice(); + + // Offscreen Canvas3D's capabilites, determined in 'getBestConfiguration' + GLCapabilities canvasCaps = (GLCapabilities)awtConfig.getChosenCapabilities(); + + // For further investigations : the user's GraphicsConfigTemplate3D (not used yet) + GraphicsConfigTemplate3D gct3D = gcInf0.getGraphicsConfigTemplate3D(); + + + // Assuming that the offscreen drawable will/can support the chosen GLCapabilities + // of the offscreen Canvas3D + + final GLCapabilities offCaps = new GLCapabilities(profile); + offCaps.copyFrom(canvasCaps); + + // double bufffering only if scene antialiasing is required/preferred and supported + if (offCaps.getSampleBuffers() == false) { + offCaps.setDoubleBuffered(false); + offCaps.setNumSamples(0); + } + + // Never stereo + offCaps.setStereo(false); + + // Set preferred offscreen drawable : framebuffer object (FBO) or pbuffer + offCaps.setFBO(true); // switches to pbuffer if FBO is not supported + // caps.setPBuffer(true); + + // !! a 'null' capability chooser; JOGL doesn't call a chooser for offscreen drawable + + // If FBO : 'offDrawable' is of type com.jogamp.opengl.GLFBODrawable + GLDrawable offDrawable = GLDrawableFactory.getFactory(profile).createOffscreenDrawable(device, offCaps, null, width, height); + +// !! these chosen caps are not final as long as the corresponding context is made current +//System.out.println("createOffScreenBuffer chosenCaps = " + offDrawable.getChosenGLCapabilities()); + + return new JoglDrawable(offDrawable, null); + } + + // 'destroyContext' is called first if context exists + @Override + void destroyOffScreenBuffer(Canvas3D cv, Context ctx, Drawable drawable) { + if (VERBOSE) System.err.println("JoglPipeline.destroyOffScreenBuffer()"); + + // it is done in 'destroyContext' + } + + // This is the native for reading the image from the offscreen buffer + @Override + void readOffScreenBuffer(Canvas3D cv, Context ctx, int format, int dataType, Object data, int width, int height) { + if (VERBOSE) System.err.println("JoglPipeline.readOffScreenBuffer()"); + + GLDrawable glDrawable = ((JoglDrawable)cv.drawable).getGLDrawable(); + GLCapabilitiesImmutable chosenCaps = glDrawable.getChosenGLCapabilities(); + GLFBODrawable fboDrawable = null; + + GL2 gl = context(ctx).getGL().getGL2(); + + // If FBO + if (chosenCaps.isFBO()) { + + fboDrawable = (GLFBODrawable)glDrawable; + + if (chosenCaps.getDoubleBuffered()) { + // swap = resolve multisampling or flip back/front FBO + fboDrawable.swapBuffers(); + // unbind texture render target, we read from FBO + gl.glBindTexture(GL.GL_TEXTURE_2D, 0); + } + + // bind FBO for reading pixel data + // GL_FRONT = SamplingSinkFBO if double buffered and multisampled + // GL_FRONT if double buffered ( = GL_BAck before swap was called) + // GL_FRONT = GL_BACK if single buffered (single FBO) + + fboDrawable.getFBObject( GL.GL_FRONT ).bind(gl); + } + // else pbuffer + + 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); + } + + // If FBO + if (chosenCaps.isFBO()) { + // bind FBO for drawing + fboDrawable.getFBObject( GL.GL_BACK ).bind(gl); + } + } + + // The native method for swapBuffers - onscreen only +@Override +void swapBuffers(Canvas3D cv, Context ctx, Drawable drawable) { + if (VERBOSE) System.err.println("JoglPipeline.swapBuffers()"); + GLDrawable draw = drawable(drawable); + draw.swapBuffers(); +} + + // native method for setting Material when no material is present + @Override + 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); + } + + @Override + void destroyContext(Drawable drawable, Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.destroyContext()"); + + JoglDrawable joglDrawable = (JoglDrawable)drawable; + GLContext context = context(ctx); + + if (GLContext.getCurrent() == context) { + context.release(); + } + context.destroy(); + + // assuming this is the right point at which to make this call + joglDrawable.getGLDrawable().setRealized(false); + + joglDrawable.destroyNativeWindow(); + } + + // This is the native method for doing accumulation. + @Override + 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. + @Override + 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. + @Override + 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. + @Override + 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 + @Override + 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 + @Override + 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 + @Override + 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 + @Override + 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 + @Override + 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 + @Override + 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 + @Override + 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 + @Override + 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); + } + } + } + + // Native method to update separate specular color control + @Override + 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 + @Override + 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 + @Override + 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 + @Override + 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 + @Override + 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 + @Override + 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 + @Override + 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 + @Override + 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 + @Override + 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 + @Override + 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 + @Override + 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 + @Override + 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 + @Override + 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 + @Override + 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 + @Override + 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 + @Override + 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. + */ + @Override + 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 + @Override + boolean useCtx(Context ctx, 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. + @Override + boolean releaseCtx(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.releaseCtx()"); + GLContext context = context(ctx); + context.release(); + return true; + } + + @Override + 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(); + + } + + @Override + 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(); + + } + + @Override + 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(); + + } + + @Override + 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. + @Override + 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. + @Override + 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); + } + } + +static boolean isOffscreenLayerSurfaceEnabled(Canvas3D cv) { + if (cv.drawable == null || cv.offScreen) + return false; + + JoglDrawable joglDrawble = (JoglDrawable)cv.drawable; + JAWTWindow jawtwindow = (JAWTWindow)joglDrawble.getNativeWindow(); + if (jawtwindow == null) + return false; + + return jawtwindow.isOffscreenLayerSurfaceEnabled(); +} + +static boolean hasFBObjectSizeChanged(JoglDrawable jdraw, int width, int height) { + if (!(jdraw.getGLDrawable() instanceof GLFBODrawable)) + return false; + + FBObject fboBack = ((GLFBODrawable)jdraw.getGLDrawable()).getFBObject(GL.GL_BACK); + if (fboBack == null) + return false; + + return (width != fboBack.getWidth() || height != fboBack.getHeight()); +} + + + // The native method for setting the Viewport. + @Override + 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 + @Override + 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); + } + + @Override + void endDisplayList(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.endDisplayList()"); + GL2 gl = context(ctx).getGL().getGL2(); + gl.glEndList(); + } + + int numInvalidLists = 0; + @Override + 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); + } + } + + @Override + 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); + } + + @Override + 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"); + } + } + + @Override + int generateTexID(Context ctx) { + if (VERBOSE) System.err.println("JoglPipeline.generateTexID()"); + + GL gl = context(ctx).getGL(); + int[] tmp = new int[] { -1 }; + gl.glGenTextures(1, tmp, 0); + + if (tmp[0] < 1) + return -1; + + return tmp[0]; + } + + @Override + 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(); + } + + @Override + 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. + @Override + 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. + @Override + 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, GL2 gl) { + + // 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 hasgl13) { + + // Force shaders to be disabled, since no multitexture support + if (!hasgl13) + return; + + if (gl.isExtensionAvailable("GL_ARB_shader_objects") && + gl.isExtensionAvailable("GL_ARB_shading_language_100")) { + + // 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) { + // 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 + checkGLSLShaderExtensions(cv, ctx, gl, gl13); + + 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); +// } + } + + 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); +// } + + } + + 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. + @Override + GraphicsConfiguration getGraphicsConfig(GraphicsConfiguration gconfig) { + if (VERBOSE) System.err.println("JoglPipeline.getGraphicsConfig()"); + + GraphicsConfigInfo gcInf0 = Canvas3D.graphicsConfigTable.get(gconfig); + AWTGraphicsConfiguration awtConfig = (AWTGraphicsConfiguration)gcInf0.getPrivateData(); + + return awtConfig.getAWTGraphicsConfiguration(); + } + + private enum DisabledCaps { + STEREO, + AA, + DOUBLE_BUFFER, + } + + // Get best graphics config from pipeline + @Override + GraphicsConfiguration getBestConfiguration(GraphicsConfigTemplate3D gct, + GraphicsConfiguration[] gc) { + if (VERBOSE) System.err.println("JoglPipeline.getBestConfiguration()"); + + // Create a GLCapabilities based on the GraphicsConfigTemplate3D + final GLCapabilities caps = new GLCapabilities(profile); + + caps.setDoubleBuffered(gct.getDoubleBuffer() != GraphicsConfigTemplate.UNNECESSARY); + + caps.setStereo(gct.getStereo() != GraphicsConfigTemplate.UNNECESSARY); + + // Scene antialiasing only if double buffering + if (gct.getSceneAntialiasing() != GraphicsConfigTemplate.UNNECESSARY && + gct.getDoubleBuffer() != GraphicsConfigTemplate.UNNECESSARY) { + caps.setSampleBuffers(true); + caps.setNumSamples(2); + } else { + caps.setSampleBuffers(false); + caps.setNumSamples(0); + } + + 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())); + + + // Issue 399: Request alpha buffer if transparentOffScreen is set + if (VirtualUniverse.mc.transparentOffScreen) { + caps.setAlphaBits(1); + } + + + // Add PREFERRED capabilities in order of least to highest priority and we will try disabling them + ArrayList<DisabledCaps> capsToDisable = new ArrayList<DisabledCaps>(); + + if (gct.getStereo() == GraphicsConfigTemplate.PREFERRED) { + capsToDisable.add(DisabledCaps.STEREO); + } + + if (gct.getSceneAntialiasing() == GraphicsConfigTemplate.PREFERRED) { + capsToDisable.add(DisabledCaps.AA); + } + + // if AA is required, so is double buffering. + if (gct.getSceneAntialiasing() != GraphicsConfigTemplate.REQUIRED && + gct.getDoubleBuffer() == GraphicsConfigTemplate.PREFERRED) { + capsToDisable.add(DisabledCaps.DOUBLE_BUFFER); + } + + + // Pick an arbitrary graphics device. + GraphicsDevice device = gc[0].getDevice(); + AbstractGraphicsScreen screen = (device != null) ? AWTGraphicsScreen.createScreenDevice(device, AbstractGraphicsDevice.DEFAULT_UNIT) : + AWTGraphicsScreen.createDefault(); + + // 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; + AWTGraphicsConfiguration awtConfig = null; + while (tryAgain) { + Frame f = new Frame(device.getDefaultConfiguration()); + f.setUndecorated(true); + f.setLayout(new BorderLayout()); + capturer = new CapabilitiesCapturer(); + try { + awtConfig = createAwtGraphicsConfiguration(caps, capturer, screen); + QueryCanvas canvas = new QueryCanvas(awtConfig, 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 { + switch (capsToDisable.remove(0)) { + case STEREO: + caps.setStereo(false); + break; + case AA: + caps.setSampleBuffers(false); + break; + case DOUBLE_BUFFER: + caps.setDoubleBuffered(false); + break; + } + awtConfig = null; + } + } + } + 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(); + } + + // FIXME chosenIndex isn't used anymore, used -1 instead of finding it. + JoglGraphicsConfiguration config = new JoglGraphicsConfiguration(chosenCaps, chosenIndex, device); + + + + // 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 + GraphicsConfigInfo gcInf0 = new GraphicsConfigInfo(gct); + gcInf0.setPrivateData(awtConfig); + + synchronized (Canvas3D.graphicsConfigTable) { + Canvas3D.graphicsConfigTable.put(config, gcInf0); + } + + return config; + } + + // Determine whether specified graphics config is supported by pipeline + @Override + 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 + @Override + boolean hasDoubleBuffer(Canvas3D cv) { + if (VERBOSE) System.err.println("JoglPipeline.hasDoubleBuffer()"); + if (VERBOSE) System.err.println(" Returning " + caps(cv).getDoubleBuffered()); + return caps(cv).getDoubleBuffered(); + } + + @Override + boolean hasStereo(Canvas3D cv) { + if (VERBOSE) System.err.println("JoglPipeline.hasStereo()"); + if (VERBOSE) System.err.println(" Returning " + caps(cv).getStereo()); + return caps(cv).getStereo(); + } + + @Override + int getStencilSize(Canvas3D cv) { + if (VERBOSE) System.err.println("JoglPipeline.getStencilSize()"); + if (VERBOSE) System.err.println(" Returning " + caps(cv).getStencilBits()); + return caps(cv).getStencilBits(); + } + + @Override + boolean hasSceneAntialiasingMultisample(Canvas3D cv) { + if (VERBOSE) System.err.println("JoglPipeline.hasSceneAntialiasingMultisample()"); + if (VERBOSE) System.err.println(" Returning " + caps(cv).getSampleBuffers()); + + return caps(cv).getSampleBuffers(); + } + + @Override + 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); + } + + private boolean checkedForGetScreenMethod = false; + private Method getScreenMethod = null; + @Override + 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<Object>() { + @Override + 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. + private final class QueryCanvas extends Canvas { + + private GLDrawable glDrawable; + private ExtendedCapabilitiesChooser chooser; + private boolean alreadyRan; + + private AWTGraphicsConfiguration awtConfig = null; + private JAWTWindow nativeWindow = null; + + private QueryCanvas(AWTGraphicsConfiguration awtConfig, + 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(awtConfig.getAWTGraphicsConfiguration()); + + this.awtConfig = awtConfig; + this.chooser = chooser; + } + + @Override + public void addNotify() { + super.addNotify(); + + nativeWindow = (JAWTWindow)NativeWindowFactory.getNativeWindow(this, awtConfig); + nativeWindow.lockSurface(); + try { + glDrawable = GLDrawableFactory.getFactory(profile).createGLDrawable(nativeWindow); + } + finally { + nativeWindow.unlockSurface(); + } + + glDrawable.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 + private void doQuery() { + if (alreadyRan) + return; + GLContext context = glDrawable.createContext(null); + int res = context.makeCurrent(); + if (res != GLContext.CONTEXT_NOT_CURRENT) { + try { + chooser.init(context); + } finally { + context.release(); + } + } + context.destroy(); + alreadyRan = true; + + glDrawable.setRealized(false); + nativeWindow.destroy(); + } + } + + private static AWTGraphicsConfiguration createAwtGraphicsConfiguration(GLCapabilities capabilities, + CapabilitiesChooser chooser, + AbstractGraphicsScreen screen) { + GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class, GLCapabilities.class); + AWTGraphicsConfiguration awtGraphicsConfiguration = (AWTGraphicsConfiguration) factory.chooseGraphicsConfiguration(capabilities, capabilities, + chooser, screen, VisualIDHolder.VID_UNDEFINED); + return awtGraphicsConfiguration; + } + + // Used in conjunction with IndexCapabilitiesChooser in pixel format + // selection -- see getBestConfiguration + static 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; + } + + @Override + 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 + private final class ContextQuerier extends DefaultGLCapabilitiesChooser + implements ExtendedCapabilitiesChooser { + private Canvas3D canvas; + private boolean done; + + public ContextQuerier(Canvas3D canvas) { + this.canvas = canvas; + } + + public boolean done() { + return done; + } + + @Override + public void init(GLContext context) { + // This is basically a temporary + JoglContext jctx = new JoglContext(context); + GL2 gl = context.getGL().getGL2(); + // Set up various properties + if (getPropertiesFromCurrentContext(jctx, gl)) { + setupCanvasProperties(canvas, jctx, gl); + } + markDone(); + } + + private void markDone() { + synchronized (this) { + done = true; + notifyAll(); + } + } + } + + private void disposeOnEDT(final Frame f) { + Runnable r = new Runnable() { + @Override + 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 + @Override + DrawingSurfaceObject createDrawingSurfaceObject(Canvas3D cv) { + if (VERBOSE) System.err.println("JoglPipeline.createDrawingSurfaceObject()"); + return new JoglDrawingSurfaceObject(cv); + } + + // Method to free the drawing surface object + @Override + 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 + @Override + 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) { + if (ctx.drawable != null) { + // latest state for on- and offscreen drawables + return (GLCapabilities)drawable(ctx.drawable).getChosenGLCapabilities(); + } + else { + // state at the time of 'getBestConfiguration' + return ((JoglGraphicsConfiguration) ctx.graphicsConfiguration).getGLCapabilities(); + } + } + + //---------------------------------------------------------------------- + // General helper routines + // + + private static ThreadLocal<FloatBuffer> nioVertexTemp = new ThreadLocal<FloatBuffer>(); + private static ThreadLocal<DoubleBuffer> nioVertexDoubleTemp = new ThreadLocal<DoubleBuffer>(); + private static ThreadLocal<FloatBuffer> nioColorTemp = new ThreadLocal<FloatBuffer>(); + private static ThreadLocal<ByteBuffer> nioColorByteTemp = new ThreadLocal<ByteBuffer>(); + private static ThreadLocal<FloatBuffer> nioNormalTemp = new ThreadLocal<FloatBuffer>(); + private static ThreadLocal<FloatBuffer[]> nioTexCoordSetTemp = new ThreadLocal<FloatBuffer[]>(); + private static ThreadLocal<FloatBuffer[]> nioVertexAttrSetTemp = new ThreadLocal<FloatBuffer[]>(); + + 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<FloatBuffer> 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<DoubleBuffer> 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<ByteBuffer> 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<FloatBuffer[]> 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; + } +} |