When trying to render a cube using VAO in GLES30 on an android, I get the following error message:
D/emuglGLESv2_enc: sendVertexAttributes: bad offset / len!!!!!
Does anyone know what this means and how to fix it? I cannot find any documentation for it anywhere, and the functions don't act like they do in lwjgl in normal java. Here is my render class:
/**
* renders an object
* @param object - the mesh object to be rendered
*/
public void renderMesh(MeshObject object) {
// bind the vertex array
GLES30.glBindVertexArray(object.getMesh().getVAO()[0]);
// get the attrib pointers
int pAttrib = GLES30.glGetAttribLocation(shaderProgramID, "vPosition");
int nAttrib = GLES30.glGetAttribLocation(shaderProgramID, "vNormal");
int tAttrib = GLES30.glGetAttribLocation(shaderProgramID, "vTextureCoords");
// enable the attributes
GLES30.glEnableVertexAttribArray(pAttrib); // position attribute
GLES30.glEnableVertexAttribArray(nAttrib); // normal attribute
GLES30.glEnableVertexAttribArray(tAttrib); // texture attribute
// send empty data
GLES30.glVertexAttribPointer(pAttrib, 3, GLES30.GL_FLOAT, false, 3 * 4, 0);
GLES30.glVertexAttribPointer(nAttrib, 3, GLES30.GL_FLOAT, false, 3 * 4, 0);
GLES30.glVertexAttribPointer(tAttrib, 2, GLES30.GL_FLOAT, false, 2 * 4, 0);
// bind the index buffer
GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, object.getMesh().getIBO()[0]);
// bind the shader
GLES30.glUseProgram(shaderProgramID);
// bind the texture
GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, object.getMesh().getTextureID());
// get pointers to the uniform locations
int viewPositionHandle = GLES30.glGetUniformLocation(shaderProgramID, "viewPos");
int mHandle = GLES30.glGetUniformLocation(shaderProgramID, "vModel");
int vHandle = GLES30.glGetUniformLocation(shaderProgramID, "vView");
int pHandle = GLES30.glGetUniformLocation(shaderProgramID, "vProjection");
// set the uniforms
GLES30.glUniform3fv(viewPositionHandle, 1, camera.getPosition().toFloatArray(), 0);
GLES30.glUniformMatrix4fv(mHandle, 1, false, object.getModelMatrix(), 0);
GLES30.glUniformMatrix4fv(vHandle, 1, false, camera.getViewMatrix(), 0);
GLES30.glUniformMatrix4fv(pHandle, 1, false, surfaceRenderer.getProjectionMatrix(), 0);
// draw the triangles specified by the index buffer
GLES30.glDrawElements(GLES30.GL_TRIANGLES, object.getMesh().getIndices().length, GLES30.GL_UNSIGNED_INT, 0);
// unbind the shader
GLES30.glUseProgram(0);
// unbind the index buffer
GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, 0);
// disable the vertex attributes
GLES30.glDisableVertexAttribArray(pAttrib); // position attribute
GLES30.glDisableVertexAttribArray(nAttrib); // normal attribute
GLES30.glDisableVertexAttribArray(tAttrib); // texture attribute
// unbind the vertex array
GLES30.glBindVertexArray(0);
}
And here is my Mesh class:
package com.bramerlabs.productivitree.graphics_engine.graphics;
import android.opengl.GLES30;
import com.bramerlabs.productivitree.graphics_engine.math.Vertex;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
public class Mesh {
// the vertex array object
private final int[] vao = new int[1];
// the buffer objects
private final int[] pbo = new int[1]; // position buffer object
private final int[] nbo = new int[1]; // normal buffer object
private final int[] tbo = new int[1]; // texture buffer object
private final int[] ibo = new int[1]; // index buffer object
private final Vertex[] vertices;
private final int[] indices;
private final int textureID;
/**
* default constructor
*
* @param vertices - a list of vertices in the mesh
* @param indices - the order in which the vertices should be drawn
*/
public Mesh(Vertex[] vertices, int[] indices, int textureID) {
this.vertices = vertices;
this.indices = indices;
this.textureID = textureID;
}
/**
* creates the mesh
*/
public void create() {
// generate and bind the vertex array
GLES30.glGenVertexArrays(1, vao, 0);
GLES30.glBindVertexArray(vao[0]);
// generate the data arrays
// generate the position buffer object
float[] positionData = new float[vertices.length * 3];
for (int i = 0; i < vertices.length; i++) {
positionData[3 * i] = vertices[i].getPosition().getX();
positionData[3 * i + 1] = vertices[i].getPosition().getY();
positionData[3 * i + 2] = vertices[i].getPosition().getZ();
}
FloatBuffer positionBuffer = createFloatBuffer(positionData, 3);
// generate the normal buffer object
float[] normalData = new float[vertices.length * 3];
for (int i = 0; i < vertices.length; i++) {
positionData[3 * i] = vertices[i].getNormal().getX();
positionData[3 * i + 1] = vertices[i].getNormal().getY();
positionData[3 * i + 2] = vertices[i].getNormal().getZ();
}
FloatBuffer normalBuffer = createFloatBuffer(normalData, 3);
// generate the texture buffer object
float[] textureData = new float[vertices.length * 2];
for (int i = 0; i < vertices.length; i++) {
textureData[2 * i] = vertices[i].getTextureCoord().getX();
textureData[2 * i + 1] = vertices[i].getTextureCoord().getY();
}
FloatBuffer textureBuffer = createFloatBuffer(textureData, 2);
// generate the index buffer object
ByteBuffer bb = ByteBuffer.allocateDirect(indices.length * 4);
bb.order(ByteOrder.nativeOrder());
IntBuffer indexBuffer = bb.asIntBuffer();
indexBuffer.put(indices).flip();
indexBuffer.position(0);
// store the data
storeData(pbo, positionBuffer, 0, 3);
storeData(nbo, normalBuffer, 1, 3);
storeData(tbo, textureBuffer, 2, 2);
// create the index buffer
GLES30.glGenBuffers(1, ibo, 0);
GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, ibo[0]);
GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER, indexBuffer.capacity(), indexBuffer, GLES30.GL_STATIC_DRAW);
GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, 0);
}
/**
* stores buffer data in an index
*/
private void storeData(int[] location, FloatBuffer buffer, int index, int size) {
// generate a buffer at the location
GLES30.glGenBuffers(1, location, 0);
// bind the buffer
GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, location[0]);
// add the data to the buffer
GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER, buffer.capacity(), buffer, GLES30.GL_STATIC_DRAW);
// set the data type attribute
GLES30.glVertexAttribPointer(index, size, GLES30.GL_FLOAT, false, 0, 0);
// unbind the buffer
GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, 0);
}
/**
* creates a buffer
* @param data - a float array of data
* @param stride - the stride of the data
* @return - a float buffer containing the data
*/
private FloatBuffer createFloatBuffer(float[] data, int stride) {
// initialize empty float buffer
ByteBuffer bb = ByteBuffer.allocateDirect(data.length * stride * 4);
bb.order(ByteOrder.nativeOrder());
FloatBuffer dataBuffer = bb.asFloatBuffer();
// add the data to the float buffer and flip it
dataBuffer.put(data).flip();
// seek to the first position
dataBuffer.position(0);
return dataBuffer;
}
/**
* getter method
* @return - the position buffer object
*/
public int[] getPBO() {
return this.pbo;
}
/**
* getter method
* @return - the normal buffer object
*/
public int[] getNBO() {
return this.nbo;
}
/**
* getter method
* @return - the texture buffer object
*/
public int[] getTBO() {
return this.tbo;
}
/**
* getter method
* @return - the index buffer object
*/
public int[] getIBO() {
return this.ibo;
}
/**
* getter method
* @return - the vertex array object
*/
public int[] getVAO() {
return this.vao;
}
/**
* getter method
* @return - the draw order
*/
public int[] getIndices() {
return this.indices;
}
/**
* getter method
* @return - the vertices
*/
public Vertex[] getVertices() {
return this.vertices;
}
public int getTextureID() {
return this.textureID;
}
}