bandarra.me

OpenGL SuperBible in Java: The GLBatch class

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, inNormalandinTexCoord` for the vertex position, color, normal and texture coordinate.

Again, all the code is available at http://code.google.com/p/opengl-superbible-java/