OSDN Git Service

[added] VertexBufferObjectSubData class that uses glBufferSubData instead of glBuffer...
authorbadlogicgames <badlogicgames@6c4fd544-2939-11df-bb46-9574ba5d0bfa>
Sun, 14 Nov 2010 15:44:07 +0000 (15:44 +0000)
committerbadlogicgames <badlogicgames@6c4fd544-2939-11df-bb46-9574ba5d0bfa>
Sun, 14 Nov 2010 15:44:07 +0000 (15:44 +0000)
gdx/src/com/badlogic/gdx/graphics/glutils/VertexBufferObjectSubData.java [new file with mode: 0644]

diff --git a/gdx/src/com/badlogic/gdx/graphics/glutils/VertexBufferObjectSubData.java b/gdx/src/com/badlogic/gdx/graphics/glutils/VertexBufferObjectSubData.java
new file mode 100644 (file)
index 0000000..5b98b1c
--- /dev/null
@@ -0,0 +1,363 @@
+package com.badlogic.gdx.graphics.glutils;\r
+\r
+import java.nio.ByteBuffer;\r
+import java.nio.ByteOrder;\r
+import java.nio.FloatBuffer;\r
+import java.nio.IntBuffer;\r
+\r
+import com.badlogic.gdx.Gdx;\r
+import com.badlogic.gdx.Application.ApplicationType;\r
+import com.badlogic.gdx.graphics.GL10;\r
+import com.badlogic.gdx.graphics.GL11;\r
+import com.badlogic.gdx.graphics.GL20;\r
+import com.badlogic.gdx.graphics.VertexAttribute;\r
+import com.badlogic.gdx.graphics.VertexAttributes;\r
+import com.badlogic.gdx.graphics.VertexAttributes.Usage;\r
+import com.badlogic.gdx.utils.BufferUtils;\r
+import com.badlogic.gdx.utils.GdxRuntimeException;\r
+\r
+/**\r
+ * <p>\r
+ * A {@link VertexData} implementation based on OpenGL vertex buffer objects.\r
+ * </p>\r
+ * \r
+ * <p>\r
+ * If the OpenGL ES context was lost you can call {@link #invalidate()} to\r
+ * recreate a new OpenGL vertex buffer object. This class can be used seamlessly\r
+ * with OpenGL ES 1.x and 2.0.\r
+ * </p>\r
+ * \r
+ * <p>\r
+ * In case OpenGL ES 2.0 is used in the application the data is bound via\r
+ * glVertexAttribPointer() according to the attribute aliases specified via\r
+ * {@link VertexAttributes} in the constructor.\r
+ * </p>\r
+ * \r
+ * <p>\r
+ * Uses indirect Buffers on Android 1.5/1.6 to fix GC invocation due to leaking\r
+ * PlatformAddress instances.\r
+ * </p>\r
+ * \r
+ * <p>\r
+ * VertexBufferObjects must be disposed via the {@link #dispose()} method when no longer needed\r
+ * </p>\r
+ * \r
+ * @author mzechner\r
+ * \r
+ */\r
+public class VertexBufferObjectSubData implements VertexData {\r
+       final static IntBuffer tmpHandle = BufferUtils.newIntBuffer(1);\r
+\r
+       final VertexAttributes attributes;\r
+       final FloatBuffer buffer;\r
+       final ByteBuffer byteBuffer;\r
+       int bufferHandle;\r
+       final boolean isDirect;\r
+       final boolean isStatic;\r
+       final int usage;\r
+       boolean isDirty = false;\r
+       boolean isBound = false;\r
+\r
+       /**\r
+        * Constructs a new interleaved VertexBufferObject.\r
+        * \r
+        * @param isStatic\r
+        *            whether the vertex data is static.\r
+        * @param numVertices\r
+        *            the maximum number of vertices\r
+        * @param attributes\r
+        *            the {@link VertexAttribute}s.\r
+        */\r
+       public VertexBufferObjectSubData(boolean isStatic, int numVertices,\r
+                       VertexAttribute... attributes) {\r
+               this.isStatic = isStatic;\r
+               this.attributes = new VertexAttributes(attributes);\r
+//             if (Gdx.app.getType() == ApplicationType.Android\r
+//                             && Gdx.app.getVersion() < 5) {\r
+//                     byteBuffer = ByteBuffer.allocate(this.attributes.vertexSize\r
+//                                     * numVertices);\r
+//                     byteBuffer.order(ByteOrder.nativeOrder());\r
+//                     isDirect = false;\r
+//             } else {\r
+                       byteBuffer = ByteBuffer.allocateDirect(this.attributes.vertexSize\r
+                                       * numVertices);\r
+                       byteBuffer.order(ByteOrder.nativeOrder());\r
+                       isDirect = true;\r
+//             }\r
+               usage = isStatic ? GL11.GL_STATIC_DRAW : GL11.GL_DYNAMIC_DRAW;\r
+               buffer = byteBuffer.asFloatBuffer();\r
+               bufferHandle = createBufferObject();\r
+       }\r
+\r
+       private int createBufferObject() {\r
+               if (Gdx.gl20 != null) {                 \r
+                       Gdx.gl20.glGenBuffers(1, tmpHandle);\r
+                       Gdx.gl20.glBindBuffer(GL20.GL_ARRAY_BUFFER, tmpHandle.get(0));\r
+                       Gdx.gl20.glBufferData(GL20.GL_ARRAY_BUFFER, byteBuffer.capacity(), null, usage);\r
+                       Gdx.gl20.glBindBuffer(GL20.GL_ARRAY_BUFFER, 0);\r
+               }\r
+               else {\r
+                       Gdx.gl11.glGenBuffers(1, tmpHandle);\r
+                       Gdx.gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, tmpHandle.get(0));\r
+                       Gdx.gl11.glBufferData(GL11.GL_ARRAY_BUFFER, byteBuffer.capacity(), null, usage);\r
+                       Gdx.gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);\r
+               }\r
+               return tmpHandle.get(0);\r
+       }\r
+\r
+       /**\r
+        * {@inheritDoc}\r
+        */\r
+       @Override\r
+       public VertexAttributes getAttributes() {\r
+               return attributes;\r
+       }\r
+\r
+       /**\r
+        * {@inheritDoc}\r
+        */\r
+       @Override\r
+       public int getNumVertices() {\r
+               return byteBuffer.limit() / attributes.vertexSize;\r
+       }\r
+\r
+       /**\r
+        * {@inheritDoc}\r
+        */\r
+       public int getNumMaxVertices() {\r
+               return byteBuffer.capacity() / attributes.vertexSize;\r
+       }\r
+\r
+       /**\r
+        * {@inheritDoc}\r
+        */\r
+       @Override\r
+       public FloatBuffer getBuffer() {\r
+               isDirty = true;\r
+               return buffer;\r
+       }\r
+\r
+       /**\r
+        * {@inheritDoc}\r
+        */\r
+       @Override\r
+       public void setVertices(float[] vertices, int offset, int count) {\r
+               isDirty = true;\r
+               if (isDirect) {\r
+                       BufferUtils.copy(vertices, byteBuffer, count, offset);\r
+                       buffer.position(0);\r
+                       buffer.limit(count);\r
+               } else {\r
+                       buffer.clear();\r
+                       buffer.put(vertices, offset, count);\r
+                       buffer.flip();\r
+                       byteBuffer.position(0);\r
+                       byteBuffer.limit(buffer.limit() << 2);\r
+               }\r
+\r
+               if (isBound) {\r
+                       if (Gdx.gl20 != null) {\r
+                               GL20 gl = Gdx.gl20;                             \r
+                               gl.glBufferSubData(GL20.GL_ARRAY_BUFFER, 0, byteBuffer.limit(),\r
+                                               byteBuffer);\r
+                       } else {\r
+                               GL11 gl = Gdx.gl11;                             \r
+                               gl.glBufferSubData(GL11.GL_ARRAY_BUFFER, 0, byteBuffer.limit(),\r
+                                               byteBuffer);\r
+                       }\r
+                       isDirty = false;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * {@inheritDoc}\r
+        */\r
+       @Override\r
+       public void bind() {\r
+               GL11 gl = Gdx.gl11;\r
+\r
+               gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, bufferHandle);\r
+               if (isDirty) {\r
+                       gl.glBufferSubData(GL11.GL_ARRAY_BUFFER, 0, byteBuffer.limit(), byteBuffer);\r
+//                     gl.glBufferData(GL11.GL_ARRAY_BUFFER, byteBuffer.limit(),\r
+//                                     byteBuffer, usage);\r
+                       isDirty = false;\r
+               }\r
+\r
+               int textureUnit = 0;\r
+               int numAttributes = attributes.size();\r
+\r
+               for (int i = 0; i < numAttributes; i++) {\r
+                       VertexAttribute attribute = attributes.get(i);\r
+\r
+                       switch (attribute.usage) {\r
+                       case Usage.Position:\r
+                               gl.glEnableClientState(GL11.GL_VERTEX_ARRAY);\r
+                               gl.glVertexPointer(attribute.numComponents, GL10.GL_FLOAT,\r
+                                               attributes.vertexSize, attribute.offset);\r
+                               break;\r
+\r
+                       case Usage.Color:\r
+                       case Usage.ColorPacked:\r
+                               int colorType = GL10.GL_FLOAT;\r
+                               if (attribute.usage == Usage.ColorPacked)\r
+                                       colorType = GL11.GL_UNSIGNED_BYTE;\r
+\r
+                               gl.glEnableClientState(GL10.GL_COLOR_ARRAY);\r
+                               gl.glColorPointer(attribute.numComponents, colorType,\r
+                                               attributes.vertexSize, attribute.offset);\r
+                               break;\r
+\r
+                       case Usage.Normal:\r
+                               gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);\r
+                               gl.glNormalPointer(GL10.GL_FLOAT, attributes.vertexSize,\r
+                                               attribute.offset);\r
+                               break;\r
+\r
+                       case Usage.TextureCoordinates:\r
+                               gl.glClientActiveTexture(GL10.GL_TEXTURE0 + textureUnit);\r
+                               gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);\r
+                               gl.glTexCoordPointer(attribute.numComponents, GL10.GL_FLOAT,\r
+                                               attributes.vertexSize, attribute.offset);\r
+                               textureUnit++;\r
+                               break;\r
+\r
+                       default:\r
+                               throw new GdxRuntimeException("unkown vertex attribute type: "\r
+                                               + attribute.usage);\r
+                       }\r
+               }\r
+\r
+               isBound = true;\r
+       }\r
+\r
+       /**\r
+        * Binds this VertexBufferObject for rendering via glDrawArrays or\r
+        * glDrawElements\r
+        * \r
+        * @param shader\r
+        *            the shader\r
+        */\r
+       public void bind(ShaderProgram shader) {\r
+               GL20 gl = Gdx.gl20;\r
+\r
+               gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, bufferHandle);\r
+               if (isDirty) {\r
+                       gl.glBufferSubData(GL11.GL_ARRAY_BUFFER, 0, byteBuffer.limit(), byteBuffer);\r
+//                     gl.glBufferData(GL20.GL_ARRAY_BUFFER, byteBuffer.limit(),\r
+//                                     byteBuffer, usage);\r
+                       isDirty = false;\r
+               }\r
+\r
+               int numAttributes = attributes.size();\r
+               for (int i = 0; i < numAttributes; i++) {\r
+                       VertexAttribute attribute = attributes.get(i);\r
+                       shader.enableVertexAttribute(attribute.alias);\r
+                       int colorType = GL20.GL_FLOAT;\r
+                       boolean normalize = false;\r
+                       if (attribute.usage == Usage.ColorPacked) {\r
+                               colorType = GL20.GL_UNSIGNED_BYTE;\r
+                               normalize = true;\r
+                       }\r
+                       shader.setVertexAttribute(attribute.alias, attribute.numComponents,\r
+                                       colorType, normalize, attributes.vertexSize,\r
+                                       attribute.offset);\r
+               }\r
+               isBound = true;\r
+       }\r
+\r
+       /**\r
+        * {@inheritDoc}\r
+        */\r
+       @Override\r
+       public void unbind() {\r
+               GL11 gl = Gdx.gl11;\r
+               int textureUnit = 0;\r
+               int numAttributes = attributes.size();  \r
+\r
+               for (int i = 0; i < numAttributes; i++) {\r
+\r
+                       VertexAttribute attribute = attributes.get(i);\r
+                       switch (attribute.usage) {\r
+                       case Usage.Position:\r
+                               break; // no-op, we also need a position bound in gles\r
+                       case Usage.Color:\r
+                       case Usage.ColorPacked:\r
+                               gl.glDisableClientState(GL11.GL_COLOR_ARRAY);\r
+                               break;\r
+                       case Usage.Normal:\r
+                               gl.glDisableClientState(GL11.GL_NORMAL_ARRAY);\r
+                               break;\r
+                       case Usage.TextureCoordinates:\r
+                               gl.glClientActiveTexture(GL11.GL_TEXTURE0 + textureUnit);\r
+                               gl.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);\r
+                               textureUnit++;\r
+                               break;\r
+                       default:\r
+                               throw new GdxRuntimeException("unkown vertex attribute type: "\r
+                                               + attribute.usage);\r
+                       }\r
+               }\r
+               \r
+               gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);\r
+               isBound = false;\r
+       }\r
+\r
+       /**\r
+        * Unbinds this VertexBufferObject.\r
+        * \r
+        * @param shader\r
+        *            the shader\r
+        */\r
+       public void unbind(ShaderProgram shader) {\r
+               GL20 gl = Gdx.gl20;\r
+               int numAttributes = attributes.size();\r
+               for (int i = 0; i < numAttributes; i++) {\r
+                       VertexAttribute attribute = attributes.get(i);\r
+                       shader.disableVertexAttribute(attribute.alias);\r
+               }\r
+               gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, 0);\r
+               isBound = false;\r
+       }\r
+\r
+       /**\r
+        * Invalidates the VertexBufferObject so a new OpenGL buffer handle is\r
+        * created. Use this in case of a context loss.\r
+        */\r
+       public void invalidate() {\r
+               bufferHandle = createBufferObject();\r
+               isDirty = true;\r
+       }\r
+\r
+       /**\r
+        * Disposes of all resources this VertexBufferObject uses.\r
+        */\r
+       @Override\r
+       public void dispose() {\r
+               if (Gdx.gl20 != null) {\r
+                       tmpHandle.clear();\r
+                       tmpHandle.put(bufferHandle);\r
+                       tmpHandle.flip();\r
+                       GL20 gl = Gdx.gl20;\r
+                       gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, 0);\r
+                       gl.glDeleteBuffers(1, tmpHandle);\r
+                       bufferHandle = 0;\r
+               } else {\r
+                       tmpHandle.clear();\r
+                       tmpHandle.put(bufferHandle);\r
+                       tmpHandle.flip();\r
+                       GL11 gl = Gdx.gl11;\r
+                       gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);\r
+                       gl.glDeleteBuffers(1, tmpHandle);\r
+                       bufferHandle = 0;\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Returns the VBO handle\r
+        * @return the VBO handle\r
+        */\r
+       public int getBufferHandle() {\r
+               return bufferHandle;\r
+       }\r
+}\r