Теперь тайлы сортируются по z глубине
This commit is contained in:
parent
8a13a99713
commit
247e1a8ba5
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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<BakedProgramState, VertexBuilder>()
|
||||
private val layers = TileLayerList()
|
||||
private val bakedMeshes = ArrayList<BakedStaticMesh>()
|
||||
private val unloadableBakedMeshes = ArrayList<BakedStaticMesh>()
|
||||
|
||||
@ -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) {
|
||||
|
@ -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<BakedProgramState, ArrayList<TileLayer>>()
|
||||
|
||||
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<TileLayer> {
|
||||
val list = ArrayList<TileLayer>()
|
||||
|
||||
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<GLTexture2D, SimpleBakedProgram>()
|
||||
private val tileRenderers = HashMap<String, TileRenderer>()
|
||||
@ -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<BakedProgramState, VertexBuilder>, 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<BakedProgramState, VertexBuilder>, 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
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user