Skip to content

Instantly share code, notes, and snippets.

@nbilyk

nbilyk/Main2.kt Secret

Created April 4, 2016 19:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nbilyk/e41e1f5532bde4c6428db5a48681f6e9 to your computer and use it in GitHub Desktop.
Save nbilyk/e41e1f5532bde4c6428db5a48681f6e9 to your computer and use it in GitHub Desktop.
import org.lwjgl.BufferUtils
import org.lwjgl.glfw.GLFW.*
import org.lwjgl.glfw.GLFWErrorCallback
import org.lwjgl.opengl.*
import org.lwjgl.opengl.GL11.*
import org.lwjgl.system.MemoryUtil.NULL
import java.io.File
import java.nio.FloatBuffer
import java.nio.ShortBuffer
class Main2 {
// We need to strongly reference callback instances.
private var errorCallback: GLFWErrorCallback? = null
// The window handle
private var window: Long = 0
// Quad variables
private var vaoId = 0
private var vboId = 0
private var vboiId = 0
private var verticesBuffer: FloatBuffer? = null
private var indicesBuffer: ShortBuffer? = null
fun run() {
// try {
initGl()
initShader()
setupQuad()
loop()
dispose()
// Destroy window and window callbacks
glfwDestroyWindow(window)
// } finally {
// // Terminate GLFW and free the GLFWErrorCallback
// glfwTerminate()
// errorCallback!!.free()
// }
}
private fun initGl() {
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
// Setup an error callback. The default implementation
// will print the error message in System.err.
errorCallback = GLFWErrorCallback.createPrint(System.err)
glfwSetErrorCallback(errorCallback)
// Initialize GLFW. Most GLFW functions will not work before doing this.
if (glfwInit() != GLFW_TRUE)
throw IllegalStateException("Unable to initialize GLFW")
// Configure our window
glfwDefaultWindowHints() // optional, the current window hints are already the default
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE) // the window will stay hidden after creation
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE) // the window will be resizable
val WIDTH = 1200
val HEIGHT = 800
// Create the window
window = glfwCreateWindow(WIDTH, HEIGHT, "Hello World!", NULL, NULL)
if (window == NULL)
throw RuntimeException("Failed to create the GLFW window")
// Get the resolution of the primary monitor
val vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor())
// Center our window
glfwSetWindowPos(
window,
(vidmode.width() - WIDTH) / 2,
(vidmode.height() - HEIGHT) / 2)
// Make the OpenGL context current
glfwMakeContextCurrent(window)
// Enable v-sync
glfwSwapInterval(1)
// Make the window visible
glfwShowWindow(window)
// This line is critical for LWJGL's interoperation with GLFW's
// OpenGL context, or any context that is managed externally.
// LWJGL detects the context that is current in the current thread,
// creates the GLCapabilities instance and makes the OpenGL
// bindings available for use.
GL.createCapabilities()
// And do this after glfwMakeContextCurrent(window)
GLUtil.setupDebugMessageCallback(System.err)
// Set the clear color
glClearColor(1.0f, 0.0f, 0.0f, 0.0f)
println("Vendor: ${GL11.glGetString(GL11.GL_VENDOR)}")
}
private var _program: Int = -1
private fun initShader() {
val vertexShaderSrc = """
#version 150
attribute vec4 a_position;
void main() {
gl_Position = a_position;
}"""
val fragmentShaderSrc = """
void main() {
gl_FragColor = vec4(0.0, 1.0, 0.0, 0.2);
}"""
_program = GL20.glCreateProgram()
compileShader(vertexShaderSrc, GL20.GL_VERTEX_SHADER)
compileShader(fragmentShaderSrc, GL20.GL_FRAGMENT_SHADER)
GL20.glLinkProgram(_program)
GL20.glUseProgram(_program)
}
private fun compileShader(shaderSrc: String, shaderType: Int): Int {
val shader = GL20.glCreateShader(shaderType)
GL20.glShaderSource(shader, shaderSrc)
GL20.glCompileShader(shader)
GL20.glAttachShader(_program, shader)
println("Shader info: " + GL20.glGetShaderInfoLog(shader))
return shader
}
fun setupQuad() {
// Sending data to OpenGL requires the usage of (flipped) byte buffers
indicesBuffer = BufferUtils.createShortBuffer(6 * 2)
verticesBuffer = BufferUtils.createFloatBuffer(indicesBuffer!!.capacity() * 3)
// Create a new Vertex Array Object in memory and select it (bind)
// A VAO can have up to 16 attributes (VBO's) assigned to it by default
// vaoId = GL30.glGenVertexArrays()
// GL30.glBindVertexArray(vaoId)
// Create a new Vertex Buffer Object in memory and select it (bind)
// A VBO is a collection of Vectors which in this case resemble the location of each vertex.
vboId = GL15.glGenBuffers()
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboId)
// Create a new VBO for the indices and select it (bind)
vboiId = GL15.glGenBuffers()
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, vboiId)
GL11.glEnable(GL_BLEND)
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA)
// GL11.glColor4f(0.0f, 1.0f, 0.0f, 0.2f)
// Put the VBO in the attributes list at index 0
GL20.glEnableVertexAttribArray(0)
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0)
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, verticesBuffer!!.capacity().toLong() shl 2, GL15.GL_STREAM_DRAW)
GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indicesBuffer!!.capacity().toLong() shl 1, GL15.GL_STREAM_DRAW)
}
private fun loop() {
// Run the rendering loop until the user has attempted to close
// the window or has pressed the ESCAPE key.
var i = 0f
while (glfwWindowShouldClose(window) == GLFW_FALSE) {
drawScene(i++)
// Poll for window events. The key callback above will only be
// invoked during this call.
glfwPollEvents()
Thread.sleep(50)
}
}
private var highestI = -1
private fun drawScene(dt: Float) {
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) // clear the framebuffer
val x = 16
val y = 16
for (i in 0..x - 1) {
val pX = i / x.toFloat()
val offsetX = pX * 2f - 1f
for (j in 0..y - 1) {
val pY = j / y.toFloat()
var offsetY = pY * 2f - 1f
// offsetY += Math.sin((dt / 15f + pX * 3f).toDouble()).toFloat()
val sx = 0.05f
val vertices = floatArrayOf(-sx + offsetX, sx + offsetY, 0f, // Left top ID: 0
-sx + offsetX, -sx + offsetY, 0f, // Left bottom ID: 1
sx + offsetX, -sx + offsetY, 0f, // Right bottom ID: 2
sx + offsetX, sx + offsetY, 0f // Right left ID: 3
)
// OpenGL expects to draw vertices in counter clockwise order by default
var h = (highestI + 1)
highestI += 4
val indices = if (i % 2 == 0) {
intArrayOf(
h + 0, h + 1, h + 2,
h + 2, h + 0, h + 3)
} else {
intArrayOf(
h + 1, h + 2, h + 3)
}
draw(vertices, indices)
}
}
flush()
glfwSwapBuffers(window) // swap the color buffers
}
private fun draw(vertices: FloatArray, indices: IntArray) {
verticesBuffer!!.put(vertices)
for (indice in indices) {
indicesBuffer!!.put(indice.toShort())
}
if (indicesBuffer!!.position() + indices.size >= indicesBuffer!!.limit()) flush()
}
private fun flush() {
val indicesL = indicesBuffer!!.position()
if (indicesL == 0) return
verticesBuffer!!.flip()
GL15.glBufferSubData(GL15.GL_ARRAY_BUFFER, 0, verticesBuffer!!)
verticesBuffer!!.clear()
checkError()
indicesBuffer!!.flip()
GL15.glBufferSubData(GL15.GL_ELEMENT_ARRAY_BUFFER, 0, indicesBuffer!!) // Doesn't work
// GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indicesBuffer!!, GL15.GL_STATIC_DRAW) // Works
indicesBuffer!!.clear()
highestI = -1
checkError()
// Draw the vertices
GL11.glDrawElements(GL11.GL_TRIANGLES, indicesL, GL11.GL_UNSIGNED_SHORT, 0)
checkError()
}
private fun checkError() {
val errorCode = GL11.glGetError()
if (errorCode != GL11.GL_NO_ERROR) {
throw Exception("GL ERROR: " + GLUtil.getErrorString(errorCode))
}
}
private fun dispose() {
// Disable the VBO index from the VAO attributes list
GL20.glDisableVertexAttribArray(0)
// Delete the vertex VBO
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0)
GL15.glDeleteBuffers(vboId)
// Delete the index VBO
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0)
GL15.glDeleteBuffers(vboiId)
// Delete the VAO
// GL30.glBindVertexArray(0)
// GL30.glDeleteVertexArrays(vaoId)
}
}
fun main(args: Array<String>) {
val file = File("native")
if (!file.exists()) throw RuntimeException("native folder does not exist")
System.setProperty("org.lwjgl.librarypath", file.absolutePath)
Main2().run()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment