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.apache.logging.log4j.LogManager
|
||||||
import org.lwjgl.Version
|
import org.lwjgl.Version
|
||||||
import org.lwjgl.glfw.GLFW.glfwSetWindowShouldClose
|
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.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.io.*
|
||||||
import ru.dbotthepony.kstarbound.world.ChunkPos
|
import ru.dbotthepony.kstarbound.world.ChunkPos
|
||||||
import ru.dbotthepony.kstarbound.world.entities.PlayerEntity
|
import ru.dbotthepony.kstarbound.world.entities.PlayerEntity
|
||||||
|
import ru.dbotthepony.kvector.vector.Color
|
||||||
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
|
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.DataInputStream
|
import java.io.DataInputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.zip.Inflater
|
import java.util.zip.Inflater
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
private val LOGGER = LogManager.getLogger()
|
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("J:\\Steam\\steamapps\\common\\Starbound\\assets\\packed.pak"))
|
||||||
//Starbound.addPakPath(File("packed.pak"))
|
//Starbound.addPakPath(File("packed.pak"))
|
||||||
|
|
||||||
Starbound.initializeGame { finished, replaceStatus, status ->
|
/*Starbound.initializeGame { finished, replaceStatus, status ->
|
||||||
client.putDebugLog(status, replaceStatus)
|
client.putDebugLog(status, replaceStatus)
|
||||||
}
|
}*/
|
||||||
|
|
||||||
client.onTermination {
|
client.onTermination {
|
||||||
Starbound.terminateLoading = true
|
Starbound.terminateLoading = true
|
||||||
@ -163,13 +171,90 @@ fun main() {
|
|||||||
|
|
||||||
//ent.position += Vector2d(y = 14.0, x = -10.0)
|
//ent.position += Vector2d(y = 14.0, x = -10.0)
|
||||||
ent.position = Vector2d(600.0 + 16.0, 721.0 + 48.0)
|
ent.position = Vector2d(600.0 + 16.0, 721.0 + 48.0)
|
||||||
client.camera.pos.x = 578f
|
//client.camera.pos.x = 578f
|
||||||
client.camera.pos.y = 695f
|
//client.camera.pos.y = 695f
|
||||||
|
|
||||||
client.onDrawGUI {
|
client.onDrawGUI {
|
||||||
client.gl.font.render("${ent.position}", y = 100f, scale = 0.25f)
|
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("${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 {
|
client.onPreDrawWorld {
|
||||||
@ -186,9 +271,9 @@ fun main() {
|
|||||||
|
|
||||||
client.input.addScrollCallback { _, x, y ->
|
client.input.addScrollCallback { _, x, y ->
|
||||||
if (y > 0.0) {
|
if (y > 0.0) {
|
||||||
client.settings.scale *= y.toFloat() * 2f
|
client.settings.zoom *= y.toFloat() * 2f
|
||||||
} else if (y < 0.0) {
|
} 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.x = ent.position.x.toFloat()
|
||||||
//client.camera.pos.y = ent.position.y.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_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.scale 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_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.scale 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)
|
//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 it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
|
||||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
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.ConfiguredStaticMesh
|
||||||
import ru.dbotthepony.kstarbound.client.render.EntityRenderer
|
import ru.dbotthepony.kstarbound.client.render.EntityRenderer
|
||||||
import ru.dbotthepony.kstarbound.client.render.ILayeredRenderer
|
import ru.dbotthepony.kstarbound.client.render.ILayeredRenderer
|
||||||
|
@ -6,7 +6,7 @@ data class ClientSettings(
|
|||||||
*
|
*
|
||||||
* Масштаб в единицу означает что один Starbound Unit будет равен 8 пикселям на экране
|
* Масштаб в единицу означает что один Starbound Unit будет равен 8 пикселям на экране
|
||||||
*/
|
*/
|
||||||
var scale: Float = 2f,
|
var zoom: Float = 2f,
|
||||||
|
|
||||||
var debugCollisions: Boolean = false,
|
var debugCollisions: Boolean = false,
|
||||||
)
|
)
|
||||||
|
@ -3,6 +3,7 @@ package ru.dbotthepony.kstarbound.client
|
|||||||
import org.lwjgl.opengl.GL46.*
|
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.gl.vertex.QuadTransformers
|
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.ILayeredRenderer
|
||||||
import ru.dbotthepony.kstarbound.client.render.renderLayeredList
|
import ru.dbotthepony.kstarbound.client.render.renderLayeredList
|
||||||
import ru.dbotthepony.kstarbound.defs.ParallaxPrototype
|
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_UNIT
|
||||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
|
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.input.UserInput
|
import ru.dbotthepony.kstarbound.client.input.UserInput
|
||||||
import ru.dbotthepony.kstarbound.client.render.Camera
|
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.client.render.TextAlignY
|
||||||
import ru.dbotthepony.kstarbound.util.formatBytesShort
|
import ru.dbotthepony.kstarbound.util.formatBytesShort
|
||||||
import ru.dbotthepony.kvector.matrix.nfloat.Matrix4f
|
import ru.dbotthepony.kvector.matrix.nfloat.Matrix4f
|
||||||
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 ru.dbotthepony.kvector.vector.ndouble.Vector2d
|
||||||
|
import ru.dbotthepony.kvector.vector.nfloat.Vector2f
|
||||||
import ru.dbotthepony.kvector.vector.nfloat.Vector3f
|
import ru.dbotthepony.kvector.vector.nfloat.Vector3f
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.nio.ByteOrder
|
||||||
|
|
||||||
class StarboundClient : AutoCloseable {
|
class StarboundClient : AutoCloseable {
|
||||||
val window: Long
|
val window: Long
|
||||||
@ -35,10 +39,16 @@ class StarboundClient : AutoCloseable {
|
|||||||
var viewportHeight = 600
|
var viewportHeight = 600
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var viewportMatrixGUI = updateViewportMatrixA()
|
/**
|
||||||
|
* Матрица преобразования экранных координат (в пикселях) в нормализованные координаты
|
||||||
|
*/
|
||||||
|
var viewportMatrixScreen = updateViewportMatrixScreen()
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var viewportMatrixGame = updateViewportMatrixB()
|
/**
|
||||||
|
* Матрица преобразования мировых координат в нормализованные координаты
|
||||||
|
*/
|
||||||
|
var viewportMatrixWorld = updateViewportMatrixWorld()
|
||||||
private set
|
private set
|
||||||
|
|
||||||
private val startupTextList = ArrayList<String>()
|
private val startupTextList = ArrayList<String>()
|
||||||
@ -58,12 +68,69 @@ class StarboundClient : AutoCloseable {
|
|||||||
finishStartupRendering = System.currentTimeMillis() + 4000L
|
finishStartupRendering = System.currentTimeMillis() + 4000L
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateViewportMatrixA(): Matrix4f {
|
private fun updateViewportMatrixScreen(): Matrix4f {
|
||||||
return Matrix4f.ortho(0f, viewportWidth.toFloat(), 0f, viewportHeight.toFloat(), 0.1f, 100f)
|
return Matrix4f.ortho(0f, viewportWidth.toFloat(), 0f, viewportHeight.toFloat(), 0.1f, 100f).translate(Vector3f(z = 2f)).toMatrix4f()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateViewportMatrixB(): Matrix4f {
|
private fun updateViewportMatrixWorld(): Matrix4f {
|
||||||
return Matrix4f.orthoDirect(0f, viewportWidth.toFloat(), 0f, viewportHeight.toFloat(), 1f, 100f)
|
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 {
|
init {
|
||||||
@ -90,9 +157,13 @@ class StarboundClient : AutoCloseable {
|
|||||||
GLFW.glfwSetFramebufferSizeCallback(window) { _, w, h ->
|
GLFW.glfwSetFramebufferSizeCallback(window) { _, w, h ->
|
||||||
viewportWidth = w
|
viewportWidth = w
|
||||||
viewportHeight = h
|
viewportHeight = h
|
||||||
viewportMatrixGUI = updateViewportMatrixA()
|
viewportMatrixScreen = updateViewportMatrixScreen()
|
||||||
viewportMatrixGame = updateViewportMatrixB()
|
viewportMatrixWorld = updateViewportMatrixWorld()
|
||||||
glViewport(0, 0, w, h)
|
glViewport(0, 0, w, h)
|
||||||
|
|
||||||
|
for (callback in onViewportChanged) {
|
||||||
|
callback.invoke(w, h)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val stack = MemoryStack.stackPush()
|
val stack = MemoryStack.stackPush()
|
||||||
@ -134,7 +205,7 @@ class StarboundClient : AutoCloseable {
|
|||||||
gl.clearColor = Color.SLATE_GREY
|
gl.clearColor = Color.SLATE_GREY
|
||||||
|
|
||||||
gl.blend = true
|
gl.blend = true
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
gl.blendFunc = BlendFunc.ALPHA_TEST
|
||||||
}
|
}
|
||||||
|
|
||||||
var frameRenderTime = 0.0
|
var frameRenderTime = 0.0
|
||||||
@ -160,6 +231,12 @@ class StarboundClient : AutoCloseable {
|
|||||||
|
|
||||||
val settings = ClientSettings()
|
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>()
|
private val onDrawGUI = ArrayList<() -> Unit>()
|
||||||
|
|
||||||
fun onDrawGUI(lambda: () -> Unit) {
|
fun onDrawGUI(lambda: () -> Unit) {
|
||||||
@ -198,11 +275,11 @@ class StarboundClient : AutoCloseable {
|
|||||||
world?.think(frameRenderTime)
|
world?.think(frameRenderTime)
|
||||||
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
|
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
|
||||||
gl.matrixStack.clear(viewportMatrixGame.toMutableMatrix4f())
|
gl.matrixStack.clear(viewportMatrixWorld.toMutableMatrix4f())
|
||||||
|
|
||||||
gl.matrixStack.push()
|
gl.matrixStack.push()
|
||||||
.translateWithMultiplication(viewportWidth / 2f, viewportHeight / 2f, 2f) // центр экрана + координаты отрисовки мира
|
.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) // перемещаем вид к камере
|
.translateWithMultiplication(-camera.pos.x, -camera.pos.y) // перемещаем вид к камере
|
||||||
|
|
||||||
for (lambda in onPreDrawWorld) {
|
for (lambda in onPreDrawWorld) {
|
||||||
@ -217,8 +294,8 @@ class StarboundClient : AutoCloseable {
|
|||||||
world?.render(
|
world?.render(
|
||||||
AABB.rectangle(
|
AABB.rectangle(
|
||||||
camera.pos.toDoubleVector(),
|
camera.pos.toDoubleVector(),
|
||||||
viewportWidth / settings.scale / PIXELS_IN_STARBOUND_UNIT,
|
viewportWidth / settings.zoom / PIXELS_IN_STARBOUND_UNIT,
|
||||||
viewportHeight / settings.scale / PIXELS_IN_STARBOUND_UNIT))
|
viewportHeight / settings.zoom / PIXELS_IN_STARBOUND_UNIT))
|
||||||
|
|
||||||
for (lambda in onPostDrawWorld) {
|
for (lambda in onPostDrawWorld) {
|
||||||
lambda.invoke()
|
lambda.invoke()
|
||||||
@ -226,7 +303,7 @@ class StarboundClient : AutoCloseable {
|
|||||||
|
|
||||||
gl.matrixStack.pop()
|
gl.matrixStack.pop()
|
||||||
|
|
||||||
gl.matrixStack.clear(viewportMatrixGUI.toMutableMatrix4f().translate(Vector3f(z = 2f)))
|
gl.matrixStack.clear(viewportMatrixScreen.toMutableMatrix4f())
|
||||||
|
|
||||||
val thisTime = System.currentTimeMillis()
|
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.apache.logging.log4j.LogManager
|
||||||
import org.lwjgl.opengl.GL
|
import org.lwjgl.opengl.GL
|
||||||
|
import org.lwjgl.opengl.GL14
|
||||||
import org.lwjgl.opengl.GL46.*
|
import org.lwjgl.opengl.GL46.*
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
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.gl.program.GLPrograms
|
import ru.dbotthepony.kstarbound.client.gl.program.GLPrograms
|
||||||
import ru.dbotthepony.kstarbound.client.gl.shader.GLShader
|
import ru.dbotthepony.kstarbound.client.gl.shader.GLShader
|
||||||
import ru.dbotthepony.kstarbound.client.gl.program.GLShaderProgram
|
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.shader.GLTransformableProgram
|
||||||
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.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.Box2DRenderer
|
||||||
import ru.dbotthepony.kstarbound.client.render.Font
|
import ru.dbotthepony.kstarbound.client.render.Font
|
||||||
import ru.dbotthepony.kstarbound.client.render.TileRenderers
|
import ru.dbotthepony.kstarbound.client.render.TileRenderers
|
||||||
@ -22,7 +25,10 @@ import ru.dbotthepony.kvector.util2d.AABB
|
|||||||
import ru.dbotthepony.kvector.vector.Color
|
import ru.dbotthepony.kvector.vector.Color
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
import java.lang.ref.Cleaner
|
import java.lang.ref.Cleaner
|
||||||
|
import java.util.*
|
||||||
import java.util.concurrent.ThreadFactory
|
import java.util.concurrent.ThreadFactory
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
import kotlin.collections.HashMap
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
private class GLStateSwitchTracker(private val enum: Int, private var value: Boolean = false) {
|
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 {
|
operator fun getValue(glStateTracker: GLStateTracker, property: KProperty<*>): T {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
@ -58,12 +64,69 @@ private class GLStateGenericTracker<T>(private var value: T, private val lambda:
|
|||||||
if (value == this.value)
|
if (value == this.value)
|
||||||
return
|
return
|
||||||
|
|
||||||
lambda.invoke(value)
|
callback.invoke(value)
|
||||||
checkForGLError()
|
checkForGLError()
|
||||||
this.value = value
|
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 {
|
interface GLCleanable : Cleaner.Cleanable {
|
||||||
/**
|
/**
|
||||||
* Выставляет флаг на то, что объект был удалён вручную и вызывает clean()
|
* Выставляет флаг на то, что объект был удалён вручную и вызывает clean()
|
||||||
@ -75,7 +138,14 @@ interface GLStreamBuilderList {
|
|||||||
val small: StreamVertexBuilder
|
val small: StreamVertexBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("PropertyName", "unused")
|
||||||
class GLStateTracker {
|
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 {
|
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)
|
||||||
@ -87,7 +157,8 @@ class GLStateTracker {
|
|||||||
GL.createCapabilities()
|
GL.createCapabilities()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var cleanerHits = ArrayList<() -> Unit>()
|
private val cleanerHits = ArrayList<() -> Unit>()
|
||||||
|
|
||||||
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 {
|
||||||
val thread = Thread(r, "OpenGL Object Cleaner@" + System.identityHashCode(this))
|
val thread = Thread(r, "OpenGL Object Cleaner@" + System.identityHashCode(this))
|
||||||
@ -101,11 +172,13 @@ class GLStateTracker {
|
|||||||
|
|
||||||
val cleanable = cleaner.register(ref) {
|
val cleanable = cleaner.register(ref) {
|
||||||
if (!cleanManual)
|
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 {
|
synchronized(cleanerHits) {
|
||||||
fn(nativeRef)
|
cleanerHits.add {
|
||||||
checkForGLError()
|
fn(nativeRef)
|
||||||
|
checkForGLError()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,11 +193,12 @@ class GLStateTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun cleanup() {
|
fun cleanup() {
|
||||||
val copy = cleanerHits
|
synchronized(cleanerHits) {
|
||||||
cleanerHits = ArrayList()
|
for (lambda in cleanerHits) {
|
||||||
|
lambda.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
for (lambda in copy) {
|
cleanerHits.clear()
|
||||||
lambda.invoke()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +209,7 @@ class GLStateTracker {
|
|||||||
set(value) {
|
set(value) {
|
||||||
ensureSameThread()
|
ensureSameThread()
|
||||||
if (field === value) return
|
if (field === value) return
|
||||||
|
isMe(value?.state)
|
||||||
field = value
|
field = value
|
||||||
|
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
@ -152,6 +227,7 @@ class GLStateTracker {
|
|||||||
set(value) {
|
set(value) {
|
||||||
ensureSameThread()
|
ensureSameThread()
|
||||||
if (field === value) return
|
if (field === value) return
|
||||||
|
isMe(value?.state)
|
||||||
field = value
|
field = value
|
||||||
|
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
@ -169,6 +245,7 @@ class GLStateTracker {
|
|||||||
set(value) {
|
set(value) {
|
||||||
ensureSameThread()
|
ensureSameThread()
|
||||||
if (field === value) return
|
if (field === value) return
|
||||||
|
isMe(value?.state)
|
||||||
field = value
|
field = value
|
||||||
|
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
@ -181,6 +258,56 @@ class GLStateTracker {
|
|||||||
checkForGLError()
|
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
|
var program: GLShaderProgram? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@ -188,6 +315,7 @@ class GLStateTracker {
|
|||||||
set(value) {
|
set(value) {
|
||||||
ensureSameThread()
|
ensureSameThread()
|
||||||
if (field === value) return
|
if (field === value) return
|
||||||
|
isMe(value?.state)
|
||||||
field = value
|
field = value
|
||||||
if (value == null) return
|
if (value == null) return
|
||||||
glBindTexture(GL_TEXTURE_2D, value.pointer)
|
glBindTexture(GL_TEXTURE_2D, value.pointer)
|
||||||
@ -210,6 +338,10 @@ class GLStateTracker {
|
|||||||
glClearColor(r, g, b, a)
|
glClearColor(r, g, b, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var blendFunc by GLStateGenericTracker(BlendFunc()) {
|
||||||
|
glBlendFuncSeparate(it.sourceColor.enum, it.destinationColor.enum, it.sourceAlpha.enum, it.destinationAlpha.enum)
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
glActiveTexture(GL_TEXTURE0)
|
glActiveTexture(GL_TEXTURE0)
|
||||||
checkForGLError()
|
checkForGLError()
|
||||||
@ -362,42 +494,42 @@ class GLStateTracker {
|
|||||||
|
|
||||||
val flat2DLines = object : GLStreamBuilderList {
|
val flat2DLines = object : GLStreamBuilderList {
|
||||||
override val small by lazy {
|
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 {
|
val flat2DTriangles = object : GLStreamBuilderList {
|
||||||
override val small by lazy {
|
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 {
|
val flat2DQuads = object : GLStreamBuilderList {
|
||||||
override val small by lazy {
|
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 {
|
val flat2DTexturedQuads = object : GLStreamBuilderList {
|
||||||
override val small by lazy {
|
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 {
|
val flat2DQuadLines = object : GLStreamBuilderList {
|
||||||
override val small by lazy {
|
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 {
|
val flat2DQuadWireframe = object : GLStreamBuilderList {
|
||||||
override val small by lazy {
|
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 {
|
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()
|
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 {
|
class GLTexture2D(val state: GLStateTracker, val name: String = "<unknown>") : AutoCloseable {
|
||||||
val pointer = glGenTextures()
|
val pointer = glGenTextures()
|
||||||
|
|
||||||
@ -63,18 +64,20 @@ class GLTexture2D(val state: GLStateTracker, val name: String = "<unknown>") : A
|
|||||||
|
|
||||||
private var mipsWarning = 2
|
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 textureMagFilter by GLTexturePropertyTracker(GL_TEXTURE_MAG_FILTER, GL_LINEAR)
|
||||||
|
|
||||||
var textureWrapS by GLTexturePropertyTracker(GL_TEXTURE_WRAP_S, GL_REPEAT)
|
var textureWrapS by GLTexturePropertyTracker(GL_TEXTURE_WRAP_S, GL_REPEAT)
|
||||||
var textureWrapT by GLTexturePropertyTracker(GL_TEXTURE_WRAP_T, GL_REPEAT)
|
var textureWrapT by GLTexturePropertyTracker(GL_TEXTURE_WRAP_T, GL_REPEAT)
|
||||||
|
|
||||||
fun bind(): GLTexture2D {
|
fun bind(): GLTexture2D {
|
||||||
if (mipsWarning == 1) {
|
if (textureMinFilter != GL_LINEAR && textureMinFilter != GL_NEAREST) {
|
||||||
LOGGER.warn("(Likely) Trying to use texture {} before generated it's mips, this probably won't work!", this)
|
if (mipsWarning == 1) {
|
||||||
mipsWarning = 0
|
LOGGER.warn("(Likely) Trying to use texture {} before generated it's mips, this probably won't work!", this)
|
||||||
} else if (mipsWarning == 2) {
|
mipsWarning = 0
|
||||||
mipsWarning = 1
|
} else if (mipsWarning == 2) {
|
||||||
|
mipsWarning = 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state.texture2D = this
|
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 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 {
|
private fun upload(mipmap: Int, loadedFormat: Int, width: Int, height: Int, bufferFormat: Int, dataFormat: Int, data: IntArray): GLTexture2D {
|
||||||
bind()
|
bind()
|
||||||
|
|
||||||
|
@ -5,9 +5,10 @@ import ru.dbotthepony.kstarbound.client.gl.shader.GLShader
|
|||||||
|
|
||||||
private fun loadShaders(
|
private fun loadShaders(
|
||||||
vertex: Collection<String>,
|
vertex: Collection<String>,
|
||||||
fragment: Collection<String>
|
fragment: Collection<String>,
|
||||||
|
geometry: Collection<String>
|
||||||
): Array<GLShader> {
|
): Array<GLShader> {
|
||||||
val result = arrayOfNulls<GLShader>(vertex.size + fragment.size)
|
val result = arrayOfNulls<GLShader>(vertex.size + fragment.size + geometry.size)
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
||||||
for (name in vertex) {
|
for (name in vertex) {
|
||||||
@ -18,13 +19,18 @@ private fun loadShaders(
|
|||||||
result[i++] = GLShader.internalFragment("shaders/$name.fsh")
|
result[i++] = GLShader.internalFragment("shaders/$name.fsh")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (name in geometry) {
|
||||||
|
result[i++] = GLShader.internalGeometry("shaders/$name.gsh")
|
||||||
|
}
|
||||||
|
|
||||||
return result as Array<GLShader>
|
return result as Array<GLShader>
|
||||||
}
|
}
|
||||||
|
|
||||||
open class GLInternalProgram(
|
open class GLInternalProgram(
|
||||||
state: GLStateTracker,
|
state: GLStateTracker,
|
||||||
vertex: Collection<String>,
|
vertex: Collection<String>,
|
||||||
fragment: Collection<String>
|
fragment: Collection<String>,
|
||||||
) : GLShaderProgram(state, *loadShaders(vertex, fragment)) {
|
geometry: Collection<String> = listOf()
|
||||||
|
) : GLShaderProgram(state, *loadShaders(vertex, fragment, geometry)) {
|
||||||
constructor(state: GLStateTracker, name: String) : this(state, listOf(name), listOf(name))
|
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)
|
glGetProgramiv(pointer, GL_LINK_STATUS, success)
|
||||||
|
|
||||||
if (success[0] == 0) {
|
if (success[0] == 0) {
|
||||||
throw ShaderLinkException(glGetShaderInfoLog(pointer))
|
throw ShaderLinkException(glGetProgramInfoLog(pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
glGetError()
|
glGetError()
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
package ru.dbotthepony.kstarbound.client.gl.program
|
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.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.GLShader
|
||||||
import ru.dbotthepony.kstarbound.client.gl.shader.GLTransformableColorableProgram
|
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.GLAttributeList
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
|
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.properties.ReadOnlyProperty
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
@ -50,7 +53,130 @@ class GLLiquidProgram(state: GLStateTracker) : GLInternalProgram(state, "liquid"
|
|||||||
val transform = this["transform"]!!
|
val transform = this["transform"]!!
|
||||||
|
|
||||||
val builder by lazy {
|
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 {
|
companion object {
|
||||||
@ -61,6 +187,11 @@ class GLLiquidProgram(state: GLStateTracker) : GLInternalProgram(state, "liquid"
|
|||||||
class GLPrograms(val state: GLStateTracker) {
|
class GLPrograms(val state: GLStateTracker) {
|
||||||
val tile by SimpleProgram("tile", ::GLTransformableColorableProgram)
|
val tile by SimpleProgram("tile", ::GLTransformableColorableProgram)
|
||||||
val font by SimpleProgram("font", ::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 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 internalVertex(file: String) = GLShader(readInternal(file), GL_VERTEX_SHADER)
|
||||||
fun internalFragment(file: String) = GLShader(readInternal(file), GL_FRAGMENT_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.checkForGLError
|
||||||
import ru.dbotthepony.kstarbound.client.gl.program.GLShaderProgram
|
import ru.dbotthepony.kstarbound.client.gl.program.GLShaderProgram
|
||||||
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 java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
@ -19,6 +20,14 @@ class GLUniformLocation(val program: GLShaderProgram, val name: String, val poin
|
|||||||
return this
|
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 {
|
fun set(value: IStruct3f): GLUniformLocation {
|
||||||
program.state.ensureSameThread()
|
program.state.ensureSameThread()
|
||||||
val (v0, v1, v2) = value
|
val (v0, v1, v2) = value
|
||||||
|
@ -26,9 +26,9 @@ private fun put(type: Int, memory: OutputStream, value: Int) {
|
|||||||
* Класс для построения геометрии для загрузки в память видеокарты.
|
* Класс для построения геометрии для загрузки в память видеокарты.
|
||||||
*/
|
*/
|
||||||
@Suppress("unchecked_cast")
|
@Suppress("unchecked_cast")
|
||||||
abstract class AbstractVertexBuilder<T : AbstractVertexBuilder<T>>(
|
abstract class AbstractVertexBuilder<out T : AbstractVertexBuilder<T>>(
|
||||||
val attributes: GLAttributeList,
|
val attributes: GLAttributeList,
|
||||||
val type: VertexType,
|
val type: GeometryType,
|
||||||
) {
|
) {
|
||||||
protected abstract val vertexMemory: OutputStream
|
protected abstract val vertexMemory: OutputStream
|
||||||
protected abstract val elementMemory: OutputStream
|
protected abstract val elementMemory: OutputStream
|
||||||
@ -165,97 +165,98 @@ abstract class AbstractVertexBuilder<T : AbstractVertexBuilder<T>>(
|
|||||||
attributeIndex++
|
attributeIndex++
|
||||||
return this as T
|
return this as T
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Помощники
|
|
||||||
fun quad(
|
|
||||||
x0: Float,
|
// Помощники
|
||||||
y0: Float,
|
fun <T : AbstractVertexBuilder<T>> T.quad(
|
||||||
x1: Float,
|
x0: Float,
|
||||||
y1: Float,
|
y0: Float,
|
||||||
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
x1: Float,
|
||||||
): T {
|
y1: Float,
|
||||||
check(type.elements == 4) { "Currently building $type" }
|
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
||||||
|
): T {
|
||||||
lambda(vertex().pushVec2f(x0, y0), 0).end()
|
check(type.elements == 4) { "Currently building $type" }
|
||||||
lambda(vertex().pushVec2f(x1, y0), 1).end()
|
|
||||||
lambda(vertex().pushVec2f(x0, y1), 2).end()
|
lambda(vertex().pushVec2f(x0, y0), 0).end()
|
||||||
lambda(vertex().pushVec2f(x1, y1), 3).end()
|
lambda(vertex().pushVec2f(x1, y0), 1).end()
|
||||||
|
lambda(vertex().pushVec2f(x0, y1), 2).end()
|
||||||
return this as T
|
lambda(vertex().pushVec2f(x1, y1), 3).end()
|
||||||
}
|
|
||||||
|
return this
|
||||||
fun quadRotated(
|
}
|
||||||
x0: Float,
|
|
||||||
y0: Float,
|
fun <T : AbstractVertexBuilder<T>> T.quadRotated(
|
||||||
x1: Float,
|
x0: Float,
|
||||||
y1: Float,
|
y0: Float,
|
||||||
x: Float,
|
x1: Float,
|
||||||
y: Float,
|
y1: Float,
|
||||||
angle: Double,
|
x: Float,
|
||||||
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
y: Float,
|
||||||
): T {
|
angle: Double,
|
||||||
check(type.elements == 4) { "Currently building $type" }
|
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
||||||
|
): T {
|
||||||
val s = sin(angle).toFloat()
|
check(type.elements == 4) { "Currently building $type" }
|
||||||
val c = cos(angle).toFloat()
|
|
||||||
|
val s = sin(angle).toFloat()
|
||||||
lambda(vertex().pushVec2f(x + x0 * c - s * y0, y + s * x0 + c * y0), 0).end()
|
val c = cos(angle).toFloat()
|
||||||
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 + x0 * c - s * y0, y + s * x0 + c * y0), 0).end()
|
||||||
lambda(vertex().pushVec2f(x + x1 * c - s * y1, y + s * x1 + c * y1), 3).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()
|
||||||
return this as T
|
lambda(vertex().pushVec2f(x + x1 * c - s * y1, y + s * x1 + c * y1), 3).end()
|
||||||
}
|
|
||||||
|
return this
|
||||||
fun quad(aabb: AABB, lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM): T {
|
}
|
||||||
return quad(
|
|
||||||
aabb.mins.x.toFloat(),
|
fun <T : AbstractVertexBuilder<T>> T.quad(aabb: AABB, lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM): T {
|
||||||
aabb.mins.y.toFloat(),
|
return quad(
|
||||||
aabb.maxs.x.toFloat(),
|
aabb.mins.x.toFloat(),
|
||||||
aabb.maxs.y.toFloat(),
|
aabb.mins.y.toFloat(),
|
||||||
lambda
|
aabb.maxs.x.toFloat(),
|
||||||
)
|
aabb.maxs.y.toFloat(),
|
||||||
}
|
lambda
|
||||||
|
)
|
||||||
fun quadZ(
|
}
|
||||||
x0: Float,
|
|
||||||
y0: Float,
|
fun <T : AbstractVertexBuilder<T>> T.quadZ(
|
||||||
x1: Float,
|
x0: Float,
|
||||||
y1: Float,
|
y0: Float,
|
||||||
z: Float,
|
x1: Float,
|
||||||
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
y1: Float,
|
||||||
): T {
|
z: Float,
|
||||||
check(type.elements == 4) { "Currently building $type" }
|
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
||||||
|
): T {
|
||||||
lambda(vertex().pushVec3f(x0, y0, z), 0).end()
|
check(type.elements == 4) { "Currently building $type" }
|
||||||
lambda(vertex().pushVec3f(x1, y0, z), 1).end()
|
|
||||||
lambda(vertex().pushVec3f(x0, y1, z), 2).end()
|
lambda(vertex().pushVec3f(x0, y0, z), 0).end()
|
||||||
lambda(vertex().pushVec3f(x1, y1, z), 3).end()
|
lambda(vertex().pushVec3f(x1, y0, z), 1).end()
|
||||||
|
lambda(vertex().pushVec3f(x0, y1, z), 2).end()
|
||||||
return this as T
|
lambda(vertex().pushVec3f(x1, y1, z), 3).end()
|
||||||
}
|
|
||||||
|
return this
|
||||||
fun quadRotatedZ(
|
}
|
||||||
x0: Float,
|
|
||||||
y0: Float,
|
fun <T : AbstractVertexBuilder<T>> T.quadRotatedZ(
|
||||||
x1: Float,
|
x0: Float,
|
||||||
y1: Float,
|
y0: Float,
|
||||||
z: Float,
|
x1: Float,
|
||||||
x: Float,
|
y1: Float,
|
||||||
y: Float,
|
z: Float,
|
||||||
angle: Double,
|
x: Float,
|
||||||
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
y: Float,
|
||||||
): T {
|
angle: Double,
|
||||||
check(type.elements == 4) { "Currently building $type" }
|
lambda: QuadVertexTransformer = EMPTY_VERTEX_TRANSFORM
|
||||||
|
): T {
|
||||||
val s = sin(angle).toFloat()
|
check(type.elements == 4) { "Currently building $type" }
|
||||||
val c = cos(angle).toFloat()
|
|
||||||
|
val s = sin(angle).toFloat()
|
||||||
lambda(vertex().pushVec3f(x + x0 * c - s * y0, y + s * x0 + c * y0, z), 0).end()
|
val c = cos(angle).toFloat()
|
||||||
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 + x0 * c - s * y0, y + s * x0 + c * y0, z), 0).end()
|
||||||
lambda(vertex().pushVec3f(x + x1 * c - s * y1, y + s * x1 + c * y1, z), 3).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()
|
||||||
return this as T
|
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>>(
|
open class DirectVertexBuilder<T : DirectVertexBuilder<T>>(
|
||||||
attributes: GLAttributeList,
|
attributes: GLAttributeList,
|
||||||
type: VertexType,
|
type: GeometryType,
|
||||||
val maxElements: Int,
|
val maxElements: Int,
|
||||||
) : AbstractVertexBuilder<DirectVertexBuilder<T>>(attributes, type) {
|
) : AbstractVertexBuilder<DirectVertexBuilder<T>>(attributes, type) {
|
||||||
val maxIndexCount = maxElements * type.indicies.size
|
val maxIndexCount = maxElements * type.indicies.size
|
||||||
val maxVertexCount = maxElements * type.elements
|
val maxVertexCount = maxElements * type.elements
|
||||||
|
|
||||||
override val vertexMemory = ByteBufferOutputStream.directLE(maxVertexCount)
|
final override val elementIndexType: Int = when (maxIndexCount) {
|
||||||
override val elementMemory = ByteBufferOutputStream.directLE(maxIndexCount)
|
|
||||||
|
|
||||||
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
|
// 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 .. 255 -> GL_UNSIGNED_BYTE
|
||||||
in 0 .. 65535 -> GL46.GL_UNSIGNED_SHORT
|
in 0 .. 65535 -> GL46.GL_UNSIGNED_SHORT
|
||||||
else -> GL46.GL_UNSIGNED_INT
|
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() {
|
override fun ensureIndexCapacity() {
|
||||||
if (vertexCount >= maxVertexCount) {
|
if (vertexCount > maxVertexCount) {
|
||||||
throw IndexOutOfBoundsException("Vertex count overflow (can hold max of $maxElements elements, that's $maxVertexCount vertexes)")
|
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
|
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)),
|
LINES(2, intArrayOf(0, 1)),
|
||||||
TRIANGLES(3, intArrayOf(0, 1, 2)),
|
TRIANGLES(3, intArrayOf(0, 1, 2)),
|
||||||
QUADS(4, intArrayOf(0, 1, 2, 1, 2, 3)),
|
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(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)),
|
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(
|
class HeapVertexBuilder(
|
||||||
attributes: GLAttributeList,
|
attributes: GLAttributeList,
|
||||||
type: VertexType,
|
type: GeometryType,
|
||||||
) : AbstractVertexBuilder<HeapVertexBuilder>(attributes, type) {
|
) : AbstractVertexBuilder<HeapVertexBuilder>(attributes, type) {
|
||||||
override val vertexMemory = FastByteArrayOutputStream()
|
override val vertexMemory = FastByteArrayOutputStream()
|
||||||
override val elementMemory = FastByteArrayOutputStream()
|
override val elementMemory = FastByteArrayOutputStream()
|
||||||
|
@ -11,7 +11,7 @@ import java.io.Closeable
|
|||||||
class StreamVertexBuilder(
|
class StreamVertexBuilder(
|
||||||
val state: GLStateTracker,
|
val state: GLStateTracker,
|
||||||
attributes: GLAttributeList,
|
attributes: GLAttributeList,
|
||||||
type: VertexType,
|
type: GeometryType,
|
||||||
maxElements: Int,
|
maxElements: Int,
|
||||||
) : DirectVertexBuilder<StreamVertexBuilder>(attributes, type, maxElements), Closeable {
|
) : DirectVertexBuilder<StreamVertexBuilder>(attributes, type, maxElements), Closeable {
|
||||||
private val vao = state.newVAO()
|
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.ClientChunk
|
||||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
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.Entity
|
||||||
import ru.dbotthepony.kstarbound.world.entities.projectile.Projectile
|
import ru.dbotthepony.kstarbound.world.entities.projectile.Projectile
|
||||||
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
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.GLAttributeList
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.HeapVertexBuilder
|
import ru.dbotthepony.kstarbound.client.gl.vertex.HeapVertexBuilder
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
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.matrix.Matrix4fStack
|
||||||
import ru.dbotthepony.kvector.vector.Color
|
import ru.dbotthepony.kvector.vector.Color
|
||||||
|
|
||||||
@ -307,7 +308,7 @@ class Font(
|
|||||||
ebo.bind()
|
ebo.bind()
|
||||||
vbo.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.quad(0f, 0f, width, height, QuadTransformers.uv())
|
||||||
builder.upload(vbo, ebo, GL_STATIC_DRAW)
|
builder.upload(vbo, ebo, GL_STATIC_DRAW)
|
||||||
|
@ -168,7 +168,7 @@ private enum class TileRenderTesselateResult {
|
|||||||
HALT
|
HALT
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun vertexTextureBuilder() = HeapVertexBuilder(GLAttributeList.TILE, VertexType.QUADS)
|
private fun vertexTextureBuilder() = HeapVertexBuilder(GLAttributeList.TILE, GeometryType.QUADS)
|
||||||
|
|
||||||
private class TileEqualityTester(val definition: TileDefinition) : EqualityRuleTester {
|
private class TileEqualityTester(val definition: TileDefinition) : EqualityRuleTester {
|
||||||
override fun test(thisTile: ITileState, otherTile: ITileState): Boolean {
|
override fun test(thisTile: ITileState, otherTile: ITileState): Boolean {
|
||||||
|
@ -8,6 +8,5 @@ uniform sampler2D _texture;
|
|||||||
uniform vec4 _color;
|
uniform vec4 _color;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
float sampled = texture(_texture, _uv_out).r;
|
_color_out = _color * texture(_texture, _uv_out).r;
|
||||||
_color_out = vec4(_color.x * sampled, _color.y * sampled, _color.z * sampled, _color.w * sampled);
|
|
||||||
}
|
}
|
||||||
|
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