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
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
if (!glfwInit()) {
|
/*if (!glfwInit()) {
|
||||||
exitProcess(1)
|
exitProcess(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,9 +37,12 @@ fun main() {
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 3)
|
glDrawArrays(GL_TRIANGLES, 0, 3)
|
||||||
glfwSwapBuffers(window)
|
glfwSwapBuffers(window)
|
||||||
}
|
}
|
||||||
glfwTerminate()
|
glfwTerminate()*/
|
||||||
}
|
|
||||||
|
|
||||||
|
Render.run()
|
||||||
|
|
||||||
|
}
|
||||||
|
/*
|
||||||
private fun createWindow(): Long {
|
private fun createWindow(): Long {
|
||||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE)
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE)
|
||||||
val window = glfwCreateWindow(800, 600, "Window Title", NULL, NULL)
|
val window = glfwCreateWindow(800, 600, "Window Title", NULL, NULL)
|
||||||
|
|
@ -47,3 +50,4 @@ private fun createWindow(): Long {
|
||||||
createCapabilities()
|
createCapabilities()
|
||||||
return window
|
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