130 lines
4.9 KiB
Kotlin
130 lines
4.9 KiB
Kotlin
package net.shadowfacts.cacao.util
|
|
|
|
import com.mojang.blaze3d.systems.RenderSystem
|
|
import net.minecraft.client.MinecraftClient
|
|
import net.minecraft.client.gui.DrawableHelper
|
|
import net.minecraft.client.gui.screen.Screen
|
|
import net.minecraft.client.render.*
|
|
import net.minecraft.client.sound.PositionedSoundInstance
|
|
import net.minecraft.client.util.math.MatrixStack
|
|
import net.minecraft.sound.SoundEvent
|
|
import net.minecraft.text.LiteralText
|
|
import net.minecraft.text.OrderedText
|
|
import net.minecraft.text.Text
|
|
import net.minecraft.util.math.Matrix4f
|
|
import net.shadowfacts.cacao.geometry.Point
|
|
import net.shadowfacts.cacao.geometry.Rect
|
|
import net.shadowfacts.cacao.util.texture.Texture
|
|
import kotlin.math.roundToInt
|
|
|
|
/**
|
|
* Helper methods for rendering using Minecraft's utilities from Cacao views.
|
|
* For unit testing, all drawing and OpenGL interaction can be disabled by setting the `cacao.drawing.disabled` JVM property to `true`.
|
|
*
|
|
* @author shadowfacts
|
|
*/
|
|
object RenderHelper: DrawableHelper() {
|
|
|
|
val disabled = (System.getProperty("cacao.drawing.disabled") ?: "false").toBoolean()
|
|
|
|
// TODO: find a better place for this
|
|
fun playSound(event: SoundEvent) {
|
|
if (disabled) return
|
|
MinecraftClient.getInstance().soundManager.play(PositionedSoundInstance.master(event, 1f))
|
|
}
|
|
|
|
/**
|
|
* Draws a solid [rect] filled with the given [color].
|
|
*/
|
|
fun fill(matrixStack: MatrixStack, rect: Rect, color: Color) {
|
|
if (disabled) return
|
|
fill(matrixStack, rect.left.toInt(), rect.top.toInt(), rect.right.toInt(), rect.bottom.toInt(), color.argb)
|
|
}
|
|
|
|
/**
|
|
* Binds and draws the given [texture] filling the [rect].
|
|
*/
|
|
fun draw(matrixStack: MatrixStack, rect: Rect, texture: Texture) {
|
|
if (disabled) return
|
|
RenderSystem.setShader(GameRenderer::getPositionTexShader)
|
|
RenderSystem.setShaderTexture(0, texture.location)
|
|
draw(matrixStack, rect.left, rect.top, texture.u, texture.v, rect.width, rect.height, texture.width, texture.height)
|
|
}
|
|
|
|
fun drawLine(start: Point, end: Point, z: Double, width: Float, color: Color) {
|
|
if (disabled) return
|
|
|
|
RenderSystem.lineWidth(width)
|
|
val tessellator = Tessellator.getInstance()
|
|
val buffer = tessellator.buffer
|
|
buffer.begin(VertexFormat.DrawMode.LINES, VertexFormats.POSITION_COLOR)
|
|
buffer.vertex(start.x, start.y, z).color(color).next()
|
|
buffer.vertex(end.x, end.y, z).color(color).next()
|
|
tessellator.draw()
|
|
}
|
|
|
|
/**
|
|
* Draws the bound texture with the given screen and texture position and size.
|
|
*/
|
|
fun draw(matrixStack: MatrixStack, x: Double, y: Double, u: Int, v: Int, width: Double, height: Double, textureWidth: Int, textureHeight: Int) {
|
|
if (disabled) return
|
|
val uStart = u.toFloat() / textureWidth
|
|
val uEnd = (u + width).toFloat() / textureWidth
|
|
val vStart = v.toFloat() / textureHeight
|
|
val vEnd = (v + height).toFloat() / textureHeight
|
|
drawTexturedQuad(matrixStack.peek().positionMatrix, x, x + width, y, y + height, 0.0, uStart, uEnd, vStart, vEnd)
|
|
}
|
|
|
|
// Copied from net.minecraft.client.gui.DrawableHelper
|
|
// TODO: use an access transformer to just call minecraft's impl
|
|
private fun drawTexturedQuad(matrix: Matrix4f, x0: Double, x1: Double, y0: Double, y1: Double, z: Double, u0: Float, u1: Float, v0: Float, v1: Float) {
|
|
val bufferBuilder = Tessellator.getInstance().buffer
|
|
bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE)
|
|
bufferBuilder.vertex(matrix, x0.toFloat(), y1.toFloat(), z.toFloat()).texture(u0, v1).next()
|
|
bufferBuilder.vertex(matrix, x1.toFloat(), y1.toFloat(), z.toFloat()).texture(u1, v1).next()
|
|
bufferBuilder.vertex(matrix, x1.toFloat(), y0.toFloat(), z.toFloat()).texture(u1, v0).next()
|
|
bufferBuilder.vertex(matrix, x0.toFloat(), y0.toFloat(), z.toFloat()).texture(u0, v0).next()
|
|
bufferBuilder.end()
|
|
BufferRenderer.draw(bufferBuilder)
|
|
}
|
|
|
|
fun drawTooltip(matrixStack: MatrixStack, text: Text, mouse: Point) {
|
|
drawTooltip(matrixStack, listOf(text.asOrderedText()), mouse)
|
|
}
|
|
|
|
fun drawTooltip(matrixStack: MatrixStack, texts: List<Text>, mouse: Point) {
|
|
drawTooltip(matrixStack, texts.map(Text::asOrderedText), mouse)
|
|
}
|
|
|
|
private val dummyScreen = object: Screen(LiteralText("")) {
|
|
init {
|
|
textRenderer = MinecraftClient.getInstance().textRenderer
|
|
itemRenderer = MinecraftClient.getInstance().itemRenderer
|
|
}
|
|
}
|
|
|
|
@JvmName("drawOrderedTooltip")
|
|
fun drawTooltip(matrixStack: MatrixStack, texts: List<OrderedText>, mouse: Point) {
|
|
if (disabled) return
|
|
if (texts.isEmpty()) return
|
|
|
|
val client = MinecraftClient.getInstance()
|
|
dummyScreen.width = client.window.scaledWidth
|
|
dummyScreen.height = client.window.scaledHeight
|
|
dummyScreen.renderOrderedTooltip(matrixStack, texts, mouse.x.roundToInt(), mouse.y.roundToInt())
|
|
}
|
|
|
|
/**
|
|
* @see org.lwjgl.opengl.GL11.glColor4f
|
|
*/
|
|
fun color(r: Float, g: Float, b: Float, alpha: Float) {
|
|
if (disabled) return
|
|
RenderSystem.setShaderColor(r, g, b, alpha)
|
|
}
|
|
|
|
private fun VertexConsumer.color(color: Color): VertexConsumer {
|
|
return color(color.red, color.green, color.blue, color.alpha)
|
|
}
|
|
|
|
}
|