From 247e1a8ba555e37811b39040b8f8337627a005d0 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 2 Feb 2022 23:24:46 +0700 Subject: [PATCH] =?UTF-8?q?=D0=A2=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D1=82?= =?UTF-8?q?=D0=B0=D0=B9=D0=BB=D1=8B=20=D1=81=D0=BE=D1=80=D1=82=D0=B8=D1=80?= =?UTF-8?q?=D1=83=D1=8E=D1=82=D1=81=D1=8F=20=D0=BF=D0=BE=20z=20=D0=B3?= =?UTF-8?q?=D0=BB=D1=83=D0=B1=D0=B8=D0=BD=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/ru/dbotthepony/kstarbound/Main.kt | 15 ++++- .../kstarbound/gl/GLStateTracker.kt | 1 + .../kstarbound/render/ChunkRenderer.kt | 15 +++-- .../kstarbound/render/TileRenderer.kt | 63 ++++++++++++++----- 4 files changed, 73 insertions(+), 21 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt index 7b9e86bf..b5e14b53 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt @@ -38,7 +38,7 @@ private fun updateViewportMatrixA(): Matrix4f { } private fun updateViewportMatrixB(): Matrix4f { - return Matrix4f.orthoDirect(0f, viewportWidth.toFloat(), 0f, viewportHeight.toFloat(), 0.1f, 100f) + return Matrix4f.orthoDirect(0f, viewportWidth.toFloat(), 0f, viewportHeight.toFloat(), 1f, 100f) } var window = 0L @@ -139,6 +139,9 @@ private fun loop() { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) val rock = ChunkTile(Starbound.loadTileDefinition("alienrock")) + val obsidian = ChunkTile(Starbound.loadTileDefinition("obsidian")) + val corruptdirt = ChunkTile(Starbound.loadTileDefinition("corruptdirt")) + val darkwood = ChunkTile(Starbound.loadTileDefinition("darkwood")) val chunk = Starbound.world.setTile(Vector2i(2, 2), rock) chunk[3, 2] = rock @@ -147,6 +150,16 @@ private fun loop() { chunk[4, 4] = rock chunk[3, 4] = rock chunk[5, 4] = rock + chunk[2, 4] = obsidian + chunk[2, 3] = obsidian + chunk[1, 4] = corruptdirt + chunk[1, 3] = corruptdirt + chunk[1, 5] = darkwood + chunk[2, 5] = darkwood + chunk[3, 5] = darkwood + chunk[1, 1] = darkwood + chunk[2, 1] = darkwood + chunk[3, 1] = darkwood for (x in 0 until 1) { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/gl/GLStateTracker.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/gl/GLStateTracker.kt index 558be675..5947c508 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/gl/GLStateTracker.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/gl/GLStateTracker.kt @@ -43,6 +43,7 @@ class GLStateTracker { } var blend by GLStateSwitchTracker(GL_BLEND) + var depthTest by GLStateSwitchTracker(GL_DEPTH_TEST) var VBO: GLVertexBufferObject? = null set(value) { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/render/ChunkRenderer.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/render/ChunkRenderer.kt index 5d1fbbf8..cd603729 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/render/ChunkRenderer.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/render/ChunkRenderer.kt @@ -3,12 +3,11 @@ package ru.dbotthepony.kstarbound.render import ru.dbotthepony.kstarbound.gl.* import ru.dbotthepony.kstarbound.math.FloatMatrix import ru.dbotthepony.kstarbound.world.Chunk -import java.util.* import kotlin.collections.ArrayList import kotlin.collections.HashMap class ChunkRenderer(val state: GLStateTracker, val chunk: Chunk) : AutoCloseable { - private val builders = HashMap() + private val layers = TileLayerList() private val bakedMeshes = ArrayList() private val unloadableBakedMeshes = ArrayList() @@ -30,13 +29,13 @@ class ChunkRenderer(val state: GLStateTracker, val chunk: Chunk) : AutoCloseable bakedMeshes.clear() } - builders.clear() + layers.clear() // TODO: Синхронизация (ибо обновления игровой логики будут в потоке вне рендер потока) for ((pos, tile) in chunk.posToTile) { if (tile != null) { val renderer = state.tileRenderers.get(tile.def.materialName) - renderer.tesselate(chunk, builders, pos) + renderer.tesselate(chunk, layers, pos) } } } @@ -67,12 +66,16 @@ class ChunkRenderer(val state: GLStateTracker, val chunk: Chunk) : AutoCloseable } } - fun uploadStatic() { + fun uploadStatic(clear: Boolean = true) { unloadUnused() - for ((baked, builder) in builders) { + for ((baked, builder) in layers.buildList()) { bakedMeshes.add(BakedStaticMesh(baked, builder)) } + + if (clear) { + layers.clear() + } } fun render(transform: FloatMatrix<*> = state.matrixStack.last) { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/render/TileRenderer.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/render/TileRenderer.kt index 2491cabc..764cd3d5 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/render/TileRenderer.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/render/TileRenderer.kt @@ -5,16 +5,50 @@ import org.lwjgl.opengl.GL46.* import ru.dbotthepony.kstarbound.Starbound import ru.dbotthepony.kstarbound.defs.TileDefinition import ru.dbotthepony.kstarbound.defs.TileRenderMatchPiece -import ru.dbotthepony.kstarbound.defs.TileRenderMatchedPiece import ru.dbotthepony.kstarbound.defs.TileRenderPiece import ru.dbotthepony.kstarbound.gl.* import ru.dbotthepony.kstarbound.math.Matrix4f import ru.dbotthepony.kstarbound.math.Vector2i -import ru.dbotthepony.kstarbound.world.CHUNK_SIZE -import ru.dbotthepony.kstarbound.world.CHUNK_SIZE_FF import ru.dbotthepony.kstarbound.world.IChunk import kotlin.collections.HashMap +data class TileLayer(val bakedProgramState: BakedProgramState, val vertexBuilder: VertexBuilder, val zPos: Int) + +class TileLayerList { + private val layers = HashMap>() + + fun getLayer(programState: BakedProgramState, zLevel: Int, compute: () -> VertexBuilder): VertexBuilder { + val list = layers.computeIfAbsent(programState) {ArrayList()} + + for (layer in list) { + if (layer.zPos == zLevel) { + return layer.vertexBuilder + } + } + + val computed = TileLayer(programState, compute.invoke(), zLevel) + list.add(computed) + return computed.vertexBuilder + } + + fun buildList(): List { + val list = ArrayList() + + for (getList in layers.values) { + list.addAll(getList) + } + + list.sortBy { + // унарный минус для инвентирования порядка (сначала маленькие, потом большие) + return@sortBy -it.zPos + } + + return list + } + + fun clear() = layers.clear() +} + class TileRenderers(val state: GLStateTracker) { private val simpleBakedPrograms = HashMap() private val tileRenderers = HashMap() @@ -91,23 +125,23 @@ class TileRenderer(val state: GLStateTracker, val tile: TileDefinition) { val (u0, v0) = texture.pixelToUV(piece.texturePosition) val (u1, v1) = texture.pixelToUV(piece.texturePosition + piece.textureSize) - builder.quadZ(a, b, c, d, 1f, VertexTransformers.uv(u0, v1, u1, v0)) + builder.quadZ(a, b, c, d, Z_LEVEL, VertexTransformers.uv(u0, v1, u1, v0)) } else { val variant = (getter.randomDoubleFor(pos) * tile.render.variants).toInt() val (u0, v0) = texture.pixelToUV(piece.texturePosition + piece.variantStride * variant) val (u1, v1) = texture.pixelToUV(piece.texturePosition + piece.textureSize + piece.variantStride * variant) - builder.quadZ(a, b, c, d, 1f, VertexTransformers.uv(u0, v1, u1, v0)) + builder.quadZ(a, b, c, d, Z_LEVEL, VertexTransformers.uv(u0, v1, u1, v0)) } } - private fun tesselatePiece(matchPiece: TileRenderMatchPiece, getter: IChunk, builders: MutableMap, pos: Vector2i, thisBuilder: VertexBuilder) { + private fun tesselatePiece(matchPiece: TileRenderMatchPiece, getter: IChunk, layers: TileLayerList, pos: Vector2i, thisBuilder: VertexBuilder) { if (matchPiece.test(getter, tile, pos)) { for (renderPiece in matchPiece.pieces) { if (renderPiece.piece.texture != null) { - tesselateAt(renderPiece.piece, getter, builders.computeIfAbsent(state.tileRenderers.simpleProgram(state.loadNamedTexture(renderPiece.piece.texture))) { - return@computeIfAbsent VertexBuilder(GLFlatAttributeList.VERTEX_TEXTURE, VertexType.QUADS) + tesselateAt(renderPiece.piece, getter, layers.getLayer(state.tileRenderers.simpleProgram(state.loadNamedTexture(renderPiece.piece.texture)), tile.render.zLevel - 1) { + return@getLayer VertexBuilder(GLFlatAttributeList.VERTEX_TEXTURE, VertexType.QUADS) }, pos, renderPiece.offset) } else { tesselateAt(renderPiece.piece, getter, thisBuilder, pos, renderPiece.offset) @@ -115,7 +149,7 @@ class TileRenderer(val state: GLStateTracker, val tile: TileDefinition) { } for (subPiece in matchPiece.subMatches) { - tesselatePiece(subPiece, getter, builders, pos, thisBuilder) + tesselatePiece(subPiece, getter, layers, pos, thisBuilder) } } } @@ -125,22 +159,22 @@ class TileRenderer(val state: GLStateTracker, val tile: TileDefinition) { * * [getter] Нужен для получения информации о ближайших блоках * - * [builders] содержит текущие программы и их билдеры + * [layers] содержит текущие программы и их билдеры и их zPos * * Тесселирует тайлы в границы -1f .. CHUNK_SIZEf + 1f на основе [pos] */ - fun tesselate(getter: IChunk, builders: MutableMap, pos: Vector2i) { + fun tesselate(getter: IChunk, layers: TileLayerList, pos: Vector2i) { // если у нас нет renderTemplate // то мы просто не можем его отрисовать tile.render.renderTemplate ?: return - val builder = builders.computeIfAbsent(bakedProgramState) { - return@computeIfAbsent VertexBuilder(GLFlatAttributeList.VERTEX_TEXTURE, VertexType.QUADS) + val builder = layers.getLayer(bakedProgramState, tile.render.zLevel) { + return@getLayer VertexBuilder(GLFlatAttributeList.VERTEX_TEXTURE, VertexType.QUADS) } for ((_, matcher) in tile.render.renderTemplate.matches) { for (matchPiece in matcher.pieces) { - tesselatePiece(matchPiece, getter, builders, pos, builder) + tesselatePiece(matchPiece, getter, layers, pos, builder) } } @@ -240,5 +274,6 @@ class TileRenderer(val state: GLStateTracker, val tile: TileDefinition) { companion object { const val BASELINE_TEXTURE_SIZE = 8f + const val Z_LEVEL = 1f } }