The following LWJGL code is expected to render a blueish square in the center of the screen. Instead, I get a blank white screen. It's like the rendering is not working at all, or that I am rendering outside of the screen.
I'm a complete noob in OpenGL and LWJGL, so I'm out of my depth. I went through everything but can't seem to find anything that might be wrong with the code.
OpenGLTest.scala
package com.summerbulb.lwjgl
import game.graphics.VertexArray
import game.input.KeyboardInput
import org.lwjgl.glfw.GLFW._
import org.lwjgl.glfw.GLFWVidMode
import org.lwjgl.opengl.GL
import org.lwjgl.opengl.GL11._
import org.lwjgl.opengl.GL20._
import org.lwjgl.system.MemoryUtil.NULL
import scala.collection.mutable
class OpenGLTest() extends Runnable {
val width: Int = 1280
val height: Int = 720
var isRunning = false
var window: Long = 0L
val vertices = Array[Float](
-0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, -0.5f, -0.5f
)
val indices = Array[Byte](
0, 1, 2,
2, 3, 0
)
val textureCoordinates = Array[Float](
0, 1,
0, 0,
1, 0,
1, 1
)
val vertShader =
"#version 400 core\n" +
"\n" +
"layout (location = 0) in vec4 position;\n" +
"layout (location = 1) in vec2 tc;\n" +
"\n" +
// "uniform mat4 pr_matrix;\n" +
"\n" +
"void main()\n" +
"{\n" +
" gl_Position = position;\n" +
"}"
val fragShader =
"#version 400 core\n" +
"\n" +
"layout (location = 0) out vec4 color;\n" +
"\n" +
"void main()\n" +
"{\n" +
" color = vec4(0.2, 0.3, 0.8, 1.0);\n" +
"}"
lazy val background = new VertexArray(vertices, indices, textureCoordinates)
lazy val shaderProgramId = createShaderProgram(vertShader, fragShader)
val cache = mutable.Map[String, Int]()
def getUniform(name: String) = {
if (cache.contains(name))
cache(name)
else {
val location = glGetUniformLocation(shaderProgramId, name)
if (location == -1) {
System.err.println("Could not find uniform variable '" + name + "'!")
} else {
cache.put(name, location)
}
location
}
}
def start() = {
isRunning = true
val thread = new Thread(this, "OpenGlTest")
thread.start()
}
def init(): Unit = {
if (!glfwInit()) {
throw new Exception("Unable to initialize GLFW")
}
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3)
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3)
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE)
window = glfwCreateWindow(width, height, "OpenGlTest", NULL, NULL)
if (window == null) {
throw new Exception("Could not create window.")
}
val vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor())
glfwSetWindowPos(window, (GLFWVidMode.WIDTH - width) / 2, (GLFWVidMode.HEIGHT - height) / 2)
glfwSetKeyCallback(window, new KeyboardInput())
glfwMakeContextCurrent(window)
glfwShowWindow(window)
GL.createCapabilities()
glClearColor(1.0f, 1.0f, 1.0f, 1.0f)
glEnable(GL_DEPTH_TEST | GL_DEPTH_BUFFER_BIT)
println("OpenGL: " + glGetString(GL_VERSION))
}
override def run(): Unit = {
init()
while (isRunning) {
update()
render()
if (glfwWindowShouldClose(window))
isRunning = false
}
}
def update(): Unit = {
glfwPollEvents()
// ESC closes the window
if (KeyboardInput.keys(GLFW_KEY_ESCAPE)) {
isRunning = false
}
}
def render(): Unit = {
glClear(GL_COLOR_BUFFER_BIT)
glUseProgram(shaderProgramId)
background.render()
glUseProgram(0)
glfwSwapBuffers(window)
}
def createShaderProgram(vert: String, frag: String): Int = {
val program:Int = glCreateProgram()
val vertID = glCreateShader(GL_VERTEX_SHADER)
val fragID = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(vertID, vert)
glShaderSource(fragID, frag)
glCompileShader(vertID)
if (glGetShaderi(vertID, GL_COMPILE_STATUS) != GL_TRUE) {
val infoLog = glGetShaderInfoLog(vertID)
throw new Exception("Failed to compile vertex shader.\nDetails:\n" + infoLog)
}
glCompileShader(fragID)
if (glGetShaderi(fragID, GL_COMPILE_STATUS) != GL_TRUE) {
val infoLog = glGetShaderInfoLog(fragID)
throw new Exception("Failed to compile fragment shader.\nDetails:\n" + infoLog)
}
glAttachShader(program, vertID)
glAttachShader(program, fragID)
glLinkProgram(program)
glValidateProgram(program)
glDeleteShader(vertID)
glDeleteShader(fragID)
val error = glGetError()
if (error != GL_NO_ERROR) {
println(error)
System.exit(200)
}
program
}
}
object OpenGLTest {
def main(args: Array[String]): Unit = {
new OpenGLTest().start()
}
}
VertexArray.scala
package game.graphics
import java.nio.{ByteBuffer, ByteOrder, FloatBuffer, IntBuffer}
import org.lwjgl.opengl.GL11._
import org.lwjgl.opengl.GL15._
import org.lwjgl.opengl.GL20._
import org.lwjgl.opengl.GL30._
class VertexArray(vertices: Array[Float], indices: Array[Byte], textureCoordinates: Array[Float]) {
val count = indices.length
val vao = glGenVertexArrays()
glBindVertexArray(vao)
val vbo = glGenBuffers()
glBindBuffer(GL_ARRAY_BUFFER, vbo)
// val verticesBuffer = BufferUtils.createFloatBuffer(vertices.length)
// verticesBuffer.put(vertices).flip()
glBufferData(GL_ARRAY_BUFFER, createFloatBuffer(vertices) , GL_STATIC_DRAW)
glVertexAttribPointer(Shader.VERTEX_ATTRIB, 3, GL_FLOAT, false, 0, 0)
glEnableVertexAttribArray(Shader.VERTEX_ATTRIB)
val tbo = glGenBuffers()
glBindBuffer(GL_ARRAY_BUFFER, tbo)
// val texCoordBuffer = BufferUtils.createFloatBuffer(textureCoordinates.length)
// texCoordBuffer.put(textureCoordinates).flip()
glBufferData(GL_ARRAY_BUFFER, createFloatBuffer(textureCoordinates), GL_STATIC_DRAW)
glVertexAttribPointer(Shader.TCOORD_ATTRIB , 2, GL_FLOAT, false, 0, 0)
glEnableVertexAttribArray(Shader.TCOORD_ATTRIB)
val ibo = glGenBuffers()
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo)
// private val indicesBuffer: ByteBuffer = BufferUtils.createByteBuffer(indices.length)
// indicesBuffer.put(indices).flip()
glBufferData(GL_ELEMENT_ARRAY_BUFFER, createByteBuffer(indices), GL_STATIC_DRAW )
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
def bind() = {
glBindVertexArray(vao)
glEnableVertexAttribArray(Shader.VERTEX_ATTRIB)
glEnableVertexAttribArray(Shader.TCOORD_ATTRIB)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo)
}
def unbind() = {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
glBindVertexArray(0)
}
def draw() = {
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_BYTE, 0)
}
def render() = {
bind()
draw()
}
def createByteBuffer(array: Array[Byte]): ByteBuffer = {
val result = ByteBuffer.allocateDirect(array.length).order(ByteOrder.nativeOrder)
result.put(array).flip
result
}
def createFloatBuffer(array: Array[Float]): FloatBuffer = {
val result = ByteBuffer.allocateDirect(array.length << 2).order(ByteOrder.nativeOrder).asFloatBuffer
result.put(array).flip
result
}
def createIntBuffer(array: Array[Int]): IntBuffer = {
val result = ByteBuffer.allocateDirect(array.length << 2).order(ByteOrder.nativeOrder).asIntBuffer
result.put(array).flip
result
}
}
The call of
glEnable(GL_DEPTH_TEST | GL_DEPTH_BUFFER_BIT)
will cause an INVALID_ENUM
error. The parameter to glEnable
has to be a single enumerator constant. The parameter is not a bit mask where, the values can be concatenated by |
.
glClearColor(1.0f, 1.0f, 1.0f, 1.0f)
glEnable(GL_DEPTH_TEST)
If you want to clear the buffers, then you've to call glClear
. The parameter of glClear
is a bit mask that indicate the buffers to be cleared:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)