Odd NullPointerException when reproducing a Java OpenGL ES 2.0 demo in Scala
Asked Answered
G

1

6

I'm trying to reproduce this JOGL demo, a Java demo on how to use OpenGL ES 2.0, in Scala. Compiling succeeds, but trying to execute this yields the following output:

Main() called
libEGL warning: DRI2: failed to authenticate
Chosen GL capabilities: GLCaps[glx vid 0xae, fbc 0x17a: rgba 8/8/8/8,
trans-rgba 0xff/ff/ff/ff, accum-rgba 16/16/16/16, dp/st/ms 24/0/0, dbl, mono  , hw,    
GLProfile[GL2ES2/GL3.hw], on-scr[.]]
INIT GL IS: jogamp.opengl.gl4.GL4bcImpl
GL_VENDOR: NVIDIA Corporation 
GL_RENDERER: GeForce GTX 260/PCIe/SSE2
GL_VERSION: 3.3.0 NVIDIA 304.88

vertex Shader successfully compiled!
fragment Shader successfully compiled!
Exception in thread "main-Display-.x11_:0.0-1-EDT-1" java.lang.NullPointerException
at jogamp.newt.driver.x11.DisplayDriver.dispatchMessagesNative(DisplayDriver.java:103)
at jogamp.newt.DisplayImpl.dispatchMessages(DisplayImpl.java:540)
at jogamp.newt.DisplayImpl$5.run(DisplayImpl.java:463)
at jogamp.newt.DefaultEDTUtil$NEDT.run(DefaultEDTUtil.java:326)
X11Util.Display: Shutdown (JVM shutdown: true, open (no close attempt): 2/2, reusable 
(open, marked uncloseable): 0, pending (open in creation order): 2)
X11Util: Open X11 Display Connections: 2
X11Util: Open[0]: NamedX11Display[:0.0, 0x7da0cab0, refCount 1, unCloseable false]
X11Util: Open[1]: NamedX11Display[:0.0, 0x7da1bea8, refCount 1, unCloseable false]

It succeeds in rendering perhaps 1 or a few frames before the exception rises. And the expection doesn't appear when I run it from the jswat debugger.

Am I missing something really obvious? Has anyone else experienced a similar problem with Scala and OpenGL ES 2.0?

I am using Linux Mint 13 and Ant to compile and run the code. My Scala code is:

import javax.media.opengl.GL;
import javax.media.opengl.GL2ES2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.GLCapabilities;

import com.jogamp.newt.opengl.GLWindow;
import com.jogamp.opengl.util._;
import com.jogamp.common.nio.Buffers;

import java.nio.FloatBuffer;

// explicitly enabling postifx length operator:
import scala.language.postfixOps;

object RectangleDisplayer extends GLEventListener {
  val vertexShaderCode : Array[String] =
Array("#if __VERSION__ >= 130\n", 
"  #define attribute in\n",
"  #define varying out\n",
"#endif\n",

"#ifdef GL_ES\n",
"precision mediump float; \n", 
"precision mediump int; \n",
"#endif \n",

"uniform mat4    uniform_Projection; \n", 
"attribute vec4  attribute_Position;\n",  
"attribute vec4  attribute_Color;\n", 

"varying vec4    varying_Color;\n", 

"void main(void)\n", 
"{\n", 
"  varying_Color = attribute_Color;\n", 
"  gl_Position = uniform_Projection * attribute_Position;\n", 
"}\n")

  val fragmentShaderCode : Array[String] =
Array("#if __VERSION__ >= 130\n",
"  #define varying in\n",
"  out vec4 mgl_FragColor;\n",
"  #define texture2D texture\n",
"  #define gl_FragColor mgl_FragColor\n",
"#endif\n",

"#ifdef GL_ES\n",
"precision mediump float;\n",
"precision mediump int;\n",
"#endif\n",

"varying vec4 varying_Color; \n",

"void main(void)\n",
"{\n",
"  gl_FragColor = varying_Color;\n",
"}\n")

  var width : Int = 640
  var height : Int = 480

  // Scheinbar müssen in Scala alle Variablen zu Beginn initialisiert sein
  var shaderProgram : Int = 0
  var vertexShader : Int = 0
  var fragmentShader : Int = 0

  var vboHandles : Array[Int] = new Array[Int](2)
  var vboVertices : Int  = 0
  var vboColors : Int = 0

  var ModelViewProjectionMatrix_location : Int = 0


  def compileShaderIntoProgram(gl : GL2ES2, theShader : Int, shaderCode : Array[String]):Unit = {
    /*println("Shader code")
    for (l <- shaderCode) {
      print(l)
    }*/
    val lengths = shaderCode map(_ length)
    gl.glShaderSource(theShader, shaderCode.length, shaderCode, lengths, 0)
    gl.glCompileShader(theShader)
  }

  def checkCompileStatus(gl : GL2ES2, theShader: Int, which : Int):Unit = {
    var compiled : Array[Int] = Array(1)
    gl.glGetShaderiv(theShader, GL2ES2.GL_COMPILE_STATUS, compiled, 0)

    var shaderType : String = "vertex"
    if (which == 1) {
      shaderType = "fragment"
    }

    if (compiled(0) != 0) {
      println(shaderType + " Shader successfully compiled!")
    } else {
      var logLength = new Array[Int](1)
      var returnedLogLength = new Array[Int](1)

      gl.glGetShaderiv(theShader, GL2ES2.GL_INFO_LOG_LENGTH, logLength, 0)

      var log : Array[Byte] = new Array[Byte](logLength(0))
      gl.glGetShaderInfoLog(theShader, logLength(0), returnedLogLength, 0, log, 0)

      println("Error compiling "+shaderType+" shader:")
      println(new String(log))

      System.exit(1)
    }
  }

  override def init(drawable : GLAutoDrawable):Unit = {
    val gl : GL2ES2 = drawable.getGL().getGL2ES2()

    println("Chosen GL capabilities: " + drawable.getChosenGLCapabilities())
    println("INIT GL IS: " + gl.getClass().getName())
    println("GL_VENDOR: " + gl.glGetString(GL.GL_VENDOR))
    println("GL_RENDERER: " + gl.glGetString(GL.GL_RENDERER))
    println("GL_VERSION: " + gl.glGetString(GL.GL_VERSION))

    // create, compile and attach shaders
    vertexShader = gl.glCreateShader(GL2ES2.GL_VERTEX_SHADER)
    fragmentShader = gl.glCreateShader(GL2ES2.GL_FRAGMENT_SHADER)

    compileShaderIntoProgram(gl, vertexShader, vertexShaderCode)
    checkCompileStatus(gl, vertexShader, 0)

    compileShaderIntoProgram(gl, fragmentShader, fragmentShaderCode)
    checkCompileStatus(gl, fragmentShader, 1)

    shaderProgram = gl.glCreateProgram()
    gl.glAttachShader(shaderProgram, vertexShader)
    gl.glAttachShader(shaderProgram, fragmentShader)

    // Associate attribute ids with the attribute names inside the (vertex) shader
    gl.glBindAttribLocation(shaderProgram, 0, "attribute_Position")
    gl.glBindAttribLocation(shaderProgram, 1, "attribute_Color")

    gl.glLinkProgram(shaderProgram)

    ModelViewProjectionMatrix_location = gl.glGetUniformLocation(shaderProgram, "uniform_Projection")

    // forward compatibility with ES 3 by creating and binding a "Vertex Buffer Object"
    gl.glGenBuffers(2, vboHandles, 0)
    vboColors = vboHandles(0)
    vboVertices = vboHandles(1)
  }

  override def display(drawable : GLAutoDrawable):Unit = {
    val gl : GL2ES2 = drawable.getGL().getGL2ES2()

    gl.glClearColor(0.0f, 0.0f, 1.0f, 1.0f)
    gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)

    gl.glUseProgram(shaderProgram)

    // Define projection matrix
    val model_view_projection : Array[Float] = 
      Array(1.0f, 0.0f, 0.0f, 0.0f,
            0.0f, 1.0f, 0.0f, 0.0f,
            0.0f, 0.0f, 1.0f, -1.0f,
            0.0f, 0.0f, 0.0f, 1.0f)

    gl.glUniformMatrix4fv(ModelViewProjectionMatrix_location, 1, false, model_view_projection, 0)

    // Define Vertex buffer
    val vertices : Array[Float] = Array(0.0f, 1.0f, 0.0f,
                                        -1.0f, -1.0f, 0.0f,
                                        1.0f, -1.0f, 0.0f)

    var fbVertices : FloatBuffer = Buffers.newDirectFloatBuffer(vertices)
    gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vboVertices)

    var numBytes : Int = vertices.length*4
    gl.glBufferData(GL.GL_ARRAY_BUFFER, numBytes, fbVertices, GL.GL_STATIC_DRAW)
    fbVertices = null

    // Associate vertex attribute 0 with the last bound VBO
    gl.glVertexAttribPointer(0, // the vertex attribute
                              3, GL.GL_FLOAT,
                              false, // normalized?
                              0, // stride
                              0 // The bound VBO data offset
                              )
    gl.glEnableVertexAttribArray(0)


    // Define color buffer
    val colors : Array[Float] = Array(1.0f, 0.0f, 0.0f, 1.0f,
                                      0.0f, 0.0f, 0.0f, 1.0f,
                                      1.0f, 1.0f, 0.0f, 0.9f)
    var fbColors : FloatBuffer = Buffers.newDirectFloatBuffer(colors)
    gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vboColors)
    numBytes = colors.length*4
    gl.glBufferData(GL.GL_ARRAY_BUFFER, numBytes, fbColors, GL.GL_STATIC_DRAW)
    fbColors = null

    // Associate vertex attribute 1 with the last bound VBO
    gl.glVertexAttribPointer(1, 4, // four positions used for each vertex
                            GL.GL_FLOAT, false, // normalized?
                            0, // stride
                            0 // the bound VBO data offset
                            )
    gl.glEnableVertexAttribArray(1)

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

    gl.glDisableVertexAttribArray(0)
    gl.glDisableVertexAttribArray(1)

    gl.glDeleteBuffers(2, vboHandles, 0)
  }

  override def reshape(drawable : GLAutoDrawable, 
    x: Int, y: Int, z: Int, h: Int):Unit = {
      width = z
      height = h

      val gl : GL2ES2 = drawable.getGL().getGL2ES2()

      gl.glViewport(0, 0, width, height)
  }

  override def dispose(drawable : GLAutoDrawable):Unit = {
    println("cleanup operations, disposing and detaching shaders")
    val gl : GL2ES2 = drawable.getGL().getGL2ES2()

    gl.glUseProgram(0)
    gl.glDetachShader(shaderProgram, vertexShader)
    gl.glDeleteShader(vertexShader)
    gl.glDetachShader(shaderProgram, fragmentShader)
    gl.glDeleteShader(fragmentShader)

    gl.glDeleteProgram(shaderProgram)
    System.exit(0)
  }

  def main(args: Array[String]): Unit = {
    println("Main() called")

    val caps : GLCapabilities = new GLCapabilities(GLProfile.get(GLProfile.GL2ES2))
    caps.setBackgroundOpaque(false)
    var glWindow : GLWindow = GLWindow.create(caps)

    // setup window parameters
    glWindow.setTitle("Scala GL ES test")
    glWindow.setSize(width, height)
    glWindow.setUndecorated(false)
    glWindow.setPointerVisible(true)
    glWindow.setVisible(true)

    // add this class as event listener to the window
    glWindow.addGLEventListener(this)
    var animator: Animator = new Animator()
    animator.add(glWindow)
    animator.start()
  }
}
Grearson answered 15/11, 2013 at 18:24 Comment(1)
You really need to add some more logging to help narrow down what could be causing the NPE instead of providing a wall of code.Amathist
B
3

I think you need to DEBUG first. Use 'println' after gl.glcreateprogram, debug it exactly where your bug come from.

'NULL Pointer Exception' can find easier than any other weird bug. (Just for me!)

Use that way and find where exception comes out first.

Belleslettres answered 27/11, 2013 at 7:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.