/* * 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.common.nio.Buffers; 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.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.DefaultGLCapabilitiesChooser; import com.jogamp.opengl.FBObject; 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; /** * 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(); // FIXME: Removed call to glColor4f because of segfault issues in Parallels Desktop driver // 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); gl.glDisable(GL.GL_STENCIL_TEST); } // 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) { // FIXME: Removed call to glColor4f because of segfault issues in Parallels Desktop driver // 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); gl.glPushAttrib(GL2.GL_TRANSFORM_BIT); gl.glMatrixMode(GL.GL_TEXTURE); gl.glLoadIdentity(); gl.glPopAttrib(); // 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); int numSamples = MasterControl.getIntegerProperty("j3d.numSamples", 2); caps.setNumSamples(numSamples); } 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 capsToDisable = new ArrayList(); 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() { @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 nioVertexTemp = new ThreadLocal(); private static ThreadLocal nioVertexDoubleTemp = new ThreadLocal(); private static ThreadLocal nioColorTemp = new ThreadLocal(); private static ThreadLocal nioColorByteTemp = new ThreadLocal(); private static ThreadLocal nioNormalTemp = new ThreadLocal(); private static ThreadLocal nioTexCoordSetTemp = new ThreadLocal(); private static ThreadLocal nioVertexAttrSetTemp = new ThreadLocal(); private static FloatBuffer getVertexArrayBuffer(float[] vertexArray) { return getVertexArrayBuffer(vertexArray, true); } private static FloatBuffer getVertexArrayBuffer(float[] vertexArray, boolean copyData) { return getNIOBuffer(vertexArray, nioVertexTemp, copyData); } private static DoubleBuffer getVertexArrayBuffer(double[] vertexArray) { return getVertexArrayBuffer(vertexArray, true); } private static DoubleBuffer getVertexArrayBuffer(double[] vertexArray, boolean copyData) { return getNIOBuffer(vertexArray, nioVertexDoubleTemp, true); } private static FloatBuffer getColorArrayBuffer(float[] colorArray) { return getColorArrayBuffer(colorArray, true); } private static FloatBuffer getColorArrayBuffer(float[] colorArray, boolean copyData) { return getNIOBuffer(colorArray, nioColorTemp, true); } private static ByteBuffer getColorArrayBuffer(byte[] colorArray) { return getColorArrayBuffer(colorArray, true); } private static ByteBuffer getColorArrayBuffer(byte[] colorArray, boolean copyData) { return getNIOBuffer(colorArray, nioColorByteTemp, true); } private static FloatBuffer getNormalArrayBuffer(float[] normalArray) { return getNormalArrayBuffer(normalArray, true); } private static FloatBuffer getNormalArrayBuffer(float[] normalArray, boolean copyData) { return getNIOBuffer(normalArray, nioNormalTemp, true); } private static FloatBuffer[] getTexCoordSetBuffer(Object[] texCoordSet) { return getNIOBuffer(texCoordSet, nioTexCoordSetTemp); } private static FloatBuffer[] getVertexAttrSetBuffer(Object[] vertexAttrSet) { return getNIOBuffer(vertexAttrSet, nioVertexAttrSetTemp); } private static FloatBuffer getNIOBuffer(float[] array, ThreadLocal threadLocal, boolean copyData) { if (array == null) { return null; } FloatBuffer buf = threadLocal.get(); if (buf == null) { buf = Buffers.newDirectFloatBuffer(array.length); threadLocal.set(buf); } else { buf.rewind(); if (buf.remaining() < array.length) { int newSize = Math.max(2 * buf.remaining(), array.length); buf = Buffers.newDirectFloatBuffer(newSize); threadLocal.set(buf); } } if (copyData) { buf.put(array); buf.rewind(); } return buf; } private static DoubleBuffer getNIOBuffer(double[] array, ThreadLocal threadLocal, boolean copyData) { if (array == null) { return null; } DoubleBuffer buf = threadLocal.get(); if (buf == null) { buf = Buffers.newDirectDoubleBuffer(array.length); threadLocal.set(buf); } else { buf.rewind(); if (buf.remaining() < array.length) { int newSize = Math.max(2 * buf.remaining(), array.length); buf = Buffers.newDirectDoubleBuffer(newSize); threadLocal.set(buf); } } if (copyData) { buf.put(array); buf.rewind(); } return buf; } private static ByteBuffer getNIOBuffer(byte[] array, ThreadLocal threadLocal, boolean copyData) { if (array == null) { return null; } ByteBuffer buf = threadLocal.get(); if (buf == null) { buf = Buffers.newDirectByteBuffer(array.length); threadLocal.set(buf); } else { buf.rewind(); if (buf.remaining() < array.length) { int newSize = Math.max(2 * buf.remaining(), array.length); buf = Buffers.newDirectByteBuffer(newSize); threadLocal.set(buf); } } if (copyData) { buf.put(array); buf.rewind(); } return buf; } private static FloatBuffer[] getNIOBuffer(Object[] array, ThreadLocal threadLocal) { if (array == null) { return null; } FloatBuffer[] bufs = threadLocal.get(); // First resize array of FloatBuffers if (bufs == null) { bufs = new FloatBuffer[array.length]; threadLocal.set(bufs); } else if (bufs.length < array.length) { FloatBuffer[] newBufs = new FloatBuffer[array.length]; System.arraycopy(bufs, 0, newBufs, 0, bufs.length); bufs = newBufs; threadLocal.set(bufs); } // Now go down array of arrays, converting each into a direct FloatBuffer for (int i = 0; i < array.length; i++) { float[] cur = (float[]) array[i]; FloatBuffer buf = bufs[i]; if (buf == null) { buf = Buffers.newDirectFloatBuffer(cur.length); bufs[i] = buf; } else { buf.rewind(); if (buf.remaining() < cur.length) { int newSize = Math.max(2 * buf.remaining(), cur.length); buf = Buffers.newDirectFloatBuffer(newSize); bufs[i] = buf; } } buf.put(cur); buf.rewind(); } return bufs; } }