On the last tutorials, we saw information about the GLShaderManager
class. But creating a shader is just the first step to be able to render your scene. The second step is passing geometry data to your shaders. And that's where the GLBatch class comes to help.
As i did with the GLShaderManager
class, i broke the GLBatch class into more than 1 class. The first one, GLBatch.java
is just an interface with a single method, draw, that receives a single paramater, a Map that contains pointers to the attribute locations. The GLBatch
does not know the GLShader
class, making the design decoupled.
The implementation class, where the real business happens is the SimpleGLShader
. This class receives the geometry data in its contructors and uses Buffer Objects to hold the data.
There are 2 constructors available. The fist one represents the minimal data needed to create a SimpleGLBatch, which are the vertex array, the element index array and the mode that must be used to create the triangles (GL_TRIANGLES
, GL_TRIANGLE_FAN
, GL_TRIANGLE_STRIP
, etc).
The second constructor has all the data supported by the class. Besides the mode, vertex array and index array, this constructor may receive, the color array, normal array and texture array. The last 3 ones may null.
The first constructor is actually a shortcurt for the 2nd constructor.
Half of the magic from the SimpleGLBatch
happens in the constructor. The other half happens inside the draw method.
For each array of data that is not null in the constructor, we have to build OpenGL buffers using genBuffer
. Here's a sample of the code:
if (vColorData != null && vColorData.length > 0) { FloatBuffer colorData = BufferUtils.createFloatBuffer(vColorData.length); colorData.put(vColorData); colorData.flip(); colorBuffer = GL15.glGenBuffers(); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, colorBuffer); GL15.glBufferData(GL15.GL_ARRAY_BUFFER, colorData, GL15.GL_STATIC_DRAW); }
This method creates a FloatBuffer
from the the array, then generates a gl buffer. The last step is filling the GL Buffer with data. Repeat this code for the vertexData
, normalData
and textureData
.
The only difference is the index array, which has a similar code, but instead of binding to the GL_ARRAY_BUFFER
, binds to the GL_ELEMENT_ARRAY_BUFFER
.
In the draw method, we draw using the buffers created in the constructor. Heres the code:
if (attributeLocations.containsKey("inColor") && colorBuffer >= 0) { GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, colorBuffer); int colorLocation = attributeLocations.get("inColor"); GL20.glVertexAttribPointer(colorLocation, 4, GL11.GL_FLOAT, false, 4 * 4, 0); GL20.glEnableVertexAttribArray(colorLocation); }
Again, the only difference is for the index array:
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
The last step is drawing the elements with a call to glDrawElements
GL11.glDrawElements(mode, numElements, GL11.GL_UNSIGNED_SHORT, 0);
An observation is that the shaders must have a standard name for the attributes. inVertex,
inColor,
inNormaland
inTexCoord` for the vertex position, color, normal and texture coordinate.
Again, all the code is available at http://code.google.com/p/opengl-superbible-java/