Shadows test
This commit is contained in:
parent
3cc8d54ede
commit
0614158a9c
@ -3,16 +3,24 @@ package ru.dbotthepony.kstarbound
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.lwjgl.Version
|
||||
import org.lwjgl.glfw.GLFW.glfwSetWindowShouldClose
|
||||
import org.lwjgl.opengl.GL11.GL_LINES
|
||||
import org.lwjgl.opengl.GL11.GL_RGBA
|
||||
import org.lwjgl.opengl.GL46
|
||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||
import ru.dbotthepony.kstarbound.client.gl.BlendFunc
|
||||
import ru.dbotthepony.kstarbound.client.gl.GLFrameBuffer
|
||||
import ru.dbotthepony.kstarbound.client.gl.GLTexture2D
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quad
|
||||
import ru.dbotthepony.kstarbound.io.*
|
||||
import ru.dbotthepony.kstarbound.world.ChunkPos
|
||||
import ru.dbotthepony.kstarbound.world.entities.PlayerEntity
|
||||
import ru.dbotthepony.kvector.vector.Color
|
||||
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.DataInputStream
|
||||
import java.io.File
|
||||
import java.util.zip.Inflater
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
private val LOGGER = LogManager.getLogger()
|
||||
|
||||
@ -28,9 +36,9 @@ fun main() {
|
||||
Starbound.addPakPath(File("J:\\Steam\\steamapps\\common\\Starbound\\assets\\packed.pak"))
|
||||
//Starbound.addPakPath(File("packed.pak"))
|
||||
|
||||
Starbound.initializeGame { finished, replaceStatus, status ->
|
||||
/*Starbound.initializeGame { finished, replaceStatus, status ->
|
||||
client.putDebugLog(status, replaceStatus)
|
||||
}
|
||||
}*/
|
||||
|
||||
client.onTermination {
|
||||
Starbound.terminateLoading = true
|
||||
@ -163,13 +171,90 @@ fun main() {
|
||||
|
||||
//ent.position += Vector2d(y = 14.0, x = -10.0)
|
||||
ent.position = Vector2d(600.0 + 16.0, 721.0 + 48.0)
|
||||
client.camera.pos.x = 578f
|
||||
client.camera.pos.y = 695f
|
||||
//client.camera.pos.x = 578f
|
||||
//client.camera.pos.y = 695f
|
||||
|
||||
client.onDrawGUI {
|
||||
client.gl.font.render("${ent.position}", y = 100f, scale = 0.25f)
|
||||
client.gl.font.render("${ent.movement.velocity}", y = 120f, scale = 0.25f)
|
||||
client.gl.font.render("${client.camera.pos}", y = 140f, scale = 0.25f)
|
||||
client.gl.font.render("${client.camera.pos} ${client.settings.zoom}", y = 140f, scale = 0.25f)
|
||||
}
|
||||
|
||||
val lightmap = GLFrameBuffer(client.gl)
|
||||
|
||||
lightmap.reattachTexture(client.viewportWidth, client.viewportHeight, GL_RGBA)
|
||||
|
||||
client.onViewportChanged { width, height -> lightmap.reattachTexture(width, height, GL_RGBA) }
|
||||
|
||||
client.onPostDrawWorld {
|
||||
lightmap.bind()
|
||||
GL46.glClear(GL46.GL_COLOR_BUFFER_BIT or GL46.GL_DEPTH_BUFFER_BIT)
|
||||
//client.gl.programs.colorQuad.clearAlpha()
|
||||
|
||||
client.gl.programs.light.use()
|
||||
client.gl.programs.light.transform.set(client.gl.matrixStack.last)
|
||||
// client.gl.programs.light.transform.set(Matrix4f.IDENTITY)
|
||||
client.gl.programs.light.baselineColor.set(Color.WHITE)
|
||||
|
||||
var builder = client.gl.programs.light.builder
|
||||
|
||||
val (rX, rY) = client.screenToWorld(client.mouseCoordinatesF)
|
||||
|
||||
builder.begin()
|
||||
|
||||
//val size = 20f / client.settings.scale
|
||||
val size = 10f
|
||||
|
||||
builder.quad(rX - size, rY - size, rX + size, rY + size, QuadTransformers.uv())
|
||||
|
||||
builder.upload()
|
||||
|
||||
//client.gl.blendFunc = BlendFunc(
|
||||
// BlendFunc.Func.DST_ALPHA,
|
||||
// BlendFunc.Func.ONE_MINUS_DST_ALPHA
|
||||
//)
|
||||
|
||||
builder.draw()
|
||||
client.gl.blendFunc = BlendFunc.ALPHA_TEST
|
||||
|
||||
client.gl.programs.lightOccluder.use()
|
||||
client.gl.programs.lightOccluder.transform.set(client.gl.matrixStack.last)
|
||||
|
||||
builder = client.gl.programs.lightOccluder.builder
|
||||
|
||||
builder.begin()
|
||||
|
||||
val lightPosition = client.screenToWorld(client.mouseCoordinatesF)
|
||||
|
||||
builder.quad(0f, 0f, 2f, 2f)
|
||||
builder.quad(-6f, 0f, -2f, 2f)
|
||||
|
||||
client.gl.programs.lightOccluder.lightPosition.set(lightPosition)
|
||||
|
||||
builder.upload()
|
||||
|
||||
client.gl.blendFunc = BlendFunc.ONLY_ALPHA
|
||||
builder.draw(GL_LINES)
|
||||
client.gl.blendFunc = BlendFunc.ALPHA_TEST
|
||||
|
||||
lightmap.unbind()
|
||||
|
||||
client.gl.activeTexture = 0
|
||||
client.gl.texture2D = lightmap.texture
|
||||
client.gl.programs.textureQuad.run(0)
|
||||
|
||||
client.gl.programs.flat.use()
|
||||
client.gl.programs.flat.color.set(Color.BLACK)
|
||||
client.gl.programs.flat.transform.set(client.gl.matrixStack.last)
|
||||
builder = client.gl.programs.flat.builder
|
||||
|
||||
builder.begin()
|
||||
|
||||
builder.quad(0f, 0f, 2f, 2f)
|
||||
builder.quad(-6f, 0f, -2f, 2f)
|
||||
|
||||
builder.upload()
|
||||
builder.draw()
|
||||
}
|
||||
|
||||
client.onPreDrawWorld {
|
||||
@ -186,9 +271,9 @@ fun main() {
|
||||
|
||||
client.input.addScrollCallback { _, x, y ->
|
||||
if (y > 0.0) {
|
||||
client.settings.scale *= y.toFloat() * 2f
|
||||
client.settings.zoom *= y.toFloat() * 2f
|
||||
} else if (y < 0.0) {
|
||||
client.settings.scale /= -y.toFloat() * 2f
|
||||
client.settings.zoom /= -y.toFloat() * 2f
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,11 +284,11 @@ fun main() {
|
||||
//client.camera.pos.x = ent.position.x.toFloat()
|
||||
//client.camera.pos.y = ent.position.y.toFloat()
|
||||
|
||||
client.camera.pos.x += if (client.input.KEY_LEFT_DOWN || client.input.KEY_A_DOWN) -client.frameRenderTime.toFloat() * 32f / client.settings.scale else 0f
|
||||
client.camera.pos.x += if (client.input.KEY_RIGHT_DOWN || client.input.KEY_D_DOWN) client.frameRenderTime.toFloat() * 32f / client.settings.scale else 0f
|
||||
client.camera.pos.x += if (client.input.KEY_LEFT_DOWN || client.input.KEY_A_DOWN) -client.frameRenderTime.toFloat() * 32f / client.settings.zoom else 0f
|
||||
client.camera.pos.x += if (client.input.KEY_RIGHT_DOWN || client.input.KEY_D_DOWN) client.frameRenderTime.toFloat() * 32f / client.settings.zoom else 0f
|
||||
|
||||
client.camera.pos.y += if (client.input.KEY_UP_DOWN || client.input.KEY_W_DOWN) client.frameRenderTime.toFloat() * 32f / client.settings.scale else 0f
|
||||
client.camera.pos.y += if (client.input.KEY_DOWN_DOWN || client.input.KEY_S_DOWN) -client.frameRenderTime.toFloat() * 32f / client.settings.scale else 0f
|
||||
client.camera.pos.y += if (client.input.KEY_UP_DOWN || client.input.KEY_W_DOWN) client.frameRenderTime.toFloat() * 32f / client.settings.zoom else 0f
|
||||
client.camera.pos.y += if (client.input.KEY_DOWN_DOWN || client.input.KEY_S_DOWN) -client.frameRenderTime.toFloat() * 32f / client.settings.zoom else 0f
|
||||
|
||||
//println(client.camera.velocity.toDoubleVector() * client.frameRenderTime * 0.1)
|
||||
|
||||
|
@ -2,6 +2,7 @@ package ru.dbotthepony.kstarbound.client
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
|
||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quad
|
||||
import ru.dbotthepony.kstarbound.client.render.ConfiguredStaticMesh
|
||||
import ru.dbotthepony.kstarbound.client.render.EntityRenderer
|
||||
import ru.dbotthepony.kstarbound.client.render.ILayeredRenderer
|
||||
|
@ -6,7 +6,7 @@ data class ClientSettings(
|
||||
*
|
||||
* Масштаб в единицу означает что один Starbound Unit будет равен 8 пикселям на экране
|
||||
*/
|
||||
var scale: Float = 2f,
|
||||
var zoom: Float = 2f,
|
||||
|
||||
var debugCollisions: Boolean = false,
|
||||
)
|
||||
|
@ -3,6 +3,7 @@ package ru.dbotthepony.kstarbound.client
|
||||
import org.lwjgl.opengl.GL46.*
|
||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quadZ
|
||||
import ru.dbotthepony.kstarbound.client.render.ILayeredRenderer
|
||||
import ru.dbotthepony.kstarbound.client.render.renderLayeredList
|
||||
import ru.dbotthepony.kstarbound.defs.ParallaxPrototype
|
||||
|
@ -10,16 +10,20 @@ import org.lwjgl.system.MemoryUtil
|
||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNIT
|
||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.client.gl.BlendFunc
|
||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
||||
import ru.dbotthepony.kstarbound.client.input.UserInput
|
||||
import ru.dbotthepony.kstarbound.client.render.Camera
|
||||
import ru.dbotthepony.kstarbound.client.render.TextAlignX
|
||||
import ru.dbotthepony.kstarbound.client.render.TextAlignY
|
||||
import ru.dbotthepony.kstarbound.util.formatBytesShort
|
||||
import ru.dbotthepony.kvector.matrix.nfloat.Matrix4f
|
||||
import ru.dbotthepony.kvector.util2d.AABB
|
||||
import ru.dbotthepony.kvector.vector.Color
|
||||
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
|
||||
import ru.dbotthepony.kvector.vector.nfloat.Vector2f
|
||||
import ru.dbotthepony.kvector.vector.nfloat.Vector3f
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
|
||||
class StarboundClient : AutoCloseable {
|
||||
val window: Long
|
||||
@ -35,10 +39,16 @@ class StarboundClient : AutoCloseable {
|
||||
var viewportHeight = 600
|
||||
private set
|
||||
|
||||
var viewportMatrixGUI = updateViewportMatrixA()
|
||||
/**
|
||||
* Матрица преобразования экранных координат (в пикселях) в нормализованные координаты
|
||||
*/
|
||||
var viewportMatrixScreen = updateViewportMatrixScreen()
|
||||
private set
|
||||
|
||||
var viewportMatrixGame = updateViewportMatrixB()
|
||||
/**
|
||||
* Матрица преобразования мировых координат в нормализованные координаты
|
||||
*/
|
||||
var viewportMatrixWorld = updateViewportMatrixWorld()
|
||||
private set
|
||||
|
||||
private val startupTextList = ArrayList<String>()
|
||||
@ -58,12 +68,69 @@ class StarboundClient : AutoCloseable {
|
||||
finishStartupRendering = System.currentTimeMillis() + 4000L
|
||||
}
|
||||
|
||||
private fun updateViewportMatrixA(): Matrix4f {
|
||||
return Matrix4f.ortho(0f, viewportWidth.toFloat(), 0f, viewportHeight.toFloat(), 0.1f, 100f)
|
||||
private fun updateViewportMatrixScreen(): Matrix4f {
|
||||
return Matrix4f.ortho(0f, viewportWidth.toFloat(), 0f, viewportHeight.toFloat(), 0.1f, 100f).translate(Vector3f(z = 2f)).toMatrix4f()
|
||||
}
|
||||
|
||||
private fun updateViewportMatrixB(): Matrix4f {
|
||||
return Matrix4f.orthoDirect(0f, viewportWidth.toFloat(), 0f, viewportHeight.toFloat(), 1f, 100f)
|
||||
private fun updateViewportMatrixWorld(): Matrix4f {
|
||||
return Matrix4f.orthoDirect(0f, viewportWidth.toFloat(), 0f, viewportHeight.toFloat(), 1f, 100f).toMatrix4f()
|
||||
}
|
||||
|
||||
private val xMousePos = ByteBuffer.allocateDirect(8).also { it.order(ByteOrder.LITTLE_ENDIAN) }.asDoubleBuffer()
|
||||
private val yMousePos = ByteBuffer.allocateDirect(8).also { it.order(ByteOrder.LITTLE_ENDIAN) }.asDoubleBuffer()
|
||||
|
||||
val mouseCoordinates: Vector2d get() {
|
||||
xMousePos.position(0)
|
||||
yMousePos.position(0)
|
||||
GLFW.glfwGetCursorPos(window, xMousePos, yMousePos)
|
||||
xMousePos.position(0)
|
||||
yMousePos.position(0)
|
||||
|
||||
return Vector2d(xMousePos.get(), yMousePos.get())
|
||||
}
|
||||
|
||||
val mouseCoordinatesF: Vector2f get() {
|
||||
xMousePos.position(0)
|
||||
yMousePos.position(0)
|
||||
GLFW.glfwGetCursorPos(window, xMousePos, yMousePos)
|
||||
xMousePos.position(0)
|
||||
yMousePos.position(0)
|
||||
|
||||
return Vector2f(xMousePos.get().toFloat(), yMousePos.get().toFloat())
|
||||
}
|
||||
|
||||
/**
|
||||
* Преобразует экранные координаты в мировые
|
||||
*/
|
||||
fun screenToWorld(x: Double, y: Double): Vector2d {
|
||||
val relativeX = camera.pos.x - (viewportWidth / 2.0 - x) / PIXELS_IN_STARBOUND_UNIT / settings.zoom
|
||||
val relativeY = (viewportHeight / 2.0 - y) / PIXELS_IN_STARBOUND_UNIT / settings.zoom + camera.pos.y
|
||||
|
||||
return Vector2d(relativeX, relativeY)
|
||||
}
|
||||
|
||||
/**
|
||||
* Преобразует экранные координаты в мировые
|
||||
*/
|
||||
fun screenToWorld(value: Vector2d): Vector2d {
|
||||
return screenToWorld(value.x, value.y)
|
||||
}
|
||||
|
||||
/**
|
||||
* Преобразует экранные координаты в мировые
|
||||
*/
|
||||
fun screenToWorld(x: Float, y: Float): Vector2f {
|
||||
val relativeX = camera.pos.x - (viewportWidth / 2f - x) / PIXELS_IN_STARBOUND_UNITf / settings.zoom
|
||||
val relativeY = (viewportHeight / 2f - y) / PIXELS_IN_STARBOUND_UNITf / settings.zoom + camera.pos.y
|
||||
|
||||
return Vector2f(relativeX, relativeY)
|
||||
}
|
||||
|
||||
/**
|
||||
* Преобразует экранные координаты в мировые
|
||||
*/
|
||||
fun screenToWorld(value: Vector2f): Vector2f {
|
||||
return screenToWorld(value.x, value.y)
|
||||
}
|
||||
|
||||
init {
|
||||
@ -90,9 +157,13 @@ class StarboundClient : AutoCloseable {
|
||||
GLFW.glfwSetFramebufferSizeCallback(window) { _, w, h ->
|
||||
viewportWidth = w
|
||||
viewportHeight = h
|
||||
viewportMatrixGUI = updateViewportMatrixA()
|
||||
viewportMatrixGame = updateViewportMatrixB()
|
||||
viewportMatrixScreen = updateViewportMatrixScreen()
|
||||
viewportMatrixWorld = updateViewportMatrixWorld()
|
||||
glViewport(0, 0, w, h)
|
||||
|
||||
for (callback in onViewportChanged) {
|
||||
callback.invoke(w, h)
|
||||
}
|
||||
}
|
||||
|
||||
val stack = MemoryStack.stackPush()
|
||||
@ -134,7 +205,7 @@ class StarboundClient : AutoCloseable {
|
||||
gl.clearColor = Color.SLATE_GREY
|
||||
|
||||
gl.blend = true
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
||||
gl.blendFunc = BlendFunc.ALPHA_TEST
|
||||
}
|
||||
|
||||
var frameRenderTime = 0.0
|
||||
@ -160,6 +231,12 @@ class StarboundClient : AutoCloseable {
|
||||
|
||||
val settings = ClientSettings()
|
||||
|
||||
private val onViewportChanged = ArrayList<(width: Int, height: Int) -> Unit>()
|
||||
|
||||
fun onViewportChanged(callback: (width: Int, height: Int) -> Unit) {
|
||||
onViewportChanged.add(callback)
|
||||
}
|
||||
|
||||
private val onDrawGUI = ArrayList<() -> Unit>()
|
||||
|
||||
fun onDrawGUI(lambda: () -> Unit) {
|
||||
@ -198,11 +275,11 @@ class StarboundClient : AutoCloseable {
|
||||
world?.think(frameRenderTime)
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
|
||||
gl.matrixStack.clear(viewportMatrixGame.toMutableMatrix4f())
|
||||
gl.matrixStack.clear(viewportMatrixWorld.toMutableMatrix4f())
|
||||
|
||||
gl.matrixStack.push()
|
||||
.translateWithMultiplication(viewportWidth / 2f, viewportHeight / 2f, 2f) // центр экрана + координаты отрисовки мира
|
||||
.scale(x = settings.scale * PIXELS_IN_STARBOUND_UNITf, y = settings.scale * PIXELS_IN_STARBOUND_UNITf) // масштабируем до нужного размера
|
||||
.scale(x = settings.zoom * PIXELS_IN_STARBOUND_UNITf, y = settings.zoom * PIXELS_IN_STARBOUND_UNITf) // масштабируем до нужного размера
|
||||
.translateWithMultiplication(-camera.pos.x, -camera.pos.y) // перемещаем вид к камере
|
||||
|
||||
for (lambda in onPreDrawWorld) {
|
||||
@ -217,8 +294,8 @@ class StarboundClient : AutoCloseable {
|
||||
world?.render(
|
||||
AABB.rectangle(
|
||||
camera.pos.toDoubleVector(),
|
||||
viewportWidth / settings.scale / PIXELS_IN_STARBOUND_UNIT,
|
||||
viewportHeight / settings.scale / PIXELS_IN_STARBOUND_UNIT))
|
||||
viewportWidth / settings.zoom / PIXELS_IN_STARBOUND_UNIT,
|
||||
viewportHeight / settings.zoom / PIXELS_IN_STARBOUND_UNIT))
|
||||
|
||||
for (lambda in onPostDrawWorld) {
|
||||
lambda.invoke()
|
||||
@ -226,7 +303,7 @@ class StarboundClient : AutoCloseable {
|
||||
|
||||
gl.matrixStack.pop()
|
||||
|
||||
gl.matrixStack.clear(viewportMatrixGUI.toMutableMatrix4f().translate(Vector3f(z = 2f)))
|
||||
gl.matrixStack.clear(viewportMatrixScreen.toMutableMatrix4f())
|
||||
|
||||
val thisTime = System.currentTimeMillis()
|
||||
|
||||
|
@ -0,0 +1,93 @@
|
||||
package ru.dbotthepony.kstarbound.client.gl
|
||||
|
||||
import org.lwjgl.opengl.GL30.GL_COLOR_ATTACHMENT0
|
||||
import org.lwjgl.opengl.GL30.GL_FRAMEBUFFER
|
||||
import org.lwjgl.opengl.GL30.GL_FRAMEBUFFER_COMPLETE
|
||||
import org.lwjgl.opengl.GL30.GL_LINEAR
|
||||
import org.lwjgl.opengl.GL30.GL_RGB
|
||||
import org.lwjgl.opengl.GL30.GL_TEXTURE
|
||||
import org.lwjgl.opengl.GL30.GL_TEXTURE_2D
|
||||
import org.lwjgl.opengl.GL30.glCheckFramebufferStatus
|
||||
import org.lwjgl.opengl.GL30.glFramebufferTexture2D
|
||||
import org.lwjgl.opengl.GL45.glCheckNamedFramebufferStatus
|
||||
import org.lwjgl.opengl.GL45.glNamedFramebufferTexture
|
||||
import org.lwjgl.opengl.GL46
|
||||
|
||||
class GLFrameBuffer(val state: GLStateTracker) : AutoCloseable {
|
||||
init {
|
||||
state.ensureSameThread()
|
||||
}
|
||||
|
||||
val pointer = GL46.glGenFramebuffers()
|
||||
|
||||
init {
|
||||
checkForGLError()
|
||||
}
|
||||
|
||||
val isComplete: Boolean get() {
|
||||
state.ensureSameThread()
|
||||
return glCheckNamedFramebufferStatus(pointer, GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE
|
||||
}
|
||||
|
||||
var texture: GLTexture2D? = null
|
||||
private set
|
||||
|
||||
fun attachTexture(width: Int, height: Int, format: Int = GL_RGB) {
|
||||
if (texture != null) {
|
||||
throw IllegalStateException("Already has texture attached")
|
||||
}
|
||||
|
||||
val texture = GLTexture2D(state, "framebuffer_$pointer")
|
||||
texture.allocate(format, width, height)
|
||||
|
||||
val old = state.framebuffer
|
||||
bind()
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.pointer, 0)
|
||||
checkForGLError()
|
||||
this.texture = texture
|
||||
texture.textureMinFilter = GL_LINEAR
|
||||
state.framebuffer = old
|
||||
}
|
||||
|
||||
fun reattachTexture(width: Int, height: Int, format: Int = GL_RGB) {
|
||||
texture?.close()
|
||||
texture = null
|
||||
attachTexture(width, height, format)
|
||||
}
|
||||
|
||||
fun bind() {
|
||||
state.framebuffer = this
|
||||
}
|
||||
|
||||
fun bindWrite() {
|
||||
state.writeFramebuffer = this
|
||||
}
|
||||
|
||||
fun bindRead() {
|
||||
state.readFramebuffer = this
|
||||
}
|
||||
|
||||
fun unbind() {
|
||||
if (state.writeFramebuffer == this) {
|
||||
state.writeFramebuffer = null
|
||||
}
|
||||
|
||||
if (state.readFramebuffer == this) {
|
||||
state.readFramebuffer = null
|
||||
}
|
||||
}
|
||||
|
||||
private val cleanable = state.registerCleanable(this, GL46::glDeleteFramebuffers, "Framebuffer", pointer)
|
||||
var isValid = true
|
||||
private set
|
||||
|
||||
override fun close() {
|
||||
state.ensureSameThread()
|
||||
|
||||
if (!isValid)
|
||||
return
|
||||
|
||||
cleanable.cleanManual()
|
||||
isValid = false
|
||||
}
|
||||
}
|
@ -2,9 +2,11 @@ package ru.dbotthepony.kstarbound.client.gl
|
||||
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.lwjgl.opengl.GL
|
||||
import org.lwjgl.opengl.GL14
|
||||
import org.lwjgl.opengl.GL46.*
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.client.freetype.FreeType
|
||||
import ru.dbotthepony.kstarbound.client.freetype.InvalidArgumentException
|
||||
import ru.dbotthepony.kstarbound.client.gl.program.GLPrograms
|
||||
import ru.dbotthepony.kstarbound.client.gl.shader.GLShader
|
||||
import ru.dbotthepony.kstarbound.client.gl.program.GLShaderProgram
|
||||
@ -12,7 +14,8 @@ import ru.dbotthepony.kstarbound.client.gl.shader.GLTransformableColorableProgra
|
||||
import ru.dbotthepony.kstarbound.client.gl.shader.GLTransformableProgram
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexType
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quad
|
||||
import ru.dbotthepony.kstarbound.client.render.Box2DRenderer
|
||||
import ru.dbotthepony.kstarbound.client.render.Font
|
||||
import ru.dbotthepony.kstarbound.client.render.TileRenderers
|
||||
@ -22,7 +25,10 @@ import ru.dbotthepony.kvector.util2d.AABB
|
||||
import ru.dbotthepony.kvector.vector.Color
|
||||
import java.io.FileNotFoundException
|
||||
import java.lang.ref.Cleaner
|
||||
import java.util.*
|
||||
import java.util.concurrent.ThreadFactory
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
private class GLStateSwitchTracker(private val enum: Int, private var value: Boolean = false) {
|
||||
@ -47,7 +53,7 @@ private class GLStateSwitchTracker(private val enum: Int, private var value: Boo
|
||||
}
|
||||
}
|
||||
|
||||
private class GLStateGenericTracker<T>(private var value: T, private val lambda: (T) -> Unit) {
|
||||
private class GLStateGenericTracker<T>(private var value: T, private val callback: (T) -> Unit) {
|
||||
operator fun getValue(glStateTracker: GLStateTracker, property: KProperty<*>): T {
|
||||
return value
|
||||
}
|
||||
@ -58,12 +64,69 @@ private class GLStateGenericTracker<T>(private var value: T, private val lambda:
|
||||
if (value == this.value)
|
||||
return
|
||||
|
||||
lambda.invoke(value)
|
||||
callback.invoke(value)
|
||||
checkForGLError()
|
||||
this.value = value
|
||||
}
|
||||
}
|
||||
|
||||
@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 ALPHA_TEST = BlendFunc(Func.SRC_ALPHA, Func.ONE_MINUS_SRC_ALPHA)
|
||||
|
||||
val ONLY_ALPHA = BlendFunc(
|
||||
Func.ZERO,
|
||||
Func.ONE,
|
||||
Func.ONE,
|
||||
Func.ZERO
|
||||
)
|
||||
|
||||
val ONLY_COLOR = BlendFunc(
|
||||
Func.ONE,
|
||||
Func.ZERO,
|
||||
Func.ZERO,
|
||||
Func.ONE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
interface GLCleanable : Cleaner.Cleanable {
|
||||
/**
|
||||
* Выставляет флаг на то, что объект был удалён вручную и вызывает clean()
|
||||
@ -75,7 +138,14 @@ interface GLStreamBuilderList {
|
||||
val small: StreamVertexBuilder
|
||||
}
|
||||
|
||||
@Suppress("PropertyName", "unused")
|
||||
class GLStateTracker {
|
||||
private fun isMe(state: GLStateTracker?) {
|
||||
if (state != null && state != this) {
|
||||
throw InvalidArgumentException("Provided object does not belong to $this state tracker (belongs to $state)")
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
check(TRACKERS.get() == null) { "Already has state tracker existing at this thread!" }
|
||||
TRACKERS.set(this)
|
||||
@ -87,7 +157,8 @@ class GLStateTracker {
|
||||
GL.createCapabilities()
|
||||
}
|
||||
|
||||
private var cleanerHits = ArrayList<() -> Unit>()
|
||||
private val cleanerHits = ArrayList<() -> Unit>()
|
||||
|
||||
private val cleaner = Cleaner.create(object : ThreadFactory {
|
||||
override fun newThread(r: Runnable): Thread {
|
||||
val thread = Thread(r, "OpenGL Object Cleaner@" + System.identityHashCode(this))
|
||||
@ -101,11 +172,13 @@ class GLStateTracker {
|
||||
|
||||
val cleanable = cleaner.register(ref) {
|
||||
if (!cleanManual)
|
||||
LOGGER.error("{} with ID {} got leaked.", name, nativeRef)
|
||||
LOGGER.error("{} with ID {} was GC'd by JVM, but it should have been removed manually.", name, nativeRef)
|
||||
|
||||
cleanerHits.add {
|
||||
fn(nativeRef)
|
||||
checkForGLError()
|
||||
synchronized(cleanerHits) {
|
||||
cleanerHits.add {
|
||||
fn(nativeRef)
|
||||
checkForGLError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,11 +193,12 @@ class GLStateTracker {
|
||||
}
|
||||
|
||||
fun cleanup() {
|
||||
val copy = cleanerHits
|
||||
cleanerHits = ArrayList()
|
||||
synchronized(cleanerHits) {
|
||||
for (lambda in cleanerHits) {
|
||||
lambda.invoke()
|
||||
}
|
||||
|
||||
for (lambda in copy) {
|
||||
lambda.invoke()
|
||||
cleanerHits.clear()
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,6 +209,7 @@ class GLStateTracker {
|
||||
set(value) {
|
||||
ensureSameThread()
|
||||
if (field === value) return
|
||||
isMe(value?.state)
|
||||
field = value
|
||||
|
||||
if (value == null) {
|
||||
@ -152,6 +227,7 @@ class GLStateTracker {
|
||||
set(value) {
|
||||
ensureSameThread()
|
||||
if (field === value) return
|
||||
isMe(value?.state)
|
||||
field = value
|
||||
|
||||
if (value == null) {
|
||||
@ -169,6 +245,7 @@ class GLStateTracker {
|
||||
set(value) {
|
||||
ensureSameThread()
|
||||
if (field === value) return
|
||||
isMe(value?.state)
|
||||
field = value
|
||||
|
||||
if (value == null) {
|
||||
@ -181,6 +258,56 @@ class GLStateTracker {
|
||||
checkForGLError()
|
||||
}
|
||||
|
||||
var readFramebuffer: GLFrameBuffer? = null
|
||||
set(value) {
|
||||
ensureSameThread()
|
||||
if (field === value) return
|
||||
isMe(value?.state)
|
||||
field = value
|
||||
|
||||
if (value == null) {
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)
|
||||
checkForGLError()
|
||||
return
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, value.pointer)
|
||||
checkForGLError()
|
||||
}
|
||||
|
||||
var writeFramebuffer: GLFrameBuffer? = null
|
||||
set(value) {
|
||||
ensureSameThread()
|
||||
if (field === value) return
|
||||
isMe(value?.state)
|
||||
field = value
|
||||
|
||||
if (value == null) {
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)
|
||||
checkForGLError()
|
||||
return
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, value.pointer)
|
||||
checkForGLError()
|
||||
}
|
||||
|
||||
var framebuffer: GLFrameBuffer?
|
||||
get() {
|
||||
val readFramebuffer = readFramebuffer
|
||||
val writeFramebuffer = writeFramebuffer
|
||||
|
||||
if (readFramebuffer == writeFramebuffer) {
|
||||
return writeFramebuffer
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
set(value) {
|
||||
readFramebuffer = value
|
||||
writeFramebuffer = value
|
||||
}
|
||||
|
||||
var program: GLShaderProgram? = null
|
||||
private set
|
||||
|
||||
@ -188,6 +315,7 @@ class GLStateTracker {
|
||||
set(value) {
|
||||
ensureSameThread()
|
||||
if (field === value) return
|
||||
isMe(value?.state)
|
||||
field = value
|
||||
if (value == null) return
|
||||
glBindTexture(GL_TEXTURE_2D, value.pointer)
|
||||
@ -210,6 +338,10 @@ class GLStateTracker {
|
||||
glClearColor(r, g, b, a)
|
||||
}
|
||||
|
||||
var blendFunc by GLStateGenericTracker(BlendFunc()) {
|
||||
glBlendFuncSeparate(it.sourceColor.enum, it.destinationColor.enum, it.sourceAlpha.enum, it.destinationAlpha.enum)
|
||||
}
|
||||
|
||||
init {
|
||||
glActiveTexture(GL_TEXTURE0)
|
||||
checkForGLError()
|
||||
@ -362,42 +494,42 @@ class GLStateTracker {
|
||||
|
||||
val flat2DLines = object : GLStreamBuilderList {
|
||||
override val small by lazy {
|
||||
return@lazy StreamVertexBuilder(this@GLStateTracker, GLAttributeList.VEC2F, VertexType.LINES, 1024)
|
||||
return@lazy StreamVertexBuilder(this@GLStateTracker, GLAttributeList.VEC2F, GeometryType.LINES, 1024)
|
||||
}
|
||||
}
|
||||
|
||||
val flat2DTriangles = object : GLStreamBuilderList {
|
||||
override val small by lazy {
|
||||
return@lazy StreamVertexBuilder(this@GLStateTracker, GLAttributeList.VEC2F, VertexType.TRIANGLES, 1024)
|
||||
return@lazy StreamVertexBuilder(this@GLStateTracker, GLAttributeList.VEC2F, GeometryType.TRIANGLES, 1024)
|
||||
}
|
||||
}
|
||||
|
||||
val flat2DQuads = object : GLStreamBuilderList {
|
||||
override val small by lazy {
|
||||
return@lazy StreamVertexBuilder(this@GLStateTracker, GLAttributeList.VEC2F, VertexType.QUADS, 1024)
|
||||
return@lazy StreamVertexBuilder(this@GLStateTracker, GLAttributeList.VEC2F, GeometryType.QUADS, 1024)
|
||||
}
|
||||
}
|
||||
|
||||
val flat2DTexturedQuads = object : GLStreamBuilderList {
|
||||
override val small by lazy {
|
||||
return@lazy StreamVertexBuilder(this@GLStateTracker, GLAttributeList.VERTEX_TEXTURE, VertexType.QUADS, 1024)
|
||||
return@lazy StreamVertexBuilder(this@GLStateTracker, GLAttributeList.VERTEX_TEXTURE, GeometryType.QUADS, 1024)
|
||||
}
|
||||
}
|
||||
|
||||
val flat2DQuadLines = object : GLStreamBuilderList {
|
||||
override val small by lazy {
|
||||
return@lazy StreamVertexBuilder(this@GLStateTracker, GLAttributeList.VEC2F, VertexType.QUADS_AS_LINES, 1024)
|
||||
return@lazy StreamVertexBuilder(this@GLStateTracker, GLAttributeList.VEC2F, GeometryType.QUADS_AS_LINES, 1024)
|
||||
}
|
||||
}
|
||||
|
||||
val flat2DQuadWireframe = object : GLStreamBuilderList {
|
||||
override val small by lazy {
|
||||
return@lazy StreamVertexBuilder(this@GLStateTracker, GLAttributeList.VEC2F, VertexType.QUADS_AS_LINES_WIREFRAME, 1024)
|
||||
return@lazy StreamVertexBuilder(this@GLStateTracker, GLAttributeList.VEC2F, GeometryType.QUADS_AS_LINES_WIREFRAME, 1024)
|
||||
}
|
||||
}
|
||||
|
||||
val quadWireframe by lazy {
|
||||
StreamVertexBuilder(this, GLAttributeList.VEC2F, VertexType.QUADS_AS_LINES_WIREFRAME, 16384)
|
||||
StreamVertexBuilder(this, GLAttributeList.VEC2F, GeometryType.QUADS_AS_LINES_WIREFRAME, 16384)
|
||||
}
|
||||
|
||||
val matrixStack = Matrix4fStack()
|
||||
|
@ -27,6 +27,7 @@ class GLTexturePropertyTracker(private val flag: Int, var value: Int) {
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
class GLTexture2D(val state: GLStateTracker, val name: String = "<unknown>") : AutoCloseable {
|
||||
val pointer = glGenTextures()
|
||||
|
||||
@ -63,18 +64,20 @@ class GLTexture2D(val state: GLStateTracker, val name: String = "<unknown>") : A
|
||||
|
||||
private var mipsWarning = 2
|
||||
|
||||
var textureMinFilter by GLTexturePropertyTracker(GL_TEXTURE_MIN_FILTER, GL_LINEAR)
|
||||
var textureMinFilter by GLTexturePropertyTracker(GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR)
|
||||
var textureMagFilter by GLTexturePropertyTracker(GL_TEXTURE_MAG_FILTER, GL_LINEAR)
|
||||
|
||||
var textureWrapS by GLTexturePropertyTracker(GL_TEXTURE_WRAP_S, GL_REPEAT)
|
||||
var textureWrapT by GLTexturePropertyTracker(GL_TEXTURE_WRAP_T, GL_REPEAT)
|
||||
|
||||
fun bind(): GLTexture2D {
|
||||
if (mipsWarning == 1) {
|
||||
LOGGER.warn("(Likely) Trying to use texture {} before generated it's mips, this probably won't work!", this)
|
||||
mipsWarning = 0
|
||||
} else if (mipsWarning == 2) {
|
||||
mipsWarning = 1
|
||||
if (textureMinFilter != GL_LINEAR && textureMinFilter != GL_NEAREST) {
|
||||
if (mipsWarning == 1) {
|
||||
LOGGER.warn("(Likely) Trying to use texture {} before generated it's mips, this probably won't work!", this)
|
||||
mipsWarning = 0
|
||||
} else if (mipsWarning == 2) {
|
||||
mipsWarning = 1
|
||||
}
|
||||
}
|
||||
|
||||
state.texture2D = this
|
||||
@ -101,6 +104,23 @@ class GLTexture2D(val state: GLStateTracker, val name: String = "<unknown>") : A
|
||||
|
||||
fun pixelToUV(pos: Vector2i) = pixelToUV(pos.x, pos.y)
|
||||
|
||||
fun allocate(mipmap: Int, loadedFormat: Int, width: Int, height: Int): GLTexture2D {
|
||||
bind()
|
||||
|
||||
require(width > 0) { "Invalid width $width" }
|
||||
require(height > 0) { "Invalid height $height" }
|
||||
this.width = width
|
||||
this.height = height
|
||||
glTexImage2D(GL_TEXTURE_2D, mipmap, loadedFormat, width, height, 0, loadedFormat, GL_UNSIGNED_BYTE, 0L)
|
||||
checkForGLError()
|
||||
uploaded = true
|
||||
return this
|
||||
}
|
||||
|
||||
fun allocate(loadedFormat: Int, width: Int, height: Int): GLTexture2D {
|
||||
return allocate(0, loadedFormat, width, height)
|
||||
}
|
||||
|
||||
private fun upload(mipmap: Int, loadedFormat: Int, width: Int, height: Int, bufferFormat: Int, dataFormat: Int, data: IntArray): GLTexture2D {
|
||||
bind()
|
||||
|
||||
|
@ -5,9 +5,10 @@ import ru.dbotthepony.kstarbound.client.gl.shader.GLShader
|
||||
|
||||
private fun loadShaders(
|
||||
vertex: Collection<String>,
|
||||
fragment: Collection<String>
|
||||
fragment: Collection<String>,
|
||||
geometry: Collection<String>
|
||||
): Array<GLShader> {
|
||||
val result = arrayOfNulls<GLShader>(vertex.size + fragment.size)
|
||||
val result = arrayOfNulls<GLShader>(vertex.size + fragment.size + geometry.size)
|
||||
var i = 0
|
||||
|
||||
for (name in vertex) {
|
||||
@ -18,13 +19,18 @@ private fun loadShaders(
|
||||
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>
|
||||
) : GLShaderProgram(state, *loadShaders(vertex, fragment)) {
|
||||
fragment: Collection<String>,
|
||||
geometry: Collection<String> = listOf()
|
||||
) : GLShaderProgram(state, *loadShaders(vertex, fragment, geometry)) {
|
||||
constructor(state: GLStateTracker, name: String) : this(state, listOf(name), listOf(name))
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ open class GLShaderProgram(val state: GLStateTracker, vararg shaders: GLShader)
|
||||
glGetProgramiv(pointer, GL_LINK_STATUS, success)
|
||||
|
||||
if (success[0] == 0) {
|
||||
throw ShaderLinkException(glGetShaderInfoLog(pointer))
|
||||
throw ShaderLinkException(glGetProgramInfoLog(pointer))
|
||||
}
|
||||
|
||||
glGetError()
|
||||
|
@ -1,13 +1,16 @@
|
||||
package ru.dbotthepony.kstarbound.client.gl.program
|
||||
|
||||
import ru.dbotthepony.kstarbound.client.gl.BlendFunc
|
||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
||||
import ru.dbotthepony.kstarbound.client.gl.GLType
|
||||
import ru.dbotthepony.kstarbound.client.gl.shader.GLShader
|
||||
import ru.dbotthepony.kstarbound.client.gl.shader.GLTransformableColorableProgram
|
||||
import ru.dbotthepony.kstarbound.client.gl.shader.GLTransformableProgram
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexType
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quad
|
||||
import ru.dbotthepony.kvector.vector.Color
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
@ -50,7 +53,130 @@ class GLLiquidProgram(state: GLStateTracker) : GLInternalProgram(state, "liquid"
|
||||
val transform = this["transform"]!!
|
||||
|
||||
val builder by lazy {
|
||||
StreamVertexBuilder(state, FORMAT, VertexType.QUADS, 16384)
|
||||
StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 16384)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val FORMAT = GLAttributeList.Builder().push(GLType.VEC2F).build()
|
||||
}
|
||||
}
|
||||
|
||||
class GLLightProgram(state: GLStateTracker) : GLInternalProgram(state, "light") {
|
||||
init {
|
||||
link()
|
||||
}
|
||||
|
||||
val baselineColor = this["baselineColor"]!!
|
||||
val transform = this["transform"]!!
|
||||
|
||||
val builder by lazy {
|
||||
StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 32)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val FORMAT = GLAttributeList.Builder().push(GLType.VEC2F).push(GLType.VEC2F).build()
|
||||
}
|
||||
}
|
||||
|
||||
class GLLightOccluderProgram(state: GLStateTracker) : GLInternalProgram(state, listOf("light_occluder"), listOf("light_occluder"), listOf("light_occluder")) {
|
||||
init {
|
||||
link()
|
||||
}
|
||||
|
||||
// val baselineColor = this["baselineColor"]!!
|
||||
val transform = this["transform"]!!
|
||||
val lightPosition = this["lightPosition"]!!
|
||||
|
||||
val builder by lazy {
|
||||
StreamVertexBuilder(state, FORMAT, GeometryType.QUADS_AS_LINES, 32)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val FORMAT = GLAttributeList.Builder().push(GLType.VEC2F).build()
|
||||
}
|
||||
}
|
||||
|
||||
class GLColorQuadProgram(state: GLStateTracker) : GLInternalProgram(state, "screen_quad") {
|
||||
init {
|
||||
link()
|
||||
}
|
||||
|
||||
val color = this["color"]!!
|
||||
|
||||
private val builder by lazy {
|
||||
val builder = StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 1)
|
||||
|
||||
builder.begin()
|
||||
builder.quad(-1f, -1f, 1f, 1f)
|
||||
builder.upload()
|
||||
|
||||
builder
|
||||
}
|
||||
|
||||
fun clearAlpha() {
|
||||
use()
|
||||
|
||||
color.set(ALPHA)
|
||||
|
||||
val old = state.blend
|
||||
val oldFunc = state.blendFunc
|
||||
|
||||
state.blend = true
|
||||
state.blendFunc = BlendFunc.ONLY_ALPHA
|
||||
builder.draw()
|
||||
state.blend = old
|
||||
state.blendFunc = oldFunc
|
||||
}
|
||||
|
||||
fun clearColor(color: Color = Color.WHITE) {
|
||||
use()
|
||||
|
||||
this.color.set(color)
|
||||
|
||||
val old = state.blend
|
||||
|
||||
state.blend = false
|
||||
builder.draw()
|
||||
state.blend = old
|
||||
}
|
||||
|
||||
companion object {
|
||||
val FORMAT = GLAttributeList.Builder().push(GLType.VEC2F).build()
|
||||
val ALPHA = Color(0f, 0f, 0f, 1f)
|
||||
}
|
||||
}
|
||||
|
||||
class GLTextureQuadProgram(state: GLStateTracker) : GLInternalProgram(state, "screen_quad_tex") {
|
||||
init {
|
||||
link()
|
||||
}
|
||||
|
||||
val texture = this["texture0"]!!
|
||||
|
||||
private val builder by lazy {
|
||||
val builder = StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 1)
|
||||
|
||||
builder.begin()
|
||||
builder.quad(-1f, -1f, 1f, 1f, QuadTransformers.uv())
|
||||
builder.upload()
|
||||
|
||||
builder
|
||||
}
|
||||
|
||||
fun run(texture: Int = 0) {
|
||||
use()
|
||||
this.texture.set(texture)
|
||||
builder.draw()
|
||||
}
|
||||
|
||||
companion object {
|
||||
val FORMAT = GLAttributeList.Builder().push(GLType.VEC2F).push(GLType.VEC2F).build()
|
||||
}
|
||||
}
|
||||
|
||||
class GLFlatProgram(state: GLStateTracker, vararg shaders: GLShader) : GLTransformableColorableProgram(state, *shaders) {
|
||||
val builder by lazy {
|
||||
StreamVertexBuilder(state, FORMAT, GeometryType.QUADS, 1024)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@ -61,6 +187,11 @@ class GLLiquidProgram(state: GLStateTracker) : GLInternalProgram(state, "liquid"
|
||||
class GLPrograms(val state: GLStateTracker) {
|
||||
val tile by SimpleProgram("tile", ::GLTransformableColorableProgram)
|
||||
val font by SimpleProgram("font", ::GLTransformableColorableProgram)
|
||||
val flat by SimpleProgram("flat", ::GLTransformableColorableProgram)
|
||||
val flat by SimpleProgram("flat", ::GLFlatProgram)
|
||||
val liquid by lazy { GLLiquidProgram(state) }
|
||||
val light by lazy { GLLightProgram(state) }
|
||||
val lightOccluder by lazy { GLLightOccluderProgram(state) }
|
||||
|
||||
val colorQuad by lazy { GLColorQuadProgram(state) }
|
||||
val textureQuad by lazy { GLTextureQuadProgram(state) }
|
||||
}
|
||||
|
@ -56,5 +56,6 @@ class GLShader(
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import org.lwjgl.opengl.GL41.*
|
||||
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
|
||||
import ru.dbotthepony.kstarbound.client.gl.program.GLShaderProgram
|
||||
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
|
||||
@ -19,6 +20,14 @@ class GLUniformLocation(val program: GLShaderProgram, val name: String, val poin
|
||||
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
|
||||
|
@ -26,9 +26,9 @@ private fun put(type: Int, memory: OutputStream, value: Int) {
|
||||
* Класс для построения геометрии для загрузки в память видеокарты.
|
||||
*/
|
||||
@Suppress("unchecked_cast")
|
||||
abstract class AbstractVertexBuilder<T : AbstractVertexBuilder<T>>(
|
||||
abstract class AbstractVertexBuilder<out T : AbstractVertexBuilder<T>>(
|
||||
val attributes: GLAttributeList,
|
||||
val type: VertexType,
|
||||
val type: GeometryType,
|
||||
) {
|
||||
protected abstract val vertexMemory: OutputStream
|
||||
protected abstract val elementMemory: OutputStream
|
||||
@ -165,97 +165,98 @@ abstract class AbstractVertexBuilder<T : AbstractVertexBuilder<T>>(
|
||||
attributeIndex++
|
||||
return this as T
|
||||
}
|
||||
|
||||
// Помощники
|
||||
fun quad(
|
||||
x0: Float,
|
||||
y0: Float,
|
||||
x1: Float,
|
||||
y1: Float,
|
||||
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
||||
): T {
|
||||
check(type.elements == 4) { "Currently building $type" }
|
||||
|
||||
lambda(vertex().pushVec2f(x0, y0), 0).end()
|
||||
lambda(vertex().pushVec2f(x1, y0), 1).end()
|
||||
lambda(vertex().pushVec2f(x0, y1), 2).end()
|
||||
lambda(vertex().pushVec2f(x1, y1), 3).end()
|
||||
|
||||
return this as T
|
||||
}
|
||||
|
||||
fun quadRotated(
|
||||
x0: Float,
|
||||
y0: Float,
|
||||
x1: Float,
|
||||
y1: Float,
|
||||
x: Float,
|
||||
y: Float,
|
||||
angle: Double,
|
||||
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
||||
): T {
|
||||
check(type.elements == 4) { "Currently building $type" }
|
||||
|
||||
val s = sin(angle).toFloat()
|
||||
val c = cos(angle).toFloat()
|
||||
|
||||
lambda(vertex().pushVec2f(x + x0 * c - s * y0, y + s * x0 + c * y0), 0).end()
|
||||
lambda(vertex().pushVec2f(x + x1 * c - s * y0, y + s * x1 + c * y0), 1).end()
|
||||
lambda(vertex().pushVec2f(x + x0 * c - s * y1, y + s * x0 + c * y1), 2).end()
|
||||
lambda(vertex().pushVec2f(x + x1 * c - s * y1, y + s * x1 + c * y1), 3).end()
|
||||
|
||||
return this as T
|
||||
}
|
||||
|
||||
fun quad(aabb: AABB, lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM): T {
|
||||
return quad(
|
||||
aabb.mins.x.toFloat(),
|
||||
aabb.mins.y.toFloat(),
|
||||
aabb.maxs.x.toFloat(),
|
||||
aabb.maxs.y.toFloat(),
|
||||
lambda
|
||||
)
|
||||
}
|
||||
|
||||
fun quadZ(
|
||||
x0: Float,
|
||||
y0: Float,
|
||||
x1: Float,
|
||||
y1: Float,
|
||||
z: Float,
|
||||
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
||||
): T {
|
||||
check(type.elements == 4) { "Currently building $type" }
|
||||
|
||||
lambda(vertex().pushVec3f(x0, y0, z), 0).end()
|
||||
lambda(vertex().pushVec3f(x1, y0, z), 1).end()
|
||||
lambda(vertex().pushVec3f(x0, y1, z), 2).end()
|
||||
lambda(vertex().pushVec3f(x1, y1, z), 3).end()
|
||||
|
||||
return this as T
|
||||
}
|
||||
|
||||
fun quadRotatedZ(
|
||||
x0: Float,
|
||||
y0: Float,
|
||||
x1: Float,
|
||||
y1: Float,
|
||||
z: Float,
|
||||
x: Float,
|
||||
y: Float,
|
||||
angle: Double,
|
||||
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
||||
): T {
|
||||
check(type.elements == 4) { "Currently building $type" }
|
||||
|
||||
val s = sin(angle).toFloat()
|
||||
val c = cos(angle).toFloat()
|
||||
|
||||
lambda(vertex().pushVec3f(x + x0 * c - s * y0, y + s * x0 + c * y0, z), 0).end()
|
||||
lambda(vertex().pushVec3f(x + x1 * c - s * y0, y + s * x1 + c * y0, z), 1).end()
|
||||
lambda(vertex().pushVec3f(x + x0 * c - s * y1, y + s * x0 + c * y1, z), 2).end()
|
||||
lambda(vertex().pushVec3f(x + x1 * c - s * y1, y + s * x1 + c * y1, z), 3).end()
|
||||
|
||||
return this as T
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Помощники
|
||||
fun <T : AbstractVertexBuilder<T>> T.quad(
|
||||
x0: Float,
|
||||
y0: Float,
|
||||
x1: Float,
|
||||
y1: Float,
|
||||
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
||||
): T {
|
||||
check(type.elements == 4) { "Currently building $type" }
|
||||
|
||||
lambda(vertex().pushVec2f(x0, y0), 0).end()
|
||||
lambda(vertex().pushVec2f(x1, y0), 1).end()
|
||||
lambda(vertex().pushVec2f(x0, y1), 2).end()
|
||||
lambda(vertex().pushVec2f(x1, y1), 3).end()
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
fun <T : AbstractVertexBuilder<T>> T.quadRotated(
|
||||
x0: Float,
|
||||
y0: Float,
|
||||
x1: Float,
|
||||
y1: Float,
|
||||
x: Float,
|
||||
y: Float,
|
||||
angle: Double,
|
||||
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
||||
): T {
|
||||
check(type.elements == 4) { "Currently building $type" }
|
||||
|
||||
val s = sin(angle).toFloat()
|
||||
val c = cos(angle).toFloat()
|
||||
|
||||
lambda(vertex().pushVec2f(x + x0 * c - s * y0, y + s * x0 + c * y0), 0).end()
|
||||
lambda(vertex().pushVec2f(x + x1 * c - s * y0, y + s * x1 + c * y0), 1).end()
|
||||
lambda(vertex().pushVec2f(x + x0 * c - s * y1, y + s * x0 + c * y1), 2).end()
|
||||
lambda(vertex().pushVec2f(x + x1 * c - s * y1, y + s * x1 + c * y1), 3).end()
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
fun <T : AbstractVertexBuilder<T>> T.quad(aabb: AABB, lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM): T {
|
||||
return quad(
|
||||
aabb.mins.x.toFloat(),
|
||||
aabb.mins.y.toFloat(),
|
||||
aabb.maxs.x.toFloat(),
|
||||
aabb.maxs.y.toFloat(),
|
||||
lambda
|
||||
)
|
||||
}
|
||||
|
||||
fun <T : AbstractVertexBuilder<T>> T.quadZ(
|
||||
x0: Float,
|
||||
y0: Float,
|
||||
x1: Float,
|
||||
y1: Float,
|
||||
z: Float,
|
||||
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
||||
): T {
|
||||
check(type.elements == 4) { "Currently building $type" }
|
||||
|
||||
lambda(vertex().pushVec3f(x0, y0, z), 0).end()
|
||||
lambda(vertex().pushVec3f(x1, y0, z), 1).end()
|
||||
lambda(vertex().pushVec3f(x0, y1, z), 2).end()
|
||||
lambda(vertex().pushVec3f(x1, y1, z), 3).end()
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
fun <T : AbstractVertexBuilder<T>> T.quadRotatedZ(
|
||||
x0: Float,
|
||||
y0: Float,
|
||||
x1: Float,
|
||||
y1: Float,
|
||||
z: Float,
|
||||
x: Float,
|
||||
y: Float,
|
||||
angle: Double,
|
||||
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
||||
): T {
|
||||
check(type.elements == 4) { "Currently building $type" }
|
||||
|
||||
val s = sin(angle).toFloat()
|
||||
val c = cos(angle).toFloat()
|
||||
|
||||
lambda(vertex().pushVec3f(x + x0 * c - s * y0, y + s * x0 + c * y0, z), 0).end()
|
||||
lambda(vertex().pushVec3f(x + x1 * c - s * y0, y + s * x1 + c * y0, z), 1).end()
|
||||
lambda(vertex().pushVec3f(x + x0 * c - s * y1, y + s * x0 + c * y1, z), 2).end()
|
||||
lambda(vertex().pushVec3f(x + x1 * c - s * y1, y + s * x1 + c * y1, z), 3).end()
|
||||
|
||||
return this
|
||||
}
|
||||
|
@ -6,24 +6,24 @@ import ru.dbotthepony.kstarbound.util.ByteBufferOutputStream
|
||||
|
||||
open class DirectVertexBuilder<T : DirectVertexBuilder<T>>(
|
||||
attributes: GLAttributeList,
|
||||
type: VertexType,
|
||||
type: GeometryType,
|
||||
val maxElements: Int,
|
||||
) : AbstractVertexBuilder<DirectVertexBuilder<T>>(attributes, type) {
|
||||
val maxIndexCount = maxElements * type.indicies.size
|
||||
val maxVertexCount = maxElements * type.elements
|
||||
|
||||
override val vertexMemory = ByteBufferOutputStream.directLE(maxVertexCount)
|
||||
override val elementMemory = ByteBufferOutputStream.directLE(maxIndexCount)
|
||||
|
||||
override val elementIndexType: Int = when (maxIndexCount) {
|
||||
final override val elementIndexType: Int = when (maxIndexCount) {
|
||||
// api performance issue 102: glDrawElements uses element index type 'GL_UNSIGNED_BYTE' that is not optimal for the current hardware configuration; consider using 'GL_UNSIGNED_SHORT' instead
|
||||
// in 0 .. 255 -> GL_UNSIGNED_BYTE
|
||||
in 0 .. 65535 -> GL46.GL_UNSIGNED_SHORT
|
||||
else -> GL46.GL_UNSIGNED_INT
|
||||
}
|
||||
|
||||
final override val vertexMemory = ByteBufferOutputStream.directLE(maxVertexCount * attributes.stride)
|
||||
final override val elementMemory = ByteBufferOutputStream.directLE(maxIndexCount * (if (elementIndexType == GL46.GL_UNSIGNED_SHORT) 2 else 4))
|
||||
|
||||
override fun ensureIndexCapacity() {
|
||||
if (vertexCount >= maxVertexCount) {
|
||||
if (vertexCount > maxVertexCount) {
|
||||
throw IndexOutOfBoundsException("Vertex count overflow (can hold max of $maxElements elements, that's $maxVertexCount vertexes)")
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package ru.dbotthepony.kstarbound.client.gl.vertex
|
||||
|
||||
enum class VertexType(val elements: Int, val indicies: IntArray) {
|
||||
enum class GeometryType(val elements: Int, val indicies: IntArray) {
|
||||
LINES(2, intArrayOf(0, 1)),
|
||||
TRIANGLES(3, intArrayOf(0, 1, 2)),
|
||||
QUADS(4, intArrayOf(0, 1, 2, 1, 2, 3)),
|
||||
QUADS_AS_LINES(4, intArrayOf(0, 1, 0, 2, 1, 3, 2, 3)),
|
||||
QUADS_AS_LINES_WIREFRAME(4, intArrayOf(0, 1, 0, 2, 1, 3, 2, 3, 0, 3, 1, 2)),
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ import java.nio.ByteBuffer
|
||||
*/
|
||||
class HeapVertexBuilder(
|
||||
attributes: GLAttributeList,
|
||||
type: VertexType,
|
||||
type: GeometryType,
|
||||
) : AbstractVertexBuilder<HeapVertexBuilder>(attributes, type) {
|
||||
override val vertexMemory = FastByteArrayOutputStream()
|
||||
override val elementMemory = FastByteArrayOutputStream()
|
||||
|
@ -11,7 +11,7 @@ import java.io.Closeable
|
||||
class StreamVertexBuilder(
|
||||
val state: GLStateTracker,
|
||||
attributes: GLAttributeList,
|
||||
type: VertexType,
|
||||
type: GeometryType,
|
||||
maxElements: Int,
|
||||
) : DirectVertexBuilder<StreamVertexBuilder>(attributes, type, maxElements), Closeable {
|
||||
private val vao = state.newVAO()
|
||||
|
@ -5,6 +5,7 @@ import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
||||
import ru.dbotthepony.kstarbound.client.ClientChunk
|
||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quadRotatedZ
|
||||
import ru.dbotthepony.kstarbound.world.entities.Entity
|
||||
import ru.dbotthepony.kstarbound.world.entities.projectile.Projectile
|
||||
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
||||
|
@ -9,7 +9,8 @@ import ru.dbotthepony.kstarbound.client.freetype.struct.FT_Pixel_Mode
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.HeapVertexBuilder
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexType
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quad
|
||||
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
||||
import ru.dbotthepony.kvector.vector.Color
|
||||
|
||||
@ -307,7 +308,7 @@ class Font(
|
||||
ebo.bind()
|
||||
vbo.bind()
|
||||
|
||||
val builder = HeapVertexBuilder(GLAttributeList.VERTEX_2D_TEXTURE, VertexType.QUADS)
|
||||
val builder = HeapVertexBuilder(GLAttributeList.VERTEX_2D_TEXTURE, GeometryType.QUADS)
|
||||
|
||||
builder.quad(0f, 0f, width, height, QuadTransformers.uv())
|
||||
builder.upload(vbo, ebo, GL_STATIC_DRAW)
|
||||
|
@ -168,7 +168,7 @@ private enum class TileRenderTesselateResult {
|
||||
HALT
|
||||
}
|
||||
|
||||
private fun vertexTextureBuilder() = HeapVertexBuilder(GLAttributeList.TILE, VertexType.QUADS)
|
||||
private fun vertexTextureBuilder() = HeapVertexBuilder(GLAttributeList.TILE, GeometryType.QUADS)
|
||||
|
||||
private class TileEqualityTester(val definition: TileDefinition) : EqualityRuleTester {
|
||||
override fun test(thisTile: ITileState, otherTile: ITileState): Boolean {
|
||||
|
@ -8,6 +8,5 @@ uniform sampler2D _texture;
|
||||
uniform vec4 _color;
|
||||
|
||||
void main() {
|
||||
float sampled = texture(_texture, _uv_out).r;
|
||||
_color_out = vec4(_color.x * sampled, _color.y * sampled, _color.z * sampled, _color.w * sampled);
|
||||
_color_out = _color * texture(_texture, _uv_out).r;
|
||||
}
|
||||
|
11
src/main/resources/shaders/light.fsh
Normal file
11
src/main/resources/shaders/light.fsh
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
#version 460
|
||||
|
||||
in vec2 oUVCoords;
|
||||
out vec4 resultColor;
|
||||
|
||||
uniform vec4 baselineColor;
|
||||
|
||||
void main() {
|
||||
resultColor = vec4(baselineColor) * smoothstep(0.0, 1.0, 1.0 - sqrt(pow(oUVCoords.x - 0.5, 2.0) + pow(oUVCoords.y - 0.5, 2.0)) * 2.0);
|
||||
}
|
14
src/main/resources/shaders/light.vsh
Normal file
14
src/main/resources/shaders/light.vsh
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
#version 460
|
||||
|
||||
layout (location = 0) in vec2 vertexPos;
|
||||
layout (location = 1) in vec2 uvCoords;
|
||||
|
||||
out vec2 oUVCoords;
|
||||
|
||||
uniform mat4 transform;
|
||||
|
||||
void main() {
|
||||
gl_Position = transform * vec4(vertexPos, 0.0, 1.0);
|
||||
oUVCoords = uvCoords;
|
||||
}
|
10
src/main/resources/shaders/light_occluder.fsh
Normal file
10
src/main/resources/shaders/light_occluder.fsh
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
#version 460
|
||||
|
||||
uniform vec2 lightPosition;
|
||||
|
||||
out vec4 resultColor;
|
||||
|
||||
void main() {
|
||||
resultColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
}
|
36
src/main/resources/shaders/light_occluder.gsh
Normal file
36
src/main/resources/shaders/light_occluder.gsh
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
#version 460
|
||||
|
||||
layout (lines) in;
|
||||
|
||||
layout (triangle_strip, max_vertices = 5) out;
|
||||
|
||||
uniform mat4 transform;
|
||||
uniform vec2 lightPosition;
|
||||
|
||||
in vec2 originalPos[];
|
||||
|
||||
void main() {
|
||||
vec4 a = gl_in[0].gl_Position;
|
||||
vec4 b = gl_in[1].gl_Position;
|
||||
|
||||
vec2 aInv = originalPos[0];
|
||||
vec2 bInv = originalPos[1];
|
||||
|
||||
gl_Position = b;
|
||||
EmitVertex();
|
||||
|
||||
gl_Position = a;
|
||||
EmitVertex();
|
||||
|
||||
gl_Position = transform * vec4(aInv + (aInv - lightPosition) * 10000, 0, 1);
|
||||
EmitVertex();
|
||||
|
||||
gl_Position = transform * vec4(bInv + (bInv - lightPosition) * 10000, 0, 1);
|
||||
EmitVertex();
|
||||
|
||||
gl_Position = b;
|
||||
EmitVertex();
|
||||
|
||||
EndPrimitive();
|
||||
}
|
13
src/main/resources/shaders/light_occluder.vsh
Normal file
13
src/main/resources/shaders/light_occluder.vsh
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
#version 460
|
||||
|
||||
layout (location = 0) in vec2 vertexPos;
|
||||
|
||||
uniform mat4 transform;
|
||||
|
||||
out vec2 originalPos;
|
||||
|
||||
void main() {
|
||||
gl_Position = transform * vec4(vertexPos, 0.0, 1.0);
|
||||
originalPos = vertexPos;
|
||||
}
|
10
src/main/resources/shaders/screen_quad.fsh
Normal file
10
src/main/resources/shaders/screen_quad.fsh
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
#version 460
|
||||
|
||||
out vec4 resultColor;
|
||||
|
||||
uniform vec4 color;
|
||||
|
||||
void main() {
|
||||
resultColor = color;
|
||||
}
|
8
src/main/resources/shaders/screen_quad.vsh
Normal file
8
src/main/resources/shaders/screen_quad.vsh
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
#version 460
|
||||
|
||||
layout (location = 0) in vec2 vertexPos;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(vertexPos, 0.0, 1.0);
|
||||
}
|
11
src/main/resources/shaders/screen_quad_tex.fsh
Normal file
11
src/main/resources/shaders/screen_quad_tex.fsh
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
#version 460
|
||||
|
||||
out vec4 resultColor;
|
||||
in vec2 uvPos;
|
||||
|
||||
uniform sampler2D texture0;
|
||||
|
||||
void main() {
|
||||
resultColor = texture(texture0, uvPos);
|
||||
}
|
12
src/main/resources/shaders/screen_quad_tex.vsh
Normal file
12
src/main/resources/shaders/screen_quad_tex.vsh
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
#version 460
|
||||
|
||||
layout (location = 0) in vec2 vertexPos;
|
||||
layout (location = 1) in vec2 inUVPos;
|
||||
|
||||
out vec2 uvPos;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(vertexPos, 0.0, 1.0);
|
||||
uvPos = inUVPos;
|
||||
}
|
Loading…
Reference in New Issue
Block a user