Java Port of www.arcsynthesis.org Hello, Triangle!

Hi

I was trying to build a Java port of the Hello, Triangle! tut1.cpp example at:

www.arcsynthesis.org

It fails at the linking stage in createProgram() with “status” equal to 0.

Does anyone know why?

Thanks

Graham

===

package modern_gl_prog;

// java
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import java.awt.Canvas;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
// gl
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GL3;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLCanvas;
import com.jogamp.common.nio.Buffers;

public class tut1 extends JFrame
{
private JPanel contentPane;
private Canvas canvas;

/**
 * Launch the application.
 */
public static void main(String[] args)
{
    EventQueue.invokeLater(new Runnable()
    {
        public void run()
        {
            try
            {
                tut1 frame = new tut1();
                frame.setVisible(true);
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    });
}

/**
 * Create the frame.
 */
public tut1() {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(100, 100, 545, 536);
    contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    setContentPane(contentPane);
    contentPane.setLayout(null);
    
    canvas = new tut1Canvas();
    canvas.setBounds(0, 0, 517, 390);
    contentPane.add(canvas);
    
}

} // class tut1

class tut1Canvas extends GLCanvas
implements GLEventListener
{
protected int mTheProgram; // handle to program object
protected int mPositionBufferObject; // handle to buffer object
protected int mvao; // vertex array object

protected int           mVertexCount = 3;
protected FloatBuffer   mVertexPositions = null;

public tut1Canvas()
{
    super();
    this.addGLEventListener(this);
}

/*
private void checkLogInfo(GL gl, int programObject) {
    IntBuffer intValue = BufferUtils.newIntBuffer(1);
    gl.glGetObjectParameterivARB(programObject, GL.GL_OBJECT_INFO_LOG_LENGTH_ARB, intValue);

    int lengthWithNull = intValue.get();

    if (lengthWithNull <= 1) {
        return;
    }

    ByteBuffer infoLog = BufferUtils.newByteBuffer(lengthWithNull);

    intValue.flip();
    gl.glGetInfoLogARB(programObject, lengthWithNull, intValue, infoLog);

    int actualLength = intValue.get();

    byte[] infoBytes = new byte[actualLength];
    infoLog.get(infoBytes);
    System.out.println("GLSL Validation >> " + new String(infoBytes));
}*/

private int createShader(GL2 gl, int eShaderType, String strShaderFile)
{
    int shader = gl.glCreateShader(eShaderType);
    String[] strings = new String[1]; strings[0] = strShaderFile;
    gl.glShaderSource(shader, 1, strings,(int[])null,0); // public void glShaderSource(int shader, int count, java.lang.String[] string, int[] length, int length_offset);

    gl.glCompileShader(shader);

    int[] statusArray = new int[1];
    int status;
    gl.glGetShaderiv(shader, GL2.GL_COMPILE_STATUS, statusArray,0);
    status = statusArray[0];
    if (status == GL.GL_FALSE)
    {
        int[] infoLogLengthArray = new int[1];
        int infoLogLength;
        gl.glGetShaderiv(shader, GL2.GL_INFO_LOG_LENGTH,infoLogLengthArray,0);
        infoLogLength = infoLogLengthArray[0];
        IntBuffer intValue = IntBuffer.allocate(1);
        ByteBuffer strInfoLog = Buffers.newDirectByteBuffer(infoLogLength + 1);
        gl.glGetShaderInfoLog(shader, infoLogLength, intValue, strInfoLog);

        String strShaderType = null;
        switch(eShaderType)
        {
            case GL2.GL_VERTEX_SHADER: strShaderType = "vertex"; break;
            case GL3.GL_GEOMETRY_SHADER: strShaderType = "geometry"; break;
            case GL2.GL_FRAGMENT_SHADER: strShaderType = "fragment"; break;
        }

        System.out.println("Compile failure in " + strShaderType + " shader: " + strInfoLog);
    }

    return shader;
}

private int createProgram(GL2 gl, int[] shaderList)
{
    int program = gl.glCreateProgram();

    for(int iLoop = 0; iLoop < shaderList.length; iLoop++)
    {
        gl.glAttachShader(program, shaderList[iLoop]);
    }

    gl.glLinkProgram(program);

    //gl.glValidateProgram(program);
    
    int[] statusArray = new int[1];
    int status;
    gl.glGetProgramiv(program,GL2.GL_LINK_STATUS,statusArray,0);
    status = statusArray[0];
    if (status == GL.GL_FALSE)
    {
        int[] infoLogLengthArray = new int[1];
        int infoLogLength;
        gl.glGetShaderiv(program, GL2.GL_INFO_LOG_LENGTH,infoLogLengthArray,0);
        infoLogLength = infoLogLengthArray[0];

        IntBuffer intValue = IntBuffer.allocate(1);
        ByteBuffer strInfoLog = ByteBuffer.allocate(infoLogLength + 1);
        gl.glGetProgramInfoLog(program, infoLogLength, intValue, strInfoLog);
        System.out.println("Linker failure: " + strInfoLog);
    }

    for(int iLoop = 0; iLoop < shaderList.length; iLoop++)
    {
        gl.glDetachShader(program, shaderList[iLoop]);
    }

    return program;
}    

public String strVertexShader()
{
    String s = new String();
    s += "#version 330

";
s += "layout(location = 0) in vec4 position;
";
s += "void main()
";
s += "{
";
s += " gl_Position = position;
";
s += "}
";
return s;
}

public String strFragmentShader()
{
    String s = new String();
    s += "#version 330

";
s += "out vec4 outputColor;
";
s += "void main()
";
s += "{
";
s += " outputColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);
";
s += "}
";
return s;
};

void initializeProgram(GL2 gl)
{
    String  vertexShaderString      = strVertexShader();
    String  fragmentShaderString    = strFragmentShader();
    int     vertexShader            = createShader(gl,GL2.GL_VERTEX_SHADER,vertexShaderString);
    int     fragmentShader          = createShader(gl,GL2.GL_VERTEX_SHADER,fragmentShaderString);
    int[] shaderList = new int[2];
    shaderList[0] = vertexShader;
    shaderList[1] = fragmentShader;
    
    mTheProgram = createProgram(gl,shaderList);
}

void initializeVertexBuffer(GL2 gl)
{
    int[] array = new int[1];
    gl.glGenBuffers(1, array, 0);
    mPositionBufferObject = array[0];

    // allocate vertex buffer [3 for (x,y,z,w) for each vertex]
    mVertexPositions = FloatBuffer.allocate(4*mVertexCount);
    mVertexPositions.put(0.75f);  mVertexPositions.put(0.75f);  mVertexPositions.put(0.75f); mVertexPositions.put(1.0f);
    mVertexPositions.put(0.75f);  mVertexPositions.put(-0.75f); mVertexPositions.put(0.0f);  mVertexPositions.put(1.0f);
    mVertexPositions.put(-0.75f); mVertexPositions.put(-0.75f); mVertexPositions.put(0.0f);  mVertexPositions.put(1.0f);

    gl.glBindBuffer(GL2.GL_ARRAY_BUFFER,mPositionBufferObject);
    gl.glBufferData(GL2.GL_ARRAY_BUFFER,3*mVertexCount,mVertexPositions, GL2.GL_STATIC_DRAW);
    gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);
}

@Override
public void init(GLAutoDrawable gLDrawable)
{
    GL2 gl = gLDrawable.getGL().getGL2();
    
    initializeProgram(gl);
    initializeVertexBuffer(gl);

    // generate vertex array and bind
    int[] array = new int[1];
    gl.glGenVertexArrays(1,array,0);
    mvao = array[0];
    gl.glBindVertexArray(mvao);
}

@Override
public void display(GLAutoDrawable gLDrawable)
{
    final GL2 gl = gLDrawable.getGL().getGL2();
    gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

    gl.glUseProgram(mTheProgram);

    gl.glBindBuffer(GL2.GL_ARRAY_BUFFER,mPositionBufferObject);
    gl.glEnableVertexAttribArray(0);
    gl.glVertexAttribPointer(0, 4, GL.GL_FLOAT,false, 0, 0);

    gl.glDrawArrays(GL.GL_TRIANGLES, 0, 3);

    gl.glDisableVertexAttribArray(0);
    gl.glUseProgram(0);

    gLDrawable.swapBuffers();
}

@Override
public void reshape(GLAutoDrawable gLDrawable, int x, int y, int width, int height)
{       
    GL2 gl = gLDrawable.getGL().getGL2();
    if (height <= 0)
    {
        height = 1;
    }
    gl.glViewport(0,0,width,height);
}

@Override
public void dispose(GLAutoDrawable arg0)
{
    // do nothing
}

} // class tut1Canvas

int fragmentShader = createShader(gl,GL2.GL_VERTEX_SHADER,fragmentShaderString);

should probably be:

int fragmentShader = createShader(gl,GL2.GL_FRAGMENT_SHADER,fragmentShaderString);

Hi

Thanks for your prompt reply.

I corrected the copy&paste error and it now passes the linker stage fine.

I noticed that the size in bytes passed to glBufferData() in initializeVertexBuffer() was incorrect and should have read:
gl.glBufferData(GL2.GL_ARRAY_BUFFER,4mVertexCountBuffers.SIZEOF_FLOAT,mVertexPositions,GL2.GL_STATIC_DRAW);

However, I still don’t see a white triangle!

Cheers

Graham

Hi

When I run this tutorial on my PC I don’t get any compile/lnk errors but when I run it on my laptop all fail:

Compile failure in vertex shader: java.nio.DirectByteBuffer[pos=0 lim=241 cap=241]
Compile failure in fragment shader: java.nio.DirectByteBuffer[pos=0 lim=183 cap=183]
Linker failure: java.nio.HeapByteBuffer[pos=0 lim=1 cap=1]

My PC has an Nvidia Quadro card and my laptop has an ATI Radeon.

Thanks

Graham

java.nio.HeapByteBuffer[pos=0 lim=1 cap=1]

that is not a glGetProgramInfoLog() message, should your log printing perhaps look something like this (I don’t know the OpenGL java bindings, but you get the idea):


System.out.println("Linker failure: " + strInfoLog.asCharBuffer().toString());

? That should show the contents of the ByteBuffer strInfoLog, not information about its type and size.
With that info it should then be possible to figure out why compiling/linking fails.

Hi

Thanks - I added strInfoLog.asCharBuffer().toString());

but the output is a series of unknown characters. Stepping through with the debugger reveals the characters to be non-ascii.

Typical output:

Compile failure in vertex shader: ???›???›???›???

Compile failure in fragment shader: ???›???›???

Linker failure:

Hmm, ok, you’ll have to find out how to get readable output from the ByteBuffer then, I’m not familiar enough with the java libraries to help, sorry.
Sounds almost like this would be a FAQ for the java bindings, but my quick search did not turn up anything.

Hi

Thanks - the ByteBuffer requires decoding, in the present case using the system encoding:

        String      encoding    = System.getProperty("file.encoding");
        CharBuffer  charBuff    = Charset.forName(encoding).decode(strInfoLog);
        String      buffString  = charBuff.toString();
        String      msg         = "Compile failure in " + strShaderType + " shader: " + buffString;

Thanks again for your help.

Graham

Hi

The compile output is as follows:

Compile failure in vertex shader: Vertex shader failed to compile with the following errors:
ERROR: 0:1: error(#106) Version number not supported by GL2
ERROR: 0:2: error(#279) Invalid layout qualifier ‘location’
ERROR: error(#273) 2 compilation errors. No code generated

and is thus failing due to an unsupported version number, which is set to 330.

I added a constructor to explicitly specify a GLCaps:

    // OPenGL 2.1 profile
    GLProfile prof = GLProfile.get(GLProfile.GL2);
    GLCapabilities caps = new GLCapabilities(prof);
    canvas = new tut1Canvas(caps);

But I still get the error.

I am using jogl-2.0-b41-20110916-windows-amd64 downloaded from jogamp.org.

Thanks

Graham

My tutorials are for GL 3.3 and above. If your hardware/drivers do not support GL 3.3, then there’s not much that can be done. Well, you could try to translate the code, but that would be difficult.