You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

252 lines
7.1 KiB
Kotlin

package me.eater.threedom.example
import me.eater.threedom.dom.Document
import me.eater.threedom.dom.IDocument
import me.eater.threedom.dom.PlainNode
import me.eater.threedom.dom.createNode
import me.eater.threedom.example.shader.Plain
import me.eater.threedom.example.vertex.Simple
import me.eater.threedom.gl.GL
import me.eater.threedom.gl.ShaderPreProcessor
import me.eater.threedom.gl.dom.PerspectiveCamera
import me.eater.threedom.gl.dom.TriMesh
import me.eater.threedom.gl.texture.Texture
import me.eater.threedom.gl.vertex.VertexArrayObject
import me.eater.threedom.gl.vertex.VertexBuffer
import me.eater.threedom.utils.joml.toFloat
import me.eater.threedom.utils.joml.translation
import me.eater.threedom.utils.joml.vec3
import org.joml.Vector2f
import org.joml.Vector3f
import org.lwjgl.glfw.GLFW.*
import org.lwjgl.glfw.GLFWErrorCallback
import org.lwjgl.opengl.GL.createCapabilities
import org.lwjgl.opengl.GL11.*
import org.lwjgl.system.MemoryStack.stackPush
import org.lwjgl.system.MemoryUtil.NULL
import java.time.Instant
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
fun main() {
GLFWErrorCallback.createPrint(System.err).set()
if (!glfwInit()) {
println("Unable to initialize GLFW")
return
}
glfwDefaultWindowHints()
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4)
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4)
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE)
val window = glfwCreateWindow(300, 300, "Hello world", NULL, NULL)
if (window == NULL) {
println("Failed creating window")
return
}
val stack = stackPush()
val pWidth = stack.mallocInt(1)
val pHeight = stack.mallocInt(1)
// Get the window size passed to glfwCreateWindow
glfwGetWindowSize(window, pWidth, pHeight)
// Get the resolution of the primary monitor
val vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor()) ?: return
// Center the window
glfwSetWindowPos(
window,
(vidmode.width() - pWidth.get(0)) / 2,
(vidmode.height() - pHeight.get(0)) / 2
)
// Make the OpenGL context current
glfwMakeContextCurrent(window)
var width = pWidth.get(0)
var height = pHeight.get(0)
// Enable v-sync
glfwSwapInterval(1)
glfwShowWindow(window)
createCapabilities()
val doc: IDocument = Document()
val triMesh = doc.createNode<TriMesh>()
val preProcessor = ShaderPreProcessor.createDefault()
val mesh = listOf(
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f
)
val buffer = mesh
.chunked(6)
.map {
Simple().apply {
position = vec3(it[0], it[1], it[2])
normal = vec3(it[3], it[4], it[5])
}
}
.let {
VertexBuffer(it)
}
val VAO = VertexArrayObject {
buffer(Simple::position)
buffer(Simple::normal)
}
triMesh.mesh = VAO
println("Loading mesh")
println("Loading shader program")
val plainShader = Plain.load(preProcessor)
val lampShader = Plain.lamp(preProcessor)
val texture = Texture()
texture.load(Simple::class.java.getResourceAsStream("/textures/fujiwara.jpg").readAllBytes())
plainShader.apply {
objectColor = vec3(1.0, 0.5, 0.0)
lightColor = vec3(1.0, 1.0, 1.0)
}
triMesh.use(lampShader)
val empty = doc.createNode<PlainNode>()
doc.addNode(empty)
empty.addNode(triMesh)
val around = mutableListOf<TriMesh>()
val amount = 3
val deg = (PI * 2) / amount
for (i in 0 until amount) {
val trimeshDup = triMesh.clone()
trimeshDup.use(plainShader)
around.add(trimeshDup)
triMesh.addNode(trimeshDup)
trimeshDup.model {
translate(2 * sin(deg * i), 0.0, 2 * cos(deg * i))
}
}
val camera = doc.createNode<PerspectiveCamera>()
doc.addNode(camera)
glfwSetFramebufferSizeCallback(window) { _, newWidth, newHeight ->
glViewport(0, 0, newWidth, newHeight)
camera.width = newWidth.toDouble()
camera.height = newHeight.toDouble()
}
glfwSetKeyCallback(window) { _, key, _, action, _ ->
if ((key == GLFW_KEY_Q || key == GLFW_KEY_ESCAPE) && action == GLFW_RELEASE)
glfwSetWindowShouldClose(window, true)
var z = 0.0
var x = 0.0
val speed = 0.1
if (key == GLFW_KEY_UP && action != GLFW_RELEASE) {
z += speed
}
if (key == GLFW_KEY_DOWN && action != GLFW_RELEASE) {
z -= speed
}
if (key == GLFW_KEY_LEFT && action != GLFW_RELEASE) {
x += speed
}
if (key == GLFW_KEY_RIGHT && action != GLFW_RELEASE) {
x -= speed
}
if (x != 0.0 || z != 0.0) {
camera.model {
translateLocal(x, 0.0, z)
}
}
}
println("Starting render loop")
glClearColor(0.3f, 0.2f, 0.2f, 1.0f)
glEnable(GL_DEPTH_TEST)
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
empty.model {
setTranslation(0.0, 0.0, sin(Instant.now().toEpochMilli().toDouble() / 1000) - 3)
}
triMesh.model {
rotateY(0.005)
}
around.forEach {
it.model {
rotateY(-0.005)
}
}
plainShader.lightPos = triMesh.absolute.translation.toFloat()
plainShader.viewPos = camera.absolute.translation.toFloat()
doc.render(GL, camera)
glfwSwapBuffers(window)
glfwPollEvents()
}
}