Тесселятор тайлов теперь знает про haltOnMatch

This commit is contained in:
DBotThePony 2022-02-03 12:04:03 +07:00
parent f0af2d5a8e
commit 4bd1cae5e1
Signed by: DBot
GPG Key ID: DCC23B5715498507
4 changed files with 118 additions and 15 deletions

View File

@ -162,6 +162,14 @@ private fun loop() {
}
}
/*
for (x in 0 .. 24) {
for (y in 0 .. 24) {
chunk[x, y] = Starbound.getTileDefinition("sewerpipe")
}
}
*/
val chunkRenderer = ChunkRenderer(state, chunk)
chunkRenderer.tesselateStatic()
chunkRenderer.uploadStatic()

View File

@ -188,8 +188,8 @@ sealed class RenderRule(params: Map<String, Any>) {
"EqualsSelf" -> RenderRuleEqualsSelf(params)
"Shadows" -> RenderRuleShadows(params)
// неизвестно что оно делает
"Connects" -> AlwaysFailingRenderRule(params)
// неизвестно что оно делает, но вероятнее всего, есть ли там что либо в принципе
"Connects" -> RenderRuleConnects(params)
else -> throw IllegalArgumentException("Unknown render rule '$name'")
}
@ -236,6 +236,15 @@ class RenderRuleShadows(params: Map<String, Any>) : RenderRule(params) {
}
}
class RenderRuleConnects(params: Map<String, Any>) : RenderRule(params) {
override fun test(getter: IChunk, thisRef: TileDefinition, thisPos: Vector2i, offsetPos: Vector2i): Boolean {
if (inverse)
return getter[thisPos + offsetPos] == null
return getter[thisPos + offsetPos] != null
}
}
class AlwaysPassingRenderRule(params: Map<String, Any>) : RenderRule(params) {
override fun test(getter: IChunk, thisRef: TileDefinition, thisPos: Vector2i, offsetPos: Vector2i): Boolean {
return inverse
@ -345,10 +354,19 @@ data class TileRenderMatchPositioned(
data class TileRenderMatchPiece(
val pieces: List<TileRenderMatchedPiece>,
val matchAllPoints: List<TileRenderMatchPositioned>,
val subMatches: List<TileRenderMatchPiece>
val matchAnyPoints: List<TileRenderMatchPositioned>,
val subMatches: List<TileRenderMatchPiece>,
val haltOnSubMatch: Boolean,
val haltOnMatch: Boolean
) {
init {
if (matchAnyPoints.isNotEmpty() || matchAllPoints.isNotEmpty()) {
require(matchAnyPoints.isEmpty() || matchAllPoints.isEmpty()) { "Both matchAllPoints and matchAnyPoints are present, this is not valid." }
}
}
/**
* Возвращает, сработали ли ВСЕ [matchAllPoints]
* Возвращает, сработали ли ВСЕ [matchAllPoints] или ЛЮБОЙ ИЗ [matchAnyPoints]
*
* Если хотя бы один из них вернул false, весь тест возвращает false
*
@ -361,7 +379,17 @@ data class TileRenderMatchPiece(
}
}
return true
if (matchAnyPoints.isEmpty()) {
return true
}
for (matcher in matchAnyPoints) {
if (matcher.test(getter, thisRef, thisPos)) {
return true
}
}
return false
}
companion object {
@ -386,6 +414,16 @@ data class TileRenderMatchPiece(
return@let ImmutableList.copyOf(list)
} ?: listOf()
val matchAnyPoints = input["matchAnyPoints"]?.asJsonArray?.let {
val list = ArrayList<TileRenderMatchPositioned>()
for (thisPiece in it) {
list.add(TileRenderMatchPositioned.fromJson(thisPiece.asJsonArray, rulePieces))
}
return@let ImmutableList.copyOf(list)
} ?: listOf()
val subMatches = input["subMatches"]?.asJsonArray?.let {
val list = ArrayList<TileRenderMatchPiece>()
@ -396,7 +434,18 @@ data class TileRenderMatchPiece(
return@let ImmutableList.copyOf(list)
} ?: listOf()
return TileRenderMatchPiece(pieces, matchAllPoints, subMatches)
val haltOnSubMatch = input["haltOnSubMatch"]?.asBoolean ?: false
val haltOnMatch = input["haltOnMatch"]?.asBoolean ?: false
return TileRenderMatchPiece(
pieces = pieces,
matchAllPoints = matchAllPoints,
matchAnyPoints = matchAnyPoints,
subMatches = subMatches,
haltOnSubMatch = haltOnSubMatch,
haltOnMatch = haltOnMatch,
)
}
}
}
@ -410,8 +459,12 @@ data class TileRenderMatch(
val name = input[0].asString
val pieces = ArrayList<TileRenderMatchPiece>()
for (elem in input[1].asJsonArray) {
pieces.add(TileRenderMatchPiece.fromJson(elem.asJsonObject, tilePieces, rulePieces))
try {
for (elem in input[1].asJsonArray) {
pieces.add(TileRenderMatchPiece.fromJson(elem.asJsonObject, tilePieces, rulePieces))
}
} catch(err: Throwable) {
throw IllegalArgumentException("Failed to deserialize render match rule $name", err)
}
return TileRenderMatch(name, ImmutableList.copyOf(pieces))

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.kstarbound.render
import org.apache.logging.log4j.LogManager
import org.lwjgl.glfw.GLFW.glfwGetTime
import org.lwjgl.opengl.GL46.*
import ru.dbotthepony.kstarbound.Starbound
@ -12,7 +13,10 @@ import ru.dbotthepony.kstarbound.math.Vector2i
import ru.dbotthepony.kstarbound.world.IChunk
import kotlin.collections.HashMap
data class TileLayer(val bakedProgramState: BakedProgramState, val vertexBuilder: VertexBuilder, val zPos: Int)
data class TileLayer(
val bakedProgramState: BakedProgramState,
val vertexBuilder: VertexBuilder,
val zPos: Int)
class TileLayerList {
private val layers = HashMap<BakedProgramState, ArrayList<TileLayer>>()
@ -63,6 +67,7 @@ class TileRenderers(val state: GLStateTracker) {
override fun setup() {
super.setup()
state.activeTexture = 0
// state.depthTest = true
program["_texture"] = 0
texture.bind()
texture.textureMagFilter = GL_NEAREST
@ -94,12 +99,19 @@ class TileRenderers(val state: GLStateTracker) {
}
}
private enum class TileRenderTesselateResult {
NO_MATCH,
CONTINUE,
HALT
}
class TileRenderer(val state: GLStateTracker, val tile: TileDefinition) {
val texture = state.loadNamedTexture(tile.render.texture).also {
it.textureMagFilter = GL_NEAREST
}
val bakedProgramState = state.tileRenderers.simpleProgram(texture)
// private var notifiedDepth = false
private fun tesselateAt(piece: TileRenderPiece, getter: IChunk, builder: VertexBuilder, pos: Vector2i, offset: Vector2i = Vector2i.ZERO) {
val fx = pos.x.toFloat()
@ -121,10 +133,18 @@ class TileRenderer(val state: GLStateTracker, val tile: TileDefinition) {
d += offset.y / BASELINE_TEXTURE_SIZE
}
/*
if (!notifiedDepth && tile.render.zLevel >= 5900) {
LOGGER.warn("Tile {} has out of bounds zLevel of {}", tile.materialName, tile.render.zLevel)
notifiedDepth = true
}
*/
if (tile.render.variants == 0 || piece.texture != null || piece.variantStride == null) {
val (u0, v0) = texture.pixelToUV(piece.texturePosition)
val (u1, v1) = texture.pixelToUV(piece.texturePosition + piece.textureSize)
//builder.quadZ(a, b, c, d, tile.render.zLevel.toFloat() + 200f, 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()
@ -132,15 +152,16 @@ class TileRenderer(val state: GLStateTracker, val tile: TileDefinition) {
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, tile.render.zLevel.toFloat() + 200f, 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, layers: TileLayerList, pos: Vector2i, thisBuilder: VertexBuilder) {
private fun tesselatePiece(matchPiece: TileRenderMatchPiece, getter: IChunk, layers: TileLayerList, pos: Vector2i, thisBuilder: VertexBuilder): TileRenderTesselateResult {
if (matchPiece.test(getter, tile, pos)) {
for (renderPiece in matchPiece.pieces) {
if (renderPiece.piece.texture != null) {
tesselateAt(renderPiece.piece, getter, layers.getLayer(state.tileRenderers.simpleProgram(state.loadNamedTexture(renderPiece.piece.texture)), tile.render.zLevel - 1) {
tesselateAt(renderPiece.piece, getter, layers.getLayer(state.tileRenderers.simpleProgram(state.loadNamedTexture(renderPiece.piece.texture)), tile.render.zLevel) {
return@getLayer VertexBuilder(GLFlatAttributeList.VERTEX_TEXTURE, VertexType.QUADS)
}, pos, renderPiece.offset)
} else {
@ -149,9 +170,21 @@ class TileRenderer(val state: GLStateTracker, val tile: TileDefinition) {
}
for (subPiece in matchPiece.subMatches) {
tesselatePiece(subPiece, getter, layers, pos, thisBuilder)
val matched = tesselatePiece(subPiece, getter, layers, pos, thisBuilder)
if (matched == TileRenderTesselateResult.HALT || matched == TileRenderTesselateResult.CONTINUE && matchPiece.haltOnSubMatch) {
return TileRenderTesselateResult.HALT
}
}
if (matchPiece.haltOnMatch) {
return TileRenderTesselateResult.HALT
}
return TileRenderTesselateResult.CONTINUE
}
return TileRenderTesselateResult.NO_MATCH
}
/**
@ -174,7 +207,11 @@ class TileRenderer(val state: GLStateTracker, val tile: TileDefinition) {
for ((_, matcher) in tile.render.renderTemplate.matches) {
for (matchPiece in matcher.pieces) {
tesselatePiece(matchPiece, getter, layers, pos, builder)
val matched = tesselatePiece(matchPiece, getter, layers, pos, builder)
if (matched == TileRenderTesselateResult.HALT) {
break
}
}
}
@ -275,5 +312,6 @@ class TileRenderer(val state: GLStateTracker, val tile: TileDefinition) {
companion object {
const val BASELINE_TEXTURE_SIZE = 8f
const val Z_LEVEL = 1f
private val LOGGER = LogManager.getLogger()
}
}

View File

@ -8,6 +8,10 @@ in vec2 _uv_out;
out vec4 _color_out;
void main() {
_color_out = texture(_texture, _uv_out);
//_color_out = vec4(1.0, 1.0, 1.0, 1.0);
vec4 texel = texture(_texture, _uv_out);
//if (texel.a < 0.5)
// discard;
_color_out = texel;
}