VAO and VBO

Started by Meanz, September 21, 2011, 20:57:15

Previous topic - Next topic

Meanz

Well, I only recently learned about VAO's and VBO's. And I wanted to share my discovery.
Also I wanted feedback on how to improve my current techniques. They are sloppy indeed ;)

import java.nio.FloatBuffer;
import org.lwjgl.opengl.ARBVertexArrayObject;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.lwjgl.opengl.ARBVertexBufferObject;
import org.lwjgl.util.vector.Vector2f;
import org.lwjgl.util.vector.Vector3f;

import static org.lwjgl.opengl.GL11.*;

public class VBO {

    private final static int intSize = Integer.SIZE / 8;
    private final static int floatSize = Float.SIZE / 8;
    private final static int doubleSize = Double.SIZE / 8;
    private final static int verticeSize = 3 * floatSize;
    private final static int normalSize = 3 * floatSize;
    private final static int texSize = 2 * floatSize;
    private final static int colorSize = 3 * floatSize;
    private final static int elementSizeFull = verticeSize + normalSize + texSize + colorSize;
    private final static int elementSizeNoNomCol = verticeSize + texSize;
    private ByteBuffer buffer;
    private int vao, vboData, vboIndices;
    private int numVertices, numTexCoords;

    public VBO() {
        vao = createVAO();
        vboData = createVBO();
        vboIndices = createVBO();
        unbindVAO();
        numVertices = 0;
        numTexCoords = 0;
        allocate(0);
    }

    public void allocate(int size) {
        buffer = ByteBuffer.allocateDirect(size);
        buffer.order(ByteOrder.nativeOrder());
    }

    public void clear() {
        buffer.clear();
        numVertices = 0;
    }

    public void compile() {
        bindVAO(vao);
        {
            /**
             * Buffer data
             */
            bindVBO(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, vboData);
            bufferVBO(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB,
                    ARBVertexBufferObject.GL_DYNAMIC_DRAW_ARB,
                    ((ByteBuffer) buffer.flip()).asFloatBuffer());

            /**
             * Bind Atrributes
             */
            glVertexPointer(3, GL_FLOAT, elementSizeNoNomCol, 0);
            glTexCoordPointer(2, GL_FLOAT, elementSizeNoNomCol, verticeSize);
            //glColorPointer(3, GL_FLOAT, elementSize, texSize + verticeSize);
            //glNormalPointer(GL_FLOAT, elementSize, verticeSize + texSize + colorSize);

            /**
             * Buffer indices
             */
            ByteBuffer indiceBuffer = ByteBuffer.allocateDirect(numVertices * 4);
            indiceBuffer.order(ByteOrder.nativeOrder());
            for (int i = 0; i < numVertices; i++) {
                indiceBuffer.putInt(i);
            }
            bindVBO(ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, vboIndices);
            bufferVBO(ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB,
                    ARBVertexBufferObject.GL_DYNAMIC_READ_ARB,
                    ((ByteBuffer)indiceBuffer.flip()).asFloatBuffer());
        }
        unbindVAO();
        /** Cleanup **/
    }

    public void draw() {
        bindVAO(vao);
        {
            glEnableClientState(GL_VERTEX_ARRAY);
            //glEnableClientState(GL_NORMAL_ARRAY);
            //glEnableClientState(GL_COLOR_ARRAY);
            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
            glDrawElements(GL_QUADS, numVertices, GL_UNSIGNED_INT, 0);
            glDisableClientState(GL_VERTEX_ARRAY);
            //glDisableClientState(GL_COLOR_ARRAY);
            //glDisableClientState(GL_NORMAL_ARRAY);
            glDisableClientState(GL_TEXTURE_COORD_ARRAY);
        }
        unbindVAO();
    }

    public ByteBuffer getBuffer() {
        return buffer;
    }

    /**
     * 
     */
    public void addFloat(float x, float y, float z) {
        buffer.putFloat(x);
        buffer.putFloat(y);
        buffer.putFloat(z);
    }

    public void addFloat(float x, float y) {
        buffer.putFloat(x);
        buffer.putFloat(y);
    }

    public void addVertex(Vector3f vert) {
        addVertex(vert.x, vert.y, vert.z);
    }

    public void addVertex(float x, float y, float z) {
        addFloat(x, y, z);
        numVertices++;
    }

    public void addTexCoord(Vector2f texCoord) {
        addTexCoord(texCoord.x, texCoord.y);
    }

    public void addTexCoord(float x, float y) {
        addFloat(x, y);
        numTexCoords++;
    }

    public void addNormal(Vector3f normal) {
        addNormal(normal.x, normal.y, normal.z);
    }

    public void addNormal(float x, float y, float z) {
        addFloat(x, y, z);
    }

    public void bufferVBO(int target, int type, FloatBuffer buffer) {
        ARBVertexBufferObject.glBufferDataARB(target, buffer, type);
    }

    public void bindVAO(int vao) {
        ARBVertexArrayObject.glBindVertexArray(vao);
    }

    public void bindVBO(int target, int vbo) {
        ARBVertexBufferObject.glBindBufferARB(target, vbo);
    }

    public void unbindVAO() {
        ARBVertexArrayObject.glBindVertexArray(0);
    }

    public int createVAO() {
        return ARBVertexArrayObject.glGenVertexArrays();
    }

    public int createVBO() {
        return ARBVertexBufferObject.glGenBuffersARB();
    }
}

Chuck

Pretty nifty!  Looks like a big help in abstracting out all that boilerplate around VBOs.

Meanz

@Chuck
Well, it does lack some obvious stuff. And that is the fact that I am assuming I won't reuse the same vertices, since I am creating the indexes on the fly. Also I have this feeling that I am missing something, but can't put my tongue on it. But anyways, this was my first attempt at creating a VAO, and I am going to create a basic framework or whatever you want to call it, to abstract out most of the heavy operations of vao's and vbo's.