Chart levels

This commit is contained in:
DBotThePony 2024-10-01 15:13:42 +07:00
parent badcc5d3d5
commit 184203ee20
Signed by: DBot
GPG Key ID: DCC23B5715498507
3 changed files with 92 additions and 18 deletions

View File

@ -1,13 +1,17 @@
package ru.dbotthepony.mc.otm.client.render package ru.dbotthepony.mc.otm.client.render
import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.BufferBuilder
import com.mojang.blaze3d.vertex.BufferUploader import com.mojang.blaze3d.vertex.BufferUploader
import com.mojang.blaze3d.vertex.ByteBufferBuilder
import com.mojang.blaze3d.vertex.DefaultVertexFormat import com.mojang.blaze3d.vertex.DefaultVertexFormat
import com.mojang.blaze3d.vertex.PoseStack import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.blaze3d.vertex.VertexFormat import com.mojang.blaze3d.vertex.VertexFormat
import it.unimi.dsi.fastutil.floats.Float2ObjectMap
import net.minecraft.client.gui.Font import net.minecraft.client.gui.Font
import net.minecraft.client.renderer.GameRenderer import net.minecraft.client.renderer.GameRenderer
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import org.lwjgl.opengl.GL11.GL_LESS
import ru.dbotthepony.kommons.math.RGBAColor import ru.dbotthepony.kommons.math.RGBAColor
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.acos import kotlin.math.acos
@ -20,6 +24,8 @@ private const val LINE_WIDTH = 1f
private const val HIGHLIGHT_WIDTH = 3f private const val HIGHLIGHT_WIDTH = 3f
private val TEXT_BACKGROUND = RGBAColor(0f, 0f, 0f, 0.5f) private val TEXT_BACKGROUND = RGBAColor(0f, 0f, 0f, 0.5f)
private val LINE_COLOR = RGBAColor(1f, 0f, 1f, 0.25f)
private val LINE_TEXT_COLOR = RGBAColor(1f, 0f, 1f, 0.5f)
data class ChartMouseLabels( data class ChartMouseLabels(
val mouseX: Float, val mouseX: Float,
@ -32,6 +38,17 @@ data class ChartMouseLabels(
val textBackgroundColor: RGBAColor = TEXT_BACKGROUND val textBackgroundColor: RGBAColor = TEXT_BACKGROUND
) )
data class ChartLevelLabels(
val labels: Map<Float, Component>,
val font: Font,
val lineColor: RGBAColor = RGBAColor.DARK_GREEN,
val textColor: RGBAColor = RGBAColor.DARK_GREEN,
val textGravity: RenderGravity = RenderGravity.TOP_RIGHT,
val textOutline: RGBAColor = RGBAColor.BLACK
)
private val BYTE_BUFFER_BUILDER = ByteBufferBuilder(786_432)
fun renderChart( fun renderChart(
poseStack: PoseStack, poseStack: PoseStack,
normalized: FloatArray, normalized: FloatArray,
@ -39,10 +56,11 @@ fun renderChart(
height: Float, height: Float,
color: RGBAColor = RGBAColor.WHITE, color: RGBAColor = RGBAColor.WHITE,
labels: ChartMouseLabels? = null, labels: ChartMouseLabels? = null,
levelLabels: ChartLevelLabels? = null,
x: Float = 0f, x: Float = 0f,
y: Float = 0f, y: Float = 0f,
) { ) {
val builder = tesselator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION) val builder = BufferBuilder(BYTE_BUFFER_BUILDER, VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR)
val step = width / normalized.size val step = width / normalized.size
val pose = poseStack.last().pose val pose = poseStack.last().pose
@ -52,6 +70,17 @@ fun renderChart(
var drawPointX = 0f var drawPointX = 0f
var drawPointY = 0f var drawPointY = 0f
if (levelLabels != null) {
for ((level, label) in levelLabels.labels) {
val y0 = y + (1f - level) * height
builder.vertex(pose, x + width, LINE_WIDTH / 2f + y0, 0f).color(levelLabels.lineColor)
builder.vertex(pose, x + width, -LINE_WIDTH / 2f + y0, 0f).color(levelLabels.lineColor)
builder.vertex(pose, x, -LINE_WIDTH / 2f + y0, 0f).color(levelLabels.lineColor)
builder.vertex(pose, x, LINE_WIDTH / 2f + y0, 0f).color(levelLabels.lineColor)
}
}
for (i in 0 until normalized.size - 1) { for (i in 0 until normalized.size - 1) {
val y0 = y + (1f - normalized[i]) * height val y0 = y + (1f - normalized[i]) * height
val y1 = y + (1f - normalized[i + 1]) * height val y1 = y + (1f - normalized[i + 1]) * height
@ -63,10 +92,10 @@ fun renderChart(
val yDiff = y1 - y0 val yDiff = y1 - y0
if (yDiff.sign == 0f) { if (yDiff.sign == 0f) {
builder.vertex(pose, x0, y0 + LINE_WIDTH / 2f, 0f) builder.vertex(pose, x0, y0 + LINE_WIDTH / 2f, 0f).color(color)
builder.vertex(pose, x0, y0 - LINE_WIDTH / 2f, 0f) builder.vertex(pose, x0, y0 - LINE_WIDTH / 2f, 0f).color(color)
builder.vertex(pose, x1, y1 - LINE_WIDTH / 2f, 0f) builder.vertex(pose, x1, y1 - LINE_WIDTH / 2f, 0f).color(color)
builder.vertex(pose, x1, y1 + LINE_WIDTH / 2f, 0f) builder.vertex(pose, x1, y1 + LINE_WIDTH / 2f, 0f).color(color)
} else { } else {
val length = (xDiff.pow(2f) + yDiff.pow(2f)).pow(0.5f) val length = (xDiff.pow(2f) + yDiff.pow(2f)).pow(0.5f)
val angle = acos(xDiff / length) * yDiff.sign - PI / 2f // rotate 90 deg val angle = acos(xDiff / length) * yDiff.sign - PI / 2f // rotate 90 deg
@ -74,10 +103,10 @@ fun renderChart(
val xDisp = cos(angle).toFloat() * LINE_WIDTH / 2f val xDisp = cos(angle).toFloat() * LINE_WIDTH / 2f
val yDisp = sin(angle).toFloat() * LINE_WIDTH / 2f val yDisp = sin(angle).toFloat() * LINE_WIDTH / 2f
builder.vertex(pose, x0 + xDisp, y0 + yDisp, 0f) builder.vertex(pose, x0 + xDisp, y0 + yDisp, 0f).color(color)
builder.vertex(pose, x0 - xDisp, y0 - yDisp, 0f) builder.vertex(pose, x0 - xDisp, y0 - yDisp, 0f).color(color)
builder.vertex(pose, x1 - xDisp, y1 - yDisp, 0f) builder.vertex(pose, x1 - xDisp, y1 - yDisp, 0f).color(color)
builder.vertex(pose, x1 + xDisp, y1 + yDisp, 0f) builder.vertex(pose, x1 + xDisp, y1 + yDisp, 0f).color(color)
} }
//graphics.renderRect(x0, y0, LINE_WIDTH, LINE_WIDTH) //graphics.renderRect(x0, y0, LINE_WIDTH, LINE_WIDTH)
@ -89,13 +118,37 @@ fun renderChart(
} }
} }
RenderSystem.setShader(GameRenderer::getPositionShader) RenderSystem.setShader(GameRenderer::getPositionColorShader)
RenderSystem.setShaderColor(color.red, color.green, color.blue, color.alpha) // RenderSystem.setShaderColor(color.red, color.green, color.blue, color.alpha)
RenderSystem.disableDepthTest() RenderSystem.disableDepthTest()
RenderSystem.disableBlend() RenderSystem.disableBlend()
RenderSystem.setShaderColor(1f, 1f, 1f, 1f)
BufferUploader.drawWithShader(builder.buildOrThrow()) BufferUploader.drawWithShader(builder.buildOrThrow())
RenderSystem.enableDepthTest()
RenderSystem.depthFunc(GL_LESS)
if (levelLabels != null && levelLabels.labels.isNotEmpty()) {
for ((level, label) in levelLabels.labels) {
val y0 = y + (1f - level) * height
val tX = x + levelLabels.textGravity.repositionX(width, levelLabels.font.width(label).toFloat()) - 1f
val tY = y0 - LINE_WIDTH - 1f - levelLabels.font.lineHeight + levelLabels.textGravity.repositionY(levelLabels.font.lineHeight * 2f + LINE_WIDTH + 2f, levelLabels.font.lineHeight.toFloat()) + 1f
levelLabels.font.draw(
poseStack,
label,
x = tX,
y = tY,
color = levelLabels.textColor,
drawOutline = true,
outlineZ = -1f,
outlineColor = levelLabels.textOutline
)
}
}
if (drawLabel != -1) { if (drawLabel != -1) {
renderRect(pose, drawPointX - LINE_WIDTH / 2f, y, LINE_WIDTH, height, color = labels!!.pillarColor) renderRect(pose, drawPointX - LINE_WIDTH / 2f, y, LINE_WIDTH, height, color = labels!!.pillarColor)
renderRect(pose, drawPointX - HIGHLIGHT_WIDTH / 2f, drawPointY - HIGHLIGHT_WIDTH / 2f, HIGHLIGHT_WIDTH, HIGHLIGHT_WIDTH, color = labels.color) renderRect(pose, drawPointX - HIGHLIGHT_WIDTH / 2f, drawPointY - HIGHLIGHT_WIDTH / 2f, HIGHLIGHT_WIDTH, HIGHLIGHT_WIDTH, color = labels.color)

View File

@ -189,8 +189,8 @@ private fun Font.drawInternal(
for ((_x, _y) in outlinePositions) { for ((_x, _y) in outlinePositions) {
drawInBatch( drawInBatch(
text, text,
x * inv + _x, (x + _x) * inv,
y * inv + _y, (y + _y) * inv,
outlineColor.toBGR(), outlineColor.toBGR(),
drawShadow, drawShadow,
poseStack.last().pose(), poseStack.last().pose(),
@ -251,7 +251,7 @@ fun Font.draw(
rounding: GravityRounding = if (scale == 1f) GravityRounding.DEFAULT else GravityRounding.NO, rounding: GravityRounding = if (scale == 1f) GravityRounding.DEFAULT else GravityRounding.NO,
drawOutline: Boolean = false, drawOutline: Boolean = false,
outlineColor: RGBAColor = RGBAColor.BLACK, outlineColor: RGBAColor = RGBAColor.BLACK,
outlineZ: Float = 0.1f, outlineZ: Float = -0.1f,
): Float { ): Float {
return drawInternal( return drawInternal(
poseStack = poseStack, poseStack = poseStack,
@ -294,7 +294,7 @@ data class TextIcon(
val customShadow: Boolean = false, val customShadow: Boolean = false,
val drawOutline: Boolean = false, val drawOutline: Boolean = false,
val outlineColor: RGBAColor = RGBAColor.BLACK, val outlineColor: RGBAColor = RGBAColor.BLACK,
val outlineZ: Float = 0.1f, val outlineZ: Float = -0.1f,
) : IGUIRenderable { ) : IGUIRenderable {
override val width: Float = font.width(text) * scale override val width: Float = font.width(text) * scale
override val height: Float = font.lineHeight * scale override val height: Float = font.lineHeight * scale
@ -352,7 +352,7 @@ fun Font.draw(
rounding: GravityRounding = if (scale == 1f) GravityRounding.DEFAULT else GravityRounding.NO, rounding: GravityRounding = if (scale == 1f) GravityRounding.DEFAULT else GravityRounding.NO,
drawOutline: Boolean = false, drawOutline: Boolean = false,
outlineColor: RGBAColor = RGBAColor.BLACK, outlineColor: RGBAColor = RGBAColor.BLACK,
outlineZ: Float = 0.1f, outlineZ: Float = -0.1f,
): Float { ): Float {
return drawInternal( return drawInternal(
poseStack = poseStack, poseStack = poseStack,
@ -400,7 +400,7 @@ fun Font.draw(
rounding: GravityRounding = if (scale == 1f) GravityRounding.DEFAULT else GravityRounding.NO, rounding: GravityRounding = if (scale == 1f) GravityRounding.DEFAULT else GravityRounding.NO,
drawOutline: Boolean = false, drawOutline: Boolean = false,
outlineColor: RGBAColor = RGBAColor.BLACK, outlineColor: RGBAColor = RGBAColor.BLACK,
outlineZ: Float = 0.1f, outlineZ: Float = -0.1f,
): Float { ): Float {
return drawInternal( return drawInternal(
poseStack = poseStack, poseStack = poseStack,

View File

@ -1,7 +1,9 @@
package ru.dbotthepony.mc.otm.client.screen.panels package ru.dbotthepony.mc.otm.client.screen.panels
import it.unimi.dsi.fastutil.floats.Float2ObjectArrayMap
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import ru.dbotthepony.kommons.math.RGBAColor import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.mc.otm.client.render.ChartLevelLabels
import ru.dbotthepony.mc.otm.client.render.ChartMouseLabels import ru.dbotthepony.mc.otm.client.render.ChartMouseLabels
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
import ru.dbotthepony.mc.otm.client.render.renderChart import ru.dbotthepony.mc.otm.client.render.renderChart
@ -23,13 +25,31 @@ open class DecimalHistoryChartPanel<out S : MatteryScreen<*>>(
override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) { override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
val maximum = graph.max() val maximum = graph.max()
val normalized: FloatArray val normalized: FloatArray
val levelLabels: ChartLevelLabels
if (maximum.isZero || maximum.isInfinite) { if (maximum.isZero || maximum.isInfinite) {
normalized = FloatArray(graph.width) { normalized = FloatArray(graph.width) {
if (graph[it].isInfinite) 0.8f else 0.0f if (graph[it].isInfinite) 0.8f else 0.0f
} }
levelLabels = ChartLevelLabels(
labels = mapOf(0.8f to formatText(maximum)),
font = font
)
} else { } else {
normalized = FloatArray(graph.width) { (graph[it] / maximum).toFloat() * 0.9f } normalized = FloatArray(graph.width) { (graph[it] / maximum).toFloat() * 0.9f }
val map = Float2ObjectArrayMap<Component>()
map[0.9f] = formatText(maximum)
map[0.9f * 0.75f] = formatText(maximum * 0.75)
map[0.9f * 0.5f] = formatText(maximum * 0.5)
map[0.9f * 0.25f] = formatText(maximum * 0.25)
levelLabels = ChartLevelLabels(
labels = map,
font = font
)
} }
graphics.renderRect(0f, 0f, this.width, this.height, color = RGBAColor.BLACK) graphics.renderRect(0f, 0f, this.width, this.height, color = RGBAColor.BLACK)
@ -44,7 +64,8 @@ open class DecimalHistoryChartPanel<out S : MatteryScreen<*>>(
mouseY - absoluteY, mouseY - absoluteY,
{ formatText(graph[it]) }, { formatText(graph[it]) },
font, font,
) ),
levelLabels = levelLabels
) )
} }