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
import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.BufferBuilder
import com.mojang.blaze3d.vertex.BufferUploader
import com.mojang.blaze3d.vertex.ByteBufferBuilder
import com.mojang.blaze3d.vertex.DefaultVertexFormat
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.blaze3d.vertex.VertexFormat
import it.unimi.dsi.fastutil.floats.Float2ObjectMap
import net.minecraft.client.gui.Font
import net.minecraft.client.renderer.GameRenderer
import net.minecraft.network.chat.Component
import org.lwjgl.opengl.GL11.GL_LESS
import ru.dbotthepony.kommons.math.RGBAColor
import kotlin.math.PI
import kotlin.math.acos
@ -20,6 +24,8 @@ private const val LINE_WIDTH = 1f
private const val HIGHLIGHT_WIDTH = 3f
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(
val mouseX: Float,
@ -32,6 +38,17 @@ data class ChartMouseLabels(
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(
poseStack: PoseStack,
normalized: FloatArray,
@ -39,10 +56,11 @@ fun renderChart(
height: Float,
color: RGBAColor = RGBAColor.WHITE,
labels: ChartMouseLabels? = null,
levelLabels: ChartLevelLabels? = null,
x: 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 pose = poseStack.last().pose
@ -52,6 +70,17 @@ fun renderChart(
var drawPointX = 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) {
val y0 = y + (1f - normalized[i]) * height
val y1 = y + (1f - normalized[i + 1]) * height
@ -63,10 +92,10 @@ fun renderChart(
val yDiff = y1 - y0
if (yDiff.sign == 0f) {
builder.vertex(pose, x0, y0 + LINE_WIDTH / 2f, 0f)
builder.vertex(pose, x0, y0 - LINE_WIDTH / 2f, 0f)
builder.vertex(pose, x1, y1 - LINE_WIDTH / 2f, 0f)
builder.vertex(pose, x1, y1 + LINE_WIDTH / 2f, 0f)
builder.vertex(pose, x0, y0 + LINE_WIDTH / 2f, 0f).color(color)
builder.vertex(pose, x0, y0 - LINE_WIDTH / 2f, 0f).color(color)
builder.vertex(pose, x1, y1 - LINE_WIDTH / 2f, 0f).color(color)
builder.vertex(pose, x1, y1 + LINE_WIDTH / 2f, 0f).color(color)
} else {
val length = (xDiff.pow(2f) + yDiff.pow(2f)).pow(0.5f)
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 yDisp = sin(angle).toFloat() * LINE_WIDTH / 2f
builder.vertex(pose, x0 + xDisp, y0 + yDisp, 0f)
builder.vertex(pose, x0 - xDisp, y0 - yDisp, 0f)
builder.vertex(pose, x1 - xDisp, y1 - yDisp, 0f)
builder.vertex(pose, x1 + xDisp, y1 + yDisp, 0f)
builder.vertex(pose, x0 + xDisp, y0 + yDisp, 0f).color(color)
builder.vertex(pose, x0 - xDisp, y0 - yDisp, 0f).color(color)
builder.vertex(pose, x1 - xDisp, y1 - yDisp, 0f).color(color)
builder.vertex(pose, x1 + xDisp, y1 + yDisp, 0f).color(color)
}
//graphics.renderRect(x0, y0, LINE_WIDTH, LINE_WIDTH)
@ -89,13 +118,37 @@ fun renderChart(
}
}
RenderSystem.setShader(GameRenderer::getPositionShader)
RenderSystem.setShaderColor(color.red, color.green, color.blue, color.alpha)
RenderSystem.setShader(GameRenderer::getPositionColorShader)
// RenderSystem.setShaderColor(color.red, color.green, color.blue, color.alpha)
RenderSystem.disableDepthTest()
RenderSystem.disableBlend()
RenderSystem.setShaderColor(1f, 1f, 1f, 1f)
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) {
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)

View File

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

View File

@ -1,7 +1,9 @@
package ru.dbotthepony.mc.otm.client.screen.panels
import it.unimi.dsi.fastutil.floats.Float2ObjectArrayMap
import net.minecraft.network.chat.Component
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.MGUIGraphics
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) {
val maximum = graph.max()
val normalized: FloatArray
val levelLabels: ChartLevelLabels
if (maximum.isZero || maximum.isInfinite) {
normalized = FloatArray(graph.width) {
if (graph[it].isInfinite) 0.8f else 0.0f
}
levelLabels = ChartLevelLabels(
labels = mapOf(0.8f to formatText(maximum)),
font = font
)
} else {
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)
@ -44,7 +64,8 @@ open class DecimalHistoryChartPanel<out S : MatteryScreen<*>>(
mouseY - absoluteY,
{ formatText(graph[it]) },
font,
)
),
levelLabels = levelLabels
)
}