Renders a quad
This commit is contained in:
parent
6ede022d4f
commit
6e8cfc7329
|
|
@ -7,7 +7,7 @@ import org.lwjgl.system.MemoryUtil.*
|
|||
import kotlin.system.exitProcess
|
||||
|
||||
fun main() {
|
||||
if (!glfwInit()) {
|
||||
/*if (!glfwInit()) {
|
||||
exitProcess(1)
|
||||
}
|
||||
|
||||
|
|
@ -37,9 +37,12 @@ fun main() {
|
|||
glDrawArrays(GL_TRIANGLES, 0, 3)
|
||||
glfwSwapBuffers(window)
|
||||
}
|
||||
glfwTerminate()
|
||||
}
|
||||
glfwTerminate()*/
|
||||
|
||||
Render.run()
|
||||
|
||||
}
|
||||
/*
|
||||
private fun createWindow(): Long {
|
||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE)
|
||||
val window = glfwCreateWindow(800, 600, "Window Title", NULL, NULL)
|
||||
|
|
@ -47,3 +50,4 @@ private fun createWindow(): Long {
|
|||
createCapabilities()
|
||||
return window
|
||||
}
|
||||
*/
|
||||
|
|
@ -0,0 +1,242 @@
|
|||
package org.ja4.vaxel
|
||||
|
||||
import org.lwjgl.BufferUtils
|
||||
import org.lwjgl.PointerBuffer
|
||||
import org.lwjgl.glfw.GLFW.*
|
||||
import org.lwjgl.glfw.GLFWKeyCallback
|
||||
import org.lwjgl.opengl.GL
|
||||
import org.lwjgl.opengl.GL20.*
|
||||
import org.lwjgl.opengl.GL30.glBindVertexArray
|
||||
import org.lwjgl.opengl.GL30.glGenVertexArrays
|
||||
import org.lwjgl.opengl.GLUtil
|
||||
import org.lwjgl.stb.STBImage.stbi_image_free
|
||||
import org.lwjgl.stb.STBImage.stbi_load_from_memory
|
||||
import org.lwjgl.system.Callback
|
||||
import org.lwjgl.system.MemoryStack
|
||||
import org.lwjgl.system.MemoryUtil.*
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.IntBuffer
|
||||
import java.nio.channels.FileChannel
|
||||
|
||||
object Render {
|
||||
|
||||
var width = 1024
|
||||
var height = 768
|
||||
var window: Long? = null
|
||||
var program: Int? = null
|
||||
var quadProgramInputPosition: Int? = null
|
||||
var quadProgramInputTextureCoords: Int? = null
|
||||
var vao: Int? = null
|
||||
var debugProc: Callback? = null
|
||||
var keyCallback: GLFWKeyCallback? = null
|
||||
|
||||
fun init() {
|
||||
glfwInit()
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3)
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0)
|
||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE)
|
||||
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE)
|
||||
window = glfwCreateWindow(width, height, "Simple quad", NULL, NULL)
|
||||
keyCallback = 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)
|
||||
}
|
||||
}
|
||||
glfwSetKeyCallback(window!!, keyCallback)
|
||||
glfwMakeContextCurrent(window!!)
|
||||
glfwShowWindow(window!!)
|
||||
MemoryStack.stackPush().use {frame ->
|
||||
val framebufferSize = frame.mallocInt(2)
|
||||
nglfwGetFramebufferSize(window!!, memAddress(framebufferSize), memAddress(framebufferSize) + 4)
|
||||
width = framebufferSize.get(0)
|
||||
height = framebufferSize.get(1)
|
||||
}
|
||||
val caps = GL.createCapabilities()
|
||||
val debugProc = GLUtil.setupDebugMessageCallback()
|
||||
createTexture()
|
||||
createQuadProgram()
|
||||
createFullScreenQuad()
|
||||
}
|
||||
|
||||
fun resizeBuffer(buffer: ByteBuffer, newCapacity: Int): ByteBuffer {
|
||||
val newBuffer = BufferUtils.createByteBuffer(newCapacity)
|
||||
buffer.flip()
|
||||
newBuffer.put(buffer)
|
||||
return newBuffer
|
||||
}
|
||||
|
||||
fun ioResourceToByteBuffer(resource: String, bufferSize: Int): ByteBuffer {
|
||||
var buffer: ByteBuffer
|
||||
val url = Thread.currentThread().contextClassLoader.getResource(resource)
|
||||
?: throw IOException("Classpath resource not found: $resource")
|
||||
val file = File(url.file)
|
||||
if (file.isFile) {
|
||||
val fis = FileInputStream(file)
|
||||
val fc = fis.channel
|
||||
buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size())
|
||||
fc.close()
|
||||
fis.close()
|
||||
} else {
|
||||
buffer = BufferUtils.createByteBuffer(bufferSize)
|
||||
val source = url.openStream() ?: throw FileNotFoundException(resource)
|
||||
source.use { source ->
|
||||
val buf = ByteArray(8192)
|
||||
while (true) {
|
||||
val bytes = source.read(buf, 0, buf.size)
|
||||
if (bytes == -1) {
|
||||
break;
|
||||
}
|
||||
if (buffer.remaining() < bytes) {
|
||||
buffer = resizeBuffer(buffer, Math.max(buffer.capacity() * 2, buffer.capacity() - buffer.remaining() + bytes))
|
||||
}
|
||||
buffer.put(buf, 0, bytes)
|
||||
}
|
||||
buffer.flip()
|
||||
}
|
||||
}
|
||||
return buffer
|
||||
}
|
||||
|
||||
fun createShader(resource: String, type: Int): Int {
|
||||
return createShader(resource, type, null)
|
||||
}
|
||||
|
||||
fun createShader(resource: String, type: Int, version: String?): Int {
|
||||
val shader = glCreateShader(type)
|
||||
val source = ioResourceToByteBuffer(resource, 8192)
|
||||
val strings: PointerBuffer
|
||||
val lengths: IntBuffer
|
||||
if (version == null) {
|
||||
strings = BufferUtils.createPointerBuffer(1)
|
||||
lengths = BufferUtils.createIntBuffer(1)
|
||||
|
||||
strings.put(0, source)
|
||||
lengths.put(0, source.remaining())
|
||||
} else {
|
||||
strings = BufferUtils.createPointerBuffer(2)
|
||||
lengths = BufferUtils.createIntBuffer(2)
|
||||
|
||||
val preamble = memUTF8("#version $version\n", false)
|
||||
|
||||
strings.put(0, preamble)
|
||||
lengths.put(0, preamble.remaining())
|
||||
|
||||
strings.put(1, source)
|
||||
lengths.put(1, source.remaining())
|
||||
}
|
||||
glShaderSource(shader, strings, lengths)
|
||||
glCompileShader(shader)
|
||||
val compiled = glGetShaderi(shader, GL_COMPILE_STATUS)
|
||||
val shaderLog = glGetShaderInfoLog(shader)
|
||||
if (shaderLog.trim().isNotEmpty()) {
|
||||
System.err.println(shaderLog)
|
||||
}
|
||||
if (compiled == 0) {
|
||||
throw AssertionError("Could not compile shader")
|
||||
}
|
||||
return shader
|
||||
}
|
||||
|
||||
fun createQuadProgram() {
|
||||
program = glCreateProgram()
|
||||
val vshader = createShader("texturedQuad.vs", GL_VERTEX_SHADER)
|
||||
val fshader = createShader("texturedQuad.fs", GL_FRAGMENT_SHADER)
|
||||
glAttachShader(program!!, vshader)
|
||||
glAttachShader(program!!, fshader)
|
||||
glLinkProgram(program!!)
|
||||
val linked = glGetProgrami(program!!, GL_LINK_STATUS)
|
||||
val programLog = glGetProgramInfoLog(program!!)
|
||||
if (programLog.trim().isNotEmpty()) {
|
||||
System.err.println(programLog)
|
||||
}
|
||||
if (linked == 0) {
|
||||
throw AssertionError("Could not link program")
|
||||
}
|
||||
glUseProgram(program!!)
|
||||
val texLocation = glGetUniformLocation(program!!, "tex")
|
||||
glUniform1i(texLocation, 0)
|
||||
quadProgramInputPosition = glGetAttribLocation(program!!, "position")
|
||||
quadProgramInputTextureCoords = glGetAttribLocation(program!!, "texCoords")
|
||||
glUseProgram(0)
|
||||
}
|
||||
|
||||
fun createFullScreenQuad() {
|
||||
vao = glGenVertexArrays()
|
||||
glBindVertexArray(vao!!)
|
||||
val positionVbo = glGenBuffers()
|
||||
var fb = BufferUtils.createFloatBuffer(2 * 6)
|
||||
fb.put(-1.0f).put(-1.0f)
|
||||
fb.put(1.0f).put(-1.0f)
|
||||
fb.put(1.0f).put(1.0f)
|
||||
fb.put(1.0f).put(1.0f)
|
||||
fb.put(-1.0f).put(1.0f)
|
||||
fb.put(-1.0f).put(-1.0f)
|
||||
fb.flip()
|
||||
glBindBuffer(GL_ARRAY_BUFFER, positionVbo)
|
||||
glBufferData(GL_ARRAY_BUFFER, fb, GL_STATIC_DRAW)
|
||||
glVertexAttribPointer(quadProgramInputPosition!!, 2, GL_FLOAT, false, 0, 0L)
|
||||
glEnableVertexAttribArray(quadProgramInputPosition!!)
|
||||
val texCoordsVbo = glGenBuffers()
|
||||
fb = BufferUtils.createFloatBuffer(2 * 6)
|
||||
fb.put(0.0f).put(1.0f)
|
||||
fb.put(1.0f).put(1.0f)
|
||||
fb.put(1.0f).put(0.0f)
|
||||
fb.put(1.0f).put(0.0f)
|
||||
fb.put(0.0f).put(0.0f)
|
||||
fb.put(0.0f).put(1.0f)
|
||||
fb.flip()
|
||||
glBindBuffer(GL_ARRAY_BUFFER, texCoordsVbo)
|
||||
glBufferData(GL_ARRAY_BUFFER, fb, GL_STATIC_DRAW)
|
||||
glVertexAttribPointer(quadProgramInputTextureCoords!!, 2, GL_FLOAT, true, 0, 0L)
|
||||
glEnableVertexAttribArray(quadProgramInputTextureCoords!!)
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0)
|
||||
glBindVertexArray(0)
|
||||
}
|
||||
|
||||
fun createTexture() {
|
||||
val width = BufferUtils.createIntBuffer(1)
|
||||
val height = BufferUtils.createIntBuffer(1)
|
||||
val components = BufferUtils.createIntBuffer(1)
|
||||
val data = stbi_load_from_memory(ioResourceToByteBuffer("environment.jpg", 1024), width, height, components, 4)?: throw AssertionError("Unable to load file")
|
||||
val id = glGenTextures()
|
||||
glBindTexture(GL_TEXTURE_2D, id)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width.get(), height.get(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
|
||||
stbi_image_free(data)
|
||||
}
|
||||
|
||||
fun render() {
|
||||
glClear(GL_COLOR_BUFFER_BIT)
|
||||
glUseProgram(program!!)
|
||||
glBindVertexArray(vao!!)
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6)
|
||||
glBindVertexArray(0)
|
||||
glUseProgram(0)
|
||||
}
|
||||
|
||||
fun loop() {
|
||||
while (!glfwWindowShouldClose(window!!)) {
|
||||
glfwPollEvents()
|
||||
glViewport(0, 0, width, height)
|
||||
render()
|
||||
glfwSwapBuffers(window!!)
|
||||
}
|
||||
}
|
||||
|
||||
fun run() {
|
||||
init()
|
||||
loop()
|
||||
if (debugProc != null) {
|
||||
debugProc!!.free()
|
||||
}
|
||||
keyCallback!!.free()
|
||||
glfwDestroyWindow(window!!)
|
||||
glfwTerminate()
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 106 KiB |
|
|
@ -0,0 +1,10 @@
|
|||
#version 130
|
||||
|
||||
uniform sampler2D tex;
|
||||
|
||||
in vec2 texCoordsVarying;
|
||||
out vec4 color;
|
||||
|
||||
void main() {
|
||||
color = texture(tex, texCoordsVarying);
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#version 130
|
||||
|
||||
in vec3 position;
|
||||
in vec2 texCoords;
|
||||
out vec2 texCoordsVarying;
|
||||
|
||||
void main() {
|
||||
texCoordsVarying = texCoords;
|
||||
gl_Position = vec4(position, 1.0);
|
||||
}
|
||||
Loading…
Reference in New Issue