This is a patch for the android shader renderer to use vertex arrays instead of vertex buffer objects.
This is due to a limitation of the OpenGL ES 2.0 bindings in Android 2.2 where
glDrawElements (int mode, int count, int type, int offset) is missing.
I have been playing around with the renderer for a few days and was finally able to render more than one mesh and more than one material by using vertex arrays only, no VBO.
As i dont have commit priviledges, it would be nice if any of you could test this and possibly commit it.
I have tested on a Samsung Galaxy S under Android 2.2.1
The patch for the renderer to turn off VBO:
[patch]
Index: src/android/com/jme3/renderer/android/OGLESShaderRenderer.java
===================================================================
ā src/android/com/jme3/renderer/android/OGLESShaderRenderer.java (revision 6806)
+++ src/android/com/jme3/renderer/android/OGLESShaderRenderer.java (working copy)
@@ -130,6 +130,7 @@
private static final Logger logger = Logger.getLogger(OGLESShaderRenderer.class.getName());
private static final boolean VALIDATE_SHADER = false;
- private static final boolean USE_VBO = false;
private final ByteBuffer nameBuf = BufferUtils.createByteBuffer(250);
private final StringBuilder stringBuf = new StringBuilder(250);
@@ -1923,9 +1924,9 @@
GLES20.glBindTexture(type, texId);
textures[unit] = image;
-
statistics.onTextureUse(tex, true);<br />
-
statistics.onTextureUse(tex.getImage(), true);<br />
}else{
-
statistics.onTextureUse(tex, false);<br />
-
statistics.onTextureUse(tex.getImage(), false);<br />
}
setupTextureParams(tex);
@@ -2510,35 +2511,53 @@
}
}
- private void renderMeshVertexArray(Mesh mesh, int lod, int count){
- /**
-
* renderMeshVertexArray renders a mesh using vertex arrays<br />
-
* @param mesh<br />
-
* @param lod<br />
-
* @param count<br />
-
*/<br />
- private void renderMeshVertexArray(Mesh mesh, int lod, int count)
- {
-
if (verboseLogging)<br />
-
logger.info("renderMeshVertexArray");<br />
- if (verboseLogging)
- logger.info("renderMeshVertexArray");
+ IntMap<VertexBuffer> buffers = mesh.getBuffers();
+ for (Entry<VertexBuffer> entry : buffers){
+ VertexBuffer vb = entry.getValue();
- if (mesh.getId() == -1){
- updateVertexArray(mesh);
- }
+ if (vb.getBufferType() == Type.InterleavedData
+ || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers
+ || vb.getBufferType() == Type.Index)
+ continue;
- if (context.boundVertexArray != mesh.getId()){
- // ARBVertexArrayObject.glBindVertexArray(mesh.getId());
- // GLES20.glBindVertexArray(mesh.getId());
- context.boundVertexArray = mesh.getId();
+ if (vb.getStride() == 0){
+ // not interleaved
+ setVertexAttrib_Array(vb);
+ }else{
+ // interleaved
+ VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData);
+ setVertexAttrib_Array(vb, interleavedData);
+ }
}
- IntMap<VertexBuffer> buffers = mesh.getBuffers();
VertexBuffer indices = null;
- if (mesh.getNumLodLevels() > 0){
+ if (mesh.getNumLodLevels() > 0)
+ {
indices = mesh.getLodLevel(lod);
- }else{
+ }
+ else
+ {
indices = buffers.get(Type.Index.ordinal());
}
- if (indices != null){
- drawTriangleList(indices, mesh, count);
- }else{
-// throw new UnsupportedOperationException("Cannot render without index buffer");
-
- if (verboseLogging)
- logger.info("GLES20.glDrawArrays(" + mesh.getMode() + ", " + 0 + ", " + mesh.getVertexCount() + ")");
+ if (indices != null)
+ {
+ drawTriangleList_Array(indices, mesh, count);
+ }
+ else
+ {
+ if (verboseLogging)
+ logger.info("GLES20.glDrawArrays(" + mesh.getMode() + ", " + 0 + ", " + mesh.getVertexCount() + ")");
GLES20.glDrawArrays(convertElementMode(mesh.getMode()), 0, mesh.getVertexCount());
}
@@ -2613,7 +2632,10 @@
// if (GLContext.getCapabilities().GL_ARB_vertex_array_object){
// renderMeshVertexArray(mesh, lod, count);
// }else{
+ if (USE_VBO)
renderMeshDefault(mesh, lod, count);
+ else
+ renderMeshVertexArray(mesh, lod, count);
// }
}
@@ -2630,4 +2652,176 @@
return true;
}
+ /**
+ * drawTriangleList_Array uses Vertex Array
+ * @param indexBuf
+ * @param mesh
+ * @param count
+ */
+ public void drawTriangleList_Array(VertexBuffer indexBuf, Mesh mesh, int count)
+ {
+ if (verboseLogging)
+ logger.info("drawTriangleList_Array(Count = " + count + ")");
+
+ if (indexBuf.getBufferType() != VertexBuffer.Type.Index)
+ throw new IllegalArgumentException("Only index buffers are allowed as triangle lists.");
+
+ boolean useInstancing = count > 1 && caps.contains(Caps.MeshInstancing);
+ if (useInstancing)
+ {
+ throw new IllegalArgumentException("Caps.MeshInstancing is not supported.");
+ }
+
+ int vertCount = mesh.getVertexCount();
+ Buffer indexData = indexBuf.getData();
+ indexData.clear();
+
+ if (mesh.getMode() == Mode.Hybrid)
+ {
+ int[] modeStart = mesh.getModeStart();
+ int[] elementLengths = mesh.getElementLengths();
+
+ int elMode = convertElementMode(Mode.Triangles);
+ int fmt = convertFormat(indexBuf.getFormat());
+ int elSize = indexBuf.getFormat().getComponentSize();
+ int listStart = modeStart[0];
+ int stripStart = modeStart[1];
+ int fanStart = modeStart[2];
+ int curOffset = 0;
+ for (int i = 0; i < elementLengths.length; i++)
+ {
+ if (i == stripStart)
+ {
+ elMode = convertElementMode(Mode.TriangleStrip);
+ }
+ else if (i == fanStart)
+ {
+ elMode = convertElementMode(Mode.TriangleStrip);
+ }
+ int elementLength = elementLengths;
+
+ indexBuf.getData().position(curOffset);
+ if (verboseLogging)
+ logger.info("glDrawElements(): " + elementLength + ", " + curOffset);
+
+ GLES20.glDrawElements(elMode, elementLength, fmt, indexBuf.getData());
+
+ curOffset += elementLength * elSize;
+ }
+ }
+ else //if (mesh.getMode() == Mode.Hybrid)
+ {
+ if (verboseLogging)
+ logger.info("glDrawElements(), indexBuf.capacity (" + indexBuf.getData().capacity() + "), vertCount (" + vertCount + ")");
+
+ GLES20.glDrawElements(
+ convertElementMode(mesh.getMode()),
+ indexBuf.getData().capacity(),
+ convertFormat(indexBuf.getFormat()),
+ indexBuf.getData()
+ );
+ }
+ }
+
+ /**
+ * setVertexAttrib_Array uses Vertex Array
+ * @param vb
+ * @param idb
+ */
+ public void setVertexAttrib_Array(VertexBuffer vb, VertexBuffer idb)
+ {
+ if (verboseLogging)
+ logger.info("setVertexAttrib_Array(" + vb + ", " + idb + ")");
+
+ if (vb.getBufferType() == VertexBuffer.Type.Index)
+ throw new IllegalArgumentException("Index buffers not allowed to be set to vertex attrib");
+
+ // Get shader
+ int programId = context.boundShaderProgram;
+ if (programId > 0)
+ {
+ VertexBuffer[] attribs = context.boundAttribs;
+
+ Attribute attrib = boundShader.getAttribute(vb.getBufferType().name());
+ int loc = attrib.getLocation();
+ if (loc == -1)
+ {
+ //throw new IllegalArgumentException("Location is invalid for attrib: [" + vb.getBufferType().name() + "]");
+ if (verboseLogging)
+ logger.warning("attribute is invalid in shader: [" + vb.getBufferType().name() + "]");
+ return;
+ }
+ else if (loc == -2)
+ {
+ String attributeName = "in" + vb.getBufferType().name();
+
+ if (verboseLogging)
+ logger.info("GLES20.glGetAttribLocation(" + programId + ", " + attributeName + ")");
+
+ loc = GLES20.glGetAttribLocation(programId, attributeName);
+ if (loc < 0)
+ {
+ attrib.setLocation(-1);
+ if (verboseLogging)
+ logger.warning("attribute is invalid in shader: [" + vb.getBufferType().name() + "]");
+ return; // not available in shader.
+ }
+ else
+ {
+ attrib.setLocation(loc);
+ }
+
+ } // if (loc == -2)
+
+ if ((attribs[loc] != vb) || vb.isUpdateNeeded())
+ {
+ // NOTE: Use data from interleaved buffer if specified
+ VertexBuffer avb = idb != null ? idb : vb;
+ avb.getData().clear();
+ avb.getData().position(vb.getOffset());
+
+ if (verboseLogging)
+ logger.info("GLES20.glVertexAttribPointer(" +
+ "location=" + loc + ", " +
+ "numComponents=" + vb.getNumComponents() + ", " +
+ "format=" + vb.getFormat() + ", " +
+ "isNormalized=" + vb.isNormalized() + ", " +
+ "stride=" + vb.getStride() + ", " +
+ "data.capacity=" + avb.getData().capacity() + ")"
+ );
+
+
+ // Upload attribute data
+ GLES20.glVertexAttribPointer(loc,
+ vb.getNumComponents(),
+ convertFormat(vb.getFormat()),
+ vb.isNormalized(),
+ vb.getStride(),
+ avb.getData());
+ checkGLError();
+
+ GLES20.glEnableVertexAttribArray(loc);
+
+ attribs[loc] = vb;
+ } // if (attribs[loc] != vb)
+ }
+ else
+ {
+ throw new IllegalStateException("Cannot render mesh without shader bound");
+ }
+ }
+
+ /**
+ * setVertexAttrib_Array uses Vertex Array
+ * @param vb
+ */
+ public void setVertexAttrib_Array(VertexBuffer vb)
+ {
+ setVertexAttrib_Array(vb, null);
+ }
+
+ public void setAlphaToCoverage(boolean value)
+ {
+ // TODO Auto-generated method stub
+ }
}
[/patch]