Chart levels
This commit is contained in:
parent
badcc5d3d5
commit
184203ee20
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user