-
-
Save nbilyk/32a2598ccf262c7a4e663e6aae0224a6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 = 300 | |
val HEIGHT = 300 | |
// 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 100 | |
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) | |
GL20.glEnableVertexAttribArray(0) | |
// 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) | |
// Put the VBO in the attributes list at index 0 | |
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0) | |
// 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) | |
} | |
private fun loop() { | |
drawScene() | |
// Run the rendering loop until the user has attempted to close | |
// the window or has pressed the ESCAPE key. | |
while (glfwWindowShouldClose(window) == GLFW_FALSE) { | |
// 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() { | |
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) // clear the framebuffer | |
val n = 8 | |
for (i in 0..n - 1) { | |
val p = i / n.toFloat() | |
val offsetX = p * 2f - 1f | |
val s = Math.sin((p * 3f).toDouble()).toFloat() | |
val offsetY = s | |
// Vertices, the order is not important. | |
val vertices = floatArrayOf(-0.5f + offsetX, 0.5f + offsetY, 0f, // Left top ID: 0 | |
-0.5f + offsetX, -0.5f + offsetY, 0f, // Left bottom ID: 1 | |
0.5f + offsetX, -0.5f + offsetY, 0f, // Right bottom ID: 2 | |
0.5f + offsetX, 0.5f + 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 = intArrayOf(// Left bottom triangle | |
h + 0, h + 1, h + 2, // Right top triangle | |
h + 2, h + 3, h + 0) | |
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 (verticesBuffer!!.position() + vertices.size > verticesBuffer!!.limit() - vertices.size) flush() | |
} | |
private fun flush() { | |
val indicesL = indicesBuffer!!.position() | |
println("indicesL ${indicesL}") | |
if (indicesL == 0) return | |
verticesBuffer!!.flip() | |
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, verticesBuffer, GL15.GL_STATIC_DRAW) | |
verticesBuffer!!.clear() | |
indicesBuffer!!.flip() | |
GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indicesBuffer!!, GL15.GL_STATIC_DRAW) | |
indicesBuffer!!.clear() | |
highestI = -1 | |
// Draw the vertices | |
GL11.glDrawElements(GL11.GL_TRIANGLES, indicesL, GL11.GL_UNSIGNED_SHORT, 0) | |
} | |
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