Created
August 6, 2019 23:54
-
-
Save xian/3b4e1f39afe1f72cf0e57746c07ad812 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
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