Opengl 3.2 SimpleJOGL

To get starting with OpenGL 3.2 I was trying to port the SimpleJOGL example using only not deprecated functions. But the screen remains black and the triangle is not drawing. I guess its something small missing that I don’t realize now.
I couldn’t find any JOGL working example using OpenGL 3.2 to make a comparison but maybe
some one have an idea or a hint? Thanks.



[b]SimpleJOGL3.java[/b]

import com.sun.opengl.util.Animator;
import com.sun.opengl.util.BufferUtil;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import javax.media.opengl.DebugGL3;
import javax.media.opengl.GL3;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;

public class SimpleJOGL3 implements GLEventListener {

  private int iData;
  private int iVertex;
  private int iFragment;
  private int iProgram;
  private int iModelView;
  private int iProjection;
  private int iVao;
  private float projection[] = new float[16];
  private float view[] = new float[16];
  protected FloatBuffer dataBuffer;

  public static void main(String[] args) {
    Frame frame = new Frame("Simple JOGL Application");
    GLCapabilities capabilities = new GLCapabilities(GLProfile.get(GLProfile.GL3));
    GLCanvas canvas = new GLCanvas(capabilities);
    canvas.addGLEventListener(new SimpleJOGL3());
    frame.add(canvas);
    final Animator animator = new Animator(canvas);
    frame.addWindowListener(new WindowAdapter() {
      @Override
      public void windowClosing(WindowEvent e) {
        new Thread(new Runnable() {
          public void run() {
            animator.stop();
            System.exit(0);
          }
        }).start();
      }
    });
    frame.setSize(640, 480);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
    animator.start();
  }

  public void init(GLAutoDrawable drawable) {
    try {
      drawable.setGL(new DebugGL3(drawable.getGL().getGL3()));
      GL3 gl = drawable.getGL().getGL3();
      System.out.println("INIT GL3 IS: " + gl.getClass().getName());
      gl.setSwapInterval(1);
      gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

      dataBuffer = BufferUtil.newFloatBuffer(24);
      dataBuffer.put(0);
      dataBuffer.put(1);
      dataBuffer.put(0);
      dataBuffer.put(-1);
      dataBuffer.put(-1);
      dataBuffer.put(0);
      dataBuffer.put(1);
      dataBuffer.put(-1);
      dataBuffer.put(0);
      dataBuffer.rewind();

      iVertex = initVertexShader(gl, loadShaderFile("simple.vert"));
      iFragment = initFragmentShader(gl, loadShaderFile("simple.frag"));
      iProgram = initShaderProgram(gl, iVertex, iFragment);

      gl.glUseProgram(iProgram);
      iProjection = gl.glGetUniformLocation(iProgram, "projection");
      iModelView = gl.glGetUniformLocation(iProgram, "modelView");

      IntBuffer intBuffer = BufferUtil.newIntBuffer(1);
      gl.glGenVertexArrays(1, intBuffer);
      iVao = intBuffer.get(0);
      gl.glBindVertexArray(iVao);

      intBuffer = BufferUtil.newIntBuffer(1);
      gl.glGenBuffers(1, intBuffer);

      iData = intBuffer.get(0);
      gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, iData);
      gl.glBufferData(GL3.GL_ARRAY_BUFFER, dataBuffer.capacity() * 4, dataBuffer, GL3.GL_STATIC_DRAW);
      gl.glBindAttribLocation(iProgram, 0, "position");
      gl.glUseProgram(0);
      gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, 0);
      gl.glBindVertexArray(0);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
    GL3 gl = drawable.getGL().getGL3();
    if (height <= 0) {
      height = 1;
    }
    final float aspect = (float) width / (float) height;
    gl.glViewport(0, 0, width, height);
    perspective(45, aspect, 1, 20);
    loadViewIdentity();
  }

  public void display(GLAutoDrawable drawable) {
    GL3 gl = drawable.getGL().getGL3();
    gl.glClear(GL3.GL_COLOR_BUFFER_BIT | GL3.GL_DEPTH_BUFFER_BIT);

    gl.glBindVertexArray(iVao);
    gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, iData);
    gl.glEnableVertexAttribArray(0);

    gl.glUseProgram(iProgram);
    view[12] = -1.5f;
    view[13] = 0;
    view[14] = -6.0f;

    gl.glUniformMatrix4fv(iProjection, 1, false, projection, 0);
    gl.glUniformMatrix4fv(iModelView, 1, false, view, 0);

    gl.glVertexAttribPointer(0, 3, GL3.GL_FLOAT, false, 3 * Float.SIZE, 0);
    gl.glDrawArrays(GL3.GL_TRIANGLES, 0, 3);
    gl.glUseProgram(0);
    gl.glDisableVertexAttribArray(0);
    gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, 0);
    gl.glBindVertexArray(0);
  }

  public void dispose(GLAutoDrawable drawable) {
    GL3 gl = drawable.getGL().getGL3();
    gl.glDeleteVertexArrays(1, new int[]{iVao}, 0);
    gl.glDeleteBuffers(1, new int[]{iData}, 0);
    gl.glDeleteProgram(iProgram);
  }

  private void perspective(float fovY, float aspect, float n, float f) {
    float angle = (float) Math.toRadians(fovY * 0.5);
    float cot = (float) Math.cos(angle) / (float) Math.sin(angle);
    projection[0] = cot / aspect;
    projection[1] = 0;
    projection[2] = 0;
    projection[3] = 0;
    projection[4] = 0;
    projection[5] = cot;
    projection[6] = 0;
    projection[7] = 0;
    projection[8] = 0;
    projection[9] = 0;
    projection[10] = -(f + n) / (f - n);
    projection[11] = -1;
    projection[12] = 0;
    projection[13] = 0;
    projection[14] = -(2 * f * n) / (f - n);
    projection[15] = 0;
  }

  private void loadViewIdentity() {
    view[0] = 1;
    view[1] = 0;
    view[2] = 0;
    view[3] = 0;
    view[4] = 0;
    view[5] = 1;
    view[6] = 0;
    view[7] = 0;
    view[8] = 0;
    view[9] = 0;
    view[10] = 1;
    view[11] = 0;
    view[12] = 0;
    view[13] = 0;
    view[14] = 0;
    view[15] = 1;
  }

  private int initVertexShader(GL3 gl, String[] vp) {
    int vo = gl.glCreateShader(GL3.GL_VERTEX_SHADER);
    gl.glShaderSource(vo, 1, vp, null);
    gl.glCompileShader(vo);
    printShaderlog(gl, vo);
    return vo;
  }

  private int initFragmentShader(GL3 gl, String[] fp) {
    int fo = gl.glCreateShader(GL3.GL_FRAGMENT_SHADER);
    gl.glShaderSource(fo, 1, fp, null);
    gl.glCompileShader(fo);
    printShaderlog(gl, fo);
    return fo;
  }

  private int initShaderProgram(GL3 gl, int vo, int fo) {
    int po = gl.glCreateProgram();
    if (vo > 0) {
      gl.glAttachShader(po, vo);
    }
    if (fo > 0) {
      gl.glAttachShader(po, fo);
    }
    gl.glBindFragDataLocation(po, 0, "fragmentColor");
    gl.glLinkProgram(po);
    gl.glValidateProgram(po);
    printProgramlog(gl, po);
    return po;
  }

  private void printShaderlog(GL3 gl, int shader) {
    IntBuffer intBuffer = BufferUtil.newIntBuffer(1);
    gl.glGetShaderiv(shader, GL3.GL_INFO_LOG_LENGTH, intBuffer);
    int infoLength = intBuffer.get(0);
    if (infoLength > 1) {
      ByteBuffer byteBuffer = BufferUtil.newByteBuffer(infoLength);
      gl.glGetShaderInfoLog(shader, infoLength, intBuffer, byteBuffer);
      byteBuffer.rewind();
      byte dst[] = new byte[byteBuffer.capacity()];
      byteBuffer.get(dst, 0, byteBuffer.capacity());
      String message = new String(dst);
      gl.glDeleteShader(shader);
      System.out.println(message);
      throw new IllegalStateException(message);
    }
  }

  private void printProgramlog(GL3 gl, int program) {
    IntBuffer intBuffer = BufferUtil.newIntBuffer(1);
    gl.glGetProgramiv(program, GL3.GL_INFO_LOG_LENGTH, intBuffer);
    int infoLength = intBuffer.get(0);
    if (infoLength > 1) {
      ByteBuffer byteBuffer = BufferUtil.newByteBuffer(infoLength);
      gl.glGetProgramInfoLog(program, infoLength, intBuffer, byteBuffer);
      byteBuffer.rewind();
      byte dst[] = new byte[byteBuffer.capacity()];
      byteBuffer.get(dst, 0, byteBuffer.capacity());
      String message = new String(dst);
      gl.glDeleteProgram(program);
      System.out.println(message);
      throw new IllegalStateException(message);
    }
  }

  public String[] loadShaderFile(String fileName) throws IOException {
    String path = "/" + fileName;
    InputStream inputStream = path.getClass().getResourceAsStream(path);
    if (inputStream == null) {
      throw new IllegalStateException("Can not load shader file: " + path);
    }
    StringBuffer stringBuffer = new StringBuffer();
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
    for (String str = bufferedReader.readLine(); str != null; str = bufferedReader.readLine()) {
      stringBuffer.append(str).append('\n');
    }
    String[] result = {stringBuffer.toString()};
    inputStream.close();
    bufferedReader.close();
    return result;
  }
}

[b]VS[/b]

#version 150 core
uniform mat4 projection;
uniform mat4 modelView;
in vec3 position;
void main(void) {
  gl_Position = projection * modelView * vec4(position, 1.0);
}

[b]FS[/b]

#version 150 core
out vec4 fragmentColor;
void main(void) {
  fragmentColor = vec4(1.0,0.0,0.0,1.0);
}


It was the wrong stride in glVertexAttribPointer, just replaced gl.glVertexAttribPointer(0, 3, GL3.GL_FLOAT, false, 3 * Float.SIZE, 0); with gl.glVertexAttribPointer(0, 3, GL3.GL_FLOAT, false, 0, 0); and that will do the trick.
keep JOGLing.

Where do you plan to put your simple examples? I find this interesting, it allows to have rudimentary examples using only non-deprecated methods.

That’s an interesting example.

Hmm, maybe in the JOGL Netbeanspack???

IMHO there is a bug in the code.

The red book says that glBindAttribLocation can only be called before linking the program. If you don’t, then you have to use glGetAttribLocation to query for the location of the attrib instead of setting it.

I suppose it doesn’t matter here because you only use one attrib, but it should be corrected, again IMHO.

Please keep in mind that in all their infinite wisdom, Sun made Float.SIZE 32, not 4.

Yes it will be problematic when more attributes are used. However, there is a simple fix: re-linking the program


gl.glLinkProgram(iProgram); 
...
gl.glBindAttribLocation(iProgram, 0, "position");
gl.glLinkProgram(iProgram); //re-link

I think I see more problems with the code.

The VAO object stores info about the VBO and attributes. In the display() function the code does VBO binding and vertex attrib array specification, wich is not the intended use of VAOs (though it should work). In display(), only VAO binding and drawing calls should be made.

IMHO there are a few things that should be modified:

  • In init(), substitute the glBindAttribLocation call by a glGetAttribLocation since the program is already linked.
  • Move the glVertexAttribPointer call from display() to init(), using the attrib location obtained from the glGetAttribLocation call.
  • Also move the glEnableVertexAttribArray() call from display() to init().
  • Remove the glBindBuffer call in display().
  • In display(), from the three last lines:
    gl.glDisableVertexAttribArray(0);
    gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, 0);
    gl.glBindVertexArray(0);
    Only the gl.glBindVertexArray(0); is needed.