diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/position/HUDElementVec2.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/position/HUDElementVec2.kt index db7fb6bd6..d60fc0dc6 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/position/HUDElementVec2.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/position/HUDElementVec2.kt @@ -2,6 +2,7 @@ package de.bixilon.minosoft.gui.rendering.hud.elements.position import de.bixilon.minosoft.data.Axes import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer +import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY import glm_.vec2.Vec2 import glm_.vec2.Vec2i @@ -25,9 +26,11 @@ class HUDElementVec2( } companion object { + private val ZERO_VECTOR = HUDElementVec2(Vec2.EMPTY, HUDElementPositionUnits.PIXELS) + fun deserialize(data: Any?): HUDElementVec2? { if (data !is Map<*, *>) { - return null + return ZERO_VECTOR } val xString = data["x"] as String val yString = data["y"] as String diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/primitive/HUDElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/primitive/HUDElement.kt index 2fbf101b6..eec359f88 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/primitive/HUDElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/primitive/HUDElement.kt @@ -18,9 +18,10 @@ import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer import de.bixilon.minosoft.gui.rendering.hud.elements.position.HUDElementPositionAnchors import de.bixilon.minosoft.gui.rendering.hud.elements.position.HUDElementVec2 import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec2 +import de.bixilon.minosoft.gui.rendering.util.mesh.SimpleTextureMesh import glm_.vec2.Vec2i -abstract class HUDElement( +open class HUDElement( var position: HUDElementPosition, val size: HUDElementVec2, val z: Int, @@ -47,7 +48,7 @@ abstract class HUDElement( prepareNext = false } - fun getPositionAtAnchor(anchor: HUDElementPositionAnchors): Vec2i { + open fun getPositionAtAnchor(anchor: HUDElementPositionAnchors): Vec2i { val realSize = size.getRealVector(hudRenderer).toVec2 val realPosition = position.getRealPosition(hudRenderer) return realPosition - realSize * position.anchor.positionTransform + realSize * anchor.positionTransform @@ -76,4 +77,6 @@ abstract class HUDElement( } open fun update() {} + + open fun prepare(mesh: SimpleTextureMesh) {} } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/primitive/HUDImageElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/primitive/HUDImageElement.kt index 8d7816f90..e3b70e943 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/primitive/HUDImageElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/primitive/HUDImageElement.kt @@ -17,7 +17,7 @@ import glm_.vec4.Vec4 import glm_.vec4.swizzle.xy class HUDImageElement: HUDElement { - private var mesh = SimpleTextureMesh() + private var textureMesh = SimpleTextureMesh() lateinit var texture: TextureLike private val textureName: ResourceLocation? @@ -48,15 +48,10 @@ class HUDImageElement: HUDElement { } override fun draw() { - mesh.draw() + textureMesh.draw() } - override fun prepare() { - super.prepare() - if (mesh.state == Mesh.MeshStates.LOADED) { - mesh.unload() - mesh = SimpleTextureMesh() - } + override fun prepare(mesh: SimpleTextureMesh) { val realZ = RenderConstants.HUD_Z_COORDINATE + RenderConstants.HUD_Z_COORDINATE_Z_FACTOR * z val positions = position.getPositions(hudRenderer, size.getRealVector(hudRenderer)) val uvs = texture.uvs @@ -70,7 +65,15 @@ class HUDImageElement: HUDElement { for (position in DRAW_ORDER) { addVertex((hudRenderer.orthographicMatrix * Vec4(positions[position], 1f, 1f)).xy, uvs[position]) } - mesh.load() + } + + override fun prepare() { + if (textureMesh.state == Mesh.MeshStates.LOADED) { + textureMesh.unload() + textureMesh = SimpleTextureMesh() + } + prepare(textureMesh) + textureMesh.load() } companion object { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/primitive/HUDSpacerElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/primitive/HUDSpacerElement.kt deleted file mode 100644 index f6d62637c..000000000 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/primitive/HUDSpacerElement.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Minosoft - * - * Copyright (C) 2021 Lukas Eisenhauer - * - * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If not, see . - * - * This software is not affiliated with Mojang AB, the original developer of Minecraft. - */ - -package de.bixilon.minosoft.gui.rendering.hud.elements.primitive - -import de.bixilon.minosoft.gui.rendering.hud.elements.position.HUDElementVec2 - -class HUDSpacerElement(position: HUDElementPosition, size: HUDElementVec2, z: Int,): - HUDElement(position, size, z) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/text/HUDTextElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/text/HUDTextElement.kt index 0d074a2d4..1c8545a1a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/text/HUDTextElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/text/HUDTextElement.kt @@ -27,18 +27,20 @@ import de.bixilon.minosoft.gui.rendering.hud.elements.position.HUDElementVec2 import de.bixilon.minosoft.gui.rendering.hud.elements.primitive.HUDElement import de.bixilon.minosoft.gui.rendering.hud.elements.primitive.HUDElementPosition import de.bixilon.minosoft.gui.rendering.hud.elements.primitive.HUDImageElement -import de.bixilon.minosoft.gui.rendering.hud.elements.primitive.HUDSpacerElement import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec2 +import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh +import de.bixilon.minosoft.gui.rendering.util.mesh.SimpleTextureMesh import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import glm_.glm import glm_.vec2.Vec2 +import glm_.vec2.Vec2i class HUDTextElement : HUDElement { val elements = mutableListOf() - + private var textureMesh = SimpleTextureMesh() private val alignment: HUDElementPositionAnchors - private lateinit var contents: List<*> + private lateinit var contents: Any private var currentText: ChatComponent? = null @@ -46,7 +48,7 @@ class HUDTextElement : HUDElement { constructor(position: HUDElementPosition, size: HUDElementVec2, json: Map? = null, activeOnMenu: HUDMenus?) : super(position, size, (json?.get("z") as Double?)?.toInt() ?: 0, activeOnMenu) { alignment = json?.get("alignment")?.let { HUDElementPositionAnchors.of(it as String) } ?: HUDElementPositionAnchors.TOP_LEFT - contents = json?.get("content") as List<*> + contents = json?.get("content")!! } constructor(position: HUDElementPosition, size: HUDElementVec2, z: Int) : super(position, size, z) { @@ -76,8 +78,8 @@ class HUDTextElement : HUDElement { } private fun addChars(chars: CharArray, color: RGBColor?, newLinePositions: MutableList): MutableList { - val maxRight = getPositionAtAnchor(HUDElementPositionAnchors.BOTTOM_RIGHT).x - val bottomLeftPosition = getPositionAtAnchor(HUDElementPositionAnchors.BOTTOM_LEFT).toVec2 + val maxRight = super.getPositionAtAnchor(HUDElementPositionAnchors.BOTTOM_RIGHT).x + val bottomLeftPosition = super.getPositionAtAnchor(HUDElementPositionAnchors.BOTTOM_LEFT).toVec2 for (char in chars) { if (char in ProtocolDefinition.LINE_BREAK_CHARS) { lastElement = null @@ -88,11 +90,11 @@ class HUDTextElement : HUDElement { HUDElementPosition(BETWEEN_CHARS_OFFSET, HUDElementPositionAnchors.BOTTOM_LEFT, it, HUDElementPositionAnchors.BOTTOM_RIGHT) } ?: run { newLinePositions += elements.size - HUDElementPosition(HUDElementVec2(getPositionAtAnchor(HUDElementPositionAnchors.BOTTOM_LEFT).toVec2, HUDElementPositionUnits.PIXELS), HUDElementPositionAnchors.BOTTOM_LEFT) + HUDElementPosition(HUDElementVec2(super.getPositionAtAnchor(HUDElementPositionAnchors.BOTTOM_LEFT).toVec2, HUDElementPositionUnits.PIXELS), HUDElementPositionAnchors.BOTTOM_LEFT) } val elementSize = HUDElementVec2(fontChar.size.toVec2, HUDElementPositionUnits.SCALED_PIXELS) val newElement = if (char == ' ') { - HUDSpacerElement(elementPosition, elementSize, z) + HUDElement(elementPosition, elementSize, z) } else { HUDImageElement(elementPosition, elementSize, z, fontChar, tint = color) } @@ -102,7 +104,7 @@ class HUDTextElement : HUDElement { lastElement = newElement if (elementRight > maxRight) { val relevantIndex = getLastSpacerElementPosition(elements.lastIndex) - if (elements[relevantIndex] is HUDSpacerElement) { + if (elements[relevantIndex] !is HUDImageElement) { elements.removeAt(relevantIndex) } newLinePositions += relevantIndex @@ -114,11 +116,11 @@ class HUDTextElement : HUDElement { private fun getLastSpacerElementPosition(position: Int): Int { for (i in 0..position) { - val j = position - i - 1 + val j = glm.max(0, position - i - 1) if (j == 0) { return position } - if (elements[j] is HUDSpacerElement) { + if (elements[j] !is HUDImageElement) { return j } if (elements[j].position.parentElement == null) { @@ -130,35 +132,43 @@ class HUDTextElement : HUDElement { private fun adjustPositionsForLineBreaks(newLinePositions: MutableList) { var y = when (alignment) { - HUDElementPositionAnchors.TOP_LEFT, HUDElementPositionAnchors.BOTTOM_LEFT -> getPositionAtAnchor(HUDElementPositionAnchors.TOP_LEFT).y - HUDElementPositionAnchors.TOP_RIGHT, HUDElementPositionAnchors.BOTTOM_RIGHT -> getPositionAtAnchor(HUDElementPositionAnchors.BOTTOM_RIGHT).y - (newLinePositions.size - 2) * (Font.CHAR_HEIGHT + 1) * Minosoft.getConfig().config.game.hud.scale.toInt() + HUDElementPositionAnchors.TOP_LEFT, HUDElementPositionAnchors.BOTTOM_LEFT -> super.getPositionAtAnchor(HUDElementPositionAnchors.TOP_LEFT).y + HUDElementPositionAnchors.TOP_RIGHT, HUDElementPositionAnchors.BOTTOM_RIGHT -> super.getPositionAtAnchor(HUDElementPositionAnchors.BOTTOM_RIGHT).y - (newLinePositions.size - 2) * (Font.CHAR_HEIGHT + 1) * Minosoft.getConfig().config.game.hud.scale.toInt() else -> TODO() } - val left = getPositionAtAnchor(HUDElementPositionAnchors.TOP_LEFT).x - val right = glm.min(hudRenderer.renderWindow.screenDimensions.x, getPositionAtAnchor(HUDElementPositionAnchors.BOTTOM_RIGHT).x) + val left = super.getPositionAtAnchor(HUDElementPositionAnchors.TOP_LEFT).x + val right = glm.min(hudRenderer.renderWindow.screenDimensions.x, super.getPositionAtAnchor(HUDElementPositionAnchors.BOTTOM_RIGHT).x) for (i in 0 until newLinePositions.lastIndex) { - elements[newLinePositions[i]].position = alignment.textAlignmentTransform.invoke(left, right, y, elements[newLinePositions[i + 1] - 1]) + elements[newLinePositions[i]].position = alignment.textAlignmentTransform.invoke(left, right, y, elements[glm.max(0, newLinePositions[i + 1] - 1)]) y += ((Font.CHAR_HEIGHT + 1) * Minosoft.getConfig().config.game.hud.scale).toInt() } } override fun draw() { - for (element in elements) { - element.draw() - } + textureMesh.draw() } override fun prepare() { + if (textureMesh.state == Mesh.MeshStates.LOADED) { + textureMesh.unload() + textureMesh = SimpleTextureMesh() + } + prepare(textureMesh) + textureMesh.load() + } + + override fun prepare(mesh: SimpleTextureMesh) { if (currentText == null) { - return + currentText = getChatComponent() } renderChatComponent(currentText!!) for (element in elements) { - element.prepare() + element.prepare(mesh) } + super.prepare() } - fun getTextComponent(): ChatComponent { + fun getChatComponent(): ChatComponent { return ChatComponent.of(contents, translator = hudRenderer.connection.version.localeManager.language, hudTextTranslator = hudRenderer.hudTextTranslator) } @@ -166,13 +176,23 @@ class HUDTextElement : HUDElement { if (!isEnabled) { return } - val newText = getTextComponent() + val newText = getChatComponent() if (currentText != newText) { currentText = newText prepareNext = true } } + override fun getPositionAtAnchor(anchor: HUDElementPositionAnchors): Vec2i { + return when (anchor) { + HUDElementPositionAnchors.CENTER -> TODO() + HUDElementPositionAnchors.TOP_LEFT -> super.getPositionAtAnchor(anchor) + HUDElementPositionAnchors.TOP_RIGHT -> Vec2i(elements[elements.lastIndex].getPositionAtAnchor(anchor).y, super.getPositionAtAnchor(anchor).x) + HUDElementPositionAnchors.BOTTOM_LEFT -> Vec2i(super.getPositionAtAnchor(anchor).x, elements[elements.lastIndex].getPositionAtAnchor(anchor).y) + HUDElementPositionAnchors.BOTTOM_RIGHT -> elements[elements.lastIndex].getPositionAtAnchor(anchor) + } + } + companion object { val BETWEEN_CHARS_OFFSET = HUDElementVec2(Vec2(1, 0), HUDElementPositionUnits.SCALED_PIXELS) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/text/HUDTextTranslator.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/text/HUDTextTranslator.kt index b115f8aaa..66c9600f3 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/text/HUDTextTranslator.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/text/HUDTextTranslator.kt @@ -18,40 +18,74 @@ import de.bixilon.minosoft.data.locale.minecraft.Translator import de.bixilon.minosoft.data.registries.ResourceLocation import de.bixilon.minosoft.data.text.ChatComponent import de.bixilon.minosoft.data.text.TextComponent +import de.bixilon.minosoft.gui.rendering.chunk.WorldRenderer import de.bixilon.minosoft.gui.rendering.util.VecUtil.round import de.bixilon.minosoft.protocol.network.connection.PlayConnection +import de.bixilon.minosoft.util.MMath.nanosToMillis import de.bixilon.minosoft.util.MMath.round -class HUDTextTranslator(val connection: PlayConnection) : Translator { +class HUDTextTranslator(private val connection: PlayConnection) : Translator { + private lateinit var worldRenderer: WorldRenderer + override fun translate(key: String?, parent: TextComponent?, vararg data: Any?): ChatComponent { if (key == null) { return ChatComponent.of(key) } + if (!this::worldRenderer.isInitialized) { + worldRenderer = connection.rendering!!.renderWindow.rendererMap[WorldRenderer.RESOURCE_LOCATION]!! as WorldRenderer + } val resourceLocation = ResourceLocation(key) if (resourceLocation !in insertRunnables) { return ChatComponent.of(key) } val runnable = insertRunnables[resourceLocation]!! // checked before - return ChatComponent.of(runnable.invoke(connection)) + return ChatComponent.of(runnable.invoke(connection, worldRenderer)) } companion object { - private val insertRunnables = mutableMapOf String>() + private val insertRunnables = mutableMapOf String>() init { - insertRunnables[ResourceLocation("minosoft:playerPosition_x")] = { connection -> + //position + insertRunnables[ResourceLocation("minosoft:playerPosition_x")] = { connection, _ -> connection.player.position.x.round(ROUND_DIGITS).toString() } - insertRunnables[ResourceLocation("minosoft:playerPosition_y")] = { connection -> + insertRunnables[ResourceLocation("minosoft:playerPosition_y")] = { connection, _ -> connection.player.position.y.round(ROUND_DIGITS).toString() } - insertRunnables[ResourceLocation("minosoft:playerPosition_z")] = { connection -> + insertRunnables[ResourceLocation("minosoft:playerPosition_z")] = { connection, _ -> connection.player.position.z.round(ROUND_DIGITS).toString() } - insertRunnables[ResourceLocation("minosoft:playerPosition_x")] = { connection -> + insertRunnables[ResourceLocation("minosoft:playerPosition_x")] = { connection, _ -> connection.player.position.round(ROUND_DIGITS).toString() } + // timings + insertRunnables[ResourceLocation("minosoft:fps")] = { connection, _ -> + connection.rendering!!.renderWindow.renderStats.fpsLastSecond.toString() + } + insertRunnables[ResourceLocation("minosoft:average_frame_time")] = { connection, _ -> + connection.rendering!!.renderWindow.renderStats.avgFrameTime.nanosToMillis.round(1).toString() + } + insertRunnables[ResourceLocation("minosoft:min_frame_time")] = { connection, _ -> + connection.rendering!!.renderWindow.renderStats.minFrameTime.nanosToMillis.round(1).toString() + } + insertRunnables[ResourceLocation("minosoft:max_frame_time")] = { connection, _ -> + connection.rendering!!.renderWindow.renderStats.maxFrameTime.nanosToMillis.round(1).toString() + } + // chunk data + insertRunnables[ResourceLocation("minosoft:queued_chunks_count")] = { _, worldRenderer -> + worldRenderer.queuedChunks.size.toString() + } + insertRunnables[ResourceLocation("minosoft:visible_chunks_count")] = { _, worldRenderer -> + worldRenderer.visibleChunks.size.toString() + } + insertRunnables[ResourceLocation("minosoft:all_chunk_secions_count")] = { _, worldRenderer -> + worldRenderer.allChunkSections.size.toString() + } + insertRunnables[ResourceLocation("minosoft:triangle_count")] = { _, worldRenderer -> + worldRenderer.triangles.toString() + } } const val ROUND_DIGITS = 2 diff --git a/src/main/java/de/bixilon/minosoft/util/MMath.kt b/src/main/java/de/bixilon/minosoft/util/MMath.kt index 2dc3e362c..999bc76e3 100644 --- a/src/main/java/de/bixilon/minosoft/util/MMath.kt +++ b/src/main/java/de/bixilon/minosoft/util/MMath.kt @@ -111,4 +111,6 @@ object MMath { val multiplicationFactor = glm.pow(10, digits) return (this * multiplicationFactor).floor / multiplicationFactor } + + val Long.nanosToMillis: Float get() = this / 1E6f }