package ru.dbotthepony.kstarbound.client.gl.vertex

import org.lwjgl.opengl.GL45
import ru.dbotthepony.kstarbound.client.StarboundClient
import ru.dbotthepony.kstarbound.client.gl.VertexArrayObject
import ru.dbotthepony.kstarbound.client.gl.BufferObject
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
import java.util.concurrent.Callable

/**
 * Быстрое наполнение буфера вершинами, загрузка в память видеокарты, и отрисовка
 */
class StreamVertexBuilder(
	attributes: VertexAttributes,
	type: GeometryType? = null,
	initialCapacity: Int = 32,
	val client: StarboundClient = StarboundClient.current()
) {
	val builder = VertexBuilder(attributes, type, initialCapacity)

	private val vao = client.mailbox.submit(Callable { VertexArrayObject() })
	private val vbo = client.mailbox.submit(Callable { BufferObject.VBO() })
	private val ebo = client.mailbox.submit(Callable { BufferObject.EBO() })

	private var initialized = false

	fun upload(drawType: Int = GL45.GL_DYNAMIC_DRAW) {
		if (vbo.isDone && ebo.isDone)
			builder.upload(vbo.get(), ebo.get(), drawType)
	}

	fun bind() = vao.get().bind()
	fun unbind() = vao.get().unbind()

	fun draw(primitives: Int = GL45.GL_TRIANGLES) {
		if (!initialized) {
			vao.get().elementBuffer = ebo.get()
			vao.get().bindAttributes(vbo.get(), builder.attributes)
			initialized = true
		}

		bind()

		try {
			GL45.glDrawElements(primitives, builder.indexCount, builder.indexType, 0L)
			checkForGLError()
		} finally {
			unbind()
		}
	}
}
