Skip to content

Instantly share code, notes, and snippets.

@xian
Created August 6, 2019 23:54
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 xian/3b4e1f39afe1f72cf0e57746c07ad812 to your computer and use it in GitHub Desktop.
Save xian/3b4e1f39afe1f72cf0e57746c07ad812 to your computer and use it in GitHub Desktop.
package baaahs.shaders
import org.joml.Matrix4f
import org.joml.Quaternionf
import org.lwjgl.BufferUtils
import org.lwjgl.glfw.GLFW.*
import org.lwjgl.glfw.GLFWErrorCallback
import org.lwjgl.glfw.GLFWFramebufferSizeCallback
import org.lwjgl.glfw.GLFWKeyCallback
import org.lwjgl.opengl.GL
import org.lwjgl.opengl.GL11
import org.lwjgl.opengl.GL20.*
import org.lwjgl.system.MemoryUtil.NULL
import org.lwjgl.system.MemoryUtil.memAddress
public fun main() {
ShaderExample(GlslShader.program).run()
}
interface ViewSettings {
companion object {
/**
* The distance between the viewer's eyes and the screen in some distance
* measure (such as centimeters).
*/
val distanceToScreen = 60.0
/**
* The height of the screen area in the same distance measure (such as
* centimeters).
*/
val screenHeight = 32.5
/**
* The vertical resolution of the screen in pixels.
*/
val screenHeightPx = 1200
}
}
class ShaderExample(val shader: String) {
internal lateinit var errorCallback: GLFWErrorCallback
internal lateinit var keyCallback: GLFWKeyCallback
internal lateinit var fbCallback: GLFWFramebufferSizeCallback
internal var window: Long = 0
internal var width = 300
internal var height = 300
internal var lock = Any()
internal var destroyed: Boolean = false
internal var viewProjMatrix = Matrix4f()
internal var fb = BufferUtils.createFloatBuffer(16)
internal fun run() {
try {
init()
loop()
synchronized(lock) {
destroyed = true
glfwDestroyWindow(window)
}
keyCallback.free()
fbCallback.free()
} finally {
glfwTerminate()
errorCallback.free()
}
}
internal fun init() {
glfwSetErrorCallback(GLFWErrorCallback.createPrint(System.err))
if (!glfwInit())
throw IllegalStateException("Unable to initialize GLFW")
glfwDefaultWindowHints()
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE)
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE)
glfwWindowHint(GLFW_SAMPLES, 8)
window = glfwCreateWindow(width, height, "Hello shaders!", NULL, NULL)
if (window == NULL)
throw RuntimeException("Failed to create the GLFW window")
glfwSetKeyCallback(window, object : GLFWKeyCallback() {
override fun invoke(window: Long, key: Int, scancode: Int, action: Int, mods: Int) {
if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE)
glfwSetWindowShouldClose(window, true)
}
})
glfwSetFramebufferSizeCallback(window, object : GLFWFramebufferSizeCallback() {
override fun invoke(window: Long, w: Int, h: Int) {
if (w > 0 && h > 0) {
width = w
height = h
}
}
})
val vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor())
glfwSetWindowPos(window, (vidmode!!.width() - width) / 2, (vidmode.height() - height) / 2)
glfwShowWindow(window)
val framebufferSize = BufferUtils.createIntBuffer(2)
nglfwGetFramebufferSize(window, memAddress(framebufferSize), memAddress(framebufferSize) + 4)
width = framebufferSize.get(0)
height = framebufferSize.get(1)
}
internal fun renderQuad() {
glBegin(GL11.GL_TRIANGLES)
glVertex3f(-1.0f, -1.0f, 1.0f)
glVertex3f(1.0f, -1.0f, 1.0f)
glVertex3f(-1.0f, 1.0f, 1.0f)
glVertex3f(1.0f, -1.0f, 1.0f)
glVertex3f(1.0f, 1.0f, 1.0f)
glVertex3f(-1.0f, 1.0f, 1.0f)
glEnd()
}
internal fun initOpenGLAndRenderInAnotherThread() {
glfwMakeContextCurrent(window)
glfwSwapInterval(0)
GL.createCapabilities()
glClearColor(0f, 0f, 0f, 1f)
glEnable(GL_DEPTH_TEST)
glEnable(GL_CULL_FACE)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
// Create a simple shader program
val program = glCreateProgram()
val vs = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(
vs,
"uniform mat4 viewProjMatrix;" +
"void main(void) {" +
" gl_Position = viewProjMatrix * gl_Vertex;" +
"}"
)
glCompileShader(vs)
glAttachShader(program, vs)
val fs = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(
fs,
shader
)
glCompileShader(fs)
glAttachShader(program, fs)
glLinkProgram(program)
glUseProgram(program)
// Obtain uniform location
val matLocation = glGetUniformLocation(program, "viewProjMatrix")
val resolutionLocation = glGetUniformLocation(program, "resolution")
val timeLocation = glGetUniformLocation(program, "time")
while (!destroyed) {
val thisTime = System.nanoTime()
glViewport(0, 0, width, height)
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
// Create a view-projection matrix
viewProjMatrix.setPerspective(
Math.atan((ViewSettings.screenHeight * height / ViewSettings.screenHeightPx) / ViewSettings.distanceToScreen).toFloat(),
width.toFloat() / height, 0.01f, 100.0f
)
.lookAt(
0.0f, 0.0f, 10.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f
)
// Upload the matrix stored in the FloatBuffer to the
// shader uniform.
glUniformMatrix4fv(matLocation, false, viewProjMatrix.get(fb))
// Render the grid without rotating
glUniform2f(resolutionLocation, 1000f, 1000f)
glUniform1f(timeLocation, thisTime / 1E9f)
// Render solid cube with outlines
glPolygonMode(GL_FRONT, GL_FILL)
renderQuad()
synchronized(lock) {
if (!destroyed) {
glfwSwapBuffers(window)
}
}
}
}
internal fun loop() {
/*
* Spawn a new thread which to make the OpenGL context current in and which does the
* rendering.
*/
Thread(Runnable { initOpenGLAndRenderInAnotherThread() }).start()
/* Process window messages in the main thread */
while (!glfwWindowShouldClose(window)) {
glfwWaitEvents()
}
}
companion object {
@JvmStatic
fun main(args: Array<String>) {
ShaderExample(GlslShader.program).run()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment