diff --git a/client/src/main/resources/textures/blocks/glass.png b/client/src/main/resources/textures/blocks/glass.png new file mode 100644 index 00000000..aee9d715 Binary files /dev/null and b/client/src/main/resources/textures/blocks/glass.png differ diff --git a/client/src/main/scala/hexacraft/client/BlockSpecs.scala b/client/src/main/scala/hexacraft/client/BlockSpecs.scala index 4030673f..bbe3d04e 100644 --- a/client/src/main/scala/hexacraft/client/BlockSpecs.scala +++ b/client/src/main/scala/hexacraft/client/BlockSpecs.scala @@ -36,5 +36,6 @@ object BlockSpecs { ) case "leaves_birch" => BlockSpec(Textures.basic("leaves_birch")) case "tnt" => BlockSpec(Textures.basic("tnt").withTop("tnt_top").withBottom("tnt_top")) + case "glass" => BlockSpec(Textures.basic("glass")) } } diff --git a/client/src/main/scala/hexacraft/client/WorldRenderer.scala b/client/src/main/scala/hexacraft/client/WorldRenderer.scala index 756b4830..2b8f803a 100644 --- a/client/src/main/scala/hexacraft/client/WorldRenderer.scala +++ b/client/src/main/scala/hexacraft/client/WorldRenderer.scala @@ -6,10 +6,9 @@ import hexacraft.infra.gpu.OpenGL import hexacraft.renderer.{GpuState, TextureArray, TextureSingle, VAO} import hexacraft.shaders.* import hexacraft.util.{NamedThreadFactory, TickableTimer} -import hexacraft.world.{BlocksInWorld, Camera, ChunkLoadingPrioritizer, CylinderSize, PosAndDir, WorldGenerator} -import hexacraft.world.block.BlockState +import hexacraft.world.* import hexacraft.world.chunk.{Chunk, ChunkColumnHeightMap, ChunkColumnTerrain, ChunkStorage} -import hexacraft.world.coord.{BlockRelWorld, ChunkRelWorld, ColumnRelWorld} +import hexacraft.world.coord.{ChunkRelWorld, ColumnRelWorld} import hexacraft.world.entity.{Entity, EntityModel} import org.joml.{Vector2ic, Vector3f} @@ -44,7 +43,7 @@ class WorldRenderer( private val terrainShader = new TerrainShader() private val solidBlockGpuState = GpuState.build(_.blend(false).cullFace(true)) - private val transmissiveBlockGpuState = GpuState.build(_.blend(true).cullFace(false)) + private val transmissiveBlockGpuState = GpuState.build(_.blend(true).cullFace(true)) private val terrainGpuState = GpuState.build(_.blend(false).cullFace(true)) @@ -301,6 +300,11 @@ class WorldRenderer( // World content renderBlocks(camera, sun) + // TODO: Opaque and translucent blocks are both rendered here, but they need to be separate. + // In the world combiner there is a normal field, but if there is glass in front of grass then the normal will be for the glass. + // The normal-based shading only happens for the grass. + // Instead we should render in two steps, or alternatively send both to the shader. How is this usually done? + // renderTerrain(camera, sun) renderEntities(camera, sun) diff --git a/client/src/main/scala/hexacraft/client/render/BlockVboData.scala b/client/src/main/scala/hexacraft/client/render/BlockVboData.scala index 540d66c5..f1a3c1f6 100644 --- a/client/src/main/scala/hexacraft/client/render/BlockVboData.scala +++ b/client/src/main/scala/hexacraft/client/render/BlockVboData.scala @@ -82,11 +82,16 @@ object BlockVboData { if neigh != null then { val bs = neigh.getBlock(c2) - val shouldRenderSide = if bs.blockType == Block.Water then { - b != bs && s < 2 && b.blockType != Block.Water - } else { - b != bs && (s == 0 || !bs.blockType.isSolid) - } + val here = b.blockType + val there = bs.blockType + + val shouldRenderSide = + if here == there then false + else if there.isTransmissive then true + else if s == 0 && here.blockHeight(b.metadata) < 1.0 then true + else false + + // TODO: sort translucent faces and the rendering glitches might be fixed if shouldRenderSide then { brightness(c.value) = neigh.lighting.getBrightness(c2) diff --git a/game/src/main/scala/hexacraft/world/block/blocks.scala b/game/src/main/scala/hexacraft/world/block/blocks.scala index 1d644e0e..96977ae0 100644 --- a/game/src/main/scala/hexacraft/world/block/blocks.scala +++ b/game/src/main/scala/hexacraft/world/block/blocks.scala @@ -29,6 +29,7 @@ object Block { val BirchLog = register(new Block(9, "log_birch", "Birch log")) val BirchLeaves = register(new Block(10, "leaves_birch", "Birch leaves")) val Tnt = register(new Block(11, "tnt", "TNT")) + val Glass = register(new BlockGlass(12, "glass", "Glass")) } class Block(val id: Byte, val name: String, val displayName: String) { @@ -72,3 +73,9 @@ class BlockAir extends Block(0, "air", "Air") { trait EmittingLight extends Block { override def lightEmitted: Byte = 14 } + +class BlockGlass(_id: Byte, _name: String, _displayName: String) extends Block(_id, _name, _displayName) { + override def isCovering(metadata: Byte, side: Int): Boolean = false + + override def isTransmissive: Boolean = true +}