diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt index 0c89600d7..a32cb55c7 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt @@ -86,6 +86,7 @@ class RenderWindow( val shaders: MutableList = mutableListOf() + val shaderManager = ShaderManager(this) lateinit var WHITE_TEXTURE: TextureLike @@ -201,6 +202,8 @@ class RenderWindow( font.load(connection.assetsManager, textures.allTextures) + shaderManager.init() + Log.log(LogMessageType.RENDERING_LOADING) { "Initializing renderer (${stopwatch.labTime()})..." } for (renderer in rendererMap.values) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/ShaderManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/ShaderManager.kt new file mode 100644 index 000000000..0caa5be44 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/ShaderManager.kt @@ -0,0 +1,31 @@ +/* + * Minosoft + * Copyright (C) 2021 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering + +import de.bixilon.minosoft.data.mappings.ResourceLocation +import de.bixilon.minosoft.gui.rendering.shader.Shader +import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition + +class ShaderManager( + val renderWindow: RenderWindow, +) { + val genericColorShader = Shader( + resourceLocation = ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "generic/color"), + ) + + + fun init() { + genericColorShader.load(renderWindow.connection.assetsManager) + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/block/outline/BlockOutlineRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/block/outline/BlockOutlineRenderer.kt index 9883d4506..85300dda6 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/block/outline/BlockOutlineRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/block/outline/BlockOutlineRenderer.kt @@ -21,18 +21,10 @@ import de.bixilon.minosoft.gui.rendering.RenderConstants import de.bixilon.minosoft.gui.rendering.RenderWindow import de.bixilon.minosoft.gui.rendering.Renderer import de.bixilon.minosoft.gui.rendering.RendererBuilder -import de.bixilon.minosoft.gui.rendering.chunk.VoxelShape -import de.bixilon.minosoft.gui.rendering.chunk.models.renderable.ElementRenderer -import de.bixilon.minosoft.gui.rendering.shader.Shader -import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY import de.bixilon.minosoft.gui.rendering.util.VecUtil.getWorldOffset import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3d +import de.bixilon.minosoft.gui.rendering.util.mesh.LineMesh import de.bixilon.minosoft.protocol.network.connection.PlayConnection -import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition -import de.bixilon.minosoft.util.BitByte.isBit -import de.bixilon.minosoft.util.MMath.positiveNegative -import glm_.vec3.Vec3 -import glm_.vec3.Vec3d import glm_.vec3.Vec3i import org.lwjgl.opengl.GL11.* @@ -43,82 +35,17 @@ class BlockOutlineRenderer( private var currentOutlinePosition: Vec3i? = null private var currentOutlineBlockState: BlockState? = null - private var outlineMesh: BlockOutlineMesh? = null - private var collisionMesh: BlockOutlineMesh? = null - private val outlineShader = Shader( - resourceLocation = ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "chunk/block/outline"), - ) + private var outlineMesh: LineMesh? = null + private var collisionMesh: LineMesh? = null - override fun init() { - outlineShader.load(connection.assetsManager) - } - - private fun drawLine(start: Vec3, end: Vec3, mesh: BlockOutlineMesh) { - val direction = (end - start).normalize() - val normal1 = Vec3(direction.z, direction.z, direction.x - direction.y) - if (normal1 == Vec3.EMPTY) { - normal1.x = normal1.z - normal1.z = direction.z - } - normal1.normalizeAssign() - val normal2 = (direction cross normal1).normalize() - for (i in 0..4) { - drawLineQuad(mesh, start, end, direction, normal1, normal2, i.isBit(0), i.isBit(1)) - } - } - - private fun drawLineQuad(mesh: BlockOutlineMesh, start: Vec3, end: Vec3, direction: Vec3, normal1: Vec3, normal2: Vec3, invertNormal1: Boolean, invertNormal2: Boolean) { - val normal1Multiplier = invertNormal1.positiveNegative - val normal2Multiplier = invertNormal2.positiveNegative - val positions = listOf( - start + normal2 * normal2Multiplier * HALF_LINE_WIDTH - direction * HALF_LINE_WIDTH, - start + normal1 * normal1Multiplier * HALF_LINE_WIDTH - direction * HALF_LINE_WIDTH, - end + normal1 * normal1Multiplier * HALF_LINE_WIDTH + direction * HALF_LINE_WIDTH, - end + normal2 * normal2Multiplier * HALF_LINE_WIDTH + direction * HALF_LINE_WIDTH, - ) - for ((_, positionIndex) in ElementRenderer.DRAW_ODER) { - mesh.addVertex(positions[positionIndex]) - } - } - - private fun drawVoxelShape(shape: VoxelShape, blockPosition: Vec3d, mesh: BlockOutlineMesh, margin: Float = 0.0f) { - for (aabb in shape) { - val min = blockPosition + aabb.min - margin - val max = blockPosition + aabb.max + margin - - fun drawSideQuad(x: Double) { - drawLine(Vec3(x, min.y, min.z), Vec3(x, max.y, min.z), mesh) - drawLine(Vec3(x, min.y, min.z), Vec3(x, min.y, max.z), mesh) - drawLine(Vec3(x, max.y, min.z), Vec3(x, max.y, max.z), mesh) - drawLine(Vec3(x, min.y, max.z), Vec3(x, max.y, max.z), mesh) - } - - // left quad - drawSideQuad(min.x) - - // right quad - drawSideQuad(max.x) - - // connections between 2 quads - drawLine(Vec3(min.x, min.y, min.z), Vec3(max.x, min.y, min.z), mesh) - drawLine(Vec3(min.x, max.y, min.z), Vec3(max.x, max.y, min.z), mesh) - drawLine(Vec3(min.x, max.y, max.z), Vec3(max.x, max.y, max.z), mesh) - drawLine(Vec3(min.x, min.y, max.z), Vec3(max.x, min.y, max.z), mesh) - } - } - - private fun draw(outlineMesh: BlockOutlineMesh, collisionMesh: BlockOutlineMesh?) { + private fun draw(outlineMesh: LineMesh, collisionMesh: LineMesh?) { glDisable(GL_CULL_FACE) if (Minosoft.config.config.game.other.blockOutline.disableZBuffer) { glDepthFunc(GL_ALWAYS) } - outlineShader.use() - outlineShader.setRGBColor("uTintColor", Minosoft.config.config.game.other.blockOutline.outlineColor) + renderWindow.shaderManager.genericColorShader.use() outlineMesh.draw() - collisionMesh?.let { - outlineShader.setRGBColor("uTintColor", Minosoft.config.config.game.other.blockOutline.collisionColor) - it.draw() - } + collisionMesh?.draw() glEnable(GL_CULL_FACE) if (Minosoft.config.config.game.other.blockOutline.disableZBuffer) { glDepthFunc(GL_LESS) @@ -165,18 +92,18 @@ class BlockOutlineRenderer( outlineMesh?.unload() collisionMesh?.unload() - outlineMesh = BlockOutlineMesh() + outlineMesh = LineMesh(Minosoft.config.config.game.other.blockOutline.outlineColor, LINE_WIDTH) val blockOffset = raycastHit.blockPosition.toVec3d + raycastHit.blockPosition.getWorldOffset(raycastHit.blockState.block) - drawVoxelShape(raycastHit.blockState.outlineShape, blockOffset, outlineMesh) + outlineMesh.drawVoxelShape(raycastHit.blockState.outlineShape, blockOffset, outlineMesh) outlineMesh.load() if (Minosoft.config.config.game.other.blockOutline.collisionBoxes) { - collisionMesh = BlockOutlineMesh() + collisionMesh = LineMesh(Minosoft.config.config.game.other.blockOutline.collisionColor, LINE_WIDTH) - drawVoxelShape(raycastHit.blockState.collisionShape, blockOffset, collisionMesh, 0.005f) + collisionMesh.drawVoxelShape(raycastHit.blockState.collisionShape, blockOffset, collisionMesh, 0.005f) collisionMesh.load() this.collisionMesh = collisionMesh } @@ -192,7 +119,6 @@ class BlockOutlineRenderer( companion object : RendererBuilder { override val RESOURCE_LOCATION = ResourceLocation("minosoft:block_outline") private const val LINE_WIDTH = 1.0f / 128.0f - private const val HALF_LINE_WIDTH = LINE_WIDTH / 2.0f override fun build(connection: PlayConnection, renderWindow: RenderWindow): BlockOutlineRenderer { return BlockOutlineRenderer(connection, renderWindow) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/block/outline/BlockOutlineMesh.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/mesh/GenericColorMesh.kt similarity index 64% rename from src/main/java/de/bixilon/minosoft/gui/rendering/chunk/block/outline/BlockOutlineMesh.kt rename to src/main/java/de/bixilon/minosoft/gui/rendering/util/mesh/GenericColorMesh.kt index 70712f530..73a536c9b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/block/outline/BlockOutlineMesh.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/mesh/GenericColorMesh.kt @@ -11,19 +11,27 @@ * This software is not affiliated with Mojang AB, the original developer of Minecraft. */ -package de.bixilon.minosoft.gui.rendering.chunk.block.outline +package de.bixilon.minosoft.gui.rendering.util.mesh -import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh -import de.bixilon.minosoft.gui.rendering.util.mesh.PositionOnlyMeshStruct +import de.bixilon.minosoft.data.text.ChatColors +import de.bixilon.minosoft.data.text.RGBColor import glm_.vec3.Vec3 -class BlockOutlineMesh : Mesh(PositionOnlyMeshStruct::class) { +open class GenericColorMesh : Mesh(GenericColorMeshStruct::class) { - fun addVertex(position: Vec3) { + fun addVertex(position: Vec3, color: RGBColor?) { data.addAll(floatArrayOf( position.x, position.y, position.z, + Float.fromBits((color ?: ChatColors.WHITE).rgba) )) } + + data class GenericColorMeshStruct( + val position: Vec3, + val color: RGBColor, + ) { + companion object : MeshStruct(GenericColorMeshStruct::class) + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/mesh/LineMesh.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/mesh/LineMesh.kt new file mode 100644 index 000000000..65ea68afc --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/mesh/LineMesh.kt @@ -0,0 +1,85 @@ +/* + * Minosoft + * Copyright (C) 2021 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.util.mesh + +import de.bixilon.minosoft.data.text.RGBColor +import de.bixilon.minosoft.gui.rendering.chunk.VoxelShape +import de.bixilon.minosoft.gui.rendering.chunk.models.renderable.ElementRenderer +import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY +import de.bixilon.minosoft.util.BitByte.isBit +import de.bixilon.minosoft.util.MMath.positiveNegative +import glm_.vec3.Vec3 +import glm_.vec3.Vec3d + +class LineMesh( + var color: RGBColor, + lineWidth: Float = 0.1f, +) : GenericColorMesh() { + private var halfLineWidth = lineWidth / 2.0f + + + fun drawLine(start: Vec3, end: Vec3, mesh: GenericColorMesh) { + val direction = (end - start).normalize() + val normal1 = Vec3(direction.z, direction.z, direction.x - direction.y) + if (normal1 == Vec3.EMPTY) { + normal1.x = normal1.z + normal1.z = direction.z + } + normal1.normalizeAssign() + val normal2 = (direction cross normal1).normalize() + for (i in 0..4) { + drawLineQuad(mesh, start, end, direction, normal1, normal2, i.isBit(0), i.isBit(1)) + } + } + + fun drawLineQuad(mesh: GenericColorMesh, start: Vec3, end: Vec3, direction: Vec3, normal1: Vec3, normal2: Vec3, invertNormal1: Boolean, invertNormal2: Boolean) { + val normal1Multiplier = invertNormal1.positiveNegative + val normal2Multiplier = invertNormal2.positiveNegative + val positions = listOf( + start + normal2 * normal2Multiplier * halfLineWidth - direction * halfLineWidth, + start + normal1 * normal1Multiplier * halfLineWidth - direction * halfLineWidth, + end + normal1 * normal1Multiplier * halfLineWidth + direction * halfLineWidth, + end + normal2 * normal2Multiplier * halfLineWidth + direction * halfLineWidth, + ) + for ((_, positionIndex) in ElementRenderer.DRAW_ODER) { + mesh.addVertex(positions[positionIndex], color) + } + } + + fun drawVoxelShape(shape: VoxelShape, blockPosition: Vec3d, mesh: GenericColorMesh, margin: Float = 0.0f) { + for (aabb in shape) { + val min = blockPosition + aabb.min - margin + val max = blockPosition + aabb.max + margin + + fun drawSideQuad(x: Double) { + drawLine(Vec3(x, min.y, min.z), Vec3(x, max.y, min.z), mesh) + drawLine(Vec3(x, min.y, min.z), Vec3(x, min.y, max.z), mesh) + drawLine(Vec3(x, max.y, min.z), Vec3(x, max.y, max.z), mesh) + drawLine(Vec3(x, min.y, max.z), Vec3(x, max.y, max.z), mesh) + } + + // left quad + drawSideQuad(min.x) + + // right quad + drawSideQuad(max.x) + + // connections between 2 quads + drawLine(Vec3(min.x, min.y, min.z), Vec3(max.x, min.y, min.z), mesh) + drawLine(Vec3(min.x, max.y, min.z), Vec3(max.x, max.y, min.z), mesh) + drawLine(Vec3(min.x, max.y, max.z), Vec3(max.x, max.y, max.z), mesh) + drawLine(Vec3(min.x, min.y, max.z), Vec3(max.x, min.y, max.z), mesh) + } + } +} diff --git a/src/main/resources/assets/minosoft/rendering/shader/chunk/block/outline/chunk_block_outline.fsh b/src/main/resources/assets/minosoft/rendering/shader/generic/color/generic_color.fsh similarity index 93% rename from src/main/resources/assets/minosoft/rendering/shader/chunk/block/outline/chunk_block_outline.fsh rename to src/main/resources/assets/minosoft/rendering/shader/generic/color/generic_color.fsh index 1a78ee811..95b24c8e5 100644 --- a/src/main/resources/assets/minosoft/rendering/shader/chunk/block/outline/chunk_block_outline.fsh +++ b/src/main/resources/assets/minosoft/rendering/shader/generic/color/generic_color.fsh @@ -13,10 +13,12 @@ #version 330 core +in vec4 finTintColor; + + out vec4 foutColor; -uniform vec4 uTintColor; void main() { - foutColor = uTintColor; + foutColor = finTintColor; } diff --git a/src/main/resources/assets/minosoft/rendering/shader/chunk/block/outline/chunk_block_outline.vsh b/src/main/resources/assets/minosoft/rendering/shader/generic/color/generic_color.vsh similarity index 87% rename from src/main/resources/assets/minosoft/rendering/shader/chunk/block/outline/chunk_block_outline.vsh rename to src/main/resources/assets/minosoft/rendering/shader/generic/color/generic_color.vsh index d735e799f..6547057c8 100644 --- a/src/main/resources/assets/minosoft/rendering/shader/chunk/block/outline/chunk_block_outline.vsh +++ b/src/main/resources/assets/minosoft/rendering/shader/generic/color/generic_color.vsh @@ -14,9 +14,16 @@ #version 330 core layout (location = 0) in vec3 vinPosition; +layout (location = 1) in uint vinTintColor; uniform mat4 uViewProjectionMatrix; +out vec4 finTintColor; + +#include "minosoft:color" + void main() { gl_Position = uViewProjectionMatrix * vec4(vinPosition, 1.0f); + + finTintColor = getRGBAColor(vinTintColor); }