diff options
author | phil <[email protected]> | 2016-11-17 18:48:44 +1300 |
---|---|---|
committer | phil <[email protected]> | 2016-11-17 18:48:44 +1300 |
commit | 7e36472d1c745be2a9ae012059680dcb42508680 (patch) | |
tree | fcfa2a549f39636e130b6f3bc1ac1b3b13d8f8ea /src | |
parent | c53d79e49a6ecb4ef6d36a4b251cdc595b0d792f (diff) |
SparseArray added for performance in gl2es2pipeline
plus a big general code tidy up of the pipeline
Diffstat (limited to 'src')
-rw-r--r-- | src/main/java/org/jogamp/java3d/Jogl2es2Context.java | 31 | ||||
-rw-r--r-- | src/main/java/org/jogamp/java3d/Jogl2es2DEPPipeline.java | 2 | ||||
-rw-r--r-- | src/main/java/org/jogamp/java3d/Jogl2es2Pipeline.java | 708 | ||||
-rw-r--r-- | src/main/java/org/jogamp/java3d/Renderer.java | 17 | ||||
-rw-r--r-- | src/main/java/org/jogamp/java3d/SparseArray.java | 584 |
5 files changed, 824 insertions, 518 deletions
diff --git a/src/main/java/org/jogamp/java3d/Jogl2es2Context.java b/src/main/java/org/jogamp/java3d/Jogl2es2Context.java index c355687..b3f94f4 100644 --- a/src/main/java/org/jogamp/java3d/Jogl2es2Context.java +++ b/src/main/java/org/jogamp/java3d/Jogl2es2Context.java @@ -34,6 +34,7 @@ import com.jogamp.opengl.GL2ES2; import com.jogamp.opengl.GL2ES3;
import com.jogamp.opengl.GLContext;
+
public class Jogl2es2Context extends JoglContext
{
@@ -41,7 +42,7 @@ public class Jogl2es2Context extends JoglContext {
super(context);
}
-
+
public GL2ES2 gl2es2()
{
return context.getGL().getGL2ES2();
@@ -62,19 +63,19 @@ public class Jogl2es2Context extends JoglContext super.setShaderProgram(object);
shaderProgram = object;
shaderProgramId = object == null ? -1 : object.getValue();
- programData = allProgramData.get(new Integer(shaderProgramId));
+ programData = allProgramData.get(shaderProgramId);
if (programData == null)
{
programData = new ProgramData();
- allProgramData.put(new Integer(shaderProgramId), programData);
+ allProgramData.put(shaderProgramId, programData);
}
}
// all buffers created are recorded for each render pass, and for cleanup
- public ArrayList<GeometryArrayRetained> geoToClearBuffers = new ArrayList<>();
+ public ArrayList<GeometryArrayRetained> geoToClearBuffers = new ArrayList<GeometryArrayRetained>();
- public HashMap<Integer, GeometryData> allGeometryData = new HashMap<>();
+ public SparseArray<GeometryData> allGeometryData = new SparseArray<GeometryData>();
public static class GeometryData
{
@@ -91,8 +92,8 @@ public class Jogl2es2Context extends JoglContext public int geoToCoordBufSize = -1;
public int geoToColorBuf = -1;
public int geoToNormalBuf = -1;
- public HashMap<Integer, Integer> geoToTexCoordsBuf = new HashMap<>();
- public HashMap<Integer, Integer> geoToVertAttribBuf = new HashMap<>();
+ public SparseArray<Integer> geoToTexCoordsBuf = new SparseArray<Integer>();
+ public SparseArray<Integer> geoToVertAttribBuf = new SparseArray<Integer>();
//Every thing below relates to interleaved data
public int coordBufId = -1; // if separate
@@ -118,11 +119,11 @@ public class Jogl2es2Context extends JoglContext }
- public HashMap<Integer, ProgramData> allProgramData = new HashMap<>();
+ public SparseArray<ProgramData> allProgramData = new SparseArray<ProgramData>();
public static class ProgramData
{
- public HashMap<String, Integer> progToGenVertAttNameToGenVertAttIndex = new HashMap<>();
+ public HashMap<String, Integer> progToGenVertAttNameToGenVertAttIndex = new HashMap<String, Integer>();
public LocationData programToLocationData = null;// null to indicate need to load
public ByteBuffer programToUBOBB = null;
public int programToUBOBuf = -1;
@@ -153,7 +154,6 @@ public class Jogl2es2Context extends JoglContext public int alphaTestFunction = RenderingAttributes.ALWAYS;
public float alphaTestValue = 0;
public int ignoreVertexColors; //-1 is not set 1,0 bool
-
}
public RenderingData renderingData = new RenderingData();
@@ -207,7 +207,7 @@ public class Jogl2es2Context extends JoglContext public int glNormal = -1;
public int[] glMultiTexCoord = new int[16];
- public HashMap<Integer, Integer> genAttIndexToLoc = new HashMap<>();
+ public SparseArray<Integer> genAttIndexToLoc = new SparseArray<Integer>();
}
@@ -348,7 +348,7 @@ public class Jogl2es2Context extends JoglContext perFrameStats = new Jogl2es2PerFrameStats();
perFrameStats.endOfPrevFrameTime = System.nanoTime();
}
-
+
// texture and raster fill variables
// raster vao and buf are not in the by geom bucket because I don't get given geom
@@ -359,7 +359,6 @@ public class Jogl2es2Context extends JoglContext public int simpleTextureShaderProgramTexCoordLoc = -1;
public int simpleTextureShaderProgramBaseMapLoc = -1;
-
// just a singleton of the handy matrix/array operations
public Jogl2es2MatrixUtil matrixUtil = new Jogl2es2MatrixUtil();
@@ -515,7 +514,6 @@ public class Jogl2es2Context extends JoglContext public static class glLightSourceLocs
{
- public int enabled = -1;
public int position = -1;
public int diffuse = -1;
public int specular = -1;
@@ -528,9 +526,8 @@ public class Jogl2es2Context extends JoglContext public boolean present()
{
- return enabled != -1 || position != -1 || diffuse != -1 || specular != -1 || constantAttenuation != -1
- || linearAttenuation != -1 || quadraticAttenuation != -1 || spotCutoff != -1 || spotExponent != -1
- || spotDirection != -1;
+ return position != -1 || diffuse != -1 || specular != -1 || constantAttenuation != -1 || linearAttenuation != -1
+ || quadraticAttenuation != -1 || spotCutoff != -1 || spotExponent != -1 || spotDirection != -1;
}
}
diff --git a/src/main/java/org/jogamp/java3d/Jogl2es2DEPPipeline.java b/src/main/java/org/jogamp/java3d/Jogl2es2DEPPipeline.java index cf1117c..7e4cccf 100644 --- a/src/main/java/org/jogamp/java3d/Jogl2es2DEPPipeline.java +++ b/src/main/java/org/jogamp/java3d/Jogl2es2DEPPipeline.java @@ -335,7 +335,6 @@ abstract class Jogl2es2DEPPipeline extends Pipeline throw new UnsupportedOperationException("accum not supported in the GL2ES2 pipeline.\n" + VALID_FORMAT_MESSAGE); } - // The following three methods are used in multi-pass case // used for display Lists @Override @@ -373,5 +372,4 @@ abstract class Jogl2es2DEPPipeline extends Pipeline + "System.setProperty(\"j3d.displaylist\", \"false\"); to avoid this issue. \n" + "Please note the recommended solution is to use NIO buffers. \n" + VALID_FORMAT_MESSAGE); } - } diff --git a/src/main/java/org/jogamp/java3d/Jogl2es2Pipeline.java b/src/main/java/org/jogamp/java3d/Jogl2es2Pipeline.java index fefe810..950e17b 100644 --- a/src/main/java/org/jogamp/java3d/Jogl2es2Pipeline.java +++ b/src/main/java/org/jogamp/java3d/Jogl2es2Pipeline.java @@ -93,7 +93,7 @@ import com.jogamp.opengl.GLProfile; import com.jogamp.opengl.Threading; /** - * Concrete implementation of Pipeline class for the JOGL rendering pipeline. + * Concrete implementation of Pipeline class for the GL2ES2 rendering pipeline. */ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline { @@ -116,6 +116,8 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline private static final boolean MINIMISE_NATIVE_SHADER = true; private static final boolean MINIMISE_NATIVE_CALLS_OTHER = true; + // This MUST be true on android fullscreen + // setPostiion on a GLWindow can lock-up if true private static final boolean NEVER_RELEASE_CONTEXT = false; /** @@ -137,19 +139,12 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // Java3D maintains strict control over which threads perform OpenGL work Threading.disableSingleThreading(); - // profile = GLProfile.get(GLProfile.GLES2); // Profile GLES2 is not available on null, but: [GLProfile[GL3bc/GL4bc.hw],... profile = GLProfile.get(GLProfile.GL2ES2); // profile = GLProfile.getMaxProgrammable(true); } - // --------------------------------------------------------------------- - - // - // GeometryArrayRetained methods - // - - // FIXME: big ugly hack for buffer clearing on removal of a geometry + // FIXME: ugly hack for buffer clearing on removal of a geometry public void registerClearBuffers(Context ctx, GeometryArrayRetained geo) { Jogl2es2Context joglesctx = (Jogl2es2Context) ctx; @@ -177,6 +172,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline if (gd != null) { if (gd.geoToIndBuf != -1) + gl.glDeleteBuffers(1, new int[] { gd.geoToIndBuf }, 0); if (gd.geoToCoordBuf != -1) gl.glDeleteBuffers(1, new int[] { gd.geoToCoordBuf }, 0); @@ -191,22 +187,25 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline gl.glDeleteBuffers(bufIds.length, bufIds, 0); } - HashMap<Integer, Integer> tcBufIds = gd.geoToTexCoordsBuf; + SparseArray<Integer> tcBufIds = gd.geoToTexCoordsBuf; if (tcBufIds != null) { - for (Integer tcBufId : tcBufIds.keySet()) + for (int i = 0; i < tcBufIds.size(); i++) { + Integer tcBufId = tcBufIds.get(tcBufIds.keyAt(i)); + if (tcBufId != null) gl.glDeleteBuffers(1, new int[] { tcBufId.intValue() }, 0); } tcBufIds.clear(); } - HashMap<Integer, Integer> vaBufIds = gd.geoToVertAttribBuf; + SparseArray<Integer> vaBufIds = gd.geoToVertAttribBuf; if (vaBufIds != null) { - for (Integer vaBufId : vaBufIds.keySet()) + for (int i = 0; i < vaBufIds.size(); i++) { + Integer vaBufId = vaBufIds.get(vaBufIds.keyAt(i)); if (vaBufId != null) gl.glDeleteBuffers(1, new int[] { vaBufId.intValue() }, 0); } @@ -340,7 +339,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline { if (EXTRA_DEBUGGING) { - System.err.println(" Number of tex coord sets: " + texCoordSetCount); + System.err.println("Number of tex coord sets: " + texCoordSetCount); } if ((vformat & GeometryArray.TEXTURE_COORDINATE_2) != 0) { @@ -435,12 +434,13 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline GeometryData gd = loadAllBuffers(ctx, gl, geo, ignoreVertexColors, vcount, vformat, vformat, verts, startVertex, clrs, startClrs); - // can it change ever? (GeometryArray.ALLOW_REF_DATA_WRITE is just my indicator of this feature) + // GeometryArray.ALLOW_REF_DATA_WRITE is just my indicator of changeability boolean morphable = geo.source.getCapability(GeometryArray.ALLOW_REF_DATA_WRITE) || geo.source.getCapability(GeometryArray.ALLOW_COORDINATE_WRITE); // not required second time around for VAO (except morphable coords) boolean bindingRequired = true; + // Note although we ask for ES2 we can get ES3, which demands a VAO or nothing renders if (ctx.gl2es3() != null) { if (gd.vaoId == -1) @@ -460,31 +460,28 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline outputErrors(ctx); } - // refill the buffers in case of writeable data + // refill the buffers in case of writeable data (morphable) if (locs.glVertex != -1) { - if (gd.geoToCoordBuf == -1) { new Throwable("Buffer load issue!").printStackTrace(); } else { - - // a good cDirty + // rather than the morphable system above we should be able to use cDirty, but it appears to be wrong // if ((cDirty & GeometryArrayRetained.COORDINATE_CHANGED) != 0) if (morphable) { - verts.position(startVertex); - // Sometime the FloatBuffer is swapped out for bigger or smaller! or is that ok? + // Sometime the FloatBuffer is swapped out for bigger or smaller if (gd.geoToCoordBufSize != verts.remaining()) { System.err.println("Morphable buffer changed " + gd.geoToCoordBufSize + " != " + verts.remaining() + " un indexed ((GeometryArray) geo.source) " + ((GeometryArray) geo.source).getName() + " " + geo.source + ", this is not nessasarily a problem"); - int prevBufId1 = gd.geoToCoordBuf1;// record to delete after re-bind + int prevBufId1 = gd.geoToCoordBuf1;// record these in order to delete after re-bind int prevBufId2 = gd.geoToCoordBuf2; int[] tmp = new int[2]; @@ -550,9 +547,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline ctx.perFrameStats.glBufferSubData++; } } - } - } else { @@ -572,7 +567,8 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline } } - // notice morphables must always rebind each frame as coord buffers are swapped + // notice morphables must always rebind each frame as coord buffers are swapped, so the vao + // (if it is bound points to the previous buffer) if (bindingRequired || morphable) { // always do coords @@ -592,7 +588,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline if (bindingRequired) { - if (((vformat & GeometryArray.COLOR) != 0) && locs.glColor != -1 && !ignoreVertexColors) { if (gd.geoToColorBuf == -1) @@ -616,7 +611,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline } else if (locs.glColor != -1) { - // ignoreVertexcolors will have been set in FFP now as the glColors is unbound + // ignoreVertexcolors will have been set in FFP, now as the glColors is unbound gl.glDisableVertexAttribArray(locs.glColor); if (OUTPUT_PER_FRAME_STATS) ctx.perFrameStats.glDisableVertexAttribArray++; @@ -653,7 +648,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline if ((vformat & GeometryArray.VERTEX_ATTRIBUTES) != 0) { - int vAttrOffset = startVertex + vAttrOff; for (int index = 0; index < vertexAttrCount; index++) { @@ -711,9 +705,8 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline { int primType = 0; - //FIXME: GL_LINE and GL_LINE_STRIP simply go from one vertex to the next drawing a line between - // each pair, what I want is a line between each set of 3 (that are not jumpers) - + // FIXME: GL_LINE and GL_LINE_STRIP simply go from one vertex to the next drawing a line between + // each pair, what I want is a line between each set of 3 (that are not degenerate) if (ctx.polygonMode == PolygonAttributes.POLYGON_LINE) geo_type = GeometryRetained.GEO_TYPE_LINE_STRIP_SET; @@ -747,7 +740,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline else { //need to override if polygonAttributes says so - if (ctx.polygonMode == PolygonAttributes.POLYGON_LINE) geo_type = GeometryRetained.GEO_TYPE_LINE_SET; else if (ctx.polygonMode == PolygonAttributes.POLYGON_POINT) @@ -756,7 +748,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline switch (geo_type) { case GeometryRetained.GEO_TYPE_QUAD_SET: - throw new UnsupportedOperationException("QuadArray.\n" + VALID_FORMAT_MESSAGE); + System.err.println("QuadArray.\n" + VALID_FORMAT_MESSAGE); case GeometryRetained.GEO_TYPE_TRI_SET: gl.glDrawArrays(GL2ES2.GL_TRIANGLES, 0, vcount); break; @@ -837,9 +829,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline } } - // used by GeometryArray by Reference with NIO buffer - // non indexed - + // used by GeometryArray by Reference with NIO buffer non indexed @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, @@ -898,7 +888,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline } else if (byteColorsDefined) { - // FIXME: doubles not supported for now + // FIXME: bytes not supported for now throw new UnsupportedOperationException("byteColorsDefined.\n" + VALID_FORMAT_MESSAGE); // if (cbdata != null) // bclrs = getColorArrayBuffer(cbdata); @@ -929,8 +919,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline cdirty, sarray, strip_len, start_array); } - // used by GeometryArray by Reference with java arrays - // non indexed + // used by GeometryArray by Reference with java arrays non indexed @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, @@ -1046,12 +1035,13 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline boolean vattrDefined = ((vdefined & GeometryArrayRetained.VATTR_FLOAT) != 0); boolean textureDefined = ((vdefined & GeometryArrayRetained.TEXCOORD_FLOAT) != 0); - // can it change ever? (GeometryArray.ALLOW_REF_DATA_WRITE is just my indicator of this feature) + // GeometryArray.ALLOW_REF_DATA_WRITE is just my indicator of changeability boolean morphable = geo.source.getCapability(GeometryArray.ALLOW_REF_DATA_WRITE) || geo.source.getCapability(GeometryArray.ALLOW_COORDINATE_WRITE); // not required second time around for VAO (except morphable coords) boolean bindingRequired = true; + // Note although we ask for ES2 we can get ES3, which demands a VAO or nothing renders if (ctx.gl2es3() != null) { if (gd.vaoId == -1) @@ -1076,28 +1066,26 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline { if (floatCoordDefined) { - if (gd.geoToCoordBuf == -1) { new Throwable("Buffer load issue!").printStackTrace(); } else { - - // a good cDirty + // rather than the morphable system above we should be able to use cDirty, but it appears to be wrong // if ((cDirty & GeometryArrayRetained.COORDINATE_CHANGED) != 0) if (morphable) { int coordoff = 3 * initialCoordIndex; fverts.position(coordoff); - // Sometime the FloatBuffer is swapped out for bigger or smaller! or is that ok? + // Sometime the FloatBuffer is swapped out for bigger or smaller if (gd.geoToCoordBufSize != fverts.remaining()) { System.err.println("Morphable buffer changed " + gd.geoToCoordBufSize + " != " + fverts.remaining() + " un indexed ((GeometryArray) geo.source) " + ((GeometryArray) geo.source).getName() + " " + geo.source + ", this is not nessasarily a problem"); - int prevBufId1 = gd.geoToCoordBuf1;// record to delete after re-bind + int prevBufId1 = gd.geoToCoordBuf1;// record these in order to delete after re-bind int prevBufId2 = gd.geoToCoordBuf2; int[] tmp = new int[2]; @@ -1220,7 +1208,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline { FloatBuffer vertexAttrs = vertexAttrBufs[index]; vertexAttrs.position(0); - HashMap<Integer, Integer> bufIds = gd.geoToVertAttribBuf; + SparseArray<Integer> bufIds = gd.geoToVertAttribBuf; Integer bufId = bufIds.get(index); gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, bufId.intValue()); gl.glBufferSubData(GL2ES2.GL_ARRAY_BUFFER, 0, vertexAttrs.remaining() * Float.SIZE / 8, vertexAttrs); @@ -1242,7 +1230,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline { FloatBuffer buf = (FloatBuffer) texCoords[texSet]; buf.position(0); - HashMap<Integer, Integer> bufIds = gd.geoToTexCoordsBuf; + SparseArray<Integer> bufIds = gd.geoToTexCoordsBuf; Integer bufId = bufIds.get(texUnit); gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, bufId.intValue()); gl.glBufferSubData(GL2ES2.GL_ARRAY_BUFFER, 0, buf.remaining() * Float.SIZE / 8, buf); @@ -1356,7 +1344,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline Integer attribLoc = locs.genAttIndexToLoc.get(index); if (attribLoc != null && attribLoc.intValue() != -1) { - HashMap<Integer, Integer> bufIds = gd.geoToVertAttribBuf; + SparseArray<Integer> bufIds = gd.geoToVertAttribBuf; if (bufIds == null) { new Throwable("Buffer load issue!").printStackTrace(); @@ -1397,7 +1385,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline FloatBuffer buf = (FloatBuffer) texCoords[texSet]; buf.position(0); - HashMap<Integer, Integer> bufIds = gd.geoToTexCoordsBuf; + SparseArray<Integer> bufIds = gd.geoToTexCoordsBuf; if (bufIds == null) { new Throwable("Buffer load issue!").printStackTrace(); @@ -1431,9 +1419,8 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline { int primType = 0; - //FIXME: GL_LINE and GL_LINE_STRIP simply go from one vertex to the next drawing a line between - // each pair, what I want is a line between each set of 3 (that are not jumpers) - + // FIXME: GL_LINE and GL_LINE_STRIP simply go from one vertex to the next drawing a line between + // each pair, what I want is a line between each set of 3 (that are not degenerate) if (ctx.polygonMode == PolygonAttributes.POLYGON_LINE) geo_type = GeometryRetained.GEO_TYPE_LINE_STRIP_SET; @@ -1467,7 +1454,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline else { // need to override if polygonAttributes says so - if (ctx.polygonMode == PolygonAttributes.POLYGON_LINE) geo_type = GeometryRetained.GEO_TYPE_LINE_SET; else if (ctx.polygonMode == PolygonAttributes.POLYGON_POINT) @@ -1476,7 +1462,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline switch (geo_type) { case GeometryRetained.GEO_TYPE_QUAD_SET: - throw new UnsupportedOperationException("QuadArray.\n" + VALID_FORMAT_MESSAGE); + System.err.println("QuadArray.\n" + VALID_FORMAT_MESSAGE); case GeometryRetained.GEO_TYPE_TRI_SET: gl.glDrawArrays(GL2ES2.GL_TRIANGLES, 0, vertexCount); break; @@ -1493,44 +1479,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline if (OUTPUT_PER_FRAME_STATS) ctx.perFrameStats.glDrawArrays++; } - - /* unbound in setRenderMode now - if (gl.isGL2ES3()) - { - GL2ES3 gl2es3 = (GL2ES3) gl; - gl2es3.glBindVertexArray(0); - if (DO_OUTPUT_ERRORS) - outputErrors(ctx); - }*/ - - //TODO: do I need to unbind these things, it seems fine not to - /* - if (vattrDefined) - { - for (int i = 0; i < vertexAttrCount; i++) - { - Integer attribLoc = locs.genAttIndexToLoc.get(i); - if (attribLoc != null && attribLoc.intValue() != -1) - { - gl.glDisableVertexAttribArray(attribLoc); - if (OUTPUT_PER_FRAME_STATS) - ctx.perFrameStats.glDisableVertexAttribArray++; - } - } - } - - if (textureDefined) - { - for (int i = 0; i < locs.glMultiTexCoord.length; i++) - { - if (locs.glMultiTexCoord[i] != -1) - { - gl.glDisableVertexAttribArray(locs.glMultiTexCoord[i]); - if (OUTPUT_PER_FRAME_STATS) - ctx.perFrameStats.glDisableVertexAttribArray++; - } - } - }*/ } else { @@ -1649,7 +1597,8 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline coordoff += 4; } else - { // Handle the case of executeInterleaved 3f + { + // Handle the case of executeInterleaved 3f stride += 3; normoff += 3; coordoff += 3; @@ -1744,12 +1693,13 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline GeometryData gd = loadAllBuffers(ctx, gl, geo, ignoreVertexColors, vcount, vformat, vformat, verts, 0, clrs, 0); - // can it change ever? (GeometryArray.ALLOW_REF_DATA_WRITE is just my indicator of this feature) + // GeometryArray.ALLOW_REF_DATA_WRITE is just my indicator of changeability boolean morphable = geo.source.getCapability(GeometryArray.ALLOW_REF_DATA_WRITE) || geo.source.getCapability(GeometryArray.ALLOW_COORDINATE_WRITE); // not required second time around for VAO (except morphable coords) boolean bindingRequired = true; + // Note although we ask for ES2 we can get ES3, which demands a VAO or nothing renders if (ctx.gl2es3() != null) { if (gd.vaoId == -1) @@ -1778,21 +1728,19 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline } else { - - // a good cDirty // if ((cDirty & GeometryArrayRetained.COORDINATE_CHANGED) != 0) if (morphable) { verts.position(0); - // Sometime the FloatBuffer is swapped out for bigger or smaller! or is that ok? + // Sometime the FloatBuffer is swapped out for bigger or smaller if (gd.geoToCoordBufSize != verts.remaining()) { System.err.println("Morphable buffer changed " + gd.geoToCoordBufSize + " != " + verts.remaining() + " un indexed ((GeometryArray) geo.source) " + ((GeometryArray) geo.source).getName() + " " + geo.source + ", this is not nessasarily a problem"); - int prevBufId1 = gd.geoToCoordBuf1;// record to delete after re-bind + int prevBufId1 = gd.geoToCoordBuf1;// record these in order to delete after re-bind int prevBufId2 = gd.geoToCoordBuf2; int[] tmp = new int[2]; @@ -1899,7 +1847,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline if (bindingRequired) { - if (((vformat & GeometryArray.COLOR) != 0) && locs.glColor != -1 && !ignoreVertexColors) { if (gd.geoToColorBuf == -1) @@ -2381,13 +2328,13 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline boolean vattrDefined = ((vdefined & GeometryArrayRetained.VATTR_FLOAT) != 0); boolean textureDefined = ((vdefined & GeometryArrayRetained.TEXCOORD_FLOAT) != 0); - //can it change ever? (GeometryArray.ALLOW_REF_DATA_WRITE is just my indicator of this feature) + // GeometryArray.ALLOW_REF_DATA_WRITE is just my indicator of changeability boolean morphable = geo.source.getCapability(GeometryArray.ALLOW_REF_DATA_WRITE) || geo.source.getCapability(GeometryArray.ALLOW_COORDINATE_WRITE); - // not required second time around for VAO - // however as morphables coords are swapped they always get rebound each draw + // not required second time around for VAO (except morphable coords) boolean bindingRequired = true; + // Note although we ask for ES2 we can get ES3, which demands a VAO or nothing renders if (ctx.gl2es3() != null) { if (gd.vaoId == -1) @@ -2412,8 +2359,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline { if (floatCoordDefined) { - // Building of buffers etc and index buffers should really take place not on the j3d thread if possible - + // TODO: Building of buffers etc and index buffers should really take place not on the j3d thread if possible if (gd.geoToCoordBuf == -1) { new Throwable("Buffer load issue!").printStackTrace(); @@ -2424,14 +2370,14 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline { fverts.position(0); - // Sometime the FloatBuffer is swapped out for bigger or smaller! or is that ok? + // Sometime the FloatBuffer is swapped out for bigger or smaller if (gd.geoToCoordBufSize != fverts.remaining()) { System.err.println("Morphable buffer changed " + gd.geoToCoordBufSize + " != " + fverts.remaining() + " ((GeometryArray) geo.source) " + ((GeometryArray) geo.source).getName() + " " + geo.source); - int prevBufId1 = gd.geoToCoordBuf1;// keep to delete below - int prevBufId2 = gd.geoToCoordBuf2;// keep to delete below + int prevBufId1 = gd.geoToCoordBuf1;// record these in order to delete below + int prevBufId2 = gd.geoToCoordBuf2; int[] tmp = new int[2]; gl.glGenBuffers(2, tmp, 0); @@ -2554,7 +2500,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline { FloatBuffer vertexAttrs = vertexAttrBufs[index]; vertexAttrs.position(0); - HashMap<Integer, Integer> bufIds = gd.geoToVertAttribBuf; + SparseArray<Integer> bufIds = gd.geoToVertAttribBuf; Integer bufId = bufIds.get(index); gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, bufId.intValue()); gl.glBufferSubData(GL2ES2.GL_ARRAY_BUFFER, 0, vertexAttrs.remaining() * Float.SIZE / 8, vertexAttrs); @@ -2576,7 +2522,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline { FloatBuffer buf = (FloatBuffer) texCoords[texSet]; buf.position(0); - HashMap<Integer, Integer> bufIds = gd.geoToTexCoordsBuf; + SparseArray<Integer> bufIds = gd.geoToTexCoordsBuf; Integer bufId = bufIds.get(texUnit); gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, bufId.intValue()); gl.glBufferSubData(GL2ES2.GL_ARRAY_BUFFER, 0, buf.remaining() * Float.SIZE / 8, buf); @@ -2688,7 +2634,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline Integer attribLoc = locs.genAttIndexToLoc.get(index); if (attribLoc != null && attribLoc.intValue() != -1) { - HashMap<Integer, Integer> bufIds = gd.geoToVertAttribBuf; + SparseArray<Integer> bufIds = gd.geoToVertAttribBuf; if (bufIds == null) { new Throwable("Buffer load issue!").printStackTrace(); @@ -2730,7 +2676,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline FloatBuffer buf = (FloatBuffer) texCoords[texSet]; buf.position(0); - HashMap<Integer, Integer> bufIds = gd.geoToTexCoordsBuf; + SparseArray<Integer> bufIds = gd.geoToTexCoordsBuf; if (bufIds == null) { new Throwable("Buffer load issue!").printStackTrace(); @@ -2753,7 +2699,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline } } } - } // general catch all @@ -2838,12 +2783,12 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline int count = sarray[i]; int indBufId = stripInd[i]; - //type Specifies the type of the values in indices. Must be + // type Specifies the type of the values in indices. Must be // GL_UNSIGNED_BYTE or GL_UNSIGNED_SHORT. - // Apparently ES3 has included this guy now, so I'm a bit commited to it - //https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDrawElements.xml - //This restriction is relaxed when GL_OES_element_index_uint is supported. - //GL_UNSIGNED_INT + // Apparently ES3 has included this GL_UNSIGNED_INT + // https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDrawElements.xml + // This restriction is relaxed when GL_OES_element_index_uint is supported. + // GL_UNSIGNED_INT gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, indBufId); gl.glDrawElements(primType, count, GL2ES2.GL_UNSIGNED_SHORT, 0); @@ -2854,7 +2799,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline ctx.perFrameStats.glDrawStripElementsStrips++; } - // gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, 0); if (OUTPUT_PER_FRAME_STATS) ctx.perFrameStats.glDrawStripElements++; @@ -2933,55 +2877,14 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline ctx.perFrameStats.glDrawElements++; } - - /* unbound in setRenderMode now - if (gl.isGL2ES3()) - { - GL2ES3 gl2es3 = (GL2ES3) gl; - gl2es3.glBindVertexArray(0); - if (DO_OUTPUT_ERRORS) - outputErrors(ctx); - }*/ - - //TODO: are these unbinds needed, seems fine without them - /* - if (vattrDefined) - { - for (int i = 0; i < vertexAttrCount; i++) - { - Integer attribLoc = locs.genAttIndexToLoc.get(i); - if (attribLoc != null && attribLoc.intValue() != -1) - { - gl.glDisableVertexAttribArray(attribLoc); - if (OUTPUT_PER_FRAME_STATS) - ctx.perFrameStats.glDisableVertexAttribArray++; - } - } - } - - if (textureDefined) - { - for (int i = 0; i < locs.glMultiTexCoord.length; i++) - { - if (locs.glMultiTexCoord[i] != -1) - { - gl.glDisableVertexAttribArray(locs.glMultiTexCoord[i]); - if (OUTPUT_PER_FRAME_STATS) - ctx.perFrameStats.glDisableVertexAttribArray++; - } - } - }*/ - } else - { if (!NO_PROGRAM_WARNING_GIVEN) System.err.println("Execute called with no shader Program in use!"); NO_PROGRAM_WARNING_GIVEN = true; } if (DO_OUTPUT_ERRORS) - outputErrors(ctx); } @@ -3008,8 +2911,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline if (OUTPUT_PER_FRAME_STATS) ctx.perFrameStats.setFFPAttributes++; - // removed if (ATTEMPT_UBO && gl.isGL2ES3())... - // if shader hasn't changed location of uniform I don't need to reset these (they are cleared to -1 at the start of each swap) if (locs.glProjectionMatrix != -1) { @@ -3382,8 +3283,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline } } - // NOTE water app shows multiple light calculations - // record for the next loop through FFP ctx.prevShaderProgram = shaderProgramId; if (DO_OUTPUT_ERRORS) @@ -3400,7 +3299,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline private static void loadLocs(Jogl2es2Context ctx, GL2ES2 gl) { ProgramData pd = ctx.programData; - if (pd.programToLocationData == null) { LocationData locs = new LocationData(); @@ -3412,8 +3310,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // shader program can be disabled, but locs still called if (shaderProgramId != -1) { - // Removed if(ATTEMPT_UBO && gl.isGL2ES3())... - locs.glProjectionMatrix = gl.glGetUniformLocation(shaderProgramId, "glProjectionMatrix"); locs.glProjectionMatrixInverse = gl.glGetUniformLocation(shaderProgramId, "glProjectionMatrixInverse"); locs.glModelMatrix = gl.glGetUniformLocation(shaderProgramId, "glModelMatrix"); @@ -3446,8 +3342,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline locs.numberOfLights = gl.glGetUniformLocation(shaderProgramId, "numberOfLights"); - //lights, notice the vertex attribute is made of a string concat - // possibly in es you can't use an array of struct to get locs? + // lights, notice the vertex attribute is made of a string concat for (int i = 0; i < locs.glLightSource.length; i++) { locs.glLightSource[i] = new glLightSourceLocs(); @@ -3495,7 +3390,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline pd.programToLocationData = locs; } - } private static GeometryData loadAllBuffers(Jogl2es2Context ctx, GL2ES2 gl, GeometryArrayRetained geo, boolean ignoreVertexColors, @@ -3556,15 +3450,12 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline if (OUTPUT_PER_FRAME_STATS) ctx.perFrameStats.glBufferData++; - } if (!ignoreVertexColors) { - if (gd.geoToColorBuf == -1) { - if (fclrs != null) { if (fclrs != fverts) @@ -3587,7 +3478,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline if (OUTPUT_PER_FRAME_STATS) ctx.perFrameStats.glBufferData++; } - } } @@ -3719,10 +3609,10 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline FloatBuffer vertexAttrs = vertexAttrBufs[index]; vertexAttrs.position(0); - HashMap<Integer, Integer> bufIds = gd.geoToVertAttribBuf; + SparseArray<Integer> bufIds = gd.geoToVertAttribBuf; if (bufIds == null) { - bufIds = new HashMap<Integer, Integer>(); + bufIds = new SparseArray<Integer>(); gd.geoToVertAttribBuf = bufIds; } @@ -3759,10 +3649,10 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline FloatBuffer buf = (FloatBuffer) texCoords[texSet]; buf.position(0); - HashMap<Integer, Integer> bufIds = gd.geoToTexCoordsBuf; + SparseArray<Integer> bufIds = gd.geoToTexCoordsBuf; if (bufIds == null) { - bufIds = new HashMap<Integer, Integer>(); + bufIds = new SparseArray<Integer>(); gd.geoToTexCoordsBuf = bufIds; } @@ -3800,8 +3690,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // System.err.println("JoglPipeline.setVertexFormat()"); } - // called by the 2 executes above - + // --------------------------------------------------------------------- // Native method for readRaster @Override void readRaster(Context ctx, int type, int xSrcOffset, int ySrcOffset, int width, int height, int hCanvas, int imageDataType, @@ -4423,8 +4312,8 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline if (OUTPUT_PER_FRAME_STATS) ((Jogl2es2Context) ctx).perFrameStats.bindGLSLVertexAttrName++; - //GL2ES2 gl = context(ctx).getGL().getGL2ES2(); - //gl.glBindAttribLocation(unbox(shaderProgramId), attrIndex + VirtualUniverse.mc.glslVertexAttrOffset, attrName); + // GL2ES2 gl = context(ctx).getGL().getGL2ES2(); + // gl.glBindAttribLocation(unbox(shaderProgramId), attrIndex + VirtualUniverse.mc.glslVertexAttrOffset, attrName); // record this for later, we'll get real locations in the locationData setup int progId = unbox(shaderProgramId); @@ -4715,12 +4604,11 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // --------------------------------------------------------------------- + private static final Vector4f black = new Vector4f(); + // // DirectionalLightRetained methods // - - private static final Vector4f black = new Vector4f(); - @Override void updateDirectionalLight(Context ctx, int lightSlot, float red, float green, float blue, float dirx, float diry, float dirz) { @@ -4731,34 +4619,11 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline if (OUTPUT_PER_FRAME_STATS) ((Jogl2es2Context) ctx).perFrameStats.updateDirectionalLight++; - /* GL2 gl = context(ctx).getGL().getGL2(); - //GL2ES2 gl = context(ctx).getGL().getGL2ES2(); - // OK ES2 requires lights to be handed across manually - // so once again just force it in there and assume shader has it - - int lightNum = GL2ES2.GL_LIGHT0 + lightSlot; - float[] values = new float[4]; - - values[0] = red; - values[1] = green; - values[2] = blue; - values[3] = 1.0f; - gl.glLightfv(lightNum, GL2ES2.GL_DIFFUSE, values, 0); - gl.glLightfv(lightNum, GL2ES2.GL_SPECULAR, values, 0); - values[0] = -dirx; - values[1] = -diry; - values[2] = -dirz; - values[3] = 0.0f; - gl.glLightfv(lightNum, GL2ES2.GL_POSITION, values, 0); - gl.glLightfv(lightNum, GL2ES2.GL_AMBIENT, black, 0); - gl.glLightf(lightNum, GL2ES2.GL_POSITION, 1.0f); - gl.glLightf(lightNum, GL2ES2.GL_LINEAR_ATTENUATION, 0.0f); - gl.glLightf(lightNum, GL2ES2.GL_QUADRATIC_ATTENUATION, 0.0f); - gl.glLightf(lightNum, GL2ES2.GL_SPOT_EXPONENT, 0.0f); - gl.glLightf(lightNum, GL2ES2.GL_SPOT_CUTOFF, 180.0f);*/ - Jogl2es2Context joglesctx = ((Jogl2es2Context) ctx); + // note the current state of MV MUST be used by the lights when setting position! + // https://www.opengl.org/discussion_boards/showthread.php/168706-Light-Position-in-eye-s-cordinate + // note can't use the modelview as it's calced late //TODO:? possibly directional should only take the view mat, but surely I'd get a blank model?? @@ -4796,7 +4661,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // // 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) @@ -4809,7 +4673,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline Jogl2es2Context joglesctx = ((Jogl2es2Context) ctx); // note the current state of MV MUST be used by the lights when setting position! - //https://www.opengl.org/discussion_boards/showthread.php/168706-Light-Position-in-eye-s-cordinate + // https://www.opengl.org/discussion_boards/showthread.php/168706-Light-Position-in-eye-s-cordinate // note can't use the modelview as it's calced late Vector4f lightPos = joglesctx.matrixUtil.transform(joglesctx.currentModelMat, joglesctx.currentViewMat, posx, posy, posz, 1.0f); @@ -4845,7 +4709,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // // 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) @@ -4898,7 +4761,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // // ExponentialFogRetained methods // - @Override void updateExponentialFog(Context ctx, float red, float green, float blue, float density) { @@ -4920,7 +4782,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // // LinearFogRetained methods // - @Override void updateLinearFog(Context ctx, float red, float green, float blue, double fdist, double bdist) { @@ -4943,7 +4804,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // native method for disabling fog @Override - void disableFog(Context ctx) { if (VERBOSE) @@ -4956,7 +4816,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline } // native method for setting fog enable flag - @Override void setFogEnableFlag(Context ctx, boolean enable) { @@ -4968,6 +4827,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline Jogl2es2Context joglesctx = ((Jogl2es2Context) ctx); joglesctx.fogData.fogEnabled = enable ? 1 : 0; } + // --------------------------------------------------------------------- // @@ -4991,7 +4851,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // native method for setting default LineAttributes @Override - void resetLineAttributes(Context ctx) { if (VERBOSE) @@ -5010,7 +4869,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // // 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, @@ -5085,7 +4943,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // native method for setting default ColoringAttributes @Override - void resetColoringAttributes(Context ctx, float r, float g, float b, float a, boolean enableLight) { if (VERBOSE) @@ -5108,7 +4965,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // interesting as Points are how particles are done properly!! // http://stackoverflow.com/questions/3497068/textured-points-in-opengl-es-2-0 // http://stackoverflow.com/questions/7237086/opengl-es-2-0-equivalent-for-es-1-0-circles-using-gl-point-smooth - @Override void updatePointAttributes(Context ctx, float pointSize, boolean pointAntialiasing) { @@ -5144,17 +5000,13 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline Jogl2es2Context joglesctx = ((Jogl2es2Context) ctx); joglesctx.pointSize = 1.0f; - // GL2ES2 gl = ((JoglesContext) ctx).gl2es2(); - // bug in desktop requiring this to be set still - // gl.glDisable(0x8642);//GL_VERTEX_PROGRAM_POINT_SIZE - // gl.glDisable(34913);//GL.GL_POINT_SPRITE); } + // --------------------------------------------------------------------- // // PolygonAttributesRetained methods // - @Override void updatePolygonAttributes(Context ctx, int polygonMode, int cullFace, boolean backFaceNormalFlip, float polygonOffset, float polygonOffsetFactor) @@ -5215,7 +5067,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // native method for setting default PolygonAttributes @Override - void resetPolygonAttributes(Context ctx) { if (VERBOSE) @@ -5255,7 +5106,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // // RenderingAttributesRetained methods // - @Override void updateRenderingAttributes(Context ctx, boolean depthBufferWriteEnableOverride, boolean depthBufferEnableOverride, boolean depthBufferEnable, boolean depthBufferWriteEnable, int depthTestFunction, float alphaTestValue, int alphaTestFunction, @@ -5331,7 +5181,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline } else { - // TODO: simple test use alpha blending instead of testing joglesctx.renderingData.alphaTestEnabled = true; joglesctx.renderingData.alphaTestFunction = getFunctionValue(alphaTestFunction); joglesctx.renderingData.alphaTestValue = alphaTestValue; @@ -5364,7 +5213,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline if (MINIMISE_NATIVE_CALLS_OTHER) joglesctx.gl_state.glEnableGL_STENCIL_TEST = true; } - } else { @@ -5383,10 +5231,8 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // native method for setting default RenderingAttributes @Override - void resetRenderingAttributes(Context ctx, boolean depthBufferWriteEnableOverride, boolean depthBufferEnableOverride) { - if (VERBOSE) System.err.println("JoglPipeline.resetRenderingAttributes()"); if (OUTPUT_PER_FRAME_STATS) @@ -5530,9 +5376,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline if (MINIMISE_NATIVE_CALLS_TRANSPARENCY) joglesctx.gl_state.glEnableGL_BLEND = false; } - } - } // @@ -5554,8 +5398,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // native method for setting default TextureAttributes @Override - - // part of TUS updateNative void resetTextureAttributes(Context ctx) { if (VERBOSE) @@ -5575,11 +5417,11 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline @Override void resetTexCoordGeneration(Context ctx) { + // TexCoordGeneration must be done in shaders // if (VERBOSE) // System.err.println("JoglPipeline.resetTexCoordGeneration()"); // if (OUTPUT_PER_FRAME_STATS) // ((JoglesContext) ctx).perFrameStats.resetTexCoordGeneration++; - } // --------------------------------------------------------------------- @@ -5587,7 +5429,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // // TextureUnitStateRetained methods // - @Override void updateTextureUnitState(Context ctx, int index, boolean enable) { @@ -5610,7 +5451,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline joglesContext.gl_state.glActiveTexture = (index + GL2ES2.GL_TEXTURE0); } } - } // --------------------------------------------------------------------- @@ -5619,7 +5459,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // TextureRetained methods // Texture2DRetained methods // - @Override void bindTexture2D(Context ctx, int objectId, boolean enable) { @@ -5663,7 +5502,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline 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 */ + // Note: useAutoMipMap is not use for SubImage in the jogl pipe if (VERBOSE) System.err.println("JoglPipeline.updateTexture2DSubImage()"); @@ -5765,7 +5604,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // // TextureCubeMapRetained methods // - @Override void bindTextureCubeMap(Context ctx, int objectId, boolean enable) { @@ -5806,6 +5644,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline 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) { + // PJ why is this the case? throw new UnsupportedOperationException(); } @@ -5908,7 +5747,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline assert false; } - // FIXME: sky goes black if this is the case (no mipmap) + // FIXME: geometries go black if this is the case (no mipmap) // so to disable automipmap, must set it to false in texture I guess? // see above glGenMipMap once on pure ES2 (if on pure ES2?) if (useAutoMipMap) @@ -5938,7 +5777,8 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline break; case ImageComponentRetained.TYPE_BYTE_ABGR: if (isExtensionAvailable.GL_EXT_abgr(gl)) - { // If its zero, should never come here! + { + // If its zero, should never come here! format = GL2.GL_ABGR_EXT; } else @@ -6003,7 +5843,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline internalFormat = imageFormat; format = -1;// indicate compressed break; - ///////////////////////////////////// PJPJPJ////////////////////////////// case ImageComponentRetained.TYPE_USHORT_GRAY: case ImageComponentRetained.TYPE_INT_BGR: case ImageComponentRetained.TYPE_INT_RGB: @@ -6022,7 +5861,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline } else { - if (format == -1) { ByteBuffer bb = (ByteBuffer) data; @@ -6059,7 +5897,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline } } } - } } else if ((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) @@ -6082,7 +5919,8 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline format = GL2ES2.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: + // 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: @@ -6097,7 +5935,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline if (forceAlphaToOne) { // this is probably fine - //new Throwable("forceAlphaToOne").printStackTrace(); + // new Throwable("forceAlphaToOne").printStackTrace(); } if (dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) @@ -6130,7 +5968,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline if (imgXOffset > 0 || (width < tilew)) { // PJ not sure what should be happening here - //new Throwable("forceAlphaToOne").printStackTrace(); + // new Throwable("(imgXOffset > 0 || (width < tilew))").printStackTrace(); } int internalFormat = 0; @@ -6178,7 +6016,8 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline break; case ImageComponentRetained.TYPE_BYTE_ABGR: if (isExtensionAvailable.GL_EXT_abgr(gl)) - { // If its zero, should never come here! + { + // If its zero, should never come here! format = GL2.GL_ABGR_EXT; numBytes = 4; } @@ -6243,7 +6082,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline boolean forceAlphaToOne = false; switch (imageFormat) { - /* GL_BGR */ + // GL_BGR case ImageComponentRetained.TYPE_INT_BGR: /* Assume XBGR format */ format = GL2ES2.GL_RGBA; type = GL2.GL_UNSIGNED_INT_8_8_8_8_REV; @@ -6347,41 +6186,16 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline case Texture.BASE_LEVEL_LINEAR: gl.glTexParameteri(target, GL2ES2.GL_TEXTURE_MAG_FILTER, GL2ES2.GL_LINEAR); break; - /* case Texture.LINEAR_SHARPEN: - // We should never get here as we've disabled the TEXTURE_SHARPEN feature - // gl.glTexParameteri(target, GL2ES2.GL_TEXTURE_MAG_FILTER, - // GL2ES2.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, GL2ES2.GL_TEXTURE_MAG_FILTER, - // GL2ES2.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, GL2ES2.GL_TEXTURE_MAG_FILTER, - // GL2ES2.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, GL2ES2.GL_TEXTURE_MAG_FILTER, - // GL2ES2.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, GL2ES2.GL_TEXTURE_MAG_FILTER, - // GL2ES2.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, GL2ES2.GL_TEXTURE_MAG_FILTER, - // GL2ES2.GL_LINEAR_DETAIL_ALPHA_SGIS); - break; - case Texture.FILTER4: - // We should never get here as we've disabled the FILTER4 feature - // gl.glTexParameteri(target, GL2ES2.GL_TEXTURE_MAG_FILTER, - // GL2ES2.GL_FILTER4_SGIS); - break;*/ + case Texture.LINEAR_SHARPEN: + case Texture.LINEAR_SHARPEN_RGB: + case Texture.LINEAR_SHARPEN_ALPHA: + case Texture2D.LINEAR_DETAIL: + case Texture2D.LINEAR_DETAIL_RGB: + case Texture2D.LINEAR_DETAIL_ALPHA: + case Texture.FILTER4: + default: + assert false; + return; } if (DO_OUTPUT_ERRORS) @@ -6470,41 +6284,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline } - /* 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)"; - } - }*/ - // mapping from java enum to gl enum private static final int[] _gl_textureCubeMapFace = { GL2ES2.GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL2ES2.GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL2ES2.GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL2ES2.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL2ES2.GL_TEXTURE_CUBE_MAP_POSITIVE_Z, @@ -6514,7 +6293,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // native method for setting blend color @Override - // part of TUS updateNative, though not in fact used void setBlendColor(Context ctx, float red, float green, float blue, float alpha) { if (VERBOSE) @@ -6535,7 +6313,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // native method for setting blend func @Override - // part of TUS updateNative void setBlendFunc(Context ctx, int srcBlendFunction, int dstBlendFunction) { if (VERBOSE) @@ -6605,23 +6382,12 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline } // native method for disabling modelClip - @Override // this is called as a reset + @Override void disableModelClip(Context ctx) { if (VERBOSE) System.err.println("JoglPipeline.disableModelClip()"); - - /*GL2 gl = context(ctx).getGL().getGL2(); - //GL2ES2 gl = context(ctx).getGL().getGL2ES2(); - // not supported - - gl.glDisable(GL2ES2.GL_CLIP_PLANE0); - gl.glDisable(GL2ES2.GL_CLIP_PLANE1); - gl.glDisable(GL2ES2.GL_CLIP_PLANE2); - gl.glDisable(GL2ES2.GL_CLIP_PLANE3); - gl.glDisable(GL2ES2.GL_CLIP_PLANE4); - gl.glDisable(GL2ES2.GL_CLIP_PLANE5);*/ } // native method for activating a particular texture unit @@ -6651,7 +6417,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // native method for setting default texture @Override - void resetTextureNative(Context ctx, int texUnitIndex) { if (VERBOSE) @@ -6667,7 +6432,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline if (!MINIMISE_NATIVE_CALLS_TEXTURE || (joglesContext.gl_state.glActiveTexture != (texUnitIndex + GL2ES2.GL_TEXTURE0))) { gl.glActiveTexture(texUnitIndex + GL2ES2.GL_TEXTURE0); - // TODO: should I enable these? + // TODO: should I bind these to 0? // gl.glBindTexture(GL2ES2.GL_TEXTURE_2D, 0);//-1 is no texture , 0 is default // gl.glBindTexture(GL2ES2.GL_TEXTURE_CUBE_MAP, 0); if (DO_OUTPUT_ERRORS) @@ -6676,13 +6441,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline joglesContext.gl_state.glActiveTexture = (texUnitIndex + GL2ES2.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); - */ } // The native method for setting the ModelView matrix. @@ -6850,27 +6608,9 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline 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(); - - //NOTE! winWidth and winHeight! multiplied into the quad xy below - //gl.glOrtho(0.0, winWidth, 0.0, winHeight, 0.0, 0.0); - - //gl.glMatrixMode(GL2.GL_MODELVIEW); - //gl.glLoadIdentity(); - + if (isExtensionAvailable.GL_EXT_abgr(gl)) { glType = GL2.GL_ABGR_EXT; @@ -6888,14 +6628,8 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline } } - //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; @@ -6917,7 +6651,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // Java 3D always clears the Z-buffer gl.glDepthMask(true); gl.glClear(GL.GL_DEPTH_BUFFER_BIT); - //gl.glPopAttrib(); } @Override @@ -6990,7 +6723,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline if (VERBOSE) System.err.println("JoglPipeline.setRenderMode()"); - //TODO: why is this not done in swap or sync? + // TODO: why is this not done in swap or sync? // UGLY HACK the render mode is set to Canvas3D.FIELD_ALL after all // geoms are drawn // so I take the opportunity to unbind the vertex array @@ -7003,8 +6736,8 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline outputErrors(ctx); } - //GL2ES2 gl = context(ctx).getGL().getGL2ES2(); - //no no drawBuffer, possibly just skip it for now + // GL2ES2 gl = context(ctx).getGL().getGL2ES2(); + // no no drawBuffer, possibly just skip it for now // ES2 is much more complex with buffers https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_buffers.txt /* int drawBuf = 0; @@ -7144,15 +6877,10 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline { ctx.setAlphaClearValue(1.0f); } - /*if (gl.isExtensionAvailable("GL_ARB_vertex_shader")) - { - gl.glGetIntegerv(GL2ES2.GL_MAX_TEXTURE_COORDS_ARB, tmp, 0); - ctx.setMaxTexCoordSets(tmp[0]); - }*/ return true; } - // Used by createNewContext above + // Used by createNewContext below private static int[] extractVersionInfo(String versionString) { // FIXME: use the second flash regex system to get the first number out @@ -7192,7 +6920,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline return new int[] { major, minor }; } - // Used by createNewContext above + // Used by createNewContext below private static void checkTextureExtensions(Canvas3D cv, JoglContext ctx, GL2ES2 gl, boolean gl13) { if (gl13) @@ -7286,7 +7014,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline } } - // Used by createNewContext above + // Used by createNewContext below private static void setupCanvasProperties(Canvas3D cv, JoglContext ctx, GL2ES2 gl) { // Note: this includes relevant portions from both the @@ -7510,7 +7238,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline gl.glDisable(GL.GL_POLYGON_OFFSET_FILL); } - // Not needed generally as transpose can be called on the inteface with gl + // Not needed generally as transpose can be called on the interface with gl public static void copyTranspose(double[] src, double[] dst) { dst[0] = src[0]; @@ -8042,7 +7770,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline return true; } - //only used for never release, just to spot first call + //only used for NEVER_RELEASE_CONTEXT, just to spot first call public static boolean currently_current = false; // Optionally release the context. Returns true if the context was released. @@ -8080,6 +7808,107 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // is probably close enough return 8; } + + // 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; + + GL2ES2 gl = context(ctx).getGL().getGL2ES2(); + + // 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;// not ok + break; + case ImageComponentRetained.TYPE_BYTE_RGB: + type = GL.GL_RGB;//ok + break; + // GL_ABGR_EXT + case ImageComponentRetained.TYPE_BYTE_ABGR: + if (isExtensionAvailable.GL_EXT_abgr(gl)) + { // If false, should never come here! + type = GL2.GL_ABGR_EXT; //ok + } + else + { + assert false; + return; + } + break; + case ImageComponentRetained.TYPE_BYTE_RGBA: + type = GL.GL_RGBA;// this a valid case for GL2ES2 + 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)); + if (DO_OUTPUT_ERRORS) + outputErrors(ctx); + } + else + { + throw new AssertionError("illegal image data type " + dataType + " Try creating a BufferedImage of type TYPE_3BYTE_BGR"); + } + + // If FBO + if (chosenCaps.isFBO()) + { + // bind FBO for drawing + fboDrawable.getFBObject(GL.GL_BACK).bind(gl); + } + } // ----------------------- Below here are initialization methods @@ -8138,7 +7967,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline { glDrawable = drawable(cv.drawable); // cv.drawable != null, set in // 'createOffScreenBuffer' - glContext = glDrawable.createContext(context(shareCtx)); + glContext = glDrawable.createContext(context(shareCtx)); } else { @@ -8163,7 +7992,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline } // assuming that this only gets called after addNotify has been called - if(!glDrawable.isRealized()) + if (!glDrawable.isRealized()) glDrawable.setRealized(true); // Apparently we are supposed to make the context current at this point @@ -8526,12 +8355,11 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline @Override Drawable createOffScreenBuffer(Canvas3D cv, Context ctx, int width, int height) { - + //OK general problem, 2 calls to setOffscreen buffer o a canvas3d will call this method once, attaching a // a new drawable all good, but // will then call makeNewContext twice using that same drawable, and that drawable doesn't like make current called twice - - + if (VERBOSE) System.err.println("JoglPipeline.createOffScreenBuffer()"); @@ -8609,106 +8437,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // 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; - - GL2ES2 gl = context(ctx).getGL().getGL2ES2(); - - // 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;// not ok - break; - case ImageComponentRetained.TYPE_BYTE_RGB: - type = GL.GL_RGB;//ok - break; - // GL_ABGR_EXT - case ImageComponentRetained.TYPE_BYTE_ABGR: - if (isExtensionAvailable.GL_EXT_abgr(gl)) - { // If false, should never come here! - type = GL2.GL_ABGR_EXT; //ok - } - else - { - assert false; - return; - } - break; - case ImageComponentRetained.TYPE_BYTE_RGBA: - type = GL.GL_RGBA;// this a valid case for GL2ES2 - 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)); - if (DO_OUTPUT_ERRORS) - outputErrors(ctx); - } - else - { - throw new AssertionError("illegal image data type " + dataType + " Try creating a BufferedImage of type TYPE_3BYTE_BGR"); - } - - // If FBO - if (chosenCaps.isFBO()) - { - // bind FBO for drawing - fboDrawable.getFBObject(GL.GL_BACK).bind(gl); - } - } // Setup the full scene antialising in D3D and ogl when GL_ARB_multisamle supported @Override @@ -9240,6 +8968,7 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline } // AWT AWT AWT AWT AWT AWT AWT AWT AWT + // everything below here demands or is used by awt code // --------------------------------------------------------------------- // Determine whether specified graphics config is supported by pipeline @@ -9278,7 +9007,6 @@ class Jogl2es2Pipeline extends Jogl2es2DEPPipeline // This method must return a valid GraphicsConfig, or else it must throw // an exception if one cannot be returned. @Override - // during Canvas3D init GraphicsConfiguration getGraphicsConfig(GraphicsConfiguration gconfig) { diff --git a/src/main/java/org/jogamp/java3d/Renderer.java b/src/main/java/org/jogamp/java3d/Renderer.java index 54d426e..2899318 100644 --- a/src/main/java/org/jogamp/java3d/Renderer.java +++ b/src/main/java/org/jogamp/java3d/Renderer.java @@ -1447,19 +1447,18 @@ ArrayList<TextureRetained> textureIDResourceTable = new ArrayList<TextureRetaine } catch (RuntimeException ex) { ex.printStackTrace(); - if (canvas != null) { + RenderingError err = new RenderingError(RenderingError.UNEXPECTED_RENDERING_ERROR, J3dI18N.getString("Renderer8")); + err.setCanvas3D(canvas); +if (canvas != null) { // drawingSurfaceObject will safely ignore // this request if this is not lock before canvas.drawingSurfaceObject.unLock(); - } + // Issue 260 : indicate fatal error and notify error listeners + canvas.setFatalError(); + err.setGraphicsDevice(canvas.graphicsConfiguration.getDevice()); +} - // Issue 260 : indicate fatal error and notify error listeners - canvas.setFatalError(); - RenderingError err = - new RenderingError(RenderingError.UNEXPECTED_RENDERING_ERROR, - J3dI18N.getString("Renderer8")); - err.setCanvas3D(canvas); - err.setGraphicsDevice(canvas.graphicsConfiguration.getDevice()); + notifyErrorListeners(err); } } diff --git a/src/main/java/org/jogamp/java3d/SparseArray.java b/src/main/java/org/jogamp/java3d/SparseArray.java new file mode 100644 index 0000000..70c725e --- /dev/null +++ b/src/main/java/org/jogamp/java3d/SparseArray.java @@ -0,0 +1,584 @@ +package org.jogamp.java3d;
+
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * SparseArrays map integers to Objects. Unlike a normal array of Objects,
+ * there can be gaps in the indices. It is intended to be more memory efficient
+ * than using a HashMap to map Integers to Objects, both because it avoids
+ * auto-boxing keys and its data structure doesn't rely on an extra entry object
+ * for each mapping.
+ *
+ * <p>Note that this container keeps its mappings in an array data structure,
+ * using a binary search to find keys. The implementation is not intended to be appropriate for
+ * data structures
+ * that may contain large numbers of items. It is generally slower than a traditional
+ * HashMap, since lookups require a binary search and adds and removes require inserting
+ * and deleting entries in the array. For containers holding up to hundreds of items,
+ * the performance difference is not significant, less than 50%.</p>
+ *
+ * <p>To help with performance, the container includes an optimization when removing
+ * keys: instead of compacting its array immediately, it leaves the removed entry marked
+ * as deleted. The entry can then be re-used for the same key, or compacted later in
+ * a single garbage collection step of all removed entries. This garbage collection will
+ * need to be performed at any time the array needs to be grown or the the map size or
+ * entry values are retrieved.</p>
+ *
+ * <p>It is possible to iterate over the items in this container using
+ * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
+ * <code>keyAt(int)</code> with ascending values of the index will return the
+ * keys in ascending order, or the values corresponding to the keys in ascending
+ * order in the case of <code>valueAt(int)</code>.</p>
+ */
+public class SparseArray<E> implements Cloneable
+{
+ private static final Object DELETED = new Object();
+ private boolean mGarbage = false;
+
+ private int[] mKeys;
+ private Object[] mValues;
+ private int mSize;
+
+ static final boolean[] EMPTY_BOOLEANS = new boolean[0];
+ static final int[] EMPTY_INTS = new int[0];
+ static final long[] EMPTY_LONGS = new long[0];
+ static final Object[] EMPTY_OBJECTS = new Object[0];
+
+ /**
+ * Creates a new SparseArray containing no mappings.
+ */
+ public SparseArray()
+ {
+ this(10);
+ }
+
+ /**
+ * Creates a new SparseArray containing no mappings that will not
+ * require any additional memory allocation to store the specified
+ * number of mappings. If you supply an initial capacity of 0, the
+ * sparse array will be initialized with a light-weight representation
+ * not requiring any additional array allocations.
+ */
+ public SparseArray(int initialCapacity)
+ {
+ if (initialCapacity == 0)
+ {
+ mKeys = EMPTY_INTS;
+ mValues = EMPTY_OBJECTS;
+ }
+ else
+ {
+ initialCapacity = idealIntArraySize(initialCapacity);
+ mKeys = new int[initialCapacity];
+ mValues = new Object[initialCapacity];
+ }
+ mSize = 0;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public SparseArray<E> clone()
+ {
+ SparseArray<E> clone = null;
+ try
+ {
+ clone = (SparseArray<E>) super.clone();
+ clone.mKeys = mKeys.clone();
+ clone.mValues = mValues.clone();
+ }
+ catch (CloneNotSupportedException cnse)
+ {
+ /* ignore */
+ }
+ return clone;
+ }
+
+ /**
+ * Gets the Object mapped from the specified key, or <code>null</code>
+ * if no such mapping has been made.
+ */
+ public E get(int key)
+ {
+ return get(key, null);
+ }
+
+ /**
+ * Gets the Object mapped from the specified key, or the specified Object
+ * if no such mapping has been made.
+ */
+ @SuppressWarnings("unchecked")
+ public E get(int key, E valueIfKeyNotFound)
+ {
+ int i = binarySearch(mKeys, mSize, key);
+
+ if (i < 0 || mValues[i] == DELETED)
+ {
+ return valueIfKeyNotFound;
+ }
+ else
+ {
+ return (E) mValues[i];
+ }
+ }
+
+ /**
+ * Removes the mapping from the specified key, if there was any.
+ */
+ public void delete(int key)
+ {
+ int i = binarySearch(mKeys, mSize, key);
+
+ if (i >= 0)
+ {
+ if (mValues[i] != DELETED)
+ {
+ mValues[i] = DELETED;
+ mGarbage = true;
+ }
+ }
+ }
+
+ /**
+ * Alias for {@link #delete(int)}.
+ */
+ public void remove(int key)
+ {
+ delete(key);
+ }
+
+ /**
+ * Removes the mapping at the specified index.
+ */
+ public void removeAt(int index)
+ {
+ if (mValues[index] != DELETED)
+ {
+ mValues[index] = DELETED;
+ mGarbage = true;
+ }
+ }
+
+ /**
+ * Remove a range of mappings as a batch.
+ *
+ * @param index Index to begin at
+ * @param size Number of mappings to remove
+ */
+ public void removeAtRange(int index, int size)
+ {
+ final int end = Math.min(mSize, index + size);
+ for (int i = index; i < end; i++)
+ {
+ removeAt(i);
+ }
+ }
+
+ private void gc()
+ {
+ // Log.e("SparseArray", "gc start with " + mSize);
+
+ int n = mSize;
+ int o = 0;
+ int[] keys = mKeys;
+ Object[] values = mValues;
+
+ for (int i = 0; i < n; i++)
+ {
+ Object val = values[i];
+
+ if (val != DELETED)
+ {
+ if (i != o)
+ {
+ keys[o] = keys[i];
+ values[o] = val;
+ values[i] = null;
+ }
+
+ o++;
+ }
+ }
+
+ mGarbage = false;
+ mSize = o;
+
+ // Log.e("SparseArray", "gc end with " + mSize);
+ }
+
+ /**
+ * Adds a mapping from the specified key to the specified value,
+ * replacing the previous mapping from the specified key if there
+ * was one.
+ */
+ public void put(int key, E value)
+ {
+ int i = binarySearch(mKeys, mSize, key);
+
+ if (i >= 0)
+ {
+ mValues[i] = value;
+ }
+ else
+ {
+ i = ~i;
+
+ if (i < mSize && mValues[i] == DELETED)
+ {
+ mKeys[i] = key;
+ mValues[i] = value;
+ return;
+ }
+
+ if (mGarbage && mSize >= mKeys.length)
+ {
+ gc();
+
+ // Search again because indices may have changed.
+ i = ~binarySearch(mKeys, mSize, key);
+ }
+
+ if (mSize >= mKeys.length)
+ {
+ int n = idealIntArraySize(mSize + 1);
+
+ int[] nkeys = new int[n];
+ Object[] nvalues = new Object[n];
+
+ // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+
+ if (mSize - i != 0)
+ {
+ // Log.e("SparseArray", "move " + (mSize - i));
+ System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
+ System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
+ }
+
+ mKeys[i] = key;
+ mValues[i] = value;
+ mSize++;
+ }
+ }
+
+ /**
+ * Returns the number of key-value mappings that this SparseArray
+ * currently stores.
+ */
+ public int size()
+ {
+ if (mGarbage)
+ {
+ gc();
+ }
+
+ return mSize;
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the key from the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ *
+ * <p>The keys corresponding to indices in ascending order are guaranteed to
+ * be in ascending order, e.g., <code>keyAt(0)</code> will return the
+ * smallest key and <code>keyAt(size()-1)</code> will return the largest
+ * key.</p>
+ */
+ public int keyAt(int index)
+ {
+ if (mGarbage)
+ {
+ gc();
+ }
+
+ return mKeys[index];
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the value from the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ *
+ * <p>The values corresponding to indices in ascending order are guaranteed
+ * to be associated with keys in ascending order, e.g.,
+ * <code>valueAt(0)</code> will return the value associated with the
+ * smallest key and <code>valueAt(size()-1)</code> will return the value
+ * associated with the largest key.</p>
+ */
+ @SuppressWarnings("unchecked")
+ public E valueAt(int index)
+ {
+ if (mGarbage)
+ {
+ gc();
+ }
+
+ return (E) mValues[index];
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, sets a new
+ * value for the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ */
+ public void setValueAt(int index, E value)
+ {
+ if (mGarbage)
+ {
+ gc();
+ }
+
+ mValues[index] = value;
+ }
+
+ /**
+ * Returns the index for which {@link #keyAt} would return the
+ * specified key, or a negative number if the specified
+ * key is not mapped.
+ */
+ public int indexOfKey(int key)
+ {
+ if (mGarbage)
+ {
+ gc();
+ }
+
+ return binarySearch(mKeys, mSize, key);
+ }
+
+ /**
+ * Returns an index for which {@link #valueAt} would return the
+ * specified key, or a negative number if no keys map to the
+ * specified value.
+ * <p>Beware that this is a linear search, unlike lookups by key,
+ * and that multiple keys can map to the same value and this will
+ * find only one of them.
+ * <p>Note also that unlike most collections' {@code indexOf} methods,
+ * this method compares values using {@code ==} rather than {@code equals}.
+ */
+ public int indexOfValue(E value)
+ {
+ if (mGarbage)
+ {
+ gc();
+ }
+
+ for (int i = 0; i < mSize; i++)
+ if (mValues[i] == value)
+ return i;
+
+ return -1;
+ }
+
+ /**
+ * Removes all key-value mappings from this SparseArray.
+ */
+ public void clear()
+ {
+ int n = mSize;
+ Object[] values = mValues;
+
+ for (int i = 0; i < n; i++)
+ {
+ values[i] = null;
+ }
+
+ mSize = 0;
+ mGarbage = false;
+ }
+
+ /**
+ * Puts a key/value pair into the array, optimizing for the case where
+ * the key is greater than all existing keys in the array.
+ */
+ public void append(int key, E value)
+ {
+ if (mSize != 0 && key <= mKeys[mSize - 1])
+ {
+ put(key, value);
+ return;
+ }
+
+ if (mGarbage && mSize >= mKeys.length)
+ {
+ gc();
+ }
+
+ int pos = mSize;
+ if (pos >= mKeys.length)
+ {
+ int n = idealIntArraySize(pos + 1);
+
+ int[] nkeys = new int[n];
+ Object[] nvalues = new Object[n];
+
+ // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+
+ mKeys[pos] = key;
+ mValues[pos] = value;
+ mSize = pos + 1;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation composes a string by iterating over its mappings. If
+ * this map contains itself as a value, the string "(this Map)"
+ * will appear in its place.
+ */
+ @Override
+ public String toString()
+ {
+ if (size() <= 0)
+ {
+ return "{}";
+ }
+
+ StringBuilder buffer = new StringBuilder(mSize * 28);
+ buffer.append('{');
+ for (int i = 0; i < mSize; i++)
+ {
+ if (i > 0)
+ {
+ buffer.append(", ");
+ }
+ int key = keyAt(i);
+ buffer.append(key);
+ buffer.append('=');
+ Object value = valueAt(i);
+ if (value != this)
+ {
+ buffer.append(value);
+ }
+ else
+ {
+ buffer.append("(this Map)");
+ }
+ }
+ buffer.append('}');
+ return buffer.toString();
+ }
+
+ public static int idealByteArraySize(int need)
+ {
+ for (int i = 4; i < 32; i++)
+ if (need <= (1 << i) - 12)
+ return (1 << i) - 12;
+
+ return need;
+ }
+
+ public static int idealIntArraySize(int need)
+ {
+ return idealByteArraySize(need * 8) / 8;
+ }
+
+ // This is Arrays.binarySearch(), but doesn't do any argument validation.
+ static int binarySearch(int[] array, int size, int value)
+ {
+ int lo = 0;
+ int hi = size - 1;
+
+ while (lo <= hi)
+ {
+ final int mid = (lo + hi) >>> 1;
+ final int midVal = array[mid];
+
+ if (midVal < value)
+ {
+ lo = mid + 1;
+ }
+ else if (midVal > value)
+ {
+ hi = mid - 1;
+ }
+ else
+ {
+ return mid; // value found
+ }
+ }
+ return ~lo; // value not present
+ }
+
+ static int binarySearch(long[] array, int size, long value)
+ {
+ int lo = 0;
+ int hi = size - 1;
+
+ while (lo <= hi)
+ {
+ final int mid = (lo + hi) >>> 1;
+ final long midVal = array[mid];
+
+ if (midVal < value)
+ {
+ lo = mid + 1;
+ }
+ else if (midVal > value)
+ {
+ hi = mid - 1;
+ }
+ else
+ {
+ return mid; // value found
+ }
+ }
+ return ~lo; // value not present
+ }
+
+ //////////////PJ extensions
+ public void putAll(SparseArray<E> sa)
+ {
+ for (int i = 0; i < sa.size(); i++)
+ put(sa.keyAt(i), sa.get(sa.keyAt(i)));
+
+ }
+
+ public int[] keySet()
+ {
+ int[] keys = new int[size()];
+ for (int i = 0; i < size(); i++)
+ keys[i] = keyAt(i);
+ return keys;
+ }
+
+ public void put(Integer key, E value)
+ {
+ throw new UnsupportedOperationException("This is exactly the sort of thing I'm trying to avoid!");
+ }
+
+ public E get(Integer key)
+ {
+ throw new UnsupportedOperationException("This is exactly the sort of thing I'm trying to avoid!");
+ }
+
+ public E remove(Integer key)
+ {
+ throw new UnsupportedOperationException("This is exactly the sort of thing I'm trying to avoid!");
+ }
+}
|