From c2f12fc024ed726b9b4479decfcb90ddefc6f52a Mon Sep 17 00:00:00 2001 From: inglettronald Date: Sun, 23 Jul 2023 09:02:00 -0500 Subject: organization --- .../dulkirfabric/util/render/AnimationPreset.kt | 17 + .../util/render/GlowingEntityInterface.kt | 11 + .../com/dulkirfabric/util/render/HudRenderUtil.kt | 41 +++ .../dulkirfabric/util/render/ItemChangeHandler.kt | 13 + .../dulkirfabric/util/render/WorldRenderUtils.kt | 351 +++++++++++++++++++++ 5 files changed, 433 insertions(+) create mode 100644 src/main/kotlin/com/dulkirfabric/util/render/AnimationPreset.kt create mode 100644 src/main/kotlin/com/dulkirfabric/util/render/GlowingEntityInterface.kt create mode 100644 src/main/kotlin/com/dulkirfabric/util/render/HudRenderUtil.kt create mode 100644 src/main/kotlin/com/dulkirfabric/util/render/ItemChangeHandler.kt create mode 100644 src/main/kotlin/com/dulkirfabric/util/render/WorldRenderUtils.kt (limited to 'src/main/kotlin/com/dulkirfabric/util/render') diff --git a/src/main/kotlin/com/dulkirfabric/util/render/AnimationPreset.kt b/src/main/kotlin/com/dulkirfabric/util/render/AnimationPreset.kt new file mode 100644 index 0000000..af4388b --- /dev/null +++ b/src/main/kotlin/com/dulkirfabric/util/render/AnimationPreset.kt @@ -0,0 +1,17 @@ +package com.dulkirfabric.util.render + +import kotlinx.serialization.Serializable + +@Serializable +data class AnimationPreset( + var posX: Int = 0, + var posY: Int = 0, + var posZ: Int = 0, + var rotX: Int = 0, + var rotY: Int = 0, + var rotZ: Int = 0, + var scale: Float = 1f, + var swingDuration: Int = 6, + var cancelReEquip: Boolean = false, + var rotationlessDrink: Boolean = true, +) \ No newline at end of file diff --git a/src/main/kotlin/com/dulkirfabric/util/render/GlowingEntityInterface.kt b/src/main/kotlin/com/dulkirfabric/util/render/GlowingEntityInterface.kt new file mode 100644 index 0000000..3033d19 --- /dev/null +++ b/src/main/kotlin/com/dulkirfabric/util/render/GlowingEntityInterface.kt @@ -0,0 +1,11 @@ +package com.dulkirfabric.util.render + +import java.awt.Color + +interface GlowingEntityInterface { + fun setDulkirEntityGlow(shouldGlow: Boolean = false, glowColor: Color) + + fun shouldDulkirEntityGlow() : Boolean + + fun getDulkirEntityGlowColor() : Color? +} \ No newline at end of file diff --git a/src/main/kotlin/com/dulkirfabric/util/render/HudRenderUtil.kt b/src/main/kotlin/com/dulkirfabric/util/render/HudRenderUtil.kt new file mode 100644 index 0000000..e055b60 --- /dev/null +++ b/src/main/kotlin/com/dulkirfabric/util/render/HudRenderUtil.kt @@ -0,0 +1,41 @@ +package com.dulkirfabric.util.render + +import com.dulkirfabric.DulkirModFabric.mc +import com.dulkirfabric.events.HudRenderEvent +import meteordevelopment.orbit.EventHandler +import net.minecraft.client.gui.DrawContext +import net.minecraft.text.Text +import java.time.Duration + +object HudRenderUtil { + + private var curTitle: Text? = null + private var clearTime: Long = -1 + + private fun drawTitle(context: DrawContext, content: Text) { + val matrices = context.matrices + val tr = mc.textRenderer + val w = tr.getWidth(content) + val sf: Float = mc.window.scaledWidth / w.toFloat() / 3 + matrices.push() + matrices.translate(mc.window.scaledWidth / 3f, mc.window.scaledHeight / 2f, 0f) + matrices.scale(sf, sf, 1f) + context.drawText(tr, content, 0, -tr.fontHeight / 2, -1, true) + matrices.pop() + } + + fun drawTitle(content: Text, duration: Duration) { + curTitle = content + clearTime = System.currentTimeMillis() + duration.toMillis() + } + + @EventHandler + fun onHudRender(event: HudRenderEvent) { + val content = curTitle ?: return + if (System.currentTimeMillis() >= clearTime) { + curTitle = null + return + } + drawTitle(event.context, content) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/dulkirfabric/util/render/ItemChangeHandler.kt b/src/main/kotlin/com/dulkirfabric/util/render/ItemChangeHandler.kt new file mode 100644 index 0000000..7f6193e --- /dev/null +++ b/src/main/kotlin/com/dulkirfabric/util/render/ItemChangeHandler.kt @@ -0,0 +1,13 @@ +package com.dulkirfabric.util.render + +import com.dulkirfabric.events.TooltipRenderChangeEvent + +object ItemChangeHandler { + var prevName = "" + fun handle(name: String) { + if (name != prevName) { + prevName = name + TooltipRenderChangeEvent.post() + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/dulkirfabric/util/render/WorldRenderUtils.kt b/src/main/kotlin/com/dulkirfabric/util/render/WorldRenderUtils.kt new file mode 100644 index 0000000..ceb631d --- /dev/null +++ b/src/main/kotlin/com/dulkirfabric/util/render/WorldRenderUtils.kt @@ -0,0 +1,351 @@ +package com.dulkirfabric.util.render + +import com.mojang.blaze3d.systems.RenderSystem +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext +import net.minecraft.client.MinecraftClient +import net.minecraft.client.font.TextRenderer +import net.minecraft.client.render.* +import net.minecraft.client.util.math.MatrixStack +import net.minecraft.text.Style +import net.minecraft.text.Text +import net.minecraft.util.Formatting +import net.minecraft.util.math.Box +import net.minecraft.util.math.Vec3d +import org.joml.Vector3f +import java.awt.Color +import kotlin.math.max +import kotlin.math.pow +import kotlin.math.sqrt + + +object WorldRenderUtils { + private fun line( + matrix: MatrixStack.Entry, buffer: BufferBuilder, + x1: Number, y1: Number, z1: Number, + x2: Number, y2: Number, z2: Number, + lineWidth: Float + ) { + val camera = MinecraftClient.getInstance().cameraEntity ?: return + RenderSystem.lineWidth(lineWidth / camera.pos.squaredDistanceTo( + Vec3d(x1.toDouble(), y1.toDouble(), z1.toDouble()) + ).pow(0.25).toFloat()) + line( + matrix, + buffer, + Vector3f(x1.toFloat(), y1.toFloat(), z1.toFloat()), + Vector3f(x2.toFloat(), y2.toFloat(), z2.toFloat()) + ) + } + + private fun line(matrix: MatrixStack.Entry, buffer: BufferBuilder, from: Vector3f, to: Vector3f) { + val normal = to.sub(from, Vector3f()).mul(-1F) + buffer.vertex(matrix.positionMatrix, from.x, from.y, from.z) + .normal(matrix.normalMatrix, normal.x, normal.y, normal.z).next() + buffer.vertex(matrix.positionMatrix, to.x, to.y, to.z) + .normal(matrix.normalMatrix, normal.x, normal.y, normal.z) + .next() + } + + /** + * Draws a box in world space, given the coordinates of the box, thickness of the lines, and color. + * TODO: write a more custom rendering function so we don't have to do this ugly translation of + * Minecraft's screen space rendering logic to a world space rendering function. + */ + fun drawBox( + context: WorldRenderContext, + box: Box, + color: Color, + thickness: Float, + depthTest: Boolean = true + ) { + val matrices = context.matrixStack() + matrices.push() + val prevShader = RenderSystem.getShader() + RenderSystem.setShader(GameRenderer::getRenderTypeLinesProgram) + RenderSystem.disableBlend() + RenderSystem.disableCull() + // RenderSystem.defaultBlendFunc() + RenderSystem.setShaderColor(color.red / 255f, color.green / 255f, color.blue / 255f, color.alpha / 255f) + if (!depthTest) { + RenderSystem.disableDepthTest() + RenderSystem.depthMask(false) + } else { + RenderSystem.enableDepthTest() + } + matrices.translate(-context.camera().pos.x, -context.camera().pos.y, -context.camera().pos.z) + val tess = RenderSystem.renderThreadTesselator() + val buf = tess.buffer + val me = matrices.peek() + + buf.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES) + buf.fixedColor(255, 255, 255, 255) + + // X Axis aligned lines + line(me, buf, box.minX, box.minY, box.minZ, box.maxX, box.minY, box.minZ, thickness) + line(me, buf, box.minX, box.maxY, box.minZ, box.maxX, box.maxY, box.minZ, thickness) + line(me, buf, box.minX, box.minY, box.maxZ, box.maxX, box.minY, box.maxZ, thickness) + line(me, buf, box.minX, box.maxY, box.maxZ, box.maxX, box.maxY, box.maxZ, thickness) + + // Y Axis aligned lines + line(me, buf, box.minX, box.minY, box.minZ, box.minX, box.maxY, box.minZ, thickness) + line(me, buf, box.maxX, box.minY, box.minZ, box.maxX, box.maxY, box.minZ, thickness) + line(me, buf, box.minX, box.minY, box.maxZ, box.minX, box.maxY, box.maxZ, thickness) + line(me, buf, box.maxX, box.minY, box.maxZ, box.maxX, box.maxY, box.maxZ, thickness) + + // Z Axis aligned lines + line(me, buf, box.minX, box.minY, box.minZ, box.minX, box.minY, box.maxZ, thickness) + line(me, buf, box.maxX, box.minY, box.minZ, box.maxX, box.minY, box.maxZ, thickness) + line(me, buf, box.minX, box.maxY, box.minZ, box.minX, box.maxY, box.maxZ, thickness) + line(me, buf, box.maxX, box.maxY, box.minZ, box.maxX, box.maxY, box.maxZ, thickness) + + buf.unfixColor() + tess.draw() + + RenderSystem.depthMask(true) + RenderSystem.enableDepthTest() + RenderSystem.enableBlend() + RenderSystem.setShaderColor( + 1f, 1f, 1f, 1f + ) + RenderSystem.setShader { prevShader } + RenderSystem.enableCull() + matrices.pop() + } + + /** + * This draw line function is intended to be used for drawing very few lines, as it's not the most efficient. + * For drawing many lines in a series, save them to an array and use the drawLineArray function. + */ + fun drawLine(context: WorldRenderContext, startPos: Vec3d, endPos: Vec3d, color: Color, thickness: Float, depthTest: Boolean = true) { + val matrices = context.matrixStack() + matrices.push() + val prevShader = RenderSystem.getShader() + RenderSystem.setShader(GameRenderer::getRenderTypeLinesProgram) + RenderSystem.disableBlend() + RenderSystem.disableCull() + // RenderSystem.defaultBlendFunc() + RenderSystem.setShaderColor(color.red / 255f, color.green / 255f, color.blue / 255f, color.alpha / 255f) + if (!depthTest) { + RenderSystem.disableDepthTest() + RenderSystem.depthMask(false) + } else { + RenderSystem.enableDepthTest() + } + matrices.translate(-context.camera().pos.x, -context.camera().pos.y, -context.camera().pos.z) + val tess = RenderSystem.renderThreadTesselator() + val buf = tess.buffer + val me = matrices.peek() + + buf.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES) + buf.fixedColor(255, 255, 255, 255) + + line(me, buf, startPos.x.toFloat(), startPos.y.toFloat(), startPos.z.toFloat(), endPos.x.toFloat(), endPos.y.toFloat(), endPos.z.toFloat(), thickness) + + buf.unfixColor() + tess.draw() + + RenderSystem.depthMask(true) + RenderSystem.enableDepthTest() + RenderSystem.enableBlend() + RenderSystem.setShaderColor( + 1f, 1f, 1f, 1f + ) + RenderSystem.setShader { prevShader } + RenderSystem.enableCull() + matrices.pop() + } + + /** + * This function is intended to be used for drawing many lines in a series, as it's more efficient than the + * drawLine function being called many times in series. + */ + fun drawLineArray(context: WorldRenderContext, posArr: List, color: Color, thickness: Float, depthTest: Boolean = true) { + val matrices = context.matrixStack() + matrices.push() + val prevShader = RenderSystem.getShader() + RenderSystem.setShader(GameRenderer::getRenderTypeLinesProgram) + RenderSystem.disableBlend() + RenderSystem.disableCull() + // RenderSystem.defaultBlendFunc() + RenderSystem.setShaderColor(color.red / 255f, color.green / 255f, color.blue / 255f, color.alpha / 255f) + if (!depthTest) { + RenderSystem.disableDepthTest() + RenderSystem.depthMask(false) + } else { + RenderSystem.enableDepthTest() + } + matrices.translate(-context.camera().pos.x, -context.camera().pos.y, -context.camera().pos.z) + val tess = RenderSystem.renderThreadTesselator() + val buf = tess.buffer + val me = matrices.peek() + + buf.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES) + buf.fixedColor(255, 255, 255, 255) + + for (i in 0 until posArr.size - 1) { + val startPos = posArr[i] + val endPos = posArr[i + 1] + line(me, buf, startPos.x.toFloat(), startPos.y.toFloat(), startPos.z.toFloat(), endPos.x.toFloat(), endPos.y.toFloat(), endPos.z.toFloat(), thickness) + } + + buf.unfixColor() + tess.draw() + + RenderSystem.depthMask(true) + RenderSystem.enableDepthTest() + RenderSystem.enableBlend() + RenderSystem.setShaderColor( + 1f, 1f, 1f, 1f + ) + RenderSystem.setShader { prevShader } + RenderSystem.enableCull() + matrices.pop() + } + + /** + * If you intend to show with distance, use a waypoint I think. If you're looking at this + * statement and screaming at me for forgetting some use case, either let me know or compile + * a method that accomplishes your goals based off of this example code. Neither of these + * things should be incredibly difficult. + */ + fun drawText( + text: Text, + context: WorldRenderContext, + pos: Vec3d, + depthTest: Boolean = true, + scale: Float = 1f + ) { + if (depthTest) { + RenderSystem.disableDepthTest() + } + RenderSystem.enableBlend() + RenderSystem.defaultBlendFunc() + RenderSystem.disableCull() + + val vertexConsumer = context.worldRenderer().bufferBuilders.entityVertexConsumers + val matrices = context.matrixStack() + matrices.push() + matrices.translate( + pos.x - context.camera().pos.x, + pos.y - context.camera().pos.y, + pos.z - context.camera().pos.z + ) + matrices.multiply(context.camera().rotation) + matrices.scale(-.025f * scale, -.025f * scale, -1F) + val matrix4f = matrices.peek().positionMatrix + val textRenderer = MinecraftClient.getInstance().textRenderer + val j: Int = (.25 * 255.0f).toInt() shl 24 + val buf = vertexConsumer.getBuffer(RenderLayer.getTextBackgroundSeeThrough()) + buf.vertex(matrix4f, -1.0f - textRenderer.getWidth(text) / 2, -1.0f, 0.0f) + .color(j) + .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE) + .next() + buf.vertex(matrix4f, -1.0f - textRenderer.getWidth(text) / 2, textRenderer.fontHeight.toFloat(), 0.0f) + .color(j) + .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE) + .next() + buf.vertex(matrix4f, textRenderer.getWidth(text).toFloat() / 2, textRenderer.fontHeight.toFloat(), 0.0f) + .color(j) + .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE) + .next() + buf.vertex(matrix4f, textRenderer.getWidth(text).toFloat() / 2, -1.0f, 0.0f) + .color(j) + .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE) + .next() + + matrices.translate(0F, 0F, 0.01F) + + textRenderer.draw( + text, -textRenderer.getWidth(text).toFloat() / 2, 0f, 0xFFFFFF, false, matrix4f, vertexConsumer, + TextRenderer.TextLayerType.SEE_THROUGH, + 0, LightmapTextureManager.MAX_LIGHT_COORDINATE + ) + + vertexConsumer.drawCurrentLayer() + matrices.pop() + RenderSystem.setShaderColor(1F, 1F, 1F, 1F) + RenderSystem.enableDepthTest() + RenderSystem.enableCull() + RenderSystem.disableBlend() + } + + fun renderWaypoint( + text: Text, + context: WorldRenderContext, + pos: Vec3d, + ) + { + RenderSystem.disableDepthTest() + RenderSystem.enableBlend() + RenderSystem.defaultBlendFunc() + RenderSystem.disableCull() + val d: Double = pos.distanceTo(MinecraftClient.getInstance().player?.pos) + val distText = Text.literal(d.toInt().toString() + "m").setStyle(Style.EMPTY.withColor(Formatting.YELLOW)) + val matrices = context.matrixStack() + val vertexConsumer = context.worldRenderer().bufferBuilders.entityVertexConsumers + matrices.push() + val magnitude = sqrt((pos.x - context.camera().pos.x).pow(2) + + (pos.y - context.camera().pos.y).pow(2) + + (pos.z - context.camera().pos.z).pow(2)) + if (magnitude < 20) { + matrices.translate( + pos.x - context.camera().pos.x, + pos.y - context.camera().pos.y, + pos.z - context.camera().pos.z + ) + } else { + matrices.translate( + (pos.x - context.camera().pos.x) / magnitude * 20, + (pos.y - context.camera().pos.y) / magnitude * 20, + (pos.z - context.camera().pos.z) / magnitude * 20 + ) + } + matrices.multiply(context.camera().rotation) + val scale = max(d.toFloat() / 7f, 1f) + if (magnitude < 20) { + matrices.scale(-.025f * scale, -.025f * scale, -1F) + } else { + matrices.scale(-.025f * 20 / 7f, -.025f * 20 / 7f, -.1F) + } + val matrix4f = matrices.peek().positionMatrix + val textRenderer = MinecraftClient.getInstance().textRenderer + val j: Int = (.25 * 255.0f).toInt() shl 24 + val buf = vertexConsumer.getBuffer(RenderLayer.getTextBackgroundSeeThrough()) + buf.vertex(matrix4f, -1.0f - textRenderer.getWidth(text) / 2, -1.0f, 0.0f) + .color(j) + .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE) + .next() + buf.vertex(matrix4f, -1.0f - textRenderer.getWidth(text) / 2, textRenderer.fontHeight.toFloat(), 0.0f) + .color(j) + .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE) + .next() + buf.vertex(matrix4f, textRenderer.getWidth(text).toFloat() / 2, textRenderer.fontHeight.toFloat(), 0.0f) + .color(j) + .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE) + .next() + buf.vertex(matrix4f, textRenderer.getWidth(text).toFloat() / 2, -1.0f, 0.0f) + .color(j) + .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE) + .next() + + matrices.translate(0F, 0F, 0.01F) + + textRenderer.draw( + text, -textRenderer.getWidth(text).toFloat() / 2, 0f, 0xFFFFFF, false, matrix4f, vertexConsumer, + TextRenderer.TextLayerType.SEE_THROUGH, + 0, LightmapTextureManager.MAX_LIGHT_COORDINATE + ) + + textRenderer.draw( + distText, -textRenderer.getWidth(distText).toFloat() / 2, 10f, 0xFFFFFF, false, matrix4f, vertexConsumer, + TextRenderer.TextLayerType.SEE_THROUGH, + 0, LightmapTextureManager.MAX_LIGHT_COORDINATE + ) + vertexConsumer.drawCurrentLayer() + matrices.pop() + RenderSystem.setShaderColor(1F, 1F, 1F, 1F) + RenderSystem.enableDepthTest() + RenderSystem.enableCull() + RenderSystem.disableBlend() + } +} \ No newline at end of file -- cgit