diff options
Diffstat (limited to 'src/main/kotlin/util/render')
-rw-r--r-- | src/main/kotlin/util/render/FacingThePlayerContext.kt | 101 | ||||
-rw-r--r-- | src/main/kotlin/util/render/LerpUtils.kt | 33 | ||||
-rw-r--r-- | src/main/kotlin/util/render/RenderCircleProgress.kt | 95 | ||||
-rw-r--r-- | src/main/kotlin/util/render/RenderContextDSL.kt | 6 | ||||
-rw-r--r-- | src/main/kotlin/util/render/RenderInWorldContext.kt | 294 | ||||
-rw-r--r-- | src/main/kotlin/util/render/TranslatedScissors.kt | 22 |
6 files changed, 551 insertions, 0 deletions
diff --git a/src/main/kotlin/util/render/FacingThePlayerContext.kt b/src/main/kotlin/util/render/FacingThePlayerContext.kt new file mode 100644 index 0000000..eb37e35 --- /dev/null +++ b/src/main/kotlin/util/render/FacingThePlayerContext.kt @@ -0,0 +1,101 @@ + +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 moe.nea.firmament.util.FirmFormatters +import moe.nea.firmament.util.MC +import moe.nea.firmament.util.assertTrueOr + +@RenderContextDSL +class FacingThePlayerContext(val worldContext: RenderInWorldContext) { + val matrixStack by worldContext::matrixStack + fun waypoint(position: BlockPos, label: Text) { + text( + label, + Text.literal("§e${FirmFormatters.formatDistance(MC.player?.pos?.distanceTo(position.toCenterPos()) ?: 42069.0)}") + ) + } + + fun text( + vararg texts: Text, + 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.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.matrixStack.translate(0F, 0F, 0.01F) + + MC.font.draw( + text, + 0F, + 0F, + -1, + false, + worldContext.matrixStack.peek().positionMatrix, + worldContext.vertexConsumers, + TextRenderer.TextLayerType.SEE_THROUGH, + 0, + LightmapTextureManager.MAX_LIGHT_COORDINATE + ) + worldContext.matrixStack.pop() + } + } + + + fun texture( + texture: Identifier, width: Int, height: Int, + u1: Float, v1: Float, + u2: Float, v2: Float, + ) { + RenderSystem.setShaderTexture(0, texture) + RenderSystem.setShader(GameRenderer::getPositionTexColorProgram) + val hw = width / 2F + val hh = height / 2F + val matrix4f: Matrix4f = worldContext.matrixStack.peek().positionMatrix + val buf = Tessellator.getInstance() + .begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR) + 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() + BufferRenderer.drawWithGlobalProgram(buf.end()) + } + +} diff --git a/src/main/kotlin/util/render/LerpUtils.kt b/src/main/kotlin/util/render/LerpUtils.kt new file mode 100644 index 0000000..f2c2f25 --- /dev/null +++ b/src/main/kotlin/util/render/LerpUtils.kt @@ -0,0 +1,33 @@ + +package moe.nea.firmament.util.render + +import me.shedaniel.math.Color + +val pi = Math.PI +val tau = 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() +} + +fun lerp(a: Float, b: Float, progress: Float): Float { + return a + (b - a) * progress +} +fun lerp(a: Int, b: Int, progress: Float): Int { + return (a + (b - a) * progress).toInt() +} + +fun ilerp(a: Float, b: Float, value: Float): Float { + 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), + ) +} + diff --git a/src/main/kotlin/util/render/RenderCircleProgress.kt b/src/main/kotlin/util/render/RenderCircleProgress.kt new file mode 100644 index 0000000..a2f42b5 --- /dev/null +++ b/src/main/kotlin/util/render/RenderCircleProgress.kt @@ -0,0 +1,95 @@ + +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.GameRenderer +import net.minecraft.client.render.Tessellator +import net.minecraft.client.render.VertexFormat.DrawMode +import net.minecraft.client.render.VertexFormats +import net.minecraft.util.Identifier + +object RenderCircleProgress { + + fun renderCircle( + drawContext: DrawContext, + texture: Identifier, + progress: Float, + u1: Float, + u2: Float, + v1: Float, + v2: Float, + ) { + RenderSystem.setShaderTexture(0, texture) + RenderSystem.setShader(GameRenderer::getPositionTexColorProgram) + RenderSystem.enableBlend() + val matrix: Matrix4f = drawContext.matrices.peek().positionMatrix + val bufferBuilder = Tessellator.getInstance().begin(DrawMode.TRIANGLES, VertexFormats.POSITION_TEXTURE_COLOR) + + 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 + } + 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) + } + } + + 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() + } + BufferRenderer.drawWithGlobalProgram(bufferBuilder.end()) + RenderSystem.disableBlend() + } + + + +} diff --git a/src/main/kotlin/util/render/RenderContextDSL.kt b/src/main/kotlin/util/render/RenderContextDSL.kt new file mode 100644 index 0000000..9bb4431 --- /dev/null +++ b/src/main/kotlin/util/render/RenderContextDSL.kt @@ -0,0 +1,6 @@ + +package moe.nea.firmament.util.render + +@DslMarker +annotation class RenderContextDSL { +} diff --git a/src/main/kotlin/util/render/RenderInWorldContext.kt b/src/main/kotlin/util/render/RenderInWorldContext.kt new file mode 100644 index 0000000..7faa499 --- /dev/null +++ b/src/main/kotlin/util/render/RenderInWorldContext.kt @@ -0,0 +1,294 @@ + + +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.BufferBuilder +import net.minecraft.client.render.BufferRenderer +import net.minecraft.client.render.Camera +import net.minecraft.client.render.GameRenderer +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.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 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, +) { + + object RenderLayers { + val TRANSLUCENT_TRIS = RenderLayer.of("firmament_translucent_tris", + VertexFormats.POSITION_COLOR, + VertexFormat.DrawMode.TRIANGLES, + RenderLayer.DEFAULT_BUFFER_SIZE, + false, true, + RenderLayer.MultiPhaseParameters.builder() + .depthTest(RenderPhase.ALWAYS_DEPTH_TEST) + .transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY) + .program(RenderPhase.COLOR_PROGRAM) + .build(false)) + } + + fun color(color: me.shedaniel.math.Color) { + color(color.red / 255F, color.green / 255f, color.blue / 255f, color.alpha / 255f) + } + + fun color(red: Float, green: Float, blue: Float, alpha: Float) { + RenderSystem.setShaderColor(red, green, blue, alpha) + } + + fun block(blockPos: BlockPos) { + matrixStack.push() + matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat()) + buildCube(matrixStack.peek().positionMatrix, tesselator) + matrixStack.pop() + } + + enum class VerticalAlign { + TOP, BOTTOM, CENTER; + + 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()) + } + } + } + + fun waypoint(position: BlockPos, vararg label: Text) { + text( + position.toCenterPos(), + *label, + Text.literal("§e${FirmFormatters.formatDistance(MC.player?.pos?.distanceTo(position.toCenterPos()) ?: 42069.0)}"), + background = 0xAA202020.toInt() + ) + } + + fun withFacingThePlayer(position: Vec3d, block: FacingThePlayerContext.() -> Unit) { + matrixStack.push() + 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) + matrixStack.translate(vec.x, vec.y, vec.z) + matrixStack.multiply(camera.rotation) + matrixStack.scale(0.025F, -0.025F, 1F) + + FacingThePlayerContext(this).run(block) + + matrixStack.pop() + vertexConsumers.drawCurrentLayer() + } + + fun sprite(position: Vec3d, sprite: Sprite, width: Int, height: Int) { + texture( + position, sprite.atlasId, width, height, sprite.minU, sprite.minV, sprite.maxU, sprite.maxV + ) + } + + fun texture( + position: Vec3d, texture: Identifier, width: Int, height: Int, + u1: Float, v1: Float, + u2: Float, v2: Float, + ) { + withFacingThePlayer(position) { + texture(texture, width, height, u1, v1, u2, v2) + } + } + + fun text(position: Vec3d, vararg texts: Text, verticalAlign: VerticalAlign = VerticalAlign.CENTER, background: Int = 0x70808080) { + withFacingThePlayer(position) { + text(*texts, verticalAlign = verticalAlign, background = background) + } + } + + fun tinyBlock(vec3d: Vec3d, size: Float) { + RenderSystem.setShader(GameRenderer::getPositionColorProgram) + matrixStack.push() + matrixStack.translate(vec3d.x, vec3d.y, vec3d.z) + matrixStack.scale(size, size, size) + matrixStack.translate(-.5, -.5, -.5) + buildCube(matrixStack.peek().positionMatrix, tesselator) + matrixStack.pop() + } + + fun wireframeCube(blockPos: BlockPos, lineWidth: Float = 10F) { + RenderSystem.setShader(GameRenderer::getRenderTypeLinesProgram) + matrixStack.push() + 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(), tesselator) + matrixStack.pop() + } + + fun line(vararg points: Vec3d, lineWidth: Float = 10F) { + line(points.toList(), 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 line(points: List<Vec3d>, lineWidth: Float = 10F) { + RenderSystem.setShader(GameRenderer::getRenderTypeLinesProgram) + RenderSystem.lineWidth(lineWidth) + val buffer = tesselator.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES) + + val matrix = matrixStack.peek() + var lastNormal: Vector3f? = null + points.zipWithNext().forEach { (a, b) -> + val normal = Vector3f(b.x.toFloat(), b.y.toFloat(), b.z.toFloat()) + .sub(a.x.toFloat(), a.y.toFloat(), a.z.toFloat()) + .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() + } + + BufferRenderer.drawWithGlobalProgram(buffer.end()) + } + + companion object { + private fun doLine( + matrix: MatrixStack.Entry, + buf: BufferBuilder, + i: Float, + j: Float, + k: Float, + x: Float, + y: Float, + z: Float + ) { + 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() + } + + + private fun buildWireFrameCube(matrix: MatrixStack.Entry, tessellator: Tessellator) { + val buf = tessellator.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES) + + for (i in 0..1) { + for (j in 0..1) { + val i = i.toFloat() + val j = j.toFloat() + doLine(matrix, buf, 0F, i, j, 1F, i, j) + doLine(matrix, buf, i, 0F, j, i, 1F, j) + doLine(matrix, buf, i, j, 0F, i, j, 1F) + } + } + BufferRenderer.drawWithGlobalProgram(buf.end()) + } + + private fun buildCube(matrix: Matrix4f, tessellator: Tessellator) { + val buf = tessellator.begin(VertexFormat.DrawMode.TRIANGLES, VertexFormats.POSITION_COLOR) + buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next() + buf.vertex(matrix, 0.0F, 0.0F, 1.0F).color(-1).next() + buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next() + buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next() + buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next() + buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next() + buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next() + buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next() + buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next() + buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next() + buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next() + buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next() + buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next() + buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next() + buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next() + buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next() + buf.vertex(matrix, 0.0F, 0.0F, 1.0F).color(-1).next() + buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next() + buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next() + buf.vertex(matrix, 0.0F, 0.0F, 1.0F).color(-1).next() + buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next() + buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next() + buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next() + buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next() + buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next() + buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next() + buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next() + buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next() + buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next() + buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next() + buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next() + buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next() + buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next() + buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next() + buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next() + buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next() + RenderLayers.TRANSLUCENT_TRIS.draw(buf.end()) + } + + + fun renderInWorld(event: WorldRenderLastEvent, block: RenderInWorldContext. () -> Unit) { + RenderSystem.disableDepthTest() + RenderSystem.enableBlend() + RenderSystem.defaultBlendFunc() + RenderSystem.disableCull() + + event.matrices.push() + 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() + + RenderSystem.setShaderColor(1F, 1F, 1F, 1F) + VertexBuffer.unbind() + RenderSystem.enableDepthTest() + RenderSystem.enableCull() + RenderSystem.disableBlend() + } + } +} + + diff --git a/src/main/kotlin/util/render/TranslatedScissors.kt b/src/main/kotlin/util/render/TranslatedScissors.kt new file mode 100644 index 0000000..c1e6544 --- /dev/null +++ b/src/main/kotlin/util/render/TranslatedScissors.kt @@ -0,0 +1,22 @@ + +package moe.nea.firmament.util.render + +import org.joml.Vector4f +import net.minecraft.client.gui.DrawContext + +fun DrawContext.enableScissorWithTranslation(x1: Float, y1: Float, x2: Float, y2: Float) { + val pMat = matrices.peek().positionMatrix + val target = Vector4f() + + target.set(x1, y1, 0f, 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 + + enableScissor(scissorX1.toInt(), scissorY1.toInt(), scissorX2.toInt(), scissorY2.toInt()) +} |