more shadows tests
This commit is contained in:
parent
1254fb276c
commit
86a8c4a130
@ -37,9 +37,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
|
||||
@ -172,8 +172,8 @@ 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)
|
||||
@ -186,7 +186,7 @@ fun main() {
|
||||
//client.camera.pos.y = ent.pos.y.toFloat()
|
||||
}
|
||||
|
||||
val lightRenderer = LightRenderer(client.gl)
|
||||
/*val lightRenderer = LightRenderer(client.gl)
|
||||
|
||||
lightRenderer.resizeFramebuffer(client.viewportWidth, client.viewportHeight)
|
||||
client.onViewportChanged(lightRenderer::resizeFramebuffer)
|
||||
@ -223,7 +223,7 @@ fun main() {
|
||||
(client.screenToWorld(client.mouseCoordinatesF) + Vector2f(0.1f)) to Color.GREEN,
|
||||
(client.screenToWorld(client.mouseCoordinatesF) + Vector2f(-0.1f)) to Color.BLUE,
|
||||
)) {
|
||||
lightRenderer.renderHardLight(lightPosition, color, radius = 10f)
|
||||
lightRenderer.renderSoftLight(lightPosition, color, radius = 40f)
|
||||
}
|
||||
|
||||
for ((lightPosition, color) in listOf(
|
||||
@ -231,11 +231,11 @@ fun main() {
|
||||
(client.screenToWorld(client.mouseCoordinatesF) + Vector2f(10.1f)) to Color.GREEN,
|
||||
(client.screenToWorld(client.mouseCoordinatesF) + Vector2f(9.9f)) to Color.BLUE,
|
||||
)) {
|
||||
lightRenderer.renderSoftLight(lightPosition, color, radius = 10f)
|
||||
//lightRenderer.renderSoftLight(lightPosition, color, radius = 10f)
|
||||
}
|
||||
|
||||
lightRenderer.renderOutputAdditive()
|
||||
}
|
||||
}*/
|
||||
|
||||
client.gl.box2dRenderer.drawShapes = false
|
||||
client.gl.box2dRenderer.drawPairs = false
|
||||
|
@ -1,17 +1,28 @@
|
||||
package ru.dbotthepony.kstarbound.client
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
|
||||
import org.lwjgl.opengl.GL11.GL_LINES
|
||||
import org.lwjgl.opengl.GL11.GL_TRIANGLES
|
||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
||||
import ru.dbotthepony.kstarbound.client.gl.program.GLHardLightGeometryProgram
|
||||
import ru.dbotthepony.kstarbound.client.gl.program.GLSoftLightGeometryProgram
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.StatefulVertexBuilder
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quad
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.shadowQuad
|
||||
import ru.dbotthepony.kstarbound.client.render.ConfiguredStaticMesh
|
||||
import ru.dbotthepony.kstarbound.client.render.EntityRenderer
|
||||
import ru.dbotthepony.kstarbound.client.render.ILayeredRenderer
|
||||
import ru.dbotthepony.kstarbound.client.render.LightRenderer
|
||||
import ru.dbotthepony.kstarbound.client.render.TileLayerList
|
||||
import ru.dbotthepony.kstarbound.defs.liquid.LiquidDefinition
|
||||
import ru.dbotthepony.kstarbound.world.*
|
||||
import ru.dbotthepony.kstarbound.world.entities.Entity
|
||||
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
||||
import ru.dbotthepony.kvector.matrix.nfloat.Matrix4f
|
||||
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
|
||||
import ru.dbotthepony.kvector.vector.nfloat.Vector2f
|
||||
import ru.dbotthepony.kvector.vector.nfloat.Vector3f
|
||||
import java.io.Closeable
|
||||
import java.util.IdentityHashMap
|
||||
import java.util.LinkedList
|
||||
@ -38,16 +49,10 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
|
||||
for (mesh in bakedMeshes) {
|
||||
mesh.first.close()
|
||||
}
|
||||
|
||||
bakedMeshes.clear()
|
||||
} else {
|
||||
for (mesh in bakedMeshes) {
|
||||
unloadableBakedMeshes.add(mesh.first)
|
||||
}
|
||||
|
||||
bakedMeshes.clear()
|
||||
}
|
||||
|
||||
bakedMeshes.clear()
|
||||
|
||||
layers.clear()
|
||||
|
||||
for ((pos, tile) in view.posToTile) {
|
||||
@ -141,8 +146,6 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
|
||||
val debugCollisions get() = world.client.settings.debugCollisions
|
||||
val posVector2d = Vector2d(x = pos.x * CHUNK_SIZEd, y = pos.y * CHUNK_SIZEd)
|
||||
|
||||
private val unloadableBakedMeshes = ArrayList<ConfiguredStaticMesh>()
|
||||
|
||||
private val foregroundRenderer = TileLayerRenderer(foreground::changeset, isBackground = false)
|
||||
private val backgroundRenderer = TileLayerRenderer(background::changeset, isBackground = true)
|
||||
|
||||
@ -160,28 +163,14 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
|
||||
* Вызывается перед tesselateStatic()
|
||||
*/
|
||||
fun loadRenderers() {
|
||||
unloadUnused()
|
||||
|
||||
foregroundRenderer.loadRenderers(getForegroundView())
|
||||
backgroundRenderer.loadRenderers(getBackgroundView())
|
||||
}
|
||||
|
||||
private fun unloadUnused() {
|
||||
if (unloadableBakedMeshes.size != 0) {
|
||||
for (baked in unloadableBakedMeshes) {
|
||||
baked.close()
|
||||
}
|
||||
|
||||
unloadableBakedMeshes.clear()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Отрисовывает всю геометрию напрямую
|
||||
*/
|
||||
fun render(stack: Matrix4fStack) {
|
||||
unloadUnused()
|
||||
|
||||
backgroundRenderer.render(stack)
|
||||
foregroundRenderer.render(stack)
|
||||
}
|
||||
@ -190,8 +179,6 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
|
||||
* Отрисовывает всю геометрию напрямую, с проверкой, изменился ли чанк
|
||||
*/
|
||||
fun bakeAndRender(stack: Matrix4fStack) {
|
||||
unloadUnused()
|
||||
|
||||
backgroundRenderer.bakeAndRender(stack, this::getBackgroundView)
|
||||
foregroundRenderer.bakeAndRender(stack, this::getForegroundView)
|
||||
}
|
||||
@ -205,9 +192,6 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
|
||||
*
|
||||
*/
|
||||
fun bake() {
|
||||
if (state.isSameThread())
|
||||
unloadUnused()
|
||||
|
||||
backgroundRenderer.autoBake(this::getBackgroundView)
|
||||
foregroundRenderer.autoBake(this::getForegroundView)
|
||||
|
||||
@ -219,12 +203,83 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
|
||||
* Загружает в видеопамять всю геометрию напрямую, если есть что загружать
|
||||
*/
|
||||
fun upload() {
|
||||
unloadUnused()
|
||||
|
||||
backgroundRenderer.autoUpload()
|
||||
foregroundRenderer.autoUpload()
|
||||
}
|
||||
|
||||
private val hardShadowGeometry = StatefulVertexBuilder(state, LightRenderer.SHADOW_FORMAT, GeometryType.QUADS_AS_LINES)
|
||||
private var hardShadowGeometryRev = -1
|
||||
private val softShadowGeometry = StatefulVertexBuilder(state, LightRenderer.SHADOW_FORMAT_SOFT, GeometryType.QUADS_ALTERNATIVE)
|
||||
private var softShadowGeometryRev = -1
|
||||
|
||||
val shadowGeometry: LightRenderer.ShadowGeometryRenderer get() {
|
||||
return object : LightRenderer.ShadowGeometryRenderer {
|
||||
override fun renderHardGeometry(
|
||||
renderer: LightRenderer,
|
||||
lightPosition: Vector2f,
|
||||
stack: Matrix4fStack,
|
||||
program: GLHardLightGeometryProgram
|
||||
) {
|
||||
if (hardShadowGeometryRev == tileChangeset) {
|
||||
program.localToWorldTransform.set(Matrix4f.IDENTITY.translateWithMultiplication(Vector3f(x = pos.x * CHUNK_SIZEf, y = pos.y * CHUNK_SIZEf)))
|
||||
hardShadowGeometry.draw(GL_LINES)
|
||||
return
|
||||
}
|
||||
|
||||
hardShadowGeometryRev = tileChangeset
|
||||
|
||||
val builder = hardShadowGeometry
|
||||
|
||||
builder.begin()
|
||||
|
||||
for (x in 0 until CHUNK_SIZE) {
|
||||
for (y in 0 until CHUNK_SIZE) {
|
||||
if (foreground[x, y].material != null) {
|
||||
builder.quad(x.toFloat(), y.toFloat(), x + 1f, y + 1f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
builder.upload()
|
||||
|
||||
program.localToWorldTransform.set(Matrix4f.IDENTITY.translateWithMultiplication(Vector3f(x = pos.x * CHUNK_SIZEf, y = pos.y * CHUNK_SIZEf)))
|
||||
builder.draw(GL_LINES)
|
||||
}
|
||||
|
||||
override fun renderSoftGeometry(
|
||||
renderer: LightRenderer,
|
||||
lightPosition: Vector2f,
|
||||
stack: Matrix4fStack,
|
||||
program: GLSoftLightGeometryProgram
|
||||
) {
|
||||
if (softShadowGeometryRev == tileChangeset) {
|
||||
program.localToWorldTransform.set(Matrix4f.IDENTITY.translateWithMultiplication(Vector3f(x = pos.x * CHUNK_SIZEf, y = pos.y * CHUNK_SIZEf)))
|
||||
softShadowGeometry.draw(GL_TRIANGLES)
|
||||
return
|
||||
}
|
||||
|
||||
softShadowGeometryRev = tileChangeset
|
||||
|
||||
val builder = softShadowGeometry
|
||||
|
||||
builder.begin()
|
||||
|
||||
for (x in 0 until CHUNK_SIZE) {
|
||||
for (y in 0 until CHUNK_SIZE) {
|
||||
if (foreground[x, y].material != null) {
|
||||
builder.shadowQuad(x.toFloat(), y.toFloat(), x + 1f, y + 1f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
builder.upload()
|
||||
|
||||
program.localToWorldTransform.set(Matrix4f.IDENTITY.translateWithMultiplication(Vector3f(x = pos.x * CHUNK_SIZEf, y = pos.y * CHUNK_SIZEf)))
|
||||
builder.draw(GL_LINES)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Хранит состояние отрисовки этого чанка
|
||||
*
|
||||
|
@ -2,6 +2,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.BlendFunc
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quadZ
|
||||
import ru.dbotthepony.kstarbound.client.render.ILayeredRenderer
|
||||
@ -12,6 +13,8 @@ import ru.dbotthepony.kstarbound.util.DoubleEdgeProgression
|
||||
import ru.dbotthepony.kstarbound.world.*
|
||||
import ru.dbotthepony.kstarbound.world.entities.Entity
|
||||
import ru.dbotthepony.kvector.util2d.AABB
|
||||
import ru.dbotthepony.kvector.vector.Color
|
||||
import ru.dbotthepony.kvector.vector.nfloat.Vector2f
|
||||
|
||||
class ClientWorld(
|
||||
val client: StarboundClient,
|
||||
@ -101,13 +104,33 @@ class ClientWorld(
|
||||
|
||||
val determineRenderers = ArrayList<ILayeredRenderer>()
|
||||
|
||||
client.lightRenderer.begin()
|
||||
|
||||
for (chunk in collectPositionAware(size.encasingChunkPosAABB())) {
|
||||
determineRenderers.add(chunk.second.OneShotRenderer(chunk.first))
|
||||
chunk.second.bake()
|
||||
client.lightRenderer.addShadowGeometry(chunk.second.shadowGeometry)
|
||||
}
|
||||
|
||||
renderLayeredList(client.gl.matrixStack, determineRenderers)
|
||||
|
||||
for ((lightPosition, color) in listOf(
|
||||
(client.screenToWorld(client.mouseCoordinatesF)) to Color.RED,
|
||||
(client.screenToWorld(client.mouseCoordinatesF) + Vector2f(0.1f)) to Color.GREEN,
|
||||
(client.screenToWorld(client.mouseCoordinatesF) + Vector2f(-0.1f)) to Color.BLUE,
|
||||
)) {
|
||||
client.lightRenderer.renderSoftLight(lightPosition, color, radius = 100f)
|
||||
}
|
||||
|
||||
val old = client.gl.blendFunc
|
||||
client.gl.blendFunc = BlendFunc.MULTIPLY_BY_SRC
|
||||
|
||||
client.gl.activeTexture = 0
|
||||
client.gl.texture2D = client.lightRenderer.outputTexture
|
||||
client.gl.programs.textureQuad.run()
|
||||
|
||||
client.gl.blendFunc = old
|
||||
|
||||
physics.debugDraw()
|
||||
|
||||
/*for (renderer in determineRenderers) {
|
||||
|
@ -14,6 +14,7 @@ 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.LightRenderer
|
||||
import ru.dbotthepony.kstarbound.client.render.TextAlignY
|
||||
import ru.dbotthepony.kstarbound.util.formatBytesShort
|
||||
import ru.dbotthepony.kvector.matrix.nfloat.Matrix4f
|
||||
@ -171,6 +172,8 @@ class StarboundClient : AutoCloseable {
|
||||
viewportMatrixWorld = updateViewportMatrixWorld()
|
||||
glViewport(0, 0, w, h)
|
||||
|
||||
lightRenderer.resizeFramebuffer(viewportWidth, viewportHeight)
|
||||
|
||||
for (callback in onViewportChanged) {
|
||||
callback.invoke(w, h)
|
||||
}
|
||||
@ -205,6 +208,11 @@ class StarboundClient : AutoCloseable {
|
||||
}
|
||||
|
||||
val gl = GLStateTracker()
|
||||
val lightRenderer = LightRenderer(gl)
|
||||
|
||||
init {
|
||||
lightRenderer.resizeFramebuffer(viewportWidth, viewportHeight)
|
||||
}
|
||||
|
||||
var world: ClientWorld? = ClientWorld(this, 0L, 0)
|
||||
|
||||
|
@ -27,7 +27,10 @@ import java.lang.ref.Cleaner
|
||||
import java.util.concurrent.ThreadFactory
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import kotlin.reflect.KMutableProperty0
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KProperty0
|
||||
|
||||
private class GLStateSwitchTracker(private val enum: Int, private var value: Boolean = false) {
|
||||
operator fun getValue(glStateTracker: GLStateTracker, property: KProperty<*>): Boolean {
|
||||
@ -51,13 +54,13 @@ private class GLStateSwitchTracker(private val enum: Int, private var value: Boo
|
||||
}
|
||||
}
|
||||
|
||||
private class GLStateGenericTracker<T>(private var value: T, private val callback: (T) -> Unit) {
|
||||
operator fun getValue(glStateTracker: GLStateTracker, property: KProperty<*>): T {
|
||||
private class GLStateGenericTracker<T>(private var value: T, private val callback: (T) -> Unit) : ReadWriteProperty<GLStateTracker, T> {
|
||||
override fun getValue(thisRef: GLStateTracker, property: KProperty<*>): T {
|
||||
return value
|
||||
}
|
||||
|
||||
operator fun setValue(glStateTracker: GLStateTracker, property: KProperty<*>, value: T) {
|
||||
glStateTracker.ensureSameThread()
|
||||
override fun setValue(thisRef: GLStateTracker, property: KProperty<*>, value: T) {
|
||||
thisRef.ensureSameThread()
|
||||
|
||||
if (value == this.value)
|
||||
return
|
||||
@ -68,6 +71,35 @@ private class GLStateGenericTracker<T>(private var value: T, private val callbac
|
||||
}
|
||||
}
|
||||
|
||||
private class TexturesTracker(maxValue: Int) : ReadWriteProperty<GLStateTracker, GLTexture2D?> {
|
||||
private val values = arrayOfNulls<GLTexture2D>(maxValue)
|
||||
|
||||
override fun getValue(thisRef: GLStateTracker, property: KProperty<*>): GLTexture2D? {
|
||||
return values[thisRef.activeTexture]
|
||||
}
|
||||
|
||||
override fun setValue(thisRef: GLStateTracker, property: KProperty<*>, value: GLTexture2D?) {
|
||||
thisRef.ensureSameThread()
|
||||
|
||||
require(value == null || thisRef === value.state) { "$value does not belong to $thisRef" }
|
||||
|
||||
if (values[thisRef.activeTexture] === value) {
|
||||
return
|
||||
}
|
||||
|
||||
values[thisRef.activeTexture] = value
|
||||
|
||||
if (value == null) {
|
||||
glBindTexture(GL_TEXTURE_2D, 0)
|
||||
checkForGLError()
|
||||
return
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, value.pointer)
|
||||
checkForGLError()
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
data class BlendFunc(
|
||||
val sourceColor: Func,
|
||||
@ -130,6 +162,13 @@ data class BlendFunc(
|
||||
Func.ZERO,
|
||||
Func.ONE
|
||||
)
|
||||
|
||||
val MULTIPLY_BY_SRC = BlendFunc(
|
||||
Func.ZERO,
|
||||
Func.SRC_COLOR,
|
||||
Func.ONE,
|
||||
Func.ZERO
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -318,17 +357,6 @@ class GLStateTracker {
|
||||
var program: GLShaderProgram? = null
|
||||
private set
|
||||
|
||||
var texture2D: GLTexture2D? = null
|
||||
set(value) {
|
||||
ensureSameThread()
|
||||
if (field === value) return
|
||||
isMe(value?.state)
|
||||
field = value
|
||||
if (value == null) return
|
||||
glBindTexture(GL_TEXTURE_2D, value.pointer)
|
||||
checkForGLError()
|
||||
}
|
||||
|
||||
var activeTexture = 0
|
||||
set(value) {
|
||||
ensureSameThread()
|
||||
@ -340,6 +368,8 @@ class GLStateTracker {
|
||||
checkForGLError()
|
||||
}
|
||||
|
||||
var texture2D: GLTexture2D? by TexturesTracker(80)
|
||||
|
||||
var clearColor by GLStateGenericTracker<IStruct4f>(Color.WHITE) {
|
||||
val (r, g, b, a) = it
|
||||
glClearColor(r, g, b, a)
|
||||
|
@ -85,6 +85,7 @@ class GLHardLightGeometryProgram(state: GLStateTracker) : GLInternalProgram(stat
|
||||
}
|
||||
|
||||
val transform = this["transform"]!!
|
||||
val localToWorldTransform = this["localToWorldTransform"]!!
|
||||
val lightPosition = this["lightPosition"]!!
|
||||
|
||||
val builder by lazy {
|
||||
@ -99,6 +100,7 @@ class GLSoftLightGeometryProgram(state: GLStateTracker) : GLInternalProgram(stat
|
||||
|
||||
val transform = this["transform"]!!
|
||||
val lightPenetration = this["lightPenetration"]!!
|
||||
val localToWorldTransform = this["localToWorldTransform"]!!
|
||||
|
||||
/**
|
||||
* Vector3f(x, y, size)
|
||||
|
@ -15,17 +15,17 @@ import java.nio.ByteBuffer
|
||||
*
|
||||
* Полезен в случаях, когда размер данных для загрузки заранее не известен.
|
||||
*/
|
||||
class HeapVertexBuilder(
|
||||
open class HeapVertexBuilder<T : HeapVertexBuilder<T>>(
|
||||
attributes: GLAttributeList,
|
||||
type: GeometryType,
|
||||
) : AbstractVertexBuilder<HeapVertexBuilder>(attributes, type) {
|
||||
override val vertexMemory = FastByteArrayOutputStream()
|
||||
override val elementMemory = FastByteArrayOutputStream()
|
||||
) : AbstractVertexBuilder<T>(attributes, type) {
|
||||
final override val vertexMemory = FastByteArrayOutputStream()
|
||||
final override val elementMemory = FastByteArrayOutputStream()
|
||||
|
||||
override var elementIndexType: Int = GL_UNSIGNED_SHORT
|
||||
final override var elementIndexType: Int = GL_UNSIGNED_SHORT
|
||||
private set
|
||||
|
||||
override fun ensureIndexCapacity() {
|
||||
final override fun ensureIndexCapacity() {
|
||||
if (elementIndexType == GL_UNSIGNED_SHORT && elementMemory.length / 2 + type.indices.size >= 30000) {
|
||||
val backing = elementMemory.array
|
||||
val copy = FastByteArrayInputStream(ByteArray(elementMemory.length) { backing[it] })
|
||||
@ -40,12 +40,12 @@ class HeapVertexBuilder(
|
||||
}
|
||||
}
|
||||
|
||||
override fun resetMemory() {
|
||||
final override fun resetMemory() {
|
||||
vertexMemory.reset()
|
||||
elementMemory.reset()
|
||||
}
|
||||
|
||||
override fun doUpload(vbo: VertexBufferObject, ebo: VertexBufferObject, drawType: Int) {
|
||||
final override fun doUpload(vbo: VertexBufferObject, ebo: VertexBufferObject, drawType: Int) {
|
||||
val vboMemory = ByteBuffer.allocateDirect(vertexMemory.length)
|
||||
vboMemory.put(vertexMemory.array, 0, vertexMemory.length)
|
||||
|
||||
|
@ -0,0 +1,47 @@
|
||||
package ru.dbotthepony.kstarbound.client.gl.vertex
|
||||
|
||||
import org.lwjgl.opengl.GL46
|
||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
||||
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
|
||||
import java.io.Closeable
|
||||
|
||||
class StatefulVertexBuilder(
|
||||
val state: GLStateTracker,
|
||||
attributes: GLAttributeList,
|
||||
type: GeometryType,
|
||||
) : HeapVertexBuilder<StatefulVertexBuilder>(attributes, type), Closeable {
|
||||
private val vao = state.newVAO()
|
||||
private val vbo = state.newVBO()
|
||||
private val ebo = state.newEBO()
|
||||
|
||||
init {
|
||||
vao.bind()
|
||||
vbo.bind()
|
||||
ebo.bind()
|
||||
|
||||
attributes.apply(vao, true)
|
||||
|
||||
vao.unbind()
|
||||
vbo.unbind()
|
||||
ebo.unbind()
|
||||
}
|
||||
|
||||
fun upload(drawType: Int = GL46.GL_STATIC_DRAW) {
|
||||
upload(vbo, ebo, drawType)
|
||||
}
|
||||
|
||||
fun bind() = vao.bind()
|
||||
fun unbind() = vao.unbind()
|
||||
|
||||
fun draw(primitives: Int = GL46.GL_TRIANGLES) {
|
||||
bind()
|
||||
GL46.glDrawElements(primitives, indexCount, elementIndexType, 0L)
|
||||
checkForGLError()
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
vao.close()
|
||||
vbo.close()
|
||||
ebo.close()
|
||||
}
|
||||
}
|
@ -26,8 +26,8 @@ import ru.dbotthepony.kvector.vector.nfloat.Vector3f
|
||||
// https://slembcke.github.io/SuperFastSoftShadows
|
||||
class LightRenderer(val state: GLStateTracker) {
|
||||
interface ShadowGeometryRenderer {
|
||||
fun renderHardGeometry(lightPosition: Vector2f, stack: Matrix4fStack, program: GLHardLightGeometryProgram)
|
||||
fun renderSoftGeometry(lightPosition: Vector2f, stack: Matrix4fStack, program: GLSoftLightGeometryProgram)
|
||||
fun renderHardGeometry(renderer: LightRenderer, lightPosition: Vector2f, stack: Matrix4fStack, program: GLHardLightGeometryProgram)
|
||||
fun renderSoftGeometry(renderer: LightRenderer, lightPosition: Vector2f, stack: Matrix4fStack, program: GLSoftLightGeometryProgram)
|
||||
}
|
||||
|
||||
private val geometry = ArrayList<ShadowGeometryRenderer>()
|
||||
@ -41,6 +41,10 @@ class LightRenderer(val state: GLStateTracker) {
|
||||
return this.geometry.remove(geometry)
|
||||
}
|
||||
|
||||
fun clearShadowGeometry() {
|
||||
geometry.clear()
|
||||
}
|
||||
|
||||
/**
|
||||
* Сюда происходит рендер маски света и самого света
|
||||
*/
|
||||
@ -49,7 +53,7 @@ class LightRenderer(val state: GLStateTracker) {
|
||||
/**
|
||||
* Сюда накапливается отрисованный свет
|
||||
*/
|
||||
private val framebufferAccumulator = GLFrameBuffer(state)
|
||||
val framebufferAccumulator = GLFrameBuffer(state)
|
||||
|
||||
val outputTexture: GLTexture2D? get() = framebufferAccumulator.texture
|
||||
|
||||
@ -58,7 +62,7 @@ class LightRenderer(val state: GLStateTracker) {
|
||||
framebufferAccumulator.reattachTexture(width, height, GL_RGBA)
|
||||
}
|
||||
|
||||
fun begin() {
|
||||
fun begin(clearGeometry: Boolean = true) {
|
||||
state.ensureSameThread()
|
||||
|
||||
if (!framebufferRender.isComplete || !framebufferAccumulator.isComplete) {
|
||||
@ -77,6 +81,10 @@ class LightRenderer(val state: GLStateTracker) {
|
||||
state.clearColor = old
|
||||
|
||||
framebufferAccumulator.unbind()
|
||||
|
||||
if (clearGeometry) {
|
||||
geometry.clear()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -161,7 +169,7 @@ class LightRenderer(val state: GLStateTracker) {
|
||||
state.blendFunc = BlendFunc.ONLY_ALPHA
|
||||
|
||||
for (renderer in geometry) {
|
||||
renderer.renderHardGeometry(position, stack, state.programs.hardLightGeometry)
|
||||
renderer.renderHardGeometry(this, position, stack, state.programs.hardLightGeometry)
|
||||
}
|
||||
|
||||
state.programs.light.use()
|
||||
@ -189,7 +197,7 @@ class LightRenderer(val state: GLStateTracker) {
|
||||
position: Vector2f,
|
||||
color: Color = Color.WHITE,
|
||||
radius: Float = 10f,
|
||||
innerRadius: Float = 1f,
|
||||
innerRadius: Float = radius / 3f,
|
||||
stack: Matrix4fStack = state.matrixStack
|
||||
) {
|
||||
state.ensureSameThread()
|
||||
@ -220,7 +228,7 @@ class LightRenderer(val state: GLStateTracker) {
|
||||
state.blendFunc = BlendFunc.ONLY_BLEND_ALPHA
|
||||
|
||||
for (renderer in geometry) {
|
||||
renderer.renderSoftGeometry(position, stack, state.programs.softLightGeometry)
|
||||
renderer.renderSoftGeometry(this, position, stack, state.programs.softLightGeometry)
|
||||
}
|
||||
|
||||
state.programs.light.use()
|
||||
@ -248,6 +256,10 @@ class LightRenderer(val state: GLStateTracker) {
|
||||
StreamVertexBuilder(state, SHADOW_FORMAT, GeometryType.QUADS_AS_LINES, 256)
|
||||
}
|
||||
|
||||
val hugeBuilder by lazy {
|
||||
StreamVertexBuilder(state, SHADOW_FORMAT, GeometryType.QUADS_AS_LINES, 16384)
|
||||
}
|
||||
|
||||
val lineBuilder by lazy {
|
||||
StreamVertexBuilder(state, SHADOW_FORMAT, GeometryType.LINES, 256)
|
||||
}
|
||||
|
@ -4,10 +4,11 @@
|
||||
layout (location = 0) in vec2 vertexPos;
|
||||
|
||||
uniform mat4 transform;
|
||||
uniform mat4 localToWorldTransform;
|
||||
|
||||
out vec2 originalPos;
|
||||
|
||||
void main() {
|
||||
gl_Position = transform * vec4(vertexPos, 0.0, 1.0);
|
||||
originalPos = vertexPos;
|
||||
gl_Position = transform * localToWorldTransform * vec4(vertexPos, 0.0, 1.0);
|
||||
originalPos = (localToWorldTransform * vec4(vertexPos, 0.0, 1.0)).xy;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ layout (location = 0) in vec4 packedVertexPos;
|
||||
layout (location = 1) in vec2 edgeType;
|
||||
|
||||
uniform mat4 transform;
|
||||
uniform mat4 localToWorldTransform;
|
||||
|
||||
uniform vec3 lightPositionAndSize;
|
||||
uniform float lightPenetration;
|
||||
@ -28,8 +29,8 @@ void main() {
|
||||
float lightSize = lightPositionAndSize.z;
|
||||
|
||||
// Unpack the vertex shader input.
|
||||
vec2 endpoint_a = packedVertexPos.zw;
|
||||
vec2 endpoint_b = packedVertexPos.xy;
|
||||
vec2 endpoint_a = (localToWorldTransform * vec4(packedVertexPos.zw, 0.0, 1.0)).xy;
|
||||
vec2 endpoint_b = (localToWorldTransform * vec4(packedVertexPos.xy, 0.0, 1.0)).xy;
|
||||
vec2 endpoint = mix(endpoint_a, endpoint_b, edgeType.x);
|
||||
|
||||
// Deltas from the segment to the light center.
|
||||
|
Loading…
Reference in New Issue
Block a user