diff options
Diffstat (limited to 'src/main/kotlin/util/render')
| -rw-r--r-- | src/main/kotlin/util/render/CustomRenderLayers.kt | 105 | ||||
| -rw-r--r-- | src/main/kotlin/util/render/DrawContextExt.kt | 210 | ||||
| -rw-r--r-- | src/main/kotlin/util/render/DumpTexture.kt | 34 | ||||
| -rw-r--r-- | src/main/kotlin/util/render/FacingThePlayerContext.kt | 104 | ||||
| -rw-r--r-- | src/main/kotlin/util/render/FirmamentShaders.kt | 20 | ||||
| -rw-r--r-- | src/main/kotlin/util/render/LerpUtils.kt | 37 | ||||
| -rw-r--r-- | src/main/kotlin/util/render/MultiSpecialGuiRenderState.kt | 47 | ||||
| -rw-r--r-- | src/main/kotlin/util/render/RenderCircleProgress.kt | 229 | ||||
| -rw-r--r-- | src/main/kotlin/util/render/RenderInWorldContext.kt | 352 | ||||
| -rw-r--r-- | src/main/kotlin/util/render/TintedOverlayTexture.kt | 21 | ||||
| -rw-r--r-- | src/main/kotlin/util/render/TranslatedScissors.kt | 41 |
11 files changed, 753 insertions, 447 deletions
diff --git a/src/main/kotlin/util/render/CustomRenderLayers.kt b/src/main/kotlin/util/render/CustomRenderLayers.kt new file mode 100644 index 0000000..4a85c17 --- /dev/null +++ b/src/main/kotlin/util/render/CustomRenderLayers.kt @@ -0,0 +1,105 @@ +package util.render + +import com.mojang.blaze3d.pipeline.BlendFunction +import com.mojang.blaze3d.pipeline.RenderPipeline +import com.mojang.blaze3d.platform.DepthTestFunction +import com.mojang.blaze3d.vertex.VertexFormat.Mode +import java.util.function.Function +import net.minecraft.client.renderer.RenderPipelines +import com.mojang.blaze3d.shaders.UniformType +import net.minecraft.client.renderer.RenderType +import net.minecraft.client.renderer.RenderStateShard +import com.mojang.blaze3d.vertex.DefaultVertexFormat +import net.minecraft.resources.ResourceLocation +import net.minecraft.Util +import moe.nea.firmament.Firmament + +object CustomRenderPipelines { + val GUI_TEXTURED_NO_DEPTH_TRIS = + RenderPipeline.builder(RenderPipelines.GUI_TEXTURED_SNIPPET) + .withVertexFormat(DefaultVertexFormat.POSITION_TEX_COLOR, Mode.TRIANGLES) + .withLocation(Firmament.identifier("gui_textured_overlay_tris")) + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .withCull(false) + .withDepthWrite(false) + .build() + val OMNIPRESENT_LINES = RenderPipeline + .builder(RenderPipelines.LINES_SNIPPET) + .withLocation(Firmament.identifier("lines")) + .withDepthWrite(false) + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .build() + val COLORED_OMNIPRESENT_QUADS = + RenderPipeline.builder(RenderPipelines.MATRICES_PROJECTION_SNIPPET)// TODO: split this up to support better transparent ordering. + .withLocation(Firmament.identifier("colored_omnipresent_quads")) + .withVertexShader("core/position_color") + .withFragmentShader("core/position_color") + .withVertexFormat(DefaultVertexFormat.POSITION_COLOR, Mode.QUADS) + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .withCull(false) + .withDepthWrite(false) + .withBlend(BlendFunction.TRANSLUCENT) + .build() + + val CIRCLE_FILTER_TRANSLUCENT_GUI_TRIS = + RenderPipeline.builder(RenderPipelines.GUI_TEXTURED_SNIPPET) + .withVertexFormat(DefaultVertexFormat.POSITION_TEX_COLOR, Mode.TRIANGLES) + .withLocation(Firmament.identifier("gui_textured_overlay_tris_circle")) + .withUniform("CutoutRadius", UniformType.UNIFORM_BUFFER) + .withFragmentShader(Firmament.identifier("circle_discard_color")) +// .withBlend(BlendFunction.TRANSLUCENT) + .build() + val PARALLAX_CAPE_SHADER = + RenderPipeline.builder(RenderPipelines.ENTITY_SNIPPET) + .withLocation(Firmament.identifier("parallax_cape")) + .withFragmentShader(Firmament.identifier("cape/parallax")) + .withSampler("Sampler0") + .withSampler("Sampler1") + .withSampler("Sampler3") + .withUniform("Animation", UniformType.UNIFORM_BUFFER) + .build() +} + +object CustomRenderLayers { + inline fun memoizeTextured(crossinline func: (ResourceLocation) -> RenderType.CompositeRenderType) = memoize(func) + inline fun <T, R> memoize(crossinline func: (T) -> R): Function<T, R> { + return Util.memoize { it: T -> func(it) } + } + + val GUI_TEXTURED_NO_DEPTH_TRIS = memoizeTextured { texture -> + RenderType.create( + "firmament_gui_textured_overlay_tris", + RenderType.TRANSIENT_BUFFER_SIZE, + CustomRenderPipelines.GUI_TEXTURED_NO_DEPTH_TRIS, + RenderType.CompositeState.builder().setTextureState( + RenderStateShard.TextureStateShard(texture, false) + ) + .createCompositeState(false) + ) + } + val LINES = RenderType.create( + "firmament_lines", + RenderType.TRANSIENT_BUFFER_SIZE, + CustomRenderPipelines.OMNIPRESENT_LINES, + RenderType.CompositeState.builder() // TODO: accept linewidth here + .createCompositeState(false) + ) + val COLORED_QUADS = RenderType.create( + "firmament_quads", + RenderType.TRANSIENT_BUFFER_SIZE, + false, true, + CustomRenderPipelines.COLORED_OMNIPRESENT_QUADS, + RenderType.CompositeState.builder() + .setLightmapState(RenderStateShard.NO_LIGHTMAP) + .createCompositeState(false) + ) + + val TRANSLUCENT_CIRCLE_GUI = + RenderType.create( + "firmament_circle_gui", + RenderType.TRANSIENT_BUFFER_SIZE, + CustomRenderPipelines.CIRCLE_FILTER_TRANSLUCENT_GUI_TRIS, + RenderType.CompositeState.builder() + .createCompositeState(false) + ) +} diff --git a/src/main/kotlin/util/render/DrawContextExt.kt b/src/main/kotlin/util/render/DrawContextExt.kt index a143d4d..9ef66f3 100644 --- a/src/main/kotlin/util/render/DrawContextExt.kt +++ b/src/main/kotlin/util/render/DrawContextExt.kt @@ -2,63 +2,33 @@ package moe.nea.firmament.util.render import com.mojang.blaze3d.systems.RenderSystem import me.shedaniel.math.Color -import org.joml.Matrix4f -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.RenderLayer -import net.minecraft.client.render.RenderLayer.MultiPhaseParameters -import net.minecraft.client.render.RenderPhase -import net.minecraft.client.render.VertexFormat -import net.minecraft.client.render.VertexFormat.DrawMode -import net.minecraft.client.render.VertexFormats -import net.minecraft.util.Identifier -import net.minecraft.util.TriState -import net.minecraft.util.Util +import org.joml.Vector3f +import util.render.CustomRenderLayers +import kotlin.math.abs +import net.minecraft.client.renderer.RenderPipelines +import net.minecraft.client.gui.GuiGraphics +import net.minecraft.client.gui.navigation.ScreenRectangle +import net.minecraft.client.renderer.MultiBufferSource +import com.mojang.blaze3d.vertex.PoseStack +import net.minecraft.resources.ResourceLocation import moe.nea.firmament.util.MC -fun DrawContext.isUntranslatedGuiDrawContext(): Boolean { - return (matrices.peek().positionMatrix.properties() and Matrix4f.PROPERTY_IDENTITY.toInt()) != 0 -} - -object GuiRenderLayers { - val GUI_TEXTURED_NO_DEPTH = Util.memoize<Identifier, RenderLayer> { texture: Identifier -> - RenderLayer.of("firmament_gui_textured_no_depth", - VertexFormats.POSITION_TEXTURE_COLOR, - DrawMode.QUADS, - DEFAULT_BUFFER_SIZE, - MultiPhaseParameters.builder() - .texture(RenderPhase.Texture(texture, TriState.FALSE, false)) - .program(RenderPhase.POSITION_TEXTURE_COLOR_PROGRAM) - .transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY) - .depthTest(RenderPhase.ALWAYS_DEPTH_TEST) - .build(false)) - } - val GUI_TEXTURED_TRIS = Util.memoize { texture: Identifier -> - RenderLayer.of("firmament_gui_textured_overlay_tris", - VertexFormats.POSITION_TEXTURE_COLOR, - DrawMode.TRIANGLES, - DEFAULT_BUFFER_SIZE, - MultiPhaseParameters.builder() - .texture(RenderPhase.Texture(texture, TriState.DEFAULT, false)) - .program(RenderPhase.POSITION_TEXTURE_COLOR_PROGRAM) - .transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY) - .depthTest(RenderPhase.ALWAYS_DEPTH_TEST) - .writeMaskState(RenderPhase.COLOR_MASK) - .build(false)) - } +fun GuiGraphics.isUntranslatedGuiDrawContext(): Boolean { + return pose().m00 == 1F && pose().m11 == 1f && pose().m01 == 0F && pose().m10 == 0F && pose().m20 == 0F && pose().m21 == 0F } @Deprecated("Use the other drawGuiTexture") -fun DrawContext.drawGuiTexture( - x: Int, y: Int, z: Int, width: Int, height: Int, sprite: Identifier -) = this.drawGuiTexture(RenderLayer::getGuiTextured, sprite, x, y, width, height) +fun GuiGraphics.drawGuiTexture( + x: Int, y: Int, z: Int, width: Int, height: Int, sprite: ResourceLocation +) = this.blitSprite(RenderPipelines.GUI_TEXTURED, sprite, x, y, width, height) -fun DrawContext.drawGuiTexture( - sprite: Identifier, +fun GuiGraphics.drawGuiTexture( + sprite: ResourceLocation, x: Int, y: Int, width: Int, height: Int -) = this.drawGuiTexture(RenderLayer::getGuiTextured, sprite, x, y, width, height) +) = this.blitSprite(RenderPipelines.GUI_TEXTURED, sprite, x, y, width, height) -fun DrawContext.drawTexture( - sprite: Identifier, +fun GuiGraphics.drawTexture( + sprite: ResourceLocation, x: Int, y: Int, u: Float, @@ -68,34 +38,130 @@ fun DrawContext.drawTexture( textureWidth: Int, textureHeight: Int ) { - this.drawTexture(RenderLayer::getGuiTextured, - sprite, - x, - y, - u, - v, - width, - height, - width, - height, - textureWidth, - textureHeight) + this.blit( + RenderPipelines.GUI_TEXTURED, + sprite, + x, + y, + u, + v, + width, + height, + width, + height, + textureWidth, + textureHeight + ) +} + +data class LineRenderState( + override val x1: Int, + override val x2: Int, + override val y1: Int, + override val y2: Int, + override val scale: Float, + override val bounds: ScreenRectangle, + val lineWidth: Float, + val w: Int, + val h: Int, + val color: Int, + val direction: LineDirection, +) : MultiSpecialGuiRenderState() { + enum class LineDirection { + TOP_LEFT_TO_BOTTOM_RIGHT, + BOTTOM_LEFT_TO_TOP_RIGHT, + } + + override fun createRenderer(vertexConsumers: MultiBufferSource.BufferSource): MultiSpecialGuiRenderer<out MultiSpecialGuiRenderState> { + return LineRenderer(vertexConsumers) + } + + override val scissorArea = null } -fun DrawContext.drawLine(fromX: Int, fromY: Int, toX: Int, toY: Int, color: Color) { - // TODO: push scissors - // TODO: use matrix translations and a different render layer +class LineRenderer(vertexConsumers: MultiBufferSource.BufferSource) : + MultiSpecialGuiRenderer<LineRenderState>(vertexConsumers) { + override fun getRenderStateClass(): Class<LineRenderState> { + return LineRenderState::class.java + } + + override fun getTranslateY(height: Int, windowScaleFactor: Int): Float { + return height / 2F + } + + override fun renderToTexture( + state: LineRenderState, + matrices: PoseStack + ) { + val gr = MC.instance.gameRenderer + val client = MC.instance + gr.globalSettingsUniform + .update( + state.bounds.width, + state.bounds.height, + client.options.glintStrength().get(), + client.level?.gameTime ?: 0L, + client.deltaTracker, + client.options.menuBackgroundBlurriness + ) + + RenderSystem.lineWidth(state.lineWidth) + val buf = bufferSource.getBuffer(CustomRenderLayers.LINES) + val matrix = matrices.last() + val wh = state.w / 2F + val hh = state.h / 2F + val lowX = -wh + val lowY = if (state.direction == LineRenderState.LineDirection.BOTTOM_LEFT_TO_TOP_RIGHT) hh else -hh + val highX = wh + val highY = -lowY + val norm = Vector3f(highX - lowX, highY - lowY, 0F).normalize() + buf.addVertex(matrix, lowX, lowY, 0F).setColor(state.color) + .setNormal(matrix, norm) + buf.addVertex(matrix, highX, highY, 0F).setColor(state.color) + .setNormal(matrix, norm) + bufferSource.endBatch() + gr.globalSettingsUniform + .update( + client.window.width, + client.window.height, + client.options.glintStrength().get(), + client.level?.gameTime ?: 0L, + client.deltaTracker, + client.options.menuBackgroundBlurriness + ) + + } + + override fun getTextureLabel(): String? { + return "Firmament Line Renderer" + } +} + + +fun GuiGraphics.drawLine(fromX: Int, fromY: Int, toX: Int, toY: Int, color: Color, lineWidth: Float = 1F) { if (toY < fromY) { drawLine(toX, toY, fromX, fromY, color) return } - RenderSystem.lineWidth(MC.window.scaleFactor.toFloat()) - draw { vertexConsumers -> - val buf = vertexConsumers.getBuffer(RenderInWorldContext.RenderLayers.LINES) - buf.vertex(fromX.toFloat(), fromY.toFloat(), 0F).color(color.color) - .normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F) - buf.vertex(toX.toFloat(), toY.toFloat(), 0F).color(color.color) - .normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F) - } + val originalRect = ScreenRectangle( + minOf(fromX, toX), minOf(toY, fromY), + abs(toX - fromX), abs(toY - fromY) + ).transformAxisAligned(pose()) + val expansionFactor = 3 + val rect = ScreenRectangle( + originalRect.left() - expansionFactor, + originalRect.top() - expansionFactor, + originalRect.width + expansionFactor * 2, + originalRect.height + expansionFactor * 2 + ) + // TODO: expand the bounds so that the thickness of the line can be used + // TODO: fix this up to work with scissorarea + guiRenderState.submitPicturesInPictureState( + LineRenderState( + rect.left(), rect.right(), rect.top(), rect.bottom(), 1F, rect, lineWidth, + originalRect.width, originalRect.height, color.color, + if (fromX < toX) LineRenderState.LineDirection.TOP_LEFT_TO_BOTTOM_RIGHT else LineRenderState.LineDirection.BOTTOM_LEFT_TO_TOP_RIGHT + ) + ) } diff --git a/src/main/kotlin/util/render/DumpTexture.kt b/src/main/kotlin/util/render/DumpTexture.kt new file mode 100644 index 0000000..2ac6a1c --- /dev/null +++ b/src/main/kotlin/util/render/DumpTexture.kt @@ -0,0 +1,34 @@ +package moe.nea.firmament.util.render + +import com.mojang.blaze3d.buffers.GpuBuffer +import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.textures.GpuTexture +import java.io.File +import com.mojang.blaze3d.platform.NativeImage + +fun dumpTexture(gpuTexture: GpuTexture, name: String) { + val w = gpuTexture.getWidth(0) + val h = gpuTexture.getHeight(0) + val buffer = RenderSystem.getDevice() + .createBuffer( + { "Dump Buffer" }, + GpuBuffer.USAGE_COPY_DST or GpuBuffer.USAGE_MAP_READ, + w * h * gpuTexture.getFormat().pixelSize() + ) + val commandEncoder = RenderSystem.getDevice().createCommandEncoder() + commandEncoder.copyTextureToBuffer( + gpuTexture, buffer, 0, { + val nativeImage = NativeImage(w, h, false) + commandEncoder.mapBuffer(buffer, true, false).use { mappedView -> + for (i in 0..<w) { + for (j in 0..<h) { + val color = mappedView.data().getInt((j + i * w) * gpuTexture.format.pixelSize()) + nativeImage.setPixelABGR(j, h - i - 1, color) + } + } + } + buffer.close() + nativeImage.writeToFile(File("$name.png")) + }, 0 + ) +} diff --git a/src/main/kotlin/util/render/FacingThePlayerContext.kt b/src/main/kotlin/util/render/FacingThePlayerContext.kt index daa8da9..dc45939 100644 --- a/src/main/kotlin/util/render/FacingThePlayerContext.kt +++ b/src/main/kotlin/util/render/FacingThePlayerContext.kt @@ -1,21 +1,15 @@ package moe.nea.firmament.util.render -import com.mojang.blaze3d.systems.RenderSystem -import io.github.notenoughupdates.moulconfig.platform.next import org.joml.Matrix4f -import net.minecraft.client.font.TextRenderer -import net.minecraft.client.render.BufferRenderer -import net.minecraft.client.render.GameRenderer -import net.minecraft.client.render.LightmapTextureManager -import net.minecraft.client.render.RenderLayer -import net.minecraft.client.render.Tessellator -import net.minecraft.client.render.VertexConsumer -import net.minecraft.client.render.VertexFormat -import net.minecraft.client.render.VertexFormats -import net.minecraft.text.Text -import net.minecraft.util.Identifier -import net.minecraft.util.math.BlockPos +import util.render.CustomRenderLayers +import net.minecraft.client.gui.Font +import net.minecraft.client.renderer.LightTexture +import net.minecraft.client.renderer.RenderType +import com.mojang.blaze3d.vertex.VertexConsumer +import net.minecraft.network.chat.Component +import net.minecraft.resources.ResourceLocation +import net.minecraft.core.BlockPos import moe.nea.firmament.util.FirmFormatters import moe.nea.firmament.util.MC import moe.nea.firmament.util.assertTrueOr @@ -23,76 +17,76 @@ import moe.nea.firmament.util.assertTrueOr @RenderContextDSL class FacingThePlayerContext(val worldContext: RenderInWorldContext) { val matrixStack by worldContext::matrixStack - fun waypoint(position: BlockPos, label: Text) { + fun waypoint(position: BlockPos, label: Component) { text( label, - Text.literal("§e${FirmFormatters.formatDistance(MC.player?.pos?.distanceTo(position.toCenterPos()) ?: 42069.0)}") + Component.literal("§e${FirmFormatters.formatDistance(MC.player?.position?.distanceTo(position.center) ?: 42069.0)}") ) } fun text( - vararg texts: Text, - verticalAlign: RenderInWorldContext.VerticalAlign = RenderInWorldContext.VerticalAlign.CENTER, - background: Int = 0x70808080, + vararg texts: Component, + verticalAlign: RenderInWorldContext.VerticalAlign = RenderInWorldContext.VerticalAlign.CENTER, + background: Int = 0x70808080, ) { assertTrueOr(texts.isNotEmpty()) { return@text } for ((index, text) in texts.withIndex()) { - worldContext.matrixStack.push() - val width = MC.font.getWidth(text) + worldContext.matrixStack.pushPose() + val width = MC.font.width(text) worldContext.matrixStack.translate(-width / 2F, verticalAlign.align(index, texts.size), 0F) val vertexConsumer: VertexConsumer = - worldContext.vertexConsumers.getBuffer(RenderLayer.getTextBackgroundSeeThrough()) - val matrix4f = worldContext.matrixStack.peek().positionMatrix - vertexConsumer.vertex(matrix4f, -1.0f, -1.0f, 0.0f).color(background) - .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next() - vertexConsumer.vertex(matrix4f, -1.0f, MC.font.fontHeight.toFloat(), 0.0f).color(background) - .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next() - vertexConsumer.vertex(matrix4f, width.toFloat(), MC.font.fontHeight.toFloat(), 0.0f) - .color(background) - .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next() - vertexConsumer.vertex(matrix4f, width.toFloat(), -1.0f, 0.0f).color(background) - .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next() + worldContext.vertexConsumers.getBuffer(RenderType.textBackgroundSeeThrough()) + val matrix4f = worldContext.matrixStack.last().pose() + vertexConsumer.addVertex(matrix4f, -1.0f, -1.0f, 0.0f).setColor(background) + .setLight(LightTexture.FULL_BLOCK) + vertexConsumer.addVertex(matrix4f, -1.0f, MC.font.lineHeight.toFloat(), 0.0f).setColor(background) + .setLight(LightTexture.FULL_BLOCK) + vertexConsumer.addVertex(matrix4f, width.toFloat(), MC.font.lineHeight.toFloat(), 0.0f) + .setColor(background) + .setLight(LightTexture.FULL_BLOCK) + vertexConsumer.addVertex(matrix4f, width.toFloat(), -1.0f, 0.0f).setColor(background) + .setLight(LightTexture.FULL_BLOCK) worldContext.matrixStack.translate(0F, 0F, 0.01F) - MC.font.draw( + MC.font.drawInBatch( text, 0F, 0F, -1, false, - worldContext.matrixStack.peek().positionMatrix, + worldContext.matrixStack.last().pose(), worldContext.vertexConsumers, - TextRenderer.TextLayerType.SEE_THROUGH, + Font.DisplayMode.SEE_THROUGH, 0, - LightmapTextureManager.MAX_LIGHT_COORDINATE + LightTexture.FULL_BRIGHT ) - worldContext.matrixStack.pop() + worldContext.matrixStack.popPose() } } fun texture( - texture: Identifier, width: Int, height: Int, - u1: Float, v1: Float, - u2: Float, v2: Float, + texture: ResourceLocation, width: Int, height: Int, + u1: Float, v1: Float, + u2: Float, v2: Float, ) { - val buf = worldContext.vertexConsumers.getBuffer(RenderLayer.getGuiTexturedOverlay(texture)) + val buf = worldContext.vertexConsumers.getBuffer(CustomRenderLayers.GUI_TEXTURED_NO_DEPTH_TRIS.apply(texture)) // TODO: this is strictly an incorrect render layer val hw = width / 2F val hh = height / 2F - val matrix4f: Matrix4f = worldContext.matrixStack.peek().positionMatrix - buf.vertex(matrix4f, -hw, -hh, 0F) - .color(-1) - .texture(u1, v1).next() - buf.vertex(matrix4f, -hw, +hh, 0F) - .color(-1) - .texture(u1, v2).next() - buf.vertex(matrix4f, +hw, +hh, 0F) - .color(-1) - .texture(u2, v2).next() - buf.vertex(matrix4f, +hw, -hh, 0F) - .color(-1) - .texture(u2, v1).next() - worldContext.vertexConsumers.draw() + val matrix4f: Matrix4f = worldContext.matrixStack.last().pose() + buf.addVertex(matrix4f, -hw, -hh, 0F) + .setColor(-1) + .setUv(u1, v1) + buf.addVertex(matrix4f, -hw, +hh, 0F) + .setColor(-1) + .setUv(u1, v2) + buf.addVertex(matrix4f, +hw, +hh, 0F) + .setColor(-1) + .setUv(u2, v2) + buf.addVertex(matrix4f, +hw, -hh, 0F) + .setColor(-1) + .setUv(u2, v1) + worldContext.vertexConsumers.endBatch() } } diff --git a/src/main/kotlin/util/render/FirmamentShaders.kt b/src/main/kotlin/util/render/FirmamentShaders.kt index ba67dbb..53afdf5 100644 --- a/src/main/kotlin/util/render/FirmamentShaders.kt +++ b/src/main/kotlin/util/render/FirmamentShaders.kt @@ -1,30 +1,12 @@ package moe.nea.firmament.util.render -import net.minecraft.client.gl.Defines -import net.minecraft.client.gl.ShaderProgramKey -import net.minecraft.client.render.RenderPhase -import net.minecraft.client.render.VertexFormat -import net.minecraft.client.render.VertexFormats -import moe.nea.firmament.Firmament import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.DebugInstantiateEvent -import moe.nea.firmament.util.MC object FirmamentShaders { - val shaders = mutableListOf<ShaderProgramKey>() - - private fun shader(name: String, format: VertexFormat, defines: Defines): ShaderProgramKey { - val key = ShaderProgramKey(Firmament.identifier(name), format, defines) - shaders.add(key) - return key - } - - val LINES = RenderPhase.ShaderProgram(shader("core/rendertype_lines", VertexFormats.LINES, Defines.EMPTY)) @Subscribe fun debugLoad(event: DebugInstantiateEvent) { - shaders.forEach { - MC.instance.shaderLoader.getOrCreateProgram(it) - } + // TODO: do i still need to work with shaders like this? } } diff --git a/src/main/kotlin/util/render/LerpUtils.kt b/src/main/kotlin/util/render/LerpUtils.kt index f2c2f25..e7f226c 100644 --- a/src/main/kotlin/util/render/LerpUtils.kt +++ b/src/main/kotlin/util/render/LerpUtils.kt @@ -1,33 +1,40 @@ - package moe.nea.firmament.util.render import me.shedaniel.math.Color +import kotlin.math.absoluteValue -val pi = Math.PI -val tau = Math.PI * 2 +val π = Math.PI +val τ = Math.PI * 2 fun lerpAngle(a: Float, b: Float, progress: Float): Float { - // TODO: there is at least 10 mods to many in here lol - val shortestAngle = ((((b.mod(tau) - a.mod(tau)).mod(tau)) + tau + pi).mod(tau)) - pi - return ((a + (shortestAngle) * progress).mod(tau)).toFloat() + // TODO: there is at least 10 mods to many in here lol + if (((b - a).absoluteValue - π).absoluteValue < 0.0001) { + return lerp(a, b, progress) + } + val shortestAngle = ((((b.mod(τ) - a.mod(τ)).mod(τ)) + τ + π).mod(τ)) - π + return ((a + (shortestAngle) * progress).mod(τ)).toFloat() } +fun wrapAngle(angle: Float): Float = (angle.mod(τ) + τ).mod(τ).toFloat() +fun wrapAngle(angle: Double): Double = (angle.mod(τ) + τ).mod(τ) + fun lerp(a: Float, b: Float, progress: Float): Float { - return a + (b - a) * progress + return a + (b - a) * progress } + fun lerp(a: Int, b: Int, progress: Float): Int { - return (a + (b - a) * progress).toInt() + return (a + (b - a) * progress).toInt() } fun ilerp(a: Float, b: Float, value: Float): Float { - return (value - a) / (b - a) + return (value - a) / (b - a) } fun lerp(a: Color, b: Color, progress: Float): Color { - return Color.ofRGBA( - lerp(a.red, b.red, progress), - lerp(a.green, b.green, progress), - lerp(a.blue, b.blue, progress), - lerp(a.alpha, b.alpha, progress), - ) + return Color.ofRGBA( + lerp(a.red, b.red, progress), + lerp(a.green, b.green, progress), + lerp(a.blue, b.blue, progress), + lerp(a.alpha, b.alpha, progress), + ) } diff --git a/src/main/kotlin/util/render/MultiSpecialGuiRenderState.kt b/src/main/kotlin/util/render/MultiSpecialGuiRenderState.kt new file mode 100644 index 0000000..a58ffdc --- /dev/null +++ b/src/main/kotlin/util/render/MultiSpecialGuiRenderState.kt @@ -0,0 +1,47 @@ +package moe.nea.firmament.util.render + +import net.minecraft.client.gui.navigation.ScreenRectangle +import net.minecraft.client.gui.render.pip.PictureInPictureRenderer +import net.minecraft.client.gui.render.state.GuiRenderState +import net.minecraft.client.gui.render.state.pip.PictureInPictureRenderState +import net.minecraft.client.renderer.MultiBufferSource + +abstract class MultiSpecialGuiRenderState : PictureInPictureRenderState { + // I wish i had manifolds @Self type here... Maybe i should switch to java after all :( + abstract fun createRenderer(vertexConsumers: MultiBufferSource.BufferSource): MultiSpecialGuiRenderer<out MultiSpecialGuiRenderState> + abstract val x1: Int + abstract val x2: Int + abstract val y1: Int + abstract val y2: Int + abstract val scale: Float + abstract val bounds: ScreenRectangle? + abstract val scissorArea: ScreenRectangle? + override fun x0(): Int = x1 + + override fun x1(): Int = x2 + + override fun y0(): Int = y1 + + override fun y1(): Int = y2 + + override fun scale(): Float = scale + + override fun scissorArea(): ScreenRectangle? = scissorArea + + override fun bounds(): ScreenRectangle? = bounds + +} + +abstract class MultiSpecialGuiRenderer<T : MultiSpecialGuiRenderState>( + vertexConsumers: MultiBufferSource.BufferSource +) : PictureInPictureRenderer<T>(vertexConsumers) { + var wasUsedThisFrame = false + fun consumeRender(): Boolean { + return wasUsedThisFrame.also { wasUsedThisFrame = false } + } + + override fun blitTexture(element: T, state: GuiRenderState) { + wasUsedThisFrame = true + super.blitTexture(element, state) + } +} diff --git a/src/main/kotlin/util/render/RenderCircleProgress.kt b/src/main/kotlin/util/render/RenderCircleProgress.kt index 805633c..acd0210 100644 --- a/src/main/kotlin/util/render/RenderCircleProgress.kt +++ b/src/main/kotlin/util/render/RenderCircleProgress.kt @@ -1,93 +1,166 @@ package moe.nea.firmament.util.render -import com.mojang.blaze3d.systems.RenderSystem -import io.github.notenoughupdates.moulconfig.platform.next -import org.joml.Matrix4f -import org.joml.Vector2f -import kotlin.math.atan2 -import kotlin.math.tan -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.BufferRenderer -import net.minecraft.client.render.RenderLayer -import net.minecraft.client.render.RenderPhase -import net.minecraft.client.render.Tessellator -import net.minecraft.client.render.VertexFormat.DrawMode -import net.minecraft.client.render.VertexFormats -import net.minecraft.util.Identifier +import com.mojang.blaze3d.vertex.VertexFormat +import util.render.CustomRenderLayers +import net.minecraft.client.gui.GuiGraphics +import net.minecraft.client.gui.navigation.ScreenRectangle +import com.mojang.blaze3d.vertex.BufferBuilder +import net.minecraft.client.renderer.RenderType +import net.minecraft.client.renderer.MultiBufferSource +import com.mojang.blaze3d.vertex.ByteBufferBuilder +import com.mojang.blaze3d.vertex.PoseStack +import net.minecraft.resources.ResourceLocation +import moe.nea.firmament.util.MC +import moe.nea.firmament.util.collections.nonNegligibleSubSectionsAlignedWith +import moe.nea.firmament.util.math.Projections +import moe.nea.firmament.util.mc.CustomRenderPassHelper object RenderCircleProgress { - fun renderCircle( - drawContext: DrawContext, - texture: Identifier, - progress: Float, - u1: Float, - u2: Float, - v1: Float, - v2: Float, - ) { - RenderSystem.enableBlend() - drawContext.draw { - val bufferBuilder = it.getBuffer(GuiRenderLayers.GUI_TEXTURED_TRIS.apply(texture)) - val matrix: Matrix4f = drawContext.matrices.peek().positionMatrix - - val corners = listOf( - Vector2f(0F, -1F), - Vector2f(1F, -1F), - Vector2f(1F, 0F), - Vector2f(1F, 1F), - Vector2f(0F, 1F), - Vector2f(-1F, 1F), - Vector2f(-1F, 0F), - Vector2f(-1F, -1F), - ) - for (i in (0 until 8)) { - if (progress < i / 8F) { - break + data class State( + override val x1: Int, + override val x2: Int, + override val y1: Int, + override val y2: Int, + val layer: RenderType.CompositeRenderType, + val u1: Float, + val u2: Float, + val v1: Float, + val v2: Float, + val angleRadians: ClosedFloatingPointRange<Float>, + val color: Int, + val innerCutoutRadius: Float, + override val scale: Float, + override val bounds: ScreenRectangle?, + override val scissorArea: ScreenRectangle?, + ) : MultiSpecialGuiRenderState() { + override fun createRenderer(vertexConsumers: MultiBufferSource.BufferSource): MultiSpecialGuiRenderer<out MultiSpecialGuiRenderState> { + return Renderer(vertexConsumers) + } + } + + class Renderer(vertexConsumers: MultiBufferSource.BufferSource) : + MultiSpecialGuiRenderer<State>(vertexConsumers) { + override fun renderToTexture( + state: State, + matrices: PoseStack + ) { + matrices.pushPose() + matrices.translate(0F, -1F, 0F) + val sections = state.angleRadians.nonNegligibleSubSectionsAlignedWith((τ / 8f).toFloat()) + .zipWithNext().toList() + val u1 = state.u1 + val u2 = state.u2 + val v1 = state.v1 + val v2 = state.v2 + val color = state.color + val matrix = matrices.last().pose() + ByteBufferBuilder(state.layer.format().vertexSize * sections.size * 3).use { allocator -> + + val bufferBuilder = BufferBuilder(allocator, VertexFormat.Mode.TRIANGLES, state.layer.format()) + + for ((sectionStart, sectionEnd) in sections) { + val firstPoint = Projections.Two.projectAngleOntoUnitBox(sectionStart.toDouble()) + val secondPoint = Projections.Two.projectAngleOntoUnitBox(sectionEnd.toDouble()) + fun ilerp(f: Float): Float = + ilerp(-1f, 1f, f) + + bufferBuilder + .addVertex(matrix, secondPoint.x, secondPoint.y, 0F) + .setUv(lerp(u1, u2, ilerp(secondPoint.x)), lerp(v1, v2, ilerp(secondPoint.y))) + .setColor(color) + + bufferBuilder + .addVertex(matrix, firstPoint.x, firstPoint.y, 0F) + .setUv(lerp(u1, u2, ilerp(firstPoint.x)), lerp(v1, v2, ilerp(firstPoint.y))) + .setColor(color) + + bufferBuilder + .addVertex(matrix, 0F, 0F, 0F) + .setUv(lerp(u1, u2, ilerp(0F)), lerp(v1, v2, ilerp(0F))) + .setColor(color) + } - val second = corners[(i + 1) % 8] - val first = corners[i] - if (progress <= (i + 1) / 8F) { - val internalProgress = 1 - (progress - i / 8F) * 8F - val angle = lerpAngle( - atan2(second.y, second.x), - atan2(first.y, first.x), - internalProgress - ) - if (angle < tau / 8 || angle >= tau * 7 / 8) { - second.set(1F, tan(angle)) - } else if (angle < tau * 3 / 8) { - second.set(1 / tan(angle), 1F) - } else if (angle < tau * 5 / 8) { - second.set(-1F, -tan(angle)) - } else { - second.set(-1 / tan(angle), -1F) + + bufferBuilder.buildOrThrow().use { buffer -> + if (state.innerCutoutRadius <= 0) { + state.layer.draw(buffer) + return + } + CustomRenderPassHelper( + { "RenderCircleProgress" }, + VertexFormat.Mode.TRIANGLES, + state.layer.format(), + MC.instance.mainRenderTarget, + false, + ).use { renderPass -> + renderPass.uploadVertices(buffer) + renderPass.setAllDefaultUniforms() + renderPass.setPipeline(state.layer.renderPipeline) + renderPass.setUniform("CutoutRadius", 4) { + it.putFloat(state.innerCutoutRadius) + } + renderPass.draw() } } - - fun ilerp(f: Float): Float = - ilerp(-1f, 1f, f) - - bufferBuilder - .vertex(matrix, second.x, second.y, 0F) - .texture(lerp(u1, u2, ilerp(second.x)), lerp(v1, v2, ilerp(second.y))) - .color(-1) - .next() - bufferBuilder - .vertex(matrix, first.x, first.y, 0F) - .texture(lerp(u1, u2, ilerp(first.x)), lerp(v1, v2, ilerp(first.y))) - .color(-1) - .next() - bufferBuilder - .vertex(matrix, 0F, 0F, 0F) - .texture(lerp(u1, u2, ilerp(0F)), lerp(v1, v2, ilerp(0F))) - .color(-1) - .next() } + matrices.popPose() + } + + override fun getRenderStateClass(): Class<State> { + return State::class.java + } + + override fun getTextureLabel(): String { + return "Firmament Circle" } - RenderSystem.disableBlend() } + fun renderCircularSlice( + drawContext: GuiGraphics, + layer: RenderType.CompositeRenderType, + u1: Float, + u2: Float, + v1: Float, + v2: Float, + angleRadians: ClosedFloatingPointRange<Float>, + color: Int = -1, + innerCutoutRadius: Float = 0F + ) { + val screenRect = ScreenRectangle(-1, -1, 2, 2).transformAxisAligned(drawContext.pose()) + drawContext.guiRenderState.submitPicturesInPictureState( + State( + screenRect.left(), screenRect.right(), + screenRect.top(), screenRect.bottom(), + layer, + u1, u2, v1, v2, + angleRadians, + color, + innerCutoutRadius, + screenRect.width / 2F, + screenRect, + null + ) + ) + } + fun renderCircle( + drawContext: GuiGraphics, + texture: ResourceLocation, + progress: Float, + u1: Float, + u2: Float, + v1: Float, + v2: Float, + color: Int = -1 + ) { + renderCircularSlice( + drawContext, + CustomRenderLayers.GUI_TEXTURED_NO_DEPTH_TRIS.apply(texture), + u1, u2, v1, v2, + (-τ / 4).toFloat()..(progress * τ - τ / 4).toFloat(), + color = color + ) + } } diff --git a/src/main/kotlin/util/render/RenderInWorldContext.kt b/src/main/kotlin/util/render/RenderInWorldContext.kt index bb58200..f6877c8 100644 --- a/src/main/kotlin/util/render/RenderInWorldContext.kt +++ b/src/main/kotlin/util/render/RenderInWorldContext.kt @@ -1,89 +1,80 @@ package moe.nea.firmament.util.render import com.mojang.blaze3d.systems.RenderSystem -import io.github.notenoughupdates.moulconfig.platform.next -import java.lang.Math.pow import org.joml.Matrix4f import org.joml.Vector3f -import net.minecraft.client.gl.VertexBuffer -import net.minecraft.client.render.Camera -import net.minecraft.client.render.RenderLayer -import net.minecraft.client.render.RenderPhase -import net.minecraft.client.render.RenderTickCounter -import net.minecraft.client.render.Tessellator -import net.minecraft.client.render.VertexConsumer -import net.minecraft.client.render.VertexConsumerProvider -import net.minecraft.client.render.VertexFormat -import net.minecraft.client.render.VertexFormats -import net.minecraft.client.texture.Sprite -import net.minecraft.client.util.math.MatrixStack -import net.minecraft.text.Text -import net.minecraft.util.Identifier -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Vec3d +import util.render.CustomRenderLayers +import kotlin.math.pow +import net.minecraft.client.Camera +import net.minecraft.client.renderer.RenderType +import net.minecraft.client.renderer.ItemBlockRenderTypes +import net.minecraft.client.DeltaTracker +import net.minecraft.client.renderer.Sheets +import com.mojang.blaze3d.vertex.VertexConsumer +import net.minecraft.client.renderer.MultiBufferSource +import net.minecraft.client.renderer.state.CameraRenderState +import net.minecraft.client.renderer.texture.TextureAtlasSprite +import com.mojang.blaze3d.vertex.PoseStack +import net.minecraft.network.chat.Component +import net.minecraft.resources.ResourceLocation +import net.minecraft.core.BlockPos +import net.minecraft.world.phys.AABB +import net.minecraft.world.phys.Vec3 import moe.nea.firmament.events.WorldRenderLastEvent import moe.nea.firmament.util.FirmFormatters import moe.nea.firmament.util.MC @RenderContextDSL class RenderInWorldContext private constructor( - private val tesselator: Tessellator, - val matrixStack: MatrixStack, - private val camera: Camera, - private val tickCounter: RenderTickCounter, - val vertexConsumers: VertexConsumerProvider.Immediate, + val matrixStack: PoseStack, + private val camera: CameraRenderState, + val vertexConsumers: MultiBufferSource.BufferSource, ) { - - object RenderLayers { - val TRANSLUCENT_TRIS = RenderLayer.of("firmament_translucent_tris", - VertexFormats.POSITION_COLOR, - VertexFormat.DrawMode.TRIANGLES, - RenderLayer.CUTOUT_BUFFER_SIZE, - false, true, - RenderLayer.MultiPhaseParameters.builder() - .depthTest(RenderPhase.ALWAYS_DEPTH_TEST) - .transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY) - .program(RenderPhase.POSITION_COLOR_PROGRAM) - .build(false)) - val LINES = RenderLayer.of("firmament_rendertype_lines", - VertexFormats.LINES, - VertexFormat.DrawMode.LINES, - RenderLayer.CUTOUT_BUFFER_SIZE, - false, false, // do we need translucent? i dont think so - RenderLayer.MultiPhaseParameters.builder() - .depthTest(RenderPhase.ALWAYS_DEPTH_TEST) - .program(FirmamentShaders.LINES) - .build(false) - ) - val COLORED_QUADS = RenderLayer.of( - "firmament_quads", - VertexFormats.POSITION_COLOR, - VertexFormat.DrawMode.QUADS, - RenderLayer.CUTOUT_BUFFER_SIZE, - false, true, - RenderLayer.MultiPhaseParameters.builder() - .depthTest(RenderPhase.ALWAYS_DEPTH_TEST) - .program(RenderPhase.POSITION_COLOR_PROGRAM) - .transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY) - .build(false) - ) - } - - @Deprecated("stateful color management is no longer a thing") - fun color(color: me.shedaniel.math.Color) { - color(color.red / 255F, color.green / 255f, color.blue / 255f, color.alpha / 255f) + fun block(blockPos: BlockPos, color: Int) { + matrixStack.pushPose() + matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat()) + buildCube(matrixStack.last().pose(), vertexConsumers.getBuffer(CustomRenderLayers.COLORED_QUADS), color) + matrixStack.popPose() } - @Deprecated("stateful color management is no longer a thing") - fun color(red: Float, green: Float, blue: Float, alpha: Float) { - RenderSystem.setShaderColor(red, green, blue, alpha) + fun box(aabb: AABB, color: Int) { + matrixStack.pushPose() + matrixStack.translate(aabb.minX, aabb.minY, aabb.minZ) + matrixStack.scale(aabb.xsize.toFloat(), aabb.ysize.toFloat(), aabb.zsize.toFloat()) + buildCube(matrixStack.last().pose(), vertexConsumers.getBuffer(CustomRenderLayers.COLORED_QUADS), color) + matrixStack.popPose() } - fun block(blockPos: BlockPos, color: Int) { - matrixStack.push() - matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat()) - buildCube(matrixStack.peek().positionMatrix, vertexConsumers.getBuffer(RenderLayers.COLORED_QUADS), color) - matrixStack.pop() + fun sharedVoxelSurface(blocks: Set<BlockPos>, color: Int) { + val m = BlockPos.MutableBlockPos() + val l = vertexConsumers.getBuffer(CustomRenderLayers.COLORED_QUADS) + blocks.forEach { + matrixStack.pushPose() + matrixStack.translate(it.x.toFloat(), it.y.toFloat(), it.z.toFloat()) + val p = matrixStack.last().pose() + m.set(it) + if (m.setX(it.x + 1) !in blocks) { + buildFaceXP(p, l, color) + } + if (m.setX(it.x - 1) !in blocks) { + buildFaceXN(p, l, color) + } + m.set(it) + if (m.setY(it.y + 1) !in blocks) { + buildFaceYP(p, l, color) + } + if (m.setY(it.y - 1) !in blocks) { + buildFaceYN(p, l, color) + } + m.set(it) + if (m.setZ(it.z + 1) !in blocks) { + buildFaceZP(p, l, color) + } + if (m.setZ(it.z - 1) !in blocks) { + buildFaceZN(p, l, color) + } + matrixStack.popPose() + } } enum class VerticalAlign { @@ -91,46 +82,46 @@ class RenderInWorldContext private constructor( fun align(index: Int, count: Int): Float { return when (this) { - CENTER -> (index - count / 2F) * (1 + MC.font.fontHeight.toFloat()) - BOTTOM -> (index - count) * (1 + MC.font.fontHeight.toFloat()) - TOP -> (index) * (1 + MC.font.fontHeight.toFloat()) + CENTER -> (index - count / 2F) * (1 + MC.font.lineHeight.toFloat()) + BOTTOM -> (index - count) * (1 + MC.font.lineHeight.toFloat()) + TOP -> (index) * (1 + MC.font.lineHeight.toFloat()) } } } - fun waypoint(position: BlockPos, vararg label: Text) { + fun waypoint(position: BlockPos, vararg label: Component) { text( - position.toCenterPos(), + position.center, *label, - Text.literal("§e${FirmFormatters.formatDistance(MC.player?.pos?.distanceTo(position.toCenterPos()) ?: 42069.0)}"), + Component.literal("§e${FirmFormatters.formatDistance(MC.player?.position?.distanceTo(position.center) ?: 42069.0)}"), background = 0xAA202020.toInt() ) } - fun withFacingThePlayer(position: Vec3d, block: FacingThePlayerContext.() -> Unit) { - matrixStack.push() + fun withFacingThePlayer(position: Vec3, block: FacingThePlayerContext.() -> Unit) { + matrixStack.pushPose() matrixStack.translate(position.x, position.y, position.z) val actualCameraDistance = position.distanceTo(camera.pos) val distanceToMoveTowardsCamera = if (actualCameraDistance < 10) 0.0 else -(actualCameraDistance - 10.0) - val vec = position.subtract(camera.pos).multiply(distanceToMoveTowardsCamera / actualCameraDistance) + val vec = position.subtract(camera.pos).scale(distanceToMoveTowardsCamera / actualCameraDistance) matrixStack.translate(vec.x, vec.y, vec.z) - matrixStack.multiply(camera.rotation) + matrixStack.mulPose(camera.orientation) matrixStack.scale(0.025F, -0.025F, 1F) FacingThePlayerContext(this).run(block) - matrixStack.pop() - vertexConsumers.drawCurrentLayer() + matrixStack.popPose() + vertexConsumers.endLastBatch() } - fun sprite(position: Vec3d, sprite: Sprite, width: Int, height: Int) { + fun sprite(position: Vec3, sprite: TextureAtlasSprite, width: Int, height: Int) { texture( - position, sprite.atlasId, width, height, sprite.minU, sprite.minV, sprite.maxU, sprite.maxV + position, sprite.atlasLocation(), width, height, sprite.u0, sprite.v0, sprite.u1, sprite.v1 ) } fun texture( - position: Vec3d, texture: Identifier, width: Int, height: Int, + position: Vec3, texture: ResourceLocation, width: Int, height: Int, u1: Float, v1: Float, u2: Float, v2: Float, ) { @@ -140,8 +131,8 @@ class RenderInWorldContext private constructor( } fun text( - position: Vec3d, - vararg texts: Text, + position: Vec3, + vararg texts: Component, verticalAlign: VerticalAlign = VerticalAlign.CENTER, background: Int = 0x70808080 ) { @@ -150,42 +141,50 @@ class RenderInWorldContext private constructor( } } - fun tinyBlock(vec3d: Vec3d, size: Float, color: Int) { - matrixStack.push() + fun tinyBlock(vec3d: Vec3, size: Float, color: Int) { + matrixStack.pushPose() matrixStack.translate(vec3d.x, vec3d.y, vec3d.z) matrixStack.scale(size, size, size) matrixStack.translate(-.5, -.5, -.5) - buildCube(matrixStack.peek().positionMatrix, vertexConsumers.getBuffer(RenderLayers.COLORED_QUADS), color) - matrixStack.pop() - vertexConsumers.draw() + buildCube(matrixStack.last().pose(), vertexConsumers.getBuffer(CustomRenderLayers.COLORED_QUADS), color) + matrixStack.popPose() + vertexConsumers.endBatch() } fun wireframeCube(blockPos: BlockPos, lineWidth: Float = 10F) { - val buf = vertexConsumers.getBuffer(RenderLayer.LINES) - matrixStack.push() + val buf = vertexConsumers.getBuffer(RenderType.LINES) + matrixStack.pushPose() + // TODO: add color arg to this // TODO: this does not render through blocks (or water layers) anymore - RenderSystem.lineWidth(lineWidth / pow(camera.pos.squaredDistanceTo(blockPos.toCenterPos()), 0.25).toFloat()) - matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat()) - buildWireFrameCube(matrixStack.peek(), buf) - matrixStack.pop() - vertexConsumers.draw() + RenderSystem.lineWidth(lineWidth / camera.pos.distanceToSqr(blockPos.center).pow(0.25).toFloat()) + val offset = 1 / 512F + matrixStack.translate( + blockPos.x.toFloat() - offset, + blockPos.y.toFloat() - offset, + blockPos.z.toFloat() - offset + ) + val scale = 1 + 2 * offset + matrixStack.scale(scale, scale, scale) + + buildWireFrameCube(matrixStack.last(), buf) + matrixStack.popPose() + vertexConsumers.endBatch() } - fun line(vararg points: Vec3d, lineWidth: Float = 10F) { - line(points.toList(), lineWidth) + fun line(vararg points: Vec3, color: Int, lineWidth: Float = 10F) { + line(points.toList(), color, lineWidth) } - fun tracer(toWhere: Vec3d, lineWidth: Float = 3f) { - val cameraForward = Vector3f(0f, 0f, -1f).rotate(camera.rotation) - line(camera.pos.add(Vec3d(cameraForward)), toWhere, lineWidth = lineWidth) + fun tracer(toWhere: Vec3, color: Int, lineWidth: Float = 3f) { + val cameraForward = Vector3f(0f, 0f, -1f).rotate(camera.orientation) + line(camera.pos.add(Vec3(cameraForward)), toWhere, color = color, lineWidth = lineWidth) } - fun line(points: List<Vec3d>, lineWidth: Float = 10F) { + fun line(points: List<Vec3>, color: Int, lineWidth: Float = 10F) { RenderSystem.lineWidth(lineWidth) - // TODO: replace with renderlayers - val buffer = tesselator.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES) + val buffer = vertexConsumers.getBuffer(CustomRenderLayers.LINES) - val matrix = matrixStack.peek() + val matrix = matrixStack.last() var lastNormal: Vector3f? = null points.zipWithNext().forEach { (a, b) -> val normal = Vector3f(b.x.toFloat(), b.y.toFloat(), b.z.toFloat()) @@ -193,23 +192,22 @@ class RenderInWorldContext private constructor( .normalize() val lastNormal0 = lastNormal ?: normal lastNormal = normal - buffer.vertex(matrix.positionMatrix, a.x.toFloat(), a.y.toFloat(), a.z.toFloat()) - .color(-1) - .normal(matrix, lastNormal0.x, lastNormal0.y, lastNormal0.z) - .next() - buffer.vertex(matrix.positionMatrix, b.x.toFloat(), b.y.toFloat(), b.z.toFloat()) - .color(-1) - .normal(matrix, normal.x, normal.y, normal.z) - .next() + buffer.addVertex(matrix.pose(), a.x.toFloat(), a.y.toFloat(), a.z.toFloat()) + .setColor(color) + .setNormal(matrix, lastNormal0.x, lastNormal0.y, lastNormal0.z) + + buffer.addVertex(matrix.pose(), b.x.toFloat(), b.y.toFloat(), b.z.toFloat()) + .setColor(color) + .setNormal(matrix, normal.x, normal.y, normal.z) + } - RenderLayers.LINES.draw(buffer.end()) } // TODO: put the favourite icons in front of items again companion object { private fun doLine( - matrix: MatrixStack.Entry, + matrix: PoseStack.Pose, buf: VertexConsumer, i: Float, j: Float, @@ -221,18 +219,18 @@ class RenderInWorldContext private constructor( val normal = Vector3f(x, y, z) .sub(i, j, k) .normalize() - buf.vertex(matrix.positionMatrix, i, j, k) - .normal(matrix, normal.x, normal.y, normal.z) - .color(-1) - .next() - buf.vertex(matrix.positionMatrix, x, y, z) - .normal(matrix, normal.x, normal.y, normal.z) - .color(-1) - .next() + buf.addVertex(matrix.pose(), i, j, k) + .setNormal(matrix, normal.x, normal.y, normal.z) + .setColor(-1) + + buf.addVertex(matrix.pose(), x, y, z) + .setNormal(matrix, normal.x, normal.y, normal.z) + .setColor(-1) + } - private fun buildWireFrameCube(matrix: MatrixStack.Entry, buf: VertexConsumer) { + private fun buildWireFrameCube(matrix: PoseStack.Pose, buf: VertexConsumer) { for (i in 0..1) { for (j in 0..1) { val i = i.toFloat() @@ -244,68 +242,72 @@ class RenderInWorldContext private constructor( } } - private fun buildCube(matrix: Matrix4f, buf: VertexConsumer, color: Int) { - // Y- - buf.vertex(matrix, 0F, 0F, 0F).color(color) - buf.vertex(matrix, 0F, 0F, 1F).color(color) - buf.vertex(matrix, 1F, 0F, 1F).color(color) - buf.vertex(matrix, 1F, 0F, 0F).color(color) - // Y+ - buf.vertex(matrix, 0F, 1F, 0F).color(color) - buf.vertex(matrix, 1F, 1F, 0F).color(color) - buf.vertex(matrix, 1F, 1F, 1F).color(color) - buf.vertex(matrix, 0F, 1F, 1F).color(color) - // X- - buf.vertex(matrix, 0F, 0F, 0F).color(color) - buf.vertex(matrix, 0F, 0F, 1F).color(color) - buf.vertex(matrix, 0F, 1F, 1F).color(color) - buf.vertex(matrix, 0F, 1F, 0F).color(color) - // X+ - buf.vertex(matrix, 1F, 0F, 0F).color(color) - buf.vertex(matrix, 1F, 1F, 0F).color(color) - buf.vertex(matrix, 1F, 1F, 1F).color(color) - buf.vertex(matrix, 1F, 0F, 1F).color(color) - // Z- - buf.vertex(matrix, 0F, 0F, 0F).color(color) - buf.vertex(matrix, 1F, 0F, 0F).color(color) - buf.vertex(matrix, 1F, 1F, 0F).color(color) - buf.vertex(matrix, 0F, 1F, 0F).color(color) - // Z+ - buf.vertex(matrix, 0F, 0F, 1F).color(color) - buf.vertex(matrix, 0F, 1F, 1F).color(color) - buf.vertex(matrix, 1F, 1F, 1F).color(color) - buf.vertex(matrix, 1F, 0F, 1F).color(color) + private fun buildFaceZP(matrix: Matrix4f, buf: VertexConsumer, rgba: Int) { + buf.addVertex(matrix, 0F, 0F, 1F).setColor(rgba) + buf.addVertex(matrix, 0F, 1F, 1F).setColor(rgba) + buf.addVertex(matrix, 1F, 1F, 1F).setColor(rgba) + buf.addVertex(matrix, 1F, 0F, 1F).setColor(rgba) } + private fun buildFaceZN(matrix: Matrix4f, buf: VertexConsumer, rgba: Int) { + buf.addVertex(matrix, 0F, 0F, 0F).setColor(rgba) + buf.addVertex(matrix, 1F, 0F, 0F).setColor(rgba) + buf.addVertex(matrix, 1F, 1F, 0F).setColor(rgba) + buf.addVertex(matrix, 0F, 1F, 0F).setColor(rgba) + } + + private fun buildFaceXP(matrix: Matrix4f, buf: VertexConsumer, rgba: Int) { + buf.addVertex(matrix, 1F, 0F, 0F).setColor(rgba) + buf.addVertex(matrix, 1F, 1F, 0F).setColor(rgba) + buf.addVertex(matrix, 1F, 1F, 1F).setColor(rgba) + buf.addVertex(matrix, 1F, 0F, 1F).setColor(rgba) + } + + private fun buildFaceXN(matrix: Matrix4f, buf: VertexConsumer, rgba: Int) { + buf.addVertex(matrix, 0F, 0F, 0F).setColor(rgba) + buf.addVertex(matrix, 0F, 0F, 1F).setColor(rgba) + buf.addVertex(matrix, 0F, 1F, 1F).setColor(rgba) + buf.addVertex(matrix, 0F, 1F, 0F).setColor(rgba) + } + + private fun buildFaceYN(matrix: Matrix4f, buf: VertexConsumer, rgba: Int) { + buf.addVertex(matrix, 0F, 0F, 0F).setColor(rgba) + buf.addVertex(matrix, 0F, 0F, 1F).setColor(rgba) + buf.addVertex(matrix, 1F, 0F, 1F).setColor(rgba) + buf.addVertex(matrix, 1F, 0F, 0F).setColor(rgba) + } + + private fun buildFaceYP(matrix: Matrix4f, buf: VertexConsumer, rgba: Int) { + buf.addVertex(matrix, 0F, 1F, 0F).setColor(rgba) + buf.addVertex(matrix, 1F, 1F, 0F).setColor(rgba) + buf.addVertex(matrix, 1F, 1F, 1F).setColor(rgba) + buf.addVertex(matrix, 0F, 1F, 1F).setColor(rgba) + } + + private fun buildCube(matrix4f: Matrix4f, buf: VertexConsumer, rgba: Int) { + buildFaceXP(matrix4f, buf, rgba) + buildFaceXN(matrix4f, buf, rgba) + buildFaceYP(matrix4f, buf, rgba) + buildFaceYN(matrix4f, buf, rgba) + buildFaceZP(matrix4f, buf, rgba) + buildFaceZN(matrix4f, buf, rgba) + } fun renderInWorld(event: WorldRenderLastEvent, block: RenderInWorldContext. () -> Unit) { - // TODO: there should be *no more global state*. the only thing we should be doing is render layers. that includes settings like culling, blending, shader color, and depth testing - // For now i will let these functions remain, but this needs to go before i do a full (non-beta) release - RenderSystem.disableDepthTest() - RenderSystem.enableBlend() - RenderSystem.defaultBlendFunc() - RenderSystem.disableCull() - - event.matrices.push() + + event.matrices.pushPose() event.matrices.translate(-event.camera.pos.x, -event.camera.pos.y, -event.camera.pos.z) val ctx = RenderInWorldContext( - RenderSystem.renderThreadTesselator(), event.matrices, event.camera, - event.tickCounter, event.vertexConsumers ) block(ctx) - event.matrices.pop() - event.vertexConsumers.draw() - RenderSystem.setShaderColor(1F, 1F, 1F, 1F) - VertexBuffer.unbind() - RenderSystem.enableDepthTest() - RenderSystem.enableCull() - RenderSystem.disableBlend() + event.matrices.popPose() + event.vertexConsumers.endBatch() } } } diff --git a/src/main/kotlin/util/render/TintedOverlayTexture.kt b/src/main/kotlin/util/render/TintedOverlayTexture.kt index a02eccc..6513574 100644 --- a/src/main/kotlin/util/render/TintedOverlayTexture.kt +++ b/src/main/kotlin/util/render/TintedOverlayTexture.kt @@ -1,10 +1,8 @@ package moe.nea.firmament.util.render -import com.mojang.blaze3d.platform.GlConst -import com.mojang.blaze3d.systems.RenderSystem import me.shedaniel.math.Color -import net.minecraft.client.render.OverlayTexture -import net.minecraft.util.math.ColorHelper +import net.minecraft.client.renderer.texture.OverlayTexture +import net.minecraft.util.ARGB import moe.nea.firmament.util.ErrorUtil class TintedOverlayTexture : OverlayTexture() { @@ -14,31 +12,24 @@ class TintedOverlayTexture : OverlayTexture() { private var lastColor: Color? = null fun setColor(color: Color): TintedOverlayTexture { - val image = ErrorUtil.notNullOr(texture.image, "Disposed TintedOverlayTexture written to") { return this } + val image = ErrorUtil.notNullOr(texture.pixels, "Disposed TintedOverlayTexture written to") { return this } if (color == lastColor) return this lastColor = color for (i in 0..<size) { for (j in 0..<size) { if (i < 8) { - image.setColorArgb(j, i, 0xB2FF0000.toInt()) + image.setPixel(j, i, 0xB2FF0000.toInt()) } else { val k = ((1F - j / 15F * 0.75F) * 255F).toInt() - image.setColorArgb(j, i, ColorHelper.withAlpha(k, color.color)) + image.setPixel(j, i, ARGB.color(k, color.color)) } } } - RenderSystem.activeTexture(GlConst.GL_TEXTURE1) - texture.bindTexture() texture.setFilter(false, false) texture.setClamp(true) - image.upload(0, - 0, 0, - 0, 0, - image.width, image.height, - false) - RenderSystem.activeTexture(GlConst.GL_TEXTURE0) + texture.upload() return this } } diff --git a/src/main/kotlin/util/render/TranslatedScissors.kt b/src/main/kotlin/util/render/TranslatedScissors.kt index 8f8bdcf..e337cf0 100644 --- a/src/main/kotlin/util/render/TranslatedScissors.kt +++ b/src/main/kotlin/util/render/TranslatedScissors.kt @@ -1,26 +1,31 @@ - package moe.nea.firmament.util.render -import org.joml.Matrix4f -import org.joml.Vector4f -import net.minecraft.client.gui.DrawContext +import me.shedaniel.math.Rectangle +import org.joml.Matrix3x2f +import org.joml.Vector3f +import net.minecraft.client.gui.GuiGraphics + +fun GuiGraphics.enableScissorWithTranslation(rect: Rectangle) { + enableScissor(rect.minX, rect.minY, rect.maxX, rect.maxY) +} -fun DrawContext.enableScissorWithTranslation(x1: Float, y1: Float, x2: Float, y2: Float) { - enableScissor(x1.toInt(), y1.toInt(), x2.toInt(), y2.toInt()) +fun GuiGraphics.enableScissorWithTranslation(x1: Float, y1: Float, x2: Float, y2: Float) { + enableScissor(x1.toInt(), y1.toInt(), x2.toInt(), y2.toInt()) } -fun DrawContext.enableScissorWithoutTranslation(x1: Float, y1: Float, x2: Float, y2: Float) { - val pMat = matrices.peek().positionMatrix.invert(Matrix4f()) - val target = Vector4f() - target.set(x1, y1, 0f, 1f) - target.mul(pMat) - val scissorX1 = target.x - val scissorY1 = target.y +fun GuiGraphics.enableScissorWithoutTranslation(x1: Float, y1: Float, x2: Float, y2: Float) { + val pMat = Matrix3x2f(pose()).invert() + var target = Vector3f() + + target.set(x1, y1, 1F) + target.mul(pMat) + val scissorX1 = target.x + val scissorY1 = target.y - target.set(x2, y2, 0f, 1f) - target.mul(pMat) - val scissorX2 = target.x - val scissorY2 = target.y + target.set(x2, y2, 1F) + target.mul(pMat) + val scissorX2 = target.x + val scissorY2 = target.y - enableScissor(scissorX1.toInt(), scissorY1.toInt(), scissorX2.toInt(), scissorY2.toInt()) + enableScissor(scissorX1.toInt(), scissorY1.toInt(), scissorX2.toInt(), scissorY2.toInt()) } |
