I'm building an opengl es app for android and I have some issues compiling the shaders. Does anyone know how I could get the shaderInfoLog displayed on the screen?
Here's some code for better comprehension:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
surfaceView=new GLSurfaceView(this);
Renderer renderer = new Renderer();
surfaceView.setEGLContextClientVersion(2);
surfaceView.setRenderer(renderer);
setContentView(surfaceView);
}
}
Renderer class
public class Renderer implements GLSurfaceView.Renderer{
private Object tri;
private int glError = 0;
Renderer(){
}
public void onSurfaceCreated(GL10 gl,EGLConfig config){
float[] positions = //simple quad vertices
{0.5f,0.5f,0.0f,
0.5f,-0.5f,0.0f,
-0.5f,-0.5f,0.0f,
-0.5f,0.5f,0.0f};
int[] index = {1,2,4,2,4,3}; //simple quad indices
ObjectLoader loader = new ObjectLoader();
tri = loader.makeObject(positions, index);
}
public void onSurfaceChanged(GL10 gl, int width, int height){
GLES20.glViewport(0,0,width,height);
}
public void onDrawFrame(GL10 gl){
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); //here I debug opengl errors as different colored backgrounds
GLES20.glClearColor(1.0f,1.0f,1.0f,1.0f);
if(glError == GLES20.GL_NO_ERROR){
GLES20.glClearColor(1.0f,0.0f,0.0f,1.0f);
}else if(glError == GLES20.GL_INVALID_ENUM){
GLES20.glClearColor(0.0f,1.0f,0.0f,1.0f);
}else if(glError == GLES20.GL_INVALID_FRAMEBUFFER_OPERATION){
GLES20.glClearColor(0.0f,0.0f,1.0f,1.0f);
}else if(glError == GLES20.GL_INVALID_OPERATION){
GLES20.glClearColor(1.0f,1.0f,0.0f,1.0f);
}else if(glError == GLES20.GL_INVALID_VALUE){
GLES20.glClearColor(0.0f,1.0f,1.0f,1.0f);
}else if(glError == GLES20.GL_OUT_OF_MEMORY){
GLES20.glClearColor(1.0f,0.0f,1.0f,1.0f);
}
render(tri);
}
private void render(Object obj){
GLES30.glBindVertexArray(obj.vaoID);
GLES30.glEnableVertexAttribArray(0);
obj.shader.start();
GLES30.glDrawElements(GLES20.GL_TRIANGLES, obj.vertcount, GLES20.GL_UNSIGNED_INT, 0);
obj.shader.stop();
GLES30.glDisableVertexAttribArray(0);
GLES30.glBindVertexArray(0);
//get the errors for debug on the next frame
glError = GLES20.glGetError();
}
}
Object class
public class Object {
public int vaoID;
public int vertcount;
public StaticShader shader;
Object(int id, int count, StaticShader s){
vaoID = id;
vertcount = count;
shader = s;
}
}
ObjectLoader class
public class ObjectLoader {
ObjectLoader(){}
public Object makeObject(float[] positions,int[] indices){
int vaoID = CreateVAO();
bindIndicesBuffer(indices);
storeDataInVao(0,positions,vaoID);
unbindVao();
StaticShader shader = new StaticShader();
return new Object(vaoID,indices.length/3, shader);
}
private int CreateVAO(){
int[] vaoID = new int[1];
GLES30.glGenVertexArrays(1,vaoID,0);
GLES30.glBindVertexArray(vaoID[0]);
return vaoID[0];
}
private void storeDataInVao(int index,float[] data, int vaoID){
int[] vboID = new int[1];
GLES20.glGenBuffers(1,vboID,0);
GLES30.glBindBuffer(GLES20.GL_ARRAY_BUFFER,vboID[0]);
FloatBuffer floatbuffer = makeFloatBuffer(data);
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER,data.length*4,floatbuffer,GLES30.GL_STATIC_DRAW);
GLES30.glVertexAttribPointer(index, 3, GLES30.GL_FLOAT,false,0,0);
GLES30.glBindBuffer(GLES20.GL_ARRAY_BUFFER,0);
}
private void bindIndicesBuffer(int[] indices){
int[] vboID = new int[1];
GLES20.glGenBuffers(1,vboID,0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER,vboID[0]);
IntBuffer buffer = makeIntBuffer(indices);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER,indices.length,buffer,GLES20.GL_STATIC_DRAW);
}
private IntBuffer makeIntBuffer(int[] data){
IntBuffer buffer = ByteBuffer.allocateDirect(data.length*4).order(ByteOrder.nativeOrder()).asIntBuffer();
buffer.put(data);
buffer.flip();
return buffer;
}
private FloatBuffer makeFloatBuffer(float[] array){
FloatBuffer floatbuffer = ByteBuffer.allocateDirect(array.length*4).order(ByteOrder.nativeOrder()).asFloatBuffer();
floatbuffer.put(array);
floatbuffer.flip();
return floatbuffer;
}
private void unbindVao(){
GLES30.glBindVertexArray(0);
}
}
StaticShader just calls the constructor of ShaderProgram, so I'll just put ShaderProgram
public abstract class ShaderProgram {
private int programID;
private int vertexShader;
private int fragmentShader;
public String shaderError = "none";
private String vertCode = "void main(){gl_Position = vec4(0.0,0.0,0.0,1.0);}";
private String fragCode = "void main(){gl_FragColor = vec4(1.0,1.0,1.0,1.0);}";
ShaderProgram(){
vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertCode);
fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragCode);
programID = GLES20.glCreateProgram();
GLES20.glAttachShader(programID, fragmentShader);
GLES20.glAttachShader(programID, vertexShader);
GLES20.glLinkProgram(programID);
GLES20.glValidateProgram(programID);
}
abstract void bindAttributes();
private int loadShader(int type, String code){
int shader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
if(shader == 0){
System.exit(-1);
}
GLES20.glShaderSource(shader, code);
if(GLES20.glGetError() == GLES20.GL_INVALID_OPERATION){
//System.exit(-1);
}
GLES20.glCompileShader(shader);
final int[] compileStatus = new int[1];
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
if (compileStatus[0] == 0)
{
shaderError = GLES20.glGetShaderInfoLog(shader);
GLES20.glDeleteShader(shader);
shader = 0;
//System.exit(-1);
}
return shader;
}
public void start(){
GLES20.glUseProgram(programID);
}
public void stop(){
GLES20.glUseProgram(0);
}
}
My goal is to display ShaderProgram.shaderError on the screen by any means.
I think I should also say that GLSurfaceView isn't initiated until MainActivity.onCreate() is done, that GLSurfaceView is on a different thread to MainActivity and that GLSurfaceView doesn't have access to MainActivity's context, making it impossible to use Toast.makeText().
For those who don't want to read the entire code, here's the hierachy:
MainActivity - creates a thread for GLSurfaceView that isn't initiated before MainActivity is done--> GLSurfaceView
GLSurfaceView
|
Renderer
|
ObjectLoader
|
StaticShader+Object
|
ShaderProgram
This is an old post of mine, but I ultimatly found the solution (in Java):
//shader is the shader ID returned by GLES30.glCreateShader();
final int[] compileStatus = new int[1];
GLES30.glGetShaderiv(shader, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
if(compileStatus[0] == 0){
System.err.println("[HERE ->] " + GLES30.glGetShaderInfoLog(shader));
Log.e("Shader Source : ", GLES30.glGetShaderSource(shader));
}
It will print the shader error and the source code afterwards