aboutsummaryrefslogtreecommitdiffstats
path: root/src/javax/media/j3d/JoglPipeline.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/javax/media/j3d/JoglPipeline.java')
-rw-r--r--src/javax/media/j3d/JoglPipeline.java8963
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;
+ }
+}