Больше рефакторинга шейдеров, но надо ещё избавится от мусора в виде configuredshaderprogram
This commit is contained in:
parent
b85b90f74c
commit
b40f3e8dca
@ -3,8 +3,8 @@ package ru.dbotthepony.kstarbound.client
|
|||||||
import org.lwjgl.opengl.GL11.GL_LINES
|
import org.lwjgl.opengl.GL11.GL_LINES
|
||||||
import org.lwjgl.opengl.GL11.GL_TRIANGLES
|
import org.lwjgl.opengl.GL11.GL_TRIANGLES
|
||||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
||||||
import ru.dbotthepony.kstarbound.client.gl.program.GLHardLightGeometryProgram
|
import ru.dbotthepony.kstarbound.client.gl.shader.GLHardLightGeometryProgram
|
||||||
import ru.dbotthepony.kstarbound.client.gl.program.GLSoftLightGeometryProgram
|
import ru.dbotthepony.kstarbound.client.gl.shader.GLSoftLightGeometryProgram
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
|
import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
|
||||||
import ru.dbotthepony.kstarbound.client.render.ConfiguredStaticMesh
|
import ru.dbotthepony.kstarbound.client.render.ConfiguredStaticMesh
|
||||||
@ -301,10 +301,10 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
|
|||||||
renderOrigin.y * CHUNK_SIZEf + (geometry.y + 1) * SHADOW_GEOMETRY_SQUARE_SIZE)
|
renderOrigin.y * CHUNK_SIZEf + (geometry.y + 1) * SHADOW_GEOMETRY_SQUARE_SIZE)
|
||||||
) {
|
) {
|
||||||
if (!setOnce) {
|
if (!setOnce) {
|
||||||
program.localToWorldTransform.set(
|
program.localToWorldTransform.value =
|
||||||
Matrix4f.IDENTITY.translateWithMultiplication(
|
Matrix4f.IDENTITY.translateWithMultiplication(
|
||||||
Vector3f(x = renderOrigin.x * CHUNK_SIZEf,
|
Vector3f(x = renderOrigin.x * CHUNK_SIZEf,
|
||||||
y = renderOrigin.y * CHUNK_SIZEf)))
|
y = renderOrigin.y * CHUNK_SIZEf))
|
||||||
|
|
||||||
setOnce = true
|
setOnce = true
|
||||||
}
|
}
|
||||||
@ -337,10 +337,10 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
|
|||||||
renderOrigin.y * CHUNK_SIZEf + (geometry.y + 1) * SHADOW_GEOMETRY_SQUARE_SIZE)
|
renderOrigin.y * CHUNK_SIZEf + (geometry.y + 1) * SHADOW_GEOMETRY_SQUARE_SIZE)
|
||||||
) {
|
) {
|
||||||
if (!setOnce) {
|
if (!setOnce) {
|
||||||
program.localToWorldTransform.set(
|
program.localToWorldTransform.value =
|
||||||
Matrix4f.IDENTITY.translateWithMultiplication(
|
Matrix4f.IDENTITY.translateWithMultiplication(
|
||||||
Vector3f(x = renderOrigin.x * CHUNK_SIZEf,
|
Vector3f(x = renderOrigin.x * CHUNK_SIZEf,
|
||||||
y = renderOrigin.y * CHUNK_SIZEf)))
|
y = renderOrigin.y * CHUNK_SIZEf))
|
||||||
|
|
||||||
setOnce = true
|
setOnce = true
|
||||||
}
|
}
|
||||||
@ -393,7 +393,7 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
|
|||||||
val program = state.programs.liquid
|
val program = state.programs.liquid
|
||||||
|
|
||||||
program.use()
|
program.use()
|
||||||
program.transform.set(it.last)
|
program.transform.value = it.last
|
||||||
|
|
||||||
val builder = program.builder
|
val builder = program.builder
|
||||||
|
|
||||||
@ -410,7 +410,7 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
program.baselineColor.set(type.color)
|
program.baselineColor.value = type.color
|
||||||
|
|
||||||
builder.upload()
|
builder.upload()
|
||||||
builder.draw()
|
builder.draw()
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
package ru.dbotthepony.kstarbound.client.gl
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL11.*
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
data class BlendFunc(
|
||||||
|
val sourceColor: Func,
|
||||||
|
val destinationColor: Func,
|
||||||
|
val sourceAlpha: Func,
|
||||||
|
val destinationAlpha: Func
|
||||||
|
) {
|
||||||
|
constructor() : this(
|
||||||
|
Func.ONE,
|
||||||
|
Func.ZERO,
|
||||||
|
Func.ONE,
|
||||||
|
Func.ZERO
|
||||||
|
)
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
source: Func, destination: Func
|
||||||
|
) : this(
|
||||||
|
source,
|
||||||
|
destination,
|
||||||
|
source,
|
||||||
|
destination
|
||||||
|
)
|
||||||
|
|
||||||
|
enum class Func(val enum: Int) {
|
||||||
|
ZERO(GL_ZERO),
|
||||||
|
ONE(GL_ONE),
|
||||||
|
SRC_COLOR(GL_SRC_COLOR),
|
||||||
|
ONE_MINUS_SRC_COLOR(GL_ONE_MINUS_SRC_COLOR),
|
||||||
|
SRC_ALPHA(GL_SRC_ALPHA),
|
||||||
|
ONE_MINUS_SRC_ALPHA(GL_ONE_MINUS_SRC_ALPHA),
|
||||||
|
DST_ALPHA(GL_DST_ALPHA),
|
||||||
|
ONE_MINUS_DST_ALPHA(GL_ONE_MINUS_DST_ALPHA),
|
||||||
|
DST_COLOR(GL_DST_COLOR),
|
||||||
|
ONE_MINUS_DST_COLOR(GL_ONE_MINUS_DST_COLOR),
|
||||||
|
SRC_ALPHA_SATURATE(GL_SRC_ALPHA_SATURATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val DEFAULT = BlendFunc()
|
||||||
|
val MULTIPLY_WITH_ALPHA = BlendFunc(Func.SRC_ALPHA, Func.ONE_MINUS_SRC_ALPHA)
|
||||||
|
val ADDITIVE = BlendFunc(Func.ONE, Func.ONE)
|
||||||
|
|
||||||
|
val ONLY_ALPHA = BlendFunc(
|
||||||
|
Func.ZERO,
|
||||||
|
Func.ONE,
|
||||||
|
Func.ONE,
|
||||||
|
Func.ZERO
|
||||||
|
)
|
||||||
|
|
||||||
|
val ONLY_BLEND_ALPHA = BlendFunc(
|
||||||
|
Func.ZERO,
|
||||||
|
Func.ONE,
|
||||||
|
Func.ONE,
|
||||||
|
Func.ONE
|
||||||
|
)
|
||||||
|
|
||||||
|
val ONLY_COLOR = BlendFunc(
|
||||||
|
Func.ONE,
|
||||||
|
Func.ZERO,
|
||||||
|
Func.ZERO,
|
||||||
|
Func.ONE
|
||||||
|
)
|
||||||
|
|
||||||
|
val MULTIPLY_BY_SRC = BlendFunc(
|
||||||
|
Func.ZERO,
|
||||||
|
Func.SRC_COLOR,
|
||||||
|
Func.ONE,
|
||||||
|
Func.ZERO
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -9,26 +9,26 @@ import org.lwjgl.opengl.GL46.*
|
|||||||
// GL_STACK_UNDERFLOW
|
// GL_STACK_UNDERFLOW
|
||||||
// GL_OUT_OF_MEMORY
|
// GL_OUT_OF_MEMORY
|
||||||
|
|
||||||
sealed class OpenGLError(message: String, val statusCode: Int) : RuntimeException(message)
|
sealed class OpenGLError(message: String?, val statusCode: Int) : RuntimeException(message)
|
||||||
|
|
||||||
class OpenGLUnknownError(statusCode: Int, message: String = "Unknown OpenGL error occured: $statusCode") : OpenGLError(message, statusCode)
|
class OpenGLUnknownError(statusCode: Int, message: String? = null) : OpenGLError(message ?: "Unknown OpenGL error occurred: $statusCode", statusCode)
|
||||||
|
|
||||||
class OpenGLInvalidEnumException(message: String = "Invalid enum provided") : OpenGLError(message, GL_INVALID_ENUM)
|
class OpenGLInvalidEnumException(message: String? = null) : OpenGLError(message ?: "Invalid enum provided", GL_INVALID_ENUM)
|
||||||
class OpenGLInvalidValueException(message: String = "Invalid value provided") : OpenGLError(message, GL_INVALID_VALUE)
|
class OpenGLInvalidValueException(message: String? = null) : OpenGLError(message ?: "Invalid value provided", GL_INVALID_VALUE)
|
||||||
class OpenGLInvalidOperationException(message: String = "Invalid operation in this context or invalid arguments provided") : OpenGLError(message, GL_INVALID_OPERATION)
|
class OpenGLInvalidOperationException(message: String? = null) : OpenGLError(message ?: "Invalid operation in this context or invalid arguments provided", GL_INVALID_OPERATION)
|
||||||
class OpenGLStackOverflowException(message: String = "Stack overflow in OpenGL") : OpenGLError(message, GL_STACK_OVERFLOW)
|
class OpenGLStackOverflowException(message: String? = null) : OpenGLError(message ?: "Stack overflow in OpenGL", GL_STACK_OVERFLOW)
|
||||||
class OpenGLStackUnderflowException(message: String = "Stack underflow in OpenGL") : OpenGLError(message, GL_STACK_UNDERFLOW)
|
class OpenGLStackUnderflowException(message: String? = null) : OpenGLError(message ?: "Stack underflow in OpenGL", GL_STACK_UNDERFLOW)
|
||||||
class OpenGLOutOfMemoryException(message: String = "Out of Memory in OpenGL") : OpenGLError(message, GL_OUT_OF_MEMORY)
|
class OpenGLOutOfMemoryException(message: String? = null) : OpenGLError(message ?: "Out of Memory in OpenGL", GL_OUT_OF_MEMORY)
|
||||||
|
|
||||||
fun checkForGLError() {
|
fun checkForGLError(message: String? = null) {
|
||||||
when (val errorCode = glGetError()) {
|
when (val errorCode = glGetError()) {
|
||||||
GL_NO_ERROR -> {}
|
GL_NO_ERROR -> {}
|
||||||
GL_INVALID_ENUM -> throw OpenGLInvalidEnumException()
|
GL_INVALID_ENUM -> throw OpenGLInvalidEnumException(message)
|
||||||
GL_INVALID_VALUE -> throw OpenGLInvalidValueException()
|
GL_INVALID_VALUE -> throw OpenGLInvalidValueException(message)
|
||||||
GL_INVALID_OPERATION -> throw OpenGLInvalidOperationException()
|
GL_INVALID_OPERATION -> throw OpenGLInvalidOperationException(message)
|
||||||
GL_STACK_OVERFLOW -> throw OpenGLStackOverflowException()
|
GL_STACK_OVERFLOW -> throw OpenGLStackOverflowException(message)
|
||||||
GL_STACK_UNDERFLOW -> throw OpenGLStackUnderflowException()
|
GL_STACK_UNDERFLOW -> throw OpenGLStackUnderflowException(message)
|
||||||
GL_OUT_OF_MEMORY -> throw OpenGLOutOfMemoryException()
|
GL_OUT_OF_MEMORY -> throw OpenGLOutOfMemoryException(message)
|
||||||
else -> throw OpenGLUnknownError(errorCode)
|
else -> throw OpenGLUnknownError(errorCode, message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ class GLFrameBuffer(val state: GLStateTracker) : AutoCloseable {
|
|||||||
val pointer = GL46.glGenFramebuffers()
|
val pointer = GL46.glGenFramebuffers()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
checkForGLError()
|
checkForGLError("Creating framebuffer")
|
||||||
}
|
}
|
||||||
|
|
||||||
val isComplete: Boolean get() {
|
val isComplete: Boolean get() {
|
||||||
@ -77,7 +77,7 @@ class GLFrameBuffer(val state: GLStateTracker) : AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val cleanable = state.registerCleanable(this, GL46::glDeleteFramebuffers, "Framebuffer", pointer)
|
private val cleanable = state.registerCleanable(this, GL46::glDeleteFramebuffers, pointer)
|
||||||
var isValid = true
|
var isValid = true
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ class GLFrameBuffer(val state: GLStateTracker) : AutoCloseable {
|
|||||||
if (!isValid)
|
if (!isValid)
|
||||||
return
|
return
|
||||||
|
|
||||||
cleanable.cleanManual()
|
cleanable.clean()
|
||||||
texture?.close()
|
texture?.close()
|
||||||
isValid = false
|
isValid = false
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,14 @@ package ru.dbotthepony.kstarbound.client.gl
|
|||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
import org.lwjgl.opengl.GL
|
import org.lwjgl.opengl.GL
|
||||||
import org.lwjgl.opengl.GL46.*
|
import org.lwjgl.opengl.GL46.*
|
||||||
|
import org.lwjgl.opengl.GLCapabilities
|
||||||
import ru.dbotthepony.kstarbound.api.ISBFileLocator
|
import ru.dbotthepony.kstarbound.api.ISBFileLocator
|
||||||
import ru.dbotthepony.kstarbound.client.freetype.FreeType
|
import ru.dbotthepony.kstarbound.client.freetype.FreeType
|
||||||
import ru.dbotthepony.kstarbound.client.freetype.InvalidArgumentException
|
import ru.dbotthepony.kstarbound.client.freetype.InvalidArgumentException
|
||||||
import ru.dbotthepony.kstarbound.client.gl.program.GLPrograms
|
import ru.dbotthepony.kstarbound.client.gl.shader.GLPrograms
|
||||||
import ru.dbotthepony.kstarbound.client.gl.shader.GLShader
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.shader.GLShaderProgram
|
import ru.dbotthepony.kstarbound.client.gl.shader.GLShaderProgram
|
||||||
import ru.dbotthepony.kstarbound.client.gl.shader.GLTransformableColorableProgram
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.shader.GLTransformableProgram
|
import ru.dbotthepony.kstarbound.client.gl.shader.GLTransformableProgram
|
||||||
|
import ru.dbotthepony.kstarbound.client.gl.shader.ShaderCompilationException
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
|
import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
|
import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
||||||
@ -21,6 +21,7 @@ import ru.dbotthepony.kvector.api.IStruct4f
|
|||||||
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
||||||
import ru.dbotthepony.kvector.util2d.AABB
|
import ru.dbotthepony.kvector.util2d.AABB
|
||||||
import ru.dbotthepony.kvector.vector.Color
|
import ru.dbotthepony.kvector.vector.Color
|
||||||
|
import java.io.File
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
import java.lang.ref.Cleaner
|
import java.lang.ref.Cleaner
|
||||||
import java.util.concurrent.ThreadFactory
|
import java.util.concurrent.ThreadFactory
|
||||||
@ -114,89 +115,6 @@ private class TexturesTracker(maxValue: Int) : ReadWriteProperty<GLStateTracker,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
|
||||||
data class BlendFunc(
|
|
||||||
val sourceColor: Func,
|
|
||||||
val destinationColor: Func,
|
|
||||||
val sourceAlpha: Func,
|
|
||||||
val destinationAlpha: Func
|
|
||||||
) {
|
|
||||||
constructor() : this(
|
|
||||||
Func.ONE,
|
|
||||||
Func.ZERO,
|
|
||||||
Func.ONE,
|
|
||||||
Func.ZERO
|
|
||||||
)
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
source: Func, destination: Func
|
|
||||||
) : this(
|
|
||||||
source,
|
|
||||||
destination,
|
|
||||||
source,
|
|
||||||
destination
|
|
||||||
)
|
|
||||||
|
|
||||||
enum class Func(val enum: Int) {
|
|
||||||
ZERO(GL_ZERO),
|
|
||||||
ONE(GL_ONE),
|
|
||||||
SRC_COLOR(GL_SRC_COLOR),
|
|
||||||
ONE_MINUS_SRC_COLOR(GL_ONE_MINUS_SRC_COLOR),
|
|
||||||
SRC_ALPHA(GL_SRC_ALPHA),
|
|
||||||
ONE_MINUS_SRC_ALPHA(GL_ONE_MINUS_SRC_ALPHA),
|
|
||||||
DST_ALPHA(GL_DST_ALPHA),
|
|
||||||
ONE_MINUS_DST_ALPHA(GL_ONE_MINUS_DST_ALPHA),
|
|
||||||
DST_COLOR(GL_DST_COLOR),
|
|
||||||
ONE_MINUS_DST_COLOR(GL_ONE_MINUS_DST_COLOR),
|
|
||||||
SRC_ALPHA_SATURATE(GL_SRC_ALPHA_SATURATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val DEFAULT = BlendFunc()
|
|
||||||
val MULTIPLY_WITH_ALPHA = BlendFunc(Func.SRC_ALPHA, Func.ONE_MINUS_SRC_ALPHA)
|
|
||||||
val ADDITIVE = BlendFunc(Func.ONE, Func.ONE)
|
|
||||||
|
|
||||||
val ONLY_ALPHA = BlendFunc(
|
|
||||||
Func.ZERO,
|
|
||||||
Func.ONE,
|
|
||||||
Func.ONE,
|
|
||||||
Func.ZERO
|
|
||||||
)
|
|
||||||
|
|
||||||
val ONLY_BLEND_ALPHA = BlendFunc(
|
|
||||||
Func.ZERO,
|
|
||||||
Func.ONE,
|
|
||||||
Func.ONE,
|
|
||||||
Func.ONE
|
|
||||||
)
|
|
||||||
|
|
||||||
val ONLY_COLOR = BlendFunc(
|
|
||||||
Func.ONE,
|
|
||||||
Func.ZERO,
|
|
||||||
Func.ZERO,
|
|
||||||
Func.ONE
|
|
||||||
)
|
|
||||||
|
|
||||||
val MULTIPLY_BY_SRC = BlendFunc(
|
|
||||||
Func.ZERO,
|
|
||||||
Func.SRC_COLOR,
|
|
||||||
Func.ONE,
|
|
||||||
Func.ZERO
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface GLCleanable : Cleaner.Cleanable {
|
|
||||||
/**
|
|
||||||
* Выставляет флаг на то, что объект был удалён вручную и вызывает clean()
|
|
||||||
*/
|
|
||||||
fun cleanManual()
|
|
||||||
}
|
|
||||||
|
|
||||||
interface GLStreamBuilderList {
|
|
||||||
val small: StreamVertexBuilder
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("PropertyName", "unused")
|
@Suppress("PropertyName", "unused")
|
||||||
class GLStateTracker(val locator: ISBFileLocator) {
|
class GLStateTracker(val locator: ISBFileLocator) {
|
||||||
private fun isMe(state: GLStateTracker?) {
|
private fun isMe(state: GLStateTracker?) {
|
||||||
@ -208,15 +126,20 @@ class GLStateTracker(val locator: ISBFileLocator) {
|
|||||||
init {
|
init {
|
||||||
check(TRACKERS.get() == null) { "Already has state tracker existing at this thread!" }
|
check(TRACKERS.get() == null) { "Already has state tracker existing at this thread!" }
|
||||||
TRACKERS.set(this)
|
TRACKERS.set(this)
|
||||||
// This line is critical for LWJGL's interoperation with GLFW's
|
|
||||||
// OpenGL context, or any context that is managed externally.
|
|
||||||
// LWJGL detects the context that is current in the current thread,
|
|
||||||
// creates the GLCapabilities instance and makes the OpenGL
|
|
||||||
// bindings available for use.
|
|
||||||
GL.createCapabilities()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val cleanerHits = ArrayList<() -> Unit>()
|
// This line is critical for LWJGL's interoperation with GLFW's
|
||||||
|
// OpenGL context, or any context that is managed externally.
|
||||||
|
// LWJGL detects the context that is current in the current thread,
|
||||||
|
// creates the GLCapabilities instance and makes the OpenGL
|
||||||
|
// bindings available for use.
|
||||||
|
val capabilities: GLCapabilities = GL.createCapabilities()
|
||||||
|
|
||||||
|
private val cleanerBacklog = ArrayList<() -> Unit>()
|
||||||
|
|
||||||
|
var objectsCleaned = 0
|
||||||
|
private set
|
||||||
|
|
||||||
private val cleaner = Cleaner.create(object : ThreadFactory {
|
private val cleaner = Cleaner.create(object : ThreadFactory {
|
||||||
override fun newThread(r: Runnable): Thread {
|
override fun newThread(r: Runnable): Thread {
|
||||||
@ -226,19 +149,16 @@ class GLStateTracker(val locator: ISBFileLocator) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
fun registerCleanable(ref: Any, fn: (Int) -> Unit, name: String, nativeRef: Int): GLCleanable {
|
fun registerCleanable(ref: Any, fn: (Int) -> Unit, nativeRef: Int): Cleaner.Cleanable {
|
||||||
var cleanManual = false
|
|
||||||
|
|
||||||
val cleanable = cleaner.register(ref) {
|
val cleanable = cleaner.register(ref) {
|
||||||
if (!cleanManual && LOGGER.isTraceEnabled)
|
objectsCleaned++
|
||||||
LOGGER.trace("{} with ID {} was GC'd by JVM, without manually calling close()", name, nativeRef)
|
|
||||||
|
|
||||||
if (isSameThread()) {
|
if (isSameThread()) {
|
||||||
fn(nativeRef)
|
fn(nativeRef)
|
||||||
checkForGLError()
|
checkForGLError()
|
||||||
} else {
|
} else {
|
||||||
synchronized(cleanerHits) {
|
synchronized(cleanerBacklog) {
|
||||||
cleanerHits.add {
|
cleanerBacklog.add {
|
||||||
fn(nativeRef)
|
fn(nativeRef)
|
||||||
checkForGLError()
|
checkForGLError()
|
||||||
}
|
}
|
||||||
@ -246,23 +166,16 @@ class GLStateTracker(val locator: ISBFileLocator) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return object : GLCleanable {
|
return cleanable
|
||||||
override fun cleanManual() {
|
|
||||||
cleanManual = true
|
|
||||||
clean()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun clean() = cleanable.clean()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun cleanup() {
|
fun cleanup() {
|
||||||
synchronized(cleanerHits) {
|
synchronized(cleanerBacklog) {
|
||||||
for (lambda in cleanerHits) {
|
for (lambda in cleanerBacklog) {
|
||||||
lambda.invoke()
|
lambda.invoke()
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanerHits.clear()
|
cleanerBacklog.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,10 +340,6 @@ class GLStateTracker(val locator: ISBFileLocator) {
|
|||||||
|
|
||||||
fun isSameThread() = thread === Thread.currentThread()
|
fun isSameThread() = thread === Thread.currentThread()
|
||||||
|
|
||||||
fun program(vararg shaders: GLShader): GLShaderProgram {
|
|
||||||
return GLShaderProgram(this, *shaders)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun newVBO(type: VBOType = VBOType.ARRAY): VertexBufferObject {
|
fun newVBO(type: VBOType = VBOType.ARRAY): VertexBufferObject {
|
||||||
return VertexBufferObject(this, type)
|
return VertexBufferObject(this, type)
|
||||||
}
|
}
|
||||||
@ -542,20 +451,25 @@ class GLStateTracker(val locator: ISBFileLocator) {
|
|||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
val shaderVertexTexture: GLTransformableProgram
|
val shaderVertexTexture: TexturedProgram
|
||||||
val shaderVertexTextureColor: GLTransformableColorableProgram
|
val shaderVertexTextureColor: TexturedColoredProgram
|
||||||
|
|
||||||
|
inner class TexturedProgram(shaders: Iterable<Shader>) : GLTransformableProgram(this@GLStateTracker, shaders) {
|
||||||
|
val texture = IUniform("_texture")
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class TexturedColoredProgram(shaders: Iterable<Shader>) : GLTransformableProgram(this@GLStateTracker, shaders) {
|
||||||
|
val texture = IUniform("_texture")
|
||||||
|
val color = F4Uniform("_color")
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val textureF = GLShader.internalFragment("shaders/fragment/texture.glsl")
|
val textureF = internalFragment("shaders/fragment/texture.glsl")
|
||||||
val textureColorF = GLShader.internalFragment("shaders/fragment/texture_color.glsl")
|
val textureColorF = internalFragment("shaders/fragment/texture_color.glsl")
|
||||||
val textureV = GLShader.internalVertex("shaders/vertex/texture.glsl")
|
val textureV = internalVertex("shaders/vertex/texture.glsl")
|
||||||
|
|
||||||
shaderVertexTexture = GLTransformableProgram(this, textureF, textureV)
|
shaderVertexTexture = TexturedProgram(listOf(textureF, textureV))
|
||||||
shaderVertexTextureColor = GLTransformableColorableProgram(this, textureColorF, textureV)
|
shaderVertexTextureColor = TexturedColoredProgram(listOf(textureColorF, textureV))
|
||||||
|
|
||||||
textureF.unlink()
|
|
||||||
textureColorF.unlink()
|
|
||||||
textureV.unlink()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val programs = GLPrograms(this)
|
val programs = GLPrograms(this)
|
||||||
@ -578,8 +492,8 @@ class GLStateTracker(val locator: ISBFileLocator) {
|
|||||||
builder.upload()
|
builder.upload()
|
||||||
|
|
||||||
programs.flat.use()
|
programs.flat.use()
|
||||||
programs.flat.color.set(color)
|
programs.flat.color.value = color
|
||||||
programs.flat.transform.set(matrixStack.last)
|
programs.flat.transform.value = matrixStack.last
|
||||||
|
|
||||||
builder.draw(GL_LINES)
|
builder.draw(GL_LINES)
|
||||||
}
|
}
|
||||||
@ -592,7 +506,7 @@ class GLStateTracker(val locator: ISBFileLocator) {
|
|||||||
builder.upload()
|
builder.upload()
|
||||||
|
|
||||||
programs.flatColor.use()
|
programs.flatColor.use()
|
||||||
programs.flatColor.transform.set(matrixStack.last)
|
programs.flatColor.transform.value = matrixStack.last
|
||||||
|
|
||||||
builder.draw(GL_TRIANGLES)
|
builder.draw(GL_TRIANGLES)
|
||||||
}
|
}
|
||||||
@ -606,8 +520,60 @@ class GLStateTracker(val locator: ISBFileLocator) {
|
|||||||
|
|
||||||
val box2dRenderer = Box2DRenderer(this)
|
val box2dRenderer = Box2DRenderer(this)
|
||||||
|
|
||||||
|
inner class Shader(body: String, type: Int) {
|
||||||
|
constructor(body: File, type: Int) : this(body.also { require(it.exists()) { "Shader file does not exists: $body" } }.readText(), type)
|
||||||
|
|
||||||
|
init {
|
||||||
|
ensureSameThread()
|
||||||
|
}
|
||||||
|
|
||||||
|
val pointer = glCreateShader(type)
|
||||||
|
|
||||||
|
init {
|
||||||
|
checkForGLError()
|
||||||
|
registerCleanable(this, ::glDeleteShader, pointer)
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (body == "") {
|
||||||
|
throw IllegalArgumentException("Shader source is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
glShaderSource(pointer, body)
|
||||||
|
glCompileShader(pointer)
|
||||||
|
|
||||||
|
val result = intArrayOf(0)
|
||||||
|
glGetShaderiv(pointer, GL_COMPILE_STATUS, result)
|
||||||
|
|
||||||
|
if (result[0] == 0) {
|
||||||
|
throw ShaderCompilationException(glGetShaderInfoLog(pointer))
|
||||||
|
}
|
||||||
|
|
||||||
|
checkForGLError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun vertex(file: File) = Shader(file, GL_VERTEX_SHADER)
|
||||||
|
fun fragment(file: File) = Shader(file, GL_FRAGMENT_SHADER)
|
||||||
|
|
||||||
|
fun vertex(contents: String) = Shader(contents, GL_VERTEX_SHADER)
|
||||||
|
fun fragment(contents: String) = Shader(contents, GL_FRAGMENT_SHADER)
|
||||||
|
|
||||||
|
fun internalVertex(file: String) = Shader(readInternal(file), GL_VERTEX_SHADER)
|
||||||
|
fun internalFragment(file: String) = Shader(readInternal(file), GL_FRAGMENT_SHADER)
|
||||||
|
fun internalGeometry(file: String) = Shader(readInternal(file), GL_GEOMETRY_SHADER)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val LOGGER = LogManager.getLogger(GLStateTracker::class.java)
|
private val LOGGER = LogManager.getLogger(GLStateTracker::class.java)
|
||||||
private val TRACKERS = ThreadLocal<GLStateTracker>()
|
private val TRACKERS = ThreadLocal<GLStateTracker>()
|
||||||
|
|
||||||
|
private fun readInternal(file: String): String {
|
||||||
|
return ClassLoader.getSystemClassLoader().getResourceAsStream(file)!!.bufferedReader()
|
||||||
|
.let {
|
||||||
|
val read = it.readText()
|
||||||
|
it.close()
|
||||||
|
read
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ class GLTexture2D(val state: GLStateTracker, val name: String = "<unknown>") : A
|
|||||||
checkForGLError()
|
checkForGLError()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val cleanable = state.registerCleanable(this, ::glDeleteTextures, "2D Texture", pointer)
|
private val cleanable = state.registerCleanable(this, ::glDeleteTextures, pointer)
|
||||||
|
|
||||||
var width = 0
|
var width = 0
|
||||||
private set
|
private set
|
||||||
@ -273,7 +273,7 @@ class GLTexture2D(val state: GLStateTracker, val name: String = "<unknown>") : A
|
|||||||
state.texture2D = null
|
state.texture2D = null
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanable.cleanManual()
|
cleanable.clean()
|
||||||
isValid = false
|
isValid = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ class VertexArrayObject(val state: GLStateTracker) : Closeable {
|
|||||||
checkForGLError()
|
checkForGLError()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val cleanable = state.registerCleanable(this, ::glDeleteVertexArrays, "Vertex Array Object", pointer)
|
private val cleanable = state.registerCleanable(this, ::glDeleteVertexArrays, pointer)
|
||||||
|
|
||||||
fun bind(): VertexArrayObject {
|
fun bind(): VertexArrayObject {
|
||||||
check(isValid) { "Tried to use NULL GLVertexArrayObject" }
|
check(isValid) { "Tried to use NULL GLVertexArrayObject" }
|
||||||
@ -51,8 +51,7 @@ class VertexArrayObject(val state: GLStateTracker) : Closeable {
|
|||||||
state.VAO = null
|
state.VAO = null
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanable.cleanManual()
|
cleanable.clean()
|
||||||
|
|
||||||
isValid = false
|
isValid = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,10 @@ class VertexBufferObject(val state: GLStateTracker, val type: VBOType = VBOType.
|
|||||||
val pointer = glGenBuffers()
|
val pointer = glGenBuffers()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
checkForGLError()
|
checkForGLError("Creating Vertex Buffer Object")
|
||||||
}
|
}
|
||||||
|
|
||||||
private val cleanable = state.registerCleanable(this, ::glDeleteBuffers, "Vertex Buffer Object", pointer)
|
private val cleanable = state.registerCleanable(this, ::glDeleteBuffers, pointer)
|
||||||
|
|
||||||
val isArray get() = type == VBOType.ARRAY
|
val isArray get() = type == VBOType.ARRAY
|
||||||
val isElementArray get() = type == VBOType.ELEMENT_ARRAY
|
val isElementArray get() = type == VBOType.ELEMENT_ARRAY
|
||||||
@ -100,7 +100,7 @@ class VertexBufferObject(val state: GLStateTracker, val type: VBOType = VBOType.
|
|||||||
state.VBO = null
|
state.VBO = null
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanable.cleanManual()
|
cleanable.clean()
|
||||||
|
|
||||||
isValid = false
|
isValid = false
|
||||||
}
|
}
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
package ru.dbotthepony.kstarbound.client.gl.program
|
|
||||||
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.shader.GLShader
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.shader.GLShaderProgram
|
|
||||||
|
|
||||||
private fun loadShaders(
|
|
||||||
vertex: Collection<String>,
|
|
||||||
fragment: Collection<String>,
|
|
||||||
geometry: Collection<String>
|
|
||||||
): Array<GLShader> {
|
|
||||||
val result = arrayOfNulls<GLShader>(vertex.size + fragment.size + geometry.size)
|
|
||||||
var i = 0
|
|
||||||
|
|
||||||
for (name in vertex) {
|
|
||||||
result[i++] = GLShader.internalVertex("shaders/$name.vsh")
|
|
||||||
}
|
|
||||||
|
|
||||||
for (name in fragment) {
|
|
||||||
result[i++] = GLShader.internalFragment("shaders/$name.fsh")
|
|
||||||
}
|
|
||||||
|
|
||||||
for (name in geometry) {
|
|
||||||
result[i++] = GLShader.internalGeometry("shaders/$name.gsh")
|
|
||||||
}
|
|
||||||
|
|
||||||
return result as Array<GLShader>
|
|
||||||
}
|
|
||||||
|
|
||||||
open class GLInternalProgram(
|
|
||||||
state: GLStateTracker,
|
|
||||||
vertex: Collection<String>,
|
|
||||||
fragment: Collection<String>,
|
|
||||||
geometry: Collection<String> = listOf()
|
|
||||||
) : GLShaderProgram(state, *loadShaders(vertex, fragment, geometry)) {
|
|
||||||
constructor(state: GLStateTracker, name: String) : this(state, listOf(name), listOf(name))
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
package ru.dbotthepony.kstarbound.client.gl.shader
|
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL46.*
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class GLShader(
|
|
||||||
body: String,
|
|
||||||
type: Int
|
|
||||||
) {
|
|
||||||
constructor(body: File, type: Int) : this(body.also { require(it.exists()) { "Shader file does not exists: $body" } }.readText(), type)
|
|
||||||
|
|
||||||
val pointer = glCreateShader(type)
|
|
||||||
var unlinked = false
|
|
||||||
private set
|
|
||||||
|
|
||||||
init {
|
|
||||||
if (body == "") {
|
|
||||||
throw IllegalArgumentException("Shader source is empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
glShaderSource(pointer, body)
|
|
||||||
glCompileShader(pointer)
|
|
||||||
|
|
||||||
val result = intArrayOf(0)
|
|
||||||
glGetShaderiv(pointer, GL_COMPILE_STATUS, result)
|
|
||||||
|
|
||||||
if (result[0] == 0) {
|
|
||||||
throw ShaderCompilationException(glGetShaderInfoLog(pointer))
|
|
||||||
}
|
|
||||||
|
|
||||||
checkForGLError()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun unlink(): Boolean {
|
|
||||||
if (unlinked)
|
|
||||||
return false
|
|
||||||
|
|
||||||
glDeleteShader(pointer)
|
|
||||||
checkForGLError()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun vertex(file: File) = GLShader(file, GL_VERTEX_SHADER)
|
|
||||||
fun fragment(file: File) = GLShader(file, GL_FRAGMENT_SHADER)
|
|
||||||
|
|
||||||
private fun readInternal(file: String): String {
|
|
||||||
return ClassLoader.getSystemClassLoader().getResourceAsStream(file)!!.bufferedReader()
|
|
||||||
.let {
|
|
||||||
val read = it.readText()
|
|
||||||
it.close()
|
|
||||||
return@let read
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun internalVertex(file: String) = GLShader(readInternal(file), GL_VERTEX_SHADER)
|
|
||||||
fun internalFragment(file: String) = GLShader(readInternal(file), GL_FRAGMENT_SHADER)
|
|
||||||
fun internalGeometry(file: String) = GLShader(readInternal(file), GL_GEOMETRY_SHADER)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +1,35 @@
|
|||||||
package ru.dbotthepony.kstarbound.client.gl.shader
|
package ru.dbotthepony.kstarbound.client.gl.shader
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2BooleanArrayMap
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2BooleanFunction
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArraySet
|
||||||
import org.lwjgl.opengl.GL46.*
|
import org.lwjgl.opengl.GL46.*
|
||||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
||||||
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
|
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
|
||||||
import ru.dbotthepony.kstarbound.client.gl.shader.GLShader
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.shader.GLUniformLocation
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.shader.ShaderLinkException
|
|
||||||
import ru.dbotthepony.kvector.api.IFloatMatrix
|
import ru.dbotthepony.kvector.api.IFloatMatrix
|
||||||
|
import ru.dbotthepony.kvector.api.IStruct2f
|
||||||
import ru.dbotthepony.kvector.api.IStruct3f
|
import ru.dbotthepony.kvector.api.IStruct3f
|
||||||
import ru.dbotthepony.kvector.api.IStruct4f
|
import ru.dbotthepony.kvector.api.IStruct4f
|
||||||
|
import ru.dbotthepony.kvector.api.concrete.IMatrix3f
|
||||||
|
import ru.dbotthepony.kvector.api.concrete.IMatrix4f
|
||||||
|
import ru.dbotthepony.kvector.matrix.nfloat.Matrix3f
|
||||||
|
import ru.dbotthepony.kvector.matrix.nfloat.Matrix4f
|
||||||
|
import ru.dbotthepony.kvector.vector.nfloat.Vector2f
|
||||||
|
import ru.dbotthepony.kvector.vector.nfloat.Vector3f
|
||||||
|
import ru.dbotthepony.kvector.vector.nfloat.Vector4f
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.nio.ByteOrder
|
||||||
|
import java.nio.FloatBuffer
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
import kotlin.collections.HashSet
|
import kotlin.NoSuchElementException
|
||||||
|
import kotlin.properties.ReadWriteProperty
|
||||||
open class GLShaderProgram(val state: GLStateTracker, shaders: Stream<GLShader>) {
|
import kotlin.reflect.KProperty
|
||||||
constructor(state: GLStateTracker, shaders: Collection<GLShader>) : this(state, shaders.stream())
|
|
||||||
constructor(state: GLStateTracker, vararg shaders: GLShader) : this(state, Arrays.stream(shaders))
|
|
||||||
|
|
||||||
|
open class GLShaderProgram(val state: GLStateTracker, shaders: Iterable<GLStateTracker.Shader>) {
|
||||||
init {
|
init {
|
||||||
state.ensureSameThread()
|
state.ensureSameThread()
|
||||||
}
|
}
|
||||||
@ -26,10 +37,12 @@ open class GLShaderProgram(val state: GLStateTracker, shaders: Stream<GLShader>)
|
|||||||
val pointer = glCreateProgram()
|
val pointer = glCreateProgram()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
checkForGLError()
|
checkForGLError("Creating shader program")
|
||||||
|
state.registerCleanable(this, ::glDeleteProgram, pointer)
|
||||||
|
|
||||||
for (shader in shaders) {
|
for (shader in shaders) {
|
||||||
glAttachShader(pointer, shader.pointer)
|
glAttachShader(pointer, shader.pointer)
|
||||||
|
checkForGLError("Attaching shader")
|
||||||
}
|
}
|
||||||
|
|
||||||
glLinkProgram(pointer)
|
glLinkProgram(pointer)
|
||||||
@ -44,33 +57,175 @@ open class GLShaderProgram(val state: GLStateTracker, shaders: Stream<GLShader>)
|
|||||||
glGetError()
|
glGetError()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val locationCache = Object2ObjectOpenHashMap<String, Optional<GLUniformLocation>>()
|
fun use() = state.use(this)
|
||||||
|
|
||||||
/**
|
private val locations = Object2ObjectArrayMap<String, Uniform<*>>()
|
||||||
* Возвращает GLUniformLocation или null, если у данной программы нет такого uniform
|
private val uniformsExist = Object2BooleanArrayMap<String>()
|
||||||
*
|
|
||||||
* В т.ч. если она была в коде шейдера, но нигде не использовалась (отсечена компилятором)
|
fun isUniformPresent(name: String): Boolean {
|
||||||
*
|
|
||||||
* Результат поиска кешируется, но для повышения производительности вызывающий код желательно так же
|
|
||||||
* должен кешировать результат (как локальное свойство или переменная, в случае многократного использования)
|
|
||||||
*/
|
|
||||||
operator fun get(name: String): GLUniformLocation? {
|
|
||||||
state.ensureSameThread()
|
state.ensureSameThread()
|
||||||
|
return uniformsExist.computeIfAbsent(name, Object2BooleanFunction { glGetUniformLocation(pointer, name) != -1 })
|
||||||
return locationCache.computeIfAbsent(name, Object2ObjectFunction {
|
|
||||||
val location = glGetUniformLocation(pointer, name)
|
|
||||||
|
|
||||||
if (location == -1)
|
|
||||||
return@Object2ObjectFunction Optional.empty<GLUniformLocation>()
|
|
||||||
|
|
||||||
return@Object2ObjectFunction Optional.of(GLUniformLocation(this, name, location))
|
|
||||||
}).orElse(null)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun set(name: String, value: IStruct4f) = this[name]?.set(value)
|
fun getUniform(name: String, orElse: ((String) -> Uniform<*>)? = null): Uniform<*>? {
|
||||||
operator fun set(name: String, value: IStruct3f) = this[name]?.set(value)
|
return locations[name] ?: orElse?.invoke(name)
|
||||||
operator fun set(name: String, value: Int) = this[name]?.set(value)
|
}
|
||||||
operator fun set(name: String, value: IFloatMatrix<*>) = this[name]?.set(value)
|
|
||||||
|
|
||||||
fun use() = state.use(this)
|
fun int(name: String): IUniform {
|
||||||
|
return locations.computeIfAbsent(name, Object2ObjectFunction { IUniform(name) }) as? IUniform ?: throw IllegalStateException("Uniform $name has type of ${locations[name]!!::class.simpleName}")
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract inner class Uniform<V : Any>(val name: String) : ReadWriteProperty<Any?, V> {
|
||||||
|
init {
|
||||||
|
state.ensureSameThread()
|
||||||
|
require(!locations.containsKey(name)) { "Already has uniform $name for ${this@GLShaderProgram} (${locations[name]})" }
|
||||||
|
}
|
||||||
|
|
||||||
|
val location = glGetUniformLocation(pointer, name)
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (location == -1)
|
||||||
|
throw NoSuchElementException("Program ${this@GLShaderProgram} does not have uniform with name $name")
|
||||||
|
|
||||||
|
locations[name] = this
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract var value: V
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "Uniform[$name, $value]"
|
||||||
|
}
|
||||||
|
|
||||||
|
// они переопределены в дочерних классах для бетонной реализации примитивов
|
||||||
|
override fun getValue(thisRef: Any?, property: KProperty<*>): V {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) {
|
||||||
|
this.value = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class FUniform(name: String) : Uniform<Float>(name) {
|
||||||
|
override var value: Float = 0f
|
||||||
|
set(value) {
|
||||||
|
state.ensureSameThread()
|
||||||
|
|
||||||
|
if (field != value) {
|
||||||
|
glProgramUniform1f(pointer, location, value)
|
||||||
|
checkForGLError()
|
||||||
|
}
|
||||||
|
|
||||||
|
field = value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getValue(thisRef: Any?, property: KProperty<*>): Float {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Float) {
|
||||||
|
this.value = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class F2Uniform(name: String) : Uniform<IStruct2f>(name) {
|
||||||
|
override var value: IStruct2f = Vector2f.ZERO
|
||||||
|
set(value) {
|
||||||
|
state.ensureSameThread()
|
||||||
|
|
||||||
|
if (field != value) {
|
||||||
|
glProgramUniform2f(pointer, location, value.component1(), value.component2())
|
||||||
|
checkForGLError()
|
||||||
|
|
||||||
|
field = if (value is Vector2f) value else Vector2f(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class F3Uniform(name: String) : Uniform<IStruct3f>(name) {
|
||||||
|
override var value: IStruct3f = Vector3f.ZERO
|
||||||
|
set(value) {
|
||||||
|
state.ensureSameThread()
|
||||||
|
|
||||||
|
if (field != value) {
|
||||||
|
glProgramUniform3f(pointer, location, value.component1(), value.component2(), value.component3())
|
||||||
|
checkForGLError()
|
||||||
|
|
||||||
|
field = if (value is Vector3f) value else Vector3f(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val buff3x3: FloatBuffer by lazy(LazyThreadSafetyMode.NONE) { ByteBuffer.allocateDirect(4 * 3 * 3).also { it.order(ByteOrder.nativeOrder()) }.asFloatBuffer() }
|
||||||
|
private val buff4x4: FloatBuffer by lazy(LazyThreadSafetyMode.NONE) { ByteBuffer.allocateDirect(4 * 4 * 4).also { it.order(ByteOrder.nativeOrder()) }.asFloatBuffer() }
|
||||||
|
|
||||||
|
inner class F3x3Uniform(name: String) : Uniform<IMatrix3f<*>>(name) {
|
||||||
|
override var value: IMatrix3f<*> = Matrix3f.ZERO
|
||||||
|
set(value) {
|
||||||
|
state.ensureSameThread()
|
||||||
|
|
||||||
|
if (field != value) {
|
||||||
|
buff3x3.position(0)
|
||||||
|
value.write(buff3x3)
|
||||||
|
buff3x3.position(0)
|
||||||
|
glProgramUniformMatrix3fv(pointer, location, false, buff3x3)
|
||||||
|
checkForGLError()
|
||||||
|
|
||||||
|
field = value.toMatrix3f()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class F4x4Uniform(name: String) : Uniform<IMatrix4f<*>>(name) {
|
||||||
|
override var value: IMatrix4f<*> = Matrix4f.ZERO
|
||||||
|
set(value) {
|
||||||
|
state.ensureSameThread()
|
||||||
|
|
||||||
|
if (field != value) {
|
||||||
|
buff4x4.position(0)
|
||||||
|
value.write(buff4x4)
|
||||||
|
buff4x4.position(0)
|
||||||
|
glProgramUniformMatrix4fv(pointer, location, false, buff4x4)
|
||||||
|
checkForGLError()
|
||||||
|
|
||||||
|
field = value.toMatrix4f()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class F4Uniform(name: String) : Uniform<IStruct4f>(name) {
|
||||||
|
override var value: IStruct4f = Vector4f.ZERO
|
||||||
|
set(value) {
|
||||||
|
state.ensureSameThread()
|
||||||
|
|
||||||
|
if (field != value) {
|
||||||
|
glProgramUniform4f(pointer, location, value.component1(), value.component2(), value.component3(), value.component4())
|
||||||
|
checkForGLError()
|
||||||
|
|
||||||
|
field = if (value is Vector4f) value else Vector4f(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class IUniform(name: String) : Uniform<Int>(name) {
|
||||||
|
override var value: Int = 0
|
||||||
|
set(value) {
|
||||||
|
state.ensureSameThread()
|
||||||
|
|
||||||
|
if (field != value) {
|
||||||
|
glProgramUniform1i(pointer, location, value)
|
||||||
|
checkForGLError()
|
||||||
|
}
|
||||||
|
|
||||||
|
field = value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getValue(thisRef: Any?, property: KProperty<*>): Int {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
|
||||||
|
this.value = value
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,3 @@ package ru.dbotthepony.kstarbound.client.gl.shader
|
|||||||
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
||||||
import ru.dbotthepony.kvector.vector.Color
|
import ru.dbotthepony.kvector.vector.Color
|
||||||
|
|
||||||
open class GLTransformableColorableProgram(state: GLStateTracker, vararg shaders: GLShader) : GLTransformableProgram(state, *shaders) {
|
|
||||||
val color = this["_color"]!!
|
|
||||||
|
|
||||||
init {
|
|
||||||
color.set(Color.WHITE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -2,11 +2,3 @@ package ru.dbotthepony.kstarbound.client.gl.shader
|
|||||||
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
||||||
import ru.dbotthepony.kvector.matrix.nfloat.Matrix4f
|
import ru.dbotthepony.kvector.matrix.nfloat.Matrix4f
|
||||||
|
|
||||||
open class GLTransformableProgram(state: GLStateTracker, vararg shaders: GLShader) : GLShaderProgram(state, *shaders) {
|
|
||||||
val transform = this["_transform"]!!
|
|
||||||
|
|
||||||
init {
|
|
||||||
transform.set(Matrix4f.IDENTITY)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
package ru.dbotthepony.kstarbound.client.gl.shader
|
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL41.*
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
|
|
||||||
import ru.dbotthepony.kvector.api.IFloatMatrix
|
|
||||||
import ru.dbotthepony.kvector.api.IStruct2f
|
|
||||||
import ru.dbotthepony.kvector.api.IStruct3f
|
|
||||||
import ru.dbotthepony.kvector.api.IStruct4f
|
|
||||||
import java.nio.ByteBuffer
|
|
||||||
import java.nio.ByteOrder
|
|
||||||
import java.nio.FloatBuffer
|
|
||||||
|
|
||||||
class GLUniformLocation(val program: GLShaderProgram, val name: String, val pointer: Int) {
|
|
||||||
fun set(value: IStruct4f): GLUniformLocation {
|
|
||||||
program.state.ensureSameThread()
|
|
||||||
val (v0, v1, v2, v3) = value
|
|
||||||
glProgramUniform4f(program.pointer, pointer, v0, v1, v2, v3)
|
|
||||||
checkForGLError()
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun set(value: IStruct2f): GLUniformLocation {
|
|
||||||
program.state.ensureSameThread()
|
|
||||||
val (v0, v1) = value
|
|
||||||
glProgramUniform2f(program.pointer, pointer, v0, v1)
|
|
||||||
checkForGLError()
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun set(value: IStruct3f): GLUniformLocation {
|
|
||||||
program.state.ensureSameThread()
|
|
||||||
val (v0, v1, v2) = value
|
|
||||||
glProgramUniform3f(program.pointer, pointer, v0, v1, v2)
|
|
||||||
checkForGLError()
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun set(value: Int): GLUniformLocation {
|
|
||||||
program.state.ensureSameThread()
|
|
||||||
glProgramUniform1i(program.pointer, pointer, value)
|
|
||||||
checkForGLError()
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun set(value: Float): GLUniformLocation {
|
|
||||||
program.state.ensureSameThread()
|
|
||||||
glProgramUniform1f(program.pointer, pointer, value)
|
|
||||||
checkForGLError()
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
private val buff3x3: FloatBuffer by lazy { ByteBuffer.allocateDirect(4 * 3 * 3).also { it.order(ByteOrder.nativeOrder()) }.asFloatBuffer() }
|
|
||||||
private val buff4x4: FloatBuffer by lazy { ByteBuffer.allocateDirect(4 * 4 * 4).also { it.order(ByteOrder.nativeOrder()) }.asFloatBuffer() }
|
|
||||||
|
|
||||||
fun set(value: IFloatMatrix<*>): GLUniformLocation {
|
|
||||||
program.state.ensureSameThread()
|
|
||||||
|
|
||||||
if (value.rows == 3 && value.columns == 3) {
|
|
||||||
// Матрица 3x3
|
|
||||||
buff3x3.position(0)
|
|
||||||
value.write(buff3x3)
|
|
||||||
buff3x3.position(0)
|
|
||||||
glProgramUniformMatrix3fv(program.pointer, pointer, false, buff3x3)
|
|
||||||
checkForGLError()
|
|
||||||
} else if (value.rows == 4 && value.columns == 4) {
|
|
||||||
// Матрица 4x4
|
|
||||||
buff4x4.position(0)
|
|
||||||
value.write(buff4x4)
|
|
||||||
buff4x4.position(0)
|
|
||||||
glProgramUniformMatrix4fv(program.pointer, pointer, false, buff4x4)
|
|
||||||
checkForGLError()
|
|
||||||
} else {
|
|
||||||
throw IllegalArgumentException("Can not use matrix with these dimensions: ${value.columns}x${value.rows}")
|
|
||||||
}
|
|
||||||
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,49 +1,47 @@
|
|||||||
package ru.dbotthepony.kstarbound.client.gl.program
|
package ru.dbotthepony.kstarbound.client.gl.shader
|
||||||
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.BlendFunc
|
import ru.dbotthepony.kstarbound.client.gl.BlendFunc
|
||||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
||||||
import ru.dbotthepony.kstarbound.client.gl.GLType
|
import ru.dbotthepony.kstarbound.client.gl.GLType
|
||||||
import ru.dbotthepony.kstarbound.client.gl.shader.GLShader
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.shader.GLShaderProgram
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.shader.GLTransformableColorableProgram
|
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
|
import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
|
import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
||||||
import ru.dbotthepony.kstarbound.client.render.GPULightRenderer
|
import ru.dbotthepony.kstarbound.client.render.GPULightRenderer
|
||||||
|
import ru.dbotthepony.kvector.matrix.nfloat.Matrix4f
|
||||||
import ru.dbotthepony.kvector.vector.Color
|
import ru.dbotthepony.kvector.vector.Color
|
||||||
import kotlin.properties.ReadOnlyProperty
|
|
||||||
import kotlin.reflect.KProperty
|
|
||||||
|
|
||||||
private class SimpleProgram<T : GLShaderProgram>(private val name: String, private val factory: (GLStateTracker, Array<out GLShader>) -> T) : ReadOnlyProperty<GLPrograms, T> {
|
open class GLTransformableProgram(state: GLStateTracker, shaders: Iterable<GLStateTracker.Shader>) : GLShaderProgram(state, shaders) {
|
||||||
private var value: T? = null
|
val transform = F4x4Uniform("_transform")
|
||||||
|
|
||||||
override fun getValue(thisRef: GLPrograms, property: KProperty<*>): T {
|
init {
|
||||||
thisRef.state.ensureSameThread()
|
transform.value = Matrix4f.IDENTITY
|
||||||
|
|
||||||
val value = value
|
|
||||||
|
|
||||||
if (value != null) {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
val vertex = GLShader.internalVertex("shaders/$name.vsh")
|
|
||||||
val fragment = GLShader.internalFragment("shaders/$name.fsh")
|
|
||||||
|
|
||||||
val newValue = factory.invoke(thisRef.state, arrayOf(vertex, fragment))
|
|
||||||
|
|
||||||
this.value = newValue
|
|
||||||
|
|
||||||
vertex.unlink()
|
|
||||||
fragment.unlink()
|
|
||||||
|
|
||||||
return newValue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GLLiquidProgram(state: GLStateTracker) : GLInternalProgram(state, "liquid") {
|
open class GLTransformableColorableProgram(state: GLStateTracker, shaders: Iterable<GLStateTracker.Shader>) : GLTransformableProgram(state, shaders) {
|
||||||
val baselineColor = this["baselineColor"]!!
|
val color = F4Uniform("_color")
|
||||||
val transform = this["transform"]!!
|
|
||||||
|
init {
|
||||||
|
color.value = Color.WHITE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun GLStateTracker.shaders(name: String): List<GLStateTracker.Shader> {
|
||||||
|
return listOf(internalVertex("shaders/$name.vsh"), internalFragment("shaders/$name.fsh"))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun GLStateTracker.gshaders(name: String): List<GLStateTracker.Shader> {
|
||||||
|
return listOf(
|
||||||
|
internalVertex(name),
|
||||||
|
internalFragment(name),
|
||||||
|
internalGeometry(name)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
class GLLiquidProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("liquid")) {
|
||||||
|
val baselineColor = F4Uniform("baselineColor")
|
||||||
|
val transform = F4x4Uniform("transform")
|
||||||
|
|
||||||
val builder by lazy {
|
val builder by lazy {
|
||||||
StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 16384)
|
StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 16384)
|
||||||
@ -54,9 +52,9 @@ class GLLiquidProgram(state: GLStateTracker) : GLInternalProgram(state, "liquid"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GLLightProgram(state: GLStateTracker) : GLInternalProgram(state, "light") {
|
class GLLightProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("light")) {
|
||||||
val baselineColor = this["baselineColor"]!!
|
val baselineColor = F4Uniform("baselineColor")
|
||||||
val transform = this["transform"]!!
|
val transform = F4x4Uniform("transform")
|
||||||
|
|
||||||
val builder by lazy {
|
val builder by lazy {
|
||||||
StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 32)
|
StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 32)
|
||||||
@ -67,34 +65,34 @@ class GLLightProgram(state: GLStateTracker) : GLInternalProgram(state, "light")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GLHardLightGeometryProgram(state: GLStateTracker) : GLInternalProgram(state, listOf("hard_light_geometry"), listOf("hard_light_geometry"), listOf("hard_light_geometry")) {
|
class GLHardLightGeometryProgram(state: GLStateTracker) : GLShaderProgram(state, state.gshaders("hard_light_geometry")) {
|
||||||
val transform = this["transform"]!!
|
val transform = F4x4Uniform("transform")
|
||||||
val localToWorldTransform = this["localToWorldTransform"]!!
|
val localToWorldTransform = F4x4Uniform("localToWorldTransform")
|
||||||
val lightPosition = this["lightPosition"]!!
|
val lightPosition = F2Uniform("lightPosition")
|
||||||
val lightPenetration = this["lightPenetration"]!!
|
val lightPenetration = FUniform("lightPenetration")
|
||||||
|
|
||||||
val builder by lazy {
|
val builder by lazy {
|
||||||
StreamVertexBuilder(state, GPULightRenderer.SHADOW_FORMAT, GeometryType.QUADS_AS_LINES, 32)
|
StreamVertexBuilder(state, GPULightRenderer.SHADOW_FORMAT, GeometryType.QUADS_AS_LINES, 32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GLSoftLightGeometryProgram(state: GLStateTracker) : GLInternalProgram(state, listOf("soft_light_geometry2"), listOf("soft_light_geometry2")) {
|
class GLSoftLightGeometryProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("soft_light_geometry2")) {
|
||||||
val transform = this["transform"]!!
|
val transform = F4x4Uniform("transform")
|
||||||
val lightPenetration = this["lightPenetration"]!!
|
val lightPenetration = FUniform("lightPenetration")
|
||||||
val localToWorldTransform = this["localToWorldTransform"]!!
|
val localToWorldTransform = F4x4Uniform("localToWorldTransform")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vector3f(x, y, size)
|
* Vector3f(x, y, size)
|
||||||
*/
|
*/
|
||||||
val lightPositionAndSize = this["lightPositionAndSize"]!!
|
val lightPositionAndSize = F3Uniform("lightPositionAndSize")
|
||||||
|
|
||||||
val builder by lazy {
|
val builder by lazy {
|
||||||
StreamVertexBuilder(state, GPULightRenderer.SHADOW_FORMAT_SOFT, GeometryType.QUADS_AS_LINES, 32)
|
StreamVertexBuilder(state, GPULightRenderer.SHADOW_FORMAT_SOFT, GeometryType.QUADS_AS_LINES, 32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GLColorQuadProgram(state: GLStateTracker) : GLInternalProgram(state, "screen_quad") {
|
class GLColorQuadProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("screen_quad")) {
|
||||||
val color = this["color"]!!
|
val color = F4Uniform("color")
|
||||||
|
|
||||||
private val builder by lazy {
|
private val builder by lazy {
|
||||||
val builder = StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 1)
|
val builder = StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 1)
|
||||||
@ -109,7 +107,7 @@ class GLColorQuadProgram(state: GLStateTracker) : GLInternalProgram(state, "scre
|
|||||||
fun clearAlpha() {
|
fun clearAlpha() {
|
||||||
use()
|
use()
|
||||||
|
|
||||||
color.set(ALPHA)
|
color.value = ALPHA
|
||||||
|
|
||||||
val old = state.blend
|
val old = state.blend
|
||||||
val oldFunc = state.blendFunc
|
val oldFunc = state.blendFunc
|
||||||
@ -124,7 +122,7 @@ class GLColorQuadProgram(state: GLStateTracker) : GLInternalProgram(state, "scre
|
|||||||
fun clearColor(color: Color = Color.WHITE) {
|
fun clearColor(color: Color = Color.WHITE) {
|
||||||
use()
|
use()
|
||||||
|
|
||||||
this.color.set(color)
|
this.color.value = color
|
||||||
|
|
||||||
val old = state.blend
|
val old = state.blend
|
||||||
|
|
||||||
@ -139,8 +137,8 @@ class GLColorQuadProgram(state: GLStateTracker) : GLInternalProgram(state, "scre
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GLTextureQuadProgram(state: GLStateTracker) : GLInternalProgram(state, "screen_quad_tex") {
|
class GLTextureQuadProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("screen_quad_tex")) {
|
||||||
val texture = this["texture0"]!!
|
val texture = IUniform("texture0")
|
||||||
|
|
||||||
private val builder by lazy {
|
private val builder by lazy {
|
||||||
val builder = StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 1)
|
val builder = StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 1)
|
||||||
@ -154,7 +152,7 @@ class GLTextureQuadProgram(state: GLStateTracker) : GLInternalProgram(state, "sc
|
|||||||
|
|
||||||
fun run(texture: Int = 0) {
|
fun run(texture: Int = 0) {
|
||||||
use()
|
use()
|
||||||
this.texture.set(texture)
|
this.texture.value = texture
|
||||||
builder.draw()
|
builder.draw()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,8 +161,8 @@ class GLTextureQuadProgram(state: GLStateTracker) : GLInternalProgram(state, "sc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GLTextureBlurredQuadProgram(state: GLStateTracker) : GLInternalProgram(state, "screen_quad_tex_blur") {
|
class GLTextureBlurredQuadProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("screen_quad_tex_blur")) {
|
||||||
val texture = this["texture0"]!!
|
val texture = IUniform("texture0")
|
||||||
|
|
||||||
private val builder by lazy {
|
private val builder by lazy {
|
||||||
val builder = StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 1)
|
val builder = StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 1)
|
||||||
@ -178,7 +176,7 @@ class GLTextureBlurredQuadProgram(state: GLStateTracker) : GLInternalProgram(sta
|
|||||||
|
|
||||||
fun run(texture: Int = 0) {
|
fun run(texture: Int = 0) {
|
||||||
use()
|
use()
|
||||||
this.texture.set(texture)
|
this.texture.value = texture
|
||||||
builder.draw()
|
builder.draw()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,18 +185,8 @@ class GLTextureBlurredQuadProgram(state: GLStateTracker) : GLInternalProgram(sta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GLFlatProgram(state: GLStateTracker, vararg shaders: GLShader) : GLTransformableColorableProgram(state, *shaders) {
|
class GLFlatColorProgram(state: GLStateTracker) : GLShaderProgram(state, state.shaders("flat_color")) {
|
||||||
val builder by lazy {
|
val transform = F4x4Uniform("transform")
|
||||||
StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 2048)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val FORMAT = GLAttributeList.Builder().push(GLType.VEC2F).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GLFlatColorProgram(state: GLStateTracker) : GLInternalProgram(state, "flat_color") {
|
|
||||||
val transform = this["transform"]!!
|
|
||||||
|
|
||||||
val builder by lazy {
|
val builder by lazy {
|
||||||
StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 16384)
|
StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 16384)
|
||||||
@ -209,10 +197,18 @@ class GLFlatColorProgram(state: GLStateTracker) : GLInternalProgram(state, "flat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class GLTileProgram(state: GLStateTracker) : GLTransformableColorableProgram(state, state.shaders("tile")) {
|
||||||
|
var texture by IUniform("_texture")
|
||||||
|
}
|
||||||
|
|
||||||
|
class GLFontProgram(state: GLStateTracker) : GLTransformableColorableProgram(state, state.shaders("font")) {
|
||||||
|
var texture by IUniform("_texture")
|
||||||
|
}
|
||||||
|
|
||||||
class GLPrograms(val state: GLStateTracker) {
|
class GLPrograms(val state: GLStateTracker) {
|
||||||
val tile by SimpleProgram("tile", ::GLTransformableColorableProgram)
|
val tile by lazy { GLTileProgram(state) }
|
||||||
val font by SimpleProgram("font", ::GLTransformableColorableProgram)
|
val font by lazy { GLFontProgram(state) }
|
||||||
val flat by SimpleProgram("flat", ::GLFlatProgram)
|
val flat by lazy { GLTransformableColorableProgram(state, state.shaders("flat")) }
|
||||||
val flatColor by lazy { GLFlatColorProgram(state) }
|
val flatColor by lazy { GLFlatColorProgram(state) }
|
||||||
val liquid by lazy { GLLiquidProgram(state) }
|
val liquid by lazy { GLLiquidProgram(state) }
|
||||||
val light by lazy { GLLightProgram(state) }
|
val light by lazy { GLLightProgram(state) }
|
@ -34,8 +34,8 @@ class Box2DRenderer(val state: GLStateTracker) : IDebugDraw {
|
|||||||
builder.upload()
|
builder.upload()
|
||||||
|
|
||||||
state.programs.flat.use()
|
state.programs.flat.use()
|
||||||
state.programs.flat.color.set(color)
|
state.programs.flat.color.value = color
|
||||||
state.programs.flat.transform.set(state.matrixStack.last)
|
state.programs.flat.transform.value = state.matrixStack.last
|
||||||
|
|
||||||
builder.draw(GL_LINES)
|
builder.draw(GL_LINES)
|
||||||
}
|
}
|
||||||
@ -60,8 +60,8 @@ class Box2DRenderer(val state: GLStateTracker) : IDebugDraw {
|
|||||||
builder.upload()
|
builder.upload()
|
||||||
|
|
||||||
state.programs.flat.use()
|
state.programs.flat.use()
|
||||||
state.programs.flat.color.set(color)
|
state.programs.flat.color.value = color
|
||||||
state.programs.flat.transform.set(state.matrixStack.last)
|
state.programs.flat.transform.value = state.matrixStack.last
|
||||||
|
|
||||||
builder.draw(GL_TRIANGLES)
|
builder.draw(GL_TRIANGLES)
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import ru.dbotthepony.kstarbound.client.gl.VertexArrayObject
|
|||||||
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
|
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexBuilder
|
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexBuilder
|
||||||
import ru.dbotthepony.kvector.api.IFloatMatrix
|
import ru.dbotthepony.kvector.api.IFloatMatrix
|
||||||
|
import ru.dbotthepony.kvector.api.concrete.IMatrix4f
|
||||||
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -18,13 +19,13 @@ import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
|||||||
* Ожидается, что состояние будет выставлено ПОЛНОСТЬЮ, т.е. НИКАКОЙ предыдущий код НЕ МОЖЕТ повлиять на результат выполнения
|
* Ожидается, что состояние будет выставлено ПОЛНОСТЬЮ, т.е. НИКАКОЙ предыдущий код НЕ МОЖЕТ повлиять на результат выполнения
|
||||||
* шейдерной программы, которая связанна с этим объектом (за исключением не вызова [setTransform] внешним кодом)
|
* шейдерной программы, которая связанна с этим объектом (за исключением не вызова [setTransform] внешним кодом)
|
||||||
*/
|
*/
|
||||||
open class ConfiguredShaderProgram(
|
open class ConfiguredShaderProgram<T : GLShaderProgram>(
|
||||||
val program: GLShaderProgram,
|
val program: T,
|
||||||
) {
|
) {
|
||||||
private val transformLocation = program["_transform"]
|
private val transformLocation = program.getUniform("_transform") as? GLShaderProgram.F4x4Uniform
|
||||||
|
|
||||||
open fun setTransform(value: IFloatMatrix<*>) {
|
open fun setTransform(value: IMatrix4f<*>) {
|
||||||
transformLocation?.set(value)
|
transformLocation?.value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,14 +41,14 @@ open class ConfiguredShaderProgram(
|
|||||||
* с заданной матрицей трансформации
|
* с заданной матрицей трансформации
|
||||||
*/
|
*/
|
||||||
class ConfiguredStaticMesh(
|
class ConfiguredStaticMesh(
|
||||||
val programState: ConfiguredShaderProgram,
|
val programState: ConfiguredShaderProgram<*>,
|
||||||
val indexCount: Int,
|
val indexCount: Int,
|
||||||
val vao: VertexArrayObject,
|
val vao: VertexArrayObject,
|
||||||
val elementIndexType: Int,
|
val elementIndexType: Int,
|
||||||
) : AutoCloseable {
|
) : AutoCloseable {
|
||||||
private var onClose = {}
|
private var onClose = {}
|
||||||
|
|
||||||
constructor(programState: ConfiguredShaderProgram, builder: VertexBuilder) : this(
|
constructor(programState: ConfiguredShaderProgram<*>, builder: VertexBuilder) : this(
|
||||||
programState,
|
programState,
|
||||||
builder.indexCount,
|
builder.indexCount,
|
||||||
programState.program.state.newVAO(),
|
programState.program.state.newVAO(),
|
||||||
@ -73,7 +74,7 @@ class ConfiguredStaticMesh(
|
|||||||
ebo.unbind()
|
ebo.unbind()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun render(transform: IFloatMatrix<*>? = null) {
|
fun render(transform: IMatrix4f<*>? = null) {
|
||||||
check(isValid) { "$this is no longer valid" }
|
check(isValid) { "$this is no longer valid" }
|
||||||
programState.setup()
|
programState.setup()
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ class Font(
|
|||||||
stack.scale(x = scale, y = scale)
|
stack.scale(x = scale, y = scale)
|
||||||
|
|
||||||
state.programs.font.use()
|
state.programs.font.use()
|
||||||
state.programs.font.color.set(color)
|
state.programs.font.color.value = color
|
||||||
state.activeTexture = 0
|
state.activeTexture = 0
|
||||||
|
|
||||||
val space = getGlyph(' ')
|
val space = getGlyph(' ')
|
||||||
@ -343,7 +343,7 @@ class Font(
|
|||||||
stack.translateWithMultiplication(bearingX, -bearingY)
|
stack.translateWithMultiplication(bearingX, -bearingY)
|
||||||
|
|
||||||
texture!!.bind()
|
texture!!.bind()
|
||||||
state.programs.font.transform.set(stack.last)
|
state.programs.font.transform.value = stack.last
|
||||||
glDrawElements(GL_TRIANGLES, indexCount, elementIndexType, 0L)
|
glDrawElements(GL_TRIANGLES, indexCount, elementIndexType, 0L)
|
||||||
checkForGLError()
|
checkForGLError()
|
||||||
|
|
||||||
|
@ -10,8 +10,8 @@ import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
|||||||
import ru.dbotthepony.kstarbound.client.gl.GLTexture2D
|
import ru.dbotthepony.kstarbound.client.gl.GLTexture2D
|
||||||
import ru.dbotthepony.kstarbound.client.gl.GLType
|
import ru.dbotthepony.kstarbound.client.gl.GLType
|
||||||
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
|
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
|
||||||
import ru.dbotthepony.kstarbound.client.gl.program.GLHardLightGeometryProgram
|
import ru.dbotthepony.kstarbound.client.gl.shader.GLHardLightGeometryProgram
|
||||||
import ru.dbotthepony.kstarbound.client.gl.program.GLSoftLightGeometryProgram
|
import ru.dbotthepony.kstarbound.client.gl.shader.GLSoftLightGeometryProgram
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
|
import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
||||||
@ -164,9 +164,9 @@ class GPULightRenderer(val state: GLStateTracker) {
|
|||||||
state.clearColor = old
|
state.clearColor = old
|
||||||
|
|
||||||
state.programs.hardLightGeometry.use()
|
state.programs.hardLightGeometry.use()
|
||||||
state.programs.hardLightGeometry.transform.set(stack.last)
|
state.programs.hardLightGeometry.transform.value = (stack.last)
|
||||||
state.programs.hardLightGeometry.lightPosition.set(position)
|
state.programs.hardLightGeometry.lightPosition.value = (position)
|
||||||
state.programs.hardLightGeometry.lightPenetration.set(1f - lightPenetration)
|
state.programs.hardLightGeometry.lightPenetration.value = (1f - lightPenetration)
|
||||||
|
|
||||||
state.blendFunc = BlendFunc.ONLY_BLEND_ALPHA
|
state.blendFunc = BlendFunc.ONLY_BLEND_ALPHA
|
||||||
|
|
||||||
@ -175,8 +175,8 @@ class GPULightRenderer(val state: GLStateTracker) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
state.programs.light.use()
|
state.programs.light.use()
|
||||||
state.programs.light.transform.set(stack.last)
|
state.programs.light.transform.value = (stack.last)
|
||||||
state.programs.light.baselineColor.set(color)
|
state.programs.light.baselineColor.value = (color)
|
||||||
|
|
||||||
// Свет
|
// Свет
|
||||||
val builder = state.programs.light.builder
|
val builder = state.programs.light.builder
|
||||||
@ -225,9 +225,9 @@ class GPULightRenderer(val state: GLStateTracker) {
|
|||||||
state.clearColor = old
|
state.clearColor = old
|
||||||
|
|
||||||
state.programs.softLightGeometry.use()
|
state.programs.softLightGeometry.use()
|
||||||
state.programs.softLightGeometry.transform.set(stack.last)
|
state.programs.softLightGeometry.transform.value = (stack.last)
|
||||||
state.programs.softLightGeometry.lightPositionAndSize.set(Vector3f(position, innerRadius))
|
state.programs.softLightGeometry.lightPositionAndSize.value = (Vector3f(position, innerRadius))
|
||||||
state.programs.softLightGeometry.lightPenetration.set(lightPenetration)
|
state.programs.softLightGeometry.lightPenetration.value = (lightPenetration)
|
||||||
|
|
||||||
state.blendFunc = BlendFunc.ONLY_BLEND_ALPHA
|
state.blendFunc = BlendFunc.ONLY_BLEND_ALPHA
|
||||||
|
|
||||||
@ -241,8 +241,8 @@ class GPULightRenderer(val state: GLStateTracker) {
|
|||||||
state.cull = false
|
state.cull = false
|
||||||
|
|
||||||
state.programs.light.use()
|
state.programs.light.use()
|
||||||
state.programs.light.transform.set(stack.last)
|
state.programs.light.transform.value = (stack.last)
|
||||||
state.programs.light.baselineColor.set(color)
|
state.programs.light.baselineColor.value = (color)
|
||||||
|
|
||||||
// Свет
|
// Свет
|
||||||
val builder = state.programs.light.builder
|
val builder = state.programs.light.builder
|
||||||
|
@ -7,6 +7,7 @@ import org.lwjgl.opengl.GL46.*
|
|||||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
||||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||||
import ru.dbotthepony.kstarbound.client.gl.*
|
import ru.dbotthepony.kstarbound.client.gl.*
|
||||||
|
import ru.dbotthepony.kstarbound.client.gl.shader.GLTileProgram
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
|
import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.*
|
import ru.dbotthepony.kstarbound.client.gl.vertex.*
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.*
|
import ru.dbotthepony.kstarbound.defs.tile.*
|
||||||
@ -17,20 +18,20 @@ import ru.dbotthepony.kvector.vector.nint.Vector2i
|
|||||||
import kotlin.collections.HashMap
|
import kotlin.collections.HashMap
|
||||||
|
|
||||||
data class TileLayer(
|
data class TileLayer(
|
||||||
val bakedProgramState: ConfiguredShaderProgram,
|
val bakedProgramState: ConfiguredShaderProgram<GLTileProgram>,
|
||||||
val vertexBuilder: VertexBuilder,
|
val vertexBuilder: VertexBuilder,
|
||||||
val zPos: Int
|
val zPos: Int
|
||||||
)
|
)
|
||||||
|
|
||||||
class TileLayerList {
|
class TileLayerList {
|
||||||
private val layers = HashMap<ConfiguredShaderProgram, Int2ObjectAVLTreeMap<TileLayer>>()
|
private val layers = HashMap<ConfiguredShaderProgram<GLTileProgram>, Int2ObjectAVLTreeMap<TileLayer>>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Получает геометрию слоя ([DynamicVertexBuilder]), который имеет программу для отрисовки [program] и располагается на [zLevel].
|
* Получает геометрию слоя ([DynamicVertexBuilder]), который имеет программу для отрисовки [program] и располагается на [zLevel].
|
||||||
*
|
*
|
||||||
* Если такого слоя нет, вызывается [compute] и создаётся новый [TileLayer], затем возвращается результат [compute].
|
* Если такого слоя нет, вызывается [compute] и создаётся новый [TileLayer], затем возвращается результат [compute].
|
||||||
*/
|
*/
|
||||||
fun computeIfAbsent(program: ConfiguredShaderProgram, zLevel: Int, compute: () -> VertexBuilder): VertexBuilder {
|
fun computeIfAbsent(program: ConfiguredShaderProgram<GLTileProgram>, zLevel: Int, compute: () -> VertexBuilder): VertexBuilder {
|
||||||
return layers.computeIfAbsent(program) { Int2ObjectAVLTreeMap() }.computeIfAbsent(zLevel, Int2ObjectFunction {
|
return layers.computeIfAbsent(program) { Int2ObjectAVLTreeMap() }.computeIfAbsent(zLevel, Int2ObjectFunction {
|
||||||
return@Int2ObjectFunction TileLayer(program, compute.invoke(), zLevel)
|
return@Int2ObjectFunction TileLayer(program, compute.invoke(), zLevel)
|
||||||
}).vertexBuilder
|
}).vertexBuilder
|
||||||
@ -83,17 +84,17 @@ class TileRenderers(val client: StarboundClient) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class ForegroundTileProgram(private val texture: GLTexture2D) : ConfiguredShaderProgram(state.programs.tile) {
|
private inner class ForegroundTileProgram(private val texture: GLTexture2D) : ConfiguredShaderProgram<GLTileProgram>(state.programs.tile) {
|
||||||
override fun setup() {
|
override fun setup() {
|
||||||
super.setup()
|
super.setup()
|
||||||
state.activeTexture = 0
|
state.activeTexture = 0
|
||||||
state.depthTest = false
|
state.depthTest = false
|
||||||
program["_texture"] = 0
|
program.texture = 0
|
||||||
texture.bind()
|
texture.bind()
|
||||||
texture.textureMagFilter = GL_NEAREST
|
texture.textureMagFilter = GL_NEAREST
|
||||||
texture.textureMinFilter = GL_NEAREST
|
texture.textureMinFilter = GL_NEAREST
|
||||||
|
|
||||||
program["_color"] = FOREGROUND_COLOR
|
program.color.value = FOREGROUND_COLOR
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
@ -113,17 +114,17 @@ class TileRenderers(val client: StarboundClient) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class BackgroundTileProgram(private val texture: GLTexture2D) : ConfiguredShaderProgram(state.programs.tile) {
|
private inner class BackgroundTileProgram(private val texture: GLTexture2D) : ConfiguredShaderProgram<GLTileProgram>(state.programs.tile) {
|
||||||
override fun setup() {
|
override fun setup() {
|
||||||
super.setup()
|
super.setup()
|
||||||
state.activeTexture = 0
|
state.activeTexture = 0
|
||||||
state.depthTest = false
|
state.depthTest = false
|
||||||
program["_texture"] = 0
|
program.texture = 0
|
||||||
texture.bind()
|
texture.bind()
|
||||||
texture.textureMagFilter = GL_NEAREST
|
texture.textureMagFilter = GL_NEAREST
|
||||||
texture.textureMinFilter = GL_NEAREST
|
texture.textureMinFilter = GL_NEAREST
|
||||||
|
|
||||||
program["_color"] = BACKGROUND_COLOR
|
program.color.value = BACKGROUND_COLOR
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
@ -146,14 +147,14 @@ class TileRenderers(val client: StarboundClient) {
|
|||||||
/**
|
/**
|
||||||
* Возвращает запечённое состояние шейдера shaderVertexTexture с данной текстурой
|
* Возвращает запечённое состояние шейдера shaderVertexTexture с данной текстурой
|
||||||
*/
|
*/
|
||||||
fun foreground(texture: GLTexture2D): ConfiguredShaderProgram {
|
fun foreground(texture: GLTexture2D): ConfiguredShaderProgram<GLTileProgram> {
|
||||||
return foregroundTilePrograms.computeIfAbsent(texture, ::ForegroundTileProgram)
|
return foregroundTilePrograms.computeIfAbsent(texture, ::ForegroundTileProgram)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Возвращает запечённое состояние шейдера shaderVertexTextureColor с данной текстурой
|
* Возвращает запечённое состояние шейдера shaderVertexTextureColor с данной текстурой
|
||||||
*/
|
*/
|
||||||
fun background(texture: GLTexture2D): ConfiguredShaderProgram {
|
fun background(texture: GLTexture2D): ConfiguredShaderProgram<GLTileProgram> {
|
||||||
return backgroundTilePrograms.computeIfAbsent(texture, ::BackgroundTileProgram)
|
return backgroundTilePrograms.computeIfAbsent(texture, ::BackgroundTileProgram)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,9 +16,9 @@ class ItemRenderer(state: GLStateTracker, entity: ItemEntity, chunk: ClientChunk
|
|||||||
return
|
return
|
||||||
|
|
||||||
state.shaderVertexTexture.use()
|
state.shaderVertexTexture.use()
|
||||||
state.shaderVertexTexture.transform.set(stack.last)
|
state.shaderVertexTexture.transform.value = (stack.last)
|
||||||
state.activeTexture = 0
|
state.activeTexture = 0
|
||||||
state.shaderVertexTexture["_texture"] = 0
|
state.shaderVertexTexture.texture.value = 0
|
||||||
|
|
||||||
for (texture in textures) {
|
for (texture in textures) {
|
||||||
texture.bind()
|
texture.bind()
|
||||||
|
Loading…
Reference in New Issue
Block a user