diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/block/state/baked/cull/FaceCullingTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/block/state/baked/cull/FaceCullingTest.kt index 610bf9256..621034c6b 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/block/state/baked/cull/FaceCullingTest.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/models/block/state/baked/cull/FaceCullingTest.kt @@ -58,168 +58,144 @@ class FaceCullingTest { assertFalse(FaceCulling.canCull(createState(), face, Directions.DOWN, null)) } - @Test fun selfNotTouching() { val face = createFace(properties = null) val neighbour = createBlock() assertFalse(FaceCulling.canCull(createState(), face, Directions.DOWN, neighbour)) } - @Test fun neighbourNotTouching() { val face = createFace() val neighbour = createBlock(properties = null) assertFalse(FaceCulling.canCull(createState(), face, Directions.DOWN, neighbour)) } - @Test fun fullNeighbour() { val face = createFace() val neighbour = createBlock() assertTrue(FaceCulling.canCull(createState(), face, Directions.DOWN, neighbour)) } - @Test fun sizeMatch() { val face = createFace(properties = FaceProperties(Vec2(0.0f, 0.5f), Vec2(1.0f, 0.5f), TextureTransparencies.OPAQUE)) val neighbour = createBlock(properties = side(FaceProperties(Vec2(0.0f, 0.5f), Vec2(1.0f, 0.5f), TextureTransparencies.OPAQUE))) assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour)) } - @Test fun greaterNeighbour() { val face = createFace(properties = FaceProperties(Vec2(0.0f, 0.5f), Vec2(1.0f, 0.5f), TextureTransparencies.OPAQUE)) val neighbour = createBlock(properties = side(FaceProperties(Vec2(0.0f, 0.5f), Vec2(1.0f, 0.6f), TextureTransparencies.OPAQUE))) assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour)) } - @Test fun smallerNeighbour() { val face = createFace(properties = FaceProperties(Vec2(0.0f, 0.5f), Vec2(1.0f, 0.5f), TextureTransparencies.OPAQUE)) val neighbour = createBlock(properties = side(FaceProperties(Vec2(0.0f, 0.5f), Vec2(1.0f, 0.4f), TextureTransparencies.OPAQUE))) assertFalse(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour)) } - @Test fun noSize() { val face = createFace(properties = FaceProperties(Vec2(0.0f, 0.5f), Vec2(1.0f, 0.5f), TextureTransparencies.OPAQUE)) val neighbour = createBlock(properties = side(FaceProperties(Vec2(0.1f, 0.5f), Vec2(1.0f, 0.5f), TextureTransparencies.OPAQUE))) assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour)) } - @Test fun shiftedNeighbour1() { val face = createFace(properties = FaceProperties(Vec2(0.0f, 0.4f), Vec2(1.0f, 0.5f), TextureTransparencies.OPAQUE)) val neighbour = createBlock(properties = side(FaceProperties(Vec2(0.1f, 0.4f), Vec2(1.0f, 0.5f), TextureTransparencies.OPAQUE))) assertFalse(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour)) } - @Test fun shiftedNeighbour2() { val face = createFace(properties = FaceProperties(Vec2(0.0f, 0.4f), Vec2(1.0f, 0.5f), TextureTransparencies.OPAQUE)) val neighbour = createBlock(properties = side(FaceProperties(Vec2(0.1f, 0.4f), Vec2(1.0f, 0.6f), TextureTransparencies.OPAQUE))) assertFalse(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour)) } - @Test fun shiftedNeighbour3() { val face = createFace(properties = FaceProperties(Vec2(0.1f, 0.8f), Vec2(0.9f, 0.9f), TextureTransparencies.OPAQUE)) val neighbour = createBlock(properties = side(FaceProperties(Vec2(0.1f, 0.5f), Vec2(0.95f, 0.95f), TextureTransparencies.OPAQUE))) assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour)) } - @Test fun multipleNeighbourFaces() { val face = createFace(properties = FaceProperties(Vec2(0.1f, 0.3f), Vec2(0.9f, 0.9f), TextureTransparencies.OPAQUE)) val neighbour = createBlock(properties = side(FaceProperties(Vec2(0.1f, 0.2f), Vec2(0.95f, 0.4f), TextureTransparencies.OPAQUE), FaceProperties(Vec2(0.1f, 0.4f), Vec2(0.95f, 0.6f), TextureTransparencies.OPAQUE), FaceProperties(Vec2(0.1f, 0.6f), Vec2(0.95f, 0.95f), TextureTransparencies.OPAQUE))) assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour)) } - @Test fun `transparent side on opaque neighbour`() { val face = createFace(transparency = TextureTransparencies.TRANSPARENT) val neighbour = createBlock(transparency = TextureTransparencies.OPAQUE) assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour)) } - @Test fun `translucent side on opaque neighbour`() { val face = createFace(transparency = TextureTransparencies.TRANSLUCENT) val neighbour = createBlock(transparency = TextureTransparencies.OPAQUE) assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour)) } - @Test fun `opaque side on transparent neighbour`() { val face = createFace(transparency = TextureTransparencies.OPAQUE) val neighbour = createBlock(transparency = TextureTransparencies.TRANSPARENT) assertFalse(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour)) } - @Test fun `opaque side on translucent neighbour`() { val face = createFace(transparency = TextureTransparencies.OPAQUE) val neighbour = createBlock(transparency = TextureTransparencies.TRANSLUCENT) assertFalse(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour)) } - @Test fun `same block, both sides transparent`() { val face = createFace(transparency = TextureTransparencies.TRANSPARENT) val neighbour = createBlock(transparency = TextureTransparencies.TRANSPARENT) assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour)) } - @Test fun `same block, both sides translucent`() { val face = createFace(transparency = TextureTransparencies.TRANSLUCENT) val neighbour = createBlock(transparency = TextureTransparencies.TRANSLUCENT) assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour)) } - @Test fun `different block, both sides transparent`() { val face = createFace(transparency = TextureTransparencies.TRANSPARENT) val neighbour = createBlock(transparency = TextureTransparencies.TRANSPARENT) assertFalse(FaceCulling.canCull(createState(1), face, Directions.EAST, neighbour)) } - @Test fun `different block, both sides translucent`() { val face = createFace(transparency = TextureTransparencies.TRANSLUCENT) val neighbour = createBlock(transparency = TextureTransparencies.TRANSLUCENT) assertFalse(FaceCulling.canCull(createState(1), face, Directions.EAST, neighbour)) } - @Test fun `same block, transparent sides, force no cull`() { val face = createFace(transparency = TextureTransparencies.TRANSPARENT) val neighbour = createBlock(transparency = TextureTransparencies.TRANSPARENT) assertFalse(FaceCulling.canCull(createBlock(forceNoCull()), face, Directions.EAST, neighbour)) } - @Test fun `same block, translucent sides, force no cull`() { val face = createFace(transparency = TextureTransparencies.TRANSLUCENT) val neighbour = createBlock(transparency = TextureTransparencies.TRANSLUCENT) assertFalse(FaceCulling.canCull(createBlock(forceNoCull()), face, Directions.EAST, neighbour)) } - @Test fun `opaque side on transparent block`() { val face = createFace(transparency = TextureTransparencies.OPAQUE) val neighbour = createBlock(transparency = TextureTransparencies.TRANSPARENT) assertFalse(FaceCulling.canCull(createBlock(), face, Directions.EAST, neighbour)) } - @Test fun `transparent side on opaque block`() { val face = createFace(transparency = TextureTransparencies.TRANSPARENT) val neighbour = createBlock(transparency = TextureTransparencies.OPAQUE) assertTrue(FaceCulling.canCull(createBlock(), face, Directions.EAST, neighbour)) } - @Test fun `opaque but no invoked custom cull`() { val block = object : Block(minosoft("dummy"), BlockSettings()), CustomBlockCulling { override val hardness get() = Broken() @@ -233,8 +209,16 @@ class FaceCullingTest { assertTrue(FaceCulling.canCull(createBlock(block), face, Directions.EAST, neighbour)) } - private fun side(vararg properties: FaceProperties): SideProperties { - return SideProperties(arrayOf(*properties), properties.first().transparency) + + fun `opaque but neighbour opaque and transparent`() { // grass block + overlay + val face = createFace(TextureTransparencies.OPAQUE, properties = FaceProperties(Vec2(0.0f, 0.0f), Vec2(1.0f, 1.0f), TextureTransparencies.OPAQUE)) + val neighbour = createBlock(properties = side(FaceProperties(Vec2(0.0f, 0.0f), Vec2(1.0f, 1.0f), TextureTransparencies.OPAQUE), FaceProperties(Vec2(0.0f, 0.0f), Vec2(1.0f, 1.0f), TextureTransparencies.TRANSPARENT), transparency = null)) + assertTrue(FaceCulling.canCull(createState(), face, Directions.EAST, neighbour)) + } + + + private fun side(vararg properties: FaceProperties, transparency: TextureTransparencies? = properties.first().transparency): SideProperties { + return SideProperties(arrayOf(*properties), transparency) } private fun forceNoCull() = object : Block(minosoft("dummy"), BlockSettings()), CustomBlockCulling { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/baked/cull/FaceCulling.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/baked/cull/FaceCulling.kt index c2b7c0904..8566eed6f 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/baked/cull/FaceCulling.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/models/block/state/baked/cull/FaceCulling.kt @@ -36,12 +36,21 @@ object FaceCulling { // impossible to see that face return true } + if (neighbourProperties.transparency == null) { + for (property in neighbourProperties.faces) { + if (property.transparency != TextureTransparencies.OPAQUE) continue + if (!properties.isCoveredBy(property)) continue + return true + } + } if (state.block is CustomBlockCulling) { return state.block.shouldCull(state, properties, direction, neighbour) } - if (neighbourProperties.transparency == null) return false // can not determinate it + if (neighbourProperties.transparency == null) { + return false + } if (state.block != neighbour.block) return false if (neighbourProperties.transparency == properties.transparency) return true @@ -59,17 +68,26 @@ object FaceCulling { var area = 0.0f for (quad in this.faces) { - val width = minOf(target.end.x, quad.end.x) - maxOf(quad.start.x, target.start.x) - val height = minOf(target.end.y, quad.end.y) - maxOf(quad.start.y, target.start.y) - - area += width * height + area += quad.getSideArea(target) } return area } + private fun FaceProperties.getSideArea(target: FaceProperties): Float { + val width = minOf(target.end.x, end.x) - maxOf(start.x, target.start.x) + val height = minOf(target.end.y, end.y) - maxOf(start.y, target.start.y) + + return width * height + } + fun FaceProperties.isCoveredBy(properties: SideProperties): Boolean { val area = properties.getSideArea(this) return surface <= area } + + fun FaceProperties.isCoveredBy(properties: FaceProperties): Boolean { + val area = properties.getSideArea(this) + return surface <= area + } }